/* AUGGY visual layer.
 *
 * The protected motion foundation remains structural authority: one fixed
 * viewer, one persistent film, one fixed HUD and twelve native snap markers.
 * This file designs around the approved LARGE, SMALL_TOP and CTA poses.
 */

:root {
  color-scheme: dark;

  --sc-canvas:     #03081b;
  --sc-surface:    #111a3c;
  --sc-ink:        #f7f0e4;
  --sc-ink-soft:   #c7b9cf;
  --sc-accent:     #f0c24b;
  --sc-accent-ink: #17100a;

  --aw-ground:       #03081b;
  --aw-ground-deep:  #03081b;
  --aw-violet:       #582bc6;
  --aw-violet-soft:  #7b50de;
  --aw-lavender:     #cdbdff;
  --aw-lavender-soft: #aa9ac7;
  --aw-gold:         #ffc928;
  --aw-gold-bright:  #ffe36c;
  --aw-gold-muted:   #d39a1c;
  --aw-neon:         rgb(0, 255, 0);
  --aw-ivory:        #f7f0e4;
  --aw-ivory-soft:   #c7b9cf;
  --aw-rule:         rgba(240, 194, 75, 0.38);
  --aw-rule-soft:    rgba(247, 240, 228, 0.14);

  --sc-font-display: Impact, Haettenschweiler, "Arial Narrow Bold", "Arial Black", sans-serif;
  --sc-font-text: "Trebuchet MS", "Arial Rounded MT Bold", Arial, system-ui, sans-serif;
  --aw-font-mechanics: Impact, Haettenschweiler, "Arial Narrow Bold", "Arial Black", sans-serif;
  --aw-font-code: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;

  /* ------------------------------------------------------------ layout --
   * Four tokens carry every composition on the site. The media queries at the
   * end of this file re-value THESE; they do not re-author layouts.
   *
   *   gutter        the left inset of every left-anchored composition
   *   rail-clear    reserved on the right for the waypoint rail
   *   bottom-clear  reserved underneath for the mobile navigation bar
   *   topbar-clear  reserved on top for persistent SCROLL + contract */
  --aw-gutter:       clamp(1rem, 4vw, 5rem);
  /* 8.5rem rail + 0.75rem padding + 3px rule + 1rem inset, plus room for a
     classic scrollbar: vw includes the scrollbar but an element's right
     edge does not, and 1000px-wide windows were losing that difference. */
  --aw-rail-clear:   12rem;
  --aw-bottom-clear: max(2rem, calc(1.25rem + env(safe-area-inset-bottom)));
  --aw-topbar-clear: calc(max(0.7rem, env(safe-area-inset-top)) + 2.9rem);

  /* ------------------------------------------------- film geometry -- *
   * The picture's own horizontal geometry, published so a composition can be
   * anchored to the FILM rather than to the viewport edge.
   *
   * These restate, in CSS custom properties, exactly what .aw-film already
   * computes for itself further down: full viewport height, width derived
   * from the declared 4:3 ratio, horizontally centred. They are a read of
   * that geometry, never an input to it - nothing about the video's size or
   * position is driven from here.
   *
   * No pose scales or translates the film horizontally (POSES in auggy.js:
   * every entry is s:1, tx:0), so the film's left edge is a pure function of
   * viewport height and width and needs no per-station term.
   *
   * On a viewport NARROWER than 4:3 the film is wider than the screen and
   * --aw-film-left goes negative: that is the real geometry, and any consumer
   * must floor it against --aw-gutter rather than follow it off-screen. */
  --aw-film-width: calc(100vh * 4 / 3);
  --aw-film-left:  calc(50vw - var(--aw-film-width) / 2);

  /* ---------------------------------------------- film-relative hero -- *
   * The anchor every bottom-left hero on the site shares: pages 9, 10, 11
   * and the closing BUY state. Declared once so "the same film-relative
   * placement logic" is literally one expression rather than four copies
   * that can drift.
   *
   * The formula that consumes this is on .aw-ov, not here - see the note
   * there. max() is what selects the two behaviours, with no breakpoint: above a
   * 4:3 viewport the film fits and the hero follows its left edge; below it
   * --aw-film-left is negative and the gutter wins, which is exactly the safe
   * portrait inset those states had before. The switch therefore lands at the
   * aspect where the film stops fitting rather than at an orientation flip. */
  --aw-hero-inset: clamp(1.25rem, 3.4svh, 3.25rem);

  /* -------------------------------------------------------- type scale --
   * See the typography note further down. Height-led, width-bounded,
   * floor-clamped. Nothing below this line re-declares a font-size against a
   * breakpoint. */
  --aw-t-hero:    clamp(3.25rem,   min(15.5svh + 0.7vw,  20vw),   15rem);
  --aw-t-display: clamp(2.35rem,   min(8.4svh  + 0.6vw,  11.5vw), 8.5rem);
  --aw-t-mega:    clamp(3rem,      min(13svh   + 0.8vw,  26vw),   13rem);
  --aw-t-figure:  clamp(2rem,      min(7.4svh  + 0.5vw,  13vw),   6rem);
  --aw-t-chip:    clamp(1.25rem,   min(3.6svh  + 0.3vw,  6.5vw),  2.7rem);
  --aw-t-lead:    clamp(1.0625rem, min(2.15svh + 0.25vw, 4.6vw),  1.9rem);
  --aw-t-body:    clamp(1rem,      min(1.9svh  + 0.2vw,  4.2vw),  1.6rem);
  --aw-t-tag:     clamp(0.95rem,   min(1.75svh + 0.18vw, 3.9vw),  1.5rem);
  --aw-t-micro:   clamp(0.8rem,    min(1.45svh + 0.14vw, 3.4vw),  1.15rem);

  /* ----------------------------------------------------- readability -- *
   * A TIGHT #03081B edge, not a floating black glow. Eight one-pixel offsets
   * make a continuous outline in the site's own ground colour; one short,
   * low-opacity blur seats the glyph on the film without tinting the film.
   * The previous mobile-only treatment layered 8px and 18px black blurs and
   * read as haze; it is gone, and this is applied on every viewport instead
   * so mobile and desktop finally match. */
  --aw-halo:
     1px  1px 0 var(--aw-ground),
    -1px  1px 0 var(--aw-ground),
     1px -1px 0 var(--aw-ground),
    -1px -1px 0 var(--aw-ground),
     0    1px 0 var(--aw-ground),
     0   -1px 0 var(--aw-ground),
     1px  0    0 var(--aw-ground),
    -1px  0    0 var(--aw-ground),
     0    2px 5px rgba(3, 8, 27, 0.5);

  /* ------------------------------------------------ display shadow -- *
   * The shadow system approved on the START hero, lifted verbatim so any
   * other display headline can reuse the SAME values rather than a lookalike.
   * Reading outward from the glyph: the shared #03081B contact ring, the
   * violet dimensional extrusion, then --aw-hero-cast furthest back.
   *
   * --aw-hero-cast is the Photoshop drop shadow transcribed: #03081B at 100%,
   * angle 133deg, distance 30px, blur 90px, spread ~3%, measured against the
   * 271px desktop START hero and expressed in em so it scales with whatever
   * font-size it lands on. Photoshop's angle is where the LIGHT is, so the
   * shadow travels 133+180 = 313deg: dx = -30*cos(133deg) = +20.5px =
   * 0.076em, dy = +30*sin(133deg) = +21.9px = 0.081em, blur = 90px = 0.332em.
   * CSS text-shadow has no spread, so the 3% is approximated by stacking the
   * same offset at tighter blurs - each pass composites, densifying the core
   * while the outer falloff stays soft. The doubled first pass is what carries
   * 100% opacity through a 90px blur. */
  --aw-hero-cast:
    0.076em 0.081em 0.332em var(--aw-ground),
    0.076em 0.081em 0.332em var(--aw-ground),
    0.076em 0.081em 0.244em var(--aw-ground),
    0.076em 0.081em 0.166em var(--aw-ground);

  --aw-halo-display:
     2px  2px 0 var(--aw-ground),
    -2px  2px 0 var(--aw-ground),
     2px -2px 0 var(--aw-ground),
    -2px -2px 0 var(--aw-ground),
     0    2px 0 var(--aw-ground),
     0   -2px 0 var(--aw-ground),
     2px  0    0 var(--aw-ground),
    -2px  0    0 var(--aw-ground),
     0    3px 8px rgba(3, 8, 27, 0.45);

  /* The whole approved stack, in paint order (first layer sits on top). */
  --aw-display-shadow:
    var(--aw-halo-display),
    0.055em 0.055em 0 var(--aw-violet),
    var(--aw-hero-cast);

  /* Written by the protected Pose controller. */
  --vs: 1;
  --vtx: 0px;
  --vty: 0px;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  width: 100%;
  background: var(--aw-ground);
  scroll-snap-type: y mandatory;
  overscroll-behavior-y: none;
  overflow-x: clip;
  scroll-behavior: auto;
}

body {
  width: 100%;
  min-width: 0;
  margin: 0;
  overflow-x: clip;
  background: var(--aw-ground);
  color: var(--aw-ivory);
  font-family: var(--sc-font-text);
  font-synthesis: none;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  overscroll-behavior-y: none;
}

::selection {
  color: var(--sc-accent-ink);
  background: var(--aw-gold);
}

html.is-locked,
html.is-locked body {
  touch-action: none;
}

/* --------------------------------------------------------------- track -- */
.aw-track {
  position: relative;
  z-index: 0;
  pointer-events: none;
}

.aw-marker {
  height: 100vh;
  height: 100svh;
  scroll-snap-align: start;
  scroll-snap-stop: always;
}

/* --------------------------------------------------------------- stage -- */
.aw-stage {
  position: fixed;
  inset: 0;
  z-index: 1;
  overflow: hidden;
  background: #03081b;
  pointer-events: none;
}

.aw-viewer {
  position: absolute;
  inset: 0;
  z-index: 1;
  transform-origin: 50% 50%;
  transform: translate3d(var(--vtx), var(--vty), 0) scale(var(--vs));
  will-change: transform;
  backface-visibility: hidden;
}

/* GEOMETRY: the video's HEIGHT is authoritative.
 *
 * Before, this was `inset:0; width:100%; height:100%; object-fit:contain`, i.e.
 * a viewport-shaped box with the 4:3 frame letterboxed inside it. The rendered
 * media rectangle was therefore min(vw, vh*4/3) x min(vh, vw*3/4) and WIDTH was
 * in the formula: measured at a constant viewport height of 857px, a 1909px
 * viewport rendered the film 1142.67 x 857 while a 989px viewport rendered it
 * 989 x 741.75. Narrowing the window shrank the picture. That is the reported
 * defect.
 *
 * Now the element IS the media rectangle: full viewport height, width derived
 * from the 4:3 ratio, centred. Viewport width no longer appears anywhere in the
 * sizing, so it cannot change the picture; it only changes how much ground is
 * left beside it.
 *
 * aspect-ratio is declared rather than inferred from the file so the box is
 * correct before metadata arrives and stays independent of the encode.
 * object-fit stays `contain` (never `cover`): the box is already exactly 4:3,
 * so it is a no-op today and a guarantee against distortion if the encode ever
 * changes.
 *
 * Consequence, by design: on a viewport NARROWER than 4:3 the film is wider
 * than the screen and is clipped left and right by .aw-stage's overflow:hidden.
 * That is the accepted trade for a picture that never resizes.
 *
 * ONE MODEL, EVERY VIEWPORT. There is deliberately no portrait variant. An
 * earlier pass carried a portrait fallback that restored the old
 * width-constrained contain behaviour; it was rejected on review, because it
 * meant a phone got a different picture from a desktop. A 390x844 portrait
 * viewport now renders the film at 1125x844, full height and horizontally
 * cropped, rather than shrinking it to 390x293. The crop is the intent.
 *
 * If a portrait rule is ever added back here, it will silently reintroduce
 * width-dependent sizing on phones. */
.aw-film {
  position: absolute;
  top: 0;
  left: 50%;
  height: 100%;
  width: auto;
  aspect-ratio: 4 / 3;
  /* scrollcraft.css sets `img, video, canvas, svg { max-width: 100% }`. On a
     viewport narrower than 4:3 that silently clamps this box back to the
     viewport width and reintroduces exactly the width-dependence this rule
     exists to remove: measured 1189x891.75 instead of 1200x900 at a 1189x900
     viewport. The engine file is not edited; the cap is lifted here. */
  max-width: none;
  translate: -50% 0;
  display: block;
  object-fit: contain;
  background: transparent;
  opacity: 1;
  filter: none;
}

/* ----------------------------------------------------------------- HUD -- */
.aw-hud {
  position: fixed;
  inset: 0;
  z-index: 2;
  display: grid;
  min-width: 0;
  pointer-events: none;
}

.aw-ov {
  /* The shared film-relative anchor, resolved PER STATE.
   *
   * The max() and the geometry behind it are described with --aw-hero-inset
   * in :root. The formula is declared here rather than there because a custom
   * property is substituted at the element that declares it: computing this
   * on :root would bake in the root inset, and a state that wants a different
   * one - the closing CTA does - could never reach it. Declared on .aw-ov, it
   * recomputes against whatever --aw-hero-inset each state carries, and the
   * expression itself still exists exactly once. */
  --aw-hero-start: max(
    var(--aw-gutter),
    calc(var(--aw-film-left) + var(--aw-hero-inset)));

  grid-area: 1 / 1;
  position: relative;
  min-width: 0;
  width: min(34rem, calc(100vw - 3rem));
  margin: 0;
  padding: 0;
  opacity: 0;
  visibility: hidden;
  transform: translate3d(0, 14px, 0);
  transition: opacity 280ms ease, transform 280ms ease, visibility 0s linear 280ms;
  pointer-events: none;
  background: transparent;
}

.aw-ov[data-active] {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: opacity 300ms ease 70ms, transform 300ms ease 70ms, visibility 0s;
  pointer-events: auto;
}

/* Authored film transitions remain pure world. */
html.is-locked .aw-ov[data-active] {
  opacity: 0;
  transform: translate3d(0, 8px, 0);
  pointer-events: none;
  transition: opacity 200ms ease, transform 200ms ease;
}

/* ...except on a TRANSIENT BEAT, which is never landed on.
 *
 * Stations 1 and 2 are played through: one forward gesture at START runs
 * 31->62, 62->93 and 93->154 back to back without releasing the lock, and one
 * reverse gesture at GOLD beats back through them. The rule above exists so
 * copy never sits on top of a moving authored range, but a beat that is only
 * ever mid-transition would then never be readable at all, and the sequence
 * would read as a skip rather than a progression.
 *
 * So the blackout is lifted for exactly those states: `is-beat` is written by
 * setOverlay() from the TRANSIENT table in auggy.js and is present only while
 * a chain is passing through. Every landing state keeps the blackout.
 *
 * pointer-events stays off: the chain owns the input for its duration and a
 * beat has nothing to click. */
html.is-locked.is-beat .aw-ov[data-active] {
  opacity: 1;
  transform: none;
  pointer-events: none;
  transition: opacity 300ms ease 70ms, transform 300ms ease 70ms, visibility 0s;
}

/* =========================================================== typography ==
 *
 * ONE fluid scale for the whole site, driven mainly by viewport HEIGHT.
 *
 * Height-led is the point. The film is height-authoritative and horizontally
 * centred, so a 2560x1080 window is the SAME composition as a 1920x1080 one
 * and must get the same type size. The previous width-led scale gave wide
 * screens laptop-sized headings floating in empty space, and rem caps stopped
 * display type growing on tall screens at all.
 *
 * Every step is min()-bounded by a vw term, so a phone never inherits a
 * height-derived size too wide for its screen, and clamp()-floored, so a
 * landscape phone never gets microscopic body text. There are no
 * breakpoint-specific font sizes anywhere below: scale is continuous. */

.aw-ov h1,
.aw-ov h2,
.aw-ov h3,
.aw-ov p,
.aw-ov dl,
.aw-ov dd,
.aw-ov dt,
.aw-ov ul {
  margin-block-start: 0;
}

.aw-ov h1,
.aw-ov h2 {
  margin-block-end: clamp(0.5rem, 1.4svh, 1.1rem);
  color: var(--aw-ivory);
  font-family: var(--sc-font-display);
  font-weight: 900;
  letter-spacing: -0.025em;
  line-height: 0.88;
  text-transform: uppercase;
  text-wrap: balance;
}

.aw-ov h2 {
  max-width: 15ch;
  font-size: var(--aw-t-display);
  text-shadow: var(--aw-halo-display), 0.06em 0.06em 0 var(--aw-violet);
}

/* ------------------------------------------------------------- eyebrow -- *
 * The tag. A solid gold chip, so it needs no halo: it is already a box. */
.aw-eyebrow {
  display: inline-block;
  width: fit-content;
  margin-block-end: clamp(0.5rem, 1.5svh, 1.1rem);
  padding: 0.34em 0.62em 0.26em;
  color: var(--aw-ground);
  background: var(--aw-gold);
  font-family: var(--sc-font-text);
  font-size: var(--aw-t-tag);
  font-weight: 900;
  letter-spacing: 0.055em;
  line-height: 1.15;
  text-transform: uppercase;
  text-shadow: none;
  transform: rotate(-1deg);
}

.aw-eyebrow.aw-eyebrow--chain {
  font-family: var(--sc-font-display);
  font-size: var(--aw-t-lead);
  letter-spacing: 0.03em;
  line-height: 1;
}

/* The CREATE chapter label. The decorative rule that used to trail it is
   gone; every ornamental horizontal line on the site went with it. */
.aw-chapter {
  width: fit-content;
  margin-block-end: clamp(0.4rem, 1.2svh, 0.9rem);
  color: var(--aw-gold-bright);
  font-family: var(--sc-font-text);
  font-size: var(--aw-t-tag);
  font-weight: 900;
  letter-spacing: 0.055em;
  line-height: 1.2;
  text-transform: uppercase;
  text-shadow: var(--aw-halo);
}

.aw-lede {
  max-width: 40ch;
  margin-block-end: 0;
  color: var(--aw-lavender);
  font-size: var(--aw-t-lead);
  font-weight: 700;
  line-height: 1.45;
  text-shadow: var(--aw-halo);
}

.aw-secondary {
  max-width: 42ch;
  margin-block-end: 0;
  color: var(--aw-lavender-soft);
  font-size: var(--aw-t-body);
  font-weight: 700;
  line-height: 1.45;
  text-shadow: var(--aw-halo);
}

/* The bright green $ has to survive gold and white film areas. A tight
   #03081B stroke is painted UNDER the fill where paint-order is supported,
   with a one-pixel #03081B ring as the universal floor. */
.aw-dollar {
  color: var(--aw-neon);
  paint-order: stroke fill;
  -webkit-text-stroke: 0.05em var(--aw-ground);
  text-shadow: var(--aw-halo);
}

.aw-bound-text .aw-dollar,
.aw-eyebrow .aw-dollar,
.aw-action .aw-dollar {
  text-shadow: none;
}

/* The ticker keeps its authored casing wherever it appears, including inside
   an uppercase display heading. */
[data-auggy-value="ticker"],
[data-auggy-value="eligibility.minimum"] {
  text-transform: none;
}

/* Gold-highlighted run of hero copy. A solid chip, so no halo. */
.aw-bound-text {
  padding: 0.08em 0.28em 0.13em;
  color: var(--aw-ground);
  font-weight: 900;
  line-height: 1.5;
  text-shadow: none;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}

.aw-bound-text--gold {
  background: var(--aw-gold);
}

/* ============================================================== states ==
 *
 * Two compositions only, and both are viewport-anchored rather than authored
 * per breakpoint:
 *
 *   .aw-ov--story  bottom-left, LEFT aligned. States 0, 1, 2, 7.
 *   .aw-ov--data   bottom-centred data presentation. States 3, 4, 5, 6.
 *
 * Both reserve --aw-rail-clear on the right so they can never reach the
 * waypoint rail, and --aw-bottom-clear underneath so they can never reach the
 * mobile navigation bar. Neither changes composition at a breakpoint; only
 * the two tokens change. */
.aw-ov--story {
  align-self: end;
  justify-self: start;
  width: min(54rem, calc(100vw - var(--aw-gutter) - var(--aw-rail-clear)));
  margin-block-end: var(--aw-bottom-clear);
  margin-inline-start: var(--aw-gutter);
}

.aw-copy {
  display: grid;
  justify-items: start;
  gap: 0;
  max-width: 100%;
  text-align: start;
}

/* START hero. The only element on the site using --aw-t-hero, so scaling it
   here scales nothing else. 1.5x the shared step, still the same fluid,
   height-led clamp underneath: no fixed pixel size anywhere.
 *
 * TWO SEPARATE EFFECTS, layered, reading outward from the glyph:
 *
 *   1. the original brand treatment - the shared #03081B contact ring plus the
 *      violet dimensional extrusion - closest to the cream letterform;
 *   2. --aw-hero-cast behind it: one large, soft, fully opaque #03081B drop
 *      that separates the hero from bright film without outlining it.
 *
 * text-shadow paints the first layer on top, so the order below IS the
 * stacking order: ring, then violet, then the navy cast furthest back. */
.aw-hero-title {
  margin-block-end: clamp(0.35rem, 1svh, 0.75rem);
  color: var(--aw-gold-bright);
  font-size: calc(var(--aw-t-hero) * 1.5);
  font-weight: 900;
  line-height: 0.74;
  letter-spacing: -0.045em;
  text-shadow: var(--aw-display-shadow);
}

/* The green $ keeps the sitewide .aw-dollar brand edge it has always had -
   inherited, not restated here - and gains the same navy cast behind it, so
   both glyph colours sit on one separation zone. No stroke is set here, so
   nothing overrides that brand edge. */
.aw-hero-title .aw-dollar {
  text-shadow:
    var(--aw-halo),
    var(--aw-hero-cast);
}

/* ==================================================== state 3: THE TAX ==
 *
 * One statement, not a split table. The old treatment set BUY TAX / SELL TAX
 * as tag-sized captions over two grid columns, so the page read as four small
 * fragments; this is a single centred display line where the words and the
 * numbers are the same size and only the colour separates them.
 *
 * It wraps rather than shrinking: one line across on a desktop, two centred
 * rows on a phone, which is the balanced answer at that width. */
.aw-ov[data-overlay-for="tax-2"] .aw-eyebrow {
  margin-block-end: clamp(0.85rem, 2.6svh, 1.9rem);
  font-size: calc(var(--aw-t-tag) * 1.6);
}

.aw-ov[data-overlay-for="tax-1"] .aw-eyebrow {
  margin-block-end: clamp(0.85rem, 2.6svh, 1.9rem);
  font-size: calc(var(--aw-t-tag) * 1.6);
}

.aw-tax-line {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: center;
  column-gap: 0.85em;
  row-gap: 0.12em;
  margin: 0;
  color: var(--aw-ivory);
  font-family: var(--sc-font-display);
  font-size: calc(var(--aw-t-display) * 1.3);
  font-weight: 900;
  letter-spacing: -0.025em;
  line-height: 0.92;
  text-transform: uppercase;
  /* the same approved stack as every other display headline */
  text-shadow: var(--aw-display-shadow);
}

/* ============================================ state 6: FOR EXAMPLE ==
 *
 * Hierarchy the page asked for, top to bottom: the buy size is the largest
 * thing on the screen, the total and the breakdown share one size, and the
 * label sits BESIDE its amount rather than under it - so each pair reads as
 * a single phrase, "$24 HOLDERS", in one font at one size.
 *
 * --aw-example-figure is declared once and used by both the total and the
 * breakdown, which is what keeps those two locked to the same size. */
.aw-ov[data-overlay-for="tax-4"] .aw-data {
  --aw-example-figure: calc(var(--aw-t-display) * 0.62);
}

/* A tag, not a headline - and the gap under it is what separates the label
   from the number rather than sheer size. */
.aw-ov[data-overlay-for="tax-4"] .aw-eyebrow {
  margin-block-end: clamp(1rem, 3.2svh, 2.4rem);
  font-size: calc(var(--aw-t-tag) * 1.3);
}

/* Dominant but not crushing: at 1.35x it left nothing underneath room to
   breathe, so it steps back to 1.15x and the space it frees goes into the
   gaps below rather than into more type. */
.aw-ov[data-overlay-for="tax-4"] .aw-figure-chip {
  margin-block-end: clamp(1rem, 3.2svh, 2.4rem);
  font-size: calc(var(--aw-t-display) * 1.15);
}

.aw-ov[data-overlay-for="tax-4"] h2 {
  max-width: none;
  margin-block-end: clamp(0.9rem, 2.8svh, 2rem);
  font-size: var(--aw-example-figure);
}

/* Amount and label sit close enough to read as one phrase but never merge. */
.aw-ov[data-overlay-for="tax-4"] .aw-tax-pair {
  gap: 0.34em;
}

/* Two rows of two, sized to their content and centred as one block, with the
   pairs left-aligned inside their column so the two columns line up. */
.aw-example-grid {
  display: grid;
  grid-template-columns: auto auto;
  justify-content: center;
  justify-items: start;
  column-gap: 1.15em;
  row-gap: 0.34em;
  margin: 0;
  color: var(--aw-ivory);
  font-family: var(--sc-font-display);
  font-size: var(--aw-example-figure);
  font-weight: 900;
  letter-spacing: -0.025em;
  line-height: 0.95;
  text-transform: uppercase;
  text-shadow: var(--aw-display-shadow);
}

/* Page 6 reuses the same line component with three pairs instead of two, so
   it steps down a little to keep them on one row; the pairs themselves never
   break, and the wrap is only ever reached on a phone. */
.aw-ov[data-overlay-for="tax-3"] .aw-tax-line {
  /* Three pairs instead of two, so the gap tightens rather than the type
     shrinking: at 0.85em the row filled 1164 of its 1184 container at
     2560x1080, which is too close to wrapping to trust. */
  column-gap: 0.6em;
  margin-block-start: clamp(0.5rem, 1.6svh, 1.1rem);
  font-size: calc(var(--aw-t-display) * 1.05);
}

/* A word and its rate stay together on one line; only the pairs may wrap. */
.aw-tax-pair {
  display: inline-flex;
  align-items: baseline;
  gap: 0.24em;
  white-space: nowrap;
}

/* ============ states 1 and 2: THE REWARD / WHAT GOLD MEANS ==
 *
 * The two-line story heroes. Scoped by station key, so nothing here reaches
 * any other state, and shared between the two so they are provably the same
 * treatment rather than two lookalikes.
 *
 * Both step up to 1.45x the shared display step - still the same fluid,
 * height-led clamp underneath, no fixed pixel size - and both take the
 * approved START shadow stack verbatim through --aw-display-shadow. */
.aw-ov[data-overlay-for="beat-1"] h2,
.aw-ov[data-overlay-for="beat-2"] h2 {
  max-width: none;
  font-size: calc(var(--aw-t-display) * 1.45);
  text-shadow: var(--aw-display-shadow);
}

/* The two lines are authored blocks rather than a wrap, so the structure is
   the same at every viewport and the gap between them is explicit.
 *
 * Spacing has to clear the SHADOW, not just the glyphs. Line one's ink runs
 * about 0.21em below its baseline, the violet extrusion adds another 0.055em
 * under that, so the lines need more than ~1em of advance before they stop
 * touching; the inherited 0.88em was under that, which is why $Auggy was
 * being buried by EARN GOLD. 0.92em of leading plus 0.2em of margin gives
 * 1.12em - clear separation with the composition still tight. */
.aw-ov[data-overlay-for="beat-1"] h2 .aw-line,
.aw-ov[data-overlay-for="beat-2"] h2 .aw-line {
  display: block;
  line-height: 0.92;
}

.aw-ov[data-overlay-for="beat-1"] h2 .aw-line + .aw-line,
.aw-ov[data-overlay-for="beat-2"] h2 .aw-line + .aw-line {
  margin-block-start: 0.2em;
}

/* ---- state 1 only: one rhythm whether the first block wraps or not -------
 *
 * Page 2 is the one hero whose first block can break. "HOLD $Auggy." sits on
 * one line while the container is wide enough for it (2560, 1920, 1440, 430
 * and 390 all are), and breaks to HOLD / $Auggy. on a narrower or taller
 * window. When it breaks, the gap inside the block is pure leading - 0.92em -
 * while the gap to EARN GOLD. is leading plus margin, 1.12em. Two different
 * gaps in one three-line hero, and at 0.92em the first one is not a gap at
 * all: HOLD's violet extrusion lands about 0.03em INSIDE the top of the $.
 *
 * So the advance is set once and then split, and the two advances are not
 * equal on purpose:
 *
 *   HOLD -> $Auggy.       1.076em   line-height alone (the wrap)
 *   $Auggy. -> EARN GOLD. 1.120em   line-height + 0.044em margin
 *
 * The 0.044em is the optical correction. The ink either side of each gap is
 * not the same: HOLD ends 0.017em under its baseline and $Auggy. starts
 * 0.858em over its own (the $ overshoots the caps), while $Auggy. ends
 * 0.112em under (g and y) and EARN GOLD. starts 0.807em over. Add the 0.055em
 * violet extrusion to both lower edges and the second pair of edges is
 * 0.044em closer together than the first at the same advance. Giving that
 * gap 0.044em more box spacing is what makes the two read as the same gap.
 *
 * 1.120em for the second advance is the value this file already used and
 * already justified above, so the measured spacing under EARN GOLD., under
 * THE REWARD and around the support line is unchanged at every viewport; the
 * first gap is the only one that moves, and it moves up to meet it. The h2
 * margins below absorb the half-leading the taller line boxes add (0.156em,
 * so 0.078em at each end) - without that, the whole block would drift up and
 * open the eyebrow and support-line gaps by that much. */
.aw-ov[data-overlay-for="beat-1"] h2 .aw-line {
  line-height: 1.076;
}

.aw-ov[data-overlay-for="beat-1"] h2 .aw-line + .aw-line {
  margin-block-start: 0.044em;
}

.aw-ov[data-overlay-for="beat-1"] h2 {
  margin-block-start: -0.078em;
  margin-block-end: max(0px, calc(clamp(0.5rem, 1.4svh, 1.1rem) - 0.078em));
}

/* ---- state 2 only: the same rhythm, with the break in the other block ---
 *
 * Page 3 has state 1's problem mirrored. Here it is the SECOND block that can
 * break: "TETHER GOLD." sits on one line while the container is wide enough
 * (2560, 1920, 1440, 430 and 390 all are) and breaks to TETHER / GOLD. on a
 * narrower or taller window. So the wide gap is the authored one and the tight
 * one is the wrap, the opposite way round from state 1:
 *
 *   XAUT IS -> TETHER   1.12em   line-height + 0.2em margin
 *   TETHER -> GOLD.     0.92em   line-height alone (the wrap)
 *
 * and at 0.92em the second gap nearly closes: about 0.038em of daylight
 * against 0.238em above it, six times the space in one three-line hero, with
 * TETHER's violet extrusion sitting on the caps of GOLD.
 *
 * Unlike state 1 this needs NO optical correction, and the metrics say why.
 * Either side of the first gap: XAUT IS ends 0.017em under its baseline (the
 * S overshoots) and TETHER starts 0.791em over its own - flat caps, no round
 * letter at full height. Either side of the second: TETHER ends exactly ON
 * its baseline and GOLD. starts 0.807em over (the O overshoots). Both pairs
 * of ink edges sum to 0.807em, the round-letter overshoot moving from the
 * bottom edge to the top edge and cancelling itself, so one advance for both
 * gaps is already optically equal and no margin has to make up a difference.
 *
 * 1.12em is that advance: the value this file already used and justified for
 * the authored gap, so the spacing under GOLD., under WHAT GOLD MEANS and
 * around the support line is unchanged at every viewport - the wrap is the
 * only gap that moves, and it opens up to meet the other. Setting it on the
 * line-height makes the margin between the blocks redundant, so that goes to
 * zero rather than being counted twice. The h2 margins absorb the 0.2em of
 * half-leading the taller line boxes add, 0.1em at each end. */
.aw-ov[data-overlay-for="beat-2"] h2 .aw-line {
  line-height: 1.12;
}

.aw-ov[data-overlay-for="beat-2"] h2 .aw-line + .aw-line {
  margin-block-start: 0;
}

/* State 2 keeps the ivory hero fill; only the word GOLD. is gold, through the
   same .aw-gold-word class state 1 already uses. */
.aw-ov[data-overlay-for="beat-2"] h2 {
  margin-block-start: -0.1em;
  /* The cast reaches ~0.081em plus its blur below the last baseline, so the
     inherited bottom margin left the support line sitting inside the shadow.
     In em, so the clearance scales with the hero rather than only working at
     one width. 0.24em was that clearance measured against 0.92em line boxes;
     at 1.12em the line box already carries 0.1em of half-leading under the
     last baseline, so the margin gives back exactly that much and the support
     line does not move. */
  margin-block-end: 0.14em;
}

/* GOLD in the site's canonical text gold. text-shadow is inherited, so the
   word already carries the same violet extrusion and #03081B cast as the
   cream letters around it - only the fill colour changes here. */
.aw-gold-word {
  color: var(--aw-gold-bright);
}

/* The $ matches START: its own sitewide brand edge, plus the same cast. */
.aw-ov[data-overlay-for="beat-1"] h2 .aw-dollar {
  text-shadow:
    var(--aw-halo),
    var(--aw-hero-cast);
}

.aw-copy--hero .aw-lede {
  /* wide enough to keep the gold-bound line unbroken on a desktop */
  max-width: 34ch;
  margin-block-start: clamp(0.5rem, 1.4svh, 1.1rem);
  font-size: var(--aw-t-lead);
}

.aw-lede--bound {
  max-width: 30ch;
}

/* The hero used to repeat X and TELEGRAM here. They now live only in the
   persistent top-left official-links bar, which is canonical and visible on
   every state, so .aw-links--inline has no remaining user. */

/* --------------------------------------------------------------- data -- */
.aw-ov--data {
  align-self: end;
  justify-self: center;
  width: min(74rem, calc(100vw - 2 * var(--aw-rail-clear)));
  margin-block-end: var(--aw-bottom-clear);
}

.aw-data {
  display: grid;
  justify-items: start;
  gap: 0;
  width: 100%;
  text-align: start;
}

/* A whole-page centred numeric composition. Used where the page IS the data
   (THE TAX, the allocations) and never for hero copy. */
.aw-data--center {
  justify-items: center;
  text-align: center;
}

.aw-data--center h2 {
  max-width: 18ch;
}

/* ========================================== state 4: XAUT REWARDS ==
 *
 * One centred unit: the figure on the left, a two-line stack on the right.
 *
 * .aw-split carries the figure's own size as its font-size, so every gap and
 * every child size below is expressed in em OF THE FIGURE - the two halves
 * therefore stay locked in proportion at any viewport instead of drifting
 * apart. 0.585em is the ratio that makes the two-line stack's rendered height
 * match the figure's, measured rather than derived: the figure renders at
 * 1.22x its font-size and the two-line stack at 2.085x, so 1.22 / 2.085 =
 * 0.585 puts them level.
 *
 * The 25vw guard is a width bound, not a breakpoint: it keeps the pair on one
 * row on a phone rather than letting the height-led size overflow. flex-wrap
 * is the safety net - if a device ever does run out of room the stack drops
 * below the figure and the composition stays centred. */
.aw-split {
  --aw-split-figure: min(calc(var(--aw-t-mega) * 1.2), 23vw);

  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  column-gap: 0.3em;
  row-gap: 0.08em;
  font-size: var(--aw-split-figure);
}

/* Scoped through .aw-split so these beat `.aw-ov h2` - the copy is a heading,
   and the generic rule was otherwise reimposing --aw-t-display, 0.88 leading
   and the plain h2 shadow on it. */
.aw-split .aw-split-figure,
.aw-split .aw-split-copy {
  margin: 0;
  max-width: none;
  font-family: var(--sc-font-display);
  font-weight: 900;
  letter-spacing: -0.035em;
  text-transform: uppercase;
  /* the approved stack: contact ring, violet extrusion, soft #03081B cast */
  text-shadow: var(--aw-display-shadow);
}

.aw-split .aw-split-figure {
  color: var(--aw-gold-bright);
  font-size: 1em;
  line-height: 0.8;
}

.aw-split .aw-split-copy {
  color: var(--aw-ivory);
  font-size: 0.585em;
  line-height: 0.86;
  text-align: start;
}

.aw-split .aw-split-copy span {
  display: block;
}

/* State 6: the buy size is a bounded chip so it reads at a glance. */
/* The buy size. Used on page 7 only. It was a bordered chip; the box read as
   clutter at display size, so it is now plain display type carrying the same
   approved shadow stack as every other headline on the site. */
.aw-figure-chip {
  margin: 0;
  color: var(--aw-gold-bright);
  font-family: var(--sc-font-display);
  font-weight: 900;
  letter-spacing: -0.02em;
  line-height: 0.9;
  text-shadow: var(--aw-display-shadow);
}

/* ========================================== state 7: WHO QUALIFIES ==
 *
 * Page 8 is a centred composition rather than the bottom-left story block it
 * used to be: label, hero line and the two rules all share one centre axis,
 * so the eye travels straight down instead of stepping left.
 *
 * The headline takes --aw-display-shadow verbatim - the same contact ring,
 * the same violet extrusion and the same soft #03081B cast as every other
 * corrected page - replacing the plain `.aw-ov h2` shadow, which carried no
 * cast and left the line sitting flat on bright film.
 *
 * Every size below is a multiple of the shared fluid step, so nothing here
 * introduces a fixed pixel size or a breakpoint. */
.aw-ov[data-overlay-for="tax-5"] .aw-eyebrow {
  margin-block-end: clamp(0.7rem, 2.2svh, 1.6rem);
  font-size: calc(var(--aw-t-tag) * 1.3);
}

.aw-ov[data-overlay-for="tax-5"] h2 {
  max-width: none;
  /* Generous, because the rules underneath are the payload and the hero has
     to stay clearly separated from them - see the margin on .aw-rules. */
  margin-block-end: 0;
  font-size: calc(var(--aw-t-display) * 1.15);
  text-shadow: var(--aw-display-shadow);
}

/* "10,000 $Auggy" is one figure and must break as one: on a narrow phone the
   line wraps after HOLD rather than splitting the amount from the ticker. */
.aw-ov[data-overlay-for="tax-5"] h2 [data-auggy-value] {
  white-space: nowrap;
}

/* The $ keeps the sitewide green brand edge and gains the same navy cast as
   the ivory letters beside it, so both colours sit on one separation zone -
   identical to the START hero and to state 1. */
.aw-ov[data-overlay-for="tax-5"] h2 .aw-dollar {
  text-shadow:
    var(--aw-halo),
    var(--aw-hero-cast);
}

/* The two rules are a left-aligned block that is CENTRED as a unit: the list
   shrinks to its content and is centred by the parent, while the lines inside
   it stay flush left so the two bullets align with each other. */
.aw-ov[data-overlay-for="tax-5"] .aw-rules {
  justify-items: start;
  width: fit-content;
  max-width: 100%;
  /* Clears the headline's cast, which reaches ~0.081em plus blur below the
     last baseline, and then adds the authored breathing room on top. */
  margin-block-start: clamp(1.9rem, 5.6svh, 4.2rem);
  gap: clamp(0.65rem, 2svh, 1.35rem);
  text-align: start;
}

.aw-ov[data-overlay-for="tax-5"] .aw-rules li {
  font-size: calc(var(--aw-t-body) * 1.5);
  line-height: 1.3;
}

/* The marker grows with the type it sits beside. */
.aw-ov[data-overlay-for="tax-5"] .aw-rules li::before {
  inset-block-start: 0.5em;
  width: 0.62em;
  height: 0.16em;
}

/* -------------------------------------------------------------- rules -- */
.aw-rules {
  display: grid;
  gap: clamp(0.3rem, 1.1svh, 0.75rem);
  margin: clamp(0.85rem, 2.4svh, 1.75rem) 0 0;
  padding: 0;
  list-style: none;
}

.aw-rules li {
  position: relative;
  padding-inline-start: 1.5em;
  color: var(--aw-ivory);
  font-size: var(--aw-t-body);
  font-weight: 700;
  line-height: 1.4;
  text-shadow: var(--aw-halo);
}

.aw-rules li::before {
  content: "";
  position: absolute;
  inset-block-start: 0.55em;
  inset-inline-start: 0;
  width: 0.7em;
  height: 0.18em;
  background: var(--aw-gold);
}

/* ============================================================ topbar ==
 *
 * Persistent, fixed, outside the HUD. SCROLL top-left on every non-final
 * state, and the contract as a genuine bounded component beside it, so
 * neither is re-authored per overlay or dropped at a breakpoint. */
.aw-topbar {
  position: fixed;
  z-index: 4;
  inset-block-start: 0;
  inset-inline: 0;
  /* Three named slots rather than space-between, so the official links sit
     immediately right of SCROLL and the contract stays pinned to the right
     edge. On a phone the same three slots re-flow to two rows without either
     end moving. */
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  grid-template-areas: "cue links contract";
  align-items: center;
  column-gap: 0.75rem;
  row-gap: 0.45rem;
  padding:
    max(0.7rem, env(safe-area-inset-top))
    max(1rem, env(safe-area-inset-right))
    0
    max(1rem, env(safe-area-inset-left));
  pointer-events: none;
}

.aw-topbar > * {
  pointer-events: auto;
}

.aw-scroll-cue { grid-area: cue; }
.aw-contract-row--persistent { grid-area: contract; justify-self: end; }

/* -------------------------------------------------- official links cluster --
 * The one element on the page that is reachable from every state, BUY
 * included. Same visual language as every other link button (gold border,
 * navy ground, cream label) at a compact size, and it wraps rather than
 * shrinking so no destination is ever dropped on a narrow screen. */
.aw-topbar-links {
  grid-area: links;
  gap: 0.4rem;
  /* the row itself is not a click target, only the buttons in it */
  pointer-events: none;
}

.aw-topbar-links > li {
  pointer-events: auto;
}

.aw-topbar-links a {
  min-height: 2.15rem;
  padding: 0.4rem 0.7rem 0.32rem;
  letter-spacing: 0.05em;
}

.aw-topbar [data-hidden] {
  opacity: 0;
  visibility: hidden;
  transition: opacity 220ms ease, visibility 0s linear 220ms;
}

.aw-scroll-cue {
  display: flex;
  align-items: center;
  /* 1.5x the micro step, gap scaled with it so the arrow keeps its current
     relative spacing to the word. Derived from the shared token rather than
     pinned to a pixel size, so it still tracks the fluid scale on every
     viewport; --aw-t-micro itself is untouched and every other consumer of it
     (contract, links, action rows) is unaffected. */
  gap: 0.675rem;
  margin: 0;
  padding-block-start: 0.28rem;
  color: var(--aw-ivory);
  font-family: var(--sc-font-text);
  font-size: calc(var(--aw-t-micro) * 1.5);
  font-weight: 900;
  letter-spacing: 0.09em;
  text-shadow: var(--aw-halo);
  transition: opacity 220ms ease, visibility 0s;
}

.aw-scroll-cue span {
  color: var(--aw-gold);
  animation: aw-scroll-nudge 2.4s ease-in-out infinite;
}

@keyframes aw-scroll-nudge {
  0%, 62%, 100% { transform: translateY(0); }
  78%           { transform: translateY(0.22em); }
}

/* ------------------------------------------------------------ contract -- *
 * Never ordinary unboxed copy: a bounded control with a real border, a
 * readable value and a COPY button, identical on every viewport. */
.aw-contract-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  width: fit-content;
  max-width: 100%;
  padding: 0.3rem 0.3rem 0.3rem 0.55rem;
  border: 2px solid var(--aw-gold);
  background: rgba(3, 8, 27, 0.9);
  text-shadow: none;
}

.aw-contract-label {
  color: var(--aw-gold-bright);
  font-family: var(--sc-font-text);
  font-size: var(--aw-t-micro);
  font-weight: 900;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
}

.aw-contract-row code {
  overflow: hidden;
  color: var(--aw-ivory);
  font-family: var(--aw-font-code);
  font-size: var(--aw-t-micro);
  font-weight: 700;
  letter-spacing: 0.01em;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.aw-contract-row button {
  flex: 0 0 auto;
  min-height: 1.9rem;
  padding: 0.3rem 0.55rem 0.24rem;
  border: 2px solid var(--aw-gold);
  color: var(--aw-ground);
  background: var(--aw-gold);
  font-family: var(--sc-font-text);
  font-size: var(--aw-t-micro);
  font-weight: 900;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  cursor: pointer;
}

.aw-contract-row button:disabled {
  color: var(--aw-lavender-soft);
  background: transparent;
  border-color: var(--aw-gold-muted);
  cursor: not-allowed;
}

.aw-copy-status {
  color: var(--aw-lavender);
  font-size: var(--aw-t-micro);
  font-weight: 700;
}

.aw-copy-status:empty {
  display: none;
}

/* =============================================================== links ==
 * A destination that is still null in config.js renders as a marked pending
 * chip. Nothing is ever linked to an invented URL. */
.aw-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.aw-links a,
.aw-action {
  display: inline-flex;
  min-height: 2.6rem;
  align-items: center;
  justify-content: center;
  /* The buy action mixes text nodes with a <span> ticker; flex layout drops
     the whitespace between them, so the word gap is restored here. */
  gap: 0.3em;
  padding: 0.5rem 0.85rem 0.42rem;
  border: 2px solid var(--aw-gold);
  color: var(--aw-ivory);
  background: rgba(3, 8, 27, 0.9);
  font-family: var(--sc-font-text);
  font-size: var(--aw-t-micro);
  font-weight: 900;
  letter-spacing: 0.06em;
  text-decoration: none;
  text-shadow: none;
  text-transform: uppercase;
}

.aw-links a:hover,
.aw-links a:focus-visible {
  color: var(--aw-ground);
  background: var(--aw-gold-bright);
}

.aw-links a[data-pending],
.aw-action[data-pending] {
  border-color: var(--aw-gold-muted);
  border-style: dashed;
  color: var(--aw-lavender-soft);
  background: rgba(3, 8, 27, 0.7);
  cursor: not-allowed;
}

.aw-links a[data-pending]::after,
.aw-action[data-pending]::after {
  content: " — SOON";
  color: var(--aw-gold-muted);
}

/* ================================================================= CTA ==
 * Links top-left, the closing line and the buy action bottom-left, contract
 * underneath. No SCROLL on the final state and no decorative top rule.
 *
 * ANCHORING. The bottom-left cluster is this page's hero, so it takes the
 * SAME --aw-hero-start the three CREATE heroes take - the one shared anchor
 * declared in :root, not a second copy of it. The CTA pose translates
 * the film vertically (ty -0.10) and never horizontally (tx 0), so the film's
 * left edge is the same pure function of viewport height and width it is on
 * pages 9-11 and needs no per-pose term.
 *
 * The bottom anchor deliberately stays --aw-bottom-clear rather than moving
 * up to the film's lifted bottom edge: the 10svh band of ground the CTA pose
 * opens underneath is what this state's contract row sits in, and on a phone
 * --aw-bottom-clear is the navigation bar's clearance. Only the LEFT edge
 * changes here. */
.aw-ov--cta {
  /* Half the shared inset, for this state only. The closing cluster sits over
     the brightest, busiest part of the film - the portal and the character -
     rather than over the quiet ground the CREATE heroes have above them, so
     it is pulled back toward the film's own left edge to stay clear of that
     composition. .aw-ov resolves --aw-hero-start against whatever inset the
     state carries, so this override reaches only this state; pages 9-11 keep
     the root value. */
  --aw-hero-inset: clamp(0.75rem, 1.7svh, 1.75rem);

  align-self: stretch;
  justify-self: start;
  width: min(60rem, calc(100vw - var(--aw-hero-start) - var(--aw-rail-clear)));
  margin-inline-start: var(--aw-hero-start);
}

/* Two authored lines rather than a wrap, so JUST THE / BEGINNING is the same
   break at every viewport instead of one that moves with the column width -
   and so the line never runs as far into the portal as the single line did.
   Same .aw-line idiom as states 1, 2 and 10; 0.14em of advance because line
   one ends in E, which carries no descender, so only the violet extrusion
   (0.055em) has to be cleared beneath it. */
.aw-ov--cta .aw-cta-title .aw-line {
  display: block;
}

.aw-ov--cta .aw-cta-title .aw-line + .aw-line {
  margin-block-start: 0.14em;
}

/* ------------------------------------------------------- closing line --
 *
 * This state has no separate heading: the line above the buy action IS the
 * page title (the section is aria-labelledby it), so it carries the display
 * treatment rather than the small gold chip it used to wear. That is also
 * what makes the approved shadow stack applicable at all - a chip is a solid
 * box and can take no text-shadow.
 *
 * Same step and same stack as the three CREATE heroes: 1.75x the shared
 * height-led display scale, and --aw-display-shadow verbatim - the #03081B
 * contact ring, the violet dimensional extrusion, then --aw-hero-cast, the
 * large soft #03081B environmental drop, furthest back. No black anywhere. */
/* Scoped through the state class so it beats the generic `.aw-ov h2`, which
   would otherwise reimpose the base display step and the cast-less shadow. */
.aw-ov--cta .aw-cta-title {
  max-width: none;
  margin: 0;
  color: var(--aw-ivory);
  font-family: var(--sc-font-display);
  /* Half the step the three CREATE heroes take. This state carries a headline
     AND a full-size action AND the contract row, so it does not want the same
     dominance they do - the buy control is the thing to reach for here, and
     the line above it sets up rather than shouts. Same shared height-led
     scale underneath, same shadow stack. */
  font-size: calc(var(--aw-t-display) * 0.875);
  font-weight: 900;
  letter-spacing: -0.025em;
  line-height: 0.92;
  text-transform: uppercase;
  text-shadow: var(--aw-display-shadow);
}

.aw-cta-surface {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: clamp(0.75rem, 2svh, 1.4rem);
  height: 100%;
  padding-block:
    max(0.7rem, env(safe-area-inset-top))
    var(--aw-bottom-clear);
}

/* The official-links row that used to hold the top of this column open now
   lives in the persistent top bar, so the primary block carries the spacer. */
.aw-cta-primary {
  margin-block-start: auto;
}

.aw-cta-primary {
  display: grid;
  justify-items: start;
  gap: clamp(0.5rem, 1.6svh, 1rem);
}

/* The main CTA, stepped up so it reads as the action rather than as a chip
   under the headline. min-height and padding move to em so the whole control
   grows with its own type instead of staying a fixed box around bigger text. */
.aw-action--buy {
  min-height: 2.6em;
  padding: 0.6em 0.95em 0.5em;
  color: var(--aw-ground);
  background: var(--aw-gold);
  font-family: var(--sc-font-display);
  font-size: calc(var(--aw-t-lead) * 1.25);
  letter-spacing: 0.02em;
  box-shadow: 5px 5px 0 var(--aw-violet);
}

/* The ticker splits two ways on this button: the word goes gold, the $ keeps
 * the sitewide neon green.
 *
 * ui.js renders the ticker as an .aw-dollar span followed by a bare text
 * node, so the word cannot be selected directly. Colouring the WRAPPER gold
 * paints that text node, and .aw-dollar's own colour declaration keeps the
 * glyph green regardless of what the wrapper inherits down - a child with its
 * own value is never reached by inheritance.
 *
 * Scoped to the PENDING button on purpose. Pending is a dark box with muted
 * gold trim, so gold and green both read cleanly on it. The live button -
 * once links.buy exists - is a solid --aw-gold panel with --aw-ground text,
 * and gold on gold would be invisible, so that state keeps inheriting the
 * panel's own foreground rather than being given a fill it cannot show. */
.aw-action--buy[data-pending] [data-auggy-value="ticker"] {
  color: var(--aw-gold-bright);
}

.aw-action--buy[data-pending] {
  box-shadow: none;
}

/* ------------------------------------------- shared CREATE resource stage --
 *
 * States 8, 9 and 10 (Character Sheet, Art Library, Sticker Pack) are three
 * different CONTENTS of ONE authored region: the large empty upper half of the
 * CREATE film, above Auggy's head. The film is height-driven and horizontally
 * centred, so the empty region is height-driven and horizontally centred too.
 *
 * Before this pass every module carried its own inset-block-start,
 * inset-inline-start/end, width and transform, and each of those was
 * re-authored inside three separate breakpoints. The consequences were the
 * reported drift: the module jumped from the left gutter to the right gutter
 * at 1025px + 4:3, re-centred at 1024px, re-centred again at 720px, stopped
 * growing at a rem cap while the viewport kept growing, and each of the three
 * states resolved to a different width and a different content-driven bottom
 * edge, so switching state moved the box.
 *
 * The stage below owns ALL outer geometry, once, for all three states:
 *
 *   top     a small viewport-relative inset from the top edge
 *   bottom  the vertical middle of the viewport - the stage IS the top half
 *   width   viewport width minus a SYMMETRIC reserve, capped, centred
 *
 * Symmetric reserve means the stage is always centred on the same axis as the
 * film, and because the reserve is never narrower than the waypoint rail the
 * stage can never reach the navigation.
 *
 * Everything here is viewport-relative (svh/vw/clamp). There are no
 * layout-mode breakpoints for the stage; the three media queries below only
 * re-value these four custom properties. */
.aw-ov.aw-ov--create {
  /* Never above the persistent SCROLL + contract bar. */
  --aw-cstage-top: max(clamp(0.85rem, 3svh, 2rem), var(--aw-topbar-clear));
  /* The floor only engages below a ~363px-tall viewport, where half the
     screen is no longer a usable module; above that the stage bottom is
     exactly the vertical midline. */
  --aw-cstage-height: max(10.5rem, calc(50svh - var(--aw-cstage-top)));
  /* The waypoint rail's own footprint: 8.5rem box + 0.75rem padding + 3px
     rule + 1rem edge inset, rounded up. The rail is centred on the viewport
     height, so on shorter viewports its top edge rises above the midline and
     into the stage. Reserving the same amount on BOTH sides keeps the stage
     symmetric - and therefore still centred on the film - while guaranteeing
     it can never reach the navigation at any viewport shape. */
  --aw-cstage-rail: 10.75rem;
  --aw-cstage-reserve: clamp(11rem, 12vw, 13rem);
  --aw-cstage-width: min(
    calc(100vw - 2 * var(--aw-cstage-reserve)),
    calc(100vw - 2 * var(--aw-cstage-rail)),
    68rem);

  align-self: stretch;
  justify-self: stretch;
  width: 100%;
  height: 100%;
  margin: 0;
}

.aw-create-stage {
  position: absolute;
  inset-block-start: max(var(--aw-cstage-top), env(safe-area-inset-top));
  inset-inline-start: 50%;
  display: grid;
  place-items: center;
  width: var(--aw-cstage-width);
  height: var(--aw-cstage-height);
  translate: -50% 0;
}

.aw-ov--create .aw-folio-copy {
  position: absolute;
  inset-block-end: var(--aw-bottom-clear);
  inset-inline-start: var(--aw-gutter);
  width: min(34rem, calc(100vw - var(--aw-gutter) - var(--aw-rail-clear)));
}

/* The module fills the stage HEIGHT. Its width follows from that height via
 * one per-module proportion, so the three states differ only in how wide a
 * slice of the shared stage they take - never in where they sit, never in
 * their top or bottom edge, never in their centre line.
 *
 * Every module is a flex column in which exactly one region is elastic and
 * every control row stays intrinsic, so a shorter stage compresses the
 * artwork rather than overflowing the box. */
.aw-resource-module {
  --aw-module-ratio: 1;

  display: flex;
  flex-direction: column;
  /* Derived from the stage height, but never narrower than the control rows
     need: on a very short viewport (a phone held landscape) the height-
     derived width fell under 11rem and OPEN/DOWNLOAD wrapped to two lines
     and burst the box. The floor is still capped by the stage width, so it
     can never push the module outside the shared region. */
  width: min(100%, max(20rem, calc(var(--aw-cstage-height) * var(--aw-module-ratio))));
  height: 100%;
  /* The module's width is derived, not authored, so the summary bar sizes its
     type against the container rather than against the viewport. */
  container-type: inline-size;
  overflow: hidden;
  border: 3px solid var(--aw-gold);
  background: var(--aw-ground);
  box-shadow: 6px 6px 0 var(--aw-violet);
  transform: rotate(-1deg);
}

/* ======================================================= CREATE resources ==
 *
 * The shared stage above owns top, height, width and centring for all three.
 * Everything below is INTERNAL layout only. */
.aw-resource-module--character-sheet { --aw-module-ratio: 1.75; }

/* These two take the full stage width. A scrolling gallery wants every pixel
   of the authored region, and the shared stage already bounds it. */
.aw-resource-module--art,
.aw-resource-module--stickers {
  width: 100%;
}

/* Shared action bar for all three resources. */
.aw-resource-actions {
  display: grid;
  flex: 0 0 auto;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  border-block-start: 3px solid var(--aw-gold);
}

.aw-resource-actions a {
  display: inline-flex;
  min-height: clamp(2.1rem, 5svh, 2.9rem);
  align-items: center;
  justify-content: center;
  padding: 0.55rem 0.5rem 0.45rem;
  color: var(--aw-ivory);
  background: var(--aw-ground);
  font-family: var(--sc-font-text);
  font-size: clamp(0.68rem, 3.1cqw, 0.92rem);
  font-weight: 900;
  letter-spacing: 0.035em;
  text-align: center;
  text-decoration: none;
  text-shadow: none;
}

.aw-resource-actions a + a {
  border-inline-start: 2px solid var(--aw-gold);
}

.aw-resource-actions a:hover,
.aw-resource-actions a:focus-visible {
  color: var(--aw-ground);
  background: var(--aw-gold-bright);
}

.aw-resource-actions a[data-pending] {
  color: var(--aw-lavender-soft);
  cursor: not-allowed;
}

.aw-resource-module:hover,
.aw-resource-module:focus-within {
  border-color: var(--aw-gold-bright);
}

/* ------------------------------------------------- state 8: character -- *
 *
 * [ portrait rail ][ LARGE cropped sheet ][ portrait rail ]
 *
 * The sheet is allowed to CROP: object-fit is cover, because a square
 * document letterboxed into a landscape module read as an insignificant card
 * surrounded by blank space. The whole sheet is one click away in OPEN IMAGE
 * and DOWNLOAD. The rails are visual support: no controls live in them. */
.aw-cs-body {
  display: grid;
  flex: 1 1 auto;
  grid-template-columns: 0.42fr minmax(0, 1fr) 0.42fr;
  min-height: 0;
}

.aw-cs-sheet {
  overflow: hidden;
  background: #f4f1ed;
}

.aw-cs-sheet img {
  display: block;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: cover;
  object-position: 50% 40%;
}

.aw-cs-rail {
  display: grid;
  /* ui.js measures the rail and writes --aw-rail-cells, so the number of
     portraits follows the stage height instead of a breakpoint. */
  grid-template-rows: repeat(var(--aw-rail-cells, 3), minmax(0, 1fr));
  min-width: 0;
  overflow: hidden;
  background: rgba(3, 8, 27, 0.62);
}

.aw-cs-rail--start { border-inline-end: 2px solid var(--aw-gold); }
.aw-cs-rail--end   { border-inline-start: 2px solid var(--aw-gold); }

.aw-cs-cell {
  position: relative;
  min-height: 0;
  overflow: hidden;
}

.aw-cs-cell + .aw-cs-cell {
  border-block-start: 1px solid var(--aw-rule-soft);
}

/* Two stacked layers per cell so a swap is a crossfade, never a flash. */
.aw-cs-cell img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  padding: 8%;
  object-fit: contain;
  opacity: 0;
  transition: opacity 620ms ease;
}

.aw-cs-cell img[data-shown] {
  opacity: 1;
}

/* ------------------------------------- states 9 and 10: horizontal strip -- *
 *
 * The gallery IS the thumbnails. No selected-image monitor, no pagination, no
 * AVAILABLE header. One horizontally scrollable row inside the shared stage.
 *
 * There is deliberately NO wheel handler on the track: a horizontally-only
 * scrollable box receives deltaX from a trackpad and passes deltaY straight
 * through to the station controller, so vertical navigation is untouched. */
.aw-strip {
  position: relative;
  display: grid;
  flex: 1 1 auto;
  grid-template-columns: auto minmax(0, 1fr) auto;
  min-height: 0;
}

/* A grid that flows in COLUMNS with a fixed cell height: rows auto-fill the
   module, so the same rule is one row on a short viewport and three on a tall
   one, and scrolling is always horizontal. No pagination anywhere. */
.aw-strip-track {
  --aw-strip-cell: clamp(4.25rem, 12.5svh, 8.5rem);

  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: max-content;
  /* auto-fill counts rows from the MIN, then 1fr grows them to fill the
     module: no dead band under the strip at any stage height. */
  grid-template-rows: repeat(auto-fill, minmax(var(--aw-strip-cell), 1fr));
  align-content: start;
  justify-content: start;
  gap: 0.4rem;
  min-width: 0;
  padding: 0.45rem;
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  scroll-behavior: smooth;
  scroll-snap-type: x proximity;
  scrollbar-width: thin;
  scrollbar-color: var(--aw-gold-muted) transparent;
}

/* The artwork row, and only the artwork row, gives up proximity snapping.
 * It has to: snapping re-quantises EVERY programmatic scroll (a scrollTo of
 * 600px came back as 704.5px, measured), which swallows the idle drift's
 * fraction of a pixel per frame whole, and toggling snap on and off around
 * the drift would make the row twitch every time a pointer arrived. Free
 * scrolling is also the better fit for a 219-item row nobody browses one cell
 * at a time. The sticker row on page 11 keeps its snapping untouched. */
.aw-resource-module--art .aw-strip-track {
  scroll-snap-type: none;
}

.aw-strip-track::-webkit-scrollbar { height: 6px; }
.aw-strip-track::-webkit-scrollbar-thumb { background: var(--aw-gold-muted); }
.aw-strip-track::-webkit-scrollbar-track { background: transparent; }

.aw-strip-item {
  height: 100%;
  padding: 0;
  border: 1px solid rgba(255, 201, 40, 0.32);
  border-radius: 0;
  background: rgba(3, 8, 27, 0.9);
  scroll-snap-align: start;
  cursor: pointer;
}

.aw-strip-item img {
  display: block;
  width: auto;
  height: 100%;
  /* Natural width where the artwork allows it, capped so one panorama cannot
     fill the whole row. scrollcraft.css caps images at 100%; lifted here. */
  max-width: min(14rem, 34vw);
  object-fit: cover;
}

.aw-strip-item:hover,
.aw-strip-item:focus-visible {
  border-color: var(--aw-gold-bright);
}

.aw-strip-item[aria-pressed="true"] {
  border-color: var(--aw-gold);
  box-shadow: inset 0 0 0 3px var(--aw-gold);
}

.aw-strip--stickers .aw-strip-item {
  aspect-ratio: 1;
  /* Site ground, not a checkerboard: transparent stickers sit on the AUGGY
     navy exactly as they will in the chat. */
  background: var(--aw-ground);
  cursor: default;
}

.aw-strip--stickers .aw-strip-item img {
  width: 100%;
  max-width: none;
  padding: 6%;
  object-fit: contain;
}

.aw-strip-nav {
  display: grid;
  place-items: center;
  width: clamp(1.6rem, 5cqw, 2.6rem);
  padding: 0;
  border: 0;
  border-inline-end: 1px solid var(--aw-rule-soft);
  color: var(--aw-gold-bright);
  background: rgba(3, 8, 27, 0.86);
  font-family: var(--sc-font-display);
  font-size: clamp(1.1rem, 4cqw, 1.9rem);
  line-height: 1;
  cursor: pointer;
}

.aw-strip-nav--next {
  border-inline-end: 0;
  border-inline-start: 1px solid var(--aw-rule-soft);
}

.aw-strip-nav:hover:not(:disabled),
.aw-strip-nav:focus-visible:not(:disabled) {
  color: var(--aw-ground);
  background: var(--aw-gold-bright);
}

.aw-strip-nav:disabled {
  color: var(--aw-lavender-soft);
  cursor: default;
  opacity: 0.4;
}

/* ---------------------------------------------- state 9: artwork preview --
 *
 * Clicking a thumbnail lays the selected 1600px derivative over the strip -
 * same module, same stage, same geometry, nothing moves. The layer is opaque
 * and covers the whole artwork region including the two nav arrows, so any
 * click on it lands on the layer itself and takes it away again. The strip
 * underneath is never unmounted, so its horizontal scroll position survives
 * the round trip untouched and returning is instant. */
.aw-art-preview {
  position: absolute;
  z-index: 2;
  display: grid;
  /* ONE explicitly sized cell, and that is the point of it. Centring the
     image in an auto-sized track left its max-height: 100% resolving against
     a track whose own height came from the image - circular, so the browser
     dropped the constraint entirely and a 1600x2138 portrait rendered at full
     height, anchored to the top, with its bottom half outside the module.
     minmax(0, 1fr) makes the cell definite (it is the layer's own inset box),
     which is exactly what percentage sizing on the image needs. */
  grid-template-rows: minmax(0, 1fr);
  grid-template-columns: minmax(0, 1fr);
  inset: 0;
  padding: 0.5rem;
  border: 0;
  background: var(--aw-ground);
  cursor: zoom-out;
  overflow: hidden;
}

.aw-art-preview[hidden] { display: none; }

/* The image BOX fills the cell and object-fit does the fitting inside it, so
   landscape, portrait, square and ultrawide all letterbox against the same
   centre and none of them is ever cropped.
 *
 * min-width / min-height: 0 are load-bearing, not tidying: a grid item's
 * automatic minimum size is its INTRINSIC size, so without them the artwork's
 * own 2138px would push the box back out of the cell however the cell is
 * sized. */
.aw-art-preview img {
  width: 100%;
  height: 100%;
  min-width: 0;
  min-height: 0;
  object-fit: contain;
  object-position: center center;
  opacity: 0;
  transition: opacity 140ms linear;
}

/* Set once the selected derivative has actually decoded, so the layer opens on
   the artwork rather than on the previous one for a frame. */
.aw-art-preview[data-ready] img {
  opacity: 1;
}

.aw-strip-loading {
  align-self: center;
  justify-self: start;
  margin: 0;
  color: var(--aw-lavender);
  font-family: var(--aw-font-code);
  font-size: 0.78rem;
  font-weight: 800;
  letter-spacing: 0.05em;
}

/* ---------------------------------------------------------- folio copy -- */
.aw-folio-copy {
  display: grid;
  justify-items: start;
  text-align: start;
}

.aw-folio-copy .aw-lede {
  max-width: 30ch;
}

/* ===== states 8, 9 and 10: CHARACTER SHEET / ART LIBRARY / STICKERS ==
 *
 * The three CREATE heroes. All three are the same composition with different
 * words, so they are authored ONCE against all three state classes rather
 * than as lookalikes that can drift apart - the same argument the shared
 * beat-1/beat-2 block above makes. Every inset, size and shadow below is
 * therefore provably identical between them.
 *
 * States 8 and 9 carry a label, a headline and a support line. State 10 asked
 * for one heading and nothing else, so it takes the same anchor, the same
 * step and the same shadow stack with only the headline present; the two
 * rules it does not use simply find nothing to match.
 *
 * Each hero is a MAJOR element of its composition and is anchored to the
 * film, not to the window.
 *
 * ANCHORING. The film is height-authoritative and 4:3, so widening the window
 * does not widen the picture - it only opens more empty ground beside it. A
 * hero pinned to --aw-gutter therefore walks away from the picture as the
 * window widens: at 2560x1080 the film's left edge is at 560px while the
 * gutter sits at 80px, stranding the hero 480px out in the dark. These take
 * --aw-hero-start instead - the shared film-relative anchor declared in
 * :root - so the hero-to-film relationship is identical at 1920x1080 and
 * 2560x1080 and viewport WIDTH alone can no longer move it.
 *
 * The film is flush to the top and bottom of the viewport in the LARGE pose
 * this state uses, so the film's bottom edge IS the viewport's: the same inset
 * is applied underneath, floored by --aw-bottom-clear so a phone can never
 * push the hero into the navigation bar.
 *
 * The resource module above each hero - the character sheet on page 9, the
 * art strip on page 10, the sticker strip on page 11 - is untouched: all
 * three are positioned by .aw-create-stage, which this block does not reach.
 * The module and the hero are separate compositions and stay that way. */
.aw-ov--character-sheet .aw-folio-copy,
.aw-ov--art-library .aw-folio-copy,
.aw-ov--sticker-pack .aw-folio-copy {
  /* The vertical band this hero actually owns: everything below the resource
     module's stage (which ends at 50svh) down to its own bottom inset. The
     module is not consulted or moved - only read - so the two compositions
     stay independent. */
  --aw-hero-gap:  clamp(0.75rem, 2svh, 1.5rem);
  --aw-hero-band: calc(
    50svh
    - max(var(--aw-bottom-clear), var(--aw-hero-inset))
    - var(--aw-hero-gap));

  inset-block-end: max(var(--aw-bottom-clear), var(--aw-hero-inset));
  inset-inline-start: var(--aw-hero-start);
  /* Bounded by where it actually starts, so the block can never reach the
     waypoint rail no matter which branch --aw-hero-start took. */
  /* Wide enough that a landscape viewport keeps DRAW $Auggy. on ONE line at
     full size - the headline stacks because it runs out of WIDTH, which only
     happens on portrait and narrow windows, rather than because a fixed
     character count forced it. Still bounded by where the block actually
     starts, so it can never reach the waypoint rail on either branch. */
  width: min(68rem, calc(100vw - var(--aw-hero-start) - var(--aw-rail-clear)));
}

/* ------------------------------------------------------------- scale --
 *
 * All three steps take the SAME multiplier off the shared fluid scale, so the
 * block enlarges as one unit and keeps its internal proportions at every
 * viewport. Nothing here is a fixed pixel size and nothing is per-breakpoint:
 * the height-led clamps in :root still do the sizing. */
.aw-ov--character-sheet .aw-eyebrow,
.aw-ov--art-library .aw-eyebrow {
  margin-block-end: clamp(0.5rem, 1.7svh, 1.3rem);
  font-size: calc(var(--aw-t-tag) * 1.75);
}

/* The approved stack verbatim - the #03081B contact ring, the violet
   dimensional extrusion, and --aw-hero-cast (the soft, fully opaque #03081B
   environmental drop) furthest back - through the shared token, so this is
   provably the same treatment as the START hero rather than a lookalike.
   Nothing here substitutes black for #03081B or rebuilds the stack. */
/* SIZE. The target is 1.75x the shared display step - about 1.35x what this
   headline rendered at before - and the shared step is left doing the fluid,
   height-led work underneath, so there is no fixed pixel size here.
 *
 * The min() is a containment cap, not a second scale. --aw-t-display is led by
 * the FULL viewport height, but this hero only ever owns --aw-hero-band, the
 * strip below the resource module. At 1.75x unbounded the block ran 33px
 * through the module's OPEN IMAGE / DOWNLOAD row at 1440x900 and 66px through
 * it at 2560x1080 - measured, not estimated. 0.325 of the band is the largest
 * step whose WHOLE block (two headline lines, the label, the support line and
 * their margins) still lands inside the band, checked at 1440x900 where the
 * band is tightest.
 *
 * Consequence, stated plainly: on a tall viewport the hero reaches the full
 * 1.75x; at 16:9 the band binds first and it settles a little under that.
 * The module is what it is competing with, and the module does not move. */
.aw-ov--character-sheet .aw-folio-copy h2,
.aw-ov--art-library .aw-folio-copy h2,
.aw-ov--sticker-pack .aw-folio-copy h2 {
  max-width: none;
  margin-block-end: clamp(0.4rem, 1.3svh, 1rem);
  font-size: min(
    calc(var(--aw-t-display) * 1.75),
    calc(var(--aw-hero-band) * 0.4));
  /* Compact where it does stack, and safe to be: the wrap puts DRAW on line
     one, which has no descender, so only the violet extrusion has to clear. */
  line-height: 0.92;
  text-shadow: var(--aw-display-shadow);
}

/* The $ keeps its sitewide green brand edge and gains the same navy cast as
   the ivory letters beside it, so both colours sit on one separation zone -
   identical to the START hero and to state 1. */
.aw-ov--character-sheet .aw-folio-copy h2 .aw-dollar,
.aw-ov--art-library .aw-folio-copy h2 .aw-dollar,
.aw-ov--sticker-pack .aw-folio-copy h2 .aw-dollar {
  text-shadow:
    var(--aw-halo),
    var(--aw-hero-cast);
}

.aw-ov--character-sheet .aw-folio-copy .aw-lede,
.aw-ov--art-library .aw-folio-copy .aw-lede {
  max-width: 26ch;
  font-size: calc(var(--aw-t-lead) * 1.75);
}

/* Page 11's headline is two authored lines rather than a wrap, so the stack
   is the same structure at every viewport instead of depending on where the
   text happens to break inside the wider shared copy block. Same .aw-line
   idiom as states 1 and 2; 0.14em of advance because line one ends in AUGGY,
   whose ivory glyphs carry no descender, so only the violet extrusion
   (0.055em) has to be cleared beneath it. */
.aw-ov--sticker-pack .aw-folio-copy h2 .aw-line {
  display: block;
}

.aw-ov--sticker-pack .aw-folio-copy h2 .aw-line + .aw-line {
  margin-block-start: 0.14em;
}

/* Nothing sits under this headline, so it keeps the flush bottom edge the
   shared block's margin would otherwise lift it off. */
.aw-ov--sticker-pack .aw-folio-copy h2 {
  margin-block-end: 0;
}

/* State 10 asked for one heading and nothing else. */
.aw-folio-copy--single h2 {
  max-width: 14ch;
  margin-block-end: 0;
}

/* --------------------------------------------------------- waypoints -- */
.aw-waypoints {
  position: fixed;
  z-index: 3;
  inset-block-start: 50%;
  inset-inline-end: max(1rem, env(safe-area-inset-right));
  max-inline-size: 8.5rem;
  padding-inline-end: 0.75rem;
  border-inline-end: 3px solid var(--aw-gold);
  color: var(--aw-ivory);
  font-family: var(--sc-font-display);
  transform: translateY(-50%);
  pointer-events: auto;
}

.aw-waypoints ol {
  display: grid;
  gap: 0.35rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.aw-waypoint {
  min-width: 0;
  text-align: center;
}

.aw-waypoint + .aw-waypoint::before {
  content: "↓";
  display: block;
  height: 1.15rem;
  color: var(--aw-gold);
  font: 900 1rem/1.15rem var(--sc-font-text);
}

.aw-waypoint button {
  position: relative;
  min-width: 7.25rem;
  min-height: 2.75rem;
  padding: 0.72rem 0.85rem 0.6rem;
  border: 2px solid var(--aw-gold);
  border-radius: 0;
  color: var(--aw-ivory);
  background: var(--aw-ground);
  box-shadow: 4px 4px 0 var(--aw-gold-muted);
  font: 900 1rem/1 var(--sc-font-display);
  letter-spacing: 0.035em;
  text-transform: uppercase;
  opacity: 0.92;
  cursor: pointer;
  -webkit-text-fill-color: currentColor;
}

.aw-waypoint button:hover,
.aw-waypoint button:focus-visible {
  color: var(--aw-ground);
  background: var(--aw-gold-bright);
  opacity: 1;
}

.aw-waypoint button[data-current] {
  color: var(--aw-ground);
  background: var(--aw-gold);
  border-color: var(--aw-gold);
  box-shadow: 4px 4px 0 var(--aw-gold-muted);
  opacity: 1;
  transform: translateX(-0.3rem);
}

.aw-waypoint button[data-current]::after {
  content: "";
  position: absolute;
  inset-block-start: 50%;
  inset-inline-end: -1.15rem;
  width: 0.5rem;
  height: 0.5rem;
  border: 1px solid var(--aw-ground);
  background: var(--aw-neon);
  transform: translateY(-50%) rotate(45deg);
}

.aw-visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

:where(a, button):focus-visible {
  outline: 2px solid var(--aw-gold-bright);
  outline-offset: 4px;
}

/* --------------------------------------------------------------- armed -- */
.aw-armed {
  position: fixed;
  z-index: 4;
  inset-inline-start: 50%;
  inset-block-end: max(clamp(2rem, 8svh, 6rem), env(safe-area-inset-bottom));
  min-height: 48px;
  padding: 0.8rem 1.5rem;
  border: 1px solid var(--aw-gold);
  border-radius: 0;
  color: var(--sc-accent-ink);
  background: var(--aw-gold);
  font: 900 0.9rem/1 var(--sc-font-text);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  transform: translateX(-50%);
  cursor: pointer;
}

.aw-armed[hidden] {
  display: none;
}

/* --------------------------------------------------------------- debug -- */
.aw-debug {
  position: fixed;
  z-index: 5;
  inset-block-start: 0;
  inset-inline-start: 0;
  padding: 4px 8px;
  color: #9ef;
  background: rgba(0, 0, 0, 0.82);
  font: 12px/1.4 var(--aw-font-code);
  pointer-events: none;
  white-space: nowrap;
}

.aw-debug[hidden] {
  display: none;
}

/* =========================================================== responsive ==
 *
 * There are four media queries in the whole file and NONE of them re-authors
 * a composition. They re-value tokens, and they change layout MODE only where
 * the mode genuinely differs: the waypoint rail becoming a bottom bar, and
 * the character-sheet side rails coming off a phone.
 *
 * Type is not touched here at all: the scale in :root is continuous. */

/* Tablet portrait. The waypoint rail is still a rail, but it is centred on
   60% of the viewport height, so on any tablet shorter than ~1240px its top
   edge rises above the midline and into the shared CREATE stage. Anchoring it
   just below the midline is the smallest containment fix and lets the stage
   keep the full width of the upper half. */
@media (min-width: 721px) and (max-width: 1024px) and (orientation: portrait) {
  :root {
    --aw-gutter: clamp(1.5rem, 4vw, 3rem);
    /* --aw-rail-clear is deliberately NOT reduced here. The rail moves below
       the midline for the CREATE stage's sake, but the story and data blocks
       are bottom-anchored and still run straight into it. */
  }

  .aw-ov.aw-ov--create {
    --aw-cstage-reserve: clamp(1.5rem, 4vw, 3rem);
    --aw-cstage-width: min(calc(100vw - 2 * var(--aw-cstage-reserve)), 46rem);
  }

  .aw-waypoints {
    inset-block-start: calc(50% + 1rem);
    transform: none;
  }
}

/* Phone. The navigation becomes a bottom bar, so it stops constraining the
   sides and starts constraining the bottom; the side rails come off the
   character sheet so the sheet itself fills the region. */
@media (max-width: 720px) {
  :root {
    --aw-gutter: max(1rem, env(safe-area-inset-left));
    --aw-rail-clear: max(1rem, env(safe-area-inset-right));
    --aw-bottom-clear: max(5.6rem, calc(4.7rem + env(safe-area-inset-bottom)));
  }

  .aw-ov.aw-ov--create {
    --aw-cstage-rail: 0.75rem;
    --aw-cstage-reserve: 0.75rem;
    --aw-cstage-width: calc(100vw - 2 * var(--aw-cstage-reserve));
  }

  .aw-topbar {
    /* SCROLL and the contract keep row one exactly as before; the links get
       row two to themselves rather than being hidden or truncated. */
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-areas:
      "cue contract"
      "links links";
    column-gap: 0.5rem;
    padding-inline: max(0.65rem, env(safe-area-inset-left)) max(0.65rem, env(safe-area-inset-right));
  }

  .aw-topbar-links {
    gap: 0.35rem;
  }

  .aw-topbar-links a {
    min-height: 2rem;
    padding: 0.35rem 0.55rem 0.28rem;
  }

  .aw-contract-row {
    padding: 0.25rem 0.25rem 0.25rem 0.45rem;
    gap: 0.35rem;
  }

  /* Portrait keeps the whole region for the sheet. The side carousels are
     visual support, not content, so they simply come off rather than being
     crushed into a phone-width column. */
  .aw-cs-rail {
    display: none;
  }

  .aw-cs-body {
    grid-template-columns: minmax(0, 1fr);
  }

  .aw-resource-module--character-sheet {
    --aw-module-ratio: 1.05;
  }

  .aw-strip-item img {
    max-width: min(8.5rem, 36vw);
  }

  .aw-links a,
  .aw-action {
    min-height: 2.5rem;
    padding-inline: 0.7rem;
  }

  .aw-waypoints {
    inset-block-start: auto;
    inset-block-end: max(0.65rem, env(safe-area-inset-bottom));
    inset-inline-start: 50%;
    inset-inline-end: auto;
    width: max-content;
    max-inline-size: calc(100vw - 1rem);
    padding-inline-end: 0;
    padding-block-end: 0.45rem;
    border-inline-end: 0;
    border-block-end: 3px solid var(--aw-gold);
    transform: translateX(-50%);
  }

  .aw-waypoints ol {
    display: flex;
    align-items: center;
    gap: 0.2rem;
    white-space: nowrap;
  }

  .aw-waypoint {
    display: flex;
    align-items: center;
  }

  .aw-waypoint + .aw-waypoint::before {
    content: "→";
    height: auto;
    margin-inline-end: 0.2rem;
    font-size: 0.9rem;
    line-height: 1;
  }

  .aw-waypoint button {
    min-width: 0;
    min-height: 2.75rem;
    padding: 0.68rem 0.5rem 0.58rem;
    box-shadow: 3px 3px 0 var(--aw-gold-muted);
    font-size: 0.875rem;
  }

  .aw-waypoint button[data-current] {
    box-shadow: 3px 3px 0 var(--aw-gold-muted);
    transform: translateY(-0.2rem);
  }

  .aw-waypoint button[data-current]::after {
    inset-block-start: auto;
    inset-block-end: -1.05rem;
    inset-inline-end: 50%;
    transform: translateX(50%) rotate(45deg);
  }
}

/* Short viewport. Only intrinsic control rows give ground, so the artwork and
   the numbers keep their share of the composition. */
@media (max-height: 650px) {
  .aw-resource-actions a {
    min-height: 2.05rem;
  }

  .aw-strip-track {
    padding: 0.3rem;
  }

}

/* Phone held LANDSCAPE. The one viewport where an exact upper half is
   over-constrained: a bottom navigation bar, the CREATE copy and a 50svh
   stage do not all fit inside 375-480px of height. The stage gives back four
   points of viewport height and the copy tightens; the model is otherwise
   unchanged. */
@media (max-width: 720px) and (max-height: 480px) {
  :root {
    --aw-bottom-clear: max(4.9rem, calc(4.3rem + env(safe-area-inset-bottom)));
  }

  .aw-ov.aw-ov--create {
    --aw-cstage-height: max(8.5rem, calc(46svh - var(--aw-cstage-top)));
  }

  .aw-resource-actions a {
    min-height: 1.95rem;
    padding-block: 0.3rem 0.25rem;
  }

  .aw-strip-track {
    --aw-strip-cell: clamp(3.4rem, 26svh, 5rem);
  }
}

@media (prefers-reduced-motion: reduce) {
  .aw-ov {
    transform: none;
    transition: opacity 160ms linear, visibility 0s linear 160ms;
  }

  .aw-ov[data-active] {
    transform: none;
    transition: opacity 160ms linear, visibility 0s;
  }

  .aw-scroll-cue span {
    animation: none;
  }

  .aw-cs-cell img {
    transition: none;
  }

  .aw-art-preview img {
    transition: none;
  }

  .aw-strip-track {
    scroll-behavior: auto;
  }

  html {
    scroll-behavior: auto;
  }
}
