/* ===== src/tokens/scrim.css — copied at build time, do not edit ===== */
/* Scrim tokens for content layered directly over imagery.

   Deliberately palette- and scheme-independent: a scrim darkens a photograph so
   the content on top stays legible, and a photograph is dark in both themes.
   Tracking the palette here would flip the scrim light in dark mode and destroy
   the contrast it exists to guarantee. */
:root {
  --cr-color-scrim: #000000;
  --cr-color-on-scrim: #ffffff;
}

/* ===== src/tokens/typography.css — copied at build time, do not edit ===== */
:root {
  --cr-font-sans: "Rubik Variable", Helvetica, Arial, sans-serif;
  --cr-font-mono: "SFMono-Regular", Consolas, "Liberation Mono", monospace;
  --cr-font-size-base: 1rem;
  --cr-font-size-h1: 3rem;
  --cr-font-size-h2: 2.5rem;
  --cr-font-size-h3: 2rem;
  /* h4–h6 sit on the 4px consensus grid (M2's headline5/headline6 steps and
     Bootstrap's h4–h6 land on the same values). h6 shares body size and is
     distinguished by weight (semibold) and snug leading, the Bootstrap
     pattern — 2px-apart-same-weight was the less legible alternative. */
  --cr-font-size-h4: 1.5rem;
  --cr-font-size-h5: 1.25rem;
  --cr-font-size-h6: 1rem;
  --cr-font-size-subtitle-1: 1rem;
  --cr-font-size-subtitle-2: 0.875rem;
  --cr-font-size-body-1: 1rem;
  --cr-font-size-body-2: 0.875rem;
  --cr-font-size-button: 0.875rem;
  --cr-font-size-caption: 0.75rem;
  --cr-font-size-overline: 0.75rem;
  --cr-font-weight-light: 300;
  --cr-font-weight-regular: 400;
  --cr-font-weight-medium: 500;
  --cr-font-weight-semibold: 600;
  --cr-font-weight-bold: 700;
  /* Button component labels (ButtonBase and its consumers) were designed as
     bold in the Muli era. Rubik renders darker at equal nominal weight, so 470
     is the Rubik axis position whose ink density matches Muli at 700 (measured
     empirically). Scoped to the Button component family only: Typography's
     `button` text variant was never bold and stays on the medium scale token.
     Rebalance if the family changes; not a step on the scale above. */
  --cr-font-weight-button: 470;

  /* Pill labels (Badge, Tag, Chip). These were literal `bold` — 700 — which is
     heavier than six of the seven design systems surveyed on 2026-08-26 and the
     only 700 in the set paired with a 14px label (Bootstrap's is 700 at 12px).
     500 is the field median: Material 3 sets both its badge and its chip there,
     and Polaris sits just above at 550. Deliberately NOT 470 — that number is
     the Rubik ink-density match for the Button family's Muli-era bold, and a
     static pill is not a button. Scoped to the pill family; `bold` stays 700
     for the twenty-six other consumers of the scale token. See CR-D-013. */
  --cr-font-weight-pill: 500;

  /* Leading primitives. Line-height is a function of size and measure, not of
     semantic role — two roles at the same size want the same rhythm. The role
     tokens below alias these, so consumers need no migration and the rhythm of
     the whole library is retuned from five values instead of thirteen. */
  --cr-leading-none: 1;
  --cr-leading-tight: 1.2;
  --cr-leading-snug: 1.3;
  --cr-leading-normal: 1.5;
  --cr-leading-relaxed: 1.7;
  /* Role aliases. Display sizes (32px+) take `tight`; headings below that
     take `snug` — including h6 at body size, where snug leading is one of the
     two axes (with weight) that keep it reading as a heading beside
     subtitle/body text. Body and UI text take `normal`. Single-line controls
     take `none` and derive their height from min-block-size + padding. */
  --cr-line-height-h1: var(--cr-leading-tight);
  --cr-line-height-h2: var(--cr-leading-tight);
  --cr-line-height-h3: var(--cr-leading-tight);
  --cr-line-height-h4: var(--cr-leading-snug);
  --cr-line-height-h5: var(--cr-leading-snug);
  --cr-line-height-h6: var(--cr-leading-snug);
  --cr-line-height-title: var(--cr-leading-snug);
  --cr-line-height-subtitle-1: var(--cr-leading-normal);
  --cr-line-height-subtitle-2: var(--cr-leading-normal);
  --cr-line-height-body-1: var(--cr-leading-normal);
  --cr-line-height-body-2: var(--cr-leading-normal);
  --cr-line-height-prose: var(--cr-leading-relaxed);
  --cr-line-height-button: var(--cr-leading-none);
  --cr-line-height-caption: var(--cr-leading-normal);
  --cr-line-height-overline: var(--cr-leading-normal);
  --cr-letter-spacing-h1: -0.01562em;
  --cr-letter-spacing-h2: -0.00833em;
  --cr-letter-spacing-h3: 0em;
  /* Heading tracking follows M2's per-size values (tracking ÷ size in px):
     24px takes 0 (headline5), 20px takes 0.25/20 (headline6), 16px takes
     0.15/16 (subtitle1). The pre-retune values were tuned for the old sizes;
     tracking must move when size does. */
  --cr-letter-spacing-h4: 0em;
  --cr-letter-spacing-h5: 0.0125em;
  --cr-letter-spacing-h6: 0.00938em;
  --cr-letter-spacing-subtitle-1: 0.00938em;
  --cr-letter-spacing-subtitle-2: 0.00714em;
  --cr-letter-spacing-body-1: 0.00938em;
  --cr-letter-spacing-body-2: 0.01071em;
  --cr-letter-spacing-button: 0.02857em;
  --cr-letter-spacing-caption: 0.03333em;
  --cr-letter-spacing-overline: 0.08333em;
  --cr-text-transform-overline: uppercase;
  --cr-text-transform-none: none;
}

/* ===== src/tokens/spacing.css — copied at build time, do not edit ===== */
:root {
  /*
   * Base 4px. `--cr-space-N` is N × 4px at every step, with no exceptions —
   * the name is the multiple, so `--cr-space-4` is 16px. Steps are skipped
   * (there is no 9, 10 or 11) but never redefined, so the arithmetic never
   * stops holding.
   *
   * The ramp stops at 48px because that is where component spacing stops.
   * Measured across four long-lived sites, everything above 48px was vertical
   * padding on a full-width container — page rhythm, not component spacing.
   * Larger values are named semantic tokens owned by the page shell, never
   * further steps here. docs/ADR/ADR-spacing-scale-shape.md §2 has the
   * measurement and §4 the decision.
   */
  /* A *length* zero, not a unitless one, and that is the whole point. It was
     unitless until 2026-09-01, with a comment claiming that composed safely
     inside calc(). It did not: `calc(0 + 10px)` with a unitless zero is
     invalid and the declaration is dropped, exactly as max() is — measured,
     and recorded as CR-D-032. Deriving it from the unit makes it `0px`, which
     is valid in calc(), max(), min() and clamp() alike, so the footgun behind
     CR-D-018 stops existing rather than being documented around. */
  /*
   * The unit is the 4px base, and every step is its multiple of it. The basis
   * is floored: `max(4px, 0.25rem)` is 4px at a 16px root, grows with the
   * user's font-size preference above that, and never renders below the
   * designed value at a smaller root — so a bundle dropped into a host that
   * carries `html { font-size: 62.5% }` cannot silently rescale.
   *
   * `[data-units="absolute"]` pins the unit for output that must never move:
   * print stylesheets, pixel-diffed screenshots, a surface matching a host's
   * fixed metrics. It is the opt-out, not the default, because the person
   * helped by scaling is the reader and the person setting the attribute is
   * not. docs/ADR/ADR-token-units-policy.md holds the measurements.
   */
  --cr-unit: max(4px, 0.25rem);

  --cr-space-0: calc(0 * var(--cr-unit));
  --cr-space-1: calc(1 * var(--cr-unit));
  --cr-space-2: calc(2 * var(--cr-unit));
  --cr-space-3: calc(3 * var(--cr-unit));
  --cr-space-4: calc(4 * var(--cr-unit));

  /* Half steps. The control padding ladder advances 0.5 unit per size step
     while height advances a full one, which is what keeps padding a stable
     share of height across the five sizes instead of tripling while height
     only doubles. --cr-space-optical already established sub-unit values. */
  --cr-space-1-5: calc(1.5 * var(--cr-unit));
  --cr-space-2-5: calc(2.5 * var(--cr-unit));
  --cr-space-3-5: calc(3.5 * var(--cr-unit));
  --cr-space-5: calc(5 * var(--cr-unit));
  --cr-space-6: calc(6 * var(--cr-unit));
  --cr-space-7: calc(7 * var(--cr-unit));
  --cr-space-8: calc(8 * var(--cr-unit));
  --cr-space-12: calc(12 * var(--cr-unit));

  /* Outside the ramp, deliberately. 2px is not a step on a 4px base, and
     naming it `space-0-5` is what made a generator read our base as 2px while
     the header claimed 4px. It is the sub-step optical correction three
     places need — the switch track inset, the comfortable row's bump over
     the small control height, and Pagination's width buffer — and it is named
     so a fourth consumer has to justify itself rather than reach for a
     half-step that looks like scale. */
  --cr-space-optical: calc(0.5 * var(--cr-unit));
}

[data-units="absolute"] {
  --cr-unit: 4px;
}

/* ===== src/tokens/icon.css — copied at build time, do not edit ===== */
:root {
  --cr-size-icon-xs: 16px;
  --cr-size-icon-sm: 20px;
  --cr-size-icon-md: 24px;
  --cr-size-icon-lg: 32px;
  --cr-size-icon-xl: 48px;

  /* Control-adornment ladder. Distinct from the standalone icon sizes above,
     which jump 24 -> 32 -> 48 because they are sized for their own sake. These
     step 4px per control size step, which holds the slack between icon and
     control at 8px per side at a 16px root: 32-16, 36-20, 40-24, 44-28, 48-32.
     Literal px, not arithmetic on the unit token — an icon is a physical mark
     like a
     hairline or a radius, and src/test/unitBasisAudit.test.ts holds every
     icon.css token to that. The consequence is deliberate — above a 16px root
     the control ladder grows and the adornment does not, so the slack widens
     rather than the glyph inflating. */
  --cr-size-control-icon-xs: 16px;
  --cr-size-control-icon-sm: 20px;
  --cr-size-control-icon-md: 24px;
  --cr-size-control-icon-lg: 28px;
  --cr-size-control-icon-xl: 32px;
}

/* ===== src/tokens/border.css — copied at build time, do not edit ===== */
/* Border width and style — two independent axes, named the same way.
 *
 * Width is deliberately two steps plus zero. A border is a hairline or an
 * emphasis edge; nothing in the library draws a third weight, and the requests
 * for one have each turned out to be a request for a different colour instead.
 *
 * The style tokens look like identity aliases, and that is the point rather
 * than an accident. `crossroads/border-token-only` can only reject a raw
 * keyword if there is a named value to reject it in favour of, so the closed
 * set has to be spelled out somewhere. It also gives a theme one place to
 * substitute — a brand that renders its dashed edges as dotted changes this
 * file, not every component that draws one.
 *
 * `double` is deliberately absent too, for a reason that only shows up when
 * you look at it: it needs roughly 3px before its two lines separate. At 1px
 * and 2px — the only widths this scale offers — it renders as a single line
 * indistinguishable from `solid`. A public value that cannot visibly differ
 * from another is a promise the system cannot keep, so it is not offered.
 * `crossroads/border-token-only` still rejects a raw `double` keyword; there is
 * no sanctioned token to point at because there is no sanctioned double.
 *
 * `hidden` is deliberately absent, and this note is why. It reads like the way
 * to hide a border while holding the layout, and it is not: `border-style:
 * hidden` computes the width to 0 exactly as `none` does, so the box collapses
 * by the border on both sides. Measured on a 100x40 content box with a 2px
 * border, `none` and `hidden` both give 100x40 while `solid` gives 104x44. To
 * swap an element between bordered and unbordered *without* moving anything,
 * keep the width and paint the edge away on the colour axis:
 *
 *   border: var(--cr-border-width-normal) var(--cr-border-style-solid) transparent;
 *
 * `hidden`'s one real behaviour is winning border-conflict resolution in a
 * `border-collapse: collapse` table, where `none` loses to any neighbouring
 * border. Add a token for it when a table actually needs that, not before.
 */
:root {
  /* Carries a unit so it survives arithmetic. Unitless `0` is a <number>, and
     `calc(-1 * 0)` is therefore a number too -- invalid wherever a <length> is
     required, so the whole declaration is dropped at computed-value time. That
     is silent: ButtonBase's ripple clip resolved to `top: auto` and jumped to
     the static position on the one variant that sets this width. `0px` and `0`
     are identical everywhere this token is already used. */
  --cr-border-width-none: 0px;
  --cr-border-width-normal: 1px;
  --cr-border-width-emphasis: 2px;

  --cr-border-style-solid: solid;
  --cr-border-style-dashed: dashed;
  --cr-border-style-dotted: dotted;
}

/* ===== src/tokens/radius.css — copied at build time, do not edit ===== */
/*
 * The radius scale.
 *
 * Three layers, per ADR-radius-preset-ladder.md §3.4:
 *
 *   primitives  none -> 4xl, a rising numeric ramp. A fixed reference scale;
 *               no preset touches it.
 *   roles       what a component actually asks for: a detail, a row, a field,
 *               a control, a surface. `pill` is one of these now (§3.3).
 *   shapes      `circle` alone, outside the system (§3.4)
 *
 * Presets assign roles directly. They used to retune the primitive ramp and
 * let the roles re-read it, which broke silently whenever a scope rebound a
 * role onto a primitive it did not itself declare — CR-D-063, where `flat`
 * rebound `surface` onto `lg` and never set `lg`, so flat themes kept rounded
 * cards. Assigning roles directly removes the failure mode rather than fixing
 * one instance of it.
 *
 * Values match Tailwind v4.3.3 exactly and Polaris 9.4.2 on seven of eight
 * steps. See docs/ADR/ADR-radius-scale-and-focus-ring.md for the survey of
 * nine systems that produced them, and for why 14px and 30px were retired.
 *
 * `xl`, `3xl` and `4xl` have no role pointing at them. They stay anyway: the
 * product *is* the token scale, the values are survey-backed, and removing
 * members from a public union to tidy an internal count is the wrong trade.
 * The old headroom justification for them is gone rather than corrected —
 * presets no longer slide along this ramp, so nothing needs room above.
 *
 * Every component reaches this scale through the role tokens, or through
 * `RadiusToken` and `getRadiusClasses` (src/components/layout/layoutTypes.ts)
 * for the six components with a `radius` prop. `crossroads/radius-token-only`
 * enforces that.
 */
:root {
  --cr-radius-none: 0;
  --cr-radius-xs: 2px;
  --cr-radius-sm: 4px;
  --cr-radius-md: 6px;
  --cr-radius-lg: 8px;
  --cr-radius-xl: 12px;
  --cr-radius-2xl: 16px;
  --cr-radius-3xl: 24px;
  --cr-radius-4xl: 32px;

  /*
   * `full` is a sentinel meaning "maximally round", not the top of the ramp.
   * It is a large length rather than `50%` because it backs `pill`, which is
   * applied to non-square elements where `50%` renders an ellipse rather than
   * a stadium. Polaris (9999px) and Bootstrap (800px) both use a length here;
   * no system surveyed uses `50%` for this step.
   */
  --cr-radius-full: 999px;

  /*
   * Roles. A component asks for the job, not the size, so a preset or a
   * density change can move the whole family coherently.
   *
   * These are `tight`. The resting state is the one that applies when the
   * attribute is absent, and `tight` declares the same values again below so
   * the file can be read without already knowing which preset `:root` is
   * (ADR §3.5). The two must not drift; `radiusPresetRoleTokens.test.ts`
   * compares them.
   */
  --cr-radius-detail: var(--cr-radius-xs);
  --cr-radius-row: 0;
  --cr-radius-field: var(--cr-radius-sm);
  --cr-radius-control: var(--cr-radius-md);
  --cr-radius-surface: var(--cr-radius-lg);
  --cr-radius-surface-large: var(--cr-radius-2xl);

  /*
   * `row` is 0 because a list row is cropped by the container it sits in
   * rather than rounding itself. That is only legal paired with an inset
   * focus ring — an outward ring on a flush row is clipped on three sides by
   * the container's own overflow. See `--cr-size-focus-offset-inset`.
   *
   * `field` and `row` were one token (`compact`) until 2026-08-29. They share
   * a value but not a job: a field is free-standing and keeps its corners,
   * a row does not.
   */

  /*
   * `pill` is a role, assigned by every preset the way `control` and `surface`
   * are — `full` in four of them and `control` in `square` (ADR §3.3). This
   * reverses the older line that placed it outside what presets may retune:
   * four presets agreeing is a judgement, not an accident, and leaves room for
   * a future preset to differ without another architecture change.
   *
   * It stays a length rather than an alias of `circle`, because `pill` is
   * applied to elements of any aspect ratio, where `50%` renders an ellipse.
   */
  --cr-radius-pill: var(--cr-radius-full);

  /*
   * Shapes. `circle` alone, and no preset touches it (ADR §3.4). `50%` is not
   * a corner value at all — it is a technique for constructing a circle, and
   * it works only because every consumer is a known square. It has no ramp
   * analogue and no meaningful intermediate: `50% / 3` is `16.7%`, a rounded
   * rectangle rather than a smaller circle. A consumer who genuinely wants
   * square avatars sets this property itself.
   */
  --cr-radius-circle: 50%;
}

/*
 * The ladder — six presets (ADR §3.2; `crisp` added for #401, see below).
 *
 * `tight` is today's default renamed; its values are unchanged, so the rename
 * is behaviour-neutral. `square` and `flat` are numerically identical and
 * differ only in `pill`: 1px of corner on a checkbox is invisible, while a
 * switch changing from capsule to rectangle is the loudest shape signal on a
 * screen. Two presets separated by the most visible lever are distinguishable;
 * two separated by a pixel are not.
 *
 * The ladder is deliberately not uniform. `tight / curved / rounded` step along
 * the primitive ramp; `square` and `flat` are a character change that
 * compresses toward zero, which is why `square`'s surface-large (5px) sits so
 * far below `tight`'s (16px). Smoothing that out would undo the decision.
 *
 * Values that sit on the ramp reference it, so the relationship stays visible.
 * `square` and `flat` use lengths because 1px, 3px and 5px are below the ramp's
 * first step and have no primitive to name.
 */
[data-radius-preset="square"],
[data-radius-preset="flat"] {
  --cr-radius-detail: 1px;
  --cr-radius-row: 0;
  --cr-radius-field: 1px;
  --cr-radius-control: 2px;
  --cr-radius-surface: 3px;
  --cr-radius-surface-large: 5px;
  --cr-radius-pill: var(--cr-radius-full);
}

/* The one difference, written as an override so the numbers above cannot
   drift apart between the two. */
[data-radius-preset="square"] {
  --cr-radius-pill: var(--cr-radius-control);
}

[data-radius-preset="tight"] {
  --cr-radius-detail: var(--cr-radius-xs);
  --cr-radius-row: 0;
  --cr-radius-field: var(--cr-radius-sm);
  --cr-radius-control: var(--cr-radius-md);
  --cr-radius-surface: var(--cr-radius-lg);
  --cr-radius-surface-large: var(--cr-radius-2xl);
  --cr-radius-pill: var(--cr-radius-full);
}

[data-radius-preset="curved"] {
  --cr-radius-detail: var(--cr-radius-sm);
  --cr-radius-row: 0;
  --cr-radius-field: var(--cr-radius-md);
  --cr-radius-control: var(--cr-radius-lg);
  --cr-radius-surface: var(--cr-radius-xl);
  --cr-radius-surface-large: var(--cr-radius-3xl);
  --cr-radius-pill: var(--cr-radius-full);
}

/*
 * `rounded` is a design-language commitment, not one more rung: its `control`
 * is `pill`, so buttons, IconButtons, SegmentedControl and Tabs become
 * capsules. The ramp has no value between 12px and the stadium threshold of
 * the smallest button, so this is the only way `rounded` can be meaningfully
 * rounder than `curved`. It is not expressible as a length.
 */
[data-radius-preset="rounded"] {
  --cr-radius-detail: var(--cr-radius-md);
  --cr-radius-row: 0;
  --cr-radius-field: var(--cr-radius-lg);
  --cr-radius-control: var(--cr-radius-pill);
  --cr-radius-surface: var(--cr-radius-2xl);
  --cr-radius-surface-large: var(--cr-radius-4xl);
  --cr-radius-pill: var(--cr-radius-full);
}

/*
 * `crisp` is the sixth rung, added for #401: a consumer matching an external
 * reference needed near-square controls (2-4px) alongside `tight`'s roomier
 * surfaces (8px+), a combination no single rung on the §3.2 ladder expresses
 * — every existing preset still moves `control` and `surface` together.
 *
 * It is not a new axis or an override mechanism; it composes two already-
 * curated looks into one named rung, the same way the ladder always has:
 * `flat`'s control/field/detail values (the "near-square" end) paired with
 * `tight`'s surface/surface-large values (the "roomier" end). `pill` stays
 * `full`, matching `flat` rather than `square` — this preset is about control
 * vs. surface proportion, not about squaring switches and chips.
 */
[data-radius-preset="crisp"] {
  --cr-radius-detail: 1px;
  --cr-radius-row: 0;
  --cr-radius-field: 1px;
  --cr-radius-control: 2px;
  --cr-radius-surface: var(--cr-radius-lg);
  --cr-radius-surface-large: var(--cr-radius-2xl);
  --cr-radius-pill: var(--cr-radius-full);
}

/* ===== src/tokens/shadow.css — copied at build time, do not edit ===== */
/* Elevation.
 *
 * Two channels, because one does not survive a theme flip. The drop shadow is
 * the primary cue; the tonal overlays below are the secondary one, used by the
 * few surfaces that need to lift off a dark page rather than cast onto it.
 *
 * GROUPS
 *
 * The shadow channel is two dimensions, not one. A *level* (1-4) is the rung —
 * how far off the page a surface sits — and belongs to the component: a Popover
 * is a 2, a Dialog is a 3, and no customization moves it. A *group* (flat, soft,
 * hard, sharp) is the house style — what a shadow at any rung looks like — and
 * belongs to the client. Switching the group re-skins every elevated surface at
 * once while each keeps its own level.
 *
 *   flat    no drop shadow at all; surfaces separate by border and tone.
 *   soft    the original ladder: wide blur, low alpha, ambient.
 *   hard    the same geometry with alpha x1.5 and blur x0.65 — darker, and
 *           tight enough that the shadow has a locatable edge.
 *   sharp   two layers doing different jobs: a low-alpha halo plus a near
 *           layer at 0.42-0.48, so the surface reads as touching the page.
 *
 * Components never name a group. They keep consuming
 * `--cr-shadow-elevation-0`…`-4`, which this file points at the active group;
 * the sixteen `--cr-shadow-<group>-<level>` tokens stay addressable so a docs
 * page can show every group side by side.
 *
 * Select a group with `data-shadow-group` on any ancestor (default: soft).
 * Bare attribute selectors rather than `:root[…]` for the same reason the theme
 * blocks below are bare: a region has to be able to differ from the page.
 *
 * THEMES
 *
 * The shadow colour is theme-specific, and CR-D-020 is why. The scale used to
 * be declared once, under bare :root, as near-black at 8%-20% alpha. That reads
 * on a light page and vanishes on a dark one: every level composited to a
 * 1.003-1.005 contrast ratio against the dark surface, so a five-step prop had
 * one visible step. Elevation 1 and elevation 4 were indistinguishable.
 *
 * Dark uses pure black at much higher alpha. The alphas were solved against the
 * live dark surface rather than picked, and they do not reproduce the light
 * ladder because they cannot: black over a near-black page saturates at a
 * ratio of about 1.35 (1.345 warm, 1.354 cold), which is below light's own
 * level 3. What they do give is four evenly separated steps that stay clear of
 * that ceiling — measured on the FAR layer alone, which is the one CR-D-020
 * solved, so these numbers are deliberately not comparable with the group table
 * below:
 *
 *   level   light   dark (warm / cold)
 *   1       1.164   1.102 / 1.106
 *   2       1.266   1.168 / 1.171
 *   3       1.371   1.222 / 1.229
 *   4       1.498   1.267 / 1.277
 *
 * Those ratios are the *soft* group's far layer. The table below is the other
 * measurement: every group, BOTH layers composited, which is what the darkest
 * point under a panel's edge actually is. Same alphas, two questions — how dark
 * the ambient wash is, against how dark the surface gets where the layers
 * overlap — so soft reads 1.102 above and 1.171 here. Neither is stale; they
 * answer different things, which nothing said until a review on PR #284 took one
 * of them for an error. Measured against surface-default, warm palette:
 *
 *   dark    level 1  level 2  level 3  level 4
 *   soft    1.171    1.231    1.280    1.312
 *   hard    1.204    1.249    1.289    1.329
 *   sharp   1.242    1.280    1.313    1.337
 *
 * The gaps narrow towards level 4 because they have to: 1.345 is what black over
 * this surface reaches, and no group can be darker than black. Up there the
 * groups separate mostly by blur — 48px soft, 31px hard, 22px sharp at level 4 —
 * which is the difference the eye reads as hardness once darkness runs out.
 *
 * All three ladders were solved against this surface on 2026-09-05, replacing
 * multipliers carried over from light. What the table shows is the constraint
 * rather than a preference: three groups and four levels do not fit into the
 * 1.171-1.345 band with a visible gap everywhere, so the gaps narrow towards
 * level 4 and geometry carries the group difference there. CR-R-007 in
 * docs/DECISION_REVIEW_LEDGER.md records the reasoning and the numbers.
 *
 * The geometry is identical across themes on purpose. Offset and blur grow
 * 1px -> 20px across the scale, so the levels separate by extent as well as by
 * darkness, and the top two stay legible despite sitting closer in contrast
 * than they do in light.
 *
 * Both themes are declared explicitly, not just dark. A light region nested
 * inside a dark one has to reset, which a :root-only base cannot do.
 */
:root {
  /* flat — no drop shadow at any level, for a design language that separates
     surfaces by border and tone instead. Declared as four tokens rather than
     writing `none` into the group block, so the lever stays pure indirection
     and a flat kit is addressable like any other group.

     This turns off the shadow channel only, and the tonal channel is NOT a
     fallback that makes it safe. In dark the tints carry a real cue, because
     they are the white-alpha wash below. In light they are all `none` by
     design — the shadow was the cue there — so under flat a light surface has
     no elevation cue at all, and elevation stops being visual: it still orders
     stacking, but it paints nothing.

     What that costs is real and observed, not theoretical:
     `<Shape tone="background" elevation={2} />` composites to exactly the page
     colour under flat in light, with no border (Shape defaults to
     `border="none"`), no tint, and now no shadow. The element is invisible.
     Choosing flat therefore moves the whole burden of separation onto border
     and tone, and a surface that relied on the shadow alone must be given one.
     CR-R-008 in docs/DECISION_REVIEW_LEDGER.md carries the case and the two
     candidate resolutions. */
  --cr-shadow-flat-1: none;
  --cr-shadow-flat-2: none;
  --cr-shadow-flat-3: none;
  --cr-shadow-flat-4: none;

  /* soft — ambient */
  --cr-shadow-soft-1: 0 1px 2px rgb(32 33 36 / 0.08),
    0 1px 3px rgb(32 33 36 / 0.08);
  --cr-shadow-soft-2: 0 4px 12px rgb(32 33 36 / 0.12),
    0 2px 4px rgb(32 33 36 / 0.08);
  --cr-shadow-soft-3: 0 12px 28px rgb(32 33 36 / 0.16),
    0 4px 10px rgb(32 33 36 / 0.1);
  --cr-shadow-soft-4: 0 20px 48px rgb(32 33 36 / 0.2),
    0 8px 18px rgb(32 33 36 / 0.12);

  /* hard — soft's geometry, alpha x1.5 and blur x0.65 */
  --cr-shadow-hard-1: 0 1px 1px rgb(32 33 36 / 0.12),
    0 1px 2px rgb(32 33 36 / 0.12);
  --cr-shadow-hard-2: 0 4px 8px rgb(32 33 36 / 0.18),
    0 2px 3px rgb(32 33 36 / 0.12);
  --cr-shadow-hard-3: 0 12px 18px rgb(32 33 36 / 0.24),
    0 4px 7px rgb(32 33 36 / 0.15);
  --cr-shadow-hard-4: 0 20px 31px rgb(32 33 36 / 0.3),
    0 8px 12px rgb(32 33 36 / 0.18);

  /* sharp — halo plus contact layer */
  --cr-shadow-sharp-1: 0 1px 1px rgb(32 33 36 / 0.12),
    0 1px 1px rgb(32 33 36 / 0.42);
  --cr-shadow-sharp-2: 0 4px 5px rgb(32 33 36 / 0.18),
    0 2px 2px rgb(32 33 36 / 0.42);
  --cr-shadow-sharp-3: 0 12px 13px rgb(32 33 36 / 0.24),
    0 4px 5px rgb(32 33 36 / 0.45);
  --cr-shadow-sharp-4: 0 20px 22px rgb(32 33 36 / 0.3),
    0 8px 8px rgb(32 33 36 / 0.48);

  /* Elevation shadows — the active group. Components name only these; the
     blocks at the end of this file repoint them. Level 0 is the absence of a
     shadow, which is the same in every group and both themes. */
  --cr-shadow-elevation-0: none;
  --cr-shadow-elevation-1: var(--cr-shadow-soft-1);
  --cr-shadow-elevation-2: var(--cr-shadow-soft-2);
  --cr-shadow-elevation-3: var(--cr-shadow-soft-3);
  --cr-shadow-elevation-4: var(--cr-shadow-soft-4);

  /* Elevation tonal overlays */
  --cr-elevation-overlay-0: none;
  --cr-elevation-overlay-1: linear-gradient(
    var(--cr-color-surface-subtle),
    var(--cr-color-surface-subtle)
  );
  --cr-elevation-overlay-2: linear-gradient(
    var(--cr-color-surface-default),
    var(--cr-color-surface-default)
  );
  --cr-elevation-overlay-3: linear-gradient(
    var(--cr-color-surface-raised),
    var(--cr-color-surface-raised)
  );
  --cr-elevation-overlay-4: linear-gradient(
    var(--cr-color-surface-overlay),
    var(--cr-color-surface-overlay)
  );

  /* Elevation tints — the relative half of the tonal channel.

     The overlays above are ABSOLUTE: each paints a named surface colour, for
     a surface whose background is expected to step with its level (Modal,
     Drawer, AppBar). Painted over any other background they do not brighten
     it, they replace it — in light theme they are opaque surface greys, so
     over a brand fill or a mismatched neutral they repaint it grey, and
     overlay-1 over surface-default actually darkens (PR #199 review, the
     Shape blocker).

     A tint is RELATIVE: nothing in light, where the drop shadow carries the
     cue on its own, and the same white-alpha wash as dark's overlays in dark,
     where the shadow saturates. Safe to compose over any background that
     wants lifting without recolouring. Shape's elevation prop pairs this
     channel, not the absolute one. */
  --cr-elevation-tint-0: none;
  --cr-elevation-tint-1: none;
  --cr-elevation-tint-2: none;
  --cr-elevation-tint-3: none;
  --cr-elevation-tint-4: none;
}

[data-theme="light"] {
  --cr-shadow-flat-1: none;
  --cr-shadow-flat-2: none;
  --cr-shadow-flat-3: none;
  --cr-shadow-flat-4: none;

  --cr-shadow-soft-1: 0 1px 2px rgb(32 33 36 / 0.08),
    0 1px 3px rgb(32 33 36 / 0.08);
  --cr-shadow-soft-2: 0 4px 12px rgb(32 33 36 / 0.12),
    0 2px 4px rgb(32 33 36 / 0.08);
  --cr-shadow-soft-3: 0 12px 28px rgb(32 33 36 / 0.16),
    0 4px 10px rgb(32 33 36 / 0.1);
  --cr-shadow-soft-4: 0 20px 48px rgb(32 33 36 / 0.2),
    0 8px 18px rgb(32 33 36 / 0.12);

  --cr-shadow-hard-1: 0 1px 1px rgb(32 33 36 / 0.12),
    0 1px 2px rgb(32 33 36 / 0.12);
  --cr-shadow-hard-2: 0 4px 8px rgb(32 33 36 / 0.18),
    0 2px 3px rgb(32 33 36 / 0.12);
  --cr-shadow-hard-3: 0 12px 18px rgb(32 33 36 / 0.24),
    0 4px 7px rgb(32 33 36 / 0.15);
  --cr-shadow-hard-4: 0 20px 31px rgb(32 33 36 / 0.3),
    0 8px 12px rgb(32 33 36 / 0.18);

  --cr-shadow-sharp-1: 0 1px 1px rgb(32 33 36 / 0.12),
    0 1px 1px rgb(32 33 36 / 0.42);
  --cr-shadow-sharp-2: 0 4px 5px rgb(32 33 36 / 0.18),
    0 2px 2px rgb(32 33 36 / 0.42);
  --cr-shadow-sharp-3: 0 12px 13px rgb(32 33 36 / 0.24),
    0 4px 5px rgb(32 33 36 / 0.45);
  --cr-shadow-sharp-4: 0 20px 22px rgb(32 33 36 / 0.3),
    0 8px 8px rgb(32 33 36 / 0.48);

  --cr-shadow-elevation-0: none;

  --cr-elevation-overlay-1: linear-gradient(
    var(--cr-color-surface-subtle),
    var(--cr-color-surface-subtle)
  );
  --cr-elevation-overlay-2: linear-gradient(
    var(--cr-color-surface-default),
    var(--cr-color-surface-default)
  );
  --cr-elevation-overlay-3: linear-gradient(
    var(--cr-color-surface-raised),
    var(--cr-color-surface-raised)
  );
  --cr-elevation-overlay-4: linear-gradient(
    var(--cr-color-surface-overlay),
    var(--cr-color-surface-overlay)
  );

  --cr-elevation-tint-0: none;
  --cr-elevation-tint-1: none;
  --cr-elevation-tint-2: none;
  --cr-elevation-tint-3: none;
  --cr-elevation-tint-4: none;
}

[data-theme="dark"] {
  --cr-shadow-flat-1: none;
  --cr-shadow-flat-2: none;
  --cr-shadow-flat-3: none;
  --cr-shadow-flat-4: none;

  --cr-shadow-soft-1: 0 1px 2px rgb(0 0 0 / 0.24),
    0 1px 3px rgb(0 0 0 / 0.24);
  --cr-shadow-soft-2: 0 4px 12px rgb(0 0 0 / 0.4),
    0 2px 4px rgb(0 0 0 / 0.32);
  --cr-shadow-soft-3: 0 12px 28px rgb(0 0 0 / 0.56),
    0 4px 10px rgb(0 0 0 / 0.44);
  --cr-shadow-soft-4: 0 20px 48px rgb(0 0 0 / 0.72),
    0 8px 18px rgb(0 0 0 / 0.56);

  /* Solved against this surface, not derived from light. The x1.5 rule these
     started as was measured on a light page where nothing was near a ceiling;
     applied to dark alphas that already run to 0.72 it drove level 3 to 0.84
     and level 4 into the 0.92 cap, so the top step of the ladder was worth
     +0.014 in composited contrast — four levels reading as three — and sharp
     had to reach 0.92 just to clear it (CR-R-007).

     These are chosen by target instead: four steps of roughly +0.043 each,
     starting above soft and stopping clear of the 1.345 ceiling, with each
     level's near/halo alpha ratio kept from light's `hard` so the two themes
     stay the same shape. Composited against surface-default:

       level  ratio   step
       1      1.204
       2      1.249   +0.045
       3      1.289   +0.040
       4      1.329   +0.040

     Ratios are rounded to three decimals and the steps are differences of the
     displayed values, so subtracting the column reproduces them exactly. The
     unrounded first step is +0.0457.

     Level 4 now sits 0.017 above soft's rather than 0.031, and that is the
     trade being made knowingly: near the ceiling, group separation costs level
     separation, and a level ladder that does not separate is the worse failure.
     What distinguishes hard from soft up there is blur — 31px against 48px —
     which is what the eye reads as hardness once darkness has run out. */
  --cr-shadow-hard-1: 0 1px 1px rgb(0 0 0 / 0.3),
    0 1px 2px rgb(0 0 0 / 0.3);
  --cr-shadow-hard-2: 0 4px 8px rgb(0 0 0 / 0.48),
    0 2px 3px rgb(0 0 0 / 0.32);
  --cr-shadow-hard-3: 0 12px 18px rgb(0 0 0 / 0.67),
    0 4px 7px rgb(0 0 0 / 0.42);
  --cr-shadow-hard-4: 0 20px 31px rgb(0 0 0 / 0.9),
    0 8px 12px rgb(0 0 0 / 0.54);

  /* Sharp's light alphas cannot be reused here, and the first attempt at this
     file did reuse them: 0.18/0.42 spends 42% of a 218-level gap on a light
     page and 42% of a 41-level gap on a dark one, which put sharp BELOW soft
     at levels 2-4 — the group that should read hardest read softest. The
     correction that followed overshot the other way: a contact layer at
     0.80-0.92 saturates at level 1, so all four levels landed between 1.312 and
     1.345 with steps of +0.015, +0.010, +0.008 — the ladder had a group but no
     rungs.

     Solved by target, like hard's, keeping each level's near/halo ratio from
     light's sharp so the contact layer stays the dominant one and the group
     still reads as a surface touching the page:

       level  ratio   step   margin over hard
       1      1.242          +0.038
       2      1.280   +0.038 +0.031
       3      1.313   +0.033 +0.024
       4      1.337   +0.024 +0.008

     Steps and margins are differences of the displayed, rounded ratios, so the
     columns check out by subtraction.

     Level 4 is where the dark band runs out. Its near layer is at 0.95 and its
     margin over hard is +0.008, which no eye will read as darkness; what still
     separates them there is blur, 22px against 31px. Four groups cannot all
     hold a visible darkness gap at the top level when black over this surface
     stops at 1.345 — that is the ceiling being full, not a tuning error, and
     it is the reason the group blocks differ in geometry rather than alpha
     alone. */
  --cr-shadow-sharp-1: 0 1px 1px rgb(0 0 0 / 0.16),
    0 1px 1px rgb(0 0 0 / 0.56);
  --cr-shadow-sharp-2: 0 4px 5px rgb(0 0 0 / 0.29),
    0 2px 2px rgb(0 0 0 / 0.67);
  --cr-shadow-sharp-3: 0 12px 13px rgb(0 0 0 / 0.43),
    0 4px 5px rgb(0 0 0 / 0.81);
  --cr-shadow-sharp-4: 0 20px 22px rgb(0 0 0 / 0.6),
    0 8px 8px rgb(0 0 0 / 0.95);

  --cr-shadow-elevation-0: none;

  --cr-elevation-overlay-1: linear-gradient(
    rgb(255 255 255 / 0.04),
    rgb(255 255 255 / 0.04)
  );
  --cr-elevation-overlay-2: linear-gradient(
    rgb(255 255 255 / 0.07),
    rgb(255 255 255 / 0.07)
  );
  --cr-elevation-overlay-3: linear-gradient(
    rgb(255 255 255 / 0.1),
    rgb(255 255 255 / 0.1)
  );
  --cr-elevation-overlay-4: linear-gradient(
    rgb(255 255 255 / 0.13),
    rgb(255 255 255 / 0.13)
  );

  /* Aliases, not copies: dark is the one theme where tint and overlay agree,
     and restating the alphas here would leave two hand-maintained ramps with
     only a comment keeping them in sync. */
  --cr-elevation-tint-0: none;
  --cr-elevation-tint-1: var(--cr-elevation-overlay-1);
  --cr-elevation-tint-2: var(--cr-elevation-overlay-2);
  --cr-elevation-tint-3: var(--cr-elevation-overlay-3);
  --cr-elevation-tint-4: var(--cr-elevation-overlay-4);
}

/* The group lever. These repoint the four tokens components consume; they
   never restate a value, so a group can only ever be one of the twelve above.
   Declared after the theme blocks and at equal specificity, so the last
   matching group wins and a nested region can differ from the page. */
[data-shadow-group="flat"] {
  --cr-shadow-elevation-1: var(--cr-shadow-flat-1);
  --cr-shadow-elevation-2: var(--cr-shadow-flat-2);
  --cr-shadow-elevation-3: var(--cr-shadow-flat-3);
  --cr-shadow-elevation-4: var(--cr-shadow-flat-4);
}

[data-shadow-group="soft"] {
  --cr-shadow-elevation-1: var(--cr-shadow-soft-1);
  --cr-shadow-elevation-2: var(--cr-shadow-soft-2);
  --cr-shadow-elevation-3: var(--cr-shadow-soft-3);
  --cr-shadow-elevation-4: var(--cr-shadow-soft-4);
}

[data-shadow-group="hard"] {
  --cr-shadow-elevation-1: var(--cr-shadow-hard-1);
  --cr-shadow-elevation-2: var(--cr-shadow-hard-2);
  --cr-shadow-elevation-3: var(--cr-shadow-hard-3);
  --cr-shadow-elevation-4: var(--cr-shadow-hard-4);
}

[data-shadow-group="sharp"] {
  --cr-shadow-elevation-1: var(--cr-shadow-sharp-1);
  --cr-shadow-elevation-2: var(--cr-shadow-sharp-2);
  --cr-shadow-elevation-3: var(--cr-shadow-sharp-3);
  --cr-shadow-elevation-4: var(--cr-shadow-sharp-4);
}

/* ===== src/tokens/motion.css — copied at build time, do not edit ===== */
:root {
  /* Motion durations */
  --cr-motion-duration-instant: 1ms;
  --cr-motion-duration-shorter: 150ms;
  --cr-motion-duration-short: 200ms;
  --cr-motion-duration-fast: 160ms;
  --cr-motion-duration-standard: 300ms;
  --cr-motion-duration-complex: 375ms;
  --cr-motion-duration-spinner: 800ms;
  --cr-motion-duration-ripple: 520ms;

  /* Motion timing curves */
  --cr-motion-ease-linear: linear;
  --cr-motion-ease-standard: cubic-bezier(0.2, 0, 0, 1);
  --cr-motion-ease-entering: cubic-bezier(0, 0, 0.2, 1);
  --cr-motion-ease-leaving: cubic-bezier(0.4, 0, 1, 1);
  --cr-motion-ease-sharp: cubic-bezier(0.4, 0, 0.6, 1);

  /* Motion distances and reusable transforms */
  --cr-motion-distance-hover-y: -1px;
  --cr-motion-distance-slide: 1rem;
  --cr-motion-scale-grow-start: 0.92;
  --cr-motion-scale-zoom-start: 0.82;
  --cr-motion-iteration-infinite: infinite;
}

/* ===== src/tokens/opacity.css — copied at build time, do not edit ===== */
:root {
  --cr-opacity-hidden: 0;
  --cr-opacity-disabled: 0.56;
  --cr-opacity-state-hover: 0.08;
  --cr-opacity-state-focus: 0.16;
  --cr-opacity-state-pressed: 0.2;
  --cr-opacity-state-selected: 0.16;
  --cr-opacity-state-disabled: 0.38;

  /* Backdrop scrim strength (CR-D-030). The colour is the generated
     `--cr-color-backdrop-color`, which is deliberately solid; this token is
     the only place the scrim's transparency lives, and overlay.css composes
     the two. Theme-specific for the same reason as the elevation scale
     (CR-D-020): a dark page needs a heavier scrim than a light one to read as
     dimmed at all. Declared in both themes, not just dark, so a light region
     nested inside a dark one resets. */
  --cr-opacity-backdrop: 0.44;
}

[data-theme="light"] {
  --cr-opacity-backdrop: 0.44;
}

[data-theme="dark"] {
  --cr-opacity-backdrop: 0.64;
}

/* ===== src/tokens/transform.css — copied at build time, do not edit ===== */
:root {
  --cr-transform-none: none;
  --cr-transform-origin-center: center;
  --cr-transform-direction-reverse: -1;
  --cr-transform-rotation-three-quarter: 270deg;
  --cr-transform-rotation-half: 180deg;
  --cr-transform-rotation-full: 360deg;
  --cr-text-align-start: start;
  --cr-text-align-center: center;
  --cr-text-align-end: end;
  --cr-text-transform-none: none;
}

/* ===== src/tokens/layout.css — copied at build time, do not edit ===== */
:root {
  --cr-size-viewport-min: 320px;
  /* The correctly named token is the definition; --cr-size-touch-target-min is
     kept as its alias because it predates the rule and 80 declarations plus the
     docs cite it by that name. The floor is not touch-specific — WCAG 2.2 SC
     2.5.8 applies to every pointer — so read "touch" here as historical. */
  --cr-size-pointer-target-floor: 24px;
  --cr-size-touch-target-min: var(--cr-size-pointer-target-floor);
  /* DR-CR-304 (amended 2026-08-29): every interactive target reserves this
     floor in both dimensions, regardless of pointer type. The value is WCAG 2.2
     SC 2.5.8 Target Size (Minimum), Level AA. It read 44px until 2026-08-29,
     citing SC 2.5.5 at Level AAA — a level this library cannot claim while text
     contrast is enforced at 4.5:1, so the extra 20px bought no conformance and
     cost real geometry. 44px remains preferred where layout permits; it is not
     a floor.

     Compose this into *target* dimensions only — never max() it against a
     visual size token, which makes that token unreachable. And never use it as
     a visual value: that is what tied the spacious row height to the floor and
     would have inverted the density scale when the floor moved. */
  /* Control heights derive from the spacing unit because they are text-coupled:
     a control that holds text has to grow when the reader enlarges it, or the
     text outgrows its box. Multiples of the 4px base, so every value is
     unchanged at a 16px root. The pointer target floor below is NOT derived —
     it is a property of fingers, not of text, and must hold at any root.
     docs/ADR/ADR-token-units-policy.md §3-E. */
  /* One step per size step: 8/9/10/11/12 units = 32/36/40/44/48px. The five
     names are the shared vocabulary in src/components/size.ts. */
  --cr-size-control-xs: calc(8 * var(--cr-unit));
  --cr-size-control-sm: calc(9 * var(--cr-unit));
  --cr-size-control-md: calc(10 * var(--cr-unit));
  --cr-size-control-lg: calc(11 * var(--cr-unit));
  --cr-size-control-xl: calc(12 * var(--cr-unit));

  /* Minimum width of a labelled control, so a short label does not render a
     square that reads as an icon button. Flat rather than a multiple of the
     control height: it is a legibility floor for the label, and a two-letter
     word needs the same room at every size. 64px matches MUI's Button
     minWidth. Icon-only controls are excluded — they are square by design. */
  --cr-size-control-min-inline: calc(16 * var(--cr-unit));
  --cr-size-control-indicator: calc(4.5 * var(--cr-unit));

  /* 36/44/52 here is Switch's own geometry, not the control ladder. The two
     were equal while the ladder was 36/44/52; it is 32/36/40/44/48 now, so they
     are independent and a reader must not assume changing one moves the other.
     Within Switch the track height and thumb are still derived from the width —
     those three scale together or the thumb stops being centred. */
  --cr-size-switch-track-width-sm: calc(9 * var(--cr-unit));
  --cr-size-switch-track-height-sm: calc(5.5 * var(--cr-unit));
  --cr-size-switch-thumb-sm: calc(4 * var(--cr-unit));
  --cr-size-switch-track-width-md: calc(11 * var(--cr-unit));
  --cr-size-switch-track-height-md: calc(6.5 * var(--cr-unit));
  --cr-size-switch-thumb-md: calc(5 * var(--cr-unit));
  --cr-size-switch-track-width-lg: calc(13 * var(--cr-unit));
  --cr-size-switch-track-height-lg: calc(7.5 * var(--cr-unit));
  --cr-size-switch-thumb-lg: calc(6 * var(--cr-unit));
  --cr-size-switch-track-width: var(--cr-size-switch-track-width-md);
  --cr-size-switch-track-height: var(--cr-size-switch-track-height-md);
  --cr-size-switch-thumb: var(--cr-size-switch-thumb-md);
  --cr-size-switch-thumb-travel: calc(
    var(--cr-size-switch-track-width) - var(--cr-size-switch-thumb) -
      var(--cr-space-2) - var(--cr-border-width-normal) -
      var(--cr-border-width-normal)
  );
  /* 2px is the market standard (Carbon, Ant, Mantine, Spectrum all use it)
     and the floor set by WCAG 2.2 Focus Appearance (SC 2.4.13). There is no
     headroom beneath it. Was 3px until 2026-08-29; the 5px total overflowed
     the menu surface's own 4px padding and was clipped by its overflow. */
  --cr-size-focus-ring: 2px;
  --cr-size-focus-offset: 2px;
  /* Flush rows are cropped by their container, so an outward ring loses
     three of its four sides. Rows draw the ring inside themselves. */
  --cr-size-focus-offset-inset: -2px;
  --cr-size-spinner: 1em;
  --cr-size-spinner-sm: 0.875em;
  --cr-size-spinner-md: 1em;
  --cr-size-spinner-lg: 1.25em;
  --cr-size-divider-thickness: 1px;
  --cr-size-divider-length: 100%;
  --cr-size-divider-min-block: 1em;
  --cr-size-data-display-compact: 24px;
  --cr-size-data-display-action: 24px;
  /* Three families, one scale: a tag's pill, a chip's pill, and the chip's
     remove control. xs is the step a compact density row asks for, sm what a
     comfortable one does, md a spacious one — a component with no size prop
     reads its step from the row it sits in (Chip.css, Tag.css).

     Every value here is a *paint* size, not a box size. The control still
     reserves --cr-size-pointer-target-floor and shrinks only what it draws, so
     an xs chip paints a 20px pill inside an unchanged 24px target. That is the
     two-layer pattern CR-D-012 established, and it is the only way a step below
     24px can exist without breaking DR-CR-304. */
  --cr-size-tag-xs: 16px;
  --cr-size-tag-sm: 20px;
  --cr-size-tag-md: 24px;
  --cr-size-chip-xs: 20px;
  --cr-size-chip-sm: 24px;
  --cr-size-chip-md: 32px;
  --cr-size-chip-remove-xs: 20px;
  --cr-size-chip-remove-sm: 24px;
  --cr-size-chip-remove-md: 32px;
  --cr-color-swatch-min-inline: 220px;
  --cr-color-swatch-preview: 44px;
  /* The painted swatch inside a ColorPicker control. Distinct from
     --cr-color-swatch-preview, which is ColorPalette's large preview tile, and
     from the 44px target the swatch sits inside (DR-CR-304). */
  --cr-size-color-swatch: 32px;
  --cr-size-avatar-sm: 32px;
  --cr-size-avatar-md: 40px;
  --cr-size-avatar-lg: 56px;
  --cr-size-avatar-xl: 80px;
  --cr-size-avatar-2xl: 120px;
  --cr-size-table-min-inline: 480px;
  --cr-size-menu-min-inline: 180px;
  --cr-size-menu-max-block: 320px;
  --cr-size-menu-panel-inline: 280px;
  --cr-menu-mobile-inset: var(--cr-space-4);
  --cr-size-overlay-max-inline: 320px;
  --cr-size-overlay-panel-inline: 300px;
  --cr-size-dialog-max-inline: 560px;
  --cr-size-dialog-max-block: 80vh;
  --cr-size-drawer-inline: 360px;
  --cr-size-drawer-collapsed: 60px;
  --cr-size-popover-min-inline: 220px;
  --cr-size-surface-glass-blur: 18px;
  --cr-overlay-viewport-inset: var(--cr-space-4);
  --cr-size-viewport-full-inline: 100vw;
  --cr-size-viewport-full-block: 100vh;
  --cr-size-visually-hidden: 1px;
  --cr-offset-visually-hidden: -1px;
  --cr-clip-visually-hidden: rect(0 0 0 0);
  --cr-clip-path-visually-hidden: inset(50%);
  --cr-white-space-nowrap: nowrap;
  --cr-container-padding-inline: var(--cr-space-4);
  /* Measure scale: how wide one column of content wants to be before it gives
     up and wraps. Drives `Grid.Root` minItemInlineSize and `Stack.Item`
     flexBasis, which are the intrinsic way to make a layout respond — items
     reflow when they stop fitting, with no container query involved.

     Distinct from the step scale in breakpoint.css: a step is a width a rule
     *breaks at*, a measure is a width an item *asks for*. Unlike steps, these
     are real custom properties consumed by real declarations. */
  --cr-measure-2xs: 8rem; /* 128px */
  --cr-measure-xs: 12rem; /* 192px */
  --cr-measure-sm: 16rem; /* 256px */
  --cr-measure-md: 20rem; /* 320px */
  --cr-measure-lg: 24rem; /* 384px */
  --cr-measure-xl: 30rem; /* 480px */
  /* Predates the measure scale and deliberately not snapped onto it: every
     auto-fit Grid in the library wraps here, so changing it is a library-wide
     visual change that belongs in its own commit, not in the one adding the
     opt-in prop. */
  --cr-grid-min-inline-size: 220px;
  /* Content-width scale. `xs` and `sm` complete the lower end: Progress labels
     and Snackbar already referenced them, so the rules existed before the
     tokens did. Roughly the same ~1.28 step as md → lg. */
  --cr-layout-content-xs: 320px;
  --cr-layout-content-sm: 440px;
  --cr-layout-content-md: 560px;
  --cr-layout-content-lg: 720px;
  --cr-flex-shrink-none: 0;
  --cr-multiselect-chip-gap: var(--cr-space-1);
  --cr-multiselect-field-max-block-size: calc(var(--cr-space-8) * 3);
  --cr-multiselect-summary-min-inline-size: var(--cr-size-chip-md);
  --cr-fileupload-dropzone-border-style: var(--cr-border-style-dashed);
  --cr-fileupload-dropzone-border-color: var(--cr-color-border-default);
  --cr-fileupload-dropzone-border-color-active: var(--cr-color-action-primary-text);
  --cr-fileupload-dropzone-bg-drag: color-mix(
    in srgb,
    var(--cr-color-action-primary-text) calc(var(--cr-opacity-state-hover) * 100%),
    transparent
  );
  --cr-fileupload-dropzone-bg-reject: var(--cr-color-feedback-danger-surface);
  --cr-fileupload-dropzone-min-block-size: calc(var(--cr-size-control-md) * 3);
  --cr-fileupload-item-gap: var(--cr-space-2);
  --cr-fileupload-item-padding: var(--cr-space-2);
  --cr-textarea-line-height: var(--cr-line-height-body-1);
  --cr-textarea-min-block-size: calc(var(--cr-size-control-md) * 2);
  --cr-textarea-resize-handle-size: var(--cr-space-3);
  --cr-textarea-count-gap: var(--cr-space-1);
  --cr-textarea-count-color: var(--cr-color-text-secondary);
  --cr-textarea-count-overflow-color: var(--cr-color-feedback-danger-text);
  --cr-hero-accent-min-block-size: calc(var(--cr-size-control-md) * 7);
  /* Layer tokens: use semantic layers instead of component-local hard-coded
     values.

     Interactive overlays share one plane; among equal z-indexes the DOM
     decides, and portals append in open order, so whatever opened last renders
     on top. A ladder of distinct values cannot express nesting — a dropdown
     portalled from inside a modal sat under the modal's backdrop for any fixed
     pair of integers. Every published ladder has this hole: Bootstrap 5.3
     orders modal 1055 below popover 1070, so a modal opened from inside a
     popover loses to it.

     The six per-kind names below are the public API and deliberately resolve to
     the same number. That is the design, not duplication to be tidied up:
     giving them distinct values is exactly what reintroduces the nesting bug.

     The toast plane stays above, because Snackbar is fixed-position where it
     mounts rather than portalled, so insertion order cannot keep a notification
     visible over a modal opened after it.

     Known limit (CR-D-022): open order only decides within one portal root, and
     `CrossroadsProvider` mints its own. Across two providers the providers' DOM
     order wins and the later-opened overlay can render underneath. */
  --cr-z-index-base: 0;
  --cr-z-index-sticky: 100;
  --cr-z-index-overlay: 1000;
  --cr-z-index-dropdown: var(--cr-z-index-overlay);
  --cr-z-index-popover: var(--cr-z-index-overlay);
  --cr-z-index-tooltip: var(--cr-z-index-overlay);
  --cr-z-index-backdrop: var(--cr-z-index-overlay);
  --cr-z-index-modal: var(--cr-z-index-overlay);
  --cr-z-index-drawer: var(--cr-z-index-overlay);
  --cr-z-index-toast: 1100;
}

/* ===== src/tokens/breakpoint.css — copied at build time, do not edit ===== */
/* Container step scale — the single set of widths responsive rules may break at.

   These are *container* steps, not device breakpoints. Element responsiveness
   uses `@container` against the nearest enclosing layout space (see
   docs/LAYOUT_RESPONSIVE_PHASE_1.md), so a step describes how much room a
   component has, not what hardware is displaying it. A component in a 20rem
   sidebar is at `xs` whether the monitor is 13" or 32".

   `var()` is invalid inside `@media` and `@container` conditions, so these
   tokens cannot be referenced from a query — a rule has to repeat the literal
   and name the step in a comment:

     @container cr-space (max-width: 48rem) { ... }   // --cr-step-md

   That makes stylelint, not CSS, the thing keeping the scale honest: the
   allowed-value list in .stylelintrc.json is what stops a seventh magic number
   appearing. Keep the two in sync when changing anything here.

   Exposed as custom properties anyway because JS and the AI manifests read the
   scale from the token layer, and because a consumer overriding a step in
   their own media query still needs a name to refer to. */
:root {
  --cr-step-xs: 20rem; /* 320px */
  --cr-step-sm: 30rem; /* 480px */
  --cr-step-md: 48rem; /* 768px */
  --cr-step-lg: 64rem; /* 1024px */
  --cr-step-xl: 80rem; /* 1280px */
}

/* ===== src/tokens/focus.css — copied at build time, do not edit ===== */
/* Focus-ring modality.
 *
 * `:focus-visible` always matches on a text input, including on a plain mouse
 * click, because the browser assumes a field expecting typed input must show
 * where typing will land. That makes a ring unavoidable on Combobox,
 * MultiSelect, and Autocomplete — all of which are a text input underneath —
 * no matter what a component stylesheet says.
 *
 * `useFocusModality` records the live interaction modality on the document
 * element. While it reads `pointer`, the ring resolves to transparent.
 *
 * Two tokens, not one, and the split is the whole point. `--cr-color-focus-ring`
 * is the ring's *colour* and always holds it; `--cr-color-focus-ring-visible` is
 * what a stylesheet paints an outline or ring shadow with, and is the only one
 * modality blanks. Blanking the colour token itself is what this file did until
 * it turned out that `Field.css` and `MultiSelect.css` also use it for
 * `border-color`, to show a focused field. Those borders went transparent on
 * every form control in the library: clicking into a field made its border
 * disappear. A field showing focus when you click it is not a focus ring and
 * must not be suppressed with one.
 *
 * So: paint rings with `-visible`, read the colour from the base token.
 */

:root,
[data-theme] {
  --cr-color-focus-ring-visible: var(--cr-color-focus-ring);
  --cr-color-focus-gap-visible: var(--cr-color-focus-gap);
}

:root[data-focus-modality="pointer"],
:root[data-focus-modality="pointer"] [data-theme] {
  --cr-color-focus-ring-visible: transparent;
  --cr-color-focus-gap-visible: transparent;
}

/* Consequence worth knowing: while the modality is pointer these render tokens
 * resolve to `transparent`, so anything that *reads* them rather than painting
 * with them sees a blanked ring. A rendered contrast audit must put the page in
 * keyboard modality before measuring — dispatch a Tab keydown — or it measures
 * the deliberately invisible ring and reports 1.11:1 for #000000. The
 * FocusState story in src/stories/ContrastAudit.stories.tsx does exactly that,
 * and is the worked example if another consumer needs the same. */

/* Forced-colors users have asked the OS for the strongest possible indicators.
 * Suppressing a ring there trades a small aesthetic win for a real loss, so the
 * modality rule is withdrawn and the system colour applies as normal. */
@media (forced-colors: active) {
  :root[data-focus-modality="pointer"],
  :root[data-focus-modality="pointer"] [data-theme] {
    --cr-color-focus-ring-visible: CanvasText;
    --cr-color-focus-gap-visible: Canvas;
  }
}
