/* Shared control foundation. Geometry, material, state, and motion live here;
   page styles may position a control but do not redraw it. */
.ctl{
 display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;
 min-height:var(--ctl-h);padding-block:0;padding-inline:var(--ctl-pad);gap:var(--ctl-gap);
 border:0;border-radius:var(--ctl-r);corner-shape:var(--corner);background:none;box-shadow:none;
 font-family:var(--sans);font-size:var(--ctl-fs);font-weight:400;line-height:var(--lh-flat);
 letter-spacing:var(--tr-body);color:var(--ctl-ink);white-space:nowrap;text-decoration:none;
 position:relative;cursor:pointer;-webkit-tap-highlight-color:transparent;filter:none;
 transition-property:color,background-color,box-shadow,text-decoration-color,transform;
 transition-duration:var(--dur-state-out);transition-timing-function:var(--ease-out)
}
.ctl .gIco,.ctl .uiIcon{width:var(--ico-md);height:var(--ico-md);flex:0 0 var(--ico-md)}
.ctl:hover,.ctl:focus-visible,.ctl[aria-selected="true"],.ctl[aria-current],
.ctl[aria-expanded="true"],.ctl[aria-pressed="true"]{transition-duration:var(--dur-state)}
.ctl:active{transition-duration:var(--dur-press);transform:scale(var(--press-scale))}
.ctl:focus-visible{outline:var(--focus-w) solid var(--ctl-focus);outline-offset:var(--sp-2)}
.ctl:focus:not(:focus-visible){outline:none}
.ctl[disabled],.ctl[aria-disabled="true"]{opacity:var(--ctl-disabled-o);cursor:default}
.ctl[disabled]:active,.ctl[aria-disabled="true"]:active{transform:none}

.ctl--primary{background:var(--ctl-primary-ground);color:var(--ctl-primary-ink);box-shadow:var(--ctl-rim)}
.ctl--primary:hover,.ctl--primary:focus-visible,.ctl--primary:active{
 background:var(--ctl-primary-ground-hover);color:var(--ctl-primary-ink);box-shadow:var(--ctl-rim-strong)
}
.ctl--secondary,.ctl--icon{
 background:var(--ctl-ground);color:var(--ctl-ink);box-shadow:var(--ctl-rim)
}
/* aria-pressed sits in this list beside aria-expanded because a toggle button IS
   a selection: the two differ in what they announce, not in what they look like.
   Without it a latched control had no resting "on" appearance in the library, and
   headmaker.html grew a private `.isOn` rule to supply one. */
.ctl--secondary:hover,.ctl--secondary:focus-visible,.ctl--secondary[aria-expanded="true"],
.ctl--secondary[aria-pressed="true"],
.ctl--icon:hover,.ctl--icon:focus-visible,.ctl--icon[aria-expanded="true"],
.ctl--icon[aria-pressed="true"]{
 background:var(--ctl-ground-hover);color:var(--ctl-ink-strong);box-shadow:var(--ctl-rim-strong)
}
.ctl--icon{width:var(--ctl-h);height:var(--ctl-h);min-width:var(--ctl-h);padding:0}
.ctl--quiet{background:none;color:var(--ctl-ink);box-shadow:none}
.ctl--quiet:hover,.ctl--quiet:focus-visible,.ctl--quiet[aria-current],
.ctl--quiet[aria-selected="true"]{background:none;color:var(--ctl-ink-strong)}
.ctl--row{width:100%;justify-content:flex-start;text-align:left}
.ctl--choice{padding-left:var(--sp-32)}
.ctl--choice[aria-checked="true"]{color:var(--ctl-ink-strong);font-weight:600}
.ctl--choice[aria-checked="true"]::before{
 content:"✓";position:absolute;left:var(--sp-10);font:inherit;color:currentColor
}
.ctl--sm{min-height:var(--ctl-h-sm);padding-inline:var(--ctl-pad-sm);gap:var(--ctl-gap-sm);font-size:var(--ctl-fs-sm)}
.ctl--sm::after{content:"";position:absolute;top:50%;left:0;right:0;height:var(--ctl-h);transform:translateY(-50%)}
.ctl--sm .gIco,.ctl--sm .uiIcon{width:var(--ico-sm);height:var(--ico-sm);flex:0 0 var(--ico-sm)}
/* A control that owns its row rather than sitting in one. `display:flex` because
   an inline-flex box at width:100% still carries the inline box's baseline gap. */
.ctl--block{display:flex;width:100%}

/* THE FIELD. The library had no form primitive at all, and that absence is the
   documented reason headmaker.html and gradientlab.html each forked `.ctl`
   rather than adopting it: a builder is mostly fields, and a system that cannot
   draw one cannot be adopted by a builder. It is a sibling of `.ctl`, not a
   variant of it, because the two disagree on the things that matter -- a field
   is left-aligned, carries a ground AT REST (its job is to look like where
   content goes), and takes a text caret rather than a pointer.
   Every value resolves through the same --ctl-* semantic layer, so retuning the
   control ladder retunes the fields with it. */
.field{
 box-sizing:border-box;display:flex;align-items:center;width:100%;
 min-height:var(--ctl-h);padding-block:0;padding-inline:var(--ctl-pad);
 border:0;border-radius:var(--ctl-r);corner-shape:var(--corner);
 background:var(--ctl-ground);box-shadow:var(--ctl-rim);
 font-family:var(--sans);font-size:var(--ctl-fs);font-weight:400;
 line-height:var(--lh-flat);letter-spacing:var(--tr-body);color:var(--ctl-ink-strong);
 transition-property:color,background-color,box-shadow;
 transition-duration:var(--dur-state-out);transition-timing-function:var(--ease-out)
}
.field:hover{transition-duration:var(--dur-state);box-shadow:var(--ctl-rim-strong)}
/* :focus, not only :focus-visible -- a text field is focused by clicking into it
   as often as by tabbing, and in both cases the caret is already there. This is
   the one control kind where a pointer focus is not an accident. */
.field:focus,.field:focus-visible{
 transition-duration:var(--dur-state);box-shadow:var(--ctl-rim-strong);
 outline:var(--focus-w) solid var(--ctl-focus);outline-offset:var(--sp-2)
}
.field::placeholder{color:var(--ctl-ink-mute)}
.field[disabled],.field[aria-disabled="true"]{opacity:var(--ctl-disabled-o);cursor:default}
/* The caret is a background image rather than a pseudo-element because a <select>
   has no generated-content box. Colour is --ctl-ink-mute's light value; the dark
   adapter repaints it, exactly as it already did for the page-local copy. */
.field--select{
 display:block;appearance:none;-webkit-appearance:none;cursor:default;
 padding-inline:var(--ctl-pad-sm) var(--sp-36);
 background-image:var(--field-caret);background-repeat:no-repeat;
 background-position:right var(--ctl-pad-sm) center;
 background-size:var(--ico-sm) var(--ico-sm)
}
.field--flex{width:auto;flex:1 1 auto;min-width:0}

/* ══ THE RANGE AND THE COLOUR WELL ═══════════════════════════════════════════
   The adoption audit (2026-08-08) measured 34 raw <input type="range"> and
   <input type="color"> elements the library could not express -- 26 ranges and
   6 wells on gradientlab.html, 2 ranges on headmaker.html -- and that single
   absence is why Gradient Maker capped at 28.6% adoption with 40 of its 56
   controls unreachable by the system. Both pages had therefore drawn their own,
   and the two drawings had already diverged on the one thing that matters:
   gradientlab's thumb is --c950 and headmaker's is --accent, which in Night
   makes one thumb near-white and the other violet. One role, two values, no
   markup that reveals which. That is the fork, one layer down from the .ctl
   fork the audit already caught.

   THESE ARE .ctl VARIANTS, NOT SIBLINGS OF IT -- unlike .field, which is a
   sibling because a text field disagrees with a button about alignment, ground
   and caret. A slider and a colour well agree with .ctl about everything the
   base actually decides: the 44px rung, the state ladder, the two motion
   durations, the disabled dim, the focus token. What they disagree about is
   that their INTERIOR is drawn by the UA in a shadow tree, so each one resets
   the four base declarations that assume a flex box of text and then dresses
   pseudo-elements the base cannot reach. Carrying .ctl is also what makes the
   adoption number honest: a primitive that opts out of the base it claims to
   join has joined nothing.

   ── the values with no --ctl-* home yet ───────────────────────────────────
   A track thickness, a thumb diameter and a state-layer radius are control
   geometry, so they belong in tokens.css beside --ctl-h and --ctl-pad. They are
   declared HERE, in the library that consumes them, because tokens.css is owned
   by a concurrent motion-token consolidation on this branch and a second writer
   in one file is how a token ends up with two definitions -- the exact failure
   this block exists to repair. Every one of them resolves through an existing
   rung or through --ctl-ink-strong, so nothing below invents a number. They are
   reported for promotion, not parked: move the block verbatim into the control
   section of tokens.css and this declaration becomes redundant rather than
   contradictory.

   --ctl-track-ground and the two state layers are color-mix on --ctl-ink-strong
   rather than --theme-rim / --theme-rim-strong, and that is deliberate:
   --theme-rim-strong is DEFINED ONLY IN DARK (site-theme.css:29) and every
   light-mode consumer is quietly running on the rgba() fallback written into
   tokens.css:498. A translucent wash of the theme's own ink inverts by itself
   in every theme, needs no fallback, and cannot drift from a token that is not
   there. This is also what satisfies the six time-of-day states: five of them
   resolve to data-theme="light" and night resolves to "dark"
   (site-theme-state.js:31), so a value derived from --ctl-ink-strong is correct
   in all six by construction rather than by a second set of numbers. */
:root{
 --ctl-track-h:var(--focus-w);            /* 2px. The site separates with hairlines;
                                             a 4px rail would be the one control
                                             drawing a bar. */
 --ctl-track-r:var(--r-pill);
 --ctl-thumb-size:var(--sp-20);           /* 20px. 20/44 = .45 -- the same ratio
                                             --ctl-r's 14/44 gives the box. */
 --ctl-track-ground:color-mix(in srgb,var(--ctl-ink-strong) 18%,transparent);
 --ctl-track-ground-hover:color-mix(in srgb,var(--ctl-ink-strong) 30%,transparent);
 /* The STATE LAYER: a hard-edged ring around the thumb, no blur and no offset,
    so it is a translucent wash and not elevation. The no-cast-shadows rule bans
    a control pretending to stand on the page; a ring concentric with the thumb
    claims no height at all. Material calls this a state layer and Radix, Base UI
    and shadcn all ship the same device, for the same reason: a 20px thumb has no
    room to change ink, so the only channel left is the space around it. */
 --ctl-state-layer:color-mix(in srgb,var(--ctl-ink-strong) 12%,transparent);
 --ctl-state-layer-strong:color-mix(in srgb,var(--ctl-ink-strong) 20%,transparent);
 --ctl-state-layer-w:var(--sp-4);
 --ctl-state-layer-w-strong:var(--sp-6);
 /* THE SWATCH RIM IS TWO-TONE, and this is the one control on the site whose
    ground is set by the visitor. A single hairline cannot survive that. The
    OUTER ring is the theme's ink, which is by definition the opposite of the
    panel, so it is the ring that does the work in the case that actually breaks
    -- a near-white value on a light panel, or a near-black one at night, where
    the fill and the ground are the same colour and the edge is the only thing
    identifying the control at all. The INNER ring is the theme's paper, and it
    covers the mirror case: a value that matches the INK, where the outer ring
    disappears into the fill.
    THE OUTER ALPHA IS 45% AND THAT NUMBER IS NOT TASTE. Composited over white,
    rgba(17,18,20,.45) is #8C8D8E, which is 3.05:1 against the paper either side
    of it -- the floor WCAG 2.2 SC 1.4.11 sets for the visual information that
    identifies a control. The site's ordinary hairline is .12-.20 and would
    measure 1.15:1 here; that is fine for a rim that merely refines a control
    which is already visible, and not fine for the one rim that IS the control.
    This is Adobe Spectrum's ColorHandle construction (translucent dark outside,
    light inside, fill in the middle) resolved through this site's two themes
    instead of through literal black and white.
    contrast-color() reached Baseline in April 2026 and would collapse the pair
    into one ring that flips off the FILL rather than off the theme -- but it
    needs the value in a custom property, which means the page mirroring
    input.value into CSS on every change, and it returns only pure black or
    white, so MDN's own example (royal blue) fails against both. Two static
    rings need no JS and have no mid-tone hole. Revisit if the swatch ever grows
    a JS value mirror for another reason. */
 --ctl-swatch-rim:
  inset 0 0 0 var(--hair-w) color-mix(in srgb,var(--ctl-ink-strong) 45%,transparent),
  inset 0 0 0 calc(var(--hair-w) * 2) color-mix(in srgb,var(--ctl-primary-ink) 55%,transparent);
 --ctl-swatch-rim-strong:
  inset 0 0 0 var(--hair-w) color-mix(in srgb,var(--ctl-ink-strong) 68%,transparent),
  inset 0 0 0 calc(var(--hair-w) * 2) color-mix(in srgb,var(--ctl-primary-ink) 82%,transparent);
}

/* ── .ctl--range ───────────────────────────────────────────────────────────
   THE BOX IS THE TARGET. A ::-webkit-slider-thumb paints outside the input's
   border box and catches nothing, which is how this site once shipped a 2px-tall
   slider with a 14px grab band that the geometry audit called BROKEN. So the
   input keeps its full --ctl-h and the VISIBLE line moves to the runnable track:
   the hairline is 2px and the target is 44, measured by hit-testing the top and
   bottom pixel rows rather than by reading the declaration. Both engines centre
   the track inside the input's content box for you, so the height alone does it.
   NOT THE ::after EXPANDER THE 38px NAV USES, and the difference is the element.
   css-pseudo-4 suppresses generated content on REPLACED elements; Chromium paints
   ::after on a range anyway and Gecko follows the spec (wpt/interop#1124), so an
   expander here would be a 44px target in one browser and a 2px one in another.
   .jbNav a is an anchor, where ::after is guaranteed. A range already accepts a
   real height, which is the reliable answer and needs no second box.
   padding-inline is reset to 0 because .ctl's 16px would inset the track --
   which on a range is not decoration, it is the thumb's travel. */
.ctl--range{
 appearance:none;-webkit-appearance:none;display:block;
 flex:1 1 0;width:100%;min-width:0;
 height:var(--ctl-h);min-height:var(--ctl-h);
 padding:0;margin:0;background:none;box-shadow:none;
 cursor:pointer;
 /* MEASURED: a range's computed touch-action is `auto`. No UA rule saves you, so
    a horizontal drag also scrolls the page under the finger. pan-y rather than
    none: the page keeps scrolling vertically until the browser sees horizontal
    intent, at which point it hands the gesture to the slider. */
 touch-action:pan-y;
 /* a range renders no text, but without this the UA's Arial shows up as a third
    font family in the page's computed styles */
 font-family:var(--sans);
 /* The filled portion -- the one thing Apple's HIG actually specifies about a
    slider ("the portion of track between the minimum value and the thumb fills
    with color"), and what makes a 26-slider panel readable as a shape rather
    than as a list of dots. Pure CSS cannot know a range's value: ::-moz-range-
    progress is Gecko-only, and ::slider-fill needs appearance:base, which
    measures unsupported in Chrome 151 (CSS.supports('appearance','base') is
    false; only base-select has shipped). So the page writes --ctl-range-value as
    a 0..1 number wherever it ALREADY syncs its readouts -- one hook, not a new
    one. The default is 0, which degrades to a plain unfilled rail rather than to
    a broken one. The stop is offset by half a thumb at each end so the fill ends
    UNDER the thumb's centre instead of at the track's edge, which is the 10px
    lie every naive percentage fill tells. */
 --ctl-range-pos:calc(
  var(--ctl-range-value,0) * (100% - var(--ctl-thumb-size)) + (var(--ctl-thumb-size) / 2)
 )
}
.ctl--range::-webkit-slider-runnable-track{
 height:var(--ctl-track-h);border-radius:var(--ctl-track-r);
 background:linear-gradient(to right,
  var(--ctl-ink-strong) 0,var(--ctl-ink-strong) var(--ctl-range-pos),
  var(--ctl-track-ground) var(--ctl-range-pos),var(--ctl-track-ground) 100%);
 transition:background var(--dur-state-out) var(--ease-out)
}
.ctl--range::-moz-range-track{
 height:var(--ctl-track-h);border-radius:var(--ctl-track-r);background:var(--ctl-track-ground)
}
/* Gecko has a real progress pseudo, so it gets the fill without the page's help. */
.ctl--range::-moz-range-progress{
 height:var(--ctl-track-h);border-radius:var(--ctl-track-r);background:var(--ctl-ink-strong)
}
/* WebKit lays the thumb out ON the track's box and needs the centring correction;
   Gecko centres it for you, which is why only one of the two carries a margin. */
.ctl--range::-webkit-slider-thumb{
 appearance:none;-webkit-appearance:none;
 width:var(--ctl-thumb-size);height:var(--ctl-thumb-size);
 border:0;border-radius:var(--r-full);background:var(--ctl-ink-strong);
 margin-top:calc((var(--ctl-track-h) - var(--ctl-thumb-size)) / 2);
 box-shadow:0 0 0 0 transparent;
 transition:box-shadow var(--dur-state-out) var(--ease-out)
}
.ctl--range::-moz-range-thumb{
 width:var(--ctl-thumb-size);height:var(--ctl-thumb-size);
 border:0;border-radius:var(--r-full);background:var(--ctl-ink-strong);
 box-shadow:0 0 0 0 transparent;
 transition:box-shadow var(--dur-state-out) var(--ease-out)
}
/* HOVER MOVES TWO CHANNELS AND NEITHER IS A FILL, the same shape as
   .ctl--secondary's rim-plus-ink: the empty rail strengthens and the thumb
   gains its state layer. Hover is claimed by the whole 44px band, not by the
   20px thumb, so the control answers the pointer before you have found the grab. */
.ctl--range:hover::-webkit-slider-runnable-track{
 background:linear-gradient(to right,
  var(--ctl-ink-strong) 0,var(--ctl-ink-strong) var(--ctl-range-pos),
  var(--ctl-track-ground-hover) var(--ctl-range-pos),var(--ctl-track-ground-hover) 100%);
 transition-duration:var(--dur-state)
}
.ctl--range:hover::-moz-range-track{background:var(--ctl-track-ground-hover)}
.ctl--range:hover::-webkit-slider-thumb,
.ctl--range:active::-webkit-slider-thumb,
.ctl--range:focus-visible::-webkit-slider-thumb{transition-duration:var(--dur-state)}
.ctl--range:hover::-webkit-slider-thumb{box-shadow:0 0 0 var(--ctl-state-layer-w) var(--ctl-state-layer)}
.ctl--range:hover::-moz-range-thumb{box-shadow:0 0 0 var(--ctl-state-layer-w) var(--ctl-state-layer)}
/* :active, NOT :hover, is what a phone can reach -- and it is the only press
   feedback a slider may have. .ctl's scale(.97) is suppressed below because
   shrinking a 44px track by 3% slides every value under the finger that is
   holding it: the press would change the number you are pressing. */
.ctl--range:active::-webkit-slider-thumb{box-shadow:0 0 0 var(--ctl-state-layer-w-strong) var(--ctl-state-layer-strong)}
.ctl--range:active::-moz-range-thumb{box-shadow:0 0 0 var(--ctl-state-layer-w-strong) var(--ctl-state-layer-strong)}
.ctl--range:active{transform:none}
/* THE FOCUS RING GOES ON THE THUMB, AND IT IS TWO-TONE.
   .ctl's ring is a rounded rectangle at 2px offset, which around a 192x44 box
   containing one hairline marks a region rather than a control -- and the thing
   the arrow keys actually move is the 20px thumb. So the ring hugs the thumb.
   Two tones because a single one cannot work here: the ring's colour is
   --ctl-focus, which in light is the same ink the thumb is painted in (the
   1.00:1 the audit measured against .ctl--primary's fill), so a paper hairline
   is laid between them. Thumb / 1px paper / 2px focus reads against the thumb on
   the inside and against the panel on the outside, in every theme, without
   depending on an offset gap the way the base ring does. */
.ctl--range:focus-visible{outline:none}
.ctl--range:focus-visible::-webkit-slider-thumb{
 box-shadow:
  0 0 0 var(--hair-w) var(--ctl-primary-ink),
  0 0 0 calc(var(--hair-w) + var(--focus-w)) var(--ctl-focus)
}
.ctl--range:focus-visible::-moz-range-thumb{
 box-shadow:
  0 0 0 var(--hair-w) var(--ctl-primary-ink),
  0 0 0 calc(var(--hair-w) + var(--focus-w)) var(--ctl-focus)
}
/* Keyboard needs no help: arrows, PageUp/PageDown, Home and End are the UA's,
   and appearance:none does not remove them. What it does remove is the ring,
   which is what the two rules above put back. */
.ctl--range[disabled],.ctl--range[aria-disabled="true"]{cursor:default}
.ctl--range[disabled]::-webkit-slider-thumb,
.ctl--range[aria-disabled="true"]::-webkit-slider-thumb{box-shadow:0 0 0 0 transparent}
.ctl--range[disabled]::-moz-range-thumb{box-shadow:0 0 0 0 transparent}

/* ── .ctl--swatch ──────────────────────────────────────────────────────────
   A 44px square well whose ground the visitor sets. Everything hard about it
   follows from that one fact, and it is why the rim above is two-tone.
   THE SHAPE IS --ctl-r, NOT --r-full. The page shipped 44px circles; a circle
   is a 22px radius, which is on no rung of the ladder, and the control system's
   rule is that radius is a function of the box and never of what is inside it.
   It also puts the well in the same family as the two icon buttons standing
   beside it in the same row -- measured, that row now has one radius in it
   instead of two. */
.ctl--swatch{
 appearance:none;-webkit-appearance:none;display:block;box-sizing:border-box;
 width:var(--ctl-h);height:var(--ctl-h);
 min-width:var(--ctl-h);min-height:var(--ctl-h);
 flex:0 0 var(--ctl-h);
 padding:0;border:0;border-radius:var(--ctl-r);corner-shape:var(--corner);
 background:none;box-shadow:none;overflow:hidden;cursor:pointer
}
/* The rim lives on the swatch pseudo, not on the input: an inset shadow on the
   host paints UNDER its shadow content, so a rim declared there is invisible. */
.ctl--swatch::-webkit-color-swatch-wrapper{padding:0}
.ctl--swatch::-webkit-color-swatch{
 border:0;border-radius:var(--ctl-r);corner-shape:var(--corner);
 box-shadow:var(--ctl-swatch-rim);
 transition:box-shadow var(--dur-state-out) var(--ease-out)
}
.ctl--swatch::-moz-color-swatch{
 border:0;border-radius:var(--ctl-r);corner-shape:var(--corner);
 box-shadow:var(--ctl-swatch-rim);
 transition:box-shadow var(--dur-state-out) var(--ease-out)
}
.ctl--swatch:hover::-webkit-color-swatch,
.ctl--swatch:focus-visible::-webkit-color-swatch,
.ctl--swatch:active::-webkit-color-swatch{
 box-shadow:var(--ctl-swatch-rim-strong);transition-duration:var(--dur-state)
}
.ctl--swatch:hover::-moz-color-swatch,
.ctl--swatch:focus-visible::-moz-color-swatch,
.ctl--swatch:active::-moz-color-swatch{
 box-shadow:var(--ctl-swatch-rim-strong);transition-duration:var(--dur-state)
}
/* SELECTED is an outer ring, because every inner channel is already spoken for
   by the visitor's colour. Paper hairline then ink, hard-edged and concentric --
   the same two-tone device as the rim and the thumb's focus, so a selected
   near-white well in daylight and a selected near-black one at night both keep
   an edge. It is 3px, and the focus ring's offset below is 4px so the two can be
   worn at once without touching. */
.ctl--swatch[aria-pressed="true"],.ctl--swatch[data-selected="true"]{
 box-shadow:
  0 0 0 var(--hair-w) var(--ctl-primary-ink),
  0 0 0 calc(var(--hair-w) + var(--focus-w)) var(--ctl-ink-strong)
}
.ctl--swatch:focus-visible{outline-offset:var(--sp-4)}
.ctl--swatch[disabled],.ctl--swatch[aria-disabled="true"]{cursor:default}

/* ── MIGRATION SHIM, and it is meant to be deleted. ─────────────────────────
   The adoption audit (2026-08-08) measured 26 of 27 one-off control families
   with no disabled state and 14 with a hover but no press. A phone has no
   hover, so those 14 acknowledge a tap with nothing at all until the action
   completes. Patching them one at a time in 13 files would have written the
   duplicate out 14 more times, so the two universal states are declared once,
   here, against the families by name.
   THE LIST IS INTERACTIVE FAMILIES ONLY. .baGo, .baChip, .baLabel and
   .battleBadge are deliberately absent: measured, .baGo is a <span
   aria-hidden="true"> with no href, no role, no listener and no tabindex
   attribute -- a decorative arrow between two screenshots. The audit read its
   DOM tabIndex of -1 as an authored attribute and filed it as an unreachable
   button; it is not a control, and giving it a press state would be inventing
   an interaction that does not exist. The badges are the same case.
   :where() so the whole block has ZERO specificity: any page rule that has an
   opinion about transform, opacity or cursor beats it without a fight, and
   migrating a family to .ctl simply makes its entry here redundant. Delete a
   name from these lists when its family adopts .ctl; delete the block when the
   lists are empty. --press-scale and --ctl-disabled-o are the same values .ctl
   itself presses and dims by, so a migrated control does not change behaviour.
   The sliders are deliberately absent from the PRESS list, and so is the field:
   a text input must not move under the caret while you are typing in it, and a
   track that shrinks under the finger holding it changes the value being
   pressed. `.mkSlider` has now left the DISABLED list too, and that is a
   migration rather than an exemption -- headmaker's two sliders carry
   `.ctl--range`, so `.ctl[disabled]` reaches them directly. One name gone; the
   block is meant to end empty. */
:where(.abLink,.aboutCta,.teamChip,.sbBtn,.tGo,.hmBtn,.hmDrop,
 .moodBtn,.moodItem,.moodGo,.reelClose,.mhToggle,.csTab,.cmpKnob,
 .pBtn,.tvChip,.tvGo,.hmPitPick):active{
 transition-duration:var(--dur-press);transform:scale(var(--press-scale))
}
:where(.abLink,.aboutCta,.teamChip,.sbBtn,.tGo,.hmBtn,.hmDrop,
 .moodBtn,.moodItem,.moodGo,.reelClose,.mhToggle,.csTab,.cmpKnob,
 .pBtn,.tvChip,.tvGo,.hmPitPick):is([disabled],[aria-disabled="true"]){
 opacity:var(--ctl-disabled-o);cursor:default
}
:where(.abLink,.aboutCta,.teamChip,.sbBtn,.tGo,.hmBtn,.hmDrop,
 .moodBtn,.moodItem,.moodGo,.reelClose,.mhToggle,.csTab,.cmpKnob,
 .pBtn,.tvChip,.tvGo,.hmPitPick):is([disabled],[aria-disabled="true"]):active{transform:none}
/* ── end migration shim ─────────────────────────────────────────────────── */

.ctl-menu{
 display:flex;flex-direction:column;gap:0;padding:var(--sp-8);min-width:var(--menu-w);
 box-sizing:border-box;border:0;border-radius:var(--radius-menu);corner-shape:var(--corner);
 /* NO CAST SHADOW. A menu is chrome: it does not stand on anything, so it has
    nothing to cast onto. It separates the way the rest of the site's chrome
    separates -- an opaque ground and a hairline rim. This rule used to read
    --ctl-menu-shadow, which is `var(--ctl-rim),var(--sh-2)`: the rim plus two
    drop layers (0 2px 8px, 0 1px 2px). That made the shared library the one
    thing on the site breaking the site's own rule, and every menu that adopted
    it inherited the breach. header.css:734 and .jbDiscMenu below were already
    written the correct way; this is the third menu converging on them, not a
    new idea. --ctl-menu-shadow (tokens.css:500) now has no consumer. */
 background:var(--ctl-menu-ground);box-shadow:var(--ctl-container-rim);
 max-height:calc(100svh - (var(--menu-viewport-gutter) * 2));overflow-y:auto;overscroll-behavior:contain;
 opacity:0;visibility:hidden;pointer-events:none;transform:translateY(var(--sp-6));
 transition:opacity var(--dur-state) var(--ease-out),transform var(--sp-settle-dur) var(--sp-settle),
  visibility 0s var(--sp-settle-dur)
}
.open>.ctl-menu,.ctl-menu[data-open],.ctl[aria-expanded="true"]+.ctl-menu{
 opacity:1;visibility:visible;pointer-events:auto;transform:none;
 transition:opacity var(--dur-state) var(--ease-out),transform var(--sp-settle-dur) var(--sp-settle)
}
.ctl-menu .ctl{border-radius:var(--radius-control)}
.skipLink.ctl{
 position:fixed;top:var(--skip-inset);left:var(--skip-inset);z-index:var(--layer-skip-link);
 transform:translateY(var(--skip-hidden-offset));transition-property:color,background-color,box-shadow,transform
}
.skipLink.ctl:focus-visible{transform:none}
:root[data-focus-modality="pointer"] .skipLink.ctl:focus-visible{transform:translateY(var(--skip-hidden-offset))}

/* Header menus are positioned by header.css, but consume the same opaque local
   material and semantic rim as every other menu on migrated pages. */
.jbDiscMenu{background:var(--ctl-menu-ground);box-shadow:var(--ctl-container-rim)}

.ctl-group:not(.jbNav){background:var(--ctl-container-ground);box-shadow:var(--ctl-container-rim)}

/* Task 2 shared surfaces. Every visible decision resolves through tokens.css;
   the page may place a primitive but may not redraw it. */
.surface{
 box-sizing:border-box;border:0;border-radius:var(--radius-container);corner-shape:var(--corner);
 background:var(--surface-ground);box-shadow:var(--surface-rim)
}
/* The Hero no longer clips. Its gradient has to continue below its own lower
   edge to fade into the work section, so the crop that keeps the portrait
   standing ON the Hero's floor moved down to .heroCharacterPeek, which is the
   element that actually owns the portrait. */
.surface--hero{
 position:relative;overflow:visible;border-radius:var(--surface-hero-radius);
 padding-inline:var(--surface-hero-pad);box-shadow:none
}
.surface--specimen{border-radius:var(--radius-container)}
.surface--media,.surface--card{
 overflow:hidden;background:var(--surface-ground);box-shadow:var(--surface-rim)
}
.surface--media{border-radius:var(--radius-media)}
.surface--card{border-radius:var(--radius-media);padding:var(--surface-pad)}
.collection{
 box-sizing:border-box;width:100%;overflow:hidden;border-radius:var(--radius-container);
 corner-shape:var(--corner);background:var(--surface-ground);box-shadow:var(--surface-rim)
}
.cases.collection{
 width:calc(100% - (var(--surface-gutter) * 2));
 max-width:calc(var(--page-max) - (var(--surface-gutter) * 2));
 background:var(--surface-ground-muted)
}
.collection__tabs{
 box-sizing:border-box;display:flex;gap:var(--gap-item);padding:var(--surface-inset);
 margin:0;border-radius:0;background:var(--surface-ground);box-shadow:inset 0 calc(var(--hair-w) * -1) 0 var(--theme-rim)
}
.collection__content{box-sizing:border-box;border-radius:0;background:var(--surface-ground);box-shadow:none;overflow:hidden}
/* THE CAPTION CLIP. Jayden: "the thumbnail section cuts off letters at the
   bottom, because of the corner rounding." He was right, and measured it is two
   clips at one edge, not one.
   The last case item's caption sat with its bottom edge EXACTLY on the container's
   bottom edge -- .csMeta rest position 1066, .collection__content bottom 1066, zero
   clearance. Two things then eat it. (1) .collection__content is overflow:hidden,
   so anything past that line is gone outright; index.html's entrance reveal
   translates .csMeta down by a measured 9.79px, which puts the whole caption
   9.79px past the line while it plays. (2) .cases.collection is overflow:hidden
   with --radius-container, so even at rest the bottom 28px of the box is inside
   the corner arcs -- and the caption's two words sit hard against the left and
   right edges. "Apollo" on the left, "2026" on the right: exactly the two he saw.
   THE CAPTION IS TEXT, SO IT DOES NOT BELONG IN A CLIPPED CORNER. The media does
   -- .csFrame carries --radius-media and its own clip already, so nothing here is
   holding the images in. What was missing is a floor: the arc, plus the inset the
   tab strip already uses at the other end of the same card. That clears the
   corner geometrically (28px above the bottom is the arc's tangent point) and
   absorbs the 9.79px reveal with 26px to spare. */
.cases.collection .collection__content{
 padding-bottom:calc(var(--radius-container) + var(--surface-inset))
}
.collection .csStageInner{padding-inline:0}
.collection .tvFrame{border-radius:0!important;box-shadow:none!important}
.cases.collection .csFrame{border-radius:var(--radius-media)!important;box-shadow:var(--surface-rim)!important}
.cases.collection .csFrame>img{border-radius:inherit!important;box-shadow:none!important}
.cases.collection .collection__tabs>.ctl--tab{flex:1 1 0;min-width:0;padding-inline:var(--surface-inset)}
.collection__tabs .csTabInk{display:none}
.media{
 box-sizing:border-box;width:100%;overflow:hidden;border-radius:var(--radius-media);
 corner-shape:var(--corner);background:var(--surface-ground);box-shadow:var(--surface-rim)
}
.media--full{padding:0}
.media--mockup{padding:var(--media-mockup-inset)}
.cmpBoard.media--full{box-shadow:var(--surface-rim)!important}
.cmpBoard.media--full::after{box-shadow:none}
.cmpBoard.media--full img{border-radius:var(--radius-media);box-shadow:none!important}
.collection__content.media--mockup{border-radius:0;box-shadow:none}
.tv.collection .collection__content{width:100%;max-width:none;margin:0;padding:var(--media-mockup-inset)}
.tv.collection.tvPhone .collection__content>img,
.playerStage.media--mockup>img{width:min(var(--panel-w),100%);margin-inline:auto}
.tv.collection.tvBoard .collection__content>img{width:100%;margin-inline:auto}
.player{max-width:none}
.playerStage.media--mockup{width:100%;margin-inline:0}
.ctl--tab{font-size:inherit;color:var(--ctl-ink-mute);background:none;box-shadow:none}
.ctl--tab:hover:not([aria-selected="true"]){background:var(--ctl-ground-hover);color:var(--ctl-ink-strong)}
.ctl--tab[aria-selected="true"],.ctl--tab.on{color:var(--ctl-ink-strong);font-weight:600}
.ctl--tab::after{
 content:"";position:absolute;left:var(--ctl-pad);right:var(--ctl-pad);bottom:0;
 height:var(--focus-w);background:var(--ctl-focus);opacity:0;transform:scaleX(0);
 transition:opacity var(--dur-state) var(--ease-out),transform var(--sp-settle-dur) var(--sp-settle)
}
.ctl--tab[aria-selected="true"]::after,.ctl--tab.on::after{opacity:1;transform:scaleX(1)}
.ctl--tick{width:var(--ctl-h);height:var(--ctl-h);min-width:var(--ctl-h);padding:0;border-radius:var(--ctl-r)}
.ctl--tick::before{
 content:"";width:var(--sp-14);height:var(--focus-w);border-radius:var(--r-hair);
 background:var(--theme-rim);transition:background-color var(--dur-state) var(--ease-out)
}
.ctl--tick[aria-pressed="true"]::before,.ctl--tick.on::before{background:var(--ctl-ink-strong)}
.carousel-toolbar{
 box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;gap:0;
 padding:var(--surface-inset);border-radius:var(--radius-menu);background:var(--ctl-container-ground);
 box-shadow:var(--ctl-container-rim)
}
.ctl--internal{background:none;box-shadow:none}
.carousel-toolbar .ctl--internal{
 width:var(--ctl-h);height:var(--ctl-h);min-width:var(--ctl-h);padding:0;
 border-radius:var(--radius-control);background:none;box-shadow:none
}
.carousel-toolbar .ctl--internal:hover,.carousel-toolbar .ctl--internal:focus-visible,
.carousel-toolbar .ctl--internal[aria-pressed="true"]{background:var(--ctl-ground-hover);box-shadow:none}
.carousel-toolbar .playerTicks{display:flex;gap:0}
.ctl--media-large{min-width:var(--ctl-h);min-height:var(--ctl-h);padding-inline:var(--ctl-pad)}
.ctl--media-large.is-icon{width:var(--ctl-h);padding:0}
.toTop.ctl{
 position:fixed;right:var(--floating-control-inset);bottom:var(--floating-control-inset);
 z-index:var(--layer-floating-control);opacity:0;pointer-events:none
}
.toTop.ctl.show{opacity:1;pointer-events:auto}
.toTop.ctl svg{transition:color var(--dur-state) var(--ease-out)}
.sbNav,.playerTicks{gap:var(--gap-item)}
.playerBar{gap:0}
.scene-swap-target{
 display:block;contain:layout paint;transition:filter var(--scene-cut-duration) var(--scene-cut-ease),
 opacity var(--scene-cut-duration) var(--scene-cut-ease)
}
.heroCharacterPeek{
 position:absolute;inset:0;z-index:2;display:flex;justify-content:center;align-items:flex-end;
 overflow:hidden;pointer-events:none;transition:transform var(--sp-settle-dur) var(--sp-settle)
}
.heroCharacterPeek.is-movie{transform:translateY(var(--hero-peek-active-offset,calc(var(--hero-peek-lift) * -1)))}
/* Transform order is translate -> rotate -> scale. Translate has to come first
   because it is the position; rotate and a UNIFORM scale commute, so the only
   thing that matters after that is the origin. The origin is the logical
   head's own centre (written by hero-head-transform.js), which makes the head
   spin in place instead of swimming around the stage's corner while you drag. */
.heroHeadTransform{
 position:absolute;left:50%;top:auto;bottom:calc((var(--hero-peek-depth) * -1) + var(--hero-peek-offset));
 width:var(--hero-peek-width);max-width:none;z-index:2;
 transform-origin:var(--hero-head-origin-x) var(--hero-head-origin-y);
 transform:translate3d(calc(-50% + var(--hero-head-x)),calc(var(--hero-head-y) + var(--hero-movie-guard-y)),0)
           rotate(var(--hero-head-rotate)) scale(var(--hero-head-scale));
 will-change:transform
}
.heroHeadTransform .stagewrap{position:relative!important;width:100%!important;max-width:none;margin:0!important}
/* The four --selection-* values are written by hero-head-transform.js at runtime.
   The 0px fallbacks are not cosmetic: without them the four properties are
   invalid at computed-value time before the first write, so `left`/`top` fall
   back to auto and the box has no defined position at all. It is hidden until
   the head is selected, so nothing showed -- but a rule that only works because
   its element is display:none is the same class of latent bug as a radius that
   never wins a declaration. */
.heroHeadSelection{
 position:absolute;left:var(--selection-x,0px);top:var(--selection-y,0px);
 width:var(--selection-w,0px);height:var(--selection-h,0px);z-index:6;
 pointer-events:auto;touch-action:none;cursor:move
}
/* The selection BOX stays the Hero-clamped bounding rect: it is the pointer
   surface, so it must never reach past the Hero into the work section. The
   OUTLINE is a separate layer inside it, drawn at the head's own unrotated
   rect and turned with it, so the line keeps hugging the subject at any angle
   instead of drifting out to a rotated bounding box. The box clips it. */
.heroHeadFrame{position:absolute;inset:0;overflow:hidden;pointer-events:none}
.heroHeadFrame::before{
 content:"";position:absolute;pointer-events:none;
 left:var(--frame-x,0px);top:var(--frame-y,0px);
 width:var(--frame-w,100%);height:var(--frame-h,100%);
 transform:rotate(var(--hero-head-rotate));transform-origin:50% 50%;
 box-shadow:inset 0 0 0 var(--selection-line) var(--selection-ink)
}
.heroHeadSelection[hidden]{display:none}
/* Handles are placed by point rather than by corner keyword, because once the
   head can rotate "top left" is no longer a side of the box. JS writes the
   turned corner as --h-x/--h-y clamped so the 44px target stays inside the
   box, and --h-dx/--h-dy carries the visible square back out to the true
   corner. At 0deg the arithmetic collapses to the authored inset geometry. */
.heroHeadHandle,.heroHeadRotate{
 position:absolute;left:var(--h-x,0px);top:var(--h-y,0px);
 width:var(--selection-hit-size);height:var(--selection-hit-size);
 margin:calc(var(--selection-hit-size) / -2) 0 0 calc(var(--selection-hit-size) / -2);
 border:0;padding:0;background:transparent;touch-action:none
}
.heroHeadHandle::before,.heroHeadRotate::before{
 content:"";position:absolute;
 left:calc(50% + var(--h-dx,0px));top:calc(50% + var(--h-dy,0px));
 width:var(--selection-handle-size);height:var(--selection-handle-size);
 transform:translate(-50%,-50%);background:var(--ctl-ground);
 box-shadow:inset 0 0 0 var(--selection-line) var(--selection-ink)
}
.heroHeadHandle[data-corner="nw"],.heroHeadHandle[data-corner="se"]{cursor:nwse-resize}
.heroHeadHandle[data-corner="ne"],.heroHeadHandle[data-corner="sw"]{cursor:nesw-resize}
/* Round, not square: the shape is what tells you this one turns rather than
   resizes, and it sits on the top edge's midpoint where no corner competes. */
.heroHeadRotate{cursor:grab}
.heroHeadRotate:active{cursor:grabbing}
.heroHeadRotate::before{
 width:var(--selection-rotate-size);height:var(--selection-rotate-size);
 border-radius:var(--r-full)
}
.heroCharacterPeek .stage{pointer-events:auto;cursor:pointer;touch-action:none}
#face:focus-visible{outline:var(--focus-w) solid var(--ctl-focus);outline-offset:var(--sp-2)}
#face[data-pointer-focus]:focus-visible{outline:none}
.heroHeadHandle:focus-visible::before,.heroHeadRotate:focus-visible::before{
 outline:var(--focus-w) solid var(--ctl-focus);outline-offset:var(--sp-2)
}
/* End Task 2 shared surfaces. */

@media(prefers-reduced-motion:reduce){
 .ctl,.ctl-menu,.field{transition-duration:1ms!important}
 .ctl:active{transform:none}
 /* The pseudo-elements need naming individually: a shadow-tree box does not
    inherit the host's transition-duration, so the block above never reached the
    thumb or the swatch. It removes MOTION, not feedback -- the state layer, the
    focus ring and the rim all still appear, instantly. */
 .ctl--range::-webkit-slider-runnable-track,.ctl--range::-webkit-slider-thumb,
 .ctl--swatch::-webkit-color-swatch{transition-duration:1ms!important}
 .ctl--range::-moz-range-track,.ctl--range::-moz-range-thumb,
 .ctl--swatch::-moz-color-swatch{transition-duration:1ms!important}
 :where(.abLink,.aboutCta,.teamChip,.sbBtn,.tGo,.hmBtn,.hmDrop,
  .moodBtn,.moodItem,.moodGo,.reelClose,.mhToggle,.csTab,.cmpKnob,
  .pBtn,.tvChip,.tvGo,.hmPitPick):active{transform:none}
 .heroCharacterPeek{transition-duration:1ms!important}
 .heroHeadTransform,.heroHeadSelection,.heroHeadFrame,.heroHeadHandle,.heroHeadRotate{transition:none!important}
}
@media(forced-colors:active){
 .ctl--secondary,.ctl--icon,.ctl-menu,.ctl-group:not(.jbNav),.field{background:Canvas;color:CanvasText;box-shadow:0 0 0 var(--hair-w) CanvasText inset}
 .ctl--primary{background:Highlight;color:HighlightText}
 /* Forced colours drop every color-mix, so the two-tone rims and the state layer
    all resolve to nothing. The thumb's focus ring goes back on the BOX as a real
    outline -- the one place the base ring is the better answer, because a system
    palette has no paper tone to lay between a thumb and its ring. */
 .ctl--range:focus-visible{outline:var(--focus-w) solid Highlight;outline-offset:var(--sp-2)}
 .ctl--range::-webkit-slider-runnable-track{background:CanvasText}
 .ctl--range::-webkit-slider-thumb{background:Highlight;box-shadow:none}
 .ctl--range::-moz-range-track{background:CanvasText}
 .ctl--range::-moz-range-progress{background:Highlight}
 .ctl--range::-moz-range-thumb{background:Highlight;box-shadow:none}
 /* forced-color-adjust:none on the swatch alone: a colour well whose whole
    purpose is to show a colour is the documented exception to repainting. */
 .ctl--swatch{forced-color-adjust:none;box-shadow:none}
 .ctl--swatch::-webkit-color-swatch{box-shadow:0 0 0 var(--focus-w) CanvasText inset}
 .ctl--swatch::-moz-color-swatch{box-shadow:0 0 0 var(--focus-w) CanvasText inset}
 .ctl--swatch[aria-pressed="true"],.ctl--swatch[data-selected="true"]{
  outline:var(--focus-w) solid Highlight;outline-offset:var(--hair-w)
 }
 .heroHeadFrame::before,.heroHeadHandle::before,.heroHeadRotate::before{
  forced-color-adjust:auto;box-shadow:none;outline:var(--selection-line) solid Highlight;outline-offset:calc(var(--selection-line) * -1)
 }
}
