/* ============================================================================
   AQOON design tokens — THE source of truth for colour, type, space and shape
   ----------------------------------------------------------------------------
   Load order:  tokens.css -> base.css -> components/*.css -> utilities.css
                -> app.css | portal.css        (surface-specific layout)
   ...then the server-rendered <style> block in base.html, which sets the
   tenant's own --brand-* values. Custom properties resolve at computed-value
   time, so that later block correctly overrides the defaults below.

   THREE LAYERS. Feature templates may only ever touch layer 3.

     Layer 1  --brand-*      the tenant's identity. TWO configured values;
                             everything else is DERIVED in app.py (_safe_fill,
                             _tint, _on_color) so no school can configure an
                             inaccessible pair and dark mode always follows the
                             school's colour rather than a hardcoded one.
     Layer 2  semantic       --ink, --surface, --success … meaning, not colour.
     Layer 3  component      --btn-primary-bg, --nav-active-fg … what to type.

   Every value below is contrast-verified; see docs/design-system.md for the
   measured ratios and scripts/check_design_tokens.py for the guard that stops
   raw hex creeping back into templates.
   ========================================================================== */

/* ---------------------------------------------------------------------------
   LAYER 1 — TENANT BRAND
   The server emits real values for these (see base.html). The fallbacks are
   the neutral AQOON defaults, used before a school configures anything and by
   any surface rendered without the theme context (e.g. the error page).
   --------------------------------------------------------------------------- */
:root{
  --brand-primary:        #1B2C6B;
  --brand-primary-dark:   #162457;   /* hover / pressed */
  --brand-primary-fill:   #1B2C6B;   /* text-safe: guaranteed >=4.5:1 with --on-brand-primary */
  --on-brand-primary:     #FFFFFF;
  --brand-primary-tint:   #a8afc7;   /* dark-mode treatment of the brand */

  --brand-secondary:      #F2C230;
  --brand-secondary-dark: #c69f27;
  --brand-secondary-fill: #F2C230;
  /* NEVER white. Measured: white on #F2C230 = 1.68:1, ink = 9.17:1. The
     server picks this per tenant; the default here is the ink case. */
  --on-brand-secondary:   #1B2537;
  --brand-secondary-tint: #fae8b0;

  /* The brand used AS TEXT on a --surface. Two derived values per brand
     because a colour readable on white is not readable on near-black: the
     sign-in card showed gold-on-white at 1.68:1 in light mode and
     navy-on-near-black at 1.33:1 in dark. The -light/-dark pair is supplied
     by the server (_readable_on in app.py); the switch below is the only
     place that chooses between them. */
  --brand-primary-text-light:   #1B2C6B;
  --brand-primary-text-dark:    #828bae;
  --brand-secondary-text-light: #856b1a;
  --brand-secondary-text-dark:  #F2C230;
  --brand-primary-text:   var(--brand-primary-text-light);
  --brand-secondary-text: var(--brand-secondary-text-light);

  /* Low-alpha brand washes for active/selected surfaces. color-mix is already
     a dependency of this codebase (app.css used it before this file existed);
     the flat fallback on the preceding line covers anything older. */
  --brand-subtle:         #E8EBF7;
  --brand-subtle:         color-mix(in srgb, var(--brand-primary) 12%, var(--surface));
  --brand-subtle-strong:  #D5DBEF;
  --brand-subtle-strong:  color-mix(in srgb, var(--brand-primary) 22%, var(--surface));
}

/* ---------------------------------------------------------------------------
   LAYER 2 — SEMANTIC
   --------------------------------------------------------------------------- */
:root{
  /* text ------------------------------------------------------------------ */
  --ink:              #1B2537;   /* 15.37:1 on --surface */
  --ink-muted:        #5A6B82;   /*  5.44:1 */
  --ink-inverse:      #FFFFFF;
  --link:             #1B5FA8;   /*  6.46:1 */
  --link-hover:       #14487F;

  /* surfaces -------------------------------------------------------------- */
  --bg:               #F4F6F9;
  --surface:          #FFFFFF;
  --surface-2:        #F8FAFC;   /* inset panels, table heads */
  --surface-3:        #EEF2F7;   /* pressed / hovered inset */

  /* lines ----------------------------------------------------------------- */
  --line:             #D6DEE8;   /* decorative separators */
  --line-interactive: #7C8A9C;   /* 3.52:1 — input & control borders, SC 1.4.11 */
  --line-strong:      #5A6B82;

  /* status: foreground on --surface --------------------------------------- */
  --success:          #0B7A48;   /* 5.40:1 */
  --warning:          #8A5300;   /* 6.33:1 */
  --danger:           #B3261E;   /* 6.54:1 */
  --info:             #1B6BA8;   /* 5.65:1 */

  /* status: soft surfaces, paired with the -on value below ---------------- */
  --success-soft:     #E7F4EC;   --on-success-soft: #0B7A48;  /* 4.77:1 */
  --warning-soft:     #FDF3DC;   --on-warning-soft: #8A5300;  /* 5.74:1 */
  --danger-soft:      #FCEBEA;   --on-danger-soft:  #B3261E;  /* 5.67:1 */
  --info-soft:        #E8F1F9;   --on-info-soft:    #1B6BA8;  /* 4.95:1 */

  /* status: solid fills that carry white text ----------------------------- */
  --success-solid:    #0B7A48;   --on-success-solid: #FFFFFF;
  --danger-solid:     #B3261E;   --on-danger-solid:  #FFFFFF;
  --info-solid:       #1B6BA8;   --on-info-solid:    #FFFFFF;
  /* Amber cannot carry white at any usable lightness — it takes dark ink. */
  --warning-solid:    #F2C230;   --on-warning-solid: #1B2537;

  /* ---------------------------------------------------------------------- */
  /* VIBRANT fills — the "basic" UI style only (see [data-ui-style="basic"]) */
  /* ---------------------------------------------------------------------- */
  /* The school's original dashboard palette, kept. The old treatment put
     WHITE on all of these and measured 2.15:1 (amber) to 4.23:1 (violet) —
     7 of 10 below AA. The colours were never the problem; the foreground
     was. Six of these fills are the ORIGINAL hex, unchanged, now paired with
     the foreground that actually passes on them: amber goes 2.15:1 -> 7.16:1
     purely by taking dark ink instead of white.

     Three hues sat at a mid luminance where NEITHER white nor ink reaches
     4.5:1. Those are nudged by the smallest step that clears it (see
     _safe_fill in app.py, which produced these values) — #ef4444 -> #f15757,
     #8b5cf6 -> #8457ea. A fill and its foreground are a self-contained pair,
     independent of the page behind them, so these need no dark-mode variant.
     Ratios below are measured, not intended. */
  --vib-info:      #0ea5e9;   --on-vib-info:    #1B2537;  /* 5.55:1  original */
  --vib-success:   #10b981;   --on-vib-success: #1B2537;  /* 6.06:1  original */
  --vib-warning:   #f59e0b;   --on-vib-warning: #1B2537;  /* 7.16:1  original */
  --vib-neutral:   #64748b;   --on-vib-neutral: #FFFFFF;  /* 4.76:1  original */
  --vib-danger:    #f15757;   --on-vib-danger:  #1B2537;  /* 4.57:1  nudged from #ef4444 */
  --vib-brand:     #8457ea;   --on-vib-brand:   #FFFFFF;  /* 4.63:1  nudged from #8b5cf6 */

  /* focus ----------------------------------------------------------------- */
  --focus-color:      var(--brand-primary);
  --focus-ring:       rgba(27, 44, 107, .28);
  --focus-ring:       color-mix(in srgb, var(--brand-primary) 32%, transparent);
  --focus-width:      3px;
  --focus-offset:     2px;
}

[data-bs-theme="dark"]{
  --ink:              #E6EDF3;   /* 14.64:1 on --surface */
  --ink-muted:        #9BA9BA;   /*  7.23:1 */
  --ink-inverse:      #0D1117;
  --link:             #9DB2F0;   /*  8.29:1 */
  --link-hover:       #C0CEF6;

  --bg:               #0D1117;
  --surface:          #161B22;
  --surface-2:        #1C222B;
  --surface-3:        #232A34;

  --line:             #2A323D;
  --line-interactive: #5C6B80;   /* 3.19:1 */
  --line-strong:      #7E8C9E;

  --success:          #4ADE80;   /*  9.93:1 */
  --warning:          #FBBF3C;   /* 10.40:1 */
  --danger:           #FF8A80;   /*  7.58:1 */
  --info:             #6BB6F0;   /*  7.89:1 */

  --success-soft:     #12291C;   --on-success-soft: #4ADE80;  /* 8.86:1 */
  --warning-soft:     #2A2110;   --on-warning-soft: #FBBF3C;  /* 9.54:1 */
  --danger-soft:      #2C1615;   --on-danger-soft:  #FF8A80;  /* 7.46:1 */
  --info-soft:        #11212E;   --on-info-soft:    #6BB6F0;  /* 7.48:1 */

  /* Solid status fills stay dark-text-on-light in dark mode: an inverted
     solid badge is how a status chip stays a chip rather than a hole. */
  --success-solid:    #4ADE80;   --on-success-solid: #0D1117;
  --danger-solid:     #FF8A80;   --on-danger-solid:  #0D1117;
  --info-solid:       #6BB6F0;   --on-info-solid:    #0D1117;
  --warning-solid:    #FBBF3C;   --on-warning-solid: #0D1117;

  /* Brand-as-text flips to the dark-surface variant. Same tenant colour,
     lightened only as far as AA requires, so the hue stays recognisable. */
  --brand-primary-text:   var(--brand-primary-text-dark);
  --brand-secondary-text: var(--brand-secondary-text-dark);

  /* The brand in dark mode is the DERIVED tint of the school's own colour.
     This is what replaced the hardcoded legacy orange (audit finding P0-4). */
  --brand-subtle:         #232A3A;
  --brand-subtle:         color-mix(in srgb, var(--brand-primary-tint) 18%, var(--surface));
  --brand-subtle-strong:  #2C3446;
  --brand-subtle-strong:  color-mix(in srgb, var(--brand-primary-tint) 28%, var(--surface));

  --focus-ring:       rgba(157, 178, 240, .34);
  --focus-ring:       color-mix(in srgb, var(--brand-primary-tint) 38%, transparent);
}

/* ---------------------------------------------------------------------------
   TYPOGRAPHY
   System stack retained deliberately: zero network cost, correct Somali
   diacritic rendering, native on every platform. No remote font dependency.
   12px is the floor — nothing smaller ships.
   --------------------------------------------------------------------------- */
:root{
  --font-sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue",
               "Noto Sans", "Liberation Sans", Arial, sans-serif,
               "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
               "Noto Color Emoji";
  --font-mono: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono",
               "Courier New", monospace;

  --fs-display: 30px;  --lh-display: 36px;
  --fs-h2:      24px;  --lh-h2:      32px;
  --fs-h3:      20px;  --lh-h3:      28px;
  --fs-h4:      17px;  --lh-h4:      24px;
  --fs-body:    15px;  --lh-body:    22px;
  --fs-sm:      13.5px; --lh-sm:     20px;
  --fs-xs:      12px;  --lh-xs:      16px;   /* floor */

  --fw-regular:  400;
  --fw-medium:   500;
  --fw-semibold: 600;
  --fw-bold:     700;

  --tracking-caps: .04em;
}

/* ---------------------------------------------------------------------------
   SPACING — 8px base
   --------------------------------------------------------------------------- */
:root{
  --space-1:  4px;
  --space-2:  8px;
  --space-3:  12px;
  --space-4:  16px;
  --space-5:  24px;
  --space-6:  32px;
  --space-7:  48px;
  --space-8:  64px;

  /* semantic spacing */
  --gutter-page:    var(--space-5);
  --gutter-page-sm: var(--space-3);
  --gap-card:       var(--space-4);
  --gap-field:      var(--space-4);
  --gap-inline:     var(--space-2);
}

/* ---------------------------------------------------------------------------
   RADIUS — a controlled scale. The audit measured five ad-hoc values in use
   (4/6/8/12/800px); these are the sanctioned ones.
   --------------------------------------------------------------------------- */
:root{
  --radius-xs:   4px;   /* chips, small inputs */
  --radius-sm:   6px;   /* buttons, inputs */
  --radius-md:   10px;  /* dropdowns, popovers */
  --radius-lg:   12px;  /* cards */
  --radius-xl:   16px;  /* modals, portal cards */
  --radius-pill: 999px;
}

/* ---------------------------------------------------------------------------
   ELEVATION — semantic, not literal. Dark mode leans on surface lightness
   rather than shadow, so the same token reads correctly in both themes.
   --------------------------------------------------------------------------- */
:root{
  --shadow-none:  none;
  --shadow-sm:    0 1px 3px rgba(15, 23, 42, .06);
  --shadow-md:    0 4px 12px rgba(15, 23, 42, .10);
  --shadow-lg:    0 12px 32px rgba(15, 23, 42, .16);
  --shadow-focus: 0 0 0 var(--focus-width) var(--focus-ring);
}
[data-bs-theme="dark"]{
  --shadow-sm:    0 1px 3px rgba(0, 0, 0, .40);
  --shadow-md:    0 4px 12px rgba(0, 0, 0, .48);
  --shadow-lg:    0 12px 32px rgba(0, 0, 0, .56);
}

/* ---------------------------------------------------------------------------
   MOTION
   --------------------------------------------------------------------------- */
:root{
  --motion-fast:  120ms;   /* hover / press / focus */
  --motion-base:  200ms;   /* enter / exit */
  --motion-slow:  320ms;
  --ease-standard: cubic-bezier(.2, 0, 0, 1);
  --ease-out:      cubic-bezier(0, 0, .2, 1);
}

/* ---------------------------------------------------------------------------
   LAYER 3 — COMPONENT TOKENS
   The only layer feature templates and component CSS should reference.
   --------------------------------------------------------------------------- */
:root{
  /* buttons ---------------------------------------------------------------- */
  --btn-primary-bg:          var(--brand-primary-fill);
  --btn-primary-fg:          var(--on-brand-primary);
  --btn-primary-bg-hover:    var(--brand-primary-dark);
  --btn-primary-border:      transparent;

  --btn-secondary-bg:        var(--brand-secondary-fill);
  --btn-secondary-fg:        var(--on-brand-secondary);
  --btn-secondary-bg-hover:  var(--brand-secondary-dark);
  --btn-secondary-border:    transparent;

  --btn-quiet-bg:            transparent;
  --btn-quiet-fg:            var(--ink);
  --btn-quiet-bg-hover:      var(--surface-3);
  --btn-quiet-border:        var(--line-interactive);

  --btn-danger-bg:           var(--danger-solid);
  --btn-danger-fg:           var(--on-danger-solid);

  /* surfaces --------------------------------------------------------------- */
  --card-bg:        var(--surface);
  --card-border:    var(--line);
  --card-radius:    var(--radius-lg);
  --card-shadow:    var(--shadow-sm);

  /* forms ------------------------------------------------------------------ */
  --input-bg:            var(--surface);
  --input-fg:            var(--ink);
  --input-border:        var(--line-interactive);
  --input-border-focus:  var(--brand-primary);
  --input-placeholder:   var(--ink-muted);
  --input-radius:        var(--radius-sm);
  --input-invalid:       var(--danger);
  --label-fg:            var(--ink);
  --help-fg:             var(--ink-muted);

  /* tables ----------------------------------------------------------------- */
  --table-head-bg:    var(--surface-2);
  --table-head-fg:    var(--ink-muted);
  --table-border:     var(--line);
  --table-row-hover:  var(--surface-2);
  --table-row-stripe: var(--surface-2);

  /* navigation ------------------------------------------------------------- */
  --nav-bg:            var(--surface);
  --nav-fg:            var(--ink);
  --nav-fg-muted:      var(--ink-muted);
  --nav-hover-bg:      var(--surface-3);
  --nav-active-bg:     var(--brand-subtle);
  --nav-active-fg:     var(--brand-primary-dark);
  --nav-active-marker: var(--brand-primary);

  /* status chips ----------------------------------------------------------- */
  --status-success-bg: var(--success-soft);  --status-success-fg: var(--on-success-soft);
  --status-warning-bg: var(--warning-soft);  --status-warning-fg: var(--on-warning-soft);
  --status-danger-bg:  var(--danger-soft);   --status-danger-fg:  var(--on-danger-soft);
  --status-info-bg:    var(--info-soft);     --status-info-fg:    var(--on-info-soft);
  --status-neutral-bg: var(--surface-3);     --status-neutral-fg: var(--ink-muted);
}

[data-bs-theme="dark"]{
  /* In dark mode the brand fill is the tint (legible on a dark surface); its
     foreground flips to the dark background colour. */
  --btn-primary-bg:       var(--brand-primary-tint);
  --btn-primary-fg:       #0D1117;
  /* Hover stays the same hue, one step brighter — never a different colour. */
  --btn-primary-bg-hover: #c3c8d9;
  --btn-primary-bg-hover: color-mix(in srgb, var(--brand-primary-tint) 78%, #FFFFFF);

  --btn-secondary-bg:       var(--brand-secondary-tint);
  --btn-secondary-fg:       #0D1117;
  --btn-secondary-bg-hover: #fcf0ca;
  --btn-secondary-bg-hover: color-mix(in srgb, var(--brand-secondary-tint) 78%, #FFFFFF);

  --nav-active-fg:     var(--brand-primary-tint);
  --nav-active-marker: var(--brand-primary-tint);
}
