/* Faqir UI Bundle — generated 2026-10-20T07:44:08.855Z */
/* 99 files */

/* === tokens/index.css === */
/* Faqir Design Tokens — assembled for tokens_split: false (Faqir 1.3.0) */

/* ── palette.css ── */
/* @ui:tokens palette — raw oklch color values, never referenced by components directly */

:root {
  /* ── Indigo ── */
  --palette-indigo-50:  oklch(0.96 0.04 264);
  --palette-indigo-100: oklch(0.92 0.08 264);
  --palette-indigo-200: oklch(0.85 0.12 264);
  --palette-indigo-300: oklch(0.75 0.16 264);
  --palette-indigo-400: oklch(0.68 0.20 264);   /* AA: --color-primary on --color-bg-muted was 4.44:1 in dark [W3-3] */
  --palette-indigo-500: oklch(0.51 0.22 264);   /* AA: --color-primary on --color-bg-muted was 4.40:1 in light [W3-3] */
  --palette-indigo-600: oklch(0.47 0.22 264);   /* keeps the hover step visible after the 500 nudge */
  --palette-indigo-700: oklch(0.42 0.20 264);
  --palette-indigo-800: oklch(0.35 0.18 264);
  --palette-indigo-900: oklch(0.28 0.14 264);
  --palette-indigo-950: oklch(0.20 0.10 264);

  /* ── Red ── */
  --palette-red-50:  oklch(0.96 0.04 25);
  --palette-red-100: oklch(0.92 0.08 25);
  --palette-red-200: oklch(0.85 0.12 25);
  --palette-red-300: oklch(0.75 0.16 25);
  --palette-red-400: oklch(0.65 0.20 25);
  --palette-red-500: oklch(0.55 0.22 25);
  --palette-red-600: oklch(0.50 0.22 25);
  --palette-red-700: oklch(0.42 0.20 25);
  --palette-red-800: oklch(0.35 0.18 25);
  --palette-red-900: oklch(0.28 0.14 25);
  --palette-red-950: oklch(0.20 0.10 25);

  /* ── Green ── */
  --palette-green-50:  oklch(0.96 0.04 155);
  --palette-green-100: oklch(0.92 0.08 155);
  --palette-green-200: oklch(0.85 0.12 155);
  --palette-green-300: oklch(0.75 0.16 155);
  --palette-green-400: oklch(0.65 0.18 155);
  --palette-green-500: oklch(0.60 0.18 155);
  --palette-green-600: oklch(0.55 0.18 155);
  --palette-green-700: oklch(0.45 0.16 155);
  --palette-green-800: oklch(0.38 0.14 155);
  --palette-green-900: oklch(0.30 0.10 155);
  --palette-green-950: oklch(0.22 0.08 155);

  /* ── Amber ── */
  --palette-amber-50:  oklch(0.96 0.04 85);
  --palette-amber-100: oklch(0.92 0.08 85);
  --palette-amber-200: oklch(0.88 0.12 85);
  --palette-amber-300: oklch(0.82 0.14 80);
  --palette-amber-400: oklch(0.78 0.15 78);
  --palette-amber-500: oklch(0.75 0.15 75);
  --palette-amber-600: oklch(0.66 0.14 55);
  --palette-amber-700: oklch(0.55 0.12 50);
  --palette-amber-800: oklch(0.45 0.10 50);
  --palette-amber-900: oklch(0.38 0.08 50);
  --palette-amber-950: oklch(0.28 0.06 50);

  /* ── Gray (cool) ── */
  --palette-gray-25:  oklch(0.995 0.001 260);
  --palette-gray-50:  oklch(0.98 0.003 260);
  --palette-gray-100: oklch(0.96 0.004 260);
  --palette-gray-200: oklch(0.92 0.006 260);
  --palette-gray-300: oklch(0.87 0.008 260);
  --palette-gray-400: oklch(0.70 0.01 260);
  --palette-gray-500: oklch(0.55 0.01 260);
  --palette-gray-600: oklch(0.44 0.01 260);
  --palette-gray-700: oklch(0.37 0.01 260);
  --palette-gray-800: oklch(0.27 0.01 260);
  --palette-gray-900: oklch(0.20 0.01 260);
  --palette-gray-950: oklch(0.14 0.01 260);

  /* ── Blue ── */
  --palette-blue-50:  oklch(0.96 0.04 240);
  --palette-blue-100: oklch(0.92 0.08 240);
  --palette-blue-200: oklch(0.85 0.12 240);
  --palette-blue-300: oklch(0.75 0.14 240);
  --palette-blue-400: oklch(0.65 0.18 240);
  --palette-blue-500: oklch(0.50 0.20 240);
  --palette-blue-600: oklch(0.45 0.20 240);
  --palette-blue-700: oklch(0.42 0.18 240);
  --palette-blue-800: oklch(0.35 0.16 240);
  --palette-blue-900: oklch(0.28 0.12 240);
  --palette-blue-950: oklch(0.20 0.08 240);
}

/* ── spacing.css ── */
/* @ui:tokens spacing — 4px base, harmonic scale */

:root {
  --space-0:   0;
  --space-px:  1px;
  --space-0h:  0.125rem;   /* 2px */
  --space-1:   0.25rem;    /* 4px */
  --space-1h:  0.375rem;   /* 6px */
  --space-2:   0.5rem;     /* 8px */
  --space-2h:  0.625rem;   /* 10px */
  --space-3:   0.75rem;    /* 12px */
  --space-3h:  0.875rem;   /* 14px */
  --space-4:   1rem;       /* 16px */
  --space-5:   1.25rem;    /* 20px */
  --space-6:   1.5rem;     /* 24px */
  --space-7:   1.75rem;    /* 28px */
  --space-8:   2rem;       /* 32px */
  --space-10:  2.5rem;     /* 40px */
  --space-12:  3rem;       /* 48px */
  --space-16:  4rem;       /* 64px */
  --space-20:  5rem;       /* 80px */
  --space-24:  6rem;       /* 96px */

  /* ── Page rhythm (task 0.8-07) ──
     Above --space-24 the scale stops being component padding and becomes
     page-section rhythm: the vertical air between the hero and the feature
     grid, the gap a landing page breathes at. Same 4px base, same harmonic
     doubling, so a section gap is a scale member and not a magic number.
     Composed through the --section-gap-* aliases in tokens/aliases.css. */
  --space-32:  8rem;       /* 128px */
  --space-40:  10rem;      /* 160px */
  --space-48:  12rem;      /* 192px */
  --space-64:  16rem;      /* 256px */
}

/* ── typography.css ── */
/* @ui:tokens typography — font families, sizes, line-heights, weights */

:root {
  /* ── Font Families ── */
  --font-sans:   system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-mono:   ui-monospace, 'Cascadia Code', 'JetBrains Mono', monospace;
  --font-serif:  'Georgia', 'Times New Roman', serif;

  /* ── Font Roles (task 1.1A-01) ──
     The three families above are the PALETTE; these three are the ROLES that
     components actually read. A theme re-points a role once and every heading,
     every paragraph and every control follows — "serif headings on a sans body"
     is one declaration rather than sixty-four stylesheet edits. Components never
     read --font-sans / --font-serif directly (gated by
     tests/tokens/role-tokens.test.ts); --font-mono stays readable by name,
     because "this is code" is a semantic choice, not a stylistic one. */
  --font-heading: var(--font-sans);   /* h1–h6, hero headline, card/dialog titles, stat values, doc headings */
  --font-body:    var(--font-sans);   /* prose, text, document body, descriptions */
  --font-ui:      var(--font-sans);   /* controls: button, input, select, badge, chip, tabs, menus */

  /* ── Code Face (task 1.1F-19) ──
     Cascadia Code and JetBrains Mono both ligate by default, so `!=`, `=>` and
     `->` in an id, a keyboard hint or a code sample were drawn as single glyphs
     on any machine that has either face installed. Every rule that sets
     `font-family: var(--font-mono)` reads this beside it as
     `font-variant-ligatures` (gated by tests/tokens/role-tokens.test.ts).
     `none` also turns contextual alternates off, which is how JetBrains Mono
     ligates. Set it to `normal` to get a face's ligatures back. A theme that
     points a ROLE at --font-mono (terminal does, for all three) is not covered:
     its body text is set by the role, and keeps the face's defaults. Not named
     --font-mono-ligatures, because a --font-* token is a family. */
  --mono-ligatures: none;

  /* ── Font Sizes ── */
  --text-xs:     0.75rem;    /* 12px */
  --text-sm:     0.875rem;   /* 14px */
  --text-base:   1rem;       /* 16px */
  --text-lg:     1.125rem;   /* 18px */
  --text-xl:     1.25rem;    /* 20px */
  --text-2xl:    1.5rem;     /* 24px */
  --text-3xl:    1.875rem;   /* 30px */
  --text-4xl:    2.25rem;    /* 36px */

  /* ── Line Heights ── */
  --leading-tight:   1.25;
  --leading-snug:    1.375;
  --leading-normal:  1.5;
  --leading-relaxed: 1.625;
  --leading-loose:   1.75;

  /* ── Font Weights ── */
  --weight-normal:   400;
  --weight-medium:   500;
  --weight-semibold: 600;
  --weight-bold:     700;

  /* ── Heading Voice (task 1.1A-01) ──
     What makes a heading sound like the theme rather than like the body text one
     size up: how heavy it is, how tightly the letters sit, whether it shouts, and
     how close its own lines run. The defaults reproduce today's primary heading
     exactly, so a project that sets none of them renders unchanged. A heading
     that deliberately steps DOWN from the primary voice (prose h2–h4, a semibold
     step below h1) keeps its own weight and leading and takes family, tracking
     and case from the voice — the step is the design, not a value to re-derive. */
  --heading-weight:    var(--weight-bold);
  --heading-tracking:  0em;           /* letter-spacing — carries a unit so it
                                         composes inside calc() where a heading
                                         already has its own optical tightening */
  --heading-transform: none;          /* text-transform */
  --heading-caps:      normal;        /* font-variant-caps — small caps are a
                                         variant, not a transform (1.1A-25), so
                                         they get a knob of their own that sits
                                         beside --heading-transform */
  --heading-leading:   var(--leading-tight);
}

/* ── effects.css ── */
/* @ui:tokens effects — radii, shape, shadows, focus, z-index */

:root {
  /* ── Radii ── */
  --radius-none: 0;
  --radius-sm:   0.25rem;    /* 4px */
  --radius-md:   0.375rem;   /* 6px */
  --radius-lg:   0.5rem;     /* 8px */
  --radius-xl:   0.75rem;    /* 12px */
  --radius-2xl:  1rem;       /* 16px */
  --radius-full: 9999px;

  /* ── Shape ── */
  /* The weight of an edge. A component names the ROLE (--border-width, or
     --border-width-strong where the design leans on a thicker rule), never a
     step, so a theme re-points every edge it ships with one declaration. */
  --border-width-sm: 1px;
  --border-width-md: 2px;
  --border-width-lg: 3px;
  --border-width:        var(--border-width-sm);   /* the default component border */
  --border-width-strong: var(--border-width-md);   /* emphasis: keycap, thick rule, active tab */
  /* Progressive: CSS Borders 4. A browser without the property ignores it; a
     value it does not know resolves to `round`, which is today's rendering. */
  --corner-shape: round;                           /* bevel | scoop | notch where supported */

  /* ── Depth ── */
  /* The colour every shadow is cast in, as BARE OKLCH channels (L C H, no
     `oklch()` around them) so each step can still set its own alpha:
     `oklch(var(--shadow-color) / 0.06)`. A theme tints its depth warm, or
     removes it entirely, with one declaration instead of rewriting five
     multi-layer values. `0 0 0` is black — today's rendering, exactly. */
  --shadow-color: 0 0 0;

  --shadow-xs:  0 1px 2px oklch(var(--shadow-color) / 0.04);
  --shadow-sm:  0 1px 3px oklch(var(--shadow-color) / 0.06), 0 1px 2px oklch(var(--shadow-color) / 0.04);
  --shadow-md:  0 4px 6px oklch(var(--shadow-color) / 0.05), 0 2px 4px oklch(var(--shadow-color) / 0.04);
  --shadow-lg:  0 10px 15px oklch(var(--shadow-color) / 0.06), 0 4px 6px oklch(var(--shadow-color) / 0.04);
  --shadow-xl:  0 20px 25px oklch(var(--shadow-color) / 0.08), 0 8px 10px oklch(var(--shadow-color) / 0.04);

  /* What an elevated surface does to whatever shows through it. Every surface
     that can float — card, surface[data-variant="overlay"] and the seven
     floating recipes — declares `backdrop-filter: var(--surface-backdrop)`
     inside the same `@supports` guard, so a frosted theme is a token rather
     than a stylesheet that reaches into seven components by selector.
     `none` is the initial value of the property: no-op until a theme speaks. */
  --surface-backdrop: none;

  /* ── Focus ── */
  /* base/reset.css owns the default ring and reads only these. Every control
     that draws its own ring reads them too, so a theme changes focus once. */
  --focus-ring-width:  2px;
  --focus-ring-offset: 2px;
  --focus-ring-style:  solid;
  --focus-ring-color:  var(--color-ring);
  --focus-shadow:      none;                       /* a glow theme puts a shadow behind the ring */

  /* ── Z-Index ── */
  --z-base:     0;
  --z-raised:   1;
  --z-dropdown: 50;
  --z-sticky:   100;
  --z-overlay:  200;
  --z-modal:    300;
  --z-toast:    400;
  --z-max:      9999;
}

/* ── Scheme islands ── */
/* The ring colour, restated where a scheme can change below the root: declared
   on `:root` alone it resolves `--color-ring` once, from the page, and a nested
   `data-theme="dark"` region would draw the light ring. See the same block in
   tokens/aliases.css. `--focus-shadow` is deliberately NOT restated — it is a
   depth value a theme owns, and restating it would replace the theme's glow
   with `none` inside every island. */
[data-theme],
[data-skin] {
  --focus-ring-color:  var(--color-ring);
}

/* ── textures.css ── */
/* @ui:tokens textures — named surface materials (SVG data URIs) */

/* ══════════════════════════════════════════════════════════════════════════
   The material palette.
   ══════════════════════════════════════════════════════════════════════════
   Six named textures, each a self-contained `url("data:image/svg+xml,…")` that
   tiles. Nothing here is consumed directly: components read the two ROLE tokens
   in `aliases.css` — `--texture-page` (body, document) and `--texture-surface`
   (surface, card, hero) — both `none` by default, so the registry renders
   exactly as it did before this file existed. A theme opts in with one
   declaration:

     --texture-page: var(--texture-grain);

   This file is deliberately OUTSIDE the themeable surface (see
   `NON_SURFACE_TOKEN_FILES` in `src/theme-manifest.ts`): a theme re-points the
   two role tokens, it does not inherit six data URIs into its manifest.

   On `currentColor`: the tint is written as `currentColor` so the markup states
   its intent and a theme can re-point the whole token, but a data-URI SVG used
   as `background-image` is its own document — `currentColor` there resolves to
   that document's initial colour (black), not to the host element's `color`.
   That IS the intended neutral for grain and paper, which are meant to darken a
   surface slightly; the alpha in each texture, not the hue, is what carries the
   effect. A theme wanting a different tint ships its own URI.

   Every texture keeps its alpha low enough to survive on both schemes, and each
   `<svg>` carries explicit `width`/`height` so the tile size is the token's,
   not the browser's default 300×150.
   ══════════════════════════════════════════════════════════════════════════ */

:root {
  /* Film grain — fractal noise masking a flat currentColor fill. The mask is
     what makes this a tint rather than the turbulence's own rainbow. */
  --texture-grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Cmask id='m'%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/mask%3E%3Crect width='160' height='160' fill='currentColor' mask='url(%23m)' opacity='0.14'/%3E%3C/svg%3E");

  /* Paper fibre — lower frequency, more octaves, softer than grain. */
  --texture-paper: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='p'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.04 0.85' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Cmask id='m'%3E%3Crect width='200' height='200' filter='url(%23p)'/%3E%3C/mask%3E%3Crect width='200' height='200' fill='currentColor' mask='url(%23m)' opacity='0.1'/%3E%3C/svg%3E");

  /* Dot field — one dot per 16px cell. */
  --texture-dots: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16'%3E%3Ccircle cx='2' cy='2' r='1' fill='currentColor' opacity='0.18'/%3E%3C/svg%3E");

  /* Graph-paper grid — hairlines on a 24px cell. */
  --texture-grid: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24'%3E%3Cpath d='M24 0H0v24' fill='none' stroke='currentColor' stroke-width='1' opacity='0.12'/%3E%3C/svg%3E");

  /* Diagonal hatching — 45°, 8px pitch. */
  --texture-stripes: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='8'%3E%3Cpath d='M-2 2 2-2M0 8 8 0M6 10l4-4' stroke='currentColor' stroke-width='1' opacity='0.12'/%3E%3C/svg%3E");

  /* Soft gradient mesh — three offset radial blooms, the only non-tiling
     texture here (it is sized to cover, not to repeat). */
  --texture-mesh: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='640' height='640'%3E%3CradialGradient id='a' cx='20%25' cy='20%25' r='60%25'%3E%3Cstop offset='0%25' stop-color='currentColor' stop-opacity='0.18'/%3E%3Cstop offset='100%25' stop-color='currentColor' stop-opacity='0'/%3E%3C/radialGradient%3E%3CradialGradient id='b' cx='80%25' cy='30%25' r='55%25'%3E%3Cstop offset='0%25' stop-color='currentColor' stop-opacity='0.14'/%3E%3Cstop offset='100%25' stop-color='currentColor' stop-opacity='0'/%3E%3C/radialGradient%3E%3CradialGradient id='c' cx='50%25' cy='90%25' r='60%25'%3E%3Cstop offset='0%25' stop-color='currentColor' stop-opacity='0.12'/%3E%3Cstop offset='100%25' stop-color='currentColor' stop-opacity='0'/%3E%3C/radialGradient%3E%3Crect width='640' height='640' fill='url(%23a)'/%3E%3Crect width='640' height='640' fill='url(%23b)'/%3E%3Crect width='640' height='640' fill='url(%23c)'/%3E%3C/svg%3E");
}

/* ── motion.css ── */
/* @ui:tokens motion — easings, durations and motion personality */

:root {
  /* ── Easings ── */
  --ease-default:  cubic-bezier(0.4, 0, 0.2, 1);
  --ease-in:       cubic-bezier(0.4, 0, 1, 1);
  --ease-out:      cubic-bezier(0, 0, 0.2, 1);
  --ease-in-out:   cubic-bezier(0.4, 0, 0.2, 1);
  --ease-bounce:   cubic-bezier(0.34, 1.56, 0.64, 1);

  /* ── Durations ── */
  --duration-instant: 50ms;
  --duration-fast:    100ms;
  --duration-normal:  200ms;
  --duration-slow:    300ms;
  --duration-slower:  500ms;

  /* ── l-transition presets (Transitions 2.0 · 0.4-11) ── */
  /* Semantic aliases consumed by base/motion-presets.css so preset CSS never
     hardcodes a duration or easing. Enter is slower/eased-out (arriving),
     leave is faster/eased-in (departing). */
  --motion-enter-duration: var(--duration-normal);
  --motion-leave-duration: var(--duration-fast);
  --motion-enter-ease:     var(--ease-out);
  --motion-leave-ease:     var(--ease-in);

  /* Preset geometry */
  --motion-slide-distance: 0.5rem;  /* slide-up travel */
  --motion-scale-from:     0.95;    /* scale start/end factor */

  /* ── Personality (1.1A-05 · §5.2 `motion`) ── */
  /* The easing PALETTE gained a spring. Like --ease-bounce it has no consumer
     of its own: a theme that wants everything to overshoot re-points
     --ease-default at it, exactly as a serif theme re-points --font-body.
     The declaration here is the cubic-bezier APPROXIMATION, because a custom
     property stores whatever tokens it is given — a browser without `linear()`
     would accept the spring happily and then drop every `transition` that used
     it, landing on the initial easing rather than on a fallback. The @supports
     block below is what makes the upgrade conditional. The approximation is
     the bounce curve, deliberately: an overshoot-and-settle cubic-bezier is the
     closest a browser without `linear()` can come to a spring. */
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);

  /* How far an interactive surface rises under the pointer. A `translate`
     VALUE, not a length: `none` is the initial value of that property, so the
     default registry computes exactly what it computed before this token
     existed, and a theme states the lift as `0 -1px`. `translate` rather than
     `transform` so a component's own transform is never clobbered. */
  --motion-hover-lift: none;

  /* ── Choreography (reveal, marquee, backdrop, glow, highlight) ── */
  /* Two more easings for the palette. `--ease-linear` is constant speed, by
     name: a loop that eases stutters once per lap, and a scroll-scrubbed
     timeline must not ease at all (the scrollbar is the easing). It is a token
     rather than the keyword so that "no component spells an easing of its own"
     stays a rule without exceptions for every new loop. `--ease-emphasized` is
     the long decelerating arrival — fast out of the gate, a slow settle — that
     makes an entrance read as placed rather than slid. */
  --ease-linear:      linear;
  --ease-emphasized:  cubic-bezier(0.2, 0, 0, 1);

  /* One step past `slower`, for entrances that cross real distance. */
  --duration-slowest: 700ms;

  /* How content arrives. Every entrance in the registry — the `reveal`
     primitive, the `l-transition` presets that travel — reads these, so a theme
     states its entrance once: a brisk theme shortens the distance and the
     duration, a theatrical one lengthens both and raises the stagger. */
  --motion-reveal-duration: var(--duration-slowest);
  --motion-reveal-ease:     var(--ease-emphasized);
  --motion-reveal-distance: 1.5rem;   /* travel of rise / fall / slide */
  --motion-reveal-scale:    0.94;     /* start factor of zoom */
  --motion-reveal-blur:     0.5rem;   /* start radius of blur */
  --motion-stagger:         70ms;     /* delay between siblings in a staggered group */

  /* Things that move without being asked: a marquee's lap, a backdrop's drift,
     a glow's orbit, a gradient's pan. One duration to slow or hurry them all
     (each component scales it for its own loop), and one play state to freeze
     them: `--motion-ambient-play: paused` on `:root` — or on any subtree — stops
     every ambient loop there without touching a transition. */
  --motion-ambient-duration: 24s;
  --motion-ambient-play:     running;
}

/* The real spring, where `linear()` is understood (Chrome 113+, Safari 17.2+,
   Firefox 112+). Declared second so it wins; guarded so it is never declared at
   all where it would be meaningless. */
@supports (animation-timing-function: linear(0, 1)) {
  :root {
    --ease-spring: linear(0, 0.3 6%, 0.7 13%, 0.95 20%, 1.03 27%, 1 40%, 1);
  }
}

/* ── semantic.css ── */
/* @ui:tokens semantic — purpose-based tokens, referenced by components */

:root {
  /* ── Surfaces ── */
  --color-bg:              var(--palette-gray-25);
  --color-bg-subtle:       var(--palette-gray-100);
  --color-bg-muted:        var(--palette-gray-200);
  /* Canonical elevation ramp. Adjacent fills and each fill/border pair are
     held to OKLab ΔE >= 0.03 by the generated theme gate. */
  --color-surface-1:        var(--color-bg-subtle);
  --color-surface-2:        var(--color-bg-muted);
  --color-surface-1-border: var(--color-border);
  --color-surface-2-border: var(--color-border-strong);
  --color-fg:              var(--palette-gray-950);
  --color-fg-muted:        var(--palette-gray-500);
  --color-fg-subtle:       var(--palette-gray-400);

  /* ── Interactive: Primary ── */
  --color-primary:         var(--palette-indigo-500);
  --color-primary-hover:   var(--palette-indigo-600);
  --color-primary-active:  var(--palette-indigo-700);
  --color-primary-fg:      white;
  --color-primary-subtle:  var(--palette-indigo-50);

  /* ── Interactive: Secondary ── */
  --color-secondary:       var(--palette-gray-100);
  --color-secondary-hover: var(--palette-gray-200);
  --color-secondary-fg:    var(--palette-gray-900);

  /* ── Interactive: Destructive ── */
  --color-destructive:        var(--palette-red-500);
  --color-destructive-hover:  var(--palette-red-600);
  --color-destructive-fg:     white;
  --color-destructive-subtle: var(--palette-red-50);

  /* ── Feedback ── */
  --color-success:         var(--palette-green-500);
  --color-success-subtle:  var(--palette-green-50);
  --color-warning:         var(--palette-amber-500);
  --color-warning-subtle:  var(--palette-amber-50);
  --color-info:            var(--palette-blue-500);
  --color-info-subtle:     var(--palette-blue-50);

  /* ── Borders ── */
  --color-border:          var(--palette-gray-200);
  --color-border-strong:   var(--palette-gray-300);
  --color-ring:            oklch(0.55 0.22 264);
}

/* ── aliases.css ── */
/* @ui:tokens aliases — per-component overrides mapping to semantic tokens */

:root {
  /* ── Controls ── */
  /* The shared interactive-control height ramp. Every control that must line up
     in a row (button, input, select, …) sizes from these, so density mode has a
     single ramp to remap — see tokens/density.css. */
  --control-height-sm: 32px;
  --control-height-md: 40px;
  --control-height-lg: 48px;

  /* ── Measure ── */
  /* The one ladder of reading-column widths (task 0.8-06). Every centred column
     in the framework resolves to one of these: the `container` primitive's
     data-measure, surface's data-max, and the form-page / wizard columns that
     used to hardcode 32rem apiece. Deliberately NOT named sm|md|lg|xl — those
     names belong to the breakpoint canon (src/utils/breakpoints.ts), and a
     ladder that reuses them invites `data-max="lg"` to be read as "at the lg
     tier" when it means "1152px wide". Measure names describe the CONTENT the
     column is cut for, not the viewport it sits in. */
  --measure-narrow:  32rem;  /* a single form column, a login card */
  --measure-content: 48rem;  /* an article body, a settings panel */
  --measure-wide:    72rem;  /* a page shell — the widest thing still centred */
  --measure-prose:   65ch;   /* optimal line length, sized in characters, so it
                                tracks the reader's font rather than the layout */

  /* ── Rhythm (task 0.8-07) ── */
  /* The vertical air between page sections and the horizontal inset of the page
     itself. Both are composed from the spacing scale rather than declared as new
     numbers, so density remaps them for free (a var() in an alias re-substitutes
     in whatever scope re-declares --space-*; see tokens/density.css). Named by
     ROLE, not by size — a page picks `--section-gap-lg` because the sections
     should feel far apart, not because it wants 8rem. */
  --section-gap-sm:  var(--space-12);  /* 3rem  — dense pages, docs, dashboards */
  --section-gap-md:  var(--space-20);  /* 5rem  — the default marketing rhythm */
  --section-gap-lg:  var(--space-32);  /* 8rem  — spacious, one idea per screen */
  --content-gutter:  var(--space-6);   /* 1.5rem — page padding-inline */

  /* ── Material ── */
  /* The two textures a theme actually points at. Components never name a
     texture from `tokens/textures.css` directly — they read one of these, so a
     theme re-points two tokens rather than every surface in the registry.
     `--texture-page` dresses the page itself (body, document);
     `--texture-surface` dresses the things that sit ON it (surface, card,
     hero). Both `none`: the initial value of `background-image`, so the
     default registry renders exactly as it did before they existed. */
  --texture-page:    none;
  --texture-surface: none;

  /* ── Decoration (1.1A-05 · §5.2 `decoration`) ── */
  /* The marks a theme draws that are not edges, fills or type: how a link is
     underlined, how a divider is dashed, what selected text looks like, what
     colour a list bullet is. Every default is the value the registry already
     rendered, so this section is a set of handles, not a restyle.
     `--marker-color` is `currentColor` — the initial value of `::marker`'s
     colour — rather than the accent, so a list only changes when a theme says
     it should. */
  --link-decoration:       underline;
  --link-underline-offset: 0.2em;
  --link-thickness:        1px;
  --divider-style:         solid;
  /* The divider's own width, following the edge by default (1.1A-26). A theme
     that asks for a `double` divider raises it to at least 3px: a double rule
     only splits into two lines from 3px, and the family's 1px hairline would
     paint it as one. */
  --divider-width:         var(--border-width);
  /* The zebra, so a theme dials the stripe without restating the four selectors
     the table's striped variant needs (stamped and nth-child, each with a hover
     twin). Deliberately NOT `--table-stripe`: `--table-level`,
     `--table-thead-h` and `--table-pin-offset` are stamped and MEASURED per
     element by the table controller, so claiming the `--table-*` namespace for
     a theme token would put runtime state on the themeable surface. */
  --stripe-bg:             var(--color-bg-subtle);
  --selection-bg:          var(--color-primary-subtle);
  --selection-fg:          var(--color-fg);
  --marker-color:          currentColor;
  /* How far a disabled control is dimmed. Seventeen rules across the primitives
     and recipes each spelled `opacity: 0.5`, which left a theme with an opinion
     about disabled legibility no way to state it except by out-specifying every
     one of them — which is exactly what `themes/contrast.css` did, with a
     blanket `:root [data-ui]:disabled` rule, until 1.1A-15 turned it into this
     one declaration. `0.5` is the value those seventeen rules already held. */
  --disabled-opacity:      0.5;

  /* ── Button ── */
  --button-radius:     var(--radius-md);
  --button-height-sm:  var(--control-height-sm);
  --button-height-md:  var(--control-height-md);
  --button-height-lg:  var(--control-height-lg);
  --button-font:       var(--font-ui);
  --button-weight:     var(--weight-medium);
  --button-text-transform: none;

  /* ── Card ── */
  --card-radius:       var(--radius-lg);
  --card-shadow:       var(--shadow-sm);
  --card-border:       var(--color-surface-1-border);
  --card-border-width: var(--border-width);
  --card-bg:           var(--color-surface-1);
  --card-padding:      var(--space-6);
  /* The two reaches a card makes beyond its resting state. `--card-hover-shadow`
     is the step it climbs to under the pointer when its data-hover says
     `raise`; `--card-media-ratio` cuts the picture across its top. Neither is
     read until the markup asks, so a card without them renders as it always
     has. */
  --card-hover-shadow: var(--shadow-lg);
  --card-media-ratio:  16 / 9;

  /* ── Input ── */
  /* The text-control silhouette. `--input-border-width` (1.1A-02) is the edge;
     `--input-fill` is what the control paints, and `input`, `textarea` and
     `select` all read it, so one declaration fills every text control.
     `--input-fill` defaults to `--input-bg`, so a project that sets `--input-bg`
     on `:root` — the 1.0 way to fill every input — still gets it. Set BELOW the
     root, `--input-bg` no longer reaches the control: `--input-fill` has already
     resolved it on `:root`, which is where a theme flips the fill, and a
     per-element `--input-bg` winning over that would need the component to tell
     "set here" from "inherited", which CSS cannot. To fill one input, or every
     input in a region, set `--input-fill` there instead. `--input-bg-filled` is
     the value a "filled" theme points `--input-fill` at — named here so the
     silhouette is a token a theme flips rather than a colour it has to pick. */
  --input-radius:       var(--radius-md);
  --input-height:       var(--control-height-md);
  --input-border:       var(--color-border);
  --input-border-width: var(--border-width);
  --input-bg:           var(--color-bg);
  --input-bg-filled:    var(--color-bg-subtle);
  --input-fill:         var(--input-bg);
  --input-font:         var(--font-ui);

  /* ── Checkbox / Switch ── */
  /* The two control shapes that do not follow `--radius-md`: a checkbox is a
     small square with a small radius, a switch is a pill. Both were literal
     `var(--radius-*)` reads in the components; named here, a theme squares its
     switches without touching the radius ladder every other surface uses.

     The geometry beside them is not decoration — it is the rest of the
     namespace. Naming ONE token `--checkbox-radius` makes `--checkbox-*` a
     token family, and the registry audit then (rightly) reads every other
     `--checkbox-…`/`--switch-…` the components carried as a token wearing a
     fallback as a disguise. They were always the default geometry; these are
     the values the fallbacks already held, said once. */
  --checkbox-size:      18px;
  --checkbox-radius:    var(--radius-sm);
  --switch-width:       44px;
  --switch-height:      24px;
  --switch-thumb:       18px;
  --switch-travel:      20px;
  --switch-radius:      var(--radius-full);
  --switch-bg:          var(--color-bg-muted);
  --switch-thumb-shadow: var(--shadow-xs);

  /* ── Floating panels ── */
  /* What a panel that floats above the page is filled with: the dialog and
     sheet panels, the drawer, the popover content (and its arrow), the dropdown
     menu and the toast. They all painted `var(--color-bg)` directly, which left
     a theme no way to make a floating surface differ from the page — the frost
     half of that pairing is `--surface-backdrop` (1.1A-04), and a blur behind an
     opaque fill renders nothing, so the fill has to be a token too. `card` has
     had `--card-bg` since 1.0; this is the same handle for the things that have
     no surface of their own. [1.1A-14] */
  --panel-bg:          var(--color-bg);

  /* ── Dialog ── */
  --dialog-radius:     var(--radius-xl);
  --dialog-shadow:     var(--shadow-xl);
  --dialog-overlay-bg: oklch(0 0 0 / 0.5);

  /* ── Badge ── */
  --badge-radius:      var(--radius-full);
  --badge-font:        var(--font-ui);

  /* ── Avatar ── */
  --avatar-radius:     var(--radius-full);
  --avatar-size-sm:    32px;
  --avatar-size-md:    40px;
  --avatar-size-lg:    56px;
}

/* ── Scheme islands ── */
/* The colour aliases above, restated wherever a scheme can change below the
   root. A custom property resolves its var() on the element that DECLARES it,
   so `--panel-bg: var(--color-bg)` on `:root` is computed once, from the page's
   colours, and a nested `<div data-theme="dark">` inherits that light value
   even though its own `--color-bg` is dark — a white dialog on a dark island.
   Components that read `var(--color-bg)` directly never had the problem; the
   aliases 1.1 routed them through did. Restating the declaration on
   `[data-theme]` and `[data-skin]` makes it resolve again there.

   Only colours are restated. Geometry does not change with the scheme, and
   shadows are the depth axis every theme owns on `:root`: restating either here
   would replace a theme's own value with the default inside every island. A
   theme that overrides one of THESE on `:root` and wants it honoured in an
   island says so on the same selectors.

   The values must match the `:root` declarations above exactly;
   `tests/tokens/scheme-islands.test.ts` fails if they drift. */
[data-theme],
[data-skin] {
  --stripe-bg:         var(--color-bg-subtle);
  --selection-bg:      var(--color-primary-subtle);
  --selection-fg:      var(--color-fg);
  --card-border:       var(--color-surface-1-border);
  --card-bg:           var(--color-surface-1);
  --input-border:      var(--color-border);
  --input-bg:          var(--color-bg);
  --input-bg-filled:   var(--color-bg-subtle);
  --input-fill:        var(--input-bg);
  --switch-bg:         var(--color-bg-muted);
  --panel-bg:          var(--color-bg);
}

/* ── document.css ── */
/* @ui:tokens document — structural tokens for document/print rendering */
/* These tokens control page geometry, document typography, table density,
   and print-specific behavior. They are consumed by document-oriented
   primitives (page-break, key-value, signature, callout, field-group)
   and the document pattern. Themes override these for visual customization. */

:root {
  /* ── Page Geometry ──
     Used by the `document` pattern and @page CSS rules.
     --page-format and --page-orientation are consumed as literal values
     in @page faqir-document { size: var(--page-format) var(--page-orientation) },
     the named page every document prints on unless it pins its paper with
     data-format + data-orientation. Page boxes inherit from the root only, so
     these are read at :root: they set the paper of every unpinned document.
     Margins are used in every faqir-document* page and the pattern's padding. */
  --page-format:            A4;
  --page-orientation:       portrait;
  --page-margin:            15mm;
  --page-margin-top:        var(--page-margin);
  --page-margin-bottom:     var(--page-margin);
  --page-margin-left:       var(--page-margin);
  --page-margin-right:      var(--page-margin);

  /* Running header/footer geometry. The heights fit inside the default page
     margins and are shared by running-element engines and the fixed fallback. */
  --doc-running-header-height: 10mm;
  --doc-running-footer-height: 8mm;
  --doc-running-gap:        var(--space-2);

  /* Running strings for the page-margin boxes. A page box is not an element:
     it inherits from the root alone, so these are read where the root declares
     them — set them on `:root` (or `<html style>`) for the file being printed.
     `none` draws nothing. `\A` breaks a line. */
  --doc-running-header:     none;
  --doc-running-footer:     none;

  /* The page counter, `Page 3 / 7`, as label + counter + separator + total +
     suffix — in English unless a document's `lang` is one of the languages
     restated at the foot of this file; restate them on `:root` for any
     other. */
  --doc-page-label:         "Page ";
  --doc-page-separator:     " / ";
  --doc-page-suffix:        "";

  /* ── Business letter (DIN 5008) ──
     Read by the document pattern's `letter` variant, which prints on A4
     portrait. Form B is the default; `data-form="a"` restates the three that
     differ (window 27mm, folds 87mm / 192mm). The marks are drawn in the
     left page margin, measured from the top edge of the sheet; the punch mark
     sits midway between the top and bottom page margins, which is 148.5mm
     because the letter page keeps both at --page-margin-top. */
  --doc-letter-margin-left:  25mm;
  --doc-letter-margin-right: 20mm;
  --doc-fold-mark-1:        105mm;
  --doc-fold-mark-2:        210mm;
  --doc-mark-inset:         4mm;                       /* from the sheet's left edge */
  --doc-mark-length:        5mm;
  --doc-punch-mark-length:  8mm;
  --doc-mark-width:         0.25mm;
  --doc-mark-color:         var(--doc-print-border-color);
  --doc-window-top:         45mm;                      /* the address field, from the top edge */
  --doc-window-left:        20mm;                      /* …and from the left edge */
  --doc-window-width:       85mm;
  --doc-window-height:      45mm;
  --doc-window-padding:     5mm;                       /* the address text's indent inside it */

  /* ── Document Typography ──
     Separate from the base typography tokens because documents have
     different optimal sizes than screen UIs. 14px body + 12px legal
     is standard for A4 business documents. */
  --doc-font:               var(--font-body);
  --doc-font-size:          var(--text-sm);           /* 14px — optimal for A4 */
  --doc-line-height:        var(--leading-normal);     /* 1.5 */
  --doc-heading-font:       var(--font-heading);
  --doc-heading-weight:     var(--weight-bold);
  /* The face the `report` variant sets in — the project's serif role, so an
     installed serif reaches a report too. */
  --doc-serif:              var(--font-serif);
  --doc-heading-size:       var(--text-xl);            /* 20px for doc titles */
  --doc-subheading-size:    var(--text-lg);            /* 18px for section titles */
  --doc-legal-size:         var(--text-xs);            /* 12px for fine print / legal text */
  --doc-legal-color:        var(--color-fg-muted);

  /* ── Document Spacing ──
     Controls the vertical rhythm of rendered documents.
     Section gap is the space between major document sections (header, body sections, footer).
     Component gap is the space between items within a section.
     Label gap is the tight spacing between a label and its associated value. */
  --doc-section-gap:        var(--space-8);            /* 32px between sections */
  --doc-component-gap:      var(--space-4);            /* 16px between components */
  --doc-label-gap:          var(--space-1);            /* 4px label to value */

  /* ── Document Table Tokens ──
     Specialized table styling for data-dense document tables (invoices, reports).
     These are separate from the table recipe's screen tokens because document
     tables need tighter padding, tabular number alignment, and print-safe colors. */
  --doc-table-header-bg:    var(--color-bg-subtle);
  --doc-table-header-fg:    var(--color-fg);
  --doc-table-header-weight: var(--weight-semibold);
  --doc-table-border:       var(--color-border-strong);
  --doc-table-cell-pad-y:   var(--space-2);            /* 8px vertical */
  --doc-table-cell-pad-x:   var(--space-3);            /* 12px horizontal */
  --doc-table-font-size:    var(--text-xs);             /* 12px — compact for data density */
  --doc-table-num-font:     tabular-nums;               /* aligned decimal columns */
  --doc-table-footer-bg:    var(--color-bg-muted);
  --doc-table-footer-weight: var(--weight-bold);
  --doc-table-stripe-bg:    var(--color-bg-subtle);
  /* The table's voice, which is how one print theme sounds unlike another
     (forecraft #48). Multipliers, so each is applied where the table draws
     and follows whatever edge, size or inset that element already has; the
     defaults draw exactly what a document table drew before. Rule scale
     weighs the row rules (× --border-width), rule-strong scale the rule under
     the head and over the totals (× --border-width-strong), num scale sets
     number, currency and percent cells (× --doc-table-font-size), and flush
     takes a row's first and last cell inset away: 1 sets the rules flush
     with the text column. */
  --doc-rule-scale:         1;
  --doc-rule-strong-scale:  1;
  --doc-table-num-scale:    1;
  --doc-table-flush:        0;

  /* ── Signature Tokens ──
     Physical signature area dimensions for printed documents.
     The gap above the line must be large enough for a handwritten signature (~40px). */
  --doc-signature-width:    60%;
  --doc-signature-gap:      var(--space-10);           /* 40px above the signing line */
  --doc-signature-line-color: var(--color-border-strong);
  --doc-signature-label-size: var(--text-xs);
  --doc-signature-label-color: var(--color-fg-muted);

  /* ── Print Control ──
     Overrides applied inside @media print to ensure clean PDF output.
     --doc-max-width limits the content width on screen to simulate A4 proportions.
     --doc-bg/--doc-fg force B&W for reliable printing regardless of theme. */
  --doc-max-width:          210mm;                     /* A4 width for screen preview */
  /* The one accent a print theme draws in. Every print theme states it and
     points --color-primary at it, so `:root { --doc-accent: #0b5 }` re-inks a
     document without generating a theme. Elsewhere it is simply the primary. */
  --doc-accent:             var(--color-primary);
  --doc-bg:                 white;                     /* always white for print */
  --doc-fg:                 oklch(0.10 0 0);           /* near-black for print */
  --doc-print-border-color: oklch(0.60 0 0);           /* medium gray borders in print */
}

/* ── Scheme islands ── */
/* `--doc-legal-color` is the one document colour screen components read (the
   key-value label and the image caption), so it is restated where a scheme can
   change below the root — see the same block in tokens/aliases.css. The rest
   of this file is print ink, which does not follow the scheme. */
[data-theme],
[data-skin] {
  --doc-legal-color:        var(--color-fg-muted);
}

/* ── Restated from a document's attributes ──
   A page box inherits from the root and nothing else, so what a document
   says about its pages — its language, a letter's DIN form — has to reach
   the root. :has() carries it there; :where() keeps each rule at :root's
   weight, so it outranks the defaults above only by coming after them, and
   a theme or a project's own `:root { … }`, loaded later, still overrides.
   Print-only: nothing on screen reads these. */
@media print {
  /* The page counter in the document's language. */
  :root:where(:has([data-ui="document"]:lang(de))) {
    --doc-page-label:     "Seite ";
    --doc-page-separator: " von ";
  }

  :root:where(:has([data-ui="document"]:lang(es))) {
    --doc-page-label:     "Página ";
    --doc-page-separator: " de ";
  }

  :root:where(:has([data-ui="document"]:lang(fr))) {
    --doc-page-label:     "Page ";
    --doc-page-separator: " sur ";
  }

  :root:where(:has([data-ui="document"]:lang(it))) {
    --doc-page-label:     "Pagina ";
    --doc-page-separator: " di ";
  }

  :root:where(:has([data-ui="document"]:lang(nl))) {
    --doc-page-label:     "Pagina ";
    --doc-page-separator: " van ";
  }

  :root:where(:has([data-ui="document"]:lang(pt))) {
    --doc-page-label:     "Página ";
    --doc-page-separator: " de ";
  }

  :root:where(:has([data-ui="document"]:lang(ro))) {
    --doc-page-label:     "Pagina ";
    --doc-page-separator: " din ";
  }

  /* DIN 5008 Form A: the address window at 27mm, the folds at 87 / 192mm. */
  :root:where(:has([data-ui="document"][data-variant="letter"][data-form="a"])) {
    --doc-window-top:     27mm;
    --doc-fold-mark-1:    87mm;
    --doc-fold-mark-2:    192mm;
  }
}

/* ── doc-aliases.css ── */
/* @ui:tokens doc-aliases — component-level document tokens */
/* Maps document-layer tokens to specific primitive/recipe attribute selectors.
   These aliases are consumed by: key-value, callout, field-group, image,
   page-break, signature, and the document pattern. */

:root {
  /* ── Key-Value ── */
  --kv-label-color:         var(--doc-legal-color);
  --kv-label-weight:        var(--weight-medium);
  --kv-label-size:          var(--doc-legal-size);
  --kv-value-color:         var(--color-fg);
  --kv-value-size:          var(--doc-font-size);
  --kv-value-weight:        var(--weight-normal);
  --kv-gap:                 var(--doc-label-gap);
  --kv-pair-gap:            var(--space-3);            /* between key-value pairs */
  --kv-grid-gap:            var(--space-4);            /* between columns in grid mode */

  /* ── Callout ── */
  --callout-radius:         var(--radius-md);
  --callout-padding-y:      var(--space-3);
  --callout-padding-x:      var(--space-4);
  --callout-border-width:   1px;
  --callout-border-left-width: 3px;                    /* thick left accent border */
  --callout-bg:             var(--color-bg-subtle);
  --callout-fg:             var(--color-fg);
  --callout-font-size:      var(--doc-font-size);
  --callout-icon-size:      var(--text-lg);

  /* ── Image ── */
  --image-radius:           var(--radius-md);
  --image-border:           var(--color-border);
  --image-border-width:     0;                         /* no border by default */
  --image-caption-size:     var(--doc-legal-size);
  --image-caption-color:    var(--doc-legal-color);

  /* ── Field Group ── */
  --field-gap:              var(--space-1h);            /* 6px between parts */
  --field-label-size:       var(--doc-font-size);
  --field-label-weight:     var(--weight-medium);
  --field-label-color:      var(--color-fg);
  --field-description-size: var(--doc-legal-size);
  --field-description-color: var(--color-fg-muted);
  --field-error-size:       var(--doc-legal-size);
  --field-error-color:      var(--color-destructive);
  --field-validating-color: var(--color-fg-muted);     /* async validation in flight */
  /* The role `--disabled-opacity` sets for every control, nudged 10% lighter:
     0.55 at the 0.5 default, which is the value this alias always held, and it
     follows a theme that states the role (1.1A-27). */
  --field-disabled-opacity: calc(var(--disabled-opacity) * 1.1);
  --field-required-color:   var(--color-destructive);
  --field-required-marker:  ' *';                      /* appended to required labels */

  /* ── Page Break ── */
  --page-break-screen-color: var(--color-border);      /* dashed line on screen */
  --page-break-screen-style: dashed;
  --page-break-screen-label-color: var(--color-fg-muted);
  --page-break-screen-label-size: var(--text-xs);

  /* ── Stat / Metric ── */
  --stat-value-size:        var(--text-2xl);
  --stat-value-weight:      var(--weight-bold);
  --stat-value-num-font:    tabular-nums;
  --stat-label-size:        var(--doc-legal-size);
  --stat-label-color:       var(--color-fg-muted);
  --stat-change-positive:   var(--color-success);
  --stat-change-negative:   var(--color-destructive);
}

/* ── Scheme islands ── */
/* The colour aliases above, restated where a scheme can change below the root —
   a custom property resolves its var() on the element that declares it, so a
   `:root`-only alias would carry the page's light value into a nested
   `data-theme="dark"` region. See the same block in tokens/aliases.css; the
   values must match the `:root` declarations above exactly. */
[data-theme],
[data-skin] {
  --kv-label-color:         var(--doc-legal-color);
  --kv-value-color:         var(--color-fg);
  --callout-bg:             var(--color-bg-subtle);
  --callout-fg:             var(--color-fg);
  --image-border:           var(--color-border);
  --image-caption-color:    var(--doc-legal-color);
  --field-label-color:      var(--color-fg);
  --field-description-color: var(--color-fg-muted);
  --field-error-color:      var(--color-destructive);
  --field-validating-color: var(--color-fg-muted);
  --field-required-color:   var(--color-destructive);
  --page-break-screen-color: var(--color-border);
  --page-break-screen-label-color: var(--color-fg-muted);
  --stat-label-color:       var(--color-fg-muted);
  --stat-change-positive:   var(--color-success);
  --stat-change-negative:   var(--color-destructive);
}

/* ── accent.css ── */
/* @ui:tokens accent — [data-accent] subtree modifier (see SPEC-1.0.md §4; forecraft #9)

   Put `data-accent="<hue>"` on ANY element and its subtree draws its accent in
   that hue, in whatever theme is active. Five tokens are re-pointed — the five
   `faqir-tweak`'s accent dial writes:

     --color-primary  --color-primary-hover  --color-primary-active
     --color-primary-subtle  --color-ring

   each with relative colour syntax over the theme's OWN value of that token:
   `oklch(from <theme value> l c <hue>)`. Lightness and chroma stay the theme's,
   so a muted theme stays muted, a pale dark-mode accent stays pale, a
   monochrome theme (chroma 0) stays monochrome, and only the hue moves.
   `--color-primary-fg` is deliberately NOT re-pointed: the label keeps the ink
   its theme chose, which is why the named hues are measured rather than picked.

     <html data-accent="violet">              … the whole page …
     <section data-accent="pink">             … one region …
     <div data-accent="custom" style="--accent-hue: 200"> … any other hue …

   ── The vocabulary ──
   Closed: the nine named hues below, plus `custom`. Each named hue is held by
   `tests/tokens/forecraft-accent.test.ts` (via `checkAccentContrast` in
   src/audit/contrast-tokens.ts) to clear every pair the `contrast-tokens` gate
   checks — primary text on the muted and subtle plates, the primary label on
   the primary fill, the focus ring on every surface — in every shipped theme,
   light and dark. Hues that failed in any theme × scheme were dropped; the
   numbers are in that test. At equal OKLCH lightness two hues still differ in
   WCAG luminance, so a theme tuned to clear AA by a hair in its own hue does
   not clear it in most others — the four themes that did (neumorph, memphis,
   aurora, paper) were darkened just enough to admit rose to orange and blue to
   indigo. Amber, yellow and the green-to-sky arc stay out (docs/accent.md).

   `custom` names no hue: the author states `--accent-hue` (a number of degrees,
   or an angle) beside it. Nothing measures a custom hue against the theme — that
   contrast is the author's to check. A `data-accent` whose hue resolves to
   nothing (a `custom` without `--accent-hue`, or a value outside the
   vocabulary) keeps the hue it would otherwise have had — the theme's, or an
   enclosing accent's, since `--accent-hue` inherits: the channel falls back
   to `h`, the origin's own hue.

   ── Why the theme's values are captured first ──
   A custom property cannot read its own value: `--color-primary:
   oklch(from var(--color-primary) …)` is a cycle, and a cycle makes the token
   invalid. So the theme's five values are first captured into `--accent-base-*`
   on the elements a theme declares them on — `:root`, and every `[data-theme]` /
   `[data-skin]` island — and the re-pointing reads the capture. Where
   `data-accent` sits on one of those same elements (`<html data-accent>`, the
   common case), it re-points the element's CHILDREN instead, so the capture and
   the re-point never meet on one element — and an island is never re-pointed
   itself, for the same reason. An island nested inside an accent region
   re-captures its own theme's values and its children are re-pointed again,
   which is how a block-form theme's `[data-theme="dark"]` island keeps the
   accent. The cost: on a capture element the accent starts one level down, so
   the element's OWN border or fill keeps the theme's accent.

   ── Print ──
   `--doc-accent` (tokens/document.css), the one ink a print theme draws in,
   follows the accent by default: it is captured and re-hued like the five, so a
   print theme's own darker `@media print` ink keeps its lightness and takes the
   accent's hue.

   ── Fallback ──
   Everything that re-points is inside `@supports` for relative colour syntax
   over a `light-dark()` origin (every one-block theme's tokens are
   `light-dark()` calls). A browser without it ignores the block and renders
   the theme's own accent: the attribute degrades to a no-op, never to a page
   with no primary colour.

   `data-accent` is NOT a sixth protocol attribute: no manifest, controller or
   component knows about it. It only re-declares tokens. */

/* ── The named hues (OKLCH degrees) ── */
[data-accent="rose"]    { --accent-hue: 16; }
[data-accent="red"]     { --accent-hue: 25; }
[data-accent="orange"]  { --accent-hue: 48; }
[data-accent="blue"]    { --accent-hue: 260; }
[data-accent="indigo"]  { --accent-hue: 277; }
[data-accent="violet"]  { --accent-hue: 293; }
[data-accent="purple"]  { --accent-hue: 304; }
[data-accent="fuchsia"] { --accent-hue: 322; }
[data-accent="pink"]    { --accent-hue: 354; }

@supports (color: oklch(from light-dark(red, red) l c h)) {
  /* ── Capture: the theme's values, where the theme declares them ── */
  :root,
  [data-theme],
  [data-skin] {
    --accent-base-primary:        var(--color-primary);
    --accent-base-primary-hover:  var(--color-primary-hover);
    --accent-base-primary-active: var(--color-primary-active);
    --accent-base-primary-subtle: var(--color-primary-subtle);
    --accent-base-ring:           var(--color-ring);
    --accent-base-doc:            var(--doc-accent);
  }

  /* ── Re-point: the theme's lightness and chroma, the accent's hue ── */
  [data-accent]:not(:root, [data-theme], [data-skin]),
  :is(:root, [data-theme], [data-skin])[data-accent] > :not([data-theme], [data-skin]),
  [data-accent] :is([data-theme], [data-skin]) > :not([data-theme], [data-skin]) {
    --color-primary:        oklch(from var(--accent-base-primary) l c var(--accent-hue, h));
    --color-primary-hover:  oklch(from var(--accent-base-primary-hover) l c var(--accent-hue, h));
    --color-primary-active: oklch(from var(--accent-base-primary-active) l c var(--accent-hue, h));
    --color-primary-subtle: oklch(from var(--accent-base-primary-subtle) l c var(--accent-hue, h));
    --color-ring:           oklch(from var(--accent-base-ring) l c var(--accent-hue, h));
    --doc-accent:           oklch(from var(--accent-base-doc) l c var(--accent-hue, h));
    /* Declared on :root, the focus ring resolved the theme's ring there. */
    --focus-ring-color:     var(--color-ring);
  }
}

/* ── density.css ── */
/* @ui:tokens density — [data-density] subtree modifier (task 0.7-11, FAQIR-NEXT §B6;
   `spacious` added 1.1A-09, SPEC-1.0.md §4)

   Put `data-density="compact"` on ANY container and its whole subtree renders
   tighter: spacing steps shrink by --density-scale and interactive controls drop
   to a shorter height ramp. `data-density="comfortable"` restores the base scale,
   so density can be reset on an inner subtree. `data-density="spacious"` is the
   third point on the ladder, above comfortable: spacing grows and the control
   ramp grows with it, gentler than the spacing multiplier for the same reason
   compact's ramp shrinks gentler — a usable hit target has a ceiling as well as
   a floor.

     <section data-density="compact">   … dense form / table / toolbar …   </section>
     <section data-density="spacious">  … roomy landing hero, kiosk UI …   </section>

   This is 100% CSS. `data-density` is NOT a sixth protocol attribute: no
   component contract, manifest, controller or audit rule knows about it — CSS
   never selects a component *through* it, it only re-declares tokens. Components
   stay written against `var(--space-*)` / `var(--control-height-*)` and inherit
   whatever the nearest density scope resolved them to.

   ── Why every token is re-declared instead of just setting a multiplier ──
   A `var()` inside a custom property is substituted on the element that DECLARES
   the property, not where it is used. `--space-4: calc(1rem * var(--density-scale))`
   declared in :root would therefore freeze at the :root value of --density-scale
   and a nested override would do nothing. Each density block re-declares the
   tokens itself, so substitution happens on the density element and descendants
   inherit the already-resolved value. That is also what makes nesting honest.

   ── Scope of the remap ──
   • --space-1 … --space-64  × --density-scale (the page-rhythm steps 32/40/48/64
     added in 0.8-07 scale with the rest: a compact page tightens the air between
     its sections exactly as it tightens the padding inside them).
     --space-0 and --space-px are invariant: 0 stays 0 and a 1px hairline is a
     hairline at any density.
   • --control-height-{sm,md,lg} → an explicit shorter ramp, NOT the spacing
     multiplier: 40px × 0.75 = 30px is below a usable hit target. Dense UIs tighten
     padding faster than they shrink controls.
   • Every :root alias in tokens/aliases.css and tokens/doc-aliases.css whose value
     references one of the above is re-declared verbatim here (same value text), so
     it re-substitutes against this scope. A drift test enforces that list.
   • tokens/document.css (--doc-*, --page-*) is deliberately NOT remapped: paged
     media geometry — page margins, running-header gaps, signature space — is a
     print concern that themes own, not a screen density mode.

   ── Cascade ──
   `[data-density]` and `:root` have identical specificity (0,1,0), so this file
   must load AFTER aliases.css/doc-aliases.css — it is last in tokens/index.css.
   A theme stylesheet loads after the tokens layer; no shipped theme overrides
   --space-* or the control ramp, and in practice `data-density` sits on a
   container rather than <html>, where a theme's :root block cannot reach it. */

[data-density="compact"] {
  --density-scale: 0.75;

  /* ── Spacing scale (× --density-scale) ── */
  --space-0h:  calc(0.125rem * var(--density-scale));
  --space-1:   calc(0.25rem  * var(--density-scale));
  --space-1h:  calc(0.375rem * var(--density-scale));
  --space-2:   calc(0.5rem   * var(--density-scale));
  --space-2h:  calc(0.625rem * var(--density-scale));
  --space-3:   calc(0.75rem  * var(--density-scale));
  --space-3h:  calc(0.875rem * var(--density-scale));
  --space-4:   calc(1rem     * var(--density-scale));
  --space-5:   calc(1.25rem  * var(--density-scale));
  --space-6:   calc(1.5rem   * var(--density-scale));
  --space-7:   calc(1.75rem  * var(--density-scale));
  --space-8:   calc(2rem     * var(--density-scale));
  --space-10:  calc(2.5rem   * var(--density-scale));
  --space-12:  calc(3rem     * var(--density-scale));
  --space-16:  calc(4rem     * var(--density-scale));
  --space-20:  calc(5rem     * var(--density-scale));
  --space-24:  calc(6rem     * var(--density-scale));
  --space-32:  calc(8rem     * var(--density-scale));
  --space-40:  calc(10rem    * var(--density-scale));
  --space-48:  calc(12rem    * var(--density-scale));
  --space-64:  calc(16rem    * var(--density-scale));

  /* ── Control height ramp ── */
  --control-height-sm: 28px;
  --control-height-md: 32px;
  --control-height-lg: 40px;

  /* ── Aliases re-substituted in this scope (values identical to the base) ── */
  --button-height-sm:  var(--control-height-sm);
  --button-height-md:  var(--control-height-md);
  --button-height-lg:  var(--control-height-lg);
  --input-height:      var(--control-height-md);
  --card-padding:      var(--space-6);
  --kv-pair-gap:       var(--space-3);
  --kv-grid-gap:       var(--space-4);
  --callout-padding-y: var(--space-3);
  --callout-padding-x: var(--space-4);
  --field-gap:         var(--space-1h);
  --section-gap-sm:    var(--space-12);
  --section-gap-md:    var(--space-20);
  --section-gap-lg:    var(--space-32);
  --content-gutter:    var(--space-6);
}

/* The default density, declared explicitly so an inner subtree can reset out of
   a compact ancestor. Values are the base scale verbatim (drift-tested). */
[data-density="comfortable"] {
  --density-scale: 1;

  /* ── Spacing scale ── */
  --space-0h:  0.125rem;
  --space-1:   0.25rem;
  --space-1h:  0.375rem;
  --space-2:   0.5rem;
  --space-2h:  0.625rem;
  --space-3:   0.75rem;
  --space-3h:  0.875rem;
  --space-4:   1rem;
  --space-5:   1.25rem;
  --space-6:   1.5rem;
  --space-7:   1.75rem;
  --space-8:   2rem;
  --space-10:  2.5rem;
  --space-12:  3rem;
  --space-16:  4rem;
  --space-20:  5rem;
  --space-24:  6rem;
  --space-32:  8rem;
  --space-40:  10rem;
  --space-48:  12rem;
  --space-64:  16rem;

  /* ── Control height ramp ── */
  --control-height-sm: 32px;
  --control-height-md: 40px;
  --control-height-lg: 48px;

  /* ── Aliases re-substituted in this scope (values identical to the base) ── */
  --button-height-sm:  var(--control-height-sm);
  --button-height-md:  var(--control-height-md);
  --button-height-lg:  var(--control-height-lg);
  --input-height:      var(--control-height-md);
  --card-padding:      var(--space-6);
  --kv-pair-gap:       var(--space-3);
  --kv-grid-gap:       var(--space-4);
  --callout-padding-y: var(--space-3);
  --callout-padding-x: var(--space-4);
  --field-gap:         var(--space-1h);
  --section-gap-sm:    var(--space-12);
  --section-gap-md:    var(--space-20);
  --section-gap-lg:    var(--space-32);
  --content-gutter:    var(--space-6);
}

/* The third density: roomier than the base scale, for a landing hero or a kiosk
   UI meant to be read at arm's length. Control heights grow slower than the
   spacing multiplier — the same asymmetry compact's ramp has, mirrored. */
[data-density="spacious"] {
  --density-scale: 1.25;

  /* ── Spacing scale (× --density-scale) ── */
  --space-0h:  calc(0.125rem * var(--density-scale));
  --space-1:   calc(0.25rem  * var(--density-scale));
  --space-1h:  calc(0.375rem * var(--density-scale));
  --space-2:   calc(0.5rem   * var(--density-scale));
  --space-2h:  calc(0.625rem * var(--density-scale));
  --space-3:   calc(0.75rem  * var(--density-scale));
  --space-3h:  calc(0.875rem * var(--density-scale));
  --space-4:   calc(1rem     * var(--density-scale));
  --space-5:   calc(1.25rem  * var(--density-scale));
  --space-6:   calc(1.5rem   * var(--density-scale));
  --space-7:   calc(1.75rem  * var(--density-scale));
  --space-8:   calc(2rem     * var(--density-scale));
  --space-10:  calc(2.5rem   * var(--density-scale));
  --space-12:  calc(3rem     * var(--density-scale));
  --space-16:  calc(4rem     * var(--density-scale));
  --space-20:  calc(5rem     * var(--density-scale));
  --space-24:  calc(6rem     * var(--density-scale));
  --space-32:  calc(8rem     * var(--density-scale));
  --space-40:  calc(10rem    * var(--density-scale));
  --space-48:  calc(12rem    * var(--density-scale));
  --space-64:  calc(16rem    * var(--density-scale));

  /* ── Control height ramp ── */
  --control-height-sm: 36px;
  --control-height-md: 44px;
  --control-height-lg: 52px;

  /* ── Aliases re-substituted in this scope (values identical to the base) ── */
  --button-height-sm:  var(--control-height-sm);
  --button-height-md:  var(--control-height-md);
  --button-height-lg:  var(--control-height-lg);
  --input-height:      var(--control-height-md);
  --card-padding:      var(--space-6);
  --kv-pair-gap:       var(--space-3);
  --kv-grid-gap:       var(--space-4);
  --callout-padding-y: var(--space-3);
  --callout-padding-x: var(--space-4);
  --field-gap:         var(--space-1h);
  --section-gap-sm:    var(--space-12);
  --section-gap-md:    var(--space-20);
  --section-gap-lg:    var(--space-32);
  --content-gutter:    var(--space-6);
}


/* === tokens/theme.css === */
/* @ui:theme default — one :root block, both schemes, via light-dark() */

/* Authored in the ONE-BLOCK form [1.1A-06]: each scheme-dependent token states
   `light-dark(<light>, <dark>)` once instead of being written in `:root`, again
   in `[data-theme="dark"]` and a third time in the `prefers-color-scheme`
   mirror. `base/reset.css` turns `data-theme` into the `color-scheme` the
   function reads, so the two authoring forms are interchangeable and every
   existing `data-theme` value keeps driving exactly what it drove before.

   The light argument is the value this theme would otherwise have INHERITED
   from tokens/semantic.css; spelling it out is the price of the single block,
   because a token cannot read its own base value (`light-dark(var(--color-bg),
   …)` on `--color-bg` is a cycle). `tests/themes/light-dark.test.ts` is what
   keeps the copy honest: every light argument must equal the base value unless
   it is one of the four deliberate AA corrections below (task 0.4-24 · §12.3),
   and that list fails in both directions.

   Darkening for AA is contrast-safe: every *solid* use of these semantic colours
   (button, progress, stepper marker) carries light text or no text, so a deeper
   tone only raises its contrast.

   The shadow ramp is the one family still authored as blocks — see below. */
:root {
  /* ── Surfaces ── */
  --color-bg:               light-dark(var(--palette-gray-25), var(--palette-gray-950));
  --color-bg-subtle:        light-dark(var(--palette-gray-100), var(--palette-gray-900));
  --color-bg-muted:         light-dark(var(--palette-gray-200), var(--palette-gray-800));
  /* Scheme-independent by construction: the elevation ramp is defined in terms
     of tokens that already carry both schemes, so it needs no second spelling. */
  --color-surface-1:        var(--color-bg-subtle);
  --color-surface-2:        var(--color-bg-muted);
  --color-surface-1-border: var(--color-border);
  --color-surface-2-border: var(--color-border-strong);
  --color-fg:               light-dark(var(--palette-gray-950), var(--palette-gray-50));
  /* AA: light gray-500 was 4.31:1 on muted surfaces (avatar/tabs); in dark,
     gray-400 is kept for subtle, so muted moves up. */
  --color-fg-muted:         light-dark(var(--palette-gray-600), var(--palette-gray-300));
  /* AA: light gray-400 was 2.61:1 (subtle text, footers, page-break);
     dark gray-500 subtle text was 4.11:1 on bg. */
  --color-fg-subtle:        light-dark(var(--palette-gray-500), var(--palette-gray-400));

  /* ── Interactive: Primary ── */
  --color-primary:          light-dark(var(--palette-indigo-500), var(--palette-indigo-400));
  --color-primary-hover:    light-dark(var(--palette-indigo-600), var(--palette-indigo-300));
  --color-primary-active:   light-dark(var(--palette-indigo-700), var(--palette-indigo-200));
  /* AA: dark ink on the luminous dark-mode accent — white was 3.4:1 [0.4-16] */
  --color-primary-fg:       light-dark(white, var(--palette-gray-950));
  --color-primary-subtle:   light-dark(var(--palette-indigo-50), oklch(0.24 0.06 264));

  /* ── Interactive: Secondary ── */
  --color-secondary:        light-dark(var(--palette-gray-100), var(--palette-gray-800));
  --color-secondary-hover:  light-dark(var(--palette-gray-200), var(--palette-gray-700));
  --color-secondary-fg:     light-dark(var(--palette-gray-900), var(--palette-gray-100));

  /* ── Interactive: Destructive ── */
  /* AA: a luminous dark red so it reads as text on subtle/dark bg
     (badge/chip/field/stat); red-500 was 3.42:1 [0.4-24] */
  --color-destructive:        light-dark(var(--palette-red-500), var(--palette-red-400));
  --color-destructive-hover:  light-dark(var(--palette-red-600), var(--palette-red-300));
  /* AA: dark ink on the luminous red for solid surfaces (button) — mirrors
     --color-primary-fg [0.4-24] */
  --color-destructive-fg:     light-dark(white, var(--palette-gray-950));
  --color-destructive-subtle: light-dark(var(--palette-red-50), oklch(0.24 0.06 25));

  /* ── Feedback ── */
  /* AA: light green-500 as soft-badge/stat/stepper text was 3.19:1 */
  --color-success:          light-dark(var(--palette-green-700), var(--palette-green-400));
  --color-success-subtle:   light-dark(var(--palette-green-50), oklch(0.24 0.054 155));
  /* AA: light amber-500 as soft-badge text was 2.02:1 */
  --color-warning:          light-dark(var(--palette-amber-800), var(--palette-amber-400));
  --color-warning-subtle:   light-dark(var(--palette-amber-50), oklch(0.24 0.045 75));
  --color-info:             light-dark(var(--palette-blue-500), var(--palette-blue-400));
  --color-info-subtle:      light-dark(var(--palette-blue-50), oklch(0.24 0.054 240));

  /* ── Borders ── */
  --color-border:           light-dark(var(--palette-gray-200), var(--palette-gray-800));
  --color-border-strong:    light-dark(var(--palette-gray-300), var(--palette-gray-700));
  --color-ring:             light-dark(oklch(0.55 0.22 264), oklch(0.65 0.20 264));
}

/* ── Dark Mode: the shadow ramp ── */
/* The one family `light-dark()` cannot collapse. It is a <color> function and a
   shadow list is not a colour, so the whole value cannot be wrapped; and the
   per-layer spelling would have to pad the dark ramp with alpha-0 layers to give
   both schemes one geometry — writing a shadow where this theme says `none`,
   and restating the base light ramp (two layers per step) to do it.
   Light stays inherited from tokens/effects.css; only dark is stated.

   Each step is cast in `--shadow-color` (1.1A-04 — bare OKLCH channels, so the
   step keeps its own alpha), which for this theme is the base layer's own
   `0 0 0`. That is the ONLY thing `default` adopts from the 1.1 families, and
   deliberately so: `default` is not a theme that resembles the token layer, it
   IS the token layer's own look, so restating a base value here would fork the
   two and let a later change to `tokens/*` silently stop reaching the reference
   theme. Every other axis `default` carries is derived from the base layer,
   which is what `tests/themes/axes.test.ts` holds equal to
   `THEME_SEED_DEFAULTS`. Casting the ramp through the channel is not a restated
   value — it is the ten literal blacks this theme used to hide from a theme
   that wants to tint them. [1.1A-15] */
[data-theme="dark"] {
  --shadow-xs:  none;
  --shadow-sm:  0 1px 3px oklch(var(--shadow-color) / 0.3);
  --shadow-md:  0 4px 6px oklch(var(--shadow-color) / 0.3);
  --shadow-lg:  0 10px 15px oklch(var(--shadow-color) / 0.4);
  --shadow-xl:  0 20px 25px oklch(var(--shadow-color) / 0.5);
}

/* Mirror of the [data-theme="dark"] block above — keep the two in sync. The
   colours need no mirror: `[data-theme="auto"]` is `color-scheme: light dark`,
   so light-dark() already follows the system preference. */
@media (prefers-color-scheme: dark) {
  [data-theme="auto"] {
    --shadow-xs:  none;
    --shadow-sm:  0 1px 3px oklch(var(--shadow-color) / 0.3);
    --shadow-md:  0 4px 6px oklch(var(--shadow-color) / 0.3);
    --shadow-lg:  0 10px 15px oklch(var(--shadow-color) / 0.4);
    --shadow-xl:  0 20px 25px oklch(var(--shadow-color) / 0.5);
  }
}


/* === fonts.css === */
/* Faqir UI — self-hosted fonts, licensed under the SIL Open Font License.
 * Managed by `faqir fonts add` / `faqir fonts remove`: hand edits are overwritten.
 * Bundled after the theme, so the role tokens below win over it.
 */

/* ── Inter · OFL-1.1 · https://openfontlicense.org ── */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("fonts/inter/inter-latin-wght-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("fonts/inter/inter-latin-ext-wght-normal.woff2") format("woff2");
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}

/* ── Instrument Serif · OFL-1.1 · https://openfontlicense.org ── */
@font-face {
  font-family: "Instrument Serif";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/instrument-serif/instrument-serif-latin-400-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
  font-family: "Instrument Serif";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/instrument-serif/instrument-serif-latin-ext-400-normal.woff2") format("woff2");
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}

/* ── JetBrains Mono · OFL-1.1 · https://openfontlicense.org ── */
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 100 800;
  font-display: swap;
  src: url("fonts/jetbrains-mono/jetbrains-mono-latin-wght-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
  font-family: "JetBrains Mono";
  font-style: normal;
  font-weight: 100 800;
  font-display: swap;
  src: url("fonts/jetbrains-mono/jetbrains-mono-latin-ext-wght-normal.woff2") format("woff2");
  unicode-range: U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}

/* Role tokens — what components read (1.1A-01). */
:root {
  --font-heading: "Instrument Serif", 'Playfair Display', 'Didot', 'Times New Roman', serif;
  --font-body: "Inter", 'Helvetica Neue', 'Arial', system-ui, sans-serif;
  --font-ui: "Inter", 'Helvetica Neue', 'Arial', system-ui, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, 'Cascadia Code', monospace;
}


/* === base/reset.css === */
/* @ui:base reset — modern CSS reset for Faqir projects */

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

* {
  margin: 0;
  padding: 0;
}

/* Colour scheme — the one place `data-theme` is translated into the platform's
   own scheme signal. `light-dark()` in a theme reads `color-scheme`, not
   `data-theme`, so a one-block theme [1.1A-06] resolves nothing at all without
   these three rules; declaring them here (rather than in each theme) is what
   makes the two authoring forms interchangeable. Nothing else in the registry
   declares `color-scheme`, so this is purely additive.

   Specificity does the mapping: `:root` is (0,0,1) and each attribute selector
   is (0,1,0), so `<html data-theme="dark">` takes the dark rule over the root
   default while a bare `<html>` — and `data-theme="light"` — keeps light. The
   same rules apply to a NESTED element carrying `data-theme`, which is how a
   dark island inside a light page has always worked here. */
:root {
  color-scheme: light;
}

[data-theme="dark"] {
  color-scheme: dark;
}

/* `auto` hands the choice to the OS: `light dark` means "either, system first",
   which is exactly what the `@media (prefers-color-scheme: dark)` mirror block
   does for a theme authored in the three-block form. */
[data-theme="auto"] {
  color-scheme: light dark;
}

html {
  -webkit-text-size-adjust: 100%;
  -moz-tab-size: 4;
  tab-size: 4;
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  color: var(--color-fg);
  background: var(--color-bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

body {
  min-height: 100dvh;
  /* The page's material. `none` by default (the initial value), so this is a
     no-op until a theme points --texture-page at one of tokens/textures.css.
     `html` keeps the background COLOUR; the texture rides on `body`, which
     covers the viewport, so the two compose instead of overwriting. */
  background-image: var(--texture-page);
}

img,
picture,
video,
canvas,
svg {
  display: block;
  max-width: 100%;
}

input,
button,
textarea,
select {
  font: inherit;
  color: inherit;
}

button {
  cursor: pointer;
  background: none;
  border: none;
}

p,
h1,
h2,
h3,
h4,
h5,
h6 {
  overflow-wrap: break-word;
}

h1, h2, h3, h4, h5, h6 {
  text-wrap: balance;
}

p {
  text-wrap: pretty;
}

a {
  color: inherit;
  text-decoration: inherit;
}

ul, ol {
  list-style: none;
}

table {
  border-collapse: collapse;
  border-spacing: 0;
}

/* Reduced motion */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* Text selection — the decoration axis reaching the one surface no component
   owns. Until 1.1 the highlight was whatever the OS drew, which is the one part
   of a themed page that never matched the theme. Both values are tokens
   (tokens/aliases.css § Decoration), so a theme states its selection once. */
::selection {
  background-color: var(--selection-bg);
  color: var(--selection-fg);
}

/* Focus visible — the default ring, and the only place it is spelled out.
   Every value is a token (tokens/effects.css § Focus), so a theme states its
   focus once and every element that has not drawn its own ring follows. */
:focus-visible {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  outline-offset: var(--focus-ring-offset);
}

/* The glow a theme may put behind the ring, at zero specificity. `box-shadow`
   is not a property focus owns: an element's resting shadow — a card's depth,
   an author's own — lives there too, and a (0,1,0) rule here replaced it with
   `none` (the default) on every keyboard focus. Under `:where()` ANY rule that
   sets a shadow outranks this one, so it lands only on an element nothing else
   shadows, and it never takes a shadow away. The controls that draw their own
   ring read `--focus-shadow` in their own `:focus-visible` rules. */
:where(:focus-visible) {
  box-shadow: var(--focus-shadow);
}

/* Hidden but accessible */
[hidden] {
  display: none !important;
}

/* Faqir cloak — hide until reactive engine initializes */
[l-cloak] {
  display: none !important;
}

/* @ui:base-value visually-hidden — text a screen reader reads and the page does not show (alias: .sr-only) */
/* Visually hidden, still read — text for assistive technology only: a label
   for an icon-only control, a table caption the layout does not show.
   `data-ui="visually-hidden"` is the protocol spelling (a base-layer value:
   no parts, variants or states); `.sr-only` stays as an alias for markup that
   predates it, but a `class` attribute is a `no-class-attribute` warning, so
   new markup writes the attribute. Never on a focusable element — a focused
   control that cannot be seen is a keyboard trap for sighted users; a link
   that should appear on focus is the `skip-link` primitive. */
.sr-only,
[data-ui="visually-hidden"] {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border-width: 0;
}


/* === base/prose.css === */
/* @ui:base prose — typography defaults for long-form content */

[data-ui="prose"] {
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: var(--leading-relaxed);
  color: var(--color-fg);
  max-inline-size: var(--measure-prose);
}

[data-ui="prose"] h1 {
  font-family: var(--font-heading);
  font-size: var(--text-4xl);
  font-weight: var(--heading-weight);
  letter-spacing: var(--heading-tracking);
  text-transform: var(--heading-transform);
  font-variant-caps: var(--heading-caps);
  line-height: var(--heading-leading);
  margin-block: var(--space-8) var(--space-4);
}

[data-ui="prose"] h2 {
  font-family: var(--font-heading);
  font-size: var(--text-3xl);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--heading-tracking);
  text-transform: var(--heading-transform);
  font-variant-caps: var(--heading-caps);
  line-height: var(--heading-leading);
  margin-block: var(--space-8) var(--space-3);
}

[data-ui="prose"] h3 {
  font-family: var(--font-heading);
  font-size: var(--text-2xl);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--heading-tracking);
  text-transform: var(--heading-transform);
  font-variant-caps: var(--heading-caps);
  line-height: var(--leading-snug);
  margin-block: var(--space-6) var(--space-3);
}

[data-ui="prose"] h4 {
  font-family: var(--font-heading);
  font-size: var(--text-xl);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--heading-tracking);
  text-transform: var(--heading-transform);
  font-variant-caps: var(--heading-caps);
  line-height: var(--leading-snug);
  margin-block: var(--space-6) var(--space-2);
}

[data-ui="prose"] p {
  margin-block: var(--space-4);
}

/* A bare anchor only. A registry component rendered as an anchor (a
   `data-ui="button"` call to action, a `data-ui="link"`) styles itself; the
   `:where()` keeps this rule at its original (0,1,1) weight. */
[data-ui="prose"] a:where(:not([data-ui])) {
  color: var(--color-primary);
  text-decoration-line: var(--link-decoration);
  text-underline-offset: var(--link-underline-offset);
}

[data-ui="prose"] a:where(:not([data-ui])):hover {
  color: var(--color-primary-hover);
}

[data-ui="prose"] strong {
  font-weight: var(--weight-semibold);
}

[data-ui="prose"] code {
  font-family: var(--font-mono);
  font-variant-ligatures: var(--mono-ligatures);
  font-size: 0.875em;
  background: var(--color-bg-muted);
  padding: var(--space-0h) var(--space-1);
  border-radius: var(--radius-sm);
}

[data-ui="prose"] pre {
  font-family: var(--font-mono);
  font-variant-ligatures: var(--mono-ligatures);
  font-size: var(--text-sm);
  line-height: var(--leading-relaxed);
  background: var(--color-bg-muted);
  padding: var(--space-4);
  border-radius: var(--radius-lg);
  overflow-x: auto;
  margin-block: var(--space-6);
}

[data-ui="prose"] pre code {
  background: none;
  padding: 0;
  border-radius: 0;
}

[data-ui="prose"] blockquote {
  border-inline-start: var(--border-width-lg) solid var(--color-border-strong);
  padding-inline-start: var(--space-4);
  color: var(--color-fg-muted);
  margin-block: var(--space-4);
}

[data-ui="prose"] ul {
  list-style: disc;
  padding-inline-start: var(--space-6);
  margin-block: var(--space-4);
}

[data-ui="prose"] ol {
  list-style: decimal;
  padding-inline-start: var(--space-6);
  margin-block: var(--space-4);
}

[data-ui="prose"] li {
  margin-block: var(--space-1);
}

/* The bullet. `currentColor` by default — the initial value — so a list looks
   exactly as it did; a theme that wants accented markers sets --marker-color. */
[data-ui="prose"] li::marker {
  color: var(--marker-color);
}

[data-ui="prose"] hr {
  border: none;
  border-block-start: var(--border-width) solid var(--color-border);
  margin-block: var(--space-8);
}

[data-ui="prose"] img {
  border-radius: var(--radius-lg);
  margin-block: var(--space-6);
}

[data-ui="prose"] table {
  inline-size: 100%;
  margin-block: var(--space-6);
  font-size: var(--text-sm);
}

[data-ui="prose"] th {
  font-weight: var(--weight-semibold);
  text-align: start;
  padding: var(--space-2) var(--space-3);
  border-block-end: var(--border-width-strong) solid var(--color-border-strong);
}

[data-ui="prose"] td {
  padding: var(--space-2) var(--space-3);
  border-block-end: var(--border-width) solid var(--color-border);
}

/* Wide tables — a table is as wide as its widest row, and on a phone that row
   pushed the whole page into sideways scroll. Wrap the table and the wrapper
   scrolls instead:

     <div role="region" tabindex="0" aria-label="Plan comparison">
       <table>…</table>
     </div>

   or a <figure> with a <figcaption> (point aria-labelledby at the caption).
   The wrapper is plain HTML — prose takes no parts — and any <div> or
   <figure> whose child is a <table> qualifies, which is the shape a markdown
   renderer emits once it wraps tables. `tabindex="0"` with a role and a name
   makes the scroller reachable and announced from the keyboard, and the
   default ring from reset.css shows its focus; the table inside drops its
   own block margin so the wrapper carries it. A bare table is unchanged. */
[data-ui="prose"] :where(div, figure):has(> table) {
  max-inline-size: 100%;
  overflow-x: auto;
  margin-block: var(--space-6);
  margin-inline: 0;
}

[data-ui="prose"] :where(div, figure):has(> table) > table {
  margin-block: 0;
}

/* Definition lists — "each setting and what it does". A term reads as a label
   and its definitions sit indented under it, one group spaced from the next. */
[data-ui="prose"] dl {
  margin-block: var(--space-4);
}

[data-ui="prose"] dt {
  font-weight: var(--weight-semibold);
  margin-block-start: var(--space-3);
}

[data-ui="prose"] dt:first-child {
  margin-block-start: 0;
}

[data-ui="prose"] dd {
  margin-inline-start: var(--space-6);
  margin-block-start: var(--space-1);
}

/* Figures — an image or a code sample with its caption. The figure carries the
   spacing, so an image inside it does not add its own. */
[data-ui="prose"] figure {
  margin-block: var(--space-6);
  margin-inline: 0;
}

[data-ui="prose"] figure > img,
[data-ui="prose"] figure > pre {
  margin-block: 0;
}

[data-ui="prose"] figcaption {
  font-size: var(--text-sm);
  color: var(--color-fg-muted);
  margin-block-start: var(--space-2);
}

/* Disclosures. The summary is the control, so it reads as one. */
[data-ui="prose"] details {
  margin-block: var(--space-4);
}

[data-ui="prose"] summary {
  font-weight: var(--weight-semibold);
  cursor: pointer;
}

/* First child no top margin, last child no bottom margin */
[data-ui="prose"] > :first-child {
  margin-block-start: 0;
}

[data-ui="prose"] > :last-child {
  margin-block-end: 0;
}


/* === base/rhythm.css === */
/* @ui:base rhythm — the default vertical rhythm (task 0.9-02, FAQIR-SPEC §20) */

/* THE RULE, in one sentence:
 *
 *   Inside a flow root, consecutive block-level Faqir components and nested flow
 *   roots are separated by `--flow-space` of vertical space.
 *
 * ── "and nested flow roots" ──
 * Not a widening for its own sake: a page written as a run of bare `<section>`s
 * is the commonest shape there is, and a rule that spaced `[data-ui]` children
 * only would leave exactly that page flush. A sectioning element is a block box
 * by definition, so the same margin is safe on it. The participant set is
 * therefore `[data-ui]` plus the flow-root tags — never "any child", which would
 * put 3rem between a heading and its own paragraph.
 *
 * ── "consecutive" ──
 * The margin goes on the SECOND of two participants, so a non-participant
 * between them suppresses it: `<h2>` followed by a table is a label and the
 * thing it labels, and a rule that pushed them 3rem apart would be a worse
 * defect than the one it fixed. (Measured, not assumed: the first draft used
 * "not the first child" and the printed invoice scaffold came back with every
 * heading floating 48px above its own section.) Prose headings keep their own
 * margins from `base/prose.css`, where that decision belongs.
 *
 * That is the whole of §20, and it is deliberately a sentence an agent can be
 * told once. Nothing has to be wrapped, no attribute has to be written, and a
 * bare sequence of components pasted into an empty file is spaced — which is
 * the defect this rule exists to remove: v0.8 shipped a complete spacing
 * vocabulary (`--space-0…64`, `--section-gap-{sm,md,lg}`, `--content-gutter`,
 * `data-gap` on all five layout primitives) in which *every gap was opt-in*, so
 * 42 of the 86 reference pages rendered with 183 zero-gap seams between demos
 * while every gate stayed green (task 0.9-01 measured it).
 *
 * ── flow root ──
 * The page's own structure: the HTML sectioning and grouping elements, plus the
 * two Faqir primitives that *are* plain block boxes (`container`, the centred
 * measure column, and `surface`, the generic padded box). An element carrying
 * any other `data-ui` is NOT a flow root — a component owns its own internal
 * layout, and `stack`/`cluster`/`grid`/`switcher` in particular already space
 * their children with `gap`, so adding a margin there would silently double it.
 *
 * ── block-level ──
 * Vertical margins on an atomic inline box (`inline-flex`, `inline-block`) do
 * not stack it — they shift it inside its line box and break the baseline it
 * shares with its neighbours. A row of badges is a row, and its spacing is a
 * different question (task 0.9-08). CSS cannot select on computed display, so
 * the 26 inline-level components are named below; the list is not maintained by
 * hand but *derived* from the registry — `tests/utils/rhythm.test.ts` recomputes
 * it from every component's root `display` (falling back to the root tag's UA
 * default, which is what makes `link` inline) and fails if this list and
 * `INLINE_LEVEL_COMPONENTS` in `src/utils/layout.ts` disagree with it.
 *
 * ── `--flow-space` ──
 * Defaults to `--section-gap-sm` (3rem), the rhythm token 0.8-07 shipped for
 * "dense pages — docs, dashboards", which is exactly the shape a bare sequence
 * of components makes. `data-gap` on the flow root changes it — the same ladder
 * and the same spelling the five layout primitives use, so nothing new has to be
 * learned — and `data-gap="0"` turns the rhythm off. It inherits, so it is set
 * once on a page and applies all the way down until another flow root says
 * otherwise.
 *
 * ── specificity ──
 * The whole selector is wrapped in `:where()` and every negation takes a
 * `:where()` argument, so it weighs (0,0,0): any component rule, any authored
 * rule, and any `data-gap` on the flow root beats it. A default that cannot be
 * overridden is not a default.
 *
 * ── two rejected candidates, recorded because the question will be asked again ──
 * 1. A `flow` PRIMITIVE (`> * + *` behind a sixth layout component). Rejected:
 *    it is a wrapper, and a rule whose answer is "wrap it" fails the one test
 *    this decision had to pass — an agent must produce spaced output without
 *    wrapping anything. It would also have spent a new component immediately
 *    before the 1.0 schema freeze.
 * 2. A `data-flow` PROP on `stack`/`surface`/`container`. Rejected for the same
 *    reason (still opt-in, still per-element) and one more: three manifests
 *    would grow an attribute meaning the same thing in three places, which is
 *    the drift the manifest system exists to prevent.
 */

/* ── the rule ── */
:where(
    body, main, article, section, aside, header, footer,
    form, fieldset, dialog, blockquote, figure,
    [data-ui="container"], [data-ui="surface"]
  ):not(:where([data-ui]:not([data-ui="container"], [data-ui="surface"])))
  > :where(
    [data-ui],
    body, main, article, section, aside, header, footer,
    form, fieldset, dialog, blockquote, figure
  )
  + :where(
    [data-ui],
    body, main, article, section, aside, header, footer,
    form, fieldset, dialog, blockquote, figure
  ):not(
    :where(
      [data-ui="avatar"], [data-ui="badge"], [data-ui="barcode"], [data-ui="button"],
      [data-ui="calendar"], [data-ui="checkbox"], [data-ui="chip"], [data-ui="combobox"],
      [data-ui="date-picker"], [data-ui="dropdown"], [data-ui="highlight"], [data-ui="icon"],
      [data-ui="image"], [data-ui="input-otp"], [data-ui="kbd"], [data-ui="link"],
      [data-ui="menubar"], [data-ui="pagination"], [data-ui="popover"], [data-ui="qr-code"],
      [data-ui="radio"], [data-ui="rating"], [data-ui="select-custom"], [data-ui="spinner"],
      [data-ui="switch"], [data-ui="toggle"], [data-ui="toggle-group"], [data-ui="tooltip"]
    )
  ) {
  margin-block-start: var(--flow-space, var(--section-gap-sm));
}

/* ── the ladder ──
 * `data-gap` on a flow root, on the same spacing scale the layout primitives
 * take. Scoped to flow roots so a `data-gap` written for a stack's own flex gap
 * cannot silently re-tune the rhythm of everything below it. */
:where(body, main, article, section, aside, header, footer, form, fieldset, dialog, blockquote, figure, [data-ui="container"], [data-ui="surface"])[data-gap="0"] { --flow-space: 0px; }
:where(body, main, article, section, aside, header, footer, form, fieldset, dialog, blockquote, figure, [data-ui="container"], [data-ui="surface"])[data-gap="1"] { --flow-space: var(--space-1); }
:where(body, main, article, section, aside, header, footer, form, fieldset, dialog, blockquote, figure, [data-ui="container"], [data-ui="surface"])[data-gap="2"] { --flow-space: var(--space-2); }
:where(body, main, article, section, aside, header, footer, form, fieldset, dialog, blockquote, figure, [data-ui="container"], [data-ui="surface"])[data-gap="3"] { --flow-space: var(--space-3); }
:where(body, main, article, section, aside, header, footer, form, fieldset, dialog, blockquote, figure, [data-ui="container"], [data-ui="surface"])[data-gap="4"] { --flow-space: var(--space-4); }
:where(body, main, article, section, aside, header, footer, form, fieldset, dialog, blockquote, figure, [data-ui="container"], [data-ui="surface"])[data-gap="6"] { --flow-space: var(--space-6); }
:where(body, main, article, section, aside, header, footer, form, fieldset, dialog, blockquote, figure, [data-ui="container"], [data-ui="surface"])[data-gap="8"] { --flow-space: var(--space-8); }
:where(body, main, article, section, aside, header, footer, form, fieldset, dialog, blockquote, figure, [data-ui="container"], [data-ui="surface"])[data-gap="10"] { --flow-space: var(--space-10); }
:where(body, main, article, section, aside, header, footer, form, fieldset, dialog, blockquote, figure, [data-ui="container"], [data-ui="surface"])[data-gap="12"] { --flow-space: var(--space-12); }
:where(body, main, article, section, aside, header, footer, form, fieldset, dialog, blockquote, figure, [data-ui="container"], [data-ui="surface"])[data-gap="16"] { --flow-space: var(--space-16); }

/* ── chrome before the content (forecraft #22) ──
 * A site header is page chrome, not a section of the content, and a skip link
 * is out of the flow: neither opens a rhythm gap. Without this, `body` (a flow
 * root) put --flow-space between a `site-header` and the `main` after it — a
 * band of page colour under a sticky bar, above a full-bleed hero backdrop.
 * The element right after either one starts flush; the same participant set
 * as the rule above, and the same zero weight, so any authored margin wins. */
:where([data-ui="site-header"], [data-ui="skip-link"])
  + :where(
    [data-ui],
    body, main, article, section, aside, header, footer,
    form, fieldset, dialog, blockquote, figure
  ) {
  margin-block-start: 0;
}


/* === base/motion-presets.css === */
/* @ui:base motion-presets — l-transition presets (Transitions 2.0 · 0.4-11 · §A4)
 *
 * The engine (faqir-core) drives l-show / l-if transitions through a single
 * `data-motion` attribute — "enter" → "enter-active" on show, "leave" →
 * "leave-active" on hide — instead of per-stage CSS classes. These rules give
 * each named preset (`fade`, `slide-up`, `scale`) its from/to styles, sourced
 * entirely from motion tokens (see tokens/motion.css). Nothing here hardcodes a
 * duration or easing.
 *
 * Lifecycle contract:
 *   data-motion="enter"         from-state, no transition (snaps into place)
 *   data-motion="enter-active"  to-state (natural) + transition → animates in
 *   data-motion="leave"         from-state (natural) + transition armed
 *   data-motion="leave-active"  to-state (exit) → animates out
 *
 * Reduced motion is handled by the engine, which never stamps `data-motion`
 * when `prefers-reduced-motion: reduce` — so no !important guard is needed here.
 */

/* ── fade ── */
[l-transition="fade"][data-motion="enter"] {
  opacity: 0;
}
[l-transition="fade"][data-motion="enter-active"] {
  transition: opacity var(--motion-enter-duration) var(--motion-enter-ease);
}
[l-transition="fade"][data-motion="leave"],
[l-transition="fade"][data-motion="leave-active"] {
  transition: opacity var(--motion-leave-duration) var(--motion-leave-ease);
}
[l-transition="fade"][data-motion="leave-active"] {
  opacity: 0;
}

/* ── slide-up ── */
[l-transition="slide-up"][data-motion="enter"] {
  opacity: 0;
  transform: translateY(var(--motion-slide-distance));
}
[l-transition="slide-up"][data-motion="enter-active"] {
  transition:
    opacity var(--motion-enter-duration) var(--motion-enter-ease),
    transform var(--motion-enter-duration) var(--motion-enter-ease);
}
[l-transition="slide-up"][data-motion="leave"],
[l-transition="slide-up"][data-motion="leave-active"] {
  transition:
    opacity var(--motion-leave-duration) var(--motion-leave-ease),
    transform var(--motion-leave-duration) var(--motion-leave-ease);
}
[l-transition="slide-up"][data-motion="leave-active"] {
  opacity: 0;
  transform: translateY(var(--motion-slide-distance));
}

/* ── scale ── */
[l-transition="scale"][data-motion="enter"] {
  opacity: 0;
  transform: scale(var(--motion-scale-from));
}
[l-transition="scale"][data-motion="enter-active"] {
  transition:
    opacity var(--motion-enter-duration) var(--motion-enter-ease),
    transform var(--motion-enter-duration) var(--motion-enter-ease);
}
[l-transition="scale"][data-motion="leave"],
[l-transition="scale"][data-motion="leave-active"] {
  transition:
    opacity var(--motion-leave-duration) var(--motion-leave-ease),
    transform var(--motion-leave-duration) var(--motion-leave-ease);
}
[l-transition="scale"][data-motion="leave-active"] {
  opacity: 0;
  transform: scale(var(--motion-scale-from));
}

/* ── The travelling presets ──
   `slide-down`, `slide-start` and `slide-end` are `slide-up` from the other
   three edges, and share its distance token. The two inline presets are
   logical: `start` is the left edge in a left-to-right page and the right edge
   in a right-to-left one, so a drawer-like panel enters from the side its
   reading direction says it lives on. `--faqir-slide` carries the signed
   offset, so each stage is written once for all three directions. */
[l-transition="slide-down"] {
  --faqir-slide: 0 calc(var(--motion-slide-distance) * -1);
}
[l-transition="slide-start"] {
  --faqir-slide: calc(var(--motion-slide-distance) * -1) 0;
}
[l-transition="slide-end"],
[l-transition="slide-start"]:dir(rtl) {
  --faqir-slide: var(--motion-slide-distance) 0;
}
[l-transition="slide-end"]:dir(rtl) {
  --faqir-slide: calc(var(--motion-slide-distance) * -1) 0;
}

:is([l-transition="slide-down"], [l-transition="slide-start"], [l-transition="slide-end"])[data-motion="enter"] {
  opacity: 0;
  translate: var(--faqir-slide);
}
:is([l-transition="slide-down"], [l-transition="slide-start"], [l-transition="slide-end"])[data-motion="enter-active"] {
  transition:
    opacity var(--motion-enter-duration) var(--motion-enter-ease),
    translate var(--motion-enter-duration) var(--motion-enter-ease);
}
:is([l-transition="slide-down"], [l-transition="slide-start"], [l-transition="slide-end"])[data-motion="leave"],
:is([l-transition="slide-down"], [l-transition="slide-start"], [l-transition="slide-end"])[data-motion="leave-active"] {
  transition:
    opacity var(--motion-leave-duration) var(--motion-leave-ease),
    translate var(--motion-leave-duration) var(--motion-leave-ease);
}
:is([l-transition="slide-down"], [l-transition="slide-start"], [l-transition="slide-end"])[data-motion="leave-active"] {
  opacity: 0;
  translate: var(--faqir-slide);
}

/* ── blur ──
   Arrives out of focus and sharpens; leaves the way it came. The radius is the
   reveal family's, so a theme that softens its entrances softens this one too. */
[l-transition="blur"][data-motion="enter"] {
  opacity: 0;
  filter: blur(var(--motion-reveal-blur));
}
[l-transition="blur"][data-motion="enter-active"] {
  transition:
    opacity var(--motion-enter-duration) var(--motion-enter-ease),
    filter var(--motion-enter-duration) var(--motion-enter-ease);
}
[l-transition="blur"][data-motion="leave"],
[l-transition="blur"][data-motion="leave-active"] {
  transition:
    opacity var(--motion-leave-duration) var(--motion-leave-ease),
    filter var(--motion-leave-duration) var(--motion-leave-ease);
}
[l-transition="blur"][data-motion="leave-active"] {
  opacity: 0;
  filter: blur(var(--motion-reveal-blur));
}

/* ── flip ──
   Hinges open on its top edge, like a card turned face up. `rotate` (not
   `transform`) so an element that already carries a transform keeps it. */
[l-transition="flip"] {
  transform-origin: center top;
}
[l-transition="flip"][data-motion="enter"] {
  opacity: 0;
  rotate: x -70deg;
}
[l-transition="flip"][data-motion="enter-active"] {
  transition:
    opacity var(--motion-enter-duration) var(--motion-enter-ease),
    rotate var(--motion-enter-duration) var(--motion-enter-ease);
}
[l-transition="flip"][data-motion="leave"],
[l-transition="flip"][data-motion="leave-active"] {
  transition:
    opacity var(--motion-leave-duration) var(--motion-leave-ease),
    rotate var(--motion-leave-duration) var(--motion-leave-ease);
}
[l-transition="flip"][data-motion="leave-active"] {
  opacity: 0;
  rotate: x -70deg;
}


/* === primitives/aspect-ratio.css === */
/* @ui:component aspect-ratio */
/* @ui:tokens color-bg-muted radius-none */

/* ── Wrapper — holds a fixed width-to-height ratio and clips its child ── */
[data-ui="aspect-ratio"] {
  display: block;
  inline-size: 100%;
  aspect-ratio: var(--aspect-ratio-value, 1 / 1);
  overflow: hidden;
  border-radius: var(--aspect-ratio-radius, var(--radius-none));
  background: var(--aspect-ratio-bg, var(--color-bg-muted));
}

/* The framed child (img, video, iframe, …) fills the box */
[data-ui="aspect-ratio"] > * {
  display: block;
  inline-size: 100%;
  block-size: 100%;
  object-fit: var(--aspect-ratio-fit, cover);
}

/* ── Ratio variants — set the ratio via the shared custom property ── */
[data-ui="aspect-ratio"][data-variant="square"] {
  --aspect-ratio-value: 1 / 1;
}

[data-ui="aspect-ratio"][data-variant="16-9"] {
  --aspect-ratio-value: 16 / 9;
}

[data-ui="aspect-ratio"][data-variant="4-3"] {
  --aspect-ratio-value: 4 / 3;
}

[data-ui="aspect-ratio"][data-variant="3-2"] {
  --aspect-ratio-value: 3 / 2;
}

[data-ui="aspect-ratio"][data-variant="21-9"] {
  --aspect-ratio-value: 21 / 9;
}

[data-ui="aspect-ratio"][data-variant="portrait"] {
  --aspect-ratio-value: 3 / 4;
}


/* === primitives/avatar.css === */
/* @ui:component avatar */
/* @ui:tokens color-bg-muted color-fg-muted radius-full font-ui text-xs text-sm text-base weight-medium avatar-size-md avatar-radius avatar-size-sm avatar-size-lg */

/* ── Base ── */
[data-ui="avatar"] {
  display: inline-flex;
  vertical-align: bottom;
  align-items: center;
  justify-content: center;
  width: var(--avatar-size-md, 40px);
  height: var(--avatar-size-md, 40px);
  border-radius: var(--avatar-radius, var(--radius-full));
  overflow: hidden;
  flex-shrink: 0;
}

/* ── Parts ── */
[data-ui="avatar"] > [data-part="image"] {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

[data-ui="avatar"] > [data-part="fallback"] {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  background: var(--color-bg-muted);
  color: var(--color-fg-muted);
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  text-transform: uppercase;
}

/* ── Sizes ── */
[data-ui="avatar"][data-size="sm"] {
  width: var(--avatar-size-sm, 32px);
  height: var(--avatar-size-sm, 32px);
}
[data-ui="avatar"][data-size="sm"] > [data-part="fallback"] {
  font-size: var(--text-xs);
}

[data-ui="avatar"][data-size="lg"] {
  width: var(--avatar-size-lg, 48px);
  height: var(--avatar-size-lg, 48px);
}
[data-ui="avatar"][data-size="lg"] > [data-part="fallback"] {
  font-size: var(--text-base, 1rem);
}


/* === primitives/backdrop.css === */
/* @ui:component backdrop */
/* @ui:tokens color-primary color-info color-success color-fg motion-ambient-duration motion-ambient-play ease-in-out ease-linear border-width */

/* ── Root ──
   A backdrop is a wrapper, not a layer you have to position: put a section
   inside it and the light is painted BEHIND that content by the root's two
   pseudo-elements. `isolation: isolate` is what keeps their negative z-index
   above the page and below the content, and `overflow: clip` trims the
   oversized layers without turning the root into a scroll container (so a
   sticky header inside one still sticks).

   Three colours drive every variant. They default to the theme's accent,
   info and success, so a backdrop is on-brand in all twenty-seven themes
   without a declaration; `--backdrop-color-1|2|3` re-point them per instance. */
[data-ui="backdrop"] {
  --faqir-backdrop-a: var(--backdrop-color-1, var(--color-primary));
  --faqir-backdrop-b: var(--backdrop-color-2, var(--color-info));
  --faqir-backdrop-c: var(--backdrop-color-3, var(--color-success));
  --faqir-backdrop-ink: var(--backdrop-ink, var(--color-fg));
  --faqir-backdrop-strength: 1;
  position: relative;
  isolation: isolate;
  overflow: clip;
}

[data-ui="backdrop"]::before,
[data-ui="backdrop"]::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: calc(var(--backdrop-opacity, 0.55) * var(--faqir-backdrop-strength));
  animation-duration: var(--backdrop-duration, var(--motion-ambient-duration));
  animation-timing-function: var(--ease-in-out);
  animation-iteration-count: infinite;
  animation-direction: alternate;
  animation-play-state: var(--motion-ambient-play);
}

/* ── Intensity ── */
[data-ui="backdrop"][data-intensity="subtle"] {
  --faqir-backdrop-strength: 0.5;
}

[data-ui="backdrop"][data-intensity="vivid"] {
  --faqir-backdrop-strength: 1.6;
}

/* ── Variant: aurora (default) ──
   Two sheets of soft colour drifting against each other. Each is larger than
   the root and blurred, so no edge of a gradient ever shows. */
[data-ui="backdrop"]:not([data-variant])::before,
[data-ui="backdrop"][data-variant="aurora"]::before {
  inset: -25%;
  background-image:
    radial-gradient(38% 46% at 22% 30%, color-mix(in oklch, var(--faqir-backdrop-a) 70%, transparent), transparent 72%),
    radial-gradient(34% 42% at 78% 24%, color-mix(in oklch, var(--faqir-backdrop-b) 62%, transparent), transparent 72%);
  filter: blur(var(--backdrop-blur, 3.5rem));
  animation-name: faqir-backdrop-drift;
}

[data-ui="backdrop"]:not([data-variant])::after,
[data-ui="backdrop"][data-variant="aurora"]::after {
  inset: -25%;
  background-image:
    radial-gradient(42% 50% at 58% 82%, color-mix(in oklch, var(--faqir-backdrop-c) 52%, transparent), transparent 72%),
    radial-gradient(30% 36% at 12% 78%, color-mix(in oklch, var(--faqir-backdrop-b) 46%, transparent), transparent 72%);
  filter: blur(var(--backdrop-blur, 3.5rem));
  animation-name: faqir-backdrop-drift;
  animation-direction: alternate-reverse;
  animation-duration: calc(var(--backdrop-duration, var(--motion-ambient-duration)) * 1.4);
}

/* ── Variant: spotlight ──
   One light from above, breathing; a cooler second light answers it from the
   side. The quietest variant with any motion in it. */
[data-ui="backdrop"][data-variant="spotlight"]::before {
  background-image: radial-gradient(55% 65% at 50% 0%, color-mix(in oklch, var(--faqir-backdrop-a) 60%, transparent), transparent 72%);
  transform-origin: center top;
  animation-name: faqir-backdrop-breathe;
  animation-duration: calc(var(--backdrop-duration, var(--motion-ambient-duration)) / 3);
}

[data-ui="backdrop"][data-variant="spotlight"]::after {
  background-image: radial-gradient(40% 45% at 85% 15%, color-mix(in oklch, var(--faqir-backdrop-b) 40%, transparent), transparent 72%);
  transform-origin: 85% 0%;
  animation-name: faqir-backdrop-breathe;
  animation-direction: alternate-reverse;
  animation-duration: calc(var(--backdrop-duration, var(--motion-ambient-duration)) / 2);
}

/* ── Variant: grid ──
   Graph paper that fades out from the top, drawn at the theme's own edge
   weight (`--border-width`), sliding one cell per lap so it never visibly
   repeats. The second layer is the accent glow the lines catch. */
[data-ui="backdrop"][data-variant="grid"]::before {
  background-image:
    linear-gradient(to right, color-mix(in oklch, var(--faqir-backdrop-ink) 16%, transparent) var(--border-width), transparent var(--border-width)),
    linear-gradient(to bottom, color-mix(in oklch, var(--faqir-backdrop-ink) 16%, transparent) var(--border-width), transparent var(--border-width));
  background-size: var(--backdrop-size, 3rem) var(--backdrop-size, 3rem);
  -webkit-mask-image: radial-gradient(ellipse 75% 70% at 50% 0%, black 25%, transparent 78%);
  mask-image: radial-gradient(ellipse 75% 70% at 50% 0%, black 25%, transparent 78%);
  animation-name: faqir-backdrop-pan;
  animation-timing-function: var(--ease-linear);
  animation-direction: normal;
  animation-duration: calc(var(--backdrop-duration, var(--motion-ambient-duration)) / 4);
}

/* ── Variant: dots ──
   The same idea in points: a dot field, one dot per cell. */
[data-ui="backdrop"][data-variant="dots"]::before {
  background-image: radial-gradient(circle at center, color-mix(in oklch, var(--faqir-backdrop-ink) 30%, transparent) calc(var(--border-width) * 1.25), transparent calc(var(--border-width) * 1.75));
  background-size: var(--backdrop-size, 1.5rem) var(--backdrop-size, 1.5rem);
  -webkit-mask-image: radial-gradient(ellipse 75% 70% at 50% 0%, black 25%, transparent 78%);
  mask-image: radial-gradient(ellipse 75% 70% at 50% 0%, black 25%, transparent 78%);
  animation-name: faqir-backdrop-pan;
  animation-timing-function: var(--ease-linear);
  animation-direction: normal;
  animation-duration: calc(var(--backdrop-duration, var(--motion-ambient-duration)) / 2);
}

[data-ui="backdrop"][data-variant="grid"]::after,
[data-ui="backdrop"][data-variant="dots"]::after {
  background-image: radial-gradient(50% 55% at 50% 0%, color-mix(in oklch, var(--faqir-backdrop-a) 45%, transparent), transparent 72%);
  transform-origin: center top;
  animation-name: faqir-backdrop-breathe;
  animation-duration: calc(var(--backdrop-duration, var(--motion-ambient-duration)) / 3);
}

/* ── Variant: beams ──
   Rays fanning down from above the top edge, swaying a few degrees. */
[data-ui="backdrop"][data-variant="beams"]::before {
  inset: -30% -20% 0;
  background-image: repeating-conic-gradient(from 150deg at 50% 0%, transparent 0deg, color-mix(in oklch, var(--faqir-backdrop-a) 34%, transparent) 5deg, transparent 11deg, color-mix(in oklch, var(--faqir-backdrop-b) 26%, transparent) 17deg, transparent 24deg);
  -webkit-mask-image: radial-gradient(ellipse 60% 85% at 50% 0%, black 10%, transparent 75%);
  mask-image: radial-gradient(ellipse 60% 85% at 50% 0%, black 10%, transparent 75%);
  filter: blur(var(--backdrop-blur, 0.5rem));
  transform-origin: center top;
  animation-name: faqir-backdrop-sway;
  animation-duration: calc(var(--backdrop-duration, var(--motion-ambient-duration)) / 2);
}

[data-ui="backdrop"][data-variant="beams"]::after {
  background-image: radial-gradient(45% 40% at 50% 0%, color-mix(in oklch, var(--faqir-backdrop-a) 50%, transparent), transparent 72%);
  transform-origin: center top;
  animation-name: faqir-backdrop-breathe;
  animation-duration: calc(var(--backdrop-duration, var(--motion-ambient-duration)) / 3);
}

/* ── Keyframes ── */
@keyframes faqir-backdrop-drift {
  from { translate: -4% -3%; rotate: -5deg; scale: 1; }
  to   { translate: 4% 3%; rotate: 7deg; scale: 1.12; }
}

@keyframes faqir-backdrop-breathe {
  from { scale: 1; opacity: calc(var(--backdrop-opacity, 0.55) * var(--faqir-backdrop-strength) * 0.7); }
  to   { scale: 1.15; }
}

@keyframes faqir-backdrop-pan {
  to { background-position: var(--backdrop-size, 3rem) var(--backdrop-size, 3rem); }
}

@keyframes faqir-backdrop-sway {
  from { rotate: -4deg; }
  to   { rotate: 4deg; }
}

/* ── Static ──
   The light without the movement — for a page that wants the mood and not
   the motion, or a section stacked under another animated one. */
[data-ui="backdrop"][data-static]::before,
[data-ui="backdrop"][data-static]::after {
  animation: none;
}

/* ── Motion ── */
@media (prefers-reduced-motion: reduce) {
  [data-ui="backdrop"]::before,
  [data-ui="backdrop"]::after {
    animation: none;
  }
}

/* ── Forced colours and print ──
   Decoration only: a high-contrast palette or a sheet of paper gets the
   content on a plain ground. */
@media (forced-colors: active), print {
  [data-ui="backdrop"]::before,
  [data-ui="backdrop"]::after {
    display: none;
  }
}


/* === primitives/badge.css === */
/* @ui:component badge */
/* @ui:tokens color-bg-muted color-fg color-primary color-primary-subtle color-secondary color-secondary-fg color-destructive color-destructive-subtle color-success color-success-subtle color-warning color-warning-subtle radius-full space-1 space-2 space-3 font-ui text-xs text-sm weight-medium corner-shape badge-radius badge-font motion-ambient-duration motion-ambient-play ease-in-out */

/* ── Base ── */
[data-ui="badge"] {
  display: inline-flex;
  vertical-align: bottom;
  align-items: center;
  gap: var(--space-1);
  padding: 0.125rem var(--space-2);
  border-radius: var(--badge-radius, var(--radius-full));
  corner-shape: var(--corner-shape);
  background: var(--color-bg-muted);
  color: var(--color-fg);
  font-family: var(--badge-font, var(--font-ui));
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  line-height: 1.5;
  white-space: nowrap;
}

/* ── Variants ── */
[data-ui="badge"][data-variant="primary"] {
  background: var(--color-primary-subtle);
  color: var(--color-primary);
}

[data-ui="badge"][data-variant="secondary"] {
  background: var(--color-secondary);
  color: var(--color-secondary-fg);
}

[data-ui="badge"][data-variant="destructive"] {
  background: var(--color-destructive-subtle);
  color: var(--color-destructive);
}

[data-ui="badge"][data-variant="success"] {
  background: var(--color-success-subtle);
  color: var(--color-success);
}

[data-ui="badge"][data-variant="warning"] {
  background: var(--color-warning-subtle);
  color: var(--color-warning);
}

/* ── Sizes ── */
[data-ui="badge"][data-size="sm"] {
  font-size: 0.625rem;
  padding: 0 var(--space-1);
}

[data-ui="badge"][data-size="lg"] {
  font-size: var(--text-sm);
  padding: 0.25rem var(--space-3, 0.75rem);
}

/* ── Live ──
   A dot before the text, breathing: "Live", "Online", "Recording". The dot
   takes the variant's colour (it is drawn in currentColor), so a success badge
   breathes green and a destructive one red. */
[data-ui="badge"][data-live]::before {
  content: "";
  position: relative;
  inline-size: 0.5em;
  block-size: 0.5em;
  border-radius: var(--radius-full);
  background-color: currentColor;
  flex-shrink: 0;
  animation: faqir-badge-live calc(var(--motion-ambient-duration) / 12) var(--ease-in-out) infinite alternate;
  animation-play-state: var(--motion-ambient-play);
}

@keyframes faqir-badge-live {
  from { opacity: 1; scale: 1; }
  to   { opacity: 0.45; scale: 0.8; }
}

@media (prefers-reduced-motion: reduce) {
  [data-ui="badge"][data-live]::before {
    animation: none;
  }
}


/* === primitives/button.css === */
/* @ui:component button */
/* @ui:tokens color-primary color-primary-hover color-primary-fg color-secondary color-secondary-hover color-secondary-fg color-destructive color-destructive-hover color-destructive-fg color-bg color-bg-muted color-bg-subtle color-fg color-border color-ring color-primary-subtle radius-md radius-full space-2 space-3 space-4 space-6 space-1 font-ui text-xs text-sm text-base weight-medium duration-fast duration-slower duration-normal ease-default ease-emphasized ease-out border-width border-width-strong border-width-md corner-shape focus-ring-width focus-ring-offset focus-ring-style focus-ring-color focus-shadow button-text-transform button-height-md button-radius button-height-sm button-height-lg motion-hover-lift motion-ambient-duration motion-ambient-play link-decoration disabled-opacity shadow-md shadow-lg shadow-xs */

/* ── Base ── */
[data-ui="button"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  height: var(--button-height-md, 40px);
  padding-inline: var(--space-4);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--button-radius, var(--radius-md));
  corner-shape: var(--corner-shape);
  background: var(--color-bg);
  color: var(--color-fg);
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  text-transform: var(--button-text-transform);
  line-height: 1;
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease-default),
              border-color var(--duration-fast) var(--ease-default),
              color var(--duration-fast) var(--ease-default),
              translate var(--duration-fast) var(--ease-default),
              box-shadow var(--duration-fast) var(--ease-default);
  user-select: none;
  white-space: nowrap;
  text-decoration: none;
}

[data-ui="button"]:hover {
  background: var(--color-bg-muted);
  /* The hover lift. `none` by default — the initial value of `translate` — so
     this rule computes what the button computed before the token existed; a
     theme with a springy personality sets `--motion-hover-lift: 0 -1px`. */
  translate: var(--motion-hover-lift);
}

[data-ui="button"]:focus-visible {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  outline-offset: var(--focus-ring-offset);
  box-shadow: var(--focus-shadow);
}

/* ── Variants ── */
[data-ui="button"][data-variant="primary"] {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: var(--color-primary-fg);
}
[data-ui="button"][data-variant="primary"]:hover {
  background: var(--color-primary-hover);
  border-color: var(--color-primary-hover);
}

[data-ui="button"][data-variant="secondary"] {
  background: var(--color-secondary);
  border-color: var(--color-secondary);
  color: var(--color-secondary-fg);
}
[data-ui="button"][data-variant="secondary"]:hover {
  background: var(--color-secondary-hover);
}

[data-ui="button"][data-variant="destructive"] {
  background: var(--color-destructive);
  border-color: var(--color-destructive);
  color: var(--color-destructive-fg);
}
[data-ui="button"][data-variant="destructive"]:hover {
  background: var(--color-destructive-hover);
  border-color: var(--color-destructive-hover);
}

[data-ui="button"][data-variant="ghost"] {
  background: transparent;
  border-color: transparent;
}
[data-ui="button"][data-variant="ghost"]:hover {
  background: var(--color-bg-muted);
}

[data-ui="button"][data-variant="outline"] {
  background: transparent;
}
[data-ui="button"][data-variant="outline"]:hover {
  background: var(--color-bg-subtle);
}

[data-ui="button"][data-variant="link"] {
  background: transparent;
  border-color: transparent;
  color: var(--color-primary);
  height: auto;
  padding: 0;
}
[data-ui="button"][data-variant="link"]:hover {
  text-decoration-line: var(--link-decoration);
}

/* ── Pressed — a toggle button, styled off aria-pressed, no JS ──
   For the unfilled variants only: default (with or without the attribute),
   outline and ghost. A filled variant has no room left to say "on" — its fill
   is already the loudest thing on the button — so it gets no pressed style;
   use the `toggle` primitive there. `:where()` keeps both rules at a variant
   rule's own specificity, so they win on order and a page can still override
   them with one more attribute. */
[data-ui="button"][aria-pressed="true"]:where(:not([data-variant]), [data-variant="default"], [data-variant="outline"], [data-variant="ghost"]) {
  background: var(--color-primary-subtle);
  border-color: var(--color-primary);
  color: var(--color-primary);
}
/* The twin: without it the variant's own :hover fill replaces the pressed one,
   and a pressed button under the pointer reads as released. */
[data-ui="button"][aria-pressed="true"]:where(:not([data-variant]), [data-variant="default"], [data-variant="outline"], [data-variant="ghost"]):hover {
  background: var(--color-primary-subtle);
}

/* ── Sizes ── */
[data-ui="button"][data-size="sm"] {
  height: var(--button-height-sm, 32px);
  padding-inline: var(--space-3);
  font-size: var(--text-xs);
}

[data-ui="button"][data-size="lg"] {
  height: var(--button-height-lg, 48px);
  padding-inline: var(--space-6);
  font-size: var(--text-base);
}

/* A link button is text at every size. The size rules above match with the
   link variant's own specificity and come later, so on their own they give it
   back a control's height and inline padding; this puts the two together the
   way they read — the size picks the font size, the box stays the text's. */
[data-ui="button"][data-variant="link"][data-size] {
  height: auto;
  padding-inline: 0;
}

/* ── States ── */
[data-ui="button"]:disabled,
[data-ui="button"][data-state="disabled"] {
  opacity: var(--disabled-opacity);
  cursor: not-allowed;
  pointer-events: none;
}

[data-ui="button"][data-state="loading"] {
  cursor: wait;
  color: transparent;
  position: relative;
}
[data-ui="button"][data-state="loading"]::after {
  content: "";
  position: absolute;
  width: 1em;
  height: 1em;
  border: var(--border-width-strong) solid currentColor;
  border-inline-end-color: transparent;
  border-radius: var(--radius-full);
  animation: faqir-spin 0.6s linear infinite;
  color: var(--color-fg);
}

/* ── Full Width ── */
[data-ui="button"][data-full] {
  width: 100%;
}

/* ── Parts ── */
[data-ui="button"] > [data-part="icon"] {
  display: inline-flex;
  width: 1em;
  height: 1em;
  flex-shrink: 0;
}

/* ── Button Group ── */
[data-ui="button-group"] {
  display: inline-flex;
}
[data-ui="button-group"] [data-ui="button"]:not(:first-child) {
  border-start-start-radius: 0;
  border-end-start-radius: 0;
  margin-inline-start: -1px;
}
[data-ui="button-group"] [data-ui="button"]:not(:last-child) {
  border-start-end-radius: 0;
  border-end-end-radius: 0;
}

/* ── Forced colors (Windows High Contrast) ──
   Pressed is carried by colour alone, and the OS replaces all three colours
   with the ones every other button gets. System colours are the ones it keeps.
   The :hover twin is listed too: it is the more specific rule, and its
   `--color-primary-subtle` would be forced back to the plain button face
   under HighlightText. */
@media (forced-colors: active) {
  [data-ui="button"][aria-pressed="true"]:where(:not([data-variant]), [data-variant="default"], [data-variant="outline"], [data-variant="ghost"]),
  [data-ui="button"][aria-pressed="true"]:where(:not([data-variant]), [data-variant="default"], [data-variant="outline"], [data-variant="ghost"]):hover {
    background: Highlight;
    border-color: Highlight;
    color: HighlightText;
  }
}

/* ── Motion ── */
@media (prefers-reduced-motion: reduce) {
  [data-ui="button"] {
    transition: none;
  }
}

@keyframes faqir-spin {
  to { transform: rotate(360deg); }
}

/* ── Effects ──
   Attention a button can ask for, one at a time, on top of any variant.
   `shine` sweeps a highlight across the face on hover — the sheen on a glossy
   key; `pulse` sends a ring out from the edge on a loop, for the one action on
   the screen that is waiting on the reader; `press` sinks under the pointer;
   `arrow` leans the trailing icon toward the inline end, the "go" cue on a
   call to action; `sink` is the neo-brutalist press, a resting offset shadow
   the button lifts off on hover and is pushed flush into on :active.
   The ring is drawn by ::before (::after belongs to the loading spinner) and
   the sheen clips to the face, so neither reaches past the border. */
[data-ui="button"][data-effect] {
  position: relative;
  isolation: isolate;
}

[data-ui="button"][data-effect="shine"] {
  overflow: hidden;
}

[data-ui="button"][data-effect="shine"]::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background-image: linear-gradient(115deg, transparent 35%, color-mix(in oklch, var(--color-primary-fg) 35%, transparent) 50%, transparent 65%);
  translate: -100% 0;
  transition: translate var(--duration-slower) var(--ease-emphasized);
}

[data-ui="button"][data-effect="shine"]:hover::before,
[data-ui="button"][data-effect="shine"]:focus-visible::before {
  translate: 100% 0;
}

[data-ui="button"][data-effect="pulse"]::before {
  content: "";
  position: absolute;
  inset: calc(var(--border-width) * -1);
  z-index: -1;
  border: var(--border-width-md) solid var(--color-primary);
  border-radius: inherit;
  animation: faqir-button-pulse calc(var(--motion-ambient-duration) / 10) var(--ease-out) infinite;
  animation-play-state: var(--motion-ambient-play);
}

@keyframes faqir-button-pulse {
  from { scale: 1; opacity: 0.8; }
  to   { scale: 1.35; opacity: 0; }
}

[data-ui="button"][data-effect="press"] {
  transition:
    background var(--duration-fast) var(--ease-default),
    border-color var(--duration-fast) var(--ease-default),
    color var(--duration-fast) var(--ease-default),
    translate var(--duration-fast) var(--ease-default),
    scale var(--duration-fast) var(--ease-default),
    box-shadow var(--duration-fast) var(--ease-default);
}

[data-ui="button"][data-effect="press"]:active {
  scale: 0.96;
}

@media (prefers-reduced-motion: reduce) {
  [data-ui="button"][data-effect="shine"]::before {
    display: none;
  }

  [data-ui="button"][data-effect="pulse"]::before {
    animation: none;
    opacity: 0;
  }

  [data-ui="button"][data-effect="press"]:active {
    scale: none;
  }
}

/* ── Effect: arrow ──
   The last icon child leans toward the inline end on hover and keyboard focus:
   `Get started →` going where it says. The nudge is a private custom property
   so right-to-left flips it in one place; the icon is whatever the page put
   there (an arrow-right glyph, ordinarily). The movement lives wholly in the
   no-preference query, so under reduced motion the icon simply stays put. */
[data-ui="button"][data-effect="arrow"] {
  --faqir-button-nudge: var(--space-1);
}

[data-ui="button"][data-effect="arrow"]:dir(rtl) {
  --faqir-button-nudge: calc(var(--space-1) * -1);
}

/* In right-to-left the glyph is mirrored, so an arrow-right points the way it
   moves. The effect is for a TRAILING icon: CSS cannot see the text beside an
   icon, so a button whose only icon leads (`★ Save`) would nudge it too —
   the manifest says so, and such a button wants no arrow effect. */
[data-ui="button"][data-effect="arrow"]:dir(rtl) > [data-part="icon"]:last-child {
  scale: -1 1;
}

@media (prefers-reduced-motion: no-preference) {
  [data-ui="button"][data-effect="arrow"] > [data-part="icon"]:last-child {
    transition: translate var(--duration-normal) var(--ease-emphasized);
  }

  [data-ui="button"][data-effect="arrow"]:hover > [data-part="icon"]:last-child,
  [data-ui="button"][data-effect="arrow"]:focus-visible > [data-part="icon"]:last-child {
    translate: var(--faqir-button-nudge) 0;
  }
}

/* ── Effect: sink ──
   Depth you can push. At rest the button carries the theme's own shadow, so a
   hard-depth theme (neo: `3px 3px 0`) draws a hard offset and a soft theme a
   soft one. On hover the button lifts off it, up and back by the sink distance
   while the shadow steps up a size, which keeps a hard shadow's tip where it
   was. On :active (the pointer, or Space held on the keyboard) the
   shadow collapses to its smallest step and the button travels the same
   distance the other way, flush into the page.
   `--sink-distance` is the travel (half a --space-1 by default) and
   `--sink-shadow` replaces the resting and hover shadow, for a theme
   that states none (brutalist sets every --shadow-* to none). The base focus
   rule writes --focus-shadow to the same property; sink keeps its depth and
   lets the focus outline, which it does not touch, mark focus.
   Reduced motion: the base rule already drops every transition, so the states
   change instantly. The shadow and the offset remain the feedback. */
[data-ui="button"][data-effect="sink"] {
  --faqir-button-sink: var(--sink-distance, calc(var(--space-1) / 2));
  box-shadow: var(--sink-shadow, var(--shadow-md));
}

[data-ui="button"][data-effect="sink"]:hover {
  box-shadow: var(--sink-shadow, var(--shadow-lg));
  translate: calc(var(--faqir-button-sink) * -1) calc(var(--faqir-button-sink) * -1);
}

[data-ui="button"][data-effect="sink"]:active {
  box-shadow: var(--shadow-xs);
  translate: var(--faqir-button-sink) var(--faqir-button-sink);
}


/* === primitives/callout.css === */
/* @ui:component callout */
/* @ui:tokens color-fg color-fg-muted color-info color-info-subtle color-warning color-warning-subtle color-destructive color-destructive-subtle color-success color-success-subtle color-border color-ring space-1 space-3 space-4 space-2 radius-sm radius-md text-sm font-heading font-body weight-semibold focus-ring-width focus-ring-offset focus-ring-style focus-ring-color focus-shadow callout-padding-y callout-padding-x callout-radius callout-border-left-width callout-font-size callout-icon-size callout-fg callout-bg callout-border-width doc-font doc-line-height doc-label-gap doc-print-border-color */

/* ── Base ── */
[data-ui="callout"] {
  display: flex;
  gap: var(--callout-padding-y);
  padding: var(--callout-padding-y) var(--callout-padding-x);
  border-radius: var(--callout-radius);
  border-inline-start: var(--callout-border-left-width) solid;
  font-family: var(--doc-font, var(--font-body));
  font-size: var(--callout-font-size);
  line-height: var(--doc-line-height, 1.5);
}

/* Parts are reached by child combinators: a callout nested in another's
   content keeps its own icon colour (a warning used to recolour the icon of
   an info callout inside it), and so does any component with an `icon` or a
   `title`. The `content` hop before the title is `:where()` so the rule keeps
   its specificity. Paragraph spacing stays a descendant rule on purpose: it
   targets prose, not a part. [1.1F-20] */

/* ── Icon ── */
[data-ui="callout"] > [data-part="icon"] {
  flex-shrink: 0;
  display: flex;
  align-items: flex-start;
  padding-top: 1px;
  font-size: var(--callout-icon-size);
}

/* ── Content ── */
[data-ui="callout"] > [data-part="content"] {
  flex: 1;
  min-width: 0;
}

[data-ui="callout"] > [data-part="content"] p {
  margin: 0;
}

[data-ui="callout"] > [data-part="content"] p + p {
  margin-top: var(--space-2, 0.5rem);
}

/* ── Title ── */
[data-ui="callout"] > :where([data-part="content"]) > [data-part="title"] {
  display: block;
  font-family: var(--font-heading);
  font-weight: var(--weight-semibold);
  margin-bottom: var(--doc-label-gap, var(--space-1, 0.25rem));
}

/* ── Dismiss (optional close button) ── */
[data-ui="callout"] > [data-part="dismiss"] {
  flex-shrink: 0;
  align-self: flex-start;
  margin-inline-start: auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-1, 0.25rem);
  border: none;
  border-radius: var(--radius-sm, 4px);
  background: transparent;
  color: inherit;
  opacity: 0.65;
  cursor: pointer;
}

[data-ui="callout"] > [data-part="dismiss"]:hover {
  opacity: 1;
}

[data-ui="callout"] > [data-part="dismiss"]:focus-visible {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  outline-offset: var(--focus-ring-offset);
  box-shadow: var(--focus-shadow);
  opacity: 1;
}

/* ── Variant: Info (default) ── */
[data-ui="callout"][data-variant="info"],
[data-ui="callout"]:not([data-variant]) {
  border-inline-start-color: var(--color-info, oklch(0.55 0.18 240));
  background: var(--color-info-subtle, oklch(0.96 0.03 240));
  color: var(--callout-fg);
}

[data-ui="callout"][data-variant="info"] > [data-part="icon"],
[data-ui="callout"]:not([data-variant]) > [data-part="icon"] {
  color: var(--color-info, oklch(0.55 0.18 240));
}

/* ── Variant: Warning ── */
[data-ui="callout"][data-variant="warning"] {
  border-inline-start-color: var(--color-warning, oklch(0.72 0.17 70));
  background: var(--color-warning-subtle, oklch(0.97 0.04 85));
  color: var(--callout-fg);
}

[data-ui="callout"][data-variant="warning"] > [data-part="icon"] {
  color: var(--color-warning, oklch(0.72 0.17 70));
}

/* ── Variant: Destructive ── */
[data-ui="callout"][data-variant="destructive"] {
  border-inline-start-color: var(--color-destructive, oklch(0.58 0.22 27));
  background: var(--color-destructive-subtle, oklch(0.97 0.03 25));
  color: var(--callout-fg);
}

[data-ui="callout"][data-variant="destructive"] > [data-part="icon"] {
  color: var(--color-destructive, oklch(0.58 0.22 27));
}

/* ── Variant: Success ── */
[data-ui="callout"][data-variant="success"] {
  border-inline-start-color: var(--color-success, oklch(0.62 0.19 145));
  background: var(--color-success-subtle, oklch(0.97 0.03 150));
  color: var(--callout-fg);
}

[data-ui="callout"][data-variant="success"] > [data-part="icon"] {
  color: var(--color-success, oklch(0.62 0.19 145));
}

/* ── Variant: Muted ── */
[data-ui="callout"][data-variant="muted"] {
  /* A semantic foreground keeps the legal/disclaimer accent visible even when
     a theme makes its ordinary hairline border blend into the surface. */
  border-inline-start-color: var(--color-fg-muted);
  background: var(--callout-bg);
  color: var(--color-fg-muted);
}

[data-ui="callout"][data-variant="muted"] > [data-part="icon"] {
  color: var(--color-fg-muted);
}

/* ── Print ── */
@media print {
  [data-ui="callout"] {
    background: none;
    border: var(--callout-border-width) solid var(--doc-print-border-color, var(--color-border, #ccc));
    border-inline-start: var(--callout-border-left-width) solid;
    break-inside: avoid;
  }

  /* Match the variant selectors' specificity without relying on !important. */
  [data-ui="callout"][data-variant],
  [data-ui="callout"]:not([data-variant]) {
    background: none;
  }

  /* Interactive dismiss control is meaningless on paper. */
  [data-ui="callout"] > [data-part="dismiss"] {
    display: none;
  }
}


/* === primitives/card.css === */
/* @ui:component card */
/* @ui:tokens color-surface-1 color-surface-2 color-surface-1-border color-surface-2-border color-fg color-fg-muted color-bg-muted color-primary radius-lg shadow-sm space-1 space-2 space-4 space-6 font-heading text-sm text-lg weight-semibold leading-tight border-width corner-shape card-border-width card-border card-radius card-bg card-shadow card-padding card-media-ratio card-hover-shadow surface-backdrop texture-surface motion-hover-lift duration-fast duration-slower duration-normal ease-default ease-emphasized ease-out section-gap-sm */

/* ── Base ── */
[data-ui="card"] {
  display: flex;
  flex-direction: column;
  border: var(--card-border-width) solid var(--card-border, var(--color-surface-1-border));
  border-radius: var(--card-radius, var(--radius-lg));
  corner-shape: var(--corner-shape);
  /* One shorthand, two layers: the material on top, the fill beneath. The fill
     is the final layer, so `--card-bg` may be a colour OR a gradient — what 1.0
     projects set it to — and the texture (`none` by default) never clobbers it. */
  background: var(--texture-surface), var(--card-bg, var(--color-surface-1));
  box-shadow: var(--card-shadow, var(--shadow-sm));
  overflow: hidden;
  transition: translate var(--duration-fast) var(--ease-default);
}

/* The hover lift, the same axis `button` reads. `none` by default (the initial
   value of `translate`), so a card sits exactly where it always sat until a
   theme says surfaces rise under the pointer. */
[data-ui="card"]:hover {
  translate: var(--motion-hover-lift);
}

@supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
  [data-ui="card"] {
    -webkit-backdrop-filter: var(--surface-backdrop);
    backdrop-filter: var(--surface-backdrop);
  }
}

/* ── Variants ── */
[data-ui="card"][data-variant="outlined"] {
  box-shadow: none;
}

[data-ui="card"][data-variant="filled"] {
  background: var(--texture-surface), var(--color-surface-2);
  border-color: var(--color-surface-2-border);
  box-shadow: none;
}

/* ── Parts ── */
[data-ui="card"] > [data-part="header"] {
  display: flex;
  flex-direction: column;
  gap: var(--space-1, 0.25rem);
  padding: var(--card-padding, var(--space-6));
  padding-bottom: 0;
}

[data-ui="card"] > [data-part="header"] > [data-part="title"],
[data-ui="card"] > [data-part="title"] {
  font-family: var(--font-heading);
  font-size: var(--text-lg);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-tight);
  color: var(--color-fg);
  margin: 0;
}

[data-ui="card"] > [data-part="header"] > [data-part="description"],
[data-ui="card"] > [data-part="description"] {
  font-size: var(--text-sm);
  color: var(--color-fg-muted);
  margin: 0;
}

/* The header is optional: a title and description written straight into the
   card (the shape @faqir-ui/forms emits for each wizard step) take the header's
   inset themselves instead of sitting flush against the border. */
[data-ui="card"] > [data-part="title"],
[data-ui="card"] > [data-part="description"] {
  padding-inline: var(--card-padding, var(--space-6));
}

[data-ui="card"] > [data-part="title"] {
  padding-block-start: var(--card-padding, var(--space-6));
}

[data-ui="card"] > [data-part="description"] {
  padding-block-start: var(--space-1, 0.25rem);
}

[data-ui="card"] > [data-part="body"] {
  padding: var(--card-padding, var(--space-6));
  flex: 1;
}

/* ── A fieldset card ──
   @faqir-ui/forms renders a group as <fieldset data-ui="card"> with a
   <legend data-part="title">. A fieldset brings the browser's margin, padding
   and min-content width, and its first legend sits ON the top border, cutting
   a notch into it. Reset, the box is the card's own; floated, the legend is no
   longer the fieldset's rendered legend but the card's first row, full width
   and inset like a title written straight into the card (above). */
fieldset[data-ui="card"] {
  min-inline-size: 0;
  margin: 0;
  padding: 0;
}

fieldset[data-ui="card"] > legend[data-part="title"] {
  float: inline-start;
  inline-size: 100%;
}

fieldset[data-ui="card"] > legend[data-part="title"] ~ * {
  clear: both;
}

/* ── Inside a form: the body keeps the form's field rhythm ──
   A card body is not a flow root (base/rhythm.css), so the fields of a
   ui:groups fieldset or a wizard step touched while the form's own fields
   stood --flow-space apart. Inside a form, a body's field-groups and nested
   cards take the same step: the form's data-gap, inherited as --flow-space.
   Weightless and scoped to forms, so a card anywhere else is untouched. */
:where(form [data-ui="card"] > [data-part="body"] > :is([data-ui="field-group"], [data-ui="card"]) + :is([data-ui="field-group"], [data-ui="card"])) {
  margin-block-start: var(--flow-space, var(--section-gap-sm));
}

[data-ui="card"] > [data-part="footer"] {
  display: flex;
  align-items: center;
  gap: var(--space-2, 0.5rem);
  padding: var(--card-padding, var(--space-6));
  padding-top: 0;
  justify-content: flex-end;
}

/* ── Sizes ── */
[data-ui="card"][data-size="sm"] > [data-part="header"],
[data-ui="card"][data-size="sm"] > [data-part="body"],
[data-ui="card"][data-size="sm"] > [data-part="footer"] {
  padding: var(--space-4);
}
[data-ui="card"][data-size="sm"] > [data-part="header"] {
  padding-bottom: 0;
}
[data-ui="card"][data-size="sm"] > [data-part="footer"] {
  padding-top: 0;
}

/* ── Motion ── */
/* The hover lift is the only thing a card animates, and it is `none` until a
   theme states one — but the house rule is that a stylesheet which transitions
   carries its own opt-out, so a reader never has to check the token first. */
@media (prefers-reduced-motion: reduce) {
  [data-ui="card"] {
    transition: none;
  }
}

/* ── Media ──
   A picture across the top of the card: full bleed to the card's edges, cut to
   `--card-media-ratio`, the image covering the frame. The figure is the part;
   the image inside is the content. */
[data-ui="card"] > [data-part="media"] {
  margin: 0;
  overflow: hidden;
  aspect-ratio: var(--card-media-ratio);
  background-color: var(--color-bg-muted);
}

[data-ui="card"] > :where([data-part="media"]) > img {
  display: block;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  transition: scale var(--duration-slower) var(--ease-emphasized);
}

/* ── Hover ──
   What a card does under the pointer, beyond the theme's lift. Each value is
   one gesture, stated once: `lift` rises by a step of the spacing scale, `raise`
   climbs the shadow ramp, `tint` draws the accent along its edge, and `zoom`
   leans into its own picture. Every one also answers to focus-within, so a
   card holding a link signals the same way from the keyboard. */
[data-ui="card"][data-hover] {
  transition:
    translate var(--duration-normal) var(--ease-out),
    box-shadow var(--duration-normal) var(--ease-out),
    border-color var(--duration-normal) var(--ease-out);
}

[data-ui="card"][data-hover="lift"]:hover,
[data-ui="card"][data-hover="lift"]:focus-within {
  translate: 0 calc(var(--space-1) * -1);
}

[data-ui="card"][data-hover="raise"]:hover,
[data-ui="card"][data-hover="raise"]:focus-within {
  translate: 0 calc(var(--space-1) * -1);
  box-shadow: var(--card-hover-shadow);
}

[data-ui="card"][data-hover="tint"]:hover,
[data-ui="card"][data-hover="tint"]:focus-within {
  border-color: var(--color-primary);
}

[data-ui="card"][data-hover="zoom"]:hover > :where([data-part="media"]) > img,
[data-ui="card"][data-hover="zoom"]:focus-within > :where([data-part="media"]) > img {
  scale: 1.05;
}

@media (prefers-reduced-motion: reduce) {
  [data-ui="card"][data-hover],
  [data-ui="card"] > :where([data-part="media"]) > img {
    transition: none;
  }
}


/* === primitives/checkbox.css === */
/* @ui:component checkbox */
/* @ui:tokens color-bg color-primary color-primary-fg color-border color-border-strong color-ring space-2 space-4 duration-fast ease-default border-width focus-ring-width focus-ring-offset focus-ring-style focus-ring-color focus-shadow checkbox-radius checkbox-size disabled-opacity */

/* -- Checkbox group --
   The wrapper for checkboxes that answer one question: a fieldset with its
   legend, or a role="group" element labelled by its field's label (what
   @faqir-ui/forms renders). The same shape as radio-group: a column, or a
   wrapping row with data-orientation="horizontal". */
[data-ui="checkbox-group"] {
  border: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

[data-ui="checkbox-group"][data-orientation="horizontal"] {
  flex-direction: row;
  flex-wrap: wrap;
  column-gap: var(--space-4);
}

/* -- Label wrapper -- */
[data-ui="checkbox-label"] {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  cursor: pointer;
}

[data-ui="checkbox-label"]:has([data-ui="checkbox"]:disabled) {
  cursor: not-allowed;
  opacity: var(--disabled-opacity);
}

/* -- Base -- */
[data-ui="checkbox"] {
  appearance: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--checkbox-size, 18px);
  height: var(--checkbox-size, 18px);
  flex-shrink: 0;
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--checkbox-radius);
  background: var(--color-bg);
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease-default),
              border-color var(--duration-fast) var(--ease-default),
              box-shadow var(--duration-fast) var(--ease-default);
}

[data-ui="checkbox"]:hover {
  border-color: var(--color-border-strong);
}

[data-ui="checkbox"]:focus-visible {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  outline-offset: var(--focus-ring-offset);
  box-shadow: var(--focus-shadow);
}

/* -- Checked -- */
[data-ui="checkbox"]:checked {
  background: var(--color-primary);
  border-color: var(--color-primary);
}

/* The tick is a MASK, not an image.
   A data-URI `stroke` is a literal no token can reach, and it shipped as
   `white`: 1.00:1 — literally invisible — on the brutalist dark primary, and
   under 3:1 in 8 of 12 dark themes. Masking paints the same glyph in
   `--color-primary-fg`, which is the token that already answers "what colour
   goes on top of --color-primary" — exactly what the indeterminate bar twenty
   lines below has always done. The mask's own stroke colour is irrelevant
   (only its alpha is read), so it is a plain opaque black. Same
   prefixed+unprefixed pair the `icon` primitive uses. [W3-3] */
[data-ui="checkbox"]:checked::before {
  content: "";
  display: block;
  width: 10px;
  height: 10px;
  background: var(--color-primary-fg);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E") center / contain no-repeat;
}

/* -- Indeterminate -- */
[data-ui="checkbox"]:indeterminate,
[data-ui="checkbox"][data-state="indeterminate"] {
  background: var(--color-primary);
  border-color: var(--color-primary);
}

[data-ui="checkbox"]:indeterminate::before,
[data-ui="checkbox"][data-state="indeterminate"]::before {
  content: "";
  display: block;
  width: 8px;
  height: 2px;
  background: var(--color-primary-fg);
  border-radius: 1px;
}

/* -- Sizes -- */
[data-ui="checkbox"][data-size="sm"] {
  width: 14px;
  height: 14px;
}
[data-ui="checkbox"][data-size="sm"]:checked::before {
  width: 8px;
  height: 8px;
}
[data-ui="checkbox"][data-size="sm"]:indeterminate::before,
[data-ui="checkbox"][data-size="sm"][data-state="indeterminate"]::before {
  width: 6px;
}

[data-ui="checkbox"][data-size="lg"] {
  width: 22px;
  height: 22px;
}
[data-ui="checkbox"][data-size="lg"]:checked::before {
  width: 14px;
  height: 14px;
}
[data-ui="checkbox"][data-size="lg"]:indeterminate::before,
[data-ui="checkbox"][data-size="lg"][data-state="indeterminate"]::before {
  width: 10px;
  height: 2px;
}

/* -- Disabled -- */
[data-ui="checkbox"]:disabled {
  cursor: not-allowed;
}

/* -- Motion -- */
@media (prefers-reduced-motion: reduce) {
  [data-ui="checkbox"] {
    transition: none;
  }
}

/* ── Forced colors (Windows High Contrast) ──
   `--color-primary` becomes the system fill, and the tick — painted through a
   mask in `--color-primary-fg` — becomes the same colour as the box it sits in.
   The mask has to opt out of the substitution to stay readable. [W3-3] */
@media (forced-colors: active) {
  [data-ui="checkbox"] {
    border: var(--border-width) solid ButtonText;
  }

  [data-ui="checkbox"]:checked,
  [data-ui="checkbox"]:indeterminate,
  [data-ui="checkbox"][data-state="indeterminate"] {
    background: Highlight;
    border-color: Highlight;
  }

  [data-ui="checkbox"]:checked::before,
  [data-ui="checkbox"]:indeterminate::before,
  [data-ui="checkbox"][data-state="indeterminate"]::before {
    forced-color-adjust: none;
    background: HighlightText;
  }

  [data-ui="checkbox"]:disabled {
    border-color: GrayText;
  }
}


/* === primitives/chip.css === */
/* @ui:component chip */
/* @ui:tokens color-bg-muted color-fg color-fg-muted color-primary color-primary-subtle color-destructive color-destructive-subtle color-border color-ring radius-full space-1 space-2 space-3 font-ui text-xs text-sm weight-medium border-width focus-ring-width focus-ring-offset focus-ring-style focus-ring-color focus-shadow */

/* ── Base ── */
[data-ui="chip"] {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-1) var(--space-2);
  border: var(--border-width) solid transparent;
  border-radius: var(--chip-radius, var(--radius-full));
  background: var(--color-bg-muted);
  color: var(--color-fg);
  font-family: var(--chip-font, var(--font-ui));
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  line-height: 1.2;
  white-space: nowrap;
}

[data-ui="chip"] > [data-part="label"] {
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ── Dismiss ── */
[data-ui="chip"] > [data-part="dismiss"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.25em;
  height: 1.25em;
  padding: 0;
  margin-inline-end: calc(var(--space-1) * -1);
  border: none;
  border-radius: var(--radius-full);
  background: transparent;
  color: var(--color-fg-muted);
  font: inherit;
  line-height: 1;
  cursor: pointer;
}

[data-ui="chip"] > [data-part="dismiss"]:hover {
  background: var(--color-border);
  color: var(--color-fg);
}

[data-ui="chip"] > [data-part="dismiss"]:focus-visible {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  /* Half the default gap — the dismiss target is small, and the full ring
     would collide with the chip's own edge. */
  outline-offset: calc(var(--focus-ring-offset) / 2);
  box-shadow: var(--focus-shadow);
}

/* ── Variants ── */
[data-ui="chip"][data-variant="primary"] {
  background: var(--color-primary-subtle);
  color: var(--color-primary);
}

[data-ui="chip"][data-variant="primary"] > [data-part="dismiss"] {
  color: var(--color-primary);
}

[data-ui="chip"][data-variant="outline"] {
  background: transparent;
  border-color: var(--color-border);
}

[data-ui="chip"][data-variant="destructive"] {
  background: var(--color-destructive-subtle);
  color: var(--color-destructive);
}

[data-ui="chip"][data-variant="destructive"] > [data-part="dismiss"] {
  color: var(--color-destructive);
}

/* ── Sizes ── */
[data-ui="chip"][data-size="sm"] {
  padding: 0 var(--space-2);
  font-size: var(--text-xs);
}

[data-ui="chip"][data-size="lg"] {
  padding: var(--space-1) var(--space-3);
  font-size: var(--text-sm);
}


/* === primitives/cluster.css === */
/* @ui:component cluster */
/* @ui:tokens space-0 space-1 space-2 space-3 space-4 space-6 space-8 space-10 space-12 space-16 */

/* The wrapping inline row (task 0.8-05).
 *
 * A cluster is a row of things that belong together and are allowed to reflow:
 * a tag row, a button row, a meta row. Its responsiveness is INTRINSIC —
 * `flex-wrap: wrap` needs no threshold, so a cluster is correct at every width,
 * including widths nobody tested (FAQIR-SPEC §15 doctrine 1). That is the whole
 * reason it exists as its own primitive rather than as a stack with a flag: the
 * wrap is not a variant of the row, it IS the row.
 *
 * Gap, alignment and justification are responsive variant groups on the canon
 * tiers (`data-gap-md`, `data-align-lg`, …) for the cases where a cluster wants
 * to breathe differently on a wide page. Tier precedence is encoded in
 * SPECIFICITY, not source order — each tier block repeats `[data-ui="cluster"]`
 * once more than the tier below it, base (0,2,0) → xl (0,6,0) — so a bundler
 * that reorders or splits blocks cannot change which tier wins (the mechanism
 * grid 2.0 introduced in task 0.8-04).
 */

/* ── Base ──
 * Wrapping, centred on the cross axis, one spacing step apart. A bare
 * `<div data-ui="cluster">` is already the row you wanted; the attributes only
 * tune it. Declared at (0,1,0) so every attribute rule below overrides it. */
[data-ui="cluster"] {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

/* ── Gap ── */
[data-ui="cluster"][data-gap="0"] { gap: var(--space-0, 0px); }
[data-ui="cluster"][data-gap="1"] { gap: var(--space-1); }
[data-ui="cluster"][data-gap="2"] { gap: var(--space-2); }
[data-ui="cluster"][data-gap="3"] { gap: var(--space-3); }
[data-ui="cluster"][data-gap="4"] { gap: var(--space-4); }
[data-ui="cluster"][data-gap="6"] { gap: var(--space-6); }
[data-ui="cluster"][data-gap="8"] { gap: var(--space-8); }
[data-ui="cluster"][data-gap="10"] { gap: var(--space-10); }
[data-ui="cluster"][data-gap="12"] { gap: var(--space-12); }
[data-ui="cluster"][data-gap="16"] { gap: var(--space-16); }

/* ── Alignment (cross axis) ── */
[data-ui="cluster"][data-align="start"] { align-items: flex-start; }
[data-ui="cluster"][data-align="center"] { align-items: center; }
[data-ui="cluster"][data-align="end"] { align-items: flex-end; }
[data-ui="cluster"][data-align="stretch"] { align-items: stretch; }
[data-ui="cluster"][data-align="baseline"] { align-items: baseline; }

/* ── Justification (main axis) ── */
[data-ui="cluster"][data-justify="start"] { justify-content: flex-start; }
[data-ui="cluster"][data-justify="center"] { justify-content: center; }
[data-ui="cluster"][data-justify="end"] { justify-content: flex-end; }
[data-ui="cluster"][data-justify="between"] { justify-content: space-between; }
[data-ui="cluster"][data-justify="around"] { justify-content: space-around; }

/* ── Child push ──
 * `data-push` on a child sends it — and everything after it — to the far end of
 * the row: the "actions on the right" idiom, written once. Logical, so it is the
 * far end in Arabic and Hebrew too. */
[data-ui="cluster"] > [data-push] {
  margin-inline-start: auto;
}

/* ── Tier `sm` — from 40rem up ── */
@media (min-width: 40rem) {
  /* Gap */
  [data-ui="cluster"][data-ui="cluster"][data-gap-sm="0"] { gap: var(--space-0, 0px); }
  [data-ui="cluster"][data-ui="cluster"][data-gap-sm="1"] { gap: var(--space-1); }
  [data-ui="cluster"][data-ui="cluster"][data-gap-sm="2"] { gap: var(--space-2); }
  [data-ui="cluster"][data-ui="cluster"][data-gap-sm="3"] { gap: var(--space-3); }
  [data-ui="cluster"][data-ui="cluster"][data-gap-sm="4"] { gap: var(--space-4); }
  [data-ui="cluster"][data-ui="cluster"][data-gap-sm="6"] { gap: var(--space-6); }
  [data-ui="cluster"][data-ui="cluster"][data-gap-sm="8"] { gap: var(--space-8); }
  [data-ui="cluster"][data-ui="cluster"][data-gap-sm="10"] { gap: var(--space-10); }
  [data-ui="cluster"][data-ui="cluster"][data-gap-sm="12"] { gap: var(--space-12); }
  [data-ui="cluster"][data-ui="cluster"][data-gap-sm="16"] { gap: var(--space-16); }

  /* Alignment (cross axis) */
  [data-ui="cluster"][data-ui="cluster"][data-align-sm="start"] { align-items: flex-start; }
  [data-ui="cluster"][data-ui="cluster"][data-align-sm="center"] { align-items: center; }
  [data-ui="cluster"][data-ui="cluster"][data-align-sm="end"] { align-items: flex-end; }
  [data-ui="cluster"][data-ui="cluster"][data-align-sm="stretch"] { align-items: stretch; }
  [data-ui="cluster"][data-ui="cluster"][data-align-sm="baseline"] { align-items: baseline; }

  /* Justification (main axis) */
  [data-ui="cluster"][data-ui="cluster"][data-justify-sm="start"] { justify-content: flex-start; }
  [data-ui="cluster"][data-ui="cluster"][data-justify-sm="center"] { justify-content: center; }
  [data-ui="cluster"][data-ui="cluster"][data-justify-sm="end"] { justify-content: flex-end; }
  [data-ui="cluster"][data-ui="cluster"][data-justify-sm="between"] { justify-content: space-between; }
  [data-ui="cluster"][data-ui="cluster"][data-justify-sm="around"] { justify-content: space-around; }
}

/* ── Tier `md` — from 48rem up ── */
@media (min-width: 48rem) {
  /* Gap */
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-gap-md="0"] { gap: var(--space-0, 0px); }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-gap-md="1"] { gap: var(--space-1); }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-gap-md="2"] { gap: var(--space-2); }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-gap-md="3"] { gap: var(--space-3); }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-gap-md="4"] { gap: var(--space-4); }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-gap-md="6"] { gap: var(--space-6); }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-gap-md="8"] { gap: var(--space-8); }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-gap-md="10"] { gap: var(--space-10); }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-gap-md="12"] { gap: var(--space-12); }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-gap-md="16"] { gap: var(--space-16); }

  /* Alignment (cross axis) */
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-align-md="start"] { align-items: flex-start; }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-align-md="center"] { align-items: center; }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-align-md="end"] { align-items: flex-end; }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-align-md="stretch"] { align-items: stretch; }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-align-md="baseline"] { align-items: baseline; }

  /* Justification (main axis) */
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-justify-md="start"] { justify-content: flex-start; }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-justify-md="center"] { justify-content: center; }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-justify-md="end"] { justify-content: flex-end; }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-justify-md="between"] { justify-content: space-between; }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-justify-md="around"] { justify-content: space-around; }
}

/* ── Tier `lg` — from 64rem up ── */
@media (min-width: 64rem) {
  /* Gap */
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-gap-lg="0"] { gap: var(--space-0, 0px); }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-gap-lg="1"] { gap: var(--space-1); }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-gap-lg="2"] { gap: var(--space-2); }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-gap-lg="3"] { gap: var(--space-3); }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-gap-lg="4"] { gap: var(--space-4); }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-gap-lg="6"] { gap: var(--space-6); }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-gap-lg="8"] { gap: var(--space-8); }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-gap-lg="10"] { gap: var(--space-10); }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-gap-lg="12"] { gap: var(--space-12); }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-gap-lg="16"] { gap: var(--space-16); }

  /* Alignment (cross axis) */
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-align-lg="start"] { align-items: flex-start; }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-align-lg="center"] { align-items: center; }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-align-lg="end"] { align-items: flex-end; }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-align-lg="stretch"] { align-items: stretch; }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-align-lg="baseline"] { align-items: baseline; }

  /* Justification (main axis) */
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-justify-lg="start"] { justify-content: flex-start; }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-justify-lg="center"] { justify-content: center; }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-justify-lg="end"] { justify-content: flex-end; }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-justify-lg="between"] { justify-content: space-between; }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-justify-lg="around"] { justify-content: space-around; }
}

/* ── Tier `xl` — from 80rem up ── */
@media (min-width: 80rem) {
  /* Gap */
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-gap-xl="0"] { gap: var(--space-0, 0px); }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-gap-xl="1"] { gap: var(--space-1); }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-gap-xl="2"] { gap: var(--space-2); }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-gap-xl="3"] { gap: var(--space-3); }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-gap-xl="4"] { gap: var(--space-4); }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-gap-xl="6"] { gap: var(--space-6); }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-gap-xl="8"] { gap: var(--space-8); }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-gap-xl="10"] { gap: var(--space-10); }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-gap-xl="12"] { gap: var(--space-12); }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-gap-xl="16"] { gap: var(--space-16); }

  /* Alignment (cross axis) */
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-align-xl="start"] { align-items: flex-start; }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-align-xl="center"] { align-items: center; }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-align-xl="end"] { align-items: flex-end; }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-align-xl="stretch"] { align-items: stretch; }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-align-xl="baseline"] { align-items: baseline; }

  /* Justification (main axis) */
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-justify-xl="start"] { justify-content: flex-start; }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-justify-xl="center"] { justify-content: center; }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-justify-xl="end"] { justify-content: flex-end; }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-justify-xl="between"] { justify-content: space-between; }
  [data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-ui="cluster"][data-justify-xl="around"] { justify-content: space-around; }
}


/* === primitives/collapsible.css === */
/* @ui:component collapsible */
/* @ui:tokens color-fg color-fg-muted color-bg-subtle color-border color-ring radius-md space-2 space-3 text-sm text-base font-ui weight-medium duration-fast duration-normal ease-default border-width border-width-strong focus-ring-width focus-ring-offset focus-ring-style focus-ring-color focus-shadow */

/* ── Root — native <details>, so it opens/closes with zero JavaScript ── */
[data-ui="collapsible"] {
  border-radius: var(--collapsible-radius, var(--radius-md));
  font-family: var(--collapsible-font, var(--font-ui));
  color: var(--color-fg);
}

/* Child combinators throughout: <summary> is always a direct child of its
   <details>, and a collapsible nested in the content keeps its own trigger —
   the `[open]` rule below used to rotate the chevron of a closed one inside
   an open one. [1.1F-20] */

/* ── Trigger — the <summary> ── */
[data-ui="collapsible"] > [data-part="trigger"] {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  padding: var(--space-3);
  font-size: var(--text-base);
  font-weight: var(--weight-medium);
  line-height: 1.4;
  cursor: pointer;
  list-style: none;
  border-radius: var(--collapsible-radius, var(--radius-md));
  transition: background var(--duration-fast) var(--ease-default);
}

/* Strip the native disclosure marker (WebKit + standard list-item marker) */
[data-ui="collapsible"] > [data-part="trigger"]::-webkit-details-marker {
  display: none;
}

[data-ui="collapsible"] > [data-part="trigger"]:hover {
  background: var(--color-bg-subtle);
}

[data-ui="collapsible"] > [data-part="trigger"]:focus-visible {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  outline-offset: var(--focus-ring-offset);
  box-shadow: var(--focus-shadow);
}

/* Chevron indicator — rotates when open, CSS-only */
[data-ui="collapsible"] > [data-part="trigger"]::after {
  content: "";
  flex: none;
  width: 0.5em;
  height: 0.5em;
  border-inline-end: var(--border-width-strong) solid var(--color-fg-muted);
  border-block-end: var(--border-width-strong) solid var(--color-fg-muted);
  transform: rotate(45deg);
  transition: transform var(--duration-normal) var(--ease-default);
}

[data-ui="collapsible"][open] > [data-part="trigger"]::after {
  transform: rotate(-135deg);
}

/* ── Content ── */
[data-ui="collapsible"] > [data-part="content"] {
  padding: 0 var(--space-3) var(--space-3);
  font-size: var(--text-sm);
  line-height: 1.6;
  color: var(--color-fg-muted);
}

/* ── Bordered variant ── */
[data-ui="collapsible"][data-variant="bordered"] {
  border: var(--border-width) solid var(--color-border);
}

/* ── Open/close animation via ::details-content, where supported ── */
/* Progressive enhancement: browsers without interpolate-size simply snap open. */
@supports (interpolate-size: allow-keywords) {
  [data-ui="collapsible"] {
    interpolate-size: allow-keywords;
  }

  [data-ui="collapsible"]::details-content {
    block-size: 0;
    overflow: hidden;
    transition: block-size var(--duration-normal) var(--ease-default),
                content-visibility var(--duration-normal) var(--ease-default) allow-discrete;
  }

  [data-ui="collapsible"][open]::details-content {
    block-size: auto;
  }
}

/* ── Motion ── */
@media (prefers-reduced-motion: reduce) {
  [data-ui="collapsible"] > [data-part="trigger"],
  [data-ui="collapsible"] > [data-part="trigger"]::after,
  [data-ui="collapsible"]::details-content {
    transition: none;
  }
}


/* === primitives/container.css === */
/* @ui:component container */
/* @ui:tokens measure-narrow measure-content measure-wide measure-prose space-0 space-1 space-2 space-3 space-4 space-6 space-8 space-10 space-12 space-16 */

/* The centred measure column (task 0.8-06).
 *
 * Three call sites in this repository hand-rolled this component before it
 * existed: the docs generator pinned an inline 72rem width onto the prose of
 * every generated page, form-page and wizard each wrote their own
 * `max-inline-size: 32rem; margin-inline: auto`, and surface hardcoded five
 * `data-max` pixel values. They are all one idea — cap the line length, centre
 * what is left — and they are all this file now.
 *
 * NAMING: `container` the component is not `container-type` the CSS feature.
 * The collision is accepted (every framework has a container), and nothing here
 * establishes a containment context — a container is a plain block box. The
 * component that queries its own inline size is `switcher` (task 0.8-05).
 *
 * `data-measure` is responsive on the canon tiers, with precedence encoded in
 * SPECIFICITY rather than source order — each tier block repeats
 * `[data-ui="container"]` once more than the tier below, base (0,2,0) → xl
 * (0,6,0) — so a bundler that reorders or splits the blocks cannot change which
 * tier wins (the mechanism grid 2.0 introduced in task 0.8-04).
 *
 * `data-gutter` is deliberately NOT responsive: it is the breathing room between
 * the column and the edge of whatever holds it, and a parent that already pads
 * (the docs shell, a dashboard cell) wants it left at the declared default of 0.
 * A tier ladder on top of that would be a second way to say the same thing.
 */

/* ── Base ──
 * A bare `<div data-ui="container">` is already an article column: capped at the
 * content measure and centred. Logical throughout — `max-inline-size` and
 * `margin-inline` mean the same thing in Arabic as in English, which the
 * `max-width` escapes this primitive replaces did not. Declared at (0,1,0) so
 * every attribute rule below overrides it. */
[data-ui="container"] {
  max-inline-size: var(--measure-content);
  margin-inline: auto;
}

/* ── Measure ──
 * One ladder, four tokens, and `full` for the deliberate opt-out: a container
 * that carries the centring and the gutter but imposes no cap. */
[data-ui="container"][data-measure="narrow"] { max-inline-size: var(--measure-narrow); }
[data-ui="container"][data-measure="content"] { max-inline-size: var(--measure-content); }
[data-ui="container"][data-measure="wide"] { max-inline-size: var(--measure-wide); }
[data-ui="container"][data-measure="prose"] { max-inline-size: var(--measure-prose); }
[data-ui="container"][data-measure="full"] { max-inline-size: 100%; }

/* ── Gutter ──
 * Inline padding only. A gutter is the space beside the column, never above it:
 * vertical rhythm belongs to the stack inside, not to the column's edge. */
[data-ui="container"][data-gutter="0"] { padding-inline: var(--space-0, 0px); }
[data-ui="container"][data-gutter="1"] { padding-inline: var(--space-1); }
[data-ui="container"][data-gutter="2"] { padding-inline: var(--space-2); }
[data-ui="container"][data-gutter="3"] { padding-inline: var(--space-3); }
[data-ui="container"][data-gutter="4"] { padding-inline: var(--space-4); }
[data-ui="container"][data-gutter="6"] { padding-inline: var(--space-6); }
[data-ui="container"][data-gutter="8"] { padding-inline: var(--space-8); }
[data-ui="container"][data-gutter="10"] { padding-inline: var(--space-10); }
[data-ui="container"][data-gutter="12"] { padding-inline: var(--space-12); }
[data-ui="container"][data-gutter="16"] { padding-inline: var(--space-16); }

/* ── Tier `sm` — from 40rem up ── */
@media (min-width: 40rem) {
  [data-ui="container"][data-ui="container"][data-measure-sm="narrow"] { max-inline-size: var(--measure-narrow); }
  [data-ui="container"][data-ui="container"][data-measure-sm="content"] { max-inline-size: var(--measure-content); }
  [data-ui="container"][data-ui="container"][data-measure-sm="wide"] { max-inline-size: var(--measure-wide); }
  [data-ui="container"][data-ui="container"][data-measure-sm="prose"] { max-inline-size: var(--measure-prose); }
  [data-ui="container"][data-ui="container"][data-measure-sm="full"] { max-inline-size: 100%; }
}

/* ── Tier `md` — from 48rem up ── */
@media (min-width: 48rem) {
  [data-ui="container"][data-ui="container"][data-ui="container"][data-measure-md="narrow"] { max-inline-size: var(--measure-narrow); }
  [data-ui="container"][data-ui="container"][data-ui="container"][data-measure-md="content"] { max-inline-size: var(--measure-content); }
  [data-ui="container"][data-ui="container"][data-ui="container"][data-measure-md="wide"] { max-inline-size: var(--measure-wide); }
  [data-ui="container"][data-ui="container"][data-ui="container"][data-measure-md="prose"] { max-inline-size: var(--measure-prose); }
  [data-ui="container"][data-ui="container"][data-ui="container"][data-measure-md="full"] { max-inline-size: 100%; }
}

/* ── Tier `lg` — from 64rem up ── */
@media (min-width: 64rem) {
  [data-ui="container"][data-ui="container"][data-ui="container"][data-ui="container"][data-measure-lg="narrow"] { max-inline-size: var(--measure-narrow); }
  [data-ui="container"][data-ui="container"][data-ui="container"][data-ui="container"][data-measure-lg="content"] { max-inline-size: var(--measure-content); }
  [data-ui="container"][data-ui="container"][data-ui="container"][data-ui="container"][data-measure-lg="wide"] { max-inline-size: var(--measure-wide); }
  [data-ui="container"][data-ui="container"][data-ui="container"][data-ui="container"][data-measure-lg="prose"] { max-inline-size: var(--measure-prose); }
  [data-ui="container"][data-ui="container"][data-ui="container"][data-ui="container"][data-measure-lg="full"] { max-inline-size: 100%; }
}

/* ── Tier `xl` — from 80rem up ── */
@media (min-width: 80rem) {
  [data-ui="container"][data-ui="container"][data-ui="container"][data-ui="container"][data-ui="container"][data-measure-xl="narrow"] { max-inline-size: var(--measure-narrow); }
  [data-ui="container"][data-ui="container"][data-ui="container"][data-ui="container"][data-ui="container"][data-measure-xl="content"] { max-inline-size: var(--measure-content); }
  [data-ui="container"][data-ui="container"][data-ui="container"][data-ui="container"][data-ui="container"][data-measure-xl="wide"] { max-inline-size: var(--measure-wide); }
  [data-ui="container"][data-ui="container"][data-ui="container"][data-ui="container"][data-ui="container"][data-measure-xl="prose"] { max-inline-size: var(--measure-prose); }
  [data-ui="container"][data-ui="container"][data-ui="container"][data-ui="container"][data-ui="container"][data-measure-xl="full"] { max-inline-size: 100%; }
}


/* === primitives/description-list.css === */
/* @ui:component description-list */
/* @ui:tokens color-fg color-fg-muted color-border space-2 space-3 space-4 space-6 space-1 text-xs text-sm text-base font-body weight-semibold border-width doc-font doc-line-height */

/* ── Base ── */
[data-ui="description-list"] {
  margin: 0;
  padding: 0;
  font-family: var(--doc-font, var(--font-body));
}

/* A term or details is the list's child, or the child of a plain <div> that
   groups one pair (HTML allows `dl > div > dt + dd`). Never a descendant
   further down: a list nested in a <dd> is its own, and a `sm` list used to
   shrink it too. The <div> hop is `:where()`, so both shapes weigh the same,
   and `:not([data-ui])` keeps a component out of the grouping role. [1.1F-20] */

/* ── Term ── */
[data-ui="description-list"] > [data-part="term"],
[data-ui="description-list"] > :where(div:not([data-ui])) > [data-part="term"] {
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  color: var(--color-fg);
  margin: 0;
  padding: 0;
}

/* ── Details ── */
[data-ui="description-list"] > [data-part="details"],
[data-ui="description-list"] > :where(div:not([data-ui])) > [data-part="details"] {
  font-size: var(--text-sm);
  color: var(--color-fg-muted);
  margin: 0;
  padding: 0;
  line-height: var(--doc-line-height, 1.5);
}

/* ── Variant: Vertical (default) ── */
[data-ui="description-list"][data-variant="vertical"],
[data-ui="description-list"]:not([data-variant]) {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

[data-ui="description-list"][data-variant="vertical"] > [data-part="term"],
[data-ui="description-list"][data-variant="vertical"] > :where(div:not([data-ui])) > [data-part="term"],
[data-ui="description-list"]:not([data-variant]) > [data-part="term"],
[data-ui="description-list"]:not([data-variant]) > :where(div:not([data-ui])) > [data-part="term"] {
  margin-bottom: var(--space-1, 0.25rem);
}

[data-ui="description-list"][data-variant="vertical"] > [data-part="details"],
[data-ui="description-list"][data-variant="vertical"] > :where(div:not([data-ui])) > [data-part="details"],
[data-ui="description-list"]:not([data-variant]) > [data-part="details"],
[data-ui="description-list"]:not([data-variant]) > :where(div:not([data-ui])) > [data-part="details"] {
  margin-bottom: var(--space-4);
}

[data-ui="description-list"][data-variant="vertical"] > [data-part="details"]:last-child,
[data-ui="description-list"][data-variant="vertical"] > :where(div:not([data-ui])) > [data-part="details"]:last-child,
[data-ui="description-list"]:not([data-variant]) > [data-part="details"]:last-child,
[data-ui="description-list"]:not([data-variant]) > :where(div:not([data-ui])) > [data-part="details"]:last-child {
  margin-bottom: 0;
}

/* ── Variant: Horizontal ── */
[data-ui="description-list"][data-variant="horizontal"] {
  display: grid;
  grid-template-columns: minmax(8rem, auto) minmax(0, 1fr);
  gap: var(--space-3) var(--space-6);
  align-items: baseline;
}

/* ── Divided ── */
[data-ui="description-list"][data-divided][data-variant="vertical"] > [data-part="details"],
[data-ui="description-list"][data-divided][data-variant="vertical"] > :where(div:not([data-ui])) > [data-part="details"],
[data-ui="description-list"][data-divided]:not([data-variant]) > [data-part="details"],
[data-ui="description-list"][data-divided]:not([data-variant]) > :where(div:not([data-ui])) > [data-part="details"] {
  padding-bottom: var(--space-4);
  border-bottom: var(--border-width) solid var(--color-border);
}

[data-ui="description-list"][data-divided][data-variant="vertical"] > [data-part="details"]:last-child,
[data-ui="description-list"][data-divided][data-variant="vertical"] > :where(div:not([data-ui])) > [data-part="details"]:last-child,
[data-ui="description-list"][data-divided]:not([data-variant]) > [data-part="details"]:last-child,
[data-ui="description-list"][data-divided]:not([data-variant]) > :where(div:not([data-ui])) > [data-part="details"]:last-child {
  border-bottom: none;
  padding-bottom: 0;
}

[data-ui="description-list"][data-divided][data-variant="horizontal"] > [data-part="term"],
[data-ui="description-list"][data-divided][data-variant="horizontal"] > :where(div:not([data-ui])) > [data-part="term"],
[data-ui="description-list"][data-divided][data-variant="horizontal"] > [data-part="details"],
[data-ui="description-list"][data-divided][data-variant="horizontal"] > :where(div:not([data-ui])) > [data-part="details"] {
  padding-bottom: var(--space-3);
  border-bottom: var(--border-width) solid var(--color-border);
}

/* ── Size: Small ── */
[data-ui="description-list"][data-size="sm"] {
  gap: var(--space-2);
}

[data-ui="description-list"][data-size="sm"] > [data-part="term"],
[data-ui="description-list"][data-size="sm"] > :where(div:not([data-ui])) > [data-part="term"] {
  font-size: var(--text-xs);
}

[data-ui="description-list"][data-size="sm"] > [data-part="details"],
[data-ui="description-list"][data-size="sm"] > :where(div:not([data-ui])) > [data-part="details"] {
  font-size: var(--text-xs);
}

/* ── Size: Large ── */
[data-ui="description-list"][data-size="lg"] {
  gap: var(--space-6);
}

[data-ui="description-list"][data-size="lg"] > [data-part="term"],
[data-ui="description-list"][data-size="lg"] > :where(div:not([data-ui])) > [data-part="term"] {
  font-size: var(--text-base, 1rem);
}

[data-ui="description-list"][data-size="lg"] > [data-part="details"],
[data-ui="description-list"][data-size="lg"] > :where(div:not([data-ui])) > [data-part="details"] {
  font-size: var(--text-base, 1rem);
}

/* ── Print ── */
@media print {
  [data-ui="description-list"] {
    break-inside: avoid;
  }
}


/* === primitives/empty-state.css === */
/* @ui:component empty-state */
/* @ui:tokens color-fg color-fg-muted color-fg-subtle text-sm text-lg text-3xl text-xs text-xl weight-medium space-2 space-3 space-4 space-8 font-heading */

/* ── Base ── */
[data-ui="empty-state"] {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: var(--space-8) var(--space-4);
  gap: var(--space-3);
}

/* Child combinators: `icon`, `title` and `description` are part names half
   the registry shares, and a descendant rule here restyled the title of a
   callout or a card placed inside the empty state. [1.1F-20] */

/* ── Icon ── */
[data-ui="empty-state"] > [data-part="icon"] {
  font-size: var(--text-3xl);
  color: var(--color-fg-subtle);
  line-height: 1;
}

/* ── Title ── */
[data-ui="empty-state"] > [data-part="title"] {
  font-family: var(--font-heading);
  font-size: var(--text-lg);
  font-weight: var(--weight-medium);
  color: var(--color-fg);
}

/* ── Description ── */
[data-ui="empty-state"] > [data-part="description"] {
  font-size: var(--text-sm);
  color: var(--color-fg-muted);
  max-width: 40ch;
}

/* ── Actions ── */
/* The action cluster is centred by the root's `align-items: center`, which sizes
   it to its content — so a row of two buttons that does not wrap overflows the
   window symmetrically, past BOTH edges, and the inline-start half is
   unreachable at any scroll position. Wrapping is the whole fix; the ceiling
   keeps a single very wide button honest too. */
[data-ui="empty-state"] > [data-part="actions"] {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-3);
  margin-top: var(--space-2);
  max-inline-size: 100%;
}

/* ── Compact size ── */
[data-ui="empty-state"][data-size="sm"] {
  padding: var(--space-4) var(--space-3);
  gap: var(--space-2);
}

[data-ui="empty-state"][data-size="sm"] > [data-part="icon"] {
  font-size: var(--text-xl);
}

[data-ui="empty-state"][data-size="sm"] > [data-part="title"] {
  font-size: var(--text-sm);
}

[data-ui="empty-state"][data-size="sm"] > [data-part="description"] {
  font-size: var(--text-xs);
}


/* === primitives/field-group.css === */
/* @ui:component field-group */
/* @ui:tokens color-fg color-fg-muted color-destructive color-success field-validating-color field-disabled-opacity field-label-size field-label-weight field-label-color field-required-color field-required-marker field-description-size field-description-color field-error-size field-error-color space-1 space-2 space-3 space-4 text-xs text-sm font-body weight-medium border-width doc-font section-gap-sm */

/* ── Base / spacing ownership ──
   A field-group owns only its tight, density-aware intra-field step: label →
   control → description/error. The surrounding flow root owns the looser step
   between sibling fields through base/rhythm.css (`--flow-space`, defaulting to
   `--section-gap-sm`). Do not add an outer margin here: doing so would double a
   form's default rhythm and make `data-gap="0"` unable to turn that rhythm off. */
[data-ui="field-group"] {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  font-family: var(--doc-font, var(--font-body));
}

/* ── Label ── */
[data-ui="field-group"] > [data-part="label"] {
  font-size: var(--field-label-size);
  font-weight: var(--field-label-weight);
  color: var(--field-label-color);
  line-height: 1.4;
}

/* ── Required Indicator ──
   Standardized required marker (§7.1): the canonical form is an explicit
   [data-part="required"] element inside the label — e.g.
   `<label data-part="label">Email <span data-part="required">*</span></label>`.
   It carries the marker's color and is announced/hidden as one unit. The legacy
   [data-required] attribute still renders a CSS ::after marker for backward
   compatibility; author pages should prefer the part. */
[data-ui="field-group"] > :where([data-part="label"]) > [data-part="required"] {
  color: var(--field-required-color);
}

[data-ui="field-group"][data-required] > [data-part="label"]::after {
  content: var(--field-required-marker);
  color: var(--field-required-color);
}

/* ── Input Slot ── */
[data-ui="field-group"] > [data-part="input"] {
  display: flex;
  flex-direction: column;
}

/* ── Description ── */
[data-ui="field-group"] > [data-part="description"] {
  font-size: var(--field-description-size);
  color: var(--field-description-color);
  margin: 0;
  line-height: 1.4;
}

/* ── Error Message ── */
[data-ui="field-group"] > [data-part="error"] {
  font-size: var(--field-error-size);
  color: var(--field-error-color);
  margin: 0;
  line-height: 1.4;
  display: none;
}

/* ── State: Invalid ──
   Normalized validation vocabulary (§7.1): invalid | validating | disabled.
   Renamed from the shipped `error` state in v2.0.0 (breaking — see manifest
   `changes`). The error part is revealed purely by state, no JS class toggling. */
[data-ui="field-group"][data-state="invalid"] > [data-part="label"] {
  color: var(--field-error-color);
}

[data-ui="field-group"][data-state="invalid"] > [data-part="error"] {
  display: block;
}

[data-ui="field-group"][data-state="invalid"] > [data-part="description"] {
  display: none;
}

[data-ui="field-group"][data-state="invalid"] [data-ui="input"],
[data-ui="field-group"][data-state="invalid"] [data-ui="textarea"],
[data-ui="field-group"][data-state="invalid"] [data-ui="select"] {
  border-color: var(--field-error-color);
  box-shadow: 0 0 0 var(--border-width) var(--field-error-color);
}

/* ── State: Validating ──
   Async constraint in flight (e.g. server-side uniqueness check). Neutral,
   muted affordance — not an error yet. Pair with aria-busy="true" on the control. */
[data-ui="field-group"][data-state="validating"] [data-ui="input"],
[data-ui="field-group"][data-state="validating"] [data-ui="textarea"],
[data-ui="field-group"][data-state="validating"] [data-ui="select"] {
  border-color: var(--field-validating-color);
  box-shadow: 0 0 0 var(--border-width) var(--field-validating-color);
}

/* ── State: Disabled ──
   Honest disabled affordance for the whole group. The control itself is also
   [disabled] for interaction/focus; this dims the surrounding parts to match. */
[data-ui="field-group"][data-state="disabled"] {
  opacity: var(--field-disabled-opacity);
  cursor: not-allowed;
}

[data-ui="field-group"][data-state="disabled"] > [data-part="label"] {
  color: var(--field-description-color);
}

/* ── State: Valid ── */
[data-ui="field-group"][data-state="valid"] [data-ui="input"],
[data-ui="field-group"][data-state="valid"] [data-ui="textarea"],
[data-ui="field-group"][data-state="valid"] [data-ui="select"] {
  border-color: var(--color-success);
  box-shadow: 0 0 0 var(--border-width) var(--color-success);
}

/* ── Variant: Horizontal ── */
[data-ui="field-group"][data-variant="horizontal"] {
  flex-direction: row;
  align-items: flex-start;
  gap: var(--space-4);
}

[data-ui="field-group"][data-variant="horizontal"] > [data-part="label"] {
  min-width: 8rem;
  padding-top: var(--space-2);
  flex-shrink: 0;
}

[data-ui="field-group"][data-variant="horizontal"] > [data-part="input"] {
  flex: 1;
}

/* ── Size: Small ── */
[data-ui="field-group"][data-size="sm"] {
  gap: var(--space-1);
}

[data-ui="field-group"][data-size="sm"] > [data-part="label"] {
  font-size: var(--text-xs);
}

/* ── Size: Large ── */
[data-ui="field-group"][data-size="lg"] {
  gap: var(--space-3);
}

[data-ui="field-group"][data-size="lg"] > [data-part="label"] {
  font-size: var(--text-sm);
}

/* ── Width: data-span ──
   A field's share of a row (full, half or third) from the md tier up; on a
   phone every field is full width. The fields' container (the form, a card
   body, a wizard step's body) becomes a six-track grid only when one of its
   field-groups carries data-span, so a form that never sets a width keeps its
   flow layout. Rows stay the field rhythm apart (--flow-space, which the
   form's data-gap sets), and the rhythm's margin between siblings comes off:
   the grid's gap is that step now, and a margin on the second field of a row
   would push it below its neighbour. Weightless (:where), so a container that
   lays itself out (a stack, a grid) keeps its own rules. */
@media (min-width: 48rem) {
  :where(:has(> [data-ui="field-group"][data-span])) {
    display: grid;
    grid-template-columns: repeat(6, minmax(0, 1fr));
    column-gap: var(--space-4);
    row-gap: var(--flow-space, var(--section-gap-sm));
    align-items: start;
  }

  :where(:has(> [data-ui="field-group"][data-span])) > :where(*) {
    grid-column: 1 / -1;
    margin-block-start: 0;
  }

  :where(:has(> [data-ui="field-group"][data-span])) > [data-ui="field-group"][data-span="half"] {
    grid-column: span 3;
  }

  :where(:has(> [data-ui="field-group"][data-span])) > [data-ui="field-group"][data-span="third"] {
    grid-column: span 2;
  }
}

/* ── Print ── */
@media print {
  [data-ui="field-group"] {
    break-inside: avoid;
  }
}


/* === primitives/glow.css === */
/* @ui:component glow */
/* @ui:tokens color-primary color-info color-border card-radius border-width-md motion-ambient-duration motion-ambient-play ease-linear ease-default duration-slow */

/* The orbit is an angle, and an angle only animates if the browser knows it is
   one: an unregistered custom property flips between its two values instead of
   sweeping. Where `@property` is not understood the ring simply holds still —
   a gradient border without the orbit, never a broken one. */
@property --faqir-glow-angle {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

/* ── Root ──
   A glow wraps one box — a card, a button, an image — and draws light around
   it. The ring is painted OUTSIDE the child by a masked pseudo-element, so the
   child keeps its own background, border and padding untouched, and may even
   be transparent. The root's radius is the only thing the two have to agree
   on; it defaults to the card's, the thing a glow most often wraps. */
[data-ui="glow"] {
  --faqir-glow-a: var(--glow-color-1, var(--color-primary));
  --faqir-glow-b: var(--glow-color-2, var(--color-info));
  position: relative;
  isolation: isolate;
  display: grid;
  border-radius: var(--glow-radius, var(--card-radius));
}

/* A <span> root wraps inline-level things — a button in a row of buttons. */
span[data-ui="glow"] {
  display: inline-grid;
}

/* ── Ring ──
   The gradient is written on the pseudo-elements themselves, not handed down
   from the root in a custom property: the angle is animated HERE, and a
   property resolves its var() on the element that declares it — a paint
   declared on the root would be frozen at the root's angle. */
[data-ui="glow"]::before,
[data-ui="glow"]::after {
  content: "";
  position: absolute;
  inset: calc(var(--glow-width, var(--border-width-md)) * -1);
  border-radius: calc(var(--glow-radius, var(--card-radius)) + var(--glow-width, var(--border-width-md)));
  background-image: conic-gradient(from var(--faqir-glow-angle), var(--faqir-glow-a), var(--faqir-glow-b), var(--faqir-glow-a));
  pointer-events: none;
  animation: faqir-glow-orbit calc(var(--glow-duration, var(--motion-ambient-duration)) / 4) var(--ease-linear) infinite;
  animation-play-state: var(--motion-ambient-play);
  transition: opacity var(--duration-slow) var(--ease-default);
}

/* The ring itself: the gradient, with everything but a border's width of it
   masked away. Two mask layers, the second covering the content box, the pair
   combined by exclusion — what is left is the frame. */
[data-ui="glow"]::before {
  z-index: 1;
  padding: var(--glow-width, var(--border-width-md));
  -webkit-mask: linear-gradient(black 0 0) content-box, linear-gradient(black 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(black 0 0) content-box exclude, linear-gradient(black 0 0);
}

/* ── Halo ──
   The same paint, blurred, behind the child: the light the ring casts. Off
   unless asked for — a ring alone is a border, a ring with a halo is a lamp. */
[data-ui="glow"]::after {
  z-index: -1;
  display: none;
  filter: blur(var(--glow-blur, 1.25rem));
  opacity: var(--glow-opacity, 0.5);
}

[data-ui="glow"][data-halo]::after {
  display: block;
}

@keyframes faqir-glow-orbit {
  to { --faqir-glow-angle: 360deg; }
}

/* ── Variant: beam ──
   Not a full ring but one bright arc travelling a quiet border — the eye
   follows it round the box. */
[data-ui="glow"][data-variant="beam"]::before {
  background-image: conic-gradient(from var(--faqir-glow-angle), transparent 0 62%, var(--faqir-glow-a) 82%, var(--faqir-glow-b) 94%, transparent 100%), linear-gradient(var(--color-border), var(--color-border));
}

[data-ui="glow"][data-variant="beam"]::after {
  background-image: conic-gradient(from var(--faqir-glow-angle), transparent 0 62%, var(--faqir-glow-a) 82%, var(--faqir-glow-b) 94%, transparent 100%);
}

/* ── Trigger: hover ──
   The light is off until the pointer or the keyboard arrives, and fades in.
   The orbit keeps running underneath, so it never starts from a standstill. */
[data-ui="glow"][data-trigger="hover"]::before,
[data-ui="glow"][data-trigger="hover"]::after {
  opacity: 0;
}

[data-ui="glow"][data-trigger="hover"]:hover::before,
[data-ui="glow"][data-trigger="hover"]:focus-within::before {
  opacity: 1;
}

[data-ui="glow"][data-trigger="hover"]:hover::after,
[data-ui="glow"][data-trigger="hover"]:focus-within::after {
  opacity: var(--glow-opacity, 0.5);
}

/* ── Static ── */
[data-ui="glow"][data-static]::before,
[data-ui="glow"][data-static]::after {
  animation: none;
}

/* ── Motion ──
   The ring stays — it is a border — and stops turning. */
@media (prefers-reduced-motion: reduce) {
  [data-ui="glow"]::before,
  [data-ui="glow"]::after {
    animation: none;
    transition: none;
  }
}

/* ── Forced colours and print ── */
@media (forced-colors: active), print {
  [data-ui="glow"]::before,
  [data-ui="glow"]::after {
    display: none;
  }
}


/* === primitives/grid.css === */
/* @ui:component grid */
/* @ui:tokens space-0 space-1 space-2 space-3 space-4 space-6 space-8 space-10 space-12 space-16 */

/* CSS Grid, mobile-first on the canon (task 0.8-04).
 *
 * `data-cols` is the base at EVERY width; `data-cols-{sm,md,lg,xl}` override it
 * from that tier's `min-width` floor up (FAQIR-SPEC §15). This inverts the 1.x
 * sheet, where `data-cols` was desktop-only and a blanket rule collapsed every
 * grid to one column at ≤640px — collapsing is now an explicit authoring
 * choice: `data-cols="1" data-cols-md="2" data-cols-lg="4"`.
 *
 * Tier precedence is encoded in SPECIFICITY, not source order: each tier block
 * repeats `[data-ui="grid"]` once more than the tier below it (base (0,2,0),
 * sm (0,3,0), md (0,4,0), lg (0,5,0), xl (0,6,0)), so a bundler that reorders
 * or splits blocks cannot change which tier wins. The 1.x sheet resolved its
 * overrides purely by document order at equal specificity — and its
 * `max-width: 640px` / `min-width: 641px` range pair left a dead zone at
 * fractional widths (640.5px matched neither); `min-width` floors leave none.
 *
 * `data-cols="auto"` is the intrinsic mode the doctrine says to reach for
 * first (§15 doctrine 1): `repeat(auto-fit, minmax(min(100%, var(--grid-min)),
 * 1fr))` — the column count derives from the space available, zero media
 * queries. `data-min` moves the item floor over rem steps; it lives on the
 * base rule at (0,1,0) so the `data-min` rules at (0,2,0) override it at any
 * source position.
 *
 * `data-align-rows` is the cross-card alignment mode. Direct card children
 * share exactly four row tracks (header, divider, body, footer) through
 * subgrid. The feature-query fallback makes every card span the full grid
 * instead: an older engine loses side-by-side density, never the visual truth
 * of corresponding rows. Equal outer heights alone cannot provide that truth.
 */

/* ── Base ── */
[data-ui="grid"] {
  display: grid;
  --grid-min: 16rem;
}

[data-ui="grid"][data-align-rows] {
  align-items: stretch;
}

/* ── Columns — the base, at every width ──
 * Tracks are `minmax(0, 1fr)`, not `1fr`: a bare `1fr` is `minmax(auto, 1fr)`,
 * whose floor is the widest item's min-content, so one wide table or an
 * unbreakable id widened the whole grid past its container. The floor is on
 * the track rather than on the items (`> * { min-inline-size: 0 }`) because
 * the `data-scroll` restore below sets the items' `min-inline-size` itself. */
[data-ui="grid"][data-cols="1"] {
  grid-template-columns: repeat(1, minmax(0, 1fr));
}

[data-ui="grid"][data-cols="2"] {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

[data-ui="grid"][data-cols="3"] {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

[data-ui="grid"][data-cols="4"] {
  grid-template-columns: repeat(4, minmax(0, 1fr));
}

[data-ui="grid"][data-cols="6"] {
  grid-template-columns: repeat(6, minmax(0, 1fr));
}

[data-ui="grid"][data-cols="12"] {
  grid-template-columns: repeat(12, minmax(0, 1fr));
}

/* ── Intrinsic mode — as many columns as fit, no query at all ── */
[data-ui="grid"][data-cols="auto"] {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--grid-min)), 1fr));
}

/* ── Item floor for the intrinsic mode (rem, not spacing steps) ── */
[data-ui="grid"][data-min="8"] { --grid-min: 8rem; }
[data-ui="grid"][data-min="12"] { --grid-min: 12rem; }
[data-ui="grid"][data-min="16"] { --grid-min: 16rem; }
[data-ui="grid"][data-min="20"] { --grid-min: 20rem; }
[data-ui="grid"][data-min="24"] { --grid-min: 24rem; }

/* ── Gap ── */
[data-ui="grid"][data-gap="0"] { gap: var(--space-0, 0px); }
[data-ui="grid"][data-gap="1"] { gap: var(--space-1); }
[data-ui="grid"][data-gap="2"] { gap: var(--space-2); }
[data-ui="grid"][data-gap="3"] { gap: var(--space-3); }
[data-ui="grid"][data-gap="4"] { gap: var(--space-4); }
[data-ui="grid"][data-gap="6"] { gap: var(--space-6); }
[data-ui="grid"][data-gap="8"] { gap: var(--space-8); }
[data-ui="grid"][data-gap="10"] { gap: var(--space-10); }
[data-ui="grid"][data-gap="12"] { gap: var(--space-12); }
[data-ui="grid"][data-gap="16"] { gap: var(--space-16); }

/* ── Child span ──
 * Holds at every width. The 1.x sheet crushed every span to `span 1` below
 * 640px as part of the forced collapse; a child now keeps its span until the
 * author changes the column count with a tier. */
[data-ui="grid"] > [data-span="2"] {
  grid-column: span 2;
}

[data-ui="grid"] > [data-span="3"] {
  grid-column: span 3;
}

[data-ui="grid"] > [data-span="4"] {
  grid-column: span 4;
}

[data-ui="grid"] > [data-span="6"] {
  grid-column: span 6;
}

[data-ui="grid"] > [data-span="full"] {
  grid-column: 1 / -1;
}

/* ── Cross-card row alignment ──
 * Four rows is a deliberate contract, not an inferred child count. A wrapping
 * grid creates a fresh four-track group for each visual row, so only cards that
 * are actually side by side share their intrinsic maxima. */
@supports (grid-template-rows: subgrid) {
  [data-ui="grid"][data-align-rows] > [data-ui="card"] {
    display: grid;
    grid-row: span 4;
    grid-template-rows: subgrid;
  }
}

/* Correct fallback: without subgrid there must be no side-by-side cards whose
 * internal landmarks pretend to align. Each card spans the grid and keeps the
 * card primitive's intrinsic flex layout and complete content order. */
@supports not (grid-template-rows: subgrid) {
  [data-ui="grid"][data-align-rows] > [data-ui="card"] {
    grid-column: 1 / -1;
  }
}

/* ── Scroll strip — mobile-first ──
 * Below `sm` the grid is a horizontal snap strip; the sm tier block restores
 * the grid. The restore carries the sm specificity boost, so it beats these
 * base rules wherever a bundler puts them. */
[data-ui="grid"][data-scroll] {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  padding-block-end: var(--space-2);
}

[data-ui="grid"][data-scroll] > * {
  min-inline-size: 280px;
  scroll-snap-align: start;
  flex-shrink: 0;
}

/* ── Tier `sm` — from 40rem up ── */
@media (min-width: 40rem) {
  [data-ui="grid"][data-ui="grid"][data-cols-sm="1"] { grid-template-columns: repeat(1, minmax(0, 1fr)); }
  [data-ui="grid"][data-ui="grid"][data-cols-sm="2"] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  [data-ui="grid"][data-ui="grid"][data-cols-sm="3"] { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  [data-ui="grid"][data-ui="grid"][data-cols-sm="4"] { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  [data-ui="grid"][data-ui="grid"][data-cols-sm="6"] { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  [data-ui="grid"][data-ui="grid"][data-cols-sm="12"] { grid-template-columns: repeat(12, minmax(0, 1fr)); }
  [data-ui="grid"][data-ui="grid"][data-cols-sm="auto"] { grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--grid-min)), 1fr)); }

  [data-ui="grid"][data-ui="grid"][data-gap-sm="0"] { gap: var(--space-0, 0px); }
  [data-ui="grid"][data-ui="grid"][data-gap-sm="1"] { gap: var(--space-1); }
  [data-ui="grid"][data-ui="grid"][data-gap-sm="2"] { gap: var(--space-2); }
  [data-ui="grid"][data-ui="grid"][data-gap-sm="3"] { gap: var(--space-3); }
  [data-ui="grid"][data-ui="grid"][data-gap-sm="4"] { gap: var(--space-4); }
  [data-ui="grid"][data-ui="grid"][data-gap-sm="6"] { gap: var(--space-6); }
  [data-ui="grid"][data-ui="grid"][data-gap-sm="8"] { gap: var(--space-8); }
  [data-ui="grid"][data-ui="grid"][data-gap-sm="10"] { gap: var(--space-10); }
  [data-ui="grid"][data-ui="grid"][data-gap-sm="12"] { gap: var(--space-12); }
  [data-ui="grid"][data-ui="grid"][data-gap-sm="16"] { gap: var(--space-16); }

  /* Restore the grid a `data-scroll` strip collapsed to. */
  [data-ui="grid"][data-ui="grid"][data-scroll] {
    display: grid;
    overflow-x: visible;
    scroll-snap-type: none;
    padding-block-end: 0;
  }

  [data-ui="grid"][data-ui="grid"][data-scroll] > * {
    min-inline-size: auto;
    scroll-snap-align: none;
    flex-shrink: 1;
  }
}

/* ── Tier `md` — from 48rem up ── */
@media (min-width: 48rem) {
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-cols-md="1"] { grid-template-columns: repeat(1, minmax(0, 1fr)); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-cols-md="2"] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-cols-md="3"] { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-cols-md="4"] { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-cols-md="6"] { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-cols-md="12"] { grid-template-columns: repeat(12, minmax(0, 1fr)); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-cols-md="auto"] { grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--grid-min)), 1fr)); }

  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-gap-md="0"] { gap: var(--space-0, 0px); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-gap-md="1"] { gap: var(--space-1); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-gap-md="2"] { gap: var(--space-2); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-gap-md="3"] { gap: var(--space-3); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-gap-md="4"] { gap: var(--space-4); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-gap-md="6"] { gap: var(--space-6); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-gap-md="8"] { gap: var(--space-8); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-gap-md="10"] { gap: var(--space-10); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-gap-md="12"] { gap: var(--space-12); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-gap-md="16"] { gap: var(--space-16); }
}

/* ── Tier `lg` — from 64rem up ── */
@media (min-width: 64rem) {
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-cols-lg="1"] { grid-template-columns: repeat(1, minmax(0, 1fr)); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-cols-lg="2"] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-cols-lg="3"] { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-cols-lg="4"] { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-cols-lg="6"] { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-cols-lg="12"] { grid-template-columns: repeat(12, minmax(0, 1fr)); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-cols-lg="auto"] { grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--grid-min)), 1fr)); }

  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-gap-lg="0"] { gap: var(--space-0, 0px); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-gap-lg="1"] { gap: var(--space-1); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-gap-lg="2"] { gap: var(--space-2); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-gap-lg="3"] { gap: var(--space-3); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-gap-lg="4"] { gap: var(--space-4); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-gap-lg="6"] { gap: var(--space-6); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-gap-lg="8"] { gap: var(--space-8); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-gap-lg="10"] { gap: var(--space-10); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-gap-lg="12"] { gap: var(--space-12); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-gap-lg="16"] { gap: var(--space-16); }
}

/* ── Tier `xl` — from 80rem up ── */
@media (min-width: 80rem) {
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-cols-xl="1"] { grid-template-columns: repeat(1, minmax(0, 1fr)); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-cols-xl="2"] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-cols-xl="3"] { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-cols-xl="4"] { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-cols-xl="6"] { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-cols-xl="12"] { grid-template-columns: repeat(12, minmax(0, 1fr)); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-cols-xl="auto"] { grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--grid-min)), 1fr)); }

  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-gap-xl="0"] { gap: var(--space-0, 0px); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-gap-xl="1"] { gap: var(--space-1); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-gap-xl="2"] { gap: var(--space-2); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-gap-xl="3"] { gap: var(--space-3); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-gap-xl="4"] { gap: var(--space-4); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-gap-xl="6"] { gap: var(--space-6); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-gap-xl="8"] { gap: var(--space-8); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-gap-xl="10"] { gap: var(--space-10); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-gap-xl="12"] { gap: var(--space-12); }
  [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-ui="grid"][data-gap-xl="16"] { gap: var(--space-16); }
}


/* === primitives/highlight.css === */
/* @ui:component highlight */
/* @ui:tokens color-primary color-info color-fg-muted color-fg color-primary-active color-primary-hover color-bg color-warning motion-ambient-duration motion-ambient-play motion-reveal-duration motion-reveal-ease ease-in-out ease-linear radius-sm border-width-lg border-width-strong duration-slow */

/* ── Root ──
   An inline run of text the eye should land on. Every variant is a background
   under (or clipped to) the glyphs — never a second copy of the text — so the
   words stay selectable, searchable and read once by a screen reader.
   `box-decoration-break: clone` makes a highlight that wraps restart on each
   line instead of stretching one painting across all of them. */
[data-ui="highlight"] {
  --faqir-highlight-ink: var(--highlight-color, var(--color-primary));
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
  background-repeat: no-repeat;
}

/* ── Variant: gradient (default) ──
   The accent gradient, clipped to the letters. `--gradient-accent` is the
   theme's signature gradient where a theme states one (aurora does); the
   fallback builds it from the accent and info colours every theme has. */
[data-ui="highlight"]:not([data-variant]),
[data-ui="highlight"][data-variant="gradient"] {
  background-image: var(--highlight-gradient, var(--gradient-accent, linear-gradient(135deg, var(--color-primary), var(--color-info))));
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
}

[data-ui="highlight"]:not([data-variant])[data-animate],
[data-ui="highlight"][data-variant="gradient"][data-animate] {
  background-size: 220% 100%;
  animation: faqir-highlight-pan calc(var(--motion-ambient-duration) / 4) var(--ease-in-out) infinite alternate;
  animation-play-state: var(--motion-ambient-play);
}

/* ── Variant: shimmer ──
   Muted text with a band of full-strength ink passing through it. */
[data-ui="highlight"][data-variant="shimmer"] {
  background-image: linear-gradient(110deg, var(--color-fg-muted) 38%, var(--color-fg) 50%, var(--color-fg-muted) 62%);
  background-size: 250% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  color: transparent;
  animation: faqir-highlight-pan calc(var(--motion-ambient-duration) / 8) var(--ease-linear) infinite;
  animation-play-state: var(--motion-ambient-play);
}

@keyframes faqir-highlight-pan {
  from { background-position: 100% 50%; }
  to   { background-position: 0% 50%; }
}

/* ── Variant: marker ──
   A highlighter stroke across the lower half of the line, in the accent at low
   strength, so the text keeps its own colour and its contrast. */
[data-ui="highlight"][data-variant="marker"] {
  margin-inline: -0.15em;
  padding-inline: 0.15em;
  border-radius: var(--radius-sm);
  background-image: linear-gradient(color-mix(in oklch, var(--faqir-highlight-ink) 30%, transparent), color-mix(in oklch, var(--faqir-highlight-ink) 30%, transparent));
  background-position: 0 88%;
  background-size: 100% 46%;
}

/* ── Variant: underline ──
   A rule under the words, as heavy as the theme's heaviest edge. */
[data-ui="highlight"][data-variant="underline"] {
  padding-block-end: 0.08em;
  background-image: linear-gradient(var(--faqir-highlight-ink), var(--faqir-highlight-ink));
  background-position: 0 100%;
  background-size: 100% var(--border-width-lg);
}

/* ── Variant: foil ──
   Metallic display text: banded light and dark, with a glint that drifts across
   it. The bands repeat every 3.9em (a long fall to a bright edge, then a sharp
   drop back to dark, as light does across a curved foil), so they scale with
   the type. They are built from the theme's primary ramp only, and the ramp
   already runs the right way in either scheme: --color-primary-hover and
   --color-primary-active step AWAY from the page (darker on a light theme,
   lighter on a dark one), so the extreme band stays legible against its
   ground whichever way the theme faces. The glint band is the opposite step,
   primary eased a quarter of the way toward the page; it is the lowest-
   contrast stop (about 3.5:1 on the default theme's light ground and 3.9:1 on
   its dark one, above the 3:1 large-text bar: foil is display type, not body
   copy). Without background-clip the text keeps its plain primary colour. */
[data-ui="highlight"][data-variant="foil"] {
  color: var(--color-primary);
}

/* The bands only exist where they can be clipped to the glyphs; painted
   behind unclipped text they would be a stripe the words sit on. */
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  [data-ui="highlight"][data-variant="foil"] {
    background-image: repeating-linear-gradient(100deg,
      var(--color-primary-active) 0,
      var(--color-primary-hover) 0.7em,
      var(--color-primary) 1.3em,
      color-mix(in oklch, var(--color-primary) 75%, var(--color-bg)) 1.8em,
      var(--color-primary) 1.95em,
      var(--color-primary-active) 2.1em,
      var(--color-primary-hover) 2.7em,
      var(--color-primary) 3.1em,
      var(--color-primary-hover) 3.5em,
      var(--color-primary-active) 3.9em);
    background-size: 200% 100%;
    background-position: 30% 50%;
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
  }
}

/* ── Variant: outline ──
   Display text drawn as its contour: a stroke in the ink colour, nothing
   inside. Without text-stroke support the words are simply the page's solid
   text, so the block sits inside the @supports. Stroke first, then fill, so
   the fill (transparent) never eats into the stroke. */
@supports (-webkit-text-stroke: 1px) {
  [data-ui="highlight"][data-variant="outline"] {
    -webkit-text-stroke: var(--border-width-strong) var(--faqir-highlight-ink);
    -webkit-text-fill-color: transparent;
    paint-order: stroke fill;
  }
}

/* ── Variant: echo ──
   Two hard copies of the text's shadow, stepping away along the diagonal: the
   Memphis / neo-brutalist double print. Offsets are em, so the echo scales with
   the type; the second colour is --highlight-echo (warning, so it stays apart
   from the primary at any theme). The text keeps its own colour and contrast. */
[data-ui="highlight"][data-variant="echo"] {
  text-shadow:
    0.04em 0.04em 0 var(--faqir-highlight-ink),
    0.08em 0.08em 0 var(--highlight-echo, var(--color-warning));
}

/* The stroke starts where the line starts: the far edge in a right-to-left page. */
[data-ui="highlight"][data-variant="marker"]:dir(rtl) {
  background-position: 100% 88%;
}

[data-ui="highlight"][data-variant="underline"]:dir(rtl) {
  background-position: 100% 100%;
}

/* Drawn in, once, like a pen stroke. Only a `from`: each ends on the size above. */
[data-ui="highlight"][data-variant="marker"][data-animate] {
  animation: faqir-highlight-draw var(--motion-reveal-duration) var(--motion-reveal-ease) both;
  animation-delay: var(--highlight-delay, var(--duration-slow));
}

[data-ui="highlight"][data-variant="underline"][data-animate] {
  animation: faqir-highlight-rule var(--motion-reveal-duration) var(--motion-reveal-ease) both;
  animation-delay: var(--highlight-delay, var(--duration-slow));
}

@keyframes faqir-highlight-draw {
  from { background-size: 0% 46%; }
}

@keyframes faqir-highlight-rule {
  from { background-size: 0% var(--border-width-lg); }
}

/* ── Motion ──
   Foil's glint exists only where motion is welcome: the bands pan across the
   glyphs on the same loop as the gradient's, cut from the ambient duration and
   frozen by --motion-ambient-play. Reduced motion leaves the bands where the
   rule above put them. */
@media (prefers-reduced-motion: no-preference) {
  [data-ui="highlight"][data-variant="foil"] {
    animation: faqir-highlight-pan calc(var(--motion-ambient-duration) / 3) var(--ease-in-out) infinite alternate;
    animation-play-state: var(--motion-ambient-play);
  }
}

@media (prefers-reduced-motion: reduce) {
  /* The [data-animate] selectors are repeated so this rule matches their
     specificity; `[data-ui="highlight"]` alone (0,1,0) lost to them (0,3,0). */
  [data-ui="highlight"],
  [data-ui="highlight"]:not([data-variant])[data-animate],
  [data-ui="highlight"][data-variant="gradient"][data-animate],
  [data-ui="highlight"][data-variant="marker"][data-animate],
  [data-ui="highlight"][data-variant="underline"][data-animate] {
    animation: none;
  }

  /* A shimmer that does not move is just dim text; give it its ink back. */
  [data-ui="highlight"][data-variant="shimmer"] {
    background-image: none;
    -webkit-text-fill-color: currentColor;
    color: inherit;
  }
}

/* ── Forced colours ──
   A clipped gradient is invisible on a system palette. Hand the text back. */
@media (forced-colors: active) {
  [data-ui="highlight"] {
    background-image: none;
    -webkit-text-fill-color: currentColor;
    color: inherit;
    animation: none;
  }

  /* The variants paint at a specificity the rule above does not reach, so each
     is named: the gradient's and shimmer's clipped fill, the foil's, the
     outline's stroke and the echo's shadow all go; the text is the system colour. */
  [data-ui="highlight"]:not([data-variant]),
  [data-ui="highlight"][data-variant="gradient"],
  [data-ui="highlight"][data-variant="shimmer"],
  [data-ui="highlight"][data-variant="foil"],
  [data-ui="highlight"][data-variant="outline"],
  [data-ui="highlight"][data-variant="echo"] {
    background-image: none;
    -webkit-text-fill-color: currentColor;
    -webkit-text-stroke: 0;
    text-shadow: none;
    color: inherit;
    animation: none;
  }
}


/* === primitives/icons.css === */
/* @ui:component icon */
/* @ui:tokens */ /* none — icons inherit color (currentColor) and size (1em) from context, by design */
/* Generated by scripts/build-icons.mjs from scripts/icons/curated-icons.txt — DO NOT EDIT BY HAND. */
/* Icons: Lucide (ISC) · lucide-static@1.24.0 · https://lucide.dev · attribution: LICENSE.lucide */

/* ── Base ── */
[data-ui="icon"] {
  display: inline-block;
  width: 1em;
  height: 1em;
  flex-shrink: 0;
  vertical-align: -0.125em;
  background-color: currentColor;
  -webkit-mask: var(--icon) center / contain no-repeat;
  mask: var(--icon) center / contain no-repeat;
}

/* ── Glyphs (120) ── */
[data-icon="activity"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2'/%3E%3C/svg%3E"); }
[data-icon="arrow-down"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 5v14'/%3E%3Cpath d='m19 12-7 7-7-7'/%3E%3C/svg%3E"); }
[data-icon="arrow-left"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m12 19-7-7 7-7'/%3E%3Cpath d='M19 12H5'/%3E%3C/svg%3E"); }
[data-icon="arrow-right"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14'/%3E%3Cpath d='m12 5 7 7-7 7'/%3E%3C/svg%3E"); }
[data-icon="arrow-up"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 12 7-7 7 7'/%3E%3Cpath d='M12 19V5'/%3E%3C/svg%3E"); }
[data-icon="award"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m15.477 12.89 1.515 8.526a.5.5 0 0 1-.81.47l-3.58-2.687a1 1 0 0 0-1.197 0l-3.586 2.686a.5.5 0 0 1-.81-.469l1.514-8.526'/%3E%3Ccircle cx='12' cy='8' r='6'/%3E%3C/svg%3E"); }
[data-icon="bell"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10.268 21a2 2 0 0 0 3.464 0'/%3E%3Cpath d='M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326'/%3E%3C/svg%3E"); }
[data-icon="bold"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 12h9a4 4 0 0 1 0 8H7a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h7a4 4 0 0 1 0 8'/%3E%3C/svg%3E"); }
[data-icon="book"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 19.5v-15A2.5 2.5 0 0 1 6.5 2H19a1 1 0 0 1 1 1v18a1 1 0 0 1-1 1H6.5a1 1 0 0 1 0-5H20'/%3E%3C/svg%3E"); }
[data-icon="bug"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 20v-9'/%3E%3Cpath d='M14 7a4 4 0 0 1 4 4v3a6 6 0 0 1-12 0v-3a4 4 0 0 1 4-4z'/%3E%3Cpath d='M14.12 3.88 16 2'/%3E%3Cpath d='M21 21a4 4 0 0 0-3.81-4'/%3E%3Cpath d='M21 5a4 4 0 0 1-3.55 3.97'/%3E%3Cpath d='M22 13h-4'/%3E%3Cpath d='M3 21a4 4 0 0 1 3.81-4'/%3E%3Cpath d='M3 5a4 4 0 0 0 3.55 3.97'/%3E%3Cpath d='M6 13H2'/%3E%3Cpath d='m8 2 1.88 1.88'/%3E%3Cpath d='M9 7.13V6a3 3 0 1 1 6 0v1.13'/%3E%3C/svg%3E"); }
[data-icon="calendar"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4'/%3E%3Cpath d='M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E"); }
[data-icon="camera"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M13.997 4a2 2 0 0 1 1.76 1.05l.486.9A2 2 0 0 0 18.003 7H20a2 2 0 0 1 2 2v9a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V9a2 2 0 0 1 2-2h1.997a2 2 0 0 0 1.759-1.048l.489-.904A2 2 0 0 1 10.004 4z'/%3E%3Ccircle cx='12' cy='13' r='3'/%3E%3C/svg%3E"); }
[data-icon="chart-column"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 3v16a2 2 0 0 0 2 2h16'/%3E%3Cpath d='M18 17V9'/%3E%3Cpath d='M13 17V5'/%3E%3Cpath d='M8 17v-3'/%3E%3C/svg%3E"); }
[data-icon="chart-line"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 3v16a2 2 0 0 0 2 2h16'/%3E%3Cpath d='m19 9-5 5-4-4-3 3'/%3E%3C/svg%3E"); }
[data-icon="chart-pie"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 12c.552 0 1.005-.449.95-.998a10 10 0 0 0-8.953-8.951c-.55-.055-.998.398-.998.95v8a1 1 0 0 0 1 1z'/%3E%3Cpath d='M21.21 15.89A10 10 0 1 1 8 2.83'/%3E%3C/svg%3E"); }
[data-icon="check"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E"); }
[data-icon="check-check"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 7 17l-5-5'/%3E%3Cpath d='m22 10-7.5 7.5L13 16'/%3E%3C/svg%3E"); }
[data-icon="chevron-down"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E"); }
[data-icon="chevron-left"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m15 18-6-6 6-6'/%3E%3C/svg%3E"); }
[data-icon="chevron-right"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m9 18 6-6-6-6'/%3E%3C/svg%3E"); }
[data-icon="chevron-up"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m18 15-6-6-6 6'/%3E%3C/svg%3E"); }
[data-icon="circle"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3C/svg%3E"); }
[data-icon="circle-alert"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cline x1='12' x2='12' y1='8' y2='12'/%3E%3Cline x1='12' x2='12.01' y1='16' y2='16'/%3E%3C/svg%3E"); }
[data-icon="circle-check"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpath d='m9 12 2 2 4-4'/%3E%3C/svg%3E"); }
[data-icon="circle-question-mark"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpath d='M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3'/%3E%3Cpath d='M12 17h.01'/%3E%3C/svg%3E"); }
[data-icon="circle-user"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Ccircle cx='12' cy='10' r='3'/%3E%3Cpath d='M7 20.662V19a2 2 0 0 1 2-2h6a2 2 0 0 1 2 2v1.662'/%3E%3C/svg%3E"); }
[data-icon="circle-x"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpath d='m15 9-6 6'/%3E%3Cpath d='m9 9 6 6'/%3E%3C/svg%3E"); }
[data-icon="clipboard"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='8' height='4' x='8' y='2' rx='1' ry='1'/%3E%3Cpath d='M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2'/%3E%3C/svg%3E"); }
[data-icon="clock"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpath d='M12 6v6l4 2'/%3E%3C/svg%3E"); }
[data-icon="cloud"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M17.5 19H9a7 7 0 1 1 6.71-9h1.79a4.5 4.5 0 1 1 0 9Z'/%3E%3C/svg%3E"); }
[data-icon="code"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m16 18 6-6-6-6'/%3E%3Cpath d='m8 6-6 6 6 6'/%3E%3C/svg%3E"); }
[data-icon="compass"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpath d='m16.24 7.76-1.804 5.411a2 2 0 0 1-1.265 1.265L7.76 16.24l1.804-5.411a2 2 0 0 1 1.265-1.265z'/%3E%3C/svg%3E"); }
[data-icon="copy"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='14' height='14' x='8' y='8' rx='2' ry='2'/%3E%3Cpath d='M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2'/%3E%3C/svg%3E"); }
[data-icon="cpu"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 20v2'/%3E%3Cpath d='M12 2v2'/%3E%3Cpath d='M17 20v2'/%3E%3Cpath d='M17 2v2'/%3E%3Cpath d='M2 12h2'/%3E%3Cpath d='M2 17h2'/%3E%3Cpath d='M2 7h2'/%3E%3Cpath d='M20 12h2'/%3E%3Cpath d='M20 17h2'/%3E%3Cpath d='M20 7h2'/%3E%3Cpath d='M7 20v2'/%3E%3Cpath d='M7 2v2'/%3E%3Crect x='4' y='4' width='16' height='16' rx='2'/%3E%3Crect x='8' y='8' width='8' height='8' rx='1'/%3E%3C/svg%3E"); }
[data-icon="credit-card"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='14' x='2' y='5' rx='2'/%3E%3Cline x1='2' x2='22' y1='10' y2='10'/%3E%3C/svg%3E"); }
[data-icon="database"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cellipse cx='12' cy='5' rx='9' ry='3'/%3E%3Cpath d='M3 5V19A9 3 0 0 0 21 19V5'/%3E%3Cpath d='M3 12A9 3 0 0 0 21 12'/%3E%3C/svg%3E"); }
[data-icon="dollar-sign"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='12' x2='12' y1='2' y2='22'/%3E%3Cpath d='M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6'/%3E%3C/svg%3E"); }
[data-icon="download"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 15V3'/%3E%3Cpath d='M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4'/%3E%3Cpath d='m7 10 5 5 5-5'/%3E%3C/svg%3E"); }
[data-icon="ellipsis"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='1'/%3E%3Ccircle cx='19' cy='12' r='1'/%3E%3Ccircle cx='5' cy='12' r='1'/%3E%3C/svg%3E"); }
[data-icon="external-link"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M15 3h6v6'/%3E%3Cpath d='M10 14 21 3'/%3E%3Cpath d='M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6'/%3E%3C/svg%3E"); }
[data-icon="eye"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0'/%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3C/svg%3E"); }
[data-icon="eye-off"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49'/%3E%3Cpath d='M14.084 14.158a3 3 0 0 1-4.242-4.242'/%3E%3Cpath d='M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143'/%3E%3Cpath d='m2 2 20 20'/%3E%3C/svg%3E"); }
[data-icon="file"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z'/%3E%3Cpath d='M14 2v5a1 1 0 0 0 1 1h5'/%3E%3C/svg%3E"); }
[data-icon="file-text"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z'/%3E%3Cpath d='M14 2v5a1 1 0 0 0 1 1h5'/%3E%3Cpath d='M10 9H8'/%3E%3Cpath d='M16 13H8'/%3E%3Cpath d='M16 17H8'/%3E%3C/svg%3E"); }
[data-icon="folder"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z'/%3E%3C/svg%3E"); }
[data-icon="folder-open"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2'/%3E%3C/svg%3E"); }
[data-icon="funnel"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10 20a1 1 0 0 0 .553.895l2 1A1 1 0 0 0 14 21v-7a2 2 0 0 1 .517-1.341L21.74 4.67A1 1 0 0 0 21 3H3a1 1 0 0 0-.742 1.67l7.225 7.989A2 2 0 0 1 10 14z'/%3E%3C/svg%3E"); }
[data-icon="git-branch"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M15 6a9 9 0 0 0-9 9V3'/%3E%3Ccircle cx='18' cy='6' r='3'/%3E%3Ccircle cx='6' cy='18' r='3'/%3E%3C/svg%3E"); }
[data-icon="globe"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpath d='M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20'/%3E%3Cpath d='M2 12h20'/%3E%3C/svg%3E"); }
[data-icon="hash"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='4' x2='20' y1='9' y2='9'/%3E%3Cline x1='4' x2='20' y1='15' y2='15'/%3E%3Cline x1='10' x2='8' y1='3' y2='21'/%3E%3Cline x1='16' x2='14' y1='3' y2='21'/%3E%3C/svg%3E"); }
[data-icon="heart"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2 9.5a5.5 5.5 0 0 1 9.591-3.676.56.56 0 0 0 .818 0A5.49 5.49 0 0 1 22 9.5c0 2.29-1.5 4-3 5.5l-5.492 5.313a2 2 0 0 1-3 .019L5 15c-1.5-1.5-3-3.2-3-5.5'/%3E%3C/svg%3E"); }
[data-icon="house"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8'/%3E%3Cpath d='M3 10a2 2 0 0 1 .709-1.528l7-6a2 2 0 0 1 2.582 0l7 6A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z'/%3E%3C/svg%3E"); }
[data-icon="image"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='18' height='18' x='3' y='3' rx='2' ry='2'/%3E%3Ccircle cx='9' cy='9' r='2'/%3E%3Cpath d='m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21'/%3E%3C/svg%3E"); }
[data-icon="info"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpath d='M12 16v-4'/%3E%3Cpath d='M12 8h.01'/%3E%3C/svg%3E"); }
[data-icon="italic"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='19' x2='10' y1='4' y2='4'/%3E%3Cline x1='14' x2='5' y1='20' y2='20'/%3E%3Cline x1='15' x2='9' y1='4' y2='20'/%3E%3C/svg%3E"); }
[data-icon="key"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m15.5 7.5 2.3 2.3a1 1 0 0 0 1.4 0l2.1-2.1a1 1 0 0 0 0-1.4L19 4'/%3E%3Cpath d='m21 2-9.6 9.6'/%3E%3Ccircle cx='7.5' cy='15.5' r='5.5'/%3E%3C/svg%3E"); }
[data-icon="layers"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83z'/%3E%3Cpath d='M2 12a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 12'/%3E%3Cpath d='M2 17a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 17'/%3E%3C/svg%3E"); }
[data-icon="link"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71'/%3E%3Cpath d='M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71'/%3E%3C/svg%3E"); }
[data-icon="list"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 5h.01'/%3E%3Cpath d='M3 12h.01'/%3E%3Cpath d='M3 19h.01'/%3E%3Cpath d='M8 5h13'/%3E%3Cpath d='M8 12h13'/%3E%3Cpath d='M8 19h13'/%3E%3C/svg%3E"); }
[data-icon="loader-circle"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 12a9 9 0 1 1-6.219-8.56'/%3E%3C/svg%3E"); }
[data-icon="lock"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='18' height='11' x='3' y='11' rx='2' ry='2'/%3E%3Cpath d='M7 11V7a5 5 0 0 1 10 0v4'/%3E%3C/svg%3E"); }
[data-icon="lock-open"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='18' height='11' x='3' y='11' rx='2' ry='2'/%3E%3Cpath d='M7 11V7a5 5 0 0 1 9.9-1'/%3E%3C/svg%3E"); }
[data-icon="log-in"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m10 17 5-5-5-5'/%3E%3Cpath d='M15 12H3'/%3E%3Cpath d='M15 3h4a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2h-4'/%3E%3C/svg%3E"); }
[data-icon="log-out"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m16 17 5-5-5-5'/%3E%3Cpath d='M21 12H9'/%3E%3Cpath d='M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4'/%3E%3C/svg%3E"); }
[data-icon="mail"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m22 7-8.991 5.727a2 2 0 0 1-2.009 0L2 7'/%3E%3Crect x='2' y='4' width='20' height='16' rx='2'/%3E%3C/svg%3E"); }
[data-icon="map"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14.106 5.553a2 2 0 0 0 1.788 0l3.659-1.83A1 1 0 0 1 21 4.619v12.764a1 1 0 0 1-.553.894l-4.553 2.277a2 2 0 0 1-1.788 0l-4.212-2.106a2 2 0 0 0-1.788 0l-3.659 1.83A1 1 0 0 1 3 19.381V6.618a1 1 0 0 1 .553-.894l4.553-2.277a2 2 0 0 1 1.788 0z'/%3E%3Cpath d='M15 5.764v15'/%3E%3Cpath d='M9 3.236v15'/%3E%3C/svg%3E"); }
[data-icon="map-pin"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 10c0 4.993-5.539 10.193-7.399 11.799a1 1 0 0 1-1.202 0C9.539 20.193 4 14.993 4 10a8 8 0 0 1 16 0'/%3E%3Ccircle cx='12' cy='10' r='3'/%3E%3C/svg%3E"); }
[data-icon="maximize"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 3H5a2 2 0 0 0-2 2v3'/%3E%3Cpath d='M21 8V5a2 2 0 0 0-2-2h-3'/%3E%3Cpath d='M3 16v3a2 2 0 0 0 2 2h3'/%3E%3Cpath d='M16 21h3a2 2 0 0 0 2-2v-3'/%3E%3C/svg%3E"); }
[data-icon="menu"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 5h16'/%3E%3Cpath d='M4 12h16'/%3E%3Cpath d='M4 19h16'/%3E%3C/svg%3E"); }
[data-icon="message-circle"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.992 16.342a2 2 0 0 1 .094 1.167l-1.065 3.29a1 1 0 0 0 1.236 1.168l3.413-.998a2 2 0 0 1 1.099.092 10 10 0 1 0-4.777-4.719'/%3E%3C/svg%3E"); }
[data-icon="message-square"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z'/%3E%3C/svg%3E"); }
[data-icon="mic"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 19v3'/%3E%3Cpath d='M19 10v2a7 7 0 0 1-14 0v-2'/%3E%3Crect x='9' y='2' width='6' height='13' rx='3'/%3E%3C/svg%3E"); }
[data-icon="minus"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14'/%3E%3C/svg%3E"); }
[data-icon="moon"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401'/%3E%3C/svg%3E"); }
[data-icon="move"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 2v20'/%3E%3Cpath d='m15 19-3 3-3-3'/%3E%3Cpath d='m19 9 3 3-3 3'/%3E%3Cpath d='M2 12h20'/%3E%3Cpath d='m5 9-3 3 3 3'/%3E%3Cpath d='m9 5 3-3 3 3'/%3E%3C/svg%3E"); }
[data-icon="music"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9 18V5l12-2v13'/%3E%3Ccircle cx='6' cy='18' r='3'/%3E%3Ccircle cx='18' cy='16' r='3'/%3E%3C/svg%3E"); }
[data-icon="package"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M11 21.73a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73z'/%3E%3Cpath d='M12 22V12'/%3E%3Cpolyline points='3.29 7 12 12 20.71 7'/%3E%3Cpath d='m7.5 4.27 9 5.15'/%3E%3C/svg%3E"); }
[data-icon="paperclip"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m16 6-8.414 8.586a2 2 0 0 0 2.829 2.829l8.414-8.586a4 4 0 1 0-5.657-5.657l-8.379 8.551a6 6 0 1 0 8.485 8.485l8.379-8.551'/%3E%3C/svg%3E"); }
[data-icon="pause"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='14' y='3' width='5' height='18' rx='1'/%3E%3Crect x='5' y='3' width='5' height='18' rx='1'/%3E%3C/svg%3E"); }
[data-icon="pencil"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z'/%3E%3Cpath d='m15 5 4 4'/%3E%3C/svg%3E"); }
[data-icon="phone"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M13.832 16.568a1 1 0 0 0 1.213-.303l.355-.465A2 2 0 0 1 17 15h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2A18 18 0 0 1 2 4a2 2 0 0 1 2-2h3a2 2 0 0 1 2 2v3a2 2 0 0 1-.8 1.6l-.468.351a1 1 0 0 0-.292 1.233 14 14 0 0 0 6.392 6.384'/%3E%3C/svg%3E"); }
[data-icon="play"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z'/%3E%3C/svg%3E"); }
[data-icon="plus"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 12h14'/%3E%3Cpath d='M12 5v14'/%3E%3C/svg%3E"); }
[data-icon="printer"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2'/%3E%3Cpath d='M6 9V3a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v6'/%3E%3Crect x='6' y='14' width='12' height='8' rx='1'/%3E%3C/svg%3E"); }
[data-icon="refresh-cw"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8'/%3E%3Cpath d='M21 3v5h-5'/%3E%3Cpath d='M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16'/%3E%3Cpath d='M8 16H3v5'/%3E%3C/svg%3E"); }
[data-icon="save"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M15.2 3a2 2 0 0 1 1.4.6l3.8 3.8a2 2 0 0 1 .6 1.4V19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2z'/%3E%3Cpath d='M17 21v-7a1 1 0 0 0-1-1H8a1 1 0 0 0-1 1v7'/%3E%3Cpath d='M7 3v4a1 1 0 0 0 1 1h7'/%3E%3C/svg%3E"); }
[data-icon="search"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m21 21-4.34-4.34'/%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3C/svg%3E"); }
[data-icon="send"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z'/%3E%3Cpath d='m21.854 2.147-10.94 10.939'/%3E%3C/svg%3E"); }
[data-icon="server"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect width='20' height='8' x='2' y='2' rx='2' ry='2'/%3E%3Crect width='20' height='8' x='2' y='14' rx='2' ry='2'/%3E%3Cline x1='6' x2='6.01' y1='6' y2='6'/%3E%3Cline x1='6' x2='6.01' y1='18' y2='18'/%3E%3C/svg%3E"); }
[data-icon="settings"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M9.671 4.136a2.34 2.34 0 0 1 4.659 0 2.34 2.34 0 0 0 3.319 1.915 2.34 2.34 0 0 1 2.33 4.033 2.34 2.34 0 0 0 0 3.831 2.34 2.34 0 0 1-2.33 4.033 2.34 2.34 0 0 0-3.319 1.915 2.34 2.34 0 0 1-4.659 0 2.34 2.34 0 0 0-3.32-1.915 2.34 2.34 0 0 1-2.33-4.033 2.34 2.34 0 0 0 0-3.831A2.34 2.34 0 0 1 6.35 6.051a2.34 2.34 0 0 0 3.319-1.915'/%3E%3Ccircle cx='12' cy='12' r='3'/%3E%3C/svg%3E"); }
[data-icon="share-2"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='18' cy='5' r='3'/%3E%3Ccircle cx='6' cy='12' r='3'/%3E%3Ccircle cx='18' cy='19' r='3'/%3E%3Cline x1='8.59' x2='15.42' y1='13.51' y2='17.49'/%3E%3Cline x1='15.41' x2='8.59' y1='6.51' y2='10.49'/%3E%3C/svg%3E"); }
[data-icon="shield"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z'/%3E%3C/svg%3E"); }
[data-icon="shield-check"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z'/%3E%3Cpath d='m9 12 2 2 4-4'/%3E%3C/svg%3E"); }
[data-icon="shopping-cart"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='8' cy='21' r='1'/%3E%3Ccircle cx='19' cy='21' r='1'/%3E%3Cpath d='M2.05 2.05h2l2.66 12.42a2 2 0 0 0 2 1.58h9.78a2 2 0 0 0 1.95-1.57l1.65-7.43H5.12'/%3E%3C/svg%3E"); }
[data-icon="skip-forward"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 4v16'/%3E%3Cpath d='M6.029 4.285A2 2 0 0 0 3 6v12a2 2 0 0 0 3.029 1.715l9.997-5.998a2 2 0 0 0 .003-3.432z'/%3E%3C/svg%3E"); }
[data-icon="sliders-horizontal"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10 5H3'/%3E%3Cpath d='M12 19H3'/%3E%3Cpath d='M14 3v4'/%3E%3Cpath d='M16 17v4'/%3E%3Cpath d='M21 12h-9'/%3E%3Cpath d='M21 19h-5'/%3E%3Cpath d='M21 5h-7'/%3E%3Cpath d='M8 10v4'/%3E%3Cpath d='M8 12H3'/%3E%3C/svg%3E"); }
[data-icon="sparkles"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z'/%3E%3Cpath d='M20 2v4'/%3E%3Cpath d='M22 4h-4'/%3E%3Ccircle cx='4' cy='20' r='2'/%3E%3C/svg%3E"); }
[data-icon="star"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M11.525 2.295a.53.53 0 0 1 .95 0l2.31 4.679a2.123 2.123 0 0 0 1.595 1.16l5.166.756a.53.53 0 0 1 .294.904l-3.736 3.638a2.123 2.123 0 0 0-.611 1.878l.882 5.14a.53.53 0 0 1-.771.56l-4.618-2.428a2.122 2.122 0 0 0-1.973 0L6.396 21.01a.53.53 0 0 1-.77-.56l.881-5.139a2.122 2.122 0 0 0-.611-1.879L2.16 9.795a.53.53 0 0 1 .294-.906l5.165-.755a2.122 2.122 0 0 0 1.597-1.16z'/%3E%3C/svg%3E"); }
[data-icon="sun"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='4'/%3E%3Cpath d='M12 2v2'/%3E%3Cpath d='M12 20v2'/%3E%3Cpath d='m4.93 4.93 1.41 1.41'/%3E%3Cpath d='m17.66 17.66 1.41 1.41'/%3E%3Cpath d='M2 12h2'/%3E%3Cpath d='M20 12h2'/%3E%3Cpath d='m6.34 17.66-1.41 1.41'/%3E%3Cpath d='m19.07 4.93-1.41 1.41'/%3E%3C/svg%3E"); }
[data-icon="tag"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z'/%3E%3Ccircle cx='7.5' cy='7.5' r='.5' fill='currentColor'/%3E%3C/svg%3E"); }
[data-icon="target"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Ccircle cx='12' cy='12' r='6'/%3E%3Ccircle cx='12' cy='12' r='2'/%3E%3C/svg%3E"); }
[data-icon="terminal"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 19h8'/%3E%3Cpath d='m4 17 6-6-6-6'/%3E%3C/svg%3E"); }
[data-icon="text-align-start"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M21 5H3'/%3E%3Cpath d='M15 12H3'/%3E%3Cpath d='M17 19H3'/%3E%3C/svg%3E"); }
[data-icon="thumbs-up"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M15 5.88 14 10h5.83a2 2 0 0 1 1.92 2.56l-2.33 8A2 2 0 0 1 17.5 22H4a2 2 0 0 1-2-2v-8a2 2 0 0 1 2-2h2.76a2 2 0 0 0 1.79-1.11L12 2a3.13 3.13 0 0 1 3 3.88Z'/%3E%3Cpath d='M7 10v12'/%3E%3C/svg%3E"); }
[data-icon="timer"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='10' x2='14' y1='2' y2='2'/%3E%3Cline x1='12' x2='15' y1='14' y2='11'/%3E%3Ccircle cx='12' cy='14' r='8'/%3E%3C/svg%3E"); }
[data-icon="trash-2"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M10 11v6'/%3E%3Cpath d='M14 11v6'/%3E%3Cpath d='M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6'/%3E%3Cpath d='M3 6h18'/%3E%3Cpath d='M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2'/%3E%3C/svg%3E"); }
[data-icon="trending-up"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M16 7h6v6'/%3E%3Cpath d='m22 7-8.5 8.5-5-5L2 17'/%3E%3C/svg%3E"); }
[data-icon="triangle-alert"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3'/%3E%3Cpath d='M12 9v4'/%3E%3Cpath d='M12 17h.01'/%3E%3C/svg%3E"); }
[data-icon="type"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 4v16'/%3E%3Cpath d='M4 7V5a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v2'/%3E%3Cpath d='M9 20h6'/%3E%3C/svg%3E"); }
[data-icon="underline"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 4v6a6 6 0 0 0 12 0V4'/%3E%3Cline x1='4' x2='20' y1='20' y2='20'/%3E%3C/svg%3E"); }
[data-icon="upload"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 3v12'/%3E%3Cpath d='m17 8-5-5-5 5'/%3E%3Cpath d='M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4'/%3E%3C/svg%3E"); }
[data-icon="user"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2'/%3E%3Ccircle cx='12' cy='7' r='4'/%3E%3C/svg%3E"); }
[data-icon="user-plus"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2'/%3E%3Ccircle cx='9' cy='7' r='4'/%3E%3Cline x1='19' x2='19' y1='8' y2='14'/%3E%3Cline x1='22' x2='16' y1='11' y2='11'/%3E%3C/svg%3E"); }
[data-icon="users"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2'/%3E%3Cpath d='M16 3.128a4 4 0 0 1 0 7.744'/%3E%3Cpath d='M22 21v-2a4 4 0 0 0-3-3.87'/%3E%3Ccircle cx='9' cy='7' r='4'/%3E%3C/svg%3E"); }
[data-icon="video"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m16 13 5.223 3.482a.5.5 0 0 0 .777-.416V7.87a.5.5 0 0 0-.752-.432L16 10.5'/%3E%3Crect x='2' y='6' width='14' height='12' rx='2'/%3E%3C/svg%3E"); }
[data-icon="volume-2"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M11 4.702a.705.705 0 0 0-1.203-.498L6.413 7.587A1.4 1.4 0 0 1 5.416 8H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2.416a1.4 1.4 0 0 1 .997.413l3.383 3.384A.705.705 0 0 0 11 19.298z'/%3E%3Cpath d='M16 9a5 5 0 0 1 0 6'/%3E%3Cpath d='M19.364 18.364a9 9 0 0 0 0-12.728'/%3E%3C/svg%3E"); }
[data-icon="wallet"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M19 7V4a1 1 0 0 0-1-1H5a2 2 0 0 0 0 4h15a1 1 0 0 1 1 1v4h-3a2 2 0 0 0 0 4h3a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1'/%3E%3Cpath d='M3 5v14a2 2 0 0 0 2 2h15a1 1 0 0 0 1-1v-4'/%3E%3C/svg%3E"); }
[data-icon="wifi"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 20h.01'/%3E%3Cpath d='M2 8.82a15 15 0 0 1 20 0'/%3E%3Cpath d='M5 12.859a10 10 0 0 1 14 0'/%3E%3Cpath d='M8.5 16.429a5 5 0 0 1 7 0'/%3E%3C/svg%3E"); }
[data-icon="x"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M18 6 6 18'/%3E%3Cpath d='m6 6 12 12'/%3E%3C/svg%3E"); }
[data-icon="zap"] { --icon: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 14a1 1 0 0 1-.78-1.63l9.9-10.2a.5.5 0 0 1 .86.46l-1.92 6.02A1 1 0 0 0 13 10h7a1 1 0 0 1 .78 1.63l-9.9 10.2a.5.5 0 0 1-.86-.46l1.92-6.02A1 1 0 0 0 11 14z'/%3E%3C/svg%3E"); }


/* === primitives/image.css === */
/* @ui:component image */
/* @ui:tokens color-bg-muted color-fg-muted radius-md space-2 space-1 text-xs font-body image-radius image-border-width image-border image-caption-size image-caption-color doc-font duration-normal duration-slower ease-out ease-emphasized ease-default */

/* ── Base ── */
[data-ui="image"] {
  display: inline-block;
  margin: 0;
  padding: 0;
  line-height: 0;
  max-width: 100%;
}

/* ── Image Element ── */
[data-ui="image"] > [data-part="img"] {
  display: block;
  max-width: 100%;
  height: auto;
  border-radius: var(--image-radius);
  border: var(--image-border-width) solid var(--image-border);
}

/* ── Caption ── */
[data-ui="image"] > [data-part="caption"] {
  display: block;
  margin-top: var(--space-2);
  font-family: var(--doc-font, var(--font-body));
  font-size: var(--image-caption-size);
  color: var(--image-caption-color);
  line-height: 1.4;
  text-align: center;
}

/* ── Variant: Responsive (default) ── */
[data-ui="image"][data-variant="responsive"] > [data-part="img"],
[data-ui="image"]:not([data-variant]) > [data-part="img"] {
  width: 100%;
  height: auto;
  object-fit: contain;
}

/* ── Variant: Thumbnail ── */
[data-ui="image"][data-variant="thumbnail"] {
  border-radius: var(--image-radius);
  overflow: hidden;
}

[data-ui="image"][data-variant="thumbnail"] > [data-part="img"] {
  aspect-ratio: 1;
  object-fit: cover;
  border-radius: 0;
}

/* ── Variant: Cover ── */
[data-ui="image"][data-variant="cover"] {
  width: 100%;
}

[data-ui="image"][data-variant="cover"] > [data-part="img"] {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 0;
}

/* ── Variant: Contain ── */
[data-ui="image"][data-variant="contain"] {
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-bg-muted);
  border-radius: var(--image-radius);
  overflow: hidden;
}

[data-ui="image"][data-variant="contain"] > [data-part="img"] {
  max-width: 100%;
  max-height: 100%;
  object-fit: contain;
  border-radius: 0;
}

/* ── Size: XS (48px) ── */
[data-ui="image"][data-size="xs"] {
  max-width: 48px;
}

/* ── Size: SM (96px) ── */
[data-ui="image"][data-size="sm"] {
  max-width: 96px;
}

/* ── Size: MD (192px) ── */
[data-ui="image"][data-size="md"],
[data-ui="image"]:not([data-size]) {
  max-width: 192px;
}

/* ── Size: LG (384px) ── */
[data-ui="image"][data-size="lg"] {
  max-width: 384px;
}

/* ── Size: Full (100%) ── */
[data-ui="image"][data-size="full"] {
  max-width: 100%;
  width: 100%;
}

/* ── Print ── */
@media print {
  [data-ui="image"] > [data-part="img"] {
    max-width: 100%;
    break-inside: avoid;
  }

  [data-ui="image"][data-size="full"] {
    max-width: 80%;
  }
}

/* ── Hover ──
   What a picture does under the pointer. `zoom` leans into the frame (the
   figure clips, so the image grows without growing the layout), `lift` rises,
   `fade` dims to say "this is a link". Focus-within gives a wrapped link the
   same cue from the keyboard. */
[data-ui="image"][data-hover] {
  transition: translate var(--duration-normal) var(--ease-out);
}

[data-ui="image"][data-hover="zoom"] {
  overflow: hidden;
  border-radius: var(--image-radius);
}

[data-ui="image"][data-hover="zoom"] > [data-part="img"] {
  transition: scale var(--duration-slower) var(--ease-emphasized);
}

[data-ui="image"][data-hover="zoom"]:hover > [data-part="img"],
[data-ui="image"][data-hover="zoom"]:focus-within > [data-part="img"] {
  scale: 1.05;
}

[data-ui="image"][data-hover="lift"]:hover,
[data-ui="image"][data-hover="lift"]:focus-within {
  translate: 0 calc(var(--space-1) * -1);
}

[data-ui="image"][data-hover="fade"] > [data-part="img"] {
  transition: opacity var(--duration-normal) var(--ease-default);
}

[data-ui="image"][data-hover="fade"]:hover > [data-part="img"],
[data-ui="image"][data-hover="fade"]:focus-within > [data-part="img"] {
  opacity: 0.8;
}

@media (prefers-reduced-motion: reduce) {
  [data-ui="image"][data-hover],
  [data-ui="image"][data-hover] > [data-part="img"] {
    transition: none;
  }
}


/* === primitives/input.css === */
/* @ui:component input */
/* @ui:tokens color-fg color-fg-muted color-border color-border-strong color-ring color-destructive radius-md space-2 space-3 space-4 space-10 font-ui text-xs text-sm text-base duration-fast ease-default border-width corner-shape focus-ring-width focus-ring-style focus-ring-color focus-shadow input-border-width input-fill input-height input-radius input-font disabled-opacity */

/* ── Base ── */
[data-ui="input"] {
  display: block;
  width: 100%;
  height: var(--input-height, 40px);
  padding-inline: var(--space-3);
  /* Longhands, not the `border:` shorthand: the shorthand's width slot takes
     ONE value, and `controls.input: underline` (1.1A-10) states the silhouette
     as a four-value box — `0 0 var(--border-width) 0` — so only a bottom rule
     is drawn. Identical to the shorthand at every other value of the token. */
  border-style: solid;
  border-color: var(--color-border);
  border-width: var(--input-border-width);
  border-radius: var(--input-radius, var(--radius-md));
  corner-shape: var(--corner-shape);
  background: var(--input-fill);
  color: var(--color-fg);
  font-family: var(--input-font, var(--font-ui));
  font-size: var(--text-sm);
  line-height: 1;
  transition: border-color var(--duration-fast) var(--ease-default),
              box-shadow var(--duration-fast) var(--ease-default);
}

[data-ui="input"]::placeholder {
  color: var(--color-fg-muted);
}

[data-ui="input"]:hover {
  border-color: var(--color-border-strong);
}

[data-ui="input"]:focus {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  /* The ring replaces the border rather than sitting outside it: inset by
     exactly the edge it covers, so a heavier shape theme stays aligned. */
  outline-offset: calc(-1 * var(--input-border-width));
  box-shadow: var(--focus-shadow);
  border-color: transparent;
}

/* ── Sizes ── */
[data-ui="input"][data-size="sm"] {
  height: 32px;
  padding-inline: var(--space-2);
  font-size: var(--text-xs);
}

[data-ui="input"][data-size="lg"] {
  height: 48px;
  padding-inline: var(--space-4);
  font-size: var(--text-base);
}

/* ── States ── */
[data-ui="input"][data-state="error"],
[data-ui="input"][aria-invalid="true"] {
  border-color: var(--color-destructive);
}
[data-ui="input"][data-state="error"]:focus,
[data-ui="input"][aria-invalid="true"]:focus {
  outline-color: var(--color-destructive);
}

[data-ui="input"]:disabled {
  opacity: var(--disabled-opacity);
  cursor: not-allowed;
}

/* ── Input Group ── */
[data-ui="input-group"] {
  display: flex;
  align-items: center;
  position: relative;
}

[data-ui="input-group"] > [data-part="prefix"],
[data-ui="input-group"] > [data-part="suffix"] {
  display: flex;
  align-items: center;
  padding-inline: var(--space-3);
  color: var(--color-fg-muted);
  font-size: var(--text-sm);
  pointer-events: none;
  position: absolute;
}

[data-ui="input-group"] > [data-part="prefix"] {
  inset-inline-start: 0;
}

[data-ui="input-group"] > [data-part="suffix"] {
  inset-inline-end: 0;
}

[data-ui="input-group"]:has(> [data-part="prefix"]) [data-ui="input"] {
  padding-inline-start: var(--space-10, 2.5rem);
}

[data-ui="input-group"]:has(> [data-part="suffix"]) [data-ui="input"] {
  padding-inline-end: var(--space-10, 2.5rem);
}

/* ── Width Variants ──
   Mobile-first (task 0.8-08): a fixed-width input is full-bleed on a phone and
   only takes its fixed cap from the canon `sm` tier up. The 1.x form said the
   same thing backwards — a 250px base undone by `@media (max-width: 640px)` —
   which put the narrow case behind an override and the wide case in the base. */
[data-ui="input"][data-width="fixed"] {
  max-width: 100%;
  width: 100%;
}

@media (min-width: 40rem) {
  [data-ui="input"][data-width="fixed"] {
    max-width: 250px;
  }
}

/* ── Motion ── */
@media (prefers-reduced-motion: reduce) {
  [data-ui="input"] {
    transition: none;
  }
}


/* === primitives/kbd.css === */
/* @ui:component kbd */
/* @ui:tokens color-bg-subtle color-fg color-border radius-sm space-1h font-mono text-xs border-width border-width-strong mono-ligatures */

/* ── Base ── */
[data-ui="kbd"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 20px;
  min-width: 20px;
  padding-inline: var(--space-1h);
  border: var(--border-width) solid var(--color-border);
  border-bottom-width: var(--border-width-strong);
  border-radius: var(--radius-sm);
  background: var(--color-bg-subtle);
  color: var(--color-fg);
  font-family: var(--font-mono);
  font-variant-ligatures: var(--mono-ligatures);
  font-size: var(--text-xs);
  line-height: 1;
  white-space: nowrap;
  user-select: none;
}


/* === primitives/key-value.css === */
/* @ui:component key-value */
/* @ui:tokens color-fg color-fg-muted space-1 space-2 space-3 space-4 text-xs text-sm text-base font-body weight-medium kv-pair-gap kv-label-size kv-label-weight kv-label-color kv-value-size kv-value-weight kv-value-color kv-gap kv-grid-gap doc-font */

/* ── Base ── */
[data-ui="key-value"] {
  display: flex;
  flex-direction: column;
  gap: var(--kv-pair-gap);
  margin: 0;
  padding: 0;
  font-family: var(--doc-font, var(--font-body));
}

/* A label or value is the list's child, or the child of a plain <div> that
   groups one pair (HTML allows `dl > div > dt + dd`). Never a descendant
   further down: `label` is a common part name, and a progress bar in a value
   used to take this list's label size and weight. The <div> hop is `:where()`,
   so both shapes weigh the same, and `:not([data-ui])` keeps a component out
   of the grouping role. [1.1F-20] */

/* ── Label ── */
[data-ui="key-value"] > [data-part="label"],
[data-ui="key-value"] > :where(div:not([data-ui])) > [data-part="label"] {
  font-size: var(--kv-label-size);
  font-weight: var(--kv-label-weight);
  color: var(--kv-label-color);
  margin: 0;
  padding: 0;
  flex-shrink: 0;
}

/* ── Value ──
   The value is the cell that carries unbreakable data: an IBAN, a reference, a
   hash. In the `1fr` track of the grid variants its automatic minimum size is
   its min-content width, so one 24-character IBAN sizes the whole grid wider
   than a phone window and every later row bleeds with it. `anywhere` (not
   `break-word`, which is ignored when min-content is computed) lets the track
   floor drop, and `min-inline-size: 0` removes the grid item's own floor. */
[data-ui="key-value"] > [data-part="value"],
[data-ui="key-value"] > :where(div:not([data-ui])) > [data-part="value"] {
  font-size: var(--kv-value-size);
  font-weight: var(--kv-value-weight);
  color: var(--kv-value-color);
  margin: 0;
  padding: 0;
  min-inline-size: 0;
  overflow-wrap: anywhere;
}

/* ── Variant: Horizontal (default) ── */
[data-ui="key-value"][data-variant="horizontal"],
[data-ui="key-value"]:not([data-variant]) {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--kv-gap) var(--kv-grid-gap);
  align-items: baseline;
}

[data-ui="key-value"][data-variant="horizontal"] > [data-part="value"],
[data-ui="key-value"][data-variant="horizontal"] > :where(div:not([data-ui])) > [data-part="value"],
[data-ui="key-value"]:not([data-variant]) > [data-part="value"],
[data-ui="key-value"]:not([data-variant]) > :where(div:not([data-ui])) > [data-part="value"] {
  text-align: end;
}

/* ── Variant: Vertical ── */
[data-ui="key-value"][data-variant="vertical"] {
  display: flex;
  flex-direction: column;
  gap: var(--kv-pair-gap);
}

[data-ui="key-value"][data-variant="vertical"] > [data-part="label"],
[data-ui="key-value"][data-variant="vertical"] > :where(div:not([data-ui])) > [data-part="label"] {
  margin-bottom: calc(-1 * var(--kv-gap));
}

/* ── Variant: Inline ── */
[data-ui="key-value"][data-variant="inline"] {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  gap: var(--kv-gap);
  align-items: baseline;
}

[data-ui="key-value"][data-variant="inline"] > [data-part="label"]::after,
[data-ui="key-value"][data-variant="inline"] > :where(div:not([data-ui])) > [data-part="label"]::after {
  content: ":";
}

[data-ui="key-value"][data-variant="inline"] > [data-part="value"],
[data-ui="key-value"][data-variant="inline"] > :where(div:not([data-ui])) > [data-part="value"] {
  margin-inline-end: var(--kv-grid-gap);
}

/* ── Grid Columns ── */
[data-ui="key-value"][data-cols="2"] {
  display: grid;
  grid-template-columns: auto 1fr auto 1fr;
  gap: var(--kv-gap) var(--kv-grid-gap);
  align-items: baseline;
}

[data-ui="key-value"][data-cols="3"] {
  display: grid;
  grid-template-columns: auto 1fr auto 1fr auto 1fr;
  gap: var(--kv-gap) var(--kv-grid-gap);
  align-items: baseline;
}

[data-ui="key-value"][data-cols="4"] {
  display: grid;
  grid-template-columns: auto 1fr auto 1fr auto 1fr auto 1fr;
  gap: var(--kv-gap) var(--kv-grid-gap);
  align-items: baseline;
}

[data-ui="key-value"][data-cols] > [data-part="value"],
[data-ui="key-value"][data-cols] > :where(div:not([data-ui])) > [data-part="value"] {
  text-align: end;
}

/* ── Grouped pairs in the grid and inline layouts ──
   `dl > div > dt + dd` is valid HTML and the manifest allows it, but in a grid
   or a flex row the <div> is ONE item: three grouped pairs in the horizontal
   grid laid out as label+value cells of the div's own block, and a data-cols
   grid put two whole pairs in each row. `display: contents` takes the plain
   grouping <div> out of the box tree, so its label and value are the grid's
   (or the row's) items exactly as ungrouped ones are. A <div> has no role to
   lose, so nothing changes for assistive technology. The vertical variant
   stacks a block <div> correctly and keeps the group's box. */
[data-ui="key-value"][data-variant="horizontal"] > :where(div:not([data-ui])),
[data-ui="key-value"]:not([data-variant]) > :where(div:not([data-ui])),
[data-ui="key-value"][data-variant="inline"] > :where(div:not([data-ui])),
[data-ui="key-value"][data-cols] > :where(div:not([data-ui])) {
  display: contents;
}

/* ── Size: Small ── */
[data-ui="key-value"][data-size="sm"] {
  gap: var(--space-1) var(--space-2);
}

[data-ui="key-value"][data-size="sm"] > [data-part="label"],
[data-ui="key-value"][data-size="sm"] > :where(div:not([data-ui])) > [data-part="label"],
[data-ui="key-value"][data-size="sm"] > [data-part="value"],
[data-ui="key-value"][data-size="sm"] > :where(div:not([data-ui])) > [data-part="value"] {
  font-size: var(--text-xs);
}

/* ── Size: Large ── */
[data-ui="key-value"][data-size="lg"] {
  gap: var(--kv-pair-gap) var(--kv-grid-gap);
}

[data-ui="key-value"][data-size="lg"] > [data-part="label"],
[data-ui="key-value"][data-size="lg"] > :where(div:not([data-ui])) > [data-part="label"] {
  font-size: var(--text-sm);
}

[data-ui="key-value"][data-size="lg"] > [data-part="value"],
[data-ui="key-value"][data-size="lg"] > :where(div:not([data-ui])) > [data-part="value"] {
  font-size: var(--text-base, 1rem);
}

/* ── Print ── */
@media print {
  [data-ui="key-value"] {
    break-inside: avoid;
  }
}


/* === primitives/label.css === */
/* @ui:component label */
/* @ui:tokens color-fg color-fg-muted color-destructive font-ui text-xs text-sm text-base weight-medium weight-normal disabled-opacity */

/* ── Base ── */
[data-ui="label"] {
  display: block;
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--color-fg);
  line-height: 1;
  cursor: pointer;
}

/* A label describes itself, not the distance to an adjacent control. Compose it
   through field-group when a field needs label/control/help spacing; that keeps
   the inner step in one owner and leaves the outer step to the default rhythm. */

/* ── Parts ── */
[data-ui="label"] > [data-part="indicator"] {
  color: var(--color-fg-muted);
  font-weight: var(--weight-normal, 400);
}

[data-ui="label"][data-variant="required"] > [data-part="indicator"] {
  color: var(--color-destructive);
}

/* ── Sizes ── */
[data-ui="label"][data-size="sm"] {
  font-size: var(--text-xs);
}

[data-ui="label"][data-size="lg"] {
  font-size: var(--text-base);
}

/* ── States ── */
[data-ui="label"][data-state="disabled"] {
  opacity: var(--disabled-opacity);
  cursor: not-allowed;
}


/* === primitives/link.css === */
/* @ui:component link */
/* @ui:tokens color-primary color-primary-hover color-primary-active color-fg color-fg-muted color-ring radius-sm space-1 focus-ring-width focus-ring-offset focus-ring-style focus-ring-color focus-shadow link-decoration link-thickness link-underline-offset duration-normal ease-out */

/* ── Base ── */
[data-ui="link"] {
  color: var(--color-primary);
  font-family: inherit;
  text-decoration-line: var(--link-decoration);
  text-decoration-thickness: var(--link-thickness);
  text-underline-offset: var(--link-underline-offset);
  border-radius: var(--radius-sm);
  cursor: pointer;
}

[data-ui="link"]:hover {
  color: var(--color-primary-hover);
}

[data-ui="link"]:active {
  color: var(--color-primary-active);
}

[data-ui="link"]:focus-visible {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  outline-offset: var(--focus-ring-offset);
  box-shadow: var(--focus-shadow);
}

/* ── Variants ── */
[data-ui="link"][data-variant="muted"] {
  color: var(--color-fg-muted);
}

[data-ui="link"][data-variant="muted"]:hover {
  color: var(--color-fg);
}

/* External links get a CSS-only indicator */
[data-ui="link"][data-variant="external"]::after {
  content: "\2197";
  display: inline-block;
  margin-inline-start: var(--space-1);
  font-size: 0.75em;
  line-height: 1;
  text-decoration: none;
}

/* ── Effects ──
   `slide` draws the underline in from the start of the text on hover instead
   of switching it on: the text-decoration goes and a background rule, as
   thick as the link family says, grows under the words. `arrow` appends an
   arrow that nudges forward — the "read more" gesture. */
[data-ui="link"][data-effect="slide"] {
  text-decoration-line: none;
  background-image: linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 0% var(--link-thickness);
  transition: background-size var(--duration-normal) var(--ease-out);
}

[data-ui="link"][data-effect="slide"]:dir(rtl) {
  background-position: 100% 100%;
}

[data-ui="link"][data-effect="slide"]:hover,
[data-ui="link"][data-effect="slide"]:focus-visible {
  background-size: 100% var(--link-thickness);
}

[data-ui="link"][data-effect="arrow"]::after {
  content: "\2192";
  display: inline-block;
  margin-inline-start: var(--space-1);
  text-decoration: none;
  transition: translate var(--duration-normal) var(--ease-out);
}

[data-ui="link"][data-effect="arrow"]:dir(rtl)::after {
  content: "\2190";
}

[data-ui="link"][data-effect="arrow"]:hover::after,
[data-ui="link"][data-effect="arrow"]:focus-visible::after {
  translate: var(--space-1) 0;
}

[data-ui="link"][data-effect="arrow"]:dir(rtl):hover::after,
[data-ui="link"][data-effect="arrow"]:dir(rtl):focus-visible::after {
  translate: calc(var(--space-1) * -1) 0;
}

@media (prefers-reduced-motion: reduce) {
  [data-ui="link"][data-effect="slide"],
  [data-ui="link"][data-effect="arrow"]::after {
    transition: none;
  }
}


/* === primitives/marquee.css === */
/* @ui:component marquee */
/* @ui:tokens space-8 motion-ambient-duration motion-ambient-play ease-linear */

/* ── Root ──
   A window onto a strip that is longer than it. The strip is written twice —
   two identical `track` parts, the second hidden from assistive technology —
   and both slide by exactly one track plus one gap, so the moment the first
   leaves, the second is standing where it started. That is the whole trick:
   no script measures anything.

   `--faqir-marquee-flow` is the travel direction along the inline axis: -1
   (towards the start edge) in a left-to-right page, +1 in a right-to-left one,
   because the tracks themselves are laid out the other way round there. */
[data-ui="marquee"] {
  --faqir-marquee-flow: -1;
  --faqir-marquee-pace: 1;
  display: flex;
  gap: var(--marquee-gap, var(--space-8));
  overflow: hidden;
  max-inline-size: 100%;
}

[data-ui="marquee"]:dir(rtl) {
  --faqir-marquee-flow: 1;
}

/* ── Track ── */
[data-ui="marquee"] > [data-part="track"] {
  display: flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: space-around;
  gap: var(--marquee-gap, var(--space-8));
  min-inline-size: 100%;
  margin: 0;
  padding: 0;
  list-style: none;
  animation: faqir-marquee-inline
    calc(var(--marquee-duration, var(--motion-ambient-duration)) * var(--faqir-marquee-pace))
    var(--ease-linear) infinite;
  animation-play-state: var(--motion-ambient-play);
}

[data-ui="marquee"] > [data-part="track"] > * {
  flex-shrink: 0;
}

@keyframes faqir-marquee-inline {
  to {
    translate: calc((100% + var(--marquee-gap, var(--space-8))) * var(--faqir-marquee-flow)) 0;
  }
}

@keyframes faqir-marquee-block {
  to {
    translate: 0 calc(-100% - var(--marquee-gap, var(--space-8)));
  }
}

/* ── Direction ── */
[data-ui="marquee"][data-direction="reverse"] > [data-part="track"] {
  animation-direction: reverse;
}

/* ── Speed ──
   A pace is a multiple of the one duration, so `--marquee-duration` (or the
   theme's `--motion-ambient-duration`) still moves all three together. */
[data-ui="marquee"][data-speed="slow"] {
  --faqir-marquee-pace: 2;
}

[data-ui="marquee"][data-speed="fast"] {
  --faqir-marquee-pace: 0.5;
}

/* ── Orientation: vertical ──
   A column needs a height to be a window; `--marquee-size` is that height. */
[data-ui="marquee"][data-variant="vertical"] {
  flex-direction: column;
  block-size: var(--marquee-size, 24rem);
}

[data-ui="marquee"][data-variant="vertical"] > [data-part="track"] {
  flex-direction: column;
  align-items: stretch;
  min-inline-size: 0;
  min-block-size: 100%;
  animation-name: faqir-marquee-block;
}

/* ── Fade ──
   The strip dissolves into the page at both ends instead of being cut by the
   window's edge. A mask, so it works over any background, texture included. */
[data-ui="marquee"][data-fade] {
  -webkit-mask-image: linear-gradient(to right, transparent, black var(--marquee-fade, 12%), black calc(100% - var(--marquee-fade, 12%)), transparent);
  mask-image: linear-gradient(to right, transparent, black var(--marquee-fade, 12%), black calc(100% - var(--marquee-fade, 12%)), transparent);
}

[data-ui="marquee"][data-variant="vertical"][data-fade] {
  -webkit-mask-image: linear-gradient(to bottom, transparent, black var(--marquee-fade, 12%), black calc(100% - var(--marquee-fade, 12%)), transparent);
  mask-image: linear-gradient(to bottom, transparent, black var(--marquee-fade, 12%), black calc(100% - var(--marquee-fade, 12%)), transparent);
}

/* ── Pause ──
   Anything that moves for more than five seconds needs a way to stop it
   (WCAG 2.2.2). The pointer and the keyboard both get one, unless the author
   opts out for a strip with nothing to read in it. */
[data-ui="marquee"]:not([data-pause="never"]):hover > [data-part="track"],
[data-ui="marquee"]:not([data-pause="never"]):focus-within > [data-part="track"] {
  animation-play-state: paused;
}

/* ── Motion ──
   Reduced motion turns the strip back into ordinary content: the duplicate
   track goes, and the one that is left wraps (or, in a column, scrolls) so
   every item is still reachable. The fade goes with it — a mask over content
   that no longer moves would just hide the ends. */
@media (prefers-reduced-motion: reduce) {
  [data-ui="marquee"] {
    flex-wrap: wrap;
    -webkit-mask-image: none;
    mask-image: none;
  }

  [data-ui="marquee"] > [data-part="track"] {
    flex-wrap: wrap;
    justify-content: center;
    min-inline-size: 0;
    animation: none;
  }

  [data-ui="marquee"] > [data-part="track"][aria-hidden="true"] {
    display: none;
  }

  [data-ui="marquee"][data-variant="vertical"] {
    flex-wrap: nowrap;
    overflow-y: auto;
  }
}

/* ── Print ── */
@media print {
  [data-ui="marquee"] {
    flex-wrap: wrap;
    block-size: auto;
    -webkit-mask-image: none;
    mask-image: none;
  }

  [data-ui="marquee"] > [data-part="track"] {
    flex-wrap: wrap;
    min-inline-size: 0;
    animation: none;
  }

  [data-ui="marquee"] > [data-part="track"][aria-hidden="true"] {
    display: none;
  }
}


/* === primitives/nav.css === */
/* @ui:component nav */
/* @ui:tokens color-fg color-fg-muted color-primary color-primary-subtle color-bg-subtle color-bg color-border text-sm weight-medium radius-md space-0h space-1 space-2 space-3 space-4 shadow-sm duration-fast ease-default border-width border-width-strong */

/* ── Base ──
   A row that wraps: six links in a horizontal, underline or pill nav are wider
   than a phone, and a row that cannot wrap pushed the whole page into sideways
   scroll. Wrapping (not a scroller) keeps every link on screen and its focus
   ring unclipped; a row that fits is unchanged. The vertical variant is a
   column, where wrapping never applies. */
[data-ui="nav"] {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-1);
}

/* ── Link ── */
[data-ui="nav"] > [data-part="link"] {
  display: inline-flex;
  align-items: center;
  padding: var(--space-1) var(--space-3);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--color-fg-muted);
  text-decoration: none;
  border-radius: var(--radius-md);
  transition: color var(--duration-fast) var(--ease-default),
              background var(--duration-fast) var(--ease-default);
  cursor: pointer;
  border: none;
  background: transparent;
  font-family: inherit;
}

[data-ui="nav"] > [data-part="link"]:hover {
  color: var(--color-fg);
  background: var(--color-bg-subtle);
}

/* Active link */
[data-ui="nav"] > [data-part="link"][data-state="active"] {
  color: var(--color-primary);
  background: var(--color-primary-subtle);
}

/* ── Vertical variant ── */
[data-ui="nav"][data-variant="vertical"] {
  flex-direction: column;
  align-items: stretch;
}

[data-ui="nav"][data-variant="vertical"] > [data-part="link"] {
  padding: var(--space-2) var(--space-3);
}

/* ── Underline variant ── */
[data-ui="nav"][data-variant="underline"] {
  border-bottom: var(--border-width) solid var(--color-border);
  gap: 0;
}

[data-ui="nav"][data-variant="underline"] > [data-part="link"] {
  border-radius: 0;
  padding: var(--space-2) var(--space-4);
  border-bottom: var(--border-width-strong) solid transparent;
  margin-bottom: -1px;
}

[data-ui="nav"][data-variant="underline"] > [data-part="link"]:hover {
  background: transparent;
  border-bottom-color: var(--color-border);
}

[data-ui="nav"][data-variant="underline"] > [data-part="link"][data-state="active"] {
  background: transparent;
  border-bottom-color: var(--color-primary);
  color: var(--color-primary);
}

/* ── Pill variant ── */
[data-ui="nav"][data-variant="pill"] {
  gap: var(--space-1);
  background: var(--color-bg-subtle);
  border-radius: var(--radius-md);
  padding: var(--space-0h);
}

[data-ui="nav"][data-variant="pill"] > [data-part="link"] {
  border-radius: var(--radius-md);
}

[data-ui="nav"][data-variant="pill"] > [data-part="link"][data-state="active"] {
  background: var(--color-bg);
  color: var(--color-fg);
  box-shadow: var(--shadow-sm);
}

/* ── Separator within nav ── */
[data-ui="nav"] > [data-part="separator"] {
  width: 1px;
  height: 1rem;
  background: var(--color-border);
  margin: 0 var(--space-1);
}

[data-ui="nav"][data-variant="vertical"] > [data-part="separator"] {
  width: auto;
  height: 1px;
  margin: var(--space-1) 0;
}

/* ── Reduced Motion ── */
@media (prefers-reduced-motion: reduce) {
  [data-ui="nav"] > [data-part="link"] {
    transition: none;
  }
}


/* === primitives/page-break.css === */
/* @ui:component page-break */
/* @ui:tokens color-border color-fg-muted space-4 space-6 text-xs font-body border-width doc-section-gap doc-font page-break-screen-style page-break-screen-color page-break-screen-label-size page-break-screen-label-color */

/* ── Base (Screen) ── */
[data-ui="page-break"] {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  margin: var(--doc-section-gap, var(--space-6)) 0;
  user-select: none;
}

[data-ui="page-break"]::before,
[data-ui="page-break"]::after {
  content: "";
  flex: 1;
  border-top: var(--border-width) var(--page-break-screen-style) var(--page-break-screen-color);
}

/* ── Label (Screen) ── */
[data-ui="page-break"] {
  font-family: var(--doc-font, var(--font-body));
  font-size: var(--page-break-screen-label-size);
  color: var(--page-break-screen-label-color);
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

/* Use CSS ordering to put the first line before the text */
[data-ui="page-break"]::before {
  order: 1;
}

/* ── Print ── */
@media print {
  /* Default: page-break-after */
  [data-ui="page-break"],
  [data-ui="page-break"][data-variant="after"] {
    visibility: hidden;
    height: 0;
    margin: 0;
    padding: 0;
    border: none;
    page-break-after: always;
    break-after: page;
  }

  [data-ui="page-break"]::before,
  [data-ui="page-break"]::after {
    display: none;
  }

  /* Variant: before */
  [data-ui="page-break"][data-variant="before"] {
    page-break-after: auto;
    break-after: auto;
    page-break-before: always;
    break-before: page;
  }
}


/* === primitives/progress.css === */
/* @ui:component progress */
/* @ui:tokens color-primary color-bg-muted color-success color-warning color-destructive color-fg-muted radius-full text-sm space-1 space-2 duration-normal ease-default border-width */

/* ── Base ── */
[data-ui="progress"] {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  width: 100%;
  min-inline-size: 0;
}

/* Child combinators: `label` is a common part name, and a descendant rule
   would style the label of whatever a bespoke progress indicator nests. The
   `track` hop is `:where()` so the fill rules keep their specificity. [1.1F-20] */

/* ── Track ── */
[data-ui="progress"] > [data-part="track"] {
  flex: 1;
  min-inline-size: 0;
  height: 0.5rem;
  background: var(--color-bg-muted);
  border-radius: var(--radius-full);
  overflow: hidden;
}

/* ── Fill ── */
[data-ui="progress"] > :where([data-part="track"]) > [data-part="fill"] {
  height: 100%;
  background: var(--color-primary);
  border-radius: var(--radius-full);
  transition: width var(--duration-normal) var(--ease-default);
}

/* ── Value without inline style ──
   data-value="0".."100" on the root sets the fill, so a server template can
   render a progress bar with no style attribute (a template engine rightly
   refuses data in one). Every engine draws whole 5 % steps; where typed attr()
   is supported (the @supports block) any number is drawn exactly. clamp()
   keeps an out-of-range value inside the track, and a value the parse refuses
   draws an empty bar, never a full one. An inline style="width: …" on the fill
   still wins, so the original form keeps working. */
[data-ui="progress"][data-value] > :where([data-part="track"]) > [data-part="fill"] {
  width: clamp(0%, var(--faqir-progress, 0%), 100%);
}

[data-ui="progress"][data-value="5"] { --faqir-progress: 5%; }
[data-ui="progress"][data-value="10"] { --faqir-progress: 10%; }
[data-ui="progress"][data-value="15"] { --faqir-progress: 15%; }
[data-ui="progress"][data-value="20"] { --faqir-progress: 20%; }
[data-ui="progress"][data-value="25"] { --faqir-progress: 25%; }
[data-ui="progress"][data-value="30"] { --faqir-progress: 30%; }
[data-ui="progress"][data-value="35"] { --faqir-progress: 35%; }
[data-ui="progress"][data-value="40"] { --faqir-progress: 40%; }
[data-ui="progress"][data-value="45"] { --faqir-progress: 45%; }
[data-ui="progress"][data-value="50"] { --faqir-progress: 50%; }
[data-ui="progress"][data-value="55"] { --faqir-progress: 55%; }
[data-ui="progress"][data-value="60"] { --faqir-progress: 60%; }
[data-ui="progress"][data-value="65"] { --faqir-progress: 65%; }
[data-ui="progress"][data-value="70"] { --faqir-progress: 70%; }
[data-ui="progress"][data-value="75"] { --faqir-progress: 75%; }
[data-ui="progress"][data-value="80"] { --faqir-progress: 80%; }
[data-ui="progress"][data-value="85"] { --faqir-progress: 85%; }
[data-ui="progress"][data-value="90"] { --faqir-progress: 90%; }
[data-ui="progress"][data-value="95"] { --faqir-progress: 95%; }
[data-ui="progress"][data-value="100"] { --faqir-progress: 100%; }

@supports (width: attr(data-value %, 0%)) {
  [data-ui="progress"][data-value] {
    --faqir-progress: attr(data-value %, 0%);
  }
}

/* ── Variants ── */
[data-ui="progress"][data-variant="success"] > :where([data-part="track"]) > [data-part="fill"] {
  background: var(--color-success);
}

[data-ui="progress"][data-variant="warning"] > :where([data-part="track"]) > [data-part="fill"] {
  background: var(--color-warning);
}

[data-ui="progress"][data-variant="destructive"] > :where([data-part="track"]) > [data-part="fill"] {
  background: var(--color-destructive);
}

/* ── Sizes ── */
[data-ui="progress"][data-size="sm"] > [data-part="track"] {
  height: 0.25rem;
}

[data-ui="progress"][data-size="lg"] > [data-part="track"] {
  height: 0.75rem;
}

/* ── Label ── */
[data-ui="progress"] > [data-part="label"] {
  flex: 0 0 auto;
  font-size: var(--text-sm);
  color: var(--color-fg-muted);
  min-inline-size: 4ch;
  padding-inline-end: var(--space-1);
  text-align: end;
}

/* ── Reduced Motion ── */
@media (prefers-reduced-motion: reduce) {
  [data-ui="progress"] > :where([data-part="track"]) > [data-part="fill"] {
    transition: none;
  }
}

/* ── Forced colors (Windows High Contrast) ──
   The OS drops every background, so the track and the fill became the same
   nothing: a progress bar that showed no progress, at any value. The fill is
   the one element here that MUST keep a colour, so it opts out of the
   substitution and paints `Highlight`; the track keeps a visible boundary. [W3-3] */
@media (forced-colors: active) {
  [data-ui="progress"] > [data-part="track"] {
    border: var(--border-width) solid ButtonText;
  }

  [data-ui="progress"] > :where([data-part="track"]) > [data-part="fill"],
  [data-ui="progress"][data-variant="success"] > :where([data-part="track"]) > [data-part="fill"],
  [data-ui="progress"][data-variant="warning"] > :where([data-part="track"]) > [data-part="fill"],
  [data-ui="progress"][data-variant="destructive"] > :where([data-part="track"]) > [data-part="fill"] {
    forced-color-adjust: none;
    background: Highlight;
  }
}


/* === primitives/quote.css === */
/* @ui:component quote */
/* @ui:tokens color-primary color-fg color-fg-muted space-4 space-3 space-6 font-body font-heading text-4xl text-lg text-sm text-2xl text-base text-3xl text-xl heading-weight heading-tracking leading-relaxed leading-snug weight-semibold weight-medium card-padding card-border-width card-border card-radius card-bg card-shadow corner-shape texture-surface duration-fast ease-default motion-hover-lift surface-backdrop border-width-lg */

/* ── Root ──
   Someone else's words, and who said them. A <figure>: the quotation is a
   <blockquote>, the attribution its <figcaption>, which is what gives the pair
   a programmatic relationship without any ARIA. */
[data-ui="quote"] {
  --faqir-quote-ink: var(--quote-accent, var(--color-primary));
  position: relative;
  display: grid;
  align-content: start;
  gap: var(--space-4);
  margin: 0;
  font-family: var(--font-body);
  color: var(--color-fg);
}

/* ── Mark ──
   The opening quotation mark, drawn large in the accent. `open-quote` rather
   than a literal glyph, so the mark is the one the document's language uses —
   “ in English, « in French, „ in German. Decoration: the blockquote element
   already says "this is a quotation", so the second `content` gives the mark an
   empty text alternative where that syntax is understood. */
[data-ui="quote"]::before {
  content: open-quote;
  content: open-quote / "";
  display: block;
  block-size: 0.5em;
  font-family: var(--font-heading);
  font-size: var(--text-4xl);
  font-weight: var(--heading-weight);
  line-height: 1;
  color: color-mix(in oklch, var(--faqir-quote-ink) 55%, transparent);
}

/* Every `open-quote` raises the document's quote depth, so without a matching
   close the second quote on a page draws the NESTED mark (‘ rather than “).
   `no-close-quote` lowers it again and draws nothing. Absolutely positioned,
   so the (empty) box is not a grid item and adds no row or gap. */
[data-ui="quote"]::after {
  content: no-close-quote;
  position: absolute;
}

/* ── Text ──
   --quote-text-size / --quote-author-size are the two knobs a context sets
   to size a quotation for its own scale — the document pattern points them
   at its body and legal sizes. A size variant still wins: it is the author
   asking. */
[data-ui="quote"] > [data-part="text"] {
  margin: 0;
  font-size: var(--quote-text-size, var(--text-lg));
  line-height: var(--leading-relaxed);
  text-wrap: pretty;
}

[data-ui="quote"] > :where([data-part="text"]) > p {
  margin: 0;
}

[data-ui="quote"] > :where([data-part="text"]) > p + p {
  margin-block-start: var(--space-3);
}

/* ── Author ──
   A two-row column flow: an optional media part (an avatar) takes both rows of
   the first column, name and role stack in the next. With no media the same
   rules stack name over role in the first column — no empty track, no indent. */
[data-ui="quote"] > [data-part="author"] {
  display: grid;
  grid-auto-flow: column;
  grid-template-rows: auto auto;
  justify-content: start;
  align-items: center;
  column-gap: var(--space-3);
  font-size: var(--quote-author-size, var(--text-sm));
  line-height: var(--leading-snug);
}

[data-ui="quote"] > :where([data-part="author"]) > [data-part="media"] {
  grid-row: span 2;
  display: flex;
}

[data-ui="quote"] > :where([data-part="author"]) > [data-part="name"] {
  font-style: normal;
  font-weight: var(--weight-semibold);
  color: var(--color-fg);
}

[data-ui="quote"] > :where([data-part="author"]) > [data-part="role"] {
  color: var(--color-fg-muted);
}

/* ── Mark: hang / none ──
   `hang` takes the mark off its own line and hangs it beside the first line
   of the text, at the text's size — the way a quotation is set in running
   copy, where a mark above the text reads as a ditto. The text and the
   attribution step in by one gutter and the mark is set flush against the
   text inside it, so it never leaves the figure's box (a page clips what
   leaves its area). `none` draws no mark at all. After the text and author
   rules on purpose: the gutter has to outweigh their `margin: 0`. */
[data-ui="quote"]:is([data-mark="hang"], [data-mark="none"])::before {
  content: none;
}

[data-ui="quote"][data-mark="none"]::after {
  content: none;
}

[data-ui="quote"][data-mark="hang"] > * {
  margin-inline-start: var(--space-6);
}

[data-ui="quote"][data-mark="hang"] > [data-part="text"] {
  position: relative;
}

[data-ui="quote"][data-mark="hang"] > [data-part="text"]::before {
  content: open-quote;
  content: open-quote / "";
  position: absolute;
  inset-block-start: 0;
  inset-inline-end: 100%;
  padding-inline-end: 0.15em;
  color: color-mix(in oklch, var(--faqir-quote-ink) 70%, transparent);
}

/* ── Variant: card ──
   The quotation on a surface of its own. It reads the card's aliases, so a
   theme that restyles cards restyles testimonial cards with them. */
[data-ui="quote"][data-variant="card"] {
  padding: var(--card-padding);
  border: var(--card-border-width) solid var(--card-border);
  border-radius: var(--card-radius);
  corner-shape: var(--corner-shape);
  background: var(--texture-surface), var(--card-bg);
  box-shadow: var(--card-shadow);
  transition: translate var(--duration-fast) var(--ease-default);
}

[data-ui="quote"][data-variant="card"]:hover {
  translate: var(--motion-hover-lift);
}

@supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
  [data-ui="quote"][data-variant="card"] {
    -webkit-backdrop-filter: var(--surface-backdrop);
    backdrop-filter: var(--surface-backdrop);
  }
}

/* ── Variant: pull ──
   An editorial pull quote: the heading voice, set large, hung on an accent
   rule. For the one sentence of an article that should stop a skimming reader. */
[data-ui="quote"][data-variant="pull"] {
  padding-inline-start: var(--space-6);
  border-inline-start: var(--border-width-lg) solid var(--faqir-quote-ink);
}

[data-ui="quote"][data-variant="pull"]::before {
  content: none;
}

[data-ui="quote"][data-variant="pull"] > [data-part="text"] {
  font-family: var(--font-heading);
  font-size: var(--text-2xl);
  font-weight: var(--weight-medium);
  letter-spacing: var(--heading-tracking);
  line-height: var(--leading-snug);
  text-wrap: balance;
}

/* ── Sizes ── */
[data-ui="quote"][data-size="sm"] {
  gap: var(--space-3);
}

[data-ui="quote"][data-size="sm"] > [data-part="text"] {
  font-size: var(--text-base);
}

[data-ui="quote"][data-size="sm"]::before {
  font-size: var(--text-3xl);
}

[data-ui="quote"][data-size="lg"] > [data-part="text"] {
  font-size: var(--text-xl);
}

[data-ui="quote"][data-variant="pull"][data-size="lg"] > [data-part="text"] {
  font-size: var(--text-3xl);
}

/* ── Alignment: center ── */
[data-ui="quote"][data-align="center"] {
  justify-items: center;
  text-align: center;
}

[data-ui="quote"][data-align="center"] > [data-part="author"] {
  justify-content: center;
  text-align: start;
}

/* ── Motion ── */
@media (prefers-reduced-motion: reduce) {
  [data-ui="quote"] {
    transition: none;
  }
}

/* ── Print ── */
@media print {
  [data-ui="quote"] {
    break-inside: avoid;
  }

  [data-ui="quote"][data-variant="card"] {
    box-shadow: none;
  }
}


/* === primitives/radio.css === */
/* @ui:component radio */
/* @ui:tokens color-bg color-primary color-border color-border-strong color-ring color-fg-muted radius-full space-2 space-4 duration-fast ease-default border-width focus-ring-width focus-ring-offset focus-ring-style focus-ring-color focus-shadow disabled-opacity text-sm */

/* -- Radio group -- */
[data-ui="radio-group"] {
  border: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

/* A row instead of a column: the options wrap, a cluster data-gap="4" step
   apart, wider than each label's own space-2 step. Written on the group whose
   direct children are the radio-labels (a fieldset's legend stays above). */
[data-ui="radio-group"][data-orientation="horizontal"] {
  flex-direction: row;
  flex-wrap: wrap;
  column-gap: var(--space-4);
}

/* -- Captions (a scale) --
   The words at a horizontal group's two ends ("Not likely" … "Very likely"),
   on their own line under the options. The group shrinks to its options so
   the last caption ends under the last option rather than at the page edge.
   A flex row's fit-content width counts a gap before every item, the captions
   included, so here the step between options is each option's end padding
   instead, and the last option has none: the group ends where it does. */
[data-ui="radio-group"]:has(> [data-part="captions"]) {
  inline-size: fit-content;
  max-inline-size: 100%;
  column-gap: 0;
}

[data-ui="radio-group"]:has(> [data-part="captions"]) > [data-ui="radio-label"] {
  padding-inline-end: var(--space-4);
}

[data-ui="radio-group"] > [data-ui="radio-label"]:has(+ [data-part="captions"]) {
  padding-inline-end: 0;
}

[data-ui="radio-group"] > [data-part="captions"] {
  /* Sized by the options, never sizing them: uncontained, the captions' own
     width would count toward the group's fit-content width. */
  contain: inline-size;
  flex-basis: 100%;
  display: flex;
  justify-content: space-between;
  gap: var(--space-4);
  font-size: var(--text-sm);
  color: var(--color-fg-muted);
}

/* -- Label wrapper -- */
[data-ui="radio-label"] {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  cursor: pointer;
}

[data-ui="radio-label"]:has([data-ui="radio"]:disabled) {
  cursor: not-allowed;
  opacity: var(--disabled-opacity);
}

/* -- Base -- */
[data-ui="radio"] {
  appearance: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--radio-size, 18px);
  height: var(--radio-size, 18px);
  flex-shrink: 0;
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-full);
  background: var(--color-bg);
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease-default),
              border-color var(--duration-fast) var(--ease-default),
              box-shadow var(--duration-fast) var(--ease-default);
}

[data-ui="radio"]:hover {
  border-color: var(--color-border-strong);
}

[data-ui="radio"]:focus-visible {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  outline-offset: var(--focus-ring-offset);
  box-shadow: var(--focus-shadow);
}

/* -- Checked -- */
[data-ui="radio"]:checked {
  border-color: var(--color-primary);
}

[data-ui="radio"]:checked::before {
  content: "";
  display: block;
  width: 10px;
  height: 10px;
  border-radius: var(--radius-full);
  background: var(--color-primary);
}

/* -- Sizes -- */
[data-ui="radio"][data-size="sm"] {
  width: 14px;
  height: 14px;
}
[data-ui="radio"][data-size="sm"]:checked::before {
  width: 7px;
  height: 7px;
}

[data-ui="radio"][data-size="lg"] {
  width: 22px;
  height: 22px;
}
[data-ui="radio"][data-size="lg"]:checked::before {
  width: 12px;
  height: 12px;
}

/* -- Disabled -- */
[data-ui="radio"]:disabled {
  cursor: not-allowed;
}

/* -- Motion -- */
@media (prefers-reduced-motion: reduce) {
  [data-ui="radio"] {
    transition: none;
  }
}

/* ── Forced colors (Windows High Contrast) ──
   Same shape as `checkbox`: the selected dot is a `--color-primary-fg` fill
   inside a `--color-primary` circle, and the OS collapses both to one colour. [W3-3] */
@media (forced-colors: active) {
  [data-ui="radio"] {
    border: var(--border-width) solid ButtonText;
  }

  [data-ui="radio"]:checked {
    background: Highlight;
    border-color: Highlight;
  }

  [data-ui="radio"]:checked::before {
    forced-color-adjust: none;
    background: HighlightText;
  }

  [data-ui="radio"]:disabled {
    border-color: GrayText;
  }
}


/* === primitives/rating.css === */
/* @ui:component rating */
/* @ui:tokens color-warning color-bg-muted text-sm text-2xl */

/* ── Root ──
   Five stars, drawn by one element. A star mask is repeated five times across
   a box five ems wide, and behind the mask a two-stop gradient is filled up to
   `value / 5` — so a half star is half a star's width of colour, with no half
   glyph, no five children and nothing for a script to keep in step.

   The size is the font size: a rating scales with the text it sits in. */
[data-ui="rating"] {
  --faqir-rating: var(--rating-value, 0);
  --faqir-rating-fill: var(--rating-color, var(--color-warning));
  --faqir-rating-track: var(--rating-track, var(--color-bg-muted));
  --faqir-rating-star: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 2.6 14.5 8.7 21.1 9.2 16 13.5 17.6 19.9 12 16.4 6.4 19.9 8 13.5 2.9 9.2 9.5 8.7z' stroke='black' stroke-width='1.8' stroke-linejoin='round'/%3E%3C/svg%3E");
  display: inline-block;
  flex-shrink: 0;
  inline-size: 5em;
  block-size: 1em;
  vertical-align: -0.125em;
  background-image: linear-gradient(to right, var(--faqir-rating-fill) calc(var(--faqir-rating) * 20%), var(--faqir-rating-track) calc(var(--faqir-rating) * 20%));
  -webkit-mask: var(--faqir-rating-star) 0 0 / 1em 1em repeat-x;
  mask: var(--faqir-rating-star) 0 0 / 1em 1em repeat-x;
  forced-color-adjust: none;
}

/* The stars fill from where the line starts. */
[data-ui="rating"]:dir(rtl) {
  background-image: linear-gradient(to left, var(--faqir-rating-fill) calc(var(--faqir-rating) * 20%), var(--faqir-rating-track) calc(var(--faqir-rating) * 20%));
}

/* ── Value ──
   Half steps as an attribute, so a rating is plain markup; any other fraction
   (an average of 4.3) goes through `--rating-value`. */
[data-ui="rating"][data-value="0"]   { --faqir-rating: 0; }
[data-ui="rating"][data-value="0.5"] { --faqir-rating: 0.5; }
[data-ui="rating"][data-value="1"]   { --faqir-rating: 1; }
[data-ui="rating"][data-value="1.5"] { --faqir-rating: 1.5; }
[data-ui="rating"][data-value="2"]   { --faqir-rating: 2; }
[data-ui="rating"][data-value="2.5"] { --faqir-rating: 2.5; }
[data-ui="rating"][data-value="3"]   { --faqir-rating: 3; }
[data-ui="rating"][data-value="3.5"] { --faqir-rating: 3.5; }
[data-ui="rating"][data-value="4"]   { --faqir-rating: 4; }
[data-ui="rating"][data-value="4.5"] { --faqir-rating: 4.5; }
[data-ui="rating"][data-value="5"]   { --faqir-rating: 5; }

/* ── Sizes ── */
[data-ui="rating"][data-size="sm"] {
  font-size: var(--text-sm);
}

[data-ui="rating"][data-size="lg"] {
  font-size: var(--text-2xl);
}

/* ── Forced colours ──
   The mask still draws the stars; the two fills become system colours so the
   filled share stays distinguishable. */
@media (forced-colors: active) {
  [data-ui="rating"] {
    --faqir-rating-fill: Highlight;
    --faqir-rating-track: GrayText;
  }
}

/* ── Print ── */
@media print {
  [data-ui="rating"] {
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
}


/* === primitives/reveal.css === */
/* @ui:component reveal */
/* @ui:tokens motion-reveal-distance motion-reveal-scale motion-reveal-blur motion-reveal-duration motion-reveal-ease motion-stagger ease-linear */

/* ── Root ──
   A reveal never lays anything out: it only decides how its content ARRIVES.
   The entrance is one keyframe pair read through four private custom
   properties, so a variant is a declaration and not a new animation, and a
   theme that re-points the `--motion-reveal-*` family restyles all of them.

   The four are re-declared on every root on purpose. They are inherited (a
   staggered group hands them to its children), and without the reset a reveal
   nested inside another would add its parent's travel to its own. */
[data-ui="reveal"] {
  --faqir-reveal-translate: 0 0;
  --faqir-reveal-scale: 1;
  --faqir-reveal-filter: none;
  --faqir-reveal-index: 0;
}

/* ── Variants: where the content comes from ── */
[data-ui="reveal"][data-variant="rise"],
[data-ui="reveal"]:not([data-variant]) {
  --faqir-reveal-translate: 0 var(--reveal-distance, var(--motion-reveal-distance));
}

[data-ui="reveal"][data-variant="fall"] {
  --faqir-reveal-translate: 0 calc(var(--reveal-distance, var(--motion-reveal-distance)) * -1);
}

/* The inline pair is logical: `start` is the left edge of a left-to-right page
   and the right edge of a right-to-left one. */
[data-ui="reveal"][data-variant="slide-start"],
[data-ui="reveal"][data-variant="slide-end"]:dir(rtl) {
  --faqir-reveal-translate: calc(var(--reveal-distance, var(--motion-reveal-distance)) * -1) 0;
}

[data-ui="reveal"][data-variant="slide-end"],
[data-ui="reveal"][data-variant="slide-start"]:dir(rtl) {
  --faqir-reveal-translate: var(--reveal-distance, var(--motion-reveal-distance)) 0;
}

[data-ui="reveal"][data-variant="zoom"] {
  --faqir-reveal-scale: var(--motion-reveal-scale);
}

[data-ui="reveal"][data-variant="blur"] {
  --faqir-reveal-filter: blur(var(--motion-reveal-blur));
}

/* ── Stagger: the order of a group ──
   With `data-stagger` the root stays put and its CHILDREN arrive, each one
   `--motion-stagger` after the sibling before it. Twelve steps are counted;
   everything past the twelfth arrives with it, which keeps a long list from
   holding its last row back for seconds. */
[data-ui="reveal"][data-stagger] > :nth-child(2)    { --faqir-reveal-index: 1; }
[data-ui="reveal"][data-stagger] > :nth-child(3)    { --faqir-reveal-index: 2; }
[data-ui="reveal"][data-stagger] > :nth-child(4)    { --faqir-reveal-index: 3; }
[data-ui="reveal"][data-stagger] > :nth-child(5)    { --faqir-reveal-index: 4; }
[data-ui="reveal"][data-stagger] > :nth-child(6)    { --faqir-reveal-index: 5; }
[data-ui="reveal"][data-stagger] > :nth-child(7)    { --faqir-reveal-index: 6; }
[data-ui="reveal"][data-stagger] > :nth-child(8)    { --faqir-reveal-index: 7; }
[data-ui="reveal"][data-stagger] > :nth-child(9)    { --faqir-reveal-index: 8; }
[data-ui="reveal"][data-stagger] > :nth-child(10)   { --faqir-reveal-index: 9; }
[data-ui="reveal"][data-stagger] > :nth-child(11)   { --faqir-reveal-index: 10; }
[data-ui="reveal"][data-stagger] > :nth-child(n+12) { --faqir-reveal-index: 11; }

/* ── Trigger: load (default) ──
   Plays once, when the element is first rendered — on page load, or the moment
   a directive inserts it. `both` holds the from-state through the delay, so a
   staggered child is not visible and then hidden and then revealed. */
[data-ui="reveal"]:not([data-stagger], [data-state]),
[data-ui="reveal"][data-stagger]:not([data-state]) > * {
  animation: faqir-reveal var(--reveal-duration, var(--motion-reveal-duration))
    var(--reveal-ease, var(--motion-reveal-ease)) both;
  animation-delay: calc(var(--reveal-delay, 0s) + var(--motion-stagger) * var(--faqir-reveal-index));
}

/* Only a `from`: the animation ends on whatever the element already is, so a
   reveal can wrap content that carries its own opacity, transform or filter. */
@keyframes faqir-reveal {
  from {
    opacity: 0;
    translate: var(--faqir-reveal-translate);
    scale: var(--faqir-reveal-scale);
    filter: var(--faqir-reveal-filter);
  }
}

/* ── Trigger: scroll ──
   The same keyframes on a view timeline: the entrance is scrubbed by the
   scrollbar as the element crosses the bottom of the viewport, and plays
   backwards when it leaves the way it came. No script, no observer. Where view
   timelines are not supported the block is skipped entirely and the rule above
   still plays the entrance once on load — the content is never left hidden.

   A time delay means nothing on a scroll timeline, so a staggered group
   offsets each child's RANGE instead: the same order, measured in scroll. */
@supports (animation-timeline: view()) {
  [data-ui="reveal"][data-trigger="scroll"]:not([data-stagger], [data-state]),
  [data-ui="reveal"][data-trigger="scroll"][data-stagger]:not([data-state]) > * {
    animation-timeline: view();
    animation-timing-function: var(--ease-linear);
    animation-delay: 0s;
    animation-range:
      entry calc(var(--reveal-range-start, 5%) + var(--faqir-reveal-index) * 6%)
      entry calc(var(--reveal-range-end, 70%) + var(--faqir-reveal-index) * 6%);
  }
}

/* ── Trigger: state ──
   For a page that wants the entrance to play ONCE, on a clock, when the element
   is first seen. The page (or the `l-intersect` plugin) writes `data-state`:
   `hidden` holds the from-state, `shown` releases it. A reveal that carries no
   `data-state` never reads this block, so markup without a script is never
   stuck invisible. */
[data-ui="reveal"][data-state]:not([data-stagger]),
[data-ui="reveal"][data-state][data-stagger] > * {
  transition:
    opacity var(--reveal-duration, var(--motion-reveal-duration)) var(--reveal-ease, var(--motion-reveal-ease)),
    translate var(--reveal-duration, var(--motion-reveal-duration)) var(--reveal-ease, var(--motion-reveal-ease)),
    scale var(--reveal-duration, var(--motion-reveal-duration)) var(--reveal-ease, var(--motion-reveal-ease)),
    filter var(--reveal-duration, var(--motion-reveal-duration)) var(--reveal-ease, var(--motion-reveal-ease));
  transition-delay: calc(var(--reveal-delay, 0s) + var(--motion-stagger) * var(--faqir-reveal-index));
}

[data-ui="reveal"][data-state="hidden"]:not([data-stagger]),
[data-ui="reveal"][data-state="hidden"][data-stagger] > * {
  opacity: 0;
  translate: var(--faqir-reveal-translate);
  scale: var(--faqir-reveal-scale);
  filter: var(--faqir-reveal-filter);
}

/* ── Motion ──
   Reduced motion removes the entrance, not the content: every trigger resolves
   to "already arrived", including a `hidden` state a script has not released.
   Paper gets the same treatment — a printed page has no entrance. */
@media (prefers-reduced-motion: reduce), print {
  /* Every selector that starts an entrance is repeated here, so this rule
     matches its specificity and, coming later, wins. `[data-ui="reveal"]`
     alone (0,1,0) lost to the trigger rules (0,2,0 to 0,4,0), and a scroll
     reveal kept scrubbing in under reduced motion. */
  [data-ui="reveal"],
  [data-ui="reveal"][data-stagger] > *,
  [data-ui="reveal"]:not([data-stagger], [data-state]),
  [data-ui="reveal"][data-stagger]:not([data-state]) > *,
  [data-ui="reveal"][data-trigger="scroll"]:not([data-stagger], [data-state]),
  [data-ui="reveal"][data-trigger="scroll"][data-stagger]:not([data-state]) > *,
  [data-ui="reveal"][data-state]:not([data-stagger]),
  [data-ui="reveal"][data-state][data-stagger] > * {
    animation: none;
    transition: none;
  }

  [data-ui="reveal"][data-state="hidden"]:not([data-stagger]),
  [data-ui="reveal"][data-state="hidden"][data-stagger] > * {
    opacity: 1;
    translate: none;
    scale: none;
    filter: none;
  }
}


/* === primitives/scroll-progress.css === */
/* @ui:component scroll-progress */
/* @ui:tokens z-sticky color-primary ease-linear */

/* ── Root ──
   A reading-progress bar: a strip pinned to the top of the page that grows
   from the start edge as the document scrolls. The scrollbar is the clock — a
   scroll timeline scrubs one keyframe pair — so there is no script, no scroll
   listener and no layout work on the main thread.

   Hidden unless scroll timelines are supported: a progress bar that cannot
   report progress is a stripe, and a stripe is worse than nothing. */
[data-ui="scroll-progress"] {
  position: fixed;
  inset-block-start: 0;
  inset-inline: 0;
  z-index: var(--z-sticky);
  display: none;
  block-size: var(--scroll-progress-size, 0.1875rem);
  background: var(--scroll-progress-color, var(--gradient-accent, var(--color-primary)));
  transform-origin: 0 50%;
  scale: 0 1;
  pointer-events: none;
}

/* It grows from where the line starts. */
[data-ui="scroll-progress"]:dir(rtl) {
  transform-origin: 100% 50%;
}

/* ── Position: bottom ── */
[data-ui="scroll-progress"][data-variant="bottom"] {
  inset-block: auto 0;
}

/* ── Scope: nearest ──
   Reports the nearest scrolling ancestor instead of the page — an article
   pane, a drawer, a code panel — and sticks to that scroller's edge. It must
   be the scroller's first (or, at the bottom, last) child. */
[data-ui="scroll-progress"][data-scope="nearest"] {
  position: sticky;
}

@supports (animation-timeline: scroll()) {
  [data-ui="scroll-progress"] {
    display: block;
    animation: faqir-scroll-progress var(--ease-linear) both;
    animation-timeline: scroll(root block);
  }

  [data-ui="scroll-progress"][data-scope="nearest"] {
    animation-timeline: scroll(nearest block);
  }
}

@keyframes faqir-scroll-progress {
  to { scale: 1 1; }
}

/* ── Motion ──
   Deliberately not removed under reduced motion: the bar never moves on its
   own, only as far as the reader's own scrolling moves it, which is the motion
   they asked for. What a reduced-motion reader does not get is the easing a
   theme may have layered on top — the bar tracks the scrollbar exactly. */
@media (prefers-reduced-motion: reduce) {
  [data-ui="scroll-progress"] {
    animation-timing-function: var(--ease-linear);
  }
}

/* ── Print ── */
@media print {
  [data-ui="scroll-progress"] {
    display: none;
  }
}


/* === primitives/select.css === */
/* @ui:component select */
/* @ui:tokens color-fg color-border color-border-strong color-ring color-destructive radius-md space-2 space-3 space-4 space-8 space-7 space-10 font-ui text-xs text-sm text-base duration-fast ease-default border-width focus-ring-width focus-ring-style focus-ring-color focus-shadow input-border-width input-fill disabled-opacity */

/* -- Base -- */
[data-ui="select"] {
  display: block;
  width: 100%;
  height: var(--select-height, 40px);
  padding-inline: var(--space-3);
  padding-inline-end: var(--space-8, 2rem);
  /* Longhands, not the `border:` shorthand: the shorthand's width slot takes
     ONE value, and `controls.input: underline` (1.1A-10) states the silhouette
     as a four-value box — `0 0 var(--border-width) 0` — so only a bottom rule
     is drawn. Identical to the shorthand at every other value of the token. */
  border-style: solid;
  border-color: var(--color-border);
  border-width: var(--input-border-width);
  border-radius: var(--select-radius, var(--radius-md));
  background: var(--select-bg, var(--input-fill));
  color: var(--color-fg);
  font-family: var(--select-font, var(--font-ui));
  font-size: var(--text-sm);
  line-height: 1;
  cursor: pointer;
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236b7280' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  /* `background-position` is PHYSICAL and CSS gives it no logical form, so in
     an RTL page the padding flipped to the left while the chevron stayed on the
     right — painted straight over the option text. One variable holds the edge,
     one holds its inset, and the two RTL rules below flip the edge. [W3-3] */
  background-position: var(--select-chevron-edge, right) var(--select-chevron-inset, var(--space-2)) center;
  background-size: 16px 16px;
  transition: border-color var(--duration-fast) var(--ease-default),
              box-shadow var(--duration-fast) var(--ease-default);
}

[dir="rtl"] [data-ui="select"],
[data-ui="select"][dir="rtl"] {
  --select-chevron-edge: left;
}
[data-ui="select"]:dir(rtl) {
  --select-chevron-edge: left;
}

[data-ui="select"]:hover {
  border-color: var(--color-border-strong);
}

[data-ui="select"]:focus {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  /* The ring replaces the border rather than sitting outside it: inset by
     exactly the edge it covers, so a heavier shape theme stays aligned. */
  outline-offset: calc(-1 * var(--input-border-width));
  box-shadow: var(--focus-shadow);
  border-color: transparent;
}

/* -- Sizes -- */
[data-ui="select"][data-size="sm"] {
  height: 32px;
  padding-inline: var(--space-2);
  padding-inline-end: var(--space-7, 1.75rem);
  font-size: var(--text-xs);
  background-size: 14px 14px;
}

[data-ui="select"][data-size="lg"] {
  height: 48px;
  padding-inline: var(--space-4);
  padding-inline-end: var(--space-10, 2.5rem);
  font-size: var(--text-base);
  background-size: 18px 18px;
  --select-chevron-inset: var(--space-3);
}

/* -- States -- */
[data-ui="select"][data-state="error"],
[data-ui="select"][aria-invalid="true"] {
  border-color: var(--color-destructive);
}
[data-ui="select"][data-state="error"]:focus,
[data-ui="select"][aria-invalid="true"]:focus {
  outline-color: var(--color-destructive);
}

[data-ui="select"]:disabled {
  opacity: var(--disabled-opacity);
  cursor: not-allowed;
}

/* -- Motion -- */
@media (prefers-reduced-motion: reduce) {
  [data-ui="select"] {
    transition: none;
  }
}


/* === primitives/separator.css === */
/* @ui:component separator */
/* @ui:tokens color-border color-fg-muted color-primary space-4 space-3 space-2 font-ui text-xs border-width-strong divider-width divider-style */

/* ── Base (horizontal) ── */
[data-ui="separator"] {
  border: none;
  border-top: var(--divider-width) var(--divider-style) var(--color-border);
  margin: 0;
  width: 100%;
}

/* ── Vertical ── */
[data-ui="separator"][data-variant="vertical"] {
  border-top: none;
  border-inline-start: var(--divider-width) var(--divider-style) var(--color-border);
  width: auto;
  height: 100%;
  align-self: stretch;
}

/* ── With label ── */
div[data-ui="separator"] {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  border-top: none;
}

div[data-ui="separator"]::before,
div[data-ui="separator"]::after {
  content: "";
  flex: 1;
  border-top: var(--divider-width) var(--divider-style) var(--color-border);
}

[data-ui="separator"] > [data-part="label"] {
  font-family: var(--font-ui);
  font-size: var(--text-xs);
  color: var(--color-fg-muted);
  white-space: nowrap;
}

/* ── Style: Dashed ── */
/* The root draws the line only on an hr: a labelled div draws it with ::before/::after,
   and a style here would switch its own border back on at the default width. */
hr[data-ui="separator"][data-style="dashed"] {
  border-top-style: dashed;
}

[data-ui="separator"][data-style="dashed"][data-variant="vertical"] {
  border-top-style: none;
  border-inline-start-style: dashed;
}

div[data-ui="separator"][data-style="dashed"]::before,
div[data-ui="separator"][data-style="dashed"]::after {
  border-top-style: dashed;
}

/* ── Style: Dotted ── */
hr[data-ui="separator"][data-style="dotted"] {
  border-top-style: dotted;
}

[data-ui="separator"][data-style="dotted"][data-variant="vertical"] {
  border-top-style: none;
  border-inline-start-style: dotted;
}

div[data-ui="separator"][data-style="dotted"]::before,
div[data-ui="separator"][data-style="dotted"]::after {
  border-top-style: dotted;
}

/* ── Style: Thick ── */
[data-ui="separator"][data-style="thick"] {
  border-top-width: var(--border-width-strong);
}

[data-ui="separator"][data-style="thick"][data-variant="vertical"] {
  border-top-width: 0;
  border-inline-start-width: var(--border-width-strong);
}

div[data-ui="separator"][data-style="thick"]::before,
div[data-ui="separator"][data-style="thick"]::after {
  border-top-width: var(--border-width-strong);
}

/* ── Style: Ornament ──
   A hairline that fades out toward both ends and meets in the middle at a small
   diamond in the accent: the break between two movements of a landing page. A
   centred mark with a rule running out each side, and nothing in the markup but
   the separator itself. Horizontal only: every rule here excludes the vertical
   variant, which keeps the solid line it already draws.

   Two constructions, because the label and the diamond are the same slot.
   · No label (an hr, or a div with no label part): the root paints the two
     rules as backgrounds and ::before is the diamond; ::after is not needed.
   · A label (a div holding a label part): the label takes the middle, and the
     existing ::before / ::after rules, flex: 1 each, are the two fading lines.
     That is the div's own construction, so it is the default for a div; the
     diamond version of a div is the :has() rule that follows, and a browser
     without :has() shows a labelled div correctly and an empty one as two
     rules with a gap, never the diamond over a label.
   Both fades are mirror images, so right-to-left needs nothing except the
   labelled form's ::before, which sits on the other side there. */
hr[data-ui="separator"][data-style="ornament"]:not([data-variant="vertical"]) {
  display: flex;
  align-items: center;
  justify-content: center;
  block-size: var(--space-3);
  border-top: none;
  background-image:
    linear-gradient(to right, transparent, var(--color-border)),
    linear-gradient(to left, transparent, var(--color-border));
  background-position: left center, right center;
  background-size: calc(50% - var(--space-4)) var(--divider-width);
  background-repeat: no-repeat;
}

hr[data-ui="separator"][data-style="ornament"]:not([data-variant="vertical"])::before {
  content: "";
  flex: none;
  inline-size: var(--space-2);
  block-size: var(--space-2);
  background: var(--color-primary);
  rotate: 45deg;
}

div[data-ui="separator"][data-style="ornament"]:not([data-variant="vertical"])::before,
div[data-ui="separator"][data-style="ornament"]:not([data-variant="vertical"])::after {
  border-top: none;
  block-size: var(--divider-width);
  background-image: linear-gradient(to right, transparent, var(--color-border));
}

div[data-ui="separator"][data-style="ornament"]:not([data-variant="vertical"])::after {
  background-image: linear-gradient(to left, transparent, var(--color-border));
}

div[data-ui="separator"][data-style="ornament"]:not([data-variant="vertical"]):dir(rtl)::before {
  background-image: linear-gradient(to left, transparent, var(--color-border));
}

div[data-ui="separator"][data-style="ornament"]:not([data-variant="vertical"]):dir(rtl)::after {
  background-image: linear-gradient(to right, transparent, var(--color-border));
}

/* A div with no label is built like the hr above. Its own rule, not part of
   the list there: a selector list with one :has() a browser cannot parse is
   dropped whole. */
div[data-ui="separator"][data-style="ornament"]:not([data-variant="vertical"]):not(:has(> [data-part="label"])) {
  justify-content: center;
  block-size: var(--space-3);
  background-image:
    linear-gradient(to right, transparent, var(--color-border)),
    linear-gradient(to left, transparent, var(--color-border));
  background-position: left center, right center;
  background-size: calc(50% - var(--space-4)) var(--divider-width);
  background-repeat: no-repeat;
}

div[data-ui="separator"][data-style="ornament"]:not([data-variant="vertical"]):not(:has(> [data-part="label"]))::before {
  flex: none;
  inline-size: var(--space-2);
  block-size: var(--space-2);
  background: var(--color-primary);
  rotate: 45deg;
}

div[data-ui="separator"][data-style="ornament"]:not([data-variant="vertical"]):not(:has(> [data-part="label"]))::after {
  display: none;
}

/* ── Vertical Sizes ── */
[data-ui="separator"][data-variant="vertical"][data-size="sm"] {
  height: 1rem;
}

[data-ui="separator"][data-variant="vertical"][data-size="md"] {
  height: 1.5rem;
}

[data-ui="separator"][data-variant="vertical"][data-size="lg"] {
  height: 2rem;
}

/* ── Forced colors ──
   Gradients and a tinted fill do not survive a system palette. The ornament
   becomes a plain rule with the diamond on it, drawn in system colours: the
   rules in the hr and in the label-less div are the root's border, in the
   labelled div the two flex pseudo-elements. */
@media (forced-colors: active) {
  hr[data-ui="separator"][data-style="ornament"]:not([data-variant="vertical"]) {
    background-image: none;
    block-size: 0;
    border-block-start: var(--divider-width) solid CanvasText;
  }

  div[data-ui="separator"][data-style="ornament"]:not([data-variant="vertical"]):not(:has(> [data-part="label"])) {
    background-image: none;
    block-size: 0;
    border-block-start: var(--divider-width) solid CanvasText;
  }

  div[data-ui="separator"][data-style="ornament"]:not([data-variant="vertical"])::before,
  div[data-ui="separator"][data-style="ornament"]:not([data-variant="vertical"])::after,
  hr[data-ui="separator"][data-style="ornament"]:not([data-variant="vertical"])::before {
    background-image: none;
    background-color: CanvasText;
  }

  /* The label-less div's diamond is drawn at a higher specificity (its
     :not(:has()) counts), so it is named on its own — never in a list with the
     hr, where an engine without :has() would drop the whole rule. */
  div[data-ui="separator"][data-style="ornament"]:not([data-variant="vertical"]):not(:has(> [data-part="label"]))::before {
    background-image: none;
    background-color: CanvasText;
  }
}


/* === primitives/signature.css === */
/* @ui:component signature */
/* @ui:tokens color-fg-muted space-2 space-12 text-xs font-body weight-medium border-width doc-font doc-signature-gap doc-signature-line-color doc-signature-label-size doc-signature-label-color doc-signature-width */

/* ── Base ── */
[data-ui="signature"] {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  font-family: var(--doc-font, var(--font-body));
  margin-top: var(--doc-signature-gap);
}

/* ── Line ── */
[data-ui="signature"] > [data-part="line"] {
  border-top: var(--border-width) solid var(--doc-signature-line-color);
  min-height: 1px;
}

/* ── Label ── */
[data-ui="signature"] > [data-part="label"] {
  font-size: var(--doc-signature-label-size);
  font-weight: var(--weight-medium);
  color: var(--doc-signature-label-color);
  line-height: 1.4;
}

/* ── Size: SM (40%) ── */
[data-ui="signature"][data-size="sm"] {
  width: 40%;
}

/* ── Size: MD (default) ── */
[data-ui="signature"][data-size="md"],
[data-ui="signature"]:not([data-size]) {
  width: var(--doc-signature-width);
}

/* ── Size: LG (80%) ── */
[data-ui="signature"][data-size="lg"] {
  width: 80%;
}

/* ── Align: Left (default) ── */
[data-ui="signature"][data-align="left"],
[data-ui="signature"]:not([data-align]) {
  align-self: flex-start;
}

/* ── Align: Center ── */
[data-ui="signature"][data-align="center"] {
  align-self: center;
}

/* ── Align: Right ── */
[data-ui="signature"][data-align="right"] {
  align-self: flex-end;
}

/* ── Print ── */
@media print {
  [data-ui="signature"] {
    margin-top: var(--space-12, 3rem);
    break-inside: avoid;
  }
}


/* === primitives/skeleton.css === */
/* @ui:component skeleton */
/* @ui:tokens color-bg-muted color-bg-subtle radius-sm radius-md radius-full ease-default */

/* ── Base (text variant is the default) ── */
[data-ui="skeleton"] {
  display: block;
  width: var(--skeleton-width, 100%);
  height: var(--skeleton-height, 1em);
  background-color: var(--color-bg-muted);
  background-image: linear-gradient(
    90deg,
    var(--color-bg-muted) 25%,
    var(--color-bg-subtle) 50%,
    var(--color-bg-muted) 75%
  );
  background-size: 200% 100%;
  border-radius: var(--skeleton-radius, var(--radius-sm));
  animation: faqir-skeleton-shimmer 1.5s var(--ease-default) infinite;
  pointer-events: none;
  user-select: none;
}

/* ── Variants ── */
[data-ui="skeleton"][data-variant="circle"] {
  width: var(--skeleton-size, 2.5rem);
  height: var(--skeleton-size, 2.5rem);
  border-radius: var(--radius-full);
  flex-shrink: 0;
}

[data-ui="skeleton"][data-variant="rect"] {
  height: var(--skeleton-height, 6rem);
  border-radius: var(--radius-md);
}

/* ── Motion ── */
@keyframes faqir-skeleton-shimmer {
  from { background-position: 200% 0; }
  to   { background-position: -200% 0; }
}

@media (prefers-reduced-motion: reduce) {
  [data-ui="skeleton"] {
    animation: none;
    background-image: none;
  }
}


/* === primitives/spinner.css === */
/* @ui:component spinner */
/* @ui:tokens color-border color-primary radius-full border-width-strong border-width-lg */

/* ── Base ── */
[data-ui="spinner"] {
  display: inline-block;
  width: 24px;
  height: 24px;
  border: var(--border-width-strong) solid var(--color-border);
  border-top-color: var(--color-primary);
  border-radius: var(--radius-full);
  animation: faqir-spin 0.75s linear infinite;
  flex-shrink: 0;
}

/* ── Sizes ── */
[data-ui="spinner"][data-size="sm"] {
  width: 16px;
  height: 16px;
}

[data-ui="spinner"][data-size="lg"] {
  width: 32px;
  height: 32px;
  border-width: var(--border-width-lg);
}

[data-ui="spinner"][data-size="xl"] {
  width: 48px;
  height: 48px;
  border-width: var(--border-width-lg);
}

/* ── Motion ── */
@keyframes faqir-spin {
  to { transform: rotate(360deg); }
}

@media (prefers-reduced-motion: reduce) {
  [data-ui="spinner"] {
    animation: none;
    border-top-color: var(--color-primary);
    opacity: 0.8;
  }
}


/* === primitives/spotlight.css === */
/* @ui:component spotlight */
/* @ui:tokens border-width card-radius color-primary duration-slow ease-default */

/* ── Root ──
   A spotlight wraps one box — a card, a tile, or a whole grid of them — and puts
   a pool of the accent on it while the pointer is over it (or focus is inside
   it). The root paints nothing of its own: no background, no border, no
   padding. Its radius is the only thing it shares with the child, so the light
   is clipped to the same silhouette; it defaults to the card's.

   The pool sits at --spotlight-x / --spotlight-y, which default to the top
   centre. CSS cannot read the pointer, so a page that wants the light to FOLLOW
   it writes those two properties itself — one `@pointermove` statement, shown
   in the manifest's `html_follow` template — and no controller ships with the
   engine for it. Without that line the light is a hover glow from the top edge.

   Under reduced motion, on a touch screen, in forced colours or in print there
   is no light at all: the child renders as if the wrapper were not there. */
[data-ui="spotlight"] {
  --faqir-spotlight-color: var(--spotlight-color, var(--color-primary));
  position: relative;
  isolation: isolate;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  border-radius: var(--spotlight-radius, var(--card-radius));
}

/* A <span> root wraps inline-level things. */
span[data-ui="spotlight"] {
  display: inline-grid;
}

/* ── The effect ──
   Only for a reader with a real pointer who has not asked for less motion. */
@media screen and (prefers-reduced-motion: no-preference) and (hover: hover) and (pointer: fine) and (forced-colors: none) {
  /* ── Light (default) ──
     A pool of the accent, painted above the child and ignoring every pointer
     event — a click lands on the card, not on the light. Invisible at rest,
     faded in on hover or when focus moves inside. */
  [data-ui="spotlight"]::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 1;
    border-radius: inherit;
    background: radial-gradient(
      circle var(--spotlight-size, 22rem) at var(--spotlight-x, 50%) var(--spotlight-y, 0%),
      var(--faqir-spotlight-color),
      color-mix(in oklch, var(--faqir-spotlight-color) 35%, transparent) 45%,
      transparent
    );
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--duration-slow) var(--ease-default);
  }

  [data-ui="spotlight"]:hover::after,
  [data-ui="spotlight"]:focus-within::after {
    opacity: var(--spotlight-opacity, 0.18);
  }

  /* ── Variant: border ──
     The light does not fall on the surface, only on its edge. The same pool,
     masked down to a border's width: two mask layers, the second covering the
     content box, combined by exclusion — what is left is the frame. A ring is a
     thin thing, so it is lit more strongly than a surface would be. */
  [data-ui="spotlight"][data-variant="border"]::after {
    padding: var(--border-width);
    -webkit-mask: linear-gradient(black 0 0) content-box, linear-gradient(black 0 0);
    -webkit-mask-composite: xor;
    mask: linear-gradient(black 0 0) content-box exclude, linear-gradient(black 0 0);
  }

  [data-ui="spotlight"][data-variant="border"]:hover::after,
  [data-ui="spotlight"][data-variant="border"]:focus-within::after {
    opacity: min(1, calc(var(--spotlight-opacity, 0.18) * 5));
  }
}

/* ── Reduced motion, forced colours, print ──
   The content and nothing else. */
@media (prefers-reduced-motion: reduce), (forced-colors: active), print {
  [data-ui="spotlight"]::after {
    display: none;
    transition: none;
  }
}


/* === primitives/stack.css === */
/* @ui:component stack */
/* @ui:tokens space-0 space-1 space-2 space-3 space-4 space-6 space-8 space-10 space-12 space-16 */

/* Flexbox, declared in full (task 0.8-03).
 *
 * Direction, gap, align and justify are responsive variant groups: every
 * declared value is also accepted as `data-<attr>-<tier>` for the four canon
 * tiers (FAQIR-SPEC §15). The tier blocks are mobile-first `min-width` and
 * appear in ascending order, so the larger tier wins by document order —
 * spec §15 rule 4, not by specificity.
 *
 * `data-variant="horizontal"` is the deprecated 0.x spelling of
 * `data-direction="horizontal"`: it selects the same rules and is removed in
 * 1.0. It cannot carry a tier suffix — `data-variant` is one of the five
 * frozen protocol attributes — which is why the canonical attribute exists.
 */

/* ── Base (vertical by default) ── */
[data-ui="stack"] {
  display: flex;
  flex-direction: column;
}

/* ── Direction ── */
[data-ui="stack"][data-variant="vertical"],
[data-ui="stack"][data-direction="vertical"] {
  flex-direction: column;
}

[data-ui="stack"][data-variant="horizontal"],
[data-ui="stack"][data-direction="horizontal"] {
  flex-direction: row;
}

/* ── Deprecated: `data-responsive` collapse ──
 * The 0.x bespoke collapse, re-expressed mobile-first: a horizontal stack
 * stays a column below `sm` and becomes a row from `sm` up. Superseded by
 * `data-direction="vertical" data-direction-sm="horizontal"`, which says the
 * same thing in the grammar every component shares. `:where()` keeps the
 * extra attribute at zero specificity, so an explicit tier value always wins.
 */
[data-ui="stack"][data-variant="horizontal"]:where([data-responsive]),
[data-ui="stack"][data-direction="horizontal"]:where([data-responsive]) {
  flex-direction: column;
}

/* ── Gap ── */
[data-ui="stack"][data-gap="0"] {
  gap: var(--space-0, 0px);
}

[data-ui="stack"][data-gap="1"] {
  gap: var(--space-1);
}

[data-ui="stack"][data-gap="2"] {
  gap: var(--space-2);
}

[data-ui="stack"][data-gap="3"] {
  gap: var(--space-3);
}

[data-ui="stack"][data-gap="4"] {
  gap: var(--space-4);
}

[data-ui="stack"][data-gap="6"] {
  gap: var(--space-6);
}

[data-ui="stack"][data-gap="8"] {
  gap: var(--space-8);
}

[data-ui="stack"][data-gap="10"] {
  gap: var(--space-10);
}

[data-ui="stack"][data-gap="12"] {
  gap: var(--space-12);
}

[data-ui="stack"][data-gap="16"] {
  gap: var(--space-16);
}

/* ── Alignment (cross axis) ── */
[data-ui="stack"][data-align="start"] {
  align-items: flex-start;
}

[data-ui="stack"][data-align="center"] {
  align-items: center;
}

[data-ui="stack"][data-align="end"] {
  align-items: flex-end;
}

[data-ui="stack"][data-align="stretch"] {
  align-items: stretch;
}

[data-ui="stack"][data-align="baseline"] {
  align-items: baseline;
}

/* ── Justification (main axis) ── */
[data-ui="stack"][data-justify="start"] {
  justify-content: flex-start;
}

[data-ui="stack"][data-justify="center"] {
  justify-content: center;
}

[data-ui="stack"][data-justify="end"] {
  justify-content: flex-end;
}

[data-ui="stack"][data-justify="between"] {
  justify-content: space-between;
}

[data-ui="stack"][data-justify="around"] {
  justify-content: space-around;
}

/* ── Wrap ── */
/* Intrinsic: a row reflows without naming a breakpoint (spec §15 doctrine 1). */
[data-ui="stack"][data-wrap] {
  flex-wrap: wrap;
}

/* ── Child Flex ── */
/* A growing child may also shrink below its content: the flex default
   `min-inline-size: auto` kept it as wide as a table or an id inside it, and
   the whole row overflowed instead of the content scrolling in its own box. */
[data-ui="stack"] > [data-flex="1"] {
  flex: 1;
  min-inline-size: 0;
}

[data-ui="stack"] > [data-flex="auto"] {
  flex: auto;
  min-inline-size: 0;
}

[data-ui="stack"] > [data-flex="none"] {
  flex: none;
}

/* ── Text Alignment ── */
[data-ui="stack"][data-align-text="start"] {
  text-align: start;
}

[data-ui="stack"][data-align-text="center"] {
  text-align: center;
}

[data-ui="stack"][data-align-text="right"] {
  text-align: end;
}

/* ── Label in horizontal stacks ── */
[data-ui="stack"][data-variant="horizontal"] > [data-ui="label"],
[data-ui="stack"][data-direction="horizontal"] > [data-ui="label"] {
  display: inline;
  margin-bottom: 0;
  white-space: nowrap;
}

/* ── Tier `sm` — from 40rem up ── */
@media (min-width: 40rem) {
  /* Deprecated `data-responsive`: restore the row it collapsed below sm. */
  [data-ui="stack"][data-variant="horizontal"]:where([data-responsive]),
  [data-ui="stack"][data-direction="horizontal"]:where([data-responsive]) {
    flex-direction: row;
  }

  [data-ui="stack"][data-direction-sm="vertical"] {
    flex-direction: column;
  }

  [data-ui="stack"][data-direction-sm="horizontal"] {
    flex-direction: row;
  }

  [data-ui="stack"][data-gap-sm="0"] {
    gap: var(--space-0, 0px);
  }

  [data-ui="stack"][data-gap-sm="1"] {
    gap: var(--space-1);
  }

  [data-ui="stack"][data-gap-sm="2"] {
    gap: var(--space-2);
  }

  [data-ui="stack"][data-gap-sm="3"] {
    gap: var(--space-3);
  }

  [data-ui="stack"][data-gap-sm="4"] {
    gap: var(--space-4);
  }

  [data-ui="stack"][data-gap-sm="6"] {
    gap: var(--space-6);
  }

  [data-ui="stack"][data-gap-sm="8"] {
    gap: var(--space-8);
  }

  [data-ui="stack"][data-gap-sm="10"] {
    gap: var(--space-10);
  }

  [data-ui="stack"][data-gap-sm="12"] {
    gap: var(--space-12);
  }

  [data-ui="stack"][data-gap-sm="16"] {
    gap: var(--space-16);
  }

  [data-ui="stack"][data-align-sm="start"] {
    align-items: flex-start;
  }

  [data-ui="stack"][data-align-sm="center"] {
    align-items: center;
  }

  [data-ui="stack"][data-align-sm="end"] {
    align-items: flex-end;
  }

  [data-ui="stack"][data-align-sm="stretch"] {
    align-items: stretch;
  }

  [data-ui="stack"][data-align-sm="baseline"] {
    align-items: baseline;
  }

  [data-ui="stack"][data-justify-sm="start"] {
    justify-content: flex-start;
  }

  [data-ui="stack"][data-justify-sm="center"] {
    justify-content: center;
  }

  [data-ui="stack"][data-justify-sm="end"] {
    justify-content: flex-end;
  }

  [data-ui="stack"][data-justify-sm="between"] {
    justify-content: space-between;
  }

  [data-ui="stack"][data-justify-sm="around"] {
    justify-content: space-around;
  }

  [data-ui="stack"][data-direction-sm="horizontal"] > [data-ui="label"] {
    display: inline;
    margin-bottom: 0;
    white-space: nowrap;
  }
}

/* ── Tier `md` — from 48rem up ── */
@media (min-width: 48rem) {
  [data-ui="stack"][data-direction-md="vertical"] {
    flex-direction: column;
  }

  [data-ui="stack"][data-direction-md="horizontal"] {
    flex-direction: row;
  }

  [data-ui="stack"][data-gap-md="0"] {
    gap: var(--space-0, 0px);
  }

  [data-ui="stack"][data-gap-md="1"] {
    gap: var(--space-1);
  }

  [data-ui="stack"][data-gap-md="2"] {
    gap: var(--space-2);
  }

  [data-ui="stack"][data-gap-md="3"] {
    gap: var(--space-3);
  }

  [data-ui="stack"][data-gap-md="4"] {
    gap: var(--space-4);
  }

  [data-ui="stack"][data-gap-md="6"] {
    gap: var(--space-6);
  }

  [data-ui="stack"][data-gap-md="8"] {
    gap: var(--space-8);
  }

  [data-ui="stack"][data-gap-md="10"] {
    gap: var(--space-10);
  }

  [data-ui="stack"][data-gap-md="12"] {
    gap: var(--space-12);
  }

  [data-ui="stack"][data-gap-md="16"] {
    gap: var(--space-16);
  }

  [data-ui="stack"][data-align-md="start"] {
    align-items: flex-start;
  }

  [data-ui="stack"][data-align-md="center"] {
    align-items: center;
  }

  [data-ui="stack"][data-align-md="end"] {
    align-items: flex-end;
  }

  [data-ui="stack"][data-align-md="stretch"] {
    align-items: stretch;
  }

  [data-ui="stack"][data-align-md="baseline"] {
    align-items: baseline;
  }

  [data-ui="stack"][data-justify-md="start"] {
    justify-content: flex-start;
  }

  [data-ui="stack"][data-justify-md="center"] {
    justify-content: center;
  }

  [data-ui="stack"][data-justify-md="end"] {
    justify-content: flex-end;
  }

  [data-ui="stack"][data-justify-md="between"] {
    justify-content: space-between;
  }

  [data-ui="stack"][data-justify-md="around"] {
    justify-content: space-around;
  }

  [data-ui="stack"][data-direction-md="horizontal"] > [data-ui="label"] {
    display: inline;
    margin-bottom: 0;
    white-space: nowrap;
  }
}

/* ── Tier `lg` — from 64rem up ── */
@media (min-width: 64rem) {
  [data-ui="stack"][data-direction-lg="vertical"] {
    flex-direction: column;
  }

  [data-ui="stack"][data-direction-lg="horizontal"] {
    flex-direction: row;
  }

  [data-ui="stack"][data-gap-lg="0"] {
    gap: var(--space-0, 0px);
  }

  [data-ui="stack"][data-gap-lg="1"] {
    gap: var(--space-1);
  }

  [data-ui="stack"][data-gap-lg="2"] {
    gap: var(--space-2);
  }

  [data-ui="stack"][data-gap-lg="3"] {
    gap: var(--space-3);
  }

  [data-ui="stack"][data-gap-lg="4"] {
    gap: var(--space-4);
  }

  [data-ui="stack"][data-gap-lg="6"] {
    gap: var(--space-6);
  }

  [data-ui="stack"][data-gap-lg="8"] {
    gap: var(--space-8);
  }

  [data-ui="stack"][data-gap-lg="10"] {
    gap: var(--space-10);
  }

  [data-ui="stack"][data-gap-lg="12"] {
    gap: var(--space-12);
  }

  [data-ui="stack"][data-gap-lg="16"] {
    gap: var(--space-16);
  }

  [data-ui="stack"][data-align-lg="start"] {
    align-items: flex-start;
  }

  [data-ui="stack"][data-align-lg="center"] {
    align-items: center;
  }

  [data-ui="stack"][data-align-lg="end"] {
    align-items: flex-end;
  }

  [data-ui="stack"][data-align-lg="stretch"] {
    align-items: stretch;
  }

  [data-ui="stack"][data-align-lg="baseline"] {
    align-items: baseline;
  }

  [data-ui="stack"][data-justify-lg="start"] {
    justify-content: flex-start;
  }

  [data-ui="stack"][data-justify-lg="center"] {
    justify-content: center;
  }

  [data-ui="stack"][data-justify-lg="end"] {
    justify-content: flex-end;
  }

  [data-ui="stack"][data-justify-lg="between"] {
    justify-content: space-between;
  }

  [data-ui="stack"][data-justify-lg="around"] {
    justify-content: space-around;
  }

  [data-ui="stack"][data-direction-lg="horizontal"] > [data-ui="label"] {
    display: inline;
    margin-bottom: 0;
    white-space: nowrap;
  }
}

/* ── Tier `xl` — from 80rem up ── */
@media (min-width: 80rem) {
  [data-ui="stack"][data-direction-xl="vertical"] {
    flex-direction: column;
  }

  [data-ui="stack"][data-direction-xl="horizontal"] {
    flex-direction: row;
  }

  [data-ui="stack"][data-gap-xl="0"] {
    gap: var(--space-0, 0px);
  }

  [data-ui="stack"][data-gap-xl="1"] {
    gap: var(--space-1);
  }

  [data-ui="stack"][data-gap-xl="2"] {
    gap: var(--space-2);
  }

  [data-ui="stack"][data-gap-xl="3"] {
    gap: var(--space-3);
  }

  [data-ui="stack"][data-gap-xl="4"] {
    gap: var(--space-4);
  }

  [data-ui="stack"][data-gap-xl="6"] {
    gap: var(--space-6);
  }

  [data-ui="stack"][data-gap-xl="8"] {
    gap: var(--space-8);
  }

  [data-ui="stack"][data-gap-xl="10"] {
    gap: var(--space-10);
  }

  [data-ui="stack"][data-gap-xl="12"] {
    gap: var(--space-12);
  }

  [data-ui="stack"][data-gap-xl="16"] {
    gap: var(--space-16);
  }

  [data-ui="stack"][data-align-xl="start"] {
    align-items: flex-start;
  }

  [data-ui="stack"][data-align-xl="center"] {
    align-items: center;
  }

  [data-ui="stack"][data-align-xl="end"] {
    align-items: flex-end;
  }

  [data-ui="stack"][data-align-xl="stretch"] {
    align-items: stretch;
  }

  [data-ui="stack"][data-align-xl="baseline"] {
    align-items: baseline;
  }

  [data-ui="stack"][data-justify-xl="start"] {
    justify-content: flex-start;
  }

  [data-ui="stack"][data-justify-xl="center"] {
    justify-content: center;
  }

  [data-ui="stack"][data-justify-xl="end"] {
    justify-content: flex-end;
  }

  [data-ui="stack"][data-justify-xl="between"] {
    justify-content: space-between;
  }

  [data-ui="stack"][data-justify-xl="around"] {
    justify-content: space-around;
  }

  [data-ui="stack"][data-direction-xl="horizontal"] > [data-ui="label"] {
    display: inline;
    margin-bottom: 0;
    white-space: nowrap;
  }
}


/* === primitives/stamp.css === */
/* @ui:component stamp */
/* @ui:tokens color-fg color-primary color-destructive color-success space-3 space-1 space-2 space-4 border-width-lg radius-sm radius-full corner-shape font-ui text-sm text-xs text-lg weight-bold */

/* ── Base ──
   A rubber-stamp mark: capitals, wide-tracked and heavy, in a double rule, set
   at a slight angle as if pressed on by hand. "Sold out", "Look 07", "No. 0417",
   "Limited edition". It is real text in a real box: the angle is a `rotate`, so
   layout, reading order and selection are untouched.
   The ink is one custom property, and the text and the border both draw in it.
   Wide tracking leaves a trailing gap after the last letter, so the inline-end
   padding gives that gap back; the word sits centred in its frame.
   --stamp-rotate is the angle (default -6deg). */
[data-ui="stamp"] {
  --faqir-stamp-ink: var(--color-fg);
  --faqir-stamp-track: 0.16em;
  --faqir-stamp-px: var(--space-3);
  --faqir-stamp-py: var(--space-1);

  /* Block-level but only as wide as its word: a stamp sits on its own line (in a
     card header, beside a row in a cluster), and a block box takes the page
     rhythm the way an atomic inline box cannot. */
  display: flex;
  inline-size: fit-content;
  align-items: center;
  justify-content: center;
  box-sizing: border-box;
  padding-block: var(--faqir-stamp-py);
  padding-inline-start: var(--faqir-stamp-px);
  padding-inline-end: calc(var(--faqir-stamp-px) - var(--faqir-stamp-track));
  border: var(--border-width-lg) double var(--faqir-stamp-ink);
  border-radius: var(--radius-sm);
  corner-shape: var(--corner-shape);
  color: var(--faqir-stamp-ink);
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  font-weight: var(--weight-bold);
  line-height: 1.1;
  letter-spacing: var(--faqir-stamp-track);
  text-transform: uppercase;
  text-align: center;
  white-space: nowrap;
  rotate: var(--stamp-rotate, -6deg);
}

/* ── Variants ──
   The ink only; the semantic colours are the ones the rest of the registry
   uses for the same meaning. */
[data-ui="stamp"][data-variant="primary"] {
  --faqir-stamp-ink: var(--color-primary);
}

[data-ui="stamp"][data-variant="destructive"] {
  --faqir-stamp-ink: var(--color-destructive);
}

[data-ui="stamp"][data-variant="success"] {
  --faqir-stamp-ink: var(--color-success);
}

/* ── Sizes ── */
[data-ui="stamp"][data-size="sm"] {
  --faqir-stamp-px: var(--space-2);
  --faqir-stamp-py: 0;
  font-size: var(--text-xs);
}

[data-ui="stamp"][data-size="lg"] {
  --faqir-stamp-px: var(--space-4);
  --faqir-stamp-py: var(--space-2);
  font-size: var(--text-lg);
}

/* ── Shape: round ──
   A circular seal. The width is in em, so a seal scales with its size and every
   seal of one size is the same disc; the text wraps and balances inside it. */
[data-ui="stamp"][data-shape="round"] {
  inline-size: 8em;
  aspect-ratio: 1;
  padding-block: var(--space-2);
  padding-inline-start: var(--space-2);
  padding-inline-end: calc(var(--space-2) - var(--faqir-stamp-track));
  border-radius: var(--radius-full);
  line-height: 1.2;
  white-space: normal;
  text-wrap: balance;
  overflow-wrap: anywhere;
}


/* === primitives/stat.css === */
/* @ui:component stat */
/* @ui:tokens color-fg color-fg-muted color-success color-destructive color-bg color-border space-1 space-4 radius-md shadow-sm font-heading font-body text-xs text-sm text-lg text-2xl text-3xl weight-semibold weight-bold border-width doc-font doc-print-border-color stat-label-size stat-label-color stat-value-size stat-value-weight stat-value-num-font stat-change-positive stat-change-negative */

/* ── Base ── */
[data-ui="stat"] {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  font-family: var(--doc-font, var(--font-body));
}

/* ── Label ── */
[data-ui="stat"] > [data-part="label"] {
  font-size: var(--stat-label-size);
  font-weight: var(--weight-semibold);
  color: var(--stat-label-color);
  line-height: 1.2;
  order: -1;
}

/* ── Value ── */
[data-ui="stat"] > [data-part="value"] {
  font-family: var(--font-heading);
  font-size: var(--stat-value-size);
  font-weight: var(--stat-value-weight);
  color: var(--color-fg);
  line-height: 1.1;
  font-variant-numeric: var(--stat-value-num-font);
  font-feature-settings: "tnum";
}

/* ── Change Indicator ── */
[data-ui="stat"] > [data-part="change"] {
  font-size: var(--text-xs);
  font-weight: var(--weight-semibold);
  color: var(--color-fg-muted);
  line-height: 1.2;
}

/* ── Icon ── */
[data-ui="stat"] > [data-part="icon"] {
  flex-shrink: 0;
  color: var(--color-fg-muted);
}

/* ── Trend: Up ── */
[data-ui="stat"][data-trend="up"] > [data-part="change"] {
  color: var(--stat-change-positive);
}

/* ── Trend: Down ── */
[data-ui="stat"][data-trend="down"] > [data-part="change"] {
  color: var(--stat-change-negative);
}

/* ── Trend: Neutral ── */
[data-ui="stat"][data-trend="neutral"] > [data-part="change"] {
  color: var(--color-fg-muted);
}

/* ── Size: Small ── */
[data-ui="stat"][data-size="sm"] > [data-part="value"] {
  font-size: var(--text-lg, 1.125rem);
}

[data-ui="stat"][data-size="sm"] > [data-part="label"] {
  font-size: var(--text-xs);
}

/* ── Size: Large ── */
[data-ui="stat"][data-size="lg"] > [data-part="value"] {
  font-size: var(--text-3xl, 1.875rem);
}

[data-ui="stat"][data-size="lg"] > [data-part="label"] {
  font-size: var(--text-sm);
}

/* ── Variant: Card ── */
[data-ui="stat"][data-variant="card"] {
  padding: var(--space-4);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-md, 0.375rem);
  background: var(--color-bg);
  box-shadow: var(--shadow-sm);
}

/* ── Value + Change Inline ── */
[data-ui="stat"] > [data-part="value"] + [data-part="change"] {
  margin-top: var(--space-1);
}

/* ── Print ── */
@media print {
  [data-ui="stat"][data-variant="card"] {
    box-shadow: none;
    border: var(--border-width) solid var(--doc-print-border-color, var(--color-border, #ccc));
  }

  [data-ui="stat"] {
    break-inside: avoid;
  }
}


/* === primitives/stepper.css === */
/* @ui:component stepper */
/* @ui:tokens color-primary color-primary-fg color-bg-muted color-fg-muted color-success color-success-subtle color-border text-sm text-xs weight-medium radius-full space-1 space-2 space-4 space-6 border-width-strong */

/* ── Base ── */
[data-ui="stepper"] {
  display: flex;
  align-items: center;
  gap: 0;
}

/* ── Step ── */
[data-ui="stepper"] > [data-part="step"] {
  display: flex;
  align-items: center;
  gap: 0;
}

/* ── Indicator (circle) ── */
[data-ui="stepper"] > :where([data-part="step"]) > [data-part="indicator"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border-radius: var(--radius-full);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  background: var(--color-bg-muted);
  color: var(--color-fg-muted);
  flex-shrink: 0;
}

/* ── Active step ── */
[data-ui="stepper"] > [data-part="step"][data-state="active"] > [data-part="indicator"] {
  background: var(--color-primary);
  color: var(--color-primary-fg);
}

/* ── Completed step ── */
/* The bare `white` that used to sit here was the last colour literal in the
   registry, and no token could reach it: on a theme whose success colour is a
   pale mint — 9 of the 12 dark themes — the numeral inside a completed step
   was white on near-white. There is no `--color-success-fg` to swap in (the
   token set pairs a `-fg` only with primary, secondary and destructive), so
   this uses the pair the contrast gate already guarantees at AA:
   `--color-success` ON `--color-success-subtle`. Completed reads as a settled
   tint next to the active step's solid fill, which is what "done" should look
   like beside "you are here". [W3-3] */
[data-ui="stepper"] > [data-part="step"][data-state="completed"] > [data-part="indicator"] {
  background: var(--color-success-subtle);
  color: var(--color-success);
}

/* ── Step label ──
   Mobile-first (task 0.8-08): the label is hidden on a phone, where a row of
   indicators is all that fits, and revealed from the canon `sm` tier up by the
   responsive block at the foot of this sheet. `revert` rather than a literal
   `inline` so the element's own tag decides — the CSS does not have to know
   that the slot ships as a `<span>`. */
[data-ui="stepper"] > :where([data-part="step"]) > [data-part="label"] {
  display: none;
  font-size: var(--text-xs);
  color: var(--color-fg-muted);
  margin-inline-start: var(--space-1);
  white-space: nowrap;
}

[data-ui="stepper"] > [data-part="step"][data-state="active"] > [data-part="label"] {
  color: var(--color-primary);
  font-weight: var(--weight-medium);
}

[data-ui="stepper"] > [data-part="step"][data-state="completed"] > [data-part="label"] {
  color: var(--color-success);
}

/* ── Connector ──
   The tight phone metrics are the base; the roomier ones arrive at `sm`. */
[data-ui="stepper"] > [data-part="connector"] {
  flex: 1;
  height: var(--border-width-strong);
  background: var(--color-border);
  margin: 0 var(--space-1);
  min-width: var(--space-2);
}

[data-ui="stepper"] > [data-part="connector"][data-state="completed"] {
  background: var(--color-success);
}

/* ── Vertical variant ── */
[data-ui="stepper"][data-variant="vertical"] {
  flex-direction: column;
  align-items: flex-start;
}

[data-ui="stepper"][data-variant="vertical"] > [data-part="step"] {
  flex-direction: row;
  align-items: center;
}

[data-ui="stepper"][data-variant="vertical"] > [data-part="connector"] {
  width: 2px;
  height: var(--space-6);
  min-width: 0;
  margin: var(--space-1) 0 var(--space-1) calc(1rem - 1px);
}

/* ── Size: small ── */
[data-ui="stepper"][data-size="sm"] > :where([data-part="step"]) > [data-part="indicator"] {
  width: 1.5rem;
  height: 1.5rem;
  font-size: var(--text-xs);
}

[data-ui="stepper"][data-size="sm"][data-variant="vertical"] > [data-part="connector"] {
  margin-inline-start: calc(0.75rem - 1px);
}

/* ── Size: large ── */
[data-ui="stepper"][data-size="lg"] > :where([data-part="step"]) > [data-part="indicator"] {
  width: 2.5rem;
  height: 2.5rem;
  font-size: var(--text-sm);
}

[data-ui="stepper"][data-size="lg"][data-variant="vertical"] > [data-part="connector"] {
  margin-inline-start: calc(1.25rem - 1px);
}

/* ── Responsive: labels and connector breathing room, from `sm` up ──
   The canon's `sm` floor (40rem / 640px). The 1.x sheet expressed the identical
   design as `@media (max-width: 640px)` overriding a desktop base; the only
   observable difference is the boundary itself, which now belongs to the wide
   side (at exactly 640px labels show rather than hide). */
@media (min-width: 40rem) {
  [data-ui="stepper"] > :where([data-part="step"]) > [data-part="label"] {
    display: revert;
  }

  [data-ui="stepper"] > [data-part="connector"] {
    min-width: var(--space-4);
    margin: 0 var(--space-2);
  }
}


/* === primitives/surface.css === */
/* @ui:component surface */
/* @ui:tokens color-bg color-surface-1 color-surface-2 color-surface-1-border color-surface-2-border measure-content measure-narrow measure-prose measure-wide radius-lg shadow-sm shadow-lg space-3 space-4 space-6 border-width corner-shape surface-backdrop texture-surface */

/* ── Base ── */
[data-ui="surface"] {
  background-color: var(--color-surface-1);
  background-image: var(--texture-surface);
  border-radius: var(--radius-lg);
  corner-shape: var(--corner-shape);
  border: var(--border-width) solid var(--color-surface-1-border);
}

/* ── Elevation Variants ── */
[data-ui="surface"][data-variant="flat"] {
  background-color: var(--color-bg);
  border: none;
  box-shadow: none;
}

[data-ui="surface"][data-variant="raised"] {
  box-shadow: var(--shadow-sm);
}

[data-ui="surface"][data-variant="overlay"] {
  background-color: var(--color-surface-2);
  box-shadow: var(--shadow-lg);
  border-color: var(--color-surface-2-border);
}

/* An overlay is the one surface variant that floats over other content, so it
   is the one that can be frosted. Guarded exactly as themes/glass.css guards
   its own: a browser without backdrop-filter renders the solid surface above
   and never sees this rule. */
@supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
  [data-ui="surface"][data-variant="overlay"] {
    -webkit-backdrop-filter: var(--surface-backdrop);
    backdrop-filter: var(--surface-backdrop);
  }
}

/* ── Padding Sizes ── */
[data-ui="surface"][data-size="sm"] {
  padding: var(--space-3);
}

[data-ui="surface"][data-size="md"] {
  padding: var(--space-4);
}

[data-ui="surface"][data-size="lg"] {
  padding: var(--space-6);
}

/* ── Measure ──
 * Re-expressed over the shared measure tokens in task 0.8-06 (surface 2.0.0).
 * The 1.x ladder was five hardcoded pixel values named sm|md|lg|xl|2xl — the
 * breakpoint canon's own names used for max-widths, so `data-max="lg"` read as
 * "at the lg tier" when it meant "1024px wide". It is now the same vocabulary
 * the `container` primitive speaks, resolving to the same tokens, and logical:
 * `max-inline-size`, not `max-width`. */
[data-ui="surface"][data-max="narrow"] {
  max-inline-size: var(--measure-narrow);
  margin-inline: auto;
}

[data-ui="surface"][data-max="content"] {
  max-inline-size: var(--measure-content);
  margin-inline: auto;
}

[data-ui="surface"][data-max="wide"] {
  max-inline-size: var(--measure-wide);
  margin-inline: auto;
}

[data-ui="surface"][data-max="prose"] {
  max-inline-size: var(--measure-prose);
  margin-inline: auto;
}

[data-ui="surface"][data-max="full"] {
  max-inline-size: 100%;
}

/* ── Text Alignment ── */
[data-ui="surface"][data-align-text="center"] {
  text-align: center;
}

[data-ui="surface"][data-align-text="right"] {
  text-align: end;
}


/* === primitives/switch.css === */
/* @ui:component switch */
/* @ui:tokens color-bg-muted color-primary color-primary-fg color-border color-ring shadow-xs space-0h space-2 duration-fast ease-default border-width focus-ring-width focus-ring-offset focus-ring-style focus-ring-color focus-shadow switch-radius switch-width switch-height switch-thumb switch-travel switch-bg switch-thumb-shadow disabled-opacity */

/* -- Label wrapper -- */
[data-ui="switch-label"] {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2, 0.5rem);
  cursor: pointer;
}

[data-ui="switch-label"]:has([data-ui="switch"]:disabled) {
  cursor: not-allowed;
  opacity: var(--disabled-opacity);
}

/* -- Base (track) -- */
/* Travel direction.
   `translateX` is PHYSICAL, and CSS has no logical translate: in an RTL page
   the track flips but the thumb still slid right, 17px outside its own track.
   One sign flip, read by every `translateX` below. `[dir]` covers the attribute
   an RTL page sets; `:dir()` is a separate rule so a browser without it still
   applies the first. [W3-3] */
[data-ui="switch"] {
  --switch-dir: 1;
}
[dir="rtl"] [data-ui="switch"],
[data-ui="switch"][dir="rtl"] {
  --switch-dir: -1;
}
[data-ui="switch"]:dir(rtl) {
  --switch-dir: -1;
}

[data-ui="switch"] {
  appearance: none;
  display: inline-flex;
  align-items: center;
  width: var(--switch-width, 44px);
  height: var(--switch-height, 24px);
  padding: var(--space-0h, 2px);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--switch-radius);
  background: var(--switch-bg, var(--color-bg-muted));
  cursor: pointer;
  position: relative;
  transition: background var(--duration-fast) var(--ease-default),
              border-color var(--duration-fast) var(--ease-default),
              box-shadow var(--duration-fast) var(--ease-default);
}

[data-ui="switch"]:focus-visible {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  outline-offset: var(--focus-ring-offset);
  box-shadow: var(--focus-shadow);
}

/* -- Thumb (pseudo-element for <input>, child for custom markup) -- */
[data-ui="switch"]::after {
  content: "";
  display: block;
  width: var(--switch-thumb, 18px);
  height: var(--switch-thumb, 18px);
  border-radius: var(--switch-radius);
  background: var(--color-primary-fg);
  box-shadow: var(--switch-thumb-shadow, var(--shadow-xs));
  transition: transform var(--duration-fast) var(--ease-default);
  pointer-events: none;
}

/* Child thumb (for non-input elements like <button>) */
[data-ui="switch"] > [data-part="thumb"] {
  display: block;
  width: var(--switch-thumb, 18px);
  height: var(--switch-thumb, 18px);
  border-radius: var(--switch-radius);
  background: var(--color-primary-fg);
  box-shadow: var(--switch-thumb-shadow, var(--shadow-xs));
  transition: transform var(--duration-fast) var(--ease-default);
  pointer-events: none;
}

/* Hide pseudo-thumb when a real thumb child exists */
[data-ui="switch"]:has(> [data-part="thumb"])::after {
  display: none;
}

/* -- On state -- */
[data-ui="switch"]:checked,
[data-ui="switch"][aria-checked="true"],
[data-ui="switch"][data-state="on"] {
  background: var(--color-primary);
  border-color: var(--color-primary);
}

[data-ui="switch"]:checked::after,
[data-ui="switch"][aria-checked="true"]::after,
[data-ui="switch"][data-state="on"]::after {
  transform: translateX(calc(var(--switch-travel, 20px) * var(--switch-dir, 1)));
}

[data-ui="switch"][aria-checked="true"] > [data-part="thumb"],
[data-ui="switch"][data-state="on"] > [data-part="thumb"] {
  transform: translateX(calc(var(--switch-travel, 20px) * var(--switch-dir, 1)));
}

/* -- Sizes -- */

/* Small: 36x20, thumb 14px, travel 16px */
[data-ui="switch"][data-size="sm"] {
  width: 36px;
  height: 20px;
}
[data-ui="switch"][data-size="sm"]::after,
[data-ui="switch"][data-size="sm"] > [data-part="thumb"] {
  width: 14px;
  height: 14px;
}
[data-ui="switch"][data-size="sm"]:checked::after,
[data-ui="switch"][data-size="sm"][aria-checked="true"]::after,
[data-ui="switch"][data-size="sm"][data-state="on"]::after,
[data-ui="switch"][data-size="sm"][aria-checked="true"] > [data-part="thumb"],
[data-ui="switch"][data-size="sm"][data-state="on"] > [data-part="thumb"] {
  transform: translateX(calc(16px * var(--switch-dir, 1)));
}

/* Large: 52x28, thumb 22px, travel 24px */
[data-ui="switch"][data-size="lg"] {
  width: 52px;
  height: 28px;
}
[data-ui="switch"][data-size="lg"]::after,
[data-ui="switch"][data-size="lg"] > [data-part="thumb"] {
  width: 22px;
  height: 22px;
}
[data-ui="switch"][data-size="lg"]:checked::after,
[data-ui="switch"][data-size="lg"][aria-checked="true"]::after,
[data-ui="switch"][data-size="lg"][data-state="on"]::after,
[data-ui="switch"][data-size="lg"][aria-checked="true"] > [data-part="thumb"],
[data-ui="switch"][data-size="lg"][data-state="on"] > [data-part="thumb"] {
  transform: translateX(calc(24px * var(--switch-dir, 1)));
}

/* -- Disabled -- */
[data-ui="switch"]:disabled {
  cursor: not-allowed;
}

/* -- Forced colors (Windows High Contrast) --
   Every colour above is dropped by the OS, so the track rendered as an empty
   pill and ON and OFF were pixel-identical: the ONE thing this control exists
   to say could not be read. `forced-color-adjust: none` on the thumb keeps a
   fill the OS would otherwise strip, and the system keywords carry the state:
   the track's border is always visible, and ON fills it with `Highlight`. [W3-3] */
@media (forced-colors: active) {
  [data-ui="switch"] {
    border: var(--border-width) solid ButtonText;
    background: ButtonFace;
  }

  [data-ui="switch"]::after,
  [data-ui="switch"] > [data-part="thumb"] {
    forced-color-adjust: none;
    background: ButtonText;
  }

  [data-ui="switch"]:checked,
  [data-ui="switch"][aria-checked="true"],
  [data-ui="switch"][data-state="on"] {
    background: Highlight;
    border-color: Highlight;
  }

  [data-ui="switch"]:checked::after,
  [data-ui="switch"][aria-checked="true"]::after,
  [data-ui="switch"][data-state="on"]::after,
  [data-ui="switch"][aria-checked="true"] > [data-part="thumb"],
  [data-ui="switch"][data-state="on"] > [data-part="thumb"] {
    background: HighlightText;
  }

  [data-ui="switch"]:disabled {
    border-color: GrayText;
  }

  [data-ui="switch"]:focus-visible {
    outline-color: Highlight;
  }
}

/* -- Motion -- */
@media (prefers-reduced-motion: reduce) {
  [data-ui="switch"],
  [data-ui="switch"]::after,
  [data-ui="switch"] > [data-part="thumb"] {
    transition: none;
  }
}


/* === primitives/switcher.css === */
/* @ui:component switcher */
/* @ui:tokens space-0 space-1 space-2 space-3 space-4 space-6 space-8 space-10 space-12 space-16 */

/* The container-driven row (task 0.8-05).
 *
 * A switcher is a row that becomes a column when it is not given enough room —
 * and it asks its OWN inline size, never the viewport. That is the doctrine's
 * middle rung (FAQIR-SPEC §15 doctrine 2) made concrete: the same markup is
 * correct full-bleed on a desktop, inside a 20rem sidebar, and inside a modal,
 * because none of those places are things a media query can see. This file
 * contains no `@media` rule at all, and that absence is the component.
 *
 * The mechanism is `container-type: inline-size` plus `@container`, the second
 * such precedent after `table`. One consequence shapes the CSS: `@container`
 * styles the container's DESCENDANTS, never the container itself, so the flip
 * cannot be written as `flex-direction` on the root. It is written on the
 * children instead — `flex-basis: 100%` puts every child on its own line
 * (a column), and the container rules release them to `flex-basis: 0`
 * (equal-width columns of one row). Mobile-first, exactly like the viewport
 * ladder: narrow is the base, width is what adds the row.
 *
 * `data-threshold` names the width at which the row is affordable, over the
 * canon tiers (`sm` 40rem · `md` 48rem · `lg` 64rem · `xl` 80rem — the numbers
 * of FAQIR-SPEC §15, `src/utils/breakpoints.ts`). The tier names mean the same
 * lengths they always did; only the box being measured is different, which is
 * why they are NOT the viewport grammar and may not be suffixed onto anything.
 * A prelude cannot read a custom property, so the numbers are literal here for
 * the same reason the canon is a module and not a token.
 *
 * `data-gap` is deliberately not responsive: a `data-gap-md` would couple a
 * switcher to the viewport, which is the one thing it exists not to do.
 */

/* ── Base ──
 * The element is its own query container, and a column until told otherwise.
 *
 * `inline-size: 100%` is not decoration: inline-size containment means the box's
 * own width may not depend on its contents, so in a shrink-to-fit context (a
 * flex or grid item, a floated parent) an unsized container resolves to zero
 * width and every threshold reads as "narrow". Taking the width from the parent
 * is what makes the query answer a real question — the same reason `table` sizes
 * its container root. */
[data-ui="switcher"] {
  container-type: inline-size;
  container-name: faqir-switcher;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  inline-size: 100%;
}

/* Every child on its own line: the column half of the switch. */
[data-ui="switcher"] > * {
  flex-basis: 100%;
  flex-grow: 1;
  /* Long words and tables may shrink instead of forcing an overflow once the
   * children sit side by side. */
  min-inline-size: 0;
}

/* ── Gap ── */
[data-ui="switcher"][data-gap="0"] { gap: var(--space-0, 0px); }
[data-ui="switcher"][data-gap="1"] { gap: var(--space-1); }
[data-ui="switcher"][data-gap="2"] { gap: var(--space-2); }
[data-ui="switcher"][data-gap="3"] { gap: var(--space-3); }
[data-ui="switcher"][data-gap="4"] { gap: var(--space-4); }
[data-ui="switcher"][data-gap="6"] { gap: var(--space-6); }
[data-ui="switcher"][data-gap="8"] { gap: var(--space-8); }
[data-ui="switcher"][data-gap="10"] { gap: var(--space-10); }
[data-ui="switcher"][data-gap="12"] { gap: var(--space-12); }
[data-ui="switcher"][data-gap="16"] { gap: var(--space-16); }

/* ── The switch — container queries only ──
 * Each block releases the children of the switchers whose threshold it is, so
 * exactly one block can ever apply to one element and the four cannot fight.
 * Every selector here is (0,2,0) against the (0,1,0) base above, so the row
 * wins wherever a bundler puts these blocks.
 *
 * `:not([data-threshold])` is the declared default (`sm`) made real rather than
 * documented: a switcher that names no threshold flips at 40rem of its own
 * width. */

/* Threshold `sm` — a row once the switcher itself is 40rem wide. */
@container faqir-switcher (min-width: 40rem) {
  [data-ui="switcher"]:not([data-threshold]) > *,
  [data-ui="switcher"][data-threshold="sm"] > * {
    flex-basis: 0;
  }
}

/* Threshold `md` — from 48rem of its own width. */
@container faqir-switcher (min-width: 48rem) {
  [data-ui="switcher"][data-threshold="md"] > * {
    flex-basis: 0;
  }
}

/* Threshold `lg` — from 64rem of its own width. */
@container faqir-switcher (min-width: 64rem) {
  [data-ui="switcher"][data-threshold="lg"] > * {
    flex-basis: 0;
  }
}

/* Threshold `xl` — from 80rem of its own width. */
@container faqir-switcher (min-width: 80rem) {
  [data-ui="switcher"][data-threshold="xl"] > * {
    flex-basis: 0;
  }
}


/* === primitives/text.css === */
/* @ui:component text */
/* @ui:tokens color-fg color-fg-muted color-primary color-destructive font-heading font-body font-mono font-ui heading-weight heading-tracking heading-transform heading-caps heading-leading text-xs text-sm text-base text-lg text-xl text-2xl text-3xl text-4xl weight-normal weight-medium weight-semibold weight-bold leading-tight leading-snug leading-normal leading-relaxed link-decoration link-thickness link-underline-offset focus-ring-width focus-ring-style focus-ring-color focus-ring-offset focus-shadow mono-ligatures space-2 */

/* ── Heading ── */
[data-ui="heading"] {
  font-family: var(--font-heading);
  font-weight: var(--heading-weight);
  color: var(--color-fg);
  line-height: var(--heading-leading);
  text-transform: var(--heading-transform);
  font-variant-caps: var(--heading-caps);
  /* The optical tightening a large heading needs, PLUS whatever tracking the
     theme's voice asks for on top of it — so a theme that wants wide-tracked
     headings sets --heading-tracking once and every size follows, instead of
     each size having to re-derive its own number. */
  letter-spacing: calc(-0.01em + var(--heading-tracking));
  /* A heading that is one unbreakable token (an id, a path) may break anywhere.
     `anywhere`, not `break-word`: only it lowers the min-content width a flex
     or grid parent sizes the heading by. */
  overflow-wrap: anywhere;
}

[data-ui="heading"][data-size="1"] {
  font-size: var(--text-4xl);
  letter-spacing: calc(-0.02em + var(--heading-tracking));
}

[data-ui="heading"][data-size="2"] {
  font-size: var(--text-3xl);
  letter-spacing: calc(-0.02em + var(--heading-tracking));
}

[data-ui="heading"][data-size="3"] {
  font-size: var(--text-2xl);
}

[data-ui="heading"][data-size="4"] {
  font-size: var(--text-xl);
  font-weight: var(--weight-semibold);
}

[data-ui="heading"][data-size="5"] {
  font-size: var(--text-lg);
  font-weight: var(--weight-semibold);
}

[data-ui="heading"][data-size="6"] {
  font-size: var(--text-base);
  font-weight: var(--weight-semibold);
}

/* ── Text ── */
[data-ui="text"] {
  font-family: var(--font-body);
  color: var(--color-fg);
}

/* Text sizes */
[data-ui="text"][data-size="xs"] { font-size: var(--text-xs); }
[data-ui="text"][data-size="sm"] { font-size: var(--text-sm); }
[data-ui="text"][data-size="base"] { font-size: var(--text-base); }
[data-ui="text"][data-size="lg"] { font-size: var(--text-lg); }
[data-ui="text"][data-size="xl"] { font-size: var(--text-xl); }

/* Display — oversized, fluid type for a landing hero, on a heading or on text.
   It takes the theme's whole heading voice (family, weight, tracking, case, caps)
   whichever root carries it, so a serif or shouting theme follows. The size
   starts at the largest step of the type scale (or 11vw on a phone, whichever
   is smaller, so a large-scale theme does not split ordinary words), grows with the viewport and stops
   at two and a quarter times that; lines run nearly solid, and the glyph box is
   not the line box, so an inline highlight's background is not cut by them.
   `anywhere` lets one long word break instead of widening the page at 360px;
   `balance` keeps the lines of a short, large phrase level. It sits before the
   weight, leading and alignment rules below so each of those can still adjust it. */
[data-ui="text"][data-size="display"],
[data-ui="heading"][data-size="display"] {
  font-family: var(--font-heading);
  font-weight: var(--heading-weight);
  font-size: clamp(min(var(--text-4xl), 11vw), 1rem + 6vw, calc(var(--text-4xl) * 2.25));
  line-height: 1;
  letter-spacing: calc(-0.03em + var(--heading-tracking));
  text-transform: var(--heading-transform);
  font-variant-caps: var(--heading-caps);
  text-wrap: balance;
  overflow-wrap: anywhere;
}

/* Text color variants */
[data-ui="text"][data-variant="muted"] { color: var(--color-fg-muted); }
[data-ui="text"][data-variant="subtle"] { color: var(--color-fg-muted); }
[data-ui="text"][data-variant="primary"] { color: var(--color-primary); }

/* Eyebrow — the small kicker above a headline ("New", "Case study"). Wide-tracked
   capitals in the control face, semibold, in the accent. There is no separate
   "primary as text" token: --color-primary is the one the themes tune for text
   contrast on both schemes (it is what variant="primary" already uses). The size
   is a default only, in :where() so a data-size on the same element still wins. */
[data-ui="text"][data-variant="eyebrow"] {
  font-family: var(--font-ui);
  font-weight: var(--weight-semibold);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--color-primary);
}

[data-ui="text"]:where([data-variant="eyebrow"]) {
  font-size: var(--text-xs);
}

/* Text weight */
[data-ui="text"][data-weight="normal"] { font-weight: var(--weight-normal); }
[data-ui="text"][data-weight="medium"] { font-weight: var(--weight-medium); }
[data-ui="text"][data-weight="semibold"] { font-weight: var(--weight-semibold); }
[data-ui="text"][data-weight="bold"] { font-weight: var(--weight-bold); }

/* Text leading */
[data-ui="text"][data-leading="tight"] { line-height: var(--leading-tight); }
[data-ui="text"][data-leading="snug"] { line-height: var(--leading-snug); }
[data-ui="text"][data-leading="normal"] { line-height: var(--leading-normal); }
[data-ui="text"][data-leading="relaxed"] { line-height: var(--leading-relaxed); }

/* Text alignment */
[data-ui="text"][data-align="center"],
[data-ui="heading"][data-align="center"] {
  text-align: center;
}

[data-ui="text"][data-align="right"],
[data-ui="heading"][data-align="right"] {
  text-align: end;
}

/* Monospace variant */
[data-ui="text"][data-variant="mono"] {
  font-family: var(--font-mono);
  font-variant-ligatures: var(--mono-ligatures);
  /* Mono text is where ids and hashes live; see the heading rule above. */
  overflow-wrap: anywhere;
}

/* Truncate */
[data-ui="text"][data-truncate] {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Extended sizes */
[data-ui="text"][data-size="2xl"] { font-size: var(--text-2xl); }
[data-ui="text"][data-size="3xl"] { font-size: var(--text-3xl); }
[data-ui="text"][data-size="4xl"] { font-size: var(--text-4xl); }

/* Destructive variant */
[data-ui="text"][data-variant="destructive"] { color: var(--color-destructive); }

/* Link — an anchor carrying data-ui="text". The reset takes every anchor's
   colour and underline away; this hands the underline back and nothing else, so
   an id or a ref in a table reads as a link in the text's own colour, variant
   and size. `:any-link`, not `[href]`: it selects on no attribute. It sits
   before the done state so a done link keeps its strikethrough. */
[data-ui="text"]:any-link {
  text-decoration-line: var(--link-decoration);
  text-decoration-thickness: var(--link-thickness);
  text-underline-offset: var(--link-underline-offset);
  text-decoration-color: currentColor;
  cursor: pointer;
}

[data-ui="text"]:any-link:focus-visible {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  outline-offset: var(--focus-ring-offset);
  box-shadow: var(--focus-shadow);
}

/* Done state */
[data-ui="text"][data-state="done"] {
  text-decoration: line-through;
  color: var(--color-fg-muted);
}

/* Tabular — inline-block with min-width for aligned label/value lists */
[data-ui="text"][data-tabular] {
  /* A component knob, not a design token — declared here so it always resolves
     and an author can see what to override (inline, or on this rule). It is NOT
     a member of the --text-* type scale despite the name it inherited. */
  --text-tabular-width: 8ch;

  display: inline-block;
  min-width: var(--text-tabular-width);
}

/* Drop cap — the first letter of a paragraph, set large in the heading face and
   the accent. Where `initial-letter` is understood the browser sinks it three
   lines and aligns its cap height to the first line's, which is the correct
   drop cap. Elsewhere a float stands in: a four-times capital whose box is
   shorter than the three lines it spans, so the text wraps beside it. The
   float approximates the sink (it assumes ordinary leading); both put the
   letter on the inline-start side, and the gap on its inline end. */
[data-ui="text"][data-dropcap]::first-letter {
  float: inline-start;
  margin-inline-end: var(--space-2);
  font-family: var(--font-heading);
  font-weight: var(--heading-weight);
  font-size: 4em;
  line-height: 0.8;
  color: var(--color-primary);
}

@supports (initial-letter: 3) {
  [data-ui="text"][data-dropcap]::first-letter {
    float: none;
    initial-letter: 3;
    font-size: inherit;
    line-height: inherit;
  }
}


/* === primitives/textarea.css === */
/* @ui:component textarea */
/* @ui:tokens color-fg color-fg-muted color-border color-border-strong color-ring color-destructive radius-md space-2 space-3 space-4 font-ui text-xs text-sm text-base duration-fast ease-default border-width focus-ring-width focus-ring-style focus-ring-color focus-shadow input-border-width input-fill disabled-opacity */

/* -- Base -- */
[data-ui="textarea"] {
  display: block;
  width: 100%;
  min-height: var(--textarea-min-height, 80px);
  padding: var(--space-2) var(--space-3);
  /* Longhands, not the `border:` shorthand: the shorthand's width slot takes
     ONE value, and `controls.input: underline` (1.1A-10) states the silhouette
     as a four-value box — `0 0 var(--border-width) 0` — so only a bottom rule
     is drawn. Identical to the shorthand at every other value of the token. */
  border-style: solid;
  border-color: var(--color-border);
  border-width: var(--input-border-width);
  border-radius: var(--textarea-radius, var(--radius-md));
  background: var(--textarea-bg, var(--input-fill));
  color: var(--color-fg);
  font-family: var(--textarea-font, var(--font-ui));
  font-size: var(--text-sm);
  line-height: 1.5;
  resize: vertical;
  transition: border-color var(--duration-fast) var(--ease-default),
              box-shadow var(--duration-fast) var(--ease-default);
}

[data-ui="textarea"]::placeholder {
  color: var(--color-fg-muted);
}

[data-ui="textarea"]:hover {
  border-color: var(--color-border-strong);
}

[data-ui="textarea"]:focus {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  /* The ring replaces the border rather than sitting outside it: inset by
     exactly the edge it covers, so a heavier shape theme stays aligned. */
  outline-offset: calc(-1 * var(--input-border-width));
  box-shadow: var(--focus-shadow);
  border-color: transparent;
}

/* -- Sizes -- */
[data-ui="textarea"][data-size="sm"] {
  min-height: 60px;
  padding: var(--space-2);
  font-size: var(--text-xs);
}

[data-ui="textarea"][data-size="lg"] {
  min-height: 120px;
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-base);
}

/* -- States -- */
[data-ui="textarea"][data-state="error"],
[data-ui="textarea"][aria-invalid="true"] {
  border-color: var(--color-destructive);
}
[data-ui="textarea"][data-state="error"]:focus,
[data-ui="textarea"][aria-invalid="true"]:focus {
  outline-color: var(--color-destructive);
}

[data-ui="textarea"]:disabled {
  opacity: var(--disabled-opacity);
  cursor: not-allowed;
  resize: none;
}

/* -- Motion -- */
@media (prefers-reduced-motion: reduce) {
  [data-ui="textarea"] {
    transition: none;
  }
}


/* === primitives/timeline.css === */
/* @ui:component timeline */
/* @ui:tokens color-border color-primary color-fg color-bg color-fg-muted color-primary-fg space-8 space-4 space-1 font-body font-ui font-heading border-width-md radius-full text-xs text-sm text-lg duration-normal ease-default ease-out ease-linear weight-semibold heading-tracking leading-snug leading-relaxed motion-ambient-duration motion-ambient-play */

/* ── Root ──
   An ordered list read down a rail. Each item draws its own segment of the
   rail (from its marker to the next item's), so the line is exactly as long
   as the content and stops at the last marker with nothing to measure. */
[data-ui="timeline"] {
  --faqir-timeline-rail: var(--timeline-rail, var(--color-border));
  --faqir-timeline-ink: var(--timeline-color, var(--color-primary));
  --faqir-timeline-marker: var(--timeline-marker-size, 0.875rem);
  --faqir-timeline-gap: var(--timeline-gap, var(--space-8));
  position: relative;
  display: grid;
  gap: var(--faqir-timeline-gap);
  margin: 0;
  padding: 0;
  list-style: none;
  font-family: var(--font-body);
  color: var(--color-fg);
}

/* ── Item ── */
[data-ui="timeline"] > [data-part="item"] {
  position: relative;
  display: grid;
  grid-template-columns: var(--faqir-timeline-marker) minmax(0, 1fr);
  column-gap: var(--space-4);
  align-items: start;
}

/* The rail segment. It runs from this item's top to the next item's top — the
   item's own height plus the gap — centred under the marker column. */
[data-ui="timeline"] > [data-part="item"]::before {
  content: "";
  position: absolute;
  inset-block: 0 calc(var(--faqir-timeline-gap) * -1);
  inset-inline-start: calc((var(--faqir-timeline-marker) - var(--border-width-md)) / 2);
  inline-size: var(--border-width-md);
  background-color: var(--faqir-timeline-rail);
}

[data-ui="timeline"] > [data-part="item"]:last-child::before {
  content: none;
}

/* ── Marker ──
   A ring on the rail. It may hold a glyph (an icon, a step number), in which
   case it grows to fit and the rail still meets it at its centre. */
[data-ui="timeline"] > :where([data-part="item"]) > [data-part="marker"] {
  position: relative;
  z-index: 1;
  display: grid;
  place-items: center;
  box-sizing: border-box;
  inline-size: var(--faqir-timeline-marker);
  block-size: var(--faqir-timeline-marker);
  margin-block-start: 0.3em;
  border: var(--border-width-md) solid var(--faqir-timeline-rail);
  border-radius: var(--radius-full);
  background-color: var(--color-bg);
  color: var(--color-fg-muted);
  font-size: var(--text-xs);
  transition:
    background-color var(--duration-normal) var(--ease-default),
    border-color var(--duration-normal) var(--ease-default);
}

/* ── Content ── */
[data-ui="timeline"] > :where([data-part="item"]) > [data-part="content"] {
  display: grid;
  gap: var(--space-1);
  min-inline-size: 0;
}

[data-ui="timeline"] > :where([data-part="item"]) > :where([data-part="content"]) > [data-part="time"] {
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
  color: var(--color-fg-muted);
}

[data-ui="timeline"] > :where([data-part="item"]) > :where([data-part="content"]) > [data-part="title"] {
  margin: 0;
  font-family: var(--font-heading);
  font-size: var(--text-lg);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--heading-tracking);
  line-height: var(--leading-snug);
  color: var(--color-fg);
}

[data-ui="timeline"] > :where([data-part="item"]) > :where([data-part="content"]) > [data-part="description"] {
  margin: 0;
  line-height: var(--leading-relaxed);
  color: var(--color-fg-muted);
}

/* ── Status ──
   What has happened, what is happening, what has not. `done` fills the marker
   and inks the rail below it; `current` rings the marker in the accent and
   lets it breathe; `upcoming` is the resting look, stated so a roadmap can say
   it out loud. */
[data-ui="timeline"] > [data-part="item"][data-status="done"]::before {
  background-color: var(--faqir-timeline-ink);
}

[data-ui="timeline"] > [data-part="item"][data-status="done"] > [data-part="marker"] {
  border-color: var(--faqir-timeline-ink);
  background-color: var(--faqir-timeline-ink);
  color: var(--color-primary-fg);
}

[data-ui="timeline"] > [data-part="item"][data-status="current"] > [data-part="marker"] {
  border-color: var(--faqir-timeline-ink);
  color: var(--faqir-timeline-ink);
}

[data-ui="timeline"] > [data-part="item"][data-status="current"] > [data-part="marker"]::after {
  content: "";
  position: absolute;
  inset: calc(var(--border-width-md) * -1);
  border: var(--border-width-md) solid var(--faqir-timeline-ink);
  border-radius: inherit;
  animation: faqir-timeline-ping calc(var(--motion-ambient-duration) / 12) var(--ease-out) infinite;
  animation-play-state: var(--motion-ambient-play);
}

@keyframes faqir-timeline-ping {
  from { scale: 1; opacity: 0.7; }
  to   { scale: 2.4; opacity: 0; }
}

/* ── Size: large markers ──
   Room for an icon or a number inside the marker. */
[data-ui="timeline"][data-size="lg"] {
  --faqir-timeline-marker: var(--timeline-marker-size, 2rem);
}

[data-ui="timeline"][data-size="lg"] > :where([data-part="item"]) > [data-part="marker"] {
  margin-block-start: 0;
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
}

/* ── Variant: alternate ──
   From the md tier the rail moves to the centre and items take turns on either
   side of it. Below md it is the default one-sided list: two half-width columns
   on a phone are two unreadable columns. */
@media (min-width: 48rem) {
  [data-ui="timeline"][data-variant="alternate"] > [data-part="item"] {
    grid-template-columns: minmax(0, 1fr) var(--faqir-timeline-marker) minmax(0, 1fr);
  }

  [data-ui="timeline"][data-variant="alternate"] > [data-part="item"]::before {
    inset-inline-start: calc(50% - var(--border-width-md) / 2);
  }

  [data-ui="timeline"][data-variant="alternate"] > :where([data-part="item"]) > [data-part="marker"] {
    grid-column: 2;
    grid-row: 1;
  }

  [data-ui="timeline"][data-variant="alternate"] > :where([data-part="item"]) > [data-part="content"] {
    grid-column: 3;
    grid-row: 1;
  }

  [data-ui="timeline"][data-variant="alternate"] > :where([data-part="item"]:nth-child(odd)) > [data-part="content"] {
    grid-column: 1;
    justify-items: end;
    text-align: end;
  }
}

/* ── Progress ──
   With `data-progress` the timeline reports how far the reader has got: every
   marker fills, and its rail segment inks in, as that item rises through the
   viewport. A view timeline per item — scrubbed by the scrollbar, no script —
   so each one answers for itself and nothing is measured. Where view timelines
   are not supported the timeline simply shows its resting state. */
@supports (animation-timeline: view()) {
  [data-ui="timeline"][data-progress] > :where([data-part="item"]) > [data-part="marker"] {
    animation: faqir-timeline-reach var(--ease-linear) both;
    animation-timeline: view();
    animation-range: cover 30% cover 50%;
  }

  [data-ui="timeline"][data-progress] > [data-part="item"]::before {
    background-image: linear-gradient(var(--faqir-timeline-ink), var(--faqir-timeline-ink));
    background-repeat: no-repeat;
    background-size: 100% 0%;
    animation: faqir-timeline-fill var(--ease-linear) both;
    animation-timeline: view();
    animation-range: cover 35% cover 75%;
  }
}

@keyframes faqir-timeline-reach {
  to {
    border-color: var(--faqir-timeline-ink);
    background-color: var(--faqir-timeline-ink);
    color: var(--color-primary-fg);
  }
}

@keyframes faqir-timeline-fill {
  to { background-size: 100% 100%; }
}

/* ── Motion ── */
@media (prefers-reduced-motion: reduce) {
  [data-ui="timeline"] > :where([data-part="item"]) > [data-part="marker"],
  [data-ui="timeline"] > [data-part="item"]::before {
    animation: none;
    transition: none;
  }

  [data-ui="timeline"] > [data-part="item"][data-status="current"] > [data-part="marker"]::after {
    animation: none;
    opacity: 0;
  }
}

/* ── Print ── */
@media print {
  [data-ui="timeline"] > [data-part="item"] {
    break-inside: avoid;
  }

  [data-ui="timeline"] > :where([data-part="item"]) > [data-part="marker"],
  [data-ui="timeline"] > [data-part="item"]::before {
    animation: none;
  }
}


/* === primitives/toggle.css === */
/* @ui:component toggle */
/* @ui:tokens color-bg color-bg-muted color-fg color-fg-muted color-border color-primary color-primary-subtle color-ring radius-md space-1 space-1h space-2 space-3 space-4 text-xs text-sm text-base font-ui weight-medium duration-fast ease-default border-width focus-ring-width focus-ring-offset focus-ring-style focus-ring-color focus-shadow disabled-opacity */

/* ── Base (off / unpressed) ── */
[data-ui="toggle"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-1h);
  padding: var(--toggle-pad-y, var(--space-1h)) var(--toggle-pad-x, var(--space-3));
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--toggle-radius, var(--radius-md));
  background: var(--color-bg);
  color: var(--color-fg-muted);
  font-family: var(--toggle-font, var(--font-ui));
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  line-height: 1;
  cursor: pointer;
  user-select: none;
  transition: background var(--duration-fast) var(--ease-default),
              border-color var(--duration-fast) var(--ease-default),
              color var(--duration-fast) var(--ease-default);
}

[data-ui="toggle"]:hover {
  background: var(--color-bg-muted);
  color: var(--color-fg);
}

[data-ui="toggle"]:focus-visible {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  outline-offset: var(--focus-ring-offset);
  box-shadow: var(--focus-shadow);
}

/* ── Pressed / on — styled entirely off aria-pressed, no JS ── */
[data-ui="toggle"][aria-pressed="true"] {
  background: var(--color-primary-subtle);
  border-color: var(--color-primary);
  color: var(--color-primary);
}

[data-ui="toggle"][aria-pressed="true"]:hover {
  background: var(--color-primary-subtle);
  color: var(--color-primary);
}

/* ── Disabled ── */
[data-ui="toggle"]:disabled {
  opacity: var(--disabled-opacity);
  cursor: not-allowed;
}

/* ── Sizes ── */
[data-ui="toggle"][data-size="sm"] {
  padding: var(--space-1) var(--space-2);
  font-size: var(--text-xs);
}

[data-ui="toggle"][data-size="lg"] {
  padding: var(--space-2) var(--space-4);
  font-size: var(--text-base);
}

/* ── Forced colors (Windows High Contrast) ──
   Pressed is carried by colour alone, and the OS replaces all three colours
   with the ones an unpressed toggle gets. System colours are the ones it
   keeps; the :hover twin is listed because it is the more specific rule. */
@media (forced-colors: active) {
  [data-ui="toggle"][aria-pressed="true"],
  [data-ui="toggle"][aria-pressed="true"]:hover {
    background: Highlight;
    border-color: Highlight;
    color: HighlightText;
  }
}

/* ── Motion ── */
@media (prefers-reduced-motion: reduce) {
  [data-ui="toggle"] {
    transition: none;
  }
}


/* === primitives/watermark.css === */
/* @ui:component watermark */
/* @ui:tokens color-fg-muted doc-font font-body text-xl text-4xl weight-bold leading-tight space-8 space-20 z-raised */

[data-ui="watermark"] {
  position: fixed;
  inset: 0;
  z-index: var(--z-raised);
  display: grid;
  place-items: center;
  overflow: hidden;
  pointer-events: none;
  user-select: none;
}

[data-ui="watermark"][data-variant="absolute"] {
  position: absolute;
}

[data-ui="watermark"] > [data-part="mark"] {
  color: var(--color-fg-muted);
  font-family: var(--doc-font, var(--font-body));
  font-size: var(--text-4xl);
  font-weight: var(--weight-bold);
  line-height: var(--leading-tight);
  letter-spacing: 0.12em;
  opacity: 0.12;
  text-align: center;
  text-transform: uppercase;
  white-space: nowrap;
  transform: rotate(-35deg);
  transform-origin: center;
}

[data-ui="watermark"] > [data-part="mark"]::before {
  content: attr(data-text);
}

[data-ui="watermark"][data-size="sm"] > [data-part="mark"] {
  font-size: var(--text-xl);
}

[data-ui="watermark"][data-size="lg"] > [data-part="mark"] {
  font-size: calc(var(--text-4xl) * 1.5);
}

[data-ui="watermark"][data-orientation="horizontal"] > [data-part="mark"] {
  transform: none;
}

[data-ui="watermark"][data-pattern="repeated"] {
  grid-template-columns: repeat(3, minmax(0, 1fr));
  grid-template-rows: repeat(3, minmax(0, 1fr));
  gap: var(--space-20);
  padding: var(--space-8);
}

[data-ui="watermark"]:not([data-pattern]) > [data-part="mark"]:not(:first-child),
[data-ui="watermark"][data-pattern="single"] > [data-part="mark"]:not(:first-child) {
  display: none;
}

@media print {
  [data-ui="watermark"] {
    position: fixed;
    inset: 0;
    overflow: hidden;
    color-adjust: exact;
    print-color-adjust: exact;
    -webkit-print-color-adjust: exact;
  }

  [data-ui="watermark"][data-variant="absolute"] {
    position: absolute;
  }
}


/* === recipes/accordion.css === */
/* @ui:component accordion */
/* @ui:tokens color-fg color-fg-muted color-border color-bg-muted space-4 text-sm text-base weight-medium duration-normal ease-default radius-lg radius-sm font-ui border-width focus-ring-width focus-ring-style focus-ring-color focus-ring-offset */

/* ── Root ── */
[data-ui="accordion"] {
  width: 100%;
}

/* Parts are reached by child combinators, never descendant ones, so an
   accordion (or anything else with a `trigger`) nested in a section's content
   keeps its own parts: an expanded section used to rotate every chevron below
   it. A trigger is its item's child, or the child of a heading that is — the
   APG shape, `<h3><button data-part="trigger">`. Hops sit in `:where()` so each
   rule keeps its specificity. [1.1F-20] */

/* ── Item ── */
[data-ui="accordion"] > [data-part="item"] {
  border-bottom: var(--border-width) solid var(--color-border);
}

[data-ui="accordion"] > [data-part="item"]:last-child {
  border-bottom: none;
}

/* ── Trigger ── */
[data-ui="accordion"] > :where([data-part="item"]) > [data-part="trigger"],
[data-ui="accordion"] > :where([data-part="item"]) > :where(h1, h2, h3, h4, h5, h6) > [data-part="trigger"] {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: var(--space-4);
  border: none;
  background: transparent;
  color: var(--color-fg);
  font-family: var(--font-ui);
  font-size: var(--text-base);
  font-weight: var(--weight-medium);
  text-align: start;
  cursor: pointer;
  transition: color var(--duration-normal) var(--ease-default);
}

[data-ui="accordion"] > :where([data-part="item"]) > [data-part="trigger"]:hover,
[data-ui="accordion"] > :where([data-part="item"]) > :where(h1, h2, h3, h4, h5, h6) > [data-part="trigger"]:hover {
  color: var(--color-fg);
  background: var(--color-bg-muted, oklch(0.96 0.004 260));
}

[data-ui="accordion"] > :where([data-part="item"]) > [data-part="trigger"]:focus-visible,
[data-ui="accordion"] > :where([data-part="item"]) > :where(h1, h2, h3, h4, h5, h6) > [data-part="trigger"]:focus-visible {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  outline-offset: calc(-1 * var(--focus-ring-offset));
  border-radius: var(--radius-sm, 0.25rem);
}

/* ── Icon (chevron) ── */
[data-ui="accordion"] > :where([data-part="item"]) > :where([data-part="trigger"]) > [data-part="icon"],
[data-ui="accordion"] > :where([data-part="item"]) > :where(h1, h2, h3, h4, h5, h6) > :where([data-part="trigger"]) > [data-part="icon"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  color: var(--color-fg-muted);
  font-size: var(--text-sm);
  transition: transform var(--duration-normal) var(--ease-default);
  transform: rotate(0deg);
}

[data-ui="accordion"] > [data-part="item"][data-state="expanded"] > :where([data-part="trigger"]) > [data-part="icon"],
[data-ui="accordion"] > [data-part="item"][data-state="expanded"] > :where(h1, h2, h3, h4, h5, h6) > :where([data-part="trigger"]) > [data-part="icon"] {
  transform: rotate(180deg);
}

/* ── Content ── */
[data-ui="accordion"] > :where([data-part="item"]) > [data-part="content"] {
  overflow: hidden;
  padding: 0 var(--space-4) var(--space-4);
  color: var(--color-fg-muted);
  font-size: var(--text-sm);
}

/* ── Bordered Variant ── */
[data-ui="accordion"][data-bordered="true"] {
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-lg);
  overflow: hidden;
}

[data-ui="accordion"][data-bordered="true"] > [data-part="item"] {
  border-bottom: var(--border-width) solid var(--color-border);
}

[data-ui="accordion"][data-bordered="true"] > [data-part="item"]:last-child {
  border-bottom: none;
}

/* ── Motion ── */
@media (prefers-reduced-motion: reduce) {
  [data-ui="accordion"] > :where([data-part="item"]) > :where([data-part="trigger"]) > [data-part="icon"],
  [data-ui="accordion"] > :where([data-part="item"]) > :where(h1, h2, h3, h4, h5, h6) > :where([data-part="trigger"]) > [data-part="icon"],
  [data-ui="accordion"] > :where([data-part="item"]) > [data-part="trigger"],
  [data-ui="accordion"] > :where([data-part="item"]) > :where(h1, h2, h3, h4, h5, h6) > [data-part="trigger"] {
    transition: none;
  }
}


/* === recipes/alert-dialog.css === */
/* @ui:component alert-dialog */
/* @ui:tokens radius-xl shadow-xl space-2 space-3 space-6 color-bg color-fg color-border color-fg-muted color-destructive duration-normal ease-default ease-out z-overlay z-modal font-heading border-width text-lg text-sm weight-semibold */

/* ── Root ── */
[data-ui="alert-dialog"] {
  position: relative;
}

/* ── Overlay (backdrop only — an alertdialog never dismisses on overlay click) ── */
[data-ui="alert-dialog"] > [data-part="overlay"] {
  position: fixed;
  inset: 0;
  z-index: var(--z-overlay);
  background: var(--alert-dialog-overlay-bg, oklch(0 0 0 / 0.5));
  opacity: 0;
  transition: opacity var(--duration-normal) var(--ease-default);
}

[data-ui="alert-dialog"][data-state="open"] > [data-part="overlay"] {
  opacity: 1;
}

[data-ui="alert-dialog"][data-state="closing"] > [data-part="overlay"] {
  opacity: 0;
}

/* ── Panel ── */
[data-ui="alert-dialog"] > [data-part="panel"] {
  position: fixed;
  z-index: var(--z-modal);
  top: 50%;
  inset-inline-start: 50%;
  transform: translate(-50%, -50%) scale(0.95);
  width: 90%;
  max-height: 85vh;
  overflow-y: auto;
  background: var(--color-bg);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--alert-dialog-radius, var(--radius-xl));
  box-shadow: var(--alert-dialog-shadow, var(--shadow-xl));
  opacity: 0;
  transition: opacity var(--duration-normal) var(--ease-out),
              transform var(--duration-normal) var(--ease-out);
}

[data-ui="alert-dialog"][data-state="open"] > [data-part="panel"] {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1);
}

[data-ui="alert-dialog"][data-state="closing"] > [data-part="panel"] {
  opacity: 0;
  transform: translate(-50%, -50%) scale(0.95);
}

/* ── Size Variants (alerts stay compact) ── */
[data-ui="alert-dialog"] > [data-part="panel"][data-size="sm"] {
  max-width: 400px;
}

[data-ui="alert-dialog"] > [data-part="panel"][data-size="md"] {
  max-width: 520px;
}

/* ── Tone Variant ── */
[data-ui="alert-dialog"] > [data-part="panel"][data-variant="destructive"] {
  border-color: var(--color-destructive, oklch(0.55 0.22 25));
}

/* The destructive tone is carried by the panel's border and its confirm button —
   NOT by the title, which at --text-lg on --color-bg is 4.22:1 in dark, below AA.
   `dialog`'s danger variant already signalled tone this way; the two recipes now
   agree, and both stay readable (task 0.9-05, found by rendering the panel). */

/* ── Header ──
   Every part is reached from the root by child combinators, so a component in
   the body keeps its own header, title and description (1.1F-21); the hops are
   in :where(), so every rule keeps the weight it had. Beyond direct children:
   the header, body and footer may sit in a <form> that is the panel's child (a
   form dialog), and a title or description may sit in one plain div, stack or
   cluster inside its section. */
[data-ui="alert-dialog"] > :where([data-part="panel"]) > [data-part="header"],
[data-ui="alert-dialog"] > :where([data-part="panel"]) > :where(form) > [data-part="header"] {
  padding: var(--space-6);
  padding-bottom: 0;
}

/* ── Title ── */
[data-ui="alert-dialog"] > :where([data-part="panel"]) > :where([data-part="header"]) > [data-part="title"],
[data-ui="alert-dialog"] > :where([data-part="panel"]) > :where([data-part="header"]) > :where(div:not([data-ui]), [data-ui="stack"], [data-ui="cluster"]) > [data-part="title"],
[data-ui="alert-dialog"] > :where([data-part="panel"]) > :where(form) > :where([data-part="header"]) > [data-part="title"],
[data-ui="alert-dialog"] > :where([data-part="panel"]) > :where(form) > :where([data-part="header"]) > :where(div:not([data-ui]), [data-ui="stack"], [data-ui="cluster"]) > [data-part="title"] {
  margin: 0;
  font-family: var(--font-heading);
  font-size: var(--text-lg, 1.125rem);
  font-weight: var(--weight-semibold, 600);
  color: var(--color-fg);
}

/* ── Description / Body ── */
[data-ui="alert-dialog"] > :where([data-part="panel"]) > [data-part="body"],
[data-ui="alert-dialog"] > :where([data-part="panel"]) > :where(form) > [data-part="body"] {
  padding: var(--space-6);
  padding-top: var(--space-2);
  color: var(--color-fg);
}

[data-ui="alert-dialog"] > :where([data-part="panel"]) > :where([data-part="header"], [data-part="body"]) > [data-part="description"],
[data-ui="alert-dialog"] > :where([data-part="panel"]) > :where([data-part="header"], [data-part="body"]) > :where(div:not([data-ui]), [data-ui="stack"], [data-ui="cluster"]) > [data-part="description"],
[data-ui="alert-dialog"] > :where([data-part="panel"]) > :where(form) > :where([data-part="header"], [data-part="body"]) > [data-part="description"],
[data-ui="alert-dialog"] > :where([data-part="panel"]) > :where(form) > :where([data-part="header"], [data-part="body"]) > :where(div:not([data-ui]), [data-ui="stack"], [data-ui="cluster"]) > [data-part="description"] {
  margin: 0;
  color: var(--color-fg-muted);
  font-size: var(--text-sm, 0.875rem);
  line-height: 1.5;
}

/* ── Footer (actions — least-destructive first in the reading order) ── */
[data-ui="alert-dialog"] > :where([data-part="panel"]) > [data-part="footer"],
[data-ui="alert-dialog"] > :where([data-part="panel"]) > :where(form) > [data-part="footer"] {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-3, 0.75rem);
  padding: var(--space-6);
  padding-top: 0;
}

/* ── Motion ── */
@media (prefers-reduced-motion: reduce) {
  [data-ui="alert-dialog"] > [data-part="overlay"],
  [data-ui="alert-dialog"] > [data-part="panel"] {
    transition: none;
  }
}


/* === recipes/barcode.css === */
/* @ui:component barcode */
/* @ui:tokens color-fg-muted color-bg doc-font doc-legal-color doc-legal-size font-mono font-body leading-normal space-2 space-12 space-16 space-20 mono-ligatures */

[data-ui="barcode"] {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  max-inline-size: 100%;
  gap: var(--space-2);
  --barcode-height: var(--space-16);
}

[data-ui="barcode"][data-size="sm"] {
  --barcode-height: var(--space-12);
}

[data-ui="barcode"][data-size="lg"] {
  --barcode-height: var(--space-20);
}

/* The controller draws the bars flush: the viewBox is the symbol, one unit per
   module and 50 units tall, so a module is --barcode-height / 50 wide. The
   quiet zone Code 128 needs (ten modules each side) is inline padding,
   --barcode-quiet modules wide, painted in the background colour. A layout
   that aligns the first bar with a caption or a column edge sets
   --barcode-quiet: 0 where the page already leaves the space, or pulls the
   box out by the padding. */
[data-ui="barcode"] > [data-part="svg"] {
  display: block;
  box-sizing: border-box;
  inline-size: auto;
  max-inline-size: 100%;
  block-size: var(--barcode-height);
  padding-inline: calc(var(--barcode-height) * var(--barcode-quiet, 10) / 50);
  background-color: var(--color-bg);
}

[data-ui="barcode"] > [data-part="caption"] {
  color: var(--doc-legal-color, var(--color-fg-muted));
  font-family: var(--font-mono, var(--doc-font, var(--font-body)));
  font-variant-ligatures: var(--mono-ligatures);
  font-size: var(--doc-legal-size);
  line-height: var(--leading-normal);
  text-align: center;
}

@media print {
  [data-ui="barcode"] {
    break-inside: avoid;
  }

  [data-ui="barcode"] > [data-part="svg"] {
    color-adjust: exact;
    print-color-adjust: exact;
    -webkit-print-color-adjust: exact;
  }
}


/* === recipes/calendar.css === */
/* @ui:component calendar */
/* @ui:tokens color-bg color-fg color-fg-muted color-fg-subtle color-border color-primary color-primary-fg color-primary-subtle color-ring color-bg-muted radius-md radius-full space-0 space-1 space-2 text-xs text-sm text-base weight-medium duration-fast ease-default font-ui border-width focus-ring-width focus-ring-style focus-ring-color focus-ring-offset disabled-opacity */

/* Nesting (1.1F-23): every part is reached by child combinators from the root,
   the hops in :where() so no rule changes weight. Kept beyond the template: the
   header is optional, so the month label and nav buttons are styled as its
   children or the root's. Days are the cells the controller renders:
   root > grid > tbody > tr > td > day. */

/* ── Root ── */
[data-ui="calendar"] {
  display: inline-block;
}

/* ── Header ── */
[data-ui="calendar"] > [data-part="header"] {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-block-end: var(--space-2, 0.5rem);
  padding: 0 var(--space-1);
}

/* ── Month Label ── */
[data-ui="calendar"] > :where([data-part="header"]) > [data-part="month-label"],
[data-ui="calendar"] > [data-part="month-label"] {
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--color-fg);
  user-select: none;
}

/* ── Nav Buttons ── */
[data-ui="calendar"] > :where([data-part="header"]) > [data-part="nav-prev"],
[data-ui="calendar"] > [data-part="nav-prev"],
[data-ui="calendar"] > :where([data-part="header"]) > [data-part="nav-next"],
[data-ui="calendar"] > [data-part="nav-next"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  padding: 0;
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-bg);
  color: var(--color-fg);
  font-size: var(--text-sm);
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease-default);
}

[data-ui="calendar"] > :where([data-part="header"]) > [data-part="nav-prev"]:hover,
[data-ui="calendar"] > [data-part="nav-prev"]:hover,
[data-ui="calendar"] > :where([data-part="header"]) > [data-part="nav-next"]:hover,
[data-ui="calendar"] > [data-part="nav-next"]:hover {
  background: var(--color-bg-muted, oklch(0.96 0.004 260));
}

[data-ui="calendar"] > :where([data-part="header"]) > [data-part="nav-prev"]:focus-visible,
[data-ui="calendar"] > [data-part="nav-prev"]:focus-visible,
[data-ui="calendar"] > :where([data-part="header"]) > [data-part="nav-next"]:focus-visible,
[data-ui="calendar"] > [data-part="nav-next"]:focus-visible {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  outline-offset: var(--focus-ring-offset);
}

[data-ui="calendar"] > :where([data-part="header"]) > [data-part="nav-prev"]:disabled,
[data-ui="calendar"] > [data-part="nav-prev"]:disabled,
[data-ui="calendar"] > :where([data-part="header"]) > [data-part="nav-next"]:disabled,
[data-ui="calendar"] > [data-part="nav-next"]:disabled {
  /* Dimmer than a disabled control — 0.4 at the 0.5 default — and it follows a
     theme's `--disabled-opacity` like every other disabled dim (1.1A-27). */
  opacity: calc(var(--disabled-opacity) * 0.8);
  cursor: not-allowed;
}

/* ── Grid (Table) ── */
[data-ui="calendar"] > [data-part="grid"] {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
}

[data-ui="calendar"] > [data-part="grid"] thead th {
  width: 36px;
  height: 28px;
  font-size: var(--text-xs, 0.75rem);
  font-weight: var(--weight-medium);
  color: var(--color-fg-muted);
  text-align: center;
  user-select: none;
}

/* ── Grid cell ── */
[data-ui="calendar"] > [data-part="grid"] td {
  text-align: center;
  padding: var(--space-0, 1px);
}

/* ── Day Button ── */
[data-ui="calendar"] > :where([data-part="grid"]) > :where(tbody) > :where(tr) > :where(td) > [data-part="day"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  padding: 0;
  border: var(--border-width) solid transparent;
  border-radius: var(--radius-full);
  background: transparent;
  color: var(--color-fg);
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  cursor: pointer;
  transition: background var(--duration-fast) var(--ease-default),
              color var(--duration-fast) var(--ease-default),
              border-color var(--duration-fast) var(--ease-default);
}

[data-ui="calendar"] > :where([data-part="grid"]) > :where(tbody) > :where(tr) > :where(td) > [data-part="day"]:hover {
  background: var(--color-bg-muted, oklch(0.96 0.004 260));
}

[data-ui="calendar"] > :where([data-part="grid"]) > :where(tbody) > :where(tr) > :where(td) > [data-part="day"]:focus-visible {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  outline-offset: var(--focus-ring-offset);
}

/* ── Today ── */
[data-ui="calendar"] > :where([data-part="grid"]) > :where(tbody) > :where(tr) > :where(td) > [data-part="day"][data-today="true"] {
  border-color: var(--color-primary);
  font-weight: var(--weight-medium);
}

/* ── Selected ── */
[data-ui="calendar"] > :where([data-part="grid"]) > :where(tbody) > :where(tr) > :where(td) > [data-part="day"][aria-selected="true"] {
  background: var(--color-primary);
  color: var(--color-primary-fg);
  border-color: var(--color-primary);
}

[data-ui="calendar"] > :where([data-part="grid"]) > :where(tbody) > :where(tr) > :where(td) > [data-part="day"][aria-selected="true"]:hover {
  background: var(--color-primary);
  color: var(--color-primary-fg);
}

/* ── Range selection ── */
[data-ui="calendar"] > :where([data-part="grid"]) > :where(tbody) > :where(tr) > :where(td) > [data-part="day"][data-state="in-range"] {
  background: var(--color-primary-subtle, oklch(0.93 0.03 264));
  border-radius: var(--radius-md);
}

/* ── Other month days ── */
[data-ui="calendar"] > :where([data-part="grid"]) > :where(tbody) > :where(tr) > :where(td) > [data-part="day"][data-outside="true"] {
  color: var(--color-fg-subtle, oklch(0.7 0 0));
}

/* ── Disabled days (aria-disabled keeps them focusable; :disabled for hard-disabled) ── */
[data-ui="calendar"] > :where([data-part="grid"]) > :where(tbody) > :where(tr) > :where(td) > [data-part="day"][aria-disabled="true"],
[data-ui="calendar"] > :where([data-part="grid"]) > :where(tbody) > :where(tr) > :where(td) > [data-part="day"]:disabled {
  opacity: var(--disabled-opacity);
  cursor: not-allowed;
  text-decoration: line-through;
}

/* ── Size: Small ── */
[data-ui="calendar"][data-size="sm"] > :where([data-part="grid"]) > :where(tbody) > :where(tr) > :where(td) > [data-part="day"] {
  width: 28px;
  height: 28px;
  font-size: var(--text-xs, 0.75rem);
}

[data-ui="calendar"][data-size="sm"] > [data-part="grid"] thead th {
  width: 28px;
  height: 24px;
  font-size: 0.625rem;
}

[data-ui="calendar"][data-size="sm"] > :where([data-part="header"]) > [data-part="nav-prev"],
[data-ui="calendar"][data-size="sm"] > [data-part="nav-prev"],
[data-ui="calendar"][data-size="sm"] > :where([data-part="header"]) > [data-part="nav-next"],
[data-ui="calendar"][data-size="sm"] > [data-part="nav-next"] {
  width: 24px;
  height: 24px;
  font-size: var(--text-xs, 0.75rem);
}

[data-ui="calendar"][data-size="sm"] > :where([data-part="header"]) > [data-part="month-label"],
[data-ui="calendar"][data-size="sm"] > [data-part="month-label"] {
  font-size: var(--text-xs, 0.75rem);
}

/* ── Size: Large ── */
[data-ui="calendar"][data-size="lg"] > :where([data-part="grid"]) > :where(tbody) > :where(tr) > :where(td) > [data-part="day"] {
  width: 44px;
  height: 44px;
  font-size: var(--text-base, 1rem);
}

[data-ui="calendar"][data-size="lg"] > [data-part="grid"] thead th {
  width: 44px;
  height: 32px;
  font-size: var(--text-sm);
}

[data-ui="calendar"][data-size="lg"] > :where([data-part="header"]) > [data-part="nav-prev"],
[data-ui="calendar"][data-size="lg"] > [data-part="nav-prev"],
[data-ui="calendar"][data-size="lg"] > :where([data-part="header"]) > [data-part="nav-next"],
[data-ui="calendar"][data-size="lg"] > [data-part="nav-next"] {
  width: 36px;
  height: 36px;
  font-size: var(--text-base, 1rem);
}

[data-ui="calendar"][data-size="lg"] > :where([data-part="header"]) > [data-part="month-label"],
[data-ui="calendar"][data-size="lg"] > [data-part="month-label"] {
  font-size: var(--text-base, 1rem);
}

/* ── Motion ── */
@media (prefers-reduced-motion: reduce) {
  [data-ui="calendar"] > :where([data-part="grid"]) > :where(tbody) > :where(tr) > :where(td) > [data-part="day"],
  [data-ui="calendar"] > :where([data-part="header"]) > [data-part="nav-prev"],
  [data-ui="calendar"] > [data-part="nav-prev"],
  [data-ui="calendar"] > :where([data-part="header"]) > [data-part="nav-next"],
  [data-ui="calendar"] > [data-part="nav-next"] {
    transition: none;
  }
}


/* === recipes/combobox.css === */
/* @ui:component combobox */
/* @ui:tokens color-bg color-fg color-fg-muted color-border color-primary-subtle radius-md radius-lg shadow-md space-1 space-2 space-3 text-sm text-base text-xs z-dropdown duration-fast ease-default font-ui border-width focus-ring-color focus-ring-width */

/* ── Root ── */
[data-ui="combobox"] {
  position: relative;
  display: inline-block;
  width: 100%;
}

/* ── Input ── */
[data-ui="combobox"] > [data-part="input"] {
  display: block;
  width: 100%;
  padding: var(--space-2) var(--space-3);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-bg);
  color: var(--color-fg);
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  line-height: 1.5;
  outline: none;
  transition: border-color var(--duration-fast) var(--ease-default),
              box-shadow var(--duration-fast) var(--ease-default);
}

[data-ui="combobox"] > [data-part="input"]::placeholder {
  color: var(--color-fg-muted);
}

[data-ui="combobox"] > [data-part="input"]:focus {
  border-color: var(--focus-ring-color);
  box-shadow: 0 0 0 var(--focus-ring-width) var(--focus-ring-color);
}

/* ── Listbox ── */
[data-ui="combobox"] > [data-part="listbox"] {
  position: absolute;
  top: 100%;
  inset-inline-start: 0;
  inset-inline-end: 0;
  z-index: var(--z-dropdown);
  margin-top: var(--space-1);
  padding: var(--space-1);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-bg);
  box-shadow: var(--shadow-md);
  max-height: 240px;
  overflow-y: auto;
  list-style: none;
  opacity: 0;
  transform: translateY(-4px);
  transition: opacity var(--duration-fast) var(--ease-default),
              transform var(--duration-fast) var(--ease-default);
}

[data-ui="combobox"][data-state="open"] > [data-part="listbox"],
[data-ui="combobox"][data-state="loading"] > [data-part="listbox"] {
  opacity: 1;
  transform: translateY(0);
}

/* ── Option ── */
[data-ui="combobox"] > :where([data-part="listbox"]) > [data-part="option"] {
  display: flex;
  align-items: center;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-md);
  color: var(--color-fg);
  font-size: var(--text-sm);
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--duration-fast) var(--ease-default);
}

[data-ui="combobox"] > :where([data-part="listbox"]) > [data-part="option"]:hover {
  background: var(--color-primary-subtle, oklch(0.96 0.04 264));
}

[data-ui="combobox"] > :where([data-part="listbox"]) > [data-part="option"][aria-selected="true"],
[data-ui="combobox"] > :where([data-part="listbox"]) > [data-part="option"][data-highlighted] {
  background: var(--color-primary-subtle, oklch(0.96 0.04 264));
}

[data-ui="combobox"] > :where([data-part="listbox"]) > [data-part="option"][data-hidden] {
  display: none;
}

/* ── Empty State ── */
[data-ui="combobox"] > :where([data-part="listbox"]) > [data-part="empty"] {
  padding: var(--space-2) var(--space-3);
  color: var(--color-fg-muted);
  font-size: var(--text-sm);
  text-align: center;
}

/* ── Size Variants ── */
[data-ui="combobox"][data-size="sm"] > [data-part="input"] {
  padding: var(--space-1) var(--space-2);
  font-size: var(--text-xs, 0.75rem);
}

[data-ui="combobox"][data-size="sm"] > :where([data-part="listbox"]) > [data-part="option"] {
  padding: var(--space-1) var(--space-2);
  font-size: var(--text-xs, 0.75rem);
}

[data-ui="combobox"][data-size="lg"] > [data-part="input"] {
  padding: var(--space-3) var(--space-3);
  font-size: var(--text-base);
}

[data-ui="combobox"][data-size="lg"] > :where([data-part="listbox"]) > [data-part="option"] {
  padding: var(--space-3) var(--space-3);
  font-size: var(--text-base);
}

/* ── Motion ── */
@media (prefers-reduced-motion: reduce) {
  [data-ui="combobox"] > [data-part="input"],
  [data-ui="combobox"] > [data-part="listbox"],
  [data-ui="combobox"] > :where([data-part="listbox"]) > [data-part="option"] {
    transition: none;
  }
}


/* === recipes/command-palette.css === */
/* @ui:component command-palette */
/* @ui:tokens color-bg color-fg color-fg-muted color-border color-primary-subtle color-bg-muted shadow-xl radius-xl radius-md radius-sm space-2 space-3 space-4 space-1 text-sm text-xs text-base weight-medium font-mono font-ui z-overlay z-modal duration-fast duration-normal ease-out border-width mono-ligatures */

/* Nesting (1.1F-23): every part is reached by child combinators from the root,
   the hops in :where() so no rule changes weight. Kept beyond the template:
   the search may sit in the panel without its wrapper, an item in the list
   without a group, and the empty state in the panel as well as the list. */

/* ── Root ── */
[data-ui="command-palette"] {
  position: relative;
}

/* ── Overlay ── */
[data-ui="command-palette"] > [data-part="overlay"] {
  position: fixed;
  inset: 0;
  z-index: var(--z-overlay);
  background: var(--command-palette-overlay-bg, oklch(0 0 0 / 0.5));
  opacity: 0;
  transition: opacity var(--duration-normal) var(--ease-out);
}

[data-ui="command-palette"][data-state="open"] > [data-part="overlay"] {
  opacity: 1;
}

/* ── Panel ── */
[data-ui="command-palette"] > [data-part="panel"] {
  position: fixed;
  z-index: var(--z-modal);
  top: 20%;
  inset-inline-start: 50%;
  transform: translateX(-50%) scale(0.95);
  width: 90%;
  max-height: 400px;
  display: flex;
  flex-direction: column;
  background: var(--color-bg);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-xl);
  overflow: hidden;
  opacity: 0;
  transition: opacity var(--duration-fast) var(--ease-out),
              transform var(--duration-fast) var(--ease-out);
}

[data-ui="command-palette"][data-state="open"] > [data-part="panel"] {
  opacity: 1;
  transform: translateX(-50%) scale(1);
}

/* ── Panel Size Variants ── */
[data-ui="command-palette"] > [data-part="panel"][data-size="sm"] {
  max-width: 480px;
}

[data-ui="command-palette"] > [data-part="panel"][data-size="md"] {
  max-width: 560px;
}

[data-ui="command-palette"] > [data-part="panel"][data-size="lg"] {
  max-width: 640px;
}

/* ── Search Wrapper ── */
[data-ui="command-palette"] > :where([data-part="panel"]) > [data-part="search-wrapper"] {
  display: flex;
  align-items: center;
  padding: var(--space-3) var(--space-4);
  border-bottom: var(--border-width) solid var(--color-border);
}

/* ── Search Input ── */
[data-ui="command-palette"] > :where([data-part="panel"]) > :where([data-part="search-wrapper"]) > [data-part="search"],
[data-ui="command-palette"] > :where([data-part="panel"]) > [data-part="search"] {
  width: 100%;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--color-fg);
  font-family: var(--font-ui);
  font-size: var(--text-base);
  outline: none;
}

[data-ui="command-palette"] > :where([data-part="panel"]) > :where([data-part="search-wrapper"]) > [data-part="search"]::placeholder,
[data-ui="command-palette"] > :where([data-part="panel"]) > [data-part="search"]::placeholder {
  color: var(--color-fg-muted);
}

/* ── List ── */
[data-ui="command-palette"] > :where([data-part="panel"]) > [data-part="list"] {
  flex: 1;
  overflow-y: auto;
  padding: var(--space-2);
}

/* ── Group ── */
[data-ui="command-palette"] > :where([data-part="panel"]) > :where([data-part="list"]) > [data-part="group"] {
  margin-bottom: var(--space-2);
}

[data-ui="command-palette"] > :where([data-part="panel"]) > :where([data-part="list"]) > [data-part="group"]:last-child {
  margin-bottom: 0;
}

[data-ui="command-palette"] > :where([data-part="panel"]) > :where([data-part="list"]) > [data-part="group"][data-hidden] {
  display: none;
}

/* ── Group Label ── */
[data-ui="command-palette"] > :where([data-part="panel"]) > :where([data-part="list"]) > :where([data-part="group"]) > [data-part="group-label"] {
  padding: var(--space-2) var(--space-3);
  /* --color-fg-subtle is 4.24:1 on the panel in light and 3.47:1 in dark —
     both below AA. Nothing caught it because the panel was never rendered
     (task 0.9-05); --color-fg-muted is what every other secondary label in
     the registry uses. */
  color: var(--color-fg-muted);
  font-size: var(--text-xs);
  font-weight: var(--weight-medium);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

/* ── Item ── */
[data-ui="command-palette"] > :where([data-part="panel"]) > :where([data-part="list"]) > :where([data-part="group"]) > [data-part="item"],
[data-ui="command-palette"] > :where([data-part="panel"]) > :where([data-part="list"]) > [data-part="item"] {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-md, 0.375rem);
  color: var(--color-fg);
  font-size: var(--text-sm);
  /* An item may be an <a href>: it reads as a command, not as a link. */
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--duration-fast) var(--ease-out);
}

[data-ui="command-palette"] > :where([data-part="panel"]) > :where([data-part="list"]) > :where([data-part="group"]) > [data-part="item"]:hover,
[data-ui="command-palette"] > :where([data-part="panel"]) > :where([data-part="list"]) > [data-part="item"]:hover {
  background: var(--color-bg-muted, oklch(0.96 0.004 260));
}

[data-ui="command-palette"] > :where([data-part="panel"]) > :where([data-part="list"]) > :where([data-part="group"]) > [data-part="item"][aria-selected="true"],
[data-ui="command-palette"] > :where([data-part="panel"]) > :where([data-part="list"]) > [data-part="item"][aria-selected="true"],
[data-ui="command-palette"] > :where([data-part="panel"]) > :where([data-part="list"]) > :where([data-part="group"]) > [data-part="item"][data-highlighted],
[data-ui="command-palette"] > :where([data-part="panel"]) > :where([data-part="list"]) > [data-part="item"][data-highlighted] {
  background: var(--color-primary-subtle, oklch(0.96 0.04 264));
}

[data-ui="command-palette"] > :where([data-part="panel"]) > :where([data-part="list"]) > :where([data-part="group"]) > [data-part="item"][data-hidden],
[data-ui="command-palette"] > :where([data-part="panel"]) > :where([data-part="list"]) > [data-part="item"][data-hidden] {
  display: none;
}

/* ── Item Label ── */
[data-ui="command-palette"] > :where([data-part="panel"]) > :where([data-part="list"]) > :where([data-part="group"]) > :where([data-part="item"]) > [data-part="item-label"],
[data-ui="command-palette"] > :where([data-part="panel"]) > :where([data-part="list"]) > :where([data-part="item"]) > [data-part="item-label"] {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ── Kbd ── */
[data-ui="command-palette"] > :where([data-part="panel"]) > :where([data-part="list"]) > :where([data-part="group"]) > :where([data-part="item"]) > [data-part="kbd"],
[data-ui="command-palette"] > :where([data-part="panel"]) > :where([data-part="list"]) > :where([data-part="item"]) > [data-part="kbd"] {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1, 0.25rem);
  padding: var(--space-1, 0.25rem) var(--space-2);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm, 0.25rem);
  background: var(--color-bg-muted, oklch(0.96 0.004 260));
  color: var(--color-fg-muted);
  font-family: var(--font-mono, ui-monospace, monospace);
  font-variant-ligatures: var(--mono-ligatures, none);
  font-size: var(--text-xs);
  line-height: 1;
  white-space: nowrap;
}

/* ── Empty State ── */
[data-ui="command-palette"] > :where([data-part="panel"]) > :where([data-part="list"]) > [data-part="empty"],
[data-ui="command-palette"] > :where([data-part="panel"]) > [data-part="empty"] {
  padding: var(--space-4);
  color: var(--color-fg-muted);
  font-size: var(--text-sm);
  text-align: center;
}

/* ── Motion ── */
@media (prefers-reduced-motion: reduce) {
  [data-ui="command-palette"] > [data-part="overlay"],
  [data-ui="command-palette"] > [data-part="panel"],
  [data-ui="command-palette"] > :where([data-part="panel"]) > :where([data-part="list"]) > :where([data-part="group"]) > [data-part="item"],
  [data-ui="command-palette"] > :where([data-part="panel"]) > :where([data-part="list"]) > [data-part="item"] {
    transition: none;
  }
}


/* === recipes/date-picker.css === */
/* @ui:component date-picker */
/* @ui:tokens color-bg color-fg color-fg-muted color-border color-primary color-ring shadow-lg radius-md radius-lg space-1 space-2 space-3 space-4 space-8 space-6 space-10 text-xs text-sm text-base z-dropdown duration-fast ease-default font-ui border-width focus-ring-width focus-ring-style focus-ring-color focus-ring-offset */
/* The month grid inside the popup is the `calendar` recipe — see calendar.css */

/* ── Root ── */
[data-ui="date-picker"] {
  position: relative;
  display: inline-block;
}

/* ── Trigger ── */
[data-ui="date-picker"] > [data-part="trigger"] {
  position: relative;
  display: inline-flex;
  align-items: center;
}

/* ── Input ── */
[data-ui="date-picker"] > :where([data-part="trigger"]) > [data-part="input"] {
  width: 100%;
  padding: var(--space-2, 0.5rem) var(--space-3);
  padding-inline-end: var(--space-8, 2.5rem);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-bg);
  color: var(--color-fg);
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  line-height: 1.5;
  cursor: pointer;
  transition: border-color var(--duration-fast) var(--ease-default);
}

[data-ui="date-picker"] > :where([data-part="trigger"]) > [data-part="input"]::placeholder {
  color: var(--color-fg-muted);
}

[data-ui="date-picker"] > :where([data-part="trigger"]) > [data-part="input"]:focus-visible {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  outline-offset: var(--focus-ring-offset);
  border-color: var(--color-primary);
}

/* ── Icon ── */
[data-ui="date-picker"] > :where([data-part="trigger"]) > [data-part="icon"] {
  position: absolute;
  inset-inline-end: var(--space-3);
  top: 50%;
  transform: translateY(-50%);
  pointer-events: none;
  color: var(--color-fg-muted);
  font-size: var(--text-sm);
}

/* ── Calendar popup ── */
[data-ui="date-picker"] > [data-part="calendar"] {
  position: absolute;
  top: 100%;
  inset-inline-start: 0;
  z-index: var(--z-dropdown);
  margin-top: var(--space-1);
  padding: var(--space-3);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-bg);
  box-shadow: var(--shadow-lg);
  opacity: 0;
  transform: translateY(-4px);
  transition: opacity var(--duration-fast) var(--ease-default),
              transform var(--duration-fast) var(--ease-default);
}

[data-ui="date-picker"][data-state="open"] > [data-part="calendar"] {
  opacity: 1;
  transform: translateY(0);
}

/* ── Size: Small ── */
[data-ui="date-picker"][data-size="sm"] > :where([data-part="trigger"]) > [data-part="input"] {
  padding: var(--space-1) var(--space-2);
  padding-inline-end: var(--space-6, 2rem);
  font-size: var(--text-xs, 0.75rem);
}

/* ── Size: Large ── */
[data-ui="date-picker"][data-size="lg"] > :where([data-part="trigger"]) > [data-part="input"] {
  padding: var(--space-3) var(--space-4);
  padding-inline-end: var(--space-10, 3rem);
  font-size: var(--text-base, 1rem);
}

/* ── Motion ── */
@media (prefers-reduced-motion: reduce) {
  [data-ui="date-picker"] > [data-part="calendar"],
  [data-ui="date-picker"] > :where([data-part="trigger"]) > [data-part="input"] {
    transition: none;
  }
}


/* === recipes/dialog.css === */
/* @ui:component dialog */
/* @ui:tokens radius-xl radius-lg radius-md shadow-xl space-6 space-8 space-3 color-bg color-fg color-border color-fg-muted color-destructive color-bg-muted panel-bg duration-normal ease-default ease-out z-overlay z-modal font-heading corner-shape border-width focus-ring-width focus-ring-style focus-ring-color focus-ring-offset surface-backdrop dialog-overlay-bg dialog-radius dialog-shadow text-lg text-base text-sm weight-semibold */

/* ── Root ── */
[data-ui="dialog"] {
  position: relative;
}

/* ── Overlay ── */
[data-ui="dialog"] > [data-part="overlay"] {
  position: fixed;
  inset: 0;
  z-index: var(--z-overlay);
  background: var(--dialog-overlay-bg, oklch(0 0 0 / 0.5));
  opacity: 0;
  transition: opacity var(--duration-normal) var(--ease-default);
}

[data-ui="dialog"][data-state="open"] > [data-part="overlay"] {
  opacity: 1;
}

[data-ui="dialog"][data-state="closing"] > [data-part="overlay"] {
  opacity: 0;
}

/* ── Panel ── */
[data-ui="dialog"] > [data-part="panel"] {
  position: fixed;
  z-index: var(--z-modal);
  top: 50%;
  inset-inline-start: 50%;
  transform: translate(-50%, -50%) scale(0.95);
  width: 90%;
  max-height: 85vh;
  overflow-y: auto;
  background: var(--panel-bg);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--dialog-radius, var(--radius-xl));
  corner-shape: var(--corner-shape);
  box-shadow: var(--dialog-shadow, var(--shadow-xl));
  opacity: 0;
  transition: opacity var(--duration-normal) var(--ease-out),
              transform var(--duration-normal) var(--ease-out);
}

/* The panel is focused on open (tabindex="-1") only so the focus trap and the
   Escape key have somewhere to start. It is not a control, so it draws no ring:
   the global :focus-visible would otherwise outline the whole panel when the
   overlay is opened from the keyboard. */
[data-ui="dialog"] > [data-part="panel"]:focus {
  outline: none;
}

@supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
  [data-ui="dialog"] > [data-part="panel"] {
    -webkit-backdrop-filter: var(--surface-backdrop);
    backdrop-filter: var(--surface-backdrop);
  }
}

[data-ui="dialog"][data-state="open"] > [data-part="panel"] {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1);
}

[data-ui="dialog"][data-state="closing"] > [data-part="panel"] {
  opacity: 0;
  transform: translate(-50%, -50%) scale(0.95);
}

/* ── Size Variants ── */
[data-ui="dialog"] > [data-part="panel"][data-size="sm"] {
  max-width: 400px;
}

[data-ui="dialog"] > [data-part="panel"][data-size="md"] {
  max-width: 520px;
}

[data-ui="dialog"] > [data-part="panel"][data-size="lg"] {
  max-width: 680px;
}

[data-ui="dialog"] > [data-part="panel"][data-size="full"] {
  width: calc(100vw - var(--space-8));
  max-width: none;
  height: calc(100vh - var(--space-8));
  max-height: none;
  border-radius: var(--radius-lg, 0.5rem);
}

/* ── Tone Variants ── */
[data-ui="dialog"] > [data-part="panel"][data-variant="danger"] {
  border-color: var(--color-destructive, oklch(0.55 0.22 25));
}

/* ── Header ──
   Every part is reached from the root by child combinators, so a component in
   the body keeps its own header, title and close (1.1F-21); the hops are in
   :where(), so every rule keeps the weight it had. Beyond direct children: the
   header, body and footer may sit in a <form> that is the panel's child (a form
   dialog), and a title, description or close button may sit in one plain div,
   stack or cluster inside its section. */
[data-ui="dialog"] > :where([data-part="panel"]) > [data-part="header"],
[data-ui="dialog"] > :where([data-part="panel"]) > :where(form) > [data-part="header"] {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-6);
  padding-bottom: 0;
}

/* ── Title ── */
[data-ui="dialog"] > :where([data-part="panel"]) > :where([data-part="header"]) > [data-part="title"],
[data-ui="dialog"] > :where([data-part="panel"]) > :where([data-part="header"]) > :where(div:not([data-ui]), [data-ui="stack"], [data-ui="cluster"]) > [data-part="title"],
[data-ui="dialog"] > :where([data-part="panel"]) > :where(form) > :where([data-part="header"]) > [data-part="title"],
[data-ui="dialog"] > :where([data-part="panel"]) > :where(form) > :where([data-part="header"]) > :where(div:not([data-ui]), [data-ui="stack"], [data-ui="cluster"]) > [data-part="title"] {
  margin: 0;
  font-family: var(--font-heading);
  font-size: var(--text-lg, 1.125rem);
  font-weight: var(--weight-semibold, 600);
  color: var(--color-fg);
}

/* ── Close Button ──
   `:not([data-ui])` is the trigger contract read backwards (task 0.9-05): a part
   that delegates its look to a primitive must not then be restyled by the recipe.
   Without it this icon-close rule also caught the footer's
   `<button data-ui="button" data-part="close">Cancel</button>` and squashed it to
   a 32px borderless square — invisible for as long as the panel was, and the
   first thing the forced-open preview showed. */
[data-ui="dialog"] > :where([data-part="panel"]) > [data-part="close"]:not([data-ui]),
[data-ui="dialog"] > :where([data-part="panel"]) > :where([data-part="header"], [data-part="footer"]) > [data-part="close"]:not([data-ui]),
[data-ui="dialog"] > :where([data-part="panel"]) > :where([data-part="header"], [data-part="footer"]) > :where(div:not([data-ui]), [data-ui="stack"], [data-ui="cluster"]) > [data-part="close"]:not([data-ui]),
[data-ui="dialog"] > :where([data-part="panel"]) > :where(form) > :where([data-part="header"], [data-part="footer"]) > [data-part="close"]:not([data-ui]),
[data-ui="dialog"] > :where([data-part="panel"]) > :where(form) > :where([data-part="header"], [data-part="footer"]) > :where(div:not([data-ui]), [data-ui="stack"], [data-ui="cluster"]) > [data-part="close"]:not([data-ui]) {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: none;
  border-radius: var(--radius-md, 0.375rem);
  background: transparent;
  color: var(--color-fg-muted);
  font-size: var(--text-base, 1rem);
  cursor: pointer;
  flex-shrink: 0;
}

[data-ui="dialog"] > :where([data-part="panel"]) > [data-part="close"]:not([data-ui]):hover,
[data-ui="dialog"] > :where([data-part="panel"]) > :where([data-part="header"], [data-part="footer"]) > [data-part="close"]:not([data-ui]):hover,
[data-ui="dialog"] > :where([data-part="panel"]) > :where([data-part="header"], [data-part="footer"]) > :where(div:not([data-ui]), [data-ui="stack"], [data-ui="cluster"]) > [data-part="close"]:not([data-ui]):hover,
[data-ui="dialog"] > :where([data-part="panel"]) > :where(form) > :where([data-part="header"], [data-part="footer"]) > [data-part="close"]:not([data-ui]):hover,
[data-ui="dialog"] > :where([data-part="panel"]) > :where(form) > :where([data-part="header"], [data-part="footer"]) > :where(div:not([data-ui]), [data-ui="stack"], [data-ui="cluster"]) > [data-part="close"]:not([data-ui]):hover {
  background: var(--color-bg-muted, oklch(0.96 0.004 260));
  color: var(--color-fg);
}

[data-ui="dialog"] > :where([data-part="panel"]) > [data-part="close"]:not([data-ui]):focus-visible,
[data-ui="dialog"] > :where([data-part="panel"]) > :where([data-part="header"], [data-part="footer"]) > [data-part="close"]:not([data-ui]):focus-visible,
[data-ui="dialog"] > :where([data-part="panel"]) > :where([data-part="header"], [data-part="footer"]) > :where(div:not([data-ui]), [data-ui="stack"], [data-ui="cluster"]) > [data-part="close"]:not([data-ui]):focus-visible,
[data-ui="dialog"] > :where([data-part="panel"]) > :where(form) > :where([data-part="header"], [data-part="footer"]) > [data-part="close"]:not([data-ui]):focus-visible,
[data-ui="dialog"] > :where([data-part="panel"]) > :where(form) > :where([data-part="header"], [data-part="footer"]) > :where(div:not([data-ui]), [data-ui="stack"], [data-ui="cluster"]) > [data-part="close"]:not([data-ui]):focus-visible {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  outline-offset: var(--focus-ring-offset);
}

/* ── Description ── */
[data-ui="dialog"] > :where([data-part="panel"]) > :where([data-part="header"], [data-part="body"]) > [data-part="description"],
[data-ui="dialog"] > :where([data-part="panel"]) > :where([data-part="header"], [data-part="body"]) > :where(div:not([data-ui]), [data-ui="stack"], [data-ui="cluster"]) > [data-part="description"],
[data-ui="dialog"] > :where([data-part="panel"]) > :where(form) > :where([data-part="header"], [data-part="body"]) > [data-part="description"],
[data-ui="dialog"] > :where([data-part="panel"]) > :where(form) > :where([data-part="header"], [data-part="body"]) > :where(div:not([data-ui]), [data-ui="stack"], [data-ui="cluster"]) > [data-part="description"] {
  color: var(--color-fg-muted);
  font-size: var(--text-sm, 0.875rem);
  margin: 0;
}

/* ── Body ── */
[data-ui="dialog"] > :where([data-part="panel"]) > [data-part="body"],
[data-ui="dialog"] > :where([data-part="panel"]) > :where(form) > [data-part="body"] {
  padding: var(--space-6);
  color: var(--color-fg);
}

/* ── Footer ── */
[data-ui="dialog"] > :where([data-part="panel"]) > [data-part="footer"],
[data-ui="dialog"] > :where([data-part="panel"]) > :where(form) > [data-part="footer"] {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-3, 0.75rem);
  padding: var(--space-6);
  padding-top: 0;
}

/* ── Motion ── */
@media (prefers-reduced-motion: reduce) {
  [data-ui="dialog"] > [data-part="overlay"],
  [data-ui="dialog"] > [data-part="panel"] {
    transition: none;
  }
}


/* === recipes/drawer.css === */
/* @ui:component drawer */
/* @ui:tokens color-bg color-fg color-border color-fg-muted color-bg-muted panel-bg shadow-xl space-4 space-6 space-3 radius-none radius-md z-overlay z-modal duration-normal duration-slow ease-out ease-default font-heading border-width focus-ring-width focus-ring-style focus-ring-color focus-ring-offset surface-backdrop text-lg text-base weight-semibold */

/* ── Root ── */
[data-ui="drawer"] {
  position: relative;
}

/* ── Overlay ── */
[data-ui="drawer"] > [data-part="overlay"] {
  position: fixed;
  inset: 0;
  z-index: var(--z-overlay);
  background: var(--drawer-overlay-bg, oklch(0 0 0 / 0.5));
  opacity: 0;
  transition: opacity var(--duration-normal) var(--ease-default);
}

[data-ui="drawer"][data-state="open"] > [data-part="overlay"] {
  opacity: 1;
}

[data-ui="drawer"][data-state="closing"] > [data-part="overlay"] {
  opacity: 0;
}

/* ── Panel ── */
[data-ui="drawer"] > [data-part="panel"] {
  position: fixed;
  top: 0;
  bottom: 0;
  z-index: var(--z-modal);
  display: flex;
  flex-direction: column;
  width: var(--drawer-width, 400px);
  max-width: 100vw;
  background: var(--panel-bg);
  border: none;
  box-shadow: var(--drawer-shadow, var(--shadow-xl));
  transition: transform var(--duration-slow) var(--ease-out);
}

/* The panel is focused on open (tabindex="-1") only so the focus trap and the
   Escape key have somewhere to start. It is not a control, so it draws no ring:
   the global :focus-visible would otherwise outline the whole panel when the
   overlay is opened from the keyboard. */
[data-ui="drawer"] > [data-part="panel"]:focus {
  outline: none;
}

@supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
  [data-ui="drawer"] > [data-part="panel"] {
    -webkit-backdrop-filter: var(--surface-backdrop);
    backdrop-filter: var(--surface-backdrop);
  }
}

/* ── Side Variants ── */
[data-ui="drawer"] > [data-part="panel"][data-variant="left"] {
  inset-inline-start: 0;
  inset-inline-end: auto;
  border-inline-end: var(--border-width) solid var(--color-border);
  border-radius: 0 var(--radius-none, 0) var(--radius-none, 0) 0;
  transform: translateX(-100%);
}

[data-ui="drawer"] > [data-part="panel"][data-variant="right"] {
  inset-inline-end: 0;
  inset-inline-start: auto;
  border-inline-start: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-none, 0) 0 0 var(--radius-none, 0);
  transform: translateX(100%);
}

/* ── Open State ── */
[data-ui="drawer"][data-state="open"] > [data-part="panel"][data-variant="left"],
[data-ui="drawer"][data-state="open"] > [data-part="panel"][data-variant="right"] {
  transform: translateX(0);
}

/* ── Closing State ── */
[data-ui="drawer"][data-state="closing"] > [data-part="panel"][data-variant="left"] {
  transform: translateX(-100%);
}

[data-ui="drawer"][data-state="closing"] > [data-part="panel"][data-variant="right"] {
  transform: translateX(100%);
}

/* ── Size Variants ── */
[data-ui="drawer"] > [data-part="panel"][data-size="sm"] {
  --drawer-width: 320px;
  width: var(--drawer-width);
}

[data-ui="drawer"] > [data-part="panel"][data-size="md"] {
  --drawer-width: 400px;
  width: var(--drawer-width);
}

[data-ui="drawer"] > [data-part="panel"][data-size="lg"] {
  --drawer-width: 560px;
  width: var(--drawer-width);
}

[data-ui="drawer"] > [data-part="panel"][data-size="full"] {
  --drawer-width: 100vw;
  width: var(--drawer-width);
}

/* ── Header ──
   Every part is reached from the root by child combinators, so a component in
   the body keeps its own header, title and close (1.1F-21); the hops are in
   :where(), so every rule keeps the weight it had. Beyond direct children: the
   header, body and footer may sit in a <form> that is the panel's child (a form
   dialog), and a title or close button may sit in one plain div, stack or
   cluster inside its section. */
[data-ui="drawer"] > :where([data-part="panel"]) > [data-part="header"],
[data-ui="drawer"] > :where([data-part="panel"]) > :where(form) > [data-part="header"] {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-6);
  padding-bottom: 0;
  flex-shrink: 0;
}

/* ── Title ── */
[data-ui="drawer"] > :where([data-part="panel"]) > :where([data-part="header"]) > [data-part="title"],
[data-ui="drawer"] > :where([data-part="panel"]) > :where([data-part="header"]) > :where(div:not([data-ui]), [data-ui="stack"], [data-ui="cluster"]) > [data-part="title"],
[data-ui="drawer"] > :where([data-part="panel"]) > :where(form) > :where([data-part="header"]) > [data-part="title"],
[data-ui="drawer"] > :where([data-part="panel"]) > :where(form) > :where([data-part="header"]) > :where(div:not([data-ui]), [data-ui="stack"], [data-ui="cluster"]) > [data-part="title"] {
  margin: 0;
  font-family: var(--font-heading);
  font-size: var(--text-lg, 1.125rem);
  font-weight: var(--weight-semibold, 600);
  color: var(--color-fg);
}

/* ── Close Button ──
   `:not([data-ui])` is the trigger contract read backwards (task 0.9-05): a part
   that delegates its look to a primitive must not then be restyled by the recipe.
   Without it this icon-close rule also caught the footer's
   `<button data-ui="button" data-part="close">Cancel</button>` and squashed it to
   a 32px borderless square — invisible for as long as the panel was, and the
   first thing the forced-open preview showed. */
[data-ui="drawer"] > :where([data-part="panel"]) > [data-part="close"]:not([data-ui]),
[data-ui="drawer"] > :where([data-part="panel"]) > :where([data-part="header"], [data-part="footer"]) > [data-part="close"]:not([data-ui]),
[data-ui="drawer"] > :where([data-part="panel"]) > :where([data-part="header"], [data-part="footer"]) > :where(div:not([data-ui]), [data-ui="stack"], [data-ui="cluster"]) > [data-part="close"]:not([data-ui]),
[data-ui="drawer"] > :where([data-part="panel"]) > :where(form) > :where([data-part="header"], [data-part="footer"]) > [data-part="close"]:not([data-ui]),
[data-ui="drawer"] > :where([data-part="panel"]) > :where(form) > :where([data-part="header"], [data-part="footer"]) > :where(div:not([data-ui]), [data-ui="stack"], [data-ui="cluster"]) > [data-part="close"]:not([data-ui]) {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: none;
  border-radius: var(--radius-md, 0.375rem);
  background: transparent;
  color: var(--color-fg-muted, oklch(0.55 0 0));
  font-size: var(--text-base, 1rem);
  cursor: pointer;
  flex-shrink: 0;
}

[data-ui="drawer"] > :where([data-part="panel"]) > [data-part="close"]:not([data-ui]):hover,
[data-ui="drawer"] > :where([data-part="panel"]) > :where([data-part="header"], [data-part="footer"]) > [data-part="close"]:not([data-ui]):hover,
[data-ui="drawer"] > :where([data-part="panel"]) > :where([data-part="header"], [data-part="footer"]) > :where(div:not([data-ui]), [data-ui="stack"], [data-ui="cluster"]) > [data-part="close"]:not([data-ui]):hover,
[data-ui="drawer"] > :where([data-part="panel"]) > :where(form) > :where([data-part="header"], [data-part="footer"]) > [data-part="close"]:not([data-ui]):hover,
[data-ui="drawer"] > :where([data-part="panel"]) > :where(form) > :where([data-part="header"], [data-part="footer"]) > :where(div:not([data-ui]), [data-ui="stack"], [data-ui="cluster"]) > [data-part="close"]:not([data-ui]):hover {
  background: var(--color-bg-muted, oklch(0.96 0.004 260));
  color: var(--color-fg);
}

[data-ui="drawer"] > :where([data-part="panel"]) > [data-part="close"]:not([data-ui]):focus-visible,
[data-ui="drawer"] > :where([data-part="panel"]) > :where([data-part="header"], [data-part="footer"]) > [data-part="close"]:not([data-ui]):focus-visible,
[data-ui="drawer"] > :where([data-part="panel"]) > :where([data-part="header"], [data-part="footer"]) > :where(div:not([data-ui]), [data-ui="stack"], [data-ui="cluster"]) > [data-part="close"]:not([data-ui]):focus-visible,
[data-ui="drawer"] > :where([data-part="panel"]) > :where(form) > :where([data-part="header"], [data-part="footer"]) > [data-part="close"]:not([data-ui]):focus-visible,
[data-ui="drawer"] > :where([data-part="panel"]) > :where(form) > :where([data-part="header"], [data-part="footer"]) > :where(div:not([data-ui]), [data-ui="stack"], [data-ui="cluster"]) > [data-part="close"]:not([data-ui]):focus-visible {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  outline-offset: var(--focus-ring-offset);
}

/* ── Body ── */
[data-ui="drawer"] > :where([data-part="panel"]) > [data-part="body"],
[data-ui="drawer"] > :where([data-part="panel"]) > :where(form) > [data-part="body"] {
  flex: 1;
  overflow-y: auto;
  padding: var(--space-6);
  color: var(--color-fg);
}

/* ── Footer ── */
[data-ui="drawer"] > :where([data-part="panel"]) > [data-part="footer"],
[data-ui="drawer"] > :where([data-part="panel"]) > :where(form) > [data-part="footer"] {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-3, 0.75rem);
  padding: var(--space-6);
  padding-top: var(--space-4);
  border-top: var(--border-width) solid var(--color-border);
  flex-shrink: 0;
}

/* ── Motion ── */
@media (prefers-reduced-motion: reduce) {
  [data-ui="drawer"] > [data-part="overlay"],
  [data-ui="drawer"] > [data-part="panel"] {
    transition: none;
  }
}


/* === recipes/dropdown.css === */
/* @ui:component dropdown */
/* @ui:tokens color-bg color-fg color-border color-primary-subtle color-primary color-bg-muted panel-bg space-1 space-2 space-3 space-4 radius-md radius-lg shadow-md text-sm text-xs text-base weight-medium duration-fast ease-default ease-out z-dropdown font-ui border-width focus-ring-width focus-ring-style focus-ring-color focus-ring-offset surface-backdrop disabled-opacity */

/* ── Root ── */
[data-ui="dropdown"] {
  position: relative;
  display: inline-block;
}

/* ── Trigger ── */
[data-ui="dropdown"] > [data-part="trigger"] {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-bg);
  color: var(--color-fg);
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--duration-fast) var(--ease-default),
              border-color var(--duration-fast) var(--ease-default);
}

[data-ui="dropdown"] > [data-part="trigger"]:hover {
  background: var(--color-bg-muted, oklch(0.96 0.004 260));
}

[data-ui="dropdown"] > [data-part="trigger"]:focus-visible {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  outline-offset: var(--focus-ring-offset);
}

/* ── Menu ── */
[data-ui="dropdown"] > [data-part="menu"] {
  position: absolute;
  top: 100%;
  inset-inline-start: 0;
  z-index: var(--z-dropdown);
  min-width: 180px;
  margin-top: var(--space-1);
  padding: var(--space-1);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--panel-bg);
  box-shadow: var(--shadow-md);
  opacity: 0;
  transform: translateY(-4px);
  transition: opacity var(--duration-fast) var(--ease-out),
              transform var(--duration-fast) var(--ease-out);
}

@supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
  [data-ui="dropdown"] > [data-part="menu"] {
    -webkit-backdrop-filter: var(--surface-backdrop);
    backdrop-filter: var(--surface-backdrop);
  }
}

[data-ui="dropdown"][data-state="open"] > [data-part="menu"] {
  opacity: 1;
  transform: translateY(0);
}

/* ── Alignment ── */
[data-ui="dropdown"] > [data-part="menu"][data-variant="end"] {
  inset-inline-start: auto;
  inset-inline-end: 0;
}

/* ── Menu Item ── */
[data-ui="dropdown"] > :where([data-part="menu"]) > [data-part="item"] {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  width: 100%;
  padding: var(--space-2) var(--space-3);
  border: none;
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--color-fg);
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  text-align: start;
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--duration-fast) var(--ease-default);
}

[data-ui="dropdown"] > :where([data-part="menu"]) > [data-part="item"]:hover,
[data-ui="dropdown"] > :where([data-part="menu"]) > [data-part="item"]:focus-visible {
  background: var(--color-primary-subtle, oklch(0.96 0.04 264));
  color: var(--color-primary);
}

/* Keyboard focus is NOT the same signal as hover.
   Both rules used to `outline: none` and paint the same `--color-primary-subtle`
   tint — a ~1.1:1 wash that is identical to what the mouse already does, so a
   keyboard user navigating the menu had no way to tell where they were. The
   tint stays (it is the menu's active-item affordance, shared by both), and
   focus additionally draws the ring, inset so it does not overlap the item
   above. [W3-3] */
[data-ui="dropdown"] > :where([data-part="menu"]) > [data-part="item"]:focus-visible {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  outline-offset: calc(-1 * var(--focus-ring-offset));
}

[data-ui="dropdown"] > :where([data-part="menu"]) > [data-part="item"]:disabled {
  opacity: var(--disabled-opacity);
  cursor: not-allowed;
  pointer-events: none;
}

/* ── Separator ── */
[data-ui="dropdown"] > :where([data-part="menu"]) > [data-part="separator"] {
  height: 1px;
  margin: var(--space-1) 0;
  border: none;
  background: var(--color-border);
}

/* ── Size Variants ── */
[data-ui="dropdown"][data-size="sm"] > [data-part="trigger"] {
  padding: var(--space-1) var(--space-2);
  font-size: var(--text-xs, 0.75rem);
}

[data-ui="dropdown"][data-size="sm"] > :where([data-part="menu"]) > [data-part="item"] {
  padding: var(--space-1) var(--space-2);
  font-size: var(--text-xs, 0.75rem);
}

[data-ui="dropdown"][data-size="sm"] > [data-part="menu"] {
  min-width: 140px;
}

[data-ui="dropdown"][data-size="lg"] > [data-part="trigger"] {
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-base, 1rem);
}

[data-ui="dropdown"][data-size="lg"] > :where([data-part="menu"]) > [data-part="item"] {
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-base, 1rem);
}

[data-ui="dropdown"][data-size="lg"] > [data-part="menu"] {
  min-width: 220px;
}

/* ── Motion ── */
@media (prefers-reduced-motion: reduce) {
  [data-ui="dropdown"] > [data-part="menu"],
  [data-ui="dropdown"] > [data-part="trigger"],
  [data-ui="dropdown"] > :where([data-part="menu"]) > [data-part="item"] {
    transition: none;
  }
}


/* === recipes/pagination.css === */
/* @ui:component pagination */
/* @ui:tokens color-bg color-bg-muted color-fg color-fg-muted color-primary color-primary-fg color-border radius-md space-1 space-2 space-3 space-4 text-xs text-sm text-base weight-medium duration-fast ease-default font-ui border-width focus-ring-width focus-ring-style focus-ring-color focus-ring-offset disabled-opacity */

/* ── Root ── */
[data-ui="pagination"] {
  display: inline-flex;
  /* An `inline-flex` box is sized by its content, so without a ceiling the
     numbered nav sets the width and pushes the whole component past a phone
     window. The ceiling is what lets the wrap below actually happen. */
  max-inline-size: 100%;
}

/* ── Nav ──
   Wraps rather than scrolls: the page numbers are the navigation, so a row that
   runs off the window is a row whose last pages cannot be reached. Wrapping
   keeps every target on screen at any width, with no breakpoint involved. */
[data-ui="pagination"] > [data-part="nav"] {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-1);
  /* A flex item's automatic minimum size is its min-content width; the nav must
     be allowed below that of the un-wrapped row for the ceiling above to bind. */
  min-inline-size: 0;
}

/* ── Shared button styles ── */
[data-ui="pagination"] > :where([data-part="nav"]) > [data-part="page"],
[data-ui="pagination"] > :where([data-part="nav"]) > [data-part="prev"],
[data-ui="pagination"] > :where([data-part="nav"]) > [data-part="next"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 36px;
  height: 36px;
  padding: 0 var(--space-2);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-bg);
  color: var(--color-fg);
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--duration-fast) var(--ease-default),
              color var(--duration-fast) var(--ease-default),
              border-color var(--duration-fast) var(--ease-default);
}

/* ── Hover ── */
[data-ui="pagination"] > :where([data-part="nav"]) > [data-part="page"]:hover,
[data-ui="pagination"] > :where([data-part="nav"]) > [data-part="prev"]:hover,
[data-ui="pagination"] > :where([data-part="nav"]) > [data-part="next"]:hover {
  background: var(--color-bg-muted, oklch(0.96 0.004 260));
}

/* ── Focus ── */
[data-ui="pagination"] > :where([data-part="nav"]) > [data-part="page"]:focus-visible,
[data-ui="pagination"] > :where([data-part="nav"]) > [data-part="prev"]:focus-visible,
[data-ui="pagination"] > :where([data-part="nav"]) > [data-part="next"]:focus-visible {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  outline-offset: var(--focus-ring-offset);
}

/* ── Active page ── */
[data-ui="pagination"] > :where([data-part="nav"]) > [data-part="page"][data-state="active"] {
  background: var(--color-primary);
  color: var(--color-primary-fg);
  border-color: var(--color-primary);
}

[data-ui="pagination"] > :where([data-part="nav"]) > [data-part="page"][data-state="active"]:hover {
  background: var(--color-primary);
  color: var(--color-primary-fg);
}

/* ── Prev / Next text ── */
[data-ui="pagination"] > :where([data-part="nav"]) > [data-part="prev"],
[data-ui="pagination"] > :where([data-part="nav"]) > [data-part="next"] {
  padding: 0 var(--space-3);
}

/* ── Disabled ── */
[data-ui="pagination"] > :where([data-part="nav"]) > [data-part="prev"]:disabled,
[data-ui="pagination"] > :where([data-part="nav"]) > [data-part="next"]:disabled {
  opacity: var(--disabled-opacity);
  cursor: not-allowed;
  pointer-events: none;
}

/* ── Ellipsis ── */
[data-ui="pagination"] > :where([data-part="nav"]) > [data-part="ellipsis"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 36px;
  height: 36px;
  color: var(--color-fg-muted);
  font-size: var(--text-sm);
  user-select: none;
}

/* ── Size: Small ── */
[data-ui="pagination"][data-size="sm"] > :where([data-part="nav"]) > [data-part="page"],
[data-ui="pagination"][data-size="sm"] > :where([data-part="nav"]) > [data-part="prev"],
[data-ui="pagination"][data-size="sm"] > :where([data-part="nav"]) > [data-part="next"] {
  min-width: 28px;
  height: 28px;
  font-size: var(--text-xs, 0.75rem);
  padding: 0 var(--space-1);
}

[data-ui="pagination"][data-size="sm"] > :where([data-part="nav"]) > [data-part="prev"],
[data-ui="pagination"][data-size="sm"] > :where([data-part="nav"]) > [data-part="next"] {
  padding: 0 var(--space-2);
}

[data-ui="pagination"][data-size="sm"] > :where([data-part="nav"]) > [data-part="ellipsis"] {
  min-width: 28px;
  height: 28px;
  font-size: var(--text-xs, 0.75rem);
}

/* ── Size: Large ── */
[data-ui="pagination"][data-size="lg"] > :where([data-part="nav"]) > [data-part="page"],
[data-ui="pagination"][data-size="lg"] > :where([data-part="nav"]) > [data-part="prev"],
[data-ui="pagination"][data-size="lg"] > :where([data-part="nav"]) > [data-part="next"] {
  min-width: 44px;
  height: 44px;
  font-size: var(--text-base, 1rem);
  padding: 0 var(--space-3);
}

[data-ui="pagination"][data-size="lg"] > :where([data-part="nav"]) > [data-part="prev"],
[data-ui="pagination"][data-size="lg"] > :where([data-part="nav"]) > [data-part="next"] {
  padding: 0 var(--space-4, 1rem);
}

[data-ui="pagination"][data-size="lg"] > :where([data-part="nav"]) > [data-part="ellipsis"] {
  min-width: 44px;
  height: 44px;
  font-size: var(--text-base, 1rem);
}

/* ── Motion ── */
@media (prefers-reduced-motion: reduce) {
  [data-ui="pagination"] > :where([data-part="nav"]) > [data-part="page"],
  [data-ui="pagination"] > :where([data-part="nav"]) > [data-part="prev"],
  [data-ui="pagination"] > :where([data-part="nav"]) > [data-part="next"] {
    transition: none;
  }
}


/* === recipes/popover.css === */
/* @ui:component popover */
/* @ui:tokens color-bg color-fg color-border color-bg-muted color-fg-muted panel-bg shadow-md radius-lg radius-md space-3 space-4 space-2 z-dropdown duration-fast ease-default font-ui border-width focus-ring-width focus-ring-style focus-ring-color focus-ring-offset surface-backdrop text-sm text-xs weight-medium */

/* ── Root ── */
[data-ui="popover"] {
  position: relative;
  display: inline-block;
}

/* ── Trigger ── */
[data-ui="popover"] > [data-part="trigger"] {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2, 0.5rem);
  padding: var(--space-2, 0.5rem) var(--space-3);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-md, 0.375rem);
  background: var(--color-bg);
  color: var(--color-fg);
  font-family: var(--font-ui);
  font-size: var(--text-sm, 0.875rem);
  font-weight: var(--weight-medium, 500);
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--duration-fast) var(--ease-default),
              border-color var(--duration-fast) var(--ease-default);
}

[data-ui="popover"] > [data-part="trigger"]:hover {
  background: var(--color-bg-muted, oklch(0.96 0.004 260));
}

[data-ui="popover"] > [data-part="trigger"]:focus-visible {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  outline-offset: var(--focus-ring-offset);
}

/* ── Content ── */
[data-ui="popover"] > [data-part="content"] {
  position: absolute;
  z-index: var(--z-dropdown);
  /* Sized by its content, not by the trigger-wide root it is positioned in —
     which squeezed every popover into a 200px column. */
  width: max-content;
  min-width: 200px;
  max-width: min(20rem, calc(100vw - 2 * var(--space-4)));
  padding: var(--space-4);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--panel-bg);
  color: var(--color-fg);
  box-shadow: var(--shadow-md);
  opacity: 0;
  transform: scale(0.95);
  transition: opacity var(--duration-fast) var(--ease-default),
              transform var(--duration-fast) var(--ease-default);
}

@supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
  [data-ui="popover"] > [data-part="content"] {
    -webkit-backdrop-filter: var(--surface-backdrop);
    backdrop-filter: var(--surface-backdrop);
  }
}

[data-ui="popover"][data-state="open"] > [data-part="content"] {
  opacity: 1;
  transform: scale(1);
}

/* ── Position: Bottom (default) ── */
[data-ui="popover"] > [data-part="content"][data-variant="bottom"] {
  top: 100%;
  margin-top: var(--space-2, 0.5rem);
}

/* ── Position: Top ── */
[data-ui="popover"] > [data-part="content"][data-variant="top"] {
  bottom: 100%;
  margin-bottom: var(--space-2, 0.5rem);
}

/* ── Position: Left ── */
[data-ui="popover"] > [data-part="content"][data-variant="left"] {
  inset-inline-end: 100%;
  top: 0;
  margin-inline-end: var(--space-2, 0.5rem);
}

/* ── Position: Right ── */
[data-ui="popover"] > [data-part="content"][data-variant="right"] {
  inset-inline-start: 100%;
  top: 0;
  margin-inline-start: var(--space-2, 0.5rem);
}

/* ── Align: Start ── */
[data-ui="popover"] > [data-part="content"][data-align="start"][data-variant="bottom"],
[data-ui="popover"] > [data-part="content"][data-align="start"][data-variant="top"] {
  inset-inline-start: 0;
}

/* ── Align: Center ── */
[data-ui="popover"] > [data-part="content"][data-align="center"][data-variant="bottom"],
[data-ui="popover"] > [data-part="content"][data-align="center"][data-variant="top"] {
  inset-inline-start: 50%;
  transform: translateX(-50%) scale(0.95);
}

[data-ui="popover"][data-state="open"] > [data-part="content"][data-align="center"][data-variant="bottom"],
[data-ui="popover"][data-state="open"] > [data-part="content"][data-align="center"][data-variant="top"] {
  transform: translateX(-50%) scale(1);
}

/* ── Align: End ── */
[data-ui="popover"] > [data-part="content"][data-align="end"][data-variant="bottom"],
[data-ui="popover"] > [data-part="content"][data-align="end"][data-variant="top"] {
  inset-inline-start: auto;
  inset-inline-end: 0;
}

/* ── Align for Left/Right positions: Start ── */
[data-ui="popover"] > [data-part="content"][data-align="start"][data-variant="left"],
[data-ui="popover"] > [data-part="content"][data-align="start"][data-variant="right"] {
  top: 0;
}

/* ── Align for Left/Right positions: Center ── */
[data-ui="popover"] > [data-part="content"][data-align="center"][data-variant="left"],
[data-ui="popover"] > [data-part="content"][data-align="center"][data-variant="right"] {
  top: 50%;
  transform: translateY(-50%) scale(0.95);
}

[data-ui="popover"][data-state="open"] > [data-part="content"][data-align="center"][data-variant="left"],
[data-ui="popover"][data-state="open"] > [data-part="content"][data-align="center"][data-variant="right"] {
  transform: translateY(-50%) scale(1);
}

/* ── Align for Left/Right positions: End ── */
[data-ui="popover"] > [data-part="content"][data-align="end"][data-variant="left"],
[data-ui="popover"] > [data-part="content"][data-align="end"][data-variant="right"] {
  top: auto;
  bottom: 0;
}

/* ── Arrow ── */
[data-ui="popover"] > [data-part="content"]::before {
  content: "";
  position: absolute;
  width: 8px;
  height: 8px;
  background: var(--panel-bg);
  border: var(--border-width) solid var(--color-border);
  transform: rotate(45deg);
}

/* Arrow for bottom position */
[data-ui="popover"] > [data-part="content"][data-variant="bottom"]::before {
  top: -5px;
  inset-inline-start: var(--space-4);
  border-inline-end: none;
  border-bottom: none;
}

[data-ui="popover"] > [data-part="content"][data-align="center"][data-variant="bottom"]::before {
  inset-inline-start: 50%;
  margin-inline-start: -4px;
}

[data-ui="popover"] > [data-part="content"][data-align="end"][data-variant="bottom"]::before {
  inset-inline-start: auto;
  inset-inline-end: var(--space-4);
}

/* Arrow for top position */
[data-ui="popover"] > [data-part="content"][data-variant="top"]::before {
  bottom: -5px;
  inset-inline-start: var(--space-4);
  border-inline-start: none;
  border-top: none;
}

[data-ui="popover"] > [data-part="content"][data-align="center"][data-variant="top"]::before {
  inset-inline-start: 50%;
  margin-inline-start: -4px;
}

[data-ui="popover"] > [data-part="content"][data-align="end"][data-variant="top"]::before {
  inset-inline-start: auto;
  inset-inline-end: var(--space-4);
}

/* Arrow for left position */
[data-ui="popover"] > [data-part="content"][data-variant="left"]::before {
  inset-inline-end: -5px;
  top: var(--space-4);
  border-inline-start: none;
  border-bottom: none;
}

[data-ui="popover"] > [data-part="content"][data-align="center"][data-variant="left"]::before {
  top: 50%;
  margin-top: -4px;
}

[data-ui="popover"] > [data-part="content"][data-align="end"][data-variant="left"]::before {
  top: auto;
  bottom: var(--space-4);
}

/* Arrow for right position */
[data-ui="popover"] > [data-part="content"][data-variant="right"]::before {
  inset-inline-start: -5px;
  top: var(--space-4);
  border-inline-end: none;
  border-top: none;
}

[data-ui="popover"] > [data-part="content"][data-align="center"][data-variant="right"]::before {
  top: 50%;
  margin-top: -4px;
}

[data-ui="popover"] > [data-part="content"][data-align="end"][data-variant="right"]::before {
  top: auto;
  bottom: var(--space-4);
}

/* ── Close Button ── */
[data-ui="popover"] > :where([data-part="content"]) > [data-part="close"] {
  position: absolute;
  top: var(--space-2, 0.5rem);
  inset-inline-end: var(--space-2, 0.5rem);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  padding: 0;
  border: none;
  border-radius: var(--radius-md, 0.375rem);
  background: transparent;
  color: var(--color-fg-muted, oklch(0.55 0 0));
  font-size: var(--text-xs, 0.75rem);
  cursor: pointer;
}

/* The close button sits in the corner; keep the content's text out from under it. */
[data-ui="popover"] > [data-part="content"]:has(> [data-part="close"]) {
  padding-inline-end: calc(var(--space-2, 0.5rem) * 2 + 24px);
}

[data-ui="popover"] > :where([data-part="content"]) > [data-part="close"]:hover {
  background: var(--color-bg-muted, oklch(0.96 0.004 260));
  color: var(--color-fg);
}

[data-ui="popover"] > :where([data-part="content"]) > [data-part="close"]:focus-visible {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  outline-offset: var(--focus-ring-offset);
}

/* ── Motion ── */
@media (prefers-reduced-motion: reduce) {
  [data-ui="popover"] > [data-part="content"],
  [data-ui="popover"] > [data-part="trigger"] {
    transition: none;
  }
}


/* === recipes/qr-code.css === */
/* @ui:component qr-code */
/* @ui:tokens color-fg-muted color-bg space-2 text-xs font-body doc-font doc-legal-size doc-legal-color */

/* ── Base ── */
[data-ui="qr-code"] {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  --qr-size: 128px;
}

/* ── Sizes: the box the code takes, quiet zone included ── */
[data-ui="qr-code"][data-size="sm"] {
  --qr-size: 80px;
}

[data-ui="qr-code"][data-size="lg"] {
  --qr-size: 200px;
}

/* ── SVG ──
   The controller draws the modules flush (the viewBox is the symbol) and
   writes the module count on the svg as --qr-modules. The quiet zone is
   padding: --qr-quiet modules (4, as ISO/IEC 18004 asks) on every side, inside
   --qr-size, painted in the background colour. A layout that already leaves
   light space round the code, or that aligns the ink with a caption or a
   column edge, sets --qr-quiet: 0 or pulls the box out by the padding. */
[data-ui="qr-code"] > [data-part="svg"],
[data-ui="qr-code"] svg {
  display: block;
  box-sizing: border-box;
  width: var(--qr-size);
  height: var(--qr-size);
  padding: calc(var(--qr-size) * var(--qr-quiet, 4) / (var(--qr-modules, 21) + 2 * var(--qr-quiet, 4)));
  background-color: var(--color-bg);
}

/* ── Caption ── */
[data-ui="qr-code"] > [data-part="caption"] {
  font-family: var(--doc-font, var(--font-body));
  font-size: var(--doc-legal-size, var(--text-xs));
  color: var(--doc-legal-color, var(--color-fg-muted));
  text-align: center;
  line-height: 1.4;
}

/* ── Print ── */
@media print {
  [data-ui="qr-code"] {
    break-inside: avoid;
  }

  [data-ui="qr-code"] svg {
    color-adjust: exact;
    print-color-adjust: exact;
    -webkit-print-color-adjust: exact;
  }
}


/* === recipes/sheet.css === */
/* @ui:component sheet */
/* @ui:tokens color-bg color-fg color-border color-fg-muted color-bg-muted panel-bg shadow-xl radius-xl radius-md space-6 z-overlay z-modal duration-normal duration-slow ease-out font-heading border-width focus-ring-width focus-ring-style focus-ring-color focus-ring-offset surface-backdrop text-lg text-base weight-semibold */

/* ── Root ── */
[data-ui="sheet"] {
  position: relative;
}

/* ── Overlay ── */
[data-ui="sheet"] > [data-part="overlay"] {
  position: fixed;
  inset: 0;
  z-index: var(--z-overlay);
  background: var(--sheet-overlay-bg, oklch(0 0 0 / 0.5));
  opacity: 0;
  transition: opacity var(--duration-normal) var(--ease-out);
}

[data-ui="sheet"][data-state="open"] > [data-part="overlay"] {
  opacity: 1;
}

[data-ui="sheet"][data-state="closing"] > [data-part="overlay"] {
  opacity: 0;
}

/* ── Panel (shared) ── */
[data-ui="sheet"] > [data-part="panel"] {
  position: fixed;
  z-index: var(--z-modal);
  display: flex;
  flex-direction: column;
  background: var(--panel-bg);
  box-shadow: var(--shadow-xl);
  transition: transform var(--duration-slow) var(--ease-out);
}

/* The panel is focused on open (tabindex="-1") only so the focus trap and the
   Escape key have somewhere to start. It is not a control, so it draws no ring:
   the global :focus-visible would otherwise outline the whole panel when the
   overlay is opened from the keyboard. */
[data-ui="sheet"] > [data-part="panel"]:focus {
  outline: none;
}

@supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
  [data-ui="sheet"] > [data-part="panel"] {
    -webkit-backdrop-filter: var(--surface-backdrop);
    backdrop-filter: var(--surface-backdrop);
  }
}

/* ── Side: Bottom ── */
[data-ui="sheet"] > [data-part="panel"][data-variant="bottom"] {
  bottom: 0;
  inset-inline-start: 0;
  inset-inline-end: 0;
  max-height: 90vh;
  border-radius: var(--radius-xl) var(--radius-xl) 0 0;
  transform: translateY(100%);
}

/* ── Side: Top ── */
[data-ui="sheet"] > [data-part="panel"][data-variant="top"] {
  top: 0;
  inset-inline-start: 0;
  inset-inline-end: 0;
  max-height: 90vh;
  border-radius: 0 0 var(--radius-xl) var(--radius-xl);
  transform: translateY(-100%);
}

/* ── Side: Left ── */
[data-ui="sheet"] > [data-part="panel"][data-variant="left"] {
  top: 0;
  inset-inline-start: 0;
  bottom: 0;
  max-width: 100vw;
  border-radius: 0 var(--radius-xl) var(--radius-xl) 0;
  border-inline-end: var(--border-width) solid var(--color-border);
  transform: translateX(-100%);
}

/* ── Side: Right ── */
[data-ui="sheet"] > [data-part="panel"][data-variant="right"] {
  top: 0;
  inset-inline-end: 0;
  bottom: 0;
  max-width: 100vw;
  border-radius: var(--radius-xl) 0 0 var(--radius-xl);
  border-inline-start: var(--border-width) solid var(--color-border);
  transform: translateX(100%);
}

/* ── Open State ── */
[data-ui="sheet"][data-state="open"] > [data-part="panel"][data-variant="bottom"],
[data-ui="sheet"][data-state="open"] > [data-part="panel"][data-variant="top"] {
  transform: translateY(0);
}

[data-ui="sheet"][data-state="open"] > [data-part="panel"][data-variant="left"],
[data-ui="sheet"][data-state="open"] > [data-part="panel"][data-variant="right"] {
  transform: translateX(0);
}

/* ── Closing State ── */
[data-ui="sheet"][data-state="closing"] > [data-part="panel"][data-variant="bottom"] {
  transform: translateY(100%);
}

[data-ui="sheet"][data-state="closing"] > [data-part="panel"][data-variant="top"] {
  transform: translateY(-100%);
}

[data-ui="sheet"][data-state="closing"] > [data-part="panel"][data-variant="left"] {
  transform: translateX(-100%);
}

[data-ui="sheet"][data-state="closing"] > [data-part="panel"][data-variant="right"] {
  transform: translateX(100%);
}

/* ── Size for Bottom/Top ── */
[data-ui="sheet"] > [data-part="panel"][data-variant="bottom"][data-size="sm"],
[data-ui="sheet"] > [data-part="panel"][data-variant="top"][data-size="sm"] {
  height: 30vh;
}

[data-ui="sheet"] > [data-part="panel"][data-variant="bottom"][data-size="md"],
[data-ui="sheet"] > [data-part="panel"][data-variant="top"][data-size="md"] {
  height: 50vh;
}

[data-ui="sheet"] > [data-part="panel"][data-variant="bottom"][data-size="lg"],
[data-ui="sheet"] > [data-part="panel"][data-variant="top"][data-size="lg"] {
  height: 75vh;
}

/* ── Size for Left/Right ── */
[data-ui="sheet"] > [data-part="panel"][data-variant="left"][data-size="sm"],
[data-ui="sheet"] > [data-part="panel"][data-variant="right"][data-size="sm"] {
  width: 280px;
}

[data-ui="sheet"] > [data-part="panel"][data-variant="left"][data-size="md"],
[data-ui="sheet"] > [data-part="panel"][data-variant="right"][data-size="md"] {
  width: 380px;
}

[data-ui="sheet"] > [data-part="panel"][data-variant="left"][data-size="lg"],
[data-ui="sheet"] > [data-part="panel"][data-variant="right"][data-size="lg"] {
  width: 500px;
}

/* ── Header ──
   Every part is reached from the root by child combinators, so a component in
   the body keeps its own header, title and close (1.1F-21); the hops are in
   :where(), so every rule keeps the weight it had. Beyond direct children: the
   header and body may sit in a <form> that is the panel's child (a form
   dialog), and a title or close button may sit in one plain div, stack or
   cluster inside its section. */
[data-ui="sheet"] > :where([data-part="panel"]) > [data-part="header"],
[data-ui="sheet"] > :where([data-part="panel"]) > :where(form) > [data-part="header"] {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-6);
  padding-bottom: 0;
  flex-shrink: 0;
}

/* ── Title ── */
[data-ui="sheet"] > :where([data-part="panel"]) > :where([data-part="header"]) > [data-part="title"],
[data-ui="sheet"] > :where([data-part="panel"]) > :where([data-part="header"]) > :where(div:not([data-ui]), [data-ui="stack"], [data-ui="cluster"]) > [data-part="title"],
[data-ui="sheet"] > :where([data-part="panel"]) > :where(form) > :where([data-part="header"]) > [data-part="title"],
[data-ui="sheet"] > :where([data-part="panel"]) > :where(form) > :where([data-part="header"]) > :where(div:not([data-ui]), [data-ui="stack"], [data-ui="cluster"]) > [data-part="title"] {
  margin: 0;
  font-family: var(--font-heading);
  font-size: var(--text-lg, 1.125rem);
  font-weight: var(--weight-semibold, 600);
  color: var(--color-fg);
}

/* ── Close Button ──
   `:not([data-ui])` is the trigger contract read backwards (task 0.9-05): a part
   that delegates its look to a primitive must not then be restyled by the recipe.
   Without it this icon-close rule also caught the footer's
   `<button data-ui="button" data-part="close">Cancel</button>` and squashed it to
   a 32px borderless square — invisible for as long as the panel was, and the
   first thing the forced-open preview showed. */
[data-ui="sheet"] > :where([data-part="panel"]) > [data-part="close"]:not([data-ui]),
[data-ui="sheet"] > :where([data-part="panel"]) > :where([data-part="header"], [data-part="footer"]) > [data-part="close"]:not([data-ui]),
[data-ui="sheet"] > :where([data-part="panel"]) > :where([data-part="header"], [data-part="footer"]) > :where(div:not([data-ui]), [data-ui="stack"], [data-ui="cluster"]) > [data-part="close"]:not([data-ui]),
[data-ui="sheet"] > :where([data-part="panel"]) > :where(form) > :where([data-part="header"], [data-part="footer"]) > [data-part="close"]:not([data-ui]),
[data-ui="sheet"] > :where([data-part="panel"]) > :where(form) > :where([data-part="header"], [data-part="footer"]) > :where(div:not([data-ui]), [data-ui="stack"], [data-ui="cluster"]) > [data-part="close"]:not([data-ui]) {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: none;
  border-radius: var(--radius-md, 0.375rem);
  background: transparent;
  color: var(--color-fg-muted, oklch(0.55 0 0));
  font-size: var(--text-base, 1rem);
  cursor: pointer;
  flex-shrink: 0;
}

[data-ui="sheet"] > :where([data-part="panel"]) > [data-part="close"]:not([data-ui]):hover,
[data-ui="sheet"] > :where([data-part="panel"]) > :where([data-part="header"], [data-part="footer"]) > [data-part="close"]:not([data-ui]):hover,
[data-ui="sheet"] > :where([data-part="panel"]) > :where([data-part="header"], [data-part="footer"]) > :where(div:not([data-ui]), [data-ui="stack"], [data-ui="cluster"]) > [data-part="close"]:not([data-ui]):hover,
[data-ui="sheet"] > :where([data-part="panel"]) > :where(form) > :where([data-part="header"], [data-part="footer"]) > [data-part="close"]:not([data-ui]):hover,
[data-ui="sheet"] > :where([data-part="panel"]) > :where(form) > :where([data-part="header"], [data-part="footer"]) > :where(div:not([data-ui]), [data-ui="stack"], [data-ui="cluster"]) > [data-part="close"]:not([data-ui]):hover {
  background: var(--color-bg-muted, oklch(0.96 0.004 260));
  color: var(--color-fg);
}

[data-ui="sheet"] > :where([data-part="panel"]) > [data-part="close"]:not([data-ui]):focus-visible,
[data-ui="sheet"] > :where([data-part="panel"]) > :where([data-part="header"], [data-part="footer"]) > [data-part="close"]:not([data-ui]):focus-visible,
[data-ui="sheet"] > :where([data-part="panel"]) > :where([data-part="header"], [data-part="footer"]) > :where(div:not([data-ui]), [data-ui="stack"], [data-ui="cluster"]) > [data-part="close"]:not([data-ui]):focus-visible,
[data-ui="sheet"] > :where([data-part="panel"]) > :where(form) > :where([data-part="header"], [data-part="footer"]) > [data-part="close"]:not([data-ui]):focus-visible,
[data-ui="sheet"] > :where([data-part="panel"]) > :where(form) > :where([data-part="header"], [data-part="footer"]) > :where(div:not([data-ui]), [data-ui="stack"], [data-ui="cluster"]) > [data-part="close"]:not([data-ui]):focus-visible {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  outline-offset: var(--focus-ring-offset);
}

/* ── Body ── */
[data-ui="sheet"] > :where([data-part="panel"]) > [data-part="body"],
[data-ui="sheet"] > :where([data-part="panel"]) > :where(form) > [data-part="body"] {
  flex: 1;
  overflow-y: auto;
  padding: var(--space-6);
  color: var(--color-fg);
}

/* ── Motion ── */
@media (prefers-reduced-motion: reduce) {
  [data-ui="sheet"] > [data-part="overlay"],
  [data-ui="sheet"] > [data-part="panel"] {
    transition: none;
  }
}


/* === recipes/sidebar.css === */
/* @ui:component sidebar */
/* @ui:tokens color-bg color-fg color-fg-muted color-border color-primary color-primary-subtle color-bg-muted color-ring shadow-xl space-1 space-2 space-3 space-4 radius-md radius-lg z-overlay z-modal text-sm weight-medium weight-semibold duration-normal duration-slow ease-out ease-default border-width focus-ring-width focus-ring-style focus-ring-color focus-ring-offset */

/* ── Root ──
   The root owns the layout column from `md` up; the panel is the visual surface.
   Off-canvas below it, so the root collapses to zero width and the content
   beside it spans the full viewport.

   MOBILE-FIRST, and that is the fix. The collapse used to be the controller's
   job alone: `createSidebar` watches a media query and rewrites `data-state`.
   So every rendering without JS — a screenshot, a print, a page whose script
   has not run yet, a reader with JS off — kept a 256px rail on a 320px phone
   and pushed the header beside it 83px off the window. `dashboard-shell` has
   been mobile-first since 0.8-09 and this is the same shape, for the same
   reason: under a min-width-only canon (FAQIR-NEXT §19), "off-canvas below md"
   can only be said as "off-canvas always, in the flow from md up". The
   controller still owns open/closed; the CSS owns which layout the width
   affords. [W3-3] */
[data-ui="sidebar"] {
  --sidebar-width: 16rem;
  --sidebar-rail-width: 3.75rem;
  --sidebar-bg: var(--color-bg);

  flex: 0 0 auto;
  inline-size: 0;
  transition: inline-size var(--duration-normal) var(--ease-default);
}

/* ── Panel ──
   Off-canvas below `md`, whatever `data-state` says; the md block below returns
   it to the flow. `visibility` rather than transform alone, so a closed drawer
   is neither painted outside the viewport nor reachable by tab: it used to be
   both. It is delayed off (not on) so the slide-out animation still plays. */
[data-ui="sidebar"] > [data-part="panel"] {
  --sidebar-offscreen: -100%;
  position: fixed;
  inset-block: 0;
  inset-inline-start: 0;
  inline-size: var(--sidebar-width);
  max-inline-size: 100%;
  block-size: 100dvh;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  background: var(--sidebar-bg);
  border-inline-end: var(--border-width) solid var(--color-border);
  border-start-end-radius: var(--radius-lg, 0.5rem);
  border-end-end-radius: var(--radius-lg, 0.5rem);
  box-shadow: var(--shadow-xl);
  z-index: var(--z-modal);
  overflow: hidden;
  transform: translateX(var(--sidebar-offscreen, -100%));
  visibility: hidden;
  transition: transform var(--duration-slow) var(--ease-out),
              visibility 0s linear var(--duration-slow);
}

[dir="rtl"] [data-ui="sidebar"] > [data-part="panel"] {
  --sidebar-offscreen: 100%;
}

[data-ui="sidebar"][data-state="drawer-open"] > [data-part="panel"] {
  transform: translateX(0);
  visibility: visible;
  transition: transform var(--duration-slow) var(--ease-out),
              visibility 0s linear 0s;
}

/* ── Header (brand + toggle) ── */
[data-ui="sidebar"] > :where([data-part="panel"]) > [data-part="header"] {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  flex-shrink: 0;
}

[data-ui="sidebar"] > :where([data-part="panel"]) > :where([data-part="header"]) > [data-part="brand"] {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  min-inline-size: 0;
  color: var(--color-fg);
  font-weight: var(--weight-semibold, 600);
  text-decoration: none;
}

[data-ui="sidebar"] > :where([data-part="panel"]) > :where([data-part="header"]) > :where([data-part="brand"]) > [data-part="brand-icon"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  inline-size: 1.75rem;
  block-size: 1.75rem;
  color: var(--color-primary);
}

[data-ui="sidebar"] > :where([data-part="panel"]) > :where([data-part="header"]) > :where([data-part="brand"]) > [data-part="brand-label"] {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ── Toggle button ──
   In the panel's header, or the root's own child: a drawer that is off-canvas
   is opened from outside its panel. Every part rule is a child chain (1.1F-21),
   so a dropdown in the footer keeps its own trigger and items. */
[data-ui="sidebar"] > [data-part="trigger"],
[data-ui="sidebar"] > :where([data-part="panel"]) > :where([data-part="header"]) > [data-part="trigger"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  inline-size: 2rem;
  block-size: 2rem;
  padding: 0;
  border: none;
  border-radius: var(--radius-md, 0.375rem);
  background: transparent;
  color: var(--color-fg-muted, oklch(0.55 0 0));
  cursor: pointer;
}

[data-ui="sidebar"] > [data-part="trigger"]:hover,
[data-ui="sidebar"] > :where([data-part="panel"]) > :where([data-part="header"]) > [data-part="trigger"]:hover {
  background: var(--color-bg-muted, oklch(0.96 0.004 260));
  color: var(--color-fg);
}

[data-ui="sidebar"] > [data-part="trigger"]:focus-visible,
[data-ui="sidebar"] > :where([data-part="panel"]) > :where([data-part="header"]) > [data-part="trigger"]:focus-visible {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  outline-offset: var(--focus-ring-offset);
}

/* The trigger's glyph is authored once, pointing at the collapse (inline-start),
   and mirrored in rail so it points at the expand. The markup can't carry the
   direction: it is written once and the state changes under it. Its
   accessible name stays "Toggle sidebar" in both states; `aria-expanded` says
   which way it goes (APG: an expanded-state button must not rename itself). */
[data-ui="sidebar"] > [data-part="trigger"] > :is(svg, [data-ui="icon"]),
[data-ui="sidebar"] > :where([data-part="panel"]) > :where([data-part="header"]) > [data-part="trigger"] > :is(svg, [data-ui="icon"]) {
  transition: scale var(--duration-normal) var(--ease-default);
}

[data-ui="sidebar"][data-state="rail"] > [data-part="trigger"] > :is(svg, [data-ui="icon"]),
[data-ui="sidebar"][data-state="rail"] > :where([data-part="panel"]) > :where([data-part="header"]) > [data-part="trigger"] > :is(svg, [data-ui="icon"]) {
  scale: -1 1;
}

/* ── Navigation ── */
[data-ui="sidebar"] > :where([data-part="panel"]) > [data-part="nav"] {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  flex: 1 1 auto;
  overflow-y: auto;
  padding: var(--space-2) var(--space-3);
}

[data-ui="sidebar"] > :where([data-part="panel"]) > :where([data-part="nav"], [data-part="footer"]) > [data-part="item"] {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  inline-size: 100%;
  padding: var(--space-2) var(--space-3);
  border: none;
  border-radius: var(--radius-md, 0.375rem);
  background: transparent;
  color: var(--color-fg-muted, oklch(0.5 0.01 260));
  font-size: var(--text-sm, 0.875rem);
  font-weight: var(--weight-medium, 500);
  text-align: start;
  text-decoration: none;
  cursor: pointer;
}

[data-ui="sidebar"] > :where([data-part="panel"]) > :where([data-part="nav"], [data-part="footer"]) > [data-part="item"]:hover {
  background: var(--color-bg-muted, oklch(0.96 0.004 260));
  color: var(--color-fg);
}

[data-ui="sidebar"] > :where([data-part="panel"]) > :where([data-part="nav"], [data-part="footer"]) > [data-part="item"]:focus-visible {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  outline-offset: calc(-1 * var(--focus-ring-offset));
}

[data-ui="sidebar"] > :where([data-part="panel"]) > :where([data-part="nav"], [data-part="footer"]) > [data-part="item"][aria-current="page"] {
  background: var(--color-primary-subtle, oklch(0.95 0.03 264 / 0.6));
  color: var(--color-primary);
}

[data-ui="sidebar"] > :where([data-part="panel"]) > :where([data-part="nav"], [data-part="footer"]) > :where([data-part="item"]) > [data-part="icon"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  inline-size: 1.25rem;
  block-size: 1.25rem;
}

[data-ui="sidebar"] > :where([data-part="panel"]) > :where([data-part="nav"], [data-part="footer"]) > :where([data-part="item"]) > [data-part="label"] {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ── Footer ── */
[data-ui="sidebar"] > :where([data-part="panel"]) > [data-part="footer"] {
  flex-shrink: 0;
  padding: var(--space-3) var(--space-4);
  border-block-start: var(--border-width) solid var(--color-border);
}

/* ── Rail (icons only) ── */
[data-ui="sidebar"][data-state="rail"] > :where([data-part="panel"]) > :where([data-part="header"]) > :where([data-part="brand"]) > [data-part="brand-label"],
[data-ui="sidebar"][data-state="rail"] > :where([data-part="panel"]) > :where([data-part="nav"], [data-part="footer"]) > :where([data-part="item"]) > [data-part="label"] {
  display: none;
}

[data-ui="sidebar"][data-state="rail"] > :where([data-part="panel"]) > [data-part="header"],
[data-ui="sidebar"][data-state="rail"] > :where([data-part="panel"]) > [data-part="nav"],
[data-ui="sidebar"][data-state="rail"] > :where([data-part="panel"]) > [data-part="footer"] {
  padding-inline: var(--space-2);
}

/* The brand glyph (28px) and trigger (32px) cannot share one inline row inside
   the rail's 44px content box. Stack them so both stay fully reachable. */
[data-ui="sidebar"][data-state="rail"] > :where([data-part="panel"]) > [data-part="header"] {
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
}

[data-ui="sidebar"][data-state="rail"] > :where([data-part="panel"]) > :where([data-part="header"]) > [data-part="brand"],
[data-ui="sidebar"][data-state="rail"] > :where([data-part="panel"]) > :where([data-part="nav"], [data-part="footer"]) > [data-part="item"] {
  justify-content: center;
  gap: 0;
}

/* ── Mobile drawer (off-canvas) ── */
[data-ui="sidebar"] > [data-part="overlay"] {
  position: fixed;
  inset: 0;
  z-index: var(--z-overlay);
  background: var(--sidebar-overlay-bg, oklch(0 0 0 / 0.5));
  opacity: 0;
  transition: opacity var(--duration-normal) var(--ease-default);
}

[data-ui="sidebar"][data-state="drawer-open"] > [data-part="overlay"] {
  opacity: 1;
}

/* ── Responsive: the sidebar rejoins the flow at the canon `md` floor ──
   Canon tiers only, min-width only (FAQIR-NEXT §19). This is the desktop
   layout the sheet used to state unconditionally. `data-state="drawer"` and
   `drawer-open` are the controller's mobile states and keep the off-canvas
   treatment even here, which is what makes a hand-set `data-state` still
   render as written. [W3-3] */
@media (min-width: 48rem) {
  [data-ui="sidebar"] {
    inline-size: var(--sidebar-width);
  }

  [data-ui="sidebar"][data-state="rail"] {
    inline-size: var(--sidebar-rail-width);
  }

  [data-ui="sidebar"][data-state="drawer"],
  [data-ui="sidebar"][data-state="drawer-open"] {
    inline-size: 0;
  }

  [data-ui="sidebar"]:not([data-state="drawer"]):not([data-state="drawer-open"]) > [data-part="panel"] {
    position: sticky;
    inset-block-start: 0;
    inset-inline-start: auto;
    inline-size: 100%;
    z-index: auto;
    border-start-end-radius: 0;
    border-end-end-radius: 0;
    box-shadow: none;
    transform: none;
    visibility: visible;
    transition: transform var(--duration-slow) var(--ease-out);
  }

  [data-ui="sidebar"]:not([data-state="drawer"]):not([data-state="drawer-open"]) > [data-part="overlay"] {
    display: none;
  }
}

/* ── Motion ── */
@media (prefers-reduced-motion: reduce) {
  [data-ui="sidebar"],
  [data-ui="sidebar"] > [data-part="panel"],
  [data-ui="sidebar"] > [data-part="overlay"],
  [data-ui="sidebar"] > [data-part="trigger"] > :is(svg, [data-ui="icon"]),
  [data-ui="sidebar"] > :where([data-part="panel"]) > :where([data-part="header"]) > [data-part="trigger"] > :is(svg, [data-ui="icon"]) {
    transition: none;
  }
}


/* === recipes/slider.css === */
/* @ui:component slider */
/* @ui:tokens color-bg color-fg-muted color-primary color-primary-subtle color-ring color-bg-muted space-3 radius-full text-sm shadow-sm duration-fast ease-default font-ui border-width border-width-strong focus-ring-width focus-ring-style focus-ring-color focus-ring-offset disabled-opacity */

/* ── Root ── */
[data-ui="slider"] {
  --slider-thumb-size: 1.25rem;
  --slider-track-size: 0.375rem;
  /* Filled span, written by the controller as percentages. */
  --slider-start: 0%;
  --slider-end: 0%;

  display: flex;
  align-items: center;
  gap: var(--space-3);
  inline-size: 100%;
  min-block-size: var(--slider-thumb-size);
  /* The controller owns dragging; keep the browser from scrolling/panning. */
  touch-action: none;
  user-select: none;
}

/* ── Track ── */
[data-ui="slider"] > [data-part="track"] {
  position: relative;
  flex: 1 1 auto;
  block-size: var(--slider-track-size);
  background: var(--color-bg-muted, oklch(0.92 0.004 260));
  border-radius: var(--radius-full, 9999px);
}

/* ── Filled range ── */
[data-ui="slider"] > :where([data-part="track"]) > [data-part="range"] {
  position: absolute;
  inset-block: 0;
  inset-inline-start: var(--slider-start, 0%);
  inset-inline-end: calc(100% - var(--slider-end, 0%));
  background: var(--color-primary);
  border-radius: inherit;
}

/* ── Thumb ── */
[data-ui="slider"] > :where([data-part="track"]) > [data-part="thumb"] {
  position: absolute;
  inset-block-start: 50%;
  inset-inline-start: var(--pos, 0%);
  inline-size: var(--slider-thumb-size);
  block-size: var(--slider-thumb-size);
  /* inset-inline-start puts the leading edge; translate centres the thumb on the
     value in both LTR and RTL (translateX is physical, so -50% always recentres). */
  transform: translate(-50%, -50%);
  background: var(--color-bg, white);
  border: var(--border-width-strong) solid var(--color-primary);
  border-radius: var(--radius-full, 9999px);
  box-shadow: var(--shadow-sm);
  cursor: grab;
  touch-action: none;
  transition: box-shadow var(--duration-fast) var(--ease-default);
}

[data-ui="slider"] > :where([data-part="track"]) > [data-part="thumb"]:hover {
  box-shadow: var(--shadow-sm),
              0 0 0 4px var(--color-primary-subtle);
}

[data-ui="slider"] > :where([data-part="track"]) > [data-part="thumb"]:focus-visible {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  outline-offset: var(--focus-ring-offset);
}

[data-ui="slider"] > :where([data-part="track"]) > [data-part="thumb"][data-state="dragging"] {
  cursor: grabbing;
  box-shadow: var(--shadow-sm),
              0 0 0 5px var(--color-primary-subtle);
}

/* ── Value output ── */
[data-ui="slider"] > [data-part="output"] {
  flex: 0 0 auto;
  min-inline-size: 3ch;
  color: var(--color-fg-muted);
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
  text-align: end;
}

/* ── Sizes ── */
[data-ui="slider"][data-size="sm"] {
  --slider-thumb-size: 1rem;
  --slider-track-size: 0.25rem;
}

[data-ui="slider"][data-size="lg"] {
  --slider-thumb-size: 1.5rem;
  --slider-track-size: 0.5rem;
}

/* ── Disabled ── */
[data-ui="slider"][data-disabled] {
  opacity: var(--disabled-opacity);
  cursor: not-allowed;
  pointer-events: none;
}

/* ── Motion ── */
@media (prefers-reduced-motion: reduce) {
  [data-ui="slider"] > :where([data-part="track"]) > [data-part="thumb"] {
    transition: none;
  }
}

/* ── Forced colors (Windows High Contrast) ──
   The filled range and the empty track differ only by background, and the OS
   drops both: the slider showed no value. The range and the thumb opt out of
   the substitution so the control still reads as "this much, up to here". [W3-3] */
@media (forced-colors: active) {
  [data-ui="slider"] > [data-part="track"] {
    border: var(--border-width) solid ButtonText;
  }

  [data-ui="slider"] > :where([data-part="track"]) > [data-part="range"] {
    forced-color-adjust: none;
    background: Highlight;
  }

  [data-ui="slider"] > :where([data-part="track"]) > [data-part="thumb"] {
    forced-color-adjust: none;
    background: ButtonText;
    border: var(--border-width) solid ButtonFace;
  }

  [data-ui="slider"] > :where([data-part="track"]) > [data-part="thumb"]:focus-visible {
    outline-color: Highlight;
  }
}


/* === recipes/table.css === */
/* @ui:component table */
/* @ui:tokens color-bg color-bg-subtle color-bg-muted color-fg color-fg-muted color-fg-subtle color-border color-border-strong color-primary color-primary-subtle color-ring color-destructive color-destructive-subtle space-0h space-1 space-2 space-3 space-4 space-5 space-8 text-xs text-sm weight-semibold weight-bold radius-sm radius-md radius-full duration-fast ease-default doc-table-footer-bg doc-table-footer-weight doc-print-border-color doc-table-font-size font-body border-width border-width-strong focus-ring-width focus-ring-style focus-ring-color focus-ring-offset stripe-bg */

/* ── Root ── */
[data-ui="table"] {
  width: 100%;
  overflow-x: auto;
}

/* Responsive tables measure themselves (data-hide-below container queries). */
[data-ui="table"][data-responsive] {
  container-type: inline-size;
  container-name: faqir-table;
}

/* Scrolling roots for sticky header/footer. Cap height via --table-max-height. */
[data-ui="table"][data-sticky-header],
[data-ui="table"][data-sticky-footer] {
  overflow: auto;
  max-block-size: var(--table-max-height, none);
}

/* Parts are child chains (1.1F-22). Below the table part the HTML table model
   fixes the structure (section, row, cell), so every rule walks it with
   weightless :where() hops and a table nested in a detail row keeps its own
   striping, hover, selection, pins and hidden columns. The cell attributes
   (data-align, data-format, data-pin, data-hide-below, data-col-hidden,
   data-negative) are read on this table's own cells only: a stack with
   data-align in a cell is not text-aligned. The quick filter may be the root's
   child or sit in one plain div, stack or cluster inside it. */

/* ── Table ── */
[data-ui="table"] > [data-part="table"] {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-family: var(--font-body);
}

/* Once any column is resized the layout freezes so widths are exact. */
[data-ui="table"][data-resized] > [data-part="table"] {
  table-layout: fixed;
}

[data-ui="table"][data-resized] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="th"],
[data-ui="table"][data-resized] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="td"] {
  overflow-wrap: break-word;
}

/* ── Header Cell ── */
[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="th"] {
  position: relative; /* anchors the injected resize handle */
  padding: var(--space-3) var(--space-4);
  text-align: start;
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  color: var(--color-fg-muted);
  background: var(--color-bg);
  border-bottom: var(--border-width-strong) solid var(--color-border);
  white-space: nowrap;
  user-select: none;
}

/* ── Sortable Header ── */
[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="th"][data-sortable] {
  cursor: pointer;
  transition: color var(--duration-fast) var(--ease-default);
}

[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="th"][data-sortable]:hover {
  color: var(--color-fg);
}

[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="th"][data-sortable]::after {
  content: "";
  display: inline-block;
  margin-inline-start: var(--space-2);
  width: 0;
  height: 0;
  vertical-align: middle;
  opacity: 0.3;
  border-inline-start: 4px solid transparent;
  border-inline-end: 4px solid transparent;
  border-bottom: 5px solid currentColor;
}

[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="th"][aria-sort="ascending"]::after {
  opacity: 1;
  border-bottom: 5px solid currentColor;
  border-top: none;
}

[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="th"][aria-sort="descending"]::after {
  opacity: 1;
  border-bottom: none;
  border-top: 5px solid currentColor;
}

/* Multi-sort order badge (data-sort-order is set by the controller). */
[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="th"][data-sort-order]::before {
  content: attr(data-sort-order);
  display: inline-block;
  margin-inline-end: var(--space-1);
  min-inline-size: 1.5em;
  padding: var(--space-0h);
  font-size: 0.65em;
  line-height: 1;
  text-align: center;
  border-radius: var(--radius-full);
  background: var(--color-primary-subtle, oklch(0.96 0.04 264));
  color: var(--color-primary);
}

/* Keyboard focus on cells (sortable headers + navigable grids). */
[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="th"]:focus-visible,
[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="td"]:focus-visible {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  outline-offset: calc(-1 * var(--focus-ring-offset));
}

/* ── Data Cell ── */
[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="td"] {
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-sm);
  color: var(--color-fg);
  border-bottom: var(--border-width) solid var(--color-border);
  background: var(--color-bg);
  transition: background var(--duration-fast) var(--ease-default);
}

/* Text, headings and breadcrumbs break anywhere on their own, so an id never
   widens a page. In a data cell that would let auto layout squeeze every
   column to one character per line; here the cell's own wrapping applies, the
   table keeps its width and scrolls in its root. Header cells need no such
   rule: they are `white-space: nowrap`, so nothing in them breaks at all. */
[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="td"] :is([data-ui="text"], [data-ui="heading"], [data-ui="breadcrumb"]) {
  overflow-wrap: inherit;
}

/* ── Checkbox Cell ── */
[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > :where(th, td) > [data-part="checkbox"] {
  cursor: pointer;
}

/* ── Row Hover ── */
[data-ui="table"] > :where([data-part="table"]) > [data-part="tbody"] > [data-part="tr"]:hover > [data-part="td"] {
  background: var(--color-bg-subtle, oklch(0.97 0.004 260));
}

/* ── Selected Row ── */
[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > [data-part="tr"][data-selected] > [data-part="td"] {
  background: var(--color-primary-subtle, oklch(0.96 0.04 264));
}

/* Row-click selection affordance. */
[data-ui="table"][data-selectable] > :where([data-part="table"]) > [data-part="tbody"] > [data-part="tr"] {
  cursor: pointer;
}

/* ── Striped Variant ──
   Static fallback via nth-child; once the controller stamps data-stripe on the
   visible rows (so hidden rows never break the pattern), the stamped rules win. */
[data-ui="table"][data-variant="striped"] > :where([data-part="table"]) > [data-part="tbody"] > [data-part="tr"]:not([data-stripe]):nth-child(even):not([data-selected]) > [data-part="td"] {
  background: var(--stripe-bg);
}

[data-ui="table"][data-variant="striped"] > :where([data-part="table"]) > [data-part="tbody"] > [data-part="tr"]:not([data-stripe]):nth-child(even):not([data-selected]):hover > [data-part="td"] {
  background: var(--stripe-bg);
}

[data-ui="table"][data-variant="striped"] > :where([data-part="table"]) > [data-part="tbody"] > [data-part="tr"][data-stripe="even"]:not([data-selected]) > [data-part="td"] {
  background: var(--stripe-bg);
}

[data-ui="table"][data-variant="striped"] > :where([data-part="table"]) > [data-part="tbody"] > [data-part="tr"][data-stripe="even"]:not([data-selected]):hover > [data-part="td"] {
  background: var(--stripe-bg);
}

/* ── Bordered Variant ── */
[data-ui="table"][data-variant="bordered"] > [data-part="table"] {
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-md, 0.375rem);
  overflow: hidden;
}

[data-ui="table"][data-variant="bordered"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="th"],
[data-ui="table"][data-variant="bordered"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="td"] {
  border: var(--border-width) solid var(--color-border);
}

/* ── Size: Small ── */
[data-ui="table"][data-size="sm"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="th"] {
  padding: var(--space-2) var(--space-2);
  font-size: var(--text-xs);
}

[data-ui="table"][data-size="sm"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="td"] {
  padding: var(--space-2) var(--space-2);
  font-size: var(--text-xs);
}

/* ── Size: Large ── */
[data-ui="table"][data-size="lg"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="th"] {
  padding: var(--space-4) var(--space-4);
  font-size: var(--text-sm);
}

[data-ui="table"][data-size="lg"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="td"] {
  padding: var(--space-4) var(--space-4);
  font-size: var(--text-sm);
}

/* ── Footer ── */
[data-ui="table"] > :where([data-part="table"]) > [data-part="tfoot"] > :where(tr) > [data-part="td"] {
  font-weight: var(--doc-table-footer-weight, var(--weight-semibold));
  border-top: var(--border-width-strong) solid var(--color-border);
  border-bottom: none;
  background: var(--doc-table-footer-bg, var(--color-bg-subtle, oklch(0.97 0.004 260)));
}

/* ── Cell Alignment ── */
[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-align="left"] {
  text-align: start;
}

[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-align="center"] {
  text-align: center;
}

[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-align="right"] {
  text-align: end;
}

/* ── Number Formatting ── */
[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-format="number"],
[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-format="currency"],
[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-format="percent"] {
  text-align: end;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum";
}

/* Accounting negatives (controller stamps data-negative on numeric cells). */
[data-ui="table"][data-negatives="red"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-negative],
[data-ui="table"][data-negatives="both"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-negative] {
  color: var(--color-destructive);
}

/* ── Grouped Rows ── */
[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > [data-part="group-header"] > td,
[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > [data-part="group-header"] > [data-part="td"] {
  font-weight: var(--weight-semibold);
  background: var(--color-bg-subtle, oklch(0.97 0.004 260));
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--color-fg-muted);
}

[data-ui="table"][data-groupable] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > [data-part="group-header"] {
  cursor: pointer;
  user-select: none;
}

/* ── Expanders (tree rows, group headers) & detail-row toggles ── */
[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > :where(th, td) > [data-part="expander"],
[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > :where(th, td) > [data-part="row-toggle"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: var(--space-5);
  block-size: var(--space-5);
  margin-inline-end: var(--space-1);
  padding: 0;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--color-fg-muted);
  cursor: pointer;
  vertical-align: middle;
}

[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > :where(th, td) > button[data-part="expander"]:hover,
[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > :where(th, td) > [data-part="row-toggle"]:hover {
  background: var(--color-bg-muted, oklch(0.94 0.004 260));
  color: var(--color-fg);
}

[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > :where(th, td) > [data-part="expander"]::before,
[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > :where(th, td) > [data-part="row-toggle"]::before {
  content: "";
  width: 0;
  height: 0;
  border-block-start: 4px solid transparent;
  border-block-end: 4px solid transparent;
  border-inline-start: 5px solid currentColor;
  transition: transform var(--duration-fast) var(--ease-default);
}

[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > :where(th, td) > [data-part="expander"][aria-expanded="true"]::before,
[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > :where(th, td) > [data-part="row-toggle"][aria-expanded="true"]::before {
  transform: rotate(90deg);
}

[dir="rtl"] [data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > :where(th, td) > [data-part="expander"][aria-expanded="true"]::before,
[dir="rtl"] [data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > :where(th, td) > [data-part="row-toggle"][aria-expanded="true"]::before {
  transform: rotate(-90deg);
}

/* Leaf placeholder keeps tree columns aligned without a control. */
[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > :where(th, td) > [data-part="expander"][data-leaf] {
  visibility: hidden;
  cursor: default;
}

/* ── Tree Indentation ── */
[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="td"][data-tree-cell] {
  padding-inline-start: calc(var(--space-4) + var(--table-level, 0) * var(--table-indent, var(--space-5)));
}

/* ── Detail Rows (master/detail) ── */
[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > [data-part="detail-row"] > [data-part="td"],
[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > [data-part="detail-row"] > td {
  background: var(--color-bg-subtle, oklch(0.97 0.004 260));
  font-size: var(--text-xs);
  color: var(--color-fg-muted);
}

/* ── Empty State Row ── */
[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > [data-part="empty"] > [data-part="td"],
[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > [data-part="empty"] > td {
  padding: var(--space-8) var(--space-4);
  text-align: center;
  color: var(--color-fg-muted);
}

/* ── Filter Row & Filter Inputs ── */
[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > [data-part="filter-row"] > [data-part="td"],
[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > [data-part="filter-row"] > [data-part="th"] {
  padding: var(--space-1) var(--space-2);
  background: var(--color-bg);
  border-bottom: var(--border-width) solid var(--color-border);
}

[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > :where(th, td) > [data-part="filter-input"],
[data-ui="table"] > [data-part="filter"],
[data-ui="table"] > :where(div:not([data-ui]), [data-ui="stack"], [data-ui="cluster"]) > [data-part="filter"] {
  inline-size: 100%;
  box-sizing: border-box;
  padding: var(--space-1) var(--space-2);
  font-family: inherit;
  font-size: var(--text-xs);
  color: var(--color-fg);
  background: var(--color-bg);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-sm);
}

[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > :where(th, td) > [data-part="filter-input"]:focus,
[data-ui="table"] > [data-part="filter"]:focus,
[data-ui="table"] > :where(div:not([data-ui]), [data-ui="stack"], [data-ui="cluster"]) > [data-part="filter"]:focus {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  outline-offset: calc(-1 * var(--border-width));
  border-color: var(--color-primary);
}

/* ── Inline Editing ── */
[data-ui="table"][data-editable] > :where([data-part="table"]) > [data-part="tbody"] > :where(tr) > [data-part="td"]:not([data-readonly]):hover {
  cursor: cell;
}

[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="td"][data-editing] {
  padding: var(--space-1) var(--space-1);
}

[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > :where(th, td) > [data-part="cell-input"] {
  inline-size: 100%;
  box-sizing: border-box;
  padding: var(--space-1) var(--space-2);
  font: inherit;
  text-align: inherit;
  color: var(--color-fg);
  background: var(--color-bg);
  border: var(--border-width) solid var(--color-primary);
  border-radius: var(--radius-sm);
  outline: none;
}

[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > :where(th, td) > [data-part="cell-input"][data-invalid] {
  border-color: var(--color-destructive);
  background: var(--color-destructive-subtle, oklch(0.97 0.02 25));
}

/* ── Drag & Drop: rows and columns ── */
[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > :where(th, td) > [data-part="drag-handle"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: var(--space-5);
  block-size: var(--space-5);
  padding: 0;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--color-fg-subtle);
  cursor: grab;
  touch-action: none;
  user-select: none;
  vertical-align: middle;
}

[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > :where(th, td) > [data-part="drag-handle"]::before {
  content: "⠿";
  font-size: var(--text-sm);
  line-height: 1;
}

[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > :where(th, td) > [data-part="drag-handle"]:hover {
  background: var(--color-bg-muted, oklch(0.94 0.004 260));
  color: var(--color-fg);
}

[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > :where(th, td) > [data-part="drag-handle"]:active {
  cursor: grabbing;
}

[data-ui="table"]:has(> :where([data-part="table"]) > :where(thead, tbody, tfoot) > [data-dragging], > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-dragging]) {
  user-select: none;
}

[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > [data-part="tr"][data-dragging] > [data-part="td"] {
  opacity: 0.5;
  background: var(--color-bg-muted, oklch(0.94 0.004 260));
}

[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > [data-part="tr"][data-drop-target][data-drop-pos="before"] > [data-part="td"] {
  border-block-start: var(--border-width-strong) solid var(--color-primary);
}

[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > [data-part="tr"][data-drop-target][data-drop-pos="after"] > [data-part="td"] {
  border-block-end: var(--border-width-strong) solid var(--color-primary);
}

[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="th"][data-dragging] {
  opacity: 0.5;
}

[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="th"][data-drop-target][data-drop-pos="before"] {
  border-inline-start: var(--border-width-strong) solid var(--color-primary);
}

[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="th"][data-drop-target][data-drop-pos="after"] {
  border-inline-end: var(--border-width-strong) solid var(--color-primary);
}

/* ── Column Resize Handles (injected by the controller) ── */
[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > :where(th, td) > [data-part="resize-handle"] {
  position: absolute;
  inset-block: 0;
  inset-inline-end: 0;
  inline-size: var(--space-2);
  cursor: col-resize;
  touch-action: none;
  user-select: none;
  z-index: 1;
}

[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > :where(th, td) > [data-part="resize-handle"]::before {
  content: "";
  position: absolute;
  inset-block: var(--space-1);
  inset-inline-end: var(--space-0h);
  inline-size: var(--space-0h);
  border-radius: var(--radius-full);
  background: transparent;
  transition: background var(--duration-fast) var(--ease-default);
}

[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > :where(th, td) > [data-part="resize-handle"]:hover::before {
  background: var(--color-primary);
}

/* ── Sticky Header / Footer ── */
[data-ui="table"][data-sticky-header] > :where([data-part="table"]) > [data-part="thead"] {
  position: sticky;
  inset-block-start: 0;
  z-index: 3;
  background: var(--color-bg);
}

[data-ui="table"][data-sticky-footer] > :where([data-part="table"]) > [data-part="tfoot"] {
  position: sticky;
  inset-block-end: 0;
  z-index: 3;
  background: var(--doc-table-footer-bg, var(--color-bg-subtle, oklch(0.97 0.004 260)));
}

/* Pinned rows stick just below the header; --table-thead-h is measured by the controller. */
[data-ui="table"] > :where([data-part="table"]) > [data-part="tbody"] > [data-part="tr"][data-pin="top"] > [data-part="td"] {
  position: sticky;
  inset-block-start: var(--table-thead-h, 0px);
  z-index: 2;
  background: var(--color-bg-subtle, oklch(0.97 0.004 260));
}

/* ── Pinned (sticky) Columns ── */
[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="td"][data-pin="start"],
[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="th"][data-pin="start"] {
  position: sticky;
  inset-inline-start: var(--table-pin-offset, 0px);
  z-index: 1;
}

[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="td"][data-pin="end"],
[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="th"][data-pin="end"] {
  position: sticky;
  inset-inline-end: var(--table-pin-offset, 0px);
  z-index: 1;
}

[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="th"][data-pin] {
  z-index: 4;
}

[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-pin="start"][data-pin-edge] {
  border-inline-end: var(--border-width) solid var(--color-border-strong, oklch(0.85 0.006 260));
}

[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-pin="end"][data-pin-edge] {
  border-inline-start: var(--border-width) solid var(--color-border-strong, oklch(0.85 0.006 260));
}

/* ── Column Visibility ── */
[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-col-hidden] {
  display: none;
}

/* ── Responsive: priority column hiding (needs data-responsive on the root) ──
   Mobile-first on the breakpoint canon (task 0.8-08, src/utils/breakpoints.ts).
   A prioritised column is hidden by default and *revealed* from its tier up, so
   every prelude is a `min-width` floor — the 1.x sheet used three `max-width`
   ceilings on a private ladder where `sm` meant 30rem, half a tier below the
   canon's 40rem.

   Three specificity facts hold this together, and the suite pins all three:
     · the base hide carries `[data-responsive]` (0,3,0) because nothing scopes
       it otherwise — the reveals do not need it, since `faqir-table` is only a
       container on a responsive root, so an unnamed-container miss already
       makes them inert;
     · each reveal is (0,3,0) too and sits *before* the stacked-mode block, so
       stacked mode still wins and card rows keep every column — the 1.x
       behaviour, preserved deliberately;
     · `:not([data-col-hidden])` keeps a column the controller hid from being
       revealed by a widening container. */
[data-ui="table"][data-responsive] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-hide-below] {
  display: none;
}

@container faqir-table (min-width: 40rem) {
  [data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-hide-below="sm"]:not([data-col-hidden]) {
    display: revert;
  }
}

@container faqir-table (min-width: 48rem) {
  [data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-hide-below="md"]:not([data-col-hidden]) {
    display: revert;
  }
}

@container faqir-table (min-width: 64rem) {
  [data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-hide-below="lg"]:not([data-col-hidden]) {
    display: revert;
  }
}

/* ── Responsive: stacked card mode ──
   The controller toggles data-stacked below the data-stack-below breakpoint;
   authors can also set data-stacked directly to force the layout. */
[data-ui="table"][data-stacked] > [data-part="table"],
[data-ui="table"][data-stacked] > :where([data-part="table"]) > [data-part="tbody"],
[data-ui="table"][data-stacked] > :where([data-part="table"]) > [data-part="tfoot"] {
  display: block;
}

[data-ui="table"][data-stacked] > :where([data-part="table"]) > [data-part="thead"] {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

[data-ui="table"][data-stacked] > :where([data-part="table"]) > [data-part="tbody"] > [data-part="tr"],
[data-ui="table"][data-stacked] > :where([data-part="table"]) > [data-part="tbody"] > [data-part="group-header"],
[data-ui="table"][data-stacked] > :where([data-part="table"]) > [data-part="tbody"] > [data-part="detail-row"],
[data-ui="table"][data-stacked] > :where([data-part="table"]) > [data-part="tbody"] > [data-part="empty"],
[data-ui="table"][data-stacked] > :where([data-part="table"]) > [data-part="tfoot"] > [data-part="tr"] {
  display: block;
  margin-block-end: var(--space-3);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-bg);
  overflow: hidden;
}

[data-ui="table"][data-stacked] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="td"],
[data-ui="table"][data-stacked] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > [data-part="group-header"] > td {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--space-4);
  text-align: end;
  border-bottom: none;
  border-block-end: var(--border-width) solid var(--color-border);
}

[data-ui="table"][data-stacked] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > [data-part="tr"] > [data-part="td"]:last-child,
[data-ui="table"][data-stacked] > :where([data-part="table"]) > [data-part="tfoot"] > :where(tr) > [data-part="td"]:last-child {
  border-block-end: none;
}

[data-ui="table"][data-stacked] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="td"]::before {
  content: attr(data-label);
  flex-shrink: 0;
  font-weight: var(--weight-semibold);
  color: var(--color-fg-muted);
  text-align: start;
}

[data-ui="table"][data-stacked] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="td"][data-tree-cell] {
  padding-inline-start: calc(var(--space-4) + var(--table-level, 0) * var(--table-indent, var(--space-5)));
}

[data-ui="table"][data-stacked] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > [data-pin],
[data-ui="table"][data-stacked] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-pin] {
  position: static;
}

/* ── Hidden rows (collapse, filter, [hidden]) — last so they beat layout modes ── */
[data-ui="table"] > :where([data-part="table"]) > [data-part="tbody"] > tr[data-part][data-collapsed],
[data-ui="table"] > :where([data-part="table"]) > [data-part="tbody"] > tr[data-part][data-filtered],
[data-ui="table"] > :where([data-part="table"]) > [data-part] > tr[data-part][hidden],
[data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > tr[data-part][hidden] {
  display: none;
}

/* ── Print: Compact ── */
@media print {
  [data-ui="table"][data-print="compact"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="th"] {
    padding: var(--space-1, 0.25rem) var(--space-2);
    font-size: var(--doc-table-font-size, var(--text-xs));
  }

  [data-ui="table"][data-print="compact"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="td"] {
    padding: var(--space-1, 0.25rem) var(--space-2);
    font-size: var(--doc-table-font-size, var(--text-xs));
  }

  [data-ui="table"] > [data-part="table"] {
    break-inside: auto;
  }

  [data-ui="table"] > :where([data-part="table"]) > [data-part="thead"] {
    display: table-header-group;
    position: static;
  }

  [data-ui="table"] > :where([data-part="table"]) > [data-part="tfoot"] {
    display: table-footer-group;
    position: static;
  }

  /* The thead above repeats on every printed page, and so does a
     table-footer-group. data-print-footer="last" prints the footer once, after
     the last row: an invoice's total on its last page only. */
  [data-ui="table"][data-print-footer="last"] > :where([data-part="table"]) > [data-part="tfoot"] {
    display: table-row-group;
  }

  [data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > [data-part="tr"] {
    break-inside: avoid;
  }

  [data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="th"],
  [data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="td"] {
    border-color: var(--doc-print-border-color, var(--color-border));
    position: static;
  }

  [data-ui="table"][data-sticky-header],
  [data-ui="table"][data-sticky-footer] {
    overflow: visible;
    max-block-size: none;
  }

  [data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > :where(th, td) > [data-part="drag-handle"],
  [data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > :where(th, td) > [data-part="resize-handle"],
  [data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > [data-part="filter-row"],
  [data-ui="table"] > [data-part="filter"],
  [data-ui="table"] > :where(div:not([data-ui]), [data-ui="stack"], [data-ui="cluster"]) > [data-part="filter"],
  [data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > :where(th, td) > [data-part="expander"],
  [data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > :where(th, td) > [data-part="row-toggle"] {
    display: none;
  }
}

/* ── Motion ── */
@media (prefers-reduced-motion: reduce) {
  [data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="th"],
  [data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > [data-part="td"],
  [data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > :where(th, td) > [data-part="expander"]::before,
  [data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > :where(th, td) > [data-part="row-toggle"]::before,
  [data-ui="table"] > :where([data-part="table"]) > :where(thead, tbody, tfoot) > :where(tr) > :where(th, td) > [data-part="resize-handle"]::before {
    transition: none;
  }
}


/* === recipes/tabs.css === */
/* @ui:component tabs */
/* @ui:tokens color-bg color-fg color-fg-muted color-border color-primary color-border-strong color-bg-muted space-1 space-2 space-3 space-4 space-6 radius-md radius-lg text-sm text-base text-xs weight-medium duration-fast ease-default font-ui border-width border-width-strong focus-ring-width focus-ring-style focus-ring-color focus-ring-offset shadow-xs */

/* ── Root ── */
[data-ui="tabs"] {
  width: 100%;
}

/* Parts are reached by child combinators, never descendant ones: a component
   nested in a panel — a collapsible, a dropdown, more tabs — has a `trigger`
   of its own, and a descendant rule here laid it out as a tab. The `list` hop
   sits in `:where()` so every rule keeps the specificity that pattern
   overrides (`settings-page`) are written against. [1.1F-20] */

/* ── Tab List ── */
/* The row WRAPS. Triggers are `white-space: nowrap` (a tab label that breaks
   mid-word is worse than a second row), so an unwrapped list is as wide as its
   labels: four tabs pushed a 320px phone 69px past its own window, and every
   page that composes tabs — `settings-page` most of all — inherited that. A
   horizontal scroller would keep them reachable, but reachable-by-gesture is
   not visible, and a settings page must not hide a section behind a swipe. [W3-3] */
[data-ui="tabs"] > [data-part="list"] {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
}

/* ── Tab Trigger (base) ── */
[data-ui="tabs"] > :where([data-part="list"]) > [data-part="trigger"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: var(--space-2) var(--space-4);
  border: none;
  background: transparent;
  color: var(--color-fg-muted);
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  cursor: pointer;
  white-space: nowrap;
  transition: color var(--duration-fast) var(--ease-default),
              background var(--duration-fast) var(--ease-default),
              border-color var(--duration-fast) var(--ease-default);
}

[data-ui="tabs"] > :where([data-part="list"]) > [data-part="trigger"]:hover {
  color: var(--color-fg);
}

[data-ui="tabs"] > :where([data-part="list"]) > [data-part="trigger"]:focus-visible {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  outline-offset: calc(-1 * var(--focus-ring-offset));
  border-radius: var(--radius-md);
}

[data-ui="tabs"] > :where([data-part="list"]) > [data-part="trigger"][aria-selected="true"] {
  color: var(--color-primary);
}

/* ── Underline Variant ── */
[data-ui="tabs"][data-variant="underline"] > [data-part="list"] {
  border-bottom: var(--border-width) solid var(--color-border);
  gap: 0;
}

[data-ui="tabs"][data-variant="underline"] > :where([data-part="list"]) > [data-part="trigger"] {
  border-bottom: var(--border-width-strong) solid transparent;
  margin-bottom: -1px;
  border-radius: 0;
}

[data-ui="tabs"][data-variant="underline"] > :where([data-part="list"]) > [data-part="trigger"][aria-selected="true"] {
  border-bottom-color: var(--color-primary);
}

[data-ui="tabs"][data-variant="underline"] > :where([data-part="list"]) > [data-part="trigger"]:hover {
  border-bottom-color: var(--color-border-strong, var(--color-border));
}

[data-ui="tabs"][data-variant="underline"] > :where([data-part="list"]) > [data-part="trigger"][aria-selected="true"]:hover {
  border-bottom-color: var(--color-primary);
}

/* ── Pill Variant ── */
[data-ui="tabs"][data-variant="pill"] > [data-part="list"] {
  background: var(--color-bg-muted, oklch(0.96 0.004 260));
  border-radius: var(--radius-lg);
  padding: var(--space-1);
}

[data-ui="tabs"][data-variant="pill"] > :where([data-part="list"]) > [data-part="trigger"] {
  border-radius: var(--radius-md);
  padding: var(--space-1) var(--space-3);
}

[data-ui="tabs"][data-variant="pill"] > :where([data-part="list"]) > [data-part="trigger"][aria-selected="true"] {
  background: var(--color-bg);
  color: var(--color-fg);
  box-shadow: var(--shadow-xs);
}

/* ── Enclosed Variant ── */
[data-ui="tabs"][data-variant="enclosed"] > [data-part="list"] {
  border-bottom: var(--border-width) solid var(--color-border);
  gap: 0;
}

[data-ui="tabs"][data-variant="enclosed"] > :where([data-part="list"]) > [data-part="trigger"] {
  border: var(--border-width) solid transparent;
  border-bottom: none;
  border-radius: var(--radius-md) var(--radius-md) 0 0;
  margin-bottom: -1px;
}

[data-ui="tabs"][data-variant="enclosed"] > :where([data-part="list"]) > [data-part="trigger"][aria-selected="true"] {
  background: var(--color-bg);
  border-color: var(--color-border);
  color: var(--color-fg);
}

/* ── Size Variants ── */
[data-ui="tabs"][data-size="sm"] > :where([data-part="list"]) > [data-part="trigger"] {
  padding: var(--space-1) var(--space-3);
  font-size: var(--text-xs, 0.75rem);
}

[data-ui="tabs"][data-size="lg"] > :where([data-part="list"]) > [data-part="trigger"] {
  padding: var(--space-3) var(--space-6, 1.5rem);
  font-size: var(--text-base);
}

/* ── Panel ── */
[data-ui="tabs"] > [data-part="panel"] {
  padding: var(--space-4);
  color: var(--color-fg);
}

/* ── Motion ── */
@media (prefers-reduced-motion: reduce) {
  [data-ui="tabs"] > :where([data-part="list"]) > [data-part="trigger"] {
    transition: none;
  }
}

/* ── Forced colors (Windows High Contrast) ──
   Selection is carried by colour alone in three of the four variants — a
   `--color-primary` label, a `--color-bg` pill, a `--color-bg` panel — and the
   OS replaces all three with the same system colour, so which tab was selected
   became unreadable. The underline variant already uses a border, which the OS
   keeps; the others get one. [W3-3] */
@media (forced-colors: active) {
  [data-ui="tabs"] > :where([data-part="list"]) > [data-part="trigger"][aria-selected="true"] {
    /* An outline the OS preserves, on every variant. */
    outline: var(--border-width-strong) solid Highlight;
    outline-offset: calc(-1 * var(--border-width-strong));
  }

  [data-ui="tabs"][data-variant="underline"] > :where([data-part="list"]) > [data-part="trigger"][aria-selected="true"] {
    border-bottom-color: Highlight;
  }

  [data-ui="tabs"] > :where([data-part="list"]) > [data-part="trigger"]:disabled,
  [data-ui="tabs"] > :where([data-part="list"]) > [data-part="trigger"][aria-disabled="true"] {
    color: GrayText;
  }
}


/* === recipes/tag-input.css === */
/* @ui:component tag-input */
/* @ui:tokens color-bg color-fg color-fg-muted color-border color-primary-subtle radius-md radius-lg shadow-md space-1 space-1h space-2 space-3 text-sm z-dropdown duration-fast ease-default font-ui border-width focus-ring-color focus-ring-width */

/* NOTE: the tags themselves are `data-ui="chip"` elements — their styling comes
   entirely from chip.css. This file styles only the field wrapper, the tag row,
   the text input, and the suggestions listbox. No chip styles are redefined. */

/* ── Root ── */
[data-ui="tag-input"] {
  position: relative;
  display: block;
  width: 100%;
}

/* ── Tag row: the chips + the text input share one field-like box ── */
[data-ui="tag-input"] > [data-part="taglist"] {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-1h);
  width: 100%;
  padding: var(--space-1h) var(--space-2);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-bg);
  list-style: none;
  transition: border-color var(--duration-fast) var(--ease-default),
              box-shadow var(--duration-fast) var(--ease-default);
}

[data-ui="tag-input"] > [data-part="taglist"]:focus-within {
  border-color: var(--focus-ring-color);
  box-shadow: 0 0 0 var(--focus-ring-width) var(--focus-ring-color);
}

/* ── Text input: borderless, grows to fill the remaining row space ── */
[data-ui="tag-input"] > :where([data-part="taglist"]) > [data-part="input"] {
  flex: 1 1 6ch;
  min-width: 6ch;
  padding: var(--space-1) 0;
  border: none;
  background: transparent;
  color: var(--color-fg);
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  line-height: 1.5;
  outline: none;
}

[data-ui="tag-input"] > :where([data-part="taglist"]) > [data-part="input"]::placeholder {
  color: var(--color-fg-muted);
}

/* ── Suggestions listbox (mirrors the combobox listbox contract) ── */
[data-ui="tag-input"] > [data-part="listbox"] {
  position: absolute;
  top: 100%;
  inset-inline-start: 0;
  inset-inline-end: 0;
  z-index: var(--z-dropdown);
  margin-top: var(--space-1);
  padding: var(--space-1);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-bg);
  box-shadow: var(--shadow-md);
  max-height: 240px;
  overflow-y: auto;
  list-style: none;
}

[data-ui="tag-input"] > :where([data-part="listbox"]) > [data-part="option"] {
  display: flex;
  align-items: center;
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-md);
  color: var(--color-fg);
  font-size: var(--text-sm);
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--duration-fast) var(--ease-default);
}

[data-ui="tag-input"] > :where([data-part="listbox"]) > [data-part="option"]:hover,
[data-ui="tag-input"] > :where([data-part="listbox"]) > [data-part="option"][data-highlighted] {
  background: var(--color-primary-subtle, oklch(0.96 0.04 264));
}

[data-ui="tag-input"] > :where([data-part="listbox"]) > [data-part="option"][data-hidden] {
  display: none;
}

[data-ui="tag-input"] > :where([data-part="listbox"]) > [data-part="empty"] {
  padding: var(--space-2) var(--space-3);
  color: var(--color-fg-muted);
  font-size: var(--text-sm);
  text-align: center;
}

/* ── Motion ── */
@media (prefers-reduced-motion: reduce) {
  [data-ui="tag-input"] > [data-part="taglist"],
  [data-ui="tag-input"] > :where([data-part="listbox"]) > [data-part="option"] {
    transition: none;
  }
}


/* === recipes/toast.css === */
/* @ui:component toast */
/* @ui:tokens color-bg color-fg color-fg-muted color-border color-success color-destructive color-warning color-bg-muted panel-bg shadow-lg radius-lg radius-md space-2 space-3 space-4 space-1 text-sm text-xs weight-medium z-toast duration-normal ease-out font-ui border-width border-width-lg focus-ring-width focus-ring-style focus-ring-color focus-ring-offset surface-backdrop */

/* ── Container ── */
[data-ui="toast"][data-part="container"] {
  position: fixed;
  z-index: var(--z-toast, 9999);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  pointer-events: none;
  max-width: 100vw;
  padding: var(--space-4);
}

/* ── Position Variants ── */
[data-ui="toast"][data-variant="top-right"] {
  top: 0;
  inset-inline-end: 0;
  align-items: flex-end;
}

[data-ui="toast"][data-variant="top-left"] {
  top: 0;
  inset-inline-start: 0;
  align-items: flex-start;
}

[data-ui="toast"][data-variant="bottom-right"] {
  bottom: 0;
  inset-inline-end: 0;
  align-items: flex-end;
  flex-direction: column-reverse;
}

[data-ui="toast"][data-variant="bottom-left"] {
  bottom: 0;
  inset-inline-start: 0;
  align-items: flex-start;
  flex-direction: column-reverse;
}

/* ── Individual Toast ── */
[data-ui="toast"] > [data-part="toast"] {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  /* Never wider than the container: on a phone 380px is wider than the screen. */
  max-width: min(380px, 100%);
  width: max-content;
  padding: var(--space-3) var(--space-4);
  background: var(--panel-bg);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  pointer-events: auto;
  opacity: 1;
  transform: translateY(0);
  transition: opacity var(--duration-normal) var(--ease-out),
              transform var(--duration-normal) var(--ease-out);
}

@supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
  [data-ui="toast"] > [data-part="toast"] {
    -webkit-backdrop-filter: var(--surface-backdrop);
    backdrop-filter: var(--surface-backdrop);
  }
}

/* ── State: Entering ── */
[data-ui="toast"][data-variant="top-right"] > [data-part="toast"][data-state="entering"],
[data-ui="toast"][data-variant="top-left"] > [data-part="toast"][data-state="entering"] {
  opacity: 0;
  transform: translateY(-16px);
}

[data-ui="toast"][data-variant="bottom-right"] > [data-part="toast"][data-state="entering"],
[data-ui="toast"][data-variant="bottom-left"] > [data-part="toast"][data-state="entering"] {
  opacity: 0;
  transform: translateY(16px);
}

/* ── State: Visible ── */
[data-ui="toast"] > [data-part="toast"][data-state="visible"] {
  opacity: 1;
  transform: translateY(0);
}

/* ── State: Exiting ── */
[data-ui="toast"][data-variant="top-right"] > [data-part="toast"][data-state="exiting"],
[data-ui="toast"][data-variant="top-left"] > [data-part="toast"][data-state="exiting"] {
  opacity: 0;
  transform: translateX(16px);
}

[data-ui="toast"][data-variant="bottom-right"] > [data-part="toast"][data-state="exiting"],
[data-ui="toast"][data-variant="bottom-left"] > [data-part="toast"][data-state="exiting"] {
  opacity: 0;
  transform: translateX(16px);
}

[data-ui="toast"][data-variant="top-left"] > [data-part="toast"][data-state="exiting"],
[data-ui="toast"][data-variant="bottom-left"] > [data-part="toast"][data-state="exiting"] {
  transform: translateX(-16px);
}

/* ── Tone Variants ── */
[data-ui="toast"] > [data-part="toast"][data-variant="success"] {
  border-inline-start: var(--border-width-lg) solid var(--color-success, oklch(0.55 0.18 145));
}

[data-ui="toast"] > [data-part="toast"][data-variant="success"] > [data-part="icon"] {
  color: var(--color-success, oklch(0.55 0.18 145));
}

[data-ui="toast"] > [data-part="toast"][data-variant="error"] {
  border-inline-start: var(--border-width-lg) solid var(--color-destructive, oklch(0.55 0.22 25));
}

[data-ui="toast"] > [data-part="toast"][data-variant="error"] > [data-part="icon"] {
  color: var(--color-destructive, oklch(0.55 0.22 25));
}

[data-ui="toast"] > [data-part="toast"][data-variant="warning"] {
  border-inline-start: var(--border-width-lg) solid var(--color-warning, oklch(0.7 0.18 85));
}

[data-ui="toast"] > [data-part="toast"][data-variant="warning"] > [data-part="icon"] {
  color: var(--color-warning, oklch(0.7 0.18 85));
}

/* ── Icon ── */
[data-ui="toast"] > :where([data-part="toast"]) > [data-part="icon"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  font-size: var(--text-sm);
  color: var(--color-fg-muted);
}

/* ── Message ── */
[data-ui="toast"] > :where([data-part="toast"]) > [data-part="message"] {
  flex: 1;
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--color-fg);
  line-height: 1.4;
}

/* ── Action Button ── */
[data-ui="toast"] > :where([data-part="toast"]) > [data-part="action"] {
  flex-shrink: 0;
  padding: var(--space-1, 0.25rem) var(--space-2);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-md, 0.375rem);
  background: transparent;
  color: var(--color-fg);
  font-family: var(--font-ui);
  font-size: var(--text-xs, 0.75rem);
  font-weight: var(--weight-medium);
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--duration-normal) var(--ease-out);
}

[data-ui="toast"] > :where([data-part="toast"]) > [data-part="action"]:hover {
  background: var(--color-bg-muted, oklch(0.96 0.004 260));
}

[data-ui="toast"] > :where([data-part="toast"]) > [data-part="action"]:focus-visible {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  outline-offset: var(--focus-ring-offset);
}

/* ── Close Button ── */
[data-ui="toast"] > :where([data-part="toast"]) > [data-part="close"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 24px;
  height: 24px;
  padding: 0;
  border: none;
  border-radius: var(--radius-md, 0.375rem);
  background: transparent;
  color: var(--color-fg-muted);
  font-size: var(--text-xs, 0.75rem);
  cursor: pointer;
}

[data-ui="toast"] > :where([data-part="toast"]) > [data-part="close"]:hover {
  background: var(--color-bg-muted, oklch(0.96 0.004 260));
  color: var(--color-fg);
}

[data-ui="toast"] > :where([data-part="toast"]) > [data-part="close"]:focus-visible {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  outline-offset: var(--focus-ring-offset);
}

/* ── Motion ── */
@media (prefers-reduced-motion: reduce) {
  [data-ui="toast"] > [data-part="toast"],
  [data-ui="toast"] > :where([data-part="toast"]) > [data-part="action"] {
    transition: none;
  }
}


/* === recipes/toggle-group.css === */
/* @ui:component toggle-group */
/* @ui:tokens color-bg color-bg-muted color-fg color-fg-muted color-border color-primary color-primary-subtle color-ring radius-md space-1 space-1h space-3 text-sm font-ui weight-medium weight-semibold duration-fast duration-normal ease-default ease-emphasized border-width focus-ring-width focus-ring-style focus-ring-color focus-ring-offset disabled-opacity button-radius shadow-sm */

/* ── Root: a segmented row of toggle buttons ── */
[data-ui="toggle-group"] {
  display: inline-flex;
  gap: var(--space-1);
  padding: var(--space-1);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-bg);
}

/* ── Item: the visible "button" (a <label> wrapping the native control) ── */
[data-ui="toggle-group"] > [data-part="item"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-1h);
  padding: var(--toggle-group-pad-y, var(--space-1h)) var(--toggle-group-pad-x, var(--space-3));
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--color-fg-muted);
  font-family: var(--toggle-group-font, var(--font-ui));
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  line-height: 1;
  cursor: pointer;
  user-select: none;
  transition: background var(--duration-fast) var(--ease-default),
              color var(--duration-fast) var(--ease-default);
}

[data-ui="toggle-group"] > [data-part="item"]:hover {
  background: var(--color-bg-muted);
  color: var(--color-fg);
}

/* ── The native control is the accessible, focusable element; hide it visually
      but keep it operable (no display:none, which would drop it from the a11y
      tree and disable focus). ── */
[data-ui="toggle-group"] > :where([data-part="item"]) > [data-part="control"] {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

/* ── Checked / on — driven off the native control's state (and the mirrored
      data-state for engines/tools that key on it). Two rules, not one list:
      `:has()` is unforgiving, so in an engine without it a shared list would
      drop the data-state branch too and nothing would ever look pressed. ── */
[data-ui="toggle-group"] > [data-part="item"]:has(> [data-part="control"]:checked) {
  background: var(--color-primary-subtle);
  color: var(--color-primary);
}

[data-ui="toggle-group"] > [data-part="item"][data-state="on"] {
  background: var(--color-primary-subtle);
  color: var(--color-primary);
}

/* ── Keyboard focus ring on the item (focus lives on the hidden control) ── */
[data-ui="toggle-group"] > [data-part="item"]:has(> [data-part="control"]:focus-visible) {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  outline-offset: var(--focus-ring-offset);
}

/* ── Disabled control ── */
[data-ui="toggle-group"] > [data-part="item"]:has(> [data-part="control"]:disabled) {
  opacity: var(--disabled-opacity);
  cursor: not-allowed;
}

/* ── Variant: segmented ──
   One track, equal-width items and a single thumb that slides under the
   checked one — the monthly/yearly switch of a pricing page. Pure CSS: the
   thumb is the root's ::before, and `:has()` tells it which column to stand
   in, so it works before (and without) the controller, on native radios.

   Single mode only. A thumb is "the one selected value"; in multi mode there
   is no such thing, so a segmented multi group keeps the default look.

   The whole variant sits behind `@supports selector(:has(*))`: an engine that
   cannot count or locate the checked item keeps the default per-item fill
   above, which is still a correct pressed state.

   The queries ask about the native input, not the control part: an item
   holds exactly one input (its control), and the root's children are its
   items, so `> :nth-child(n) > input:checked` is a child chain that cannot
   reach into a nested component. */
@supports selector(:has(*)) {
  [data-ui="toggle-group"][data-variant="segmented"]:not([data-mode="multi"]) {
    --faqir-tg-count: 1;
    --faqir-tg-index: 0;
    --faqir-tg-dir: 1;
    --faqir-tg-inset: var(--space-1);
    position: relative;
    isolation: isolate;
    display: inline-grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    gap: 0;
    padding: var(--faqir-tg-inset);
    border-radius: var(--button-radius);
    background: var(--toggle-group-track-bg, var(--color-bg-muted));
  }

  /* The thumb: one column wide, inset by the track's padding, concentric with
     the track's corners (a pill stays a pill, a square stays square). It is
     decoration — the checked state is the radio's, and the label says it. */
  [data-ui="toggle-group"][data-variant="segmented"]:not([data-mode="multi"])::before {
    content: "";
    position: absolute;
    z-index: -1;
    inset-block: var(--faqir-tg-inset);
    inset-inline-start: var(--faqir-tg-inset);
    inline-size: calc((100% - 2 * var(--faqir-tg-inset)) / var(--faqir-tg-count));
    border: var(--border-width) solid color-mix(in oklch, var(--color-border) 70%, transparent);
    border-radius: max(0px, calc(var(--button-radius) - var(--faqir-tg-inset)));
    background: var(--toggle-group-thumb-bg, var(--color-bg));
    box-shadow: var(--shadow-sm);
    pointer-events: none;
    translate: calc(var(--faqir-tg-index) * var(--faqir-tg-dir) * 100%) 0;
    transition: translate var(--duration-normal) var(--ease-emphasized);
  }

  /* Right-to-left: the first column is on the right, so the thumb travels
     the other way. */
  [data-ui="toggle-group"][data-variant="segmented"]:not([data-mode="multi"]):dir(rtl) {
    --faqir-tg-dir: -1;
  }

  /* Nothing checked yet: there is nothing to point at. */
  [data-ui="toggle-group"][data-variant="segmented"]:not([data-mode="multi"]):not(:has(> * > input:checked))::before {
    opacity: 0;
  }

  /* How many columns — up to six. */
  [data-ui="toggle-group"][data-variant="segmented"]:not([data-mode="multi"]):has(> :nth-child(2)) { --faqir-tg-count: 2; }
  [data-ui="toggle-group"][data-variant="segmented"]:not([data-mode="multi"]):has(> :nth-child(3)) { --faqir-tg-count: 3; }
  [data-ui="toggle-group"][data-variant="segmented"]:not([data-mode="multi"]):has(> :nth-child(4)) { --faqir-tg-count: 4; }
  [data-ui="toggle-group"][data-variant="segmented"]:not([data-mode="multi"]):has(> :nth-child(5)) { --faqir-tg-count: 5; }
  [data-ui="toggle-group"][data-variant="segmented"]:not([data-mode="multi"]):has(> :nth-child(6)) { --faqir-tg-count: 6; }

  /* Which column is checked. The native :checked state only: a stale
     data-state written into static markup must not move the thumb. */
  [data-ui="toggle-group"][data-variant="segmented"]:not([data-mode="multi"]):has(> :nth-child(2) > input:checked) { --faqir-tg-index: 1; }
  [data-ui="toggle-group"][data-variant="segmented"]:not([data-mode="multi"]):has(> :nth-child(3) > input:checked) { --faqir-tg-index: 2; }
  [data-ui="toggle-group"][data-variant="segmented"]:not([data-mode="multi"]):has(> :nth-child(4) > input:checked) { --faqir-tg-index: 3; }
  [data-ui="toggle-group"][data-variant="segmented"]:not([data-mode="multi"]):has(> :nth-child(5) > input:checked) { --faqir-tg-index: 4; }
  [data-ui="toggle-group"][data-variant="segmented"]:not([data-mode="multi"]):has(> :nth-child(6) > input:checked) { --faqir-tg-index: 5; }

  /* Items: transparent over the track; the thumb is the only fill. Later than
     the default checked rules at equal or higher weight, so neither the
     :checked fill nor a data-state="on" left in static markup paints here. */
  [data-ui="toggle-group"][data-variant="segmented"]:not([data-mode="multi"]) > [data-part="item"],
  [data-ui="toggle-group"][data-variant="segmented"]:not([data-mode="multi"]) > [data-part="item"][data-state="on"] {
    border-radius: max(0px, calc(var(--button-radius) - var(--faqir-tg-inset)));
    background: transparent;
    color: var(--color-fg-muted);
    white-space: nowrap;
  }

  [data-ui="toggle-group"][data-variant="segmented"]:not([data-mode="multi"]) > [data-part="item"]:hover {
    background: transparent;
    color: var(--color-fg);
  }

  /* The checked label reads above the thumb in the strongest ink, and heavier,
     so the choice is never told by a faint thumb fill alone. */
  [data-ui="toggle-group"][data-variant="segmented"]:not([data-mode="multi"]) > [data-part="item"]:has(> input:checked) {
    background: transparent;
    color: var(--color-fg);
    font-weight: var(--weight-semibold);
  }

  /* Seven or more: a thumb a seventh wide would be a lie, so the thumb stands
     down and the checked item wears it in place (still raised, just not
     sliding). */
  [data-ui="toggle-group"][data-variant="segmented"]:not([data-mode="multi"]):has(> :nth-child(7))::before {
    display: none;
  }

  [data-ui="toggle-group"][data-variant="segmented"]:not([data-mode="multi"]):has(> :nth-child(7)) > [data-part="item"]:has(> input:checked) {
    background: var(--toggle-group-thumb-bg, var(--color-bg));
    box-shadow: var(--shadow-sm);
  }
}

/* ── Forced colours ──
   The OS repaints backgrounds and drops shadows, which erases both the
   default fill and the segmented thumb. The checked item takes the system
   selection colours instead, and the thumb stands down. Opting the item out
   of the forced palette also un-forces its focus outline, so the outline is
   handed the system ink explicitly. The segmented selectors repeat at their
   own weight so this block, coming later, wins over them. */
@media (forced-colors: active) {
  [data-ui="toggle-group"] > [data-part="item"]:has(> input:checked),
  [data-ui="toggle-group"][data-variant="segmented"]:not([data-mode="multi"]) > [data-part="item"]:has(> input:checked),
  [data-ui="toggle-group"][data-variant="segmented"]:not([data-mode="multi"]):has(> :nth-child(7)) > [data-part="item"]:has(> input:checked) {
    forced-color-adjust: none;
    background: Highlight;
    color: HighlightText;
    outline-color: CanvasText;
  }

  [data-ui="toggle-group"]::before {
    display: none;
  }
}

/* ── Motion ── */
@media (prefers-reduced-motion: reduce) {
  [data-ui="toggle-group"] > [data-part="item"],
  [data-ui="toggle-group"]::before {
    transition: none;
  }
}

/* The thumb's own selector, at its own specificity: the rule above (0,1,1)
   loses to it (0,3,1), so the thumb would keep sliding. Kept inside the same
   feature query as the thumb it stops. */
@supports selector(:has(*)) {
  @media (prefers-reduced-motion: reduce) {
    [data-ui="toggle-group"][data-variant="segmented"]:not([data-mode="multi"])::before {
      transition: none;
    }
  }
}


/* === recipes/tooltip.css === */
/* @ui:component tooltip */
/* @ui:tokens color-bg color-fg radius-md space-1h space-2 text-xs z-dropdown duration-fast ease-default font-ui surface-backdrop */

/* ── Root ── */
[data-ui="tooltip"] {
  /* A component knob, not a member of the --z-* ladder: a tooltip sits on the
     dropdown layer by default and an author raises just this one by overriding
     here. Declared rather than left to a var() fallback so it always resolves. */
  --z-tooltip: var(--z-dropdown);

  position: relative;
  display: inline-block;
}

/* ── Content ── */
[data-ui="tooltip"] > [data-part="content"] {
  position: absolute;
  z-index: var(--z-tooltip);
  background: var(--color-fg);
  color: var(--color-bg);
  border-radius: var(--radius-md);
  padding: var(--space-1h, 0.375rem) var(--space-2);
  font-family: var(--font-ui);
  font-size: var(--text-xs, 0.75rem);
  line-height: 1.4;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  transform: scale(0.95);
  transition: opacity var(--duration-fast) var(--ease-default),
              transform var(--duration-fast) var(--ease-default);
}

@supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
  [data-ui="tooltip"] > [data-part="content"] {
    -webkit-backdrop-filter: var(--surface-backdrop);
    backdrop-filter: var(--surface-backdrop);
  }
}

/* Default position (top) when no variant is specified */
[data-ui="tooltip"]:not([data-variant]) > [data-part="content"] {
  bottom: 100%;
  inset-inline-start: 50%;
  transform: translateX(-50%) translateY(-4px) scale(0.95);
  margin-bottom: 4px;
}

[data-ui="tooltip"][data-state="visible"] > [data-part="content"] {
  opacity: 1;
  transform: scale(1);
}

[data-ui="tooltip"]:not([data-variant])[data-state="visible"] > [data-part="content"] {
  transform: translateX(-50%) translateY(-4px) scale(1);
}

/* ── Arrow (::before pseudo-element) ── */
[data-ui="tooltip"] > [data-part="content"]::before {
  content: "";
  position: absolute;
  width: 8px;
  height: 8px;
  background: var(--color-fg);
  transform: rotate(45deg);
}

/* Default arrow (top) when no variant */
[data-ui="tooltip"]:not([data-variant]) > [data-part="content"]::before {
  bottom: -4px;
  inset-inline-start: 50%;
  margin-inline-start: -4px;
}

/* ── Position: Top ── */
[data-ui="tooltip"][data-variant="top"] > [data-part="content"] {
  bottom: 100%;
  inset-inline-start: 50%;
  transform: translateX(-50%) translateY(-4px) scale(0.95);
  margin-bottom: 4px;
}

[data-ui="tooltip"][data-variant="top"][data-state="visible"] > [data-part="content"] {
  transform: translateX(-50%) translateY(-4px) scale(1);
}

[data-ui="tooltip"][data-variant="top"] > [data-part="content"]::before {
  bottom: -4px;
  inset-inline-start: 50%;
  margin-inline-start: -4px;
}

/* ── Position: Bottom ── */
[data-ui="tooltip"][data-variant="bottom"] > [data-part="content"] {
  top: 100%;
  inset-inline-start: 50%;
  transform: translateX(-50%) translateY(4px) scale(0.95);
  margin-top: 4px;
}

[data-ui="tooltip"][data-variant="bottom"][data-state="visible"] > [data-part="content"] {
  transform: translateX(-50%) translateY(4px) scale(1);
}

[data-ui="tooltip"][data-variant="bottom"] > [data-part="content"]::before {
  top: -4px;
  inset-inline-start: 50%;
  margin-inline-start: -4px;
}

/* ── Position: Left ── */
[data-ui="tooltip"][data-variant="left"] > [data-part="content"] {
  inset-inline-end: 100%;
  top: 50%;
  transform: translateY(-50%) translateX(-4px) scale(0.95);
  margin-inline-end: 4px;
}

[data-ui="tooltip"][data-variant="left"][data-state="visible"] > [data-part="content"] {
  transform: translateY(-50%) translateX(-4px) scale(1);
}

[data-ui="tooltip"][data-variant="left"] > [data-part="content"]::before {
  inset-inline-end: -4px;
  top: 50%;
  margin-top: -4px;
}

/* ── Position: Right ── */
[data-ui="tooltip"][data-variant="right"] > [data-part="content"] {
  inset-inline-start: 100%;
  top: 50%;
  transform: translateY(-50%) translateX(4px) scale(0.95);
  margin-inline-start: 4px;
}

[data-ui="tooltip"][data-variant="right"][data-state="visible"] > [data-part="content"] {
  transform: translateY(-50%) translateX(4px) scale(1);
}

[data-ui="tooltip"][data-variant="right"] > [data-part="content"]::before {
  inset-inline-start: -4px;
  top: 50%;
  margin-top: -4px;
}

/* ── Motion ── */
@media (prefers-reduced-motion: reduce) {
  [data-ui="tooltip"] > [data-part="content"] {
    transition: none;
  }
}


/* === patterns/auth-form.css === */
/* @ui:component auth-form */
/* @ui:tokens color-fg color-fg-muted color-border color-ring color-primary color-primary-hover color-destructive color-destructive-subtle radius-lg radius-sm shadow-sm space-1 space-2 space-3 space-4 space-5 space-6 space-8 font-heading font-body heading-weight heading-tracking heading-transform heading-caps heading-leading text-sm text-lg text-xl text-2xl weight-medium weight-bold leading-tight leading-normal border-width focus-ring-width focus-ring-style focus-ring-color focus-ring-offset link-decoration card-radius card-shadow card-border */

/* ── Root Container ── */
[data-ui="auth-form"] {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  font-family: var(--font-body);
}

/* Mobile-first (task 0.8-09): on a phone the card IS the page — edge to edge,
   square, no shadow, no side rules. The canon sm block at the foot of the sheet
   turns it back into a card.

   It has to RESTATE card.css's box there rather than unset anything: `revert`
   drops to the user-agent origin, which would take the card primitive's own
   author rules with it. The values below go through card's own custom
   properties, so a theme that retunes `--card-radius` still reaches them. */
[data-ui="auth-form"] > [data-ui="card"] {
  width: 100%;
  max-width: 100%;
  border-radius: 0;
  box-shadow: none;
  border-inline-start: none;
  border-inline-end: none;
}

/* ── Header ── */
[data-ui="auth-form"] [data-part="header"] {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-6);
  padding-bottom: 0;
  text-align: center;
}

[data-ui="auth-form"] [data-part="title"] {
  margin: 0;
  font-family: var(--font-heading);
  font-size: var(--text-xl);
  font-weight: var(--heading-weight);
  letter-spacing: var(--heading-tracking);
  text-transform: var(--heading-transform);
  font-variant-caps: var(--heading-caps);
  line-height: var(--heading-leading);
  color: var(--color-fg);
}

[data-ui="auth-form"] [data-part="description"] {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--color-fg-muted);
  line-height: var(--leading-normal);
}

/* ── Error Message ── */
[data-ui="auth-form"] [data-part="error"] {
  display: none;
  margin: var(--space-4) var(--space-6) 0;
  padding: var(--space-3);
  background: var(--color-destructive-subtle);
  border: var(--border-width) solid var(--color-destructive);
  border-radius: var(--radius-lg);
  color: var(--color-destructive);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
}

[data-ui="auth-form"] [data-part="error"] p {
  margin: 0;
}

[data-ui="auth-form"][data-state="error"] [data-part="error"] {
  display: block;
}

[data-ui="auth-form"] [data-part="error"]:not([hidden]) {
  display: block;
}

/* ── Form ── */
[data-ui="auth-form"] [data-part="form"] {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-6);
}

/* ── Field Groups ── */
[data-ui="auth-form"] [data-part="email-field"],
[data-ui="auth-form"] [data-part="password-field"],
[data-ui="auth-form"] [data-part="name-field"] {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

/* ── Submit Button ── */
[data-ui="auth-form"] [data-part="submit"] {
  width: 100%;
  margin-top: var(--space-2);
}

/* ── Separator ── */
[data-ui="auth-form"] [data-part="separator"] {
  padding: 0 var(--space-6);
}

/* ── Social Buttons ── */
[data-ui="auth-form"] [data-part="social"] {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: 0 var(--space-6);
}

[data-ui="auth-form"] [data-part="social"] > [data-ui="button"] {
  width: 100%;
}

/* ── Footer ── */
[data-ui="auth-form"] [data-part="footer"] {
  padding: var(--space-4) var(--space-6) var(--space-6);
  text-align: center;
  font-size: var(--text-sm);
  color: var(--color-fg-muted);
}

[data-ui="auth-form"] [data-part="footer"] p {
  margin: 0;
}

[data-ui="auth-form"] [data-part="footer"] a {
  color: var(--color-primary);
  text-decoration: none;
  font-weight: var(--weight-medium);
}

[data-ui="auth-form"] [data-part="footer"] a:hover {
  text-decoration-line: var(--link-decoration);
  color: var(--color-primary-hover);
}

[data-ui="auth-form"] [data-part="footer"] a:focus-visible {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  outline-offset: var(--focus-ring-offset);
  border-radius: var(--radius-sm, 0.25rem);
}

/* ── Mode Variants ── */

/* Login mode: hide name field */
[data-ui="auth-form"][data-variant="login"] [data-part="name-field"] {
  display: none;
}

/* Register mode: hide social section and separator */
[data-ui="auth-form"][data-variant="register"] [data-part="social"],
[data-ui="auth-form"][data-variant="register"] [data-part="separator"] {
  display: none;
}

/* Forgot-password mode: hide password, name, social, separator */
[data-ui="auth-form"][data-variant="forgot-password"] [data-part="password-field"],
[data-ui="auth-form"][data-variant="forgot-password"] [data-part="name-field"],
[data-ui="auth-form"][data-variant="forgot-password"] [data-part="social"],
[data-ui="auth-form"][data-variant="forgot-password"] [data-part="separator"] {
  display: none;
}

/* ── State: Loading ── */
[data-ui="auth-form"][data-state="loading"] [data-part="form"] {
  opacity: 0.7;
  pointer-events: none;
}

/* ── State: Success ── */
[data-ui="auth-form"][data-state="success"] [data-part="error"] {
  display: none;
}

/* ── Size Variants ── */

/* Small */
[data-ui="auth-form"][data-size="sm"] > [data-ui="card"] {
  max-width: var(--auth-form-max-width-sm, 340px);
}

[data-ui="auth-form"][data-size="sm"] [data-part="header"] {
  padding: var(--space-4);
  padding-bottom: 0;
}

[data-ui="auth-form"][data-size="sm"] [data-part="title"] {
  font-size: var(--text-lg);
}

[data-ui="auth-form"][data-size="sm"] [data-part="form"] {
  padding: var(--space-4);
  gap: var(--space-3);
}

[data-ui="auth-form"][data-size="sm"] [data-part="separator"] {
  padding: 0 var(--space-4);
}

[data-ui="auth-form"][data-size="sm"] [data-part="social"] {
  padding: 0 var(--space-4);
  gap: var(--space-2);
}

[data-ui="auth-form"][data-size="sm"] [data-part="footer"] {
  padding: var(--space-3) var(--space-4) var(--space-4);
}

[data-ui="auth-form"][data-size="sm"] [data-part="error"] {
  margin: var(--space-3) var(--space-4) 0;
}

/* Large */
[data-ui="auth-form"][data-size="lg"] > [data-ui="card"] {
  max-width: var(--auth-form-max-width-lg, 480px);
}

[data-ui="auth-form"][data-size="lg"] [data-part="header"] {
  padding: var(--space-8);
  padding-bottom: 0;
}

[data-ui="auth-form"][data-size="lg"] [data-part="title"] {
  font-size: var(--text-2xl);
}

[data-ui="auth-form"][data-size="lg"] [data-part="form"] {
  padding: var(--space-8);
  gap: var(--space-5);
}

[data-ui="auth-form"][data-size="lg"] [data-part="separator"] {
  padding: 0 var(--space-8);
}

[data-ui="auth-form"][data-size="lg"] [data-part="social"] {
  padding: 0 var(--space-8);
  gap: var(--space-4);
}

[data-ui="auth-form"][data-size="lg"] [data-part="footer"] {
  padding: var(--space-5) var(--space-8) var(--space-8);
}

[data-ui="auth-form"][data-size="lg"] [data-part="error"] {
  margin: var(--space-5) var(--space-8) 0;
}

/* ── Responsive ──
   Canon tiers only, min-width only (FAQIR-NEXT §19). One step, at sm.

   The pre-canon floor was an ad-hoc 480px — the one value in the registry that
   had no canon tier under it. There is no `xs` (§19): a fifth tier would exist
   to serve a single declaration in a single pattern, and the canon's whole point
   is that four numbers describe the framework. So full bleed now runs to 640px,
   which is a larger phone in landscape rather than a smaller one in portrait —
   and full bleed is the *better* answer at that width anyway, since a 400px card
   floating in 600px of viewport reads as a dialog that failed to centre.

   The old `flex-direction: column` on [data-part="social"] is gone rather than
   flipped: the base rule already declares it, so that line never did anything. */
@media (min-width: 40rem) {
  [data-ui="auth-form"] > [data-ui="card"] {
    max-width: var(--auth-form-max-width, 400px);
    border-radius: var(--card-radius, var(--radius-lg));
    box-shadow: var(--card-shadow, var(--shadow-sm));
    border-inline-start: var(--border-width) solid var(--card-border, var(--color-border));
    border-inline-end: var(--border-width) solid var(--card-border, var(--color-border));
  }
}

/* ── Reduced Motion ── */
@media (prefers-reduced-motion: reduce) {
  [data-ui="auth-form"] [data-part="form"],
  [data-ui="auth-form"] [data-part="error"],
  [data-ui="auth-form"] [data-part="footer"] a {
    transition: none;
  }
}


/* === patterns/bento.css === */
/* @ui:component bento */
/* @ui:tokens space-4 space-12 space-8 space-3 space-32 space-10 space-16 space-6 font-body font-heading color-fg color-bg color-fg-muted color-primary color-bg-subtle color-primary-subtle text-xl text-lg text-base text-3xl heading-weight heading-tracking heading-transform heading-caps heading-leading measure-content leading-relaxed leading-normal card-padding card-bg card-border-width card-border card-radius texture-surface corner-shape duration-fast duration-normal ease-default ease-linear motion-hover-lift motion-reveal-duration motion-reveal-ease motion-stagger motion-reveal-distance radius-md */

/* ── Root ──
   A one-column grid for the heading and the tile grid beneath it. Every
   unconditional declaration is the PHONE case; the canon floors at the foot of
   the sheet widen it. */
[data-ui="bento"] {
  display: grid;
  gap: var(--space-4);
  padding-block: var(--space-12);
  padding-inline: var(--space-4);
  font-family: var(--font-body);
  color: var(--color-fg);
  background: var(--color-bg);
}

/* ── Heading ── */
[data-ui="bento"] > [data-part="heading"] {
  margin: 0;
  font-family: var(--font-heading);
  font-size: var(--text-xl);
  font-weight: var(--heading-weight);
  letter-spacing: var(--heading-tracking);
  text-transform: var(--heading-transform);
  font-variant-caps: var(--heading-caps);
  line-height: var(--heading-leading);
  text-wrap: balance;
}

/* ── Description ── */
[data-ui="bento"] > [data-part="description"] {
  margin: 0;
  max-inline-size: var(--measure-content);
  font-size: var(--text-lg);
  line-height: var(--leading-relaxed);
  color: var(--color-fg-muted);
}

/* ── Items ──
   A real <ul>; the marker is removed, not the semantics. One column on a
   phone, so a span is never wider than the grid. `dense` lets a later small
   tile back-fill the hole a wide or tall one leaves, which is what makes the
   mosaic read as a mosaic rather than a grid with gaps. */
[data-ui="bento"] > [data-part="items"] {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-auto-flow: dense;
  gap: var(--bento-gap, var(--space-4));
  margin: 0;
  margin-block-start: var(--space-8);
  padding: 0;
  list-style: none;
}

/* ── Item ──
   The tile is drawn by this part, not by a nested card: a nested component
   would own the data-part on its children. It reads the same card aliases a
   card does, so a theme that re-skins cards re-skins tiles. `isolation`
   gives the sheen below somewhere to sit — behind the content, above the
   fill — and `clip` trims it without making the tile a scroll container.
   A flex column, so a media area grows into the spare height of a tall tile
   while the words stay anchored at the foot. */
[data-ui="bento"] > :where([data-part="items"]) > [data-part="item"] {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  position: relative;
  isolation: isolate;
  overflow: clip;
  padding: var(--card-padding);
  background: var(--texture-surface), var(--card-bg);
  border: var(--card-border-width) solid var(--card-border);
  border-radius: var(--card-radius);
  corner-shape: var(--corner-shape);
  transition: translate var(--duration-fast) var(--ease-default);
}

/* ── Hover: lift and spotlight ──
   The lift is the axis `card` and `button` read — `none` unless a theme says
   surfaces rise under the pointer. The sheen is a soft pool of the accent
   fading in from the top edge; it is a pseudo-element so it costs no markup
   and can never be focused or read. `focus-within` lights a tile whose
   content holds a link, so keyboard users get the same cue. */
[data-ui="bento"] > :where([data-part="items"]) > [data-part="item"]::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: 0;
  background: radial-gradient(
    70% 60% at 50% 0%,
    color-mix(in oklch, var(--color-primary) 14%, transparent),
    transparent 70%
  );
  transition: opacity var(--duration-normal) var(--ease-default);
}

[data-ui="bento"] > :where([data-part="items"]) > [data-part="item"]:hover,
[data-ui="bento"] > :where([data-part="items"]) > [data-part="item"]:focus-within {
  translate: var(--motion-hover-lift);
}

[data-ui="bento"] > :where([data-part="items"]) > [data-part="item"]:hover::after,
[data-ui="bento"] > :where([data-part="items"]) > [data-part="item"]:focus-within::after {
  opacity: 1;
}

/* ── Media ──
   The tile's visual: a stretched area whose single child fills it, so a
   nested backdrop paints the whole panel. It grows to take the spare height
   of a tall tile. It is a grid rather than a block so the child needs no
   sizing of its own. */
[data-ui="bento"] > :where([data-part="items"]) > :where([data-part="item"]) > [data-part="media"] {
  display: grid;
  flex: 1 1 auto;
  min-block-size: var(--space-32);
  margin: 0;
  border-radius: var(--radius-md);
  background: var(--color-bg-subtle);
  overflow: clip;
}

/* ── Icon ──
   A tinted plate that WRAPS the icon primitive; it is never the icon. An icon
   paints its glyph with background-color:currentColor through a mask, so a
   background on the icon element would repaint the glyph instead of framing
   it. The nested icon inherits its size (1em) and colour from this box. */
[data-ui="bento"] > :where([data-part="items"]) > :where([data-part="item"]) > [data-part="icon"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  align-self: start;
  inline-size: var(--space-10);
  block-size: var(--space-10);
  font-size: var(--text-xl);
  color: var(--color-primary);
  background: var(--color-primary-subtle);
  border-radius: var(--radius-md);
}

/* ── Title ── */
[data-ui="bento"] > :where([data-part="items"]) > :where([data-part="item"]) > [data-part="title"] {
  margin: 0;
  font-family: var(--font-heading);
  font-size: var(--text-lg);
  font-weight: var(--heading-weight);
  letter-spacing: var(--heading-tracking);
  line-height: var(--heading-leading);
}

/* ── Item description ── */
[data-ui="bento"] > :where([data-part="items"]) > :where([data-part="item"]) > [data-part="description"] {
  margin: 0;
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  color: var(--color-fg-muted);
}

/* ── Entrance ──
   With data-animate the tiles arrive one after another, the way a staggered
   reveal's children do: one keyframe pair, delayed by a private index that
   nth-child writes. Twelve steps are counted; everything past the twelfth
   arrives with it, so a long grid never holds its last row back for seconds.
   `both` holds the from-state through the delay, so a late tile is not
   visible and then hidden and then revealed. */
[data-ui="bento"][data-animate] > :where([data-part="items"]) > [data-part="item"] {
  --faqir-bento-index: 0;
  animation: faqir-bento-reveal var(--motion-reveal-duration) var(--motion-reveal-ease) both;
  animation-delay: calc(var(--motion-stagger) * var(--faqir-bento-index));
}

[data-ui="bento"][data-animate] > :where([data-part="items"]) > :nth-child(2)    { --faqir-bento-index: 1; }
[data-ui="bento"][data-animate] > :where([data-part="items"]) > :nth-child(3)    { --faqir-bento-index: 2; }
[data-ui="bento"][data-animate] > :where([data-part="items"]) > :nth-child(4)    { --faqir-bento-index: 3; }
[data-ui="bento"][data-animate] > :where([data-part="items"]) > :nth-child(5)    { --faqir-bento-index: 4; }
[data-ui="bento"][data-animate] > :where([data-part="items"]) > :nth-child(6)    { --faqir-bento-index: 5; }
[data-ui="bento"][data-animate] > :where([data-part="items"]) > :nth-child(7)    { --faqir-bento-index: 6; }
[data-ui="bento"][data-animate] > :where([data-part="items"]) > :nth-child(8)    { --faqir-bento-index: 7; }
[data-ui="bento"][data-animate] > :where([data-part="items"]) > :nth-child(9)    { --faqir-bento-index: 8; }
[data-ui="bento"][data-animate] > :where([data-part="items"]) > :nth-child(10)   { --faqir-bento-index: 9; }
[data-ui="bento"][data-animate] > :where([data-part="items"]) > :nth-child(11)   { --faqir-bento-index: 10; }
[data-ui="bento"][data-animate] > :where([data-part="items"]) > :nth-child(n+12) { --faqir-bento-index: 11; }

/* Only a `from`: the animation ends on whatever the tile already is, so the
   hover lift still reads the moment the entrance is over. */
@keyframes faqir-bento-reveal {
  from {
    opacity: 0;
    translate: 0 var(--motion-reveal-distance);
  }
}

/* ── Entrance on scroll ──
   A feature grid usually sits below the fold, where a load-time entrance
   plays to nobody. Where view timelines exist the same keyframes are scrubbed
   by the scrollbar as each tile crosses the bottom of the viewport; a time
   delay means nothing there, so the stagger offsets each tile's RANGE
   instead. Elsewhere the block is skipped and the load entrance above still
   plays — the tiles are never left hidden. */
@supports (animation-timeline: view()) {
  [data-ui="bento"][data-animate] > :where([data-part="items"]) > [data-part="item"] {
    animation-timeline: view();
    animation-timing-function: var(--ease-linear);
    animation-delay: 0s;
    animation-range:
      entry calc(5% + var(--faqir-bento-index) * 6%)
      entry calc(70% + var(--faqir-bento-index) * 6%);
  }
}

/* ── Motion ──
   Reduced motion removes the entrance and the lift, not the tiles: every tile
   is already arrived and stays put under the pointer. Paper gets the same
   treatment — a printed page has no entrance and no hover. */
@media (prefers-reduced-motion: reduce), print {
  /* The entrance's own selector is repeated so this rule matches its
     specificity: the plain one alone (0,2,0) lost to [data-animate] (0,3,0),
     and the tiles kept scrubbing in under reduced motion. */
  [data-ui="bento"][data-animate] > :where([data-part="items"]) > [data-part="item"],
  [data-ui="bento"] > :where([data-part="items"]) > [data-part="item"],
  [data-ui="bento"] > :where([data-part="items"]) > [data-part="item"]::after {
    animation: none;
    transition: none;
  }

  [data-ui="bento"] > :where([data-part="items"]) > [data-part="item"]:hover,
  [data-ui="bento"] > :where([data-part="items"]) > [data-part="item"]:focus-within {
    translate: none;
  }
}

/* ── Responsive ──
   Canon tiers only, min-width only, ascending. sm: the type scale and the
   block padding open up. md: two columns, and a wide or large tile may span
   them. lg: four columns with a row floor, so a tall or large tile has two
   rows of real height to span. Spans live in the tier that has the tracks
   for them — a `span 2` in a one-column grid would invent a second column. */
@media (min-width: 40rem) {
  [data-ui="bento"] {
    padding-block: var(--space-16);
    padding-inline: var(--space-6);
  }

  [data-ui="bento"] > [data-part="heading"] {
    font-size: var(--text-3xl);
  }
}

@media (min-width: 48rem) {
  [data-ui="bento"] > [data-part="items"] {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  [data-ui="bento"] > :where([data-part="items"]) > [data-part="item"][data-span="wide"],
  [data-ui="bento"] > :where([data-part="items"]) > [data-part="item"][data-span="large"] {
    grid-column: span 2;
  }
}

@media (min-width: 64rem) {
  [data-ui="bento"] > [data-part="items"] {
    grid-template-columns: repeat(4, minmax(0, 1fr));
    grid-auto-rows: minmax(var(--bento-row, 12rem), auto);
  }

  [data-ui="bento"] > :where([data-part="items"]) > [data-part="item"][data-span="tall"],
  [data-ui="bento"] > :where([data-part="items"]) > [data-part="item"][data-span="large"] {
    grid-row: span 2;
  }
}


/* === patterns/crud-table.css === */
/* @ui:component crud-table */
/* @ui:tokens color-bg color-bg-subtle color-fg color-fg-muted color-border color-destructive radius-md radius-lg space-1 space-2 space-3 space-4 space-6 space-8 font-body text-sm text-base text-lg weight-medium weight-semibold duration-fast ease-default border-width */

/* ── Root ── */
[data-ui="crud-table"] {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  width: 100%;
  font-family: var(--font-body);
}

/* ── Toolbar ── */
[data-ui="crud-table"] [data-part="toolbar"] {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
}

[data-ui="crud-table"] [data-part="search"] {
  flex: 1 1 auto;
  min-width: 0;
  max-width: 320px;
}

[data-ui="crud-table"] [data-part="filters"] {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
}

[data-ui="crud-table"] [data-part="filters"] [data-part="dismiss"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-inline-start: var(--space-1);
  padding: 0;
  border: none;
  background: transparent;
  color: inherit;
  font-size: var(--text-sm);
  cursor: pointer;
  opacity: 0.7;
  transition: opacity var(--duration-fast) var(--ease-default);
}

[data-ui="crud-table"] [data-part="filters"] [data-part="dismiss"]:hover {
  opacity: 1;
}

[data-ui="crud-table"] [data-part="actions"] {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-inline-start: auto;
  flex-shrink: 0;
}

/* ── Bulk Actions ── */
[data-ui="crud-table"] [data-part="bulk-actions"] {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  background: var(--color-bg-subtle);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-md);
}

[data-ui="crud-table"] [data-part="bulk-actions"] [data-part="selection-count"] {
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--color-fg);
  margin-inline-end: auto;
}

/* ── Table Wrapper ── */
[data-ui="crud-table"] [data-part="table-wrapper"] {
  width: 100%;
  overflow-x: auto;
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-bg);
}

/* ── Row Actions ── */
[data-ui="crud-table"] [data-part="row-actions"] {
  display: flex;
  align-items: center;
  gap: var(--space-1);
  flex-wrap: nowrap;
}

/* ── Pagination Wrapper ── */
[data-ui="crud-table"] [data-part="pagination"] {
  display: flex;
  align-items: center;
  justify-content: flex-end;
}

/* ── Empty State ── */
[data-ui="crud-table"] [data-part="empty-state"] {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  padding: var(--space-8) var(--space-4);
  text-align: center;
  min-height: 240px;
  border: var(--border-width) dashed var(--color-border);
  border-radius: var(--radius-lg);
  background: var(--color-bg);
}

[data-ui="crud-table"] [data-part="empty-icon"] {
  font-size: var(--text-lg);
  color: var(--color-fg-muted);
  opacity: 0.6;
}

[data-ui="crud-table"] [data-part="empty-title"] {
  margin: 0;
  font-size: var(--text-base);
  font-weight: var(--weight-semibold);
  color: var(--color-fg);
}

[data-ui="crud-table"] [data-part="empty-description"] {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--color-fg-muted);
  max-width: 360px;
}

/* ── Edit Dialog Form Fields ── */
[data-ui="crud-table"] [data-part="edit-dialog"] [data-part="body"] {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

[data-ui="crud-table"] [data-part="edit-dialog"] [data-part="field"] {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

/* ── Loading State ── */
[data-ui="crud-table"][data-state="loading"] [data-part="table-wrapper"] {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 200px;
  opacity: 0.6;
  pointer-events: none;
}

/* ── Empty State Visibility ── */
[data-ui="crud-table"][data-state="empty"] [data-part="table-wrapper"] {
  display: none;
}

[data-ui="crud-table"][data-state="empty"] [data-part="pagination"] {
  display: none;
}

[data-ui="crud-table"][data-state="empty"] [data-part="empty-state"] {
  display: flex;
}

/* ── Error State ── */
[data-ui="crud-table"][data-state="error"] [data-part="table-wrapper"] {
  border-color: var(--color-destructive);
}

/* ── Density: Compact ── */
[data-ui="crud-table"][data-variant="compact"] {
  gap: var(--space-2);
}

[data-ui="crud-table"][data-variant="compact"] [data-part="toolbar"] {
  gap: var(--space-2);
}

[data-ui="crud-table"][data-variant="compact"] [data-part="bulk-actions"] {
  padding: var(--space-2) var(--space-3);
}

[data-ui="crud-table"][data-variant="compact"] [data-part="empty-state"] {
  padding: var(--space-6) var(--space-3);
  min-height: 160px;
}

/* ── Density: Comfortable ── */
[data-ui="crud-table"][data-variant="comfortable"] {
  gap: var(--space-6);
}

[data-ui="crud-table"][data-variant="comfortable"] [data-part="toolbar"] {
  gap: var(--space-4);
}

[data-ui="crud-table"][data-variant="comfortable"] [data-part="bulk-actions"] {
  padding: var(--space-4) var(--space-6);
}

[data-ui="crud-table"][data-variant="comfortable"] [data-part="empty-state"] {
  padding: var(--space-8) var(--space-6);
  min-height: 320px;
}

/* ── Motion ── */
@media (prefers-reduced-motion: reduce) {
  [data-ui="crud-table"] [data-part="filters"] [data-part="dismiss"],
  [data-ui="crud-table"] [data-part="table-wrapper"],
  [data-ui="crud-table"] [data-part="bulk-actions"] {
    transition: none;
  }
}


/* === patterns/cta.css === */
/* @ui:component cta */
/* @ui:tokens color-fg color-fg-muted color-primary color-primary-fg color-info space-4 space-8 space-3 space-12 font-body font-heading card-bg card-border border-width radius-2xl radius-lg corner-shape text-sm text-3xl text-base text-2xl text-4xl text-lg weight-semibold leading-snug leading-relaxed heading-weight heading-tracking heading-transform heading-caps heading-leading measure-prose */

/* ── Root ──
   One panel that asks for one thing. A grid, so the layout variants only
   change how the same parts flow — stacked and centred, copy beside media,
   or one compact row — and the tone variants only change what the panel is
   painted with.

   Three private properties carry the tone: the ink, the muted ink the
   description and the note are set in, and the accent the eyebrow is set in.
   A tone re-points them once and every part follows; `--cta-fg` re-points the
   ink for all three tones.

   Mobile-first: every declaration outside the `@media` blocks at the foot of
   the sheet is the PHONE case; the canon floors only ever widen it. */
[data-ui="cta"] {
  --faqir-cta-ink: var(--cta-fg, var(--color-fg));
  --faqir-cta-muted: var(--color-fg-muted);
  --faqir-cta-accent: var(--color-primary);
  display: grid;
  gap: var(--space-4);
  padding: var(--cta-padding, var(--space-8));
  font-family: var(--font-body);
  color: var(--faqir-cta-ink);
  background: var(--cta-bg, var(--card-bg));
  border: var(--border-width) solid var(--card-border);
  border-radius: var(--radius-2xl);
  corner-shape: var(--corner-shape);
  overflow: clip;
}

/* ── Eyebrow ── */
[data-ui="cta"] > [data-part="eyebrow"],
[data-ui="cta"] > :where([data-part="content"]) > [data-part="eyebrow"] {
  margin: 0;
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-snug);
  color: var(--faqir-cta-accent);
}

/* ── Headline ──
   The heading voice. A nested highlight inside it keeps the words real text;
   the effect is a background under the glyphs. */
[data-ui="cta"] > [data-part="headline"],
[data-ui="cta"] > :where([data-part="content"]) > [data-part="headline"] {
  margin: 0;
  font-family: var(--font-heading);
  font-size: var(--text-3xl);
  font-weight: var(--heading-weight);
  letter-spacing: var(--heading-tracking);
  text-transform: var(--heading-transform);
  font-variant-caps: var(--heading-caps);
  line-height: var(--heading-leading);
  color: var(--faqir-cta-ink);
  text-wrap: balance;
}

/* ── Description ── */
[data-ui="cta"] > [data-part="description"],
[data-ui="cta"] > :where([data-part="content"]) > [data-part="description"] {
  margin: 0;
  max-inline-size: var(--measure-prose);
  font-size: var(--text-base);
  line-height: var(--leading-relaxed);
  color: var(--faqir-cta-muted);
}

/* ── Actions ──
   Stacked and full-bleed on a phone: two side-by-side buttons in 320px of
   viewport are two truncated buttons. They become a row at the sm floor. The
   buttons inside keep their own contract — on a primary or gradient tone the
   markup uses the button's secondary variant, which is what reads on a filled
   panel; the pattern never restyles a nested component. */
[data-ui="cta"] > [data-part="actions"],
[data-ui="cta"] > :where([data-part="content"]) > [data-part="actions"] {
  display: flex;
  flex-wrap: wrap;
  flex-direction: column;
  align-items: stretch;
  inline-size: 100%;
  gap: var(--space-3);
  margin-block-start: var(--space-4);
}

/* ── Note ── */
[data-ui="cta"] > [data-part="note"],
[data-ui="cta"] > :where([data-part="content"]) > [data-part="note"] {
  margin: 0;
  font-size: var(--text-sm);
  line-height: var(--leading-snug);
  color: var(--faqir-cta-muted);
}

/* ── Content ──
   The text column of the split and banner layouts: a grid of its own, so the
   inner rhythm matches the centred layout, where the parts sit directly in
   the root. */
[data-ui="cta"] > [data-part="content"] {
  display: grid;
  gap: var(--space-4);
  justify-items: start;
}

/* ── Media ── */
[data-ui="cta"] > [data-part="media"] {
  margin: 0;
  border-radius: var(--radius-lg);
  corner-shape: var(--corner-shape);
  overflow: clip;
}

[data-ui="cta"] > :where([data-part="media"]) > img {
  display: block;
  inline-size: 100%;
  block-size: auto;
}

/* ── Layout: center (default) ── */
[data-ui="cta"]:not([data-variant]),
[data-ui="cta"][data-variant="center"] {
  justify-items: center;
  text-align: center;
}

[data-ui="cta"]:not([data-variant]) > [data-part="actions"],
[data-ui="cta"][data-variant="center"] > [data-part="actions"] {
  justify-content: center;
}

/* ── Layout: split ──
   Copy and media share the row from the lg floor; until then the media
   follows the copy, in source order. */
[data-ui="cta"][data-variant="split"] {
  align-items: center;
  gap: var(--space-8);
}

/* ── Layout: banner ──
   One compact row from the md floor: the copy at the start, the actions at
   the end. The headline steps down a size so the row stays a row. */
[data-ui="cta"][data-variant="banner"] {
  align-items: center;
}

[data-ui="cta"][data-variant="banner"] > :where([data-part="content"]) > [data-part="headline"] {
  font-size: var(--text-2xl);
}

[data-ui="cta"][data-variant="banner"] > :where([data-part="content"]) > [data-part="description"] {
  font-size: var(--text-base);
}

/* ── Tone: primary ──
   The accent as the panel. The ink is the accent's own foreground, the muted
   ink is that foreground let through at most of its strength, and the
   eyebrow takes the ink — an accent-coloured eyebrow on an accent panel
   would vanish. */
[data-ui="cta"][data-tone="primary"] {
  --faqir-cta-ink: var(--cta-fg, var(--color-primary-fg));
  --faqir-cta-muted: color-mix(in oklch, var(--faqir-cta-ink) 88%, transparent);
  --faqir-cta-accent: var(--faqir-cta-ink);
  background: var(--cta-bg, var(--color-primary));
  border-color: transparent;
}

/* ── Tone: gradient ──
   The theme's accent gradient where it states one, else the accent running
   into info. The same ink as the primary tone, because the gradient is built
   from colours that share the accent's foreground. */
[data-ui="cta"][data-tone="gradient"] {
  --faqir-cta-ink: var(--cta-fg, var(--color-primary-fg));
  --faqir-cta-muted: color-mix(in oklch, var(--faqir-cta-ink) 88%, transparent);
  --faqir-cta-accent: var(--faqir-cta-ink);
  background: var(--cta-gradient, var(--gradient-accent, linear-gradient(135deg, var(--color-primary), var(--color-info))));
  border-color: transparent;
}

/* ── Transparent ──
   For a panel inside a backdrop: the backdrop paints the light BEHIND its
   content, so the panel's own fill and edge would hide it. The padding and
   the radius stay, so the copy keeps its room. */
[data-ui="cta"][data-transparent] {
  background: none;
  border-color: transparent;
}

/* ── Print ── */
@media print {
  [data-ui="cta"] {
    break-inside: avoid;
  }
}

/* ── Responsive ──
   Canon tiers only, min-width only, ascending. sm: the type scale opens up,
   the panel takes its full padding and the action row is a row again. md:
   the banner becomes its row. lg: the split layout earns its second column. */
@media (min-width: 40rem) {
  [data-ui="cta"] {
    padding: var(--cta-padding, var(--space-12));
  }

  [data-ui="cta"][data-variant="banner"] {
    padding: var(--cta-padding, var(--space-8));
  }

  [data-ui="cta"] > [data-part="headline"],
  [data-ui="cta"] > :where([data-part="content"]) > [data-part="headline"] {
    font-size: var(--text-4xl);
  }

  [data-ui="cta"][data-variant="banner"] > :where([data-part="content"]) > [data-part="headline"] {
    font-size: var(--text-2xl);
  }

  [data-ui="cta"] > [data-part="description"],
  [data-ui="cta"] > :where([data-part="content"]) > [data-part="description"] {
    font-size: var(--text-lg);
  }

  [data-ui="cta"][data-variant="banner"] > :where([data-part="content"]) > [data-part="description"] {
    font-size: var(--text-base);
  }

  /* `normal` rather than a value of its own: this is the initial align-items,
     so the row is exactly the un-stacked default and nothing is "undone". */
  [data-ui="cta"] > [data-part="actions"],
  [data-ui="cta"] > :where([data-part="content"]) > [data-part="actions"] {
    inline-size: auto;
    flex-direction: row;
    align-items: normal;
  }
}

@media (min-width: 48rem) {
  [data-ui="cta"][data-variant="banner"] {
    grid-template-columns: minmax(0, 1fr) auto;
    gap: var(--space-8);
  }

  [data-ui="cta"][data-variant="banner"] > [data-part="actions"] {
    justify-content: end;
    margin-block-start: 0;
  }
}

@media (min-width: 64rem) {
  [data-ui="cta"][data-variant="split"] {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: var(--space-12);
  }
}


/* === patterns/dashboard-shell.css === */
/* @ui:component dashboard-shell */
/* @ui:tokens color-bg color-bg-subtle color-bg-muted color-fg color-fg-muted color-border color-primary color-primary-subtle space-2 space-3 space-4 space-6 space-1 radius-md shadow-md font-body font-ui text-xs text-sm text-lg text-2xl weight-medium weight-semibold weight-bold leading-tight leading-normal duration-normal duration-slow ease-default ease-out z-sticky z-overlay border-width focus-ring-width focus-ring-style focus-ring-color focus-ring-offset */

/* ── Shell Grid Layout ──
   Mobile-first (task 0.8-09): the base is the PHONE shell — one column, header
   over content over footer, and the sidebar off-canvas as a drawer. The single
   `@media (min-width: 48rem)` block at the foot of the sheet puts the sidebar
   back in the flow.

   This is the one pattern where the narrow case is the *more* decorated one, so
   the md block has real resets in it. That is a consequence of the canon being
   min-width-only (FAQIR-NEXT §19): "position: fixed below md" can only be said
   as "position: fixed always, static from md up". */
[data-ui="dashboard-shell"] {
  display: grid;
  /* `minmax(0, 1fr)`, not `1fr`: a `1fr` track has `auto` for its minimum, so it
     never shrinks below the min-content of the header/content/footer inside it
     and the whole shell grew 9px wider than the phone it was on. [W3-3] */
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: var(--shell-header-height, 3.5rem) 1fr auto;
  grid-template-areas:
    "header"
    "content"
    "footer";
  min-height: 100vh;
  background: var(--color-bg);
  font-family: var(--font-body);
  color: var(--color-fg);
}

/* ── Sidebar-Right Variant ──
   Same single column below md; only the drawer's side and the md grid differ. */
[data-ui="dashboard-shell"][data-variant="right"] {
  grid-template-columns: minmax(0, 1fr);
  grid-template-areas:
    "header"
    "content"
    "footer";
}

/* ── Sidebar ──
   Off-canvas by default; `data-state="expanded"` slides it in. `grid-area` is
   harmless while it is `position: fixed` and is what places it from md up. */
[data-ui="dashboard-shell"] > [data-part="sidebar"] {
  grid-area: sidebar;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-4);
  background: var(--color-bg-subtle);
  border-inline-end: var(--border-width) solid var(--color-border);
  overflow-y: auto;
  position: fixed;
  top: 0;
  inset-inline-start: 0;
  bottom: 0;
  width: var(--shell-sidebar-width, 16rem);
  z-index: var(--z-overlay, 200);
  box-shadow: var(--shadow-md);
  transform: translateX(-100%);
  /* A closed drawer sat outside the window, painted and tabbable: the nav links
     inside it took focus with nothing visible on screen. `visibility` removes it
     from both, and is delayed off (not on) so the slide-out still animates. [W3-3] */
  visibility: hidden;
  transition: transform var(--duration-slow) var(--ease-out),
              visibility 0s linear var(--duration-slow);
}

[data-ui="dashboard-shell"][data-variant="right"] > [data-part="sidebar"] {
  border-inline-end: none;
  border-inline-start: var(--border-width) solid var(--color-border);
  inset-inline-start: auto;
  inset-inline-end: 0;
  transform: translateX(100%);
}

[data-ui="dashboard-shell"] > [data-part="sidebar"][data-state="expanded"],
[data-ui="dashboard-shell"][data-variant="right"] > [data-part="sidebar"][data-state="expanded"] {
  transform: translateX(0);
  visibility: visible;
  transition: transform var(--duration-slow) var(--ease-out),
              visibility 0s linear 0s;
}

/* ── Sidebar Collapsed ──
   Only the rail's own metrics live here; the two `:has()` rules that narrow the
   shell's first column moved into the md block, because below md there is no
   sidebar column to narrow. (They used to sit out here and outrank the
   single-column rule at (0,3,0) vs (0,1,0), so a collapsed sidebar on a phone
   produced a 4rem column no grid area was ever placed in.) */
[data-ui="dashboard-shell"] > [data-part="sidebar"][data-state="collapsed"] {
  padding: var(--space-4) var(--space-2);
  align-items: center;
}

[data-ui="dashboard-shell"] > [data-part="sidebar"][data-state="collapsed"] [data-part="nav-label"],
[data-ui="dashboard-shell"] > [data-part="sidebar"][data-state="collapsed"] [data-part="sidebar-user-name"],
[data-ui="dashboard-shell"] > [data-part="sidebar"][data-state="collapsed"] [data-part="logo"] span {
  display: none;
}

/* A collapsed rail owns the full width of its nav. Trailing badges need their
   labels to be meaningful and do not fit beside a glyph in the 4rem column, so
   they join the labels in the declared collapsed presentation. */
[data-ui="dashboard-shell"] > [data-part="sidebar"][data-state="collapsed"] [data-part="nav"] {
  inline-size: 100%;
}

[data-ui="dashboard-shell"] > [data-part="sidebar"][data-state="collapsed"] [data-part="nav-item"] {
  justify-content: center;
}

[data-ui="dashboard-shell"] > [data-part="sidebar"][data-state="collapsed"] [data-part="nav-item"] [data-ui="badge"] {
  display: none;
}

/* ── Logo ── */
[data-ui="dashboard-shell"] > [data-part="sidebar"] [data-part="logo"] {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-lg);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-tight);
  color: var(--color-fg);
  white-space: nowrap;
  overflow: hidden;
}

/* ── Navigation ── */
[data-ui="dashboard-shell"] > [data-part="sidebar"] [data-part="nav"] {
  display: flex;
  flex-direction: column;
  gap: var(--space-1, 0.25rem);
  flex: 1;
}

/* ── Nav Item ── */
[data-ui="dashboard-shell"] > [data-part="sidebar"] [data-part="nav-item"] {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-md);
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  line-height: var(--leading-normal);
  color: var(--color-fg-muted);
  text-decoration: none;
  white-space: nowrap;
  overflow: hidden;
  cursor: pointer;
  transition: background var(--duration-normal) var(--ease-default),
              color var(--duration-normal) var(--ease-default);
}

[data-ui="dashboard-shell"] > [data-part="sidebar"] [data-part="nav-item"]:hover {
  background: var(--color-bg-muted);
  color: var(--color-fg);
}

[data-ui="dashboard-shell"] > [data-part="sidebar"] [data-part="nav-item"]:focus-visible {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  outline-offset: calc(-1 * var(--focus-ring-offset));
}

/* ── Nav Item Active ── */
[data-ui="dashboard-shell"] > [data-part="sidebar"] [data-part="nav-item"][aria-current="page"] {
  background: var(--color-primary-subtle);
  color: var(--color-primary);
  font-weight: var(--weight-semibold);
}

/* ── Nav Icon ── */
[data-ui="dashboard-shell"] > [data-part="sidebar"] [data-part="nav-icon"] {
  flex-shrink: 0;
  width: var(--space-4);
  height: var(--space-4);
}

/* ── Nav Badge Positioning ── */
[data-ui="dashboard-shell"] > [data-part="sidebar"] [data-part="nav-item"] [data-ui="badge"] {
  margin-inline-start: auto;
}

/* ── Sidebar User ── */
[data-ui="dashboard-shell"] > [data-part="sidebar"] [data-part="sidebar-user"] {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  font-size: var(--text-sm);
  color: var(--color-fg-muted);
  white-space: nowrap;
  overflow: hidden;
}

/* ── Header ── */
/* Mobile-first gutters. A 48px inline padding plus a search field plus an
   actions cluster does not fit a 320px window, and the header pushed itself
   49px past its own edge — with the user menu, the thing that opens the
   sidebar, among the parts outside it. The `md` block restores the roomier
   desktop gutter. [W3-3] */
[data-ui="dashboard-shell"] > [data-part="header"] {
  grid-area: header;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0 var(--space-3);
  background: var(--color-bg);
  border-bottom: var(--border-width) solid var(--color-border);
  position: sticky;
  top: 0;
  z-index: var(--z-sticky);
}

/* ── Search ── */
[data-ui="dashboard-shell"] > [data-part="header"] [data-part="search"] {
  /* `flex: 1` alone keeps the field's own min-content as a floor; a search input
     will not give that up on a phone without an explicit one. */
  flex: 1 1 0;
  min-inline-size: 0;
  max-width: 28rem;
}

/* ── Header Actions ── */
[data-ui="dashboard-shell"] > [data-part="header"] [data-part="header-actions"] {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-inline-start: auto;
  min-inline-size: 0;
}

/* ── User Menu ── */
[data-ui="dashboard-shell"] > [data-part="header"] [data-part="user-menu"] {
  display: flex;
  align-items: center;
  min-inline-size: 0;
}

/* The account name is the header's only elastic text: let it ellipsize rather
   than set the width of everything beside it. */
[data-ui="dashboard-shell"] > [data-part="header"] [data-part="user-menu"] [data-part="trigger"] {
  min-inline-size: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── Content ── */
[data-ui="dashboard-shell"] > [data-part="content"] {
  grid-area: content;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  /* Same reason as the header: 48px of gutter is a sixth of a 320px window. */
  padding: var(--space-3);
  overflow-y: auto;
  min-inline-size: 0;
}

/* ── Content Metric ── */
[data-ui="dashboard-shell"] > [data-part="content"] [data-part="metric"] {
  font-size: var(--text-2xl, 1.5rem);
  font-weight: var(--weight-bold, 700);
  line-height: var(--leading-tight);
  color: var(--color-fg);
}

/* ── Activity Item ── */
[data-ui="dashboard-shell"] > [data-part="content"] [data-part="activity-item"] {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) 0;
  font-size: var(--text-sm);
  color: var(--color-fg);
}

[data-ui="dashboard-shell"] > [data-part="content"] [data-part="activity-item"] [data-ui="badge"] {
  margin-inline-start: auto;
}

/* ── Footer ── */
[data-ui="dashboard-shell"] > [data-part="footer"] {
  grid-area: footer;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-6);
  border-top: var(--border-width) solid var(--color-border);
  font-size: var(--text-xs);
  color: var(--color-fg-muted);
}

/* ── Responsive: the sidebar rejoins the flow at the canon md floor ──
   Canon tiers only, min-width only (FAQIR-NEXT §19). Four `transform: none`
   declarations rather than one, because the base states them at four different
   specificities ((0,2,0) through (0,4,0)) and an override has to meet each; the
   md block is later in the sheet, so equal specificity is enough to win. */
@media (min-width: 48rem) {
  [data-ui="dashboard-shell"] > [data-part="header"] {
    gap: var(--space-4);
    padding: 0 var(--space-6);
  }

  [data-ui="dashboard-shell"] > [data-part="content"] {
    gap: var(--space-6);
    padding: var(--space-6);
  }

  [data-ui="dashboard-shell"] {
    grid-template-columns: var(--shell-sidebar-width, 16rem) minmax(0, 1fr);
    grid-template-areas:
      "sidebar header"
      "sidebar content"
      "sidebar footer";
  }

  [data-ui="dashboard-shell"][data-variant="right"] {
    grid-template-columns: minmax(0, 1fr) var(--shell-sidebar-width, 16rem);
    grid-template-areas:
      "header  sidebar"
      "content sidebar"
      "footer  sidebar";
  }

  /* A collapsed sidebar narrows the column it actually occupies — which only
     exists from here up. */
  [data-ui="dashboard-shell"]:has(> [data-part="sidebar"][data-state="collapsed"]) {
    grid-template-columns: var(--shell-sidebar-collapsed-width, 4rem) minmax(0, 1fr);
  }

  [data-ui="dashboard-shell"][data-variant="right"]:has(> [data-part="sidebar"][data-state="collapsed"]) {
    grid-template-columns: minmax(0, 1fr) var(--shell-sidebar-collapsed-width, 4rem);
  }

  [data-ui="dashboard-shell"] > [data-part="sidebar"] {
    position: static;
    inset: auto;
    width: auto;
    z-index: auto;
    box-shadow: none;
    transform: none;
    visibility: visible;
    transition: width var(--duration-slow) var(--ease-out),
                padding var(--duration-slow) var(--ease-out);
  }

  [data-ui="dashboard-shell"][data-variant="right"] > [data-part="sidebar"] {
    inset: auto;
    transform: none;
  }

  [data-ui="dashboard-shell"] > [data-part="sidebar"][data-state="expanded"] {
    transform: none;
  }

  [data-ui="dashboard-shell"][data-variant="right"] > [data-part="sidebar"][data-state="expanded"] {
    transform: none;
  }

  /* The toggle opens the phone drawer. From here up the sidebar is docked and
     the drawer does not exist, so a toggle left on screen would do nothing. */
  [data-ui="dashboard-shell"] > :where([data-part="header"]) > [data-part="sidebar-toggle"] {
    display: none;
  }
}

/* ── Reduced Motion ── */
@media (prefers-reduced-motion: reduce) {
  [data-ui="dashboard-shell"] > [data-part="sidebar"],
  [data-ui="dashboard-shell"] > [data-part="sidebar"] [data-part="nav-item"] {
    transition: none;
  }
}


/* === patterns/document.css === */
/* @ui:component document */
/* @ui:tokens color-bg color-fg color-fg-muted color-border space-2 space-4 space-6 space-8 space-12 shadow-lg radius-md font-body text-xs text-sm weight-semibold weight-bold leading-normal page-format page-orientation page-margin-top page-margin-right page-margin-bottom page-margin-left doc-running-header-height doc-running-footer-height doc-running-gap doc-print-border-color doc-heading-font doc-heading-weight doc-font doc-legal-size doc-legal-color doc-max-width doc-font-size doc-line-height doc-section-gap doc-component-gap doc-table-cell-pad-y doc-table-cell-pad-x doc-table-font-size doc-table-header-weight doc-table-header-fg doc-table-header-bg doc-table-border doc-table-num-font doc-table-footer-weight doc-table-footer-bg doc-table-stripe-bg doc-bg doc-fg doc-letter-margin-right doc-letter-margin-left doc-fold-mark-1 doc-mark-length doc-mark-inset doc-mark-width doc-mark-color doc-punch-mark-length doc-fold-mark-2 doc-running-header doc-running-footer doc-serif doc-page-label doc-page-separator doc-page-suffix doc-window-top doc-window-height doc-window-width doc-window-padding doc-window-left doc-rule-scale doc-rule-strong-scale doc-table-flush doc-table-num-scale z-raised border-width border-width-strong texture-page */

/* ── Page Rules ──
   Named pages. An unnamed `@page` is global once this sheet is bundled: every
   printed page of the app took the document's paper, margins and counter.
   A document now asks for its own page by name (`page:` below), so a file
   with no document prints on the browser's defaults. (A file that does print
   a document hands its <body> the same page — see the print block — so an
   empty element before the document cannot force a blank first page.)

   `faqir-document` is the token-driven page — paper and margins from
   tokens/document.css, read at :root because a page box inherits from the
   root alone. A document that states BOTH data-format and data-orientation
   pins its paper with a literal named page instead, which is what lets one
   file print an A4 and a Letter document side by side. Page selector lists
   (`@page a, b`) are not parsed by Chromium, so each page is spelled out. */
@page faqir-document {
  size: var(--page-format) var(--page-orientation);
  margin: var(--page-margin-top)
          var(--page-margin-right)
          var(--page-margin-bottom)
          var(--page-margin-left);
}

@page faqir-document-a4-portrait {
  size: A4 portrait;
  margin: var(--page-margin-top) var(--page-margin-right) var(--page-margin-bottom) var(--page-margin-left);
}

@page faqir-document-a4-landscape {
  size: A4 landscape;
  margin: var(--page-margin-top) var(--page-margin-right) var(--page-margin-bottom) var(--page-margin-left);
}

@page faqir-document-letter-portrait {
  size: letter portrait;
  margin: var(--page-margin-top) var(--page-margin-right) var(--page-margin-bottom) var(--page-margin-left);
}

@page faqir-document-letter-landscape {
  size: letter landscape;
  margin: var(--page-margin-top) var(--page-margin-right) var(--page-margin-bottom) var(--page-margin-left);
}

/* The `letter` variant: a DIN 5008 business letter on A4 portrait. The fold
   and punch marks are page-margin boxes, because nothing in the document can
   paint outside the page area. The top box ends at the first fold, the bottom
   box begins at the second, and the middle box — which a page centres between
   the top and bottom margins — is a zero-height rule at 148.5mm, which is why
   this page keeps both margins at --page-margin-top. */
@page faqir-document-letter {
  size: A4 portrait;
  margin: var(--page-margin-top)
          var(--doc-letter-margin-right)
          var(--page-margin-top)
          var(--doc-letter-margin-left);

  @left-top {
    content: "";
    box-sizing: border-box;
    block-size: calc(var(--doc-fold-mark-1) - var(--page-margin-top));
    inline-size: var(--doc-mark-length);
    margin-inline-start: var(--doc-mark-inset);
    margin-inline-end: auto;
    border-block-end: var(--doc-mark-width) solid var(--doc-mark-color);
  }

  @left-middle {
    content: "";
    box-sizing: border-box;
    block-size: 0;
    inline-size: var(--doc-punch-mark-length);
    margin-inline-start: var(--doc-mark-inset);
    margin-inline-end: auto;
    border-block-start: var(--doc-mark-width) solid var(--doc-mark-color);
  }

  @left-bottom {
    content: "";
    box-sizing: border-box;
    block-size: calc(297mm - var(--page-margin-top) - var(--doc-fold-mark-2));
    inline-size: var(--doc-mark-length);
    margin-inline-start: var(--doc-mark-inset);
    margin-inline-end: auto;
    border-block-start: var(--doc-mark-width) solid var(--doc-mark-color);
  }
}

/* Margin boxes. They live on the unnamed page so that every faqir-document*
   page shares them; each one's content is a custom property that is `none`
   until a document asks for it (the counter is switched on, in @media print
   below, only in a file that contains a document). Margin boxes read the
   ROOT's custom properties — a page box is not an element and has no other
   ancestor — which is also why `attr()` cannot reach a document's attributes
   from here, and why the running strings are root tokens. */
@page {
  /* The running header as a string (`--doc-running-header`): the Chromium
     path, since Chromium has no running elements. */
  @top-left {
    content: var(--doc-running-header);
    white-space: pre-wrap;
    vertical-align: var(--faqir-doc-running-header-align, middle);
    padding-block-end: var(--faqir-doc-running-gap, 0);
    border-block-end: var(--faqir-doc-running-rule, none);
    font-family: var(--doc-font);
    font-size: var(--doc-legal-size);
    color: var(--doc-legal-color);
  }

  /* Paged-media engines (Prince, WeasyPrint, Vivliostyle) consume the running
     elements. Browser engines that do not support element() keep the fixed
     fallback declared under @media print below. */
  @top-center {
    content: element(faqir-doc-header);
  }

  /* The running footer as a string (`--doc-running-footer`). With
     data-running="margin" it and the counter are top-aligned under one
     shared hairline, so the footer's first line and the counter share a
     baseline. */
  @bottom-left {
    content: var(--doc-running-footer);
    white-space: pre-wrap;
    vertical-align: var(--faqir-doc-running-footer-align, middle);
    padding-block-start: var(--faqir-doc-running-gap, 0);
    border-block-start: var(--faqir-doc-running-rule, none);
    font-family: var(--doc-font);
    font-size: var(--doc-legal-size);
    color: var(--doc-legal-color);
  }

  @bottom-center {
    content: element(faqir-doc-footer);
  }

  /* Chromium 131+ and dedicated paged-media engines support page counters in
     margin boxes. Browser-generated headers/footers should stay disabled. */
  @bottom-right {
    content: var(--faqir-doc-page-counter, none);
    vertical-align: var(--faqir-doc-running-footer-align, middle);
    padding-block-start: var(--faqir-doc-running-gap, 0);
    border-block-start: var(--faqir-doc-running-rule, none);
    font-family: var(--doc-font);
    font-size: var(--doc-legal-size);
    color: var(--doc-legal-color);
  }
}

/* The first printed page: `data-header="from-page-2"` (and every letter, whose
   first page carries the letterhead) leaves the running header off it. */
@page :first {
  @top-left {
    content: var(--faqir-doc-running-header-first, var(--doc-running-header));
  }
}

/* ── Which page a document prints on ── */
[data-ui="document"] {
  page: faqir-document;
}

[data-ui="document"]:where([data-format="a4"][data-orientation="portrait"]) {
  page: faqir-document-a4-portrait;
}

[data-ui="document"]:where([data-format="a4"][data-orientation="landscape"]) {
  page: faqir-document-a4-landscape;
}

[data-ui="document"]:where([data-format="letter"][data-orientation="portrait"]) {
  page: faqir-document-letter-portrait;
}

[data-ui="document"]:where([data-format="letter"][data-orientation="landscape"]) {
  page: faqir-document-letter-landscape;
}

[data-ui="document"]:where([data-variant="letter"]) {
  page: faqir-document-letter;
}

/* ── Base (Screen) ──
   Mobile-first (task 0.8-09): a phone gives the page no room for a paper margin,
   so the sheet fills the viewport and squares its corners here; the canon md
   block at the foot restores the page-on-a-desk framing. `max-width` is not a
   media query — it is the paper's own measure and applies at every width. */
[data-ui="document"] {
  max-width: var(--doc-max-width);
  margin: var(--space-4) auto;
  padding: var(--space-6) var(--space-4);
  background-color: var(--color-bg, #fff);
  background-image: var(--texture-page);
  color: var(--color-fg);
  font-family: var(--doc-font, var(--font-body));
  font-size: var(--doc-font-size);
  line-height: var(--doc-line-height);
  /* The fallback here used to spell out two rgba() layers, which is a shadow
     colour no theme could reach. --shadow-lg is always defined by the token
     layer, and it now carries --shadow-color, so the fallback is gone rather
     than re-tokenised. */
  box-shadow: var(--shadow-lg);
  border-radius: 0;
  position: relative;
  /* A quotation inside a document is set in the document's own sizes: the
     verbatim at body size, its attribution at the legal size — never the
     screen ramp's --text-lg over --text-sm. `quote` reads these two knobs, so
     this needs no selector into the quote at all. */
  --quote-text-size: var(--doc-font-size);
  --quote-author-size: var(--doc-legal-size);
}

/* ── Format: Letter ── */
[data-ui="document"][data-format="letter"] {
  max-width: 8.5in;
}

/* ── Running header ──
   header remains a non-breaking selector alias for pre-1.1.0 documents. */
[data-ui="document"] > [data-part="doc-header"],
[data-ui="document"] > [data-part="header"] {
  margin-block-end: var(--doc-section-gap);
  padding-block-end: var(--doc-component-gap);
  border-block-end: var(--border-width) solid var(--color-border);
}

/* ── Body ── */
[data-ui="document"] [data-part="body"] {
  display: flex;
  flex-direction: column;
  gap: var(--doc-section-gap);
}

/* ── Headings ──
   The document's own heading face and weight (1.1A-21): a print theme sets
   --doc-heading-font / --doc-heading-weight to give its titles a voice apart
   from the body copy. Both default to the page's role families in
   tokens/document.css — and the print themes keep them there, so a face the
   project installed reaches the paper (forecraft #38) — and each falls
   back to what a heading rendered before the tokens had a reader. A heading
   that carries its own data-weight keeps it — that is the author asking. */
[data-ui="document"] :is(h1, h2, h3, h4, h5, h6) {
  font-family: var(--doc-heading-font, var(--font-body));
  font-weight: var(--doc-heading-weight, var(--weight-bold));
}

/* ── Running footer ──
   footer remains a non-breaking selector alias for pre-1.1.0 documents. */
[data-ui="document"] > [data-part="doc-footer"],
[data-ui="document"] > [data-part="footer"] {
  margin-block-start: var(--doc-section-gap);
  padding-block-start: var(--doc-component-gap);
  border-block-start: var(--border-width) solid var(--color-border);
  font-size: var(--doc-legal-size);
  color: var(--doc-legal-color);
}

/* ── Variant: Invoice ── */
[data-ui="document"][data-variant="invoice"] {
  font-size: var(--doc-font-size);
}

[data-ui="document"][data-variant="invoice"] > [data-part="doc-header"],
[data-ui="document"][data-variant="invoice"] > [data-part="header"] {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  flex-wrap: wrap;
  gap: var(--doc-component-gap);
}

[data-ui="document"][data-variant="invoice"] [data-part="body"] {
  gap: var(--doc-component-gap);
}

/* ── Variant: Form ── */
[data-ui="document"][data-variant="form"] [data-part="body"] {
  gap: var(--doc-component-gap);
}

[data-ui="document"][data-variant="form"] > [data-part="doc-header"],
[data-ui="document"][data-variant="form"] > [data-part="header"] {
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
}

/* ── Variant: Report ── */
[data-ui="document"][data-variant="report"] {
  /* A report is serif-set by definition. It re-points the document's own font
     ROLE rather than its `font-family`, so every doc primitive nested inside it
     (key-value, callout, signature — all of which read --doc-font) follows the
     report into serif instead of staying sans inside a serif page. `report` is
     the author asking for serif; a theme that wants its own document face
     declares --doc-font at :root, which this variant deliberately outranks.
     The face is a token, --doc-serif, which follows the project's serif role
     (--font-serif) — so an installed serif sets the report, and the system
     faces are only that role's fallbacks. */
  --doc-font: var(--doc-serif);
  line-height: 1.6;
}

[data-ui="document"][data-variant="report"] > [data-part="doc-header"],
[data-ui="document"][data-variant="report"] > [data-part="header"] {
  text-align: center;
}

[data-ui="document"][data-variant="report"] [data-part="body"] {
  gap: var(--doc-section-gap);
}

/* ── Variant: Letter (DIN 5008) ──
   On screen the address is a block between letterhead and body; the print
   block below puts it in the envelope window and draws the fold marks. */
[data-ui="document"][data-variant="letter"] > [data-part="address"] {
  margin-block-end: var(--doc-section-gap);
  font-style: normal;
}

/* ── Document-context table overrides ──
   Tables inside a document pattern use doc-table tokens
   for compact, data-dense rendering. */
[data-ui="document"] [data-ui="table"] [data-part="th"] {
  padding: var(--doc-table-cell-pad-y) var(--doc-table-cell-pad-x);
  font-size: var(--doc-table-font-size);
  font-weight: var(--doc-table-header-weight);
  color: var(--doc-table-header-fg);
  background: var(--doc-table-header-bg);
  border-bottom-color: var(--doc-table-border);
}

[data-ui="document"] [data-ui="table"] [data-part="td"] {
  padding: var(--doc-table-cell-pad-y) var(--doc-table-cell-pad-x);
  font-size: var(--doc-table-font-size);
  border-bottom-width: calc(var(--border-width) * var(--doc-rule-scale));
}

/* The rule under the head. Not in a `bordered` table, whose grid draws every
   cell edge at one weight. */
[data-ui="document"] [data-ui="table"]:not([data-variant="bordered"]) [data-part="th"] {
  border-bottom-width: calc(var(--border-width-strong) * var(--doc-rule-strong-scale));
}

/* A row's outer cells: a print theme that sets the rules flush with the text
   column takes this inset away (forecraft #48). */
[data-ui="document"] [data-ui="table"] :is([data-part="th"], [data-part="td"]):first-child {
  padding-inline-start: calc(var(--doc-table-cell-pad-x) * (1 - var(--doc-table-flush)));
}

[data-ui="document"] [data-ui="table"] :is([data-part="th"], [data-part="td"]):last-child {
  padding-inline-end: calc(var(--doc-table-cell-pad-x) * (1 - var(--doc-table-flush)));
}

[data-ui="document"] [data-ui="table"] [data-format="number"],
[data-ui="document"] [data-ui="table"] [data-format="currency"],
[data-ui="document"] [data-ui="table"] [data-format="percent"] {
  font-variant-numeric: var(--doc-table-num-font);
}

[data-ui="document"] [data-ui="table"] [data-part="td"]:is([data-format="number"], [data-format="currency"], [data-format="percent"]) {
  font-size: calc(var(--doc-table-font-size) * var(--doc-table-num-scale));
}

[data-ui="document"] [data-ui="table"] [data-part="tfoot"] [data-part="td"] {
  font-weight: var(--doc-table-footer-weight);
  background: var(--doc-table-footer-bg);
  border-top-color: var(--doc-table-border);
  border-top-width: calc(var(--border-width-strong) * var(--doc-rule-strong-scale));
}

[data-ui="document"] [data-ui="table"][data-variant="striped"] [data-part="tbody"] [data-part="tr"]:nth-child(even) [data-part="td"] {
  background: var(--doc-table-stripe-bg);
}

/* ── Document-context separator overrides ── */
[data-ui="document"] [data-ui="separator"] {
  border-top-color: var(--color-border);
}

/* ── Responsive ──
   Canon tiers only, min-width only (FAQIR-NEXT §19). One step: from md up there
   is room around the sheet, so it gets its margin, its printer's margins and its
   rounded corners back.

   Deliberately BEFORE the print block. A `min-width` query is true on paper too
   — a Letter page box is 8.5in ≈ 816px, comfortably past the md floor — so if
   this sat last it would hand a printed document a 2rem margin and a rounded
   corner. The pre-canon `max-width: 768px` form never matched a page and could
   sit anywhere; the mobile-first form has to be outranked by print. */
@media (min-width: 48rem) {
  [data-ui="document"] {
    margin: var(--space-8) auto;
    padding: var(--space-12) var(--space-8);
    border-radius: var(--radius-md, 0.375rem);
  }
}

/* ── Print ── */
@media print {
  /* A change of page name is a forced break, and Chromium honours it even at
     the very top of the flow: an empty element before a document — a toast
     region, a skip-link host — printed a blank first page. So the <body> of a
     file that prints a document takes the document's page as well, and nothing
     in it changes page name except where two documents ask for different paper
     (the last rule that matches names the body's page). Without a document the
     body is unnamed, and prints on the browser's defaults. */
  html:where(:has([data-ui="document"])) > body {
    page: faqir-document;
  }

  html:where(:has([data-ui="document"]:where([data-format="a4"][data-orientation="portrait"]))) > body {
    page: faqir-document-a4-portrait;
  }

  html:where(:has([data-ui="document"]:where([data-format="a4"][data-orientation="landscape"]))) > body {
    page: faqir-document-a4-landscape;
  }

  html:where(:has([data-ui="document"]:where([data-format="letter"][data-orientation="portrait"]))) > body {
    page: faqir-document-letter-portrait;
  }

  html:where(:has([data-ui="document"]:where([data-format="letter"][data-orientation="landscape"]))) > body {
    page: faqir-document-letter-landscape;
  }

  html:where(:has([data-ui="document"]:where([data-variant="letter"]))) > body {
    page: faqir-document-letter;
  }

  [data-ui="document"] {
    max-width: none;
    margin: 0;
    padding: 0;
    box-shadow: none;
    border-radius: 0;
    background: var(--doc-bg, white);
    color: var(--doc-fg, black);
  }

  /* Browser fallback first; supporting paged-media engines override it with
     running(). Unsupported declarations are discarded, leaving position:fixed
     to repeat the same DOM element on every printed page. */
  [data-ui="document"] > [data-part="doc-header"],
  [data-ui="document"] > [data-part="header"] {
    position: fixed;
    position: running(faqir-doc-header);
    inset-block-start: 0;
    inset-inline: 0;
    block-size: var(--doc-running-header-height);
    box-sizing: border-box;
    z-index: var(--z-raised);
    margin-block-end: 0;
    padding-block-end: var(--doc-running-gap);
    border-block-end: var(--border-width) solid var(--doc-print-border-color);
    background: var(--doc-bg);
    transform: translateZ(0);
  }

  [data-ui="document"] > [data-part="doc-footer"],
  [data-ui="document"] > [data-part="footer"] {
    position: fixed;
    position: running(faqir-doc-footer);
    inset-block-end: 0;
    inset-inline: 0;
    block-size: var(--doc-running-footer-height);
    box-sizing: border-box;
    z-index: var(--z-raised);
    margin-block-start: 0;
    padding-block-start: var(--doc-running-gap);
    border-block-start: var(--border-width) solid var(--doc-print-border-color);
    background: var(--doc-bg);
    transform: translateZ(0);
  }

  /* Chromium keeps fixed elements out of flow. Clone the body decoration at
     each page fragment so content never enters the repeated header/footer
     areas. Engines with native running() support use their margin boxes. */
  @supports not (position: running(faqir-doc-header)) {
    [data-ui="document"] > [data-part="body"] {
      padding-block-start: calc(var(--doc-running-header-height) + var(--doc-running-gap));
      padding-block-end: calc(var(--doc-running-footer-height) + var(--doc-running-gap));
      -webkit-box-decoration-break: clone;
      box-decoration-break: clone;
    }

    /* A part drawn in the page margin (or, for a letter, in flow on page 1)
       needs no room kept for it on every page. */
    [data-ui="document"]:is([data-running="margin"], [data-header="from-page-2"], [data-variant="letter"]) > [data-part="body"] {
      padding-block-start: 0;
    }

    [data-ui="document"][data-running="margin"] > [data-part="body"] {
      padding-block-end: 0;
    }
  }

  /* ── Running strings in the page margin ──
     data-running="margin" prints the running header and footer from the
     --doc-running-header / --doc-running-footer strings in the page-margin
     boxes, with the counter on the footer's line; data-header="from-page-2"
     does the same for the header alone and leaves it off the first page. The
     DOM parts stay for the screen. (A letter keeps its doc-header: it is the
     letterhead, printed in flow on the first page.) */
  [data-ui="document"][data-running="margin"] > :is([data-part="doc-header"], [data-part="header"], [data-part="doc-footer"], [data-part="footer"]),
  [data-ui="document"][data-header="from-page-2"]:not([data-variant="letter"]) > :is([data-part="doc-header"], [data-part="header"]) {
    display: none;
  }

  /* The margin boxes read the root, so a document's attributes reach them
     through :has() on <html>. Not `:root`: a component sheet may load before
     or after a theme, so it declares no token at the root — these set private
     --faqir-* knobs the margin boxes read, and the tokens a document's
     attributes restate (its language's counter words, a Form A letter's
     geometry) are restated in tokens/document.css. :where() keeps every one
     at a type selector's weight. */
  html:where(:has([data-ui="document"])) {
    --faqir-doc-page-counter: var(--doc-page-label) counter(page) var(--doc-page-separator) counter(pages) var(--doc-page-suffix);
  }

  html:where(:has([data-ui="document"][data-running="margin"])) {
    --faqir-doc-running-header-align: bottom;
    --faqir-doc-running-footer-align: top;
    --faqir-doc-running-gap: var(--doc-running-gap);
    --faqir-doc-running-rule: var(--border-width) solid var(--doc-print-border-color);
  }

  html:where(:has([data-ui="document"]:is([data-header="from-page-2"], [data-variant="letter"]))) {
    --faqir-doc-running-header-first: none;
  }

  /* ── Variant: Letter (DIN 5008) ──
     Page 1 is three bands measured from the top of the sheet: the letterhead
     (the doc-header, in flow and not repeated) down to the address window,
     the address in the window, then the body. Form A (data-form="a") moves
     the window and the folds up: tokens/document.css restates the three. */
  [data-ui="document"][data-variant="letter"] > :is([data-part="doc-header"], [data-part="header"]) {
    position: static;
    box-sizing: border-box;
    block-size: calc(var(--doc-window-top) - var(--page-margin-top));
    margin-block-end: 0;
    padding-block-end: 0;
    border-block-end: 0;
    overflow: hidden;
  }

  [data-ui="document"][data-variant="letter"] > [data-part="address"] {
    box-sizing: border-box;
    block-size: var(--doc-window-height);
    inline-size: calc(var(--doc-window-width) - var(--doc-window-padding));
    margin-block: 0;
    margin-inline-start: calc(var(--doc-window-left) + var(--doc-window-padding) - var(--doc-letter-margin-left));
    overflow: hidden;
  }

  /* Print border color for nested tables */
  [data-ui="document"] [data-ui="table"] [data-part="th"] {
    border-bottom-color: var(--doc-print-border-color);
  }

  [data-ui="document"] [data-ui="table"] [data-part="td"] {
    border-bottom-color: var(--doc-print-border-color);
  }
}



/* === patterns/faq.css === */
/* @ui:component faq */
/* @ui:tokens space-4 space-12 space-3 space-10 space-16 space-6 space-8 font-body font-heading font-ui color-fg color-bg color-fg-muted text-xl text-lg text-sm text-3xl heading-weight heading-tracking heading-transform heading-caps heading-leading leading-relaxed leading-normal measure-content */

/* ── Root ──
   A one-column grid; the layout variants only change how that grid flows, so
   the same markup reads centred or split. Every unconditional declaration is
   the PHONE case and the `@media` floors at the foot of the sheet widen it.

   The questions themselves are nested collapsibles — native <details>, so the
   whole section opens and closes with zero JavaScript. This sheet never
   touches a collapsible's own parts: the stack is spaced through
   [data-part="items"], and the numbering below hangs off the collapsible's
   ROOT, which is this part's direct child. */
[data-ui="faq"] {
  display: grid;
  gap: var(--space-4);
  padding-block: var(--space-12);
  padding-inline: var(--space-4);
  font-family: var(--font-body);
  color: var(--color-fg);
  background: var(--color-bg);
}

/* ── Intro ──
   The split layout gathers heading, description and footer into one column
   so they can stick together while the questions scroll. The stacked layout
   does not need the wrapper, so every intro part below is reached both ways. */
[data-ui="faq"] > [data-part="intro"] {
  display: grid;
  gap: var(--space-4);
  align-content: start;
}

/* ── Heading ── */
[data-ui="faq"] > [data-part="heading"],
[data-ui="faq"] > :where([data-part="intro"]) > [data-part="heading"] {
  margin: 0;
  font-family: var(--font-heading);
  font-size: var(--text-xl);
  font-weight: var(--heading-weight);
  letter-spacing: var(--heading-tracking);
  text-transform: var(--heading-transform);
  font-variant-caps: var(--heading-caps);
  line-height: var(--heading-leading);
  text-wrap: balance;
}

/* ── Description ── */
[data-ui="faq"] > [data-part="description"],
[data-ui="faq"] > :where([data-part="intro"]) > [data-part="description"] {
  margin: 0;
  font-size: var(--text-lg);
  line-height: var(--leading-relaxed);
  color: var(--color-fg-muted);
}

/* ── Items ──
   The stack of collapsibles. The gap is the only thing this part draws — the
   border, padding and chevron belong to the collapsible — and it is a knob so
   a page can tighten a long list without re-styling the primitive. The text
   alignment is reset here because the stacked layout centres its prose and a
   question should still read from the start edge. */
[data-ui="faq"] > [data-part="items"] {
  display: grid;
  gap: var(--faq-gap, var(--space-3));
  margin-block-start: var(--space-4);
  text-align: start;
}

/* ── Footer ── */
[data-ui="faq"] > [data-part="footer"],
[data-ui="faq"] > :where([data-part="intro"]) > [data-part="footer"] {
  margin: 0;
  margin-block-start: var(--space-4);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  color: var(--color-fg-muted);
}

/* ── Numbered ──
   A CSS counter on the items part, stepped by each direct child — the
   collapsible root, never its summary — and drawn by that child's ::before.
   The figure sits in a gutter opened with padding on the child, so the
   collapsible's own summary padding and chevron are untouched; it is a small
   UI-face number in the muted ink, a label rather than a headline. */
[data-ui="faq"][data-numbered] > :where([data-part="items"]) {
  counter-reset: faqir-faq;
}

[data-ui="faq"][data-numbered] > :where([data-part="items"]) > * {
  position: relative;
  padding-inline-start: var(--space-10);
  counter-increment: faqir-faq;
}

[data-ui="faq"][data-numbered] > :where([data-part="items"]) > *::before {
  content: counter(faqir-faq, decimal-leading-zero);
  position: absolute;
  inset-inline-start: var(--space-3);
  inset-block-start: var(--space-3);
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
  line-height: var(--leading-normal);
  color: var(--color-fg-muted);
}

/* ── Layout: stacked (default) ──
   One centred column no wider than the content measure: the grid's single
   track is capped and centred, so the prose is centred and the questions
   below it stay a comfortable reading width. */
[data-ui="faq"]:not([data-variant]),
[data-ui="faq"][data-variant="stacked"] {
  grid-template-columns: minmax(0, var(--measure-content));
  justify-content: center;
  text-align: center;
}

/* ── Layout: split ──
   One column on a phone, exactly like stacked but start-aligned; the second
   column and the sticky intro arrive at the lg floor. */
[data-ui="faq"][data-variant="split"] {
  grid-template-columns: minmax(0, 1fr);
  align-items: start;
}

/* ── Responsive ──
   Canon tiers only, min-width only, ascending. sm: the type scale and the
   block padding open up. lg: the split variant earns its second column and
   the intro sticks below the top edge so the heading keeps the questions
   company as a long list scrolls. */
@media (min-width: 40rem) {
  [data-ui="faq"] {
    padding-block: var(--space-16);
    padding-inline: var(--space-6);
  }

  [data-ui="faq"] > [data-part="heading"],
  [data-ui="faq"] > :where([data-part="intro"]) > [data-part="heading"] {
    font-size: var(--text-3xl);
  }
}

@media (min-width: 64rem) {
  [data-ui="faq"][data-variant="split"] {
    grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
    gap: var(--space-12);
  }

  [data-ui="faq"][data-variant="split"] > [data-part="intro"] {
    position: sticky;
    inset-block-start: var(--space-8);
  }

  [data-ui="faq"][data-variant="split"] > [data-part="items"] {
    margin-block-start: 0;
  }
}


/* === patterns/feature-grid.css === */
/* @ui:component feature-grid */
/* @ui:tokens color-bg color-fg color-fg-muted color-primary color-primary-subtle space-2 space-3 space-4 space-6 space-8 space-10 space-12 space-16 font-body font-heading text-base text-lg text-xl text-3xl weight-bold leading-tight leading-normal leading-relaxed radius-md heading-weight heading-tracking heading-transform heading-caps */

/* ── Root ──
   Mobile-first (task 0.8-09): everything outside the two `@media` blocks at the
   foot of the sheet is the phone case, and the canon floors widen it. */
[data-ui="feature-grid"] {
  display: grid;
  gap: var(--space-4);
  padding-block: var(--space-12);
  padding-inline: var(--space-4);
  font-family: var(--font-body);
  color: var(--color-fg);
  background: var(--color-bg);
}

/* ── Section heading ──
   The heading voice, like bento, faq, pricing and the hero: family, weight,
   tracking, case and caps come from the theme type axis, so a one-weight
   display face is never asked for a bold it does not have. */
[data-ui="feature-grid"] [data-part="heading"] {
  margin: 0;
  font-family: var(--font-heading);
  font-size: var(--text-xl);
  font-weight: var(--heading-weight);
  letter-spacing: var(--heading-tracking);
  text-transform: var(--heading-transform);
  font-variant-caps: var(--heading-caps);
  line-height: var(--leading-tight);
  text-wrap: balance;
}

[data-ui="feature-grid"] [data-part="description"] {
  margin: 0;
  max-inline-size: 44rem;
  font-size: var(--text-lg);
  line-height: var(--leading-relaxed);
  color: var(--color-fg-muted);
}

/* ── Items ──
   A real <ul>; the marker is removed rather than the semantics. Column count
   comes from data-cols on the root, mirroring the grid primitive's vocabulary —
   and, since 0.8-04, its mobile-first SEMANTICS too: `data-cols` is the widest
   count, reached at the lg floor, and one column is the phone base. The per-count
   rules therefore live in the tier blocks, not here. */
[data-ui="feature-grid"] [data-part="items"] {
  display: grid;
  gap: var(--space-6);
  margin: 0;
  margin-block-start: var(--space-8);
  padding: 0;
  list-style: none;
  grid-template-columns: 1fr;
}

/* ── Item ── */
[data-ui="feature-grid"] [data-part="item"] {
  display: grid;
  gap: var(--space-2);
  align-content: start;
}

/* ── Item icon ──
   The plate WRAPS the icon primitive; it never is one. An icon paints its glyph
   with background-color:currentColor through a mask, so a background on the
   icon element would repaint the glyph instead of framing it. The nested icon
   inherits both its size (1em) and its colour (currentColor) from this box. */
[data-ui="feature-grid"] [data-part="icon"] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: var(--space-10);
  block-size: var(--space-10);
  margin-block-end: var(--space-2);
  font-size: var(--text-xl);
  color: var(--color-primary);
  background: var(--color-primary-subtle);
  border-radius: var(--radius-md);
}

[data-ui="feature-grid"] [data-part="item-title"] {
  margin: 0;
  font-family: var(--font-heading);
  font-size: var(--text-lg);
  font-weight: var(--heading-weight);
  letter-spacing: var(--heading-tracking);
  line-height: var(--leading-tight);
}

[data-ui="feature-grid"] [data-part="item-description"] {
  margin: 0;
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  color: var(--color-fg-muted);
}

/* ── Footer ── */
[data-ui="feature-grid"] [data-part="footer"] {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-block-start: var(--space-10);
}

/* ── Responsive ──
   Canon tiers only, min-width only, ascending (FAQIR-NEXT §19). One column on a
   phone, two from sm, the declared count from lg — the same 640/1024 steps as
   before, now expressed as floors, so the boundary belongs to the wider layout.
   `data-cols="2"` needs no sm rule (two is already the sm default) but does need
   an lg one, or it would inherit lg's three. */
@media (min-width: 40rem) {
  [data-ui="feature-grid"] {
    padding-block: var(--space-16);
    padding-inline: var(--space-6);
  }

  [data-ui="feature-grid"] [data-part="heading"] {
    font-size: var(--text-3xl);
  }

  [data-ui="feature-grid"] [data-part="items"] {
    grid-template-columns: repeat(2, 1fr);
    gap: var(--space-8);
  }
}

@media (min-width: 64rem) {
  [data-ui="feature-grid"] [data-part="items"] {
    grid-template-columns: repeat(3, 1fr);
  }

  [data-ui="feature-grid"][data-cols="2"] [data-part="items"] {
    grid-template-columns: repeat(2, 1fr);
  }

  [data-ui="feature-grid"][data-cols="3"] [data-part="items"] {
    grid-template-columns: repeat(3, 1fr);
  }

  [data-ui="feature-grid"][data-cols="4"] [data-part="items"] {
    grid-template-columns: repeat(4, 1fr);
  }
}


/* === patterns/form-page.css === */
/* @ui:component form-page */
/* @ui:tokens color-fg color-fg-muted measure-narrow space-5 space-8 font-body text-sm text-2xl weight-semibold leading-tight leading-normal */
/* form-page — page-level framing for a schema-rendered form.
   The markup is emitted verbatim by @faqir-ui/forms (this reference page is the
   pinned golden target for that generator), so every field's look comes from the
   composed primitives: field-group, input, radio-group, textarea, checkbox. This
   sheet only sets the page's reading measure and vertical rhythm — the plain
   generated form has no data-ui root, so it is scoped to the bare l-data form
   that the generator produces (the wizard form carries data-ui and is excluded).
   Attribute + token selectors only; logical properties throughout.

   One step between everything in the form: the heading, the description, every
   field and card, the buttons. It is the form's data-gap (the generator writes
   data-gap="4"), read as --flow-space, which a card body inside the form keeps
   too, so a grouped form and a wizard step space their fields exactly as a flat
   form does. The form is a grid (one column) and the gap is its row gap; the
   rhythm's margin on its children comes off, since the gap already is that
   step. A field-group with data-span turns the columns into six from the md
   tier (field-group.css). */

:where(form[l-data]:not([data-ui])) {
  display: grid;
  row-gap: var(--flow-space, var(--space-5));
  max-inline-size: var(--measure-narrow);
  margin-inline: auto;
  padding-block: var(--space-8);
  font-family: var(--font-body);
}

:where(form[l-data]:not([data-ui])) > :where(*) {
  margin-block-start: 0;
}

:where(form[l-data]:not([data-ui]) > h1) {
  margin: 0;
  font-size: var(--text-2xl);
  font-weight: var(--weight-semibold);
  line-height: var(--leading-tight);
  color: var(--color-fg);
}

:where(form[l-data]:not([data-ui]) > p) {
  margin: 0;
  color: var(--color-fg-muted);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
}


/* === patterns/hero.css === */
/* @ui:component hero */
/* @ui:tokens color-bg color-fg color-fg-muted space-3 space-4 space-6 space-8 space-12 space-16 space-20 space-24 space-32 font-heading font-body heading-weight heading-tracking heading-transform heading-caps heading-leading text-sm text-base text-lg text-3xl text-4xl weight-bold leading-tight leading-relaxed radius-lg texture-surface measure-wide motion-reveal-duration motion-reveal-ease motion-stagger motion-reveal-distance motion-reveal-scale */

/* ── Root ──
   A one-column grid by default; the layout variants only change how that grid
   flows, so the same markup works centred or split.

   Mobile-first (task 0.8-09): every declaration here is the PHONE case, and the
   `@media (min-width: …)` blocks at the foot of the sheet widen it from a canon
   floor up. Nothing below is an override of something bigger. */
[data-ui="hero"] {
  display: grid;
  gap: var(--space-4);
  padding-block: var(--space-12);
  padding-inline: var(--space-4);
  font-family: var(--font-body);
  color: var(--color-fg);
  /* The page colour unless the author says otherwise; inside a backdrop the
     rule below makes it transparent so the light behind it shows. */
  background-color: var(--hero-bg, var(--color-bg));
  background-image: var(--texture-surface);
}

/* A hero inside a backdrop lets the backdrop show: an opaque --color-bg fill
   covered the scene the page wrapped it in. Zero specificity, so any
   `--hero-bg` the author sets on the hero itself (a rule or inline) still
   wins. */
:where([data-ui="backdrop"] [data-ui="hero"]) {
  --hero-bg: transparent;
}

/* ── Eyebrow ── */
[data-ui="hero"] [data-part="eyebrow"] {
  justify-self: start;
  margin-block-end: var(--space-3);
}

/* ── Headline ── */
[data-ui="hero"] [data-part="headline"] {
  margin: 0;
  font-family: var(--font-heading);
  font-size: var(--hero-display-size, var(--text-3xl));
  font-weight: var(--heading-weight);
  letter-spacing: var(--heading-tracking);
  text-transform: var(--heading-transform);
  font-variant-caps: var(--heading-caps);
  line-height: var(--heading-leading);
  color: var(--color-fg);
  text-wrap: balance;
}

/* ── Description ── */
[data-ui="hero"] [data-part="description"] {
  margin: 0;
  max-inline-size: 42rem;
  font-size: var(--text-base);
  line-height: var(--leading-relaxed);
  color: var(--color-fg-muted);
}

/* ── Actions ──
   Stacked and full-bleed on a phone: two side-by-side buttons in 320px of
   viewport are two truncated buttons. They become a row at the sm floor. */
[data-ui="hero"] [data-part="actions"] {
  display: flex;
  flex-wrap: wrap;
  flex-direction: column;
  align-items: stretch;
  inline-size: 100%;
  gap: var(--space-3);
  margin-block-start: var(--space-4);
}

/* ── Note ── */
[data-ui="hero"] [data-part="note"] {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--color-fg-muted);
}

/* ── Media ── */
[data-ui="hero"] [data-part="media"] {
  margin: 0;
  border-radius: var(--radius-lg);
  overflow: hidden;
}

/* ── Layout: center (default) ── */
[data-ui="hero"][data-variant="center"] {
  justify-items: center;
  text-align: center;
  padding-block: var(--space-12);
}

[data-ui="hero"][data-variant="center"] [data-part="eyebrow"] {
  justify-self: center;
}

[data-ui="hero"][data-variant="center"] [data-part="actions"] {
  justify-content: center;
}

/* ── Layout: split ──
   Copy and media share the row; [data-part="content"] keeps the text column a
   grid of its own so the inner rhythm matches the centred variant. */
[data-ui="hero"][data-variant="split"] {
  grid-template-columns: 1fr;
  align-items: center;
  gap: var(--space-8);
  padding-block: var(--space-16);
}

[data-ui="hero"][data-variant="split"] [data-part="content"] {
  display: grid;
  gap: var(--space-4);
  justify-items: start;
}

/* --hero-display-size sizes the headline in every layout; unset, the split
   layout keeps --text-3xl at every width (its column is half the row). */
[data-ui="hero"][data-variant="split"] [data-part="headline"] {
  font-size: var(--hero-display-size, var(--text-3xl));
}

/* ── Layout: cover ──
   The full-bleed opener: near a whole viewport tall, the words anchored to the
   bottom-start corner with a display-size headline, and the media slot moved
   BEHIND them as the backdrop. `svh` is the small viewport — the height left
   when a phone's browser chrome is showing — so the headline is never pushed
   under the toolbar; engines without it keep the `vh` line above it.

   `isolation` gives the media and the scrim a stacking context of their own:
   their negative z-index sits above the section's fill and below the words.
   `clip` trims an oversized backdrop without making the section a scroll
   container. A single `minmax(0, 1fr)` track lets a long word wrap instead of
   widening the page at 360px. */
[data-ui="hero"][data-variant="cover"] {
  position: relative;
  isolation: isolate;
  overflow: clip;
  grid-template-columns: minmax(0, 1fr);
  align-content: end;
  justify-items: start;
  min-block-size: 88vh;
  min-block-size: 88svh;
  padding-block: var(--space-24) var(--space-12);
  /* Full-bleed ground, aligned words: the gutter grows so the copy starts on
     the same line as a `container data-measure="wide"` below it, and never
     shrinks below the tier's own gutter (the same max() at each tier below). */
  padding-inline: max(var(--space-4), calc((100% - var(--measure-wide)) / 2));
}

/* The text column, when the copy is wrapped: the same inner rhythm as split. */
[data-ui="hero"][data-variant="cover"] > [data-part="content"] {
  display: grid;
  gap: var(--space-4);
  justify-items: start;
  min-inline-size: 0;
}

/* Display type: fluid between the scale's largest step and three and a half
   times it, so the theme's type scale still sets both ends — except that the
   floor gives way to 11vw on a phone, where a large-scale theme's biggest step
   would split an ordinary word across lines. The heading role
   (family, weight, tracking, case) is the theme's; the leading tightens with
   size, and a word longer than the line breaks rather than overflowing. */
[data-ui="hero"][data-variant="cover"] > [data-part="headline"],
[data-ui="hero"][data-variant="cover"] > :where([data-part="content"]) > [data-part="headline"] {
  max-inline-size: 20ch;
  font-size: var(--hero-display-size, clamp(min(var(--text-4xl), 11vw), calc(var(--text-sm) + 7vw), calc(var(--text-4xl) * 3.5)));
  line-height: calc(var(--leading-tight) * 0.84);
  overflow-wrap: anywhere;
  hyphens: auto;
  text-wrap: balance;
}

/* The backdrop. Absolutely filling the section behind the words; its single
   child (an image with data-variant="cover", a backdrop, a video) stretches
   to fill it as a grid item. Square-cornered: it is the section's edge. */
[data-ui="hero"][data-variant="cover"] > [data-part="media"] {
  position: absolute;
  inset: 0;
  z-index: -1;
  display: grid;
  border-radius: 0;
}

/* A scrim from the bottom edge, in the section's own colour, so the words
   keep their contrast over any photograph. Over a plain fill it is the fill
   itself and cannot be seen; a hero set to --hero-bg: transparent (inside a
   backdrop) gets a transparent scrim. --hero-scrim replaces it. */
[data-ui="hero"][data-variant="cover"]::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: var(--hero-scrim, linear-gradient(
    to top,
    color-mix(in oklch, var(--hero-bg, var(--color-bg)) 92%, transparent),
    color-mix(in oklch, var(--hero-bg, var(--color-bg)) 55%, transparent) 45%,
    transparent 85%
  ));
}

/* ── Entrance ──
   With data-animate the hero assembles itself on load, the way a staggered
   reveal's children do: eyebrow, headline, description, actions, note, then
   media, each one --motion-stagger after the last, whether the copy sits on
   the section or inside [data-part="content"]. One keyframe pair, a step
   number per part. `both` holds the from-state through each delay, so a late
   part is never seen, hidden, then revealed. The hero is above the fold, so
   this is a load entrance, not a scroll-scrubbed one. */
[data-ui="hero"][data-animate] > :is([data-part="eyebrow"], [data-part="headline"], [data-part="description"], [data-part="actions"], [data-part="note"], [data-part="media"]),
[data-ui="hero"][data-animate] > :where([data-part="content"]) > :is([data-part="eyebrow"], [data-part="headline"], [data-part="description"], [data-part="actions"], [data-part="note"]) {
  --faqir-hero-step: 0;
  animation: faqir-hero-rise var(--motion-reveal-duration) var(--motion-reveal-ease) both;
  animation-delay: calc(var(--motion-stagger) * var(--faqir-hero-step));
}

[data-ui="hero"][data-animate] > [data-part="headline"],
[data-ui="hero"][data-animate] > :where([data-part="content"]) > [data-part="headline"] { --faqir-hero-step: 1; }
[data-ui="hero"][data-animate] > [data-part="description"],
[data-ui="hero"][data-animate] > :where([data-part="content"]) > [data-part="description"] { --faqir-hero-step: 2; }
[data-ui="hero"][data-animate] > [data-part="actions"],
[data-ui="hero"][data-animate] > :where([data-part="content"]) > [data-part="actions"] { --faqir-hero-step: 3; }
[data-ui="hero"][data-animate] > [data-part="note"],
[data-ui="hero"][data-animate] > :where([data-part="content"]) > [data-part="note"] { --faqir-hero-step: 4; }
[data-ui="hero"][data-animate] > [data-part="media"] { --faqir-hero-step: 5; }

/* A cover's media is the stage, not the last act: it settles in place first
   (a fade and a slight zoom-out — sliding a full-bleed layer would open a gap
   at its edge) and the words arrive onto it. */
[data-ui="hero"][data-animate][data-variant="cover"] > [data-part="media"] {
  --faqir-hero-step: 0;
  animation-name: faqir-hero-settle;
}

/* Only a `from`: every part ends exactly where it already is. */
@keyframes faqir-hero-rise {
  from {
    opacity: 0;
    translate: 0 var(--motion-reveal-distance);
  }
}

@keyframes faqir-hero-settle {
  from {
    opacity: 0;
    scale: calc(2 - var(--motion-reveal-scale));
  }
}

/* ── Motion ──
   Reduced motion removes the entrance, not the content: every part is already
   in place. Paper gets the same treatment — a printed page has no entrance. */
@media (prefers-reduced-motion: reduce), print {
  [data-ui="hero"][data-animate] > :is([data-part="eyebrow"], [data-part="headline"], [data-part="description"], [data-part="actions"], [data-part="note"], [data-part="media"]),
  [data-ui="hero"][data-animate] > :where([data-part="content"]) > :is([data-part="eyebrow"], [data-part="headline"], [data-part="description"], [data-part="actions"], [data-part="note"]),
  [data-ui="hero"][data-animate][data-variant="cover"] > [data-part="media"] {
    animation: none;
  }
}

/* A cover on paper is as tall as its words. */
@media print {
  [data-ui="hero"][data-variant="cover"] {
    min-block-size: auto;
  }
}

/* ── Responsive ──
   Canon tiers only, min-width only, ascending (FAQIR-NEXT §19). The hero owns
   the page, so a viewport media query is the right rung of the doctrine here —
   the intrinsic and container-query rungs cannot see how much page is left.

   sm: the type scale and the block padding open up, and the action row is a row
   again. lg: the split variant earns its second column. The cover's padding
   grows at both floors; its headline needs no tier — it is fluid already. */
@media (min-width: 40rem) {
  [data-ui="hero"] {
    padding-block: var(--space-20);
    padding-inline: var(--space-6);
  }

  [data-ui="hero"][data-variant="center"] {
    padding-block: var(--space-20);
  }

  [data-ui="hero"] [data-part="headline"] {
    font-size: var(--hero-display-size, var(--text-4xl));
  }

  [data-ui="hero"] [data-part="description"] {
    font-size: var(--text-lg);
  }

  /* `normal` rather than a value of its own: this is the initial align-items,
     so the row is exactly the un-stacked default and nothing is "undone". */
  [data-ui="hero"] [data-part="actions"] {
    inline-size: auto;
    flex-direction: row;
    align-items: normal;
  }

  [data-ui="hero"][data-variant="cover"] {
    padding-block: var(--space-32) var(--space-16);
    padding-inline: max(var(--space-8), calc((100% - var(--measure-wide)) / 2));
  }
}

@media (min-width: 64rem) {
  [data-ui="hero"][data-variant="split"] {
    grid-template-columns: 1fr 1fr;
    gap: var(--space-12);
  }

  [data-ui="hero"][data-variant="cover"] {
    padding-block-end: var(--space-20);
    padding-inline: max(var(--space-16), calc((100% - var(--measure-wide)) / 2));
  }
}


/* === patterns/logo-cloud.css === */
/* @ui:component logo-cloud */
/* @ui:tokens space-6 space-10 space-4 space-8 space-32 space-12 font-body font-ui color-fg color-fg-muted text-sm weight-medium leading-normal measure-wide duration-normal ease-default */

/* ── Root ──
   A centred stack: the eyebrow over the logos. The row of logos is centred as
   a block, never justified — a "trusted by" strip with its logos pushed to the
   edges reads as a toolbar, not a chorus.

   Mobile-first (task 0.8-09): everything outside the `@media` block at the
   foot of the sheet is the phone case; the floor only opens the gaps. */
[data-ui="logo-cloud"] {
  display: grid;
  gap: var(--space-6);
  padding-block: var(--space-10);
  padding-inline: var(--space-4);
  font-family: var(--font-body);
  color: var(--color-fg);
  text-align: center;
}

/* ── Heading ──
   Small, muted, in the UI face: an eyebrow that names the strip without
   competing with the page's own headings. It is a <p>, so it stays out of the
   document outline — the section still points aria-labelledby at it. */
[data-ui="logo-cloud"] > [data-part="heading"] {
  margin: 0;
  font-family: var(--font-ui);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  line-height: var(--leading-normal);
  color: var(--color-fg-muted);
}

/* ── Items (grid layout) ──
   A wrapping, centred flex row — a cluster — rather than a column grid, so a
   strip of five logos and a strip of nine both sit in the middle with even
   air between them, and the last row centres itself. */
[data-ui="logo-cloud"] > [data-part="items"] {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  justify-self: center;
  gap: var(--space-6) var(--space-8);
  max-inline-size: var(--logo-cloud-max, var(--measure-wide));
  margin: 0;
  padding: 0;
  list-style: none;
}

/* ── Item ──
   Two homes: the pattern's own list, or a track of the nested marquee. The
   marquee's tracks are <ul> elements that are the marquee's own part, so the
   hop is written as the element, not the part — this sheet never names
   another component's slot. */
[data-ui="logo-cloud"] > :where([data-part="items"]) > [data-part="item"],
[data-ui="logo-cloud"] > :where([data-ui="marquee"]) > :where(ul) > [data-part="item"] {
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0;
  padding: 0;
}

/* ── Logo ──
   Every mark is set to one height and keeps its own width, so a wide wordmark
   and a square glyph read at the same visual weight. Dimmed and desaturated
   at rest so the strip is a texture, not a row of brand colours fighting the
   page; the colour returns under the pointer, or when focus lands inside the
   item (a logo wrapped in a link). */
[data-ui="logo-cloud"] > :where([data-part="items"]) > :where([data-part="item"]) > [data-part="logo"],
[data-ui="logo-cloud"] > :where([data-ui="marquee"]) > :where(ul) > :where([data-part="item"]) > [data-part="logo"] {
  display: block;
  block-size: var(--logo-cloud-height, var(--space-8));
  inline-size: auto;
  max-inline-size: var(--logo-cloud-width, var(--space-32));
  object-fit: contain;
  opacity: var(--logo-cloud-dim, 0.7);
  filter: grayscale(1);
  transition: opacity var(--duration-normal) var(--ease-default), filter var(--duration-normal) var(--ease-default);
}

[data-ui="logo-cloud"] > :where([data-part="items"]) > :where([data-part="item"]:hover) > [data-part="logo"],
[data-ui="logo-cloud"] > :where([data-part="items"]) > :where([data-part="item"]:focus-within) > [data-part="logo"],
[data-ui="logo-cloud"] > :where([data-ui="marquee"]) > :where(ul) > :where([data-part="item"]:hover) > [data-part="logo"],
[data-ui="logo-cloud"] > :where([data-ui="marquee"]) > :where(ul) > :where([data-part="item"]:focus-within) > [data-part="logo"] {
  opacity: 1;
  filter: none;
}

/* ── Colour ──
   Keeps every mark in its own colours at rest — for a strip of few, well-set
   logos, or a brand whose marks are the point. */
[data-ui="logo-cloud"][data-color] > :where([data-part="items"]) > :where([data-part="item"]) > [data-part="logo"],
[data-ui="logo-cloud"][data-color] > :where([data-ui="marquee"]) > :where(ul) > :where([data-part="item"]) > [data-part="logo"] {
  opacity: 1;
  filter: none;
}

/* ── Responsive ──
   Canon tiers only, min-width only, ascending (FAQIR-NEXT §19). One floor:
   from md the strip breathes — wider gutters, more air between the marks. */
@media (min-width: 48rem) {
  [data-ui="logo-cloud"] {
    gap: var(--space-8);
    padding-block: var(--space-12);
    padding-inline: var(--space-6);
  }

  [data-ui="logo-cloud"] > [data-part="items"] {
    gap: var(--space-8) var(--space-12);
  }
}

/* ── Motion ──
   The colour returns at once; the strip itself is the marquee's business,
   and the marquee already stands still here. */
@media (prefers-reduced-motion: reduce) {
  [data-ui="logo-cloud"] > :where([data-part="items"]) > :where([data-part="item"]) > [data-part="logo"],
  [data-ui="logo-cloud"] > :where([data-ui="marquee"]) > :where(ul) > :where([data-part="item"]) > [data-part="logo"] {
    transition: none;
  }
}

/* ── Print ──
   Ink is cheaper than a grey wash: the marks print in full. */
@media print {
  [data-ui="logo-cloud"] > :where([data-part="items"]) > :where([data-part="item"]) > [data-part="logo"],
  [data-ui="logo-cloud"] > :where([data-ui="marquee"]) > :where(ul) > :where([data-part="item"]) > [data-part="logo"] {
    opacity: 1;
    filter: none;
  }
}


/* === patterns/pricing.css === */
/* @ui:component pricing */
/* @ui:tokens color-bg color-fg color-fg-muted color-primary color-surface-1 space-1 space-2 space-4 space-6 space-8 space-12 space-16 space-3 space-48 font-heading font-body heading-tracking heading-transform heading-caps heading-leading heading-weight text-sm text-base text-lg text-3xl text-2xl weight-semibold weight-bold leading-tight leading-normal leading-relaxed shadow-md border-width-strong motion-enter-duration motion-enter-ease motion-slide-distance texture-surface card-bg */

/* ── Root ──
   Mobile-first (task 0.8-09): everything outside the two `@media` blocks at the
   foot of the sheet is the phone case, and the canon floors widen it. */
[data-ui="pricing"] {
  display: grid;
  gap: var(--space-4);
  padding-block: var(--space-12);
  padding-inline: var(--space-4);
  font-family: var(--font-body);
  color: var(--color-fg);
  background: var(--color-bg);
}

/* ── Section heading ── */
/* The heading speaks in the theme's heading voice, like bento's and the
   hero's: weight, tracking, case and caps come from the type axis. */
[data-ui="pricing"] [data-part="heading"] {
  margin: 0;
  font-family: var(--font-heading);
  font-size: var(--text-2xl);
  font-weight: var(--heading-weight);
  letter-spacing: var(--heading-tracking);
  text-transform: var(--heading-transform);
  font-variant-caps: var(--heading-caps);
  line-height: var(--leading-tight);
  text-wrap: balance;
}

[data-ui="pricing"] > [data-part="description"] {
  margin: 0;
  max-inline-size: 44rem;
  font-size: var(--text-lg);
  line-height: var(--leading-relaxed);
  color: var(--color-fg-muted);
}

/* ── Billing switch ──
   A monthly/yearly switch with zero JavaScript: a segmented toggle-group of
   two native radios (value="monthly" / value="yearly") in a direct-child
   [data-part="billing"], and every price written twice — once inside a
   [data-part="monthly"] wrapper, once inside a [data-part="yearly"] one.
   `:has()` reads which radio is checked and shows one wrapper of each pair.

   Hidden until `:has()` is known to work: without it the radios could not
   change a single price, so nobody is shown a switch that does nothing. The
   prices then read monthly, which is what the wrappers say by default. */
[data-ui="pricing"] > [data-part="billing"] {
  display: none;
}

@supports selector(:has(*)) {
  [data-ui="pricing"] > [data-part="billing"] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: var(--space-3);
    margin-block-start: var(--space-4);
  }

  /* Exactly one wrapper of each pair is in the render tree — and so in the
     accessibility tree — at a time: display:none, never opacity, so a screen
     reader hears one price per tier. */
  [data-ui="pricing"]:not(:has(> [data-part="billing"] input[value="yearly"]:checked)) [data-part="yearly"],
  [data-ui="pricing"]:has(> [data-part="billing"] input[value="yearly"]:checked) [data-part="monthly"] {
    display: none;
  }

  /* The price that just arrived settles in: a short fade and a small rise on
     the enter tokens. It replays whenever the wrapper comes back from
     display:none, which is exactly when the switch flips. */
  [data-ui="pricing"]:has(> [data-part="billing"] input[value="yearly"]:checked) [data-part="yearly"],
  [data-ui="pricing"]:has(> [data-part="billing"] input[value="monthly"]:checked) [data-part="monthly"] {
    animation: faqir-pricing-swap var(--motion-enter-duration) var(--motion-enter-ease) both;
  }
}

/* No `:has()`: the yearly wrappers never show. `not selector()` is also true
   in an engine too old to know the selector() test at all. */
@supports not selector(:has(*)) {
  [data-ui="pricing"] [data-part="yearly"] {
    display: none;
  }
}

/* An inline wrapper (a <span> inside the stat's value or label) is laid out as
   an inline-block so the rise can move it; inline boxes ignore translate. In
   :where() so every hiding rule above outranks it. */
:where([data-ui="pricing"] span:is([data-part="monthly"], [data-part="yearly"])) {
  display: inline-block;
}

/* Only a `from`: the price ends exactly where it already is. */
@keyframes faqir-pricing-swap {
  from {
    opacity: 0;
    translate: 0 calc(var(--motion-slide-distance) / 2);
  }
}

/* ── Tiers ──
   A real grid primitive owns the layout attributes while manifest-aware part
   ownership keeps `tiers` and `tier` with pricing (grid declares neither slot).
   `data-align-rows` makes every direct card a four-row subgrid. The redundant
   contextual column declarations preserve pricing's root `data-cols` API; the
   nested grid attributes are the canonical ladder and the browser-test oracle. */
[data-ui="pricing"] [data-part="tiers"] {
  margin-block-start: var(--space-8);
  align-items: stretch;
  grid-template-columns: 1fr;
}

/* ── Tier ──
   The tier IS a card; everything below restyles the card's own slots in the
   pricing context, so the card primitive stays the single source of its box. */
[data-ui="pricing"] [data-part="tier"] {
  row-gap: var(--space-4);
}

[data-ui="pricing"] [data-part="tier"] [data-part="header"] {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-2);
}

[data-ui="pricing"] [data-part="tier"] [data-part="title"] {
  margin: 0;
  font-family: var(--font-heading);
  font-size: var(--text-lg);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--heading-tracking);
  text-transform: var(--heading-transform);
  font-variant-caps: var(--heading-caps);
  line-height: var(--heading-leading);
}

[data-ui="pricing"] [data-part="tier"] [data-part="header"] [data-part="description"] {
  margin: 0;
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  color: var(--color-fg-muted);
}

/* The price is the stat primitive. Its label carries `order: -1` so the caption
   sits above the number; in a price block the number leads, so DOM order wins. */
[data-ui="pricing"] [data-part="tier"] [data-ui="stat"] {
  margin-block-start: auto;
  padding-block-start: var(--space-2);
}

[data-ui="pricing"] [data-part="tier"] [data-ui="stat"] [data-part="label"] {
  order: 0;
  color: var(--color-fg-muted);
}

/* ── Feature list ──
   Plain <ul> inside the card body: a data-part here would belong to the card. */
[data-ui="pricing"] [data-part="tier"] [data-part="body"] ul {
  display: grid;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

[data-ui="pricing"] [data-part="tier"] [data-part="body"] li {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
}

[data-ui="pricing"] [data-part="tier"] [data-part="body"] li [data-ui="icon"] {
  flex-shrink: 0;
  margin-block-start: var(--space-1);
  color: var(--color-primary);
}

/* ── Tier footer ── */
[data-ui="pricing"] [data-part="tier"] [data-part="footer"] {
  display: flex;
  padding-block-start: var(--space-2);
}

[data-ui="pricing"] [data-part="tier"] [data-part="footer"] > * {
  inline-size: 100%;
  text-align: center;
}

/* ── Featured tier ── */
[data-ui="pricing"] [data-part="tier"][data-state="featured"] {
  border-color: var(--color-primary);
  box-shadow: var(--shadow-md);
  outline: var(--border-width-strong) solid var(--color-primary);
}

/* The ring says "this one"; a faint wash of the accent from the top edge says
   it from across the room. The card's own layers stay underneath — its
   texture and its fill, a colour or a gradient — so the wash tints whatever
   the theme's card already is. It sits above its neighbours so the ring and
   the shadow are never clipped by the next card's paint. */
[data-ui="pricing"] > :where([data-part="tiers"]) > [data-part="tier"][data-state="featured"] {
  position: relative;
  z-index: 1;
  background:
    linear-gradient(to bottom, color-mix(in oklch, var(--color-primary) 7%, transparent), transparent var(--space-48)),
    var(--texture-surface),
    var(--card-bg, var(--color-surface-1));
}

/* ── Footnote ── */
[data-ui="pricing"] [data-part="footnote"] {
  margin: 0;
  margin-block-start: var(--space-6);
  font-size: var(--text-sm);
  color: var(--color-fg-muted);
}

/* ── Motion ──
   Reduced motion swaps the prices without the settle; paper has nothing to
   settle. The selectors repeat the swap's own, so they meet it at its weight
   and win by coming later. */
@media (prefers-reduced-motion: reduce), print {
  [data-ui="pricing"]:has(> [data-part="billing"] input[value="yearly"]:checked) [data-part="yearly"],
  [data-ui="pricing"]:has(> [data-part="billing"] input[value="monthly"]:checked) [data-part="monthly"] {
    animation: none;
  }
}

/* ── Responsive ──
   Canon tiers only, min-width only, ascending (FAQIR-NEXT §19). One tier per row
   on a phone, two from sm, the declared count from lg — the same 640/1024 steps
   as before, now expressed as floors. `data-cols="2"` needs no sm rule (two is
   already the sm default) but does need an lg one, or it would inherit three. */
@media (min-width: 40rem) {
  [data-ui="pricing"] [data-part="heading"] {
    font-size: var(--text-3xl);
  }

  [data-ui="pricing"] {
    padding-block: var(--space-16);
    padding-inline: var(--space-6);
  }

  [data-ui="pricing"] [data-part="tiers"] {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 64rem) {
  [data-ui="pricing"] [data-part="tiers"] {
    grid-template-columns: repeat(3, 1fr);
  }

  [data-ui="pricing"][data-cols="2"] [data-part="tiers"],
  [data-ui="pricing"][data-cols="2"] > [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-part="tiers"] {
    grid-template-columns: repeat(2, 1fr);
  }

  [data-ui="pricing"][data-cols="3"] [data-part="tiers"],
  [data-ui="pricing"][data-cols="3"] > [data-ui="grid"][data-ui="grid"][data-ui="grid"][data-part="tiers"] {
    grid-template-columns: repeat(3, 1fr);
  }
}


/* === patterns/settings-page.css === */
/* @ui:component settings-page */
/* @ui:tokens color-bg color-fg color-fg-muted color-border color-primary color-border-strong space-1 space-2 space-3 space-4 space-6 space-8 space-48 radius-lg shadow-md font-heading font-body heading-tracking heading-transform heading-caps heading-leading text-sm text-lg text-xl weight-semibold leading-tight leading-normal duration-fast ease-default z-sticky border-width border-width-strong */

/* ── Root ── */
[data-ui="settings-page"] {
  display: flex;
  flex-direction: column;
  gap: var(--space-8);
  width: 100%;
  max-width: 768px;
  margin-inline: auto;
  font-family: var(--font-body);
  color: var(--color-fg);
}

/* ── Header ── */
[data-ui="settings-page"] [data-part="header"] {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

/* ── Title ── */
[data-ui="settings-page"] [data-part="title"] {
  margin: 0;
  font-family: var(--font-heading);
  font-size: var(--text-xl, 1.25rem);
  font-weight: var(--weight-semibold, 600);
  letter-spacing: var(--heading-tracking);
  text-transform: var(--heading-transform);
  font-variant-caps: var(--heading-caps);
  line-height: var(--heading-leading);
  color: var(--color-fg);
}

/* ── Description ── */
[data-ui="settings-page"] [data-part="description"] {
  margin: 0;
  font-size: var(--text-sm, 0.875rem);
  line-height: var(--leading-normal);
  color: var(--color-fg-muted);
}

/* ── Sections ── */
[data-ui="settings-page"] [data-part="section"] {
  margin-block-start: var(--space-6);
}

[data-ui="settings-page"] [data-part="section"] + [data-part="section"] {
  margin-block-start: var(--space-6);
}

/* ── Section Title ── */
[data-ui="settings-page"] [data-part="section-title"] {
  margin: 0;
  font-size: var(--text-lg, 1.125rem);
  font-weight: var(--weight-semibold, 600);
  line-height: var(--leading-tight);
  color: var(--color-fg);
}

/* ── Section Description ── */
[data-ui="settings-page"] [data-part="section-description"] {
  margin: 0;
  margin-block-start: var(--space-1);
  font-size: var(--text-sm, 0.875rem);
  line-height: var(--leading-normal);
  color: var(--color-fg-muted);
}

/* ── Field Groups ── */
[data-ui="settings-page"] [data-part="field-group"] {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

[data-ui="settings-page"] [data-part="field-group"] + [data-part="field-group"] {
  margin-block-start: var(--space-4);
}

/* ── Card body spacing for fields ── */
[data-ui="settings-page"] [data-ui="card"] [data-part="body"] {
  display: flex;
  flex-direction: column;
}

/* ── Actions (sticky bar) ── */
[data-ui="settings-page"] [data-part="actions"] {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-3, 0.75rem);
  padding: var(--space-4);
  background: var(--color-bg);
  border-top: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  position: sticky;
  bottom: 0;
  z-index: var(--z-sticky);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--duration-fast) var(--ease-default);
}

/* ── Show actions bar when dirty or saving ── */
[data-ui="settings-page"][data-state="dirty"] [data-part="actions"],
[data-ui="settings-page"][data-state="saving"] [data-part="actions"] {
  opacity: 1;
  pointer-events: auto;
}

/* ── Saving state ── */
[data-ui="settings-page"][data-state="saving"] [data-part="save-button"] {
  cursor: not-allowed;
}

/* ── Saved state (briefly visible then fades) ── */
[data-ui="settings-page"][data-state="saved"] [data-part="actions"] {
  opacity: 1;
  pointer-events: auto;
}

/* ── Confirm Dialog ── */
[data-ui="settings-page"] [data-part="confirm-dialog"] {
  /* Dialog component handles its own positioning and visibility */
}

/* ══════════════════════════════════════════════
   Horizontal Layout Variant
   Tabs on left, content on right
   ══════════════════════════════════════════════ */

[data-ui="settings-page"][data-variant="horizontal"] {
  max-width: 960px;
}

/* Mobile-first. The horizontal variant is a fixed 192px rail beside a `1fr`
   column, and this sheet carried NO media query at all — so on a 375px phone the
   rail plus its gap plus the panel's own minimum forced the page 403px wide,
   with the right-hand edge of every settings card painted outside the viewport.
   Below the canon `md` tier the rail stacks above the panel, which is the layout
   the default (vertical) variant already had. [W3-3] */
[data-ui="settings-page"][data-variant="horizontal"] [data-ui="tabs"] {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-6);
  align-items: start;
}

[data-ui="settings-page"][data-variant="horizontal"] [data-ui="tabs"] [data-part="list"] {
  /* A row of tabs again, as in the default variant, until there is room for a
     rail — and one that WRAPS. A horizontal scroller would keep the triggers
     reachable, but reachable-by-gesture is not the same as visible, and a
     settings page is not a place to hide a section behind a swipe. */
  flex-direction: row;
  flex-wrap: wrap;
  border-inline-end: none;
  border-bottom: var(--border-width) solid var(--color-border);
  padding-inline-end: 0;
  position: static;
}

[data-ui="settings-page"][data-variant="horizontal"] [data-ui="tabs"] [data-part="panel"] {
  /* `grid-column: 2` has no column 2 to sit in while the grid is single-track. */
  grid-column: 1;
}

@media (min-width: 48rem) {
  [data-ui="settings-page"][data-variant="horizontal"] [data-ui="tabs"] {
    grid-template-columns: var(--space-48) 1fr;
    gap: var(--space-8);
  }

  [data-ui="settings-page"][data-variant="horizontal"] [data-ui="tabs"] [data-part="list"] {
    flex-direction: column;
    border-bottom: none;
    border-inline-end: var(--border-width) solid var(--color-border);
    padding-inline-end: var(--space-4);
    position: sticky;
    top: var(--space-4);
    flex-wrap: nowrap;
  }

  [data-ui="settings-page"][data-variant="horizontal"] [data-ui="tabs"] [data-part="panel"] {
    grid-column: 2;
  }

  /* The rail's own trigger treatment: a start-edge marker instead of the
     underline. Below `md` the triggers are a row again, so they keep the
     default tabs look rather than a border on an edge that is not there. */
  [data-ui="settings-page"][data-variant="horizontal"] [data-ui="tabs"] [data-part="trigger"] {
    justify-content: flex-start;
    text-align: start;
    border-bottom: none;
    border-inline-start: var(--border-width-strong) solid transparent;
    margin-bottom: 0;
    margin-inline-end: -1px;
    padding: var(--space-2) var(--space-3);
    border-radius: 0;
  }

  [data-ui="settings-page"][data-variant="horizontal"] [data-ui="tabs"] [data-part="trigger"][aria-selected="true"] {
    border-inline-start-color: var(--color-primary);
    border-bottom-color: transparent;
  }

  [data-ui="settings-page"][data-variant="horizontal"] [data-ui="tabs"] [data-part="trigger"]:hover {
    border-inline-start-color: var(--color-border-strong, var(--color-border));
    border-bottom-color: transparent;
  }

  [data-ui="settings-page"][data-variant="horizontal"] [data-ui="tabs"] [data-part="trigger"][aria-selected="true"]:hover {
    border-inline-start-color: var(--color-primary);
  }
}

/* ══════════════════════════════════════════════
   Reduced Motion
   ══════════════════════════════════════════════ */

@media (prefers-reduced-motion: reduce) {
  [data-ui="settings-page"] [data-part="actions"] {
    transition: none;
  }
}


/* === patterns/site-footer.css === */
/* @ui:component site-footer */
/* @ui:tokens color-bg-subtle color-fg color-fg-muted color-border space-2 space-3 space-4 space-6 space-8 space-10 space-12 font-body text-sm text-base text-lg weight-semibold weight-bold leading-normal border-width */

/* ── Root ──
   Mobile-first (task 0.8-09): everything outside the two `@media` blocks at the
   foot of the sheet is the phone case, and the canon floors widen it. */
[data-ui="site-footer"] {
  display: grid;
  gap: var(--space-8);
  padding-block: var(--space-10);
  padding-inline: var(--space-4);
  font-family: var(--font-body);
  font-size: var(--text-sm);
  color: var(--color-fg-muted);
  background: var(--color-bg-subtle);
  border-block-start: var(--border-width) solid var(--color-border);
}

/* ── Brand ── */
[data-ui="site-footer"] [data-part="brand"] {
  display: grid;
  gap: var(--space-2);
  align-content: start;
}

[data-ui="site-footer"] [data-part="logo"] {
  margin: 0;
  font-size: var(--text-lg);
  font-weight: var(--weight-bold);
  color: var(--color-fg);
}

[data-ui="site-footer"] [data-part="tagline"] {
  margin: 0;
  max-inline-size: 28rem;
  line-height: var(--leading-normal);
}

[data-ui="site-footer"] [data-part="social"] {
  display: flex;
  gap: var(--space-3);
  margin-block-start: var(--space-2);
  font-size: var(--text-base);
}

/* ── Link columns ──
   Each column is a heading plus a nested data-ui="nav"; the nav owns its own
   [data-part="link"] elements, so only spacing is set here. */
[data-ui="site-footer"] [data-part="columns"] {
  display: grid;
  gap: var(--space-6);
  grid-template-columns: 1fr;
}

[data-ui="site-footer"] [data-part="column"] {
  display: grid;
  gap: var(--space-3);
  align-content: start;
}

[data-ui="site-footer"] [data-part="column-title"] {
  margin: 0;
  font-size: var(--text-sm);
  font-weight: var(--weight-semibold);
  color: var(--color-fg);
}

[data-ui="site-footer"] [data-part="column"] [data-ui="nav"] {
  gap: var(--space-2);
}

/* ── Bottom bar ──
   Two lines on a phone (copyright over legal links), one justified row from sm. */
[data-ui="site-footer"] [data-part="bottom"] {
  display: flex;
  flex-wrap: wrap;
  flex-direction: column;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
}

[data-ui="site-footer"] [data-part="copyright"] {
  margin: 0;
}

[data-ui="site-footer"] [data-part="legal"] {
  display: flex;
  gap: var(--space-4);
}

/* ── Layout: columns (default) ──
   Brand column beside the link columns; the bottom bar spans the full width. */
[data-ui="site-footer"][data-variant="columns"] {
  grid-template-columns: 1fr;
  align-items: start;
  row-gap: var(--space-10);
  column-gap: var(--space-12);
}

[data-ui="site-footer"][data-variant="columns"] > [data-ui="separator"],
[data-ui="site-footer"][data-variant="columns"] [data-part="bottom"] {
  grid-column: 1 / -1;
}

/* ── Layout: compact ── */
[data-ui="site-footer"][data-variant="compact"] {
  gap: var(--space-4);
  padding-block: var(--space-8);
}

/* ── Responsive ──
   Canon tiers only, min-width only, ascending (FAQIR-NEXT §19). Everything is a
   single stack on a phone; the link columns pair up at sm and reach three at lg,
   where the brand column also moves alongside them. The lg `row-gap` restates
   the root's own `gap` — the columns variant carries a looser row rhythm only
   while it is stacked. */
@media (min-width: 40rem) {
  [data-ui="site-footer"] {
    padding-block: var(--space-12);
    padding-inline: var(--space-6);
  }

  [data-ui="site-footer"] [data-part="columns"] {
    grid-template-columns: repeat(2, 1fr);
    gap: var(--space-8);
  }

  [data-ui="site-footer"] [data-part="bottom"] {
    flex-direction: row;
    align-items: center;
  }
}

@media (min-width: 64rem) {
  [data-ui="site-footer"][data-variant="columns"] {
    grid-template-columns: minmax(16rem, 1fr) 2fr;
    row-gap: var(--space-8);
  }

  [data-ui="site-footer"] [data-part="columns"] {
    grid-template-columns: repeat(3, 1fr);
  }
}


/* === patterns/site-header.css === */
/* @ui:component site-header */
/* @ui:tokens panel-bg space-4 space-2 space-1 space-3 space-5 space-32 space-6 control-height-lg control-height-sm measure-wide font-ui font-heading color-fg color-border color-bg-subtle border-width border-width-md text-lg text-sm weight-bold weight-medium heading-tracking leading-tight radius-sm radius-full radius-lg focus-ring-width focus-ring-style focus-ring-color focus-ring-offset focus-shadow button-radius duration-fast duration-normal ease-default ease-linear shadow-md z-sticky card-shadow surface-backdrop */

/* ── Root ──
   One grid row: brand at the start, the disclosure toggle at the end, and —
   from the md floor — the nav centred between them with the actions at the end.
   The four parts are direct children of the header, so there is no inner row
   to centre; instead `padding-inline` grows to whatever is left once the row
   is `--site-header-max` wide, which centres the content with no wrapper and
   no measurement. Below that width the gutter is the floor.

   The fill is resolved once into `--faqir-site-header-fill`, because three
   things paint it — the bar, the dropped menu panel and the condense
   keyframes — and the glass variant replaces it with a translucent mix.

   `position: relative` so the menu panel, which drops out of the bar as an
   overlay, has the bar as its containing block; sticky keeps that property.

   Mobile-first: everything outside the `@media` block at the foot of the
   sheet is the phone case, where the nav and the actions live in the menu. */
[data-ui="site-header"] {
  --faqir-site-header-fill: var(--site-header-bg, var(--panel-bg));
  position: relative;
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  column-gap: var(--space-4);
  min-block-size: var(--site-header-height, var(--control-height-lg));
  padding-block: var(--space-2);
  padding-inline: max(var(--space-4), calc((100% - var(--site-header-max, var(--measure-wide))) / 2));
  font-family: var(--font-ui);
  color: var(--color-fg);
  background-color: var(--faqir-site-header-fill);
  border-block-end: var(--border-width) solid var(--color-border);
}

/* ── Brand ──
   A wordmark is display type, so it reads the heading face; it is a link home,
   so it keeps the text colour rather than the link colour. */
[data-ui="site-header"] > [data-part="brand"] {
  justify-self: start;
  font-family: var(--font-heading);
  font-size: var(--text-lg);
  font-weight: var(--weight-bold);
  letter-spacing: var(--heading-tracking);
  line-height: var(--leading-tight);
  color: var(--color-fg);
  text-decoration: none;
  white-space: nowrap;
  border-radius: var(--radius-sm);
}

[data-ui="site-header"] > [data-part="brand"]:focus-visible {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  outline-offset: var(--focus-ring-offset);
  box-shadow: var(--focus-shadow);
}

/* ── Nav and actions ──
   Hidden on a phone: the same links are in the menu panel, and two copies of
   a navigation landmark on screen at once is one too many. The nested
   data-ui="nav" owns its own [data-part="link"] slots; this wrapper only
   places it. */
[data-ui="site-header"] > [data-part="nav"],
[data-ui="site-header"] > [data-part="actions"] {
  display: none;
}

/* ── Menu ──
   A native <details>, so the phone menu opens and closes with zero
   JavaScript, and the <summary> is a real button to the keyboard and to
   assistive technology. Child combinators throughout: a collapsible in the
   panel keeps its own trigger. */
[data-ui="site-header"] > [data-part="menu"] {
  justify-self: end;
}

[data-ui="site-header"] > :where([data-part="menu"]) > [data-part="toggle"] {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-block-size: var(--control-height-sm);
  padding-block: var(--space-1);
  padding-inline: var(--space-3);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  line-height: var(--leading-tight);
  color: var(--color-fg);
  border-radius: var(--button-radius);
  cursor: pointer;
  list-style: none;
  user-select: none;
  transition: background-color var(--duration-fast) var(--ease-default);
}

/* Strip the native disclosure marker (WebKit + standard list-item marker). */
[data-ui="site-header"] > :where([data-part="menu"]) > [data-part="toggle"]::-webkit-details-marker {
  display: none;
}

[data-ui="site-header"] > :where([data-part="menu"]) > [data-part="toggle"]:hover {
  background-color: var(--color-bg-subtle);
}

[data-ui="site-header"] > :where([data-part="menu"]) > [data-part="toggle"]:focus-visible {
  outline: var(--focus-ring-width) var(--focus-ring-style) var(--focus-ring-color);
  outline-offset: var(--focus-ring-offset);
  box-shadow: var(--focus-shadow);
}

/* Chevron: two borders of a small square, turned. Sized in em so it follows
   the toggle's own type, as a glyph would. */
[data-ui="site-header"] > :where([data-part="menu"]) > [data-part="toggle"]::after {
  content: "";
  flex: none;
  inline-size: 0.5em;
  block-size: 0.5em;
  border-inline-end: var(--border-width-md) solid currentColor;
  border-block-end: var(--border-width-md) solid currentColor;
  rotate: 45deg;
  translate: 0 -0.125em;
  transition: rotate var(--duration-normal) var(--ease-default), translate var(--duration-normal) var(--ease-default);
}

[data-ui="site-header"] > :where([data-part="menu"][open]) > [data-part="toggle"]::after {
  rotate: -135deg;
  translate: 0 0.125em;
}

/* ── Panel ──
   Drops out of the bar as an overlay rather than growing the row, so the brand
   and the toggle stay where the reader left them when the menu opens. It
   paints the same fill as the bar and closes with the same hairline. */
[data-ui="site-header"] > :where([data-part="menu"]) > [data-part="panel"] {
  position: absolute;
  inset-inline: 0;
  inset-block-start: 100%;
  display: grid;
  gap: var(--space-4);
  padding-block: var(--space-4);
  padding-inline: var(--space-4);
  background-color: var(--faqir-site-header-fill);
  border-block-end: var(--border-width) solid var(--color-border);
  box-shadow: var(--shadow-md);
}

/* The actions inside the panel stack full width, under a rule of their own. */
[data-ui="site-header"] > :where([data-part="menu"]) > :where([data-part="panel"]) > [data-part="actions"] {
  display: grid;
  gap: var(--space-2);
  padding-block-start: var(--space-4);
  border-block-start: var(--border-width) solid var(--color-border);
}

/* ── Sticky ── */
[data-ui="site-header"][data-sticky] {
  position: sticky;
  inset-block-start: 0;
  z-index: var(--z-sticky);
}

/* ── Style: floating ──
   A pill inset from the page edges, lifted by the card shadow so it reads as
   a surface over the page rather than a band of it. The menu panel follows:
   its own rounded card, a beat below the pill. */
[data-ui="site-header"][data-variant="floating"] {
  margin-block-start: var(--space-3);
  margin-inline: var(--space-3);
  padding-inline: max(var(--space-5), calc((100% - var(--site-header-max, var(--measure-wide))) / 2));
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-full);
  box-shadow: var(--card-shadow);
}

[data-ui="site-header"][data-variant="floating"][data-sticky] {
  inset-block-start: var(--space-3);
}

[data-ui="site-header"][data-variant="floating"] > :where([data-part="menu"]) > [data-part="panel"] {
  margin-block-start: var(--space-2);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-lg);
}

/* ── Style: glass ──
   The fill becomes a translucent mix of itself, and — where the browser can
   blur what lies behind — the theme's frost (`--surface-backdrop`) is applied
   to the bar and to the dropped panel. A blur behind an opaque fill renders
   nothing, which is why the fill is the half that changes unconditionally. */
[data-ui="site-header"][data-variant="glass"] {
  --faqir-site-header-fill: color-mix(in oklch, var(--site-header-bg, var(--panel-bg)) 72%, transparent);
}

@supports ((-webkit-backdrop-filter: blur(1rem)) or (backdrop-filter: blur(1rem))) {
  [data-ui="site-header"][data-variant="glass"],
  [data-ui="site-header"][data-variant="glass"] > :where([data-part="menu"]) > [data-part="panel"] {
    -webkit-backdrop-filter: var(--surface-backdrop);
    backdrop-filter: var(--surface-backdrop);
  }
}

/* ── Condense ──
   The bar starts transparent and roomy over the top of the page and settles
   into its fill, its hairline and its working padding over the first 8rem of
   scroll (`--space-32`). The scrollbar is the clock — a scroll timeline scrubs
   one keyframe pair — so nothing listens, nothing measures. Where scroll
   timelines are not understood the block is skipped whole and the header is
   the plain (sticky) bar above: the `to` frame restates the root's own values,
   so the two agree. Meant for a sticky bar; a static one scrolls away before
   it has settled. */
@supports (animation-timeline: scroll()) {
  [data-ui="site-header"][data-condense] {
    animation: faqir-site-header-condense var(--ease-linear) both;
    animation-timeline: scroll(root block);
    animation-range: 0 var(--space-32);
  }
}

@keyframes faqir-site-header-condense {
  from {
    padding-block: var(--space-4);
    background-color: transparent;
    border-block-end: var(--border-width) solid transparent;
  }

  to {
    padding-block: var(--space-2);
    background-color: var(--faqir-site-header-fill);
    border-block-end: var(--border-width) solid var(--color-border);
  }
}

/* ── Responsive ──
   Canon tiers only, min-width only, ascending (FAQIR-NEXT §19). One floor: at
   md the inline nav and actions appear, the row becomes `auto 1fr auto` with
   the nav centred in the middle track, and the menu goes — the panel's links
   are now on screen already. */
@media (min-width: 48rem) {
  [data-ui="site-header"] {
    grid-template-columns: auto 1fr auto;
    column-gap: var(--space-6);
    padding-inline: max(var(--space-6), calc((100% - var(--site-header-max, var(--measure-wide))) / 2));
  }

  [data-ui="site-header"] > [data-part="nav"] {
    display: flex;
    justify-content: center;
    min-inline-size: 0;
  }

  [data-ui="site-header"] > [data-part="actions"] {
    display: flex;
    align-items: center;
    justify-content: end;
    gap: var(--space-2);
  }

  [data-ui="site-header"] > [data-part="menu"] {
    display: none;
  }
}

/* ── Motion ──
   The toggle's hover and chevron stop transitioning. The condense is kept:
   it never moves on its own, only as far as the reader's own scrolling moves
   it, and it is scrubbed at constant speed either way. */
@media (prefers-reduced-motion: reduce) {
  [data-ui="site-header"] > :where([data-part="menu"]) > [data-part="toggle"],
  [data-ui="site-header"] > :where([data-part="menu"]) > [data-part="toggle"]::after {
    transition: none;
  }

  [data-ui="site-header"][data-condense] {
    animation-timing-function: var(--ease-linear);
  }
}

/* ── Print ──
   A sticky bar on paper is a bar on every page; the menu has nowhere to go. */
@media print {
  [data-ui="site-header"] {
    position: static;
    box-shadow: none;
  }

  [data-ui="site-header"] > [data-part="menu"] {
    display: none;
  }

  [data-ui="site-header"] > [data-part="nav"],
  [data-ui="site-header"] > [data-part="actions"] {
    display: flex;
  }
}


/* === patterns/stats-dashboard.css === */
/* @ui:component stats-dashboard */
/* @ui:tokens color-bg color-fg color-fg-muted color-border space-1 space-2 space-3 space-4 space-6 space-8 space-12 space-px font-heading font-body heading-tracking heading-transform heading-caps heading-leading heading-weight text-sm text-base text-lg text-3xl weight-semibold weight-bold leading-tight leading-normal leading-relaxed */

/* ── Root ──
   A reporting page: title block, KPI row, then the panel region. The KPI row
   is the grid primitive, so this sheet never sets its columns.

   Mobile-first (task 0.8-09): everything outside the two `@media` blocks at the
   foot of the sheet is the phone case, and the canon floors widen it. */
[data-ui="stats-dashboard"] {
  display: grid;
  gap: var(--space-3);
  padding-block: var(--space-8);
  padding-inline: var(--space-4);
  font-family: var(--font-body);
  color: var(--color-fg);
  background: var(--color-bg);
}

/* ── Title block ── */
[data-ui="stats-dashboard"] [data-part="heading"] {
  margin: 0;
  font-family: var(--font-heading);
  font-size: var(--text-3xl);
  font-weight: var(--heading-weight);
  letter-spacing: var(--heading-tracking);
  line-height: var(--leading-tight);
  text-wrap: balance;
}

[data-ui="stats-dashboard"] > [data-part="description"] {
  margin: 0;
  max-inline-size: 44rem;
  font-size: var(--text-lg);
  line-height: var(--leading-relaxed);
  color: var(--color-fg-muted);
}

/* The reporting period is metadata, not prose — small, muted, tabular. */
[data-ui="stats-dashboard"] [data-part="period"] {
  margin: 0;
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  color: var(--color-fg-muted);
  font-variant-numeric: tabular-nums;
}

/* ── KPI row ──
   [data-part="metrics"] is itself data-ui="grid": the mobile-first 1 → 2 → 4
   column ladder lives in grid.css. Only the vertical rhythm is ours. */
[data-ui="stats-dashboard"] [data-part="metrics"] {
  margin-block-start: var(--space-4);
}

[data-ui="stats-dashboard"] [data-part="metrics"] > [data-ui="stat"] {
  block-size: 100%;
}

/* ── Panel region ──
   Report panel + a narrower companion panel. Pattern CSS rather than a nested
   data-ui="grid" here, because [data-part="report"] must stay this pattern's
   part: a grid between them would own it.

   Stacked until lg: a report table needs the width long before a KPI card does,
   which is why this region collapses a tier earlier than the metrics row. */
[data-ui="stats-dashboard"] [data-part="reports"] {
  display: grid;
  gap: var(--space-6);
  margin-block-start: var(--space-4);
  align-items: start;
  grid-template-columns: 1fr;
}

/* A lone panel spans the full width instead of leaving a hole. */
[data-ui="stats-dashboard"] [data-part="reports"] > [data-part="report"]:only-child {
  grid-column: 1 / -1;
}

/* ── Panel ──
   The panel IS a card; everything below restyles the card's own slots in the
   reporting context. */
[data-ui="stats-dashboard"] [data-part="report"] {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  min-inline-size: 0;
}

[data-ui="stats-dashboard"] [data-part="report"] [data-part="title"] {
  margin: 0;
  font-family: var(--font-heading);
  font-size: var(--text-lg);
  font-weight: var(--weight-semibold);
  letter-spacing: var(--heading-tracking);
  text-transform: var(--heading-transform);
  font-variant-caps: var(--heading-caps);
  line-height: var(--heading-leading);
}

[data-ui="stats-dashboard"] [data-part="report"] [data-part="header"] [data-part="description"] {
  margin: 0;
  margin-block-start: var(--space-1);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  color: var(--color-fg-muted);
}

/* The table brings its own look; the panel only guarantees it can scroll
   sideways on a narrow screen instead of stretching the card. */
[data-ui="stats-dashboard"] [data-part="report"] [data-part="body"] {
  min-inline-size: 0;
}

[data-ui="stats-dashboard"] [data-part="report"] [data-ui="table"] {
  inline-size: 100%;
  overflow-x: auto;
}

/* ── Breakdown list ──
   Plain <ul> inside the card body: a data-part here would belong to the card. */
[data-ui="stats-dashboard"] [data-part="report"] [data-part="body"] ul {
  display: grid;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

[data-ui="stats-dashboard"] [data-part="report"] [data-part="body"] li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding-block: var(--space-2);
  border-block-end: var(--space-px, 1px) solid var(--color-border);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
}

[data-ui="stats-dashboard"] [data-part="report"] [data-part="body"] li:last-child {
  border-block-end: 0;
}

[data-ui="stats-dashboard"] [data-part="report"] [data-part="footer"] {
  margin-block-start: auto;
}

/* ── Footnote ── */
[data-ui="stats-dashboard"] [data-part="footnote"] {
  margin: 0;
  margin-block-start: var(--space-6);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  color: var(--color-fg-muted);
}

/* ── Responsive ──
   Canon tiers only, min-width only, ascending (FAQIR-NEXT §19). Two of the three
   things this page can reflow are elsewhere: the KPI row is data-ui="grid" and
   collapses in grid.css, each report table stacks against its own container in
   table.css. Only the page frame and the panel split are this sheet's. */
@media (min-width: 40rem) {
  [data-ui="stats-dashboard"] {
    padding-block: var(--space-12);
    padding-inline: var(--space-6);
  }
}

@media (min-width: 64rem) {
  [data-ui="stats-dashboard"] [data-part="reports"] {
    grid-template-columns: 2fr 1fr;
  }
}


/* === patterns/testimonials.css === */
/* @ui:component testimonials */
/* @ui:tokens space-4 space-12 space-6 space-8 space-3 space-10 space-16 font-body font-heading color-fg color-bg color-fg-muted text-2xl text-lg text-3xl heading-weight heading-tracking heading-transform heading-caps heading-leading measure-prose leading-relaxed motion-reveal-duration motion-reveal-ease motion-stagger motion-reveal-distance ease-linear */

/* ── Root ──
   A wall of quotes: a section heading, an optional description, and the
   quotes themselves as card quotes inside a real list. The three layouts
   only change how that list flows — a grid of equal rows, packed columns, or
   two moving strips — so one set of markup serves all of them.

   Mobile-first: every declaration outside the `@media` blocks at the foot of
   the sheet is the PHONE case; the canon floors only ever widen it. */
[data-ui="testimonials"] {
  display: grid;
  gap: var(--space-4);
  padding-block: var(--space-12);
  padding-inline: var(--space-4);
  font-family: var(--font-body);
  color: var(--color-fg);
  background: var(--color-bg);
}

/* ── Heading ── */
[data-ui="testimonials"] > [data-part="heading"] {
  margin: 0;
  font-family: var(--font-heading);
  font-size: var(--text-2xl);
  font-weight: var(--heading-weight);
  letter-spacing: var(--heading-tracking);
  text-transform: var(--heading-transform);
  font-variant-caps: var(--heading-caps);
  line-height: var(--heading-leading);
  text-wrap: balance;
}

/* ── Description ── */
[data-ui="testimonials"] > [data-part="description"] {
  margin: 0;
  max-inline-size: var(--measure-prose);
  font-size: var(--text-lg);
  line-height: var(--leading-relaxed);
  color: var(--color-fg-muted);
}

/* ── Items ──
   A real <ul>; the marker goes, the semantics stay, so assistive technology
   announces "list, 6 items" before the first quote. One column on a phone;
   the grid layout widens to two at md and three at lg below. `minmax(0, 1fr)`
   rather than `1fr`: a long unbroken word in one quote must not push its
   column wider than the others. */
[data-ui="testimonials"] > [data-part="items"] {
  display: grid;
  grid-template-columns: repeat(1, minmax(0, 1fr));
  gap: var(--testimonials-gap, var(--space-6));
  margin: 0;
  margin-block-start: var(--space-8);
  padding: 0;
  list-style: none;
}

/* ── Item ──
   Each item WRAPS one card quote. The item is a grid of its own so the quote
   stretches to the row's height: in a grid of testimonials the short quote
   and the long one get the same card. `--faqir-testimonials-index` is the
   item's place in the stagger, read by the animate rules below. */
[data-ui="testimonials"] > :where([data-part="items"]) > [data-part="item"] {
  --faqir-testimonials-index: 0;
  display: grid;
  margin: 0;
  padding: 0;
}

/* ── Layout: columns ──
   CSS multi-column instead of grid, so cards of different heights pack
   top-to-bottom like a masonry wall with no script measuring anything. Each
   item refuses to split across a column break; the gap below it is the
   column's rhythm, which is why the list's own gap does nothing here. */
[data-ui="testimonials"][data-variant="columns"] > [data-part="items"] {
  display: block;
  columns: 1;
  column-gap: var(--testimonials-gap, var(--space-6));
}

[data-ui="testimonials"][data-variant="columns"] > :where([data-part="items"]) > [data-part="item"] {
  display: block;
  break-inside: avoid;
  margin-block-end: var(--testimonials-gap, var(--space-6));
}

[data-ui="testimonials"][data-variant="columns"] > :where([data-part="items"]) > [data-part="item"]:last-child {
  margin-block-end: 0;
}

/* ── Layout: marquee ──
   Two nested marquee strips stacked, the second running the other way at
   half the pace, which is what makes a pair of strips read as depth. The
   marquee owns the motion, the pause and the reduced-motion fallback; this
   sheet only stacks the strips and sizes the cards.

   A card in a strip needs a width of its own — a marquee lays its items on
   one line and a quote would otherwise take the whole strip. The width is
   set on [data-part="slide"], the pattern's own wrapper around each quote,
   never on the marquee's items or on the quote, so the nested components
   are never restyled. The hops to it go through :where() to keep the rule's
   weight at a single part. */
[data-ui="testimonials"] > [data-part="strips"] {
  display: grid;
  gap: var(--testimonials-gap, var(--space-6));
  margin-block-start: var(--space-8);
}

[data-ui="testimonials"] > :where([data-part="strips"]) > :where([data-ui="marquee"]) > :where([data-part="track"]) > :where(li) > [data-part="slide"] {
  display: grid;
  inline-size: var(--testimonials-card-width, 20rem);
}

/* ── Footer ── */
[data-ui="testimonials"] > [data-part="footer"] {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-block-start: var(--space-10);
}

/* ── Animate: the items arrive in order ──
   The reveal primitive's stagger, applied to the list's own items: it cannot
   wrap them, because `items` is this pattern's part and a reveal staggers
   its direct children. Same recipe, same tokens — the entrance reads the
   `--motion-reveal-*` family and the delay is one `--motion-stagger` per
   sibling, so a theme that restyles reveals restyles this too. Twelve steps
   are counted; everything past the twelfth arrives with it, so a long wall
   does not hold its last row back for seconds. `both` holds the from-state
   through the delay, so a late item is not visible, then hidden, then shown. */
[data-ui="testimonials"][data-animate] > :where([data-part="items"]) > [data-part="item"] {
  animation: faqir-testimonials-reveal var(--motion-reveal-duration) var(--motion-reveal-ease) both;
  animation-delay: calc(var(--motion-stagger) * var(--faqir-testimonials-index));
}

[data-ui="testimonials"][data-animate] > :where([data-part="items"]) > [data-part="item"]:nth-child(2)    { --faqir-testimonials-index: 1; }
[data-ui="testimonials"][data-animate] > :where([data-part="items"]) > [data-part="item"]:nth-child(3)    { --faqir-testimonials-index: 2; }
[data-ui="testimonials"][data-animate] > :where([data-part="items"]) > [data-part="item"]:nth-child(4)    { --faqir-testimonials-index: 3; }
[data-ui="testimonials"][data-animate] > :where([data-part="items"]) > [data-part="item"]:nth-child(5)    { --faqir-testimonials-index: 4; }
[data-ui="testimonials"][data-animate] > :where([data-part="items"]) > [data-part="item"]:nth-child(6)    { --faqir-testimonials-index: 5; }
[data-ui="testimonials"][data-animate] > :where([data-part="items"]) > [data-part="item"]:nth-child(7)    { --faqir-testimonials-index: 6; }
[data-ui="testimonials"][data-animate] > :where([data-part="items"]) > [data-part="item"]:nth-child(8)    { --faqir-testimonials-index: 7; }
[data-ui="testimonials"][data-animate] > :where([data-part="items"]) > [data-part="item"]:nth-child(9)    { --faqir-testimonials-index: 8; }
[data-ui="testimonials"][data-animate] > :where([data-part="items"]) > [data-part="item"]:nth-child(10)   { --faqir-testimonials-index: 9; }
[data-ui="testimonials"][data-animate] > :where([data-part="items"]) > [data-part="item"]:nth-child(11)   { --faqir-testimonials-index: 10; }
[data-ui="testimonials"][data-animate] > :where([data-part="items"]) > [data-part="item"]:nth-child(n+12) { --faqir-testimonials-index: 11; }

/* Only a `from`: the animation ends on whatever the item already is. */
@keyframes faqir-testimonials-reveal {
  from {
    opacity: 0;
    translate: 0 var(--motion-reveal-distance);
  }
}

/* Where view timelines are understood the entrance is scrubbed by the
   scrollbar as each item crosses the bottom of the viewport, and a time delay
   means nothing, so the stagger offsets each item's RANGE instead: the same
   order, measured in scroll. Elsewhere the block is skipped and the rule above
   plays the entrance once on load — the quotes are never left hidden. */
@supports (animation-timeline: view()) {
  [data-ui="testimonials"][data-animate] > :where([data-part="items"]) > [data-part="item"] {
    animation-timeline: view();
    animation-timing-function: var(--ease-linear);
    animation-delay: 0s;
    animation-range:
      entry calc(5% + var(--faqir-testimonials-index) * 6%)
      entry calc(70% + var(--faqir-testimonials-index) * 6%);
  }
}

/* ── Motion ──
   Reduced motion removes the entrance, not the quotes. Paper gets the same
   treatment — a printed page has no entrance — and a quote never breaks
   across two pages. The marquee strips carry their own fallbacks. */
@media (prefers-reduced-motion: reduce), print {
  [data-ui="testimonials"][data-animate] > :where([data-part="items"]) > [data-part="item"] {
    animation: none;
  }
}

@media print {
  [data-ui="testimonials"] > :where([data-part="items"]) > [data-part="item"] {
    break-inside: avoid;
  }
}

/* ── Responsive ──
   Canon tiers only, min-width only, ascending. sm: the section opens up and
   the heading takes the display size. md: two columns, in both the grid and
   the packed layout. lg: three. The marquee layout has no columns to widen. */
@media (min-width: 40rem) {
  [data-ui="testimonials"] {
    padding-block: var(--space-16);
    padding-inline: var(--space-6);
  }

  [data-ui="testimonials"] > [data-part="heading"] {
    font-size: var(--text-3xl);
  }
}

@media (min-width: 48rem) {
  [data-ui="testimonials"] > [data-part="items"] {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  [data-ui="testimonials"][data-variant="columns"] > [data-part="items"] {
    columns: 2;
  }
}

@media (min-width: 64rem) {
  [data-ui="testimonials"] > [data-part="items"] {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  [data-ui="testimonials"][data-variant="columns"] > [data-part="items"] {
    columns: 3;
  }
}


/* === patterns/wizard.css === */
/* @ui:component wizard */
/* @ui:tokens color-fg color-success-subtle measure-narrow radius-lg space-3 space-4 space-6 font-body font-heading text-sm text-2xl leading-tight leading-normal heading-weight heading-tracking */
/* wizard — multi-step form pattern.
   Layout only: the stepper, card panels, field-groups and buttons carry their
   own look from their primitives. This sheet stacks the pieces, lays out the
   navigation row, and reveals the completion message on data-state="submitted".
   Attribute + token selectors only; logical properties throughout. */

[data-ui="wizard"] {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
  max-inline-size: var(--measure-narrow);
  margin-inline: auto;
  font-family: var(--font-body);
}

[data-ui="wizard"] [data-part="heading"] {
  margin: 0;
  font-family: var(--font-heading);
  font-size: var(--text-2xl);
  font-weight: var(--heading-weight);
  letter-spacing: var(--heading-tracking);
  line-height: var(--leading-tight);
  color: var(--color-fg);
}

/* Navigation row: Back on the leading edge, Next/Submit on the trailing edge. */
[data-ui="wizard"] [data-part="actions"] {
  display: flex;
  gap: var(--space-3);
  align-items: center;
}

[data-ui="wizard"] [data-part="next"],
[data-ui="wizard"] [data-part="submit"] {
  margin-inline-start: auto;
}

/* Completion message: hidden until the wizard reports it is done. */
[data-ui="wizard"] [data-part="complete"] {
  display: none;
  margin: 0;
  padding-block: var(--space-3);
  padding-inline: var(--space-4);
  border-radius: var(--radius-lg);
  background: var(--color-success-subtle);
  color: var(--color-fg);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
}

[data-ui="wizard"][data-state="submitted"] [data-part="complete"] {
  display: block;
}

/* When the wizard is complete, retire the step panels and the nav row so the
   confirmation stands alone — still no JS, purely the submitted state. */
[data-ui="wizard"][data-state="submitted"] [data-part="panel"],
[data-ui="wizard"][data-state="submitted"] [data-part="actions"] {
  display: none;
}
