/* Design System — canonical token layer for YOKU ONE.
   VARIANT A — "One Platform" (2026-09-25), a local-only design-system
   exploration branch (`design-variant-a-oneplatform`), never pushed to
   master/Railway. Source: Documents\YokuOne\one-platform-design-system.zip
   — a React/tokens package built for this exact product ("branch staff
   count stock, franchise owners watch branches, HQ runs campaigns and
   reviews submissions"). This app is FastAPI+Jinja2+vanilla CSS, so the
   React component bundle isn't usable directly; what's ported here is the
   package's token layer (`project/tokens.css`) remapped onto THIS file's
   existing variable names, so every rule in style.css/yoku-one.css/
   admin.css re-themes with zero template edits — same trick the Harbor
   Mist swap this replaces used.

   Semantic mapping (this system's 3-step surface ladder lines up almost
   exactly with One Platform's): --surface (page bg) = their surface-page;
   --surface-raised (cards) = their surface (white — "cards on a tinted
   page"); --surface-sunken (recessed-inside-a-card) = their surface-sunken.
   Their `aqua-600` (a secondary UI-strength hue, "not for text") takes our
   --accent-500 fill-only role; their `seasonal` purple is a near 1:1 match
   for this app's one deliberate violet hue, so --violet-tint/--on-violet
   map onto it rather than being re-derived. Where the source gives only
   2 steps and this file wants 3-4 (--primary-50..300, --ink-tertiary),
   the nearest source step is reused — marked DERIVED, same pattern the
   Harbor Mist block used.

   Radius: One Platform's stated principle is "Nothing is square" — every
   container takes a radius token, escalating from 6 to 28px. Re-scaled
   (not copied 1:1) onto this file's existing 4-step ladder so nothing
   downstream needs a new class: xs 2→6, sm(default control) 4→12,
   md(cards) 6→16, lg(modals) 8→20. Genuinely rounder than the previous
   2/4/6/8 system — that IS the point of trying this direction. */
:root, [data-theme="light"] {
  --surface: #f1f5fb; /* One Platform surface-page — the tinted scroll background every card floats on. */
  --surface-sunken: #f7f9fd; /* Their surface-sunken — recessed areas inside a card: table headers, disabled fields. */
  --surface-raised: #ffffff; /* Their surface — cards, sheets, input fields are white on the tinted page. */
  --border: #e4ebf5; /* Hairline dividers/card outlines only — under 3:1, decorative. */
  --border-strong: #7e93b0; /* Controls that must be perceivable: inputs, selects, outline buttons. 3.1:1. */
  --ink: #0f1b2d; /* Primary text. 17.3:1+ on every surface step. */
  --ink-secondary: #5b6b82; /* Captions, helper text, secondary labels (their ink-muted). */
  --ink-tertiary: #5f7089; /* Their ink-subtle — placeholders, inactive labels; the lightest tone that still reads. */
  --primary-50: #f4f8ff; /* Their brand-050 — faintest tint (info-note bg, selected row). */
  --primary-100: #e8f1fe; /* Their brand-100 — hover bg for ghost/tertiary buttons and chips, icon-tile fill. */
  --primary-200: #e8f1fe; /* DERIVED — source has no 3rd tint step; reuses brand-100. */
  --primary-300: #e8f1fe; /* DERIVED — disabled primary-button fill. */
  --primary-500: #0d66f9; /* Their brand-600 — THE brand blue. Primary button, active tab, icon glyphs. 4.9:1 on white. */
  --primary-600: #0a4fc4; /* Their brand-700 — pressed state of brand-600. */
  --primary-700: #082f76; /* DERIVED — brand-700 darkened further; source stops at one pressed step. */
  --brand-deep: #0d66f9; /* Same value as primary-500 — kept as its own token, same reasoning as the previous spec. */
  --on-brand-deep: #ffffff;
  --on-primary: #ffffff;
  --accent-100: #e3fbfa; /* DERIVED pale aqua tint — source gives no light tint step for aqua. */
  --accent-500: #23c9c2; /* Their aqua-600 — chart series two, illustration accents. A FILL, never text, same rule as the previous spec's gold. */
  --accent-700: #0f1b2d; /* = ink, following the same "soft tint carries ink" rule as before. */
  --focus: #0d66f9; /* Their focus-ring = brand-600 in light mode. 2px solid, 2px offset. */
  --brand-text: #0a52cc; /* Their brand-text: blue TEXT and links (6.79:1 on white). primary-500 is a fill — as small text in dark mode it fails 4.5:1. */
  --success: #0f7a4a; /* Their success — the ปกติ state. 4.8:1 on success-surface. */
  --success-tint: #e6f6ee;
  --on-success: #0f7a4a; /* Already accessible on its own tint per the source; no separate darker step given. */
  --warning: #8a5200; /* Their warning — the ใกล้หมด state. */
  --warning-tint: #fff4e2;
  --on-warning: #8a5200;
  --danger: #c0272d; /* Their danger — the หมด state. Text/icon role: flips lighter in dark mode below. */
  --danger-tint: #fdeceb;
  --on-danger: #c0272d;
  --danger-solid: #d92d20; /* Added 2026-09-25 (design audit): their danger-solid — notification count bubbles, badges,
     .btn-danger. Deliberately does NOT flip with the theme the way --danger does (dark-mode --danger is a pale salmon
     for text-on-surface legibility, which is unreadable as a fill with white text) — a fixed saturated red is the same
     "one solid state colour" role --success-solid already plays. */
  --on-danger-solid: #ffffff; /* Same in both themes — the source's own pairing. */
  --violet-tint: #f2ecfe; /* Their seasonal-surface — a near-exact match for this app's one violet hue. */
  --on-violet: #6d28d9; /* Their seasonal. */
}

/* Dark — One Platform ships this as a full counterpart, not a filter. */
[data-theme="dark"] {
  --surface: #0b1220;
  --surface-sunken: #0e1725;
  --surface-raised: #121c2b;
  --border: #223148;
  --border-strong: #56698a;
  --ink: #eaf0f8;
  --ink-secondary: #9dafc6;
  --ink-tertiary: #8093ac;
  --primary-50: #101c30;
  --primary-100: #13233c;
  --primary-200: #13233c;
  --primary-300: #13233c;
  --primary-500: #1a6ef7;
  --primary-600: #0a4fc4;
  --primary-700: #082f76; /* DERIVED, shared with light — source gives one pressed step per theme. */
  --brand-deep: #1a6ef7;
  --on-brand-deep: #ffffff;
  --on-primary: #ffffff;
  --accent-100: #10302e; /* DERIVED dark aqua tint. */
  --accent-500: #2fd8d0;
  --accent-700: #eaf0f8; /* = ink dark. */
  --focus: #4d8dfb;
  --brand-text: #7cb0ff;
  --success: #5fd39b;
  --success-tint: #0f2a1f;
  --on-success: #5fd39b;
  --warning: #f2b552;
  --warning-tint: #2b2010;
  --on-warning: #f2b552;
  --danger: #ff9089;
  --danger-tint: #2e1617;
  --on-danger: #ff9089;
  --danger-solid: #d92d20; /* Same value as light — deliberately fixed, see the light block's comment. */
  --on-danger-solid: #ffffff;
  --violet-tint: #241a3d;
  --on-violet: #b79cff;
}
:root {
  /* Derived blends, referenced from 3+ call sites each (form-field borders,
     icon chips) — defined once here rather than repeating the same
     color-mix() literal at every call site. Resolve lazily against
     whichever theme's --border-strong/--border/--primary-500/--card are
     active, same as any other var() reference. */
  --border-blend: color-mix(in srgb, var(--border-strong) 55%, var(--border) 45%);
  --icon-chip-bg: color-mix(in srgb, var(--primary-500) 55%, var(--card) 45%);
  --space-2: 2px; /* Icon-to-label gap inside a chip or inline tag — the tightest gap in the system. */
  --space-4: 4px; /* Gap between a table cell's stacked lines; icon-to-text gap in a compact list row; dense stat-tile internal padding. */
  --space-8: 8px; /* Vertical padding inside a compact list row or table cell; gap between a label and its control. */
  --space-12: 12px; /* Input and button padding; gap between fields in a form; horizontal padding of a stat tile on mobile. */
  --space-16: 16px; /* Card and panel padding; page gutter on mobile; gap between unrelated controls in a toolbar. */
  --space-24: 24px; /* Gap between grouped sections on a screen; card padding on tablet/desktop; gap between a heading and the content under it. */
  --space-32: 32px; /* Gap between major, unrelated blocks — a page's header and its content, one card group and the next. */
  --space-48: 48px; /* Top padding of a screen; empty-state and onboarding spacing — the most generous step, used sparingly. */
  --radius-xs: 6px; /* Checkboxes, switches, small tags and the inner corner of a nested control. */
  --radius-sm: 12px; /* Buttons, inputs, chips and list rows — the default control radius. */
  --radius-md: 16px; /* Cards, panels, dropdowns and popovers. */
  --radius-lg: 20px; /* Modals, sheets and any large surface — the largest radius in the system. */
  /* One Platform sets sans, thai AND numeric to the same face (2026-10-01),
     so the system now has ONE typeface and weight is what separates a
     heading from body text. Prompt is a Thai+Latin family, which is why
     Noto Sans Thai is gone rather than kept as a Thai fallback. */
  --font-sans: 'Prompt', system-ui, -apple-system, sans-serif;
  /* Legacy names, kept as aliases: five harbor.css rules and style.css call
     them, and nothing is gained by renaming call sites to reach one value. */
  --font-mitr: var(--font-sans);
  --font-noto-sans-thai: var(--font-sans);
  --text-Heading: 600 18px/1.5 var(--font-sans); /* Headings. 600, not 400 — with one family a 400 heading is indistinguishable from the body text beside it. */
  --text-body: 400 16px/1.5 var(--font-sans); /* Body copy, descriptions and small text. */
}
/* ---------------------------------------------------------------------
   Fleet base. These three rules are mandatory in every app that uses this
   system (DESIGN.md: The +2pt Root Rule, and the button font-family gotcha),
   and they are byte-identical everywhere — so they live in the ONE file the
   README says to copy as-is, instead of in prose each app has to remember.
   Each of them has already been forgotten once and shipped a real bug.
   This file loads after the app's own style.css, so these win. See also
   The Last-Wins Rule.
   --------------------------------------------------------------------- */

/* +2pt over the browser's 16px default. Almost every size in this system is
   rem-based, so this one line sets the whole app's reading size; an app that
   skips it renders ~14% smaller than its siblings. The body line is NOT
   optional — the shared style.css pins body to a literal 16px, not a rem, so
   body copy would stay small while every heading around it grew. */
html { font-size: calc(16px + 2pt); }
body {
  font-family: var(--font-noto-sans-thai);
  font-size: 1rem;
}

/* Form controls do not inherit body's font-family in any browser — they
   default to the platform UI font — so every button, input and select
   silently renders off-system until this is set. <a>-styled buttons never
   had the problem, which is exactly why it went unnoticed. */
button, input, select, textarea, optgroup { font-family: inherit; }

/* The Page Ladder: one width ladder for the whole fleet, held in a variable
   so a page and any fixed bar it owns share one value. Defined here; APPLIED
   per app, because it is opt-in by design — a long form page wants it, a
   login screen does not:
       .page { max-width: var(--page-max); }
   The console shell opts out with .page.page-app { max-width: none; },
   which wins on specificity with no !important. These steps are separate
   from the system's other breakpoints and coexist with them: 980px is the
   nav shell's posture change, 700/1000/1300px are column counts within a
   page. */
:root { --page-max: 480px; }
@media (min-width: 600px)  { :root { --page-max: 640px; } }
@media (min-width: 900px)  { :root { --page-max: 880px; } }
@media (min-width: 1200px) { :root { --page-max: 1080px; } }
