/* ============================================================
   Design System — Design Tokens (oklch native)

   DaisyUI v4 color architecture:
   - base-100/200/300  → surface hierarchy (bg, card, elevated)
   - base-content      → main text; use /50 /70 opacity for muted
   - primary/secondary/accent/neutral → brand colors
   - info/success/warning/error → semantic status

   We use oklch() directly — exact DaisyUI color matching,
   no lossy HSL conversion. Requires modern browser.

   Usage: var(--background), var(--primary) etc.
   Opacity: color-mix(in oklch, var(--primary) 15%, transparent)
   ============================================================ */

/* Cascade layers (v2 A20) — declare the order ONCE; it governs regardless of the
   order the three files are linked/imported. Later layers win at equal specificity:
   base < components < utilities, so a utility (re-gap-4, re-text-danger) can override a
   component default. `docs` sits between base and components for the docs site's prose
   (see DocsShell). Unlayered rules (a consumer's own CSS) still beat every layer. */
@layer base, docs, components, utilities;

/* Metric-matched fallback for Inter (landing CLS, 2026-10-07). Inter loads with display:swap and never blocks paint, so the
   first paint uses the next family in --font-sans; when Inter arrives the text re-wraps and everything under it moves (split
   measured CLS 0.287 on a cold run). These faces draw a LOCAL font scaled to Inter's average glyph width and given Inter's
   ascent/descent, so the swap changes the letterforms, not the line breaks. Values are computed, not tuned: average advance
   weighted by English letter frequency (the next/font method) from Inter's latin woff2 (v20) against Arial / Roboto.
   Two weights per family because a synthetic bold is wider than Inter Bold: 400 for ≤549, Inter 600/700 (mean) above.
   Arial covers macOS/Windows; Roboto covers Android, where Arial does not exist. A face whose local() is missing is skipped
   and the stack falls through to the next one. */
@font-face{font-family:"Inter Fallback";src:local("Arial"),local("ArialMT");font-weight:100 549;
  size-adjust:107.16%;ascent-override:90.40%;descent-override:22.51%;line-gap-override:0%}
@font-face{font-family:"Inter Fallback";src:local("Arial Bold"),local("Arial-BoldMT");font-weight:550 1000;
  size-adjust:101.52%;ascent-override:95.43%;descent-override:23.77%;line-gap-override:0%}
@font-face{font-family:"Inter Fallback Roboto";src:local("Roboto"),local("Roboto-Regular");font-weight:100 549;
  size-adjust:107.11%;ascent-override:90.45%;descent-override:22.52%;line-gap-override:0%}
@font-face{font-family:"Inter Fallback Roboto";src:local("Roboto Bold"),local("Roboto-Bold");font-weight:550 1000;
  size-adjust:108.12%;ascent-override:89.60%;descent-override:22.31%;line-gap-override:0%}

@layer base {
/* ── LIGHT THEME ────────────────────────────────────────────── */
:root {
  color-scheme: light;

  /* Base surfaces (DaisyUI light) */
  --background:          oklch(100% 0 0);              /* white */
  --surface:             oklch(98% 0 0);               /* base-200 */
  /* The ground of a full-screen entry page. Its own token because the two themes want
     opposite relationships to --surface: in light a sign-in screen wants to be LIGHTER than
     the app's raised surface (98% read as grey behind a white card), in dark it wants exactly
     --surface. One semantic token could not be both, and changing --surface itself would move
     every raised surface in the system to fix one page. */
  --re-gate-bg:          var(--neutral-50);
  --surface-alt:         oklch(95% 0 0);               /* base-300 */
  --foreground:          oklch(21% 0.006 285.885);     /* near-black */

  --card:                oklch(100% 0 0);
  --card-foreground:     oklch(21% 0.006 285.885);
  --popover:             oklch(100% 0 0);
  --popover-foreground:  oklch(21% 0.006 285.885);

  /* Primary — indigo (Airy / Stripe-inspired, original signature ≈ #533afd) */
  --primary:             oklch(52% 0.22 276);
  --primary-foreground:  oklch(99% 0.01 276);

  /* Secondary — soft indigo-gray */
  --secondary:           oklch(94% 0.015 285);
  --secondary-foreground:oklch(30% 0.03 285);

  /* Muted */
  --muted:               oklch(95% 0.006 264);
  /* v11 §V11-1 — two tint tiers for a nested block that has to read as part of a list, not as
     a panel. Derived from --foreground, NOT from --muted, and that is the whole design:
     --muted sits ~5 lightness points from --card, so squeezing two steps inside that gap gave
     1.02 of contrast between them — invisible. --foreground is far away, so a small percentage
     buys a controlled step. Measured: 1.054 / 1.062 light and 1.049 / 1.045 dark, i.e. three
     evenly spaced grounds, each step larger than the --muted-derived version managed.
     Named --tint-* rather than --muted-* because they are no longer part of that family.
     oklab, because a two-colour mix in oklch interpolates hue (see --re-note-hue). */
  --tint-soft:           color-mix(in oklab, var(--foreground) 5%, var(--card));
  --tint-softer:         color-mix(in oklab, var(--foreground) 2.5%, var(--card));
  --muted-foreground:    oklch(55% 0.012 264);         /* base-content/55 equivalent */
  --text-strong-muted:   var(--dark-500);              /* muted but more contrast than --muted-foreground; theme-aware */

  /* Accent — teal */
  --accent:              oklch(72% 0.156 194);         /* teal */
  --accent-foreground:   oklch(22% 0.01 300);   /* dark, not white: white on --accent measured 2.18 and the label vanished. 7.76 with this */

  /* Status */
  /* 56%, not the original 65%. This is the one role no label choice could fix: measured on its
     own fill in the light theme, white 3.90 and near-black 4.34 — both under AA, so the pair
     was never the problem, the FILL was. Candidates measured as text-on-page / label-on-fill:
       65% 0.3 30   4.00 / 3.84   (the original)
       58% 0.25 28  4.67 / 4.48   — clears as text, still 0.02 short on the fill
       56% 0.24 28  5.08 / 4.87   ← this one: the smallest move that clears BOTH
     (the scan used pure white as the label; with the real --danger-foreground the fill
      measures 4.77, still over 4.5 — and the dark theme 5.00 / 4.69)
       54% 0.22 27  5.69 / 5.46   — clears comfortably, reads closer to maroon
     58% was rejected on our own rule: a signal that clears by 0.02 counts as not clearing.
     It also fixes `re-text-danger`, which was 4.00 on a white page. */
  --destructive:         oklch(56% 0.24 28);
  --destructive-foreground: oklch(98% 0.01 30);
  --success:             oklch(76% 0.177 163);         /* DaisyUI success */
  --success-foreground:  oklch(22% 0.01 163);   /* dark, not near-white: a solid success badge measured 1.86 — its own label unreadable, which is not a misuse, it is the pair being wrong. 8.85 with this */
  --warning:             oklch(80.2% 0.170 73);        /* #FFAA02 — golden orange (logo, light candidate) */
  --warning-foreground:  oklch(22% 0.01 75);    /* dark. The old comment said the quiet part out loud — "low contrast at this brightness" — and kept white anyway: 1.91. 9.08 with this */
  --info:                oklch(74% 0.16 233);          /* DaisyUI info */
  --info-foreground:     oklch(24% 0.012 243);  /* neutral near-black — reads clean on cyan */

  /* Borders / input — soft indigo-tinted */
  --border:              oklch(90% 0.008 285);
  /* v6 V6-10 — the boundary of a FLOATING or interactive surface (prompt bar, tab-bar island,
     sheet, popover). --border is a hairline meant for dividers inside a box, where spacing
     already carries the structure; as the edge of a floating surface it disappears at phone
     scale. Measured against --card: --border 1.35:1, this 1.75:1.
     Deliberately brand-INDEPENDENT: a brand-tinted mix was measured across the theme set and
     came out WORSE than today for some brands (neutral 1.23:1, and 1.18:1 for pink in dark) —
     tinting cannot fix a lightness problem. Kept lighter than the 2.01:1 neutral that read as
     "too dark" in review, so the gap to WCAG 1.4.11's 3:1 is a deliberate choice: reaching it
     needs oklch(68%), which is a visibly heavy frame. */
  --border-elevated:     oklch(82% 0.012 285);
  /* The RESTING surface tier. The DS already had two: --border for a separator (1.35:1 vs
     --card in light, 1.30 in dark) and --border-elevated for something that floats over
     content and carries a shadow (1.75 / 1.85). A card that sits IN the flow had no tier of
     its own and borrowed the separator's, which is why in light — where --card and
     --background are the SAME white, contrast 1.00 — a card read as no card at all on a
     phone (labs §V20-1).
     DERIVED, not hand-picked, and that is what makes it hold: mixed from each theme's own
     --border and --muted-foreground it measures 1.58:1 in BOTH themes, while the two
     hand-picked tiers drift (1.35/1.30 and 1.75/1.85).
     Neutral, not brand-toned, and the user's reason is a number: the DS ships 15 brands, so
     one percentage of --brand would produce fifteen different contrasts and near-zero effect
     on `neutral`. A token whose value follows the THEME is a token; one that follows the
     BRAND is not. (kullanıcı, 2026-09-07: "Marka tonu işi karıştırır… C nötr ama görünür
     daha iyi bir seçenek.")
     ⚠ Declared in both theme blocks, never once on :root — it reads --border and
     --muted-foreground, which are redefined by .dark, and .dark is a bare class a consumer
     can put on a subtree. */
  --border-surface:      color-mix(in oklch, var(--border) 86%, var(--muted-foreground) 14%);
  --input:               oklch(90% 0.008 285);
  --ring:                oklch(52% 0.22 276);

  /* ── Brand accent & composition slots ───────────────────────────
     --brand is the single accent hue. Composition slots derive from it,
     so buttons, links, headings, glows and tints stay coherent within a
     template. Swap the whole kit's accent with:
       <html data-brand="teal | violet | emerald | amber | rose">
     (no attribute = indigo signature). Slots are defined once here and
     re-resolve automatically under .dark and data-brand. */
  --brand:               oklch(52% 0.22 276);   /* = primary (Airy indigo, original signature) */
  --brand-foreground:    var(--primary-foreground);   /* tracks the active brand's foreground (preset-aware) */
  --c-link:              var(--brand);
  --c-heading-accent:    var(--brand);
  --c-focus:             var(--brand);
  --c-glow:              var(--brand);
  --c-surface-tint:      color-mix(in oklch, var(--brand) 8%, transparent);

  /* ── Palette scales (oklch, theme-independent) ─────────────────
     16 hues × 10 steps (50→900). The brand/composition system and the
     re-c-{role} dictionary read from these; data-brand presets anchor at 700. */
  --rose-50: oklch(96.5% 0.018 12); --rose-100: oklch(93% 0.036 12); --rose-200: oklch(86.5% 0.074 12); --rose-300: oklch(78.5% 0.128 12); --rose-400: oklch(69.5% 0.189 12); --rose-500: oklch(61.5% 0.216 12); --rose-600: oklch(54.5% 0.218 12); --rose-700: oklch(47.5% 0.191 12); --rose-800: oklch(40.5% 0.163 12); --rose-900: oklch(33.5% 0.135 12);
  --red-50: oklch(96.5% 0.017 27); --red-100: oklch(93% 0.036 27); --red-200: oklch(86.5% 0.073 27); --red-300: oklch(78.5% 0.125 27); --red-400: oklch(69.5% 0.193 27); --red-500: oklch(61.5% 0.221 27); --red-600: oklch(54.5% 0.223 27); --red-700: oklch(47.5% 0.194 27); --red-800: oklch(40.5% 0.166 27); --red-900: oklch(33.5% 0.138 27);
  --orange-50: oklch(96.5% 0.019 48); --orange-100: oklch(93% 0.039 48); --orange-200: oklch(86.5% 0.08 48); --orange-300: oklch(78.5% 0.131 48); --orange-400: oklch(69.5% 0.172 48); --orange-500: oklch(61.5% 0.168 48); --orange-600: oklch(54.5% 0.149 48); --orange-700: oklch(47.5% 0.13 48); --orange-800: oklch(40.5% 0.112 48); --orange-900: oklch(33.5% 0.093 48);
  --brown-50: oklch(96.5% 0.008 55); --brown-100: oklch(93% 0.015 55); --brown-200: oklch(86.5% 0.029 55); --brown-300: oklch(78.5% 0.045 55); --brown-400: oklch(69.5% 0.059 55); --brown-500: oklch(61.5% 0.067 55); --brown-600: oklch(54.5% 0.07 55); --brown-700: oklch(47.5% 0.07 55); --brown-800: oklch(40.5% 0.063 55); --brown-900: oklch(33.5% 0.055 55);
  --amber-50: oklch(98.5% 0.012 75); --amber-100: oklch(95.5% 0.036 75); --amber-200: oklch(91% 0.075 75); --amber-300: oklch(86% 0.118 75); --amber-400: oklch(80.5% 0.155 75); --amber-500: oklch(74.5% 0.157 75); --amber-600: oklch(68% 0.144 75); --amber-700: oklch(60.5% 0.128 75); --amber-800: oklch(51% 0.108 75); --amber-900: oklch(42% 0.089 75);
  --yellow-50: oklch(98.5% 0.023 102); --yellow-100: oklch(95.5% 0.043 102); --yellow-200: oklch(91% 0.082 102); --yellow-300: oklch(86% 0.125 102); --yellow-400: oklch(80.5% 0.164 102); --yellow-500: oklch(74.5% 0.156 102); --yellow-600: oklch(68% 0.143 102); --yellow-700: oklch(60.5% 0.127 102); --yellow-800: oklch(51% 0.107 102); --yellow-900: oklch(42% 0.089 102);
  --lime-50: oklch(98.5% 0.026 128); --lime-100: oklch(95.5% 0.048 128); --lime-200: oklch(91% 0.092 128); --lime-300: oklch(86% 0.141 128); --lime-400: oklch(80.5% 0.185 128); --lime-500: oklch(74.5% 0.195 128); --lime-600: oklch(68% 0.178 128); --lime-700: oklch(60.5% 0.159 128); --lime-800: oklch(51% 0.134 128); --lime-900: oklch(42% 0.111 128);
  --green-50: oklch(96.5% 0.026 148); --green-100: oklch(93% 0.047 148); --green-200: oklch(86.5% 0.09 148); --green-300: oklch(78.5% 0.138 148); --green-400: oklch(69.5% 0.181 148); --green-500: oklch(61.5% 0.178 148); --green-600: oklch(54.5% 0.158 148); --green-700: oklch(47.5% 0.138 148); --green-800: oklch(40.5% 0.118 148); --green-900: oklch(33.5% 0.098 148);
  --emerald-50: oklch(96.5% 0.023 162); --emerald-100: oklch(93% 0.042 162); --emerald-200: oklch(86.5% 0.08 162); --emerald-300: oklch(78.5% 0.122 162); --emerald-400: oklch(69.5% 0.153 162); --emerald-500: oklch(61.5% 0.135 162); --emerald-600: oklch(54.5% 0.12 162); --emerald-700: oklch(47.5% 0.105 162); --emerald-800: oklch(40.5% 0.09 162); --emerald-900: oklch(33.5% 0.075 162);
  --teal-50: oklch(96.5% 0.018 195); --teal-100: oklch(93% 0.033 195); --teal-200: oklch(86.5% 0.063 195); --teal-300: oklch(78.5% 0.096 195); --teal-400: oklch(69.5% 0.119 195); --teal-500: oklch(61.5% 0.105 195); --teal-600: oklch(54.5% 0.093 195); --teal-700: oklch(47.5% 0.081 195); --teal-800: oklch(40.5% 0.07 195); --teal-900: oklch(33.5% 0.058 195);
  --blue-50: oklch(96.5% 0.017 256); --blue-100: oklch(93% 0.034 256); --blue-200: oklch(86.5% 0.067 256); --blue-300: oklch(78.5% 0.11 256); --blue-400: oklch(69.5% 0.16 256); --blue-500: oklch(61.5% 0.182 256); --blue-600: oklch(54.5% 0.187 256); --blue-700: oklch(47.5% 0.163 256); --blue-800: oklch(40.5% 0.14 256); --blue-900: oklch(33.5% 0.117 256);
  --indigo-50: oklch(96.5% 0.017 276); --indigo-100: oklch(93% 0.034 276); --indigo-200: oklch(86.5% 0.067 276); --indigo-300: oklch(78.5% 0.11 276); --indigo-400: oklch(69.5% 0.161 276); --indigo-500: oklch(61.5% 0.21 276); --indigo-600: oklch(54.5% 0.22 276); --indigo-700: oklch(47.5% 0.22 276); --indigo-800: oklch(40.5% 0.198 276); --indigo-900: oklch(33.5% 0.172 276);
  --violet-50: oklch(96.5% 0.019 300); --violet-100: oklch(93% 0.039 300); --violet-200: oklch(86.5% 0.078 300); --violet-300: oklch(78.5% 0.129 300); --violet-400: oklch(69.5% 0.19 300); --violet-500: oklch(61.5% 0.235 300); --violet-600: oklch(54.5% 0.245 300); --violet-700: oklch(47.5% 0.245 300); --violet-800: oklch(40.5% 0.217 300); --violet-900: oklch(33.5% 0.18 300);
  --purple-50: oklch(96.5% 0.026 318); --purple-100: oklch(93% 0.052 318); --purple-200: oklch(86.5% 0.104 318); --purple-300: oklch(78.5% 0.16 318); --purple-400: oklch(69.5% 0.21 318); --purple-500: oklch(61.5% 0.24 318); --purple-600: oklch(54.5% 0.25 318); --purple-700: oklch(47.5% 0.231 318); --purple-800: oklch(40.5% 0.198 318); --purple-900: oklch(33.5% 0.164 318);
  --fuchsia-50: oklch(96.5% 0.025 335); --fuchsia-100: oklch(93% 0.052 335); --fuchsia-200: oklch(86.5% 0.107 335); --fuchsia-300: oklch(78.5% 0.163 335); --fuchsia-400: oklch(69.5% 0.214 335); --fuchsia-500: oklch(61.5% 0.245 335); --fuchsia-600: oklch(54.5% 0.243 335); --fuchsia-700: oklch(47.5% 0.212 335); --fuchsia-800: oklch(40.5% 0.181 335); --fuchsia-900: oklch(33.5% 0.151 335);
  --pink-50: oklch(96.5% 0.02 352); --pink-100: oklch(93% 0.041 352); --pink-200: oklch(86.5% 0.084 352); --pink-300: oklch(78.5% 0.146 352); --pink-400: oklch(69.5% 0.193 352); --pink-500: oklch(61.5% 0.221 352); --pink-600: oklch(54.5% 0.226 352); --pink-700: oklch(47.5% 0.198 352); --pink-800: oklch(40.5% 0.169 352); --pink-900: oklch(33.5% 0.141 352);
  /* neutral scales — Dark (slate) & Neutral (light grey), indigo-tinted */
  --dark-50: oklch(62% 0.002 282); --dark-100: oklch(56.5% 0.003 282); --dark-200: oklch(51% 0.006 282); --dark-300: oklch(45.5% 0.009 282); --dark-400: oklch(40% 0.012 282); --dark-500: oklch(34.5% 0.013 282); --dark-600: oklch(29% 0.014 282); --dark-700: oklch(23.5% 0.014 282); --dark-800: oklch(18.5% 0.013 282); --dark-900: oklch(13.5% 0.011 282);
  --neutral-50: oklch(99% 0.001 282); --neutral-100: oklch(96.5% 0.002 282); --neutral-200: oklch(93.5% 0.004 282); --neutral-300: oklch(90% 0.006 282); --neutral-400: oklch(85.5% 0.008 282); --neutral-500: oklch(80% 0.01 282); --neutral-600: oklch(74% 0.01 282); --neutral-700: oklch(68% 0.01 282); --neutral-800: oklch(62% 0.009 282); --neutral-900: oklch(55% 0.008 282);

  /* Radius scale — Airy: large & rounded (Stripe-inspired).
     These four are the PRIMITIVES (the `md` step of the data-radius knob below); they are
     stated as literals rather than as calc() offsets off --radius so each knob step can
     retune them independently — a fixed ±0.375rem offset is wrong at both ends of the
     scale (it drives the small step to 0 at `sm` and to an 18px "inset" at `full`).
     --radius / --radius-md stay identical, as they always were. */
  --radius: 0.75rem;
  --radius-sm: 0.375rem;
  --radius-md: 0.75rem;
  --radius-lg: 1.125rem;
  --radius-xl: 1.5rem;
  --radius-full: 9999px;   /* the pill. Constant at every knob step — a badge, a FAB or an
                              avatar button is a pill BY SHAPE, not by taste, so `sm` must
                              not un-round it. */

  /* Semantic radius aliases — the names components should reach for.
     They exist so a rule can say WHAT it is rounding, which is the only information the
     knob needs to size the corner correctly at its `full` step (see below). */
  --radius-inset:   var(--radius-sm);   /* a part nested INSIDE a control or a surface — a nav row, a close button, a tag, a code chip. Must read smaller than its parent's corner. */
  --radius-control: var(--radius-md);   /* a ONE-LINE control whose height is --control-h-* and whose content never wraps — button, input, select, nav item. Only this tier may become a pill. */
  --radius-surface: var(--radius-lg);   /* anything that can grow to two or more lines — card, modal, sheet, panel, table shell, row list. Capped BELOW pill at every step. */

  /* Soft chromatic shadow (Airy — indigo-tinted depth, not neutral gray) */
  /* Soft chromatic shadow — hue follows the active brand (relative-color) */
  --shadow-sm: 0 1px 2px oklch(from var(--brand) 45% 0.05 h / 0.08);
  --shadow:    0 2px 8px oklch(from var(--brand) 45% 0.05 h / 0.10);
  --shadow-md: 0 6px 20px oklch(from var(--brand) 45% 0.05 h / 0.12);
  --shadow-lg: 0 16px 40px oklch(from var(--brand) 45% 0.05 h / 0.16);

  /* Kanonik semantic palet — danger = destructive alias (cascade ile dark'ta da doğru) */
  --danger: var(--destructive);
  --danger-foreground: var(--destructive-foreground);

  /* Control knob (switch/toggle beyaz topuz) */
  --knob: oklch(100% 0 0);

  --font-sans: Inter, "Inter Fallback", "Inter Fallback Roboto", system-ui, -apple-system, sans-serif;
  --font-mono: "JetBrains Mono", Menlo, Monaco, monospace;

  /* Chart — light */
  --chart-1:  var(--brand);            /* follows the active brand */
  --chart-2:  oklch(60%  0.22  295);   /* purple */
  --chart-3:  oklch(72%  0.156 194);   /* teal — accent */
  --chart-4:  oklch(76%  0.177 163);   /* green */
  --chart-5:  oklch(82%  0.189 84);    /* amber */
  --chart-6:  oklch(65%  0.3   30);    /* red */
}

/* ── SYNTHWAVE DARK — DaisyUI v4 exact values ───────────────── */
.dark {
  color-scheme: dark;

  /* Surfaces — Airy dark (slate-indigo substrate, less saturated than synthwave) */
  --background:          oklch(19% 0.025 274);         /* deep slate-indigo */
  --surface:             oklch(23% 0.025 274);         /* card lift */
  --re-gate-bg:          var(--surface);   /* dark wants the raised surface itself — the light value would be a white screen on a dark page */
  --surface-alt:         oklch(27% 0.028 274);         /* elevated */
  --foreground:          oklch(93% 0.012 274);         /* bright lavender-white — high readability */

  --card:                oklch(22.5% 0.025 274);
  --card-foreground:     oklch(93% 0.012 274);
  --popover:             oklch(25% 0.028 274);
  --popover-foreground:  oklch(93% 0.012 274);

  /* Brand — bright indigo (Airy, original dark signature) */
  --primary:             oklch(66% 0.19 276);
  --primary-foreground:  oklch(22% 0.01 276);   /* dark: the dark theme lifts --primary to 66% L, so a near-white label falls to 3.22. 5.25 with this */

  /* Secondary — muted indigo-slate */
  --secondary:           oklch(32% 0.04 280);
  --secondary-foreground:oklch(90% 0.02 280);

  /* Muted surface */
  --muted:               oklch(26% 0.02 274);
  --muted-foreground:    oklch(68% 0.02 274);
  --text-strong-muted:   var(--neutral-500);

  /* Accent — teal (retained; pairs cleanly with indigo) */
  --accent:              oklch(72% 0.14 195);
  --accent-foreground:   oklch(19% 0.025 274);

  /* Status — dark-tuned */
  --destructive:         oklch(64% 0.20 22);
  --destructive-foreground: oklch(22% 0.01 22);  /* dark: 3.48 -> 4.69. The LIGHT theme cannot be fixed this way — see the note by --destructive there */
  --success:             oklch(70% 0.15 158);
  --success-foreground:  oklch(16% 0.03 158);
  --warning:             oklch(80.2% 0.170 73);        /* #FFAA02 */
  --warning-foreground:  oklch(22% 0.01 75);    /* dark — the warning fill is the same bright amber in both themes, so the label is wrong in both. 1.91 -> 9.08 */
  --info:                oklch(70% 0.14 235);
  --info-foreground:     oklch(23% 0.012 235);

  /* Neutral — indigo (nav/UI accents) */
  --neutral:             oklch(50% 0.10 276);
  --neutral-foreground:  oklch(90% 0.03 276);

  /* Borders */
  --border:              oklch(31% 0.02 274);
  --border-elevated:     oklch(40% 0.025 274);   /* v6 V6-10 — 1.85:1 vs --card, where --border is 1.30:1 (dark was marginally WORSE than light before this) */
  --border-surface:      color-mix(in oklch, var(--border) 86%, var(--muted-foreground) 14%);   /* resting surface tier — see the light block */
  --input:               oklch(31% 0.02 274);
  --ring:                oklch(66% 0.19 276);           /* indigo */

  /* Brand accent (dark) — bright indigo (original dark signature) */
  --brand:               oklch(66% 0.19 276);
  --brand-foreground:    var(--primary-foreground);

  /* No --radius here on purpose: it was a verbatim copy of the :root value, so it changed
     nothing — but it would have clobbered a data-radius set on an ANCESTOR of the .dark
     element (radius is scopable, the theme is not). Shape is theme-independent. */
  --font-sans: Inter, "Inter Fallback", "Inter Fallback Roboto", system-ui, -apple-system, sans-serif;
  --font-mono: "JetBrains Mono", Menlo, Monaco, monospace;

  /* Soft chromatic shadow — dark (deeper, indigo-tinted) */
  --shadow-sm: 0 1px 2px oklch(0% 0 0 / 0.30);
  --shadow:    0 2px 8px oklch(0% 0 0 / 0.36);
  --shadow-md: 0 6px 20px oklch(0% 0 0 / 0.44);
  --shadow-lg: 0 16px 40px oklch(0% 0 0 / 0.52);

  /* Chart — indigo-family dark */
  --chart-1:  var(--brand);            /* follows the active brand */
  --chart-2:  oklch(70%  0.16  320);   /* violet */
  --chart-3:  oklch(72%  0.14  195);   /* teal — accent */
  --chart-4:  oklch(72%  0.15  158);   /* green */
  --chart-5:  oklch(80%  0.15  78);    /* amber */
  --chart-6:  oklch(68%  0.18  25);    /* coral */
}

/* ── Brand presets — theme-independent ──────────────────────────────
   <html data-brand="violet"> remaps --brand + --primary + --ring so the whole
   kit's accent follows — buttons, links, glows, tints all recolor. Each preset
   reads a palette token — most at step 700; red/pink at 600 and blue at a custom
   mid-tone, where they read more vivid — always with WHITE foreground. Indigo is
   the DEFAULT brand (its original signature lives on :root/.dark) so it needs no
   preset. amber/yellow/lime only clear white text at their darkest steps (800),
   so their brand reads as bronze/olive. fuchsia/rose stay palette-only (too close
   to a kept hue). Status colors NOT remapped. */
/* indigo IS the signature — the value on :root/.dark above — and it had no preset, which made
   "I chose indigo" and "I forgot to choose" indistinguishable. A consumer gave brand colours to
   a product family and four of them came out identically branded; nobody noticed until two of
   their cards were seen side by side. The switcher on this DS's own docs already treated indigo
   as a preset NAME (`getAttribute('data-brand') || 'indigo'`) and wrote data-brand="indigo",
   which matched no rule and got the right colour only by falling through to :root.

   The values are the signature's, deliberately duplicated rather than inherited: the point is
   that the attribute EXISTS, so intent is readable. Verified identical to the fall-through on
   --brand / --primary / --primary-foreground / --ring in both themes. (labs v35 §1) */
[data-brand="indigo"]  { --brand: oklch(52% 0.22 276);  --primary: oklch(52% 0.22 276);  --primary-foreground: oklch(99% 0.01 276); --ring: oklch(52% 0.22 276); }
[data-brand="red"]     { --brand: var(--red-600);     --primary: var(--red-600);     --primary-foreground: oklch(99% 0.01 27);  --ring: var(--red-600); }
[data-brand="orange"]  { --brand: var(--orange-700);  --primary: var(--orange-700);  --primary-foreground: oklch(99% 0.01 48);  --ring: var(--orange-700); }
[data-brand="amber"]   { --brand: var(--amber-800);   --primary: var(--amber-800);   --primary-foreground: oklch(99% 0.01 75);  --ring: var(--amber-800); }   /* step 800 — darkest to hold white text (bronze) */
[data-brand="yellow"]  { --brand: var(--yellow-800);  --primary: var(--yellow-800);  --primary-foreground: oklch(99% 0.01 102); --ring: var(--yellow-800); }  /* step 800 (dark olive) */
[data-brand="lime"]    { --brand: var(--lime-800);    --primary: var(--lime-800);    --primary-foreground: oklch(99% 0.01 128); --ring: var(--lime-800); }   /* step 800 (dark olive-green) */
[data-brand="brown"]   { --brand: var(--brown-700);   --primary: var(--brown-700);   --primary-foreground: oklch(99% 0.01 55);  --ring: var(--brown-700); }
[data-brand="green"]   { --brand: var(--green-700);   --primary: var(--green-700);   --primary-foreground: oklch(99% 0.01 148); --ring: var(--green-700); }
[data-brand="emerald"] { --brand: var(--emerald-600); --primary: var(--emerald-600); --primary-foreground: oklch(99% 0.01 162); --ring: var(--emerald-600); }  /* 600 — vivid emerald, white clears AA */
[data-brand="teal"]    { --brand: oklch(53% 0.11 194); --primary: oklch(53% 0.11 194); --primary-foreground: oklch(99% 0.01 194); --ring: oklch(53% 0.11 194); }  /* 53%, not 54.5%: white on the old value measured 4.47 against the fill — under AA by 0.03, which is a fail that reads as a pass. 53% gives 4.84/4.72 */
[data-brand="blue"]    { --brand: oklch(51% 0.19 256); --primary: oklch(51% 0.19 256); --primary-foreground: oklch(99% 0.01 256); --ring: oklch(51% 0.19 256); }  /* custom mid-tone (600↔700) */
[data-brand="violet"]  { --brand: var(--violet-700);  --primary: var(--violet-700);  --primary-foreground: oklch(99% 0.01 300); --ring: var(--violet-700); }
[data-brand="purple"]  { --brand: var(--purple-700);  --primary: var(--purple-700);  --primary-foreground: oklch(99% 0.01 318); --ring: var(--purple-700); }
[data-brand="pink"]    { --brand: var(--pink-600);    --primary: var(--pink-600);    --primary-foreground: oklch(99% 0.01 352); --ring: var(--pink-600); }
[data-brand="dark"]    { --brand: var(--dark-700);    --primary: var(--dark-700);    --primary-foreground: oklch(99% 0.005 282); --ring: var(--dark-700); }   /* slate 700 — white text */
[data-brand="neutral"] { --brand: var(--neutral-900); --primary: var(--neutral-900); --primary-foreground: oklch(99% 0.005 282); --ring: var(--neutral-900); }   /* 900, not 600: a BRAND has to be visible on the page, and 600 measured 2.31 against a white ground — the ring was the casualty. 900 is the first step of this family that clears 4.5 (4.85), and at that depth the label flips to white. The dark theme keeps 600 (7.99), which is why this preset is the one that differs by theme in BOTH directions. */

/* ── The same presets, in the DARK theme ─────────────────────────────────────────
   Every preset above picks ONE value, tuned so white text clears AA on the fill against a
   WHITE page. On a dark page that value is a dark colour on a dark ground, and the brand
   stops being visible — including `--ring`, which is the focus indicator.

   Measured, 15 presets x 2 themes, `--brand` against `--background` (canvas composite, not
   against black; positive control black/white = 21.0). Before this block, in the dark theme:

     under 3.0   dark 1.11 · violet 2.40 · purple 2.43 · orange 2.64 · brown 2.70 · green 2.95
     3.0-4.5     amber 3.15 · blue 3.18 · yellow 3.23 · pink 3.29 · lime 3.33 · red 3.33
                 emerald 3.97 · teal 4.03
     passing     neutral 7.99, and the :root signature 5.60

   Fourteen of fifteen. The signature passed because :root ALREADY has a dark counterpart
   (`--brand: oklch(66% .19 276)`); the presets simply never got one. That is the whole defect,
   and violet mattered most because a consumer had given it to four products.

   The step is 400 across the chromatic families, and it is measured rather than chosen: at 400
   every one of them clears 4.5 on the ground AND 4.5 for a near-black label on the fill. 500
   clears the ground for some and drops the label to 4.1; 300 is brighter than the brand needs.
   `--primary-foreground` flips to near-black here for the same reason the step moved — a bright
   fill takes a dark label, and inheriting the light theme's white label is what made a solid
   success badge unreadable elsewhere in this file.

   Two exceptions, both measured:
   - `dark` has NO passing step in its own family on a dark ground (200 is the best, at 3.22),
     because a near-black brand on a near-black page cannot work. It borrows neutral-300.
   - `neutral` is the mirror: 600 measures 7.99 here and 2.31 on a white ground. It is the one
     preset built for THIS ground, so it is written twice — 900 in the light block above, 600
     here — and it is the only one that differs by theme in both directions.

   ⚠ `:is(.dark,.dark *)`, NOT `.dark[data-brand]`. The light block above is a BARE attribute
   selector, so it matches the knob on any element — a badge, a card, one section of a page.
   The dark block was a compound, which needs `.dark` and the attribute on the SAME element, so
   it only ever matched `<html class="dark" data-brand>`. Put the knob on a descendant and the
   dark theme silently fell through to the LIGHT preset: measured `<html class="dark">` with
   `<span data-brand="violet">` → `--brand` resolved to violet-700 (the light value) and
   `--primary-foreground` to near-white, on a dark ground. A consumer reported 2.22 contrast.
   The asymmetry is the bug, not the value — a knob that works anywhere in one theme and only
   on the root in the other is worse than one that is root-only in both, because the light
   theme teaches the wrong rule and the dark theme pays for it. `:is()` takes the specificity
   of its most specific argument, so this stays (0,2,0) exactly as the compound was; nothing
   downstream re-orders.
   ────────────────────────────────────────────────────────────────────────────── */
:is(.dark,.dark *)[data-brand="indigo"]  { --brand: oklch(66% 0.19 276); --primary: oklch(66% 0.19 276); --primary-foreground: oklch(22% 0.01 276); --ring: oklch(66% 0.19 276); }   /* the dark signature, same reason. ⚠ The foreground is 22%, not 98%: writing the OLD near-white value here would have silently undone the label fix for this one preset — caught only because the comparison included --primary-foreground, which is exactly why it was asked for. */
:is(.dark,.dark *)[data-brand="red"]     { --brand: var(--red-400);     --primary: var(--red-400);     --primary-foreground: oklch(22% 0.01 27);  --ring: var(--red-400); }
:is(.dark,.dark *)[data-brand="orange"]  { --brand: var(--orange-400);  --primary: var(--orange-400);  --primary-foreground: oklch(22% 0.01 48);  --ring: var(--orange-400); }
:is(.dark,.dark *)[data-brand="amber"]   { --brand: var(--amber-400);   --primary: var(--amber-400);   --primary-foreground: oklch(22% 0.01 75);  --ring: var(--amber-400); }
:is(.dark,.dark *)[data-brand="yellow"]  { --brand: var(--yellow-400);  --primary: var(--yellow-400);  --primary-foreground: oklch(22% 0.01 102); --ring: var(--yellow-400); }
:is(.dark,.dark *)[data-brand="lime"]    { --brand: var(--lime-400);    --primary: var(--lime-400);    --primary-foreground: oklch(22% 0.01 128); --ring: var(--lime-400); }
:is(.dark,.dark *)[data-brand="brown"]   { --brand: var(--brown-400);   --primary: var(--brown-400);   --primary-foreground: oklch(22% 0.01 55);  --ring: var(--brown-400); }
:is(.dark,.dark *)[data-brand="green"]   { --brand: var(--green-400);   --primary: var(--green-400);   --primary-foreground: oklch(22% 0.01 148); --ring: var(--green-400); }
:is(.dark,.dark *)[data-brand="emerald"] { --brand: var(--emerald-400); --primary: var(--emerald-400); --primary-foreground: oklch(22% 0.01 162); --ring: var(--emerald-400); }
:is(.dark,.dark *)[data-brand="teal"]    { --brand: oklch(70% 0.11 194); --primary: oklch(70% 0.11 194); --primary-foreground: oklch(22% 0.01 194); --ring: oklch(70% 0.11 194); }
:is(.dark,.dark *)[data-brand="blue"]    { --brand: oklch(68% 0.16 256); --primary: oklch(68% 0.16 256); --primary-foreground: oklch(22% 0.01 256); --ring: oklch(68% 0.16 256); }
:is(.dark,.dark *)[data-brand="violet"]  { --brand: var(--violet-400);  --primary: var(--violet-400);  --primary-foreground: oklch(22% 0.01 300); --ring: var(--violet-400); }
:is(.dark,.dark *)[data-brand="purple"]  { --brand: var(--purple-400);  --primary: var(--purple-400);  --primary-foreground: oklch(22% 0.01 318); --ring: var(--purple-400); }
:is(.dark,.dark *)[data-brand="pink"]    { --brand: var(--pink-400);    --primary: var(--pink-400);    --primary-foreground: oklch(22% 0.01 352); --ring: var(--pink-400); }
:is(.dark,.dark *)[data-brand="dark"]    { --brand: var(--neutral-300); --primary: var(--neutral-300); --primary-foreground: oklch(22% 0.005 282); --ring: var(--neutral-300); }   /* borrows the neutral family: no step of its own clears 3.0 here */
/* ⚠ neutral DOES need one after all, and the reason is that this block's own light fix moved
   it: the note above said "600 already measures 7.99 here, no override needed", which was true
   of the value that used to be there. Changing the light value to 900 handed 900 to the dark
   theme too (3.81), i.e. fixing one theme broke the other through the cascade. A preset that
   differs by theme in BOTH directions has to say so twice. */
:is(.dark,.dark *)[data-brand="neutral"] { --brand: var(--neutral-600); --primary: var(--neutral-600); --primary-foreground: oklch(22% 0.01 282); --ring: var(--neutral-600); }

/* ── Radius scale — the third knob, next to data-brand and data-density ──────────
   <html data-radius="sm | md | lg | full"> retunes every radius primitive at once, so a
   rule that already reads var(--radius-md) follows along without being rewritten.
   `md` IS the default (identical numbers to the values on :root above) — the attribute
   only has to be written to move OFF the default.

   Why the scale is size-aware, and why `full` is not one number
   ─────────────────────────────────────────────────────────────
   `full` cannot mean 9999px globally: a pill card, a pill table or a pill modal is wrong,
   because a corner only reads as "fully round" on a box whose short side it can actually
   consume — one line of a control. So `full` splits by tier: CONTROLS become pills, while
   SURFACES stop at 1.75rem, the value that sits in the same family as the corner a pill
   control actually paints (a 40px-tall pill paints a 20px corner). The inset tier tops out
   at 0.75rem so a nested part still reads smaller than the thing it sits in.

   Scoping: these are BARE attribute selectors, unlike data-density (which is :root-scoped
   because it collides with data-density used as a JS click hook). Radius has no such hook,
   and a local scope is a feature here — a docs page can show four radius steps side by side
   by putting data-radius on four wrappers without restyling itself. Declared AFTER .dark so
   the two never race at equal specificity on the same element.

   Every step restates the three semantic aliases as LITERALS instead of leaning on the
   `--radius-inset: var(--radius-sm)` line on :root. That is not redundancy: a custom
   property is substituted at the element that declares it, so an alias declared on :root
   inherits its :root value into a subtree and would ignore a data-radius set further down.
   Restating them is what makes the knob work on a container as well as on <html>. */
[data-radius="sm"] {
  --radius:    0.375rem;   /*  6px */
  --radius-sm: 0.1875rem;  /*  3px */
  --radius-md: 0.375rem;   /*  6px */
  --radius-lg: 0.5rem;     /*  8px */
  --radius-xl: 0.75rem;    /* 12px */
  --radius-inset:   0.1875rem;
  --radius-control: 0.375rem;
  --radius-surface: 0.5rem;
  /* re-declared in every knob block on purpose: a custom property is SUBSTITUTED at the
     element that declares it, so a :root-only --re-box-inset would resolve against
     :root's --radius-surface and inherit that number down — a subtree's data-radius
     would change its corners and silently leave its text inset behind. Measured: all
     four steps read 18px until this line existed. */
  --re-box-inset: max(var(--pad-x), var(--radius-surface) * 0.75 * var(--density-mult, 1));
  --re-label-gutter: calc(var(--re-box-inset) + 1px);
}
[data-radius="md"] {       /* the DEFAULT — restated so a subtree can opt back IN to it */
  --radius:    0.75rem;    /* 12px */
  --radius-sm: 0.375rem;   /*  6px */
  --radius-md: 0.75rem;    /* 12px */
  --radius-lg: 1.125rem;   /* 18px */
  --radius-xl: 1.5rem;     /* 24px */
  --radius-inset:   0.375rem;
  --radius-control: 0.75rem;
  --radius-surface: 1.125rem;
  /* re-declared here too — see the note in the sm block. `md` IS the default, but a
     subtree opting back IN to it must re-resolve the inset, not inherit an ancestor's. */
  --re-box-inset: max(var(--pad-x), var(--radius-surface) * 0.75 * var(--density-mult, 1));
  --re-label-gutter: calc(var(--re-box-inset) + 1px);
}
[data-radius="lg"] {
  --radius:    1.125rem;   /* 18px */
  --radius-sm: 0.5rem;     /*  8px */
  --radius-md: 1.125rem;   /* 18px */
  --radius-lg: 1.5rem;     /* 24px */
  --radius-xl: 1.875rem;   /* 30px */
  --radius-inset:   0.5rem;
  --radius-control: 1.125rem;
  --radius-surface: 1.5rem;
  /* re-declared in every knob block on purpose: a custom property is SUBSTITUTED at the
     element that declares it, so a :root-only --re-box-inset would resolve against
     :root's --radius-surface and inherit that number down — a subtree's data-radius
     would change its corners and silently leave its text inset behind. Measured: all
     four steps read 18px until this line existed. */
  --re-box-inset: max(var(--pad-x), var(--radius-surface) * 0.75 * var(--density-mult, 1));
  --re-label-gutter: calc(var(--re-box-inset) + 1px);
}
[data-radius="full"] {
  --radius:    1.5rem;     /* 24px — the primitive stays surface-safe, so an un-migrated
                              rule (or a consumer's own var(--radius-md)) gets rounder
                              WITHOUT silently turning into a lozenge. */
  --radius-sm: 0.75rem;    /* 12px */
  --radius-md: 1.5rem;     /* 24px */
  --radius-lg: 1.75rem;    /* 28px */
  --radius-xl: 2rem;       /* 32px */
  --radius-inset:   0.75rem;   /* 12px */
  /* The one place a tier stops tracking the scale: a one-line control is the only box a
     pill fits, so this tier — and only this tier — reaches --radius-full. */
  --radius-control: 9999px;
  --radius-surface: var(--re-radius-surface-max);   /* 28px — the cap. A card, a modal or a table never pills. */
  /* re-declared in every knob block on purpose: a custom property is SUBSTITUTED at the
     element that declares it, so a :root-only --re-box-inset would resolve against
     :root's --radius-surface and inherit that number down — a subtree's data-radius
     would change its corners and silently leave its text inset behind. Measured: all
     four steps read 18px until this line existed. */
  --re-box-inset: max(var(--pad-x), var(--radius-surface) * 0.75 * var(--density-mult, 1));
  --re-label-gutter: calc(var(--re-box-inset) + 1px);
}

/* ── Density & Spacing Scale ────────────────────────────────────
   3 yoğunluk: compact / standard (DEFAULT) / comfortable.
   <html data-density="..."> ile değişir. Componentler bu
   primitive'leri (--pad-y/x, --control-h-*, --re-space-*, --font-scale)
   okur → density tek attribute ile her yere yayılır.

   Kullanım:  <html data-density="compact">      (yoğun, data-heavy)
              <html>  veya  data-density="standard"  (varsayılan — ham ölçek)
              <html data-density="comfortable">  (ferah — opt-in)
   ──────────────────────────────────────────────────────────────── */
/* Root-scoped (v2 A19): density lives ONLY on the document root. Bare
   [data-density] would let ANY element reassign --font-scale/--control-h-*,
   colliding with data-density used as a click hook (measured: mis-scaled
   segment items). Keep density on <html>; use a different attr for hooks. */
:root,
:root[data-density="standard"] {      /* DEFAULT — the unmanipulated baseline (all scales = 1) */
  --re-space-unit: 0.3125rem;   /* 5px */
  --control-h-sm: 2rem;
  --control-h-md: 2.625rem;
  --control-h-lg: 3.25rem;
  --pad-y: 0.875rem;
  --pad-x: 1.125rem;
  --font-scale: 1;        /* raw font sizes — no manipulation at standard */
  --density-mult: 1;      /* raw chrome px — no manipulation at standard */
}
:root[data-density="comfortable"] {   /* airy — opt-in */
  --re-space-unit: 0.375rem;    /* 6px */
  --control-h-sm: 2.15rem;
  --control-h-md: 2.85rem;
  --control-h-lg: 3.4rem;
  --pad-y: 1rem;
  --pad-x: 1.3rem;
  --font-scale: 1.06;
  --density-mult: 1.12;   /* generic px scaler for fixed chrome (navbar/footer/nav/rail) */
}
:root[data-density="compact"] {       /* dense — data-heavy */
  --re-space-unit: 0.1875rem;   /* 3px */
  --control-h-sm: 1.6rem;
  --control-h-md: 1.9rem;
  --control-h-lg: 2.3rem;
  --pad-y: 0.4rem;
  --pad-x: 0.7rem;
  --font-scale: 0.95;
  --density-mult: 0.72;
}
/* Türetilmiş spacing scale — density-aware, utility + component'ler okur */
:root {
  --re-space-1: calc(var(--re-space-unit) * 1);
  --re-space-2: calc(var(--re-space-unit) * 2);
  --re-space-3: calc(var(--re-space-unit) * 3);
  --re-space-4: calc(var(--re-space-unit) * 4);
  --re-space-5: calc(var(--re-space-unit) * 5);
  --re-space-6: calc(var(--re-space-unit) * 6);
  --re-space-8: calc(var(--re-space-unit) * 8);
  /* Single source for the content column's side padding. The page column (.container)
     and any bleeding strip (.re-bleed-x) read the same value so they stay aligned.

     DERIVED, not a constant. The page column is exactly as wide as a bled section needs
     plus a fixed clearance: re-section-bleed pulls its box out by --re-label-gutter so the
     box's TEXT lands on the page's text column, and --re-bleed-clear is the strip of page
     that must stay visible outside the box's frame. Both terms are load-bearing -- drop the
     first and the bleed misaligns, drop the second and the box's frame ends up flush against
     the page edge.

     It used to be `20px * --density-mult`. That was measured against the requirement and lost
     in ALL TWELVE combinations (3 densities x 4 radii), so it is gone rather than kept as a
     max() term that never wins -- "the box's text aligns with the heading" and "the box's
     frame keeps 5px from the page edge" together SET the gutter, they do not fit inside a
     chosen one.

     ⚠ But it is derived from the WORST-CASE label gutter, not the current one. Reading
     --re-label-gutter directly made the page column follow data-radius: measured, .container
     padded 24px at sm/md/lg and 27px at `full`, so switching the radius knob resized the
     text column by 6px and the whole page reflowed. The knob is about CORNERS; a page column
     has none. Sizing the gutter for the largest gutter any radius can ask for keeps the
     alignment exact and the clearance >= 5px at every step, and the column never moves:
     standard 27px, compact 19.4, comfortable 30.2 -- flat across all four radii.
     The cost is 3px of page padding at sm/md/lg that only `full` actually needs. That is the
     right side to pay it on: a page that never changes width, against 6px of one-off reflow. */
  /* How much page has to stay visible outside a bled box's frame. Deliberately NOT scaled by
     --density-mult: it is a "don't crowd the edge" minimum, and a minimum that shrinks with
     density stops being one. Raising it widens every page column by the same amount. */
  --re-bleed-clear: 5px;
  /* The `full` step's --radius-surface, named once so the gutter below and the knob block
     itself read the SAME number. Two copies of 1.75rem would agree until one moved. */
  --re-radius-surface-max: 1.75rem;
  --re-box-inset-max: max(var(--pad-x), var(--re-radius-surface-max) * 0.75 * var(--density-mult, 1));
  --re-gutter: calc(var(--re-box-inset-max) + 1px + var(--re-bleed-clear));
  /* The `-sm` control step, named ONCE. Two things read it: the `-sm` variants themselves, and
     a container that has to size what it holds — a re-ph-actions slot with more than one
     control drops to it. Without a name, that container would have to re-declare these three
     numbers, which is the duplicated-constant mistake this repo keeps paying for.
     Safe on plain :root: the density blocks are `:root[data-density=…]`, i.e. the SAME element,
     so `var(--pad-x)` here substitutes whichever density won. (If density ever becomes settable
     on a container, like data-radius already is, these move into each block.) */
  --re-ctl-sm-h:  var(--control-h-sm);
  --re-ctl-sm-px: calc(var(--pad-x) * .72);
  --re-ctl-sm-fs: calc(0.75rem * var(--font-scale));
  /* re-section-label's reserved leading slot: the icon sits in it, the text starts after it,
     and it is reserved whether or not there is an icon. 19px = the 13px icon + the 6px gap
     it used to have, so an icon'd label is pixel-identical to before. */
  /* ── The horizontal inset for text inside a box ──────────────────────────────
     Whichever is larger: what DENSITY asks for, or what the CORNER needs at that density.
     Neither axis overrides the other — the corner's demand is itself scaled by
     --density-mult, so "large radius + compact density" stays compact instead of the radius
     quietly winning. Without this, a box's text sits at a fixed distance while its corner
     grows around it: at data-radius="full" an re-row had a 28px corner and 14px of inset,
     and the label read as crowded into the curve.
     0.75 of the corner is the measured comfortable ratio — re-input at `full` lands at
     18/21 = 0.86 and reads right; re-row was at 14/28 = 0.5 and did not. */
  --re-box-inset: max(var(--pad-x), var(--radius-surface) * 0.75 * var(--density-mult, 1));
  --re-label-gutter: calc(var(--re-box-inset) + 1px);  /* the box's 1px border, so the
     label's text starts exactly where the box's text does — at every density and radius */
  --re-fab-h: 56px;   /* the FAB's own size — read by re-fab AND by the content clearance it needs (v7 §V7-9), so the two can never drift apart */
  /* Bottom tab bar placement — single source for the bar itself, the content
     clearance under it, and the FAB's lift. Override once to retune all three. */
  --re-tabbar-h: calc(58px * var(--density-mult, 1));   /* item height = icon 22 + gap 2 + label 13 + padding 20 */
  --re-tabbar-inset: 12px;   /* re-tabbar-float: gap to the left/right/bottom edges */
  --re-tabbar-item-w: calc(76px * var(--density-mult, 1));  /* re-tabbar-float: fixed item width, so the island's width follows the item COUNT (4 tabs = narrower than 5, and it never stretches edge to edge) */
  /* ── Calendar geometry (labs §V28-1) ────────────────────────────────────────
     The week grid's numbers, in one place, because three of them appear in more than
     one rule: the rail width is shared by the head row, the all-day band and the body
     (one grid, so it CANNOT drift — see re-cal-week), and the hour height is read by
     the rail label, the hour lines and every timed event's top/height. A consumer that
     wants a denser week retunes --re-cal-hour-h and nothing else moves. */
  /* The "today" disc, as a RATIO of the number it wraps — not a px size. Two views draw it
     and they had drifted: the month's was 19px around 11px type (1.73) while the week's was
     22px around 14px type (1.57), and the tighter one read as a digit squeezed into a circle.
     One number, in `em`, so it follows --font-scale and every density for free. The month
     lands at 18.9px where it was 19 — the fix is the WEEK's 22 → 24.1. */
  /* Two consecutive re-hint lines. The bound is typographic, not taste: a paragraph break must
     exceed the LEADING inside a paragraph (13px type at 1.4 → 5.2px), or two paragraphs read
     as one wrapped block; and it must stay under the gap that separates a section's PARTS
     (--re-section-gap, 10px), or the grouping information is gone. (labs §V29-1)

     ⚠ `calc(7px * density-mult)` alone was NOT enough, and only measuring all three densities
     showed it: the part gap follows --density-mult while the leading follows --font-scale, and
     at compact those two scales pull apart — 5.0px of gap against 4.9px of leading, i.e. the
     rule held by 0.1px and would have stopped holding on any retune of either scale. So the
     lower bound is WRITTEN, not hoped for: max() against 1.3x the leading
     (0.4 x 0.8125rem x font-scale is the leading itself). Measured after — compact
     4.9 < 6.4 < 7.2, standard 5.2 < 7.0 < 10.0, comfortable 5.5 < 7.8 < 11.2. */
  --re-hint-gap: max(calc(7px * var(--density-mult, 1)),
                     calc(0.52 * 0.8125rem * var(--font-scale)));
  /* The breathing room a fitted diagram keeps on all four sides. NOT density-scaled, and that
     is deliberate: --density-mult rescales how tightly the UI packs its controls, while this
     is optical margin around a DRAWING — the drawing does not get denser when the chrome
     does. A fixed 24px also keeps `fit` reproducible when someone compares two screenshots.
     (labs §RD-1b) */
  /* WCAG 2.5.8 Target Size (Minimum), AA: 24x24 CSS px. Named once so a control that is
     smaller than its own hit area can say WHY its pseudo-element is that size, and so a
     consumer auditing their own controls reads the DS's number instead of copying 24.
     Not 44 (2.5.5, AAA): the DS's own controls clear 24 by construction — --control-h-sm is
     already above it — and the only members of this class are text-sized controls like
     re-ph-back, where 44 would dominate the rhythm of the row it sits in. */
  --re-tap-min: 24px;
  --re-diagram-fit-pad: 24px;
  --re-cal-today-ratio: 1.72;
  --re-cal-hour-h: calc(44px * var(--density-mult, 1));  /* one hour of the day, vertically */
  --re-cal-rail-w: calc(52px * var(--density-mult, 1));  /* the time rail — fits "09:00" at --font-scale 1 */
  --re-cal-col-min: 92px;    /* a day column's floor: below this an event title has no room, so the week scrolls sideways instead of shrinking. 7 x 92 + rail = 696px, i.e. a phone scrolls and a tablet does not */
  --re-tabbar-count: 4;      /* re-tabbar-float: how many tabs the island holds — its width is item-w x count, so set this when you have 3 or 5 (v6 V6-4: it used to be inferred from content, which WebKit sized wrong and clipped a tab) */
  /* ── Icon size — ONE ratio, not ten px values ────────────────────────────────
     An icon that sits next to text is sized BY that text: --re-icon-ratio x the
     adjacent text's font-size. Because it reads `em` it follows --font-scale, so
     density propagates for free and no component has to restate a number.

     1.15 is measured, not picked: across the 16 components that already sized an
     icon, 11 of them land within 1.1px of what they draw today. The five that do
     not are genuinely a different requirement, and each DECLARES its own ratio at
     its own rule (re-tabbar-item 2, re-fab 1.6, re-tile-icon/re-weather-icon 1.4,
     the chip family 1). A declared ratio is not a magic number; `width: 22px` is.

     An icon with NO text to follow — a glyph alone in a fixed control — is the
     other family: it reads the CONTROL's height through its own
     --re-{component}-icon token (re-navbar-toggle, re-row-menu, re-check-btn…).
     There is nothing for a ratio-on-text to attach to there. */
  --re-icon-ratio: 1.15;
  /* The section heading's icon. The label (11px) and its subline (13px) both draw
     it, and they must draw it at ONE size — two icons of different sizes in the
     same heading read as an error. So the size is the LABEL's, named once here,
     rather than each rule resolving 1em against its own line. */
  --re-label-icon: calc(0.6875rem * var(--font-scale) * var(--re-icon-ratio));
}

/* ⚠ Declared on `svg`, deliberately NOT on :root.
   A var() inside a custom property is substituted at the element that DECLARES it, so a
   :root-only --re-icon would bake in :root's ratio and a component's own
   --re-icon-ratio would be silently ignored. Measured: with the token on :root, a host
   at font-size 11px with --re-icon-ratio 2 still drew 12.64px instead of 22px.
   `em`, by contrast, is NOT resolved at declaration — it stays a token until used — so
   declaring this on the svg itself gives the right answer twice over: the ratio resolves
   against the svg's inherited value, and 1em against the svg's inherited font-size.
   Same trap as --re-box-inset and the radius knob, one level down.

   Consequence worth knowing: this rule SHADOWS a --re-icon set on an ancestor. To resize
   an icon, set --re-icon-ratio on the host — not --re-icon. */
svg { --re-icon: calc(1em * var(--re-icon-ratio)); }

/* ── Base resets ─────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }

/* The two lines a reset owes the DS, and the DS never wrote.
   Found by measuring: the layout skeletons each pulled in a third-party CSS framework, used
   ZERO of its utilities (0 of 928 class tokens across the eight files), and were silently
   relying on its preflight for exactly these two behaviours. Once that load came out,
   95–203 element boxes moved per layout — which is how much the DS was borrowing.

   1. line-height. The string did not appear ANYWHERE in this file, so without preflight every
      run of text fell back to the UA's `normal` — measured, a 16.5px line became 14px and a
      22.5px one became 19px. Components that set their own line-height were unaffected, which
      is why nobody saw it.
   2. Form controls do not inherit the page font. The DS worked around this 39 separate times
      in the components sheet (`font-family:inherit`, once per component) and missed at least
      one: re-navbar-toggle rendered in Arial the moment the borrowed preflight was gone. A
      per-component workaround repeated 39 times is a missing base rule wearing a disguise. */
html { line-height: 1.5; }
button, input, optgroup, select, textarea {
  font-family: inherit;
  font-size: 100%;
  line-height: inherit;
  letter-spacing: inherit;
  color: inherit;
  margin: 0;
  padding: 0;   /* the UA gives <button> 1px 6px; every DS control sets its own */
}
/* The UA's monospace default is not the DS's — measured, a <kbd> fell back from
   JetBrains Mono to the generic `monospace` the moment preflight was gone. */
code, kbd, samp, pre { font-family: var(--font-mono); }
/* An inline <svg> sits on a text baseline and drags the line box with it — measured, a 14px
   icon in a 4px-padded button made the button 27.5px instead of 22px. Every icon in this
   system is a box next to text, never a glyph inside a run of it. */
img, svg, video, canvas, audio, iframe, embed, object { display: block; vertical-align: middle; }
/* The UA gives every table cell 1px of padding and separates borders; DS tables set their
   own, and a 1px offset nobody declared is exactly the kind of drift that gets reported. */
table { border-collapse: collapse; }
th, td { padding: 0; }
/* `hidden` attribute must beat any display-bearing class (re-flex/re-grid/…) */
[hidden] { display: none !important; }

body {
  margin: 0;
  font-family: var(--font-sans);
  background-color: var(--background);
  color: var(--foreground);
  -webkit-font-smoothing: antialiased;
}

/* ── Section — vertical spacing wrapper ─────────────────────────
   Full-width vertical rhythm layer. Backgrounds/borders go edge-to-edge.
   Content inside section is wrapped with .container.

   Usage:
     <main>
       <div class="re-section">
         <div class="container container-lg">
           ...page content...
         </div>
       </div>
     </main>

   Sizes (UIKit-inspired):
   xsm → 10px  top/bottom
   sm  → 20px  top/bottom
   default → 40px  top/bottom
   lg  → 60px  top/bottom
   ────────────────────────────────────────────────────────────── */
.re-section        { padding-top: calc(48px * var(--density-mult,1)); padding-bottom: calc(48px * var(--density-mult,1)); }
.re-section-xsm    { padding-top: calc(12px * var(--density-mult,1)); padding-bottom: calc(12px * var(--density-mult,1)); }
.re-section-sm     { padding-top: calc(24px * var(--density-mult,1)); padding-bottom: calc(24px * var(--density-mult,1)); }
.re-section-lg     { padding-top: calc(72px * var(--density-mult,1)); padding-bottom: calc(72px * var(--density-mult,1)); }

/* Section color variants — full-bleed background layers (token-based) */
.re-section-muted   { background: var(--muted); }
.re-section-card    { background: var(--card); }
.re-section-primary { background: color-mix(in oklch, var(--primary) 8%, transparent); }
.re-section-accent  { background: color-mix(in oklch, var(--accent) 10%, transparent); }

/* Section space removal — kill top/bottom padding (stacked sections'ta çift boşluğu önler) */
.re-section-remove-top    { padding-top: 0; }
.re-section-remove-bottom { padding-bottom: 0; }

/* ── Padding utilities ───────────────────────────────────────────
   UIKit-inspired: selectively add or remove padding.
   Useful when two stacked sections create double vertical gap.

   Usage — remove top padding of content section below a page-header:
     <div class="re-section re-section-sm re-padding-remove-top">

   ────────────────────────────────────────────────────────────── */
.re-padding          { padding: 20px !important; }
.re-padding-sm       { padding: 10px !important; }
.re-padding-lg       { padding: 40px !important; }
.re-padding-remove            { padding: 0 !important; }
.re-padding-remove-top        { padding-top: 0 !important; }
.re-padding-remove-bottom     { padding-bottom: 0 !important; }
.re-padding-remove-vertical   { padding-top: 0 !important; padding-bottom: 0 !important; }
.re-padding-remove-horizontal { padding-left: 0 !important; padding-right: 0 !important; }

/* ── Container — horizontal centering ───────────────────────────
   Centers content horizontally with consistent side padding.
   Does NOT set display:flex — layout inside is up to the content.

   Usage:
     <div class="container container-md">
       ...content...
     </div>

   For article + TOC side-by-side, add flex on an inner wrapper:
     <div class="container container-lg">
       <div style="display:flex;gap:32px;align-items:flex-start;">
         <article style="flex:1;min-width:0;">...</article>
         <aside id="toc" style="width:152px;flex-shrink:0;">...</aside>
       </div>
     </div>

   Sizes:
   sm  →  800px   lg  → 1120px   2xl → 1540px
   md  →  960px   xl  → 1280px   full → no max-width
   ────────────────────────────────────────────────────────────── */
/* The .container block moved to @layer utilities at the end of this file — see the note
   there. It is still documented above. */

/* ── Scrollbar utility ──────────────────────────────────────────
   Thin scrollbar hidden by default, visible on hover.
   Prevents layout shift: space is always reserved (scrollbar-width:thin).

   Usage:
     .re-scroll-y  — vertical scroll (boxes, sidebars, modals)
     .re-scroll-x  — horizontal scroll (wide tables, code blocks)
     .re-scroll    — both axes

   `html, body` lead the lists — BOTH, on purpose. Which element's scrollbar styles the
   VIEWPORT is a long-standing engine quirk: the used value propagates from html, and some
   builds read the pseudo-elements off html while others read them off body. Headless measured
   4px from `html` alone; a review on a real browser saw the UA's thick bar with its opaque
   track on the same page, which is what "no rule applied at all" looks like. Naming both costs
   nothing and removes the question.

   A DOCUMENT-scrolled page is a DS shape too, not an
   accident: two of the eight layouts (topbar-only, topbar-toc) are deliberately
   `re-navbar-sticky` + a plain `<main>`, so the viewport scrollbar IS their scrollbar. Left
   unstyled it was the UA's — measured 15px against 4px in the six app shells beside them in
   the same gallery, which is what a review saw as "one layout's scrollbar is thick and dark".
   A consumer who wants the native one back overrides it unlayered.

   Three COMPONENTS are named in these lists too — .re-cal-week, .re-main, .re-ms-list — and
   that is deliberate. Each of them scrolls BY DEFINITION (its own rule sets overflow), so
   none may depend on the consumer also remembering `re-scroll`. They used to carry their own
   copies of the nine declarations below: three copies that agreed with each other, drifted
   from this one (re-main had painted its track), and were all wrong in the same way — see the
   measurement note under this comment. A duplicated constant that happens to agree is not one
   constant. If a fourth component needs this, add it to these lists rather than pasting.

   Always pair with a max-height / max-width constraint:
     <div class="re-scroll-y" style="max-height:320px;">...</div>
     <div class="re-scroll-x">
       <table class="re-table">...</table>
     </div>
   ────────────────────────────────────────────────────────────── */
/* ⚠ MEASURED, and it inverts what you would expect: if EITHER `scrollbar-width` or
   `scrollbar-color` is specified, Blink/WebKit ignore `::-webkit-scrollbar` ENTIRELY. So this
   block used to claim 4px and reserve 11px, and a version that only reset `scrollbar-width`
   reserved 15px — worse than before. Four measurements, same box, Chrome:

     scrollbar-width:thin + color + ::-webkit 4px   → 11px   (what this file shipped)
     scrollbar-width:auto, color still set          → 15px   (the tempting half-fix)
     BOTH back to auto, ::-webkit does the work     →  4px   ✓
     nothing at all                                 → 15px

   Hence the split: the standard properties are for engines with no `::-webkit-scrollbar`
   (Firefox), and where the pseudo-elements DO exist both properties are handed back to `auto`
   so they stop suppressing them. The :hover rule has to be inside the same handover or the
   scrollbar reserves 15px on hover and the content reflows under the pointer. */
:is(html,body,.re-scroll,.re-scroll-y,.re-scroll-x,.re-cal-week,.re-main,.re-ms-list) {
  scrollbar-width: thin;
  scrollbar-color: transparent transparent;
}
:is(html,body,.re-scroll,.re-scroll-y,.re-scroll-x,.re-cal-week,.re-main,.re-ms-list):hover {
  scrollbar-color: color-mix(in oklch, var(--foreground) 20%, transparent) transparent;
}
.re-scroll   { overflow: auto; }
.re-scroll-y { overflow-y: auto; overflow-x: hidden; }
.re-scroll-x { overflow-x: auto; overflow-y: hidden; }

@supports selector(::-webkit-scrollbar) {
  :is(html,body,.re-scroll,.re-scroll-y,.re-scroll-x,.re-cal-week,.re-main,.re-ms-list),
  :is(html,body,.re-scroll,.re-scroll-y,.re-scroll-x,.re-cal-week,.re-main,.re-ms-list):hover {
    scrollbar-width: auto;
    scrollbar-color: auto;
  }
  :is(html,body,.re-scroll,.re-scroll-y,.re-scroll-x,.re-cal-week,.re-main,.re-ms-list)::-webkit-scrollbar { width: 4px; height: 4px }
  :is(html,body,.re-scroll,.re-scroll-y,.re-scroll-x,.re-cal-week,.re-main,.re-ms-list)::-webkit-scrollbar-track { background: transparent }
  /* Transparent at rest, so a resting scroller shows a 4px empty channel rather than a bar —
     which is the "only visible while scrolling" behaviour, done with hover because there is no
     `:scrolling` selector. */
  :is(html,body,.re-scroll,.re-scroll-y,.re-scroll-x,.re-cal-week,.re-main,.re-ms-list)::-webkit-scrollbar-thumb {
    background: transparent; border-radius: 2px }
  :is(html,body,.re-scroll,.re-scroll-y,.re-scroll-x,.re-cal-week,.re-main,.re-ms-list):hover::-webkit-scrollbar-thumb {
    background: color-mix(in oklch, var(--foreground) 20%, transparent) }
}
}  /* @layer base */


/* ══════════════════════════════════════════════════════════════════════════════
   The page column, in @layer UTILITIES — not base.

   `.container` is a name the DS does not own. A CSS framework a consumer loads may ship its
   own, in its own `utilities` layer, with a responsive max-width that reaches 1536px. Layer
   order beats specificity, so while this block sat in `base` the DS lost outright: measured
   on app-topbar at a 1600px viewport, a column asking for `container-md` (960px) rendered at
   **1536px**, and `.container.container-md` — two classes against their one — did not help,
   because no amount of specificity crosses a layer boundary.

   Both sheets name a `utilities` layer, so the two merge and specificity decides inside it.
   The compound selector then wins, and a consumer's own unlayered CSS still beats both.

   `.container` is a page primitive rather than a base reset anyway, so this is where it
   belonged; the collision is what made that visible. Everything the components layer says
   about a container (`.re-navbar > .container`, `.re-ph-body > .container`) sets `display`
   and `gap`, which this block does not touch, so nothing changes for them.
   ══════════════════════════════════════════════════════════════════════════════ */
@layer utilities {
.container {
  width: 100%;
  margin-left: auto;
  margin-right: auto;
  padding-left: var(--re-gutter);
  padding-right: var(--re-gutter);
  box-sizing: border-box;
}
/* Written as `.container.container-md`, not `.container-md`, for a measured reason:
   a framework a consumer loads alongside the DS may ship its OWN `.container` utility with a
   responsive max-width — at a wide viewport, 1536px. Same one class of specificity as ours,
   so source order decides, and in the page where this was measured (app-topbar at 1600px,
   loading such a framework) theirs won: the column asked for 960 and rendered at 1536.

   The compound selector is two classes against their one, so ours wins wherever both are
   present — which is always, since the size class is only meaningful on a `.container`. No
   rename, no markup change, and a consumer's own unlayered CSS still beats it. */
.container.container-sm   { max-width: 800px; }
.container.container-md   { max-width: 960px; }   /* default */
.container.container-lg   { max-width: 1120px; }
.container.container-xl   { max-width: 1280px; }
.container.container-2xl  { max-width: 1540px; }
.container.container-full { max-width: none; }
}
