/* ============================================================================
   css/howvex.css — "How VEX works" (sections/15-how-vex-works.html · js/howvex.js)
   Semantic tokens only (tokens.css Part 2). No hex, no shadows, no gradients.
   DEFAULT = the static layout (no JS · reduced motion · #noanim):
     three stacked cards — table → graph with the path lit → the briefing card —
     each under its mono step label. JS adds .howvex--live to pin the stage and
     drive every part from scroll progress (inline transforms/opacity only).
   LIVE runs at every width, phones included. The three phases play inside a
   CSS-drawn laptop screen; the screen is a size container, so how much of the
   sheet / how dense the card gets is a question about the SCREEN box, never the
   window (see the @container hvscreen rules).
   ============================================================================ */

.howvex__anchor { display: block; height: 0; }
.howvex__rail { display: none; }                       /* live only */
.howvex__step { margin-bottom: var(--spacing-16); text-align: center; }
.howvex__phase + .howvex__phase { margin-top: var(--spacing-48); }
.howvex__phase p { max-width: none; }

/* --- 01 · the raw-data table: a hairline data sheet on the surface --------- */
.hv-table {
  width: min(100%, 720px); margin: 0 auto;
  background: var(--surface); border: 1px solid var(--hair); border-radius: var(--radius-xl);
  padding: var(--spacing-8) var(--spacing-16) var(--spacing-12);
  color: var(--ink-2); font-size: 13px; line-height: 1.3; font-variant-numeric: tabular-nums;
}
.hv-row {
  display: grid; grid-template-columns: 58px 92px 66px 64px 96px minmax(0, 1fr) 68px 84px;
  column-gap: var(--spacing-8); align-items: center; height: 30px; padding: 0 var(--spacing-4);
  border-top: 1px solid var(--hair); white-space: nowrap;
}
.hv-row > span { overflow: hidden; text-overflow: ellipsis; }
.hv-row .r { text-align: right; }
.hv-row--head { border-top: 0; height: 32px; font-family: var(--font-mono); font-size: var(--fs-label); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--muted); }
.hv-rows > .hv-row:first-child { border-top: 1px solid var(--hair-2); }
.hv-table__cap { margin-top: var(--spacing-12); padding-top: var(--spacing-8); border-top: 1px solid var(--hair); }

/* --- 02 · the brain: hairline mesh, ink nodes, one blue path, lemon lever ---- */
.hv-graph { position: relative; width: min(100%, 720px); margin: 0 auto; }
.hv-graph__svg { display: block; width: 100%; height: auto; overflow: visible; }
.hv-graph .e { stroke: var(--hair-2); stroke-width: 1; fill: none; }
.hv-graph .n { fill: var(--ink-2); opacity: var(--hv-n, 1); }
.hv-graph .p { fill: var(--accent-blue); transform-box: fill-box; transform-origin: center; }
.hv-graph .lever { fill: var(--accent-blue); stroke: var(--accent-blue); stroke-width: 1; transform-box: fill-box; transform-origin: center; }
.hv-graph .path { fill: none; stroke: var(--accent-blue); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.hv-lbl {
  position: absolute; white-space: nowrap; pointer-events: none;
  font-family: var(--font-mono); font-size: var(--fs-label); letter-spacing: var(--tracking-label); text-transform: uppercase; line-height: var(--leading-label);
  color: var(--ink-2); background: var(--bg); padding: 2px 5px; border-radius: 2px;
}
.hv-lbl b, .hv-lbl i { font: inherit; letter-spacing: inherit; }
.hv-lbl i { display: none; }                           /* the short setting — see the 420 px rule */
/* static positions (% of the graph box — the SVG fills it exactly when height is auto); JS sets px in live mode */
.hv-lbl:nth-of-type(1) { left: calc(17.3% + 12px); top: 28.2%; transform: translateY(-50%); }
.hv-lbl:nth-of-type(2) { left: calc(41.7% + 12px); top: 44.5%; transform: translateY(-50%); }
.hv-lbl:nth-of-type(3) { left: 64.7%; top: calc(54.1% + 12px); transform: translate(-50%, 0); }
.hv-lbl:nth-of-type(4) { left: calc(83.3% + 6px); top: calc(78.2% + 14px); transform: translate(-100%, 0); }

/* --- 03 · the briefing card (24 / 16 / 14 + mono 11) ------------------------ */
.hv-card { width: min(100%, 560px); margin: 0 auto; background: var(--surface); color: var(--ink); border: 1px solid var(--hair); border-radius: var(--radius-xl); padding: var(--spacing-24); }
.hv-card > * + * { margin-top: var(--spacing-12); }
.hv-card__head { margin-top: var(--spacing-8); font-family: var(--font-mono); font-size: var(--fs-label); line-height: var(--leading-label); letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--st-critical); }   /* .hv-card__tag = .mono (muted) */
.hv-card__money { margin-top: var(--spacing-8); font-weight: var(--font-weight-medium); font-size: 24px; line-height: 1.2; letter-spacing: -0.01em; font-variant-numeric: tabular-nums; }
.hv-card__money .tail { color: var(--ink-2); }
.hv-card__lede { font-size: 16px; line-height: 1.5; }
.hv-card__why { font-size: 14px; line-height: 1.5; color: var(--ink-2); }
.hv-card__action { margin-top: var(--spacing-16); font-size: 16px; line-height: 1.5; }
.hv-card__foot { margin-top: var(--spacing-16); padding-top: var(--spacing-16); border-top: 1px solid var(--hair); display: flex; align-items: center; justify-content: space-between; gap: var(--spacing-12) var(--spacing-16); flex-wrap: wrap; }

/* --- the rail (live): three mono steps, a hairline bar under each fills with progress --- */
.howvex__rail li { max-width: none; }
.hv-step { position: relative; display: block; width: 100%; text-align: left; padding: 0 0 var(--spacing-12); color: var(--muted); transition: color var(--ui-duration) var(--ui-ease); }
.hv-step__k, .hv-step__t { font-family: var(--font-mono); font-size: var(--fs-label); letter-spacing: var(--tracking-label); text-transform: uppercase; line-height: var(--leading-label); }
.hv-step__k { margin-right: var(--spacing-8); }
.hv-step__d { display: block; margin-top: 6px; font-size: 13px; line-height: 1.45; letter-spacing: 0; color: var(--muted); max-width: 22ch; }
.hv-step.is-on { color: var(--ink); }
.hv-step.is-on .hv-step__d { color: var(--ink-2); }
.hv-step__bar { position: absolute; left: 0; right: 0; bottom: 0; height: 2px; background: var(--hair); overflow: hidden; }
.hv-step__bar::after { content: ""; position: absolute; inset: 0; background: var(--ink); transform: scaleX(var(--hv-fill, 0)); transform-origin: left center; }

/* --- the dots (live): rows condense into these, they land on the nodes ---- */
.hv-dot { position: absolute; left: 0; top: 0; width: 8px; height: 8px; margin: -4px 0 0 -4px; border-radius: 50%; background: var(--ink-2); opacity: 0; pointer-events: none; will-change: transform, opacity; }

/* --- the laptop wrappers are inert until live: the static stack is untouched --- */
.hv-laptop, .hv-laptop__lid, .hv-laptop__screen { display: contents; }
.hv-laptop__cam, .hv-laptop__hinge, .hv-laptop__deck { display: none; }

/* ============================================================================
   LIVE — the pinned stage, inside a laptop.
   The stage is sticky under the nav pill and SHORTER than the small viewport
   (100svh), so a mobile URL bar sliding in never moves the pin and never
   changes the document height. js/howvex.js writes .howvex__track's height in
   px: trackHeight = stageHeight + travel. Nothing inside the stage may change
   its own box while p runs — every phase is an absolute layer, and only
   transform / opacity / three CSS variables are written per frame.
   ============================================================================ */
.howvex--live {
  --hv-top: 84px;      /* the nav pill is 56 tall at top:16 → 72; +12 of air   */
  --hv-gap: 16px;      /* air under the stage                                  */
  --hv-pad: 10px;      /* the bezel                                            */
  --hv-deck: 22px;     /* hinge + deck under the lid                           */
  /* the widest lid whose 16:10 screen still fits the box: cqw / cqh are the
     .hv-laptop container, so this is exact at every stage size (no JS needed) */
  --hv-lid-w: min(94cqw, (100cqh - var(--hv-deck) - 2 * var(--hv-pad) - 2px) * 1.6 + 2 * var(--hv-pad) + 2px);
}
.howvex--live .howvex__track { height: var(--hv-track, 300svh); }
.howvex--live .howvex__stage {
  position: sticky; top: var(--hv-top);
  height: calc(100vh - var(--hv-top) - var(--hv-gap));
  height: calc(100svh - var(--hv-top) - var(--hv-gap));
}
.howvex--live .howvex__grid { display: grid; grid-template-columns: 200px minmax(0, 1fr); gap: var(--spacing-40); height: 100%; align-items: center; }
.howvex--live .howvex__rail { display: flex; flex-direction: column; gap: var(--spacing-24); list-style: none; margin: 0; padding: 0; }
.howvex--live .howvex__step { display: none; }

/* --- the laptop: a flat bezel, a hairline screen edge, a camera dot, a hinge
       and a hint of a deck. Drawn with borders and two flat surfaces only. --- */
.howvex--live .hv-laptop {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  width: 100%; height: 100%; min-height: 0;
  container: hvlaptop / size; perspective: 1400px;
}
.howvex--live .hv-laptop__lid {
  display: block; position: relative; box-sizing: border-box; flex: 0 0 auto;
  width: var(--hv-lid-w); padding: var(--hv-pad);
  background: var(--surface-stage); border: 1px solid var(--hair-2); border-radius: 12px 12px 3px 3px;
  transform-origin: 50% 100%; transform: scale(var(--hv-lid-s, 1)) rotateX(var(--hv-lid-r, 0deg));
  will-change: transform;
}
.howvex--live .hv-laptop__cam { display: block; position: absolute; top: 3px; left: 50%; width: 3px; height: 3px; margin-left: -1.5px; border-radius: 50%; background: var(--hair-2); }
.howvex--live .hv-laptop__screen {
  display: block; position: relative; box-sizing: border-box; width: 100%; aspect-ratio: 16 / 10;
  background: var(--bg); border: 1px solid var(--hair-2); border-radius: 3px; overflow: hidden;
  container: hvscreen / size;
}
.howvex--live .hv-laptop__hinge { display: block; flex: 0 0 auto; width: 16%; height: 4px; box-sizing: border-box; background: var(--surface-stage); border: 1px solid var(--hair-2); border-top: 0; border-radius: 0 0 2px 2px; }
.howvex--live .hv-laptop__deck {
  display: block; position: relative; flex: 0 0 auto; box-sizing: border-box;
  width: calc(var(--hv-lid-w) + 4cqw); height: calc(var(--hv-deck) - 4px);
  background: var(--surface-stage); border: 1px solid var(--hair-2); border-top: 0; border-radius: 2px 2px 9px 9px;
}
.howvex--live .hv-laptop__deck::after { content: ""; position: absolute; left: 50%; bottom: 3px; width: 22%; height: 1px; margin-left: -11%; background: var(--hair-2); }

/* --- the three phases: absolute layers on one canvas, blended by progress.
       flex, not grid: a percentage height on a centred GRID item resolves
       against the item's own intrinsic height in Chrome, which is how the map
       used to grow past a short screen and get its bottom row cut off. --- */
.howvex--live .howvex__canvas { position: relative; width: 100%; height: 100%; }
.howvex--live .howvex__phase { position: absolute; inset: 0; margin: 0; padding: var(--spacing-8); display: flex; align-items: center; justify-content: center; pointer-events: none; will-change: transform, opacity; }
.howvex--live .howvex__phase--card { padding: var(--spacing-12) var(--spacing-8); }
.howvex--live .hv-table { width: min(100%, 720px); max-height: 100%; overflow: hidden; }
/* the box fills the phase; preserveAspectRatio="meet" centres the drawing in it */
.howvex--live .hv-graph { width: min(100%, 720px); height: 100%; margin: 0; }
.howvex--live .hv-graph__svg { width: 100%; height: 100%; }
.howvex--live .hv-graph .e line { stroke-dasharray: 1; stroke-dashoffset: var(--hv-edge, 0); }   /* pathLength="1" is set by JS */
.howvex--live .hv-graph .path { stroke-dasharray: 1; stroke-dashoffset: var(--hv-path, 1); }
.howvex--live .hv-graph .p, .howvex--live .hv-graph .lever, .howvex--live .hv-lbl { opacity: 0; }
.howvex.is-measuring .howvex__phase, .howvex.is-measuring .hv-row { transform: none !important; }   /* JS measures at rest */

/* the rail goes horizontal above the laptop on narrow desktops / tablets */
@media (max-width: 1023px) {
  .howvex--live .howvex__grid { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto minmax(0, 1fr); align-items: stretch; row-gap: var(--spacing-20); }
  .howvex--live .howvex__rail { flex-direction: row; gap: var(--spacing-16); }
  .howvex--live .howvex__rail li { flex: 1 1 0; }
  .howvex--live .hv-step__d { display: none; }
  .howvex--live .hv-row { grid-template-columns: 52px 88px 62px 96px minmax(0, 1fr) 64px 78px; }
  .howvex--live .hv-row > span:nth-child(4) { display: none; }   /* country */
}

/* short and wide (landscape phones, short laptop windows): the 16:10 screen would
   be a postage stamp in a tall empty band, so the lid fills the box instead. */
@media (min-width: 720px) and (max-height: 620px) {
  .howvex--live { --hv-pad: 6px; --hv-deck: 12px; --hv-lid-w: 96cqw; --hv-top: 72px; --hv-gap: 10px; }
  .howvex--live .hv-laptop__lid { flex: 1 1 auto; min-height: 0; border-radius: 8px 8px 2px 2px; }
  .howvex--live .hv-laptop__screen { height: 100%; aspect-ratio: auto; }
  .howvex--live .hv-laptop__cam { top: 1px; width: 2px; height: 2px; margin-left: -1px; }
  /* every px of a 390 px-tall viewport counts: thinner chrome, tighter rail */
  .howvex--live .howvex__grid { row-gap: var(--spacing-8); }
  .howvex--live .hv-step { padding-bottom: 6px; }
  .howvex--live .howvex__phase { padding: var(--spacing-4); }
}

/* --- phones: the same animation, one column, a slim bezel, a shorter sheet.
       DATE · NETWORK · ECPM · REVENUE — the .howvex--live selector is repeated so
       these beat the tablet rules above, which are more specific. --- */
@media (max-width: 719px) {
  .hv-row, .howvex--live .hv-row { grid-template-columns: 48px minmax(0, 1fr) 58px 68px; column-gap: var(--spacing-4); }
  .hv-row > span:nth-child(3), .hv-row > span:nth-child(4), .hv-row > span:nth-child(5), .hv-row > span:nth-child(6) { display: none; }
  .hv-card { padding: var(--spacing-20); }

  .howvex--live { --hv-top: 76px; --hv-gap: 12px; --hv-pad: 5px; --hv-deck: 14px; --hv-lid-w: 94cqw; }
  .howvex--live .howvex__grid { row-gap: var(--spacing-16); }
  .howvex--live .howvex__rail { gap: var(--spacing-8); }
  .howvex--live .hv-step { padding-bottom: var(--spacing-8); }
  /* three steps have to sit inside 342 px: 10 px mono, tighter tracking, no wrap */
  .howvex--live .hv-step__k, .howvex--live .hv-step__t { font-size: 10px; letter-spacing: 0.04em; }
  .howvex--live .hv-step__k { margin-right: 3px; }
  .howvex--live .hv-step > span { white-space: nowrap; }
  /* the lid fills the portrait box — a 16:10 letterbox here would be 200 px tall */
  .howvex--live .hv-laptop__lid { flex: 1 1 auto; min-height: 0; border-radius: 8px 8px 2px 2px; }
  .howvex--live .hv-laptop__screen { height: 100%; aspect-ratio: auto; border-radius: 2px; }
  .howvex--live .hv-laptop__cam { top: 1px; width: 2px; height: 2px; margin-left: -1px; }
  .howvex--live .hv-laptop__deck { border-radius: 2px 2px 6px 6px; }
  .howvex--live .howvex__phase { padding: var(--spacing-4); }
  .howvex--live .hv-table { font-size: 12px; }
  .howvex--live .hv-row { height: 34px; }
  .howvex--live .hv-rows > .hv-row:nth-child(n+10) { display: none; }   /* 9 of the 12 rows */
  /* the map is rendered about half size here: let it bleed past the phase (the
     bezel clips it) so it is 20 % bigger, and thicken every stroke so it reads */
  .howvex--live .hv-graph { flex: none; width: 120%; max-width: none; margin-inline: -10%; }
  .howvex--live .hv-graph .e line { stroke-width: 2; }
  .howvex--live .hv-graph .path { stroke-width: 4; }
  .howvex--live .hv-graph .n circle { r: 5.5; }
  .howvex--live .hv-graph .p { r: 10; }
  .howvex--live .hv-graph .lever { width: 20px; height: 20px; }
  .howvex--live .hv-card { padding: var(--spacing-16); }
  .howvex--live .hv-card__money { font-size: 19px; }
  .howvex--live .hv-card__lede { font-size: 15px; }
  .howvex--live .hv-card__action { font-size: 15px; }
  .howvex--live .hv-card__why { font-size: 13px; }
}

/* under 420 px the four map labels use their short setting */
@media (max-width: 420px) { .hv-lbl b { display: none; } .hv-lbl i { display: inline; } }

/* ============================================================================
   How dense the content gets is a question about the SCREEN box, not the window
   — a 1024×768 desktop and a landscape phone can hand the same screen height.
   Last in the file on purpose: the screen is the real constraint, so these win.
   ============================================================================ */
/* the sheet: how many rows fit */
@container hvscreen (max-height: 470px) { .howvex--live .hv-rows > .hv-row:nth-child(n+11) { display: none; } }
@container hvscreen (max-height: 400px) { .howvex--live .hv-rows > .hv-row:nth-child(n+9)  { display: none; } }
@container hvscreen (max-height: 330px) { .howvex--live .hv-rows > .hv-row:nth-child(n+7)  { display: none; } }

/* the card: tighten before anything is dropped */
@container hvscreen (max-height: 560px) {
  .howvex--live .hv-card { padding: var(--spacing-20); }
  .howvex--live .hv-card > * + * { margin-top: var(--spacing-8); }
  .howvex--live .hv-card__action, .howvex--live .hv-card__foot { margin-top: var(--spacing-12); }
}
@container hvscreen (max-height: 470px) {
  .howvex--live .hv-card { padding: var(--spacing-16); }
  .howvex--live .hv-card__money { font-size: 20px; }
  .howvex--live .hv-card__lede, .howvex--live .hv-card__action { font-size: 15px; }
  .howvex--live .hv-card__why { font-size: 13px; }
  .howvex--live .hv-card__jobs { display: none; }
}
@container hvscreen (max-height: 400px) {
  .howvex--live .hv-card__why { display: none; }
  .howvex--live .hv-card__action { font-size: 14px; }
  .howvex--live .hv-card__foot { padding-top: var(--spacing-8); }
}
/* a narrow AND short screen (a small phone) wraps every line two or three times
   over, so the reasoning step goes before the card would be clipped */
@container hvscreen (max-width: 420px) and (max-height: 620px) {
  .howvex--live .hv-card { padding: var(--spacing-16); }
  .howvex--live .hv-card > * + * { margin-top: var(--spacing-8); }
  .howvex--live .hv-card__money { font-size: 18px; }
  .howvex--live .hv-card__lede, .howvex--live .hv-card__action { font-size: 14px; }
  .howvex--live .hv-card__jobs { display: none; }
}
@container hvscreen (max-width: 420px) and (max-height: 520px) { .howvex--live .hv-card__why { display: none; } }
/* landscape phones and very short laptop windows: about 200 px of screen. The
   sheet loses its caption and half its rows, the card keeps what broke, what it
   costs and what to do — the four jobs line and the reasoning step out. */
@container hvscreen (max-height: 250px) {
  .howvex--live .hv-rows > .hv-row:nth-child(n+6) { display: none; }
  .howvex--live .hv-row, .howvex--live .hv-row--head { height: 26px; }
  .howvex--live .hv-table { padding: var(--spacing-4) var(--spacing-12) var(--spacing-8); font-size: 12px; }
  .howvex--live .hv-table__cap { display: none; }
  .howvex--live .hv-card { padding: var(--spacing-12) var(--spacing-16); }
  .howvex--live .hv-card__money { font-size: 18px; margin-top: var(--spacing-4); }
  .howvex--live .hv-card__head { margin-top: var(--spacing-4); }
  .howvex--live .hv-card__lede { font-size: 14px; }
  .howvex--live .hv-card__action { padding: var(--spacing-8) var(--spacing-12); }
  .howvex--live .hv-card__jobs, .howvex--live .hv-card__foot { display: none; }
}
@container hvscreen (max-height: 200px) {
  .howvex--live .hv-rows > .hv-row:nth-child(n+5) { display: none; }
  .howvex--live .hv-card__tag { display: none; }
  .howvex--live .hv-card__foot { display: none; }
}
@container hvscreen (max-width: 480px) { .howvex--live .hv-table { font-size: 12px; } }

/* --- reduced motion / #noanim: no live mode (JS never adds the class), and nothing waits on a transition --- */
@media (prefers-reduced-motion: reduce) { .hv-step { transition: none; } }
.no-anim .hv-step { transition: none; }
