/* ==========================================================================
 Tokens (shared with the main site palette — see /css/style.css)
 ========================================================================== */

:root {
  color-scheme: light dark;

  --page-bg: #ffffff;
  --page-bg-secondary: rgb(255 255 255 / 0.5);
  --text-main: #161616;
  /* Between main and muted: emphasised list and quote copy. */
  --text-secondary: rgb(0 0 0 / 0.72);
  --text-muted: rgb(0 0 0 / 0.55);
  --text-soft: rgb(0 0 0 / 0.4);

  --glass-bg: rgb(200 200 200 / 0.35);
  --glass-bg-hover: rgb(0 0 0 / 1);

  --sheet-bg: rgb(0 0 0 / 0.03);
  --levitated-button-bg: rgb(241 241 241 / 0.6);

  --icon-filter: brightness(0) opacity(0.55);
  --icon-filter-hover: brightness(0) invert(1) opacity(0.8);

  --selection-bg: rgb(0 0 0 / 0.3);
}

@media (prefers-color-scheme: dark) {
  :root {
    --page-bg: #141414;
    --page-bg-secondary: rgb(0 0 0 / 0.5);
    --text-main: #f5f5f5;
    --text-secondary: rgb(255 255 255 / 0.78);
    --text-muted: rgb(255 255 255 / 0.6);
    --text-soft: rgb(255 255 255 / 0.45);

    --glass-bg: rgb(120 120 120 / 0.28);
    --glass-bg-hover: rgb(255 255 255 / 1);

    --sheet-bg: rgb(255 255 255 / 0.045);
    --levitated-button-bg: rgb(42 42 42 / 0.6);

    --icon-filter: brightness(0) invert(1) opacity(0.65);
    --icon-filter-hover: brightness(0) opacity(0.85);

    --selection-bg: rgb(255 255 255 / 0.25);
  }
}

/* ==========================================================================
 Base
 ========================================================================== */

* {
  box-sizing: border-box;
}

::-moz-selection {
  background: var(--selection-bg);
  text-shadow: none;
}

::selection {
  background: var(--selection-bg);
  text-shadow: none;
}

html,
body {
  margin: 0;
  width: 100%;
  min-height: 100%;
  font-family: Inter, -apple-system, BlinkMacSystemFont, "SF Pro Display",
  "Segoe UI", sans-serif;
  background: var(--page-bg);
  color: var(--text-main);
}

a {
  color: inherit;
  text-decoration: none;
}

img,
video {
  max-width: 100%;
  display: block;
  -webkit-user-drag: none;
  user-select: none;
  pointer-events: none;
}

/* ==========================================================================
 Layout
 ========================================================================== */

.detail-main {
  --content-pad: clamp(20px, 6vw, 48px);

  max-width: 900px;
  margin: 0 auto;
  padding: clamp(90px, 14vw, 140px) var(--content-pad) clamp(160px, 20vw, 210px);
}

@media (min-width: 900px) {
  .detail-main {
    max-width: 1160px;
  }
}

/* ==========================================================================
 Hero
 ========================================================================== */

@keyframes rise-in {
  from {
    opacity: 0;
    filter: blur(16px);
    transform: translateY(18px);
  }
  to {
    opacity: 1;
    filter: blur(0);
    transform: translateY(0);
  }
}

/* Same rise as above, but on the standalone `translate` property instead
   of `transform` — used by elements that also need `transform`/`scale`
   free for their own interaction states (e.g. a press effect), since a
   fill-mode:both animation otherwise keeps pinning `transform` in the
   cascade even after it finishes, blocking later class-driven changes. */
@keyframes rise-in-translate {
  from {
    opacity: 0;
    filter: blur(16px);
    translate: 0 18px;
  }
  to {
    opacity: 1;
    filter: blur(0);
    translate: 0 0;
  }
}

.detail-hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: clamp(28px, 4vw, 40px);

  margin-bottom: clamp(120px, 15vw, 200px);
}

.detail-hero-text {
  width: 100%;
}

.detail-hero h1 {
  font-size: clamp(34px, 6vw, 60px);
  font-weight: 600;
  line-height: 1.05;
  letter-spacing: -0.01em;
  margin: 0 0 14px;

  animation: rise-in 900ms cubic-bezier(0.22, 1, 0.36, 1) both;
}

.detail-hero-eyebrow {
  font-size: 13px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-soft);
  margin: 0 0 20px;

  animation: rise-in 900ms cubic-bezier(0.22, 1, 0.36, 1) 60ms both;
}

/* Product Page CTA + App Store button, side by side. A block-level flex
   row spans the full width of .detail-hero-text, so it needs its own
   justify-content to stay centred with the rest of the hero text in the
   narrow/column layout (text-align alone only affects inline content). */
.detail-hero-actions {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  margin: 12px 0 0;
}

/* Product Page CTA — same look as the floating .detail-back pill, just
   inline in the hero and shown immediately (no entrance transition). */
.detail-hero-cta {
  display: inline-flex;
  align-items: center;
  gap: 8px;

  height: 50px;
  padding: 0 18px 0 14px;
  margin: 0;

  border: 1px solid rgb(127 127 127 / 0.10);
  border-radius: 999px;
  background: var(--levitated-button-bg);
  backdrop-filter: blur(30px);
  -webkit-backdrop-filter: blur(30px);

  box-shadow:
    0 12px 30px rgb(0 0 0 / 0.10),
    0 4px 10px rgb(0 0 0 / 0.06);

  white-space: nowrap;

  font-size: 19px;
  font-weight: 400;
  color: var(--text-muted);

  cursor: pointer;

  transition:
    background 240ms ease,
    color 240ms ease,
    scale 240ms ease;

  animation: rise-in-translate 900ms cubic-bezier(0.22, 1, 0.36, 1) 90ms both;
}

.detail-hero-cta img {
  width: 15px;
  height: 21px;
  margin-left: 7px;
  margin-right: 3px;
  margin-top: 2px;
  object-fit: contain;
  pointer-events: none;
  filter: var(--icon-filter);
  transition: filter 200ms ease;
}

/* Storefront icon is closer to square than the Product Page pointer icon,
   so it needs its own size instead of sharing .detail-hero-cta img's. */
.detail-hero-cta img.detail-hero-cta-icon-storefront {
  width: 20px;
  height: 20px;
}

.detail-hero-cta:hover {
  background: var(--glass-bg-hover);
  color: var(--page-bg);
}

.detail-hero-cta:hover img {
  filter: var(--icon-filter-hover);
}

.detail-hero-cta.is-pressed,
.detail-hero-cta:hover.is-pressed {
  scale: 0.85;

  transition:
    scale 420ms cubic-bezier(0.22, 1, 0.36, 1),
    background 240ms ease,
    color 240ms ease;
}

/* Circular icon-link button — companion to the CTA in the hero, same
   materials (App Store, storefront map link, etc). */
.detail-hero-icon-link {
  display: grid;
  place-items: center;
  flex: 0 0 auto;

  width: 50px;
  height: 50px;

  border: 1px solid rgb(127 127 127 / 0.10);
  border-radius: 999px;
  background: var(--levitated-button-bg);
  backdrop-filter: blur(30px);
  -webkit-backdrop-filter: blur(30px);

  box-shadow:
    0 12px 30px rgb(0 0 0 / 0.10),
    0 4px 10px rgb(0 0 0 / 0.06);

  cursor: pointer;

  transition:
    background 240ms ease,
    scale 240ms ease;

  animation: rise-in-translate 900ms cubic-bezier(0.22, 1, 0.36, 1) 90ms both;
}

.detail-hero-icon-link img {
  width: 22px;
  height: 22px;
  object-fit: contain;
  pointer-events: none;
  filter: var(--icon-filter);
  transition: filter 200ms ease;
}

.detail-hero-icon-link:hover {
  background: var(--glass-bg-hover);
}

.detail-hero-icon-link:hover img {
  filter: var(--icon-filter-hover);
}

.detail-hero-icon-link.is-pressed,
.detail-hero-icon-link:hover.is-pressed {
  scale: 0.85;

  transition:
    scale 420ms cubic-bezier(0.22, 1, 0.36, 1),
    background 240ms ease;
}

.detail-hero-image {
  order: -1;
  width: 100%;

  animation: rise-in 1000ms cubic-bezier(0.22, 1, 0.36, 1) 160ms both;
}

.detail-hero-image picture,
.detail-hero-image img {
  width: 100%;
  height: auto;
  display: block;
}

/* Introduction footnote — clamped to two lines with an expand/collapse control */

.detail-hero-intro {
  position: relative;
  margin-top: 28px;

  animation: rise-in 900ms cubic-bezier(0.22, 1, 0.36, 1) 120ms both;
}

.detail-hero-intro.is-expanded {
  padding-bottom: 30px;
  transition: padding-bottom 500ms cubic-bezier(0.16, 1, 0.3, 1);
}

.detail-hero-intro-text {
  --intro-line: 22px;

  margin: 0;
  text-align: left;

  font-size: clamp(14px, 1.3vw, 15px);
  font-weight: 400;
  line-height: var(--intro-line);
  color: var(--text-muted);

  max-height: calc(var(--intro-line) * 2);
  overflow: hidden;

  transition: max-height 500ms cubic-bezier(0.16, 1, 0.3, 1);
}

.detail-hero-intro-more {
  position: absolute;
  right: 0;
  bottom: 0;
  height: 22px;
  padding: 0 0 0 28px;

  display: inline-flex;
  align-items: center;

  border: none;
  background: linear-gradient(to right, transparent, var(--page-bg) 45%);

  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-main);
  cursor: pointer;

  transition: color 200ms ease;
}

.detail-hero-intro.is-expanded .detail-hero-intro-more {
  padding-left: 0;
  background: none;
}

.detail-hero-intro-more:hover {
  color: var(--text-muted);
}

@media (min-width: 900px) {
  .detail-hero {
    flex-direction: row;
    align-items: flex-start;
    text-align: left;
    gap: clamp(40px, 6vw, 80px);
  }

  .detail-hero-text,
  .detail-hero-image {
    flex: 1 1 0;
    width: auto;
  }

  .detail-hero-image {
    order: 0;
  }

  .detail-hero-actions {
    justify-content: flex-start;
  }
}

/* ==========================================================================
 Article sections
 ========================================================================== */

.article-section {
  display: flex;
  flex-direction: column;

  opacity: 0;
  filter: blur(10px);
  transform: translateY(28px);

  transition:
    opacity 800ms cubic-bezier(0.22, 1, 0.36, 1),
    filter 900ms cubic-bezier(0.16, 1, 0.3, 1),
    transform 900ms cubic-bezier(0.16, 1, 0.3, 1);
}

.article-section.is-visible {
  opacity: 1;
  filter: blur(0);
  transform: translateY(0);
}

.article-section + .article-section {
  margin-top: clamp(48px, 6vw, 72px);
  padding-top: clamp(48px, 6vw, 72px);
  border-top: 1px solid rgb(128 128 128 / 0.18);
}

.article-text {
  min-width: 0;
}

.article-section h2 {
  margin: 0;
  font-size: clamp(24px, 2.6vw, 34px);
  font-weight: 600;
}

.article-section p {
  margin: 24px 0 0;
  max-width: 100%;
  color: var(--text-muted);
  font-size: clamp(16px, 1.4vw, 18px);
  font-weight: 400;
  line-height: 1.55;
}

/* Pull-quote — a secondary surface with a pill rule running the height of the
   copy. Stretch alignment is what keeps the rule matched to the text rather
   than a fixed height. */
.article-quote {
  margin: 24px 0 0;
  padding: clamp(18px, 2vw, 24px) clamp(20px, 2.2vw, 28px) clamp(18px, 2vw, 24px) clamp(14px, 1.5vw, 18px);

  display: flex;
  align-items: stretch;
  gap: clamp(16px, 1.6vw, 20px);

  background: var(--sheet-bg);
  border-radius: 18px;
}

.article-quote::before {
  content: "";
  flex: 0 0 4px;
  border-radius: 999px;
  background: var(--text-soft);
}

.article-quote p {
  margin: 0;
  color: var(--text-secondary);
  font-size: clamp(17px, 1.6vw, 21px);
  font-weight: 500;
  line-height: 1.5;
}

/* Numbered principle cards — a counter rather than hard-coded numerals, so
   the sequence stays correct if any are reordered or added. */
.principle-grid {
  counter-reset: principle;

  margin: clamp(28px, 3vw, 40px) 0 0;
  padding: 0;
  list-style: none;

  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(14px, 1.4vw, 20px);
}

.principle {
  padding: clamp(20px, 2.2vw, 28px);
  background: var(--sheet-bg);
  border-radius: 18px;
}

.principle::before {
  counter-increment: principle;
  content: counter(principle, decimal-leading-zero);

  display: block;
  margin-bottom: clamp(10px, 1.2vw, 14px);

  font-size: clamp(28px, 3vw, 38px);
  font-weight: 300;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--text-soft);
}

.principle-title {
  margin: 0;
  color: var(--text-main);
  font-size: clamp(18px, 1.7vw, 22px);
  font-weight: 600;
  line-height: 1.3;
}

.principle p {
  margin: 12px 0 0;
}

@media (max-width: 760px) {
  .principle-grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* Collapsible sub-sections — one topic open at a time beside its media, with
   a stepper that tracks the open item. Collapsed topics sit as pills; the open
   one grows into a card. */
/* Local elevation scale. Each step has to move the same direction in both
   themes — darker-on-lighter reads as a hole rather than a raised card, which
   is what happens in dark mode if the card simply reuses the page colour. */
.closer-look {
  --closer-panel: rgb(0 0 0 / 0.03);
  --closer-card: #ffffff;
  --closer-chip: rgb(0 0 0 / 0.05);
  --closer-pad: clamp(22px, 3vw, 44px);
  --closer-gap: 10px;
  /* How much of the neighbouring topic stays visible either side of the open
     one in the narrow scroller. This is the knob for the open card's width:
     the track reserves it as padding, and the card matches the content box
     that leaves — so widening the peek narrows the card without breaking the
     centring. Scales with the viewport so the card does not sprawl on wider
     screens while staying readable on a phone. */
  --closer-peek: clamp(56px, 10vw, 120px);

  margin-top: clamp(26px, 3vw, 38px);
  padding: var(--closer-pad);

  background: var(--closer-panel);
  border-radius: clamp(24px, 3vw, 32px);
}

@media (prefers-color-scheme: dark) {
  .closer-look {
    --closer-panel: rgb(255 255 255 / 0.04);
    --closer-card: rgb(255 255 255 / 0.09);
    --closer-chip: rgb(255 255 255 / 0.15);
  }
}

.closer-look-layout {
  display: grid;
  gap: clamp(24px, 3vw, 44px);
}

.closer-look-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-width: 0;
}

/* Lifted off the panel rather than sharing its fill — otherwise the pills and
   the surface they sit on are the same colour and disappear into each other.
   The fill sits on the toggle, not the item, so a toggle keeps its pill look
   when the narrow layout moves it out into the strip. */
.closer-look-item {
  border-radius: 30px;
  overflow: hidden;

  transition:
    width 900ms cubic-bezier(0.32, 0.72, 0, 1),
    border-radius 760ms cubic-bezier(0.32, 0.72, 0, 1),
    background 700ms cubic-bezier(0.32, 0.72, 0, 1);
}

.closer-look-item.is-active {
  background: var(--closer-card);
  border-radius: 22px;
}

.closer-look-toggle {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;

  padding: 9px 20px 9px 9px;

  border: 0;
  border-radius: 999px;
  background: var(--closer-card);
  cursor: pointer;
  text-align: left;

  color: var(--text-main);
  font-family: inherit;
  font-size: clamp(16px, 1.4vw, 18px);
  font-weight: 600;
  line-height: 1.3;

  transition:
    background 700ms cubic-bezier(0.32, 0.72, 0, 1),
    border-radius 760ms cubic-bezier(0.32, 0.72, 0, 1),
    padding 900ms cubic-bezier(0.32, 0.72, 0, 1);
}

/* Outlined plus, drawn rather than shipped as an asset so it inherits colour. */
.closer-look-plus {
  position: relative;
  flex: 0 0 32px;
  height: 32px;

  border: 1px solid rgb(128 128 128 / 0.35);
  border-radius: 999px;

  transition:
    opacity 460ms cubic-bezier(0.32, 0.72, 0, 1),
    transform 760ms cubic-bezier(0.32, 0.72, 0, 1);
}

.closer-look-plus::before,
.closer-look-plus::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  background: var(--text-muted);
  transform: translate(-50%, -50%);
}

.closer-look-plus::before {
  width: 11px;
  height: 1.5px;
}

.closer-look-plus::after {
  width: 1.5px;
  height: 11px;
}

/* Keyed off the toggle's own state, not the item's — narrow moves the toggle
   out into the strip, where an item-anchored selector no longer reaches it. */
.closer-look-toggle[aria-expanded="true"] .closer-look-plus {
  opacity: 0;
  transform: scale(0.6);
  flex-basis: 0;
  height: 0;
  border: 0;
}

/* The open item drops the plus and reclaims its space for the copy. Its fill
   comes from the item beneath it, so the toggle becomes the card's header. */
.closer-look-item.is-active .closer-look-toggle {
  gap: 0;
  padding: clamp(18px, 2vw, 24px) clamp(20px, 2.2vw, 26px) 0;
  background: none;
  border-radius: 0;
}



.closer-look-body {
  height: 0;
  overflow: hidden;
  transition: height 1000ms cubic-bezier(0.32, 0.72, 0, 1);
}

/* A closed body is height 0, but its text still has an intrinsic width, which
   would stretch a shrink-to-fit pill out to the width of its hidden copy. */
.closer-look-item:not(.is-active) .closer-look-body {
  width: 0;
}

.closer-look-copy {
  padding: 0 clamp(20px, 2.2vw, 26px) clamp(18px, 2vw, 24px);

  opacity: 0;
  transform: translateY(8px);

  transition:
    opacity 700ms cubic-bezier(0.32, 0.72, 0, 1),
    transform 900ms cubic-bezier(0.32, 0.72, 0, 1);
}

.closer-look-item.is-active .closer-look-copy {
  opacity: 1;
  transform: none;
  transition-delay: 140ms;
}

.closer-look-copy p {
  margin: 14px 0 0;
}

.closer-look-copy strong {
  color: var(--text-main);
  font-weight: 600;
}

/* Media — figures stacked in one cell so switching cross-fades instead of
   resizing the column. */
.closer-look-media {
  display: grid;
  min-width: 0;
}

.closer-look-figure {
  grid-area: 1 / 1;
  margin: 0;

  opacity: 0;
  pointer-events: none;
  transition: opacity 760ms cubic-bezier(0.32, 0.72, 0, 1);
}

.closer-look-figure.is-active {
  opacity: 1;
  pointer-events: auto;
}

.closer-look.is-media-empty .closer-look-media {
  display: none;
}

.closer-look-figure img {
  width: 100%;
  height: auto;
  display: block;
}

/* Suppresses the open/slide animations while the initial state is applied. */
.closer-look.is-static .closer-look-item,
.closer-look.is-static .closer-look-body,
.closer-look.is-static .closer-look-copy,
.closer-look.is-static .closer-look-figure,
.closer-look.is-static .closer-look-plus,
.closer-look.is-static .closer-look-toggle {
  transition: none;
}

@media (min-width: 900px) {
  .closer-look-layout {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    align-items: start;
    gap: clamp(40px, 5vw, 64px);
  }

  .closer-look-media {
    position: sticky;
    top: clamp(24px, 4vw, 48px);
  }

  /* Closed topics hug their subheading instead of ruling off the whole
     column; only the open card spans the full width. Sizing is explicit
     rather than by stretch so the change between them can animate. */
  .closer-look-item {
    align-self: flex-start;
  }

  .closer-look-item.is-active {
    width: 100%;
  }

  .closer-look-item .closer-look-toggle {
    width: auto;
  }

  .closer-look-item.is-active .closer-look-toggle {
    width: 100%;
  }
}

/* Narrow: topics scroll sideways as a row and the open one widens in place,
   so its copy stays attached to the toggle it came from — same relationship
   as the wide accordion, just laid out horizontally. */
@media (max-width: 899px) {
  /* Topics lead, media follows — the grid's own gap spaces them. */
  .closer-look-list {
    flex-direction: row;
    align-items: flex-start;
    gap: var(--closer-gap);

    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;

    /* Topics resize as they open and close, and the browser would otherwise
       nudge the scroll offset to keep the old content still — which fights
       the centring and lands the open card off to one side. */
    overflow-anchor: none;

    /* Pulled out to the panel's edges so topics scroll away at the panel
       boundary rather than along an inset line. The padding back is a peek
       plus its gap, which makes the content box exactly one card wide — so a
       card sized to 100% is centred in the track at rest, and the first and
       last can reach the centre instead of clamping short of it. */
    margin-left: calc(-1 * var(--closer-pad));
    margin-right: calc(-1 * var(--closer-pad));
    padding-left: calc(var(--closer-peek) + var(--closer-gap));
    padding-right: calc(var(--closer-peek) + var(--closer-gap));
  }

  .closer-look-list::-webkit-scrollbar {
    display: none;
  }

  .closer-look-item {
    flex: 0 0 auto;
    max-width: 86vw;
  }

  /* The track's padding already reserves a peek either side, so the content
     box is exactly the card's width. Matching it means the card is centred
     whenever the track sits at either end, which is what stops click-to-open
     and scroll-to-open disagreeing about which topic is centred. */
  .closer-look-item.is-active {
    width: 100%;
  }

  /* Collapsed topics stay on one line; the open one wraps as a card. */
  .closer-look-toggle {
    white-space: nowrap;
  }

  .closer-look-item.is-active .closer-look-toggle {
    white-space: normal;
  }
}

/* The questions students actually ask — set as objects rather than a plain
   list, so they read as the thoughts they represent. */
.question-list {
  margin: 18px 0 0;
  padding: 0;
  list-style: none;

  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.question-list li {
  padding: 10px 16px;

  background: var(--closer-chip, var(--sheet-bg));
  border-radius: 20px;

  color: var(--text-main);
  font-size: clamp(15px, 1.3vw, 16px);
  font-weight: 500;
  line-height: 1.4;
}

/* Grouped method list — one panel rather than separate cards, since these
   read as a single body of work rather than parallel ideas. */
.method-list {
  margin: 18px 0 0;
  padding: clamp(18px, 2vw, 24px) clamp(20px, 2.2vw, 26px);
  list-style: none;

  background: var(--sheet-bg);
  border-radius: 18px;

  display: grid;
  gap: 12px;
}

.method-list li {
  display: flex;
  align-items: flex-start;
  gap: 14px;

  color: var(--text-secondary);
  font-size: clamp(16px, 1.4vw, 18px);
  line-height: 1.55;
}

.method-list li::before {
  content: "";
  flex: 0 0 14px;
  height: 4px;
  /* Sits against the optical centre of the first line, and scales with it. */
  margin-top: 0.62em;
  border-radius: 999px;
  background: var(--text-soft);
}

/* Outcomes — a grouped list: one surface, hairline dividers inset to the
   text, each row marked done. The check is a circle with the tick knocked
   out, masked from a text colour so it follows the theme without an image
   swap. */
.outcome-list {
  --check: 20px;
  --check-gap: 14px;

  margin: 24px 0 0;
  padding: clamp(6px, 0.8vw, 10px) clamp(18px, 2vw, 22px);
  list-style: none;

  background: var(--sheet-bg);
  border-radius: 24px;
}

.outcome-list li {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: var(--check-gap);

  padding: clamp(14px, 1.6vw, 18px) 0;

  color: var(--text-secondary);
  font-size: clamp(16px, 1.4vw, 18px);
  line-height: 1.45;
}

.outcome-list li + li::after {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  left: calc(var(--check) + var(--check-gap));
  height: 1px;
  background: rgb(128 128 128 / 0.18);
}

.outcome-list li::before {
  content: "";
  flex: none;
  width: var(--check);
  height: var(--check);
  /* Centre on the first line at any font size. */
  margin-top: calc((1.45em - var(--check)) / 2);

  background: var(--text-muted);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cmask id='m'%3E%3Ccircle cx='10' cy='10' r='10' fill='white'/%3E%3Cpath d='M5.9 10.3l2.7 2.7 5.5-5.8' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/mask%3E%3Ccircle cx='10' cy='10' r='10' fill='white' mask='url(%23m)'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cmask id='m'%3E%3Ccircle cx='10' cy='10' r='10' fill='white'/%3E%3Cpath d='M5.9 10.3l2.7 2.7 5.5-5.8' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/mask%3E%3Ccircle cx='10' cy='10' r='10' fill='white' mask='url(%23m)'/%3E%3C/svg%3E") center / contain no-repeat;
}

/* Reflection — three lesson cards, each with an illustration that acts out
   its lesson when the card is engaged (.is-active, set by project.js: under
   the pointer, or while in view on touch screens):
     01 scattered dots settle into one grid       — simplicity from complexity
     02 six platform nodes link to a shared hub   — systems, not screens
     03 release bars climb, the latest goes live  — a product that keeps growing
   Cards rise in one after another as the section arrives. */
.reflection-list {
  --stage: #ffffff;
  --mark: rgb(0 0 0 / 0.08);
  --glow: rgb(0 0 0 / 0.28);
  --lift-shadow: 0 18px 40px rgb(0 0 0 / 0.08), 0 4px 12px rgb(0 0 0 / 0.04);

  counter-reset: lesson;

  display: grid;
  gap: clamp(14px, 1.6vw, 20px);

  margin: clamp(28px, 3vw, 40px) 0 0;
  padding: 0;
  list-style: none;
}

@media (prefers-color-scheme: dark) {
  .reflection-list {
    --stage: rgb(255 255 255 / 0.05);
    --mark: rgb(255 255 255 / 0.14);
    --glow: rgb(255 255 255 / 0.4);
    --lift-shadow: 0 18px 40px rgb(0 0 0 / 0.4), 0 4px 12px rgb(0 0 0 / 0.25);
  }
}

@media (min-width: 900px) {
  .reflection-list {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

.reflection-card {
  --reveal-delay: 0ms;
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);

  position: relative;
  isolation: isolate;
  padding: clamp(10px, 1.1vw, 12px);

  background: var(--sheet-bg);
  border-radius: clamp(22px, 2.6vw, 28px);

  /* Start state; only the reveal below animates it in. */
  opacity: 0;
  translate: 0 28px;
}

.reflection-card:nth-child(2) { --reveal-delay: 150ms; }
.reflection-card:nth-child(3) { --reveal-delay: 300ms; }

.article-section.is-visible .reflection-card {
  opacity: 1;
  translate: 0 0;

  /* The reveal is staggered; the lift and shadow respond immediately. */
  transition:
    opacity 800ms cubic-bezier(0.22, 1, 0.36, 1) var(--reveal-delay),
    translate 1000ms var(--ease-out) var(--reveal-delay),
    transform 500ms var(--ease-out),
    box-shadow 500ms var(--ease-out);
}

.reflection-card.is-active {
  transform: translateY(-4px);
  box-shadow: var(--lift-shadow);
}

/* Edge glow that follows the pointer: a radial light clipped to a 1px ring. */
.reflection-card::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  padding: 1px;

  border-radius: inherit;
  background: radial-gradient(280px circle at var(--mx, 50%) var(--my, 0%), var(--glow), transparent 70%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);

  opacity: 0;
  transition: opacity 400ms ease;
  pointer-events: none;
}

.reflection-card.is-active::after {
  opacity: 1;
}

.reflection-visual {
  position: relative;
  aspect-ratio: 5 / 3;

  color: var(--text-main);
  background: var(--stage);
  border-radius: clamp(14px, 1.7vw, 18px);
}

.reflection-visual::before {
  counter-increment: lesson;
  content: counter(lesson, decimal-leading-zero);

  position: absolute;
  top: clamp(12px, 1.3vw, 16px);
  left: clamp(14px, 1.5vw, 18px);

  color: var(--text-soft);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.06em;
  font-variant-numeric: tabular-nums;
}

.reflection-art {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.reflection-card p {
  margin: 0;
  padding: clamp(16px, 1.8vw, 22px) clamp(8px, 1vw, 12px) clamp(8px, 1vw, 12px);
}

/* The phrase each lesson turns on, marked like a highlighter stroke. */
.reflection-card strong {
  color: var(--text-main);
  font-weight: 500;

  background: linear-gradient(transparent 62%, var(--mark) 62%, var(--mark) 92%, transparent 92%);
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}

/* Stacked (narrow) layout: each card turns into a row — a square
   illustration tile beside the text, both pinned to the top. */
@media (max-width: 899px) {
  .reflection-card {
    display: grid;
    grid-template-columns: minmax(96px, 34%) minmax(0, 1fr);
    align-items: start;
  }

  .reflection-visual {
    aspect-ratio: 1;
  }

  .reflection-card p {
    padding: 4px clamp(6px, 1.2vw, 12px) 6px clamp(14px, 3vw, 22px);
  }
}

/* 01 — order */
.reflection-art--order circle {
  fill: currentColor;
  fill-opacity: 0.32;
  transform: translate(calc(var(--dx) * 1px), calc(var(--dy) * 1px)) scale(var(--s));
  transform-box: fill-box;
  transform-origin: center;
  transition:
    transform 900ms var(--ease-out) calc(var(--i) * 25ms),
    fill-opacity 600ms ease calc(var(--i) * 25ms);
}

.reflection-card.is-active .reflection-art--order circle {
  fill-opacity: 0.8;
  transform: none;
}

/* 02 — system */
.reflection-art--system path {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.2;
  stroke-linejoin: round;
}

.reflection-art--system .net-base {
  stroke-opacity: 0.12;
}

.reflection-art--system .net-draw path {
  stroke-opacity: 0.6;
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  transition: stroke-dashoffset 700ms var(--ease-out) calc(var(--i) * 70ms);
}

.reflection-card.is-active .reflection-art--system .net-draw path {
  stroke-dashoffset: 0;
}

.reflection-art--system circle {
  fill: currentColor;
  transform-box: fill-box;
  transform-origin: center;
}

.reflection-art--system .net-node {
  fill-opacity: 0.35;
  transition: fill-opacity 500ms ease calc(var(--i) * 70ms + 150ms);
}

.reflection-art--system .net-hub {
  fill-opacity: 0.5;
  transition:
    transform 700ms var(--ease-out),
    fill-opacity 500ms ease;
}

.reflection-card.is-active .reflection-art--system .net-node {
  fill-opacity: 0.85;
}

.reflection-card.is-active .reflection-art--system .net-hub {
  fill-opacity: 1;
  transform: scale(1.25);
}

/* 03 — growth */
.reflection-art--growth .growth-base {
  stroke: currentColor;
  stroke-opacity: 0.14;
  stroke-width: 1;
}

.reflection-art--growth rect {
  fill: currentColor;
  fill-opacity: var(--o);
  transform: scaleY(0.22);
  transform-box: fill-box;
  transform-origin: 50% 100%;
  transition: transform 900ms var(--ease-out) calc(var(--i) * 70ms);
}

.reflection-card.is-active .reflection-art--growth rect {
  transform: none;
}

.reflection-art--growth .growth-live,
.reflection-art--growth .growth-pulse {
  transform-box: fill-box;
  transform-origin: center;
}

.reflection-art--growth .growth-live {
  fill: currentColor;
  opacity: 0;
  transform: scale(0.4);
  transition:
    opacity 400ms ease,
    transform 600ms var(--ease-out);
}

.reflection-card.is-active .reflection-art--growth .growth-live {
  opacity: 1;
  transform: none;
  /* Lands once the last bar has finished climbing. */
  transition-delay: 650ms;
}

.reflection-art--growth .growth-pulse {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.2;
  opacity: 0;
}

.reflection-card.is-active .reflection-art--growth .growth-pulse {
  animation: reflection-pulse 2.4s ease-out 1s infinite;
}

@keyframes reflection-pulse {
  from {
    opacity: 0.6;
    transform: scale(1);
  }
  to {
    opacity: 0;
    transform: scale(3.2);
  }
}

/* Evolution timeline — each change is a node on one connecting rule. The
   rule carries on past the last node and fades out, since the sequence is
   still being written. Nodes are ringed in the page colour so the rule
   appears to break around them in either theme. */
.evolution-list {
  --node: 9px;
  --node-gap: clamp(16px, 1.8vw, 22px);
  --tail: clamp(30px, 3.2vw, 40px);
  --rule: rgb(0 0 0 / 0.14);
  /* Centre of the first line, so nodes and rule sit on it at any size. */
  --line-centre: 0.725em;

  position: relative;
  display: grid;
  gap: clamp(14px, 1.6vw, 18px);

  margin: 24px 0 0;
  padding: 0 0 var(--tail);
  list-style: none;

  font-size: clamp(16px, 1.4vw, 18px);
  line-height: 1.45;
}

@media (prefers-color-scheme: dark) {
  .evolution-list {
    --rule: rgb(255 255 255 / 0.16);
  }
}

.evolution-list::before {
  content: "";
  position: absolute;
  top: var(--line-centre);
  bottom: 0;
  left: calc(var(--node) / 2 - 1px);
  width: 2px;

  border-radius: 999px;
  background: linear-gradient(
    to bottom,
    var(--rule) calc(100% - var(--tail) - var(--line-centre)),
    transparent
  );
}

.evolution-list li {
  position: relative;
  padding-left: calc(var(--node) + var(--node-gap));

  color: var(--text-secondary);
  font-weight: 500;
}

.evolution-list li::before {
  content: "";
  position: absolute;
  top: calc(var(--line-centre) - var(--node) / 2);
  left: 0;
  width: var(--node);
  height: var(--node);

  border-radius: 50%;
  background: var(--text-soft);
  box-shadow: 0 0 0 4px var(--page-bg);
}

/* Platform features as Siri-suggestion pills, held in a panel. project.js
   re-deals them into rows that drift in alternating directions; without it
   (or with reduced motion) the pills simply wrap inside the panel. */
.feature-marquee {
  --marquee-panel: rgb(0 0 0 / 0.03);
  --pill-bg: #ffffff;
  --marquee-pad: clamp(18px, 2.4vw, 28px);
  --marquee-gap: 10px;

  position: relative;
  margin: clamp(16px, 2vw, 22px) 0 clamp(20px, 2.4vw, 28px);
  padding: var(--marquee-pad);
  overflow: hidden;

  background: var(--marquee-panel);
  border-radius: clamp(24px, 3vw, 32px);
}

@media (prefers-color-scheme: dark) {
  .feature-marquee {
    --marquee-panel: rgb(255 255 255 / 0.04);
    --pill-bg: rgb(255 255 255 / 0.1);
  }
}

.feature-pills {
  display: flex;
  flex-wrap: wrap;
  gap: var(--marquee-gap);

  margin: 0;
  padding: 0;
  list-style: none;
}

.feature-pills li,
.feature-marquee-track li {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  max-width: 100%;

  padding: 8px 20px 8px 12px;

  color: var(--text-main);
  line-height: 1.3;

  background: var(--pill-bg);
  border-radius: 999px;
}

/* Rows run edge to edge and fade out at the panel's sides. */
.feature-marquee.is-running {
  padding-inline: 0;
}

.feature-marquee.is-running > .feature-pills {
  /* Kept for screen readers; the rows are decorative copies. */
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.feature-marquee-rows {
  display: grid;
  gap: var(--marquee-gap);

  -webkit-mask-image: linear-gradient(90deg, transparent, #000 var(--marquee-pad), #000 calc(100% - var(--marquee-pad)), transparent);
  mask-image: linear-gradient(90deg, transparent, #000 var(--marquee-pad), #000 calc(100% - var(--marquee-pad)), transparent);
}

/* The track holds its sequence twice, so shifting it by half lands on an
   identical frame. Spacing is a trailing margin rather than flex gap so that
   half the track is exactly one sequence plus its spacing. */
.feature-marquee-track {
  display: flex;
  width: max-content;
  margin: 0;
  padding: 0;
  list-style: none;

  animation: feature-marquee var(--marquee-duration, 60s) linear var(--marquee-delay, 0s) infinite;
}

.feature-marquee-row.is-reverse .feature-marquee-track {
  animation-direction: reverse;
}

.feature-marquee-track li {
  max-width: none;
  margin-inline-end: var(--marquee-gap);
  white-space: nowrap;
}

@keyframes feature-marquee {
  to {
    transform: translate3d(-50%, 0, 0);
  }
}

.feature-pills img,
.feature-marquee-track img {
  flex: none;
  width: 32px;
  height: 32px;
  /* The artwork already carries its rounded-square mask. */
  border-radius: 22%;
}

/* Wide screens: text left, media right — media pins in place while the
   (usually taller) text column scrolls past it. */
@media (min-width: 900px) {
  /* Direct child only: sub-sections now carry their own .article-media, and a
     descendant match would turn the parent section into a grid as well. */
  .article-section:has(> .article-media) {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    align-items: start;
    gap: clamp(40px, 5vw, 64px);
  }

  .article-media {
    position: sticky;
    top: clamp(24px, 4vw, 48px);
    align-self: start;
    margin-top: 0;
  }

  .article-media .article-image-single,
  .article-media .article-image-pager,
  .article-media .sketchfab-embed-wrapper {
    margin-top: 0;
  }

  .article-media .article-image-single,
  .article-media .sketchfab-embed-wrapper {
    margin-left: 0;
    margin-right: 0;
  }

  .article-media .article-image-single picture,
  .article-media .article-image-single img,
  .article-media .article-image-single .article-video {
    padding-left: 0;
    padding-right: 0;
  }

  .article-media .sketchfab-embed-wrapper iframe {
    padding-left: 0;
    padding-right: 0;
  }

  .article-media .article-image-caption {
    padding-left: 0;
    padding-right: 0;
  }
}

/* Images */

.article-image-single {
  margin-top: clamp(20px, 2.4vw, 32px);
  margin-left: calc(-1 * var(--content-pad));
  margin-right: calc(-1 * var(--content-pad));
}

.article-image-pager {
  margin-top: clamp(20px, 2.4vw, 32px);
}

.article-image-single picture {
  display: block;
  overflow: hidden;
}

.article-image-single picture,
.article-image-single img,
.article-image-single .article-video {
  width: 100%;
  padding-left: calc(1/2 * var(--content-pad));
  padding-right: calc(1/2 * var(--content-pad));
  height: auto;
  display: block;
}

/* Sketchfab 3D embed — same bleed/padding treatment as .article-image-single
   so it lines up with the other media widths in the article column. */
.sketchfab-embed-wrapper {
  margin-top: clamp(20px, 2.4vw, 32px);
  margin-left: calc(-1 * var(--content-pad));
  margin-right: calc(-1 * var(--content-pad));
}

.sketchfab-embed-wrapper iframe {
  width: 100%;
  aspect-ratio: 4 / 3;
  padding-left: calc(1/2 * var(--content-pad));
  padding-right: calc(1/2 * var(--content-pad));
  box-sizing: border-box;
  display: block;
  border: none;
}

/* Multi-image pager */

.article-image-track {
  display: flex;
  overflow-x: auto;
  overflow-y: hidden;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}

.article-image-track::-webkit-scrollbar {
  display: none;
}

.article-image-slide {
  flex: 0 0 100%;
  scroll-snap-align: center;
  margin: 0;
  line-height: 0;
}

.article-image-slide picture,
.article-image-slide img {
  width: 100%;
  height: auto;
  display: block;
}

/* Single image caption re-indented to align with text (compensates for negative margins) */
.article-image-caption {
  padding-left: var(--content-pad);
  padding-right: var(--content-pad);
}

/* Captions */

.article-image-caption {
  display: block;
  margin-top: 10px;

  font-size: clamp(12px, 1vw, 14px);
  font-weight: 400;
  color: var(--text-soft);
  line-height: 1.4;
}

/* Pager footer: captions on the left, prev/next controls on the right */

.article-pager-footer {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-top: 10px;
}

.article-pager-captions {
  position: relative;
  min-height: 1.4em;
  flex: 1 1 auto;
  min-width: 0;
}

.article-pager-caption-item {
  display: block;
  position: absolute;
  inset: 0;

  font-size: clamp(12px, 1vw, 14px);
  font-weight: 400;
  color: var(--text-soft);
  line-height: 1.4;

  opacity: 0;
  transition: opacity 300ms ease;
  pointer-events: none;
}

.article-pager-caption-item.is-active {
  opacity: 1;
  pointer-events: auto;
}

/* Prev/next controls */

.article-pager-nav {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 6px;
}

.article-pager-btn {
  width: 28px;
  height: 28px;
  padding: 0;

  display: grid;
  place-items: center;

  border: 1px solid rgb(127 127 127 / 0.14);
  border-radius: 999px;
  background: var(--sheet-bg);

  cursor: pointer;

  transition:
    background 200ms ease,
    border-color 200ms ease,
    transform 200ms ease,
    opacity 200ms ease;
}

.article-pager-btn img {
  width: 8px;
  height: 13px;
  object-fit: contain;
  pointer-events: none;
  filter: var(--icon-filter);
  transition: filter 200ms ease;
}

.article-pager-btn:hover:not(:disabled) {
  background: var(--glass-bg-hover);
  border-color: transparent;
}

.article-pager-btn:hover:not(:disabled) img {
  filter: var(--icon-filter-hover);
}

.article-pager-btn:active:not(:disabled) {
  transform: scale(0.88);
}

.article-pager-btn:disabled {
  opacity: 0.3;
  cursor: default;
}

/* ==========================================================================
 Floating bottom back button
 Mirrors .back-link in myschoolapp/css/legal.css — same sizing, timing and
 press animation, with the site's neutral hover instead of legal's accent.
 ========================================================================== */

.detail-actions {
  position: fixed;
  left: 50%;
  bottom: 48px;
  transform: translateX(-50%);

  display: flex;
  align-items: center;

  z-index: 70;
}

.detail-back {
  width: 56px;
  height: 56px;
  margin-right: 12px;

  display: grid;
  place-items: center;

  border: 1px solid rgb(127 127 127 / 0.10);
  border-radius: 999px;
  background: var(--levitated-button-bg);
  backdrop-filter: blur(30px);
  -webkit-backdrop-filter: blur(30px);

  box-shadow:
    0 12px 30px rgb(0 0 0 / 0.10),
    0 4px 10px rgb(0 0 0 / 0.06);

  cursor: pointer;

  opacity: 0;
  filter: blur(20px);
  transform: translateY(120px) scale(0);

  transition:
    opacity 520ms cubic-bezier(0.22, 1, 0.36, 1),
    transform 900ms cubic-bezier(0.34, 1.56, 0.64, 1),
    filter 900ms cubic-bezier(0.16, 1, 0.3, 1),
    background 240ms ease,
    box-shadow 260ms ease;
}

.detail-actions.is-visible .detail-back {
  opacity: 1;
  filter: blur(0);
  transform: translateY(0) scale(1);
}

.detail-back img {
  width: 16px;
  height: 22px;
  object-fit: contain;
  pointer-events: none;
  filter: var(--icon-filter);
  transition:
    filter 200ms ease,
    opacity 260ms ease;
}

.detail-back:hover {
  background: var(--glass-bg-hover);
}

.detail-back:hover img {
  filter: var(--icon-filter-hover);
}

.detail-back.is-pressed,
.detail-back:hover.is-pressed {
  transform: translateY(0) scale(0.85);

  transition:
    transform 420ms cubic-bezier(0.22, 1, 0.36, 1),
    background 240ms ease;
}

.detail-back:focus-visible {
  outline: 2px solid var(--text-main);
  outline-offset: 3px;
}

/* ==========================================================================
 Scroll status pill — appears once the hero has scrolled out of view,
 showing the project name and the article section currently in focus.
 ========================================================================== */

.detail-status {
  position: relative;
  z-index: 1;

  height: 56px;
  width: fit-content;
  max-width: 0;
  margin-right: 0;
  overflow: hidden;

  border: 1px solid rgb(127 127 127 / 0.10);
  border-radius: 999px;
  background: var(--levitated-button-bg);
  backdrop-filter: blur(30px);
  -webkit-backdrop-filter: blur(30px);

  box-shadow:
    0 12px 30px rgb(0 0 0 / 0.10),
    0 4px 10px rgb(0 0 0 / 0.06);

  opacity: 0;
  filter: blur(20px);
  transform: translateY(120px) scale(0);

  transition:
    opacity 520ms cubic-bezier(0.22, 1, 0.36, 1),
    transform 900ms cubic-bezier(0.34, 1.56, 0.64, 1),
    filter 900ms cubic-bezier(0.16, 1, 0.3, 1),
    max-width 900ms cubic-bezier(0.32, 1.2, 0.64, 1),
    margin-right 900ms cubic-bezier(0.32, 1.2, 0.64, 1),
    box-shadow 260ms ease,
    background 240ms ease,
    width 480ms cubic-bezier(0.34, 1.15, 0.64, 1),
    height 480ms cubic-bezier(0.34, 1.15, 0.64, 1),
    border-radius 480ms cubic-bezier(0.34, 1.15, 0.64, 1);
}

.detail-status.is-visible {
  opacity: 1;
  filter: blur(0);
  transform: translateY(0) scale(1);
  /* Never let the pill (plus the fixed-size back/menu buttons around it)
     push the floating bar past the viewport edges. */
  max-width: min(320px, calc(100vw - 168px));
  margin-right: 12px;
}

.detail-status:hover:not(.is-open) {
  background: var(--glass-bg-hover);
}

.detail-status:hover:not(.is-open) .detail-status-toggle img {
  filter: var(--icon-filter-hover);
}

.detail-status:hover:not(.is-open) .detail-status-project {
  color: var(--page-bg-secondary);
}

.detail-status:hover:not(.is-open) .detail-status-section {
  color: var(--page-bg);
}

.detail-status.is-pressed:not(.is-open),
.detail-status:hover.is-pressed:not(.is-open) {
  transform: translateY(0) scale(0.85);

  transition:
    transform 420ms cubic-bezier(0.22, 1, 0.36, 1),
    background 240ms ease;
}

/* Expanding to the section list morphs this same pill — width/height/
   radius grow together with the icon+label cross-fading into the list,
   exactly like .detail-menu. */

.detail-status.is-open {
  z-index: 2;
  width: 280px;
  max-width: 280px;
  border-radius: 26px;
}

/* Guard used while JS swaps .detail-status between flex-flow and
   absolute positioning (open/close), so that switch is instant — only
   width/height/border-radius should visibly animate, not the position
   itself. Applied for a single forced reflow, then removed. */
.detail-status.is-snapping {
  transition: none !important;
}

.detail-status-toggle {
  all: unset;
  box-sizing: border-box;
  height: 56px;

  display: flex;
  align-items: center;
  gap: 10px;

  padding: 0 20px 0 18px;
  white-space: nowrap;
  cursor: pointer;

  opacity: 1;
  filter: blur(0);

  transition:
    opacity 260ms ease,
    filter 260ms ease;
}

.detail-status.is-open .detail-status-toggle {
  position: absolute;
  inset: 0;
  opacity: 0;
  filter: blur(14px);
  pointer-events: none;
}

.detail-status-toggle img {
  width: 30px;
  height: 26px;
  flex: 0 0 auto;
  object-fit: contain;
  pointer-events: none;
  filter: var(--icon-filter);
}

.detail-status-text {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}

.detail-status-project,
.detail-status-section {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.detail-status-project {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--text-soft);
  transition: color 200ms ease;
}

.detail-status-section {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-main);

  transition: opacity 200ms ease;
}

.detail-status-section.is-changing {
  opacity: 0;
}

/* Expandable section list — cross-fades in as the pill morphs into a
   panel, same technique as .detail-menu-list. */

.detail-status-list {
  position: absolute;
  inset: 0;
  overflow-y: auto;

  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 12px;

  opacity: 0;
  filter: blur(14px);
  pointer-events: none;

  transition:
    opacity 260ms ease,
    filter 260ms ease;
}

.detail-status.is-open .detail-status-list {
  opacity: 1;
  filter: blur(0);
  pointer-events: auto;
  transition-delay: 160ms;
}

.detail-status-item {
  display: flex;
  align-items: center;
  flex-shrink: 0;

  height: 44px;
  padding: 0 12px;
  border: none;
  border-radius: 14px;
  background: none;

  font: inherit;
  font-size: 14px;
  font-weight: 500;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  text-align: left;
  cursor: pointer;

  transition:
    background 200ms ease,
    color 200ms ease;
}

.detail-status-item:hover {
  background: var(--sheet-bg);
  color: var(--text-main);
}

.detail-status-item.is-current {
  background: var(--sheet-bg);
  color: var(--text-main);
  font-weight: 600;
}

.detail-status-toggle:focus-visible,
.detail-status-item:focus-visible {
  outline: 2px solid var(--text-main);
  outline-offset: 2px;
}

/* Invisible placeholder that reserves the pill's collapsed footprint in the
   flex row while .detail-status is pulled out to position:absolute for its
   open/expanded state — keeps the back and menu buttons from being pushed. */
.detail-status-slot {
  width: 0;
  height: 56px;
  margin-right: 0;
  flex: 0 0 auto;
  visibility: hidden;
}

/* ==========================================================================
 Project switcher — a circular button that expands into a rounded-rect
 menu listing all projects. Icon and list cross-fade with a blur transition.
 ========================================================================== */

.detail-menu-slot {
  width: 56px;
  height: 56px;
  flex: 0 0 auto;
  visibility: hidden;
}

.detail-menu {
  position: absolute;
  right: 0;
  bottom: 0;
  z-index: 1;

  width: 56px;
  height: 56px;
  overflow: hidden;

  border: 1px solid rgb(127 127 127 / 0.10);
  border-radius: 999px;
  background: var(--levitated-button-bg);
  backdrop-filter: blur(30px);
  -webkit-backdrop-filter: blur(30px);

  box-shadow:
    0 12px 30px rgb(0 0 0 / 0.10),
    0 4px 10px rgb(0 0 0 / 0.06);

  opacity: 0;
  filter: blur(20px);
  transform: translateY(120px) scale(0);

  transition:
    opacity 520ms cubic-bezier(0.22, 1, 0.36, 1),
    transform 900ms cubic-bezier(0.34, 1.56, 0.64, 1),
    filter 900ms cubic-bezier(0.16, 1, 0.3, 1),
    background 240ms ease,
    width 480ms cubic-bezier(0.34, 1.15, 0.64, 1),
    height 480ms cubic-bezier(0.34, 1.15, 0.64, 1),
    border-radius 480ms cubic-bezier(0.34, 1.15, 0.64, 1);
}

.detail-actions.is-visible .detail-menu {
  opacity: 1;
  filter: blur(0);
  transform: translateY(0) scale(1);
}

.detail-menu:hover:not(.is-open) {
  background: var(--glass-bg-hover);
}

.detail-menu:hover:not(.is-open) .detail-menu-toggle img {
  filter: var(--icon-filter-hover);
}

.detail-menu.is-pressed:not(.is-open),
.detail-menu:hover.is-pressed:not(.is-open) {
  transform: translateY(0) scale(0.85);

  transition:
    transform 420ms cubic-bezier(0.22, 1, 0.36, 1),
    background 240ms ease;
}

.detail-menu.is-open {
  z-index: 2;
  width: 260px;
  height: 208px;
  border-radius: 26px;
}

.detail-menu-toggle {
  position: absolute;
  inset: 0;

  display: grid;
  place-items: center;

  border: none;
  background: none;
  padding: 0;
  cursor: pointer;

  opacity: 1;
  filter: blur(0);

  transition:
    opacity 260ms ease,
    filter 260ms ease;
}

.detail-menu-toggle img {
  width: 28px;
  height: 24px;
  margin-top: 2px;
  object-fit: contain;
  pointer-events: none;
  filter: var(--icon-filter);
}

.detail-menu.is-open .detail-menu-toggle {
  opacity: 0;
  filter: blur(14px);
  pointer-events: none;
}

.detail-menu-list {
  position: absolute;
  inset: 0;

  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 12px;

  opacity: 0;
  filter: blur(14px);
  pointer-events: none;

  transition:
    opacity 260ms ease,
    filter 260ms ease;
}

.detail-menu.is-open .detail-menu-list {
  opacity: 1;
  filter: blur(0);
  pointer-events: auto;
  transition-delay: 160ms;
}

.detail-menu-item {
  display: flex;
  align-items: center;

  height: 44px;
  padding: 0 12px;
  border-radius: 14px;

  font-size: 14px;
  font-weight: 500;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;

  transition:
    background 200ms ease,
    color 200ms ease;
}

.detail-menu-item:hover {
  background: var(--sheet-bg);
  color: var(--text-main);
}

.detail-menu-item.is-current {
  background: var(--sheet-bg);
  color: var(--text-main);
  font-weight: 600;
}

.detail-menu-toggle:focus-visible,
.detail-menu-item:focus-visible {
  outline: 2px solid var(--text-main);
  outline-offset: 2px;
}

/* Whichever of back/status/menu isn't the one being interacted with is
   disabled while another is open — only its shadow, icon and text dim,
   the pill itself stays fully opaque. */

.detail-actions:has(.detail-menu.is-open) .detail-back,
.detail-actions:has(.detail-menu.is-open) .detail-status,
.detail-actions:has(.detail-status.is-open) .detail-back,
.detail-actions:has(.detail-status.is-open) .detail-menu {
  pointer-events: none;
  box-shadow:
    0 12px 30px rgb(0 0 0 / 0.03),
    0 4px 10px rgb(0 0 0 / 0.02);
}

.detail-actions:has(.detail-menu.is-open) .detail-back img,
.detail-actions:has(.detail-menu.is-open) .detail-status-toggle,
.detail-actions:has(.detail-status.is-open) .detail-back img,
.detail-actions:has(.detail-status.is-open) .detail-menu-toggle {
  opacity: 0.4;
}

/* ==========================================================================
 Responsive
 ========================================================================== */

@media (max-width: 500px) {
  .detail-main {
    --content-pad: 20px;
  }

  .detail-menu.is-open {
    width: min(260px, calc(100vw - 96px));
  }

  .detail-status.is-open {
    width: min(280px, calc(100vw - 48px));
    max-width: min(280px, calc(100vw - 48px));
  }

  .detail-status-project,
  .detail-status-section {
    max-width: 38vw;
    overflow: hidden;
    text-overflow: ellipsis;
  }
}

@media (prefers-reduced-motion: reduce) {
  .detail-hero-eyebrow,
  .detail-hero h1,
  .detail-hero-cta,
  .detail-hero-intro,
  .detail-hero-image {
    animation: none;
  }

  .detail-back,
  .detail-menu {
    transition-delay: 0ms !important;
  }

  .detail-hero-intro-text,
  .detail-hero-intro.is-expanded {
    transition: none;
  }

  .article-section {
    transition: none;
  }

  .feature-marquee-track {
    animation: none;
  }

  .reflection-card,
  .article-section.is-visible .reflection-card,
  .reflection-card::after,
  .reflection-art * {
    transition: none !important;
  }

  .reflection-card {
    opacity: 1;
    translate: none;
  }

  .reflection-card.is-active {
    transform: none;
  }

  .reflection-card.is-active .reflection-art--growth .growth-pulse {
    animation: none;
  }

  .detail-status,
  .detail-status-toggle,
  .detail-status-section,
  .detail-status-list,
  .detail-status-item,
  .detail-menu,
  .detail-menu-toggle,
  .detail-menu-list,
  .detail-menu-item {
    transition: none;
  }
}
