/* ============================================================
   STACKERFOX - section styles
   ============================================================ */

/* ---------------- 1. hero ---------------- */

.hero {
  position: relative;
  min-height: 100svh;
  display: grid;
  align-content: center;
  padding-block: calc(var(--nav-h) + clamp(24px, 5vh, 60px)) clamp(90px, 12vh, 150px);
  overflow: hidden;
}

.hero-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(24px, 4vw, 40px);
  align-items: center;
}

/* two columns on a wide screen, and on a phone on its side, where a sphere
   under the copy would have no height at all */
@media (min-width: 1025px), (orientation: landscape) and (min-width: 600px) {
  .hero-grid { grid-template-columns: minmax(0, 1.08fr) minmax(0, 0.92fr); }
}

.hero-copy { position: relative; z-index: 2; min-width: 0; }

.hero h1 {
  margin-top: clamp(14px, 2.4vh, 30px);
  /* the fit fills this box, so a narrower box is a smaller headline */
  max-width: 80%;
}

/* the dot in front of the hero's eyebrow line blinks like a live light:
   half a second on, half a second off (only this one; other eyebrows stay still) */
.hero .eyebrow::before { animation: hero-dot-blink 1s steps(1, end) infinite; }
@keyframes hero-dot-blink { 50% { opacity: 0; } }

/* the circled word: an svg ellipse that draws itself once the line lands */
.circled { position: relative; display: inline-block; }
.circled svg {
  position: absolute;
  left: 50%; top: 50%;
  width: 128%; height: 168%;
  transform: translate(-50%, -50%) rotate(-2.5deg);
  overflow: visible;
  pointer-events: none;
}
.circled svg path {
  fill: none;
  stroke: currentColor;
  stroke-width: 5;
  stroke-linecap: round;
  stroke-dasharray: var(--len, 900);
  stroke-dashoffset: var(--len, 900);
  transition: stroke-dashoffset 1.1s var(--ease-out) 0.75s;
}
.circled.is-in svg path { stroke-dashoffset: 0; }

.hero-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: clamp(18px, 3vw, 40px);
  margin-top: clamp(26px, 4.5vh, 54px);
  max-width: 46rem;
}
.hero-foot .btn { flex: none; }

.hero-cloud {
  position: relative;
  aspect-ratio: 1.32;
  width: 100%;
}
/* the canvas is a good deal larger than its box, so the sphere's breath,
   its wobble, a poke from the fox and its lean toward the pointer all have
   room: no dot ever meets the canvas edge, so nothing is cut and nothing
   needs fading */
.hero-cloud canvas { position: absolute; inset: -30%; width: 160%; height: 160%; max-width: none; }

@media (max-width: 1024px) {
  .hero-copy { max-width: none; }
  .hero-foot { position: relative; z-index: 2; margin-top: clamp(14px, 2.4vh, 26px); }
}

/* An upright phone or tablet is arranged the way the reference arranges it:
   the hero is exactly one screen, a small dot sphere sits in the top-right
   corner (400px on a tablet, 160px on a phone), the headline starts below
   it, and the lede is pushed to the bottom of the screen. Padding is the
   reference's: nav + 26..40px above, 84px on a phone / 60px on a tablet below. */
@media (max-width: 1024px) and (orientation: portrait) {
  .hero {
    --sphere: clamp(160px, 52vw, 400px);
    height: 100svh;
    min-height: 0;
    display: flex;
    flex-direction: column;
    padding-block: calc(var(--nav-h) + clamp(26px, 5vw, 40px)) clamp(60px, calc(118px - 8vw), 84px);
  }
  .hero-grid { flex: 1; min-height: 0; display: flex; flex-direction: column; align-items: stretch; }
  .hero-copy { flex: 1; min-height: 0; display: flex; flex-direction: column; }
  /* the sphere sits under the eyebrow line, not beside it: the eyebrow
     stays one line and the sphere starts a little lower (--drop) */
  .hero { --drop: 46px; }
  .hero-cloud {
    position: absolute;
    top: calc(var(--nav-h) + 10px + var(--drop));
    right: var(--gutter);
    width: var(--sphere);
    height: var(--sphere);
    aspect-ratio: auto;
    z-index: 1;
  }
  /* the headline clears the sphere (its top overlaps the sphere's last fifth,
     as the reference's does) and is capped at the reference's 11vw */
  .hero h1 { margin-top: calc(var(--sphere) * 0.72 + 10px + var(--drop)); --fit-max: 11vw; }
  .hero-foot { margin-top: auto; padding-top: clamp(26px, 4.5vh, 54px); }
  /* the eyebrow runs as one line above the sphere */
  .hero .eyebrow { white-space: nowrap; }
}

/* on a phone the reference lets the headline fill the measure, drops the
   button (the dock carries it) and runs the lede at 16px */
@media (max-width: 480px) {
  .hero { --sphere: 160px; --fit-min: 88px; }
  .hero h1 { --fit-max: 260px; }
  /* one word per line, always - "Digital," / "but" / "foxier." - the
     reference's phone headline is three short words at ~113px; initFit
     measures the widest word because each .w is a block. This used to
     collapse to two lines ("but foxier." together) on a short viewport,
     but that reads noticeably smaller since the fit-to-width pass then
     has to shrink for the longer combined line instead */
  .hero h1 .line-mask > span > .w { display: block; }
  .hero-foot .btn { display: none; }
  .hero-foot .lede { font-size: 1rem; }
}

/* a phone on its side has about 390px: the hero drops its eyebrow line and
   most of its padding so the headline and lede still fit one screen */
@media (max-height: 500px) and (orientation: landscape) {
  .hero { padding-block: calc(var(--nav-h) + 8px) 64px; }
  .hero .eyebrow { display: none; }
  .hero h1 { margin-top: 0; }
  .hero-foot { margin-top: 12px; }
  .hero-foot .lede { font-size: 0.95rem; }
  /* the sphere's own aspect ratio would make it taller than the screen */
  .hero-cloud { max-height: calc(100svh - var(--nav-h) - 72px); }
}

/* the page jolts when the fox bites or pokes the hero sphere */
main.is-shake { animation: page-shake 0.22s linear; }
@keyframes page-shake {
  0%   { transform: translate(0, 0); }
  20%  { transform: translate(var(--shake, 3px), calc(var(--shake, 3px) * -0.6)); }
  40%  { transform: translate(calc(var(--shake, 3px) * -0.8), calc(var(--shake, 3px) * 0.5)); }
  60%  { transform: translate(calc(var(--shake, 3px) * 0.5), calc(var(--shake, 3px) * 0.4)); }
  80%  { transform: translate(calc(var(--shake, 3px) * -0.3), calc(var(--shake, 3px) * -0.2)); }
  100% { transform: translate(0, 0); }
}
@media (prefers-reduced-motion: reduce) { main.is-shake { animation: none; } }

/* ---------------- 2. ticker ---------------- */

.ticker {
  position: relative;
  border-block: 1.5px solid rgb(var(--ink-rgb) / 0.9);
  background: var(--ink);
  color: var(--ground);
  padding-block: clamp(10px, 1.4vw, 17px);
  overflow: hidden;
  display: flex;
  gap: 0;
}

.ticker-run {
  display: flex;
  align-items: center;
  gap: clamp(20px, 2.4vw, 40px);
  padding-right: clamp(20px, 2.4vw, 40px);
  flex: none;
  white-space: nowrap;
  will-change: transform;
}

.ticker span {
  font-size: clamp(1rem, 1.8vw, 1.6rem);
  font-weight: 800;
  letter-spacing: -0.03em;
}
.ticker em { font-style: normal; color: var(--signal-lift); font-size: 0.8em; }

/* ---------------- reference column ----------------
   The reference caps every reading section at a 1320px column and centres
   it, so on a wide monitor the type sits in the middle with open ground on
   both sides instead of stretching gutter to gutter. The hero, statement,
   work wall and contact keep their full bleed; only these four take the cap.
   It is done with padding, not max-width, so the colour block still bleeds. */
#what, #how, #workHead, #stack, #faq, #skulk, #slot, .layer > .wrap {
  --col: 1320px;
  --section-y: clamp(60px, 9vw, 140px);
  padding-inline: max(var(--gutter), calc((100% - var(--col)) / 2));
}
/* the reference's FAQ narrows again to an 1100px reading column */
#faq { --col: 1100px; }
/* its phase panels keep a 44px inner gutter inside the 1320 column */
.layer > .wrap { --col: 1232px; }
/* and its workforce band is shallower than the reading sections */
#skulk { --section-y: clamp(50px, 7vw, 110px); overflow-x: clip; }

/* the reference's section eyebrow is a shade bigger than the meta mono */
#what .eyebrow, #how .eyebrow, #workHead .eyebrow { font-size: 0.8125rem; letter-spacing: 0.14em; }
/* and its intro paragraph runs at 18.7px, 600, in a 531px measure */
#what .lede, #how .lede, #workHead .lede { font-size: clamp(1rem, 1.3vw, 1.19rem); font-weight: 600; max-width: 531px; }

/* ---------------- 3. what we do ---------------- */

.what { padding-bottom: clamp(50px, 7vw, 96px); }

/* the cap is a character count, and data-fit measures this box's own content
   width, so a line longer than the cap clips instead of shrinking; min() lets
   a narrow column take over the cap and the fit scale the type down */
.what h2 { max-width: min(18ch, 100%); }

/* the eyebrow is inline-flex and the headline an inline-block scan box, so
   on a narrow screen they shared one line and crushed the eyebrow; each
   gets its own line */
.what .stack-head .eyebrow { display: flex; }

/* the rotator swaps the last word without moving the line */
.rotator {
  position: relative;
  display: inline-grid;
  vertical-align: top;
}
.rotator > span {
  grid-area: 1 / 1;
  opacity: 0;
  transform: translateY(0.42em) rotate(3deg);
  /* its own timing rather than the shared tokens: the word should ease in
     slowly enough to be read as a change, not blink */
  transition: opacity 0.62s var(--ease-out), transform 0.9s var(--ease-out);
}
.rotator > span.is-on { opacity: 1; transform: none; }
.rotator > span.is-out { opacity: 0; transform: translateY(-0.42em) rotate(-3deg); }

.what-side { display: grid; gap: clamp(16px, 2vw, 26px); align-content: end; }
/* the side copy sits at the bottom right of the head, ranged right, so its
   last line lands on the headline's baseline */
@media (min-width: 1025px) {
  .what .stack-head { grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr); }
  .what-side-right { justify-items: start; text-align: left; padding-left: clamp(40px, 6vw, 110px); }
  .what-side-right .what-jump { flex-wrap: nowrap; gap: 8px 18px; white-space: nowrap; }
}

.what-jump {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 22px;
}
.what-jump a {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: var(--accent-text);
  transition: transform var(--dur-2) var(--ease-back);
}
.what-jump a::before { content: "\25c6"; font-size: 0.7em; }
.what-jump a:hover { transform: translateX(3px); }

/* ---------------- 4. stack layers ---------------- */

/* Each layer has rounded top corners, so its corners reveal whatever sits
   behind. For layers 2 and 3 that is the previous layer, still painted. For
   layer 1 it is this container - which must match the bone section above it,
   or the page colour shows through the two corner notches. */
.layers { position: relative; background: var(--bone); }

.layer {
  position: sticky;
  top: 0;
  min-height: 100svh;
  display: grid;
  align-content: center;
  padding-block: calc(var(--nav-h) + 40px) clamp(60px, 9vh, 110px);
  overflow: hidden;
  border-start-start-radius: var(--r-panel);
  border-start-end-radius: var(--r-panel);
  will-change: transform;
}

.layer-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(28px, 4vw, 56px);
  align-items: center;
}

/* the reference's phases stack copy over widget through 1024 */
@media (min-width: 1025px) {
  .layer-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
}

.layer-copy { display: grid; gap: clamp(12px, 1.6vw, 20px); align-content: start; max-width: 34rem; }

/* the 01 - 02 - 03 progress readout */
.layer-steps { display: flex; align-items: center; gap: 9px; }
.layer-steps b { font-family: var(--font-mono); font-size: var(--t-mono); font-weight: 500; opacity: 0.55; letter-spacing: 0.12em; }
.layer-steps b.is-on { opacity: 1; font-weight: 700; }
.layer-steps i { display: block; width: 30px; height: 1.5px; background: currentColor; opacity: 0.35; }
.layer-steps i.is-on { opacity: 1; }

.layer-list { display: grid; gap: 6px; }
.layer-list li {
  font-family: var(--font-mono);
  font-size: clamp(0.76rem, 0.92vw, 0.9rem);
  letter-spacing: 0.02em;
  color: var(--accent-text);
}
.layer-list li::before { content: "\2192  "; }

/* the big ghost numeral behind each layer */
.layer-ghost {
  position: absolute;
  right: -0.06em;
  bottom: -0.3em;
  font-size: clamp(14rem, 30vw, 32rem);
  font-weight: 800;
  letter-spacing: -0.06em;
  line-height: 0.8;
  opacity: 0.055;
  pointer-events: none;
  user-select: none;
}

/* ---- live widget shell ---- */

.widget {
  position: relative;
  aspect-ratio: 1.32;
  width: 100%;
  border-radius: var(--r-panel);
  background: var(--void);
  color: var(--bone);
  padding: clamp(16px, 1.9vw, 26px);
  overflow: hidden;
  display: grid;
  grid-template-rows: auto 1fr auto;
  gap: 12px;
  box-shadow: 0 30px 70px -30px rgb(var(--ink-rgb) / 0.5);
}

.layer.block-void .widget {
  background: rgb(var(--ground-rgb) / 0.04);
  border: 1.5px solid rgb(var(--ground-rgb) / 0.18);
  box-shadow: none;
}

.widget-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  color: rgb(var(--ground-rgb) / 0.75);
}

.widget-body { position: relative; display: grid; place-items: center; }
.widget-foot { display: flex; flex-wrap: wrap; gap: 7px; }

.pillet {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.08em;
  padding: 5px 10px;
  border-radius: var(--r-pill);
  background: rgb(var(--ground-rgb) / 0.1);
  color: rgb(var(--ground-rgb) / 0.85);
}
.pillet.is-ok { background: rgb(63 213 154 / 0.14); color: var(--ok); }

/* widget 1: routing graph */
.graph { width: 100%; height: 100%; }
.graph .node {
  fill: none;
  stroke: var(--ground);
  stroke-width: 1.6;
}
.graph .node.is-hot { fill: var(--ground); }
.graph .node-t { font-family: var(--font-mono); font-size: 11px; fill: var(--ground); letter-spacing: 0.04em; }
.graph .node.is-hot + .node-t { fill: var(--void); }
.graph .wire {
  fill: none;
  stroke: var(--ground);
  stroke-width: 1.4;
  opacity: 0.45;
}
.graph .pulse { fill: var(--signal); }

/* widget 2: stack assembly */
.assembly { width: 100%; display: grid; gap: 8px; align-content: center; }
.asm-row {
  display: grid;
  grid-template-columns: 78px 1fr;
  align-items: center;
  gap: 12px;
}
.asm-row > span {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: 0.06em;
  color: rgb(var(--ground-rgb) / 0.75);
}
.asm-bar {
  height: 20px;
  border-radius: 5px;
  background: rgb(var(--ground-rgb) / 0.1);
  overflow: hidden;
  position: relative;
}
.asm-bar i {
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(
    -45deg,
    rgb(var(--ground-rgb) / 0.75) 0 6px,
    rgb(var(--ground-rgb) / 0.3) 6px 12px
  );
  transform: scaleX(var(--f, 0));
  transform-origin: 0 50%;
  transition: transform 0.9s var(--ease-out);
}
.asm-note { font-family: var(--font-mono); font-size: 10.5px; color: var(--ok); letter-spacing: 0.06em; margin-top: 4px; }

.toggle-live {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  cursor: pointer;
}
.toggle-live i {
  width: 30px; height: 16px;
  border-radius: 100px;
  background: rgb(var(--ground-rgb) / 0.25);
  position: relative;
  transition: background-color var(--dur-2) var(--ease-out);
}
.toggle-live i::after {
  content: "";
  position: absolute;
  top: 2px; left: 2px;
  width: 12px; height: 12px;
  border-radius: 50%;
  background: var(--ground);
  transition: transform var(--dur-2) var(--ease-back);
}
.toggle-live[aria-pressed="true"] i { background: rgb(var(--ground-rgb) / 0.45); }
.toggle-live[aria-pressed="true"] i::after { transform: translateX(14px); }

/* widget 3: ship log */
.shiplog {
  width: 100%; height: 100%;
  display: flex;
  align-items: flex-end;
  gap: clamp(5px, 0.9vw, 11px);
}
.shiplog i {
  flex: 1;
  border-radius: 5px 5px 2px 2px;
  background: var(--ground);
  height: 6%;
  transition: height 0.8s var(--ease-back);
}
.shiplog i:nth-child(even) { background: rgb(var(--ground-rgb) / 0.35); }

/* Below the two-column breakpoint the layers stop pinning and simply
   stack down the page. Pinning a panel taller than the viewport would
   clip its widget, and on a phone the scroll itself is the choreography. */
@media (max-width: 1024px) {
  /* the reference keeps every phase one full screen on tablets and phones
     too (932 / 844 / 667px tall), with the copy centred in it */
  .layer {
    padding-block: clamp(52px, 9vw, 80px) clamp(60px, 10vw, 96px);
  }
  .layer-ghost { font-size: clamp(9rem, 42vw, 16rem); opacity: 0.07; }
  .widget { aspect-ratio: 1.15; }
}

/* ---------------- 5. skulk ---------------- */

.skulk-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(30px, 4vw, 60px);
  align-items: center;
}
@media (min-width: 940px) {
  .skulk-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 0.92fr); }
}

.skulk h2 { max-width: 15ch; }
#skulk .lede { font-weight: 600; }

/* headline left, supporting line to its right, cards below - the reference's
   how-we-work arrangement */
.how-head { display: grid; gap: clamp(18px, 2.6vw, 40px); align-items: end; }
@media (min-width: 1025px) {
  .how-head { grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr); }
  /* two lines, its right edge on the last card's right edge */
  /* the paragraph sits at the right of the column — its box ends on the last
     card's right edge — but it reads left-aligned, on its own written breaks */
  .how-head .lede { max-width: none; width: max-content; justify-self: end; text-align: left; font-weight: 650; }
}

.deck-wrap { display: grid; justify-items: center; gap: 88px; }
/* the deck and its button sit toward the right of their column */
@media (min-width: 940px) {
  .deck-wrap { justify-self: end; width: min(100%, 420px); margin-right: clamp(0px, 3vw, 44px); }
}

/* the deck button: brand black with the coat colour for its type */
#deckNext { --btn-bg: var(--ink); --btn-fg: var(--ground); border-color: var(--ink); }
#deckNext::after { background: var(--signal); }
#deckNext:hover { color: var(--ink); }

.deck {
  position: relative;
  width: min(100%, 420px);
  aspect-ratio: 0.94;
  cursor: pointer;
}
/* the cards behind the front one fan out up to 25px to the left; where the
   deck already fills the column, make room for them so none leave the screen */
@media (max-width: 520px) {
  .deck { width: calc(100% - 28px); margin-left: 28px; }
}

.pass {
  position: absolute;
  inset: 0;
  background: var(--bone);
  color: var(--ink);
  border: 2px solid var(--ink);
  border-radius: var(--r-panel);
  padding: clamp(16px, 2.1vw, 24px);
  display: grid;
  grid-template-rows: auto auto 1fr auto;
  gap: 12px;
  box-shadow: 7px 8px 0 0 var(--ink);
  transform-origin: 50% 120%;
  transition: transform var(--dur-4) var(--ease-back), opacity var(--dur-3) var(--ease-out);
  will-change: transform;
}

.pass-top { display: flex; justify-content: space-between; align-items: center; gap: 10px; color: var(--ink-mute); }
.pass-top .live { width: 8px; height: 8px; border-radius: 50%; background: var(--ok); }

.pass-id { display: flex; align-items: center; gap: 13px; }
.pass-id canvas { width: 46px; height: 46px; flex: none; }
.pass-id h3 { font-size: clamp(1.25rem, 2vw, 1.7rem); font-weight: 800; letter-spacing: -0.03em; line-height: 1; }
.pass-id p { color: var(--ink-mute); margin-top: 3px; }

.pass-rows { display: grid; align-content: start; gap: 0; }
.pass-rows div {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
  padding-block: 9px;
  border-bottom: 1px dashed rgb(var(--ink-rgb) / 0.25);
}
.pass-rows dt { color: var(--ink-mute); font-family: var(--font-mono); font-size: var(--t-mono); letter-spacing: 0.12em; text-transform: uppercase; }
.pass-rows dd { margin: 0; font-weight: 700; text-align: right; }

.pass-quote {
  background: var(--ground);
  border-radius: var(--r-tile);
  padding: 11px 14px;
  font-weight: 700;
  font-size: 0.95rem;
  line-height: 1.3;
}

@media (max-width: 520px) {
  /* the reference's phone pass runs smaller and tighter than ours did:
     10px mono meta, a 21px id, 13px values and a 13px quote */
  .pass { padding: 22px 20px; gap: 12px; }
  .pass-top { font-size: 10px; }
  .pass-id { gap: 12px; }
  .pass-id canvas { width: 42px; height: 42px; }
  .pass-id h3 { font-size: 1.3rem; }
  .pass-id p { font-size: 10px; margin-top: 3px; }
  .pass-rows div { padding-block: 11px; }
  .pass-rows dt { font-size: 10px; }
  .pass-rows dd { font-size: 0.8125rem; }
  .pass-quote { font-size: 0.8125rem; line-height: 1.35; padding: 14px 16px; margin-top: 4px; }
  /* the quote follows the rows, as the reference's does, and the air the
     card has left sits under it rather than between them */
  .pass { grid-template-rows: auto auto auto auto; align-content: start; }
  /* the deck takes the height of its tallest card instead of a fixed ratio:
     at 360px a two-line quote ran out of the bottom of a 0.94 card */
  .deck { aspect-ratio: auto; display: grid; }
  .pass { position: relative; inset: auto; grid-area: 1 / 1; }
}

/* ---------------- 6. how ---------------- */

.moves {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(14px, 1.6vw, 22px);
  margin-top: clamp(30px, 4vw, 56px);
}
/* the reference runs the three cards as one column through 1024 */
@media (min-width: 1025px) { .moves { grid-template-columns: repeat(3, 1fr); } }

.move {
  position: relative;
  background: var(--ground);
  border: 2px solid var(--ink);
  border-radius: var(--r-panel);
  padding: clamp(20px, 2.2vw, 30px);
  display: grid;
  gap: 10px;
  align-content: start;
  overflow: hidden;
  transition: transform var(--dur-3) var(--ease-back);
}
.move:hover { transform: translateY(-6px); }

.move-n { font-family: var(--font-mono); font-size: var(--t-mono); letter-spacing: 0.16em; text-transform: uppercase; color: var(--ink-soft); }
/* the reference's small heading band: 27.2px, 700, normal leading */
.move h3 { font-size: var(--t-h3); font-weight: 700; letter-spacing: var(--track-md); line-height: normal; }
/* the reference's card body: 15px, 500, 1.55 leading */
.move p { color: var(--ink-soft); font-size: 0.94rem; font-weight: 500; line-height: 1.55; }

/* a bar stack that fills as the card enters, echoing the stack idea */
.move-bars { display: flex; gap: 4px; margin-top: 6px; }
.move-bars i {
  height: 6px; flex: 1;
  border-radius: 2px;
  background: rgb(var(--ink-rgb) / 0.18);
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform var(--dur-3) var(--ease-out);
}
.move.is-in .move-bars i { transform: scaleX(1); }
.move-bars i.is-fill { background: var(--ink); }

.how-foot {
  margin-top: clamp(26px, 3.4vw, 46px);
  padding-top: 18px;
  border-top: 1px solid rgb(var(--ink-rgb) / 0.18);
  color: var(--accent-text);
}

/* ---------------- 7. promise ---------------- */

.promise {
  --promise-size: clamp(2.6rem, 8.4vw, 8rem);
  position: relative;
  min-height: 88svh;
  display: grid;
  align-content: center;
  overflow: hidden;
}
/* on a phone the dots gather below the words rather than behind them, so the
   section leaves them a square of room at the bottom, above the readout */
@media (max-width: 699px) {
  /* the section is as tall as its words plus the mark under them: no
     screen-height minimum pushing the two apart */
  .promise { min-height: 0; padding-top: 72px; padding-bottom: calc(60vw + 72px); }
}

.promise-inner { position: relative; z-index: 2; display: grid; gap: clamp(6px, 0.7vw, 12px); }
/* display type carries a left side bearing, so the eyebrow's ink sits left of
   the headline's. it is nudged in by that bearing, measured off the same size */
.promise-inner .eyebrow { margin-left: calc(var(--promise-size) * 0.086); }

.promise h2 {
  color: var(--ground);
  text-transform: uppercase;
  max-width: 14ch;
  font-size: var(--promise-size);
  line-height: 0.88;
  letter-spacing: -0.045em;
}

/* the scanning line that sweeps the statement */
.scanline {
  position: absolute;
  left: 0;
  width: 100%;
  height: 2px;
  background: linear-gradient(90deg, transparent, var(--ground) 25%, var(--glow-a) 50%, var(--ground) 75%, transparent);
  filter: blur(0.4px);
  box-shadow: 0 0 26px 5px rgb(var(--ground-rgb) / 0.45);
  opacity: 0;
  pointer-events: none;
}

/* full-bleed: the specks fly out of the fox by the headline and cross the whole section */
.promise-cloud { position: absolute; inset: 0; }
.promise-cloud canvas { width: 100%; height: 100%; }
.promise-readout.is-done { background: var(--ground); color: var(--void); }
.promise-readout {
  position: absolute;
  transition: background-color var(--dur-3) var(--ease-out), color var(--dur-3) var(--ease-out);
  right: clamp(10px, 3vw, 60px);
  top: 46%;
  padding: 6px 12px;
  border-radius: var(--r-pill);
  background: rgb(var(--ground-rgb) / 0.14);
  color: var(--ground);
}

@media (max-width: 860px) {
  .promise-cloud { width: 100%; opacity: 0.42; }
  .promise-readout { top: auto; bottom: 8%; right: var(--gutter); }
}
/* the readout is the tour's: it shows while the show plays and goes once
   the mark is back in production */
.promise-readout.is-done { display: none; }

/* ---------------- 8. work wall ---------------- */

/* the wall is one endless row now: it drifts on its own and your hand can
   take it over. drag is the only control — see js/sections.js */
.slider {
  position: relative;
  width: calc(100vw - var(--sbw, 0px));
  margin-left: calc(50% - 50vw + var(--sbw, 0px) / 2);
  --peek: clamp(34px, 5vw, 74px);        /* the sliver of the next card, so three never looks like all of them */
}
.wall {
  display: flex;
  overflow-x: auto;
  scrollbar-width: none;
  cursor: grab;
  user-select: none;
  touch-action: pan-y;
}
.wall::-webkit-scrollbar { display: none; }
.wall.is-drag { cursor: grabbing; }
/* the cards are links, so the browser wants to drag the link, not the row */
.wall a, .wall canvas, .wall img { -webkit-user-drag: none; user-drag: none; }
.wall .tile { flex: 0 0 calc(100% - var(--peek)); }
@media (min-width: 620px) { .wall .tile { flex-basis: calc((100% - var(--peek)) / 2); } }
/* three across only once a tile clears ~370px: at 900-1180 the titles wrapped
   to three lines and ran into the chips */
@media (min-width: 1180px) { .wall .tile { flex-basis: calc((100% - var(--peek)) / 3); } }

/* the top line: two arrows and a word. it describes the row, it is not a
   control — no pointer, no click, it just leans left and right */
.shint {
  display: flex; align-items: center; gap: 10px;
  padding: 0 var(--gutter) 12px;          /* left, clear of the chapter rail on the right edge */
  pointer-events: none; user-select: none;
  font-family: var(--font-mono); font-size: var(--t-mono);
  letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-soft);
}
.shint i { font-style: normal; font-size: 15px; line-height: 1; color: var(--ink); animation: lean 2.6s var(--ease-out) infinite; }
.shint i.r { animation-name: leanR; animation-delay: 1.3s; }
@keyframes lean  { 0%, 100% { transform: none; opacity: 0.45 } 45% { transform: translateX(-5px); opacity: 1 } }
@keyframes leanR { 0%, 100% { transform: none; opacity: 0.45 } 45% { transform: translateX(5px);  opacity: 1 } }
@media (prefers-reduced-motion: reduce) { .shint i { animation: none; opacity: 0.8 } }

.tile {
  position: relative;
  aspect-ratio: 1.42;
  overflow: hidden;
  display: block;
  background: var(--cloud-b);
  isolation: isolate;
}

.tile-media { position: absolute; inset: 0; }
.tile-media canvas,
.tile-media img { width: 100%; height: 100%; object-fit: cover; }

.tile::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgb(0 0 0 / 0.88) 0%, rgb(0 0 0 / 0.42) 34%, rgb(0 0 0 / 0.06) 62%);
  z-index: 1;
  transition: opacity var(--dur-3) var(--ease-out);
}

/* the wall reads as one greyscale set, and only the tile you are on
   comes up in colour. it makes hovering feel like picking something up */
.tile-media {
  filter: grayscale(1) contrast(1.06);
  transition: transform 0.9s var(--ease-out), filter 0.6s var(--ease-out);
}
.tile:hover .tile-media,
.tile:focus-visible .tile-media { transform: scale(1.045); filter: grayscale(0) contrast(1); }
.tile:hover::after { opacity: 0.82; }

.tile-case {
  position: absolute;
  z-index: 3;
  left: clamp(14px, 1.6vw, 22px);
  bottom: 38%;
  font-family: var(--font-mono);
  font-size: clamp(9px, 0.72vw, 11px);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 7px 13px;
  border-radius: var(--r-pill);
  background: var(--ground);
  color: var(--ink);
  opacity: 0;
  transform: translateY(8px);
  transition: opacity var(--dur-2) var(--ease-out), transform var(--dur-3) var(--ease-back);
}
.tile:hover .tile-case,
.tile:focus-visible .tile-case { opacity: 1; transform: none; }

.tile-n {
  position: absolute;
  top: clamp(14px, 1.6vw, 22px);
  left: clamp(14px, 1.6vw, 22px);
  z-index: 3;
  color: rgb(255 255 255 / 0.78);
}

.tile-chips {
  position: absolute;
  inset: clamp(48px, 6vw, 80px) clamp(14px, 1.6vw, 22px) 38%;
  z-index: 3;
  pointer-events: none;
}

.tile-chip {
  position: absolute;
  font-family: var(--font-mono);
  font-size: clamp(9px, 0.72vw, 11px);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 7px 12px;
  border-radius: var(--r-pill);
  background: rgb(18 16 15 / 0.86);
  color: #fff;
  backdrop-filter: blur(6px);
  display: inline-flex;
  align-items: center;
  gap: 7px;
  white-space: nowrap;
  opacity: 0;
  transform: translateY(10px) scale(0.94);
  transition: opacity var(--dur-3) var(--ease-out), transform var(--dur-4) var(--ease-back);
}
.tile-chip .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--ground); }
.tile.is-in .tile-chip { opacity: 1; transform: none; }
.tile.is-in .tile-chip:nth-child(2) { transition-delay: 0.12s; }

.tile-foot {
  position: absolute;
  inset-inline: clamp(14px, 1.6vw, 22px);
  bottom: clamp(14px, 1.6vw, 22px);
  z-index: 3;
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: end;
  gap: 14px;
  color: #fff;
}

.tile-foot h3 {
  font-size: clamp(1.5rem, 2.5vw, 2.4rem);
  font-weight: 800;
  letter-spacing: -0.035em;
  line-height: 1;
}
.tile-foot h3 span {
  display: inline-block;
  transition: transform var(--dur-3) var(--ease-back);
}
.tile:hover .tile-foot h3 span { transform: translateX(6px); }

.tile-cat { color: var(--ground); margin-top: 6px; }
.tile-stat { text-align: right; }
.tile-stat b {
  display: block;
  font-size: clamp(1.5rem, 2.4vw, 2.3rem);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.tile-stat span { color: rgb(255 255 255 / 0.78); }

.tile-open {
  position: absolute;
  top: clamp(14px, 1.6vw, 22px);
  right: clamp(14px, 1.6vw, 22px);
  z-index: 3;
  width: 40px; height: 40px;
  border-radius: 50%;
  display: grid; place-items: center;
  background: rgb(255 255 255 / 0.12);
  color: #fff;
  border: 1px solid rgb(255 255 255 / 0.25);
  transform: scale(0.6);
  opacity: 0;
  transition: transform var(--dur-3) var(--ease-back), opacity var(--dur-2) var(--ease-out);
}
.tile:hover .tile-open { transform: scale(1); opacity: 1; }

/* the open slot */
.slot {
  display: grid;
  align-content: center;
  gap: clamp(16px, 2vw, 26px);
  padding-block: clamp(60px, 9vw, 130px);
}
.slot h2 { color: var(--ground); max-width: 11ch; }
.slot-copy { display: grid; gap: 1em; max-width: 62ch; }
.slot { position: relative; overflow: hidden; }
/* the mesh drifts across the whole section; the copy sits on top of it, so
   it only ever shows through wherever the section is empty */
.slot-net { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0.5; }
.slot-main { position: relative; z-index: 2; display: grid; gap: clamp(16px, 2vw, 26px); }
.slot-row { display: flex; flex-wrap: wrap; align-items: center; gap: clamp(16px, 3vw, 42px); }
.slot-meta b { font-size: clamp(1.5rem, 2.4vw, 2.2rem); font-weight: 800; letter-spacing: -0.03em; display: block; line-height: 1; }

/* ---------------- 9. numbers ---------------- */

.numbers { position: relative; overflow: hidden; padding-block: clamp(50px, 7vw, 96px); }

.stat b {
  display: block;
  font-size: clamp(2.5rem, 6vw, 5rem);
  font-weight: 800;
  letter-spacing: -0.05em;
  line-height: 0.9;
  color: var(--ground);
  font-variant-numeric: tabular-nums;
}
.stat span { display: block; margin-top: 10px; color: rgb(var(--ground-rgb) / 0.78); }

/* ---------------- 10. the stack (physics) ---------------- */

/* a shallower top than the other reading sections */
#stack { padding-top: clamp(40px, 5vw, 76px); }

/* phones and tablets: headline, then the note (left), then the button (right) */
.toolkit-head { display: grid; grid-template-columns: 1fr; gap: 16px; }
.toolkit-side { display: grid; gap: 16px; justify-items: start; }
.toolkit-side .pit-tidy { justify-self: end; }
/* the button keeps one width whichever word it shows */
.pit-tidy { min-width: 9.5em; justify-content: center; }

/* wide: the headline and the note share one row and sit on the same
   baseline; the button sits under the note, both flush with the pit's
   right edge */
@media (min-width: 901px) {
  .toolkit-head {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-rows: auto auto;
    gap: 16px 30px;
  }
  .toolkit-side { display: contents; }
  .toolkit-head h2 { grid-column: 1; grid-row: 1; align-self: last baseline; }
  /* one line, so the dot sits on the text */
  .toolkit-side .eyebrow { grid-column: 2; grid-row: 1; align-self: last baseline; justify-self: end; white-space: nowrap; }
  .toolkit-side .pit-tidy { grid-column: 2; grid-row: 2; justify-self: end; }
}

/* the how lede breaks after "click" where it has the width for it */
@media (max-width: 1024px) { .br-desk { display: none; } }

/* the reference's toolkit box: 520px tall, and the section sits closer to
   whatever follows it (90px below against 140px above) */
#stack { padding-bottom: clamp(40px, 6vw, 90px); }

.pit {
  position: relative;
  margin-top: clamp(18px, 2vw, 26px);
  height: clamp(340px, 46vw, 520px);
  border-radius: var(--r-panel);
  background: var(--void);
  overflow: hidden;
  touch-action: pan-y;
}

.pit canvas { position: absolute; inset: 0; width: 100%; height: 100%; }

/* static fallback if the physics engine does not load */
.pit-fallback {
  position: absolute;
  inset: 0;
  display: none;
  flex-wrap: wrap;
  align-content: center;
  justify-content: center;
  gap: 10px;
  padding: clamp(20px, 4vw, 50px);
}
.pit.is-static .pit-fallback { display: flex; }
.pit-fallback span {
  padding: 0.62em 1.15em;
  border-radius: var(--r-pill);
  border: 1.5px solid var(--ground);
  color: var(--ground);
  font-weight: 700;
}

/* ---------------- 11. faq ---------------- */

/* the reference sets the eyebrow immediately after the headline on the same
   baseline, not pushed out to the opposite edge */
.faq-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 14px 20px;
}

/* on a phone the reference drops the label under the headline */
@media (max-width: 480px) {
  .faq-head { flex-direction: column; align-items: flex-start; gap: 14px; }
}

.faq-list { margin-top: clamp(26px, 3.4vw, 46px); border-top: 1.5px solid rgb(var(--ink-rgb) / 0.85); }

.qa { border-bottom: 1.5px solid rgb(var(--ink-rgb) / 0.85); }

.qa-btn {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  padding-block: clamp(18px, 2.2vw, 30px);
  text-align: left;
  cursor: pointer;
  font-size: var(--t-faq);
  font-weight: 700;
  letter-spacing: var(--track-md);
  line-height: 1.2;
  transition: color var(--dur-2) var(--ease-out);
}
.qa-btn:hover { color: var(--accent-text); }

.qa-sign {
  position: relative;
  flex: none;
  width: 22px; height: 22px;
}
.qa-sign::before,
.qa-sign::after {
  content: "";
  position: absolute;
  inset: 50% 0 auto 0;
  height: 2.5px;
  margin-top: -1.25px;
  background: currentColor;
  transition: transform var(--dur-3) var(--ease-back);
}
.qa-sign::after { transform: rotate(90deg); }
.qa[data-open="true"] .qa-sign::after { transform: rotate(0deg); }

.qa-panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--dur-4) var(--ease-inout);
}
.qa[data-open="true"] .qa-panel { grid-template-rows: 1fr; }
.qa-panel > div { overflow: hidden; }
.qa-panel p {
  max-width: 62ch;
  padding-bottom: clamp(20px, 2.4vw, 30px);
  color: var(--ink-soft);
  font-weight: 600;
}

/* ---------------- 12. contact ---------------- */

.contact { position: relative; overflow: hidden; }
.contact h2 { max-width: 9ch; }
/* the reference's contact headline is 11vw on tablets and 48px on phones */
@media (max-width: 1024px) { .contact h2 { --fit-max: 11vw; } }
@media (max-width: 480px) { .contact h2 { --fit-max: 48px; } }

.contact-meta {
  display: grid;
  grid-template-columns: 1fr;
  gap: clamp(20px, 2.6vw, 40px);
  margin-top: clamp(40px, 6vw, 86px);
}
@media (min-width: 720px) { .contact-meta { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

.contact-meta h4 { color: var(--accent-text); margin-bottom: 8px; }
.contact-meta p { font-size: clamp(1.05rem, 1.5vw, 1.35rem); font-weight: 700; letter-spacing: -0.02em; }
.contact-meta small { display: block; margin-top: 4px; color: var(--ink-soft); font-size: 0.9rem; font-weight: 600; }

.mailto { position: relative; display: inline-block; }
.mailto::after {
  content: "";
  position: absolute;
  left: 0; bottom: -2px;
  width: 100%; height: 2px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: 100% 50%;
  transition: transform var(--dur-3) var(--ease-out);
}
.mailto:hover::after { transform: scaleX(1); transform-origin: 0 50%; }


/* ---------------- 13. footer ---------------- */

.foot { padding-block: clamp(34px, 4vw, 54px) clamp(16px, 2vw, 26px); overflow: hidden; }

/* ---------------- pointer glow ----------------
   on the dark bands (about me, the statement, the footer) a soft brand-
   coloured light follows the pointer behind the copy. --gx / --gy are set
   in px by chrome.js, --gl fades it in while the pointer is over the band */
.has-glow { position: relative; isolation: isolate; }
.has-glow::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: var(--gl, 0);
  background: radial-gradient(
    circle 380px at var(--gx, 50%) var(--gy, 50%),
    rgb(var(--ground-rgb) / 0.20) 0%,
    rgb(var(--ground-rgb) / 0.08) 38%,
    transparent 72%
  );
  transition: opacity var(--dur-3) var(--ease-out);
}
@media (pointer: coarse), (prefers-reduced-motion: reduce) { .has-glow::before { display: none; } }

.foot-top {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 18px;
}

/* the wordmark, faint until it enters, then solid. It is a fill, not a
   text-stroke: Chrome strokes a variable font at its default weight, so an
   outline sat as a thin second copy over the heavy fill. The size is a
   fraction of the container width so the word never runs past the gutter. */
.foot-mark {
  /* the vector wordmark, inlined in index.html as #wordGlyph, full column width */
  display: block;
  width: 100%;
  height: auto;
  margin-block: clamp(20px, 3vw, 40px);
  fill: rgb(var(--ground-rgb) / 0.12);
  user-select: none;
  transition: fill 1s var(--ease-out), opacity var(--dur-4) var(--ease-out), transform var(--dur-4) var(--ease-out);
}
.foot-mark.is-in { fill: var(--ground); }

/* on a phone the dock is a full-width bar over the bottom of the page; the
   wordmark and the bottom line sit above it instead of under it */
@media (max-width: 640px) {
  .foot { padding-bottom: 84px; }
  .foot-mark { margin-block: 26px 30px; }
}

.foot-bottom {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 12px;
  color: rgb(var(--ground-rgb) / 0.72);
}
.foot-readout { font-variant-numeric: tabular-nums; }

/* ---------------- game overlay ---------------- */

.game {
  position: fixed;
  inset: 0;
  z-index: var(--z-game);
  background: rgb(var(--ink-rgb) / 0.94);
  backdrop-filter: blur(10px);
  display: grid;
  place-items: center;
  padding: clamp(14px, 3vw, 30px);
}
.game[hidden] { display: none; }

.game-panel {
  width: min(100%, 460px);
  display: grid;
  gap: 14px;
  justify-items: center;
  color: var(--ground);
}
.game-canvas {
  /* as wide as it can be while the whole panel still fits a short or
     landscape screen: the bar and hint take about 150px */
  width: min(100%, calc((100svh - 150px) * 0.78));
  aspect-ratio: 0.78;
  border-radius: var(--r-panel);
  background: var(--void);
  border: 1.5px solid rgb(var(--ground-rgb) / 0.2);
}
.game-bar { display: flex; align-items: center; justify-content: space-between; gap: 14px; width: 100%; }
.game-score b { font-size: 1.5rem; font-variant-numeric: tabular-nums; }

/* the game panel sits on the ink scrim, so its ghost button needs the
   dark-surface treatment rather than the default light one */
.game .btn-ghost {
  --btn-fg: var(--ground);
  border-color: rgb(var(--ground-rgb) / 0.4);
}
.game .btn-ghost::after { background: var(--ground); }
.game .btn-ghost:hover { color: var(--void); }
.game-hint, .game-score { color: rgb(var(--ground-rgb) / 0.75); }

/* ---------------- headline scan ----------------
   The fox reads the headline before you do: a grid and a sweep cross the
   line while a readout counts up, then it reports back. */

.scanbox { position: relative; display: inline-block; }

.scanbox::before {
  content: "";
  position: absolute;
  inset: -4% -2%;
  pointer-events: none;
  opacity: 0;
  background-image:
    repeating-linear-gradient(to right, rgb(var(--ink-rgb) / 0.18) 0 1px, transparent 1px 22px),
    repeating-linear-gradient(to bottom, rgb(var(--ink-rgb) / 0.18) 0 1px, transparent 1px 22px);
  transition: opacity var(--dur-3) var(--ease-out);
}

.scanbox::after {
  content: "";
  position: absolute;
  top: -4%; bottom: -4%;
  width: 3px;
  left: 0;
  pointer-events: none;
  background: var(--signal);
  box-shadow: 0 0 22px 5px rgb(var(--signal-rgb) / 0.5);
  opacity: 0;
}

.scanbox.is-scanning::before { opacity: 1; }
.scanbox.is-scanning::after { opacity: 1; animation: sweep 1.9s var(--ease-inout) forwards; }

@keyframes sweep {
  0%   { left: 0; opacity: 0; }
  8%   { opacity: 1; }
  92%  { opacity: 1; }
  100% { left: 100%; opacity: 0; }
}

.scan-readout {
  display: flex;
  width: fit-content;
  align-items: center;
  gap: 8px;
  margin-top: 14px;
  padding: 6px 12px;
  border-radius: var(--r-pill);
  background: rgb(var(--ink-rgb) / 0.08);
  color: var(--ink-soft);
  opacity: 0;
  transform: translateY(6px);
  transition: opacity var(--dur-3) var(--ease-out), transform var(--dur-3) var(--ease-out);
}
.scan-readout.is-on { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .scanbox::before, .scanbox::after { display: none; }
}

/* the ticker runs hot when the fox leans on it */
.ticker.is-hot { background: var(--signal); }
.ticker.is-hot em { color: var(--void); }
.ticker { transition: background-color var(--dur-3) var(--ease-out); }

/* ---------------- case study ----------------
   The wall is not terminal: each tile opens onto the note behind it. */

.case {
  position: fixed;
  inset: 0;
  z-index: var(--z-game);
  display: grid;
  place-items: center;
  padding: clamp(12px, 3vw, 40px);
  background: rgb(var(--ink-rgb) / 0.86);
  backdrop-filter: blur(14px);
  opacity: 0;
  transition: opacity var(--dur-3) var(--ease-out);
}
.case[hidden] { display: none; }
.case.is-on { opacity: 1; }

.case-panel {
  position: relative;
  width: min(100%, 1040px);
  max-height: 90svh;
  overflow: auto;
  background: var(--bone);
  color: var(--ink);
  border-radius: var(--r-panel);
  display: grid;
  grid-template-columns: 1fr;
  transform: translateY(20px) scale(0.98);
  transition: transform var(--dur-4) var(--ease-back);
}
.case.is-on .case-panel { transform: none; }

@media (min-width: 860px) {
  .case-panel { grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr); }
}

.case-art { position: relative; min-height: 220px; background: var(--cloud-b); }
.case-art canvas { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
/* below 860px the art and body stack in one column, so the whole card has
   to clear in about one svh-ish screen with no internal scroll: the art
   gives up height, the name drops off .t-lg's desktop-section size, and
   the note is let off its 34ch measure (a narrower cap than this column
   already is) so it wraps in fewer, not narrower, lines */
@media (max-width: 859px) {
  .case-art { min-height: 34svh; }
  #caseName { font-size: clamp(1.5rem, 7vw, 2.1rem); }
  .case-body .lede { max-width: none; }
}

.case-body {
  padding: clamp(22px, 3vw, 44px);
  display: grid;
  gap: clamp(10px, 1.4vw, 16px);
  align-content: start;
}
.case-index { color: var(--ink-mute); }
.case-cat { color: var(--accent-text); }

.case-rows { display: grid; gap: 0; margin-top: 6px; }
.case-rows > div {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  padding-block: 10px;
  border-bottom: 1px solid rgb(var(--ink-rgb) / 0.14);
}
.case-rows dt { color: var(--ink-mute); font-family: var(--font-mono); font-size: var(--t-mono); letter-spacing: 0.12em; text-transform: uppercase; }
.case-rows dd { margin: 0; font-weight: 700; text-align: right; }

.case-actions { display: flex; gap: 10px; margin-top: 10px; }

/* previous/next: a plain arrow pair, not a row of labelled buttons - it
   keeps the panel short enough on a phone to need no internal scroll */
.case-arrow {
  width: 42px; height: 42px;
  flex: none;
  border-radius: 50%;
  border: 1.5px solid rgb(var(--ink-rgb) / 0.25);
  background: transparent;
  color: var(--ink);
  display: grid;
  place-items: center;
  font-size: 1.1rem;
  cursor: pointer;
  transition: transform var(--dur-2) var(--ease-back), border-color var(--dur-2) var(--ease-out);
}
.case-arrow:hover { transform: scale(1.12); border-color: var(--ink); }

.case-close {
  position: absolute;
  top: 12px; right: 12px;
  width: 42px; height: 42px;
  border-radius: 50%;
  display: grid; place-items: center;
  background: var(--ink);
  color: var(--ground);
  cursor: pointer;
  transition: transform var(--dur-2) var(--ease-back);
}
.case-close:hover { transform: rotate(90deg); }

/* ---------------- tour props ---------------- */

/* a rubber stamp the fox thumps onto a card: lands big, settles, fades */
.stamp {
  position: absolute;
  right: 8%;
  top: 12%;
  z-index: 5;
  padding: 6px 12px 5px;
  border: 2.5px solid currentColor;
  border-radius: 8px;
  color: var(--signal);
  font-family: var(--font-mono);
  font-size: clamp(0.8rem, 1.1vw, 1rem);
  font-weight: 800;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  pointer-events: none;
  transform: rotate(var(--rot, -8deg));
  animation: stamp-in 0.42s var(--ease-back) both;
  transition: opacity 0.6s var(--ease-out);
}
.stamp.on-dark { color: var(--ground); }
.stamp.is-gone { opacity: 0; }
@keyframes stamp-in {
  0% { opacity: 0; transform: rotate(var(--rot, -8deg)) scale(2.4); }
  60% { opacity: 1; transform: rotate(var(--rot, -8deg)) scale(0.94); }
  100% { opacity: 1; transform: rotate(var(--rot, -8deg)) scale(1); }
}

/* the fox knocks the questions off their shelf: the words fall into a pile */
.qa-word { display: inline-block; white-space: pre; will-change: transform; }
.qa-word.is-back { transition: transform 0.7s var(--ease-inout); }
.faq-list, .qa { transition: border-color 0.4s var(--ease-out); }
.faq-list.is-tumbled, .faq-list.is-tumbled .qa { border-color: transparent; }
.faq-list.is-tumbled .qa-sign { opacity: 0; }