/* ============================================================================
   UFUQ · أفق — design tokens
   ----------------------------------------------------------------------------
   Values only. No selectors beyond :root and data-attribute scopes.

   Hex is declared first as a fallback; OKLCH redeclares it for modern engines.
   Every contrast figure in the comments was COMPUTED, not estimated — see
   design-system.html for the full measured table.

   The scene this system is built for:
     A salaried parent in Riyadh, 10pm on the sofa, phone in hand, working out
     whether the new car payment still leaves them safe when school fees land.
     They need a calm horizon line, not a trading terminal.

   That is why the default theme is light, the ink ramp is short and dark, and
   exactly one colour is allowed to be loud.
   ========================================================================== */

/* ---------------------------------------------------------------- fonts ----
   Self-hosted. The prototype must render with the network off — a client
   opens this from a file in a meeting room, and a webfont CDN is a
   single point of failure we refuse to have.                                */

@font-face { font-family: 'Plex Sans'; font-style: normal; font-weight: 400; font-display: swap; src: url('../fonts/ibm-plex-sans-400.woff2') format('woff2'); }
@font-face { font-family: 'Plex Sans'; font-style: normal; font-weight: 500; font-display: swap; src: url('../fonts/ibm-plex-sans-500.woff2') format('woff2'); }
@font-face { font-family: 'Plex Sans'; font-style: normal; font-weight: 600; font-display: swap; src: url('../fonts/ibm-plex-sans-600.woff2') format('woff2'); }
@font-face { font-family: 'Plex Sans'; font-style: normal; font-weight: 700; font-display: swap; src: url('../fonts/ibm-plex-sans-700.woff2') format('woff2'); }

@font-face { font-family: 'Plex Arabic'; font-style: normal; font-weight: 400; font-display: swap; src: url('../fonts/ibm-plex-sans-arabic-400.woff2') format('woff2'); }
@font-face { font-family: 'Plex Arabic'; font-style: normal; font-weight: 500; font-display: swap; src: url('../fonts/ibm-plex-sans-arabic-500.woff2') format('woff2'); }
@font-face { font-family: 'Plex Arabic'; font-style: normal; font-weight: 700; font-display: swap; src: url('../fonts/ibm-plex-sans-arabic-700.woff2') format('woff2'); }

@font-face { font-family: 'Plex Serif'; font-style: normal; font-weight: 400; font-display: swap; src: url('../fonts/ibm-plex-serif-400.woff2') format('woff2'); }
@font-face { font-family: 'Plex Serif'; font-style: normal; font-weight: 500; font-display: swap; src: url('../fonts/ibm-plex-serif-500.woff2') format('woff2'); }
@font-face { font-family: 'Plex Serif'; font-style: normal; font-weight: 600; font-display: swap; src: url('../fonts/ibm-plex-serif-600.woff2') format('woff2'); }

@font-face { font-family: 'Plex Mono'; font-style: normal; font-weight: 400; font-display: swap; src: url('../fonts/ibm-plex-mono-400.woff2') format('woff2'); }
@font-face { font-family: 'Plex Mono'; font-style: normal; font-weight: 500; font-display: swap; src: url('../fonts/ibm-plex-mono-500.woff2') format('woff2'); }


:root {
  color-scheme: light;

  /* ── Brand ────────────────────────────────────────────────────────────────
     Hue 279, a measured indigo. Chosen against two reflexes, not toward a
     preference: fintech defaults to navy-and-gold, and "fintech but not that"
     defaults to a black terminal. This is neither. It also sits far from every
     hue that carries money meaning here (green 165, red 28, amber 68-75), so
     the brand can never be mistaken for a financial state.
     NO MONEY STATE USES HUE 279.                                            */
  --brand:        #5858c5;  --brand:        oklch(0.520 0.165 279);  /* 5.81:1 on white */
  --brand-hover:  #4743b1;  --brand-hover:  oklch(0.455 0.170 279);  /* 7.76:1 */
  --brand-ring:   #6e72da;  --brand-ring:   oklch(0.600 0.155 279);  /* 4.13:1 — focus ring */
  --brand-line:   #c6ccfa;  --brand-line:   oklch(0.855 0.065 279);
  --brand-wash:   #edf0ff;  --brand-wash:   oklch(0.957 0.022 279);
  --brand-ink:    #ffffff;
  /* The knob of a switch and the label on a danger button are white in both
     themes — they sit on a saturated fill, not on a surface. */
  --knob:         #ffffff;

  /* ── Chrome — the phone status bar and the landing page's dark bands ───── */
  --chrome:       #17181f;  --chrome:       oklch(0.205 0.014 279);
  --chrome-2:     #22232c;  --chrome-2:     oklch(0.260 0.016 279);
  --chrome-line:  #32333f;  --chrome-line:  oklch(0.330 0.018 279);
  --ink-on-chrome:   #f2f2f6;                                        /* 15.8:1 on chrome */
  --ink-on-chrome-2: #b0b1bd;                                        /*  7.4:1 on chrome */
  /* Money semantics ON the chrome layer. The tooltip is dark in both themes,
     so the light-mode --in / --out steps would be unreadable inside it. */
  --in-on-chrome:    #6fe3b4;
  --out-on-chrome:   #ffab9e;

  /* ── Surfaces — neutrals tinted 279, toward the brand's own hue.
     Never warm. A warm-tinted near-white is the saturated AI default and it
     also makes money-green read sickly.                                     */
  --bg:           #ffffff;  --bg:           oklch(1.000 0.000 0);
  --surface:      #fafbfd;  --surface:      oklch(0.988 0.003 279);
  --surface-2:    #f4f4f7;  --surface-2:    oklch(0.968 0.004 279);
  --surface-sunk: #ececf1;  --surface-sunk: oklch(0.945 0.006 279);

  /* ── Ink ramp ─────────────────────────────────────────────────────────────
     --ink-3 is the TEXT FLOOR: 4.98:1 on white, 4.54:1 on --surface-sunk.
     Nothing lighter may ever carry a glyph — including placeholders, disabled
     labels and captions. --ink-4 is for non-text and large text ONLY.       */
  --ink:    #1c1d28;  --ink:    oklch(0.235 0.021 279);   /* 16.72:1 */
  --ink-2:  #51535e;  --ink-2:  oklch(0.445 0.018 279);   /*  7.64:1 */
  --ink-3:  #6e6f7a;  --ink-3:  oklch(0.545 0.016 279);   /*  4.98:1  ← floor */
  --ink-4:  #84858f;  --ink-4:  oklch(0.620 0.014 279);   /*  3.66:1  non-text only */
  --ink-inv:#fbfbfc;  --ink-inv:oklch(0.985 0.002 279);

  /* ── Lines. Not text colours. --line-control is the 3:1 floor for the
     boundary of an interactive control (WCAG 1.4.11).                       */
  --line:         #e0e1e7;  --line:         oklch(0.912 0.008 279);
  --line-strong:  #cbccd4;  --line-strong:  oklch(0.848 0.011 279);
  --line-control: #90919b;  --line-control: oklch(0.660 0.014 279);  /* 3.13:1 */

  /* ── Money semantics ──────────────────────────────────────────────────────
     RESERVED. These four never double as chart series colours, and never
     carry meaning without an icon or a label beside them — an arrow, a sign,
     a word. Colour alone is not a channel.

     `-mark` is the chart/marker step (larger areas, lower contrast is fine);
     the base step is the TEXT step and clears 4.5:1.                        */
  --in:        #007d58;  --in:        oklch(0.520 0.115 165);  /* 5.15:1 — income text */
  --in-mark:   #029e72;  --in-mark:   oklch(0.620 0.130 165);  /* 3.42:1 — income mark */
  --in-line:   #a4dfc4;  --in-line:   oklch(0.855 0.070 165);
  --in-fill:   #ddf7eb;  --in-fill:   oklch(0.955 0.032 165);

  --out:       #b94339;  --out:       oklch(0.545 0.155 28);   /* 5.35:1 — expense text */
  --out-mark:  #d95448;  --out-mark:  oklch(0.620 0.170 28);   /* 3.95:1 */
  --out-line:  #f6c3bb;  --out-line:  oklch(0.860 0.060 28);
  --out-fill:  #ffedea;  --out-fill:  oklch(0.960 0.022 28);

  --warn:      #a06616;  --warn:      oklch(0.560 0.115 68);   /* 4.77:1 — low balance */
  --warn-mark: #e8a127;  --warn-mark: oklch(0.760 0.150 75);   /* 2.20:1 — icon+label required */
  --warn-line: #efc895;  --warn-line: oklch(0.855 0.080 75);
  --warn-fill: #fff0d1;  --warn-fill: oklch(0.962 0.045 80);

  --crit:      #b91c1e;  --crit:      oklch(0.505 0.190 27);   /* 6.47:1 — below zero */
  --crit-fill: #ffe7e4;  --crit-fill: oklch(0.950 0.030 25);

  /* ── Data visualisation ───────────────────────────────────────────────────
     FORECAST: the signature chart. Actual is ink (it happened, it is fact);
     projection is brand, dashed (it is our claim, not a fact). The band is the
     same hue at low alpha. Nothing about a projection should look as certain
     as the past.                                                            */
  --viz-actual:   var(--ink);
  --viz-proj:     var(--brand);
  --viz-band:     oklch(0.520 0.165 279 / 0.10);
  --viz-danger:   oklch(0.505 0.190 27 / 0.07);   /* the region below zero */
  --viz-grid:     #eceef2;
  --viz-axis:     #cbccd4;

  /* CATEGORY SERIES — fixed order, never cycled. Validated as a set against
     both surfaces: adjacent-pair CVD dE 9.2 light / 8.9 dark (>=8 target),
     adjacent normal-vision dE 19.6 light / 19.3 dark (>=15 floor).
     Slots 3-5 sit under 3:1 on the light surface, so every category chart
     SHIPS DIRECT LABELS AND A TABLE VIEW — that is the relief rule, and it is
     not optional. A sixth category folds into --viz-other, never a new hue.  */
  --viz-1: #2a78d6;   /* Housing    4.42:1 */
  --viz-2: #eb6834;   /* Food       3.20:1 */
  --viz-3: #1baf7a;   /* Transport  2.82:1 ← label required */
  --viz-4: #eda100;   /* Education  2.17:1 ← label required */
  --viz-5: #e87ba4;   /* Health     2.69:1 ← label required */
  --viz-other: #a9abb6;

  /* ── Type ─────────────────────────────────────────────────────────────────
     One superfamily across three scripts. Plex Sans and Plex Sans Arabic are
     the same design intent extended to a second script — a script extension,
     not a font pairing. Plex Arabic sits in the Latin stack too, so an Arabic
     merchant name renders correctly on an English screen.

     Plex Serif is a display face and appears on index.html ONLY. It is banned
     from UI labels, buttons and data.                                       */
  --font-ui:      'Plex Sans', 'Plex Arabic', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-display: 'Plex Serif', Georgia, 'Times New Roman', serif;
  --font-num:     'Plex Mono', ui-monospace, 'SF Mono', Menlo, Consolas, monospace;

  /* Fixed rem steps, ratio ~1.15. Not fluid: product UI is read at a
     consistent DPI on a 390px phone, and a heading that shrinks inside a
     panel looks worse, not better. index.html overrides this with its own
     fluid display scale, because a brand surface is the one place that is
     right.                                                                  */
  --t-micro:  0.6875rem;  /* 11 */
  --t-meta:   0.75rem;    /* 12 */
  --t-dense:  0.8125rem;  /* 13 */
  --t-body:   0.875rem;   /* 14 */
  --t-lg:     1rem;       /* 16 */
  --t-h3:     1.125rem;   /* 18 */
  --t-h2:     1.3125rem;  /* 21 */
  --t-h1:     1.5rem;     /* 24 */
  --t-metric: 2rem;       /* 32 — a balance */
  --t-hero:   2.625rem;   /* 42 — the one big number on the dashboard */

  --lh-tight: 1.15;
  --lh-ui:    1.4;
  --lh-prose: 1.6;

  /* Arabic runs 20-30% longer than English and must never be letter-spaced.
     Both facts are handled in base.css under html[lang="ar"].               */

  /* ── Space — 4px base ─────────────────────────────────────────────────── */
  --s-1: 4px;   --s-2: 8px;   --s-3: 12px;  --s-4: 16px;  --s-5: 20px;
  --s-6: 24px;  --s-7: 32px;  --s-8: 40px;  --s-9: 48px;  --s-10: 64px;

  /* ── Radius ───────────────────────────────────────────────────────────── */
  --r-xs: 4px;  --r-sm: 6px;  --r: 10px;  --r-lg: 14px;  --r-xl: 20px;  --r-full: 999px;

  /* ── Elevation — three tight steps. Borders carry structure; shadow is a
     third-order cue. Nothing floats far off the page.                       */
  --e-1: 0 1px 2px rgba(28,29,40,0.05), 0 1px 1px rgba(28,29,40,0.04);
  --e-2: 0 2px 4px rgba(28,29,40,0.06), 0 6px 16px rgba(28,29,40,0.07);
  --e-3: 0 8px 20px rgba(28,29,40,0.10), 0 24px 48px rgba(28,29,40,0.12);

  /* ── Shell ────────────────────────────────────────────────────────────── */
  --phone-w:    390px;   /* iPhone 15 logical width */
  --phone-h:    844px;
  --statusbar:  44px;
  --appbar:     52px;
  --tabbar:     64px;
  --safe-bot:   22px;    /* home indicator */

  /* ── Motion ───────────────────────────────────────────────────────────────
     Product UI: 150-250ms. Users are in a task; they should not wait for
     choreography. Every duration here has a reduced-motion answer in base.css. */
  --ease-out:    cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
  --d-press:  120ms;
  --d-hover:  160ms;
  --d-pop:    190ms;
  --d-sheet:  240ms;
  --d-draw:   900ms;   /* the forecast line drawing itself in, once, on load */

  /* ── Z-index — semantic scale only. Never an arbitrary 999. ───────────── */
  --z-base: 1;  --z-raised: 10;  --z-dropdown: 100;  --z-sticky: 200;
  --z-backdrop: 300;  --z-sheet: 400;  --z-toast: 500;  --z-tooltip: 600;
}


/* ============================================================================
   DARK THEME
   ----------------------------------------------------------------------------
   Selected, not flipped. The ground is chroma 0 — a tinted dark ground plus a
   tinted brand is the tell. The panel layers carry the faint 279 tint instead.
   The category series are re-stepped for the dark surface and re-validated as
   a set; they are not the light hexes with a filter over them.
   ========================================================================== */

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

  --brand:        #8c92f9;  --brand:        oklch(0.700 0.150 279);  /* 6.74:1 on --bg */
  --brand-hover:  #a3abff;  --brand-hover:  oklch(0.770 0.130 279);
  --brand-ring:   #8c92f9;  --brand-ring:   oklch(0.700 0.150 279);
  --brand-line:   #3e4177;  --brand-line:   oklch(0.400 0.090 279);
  --brand-wash:   #22243c;  --brand-wash:   oklch(0.270 0.045 279);
  --brand-ink:    #101012;

  --chrome:       #0c0c0e;  --chrome:       oklch(0.145 0.003 279);
  --chrome-2:     #17181d;  --chrome-2:     oklch(0.205 0.006 279);
  --chrome-line:  #2e2f34;  --chrome-line:  oklch(0.305 0.010 279);
  --ink-on-chrome:   #f3f3f5;
  --ink-on-chrome-2: #b6b7c0;

  --bg:           #101012;  --bg:           oklch(0.178 0.000 0);
  --surface:      #17181d;  --surface:      oklch(0.205 0.006 279);
  --surface-2:    #1e1f25;  --surface-2:    oklch(0.248 0.008 279);
  --surface-sunk: #0b0b0d;  --surface-sunk: oklch(0.150 0.003 279);

  --ink:    #f3f3f5;  --ink:    oklch(0.965 0.003 279);   /* 17.15:1 */
  --ink-2:  #b6b7c0;  --ink-2:  oklch(0.782 0.012 279);   /*  9.52:1 */
  --ink-3:  #92949d;  --ink-3:  oklch(0.668 0.014 279);   /*  6.29:1  ← floor */
  --ink-4:  #7b7d85;  --ink-4:  oklch(0.590 0.013 279);   /*  4.54:1  non-text only */
  --ink-inv:#101012;

  --line:         #2e2f34;  --line:         oklch(0.305 0.010 279);
  --line-strong:  #414249;  --line-strong:  oklch(0.380 0.012 279);
  --line-control: #686a73;  --line-control: oklch(0.525 0.014 279);  /* 3.53:1 */

  --in:        #2dc08e;  --in:        oklch(0.720 0.140 165);  /* 8.02:1 */
  --in-mark:   #2dc08e;  --in-mark:   oklch(0.720 0.140 165);
  --in-line:   #1a533e;  --in-line:   oklch(0.400 0.070 165);
  --in-fill:   #0e2a1f;  --in-fill:   oklch(0.260 0.040 165);

  --out:       #ea6b5e;  --out:       oklch(0.680 0.160 28);   /* 6.00:1 */
  --out-mark:  #ea6b5e;  --out-mark:  oklch(0.680 0.160 28);
  --out-line:  #6c352f;  --out-line:  oklch(0.400 0.080 28);
  --out-fill:  #381c19;  --out-fill:  oklch(0.265 0.045 28);

  --warn:      #f2ab35;  --warn:      oklch(0.790 0.150 75);   /* 9.45:1 */
  --warn-mark: #f2ab35;  --warn-mark: oklch(0.790 0.150 75);
  --warn-line: #5c4110;  --warn-line: oklch(0.400 0.070 75);
  --warn-fill: #372508;  --warn-fill: oklch(0.280 0.050 75);

  --crit:      #f0574e;  --crit:      oklch(0.660 0.190 27);   /* 5.48:1 */
  --crit-fill: #3f1917;  --crit-fill: oklch(0.270 0.060 25);

  --viz-band:   oklch(0.700 0.150 279 / 0.16);
  --viz-danger: oklch(0.660 0.190 27 / 0.12);
  --viz-grid:   #24252b;
  --viz-axis:   #3a3b42;

  /* Re-stepped for the dark ground and re-validated: adjacent CVD dE 8.9,
     adjacent normal-vision dE 19.3, and every slot clears 3:1 here — so the
     relief rule that binds slots 3-5 in light mode does not bind in dark.   */
  --viz-1: #3987e5;   /* Housing    4.78:1 */
  --viz-2: #d95926;   /* Food       4.48:1 */
  --viz-3: #199e70;   /* Transport  5.11:1 */
  --viz-4: #c98500;   /* Education  5.67:1 */
  --viz-5: #d55181;   /* Health     4.41:1 */
  --viz-other: #6a6c76;

  --e-1: 0 1px 2px rgba(0,0,0,0.40);
  --e-2: 0 2px 4px rgba(0,0,0,0.44), 0 6px 16px rgba(0,0,0,0.40);
  --e-3: 0 8px 20px rgba(0,0,0,0.50), 0 24px 48px rgba(0,0,0,0.46);
}
