/* ============================================================================
   UNIÓN , lane C. Controls, forms and states. Owned by lane C only.

   Everything here composes from css/devices.css and reads css/tokens.css. No hex,
   no font name, no easing curve and no duration is written in this file. The one
   documented system-wide exception applies: #000 / #0000 inside a mask gradient
   are alpha stencils, not colour, and appear only where an edge has to fade.

   Every class is POSITION-INDEPENDENT: no page-level selector, no fixed viewport
   assumption, no outer margin. A control can be lifted into the site or a deck
   slide unchanged.
   ============================================================================ */

/* ---------------------------------------------------------------------------
   Shared furniture for this page's specs only (documentation layout, not brand).
   --------------------------------------------------------------------------- */
.c-row{display:flex;flex-wrap:wrap;gap:var(--s5);align-items:flex-start}
.c-row--tight{gap:var(--s4)}
.c-col{display:flex;flex-direction:column;gap:var(--s4);align-items:flex-start;min-width:0}
.c-cap{display:block;margin-top:var(--s2);max-width:24ch;
  font:700 var(--size-micro)/1.4 var(--font);letter-spacing:var(--track-micro);
  text-transform:uppercase;opacity:.65}
.c-replay{appearance:none;cursor:pointer;background:none;color:inherit;
  border:var(--rule) solid currentColor;padding:var(--s2) var(--s4);min-height:var(--tap-min);
  font:700 var(--size-micro)/1 var(--font);letter-spacing:var(--track-micro);
  text-transform:uppercase;border-radius:var(--radius-slab)}
.c-replay:hover{background:var(--yellow);color:var(--black);border-color:var(--yellow)}
/* a pair of demo controls sitting OUTSIDE the component they drive, so the
   component itself carries only the copy Louis's screenshot shows */
.c-demo-row{display:flex;flex-wrap:wrap;gap:var(--s3)}

/* A mock viewport, for the components that only exist against a page edge (the
   toast, the sheet, the modal, the cookie notice). It is a documentation frame,
   so the component inside it keeps its own real positioning. */
.c-view{position:relative;overflow:hidden;background:var(--cream);color:var(--black);
  border:var(--rule-heavy) solid var(--black);border-radius:var(--radius-slab);
  height:340px;width:100%;max-width:760px;contain:layout paint}
.c-view__inner{padding:var(--s5);height:100%;overflow:hidden}
.c-view__foot{position:absolute;left:0;right:0;bottom:0;z-index:var(--z-chrome);
  display:flex;align-items:center;justify-content:space-between;gap:var(--s4);
  padding:var(--s2) var(--s4);background:var(--black);color:var(--cream)}
.c-view__foot .t-micro{opacity:.7}

/* ============================================================================
   C1 , RIVER-INSIDE BUTTON          starred set-17 Q2
   The control is a solid slab at rest and the river wipes in across its INSIDE,
   so the pattern is what the button is made of underneath. Two directions, one
   mechanism inverted: primary floods in from the leading edge, secondary starts
   as river and drains downward to clear a reading field.

   The label rides on its own cream field, exactly as the wordmark sits on a
   cut-out shape on the patterned cup and ticket. That is the only thing keeping
   it legible once the river is in, and it is why this control is allowed pattern
   at all: nothing is ever read THROUGH the pattern.
   Verb: FLOOD (the river is a colour spreading from an edge).
   ============================================================================ */
.c-river-btn{position:relative;appearance:none;border:0;cursor:pointer;padding:0;
  background:none;isolation:isolate;display:block;text-decoration:none;color:inherit}
.c-river-btn__face{position:relative;display:flex;align-items:center;gap:var(--s4);
  padding:var(--s5) clamp(var(--s5),2.4vw,var(--s6));
  background:var(--black);color:var(--ink-invert);
  border-radius:var(--radius-slab);overflow:hidden;min-height:var(--tap-min);
  transition:transform var(--dur-state) var(--ease-out)}
.c-river-btn__face > u-svg{width:clamp(26px,2.4vw,36px);flex:none;
  position:relative;z-index:var(--z-body)}
/* the reading field: the label's own cream cut-out, never transparent */
.c-river-btn__t{position:relative;z-index:var(--z-body);padding:var(--s1) var(--s3);
  background:var(--cream);color:var(--black);
  font:900 clamp(20px,2vw,30px)/1 var(--font);font-stretch:var(--wdth-condensed);
  text-transform:uppercase;letter-spacing:.01em;white-space:nowrap}
/* the river lives INSIDE and is wiped in from the leading edge */
.c-river-btn__inside{position:absolute;inset:0;z-index:var(--z-river);
  clip-path:inset(0 100% 0 0);
  transition:clip-path var(--dur-flood) var(--ease-verb-flood)}
.c-river-btn:hover .c-river-btn__inside,
.c-river-btn:focus-visible .c-river-btn__inside,
.c-river-btn.is-hover .c-river-btn__inside,
.c-river-btn.is-focus .c-river-btn__inside{clip-path:inset(0 0 0 0)}
.c-river-btn:active .c-river-btn__face,
.c-river-btn.is-active .c-river-btn__face{transform:translateY(3px)}
.c-river-btn.is-focus .c-river-btn__face{outline:var(--focus-width) solid var(--focus-colour-on-dark);
  outline-offset:calc(var(--focus-offset) * -1)}
.c-river-btn:focus-visible .c-river-btn__face{outline-offset:calc(var(--focus-offset) * -1)}
/* DISABLED: the river is removed and the label's cream field drops to the
   hairline. A plain opacity drop renders the black slab GREY against cream, and
   grey is not in this palette. Measured on the first render, where it was the
   ugliest thing on the page. */
.c-river-btn.is-disabled,.c-river-btn[disabled]{pointer-events:none;cursor:not-allowed}
.c-river-btn.is-disabled .c-river-btn__inside,
.c-river-btn[disabled] .c-river-btn__inside{display:none}
.c-river-btn.is-disabled .c-river-btn__t,
.c-river-btn[disabled] .c-river-btn__t{background:var(--hairline);color:var(--cream)}
.c-river-btn.is-disabled .c-river-btn__face > u-svg,
.c-river-btn[disabled] .c-river-btn__face > u-svg{opacity:.35}
/* the ghost inversion: river at rest, the press DRAINS it downward */
.c-river-btn--ghost .c-river-btn__face{background:none;color:var(--ink);
  box-shadow:inset 0 0 0 var(--rule-heavy) var(--black)}
.c-river-btn--ghost .c-river-btn__inside{clip-path:inset(0 0 0 0)}
.c-river-btn--ghost:hover .c-river-btn__inside,
.c-river-btn--ghost:focus-visible .c-river-btn__inside,
.c-river-btn--ghost.is-hover .c-river-btn__inside{clip-path:inset(0 0 100% 0)}
.c-river-btn--ghost.is-focus .c-river-btn__face{outline-color:var(--focus-colour)}

/* ============================================================================
   C2 , THE BUTTON FAMILY. TWO SHAPES, BOTH REAL, ONE DEFAULT.

   MEASURED off the starred shots (L1 at 18.03.20 and Q2 at 18.23.00): the button
   Louis actually starred is a SQUARE pink slab with black condensed 900 caps and
   NO arrow. Not a pill, no radius, no icon. That is `.c-slabbtn` below and it is
   the DEFAULT for anything new.

   The full pill (`.u-pill`, in devices.css) comes from the poster mockups, not
   from a starred screen. It is kept and documented, because the mockups are the
   source of taste, but it is the second option and it is named as such. Every
   starred component on this page keeps its own button exactly as starred.
   ============================================================================ */
/* the STARRED button: a square pink slab. Black condensed caps. No arrow. */
.c-slabbtn{display:inline-flex;align-items:center;justify-content:center;
  appearance:none;cursor:pointer;text-decoration:none;border:0;
  padding:var(--s4) var(--s6);min-height:var(--tap-min);
  background:var(--primary);color:var(--black);border-radius:var(--radius-slab);
  font:900 clamp(17px,1.8vw,22px)/1 var(--font);font-stretch:var(--wdth-condensed);
  text-transform:uppercase;letter-spacing:.04em;
  transition:transform var(--dur-squash) var(--ease-verb-squash),
             background var(--dur-state) var(--ease-out)}
.c-slabbtn:hover,.c-slabbtn.is-hover{transform:scale(1.03,.95)}
.c-slabbtn:active,.c-slabbtn.is-active{transform:scale(.97,1.04)}
.c-slabbtn.is-focus{outline:var(--focus-width) solid var(--focus-colour);
  outline-offset:var(--focus-offset)}
.c-slabbtn.is-disabled,.c-slabbtn[disabled]{cursor:not-allowed;transform:none;
  background:var(--hairline);color:var(--cream)}
/* on a dark ground the focus ring goes yellow, as the system says */
.on-dark .c-slabbtn.is-focus,.spec-stage--black .c-slabbtn.is-focus{
  outline-color:var(--focus-colour-on-dark)}

/* the SECONDARY: square, because a second pill would read as a tab bar */
.c-btn2{display:inline-flex;align-items:center;gap:var(--s4);appearance:none;
  cursor:pointer;text-decoration:none;border:0;
  padding:var(--s4) var(--s5);min-height:var(--tap-min);
  background:var(--dc,var(--primary));color:var(--black);border-radius:var(--radius-slab);
  font:900 clamp(16px,1.6vw,21px)/1 var(--font);font-stretch:var(--wdth-condensed);
  text-transform:uppercase;letter-spacing:.02em;
  transition:transform var(--dur-state) var(--ease-out)}
.c-btn2--ghost{background:none;color:var(--ink);
  box-shadow:inset 0 0 0 var(--rule) currentColor}
.c-btn2 svg{width:30px;height:18px;flex:none}
.c-btn2 svg path{fill:none;stroke:currentColor;stroke-width:4.5;
  stroke-linecap:round;stroke-linejoin:round}
.c-btn2:hover,.c-btn2.is-hover{transform:translateX(var(--s2))}
.c-btn2:active,.c-btn2.is-active{transform:translateX(var(--s2)) scale(1,.95)}
.c-btn2.is-focus{outline:var(--focus-width) solid var(--focus-colour);
  outline-offset:var(--focus-offset)}
/* same ruling as the slab: the hairline, never an opacity drop */
.c-btn2.is-disabled,.c-btn2[disabled]{cursor:not-allowed;transform:none;
  background:var(--hairline);color:var(--cream)}
.c-btn2--ghost.is-disabled,.c-btn2--ghost[disabled]{background:none;color:var(--hairline);
  box-shadow:inset 0 0 0 var(--rule) var(--hairline)}

/* the TEXT LINK: the arrow travels, the underline is a rule at the system weight */
.c-link{display:inline-flex;align-items:center;gap:var(--s3);text-decoration:none;
  color:inherit;min-height:var(--tap-min);
  font:900 var(--size-title)/1 var(--font);font-stretch:var(--wdth-condensed);
  text-transform:uppercase;
  box-shadow:inset 0 calc(var(--rule) * -1) 0 currentColor}
.c-link svg{width:28px;height:17px;flex:none;
  transition:transform var(--dur-state) var(--ease-bounce)}
.c-link svg path{fill:none;stroke:currentColor;stroke-width:4.5;
  stroke-linecap:round;stroke-linejoin:round}
.c-link:hover svg,.c-link.is-hover svg{transform:translateX(var(--s2))}
.c-link.is-focus{outline:var(--focus-width) solid var(--focus-colour);
  outline-offset:var(--focus-offset)}
.c-link.is-disabled{opacity:.45;pointer-events:none}

/* the ICON BUTTON: a square black tile, the wave or a glyph inside it */
.c-iconbtn{display:inline-flex;align-items:center;justify-content:center;
  appearance:none;cursor:pointer;border:0;padding:var(--s3);
  width:var(--tap-min);height:var(--tap-min);flex:none;
  background:var(--black);color:var(--cream);border-radius:var(--radius-slab);
  font:900 var(--size-title)/1 var(--font);font-stretch:var(--wdth-condensed);
  transition:background var(--dur-state) var(--ease-out)}
.c-iconbtn u-svg{width:22px;display:block}
.c-iconbtn:hover,.c-iconbtn.is-hover{background:var(--primary);color:var(--black)}
.c-iconbtn.is-focus{outline:var(--focus-width) solid var(--focus-colour);
  outline-offset:var(--focus-offset)}
/* a SOLID BLACK tile cannot dim by opacity: against cream it renders grey, and
   grey is not in this palette. It loses its fill instead. */
.c-iconbtn.is-disabled,.c-iconbtn[disabled]{cursor:not-allowed;
  background:var(--hairline);color:var(--cream)}

/* ============================================================================
   C3 , STUB-TEAR CONFIRM             starred set-01 A4
   The irreversible yes, made to feel like one. This is .d-stub with the tear
   wired up; no geometry is redefined here. Only the confirm's own affordance
   (the grab line on the tab) and the post-tear message belong to lane C.
   Verb: TEAR.
   ============================================================================ */
.c-tear{display:flex;flex-direction:column;gap:var(--s4);align-items:flex-start;
  max-width:560px}
.c-tear__done{display:none;font:700 var(--size-small)/1.4 var(--font)}
.c-tear.is-done .c-tear__done{display:block}
.c-tear.is-done .c-tear__hint{display:none}
.c-tear__hint{font:700 var(--size-micro)/1.4 var(--font);
  letter-spacing:var(--track-micro);text-transform:uppercase;opacity:.65}

/* ============================================================================
   C4 , STUB STEPPER                  starred set-01 A10
   How many tickets, SEEN not counted: each press stamps another stub into the
   row, springing in from flat. The chips are .d-stub--chip; the stepper's own
   parts are the two square keys and the read-out between them.
   Verb: STAMP (on the arriving chip), SQUASH (on the key).
   ============================================================================ */
.c-step{display:inline-flex;align-items:stretch;border-radius:var(--radius-slab)}
.c-step__key{appearance:none;cursor:pointer;border:0;
  width:var(--tap-min);min-height:var(--tap-min);padding:0 var(--s4);
  background:var(--black);color:var(--cream);
  font:900 clamp(22px,2.2vw,30px)/1 var(--font);font-stretch:var(--wdth-condensed);
  transition:transform var(--dur-squash) var(--ease-verb-squash)}
.c-step__key:hover,.c-step__key.is-hover{background:var(--primary);color:var(--black)}
.c-step__key:active,.c-step__key.is-active{transform:scale(1,.92)}
.c-step__key.is-focus{outline:var(--focus-width) solid var(--focus-colour);
  outline-offset:calc(var(--focus-offset) * -1)}
/* same ruling as the icon button: the black key loses its fill, not its opacity */
.c-step__key[disabled]{cursor:not-allowed;background:var(--hairline);color:var(--cream)}
.c-step__n{display:flex;align-items:center;justify-content:center;min-width:72px;
  padding:0 var(--s4);background:var(--cream);color:var(--black);
  font:900 clamp(24px,2.6vw,34px)/1 var(--font);font-stretch:var(--wdth-condensed)}
.c-step__row{display:flex;gap:var(--s2);align-items:flex-end;flex-wrap:wrap;min-height:92px}
.c-step__note{font:700 var(--size-micro)/1 var(--font);letter-spacing:var(--track-micro);
  text-transform:uppercase;opacity:.65;align-self:center}

/* ============================================================================
   C5 , TOGGLE, TICK AND STAGE DOT , starred set-01 A7. THE APPROVED COMPONENT.

   PORTED, NOT REDESIGNED (Louis's rule, 20 Sep). This is the control Louis
   starred, carried over the same: same look, same proportions, same mechanism,
   same copy. The only changes are raw values swapped for tokens.

   MEASURED off the starred shot (18.01.11) and the lab source:
     toggle   132x56 black slab, 6px inset, a 60x44 knob that travels 60px and
              turns pink when on; the word sits opposite the knob in cream
     tick     44px cream square, heavy black rule, the stroke DRAWN by
              stroke-dashoffset, ground turns yellow when checked
     dot      34px circle, black ring, filled by inset box-shadow in stage colour
   Verbs: the knob travels, the tick DRAWS, the dot fills.
   ============================================================================ */
/* --- the toggle. A black slab with a travelling knob. --- */
.c-tog{appearance:none;border:0;cursor:pointer;background:var(--black);padding:6px;
  width:132px;height:56px;position:relative;display:block;
  border-radius:var(--radius-slab)}
.c-tog__knob{position:absolute;top:6px;left:6px;width:60px;height:44px;
  background:var(--cream);border-radius:var(--radius-slab);
  transition:transform var(--dur-bounce) var(--ease-verb-bounce),
             background var(--dur-state) var(--ease-out)}
.c-tog[aria-pressed="true"] .c-tog__knob,
.c-tog[aria-checked="true"] .c-tog__knob{transform:translateX(60px);background:var(--primary)}
.c-tog em{position:absolute;right:14px;top:50%;transform:translateY(-50%);
  color:var(--ink-invert);font:900 14px/1 var(--font);font-stretch:var(--wdth-condensed);
  text-transform:uppercase;letter-spacing:.08em;font-style:normal}
.c-tog[aria-pressed="true"] em,
.c-tog[aria-checked="true"] em{right:auto;left:16px;color:var(--ink-invert)}
.c-tog:focus-visible,.c-tog.is-focus{outline:var(--focus-width) solid var(--focus-colour);
  outline-offset:var(--focus-offset)}
/* DISABLED, measured on the render: a plain opacity drop turns the black slab
   GREY against cream, and grey is not in this palette. It is also the exact tell
   of the stock widget the starred build was marked down for. So a disabled
   control keeps its black and loses its contents instead: the knob and the word
   go to the hairline, which is black at 25% and is already a system value. */
.c-tog.is-disabled,.c-tog[disabled]{cursor:not-allowed}
.c-tog.is-disabled .c-tog__knob,.c-tog[disabled] .c-tog__knob{background:var(--hairline)}
.c-tog.is-disabled em,.c-tog[disabled] em{opacity:.4}

/* --- the tick. A cream square, the stroke drawn along its own length. --- */
.c-cb{display:flex;align-items:center;gap:14px;cursor:pointer;min-height:var(--tap-min);
  font:900 20px/1 var(--font);font-stretch:var(--wdth-condensed);text-transform:uppercase}
.c-cb input{position:absolute;opacity:0;width:0;height:0}
.c-cb__box{width:44px;height:44px;flex:0 0 44px;background:var(--cream);position:relative;
  border-radius:var(--radius-slab);box-shadow:inset 0 0 0 var(--rule-heavy) var(--black);
  transition:background var(--dur-state) var(--ease-out)}
.c-cb__box svg{position:absolute;inset:6px;width:auto;height:auto}
.c-cb__box path{stroke:var(--black);stroke-width:9;stroke-linecap:round;stroke-linejoin:round;
  fill:none;stroke-dasharray:44;stroke-dashoffset:44;
  transition:stroke-dashoffset var(--dur-draw) var(--ease-verb-draw)}
.c-cb input:checked + .c-cb__box,.c-cb.is-checked .c-cb__box{background:var(--care)}
.c-cb input:checked + .c-cb__box path,
.c-cb.is-checked .c-cb__box path{stroke-dashoffset:0}
.c-cb input:focus-visible + .c-cb__box,
.c-cb.is-focus .c-cb__box{outline:var(--focus-width) solid var(--focus-colour);
  outline-offset:var(--focus-offset)}
.c-cb.is-error .c-cb__box{box-shadow:inset 0 0 0 var(--rule-heavy) var(--black),
  inset 0 0 0 9px var(--coral)}
/* same ruling as the toggle: dim the RULE to the hairline rather than dropping
   the whole control's opacity, which renders the black edge as grey */
.c-cb.is-disabled{pointer-events:none;color:var(--hairline)}
.c-cb.is-disabled .c-cb__box{box-shadow:inset 0 0 0 var(--rule-heavy) var(--hairline)}
.c-r.is-disabled{pointer-events:none;color:var(--hairline)}
.c-r.is-disabled .c-r__dot{box-shadow:inset 0 0 0 var(--rule-heavy) var(--hairline)}
@media (prefers-reduced-motion:reduce){.c-cb__box path{transition:none}}

/* --- the stage dot. A ring that fills with its stage colour. --- */
.c-rad{display:flex;flex-direction:column;gap:10px}
.c-r{display:flex;align-items:center;gap:14px;cursor:pointer;min-height:var(--tap-min);
  font:900 20px/1 var(--font);font-stretch:var(--wdth-condensed);text-transform:uppercase}
.c-r input{position:absolute;opacity:0;width:0;height:0}
.c-r__dot{width:34px;height:34px;flex:0 0 34px;border-radius:var(--radius-round);
  background:transparent;box-shadow:inset 0 0 0 var(--rule-heavy) var(--black);
  transition:box-shadow var(--dur-bounce) var(--ease-verb-bounce)}
.c-r input:checked + .c-r__dot,
.c-r.is-selected .c-r__dot{box-shadow:inset 0 0 0 17px var(--stage)}
.c-r input:focus-visible + .c-r__dot,
.c-r.is-focus .c-r__dot{outline:var(--focus-width) solid var(--focus-colour);
  outline-offset:var(--focus-offset)}

/* ============================================================================
   C5p , PROPOSAL, NOT APPROVED. The same three decisions as festival objects.
   Kept beside the approved control, never in place of it. Louis has not seen or
   signed this off; nothing may ship it until he has.
     the toggle as a MIXER FADER on a totem-bar track
     the tick as a DRAWN stroke that overshoots its box
     the radio as a SOUNDWAVE BAR that stands up in its stage colour
   Verbs: SQUASH (the fader lands), DRAW (the tick), BOUNCE (the bar stands).
   ============================================================================ */
/* --- the fader. A short totem bar laid flat, with a heavy cap riding it. --- */
.c-fader{display:inline-flex;align-items:center;gap:var(--s4)}
.c-fader__sw{appearance:none;cursor:pointer;border:0;padding:0;background:none;
  position:relative;display:block;
  width:132px;height:var(--tap-min);flex:none}
/* the track IS a totem bar: square, full-bleed colour, black rule under it */
.c-fader__track{position:absolute;left:0;right:0;top:50%;transform:translateY(-50%);
  height:16px;background:var(--hairline);border-radius:var(--radius-slab)}
.c-fader__track::before{content:"";position:absolute;inset:0;background:var(--dc,var(--primary));
  transform-origin:0 50%;transform:scaleX(0);
  transition:transform var(--dur-bounce) var(--ease-verb-bounce)}
/* the cap: a square fader knob with its own grip lines, like a mixer */
.c-fader__cap{position:absolute;top:0;bottom:0;left:0;width:44px;
  background:var(--black);border-radius:var(--radius-slab);
  display:flex;align-items:center;justify-content:center;gap:3px;
  transition:transform var(--dur-bounce) var(--ease-verb-bounce)}
.c-fader__cap i{display:block;width:3px;height:16px;background:var(--cream)}
.c-fader__sw[aria-checked="true"] .c-fader__cap{transform:translateX(88px)}
.c-fader__sw[aria-checked="true"] .c-fader__track::before{transform:scaleX(1)}
.c-fader__sw:focus-visible,.c-fader__sw.is-focus{outline:var(--focus-width) solid var(--focus-colour);
  outline-offset:var(--focus-offset)}
.c-fader__sw.is-disabled,.c-fader__sw[disabled]{cursor:not-allowed}
.c-fader__sw.is-disabled .c-fader__cap,
.c-fader__sw[disabled] .c-fader__cap{background:var(--hairline)}
.c-fader__state{font:900 var(--size-title)/1 var(--font);font-stretch:var(--wdth-condensed);
  text-transform:uppercase;min-width:4ch}

/* --- the tick. A drawn ribbon stroke, in the brand's fat round-ended weight.
   The box is square and the stroke overshoots it, the way a hand-drawn tick
   does, so it never reads as a form widget. --- */
.c-check{display:flex;align-items:center;gap:var(--s4);cursor:pointer;
  min-height:var(--tap-min);
  font:900 clamp(17px,1.8vw,22px)/1.05 var(--font);font-stretch:var(--wdth-condensed);
  text-transform:uppercase}
.c-check input{position:absolute;opacity:0;width:1px;height:1px;margin:0;pointer-events:none}
.c-check__box{position:relative;width:40px;height:40px;flex:none;
  background:var(--cream);border-radius:var(--radius-slab);
  box-shadow:inset 0 0 0 var(--rule-heavy) var(--black);
  transition:background var(--dur-flood) var(--ease-verb-flood)}
.c-check__box svg{position:absolute;left:-14%;top:-24%;width:128%;height:128%;
  overflow:visible}
.c-check__box svg path{fill:none;stroke:var(--black);stroke-width:9;
  stroke-linecap:round;stroke-linejoin:round;
  stroke-dasharray:64;stroke-dashoffset:64;
  transition:stroke-dashoffset var(--dur-draw) var(--ease-verb-draw)}
.c-check input:checked ~ .c-check__box{background:var(--dc,var(--care))}
.c-check input:checked ~ .c-check__box svg path{stroke-dashoffset:0}
.c-check input:focus-visible ~ .c-check__box,
.c-check.is-focus .c-check__box{outline:var(--focus-width) solid var(--focus-colour);
  outline-offset:var(--focus-offset)}
.c-check:hover .c-check__box,.c-check.is-hover .c-check__box{background:var(--dc,var(--care))}
.c-check:hover input:not(:checked) ~ .c-check__box{opacity:.5}
.c-check.is-checked .c-check__box{background:var(--dc,var(--care))}
.c-check.is-checked .c-check__box svg path{stroke-dashoffset:0}
.c-check.is-disabled{opacity:.45;pointer-events:none}
.c-check.is-error .c-check__box{box-shadow:inset 0 0 0 var(--rule-heavy) var(--black),
  inset 0 0 0 9px var(--coral)}
@media (prefers-reduced-motion:reduce){
  .c-check__box svg path{transition:none}
}

/* --- the stage choice. A soundwave BAR that stands up in its stage colour.
   Not a dot: the mark itself is the selection, standing to attention. --- */
.c-stage{display:flex;align-items:center;gap:var(--s4);cursor:pointer;
  min-height:var(--tap-min);
  font:900 clamp(17px,1.8vw,22px)/1.05 var(--font);font-stretch:var(--wdth-condensed);
  text-transform:uppercase}
.c-stage input{position:absolute;opacity:0;width:1px;height:1px;margin:0;pointer-events:none}
.c-stage__bars{display:flex;align-items:flex-end;gap:4px;height:40px;flex:none;
  width:40px;padding-bottom:2px;
  box-shadow:inset 0 calc(var(--rule) * -1) 0 var(--hairline)}
/* the bars must each be full height and scale DOWN from their own baseline; with
   flex:1 1 0 they collapsed to a line at rest, which is what the first render of
   the proposal showed */
.c-stage__bars i{display:block;width:10px;height:100%;flex:none;background:var(--stage);
  transform-origin:50% 100%;transform:scaleY(.14);opacity:.35;
  border-radius:var(--radius-slab);
  transition:transform var(--dur-bounce) var(--ease-verb-bounce),
             opacity var(--dur-state) var(--ease-out)}
/* PROPOSED TOKENS: --stagger-1 / --stagger-2, the two step delays a three-part
   device uses when its parts arrive in sequence. Listed in evidence/C.md for the
   planner to merge into tokens.css. Declared locally so no raw ms is written. */
.c-stage__bars{--stagger-1:60ms;--stagger-2:120ms}
.c-stage__bars i:nth-child(2){transition-delay:var(--stagger-1)}
.c-stage__bars i:nth-child(3){transition-delay:var(--stagger-2)}
.c-stage input:checked ~ .c-stage__bars i,
.c-stage.is-selected .c-stage__bars i{opacity:1}
.c-stage input:checked ~ .c-stage__bars i:nth-child(1),
.c-stage.is-selected .c-stage__bars i:nth-child(1){transform:scaleY(.72)}
.c-stage input:checked ~ .c-stage__bars i:nth-child(2),
.c-stage.is-selected .c-stage__bars i:nth-child(2){transform:scaleY(1)}
.c-stage input:checked ~ .c-stage__bars i:nth-child(3),
.c-stage.is-selected .c-stage__bars i:nth-child(3){transform:scaleY(.6)}
.c-stage:hover .c-stage__bars i,.c-stage.is-hover .c-stage__bars i{opacity:.7}
.c-stage input:focus-visible ~ .c-stage__bars,
.c-stage.is-focus .c-stage__bars{outline:var(--focus-width) solid var(--focus-colour);
  outline-offset:var(--focus-offset)}
.c-stage.is-disabled{opacity:.45;pointer-events:none}

/* ============================================================================
   C6 , EN / ES STICKER PRESS         starred set-02 N10
   The sticker bubble's fat rounded outline as the track; the knob presses across
   and the chosen label squashes like the bubble lettering. This is
   .d-sticker--switch from devices.css. Lane C adds NOTHING to its geometry: only
   the round cut, because the starred shot's track is fully round, and the device
   default is square.
   Verb: SQUASH.
   ============================================================================ */
/* The planner has fixed .d-sticker--switch in css/devices.css to match N10: a
   rounded outlined track with the knob sitting under ONE label. It is used here
   exactly as it ships. Lane C adds NOTHING to it, so there is no rule in this
   file for the switch at all. */

/* ============================================================================
   C9p , PROPOSAL, NOT APPROVED. The same toast with the verb changed from a
   slide to a DROP with the label stamping. Kept beside the approved one.
   ============================================================================ */
.c-toast-dock--p{position:absolute;left:var(--s5);right:var(--s5);bottom:var(--s8);
  z-index:var(--z-overlay);display:flex;flex-direction:column;gap:var(--s3);
  pointer-events:none;align-items:flex-start}
.c-toast-dock--p > *{pointer-events:auto;max-width:460px}

/* ============================================================================
   C7 , SOLD-OUT STAMP                starred set-03 A10
   A tier that has gone, without the page going dead: the pink label-in-slab
   STAMPS down over the stub at an angle, the stub's own copy drops back, and the
   waitlist turns yellow to become the live control.
   Verb: STAMP.
   ============================================================================ */
.c-sold{position:relative;display:block;max-width:420px;width:100%}
/* the tier card itself is a black slab with a pink perforation across it, as in
   the starred shot: a ticket drawn flat, not a .d-stub with a tab. */
.c-sold__card{background:var(--black);color:var(--ink-invert);
  border-radius:var(--radius-slab);padding:var(--s5);
  display:flex;flex-direction:column;gap:var(--s4);
  transition:opacity var(--dur-stamp) var(--ease-out)}
.c-sold__perf{height:3px;background:repeating-linear-gradient(90deg,
  var(--dc,var(--primary)) 0 9px,transparent 9px 18px)}
.c-sold__t{margin:0;font:900 clamp(26px,3.2vw,40px)/.92 var(--font);
  font-stretch:var(--wdth-condensed);text-transform:uppercase}
.c-sold__meta{margin:0;font:700 var(--size-micro)/1.5 var(--font);
  letter-spacing:var(--track-micro);text-transform:uppercase;opacity:.85}
/* the stamp: the poster's own label-in-slab, thrown down at an angle */
.c-sold__stamp{position:absolute;left:50%;top:44%;z-index:var(--z-raise);
  transform:translate(-50%,-50%) rotate(-8deg);
  display:none;padding:var(--s3) var(--s5);
  background:var(--primary);color:var(--black);border-radius:var(--radius-slab);
  box-shadow:0 0 0 var(--rule-heavy) var(--black);
  font:900 clamp(26px,3.4vw,44px)/1 var(--font);font-stretch:var(--wdth-condensed);
  text-transform:uppercase;letter-spacing:.02em;white-space:nowrap}
.c-sold.is-sold .c-sold__stamp{display:block}
/* the copy DROPS BACK, so the stamp is the only thing that reads */
.c-sold.is-sold .c-sold__t,.c-sold.is-sold .c-sold__meta{opacity:.3}
/* and the waitlist turns yellow to become the live control */
.c-sold.is-sold .c-btn2{--dc:var(--care)}

/* ============================================================================
   C8 , RIBBON SKELETON , starred set-03 A5. THE APPROVED COMPONENT.

   PORTED, NOT REDESIGNED. This is the skeleton Louis starred, carried over the
   same. MEASURED off the starred shot (18.28.40) and the lab source: each line
   is a round-ended stroke at clamp(24px,3.4vw,34px) tall, at its own length,
   cycling pink / coral / yellow / black / coral down the rows, scaling from
   scaleX(.12) to 1 and back on a 1.6s loop staggered 120ms a row. The time sits
   in a 78px column at 30% opacity. No grey bars: the placeholder is the stage's
   own colour.
   Verb: DRAW.
   ============================================================================ */
.c-skel-a{display:flex;flex-direction:column;gap:clamp(var(--s4),2.2vw,var(--s6));
  width:100%;max-width:620px}
.c-skel-a__hd{display:flex;gap:0}
.c-skel-a__hd b{background:var(--primary);color:var(--black);padding:7px 10px;
  font:900 12px/1 var(--font);font-stretch:var(--wdth-condensed);
  text-transform:uppercase;letter-spacing:.1em}
.c-skel-a__hd i{background:var(--black);color:var(--ink-invert);padding:7px 10px;
  font-style:normal;font:700 12px/1 var(--font);letter-spacing:var(--track-micro);
  text-transform:uppercase}
.c-skel-a__row{display:grid;grid-template-columns:78px 1fr;align-items:center;gap:14px}
.c-skel-a__row time{font:900 clamp(17px,2vw,24px)/1 var(--font);
  font-stretch:var(--wdth-condensed);opacity:.3}
.c-skel-a__line{position:relative;height:clamp(24px,3.4vw,34px);width:var(--len,80%)}
/* the stroke: a fat round-ended bar, which is what .d-ribbon--bar already is */
.c-skel-a__line b{position:absolute;inset:0;display:block;
  border-radius:var(--radius-round);background:var(--primary);transform-origin:0 50%}
/* the colour cycle counts the ROWS, not the stack's children: the head block is
   also a child, so nth-child would shift every colour by one and the 22:00 row
   would come up coral instead of pink. nth-of-type on .c-skel-a__row is wrong
   too (they are all divs), so the rows are counted among themselves. */
.c-skel-a__row:nth-of-type(2) .c-skel-a__line b{background:var(--coral)}
.c-skel-a__row:nth-of-type(3) .c-skel-a__line b{background:var(--yellow)}
.c-skel-a__row:nth-of-type(4) .c-skel-a__line b{background:var(--black)}
.c-skel-a__row:nth-of-type(5) .c-skel-a__line b{background:var(--coral)}
.c-skel-a.is-loading .c-skel-a__line b{animation:c-skel-a-draw 1.6s var(--ease-out) infinite}
.c-skel-a.is-loading .c-skel-a__row:nth-of-type(2) .c-skel-a__line b{animation-delay:.12s}
.c-skel-a.is-loading .c-skel-a__row:nth-of-type(3) .c-skel-a__line b{animation-delay:.24s}
.c-skel-a.is-loading .c-skel-a__row:nth-of-type(4) .c-skel-a__line b{animation-delay:.36s}
.c-skel-a.is-loading .c-skel-a__row:nth-of-type(5) .c-skel-a__line b{animation-delay:.48s}
@keyframes c-skel-a-draw{0%{transform:scaleX(.12)}44%{transform:scaleX(1)}
  100%{transform:scaleX(1)}}
@media (prefers-reduced-motion:reduce){
  .c-skel-a.is-loading .c-skel-a__line b{animation:none;transform:scaleX(1);opacity:.3}
}

/* ============================================================================
   C8p , PROPOSAL, NOT APPROVED. The same skeleton with the pills replaced by
   real UNION_RIBBON strokes, inlined through <u-svg> and wiped along their own
   length. Kept beside the approved one, never in place of it.
   Verb: DRAW.
   ============================================================================ */
.c-skel{display:flex;flex-direction:column;gap:var(--s5);width:100%;max-width:620px}
.c-skel__hd{display:flex;align-items:stretch;gap:0}
.c-skel__row{display:grid;grid-template-columns:auto 1fr;align-items:center;
  gap:var(--s5);min-height:46px}
.c-skel__time{font:900 clamp(20px,2.2vw,28px)/1 var(--font);
  font-stretch:var(--wdth-condensed);opacity:.35;min-width:5ch}
/* the stroke: a REAL ribbon asset, clipped to nothing and wiped along its length */
.c-skel__stroke{position:relative;display:block;overflow:hidden;
  clip-path:inset(0 100% 0 0);
  animation:c-skel-draw var(--dur-draw) var(--ease-verb-draw) forwards}
.c-skel__stroke u-svg{display:block;width:100%}
.c-skel__stroke u-svg svg{display:block;width:100%;height:auto}
.c-skel__row:nth-child(2) .c-skel__stroke{animation-delay:.10s}
.c-skel__row:nth-child(3) .c-skel__stroke{animation-delay:.20s}
.c-skel__row:nth-child(4) .c-skel__stroke{animation-delay:.30s}
.c-skel__row:nth-child(5) .c-skel__stroke{animation-delay:.40s}
.c-skel__row:nth-child(6) .c-skel__stroke{animation-delay:.50s}
@keyframes c-skel-draw{to{clip-path:inset(0 0 0 0)}}
/* the still, forced state: every stroke shown fully drawn, no animation */
.c-skel.is-loading .c-skel__stroke{animation:none;clip-path:inset(0 0 0 0)}
@media (prefers-reduced-motion:reduce){
  .c-skel__stroke{animation:none;clip-path:inset(0 0 0 0)}
}

/* ============================================================================
   C9 , LABEL-IN-SLAB TOAST , starred set-03 A7. THE APPROVED COMPONENT.

   PORTED, NOT REDESIGNED. MEASURED off the lab source: the dock sits 14px from
   each side and 16px from the foot; the toast is a black slab with a coloured
   tag flush at its left edge, arriving from translateY(130%) on the bounce ease
   over .55s and leaving the same way on ease-in over .4s. Pink tag for a save,
   yellow for a clash, coral for offline.
   Verb: the tag bar arrives from its own edge.
   ============================================================================ */
.c-toast-dock{position:absolute;left:14px;right:14px;bottom:16px;
  z-index:var(--z-overlay);display:flex;flex-direction:column;gap:var(--s2);
  pointer-events:none;align-items:stretch}
.c-toast-dock > *{pointer-events:auto}
.c-toast{display:flex;align-items:stretch;background:var(--black);color:var(--ink-invert);
  border-radius:var(--radius-slab);transform:translateY(130%);opacity:0;
  will-change:transform}
.c-toast.is-in{animation:c-toast-in .55s var(--ease-bounce) forwards}
@keyframes c-toast-in{to{transform:translateY(0);opacity:1}}
.c-toast.is-out{animation:c-toast-out .4s var(--ease-in) forwards}
@keyframes c-toast-out{to{transform:translateY(130%);opacity:0}}
/* the still, forced state: the toast shown landed, so it reads in a screenshot */
.c-toast.is-shown{transform:none;opacity:1}
.c-toast__tag{background:var(--primary);color:var(--black);display:flex;align-items:center;
  padding:0 12px;font:900 12px/1 var(--font);font-stretch:var(--wdth-condensed);
  text-transform:uppercase;letter-spacing:.1em;flex:none}
.c-toast--clash .c-toast__tag{background:var(--care)}
.c-toast--offline .c-toast__tag{background:var(--coral)}
.c-toast__body{padding:12px 14px;font:700 var(--size-small)/1.3 var(--font)}
@media (prefers-reduced-motion:reduce){
  .c-toast{transform:none;opacity:1}
  .c-toast.is-in,.c-toast.is-out{animation:none}
}

/* ============================================================================
   C10 , LIVE ALERT TOTEM BAR         starred set-03 A8
   The totem bar with the soundwave pulsing at one end as a live light, the
   message running as a slow marquee, stage colour saying which stage before a
   word is read. This is .d-totem__bar--alert, unchanged. Lane C owns only the
   stack that shows two of them at once.
   ============================================================================ */
.c-alerts{display:flex;flex-direction:column;gap:var(--s5);width:100%}

/* LOCAL OVERRIDE of shared .d-totem__bar--alert, measured off Louis's A8 shot
   (18.02.17, a 2x capture of a 759px-wide window). His live light is TWO upright
   bars on a 33px black end block, each bar 6px wide and 24.5px tall, and there is
   NO close button. The shared device ships three shorter bars in a 60px block and
   a close. Band height (42px), heavy rules (3px) and cap height (12.5px) already
   matched his, so only the end block is corrected here. Raised to lane C, because
   devices.html shows the same device and I do not own that file. */
.c-alerts .d-totem__pulse,
.spec-states .d-totem__bar--alert .d-totem__pulse{padding:0 var(--s2);gap:5px}
/* His bars stand at FULL height and dip; the shared device rests at scaleY(.3)
   and grows, so a screenshot catches two stubs about a third of his. Rest tall,
   pulse down: the same live light, correct at any frame rather than at one. */
.c-alerts .d-totem__pulse i,
.spec-states .d-totem__bar--alert .d-totem__pulse i{height:25px;transform:scaleY(1)}
.c-alerts .d-totem__bar--alert.is-live .d-totem__pulse i,
.spec-states .d-totem__bar--alert.is-live .d-totem__pulse i{
  animation:c-pulse-down .7s ease-in-out infinite alternate}
@keyframes c-pulse-down{to{transform:scaleY(.42)}}
.c-alerts .d-totem__x{display:none}
@media (prefers-reduced-motion:reduce){
  .c-alerts .d-totem__bar--alert.is-live .d-totem__pulse i,
  .spec-states .d-totem__bar--alert.is-live .d-totem__pulse i{
    animation:none;transform:scaleY(1)}
}

/* ============================================================================
   C11 , DOORS COUNTDOWN              starred set-11 T8 , unscored
   Each digit is a solid block with the next digit on its next face; the block
   turns a QUARTER to change the number, so a minute passing is a physical event.
   CSS 3D, no WebGL, as briefed. Built as a four-faced cube turning on X.

   MEASURED off T8 at 17.55.44: the faces are CREAM with black digits, on a coral
   ground, the blocks butt up against each other with a visible dark side wall, and
   the separator is two square dots, not a colon glyph.
   Verb: its own quarter turn, on the bounce ease.
   ============================================================================ */
/* MEASURED off T8 at 17.55.44 (a 2x capture of a 1599px-wide window), all figures
   in CSS px and as a share of the STAGE, because the lab sized by viewport and had
   no sidebar:
     four blocks, CENTRED       group 477px wide = 29.8% of the stage
     block                      100px wide x 135px tall (1 : 1.35, the lab's 1.5 x 2.0 box)
     within a pair              11px apart          between the pairs  46px (the colon)
     digit                      about 60px tall, condensed 900
     caption + button           bottom LEFT, button 130 x 40px, outlined
   No HOURS / MINUTES labels: his shot has none, and the port carries no addition.
   The block is a real object: a cream face standing proud of a warm-black SIDE, so
   the thickness is visible at rest rather than implied by a rule. CSS 3D, no WebGL. */
.c-count-stage{display:flex;flex-direction:column;justify-content:center;
  min-height:clamp(320px,34vw,430px)}
/* the eye sits LEFT of the row and a touch above it, which is the view his shot
   was taken from: every block shows its right side wall, and the top edge of each
   face catches a little of the turn. Centre the origin and the walls vanish. */
.c-count{--cd:clamp(46px,8.4vw,100px);
  display:flex;align-items:center;justify-content:center;flex:1 1 auto;
  perspective:2600px;perspective-origin:34% 44%}
/* the colon: two square dots at the block's own scale, sitting in the wider gap
   between the pairs. Not a glyph. */
.c-count__sep{display:flex;flex-direction:column;justify-content:center;
  gap:calc(var(--cd) * .20);
  padding:0 calc(var(--cd) * .23);align-self:center}
.c-count__sep i{display:block;width:calc(var(--cd) * .13);height:calc(var(--cd) * .13);
  background:var(--black)}
/* the whole row is turned a few degrees on Y, the way the lab's camera sits off
   the axis: without it every block is edge-on and the thickness is invisible at
   rest, which is the drift his shot catches. --cy is that angle, one place. */
.c-count{--cy:-7deg}
.c-count__d{--turn:0deg;position:relative;width:var(--cd);height:calc(var(--cd) * 1.35);
  flex:none;transform-style:preserve-3d;
  transform:rotateY(var(--cy)) rotateX(var(--turn));
  transition:transform var(--dur-drop) var(--ease-verb-drop)}
/* HH:MM is two TIGHT pairs, not four evenly spaced blocks: 11px inside a pair
   against the colon's 46px between them, measured off his shot. */
.c-count__d + .c-count__d{margin-left:calc(var(--cd) * .11)}
.c-count__d[data-face="1"]{--turn:-90deg}
.c-count__d[data-face="2"]{--turn:-180deg}
.c-count__d[data-face="3"]{--turn:-270deg}
/* THE THICKNESS. In his shot it reads as a narrow dark strip down the RIGHT of
   each block: the camera sits a little left of centre, so the block's right side
   wall is the one turned towards you, and that strip is what makes a quarter turn
   read as an object moving rather than a card swapping.
   The four faces already close the box around the X axis; what is open is the two
   ENDS, and the right-hand one is the strip you see. It is the block's own depth
   wide and CENTRED in that depth, so it turns with the block and stays inside its
   footprint. Hinging it on the edge (the first build) swung it out of the top of
   the block as a black spike on every mid-turn. */
.c-count__d::after{content:"";position:absolute;top:0;bottom:0;
  left:50%;width:calc(var(--cd) * 1.35);margin-left:calc(var(--cd) * -.675);
  background:var(--black);backface-visibility:hidden;
  transform:rotateY(90deg) translateZ(calc(var(--cd) * .5))}
.c-count__f{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  background:var(--cream);color:var(--black);border-radius:var(--radius-slab);
  font:900 calc(var(--cd) * .80)/1 var(--font);font-stretch:var(--wdth-condensed);
  letter-spacing:-.02em;backface-visibility:hidden}
/* No rule on the face: his are plain cream, and the thing that separates one
   block from the next is the SIDE, not an outline. The flat fallback puts the
   rule back, because with no depth there is nothing else to hold the edge. */
/* the four faces, each a quarter turn round X, pushed out by HALF THE HEIGHT so
   they meet at the block's own edges and enclose the side walls */
.c-count__f:nth-child(1){transform:translateZ(calc(var(--cd) * .675))}
.c-count__f:nth-child(2){transform:rotateX(90deg) translateZ(calc(var(--cd) * .675))}
.c-count__f:nth-child(3){transform:rotateX(180deg) translateZ(calc(var(--cd) * .675))}
.c-count__f:nth-child(4){transform:rotateX(270deg) translateZ(calc(var(--cd) * .675))}
/* the FLAT FALLBACK, declared as a real option rather than a rescue: if the 3D
   does not hold, the same block swaps faces with no depth. Set .c-count--flat. */
.c-count--flat{perspective:none;--cy:0deg}
.c-count--flat .c-count__d{transform-style:flat;transform:none}
.c-count--flat .c-count__d::after{display:none}
.c-count--flat .c-count__f{backface-visibility:visible;opacity:0;transform:none;
  box-shadow:inset 0 0 0 var(--rule) var(--black);
  transition:opacity var(--dur-state) var(--ease-out)}
.c-count--flat .c-count__d[data-face="0"] .c-count__f:nth-child(1),
.c-count--flat .c-count__d[data-face="1"] .c-count__f:nth-child(2),
.c-count--flat .c-count__d[data-face="2"] .c-count__f:nth-child(3),
.c-count--flat .c-count__d[data-face="3"] .c-count__f:nth-child(4){opacity:1}
/* The state cells stand on a coral pad, because a rule-less cream face is
   invisible on the page's cream ground and the block only ever lives on coral.
   Showing it on the wrong ground would document a component that does not exist. */
.c-count-pad{background:var(--coral);padding:var(--s5) var(--s5) var(--s6);
  align-self:stretch}
/* his caption and his button, bottom left under the stage, on one line */
.c-count-foot{display:flex;flex-wrap:wrap;align-items:center;gap:var(--s4) var(--s7);
  margin-top:var(--s7)}
.c-count-cap{margin:0;font:700 var(--size-micro)/1.4 var(--font);
  letter-spacing:var(--track-micro);text-transform:uppercase;color:var(--black)}
.c-count-btn{appearance:none;cursor:pointer;background:var(--cream);color:var(--black);
  border:var(--rule-heavy) solid var(--black);border-radius:var(--radius-slab);
  padding:var(--s3) var(--s5);min-height:var(--tap-min);
  font:700 var(--size-micro)/1 var(--font);letter-spacing:var(--track-micro);
  text-transform:uppercase}
.c-count-btn:hover{background:var(--black);color:var(--cream)}
@media (prefers-reduced-motion:reduce){.c-count__d{transition:none}}
@media (max-width:700px){.c-count{--cd:clamp(42px,15vw,64px)}}

/* ============================================================================
   C12 , THE FORM. Text, email, select, textarea, search.
   Square, heavy-ruled, cream field, black ink. A field is a slab you write in, so
   it takes the slab's shape and the system's rule weight. No rounded input exists.
   ============================================================================ */
.c-field{display:flex;flex-direction:column;gap:var(--s2);min-width:0;width:100%;
  max-width:420px}
.c-field__l{font:700 var(--size-micro)/1 var(--font);letter-spacing:var(--track-micro);
  text-transform:uppercase}
.c-field__i{appearance:none;width:100%;min-height:var(--tap-min);
  padding:var(--s3) var(--s4);background:var(--cream);color:var(--black);
  border:0;box-shadow:inset 0 0 0 var(--rule-heavy) var(--black);
  border-radius:var(--radius-slab);
  font:400 var(--size-body)/1.4 var(--font);
  transition:box-shadow var(--dur-state) var(--ease-out)}
.c-field__i::placeholder{color:var(--black);opacity:.4}
.c-field__i:hover,.c-field__i.is-hover{box-shadow:inset 0 0 0 var(--rule-heavy) var(--black),
  inset 0 calc(var(--s1) * -1) 0 var(--primary)}
.c-field__i:focus-visible,.c-field__i.is-focus{outline:var(--focus-width) solid var(--focus-colour);
  outline-offset:var(--focus-offset)}
/* the field's heavy BLACK rule greys out under opacity, so the rule itself steps
   down to the hairline and the field keeps its cream */
.c-field__i[disabled],.c-field__i.is-disabled{cursor:not-allowed;color:var(--hairline);
  box-shadow:inset 0 0 0 var(--rule-heavy) var(--hairline)}
textarea.c-field__i{min-height:128px;resize:vertical}
/* the select keeps its native menu and takes a SOLID arrow, drawn as the system's */
.c-field__sel{position:relative;display:block}
.c-field__sel select{appearance:none;padding-right:var(--s8)}
/* the arrow path is already drawn pointing DOWN, so it takes no rotation. The
   first render rotated it and it pointed left. */
.c-field__sel svg{position:absolute;right:var(--s4);top:50%;width:22px;height:14px;
  transform:translateY(-50%);pointer-events:none}
.c-field__sel svg path{fill:currentColor;stroke:none}
.c-field__h{font:400 var(--size-small)/1.4 var(--font);opacity:.7}
/* the messages. Error is CORAL as a rule, never red; success is YELLOW, the
   system's "done" colour, as on the torn stub. Both carry a word, never a colour
   on its own. */
.c-field__m{display:flex;align-items:center;gap:var(--s2);
  font:700 var(--size-small)/1.3 var(--font)}
.c-field--error .c-field__i{box-shadow:inset 0 0 0 var(--rule-heavy) var(--black),
  inset 0 0 0 7px var(--coral)}
.c-field--success .c-field__i{box-shadow:inset 0 0 0 var(--rule-heavy) var(--black),
  inset 0 0 0 7px var(--care)}
.c-field__m i{display:block;width:12px;height:12px;flex:none;background:var(--coral)}
/* the message element exists at REST (so it is not inserted after an error,
   which some screen readers miss) but must not show its marker until there is
   something to say. Measured on the first render, where a stray coral square
   sat under every field. Hiding the MARKER only, never the element, so the
   message stays in the DOM and in the accessibility tree at all times. */
.c-field:not(.c-field--error):not(.c-field--success) .c-field__m i{visibility:hidden}
.c-field--success .c-field__m i{background:var(--care)}
/* the SEARCH field: the same field with the wave as its glyph and a real submit */
.c-search{display:flex;align-items:stretch;max-width:480px;width:100%}
.c-search .c-field__i{box-shadow:inset 0 0 0 var(--rule-heavy) var(--black)}
.c-search__go{appearance:none;cursor:pointer;border:0;flex:none;
  padding:0 var(--s5);min-height:var(--tap-min);
  background:var(--black);color:var(--cream);border-radius:var(--radius-slab);
  font:900 var(--size-title)/1 var(--font);font-stretch:var(--wdth-condensed);
  text-transform:uppercase}
.c-search__go:hover{background:var(--primary);color:var(--black)}

/* the FIELDSET: a group with a real legend, at the system's micro weight */
.c-set{border:0;margin:0;padding:0;min-width:0}
.c-set > legend{padding:0;margin:0 0 var(--s4);
  font:700 var(--size-micro)/1 var(--font);letter-spacing:var(--track-micro);
  text-transform:uppercase}
.c-set__items{display:flex;flex-direction:column;gap:var(--s3);align-items:flex-start}

/* ============================================================================
   C13 , CHIPS AND FILTERS, as label-in-slab
   A filter is a .d-label you can press. Selected is the label at full colour with
   the system's inset rule; unselected is the label's outline only, so the row
   reads as a set of tags rather than a set of buttons.
   ============================================================================ */
.c-chips{display:flex;flex-wrap:wrap;gap:var(--s2)}
.c-chip{appearance:none;cursor:pointer;border:0;min-height:var(--tap-min);
  padding:var(--s3) var(--s4);background:none;color:var(--ink);
  box-shadow:inset 0 0 0 var(--rule) currentColor;border-radius:var(--radius-slab);
  font:900 13px/1 var(--font);font-stretch:var(--wdth-condensed);
  text-transform:uppercase;letter-spacing:.04em;
  transition:background var(--dur-state) var(--ease-out)}
.c-chip:hover,.c-chip.is-hover{background:var(--dc,var(--primary));color:var(--black);
  box-shadow:inset 0 0 0 var(--rule) var(--black)}
.c-chip[aria-pressed="true"],.c-chip.is-selected{background:var(--dc,var(--primary));
  color:var(--black);box-shadow:inset 0 0 0 var(--rule-heavy) var(--black)}
.c-chip.is-focus{outline:var(--focus-width) solid var(--focus-colour);
  outline-offset:var(--focus-offset)}
.c-chip.is-disabled,.c-chip[disabled]{opacity:.4;cursor:not-allowed}

/* ============================================================================
   C14 , TABS and PAGINATION
   Tabs are totem bars laid on their side: square, full colour when current, the
   ground showing through when not. Pagination is the same key as the stepper.
   ============================================================================ */
.c-tabs{display:flex;flex-wrap:wrap;gap:0;
  box-shadow:inset 0 calc(var(--rule) * -1) 0 var(--black)}
.c-tab{appearance:none;cursor:pointer;border:0;background:none;color:var(--ink);
  padding:var(--s4) var(--s5);min-height:var(--tap-min);border-radius:var(--radius-slab);
  font:900 clamp(15px,1.6vw,20px)/1 var(--font);font-stretch:var(--wdth-condensed);
  text-transform:uppercase;letter-spacing:.02em;
  transition:background var(--dur-state) var(--ease-out)}
.c-tab:hover,.c-tab.is-hover{background:var(--hairline)}
.c-tab[aria-selected="true"],.c-tab.is-selected{background:var(--stage);color:var(--black)}
.c-tab.is-focus{outline:var(--focus-width) solid var(--focus-colour);
  outline-offset:calc(var(--focus-offset) * -1)}
.c-tab.is-disabled,.c-tab[disabled]{opacity:.4;cursor:not-allowed}
.c-panel{padding:var(--s5) 0 0}

.c-page{display:flex;align-items:center;gap:var(--s2);flex-wrap:wrap}
.c-page__n{appearance:none;cursor:pointer;border:0;
  min-width:var(--tap-min);min-height:var(--tap-min);padding:0 var(--s3);
  background:none;color:var(--ink);border-radius:var(--radius-slab);
  box-shadow:inset 0 0 0 var(--rule) currentColor;
  font:900 var(--size-title)/1 var(--font);font-stretch:var(--wdth-condensed)}
.c-page__n[aria-current="page"],.c-page__n.is-selected{background:var(--primary);
  color:var(--black);box-shadow:inset 0 0 0 var(--rule-heavy) var(--black)}
.c-page__n:hover,.c-page__n.is-hover{background:var(--primary);color:var(--black)}
.c-page__n.is-focus{outline:var(--focus-width) solid var(--focus-colour);
  outline-offset:var(--focus-offset)}
.c-page__n[disabled]{opacity:.35;cursor:not-allowed}

/* ============================================================================
   C15 , MODAL and BOTTOM SHEET
   The modal is a black slab that DROPS in; the sheet is the same slab arriving
   from the bottom edge on a phone. Both keep a real <dialog>-shaped role, a
   labelled heading and a close that is a genuine button.
   ============================================================================ */
.c-scrim{position:absolute;inset:0;z-index:var(--z-overlay);
  background:var(--black);opacity:.72}
.c-modal{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);
  z-index:var(--z-overlay);width:min(440px,calc(100% - var(--s7)));
  background:var(--black);color:var(--ink-invert);border-radius:var(--radius-slab);
  box-shadow:0 0 0 var(--rule-heavy) var(--black);
  --focus-colour:var(--focus-colour-on-dark)}
.c-modal__hd{display:flex;align-items:stretch;gap:0}
/* the header label must keep its own width: it is a nowrap label-in-slab, so
   letting it shrink as a flex item clipped "Entry policy" at 390 (shot.py caught
   it). The close is what gives way, and it still holds its tap target. */
.c-modal__hd > .d-label{flex:0 0 auto}
.c-modal__x{margin-left:auto;appearance:none;cursor:pointer;border:0;flex:0 1 auto;
  min-width:var(--tap-min);min-height:var(--tap-min);
  background:var(--cream);color:var(--black);border-radius:var(--radius-slab);
  font:900 var(--size-title)/1 var(--font);font-stretch:var(--wdth-condensed)}
.c-modal__x:hover{background:var(--primary)}
.c-modal__b{padding:var(--s5)}
.c-modal__t{margin:0 0 var(--s3);font:900 clamp(22px,2.6vw,32px)/1 var(--font);
  font-stretch:var(--wdth-condensed);text-transform:uppercase}
.c-modal__x1{margin:0 0 var(--s5);font-size:var(--size-small);line-height:1.5;opacity:.85}
.c-modal__acts{display:flex;flex-wrap:wrap;gap:var(--s3)}
/* the SHEET: the same object, docked to the bottom edge, full width */
.c-modal--sheet{top:auto;bottom:0;left:0;transform:none;width:100%;
  max-width:none;border-radius:var(--radius-slab)}
.c-modal--sheet .c-modal__b{padding-bottom:var(--s6)}
.c-modal--sheet::before{content:"";display:block;width:64px;height:5px;
  margin:var(--s3) auto 0;background:var(--cream);opacity:.6}

/* ============================================================================
   C16 , TOOLTIP
   A black slab, square, with a solid pointer. It is never the only place a fact
   lives, because it cannot be reached on a phone.
   ============================================================================ */
.c-tipwrap{position:relative;display:inline-flex}
.c-tip{position:absolute;left:50%;bottom:calc(100% + var(--s3));
  transform:translateX(-50%);z-index:var(--z-overlay);
  padding:var(--s2) var(--s3);background:var(--black);color:var(--ink-invert);
  border-radius:var(--radius-slab);white-space:nowrap;
  font:700 var(--size-small)/1.2 var(--font);
  opacity:0;visibility:hidden;
  transition:opacity var(--dur-state) var(--ease-out),visibility 0s linear var(--dur-state)}
.c-tip::after{content:"";position:absolute;left:50%;top:100%;
  width:12px;height:8px;transform:translateX(-50%);background:var(--black);
  clip-path:polygon(0 0,100% 0,50% 100%)}
.c-tipwrap:hover .c-tip,.c-tipwrap:focus-within .c-tip,
.c-tipwrap.is-hover .c-tip{opacity:1;visibility:visible;transition-delay:0s,0s}

/* ============================================================================
   C17 , PROGRESS and PAGE LOAD
   Progress is the soundwave filling: .d-wave--progress with --p 0..1 driving how
   many bars are live. The page-load state is the mark introducing itself, which
   is UNION.wave(el,'intro'), never a spinner.
   ============================================================================ */
.c-prog{display:flex;flex-direction:column;gap:var(--s2);width:100%;max-width:420px}
.c-prog__top{display:flex;align-items:baseline;justify-content:space-between;gap:var(--s4)}
.c-prog .d-wave--progress i{opacity:.22}
.c-prog .d-wave--progress i:nth-child(-n+1){opacity:1}
.c-prog[data-p="2"] .d-wave--progress i:nth-child(-n+2){opacity:1}
.c-prog[data-p="3"] .d-wave--progress i:nth-child(-n+3){opacity:1}
.c-prog[data-p="4"] .d-wave--progress i:nth-child(-n+4){opacity:1}
.c-prog[data-p="5"] .d-wave--progress i:nth-child(-n+5){opacity:1}
.c-prog[data-p="6"] .d-wave--progress i:nth-child(-n+6){opacity:1}
.c-prog[data-p="7"] .d-wave--progress i:nth-child(-n+7){opacity:1}
.c-prog[data-p="8"] .d-wave--progress i{opacity:1}
.c-load{display:flex;flex-direction:column;align-items:center;gap:var(--s4);
  padding:var(--s7) var(--s5);text-align:center}
.c-load u-svg{width:96px;display:block}

/* ============================================================================
   C18 , EMPTY, ERROR, 404
   All three are the same object: a slab that says what happened and offers the
   one thing to do next. The mascot appears on the 404 ONLY, large, on a colour
   ground, because that is the one moment with room for a character.
   ============================================================================ */
.c-msg{display:flex;flex-direction:column;gap:var(--s4);align-items:flex-start;
  max-width:52ch}
.c-msg__t{margin:0;font:900 clamp(26px,3.4vw,52px)/.92 var(--font);
  font-stretch:var(--wdth-condensed);text-transform:uppercase}
.c-msg__x{margin:0;font-size:var(--size-body);line-height:1.5;max-width:46ch}
.c-404{display:flex;flex-wrap:wrap;gap:var(--s6);align-items:center}

/* ============================================================================
   C19 , COOKIE NOTICE and INLINE NOTICES
   The cookie notice is a totem bar across the foot, not a dialog: it does not
   trap focus and it does not block the page. The inline notice levels are
   info (pink), warning (coral) and care (yellow, black ink, brand stepped back).
   ============================================================================ */
.c-cookie{position:absolute;left:0;right:0;bottom:0;z-index:var(--z-overlay);
  display:flex;flex-wrap:wrap;align-items:center;gap:var(--s4);
  padding:var(--s4) var(--s5);background:var(--black);color:var(--ink-invert);
  border-top:var(--rule-heavy) solid var(--primary);
  --focus-colour:var(--focus-colour-on-dark)}
.c-cookie p{margin:0;flex:1 1 260px;font-size:var(--size-small);line-height:1.45}
.c-cookie__acts{display:flex;gap:var(--s3);flex-wrap:wrap}

.c-note{display:flex;align-items:flex-start;gap:var(--s4);
  padding:var(--s4);border-radius:var(--radius-slab);
  background:var(--dc,var(--primary));color:var(--black);max-width:560px}
/* the body must FILL the row beside the icon. Without flex:1 the block shrinks
   to the title's width and the sentence under it renders ragged-right of it,
   which is what the first render did on the info and warning levels. */
.c-note__b{min-width:0;flex:1 1 auto;text-align:left}
.c-note__t{display:block;margin-bottom:var(--s1);
  font:900 var(--size-title)/1 var(--font);font-stretch:var(--wdth-condensed);
  text-transform:uppercase}
.c-note p{margin:0;font-size:var(--size-small);line-height:1.45}
.c-note--info{--dc:var(--primary)}
.c-note--warning{--dc:var(--coral)}
/* CARE: welfare and safety. The brand steps back. Black on yellow, no device,
   no pattern, nothing decorative. */
.c-note--care{--dc:var(--care)}
.c-note--care .c-note__t{font-stretch:normal;font-weight:900;letter-spacing:0}
.c-note__i{flex:none;width:34px}

/* ---------------------------------------------------------------------------
   Phone. The whole page's controls hold their 44px targets at 390; these are the
   few places where a desktop proportion has to give.
   --------------------------------------------------------------------------- */
@media (max-width:700px){
  .c-river-btn__t{font-size:clamp(17px,4.6vw,22px);white-space:normal}
  .c-river-btn__face{padding:var(--s4)}
  .c-fader__sw{width:116px}
  .c-fader__sw[aria-checked="true"] .c-fader__cap{transform:translateX(72px)}
  /* The mock viewport is a documentation frame with overflow hidden. At 390 the
     modal inside it stands 342px tall, so a 300px frame cut its header and
     "Entry policy" lost its top (shot.py's clipped-text check caught it, on the
     HEIGHT, not the width). The frame gives, not the component: a modal trimmed
     to fit would stop being the modal the spec is documenting. */
  .c-view{height:300px}
  .c-view:has(.c-modal){height:400px}
  .c-sold__stamp{font-size:clamp(22px,7vw,30px)}
  .c-step__n{min-width:56px}
}
