/* FuelFlow — design tokens.
 *
 * Single source of truth for colour, type, space, shape and motion. Nothing
 * downstream may hard-code a value that exists here; tests/test_styles.py
 * fails the build on a hex literal outside this file.
 *
 * Colour is spent on action and status, never decoration. Every semantic
 * colour is paired in markup with a glyph and a word, so status is never
 * carried by hue alone (WCAG 2.2 §1.4.1).
 *
 * Token NAMES match ~/Projects/fuel-trading-system so components written
 * against that system transfer here unchanged. The VALUES are FuelFlow's:
 * this product's identity is a deep navy with a warm orange signature, not
 * the reference's cyan, and that identity predates this file — the ramps
 * below are the ones the application already used, promoted to tokens.
 */

:root {
  /* ---- brand: FuelFlow navy ---------------------------------------------
   * The product accent, and the only blue that carries an action. Deep enough
   * at 600 for white text to meet WCAG AA on a button.
   */
  --brand-50:  #eff3fb;
  --brand-100: #dae4f6;
  --brand-200: #b3c7ec;
  --brand-300: #82a3de;
  --brand-400: #4f7acb;
  --brand-500: #2557ac;
  --brand-600: #104090;
  --brand-700: #0d3475;
  --brand-800: #0a295d;
  --brand-900: #071d42;

  /* Navigation chrome is near-black navy so the orange signature reads as the
   * one warm thing on the screen. Orange is chrome-only: it never carries a
   * status, because a forecourt product cannot afford amber to mean two
   * things. */
  --chrome:        #0c2144;
  --chrome-accent: #ff6f44;
  --chrome-text:   rgba(255, 255, 255, .78);
  --chrome-muted:  rgba(255, 255, 255, .45);
  --chrome-line:   rgba(255, 255, 255, .08);
  --chrome-hover:  rgba(255, 255, 255, .07);
  --chrome-active: rgba(255, 255, 255, .12);

  /* Application chrome and activity cues. */
  --appbar-bg:    #071630;
  --appbar-hover: #12294e;
  --appbar-text:  #ffffff;
  --cue-bg:       #104090;
  --cue-bg-hover: #0d3475;
  --cue-text:     #ffffff;

  /* Categorical series, in the order a chart consumes them. Navy and orange
   * lead because they are the product's own pair; green and amber follow but
   * are deliberately the *fourth* and *fifth* slices, so a two- or
   * three-series chart never accidentally borrows a status colour. Each is
   * contrast-checked against the card surface in tests/test_styles.py. */
  --chart-1: #104090;
  --chart-2: #ff6f44;
  --chart-3: #4f7acb;
  --chart-4: #047857;
  --chart-5: #92400e;
  --chart-6: #82a3de;
  --chart-grid:  #e5e7eb;
  --chart-label: #4b5563;

  /* ---- neutrals: FuelFlow slate ------------------------------------------ */
  --n-0:   #ffffff;
  --n-25:  #f9fafb;
  --n-50:  #f3f4f6;
  --n-100: #eceef1;
  --n-150: #e5e7eb;
  --n-200: #d1d5db;
  --n-300: #b5bcc6;
  --n-400: #9ca3af;
  --n-500: #6b7280;
  --n-600: #4b5563;
  --n-700: #374151;
  --n-800: #1f2937;
  --n-900: #0a0f1e;

  /* ---- semantic ----------------------------------------------------------
   * pos/neg are the ledger's credit/debit pair, not merely "success/error".
   */
  --pos-50:  #ecfdf5;
  --pos-200: #a7e5c2;
  --pos-300: #6ee7b7;
  --pos-600: #047857;
  --pos-700: #065f46;

  --neg-50:  #fef2f2;
  --neg-200: #fecaca;
  --neg-600: #b91c1c;
  --neg-700: #991b1b;

  --warn-50:  #fef3c7;
  --warn-200: #f2d1a0;
  --warn-600: #b45309;
  --warn-700: #92400e;

  /* Informational blue is a lighter, cooler blue than the brand navy so an
   * information notice is never mistaken for a primary action. */
  --info-50:  #e0f2fe;
  --info-200: #bae6fd;
  --info-600: #0284c7;
  --info-700: #075985;

  /* ---- financial column group --------------------------------------------
   * A run of money columns is tinted so it reads as one block — the financial
   * position of a row — rather than several unrelated figures sharing a table.
   * The tint is deliberately weak: it groups, it does not highlight. Anything
   * stronger and every row looks like an exception, which is the signal these
   * screens must keep in reserve for rows that are.
   */
  --fin-bg:       #f5f8fd;
  --fin-bg-hover: #e9f0fa;
  --fin-border:   var(--brand-100);
  --fin-head:     var(--brand-700);

  /* ---- surfaces ----------------------------------------------------------- */
  --bg-app:      var(--n-25);
  --bg-surface:  var(--n-0);
  --bg-sunken:   var(--n-100);
  --bg-hover:    var(--n-50);
  --bg-selected: var(--brand-50);

  --border:        var(--n-200);
  --line:          var(--border);
  --surface:       var(--bg-surface);
  --surface-2:     var(--bg-sunken);
  --muted:         var(--n-600);
  --border-strong: var(--n-300);

  --text:        var(--n-800);
  --text-muted:  var(--n-600);
  --text-subtle: var(--n-500);
  --text-invert: var(--n-0);

  /* ---- tables --------------------------------------------------------------
   * The list treatment follows the MyWetStock reference (wetstock-ui.css):
   * a barely-tinted header row in muted sentence-case text, rows ruled
   * horizontally only, a tinted hover, and cell gutters that line up with the
   * panel the table sits in. Every value is an alias, so the look follows the
   * colour mode and the staff palette without a second set of numbers. */
  --table-head-bg:   var(--n-25);
  --table-head-text: var(--text-muted);
  --table-head-rule: var(--n-200);
  --table-rule:      var(--n-100);
  --table-hover:     var(--brand-50);
  --table-text:      var(--text);
  --table-gutter:    var(--s-5);
  --table-head-py:   10px;

  /* ---- type --------------------------------------------------------------
   * 14px base. Headings stay small on purpose: a 40px page title costs a row
   * of data on a screen someone reads for seven hours. Inter is already loaded
   * by the shell and is the product's face; the stack degrades to the system
   * UI font rather than to a serif.
   */
  --font-sans: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
               "Helvetica Neue", Arial, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
               "Liberation Mono", monospace;

  --fs-11: 0.6875rem;
  --fs-12: 0.75rem;
  --fs-13: 0.8125rem;
  --fs-14: 0.875rem;
  --fs-16: 1rem;
  --fs-18: 1.125rem;
  --fs-22: 1.375rem;
  --fs-28: 1.75rem;
  --fs-32: 2rem;

  --fw-regular: 400;
  --fw-medium: 500;
  --fw-semibold: 600;
  --fw-bold: 700;
  /* Reserved for figures that carry a decision — a balance, a KPI, an amount
   * on an invoice. Weight is how this product gets its authority, because size
   * cannot. */
  --fw-heavy: 800;

  --lh-tight: 1.25;
  --lh-normal: 1.5;

  /* ---- space: 4px grid ---------------------------------------------------- */
  --s-1: 4px;
  --s-2: 8px;
  --s-3: 12px;
  --s-4: 16px;
  --s-5: 20px;
  --s-6: 24px;
  --s-8: 32px;
  --s-10: 40px;
  --s-12: 48px;
  --s-16: 64px;

  /* ---- shape -------------------------------------------------------------
   * Softer than the reference by 2px at every step. That is FuelFlow's own
   * corner and it predates this file; keeping the reference's sharper radii
   * would have made the port look like a different product.
   */
  --r-sm: 6px;
  --r-md: 8px;
  --r-lg: 12px;
  --r-pill: 999px;

  /* Three elevations: a hairline at rest, a lift for cards, a float for
   * overlays. Tinted with the navy ink rather than pure black so shadows sit
   * in the same colour world as everything else. */
  --shadow-sm: 0 1px 3px rgba(15, 23, 42, .05), 0 1px 2px rgba(15, 23, 42, .03);
  --shadow-md: 0 4px 14px rgba(15, 23, 42, .06), 0 1px 4px rgba(15, 23, 42, .04);
  --shadow-lg: 0 16px 40px rgba(15, 23, 42, .10), 0 4px 12px rgba(15, 23, 42, .04);

  /* ---- layout ------------------------------------------------------------- */
  /* FuelFlow's own rail width, as the colour ramps are FuelFlow's own: the
     reference supplies the token NAME, this product supplies the value. */
  --rail-w: 218px;
  --rail-w-expanded: 218px;
  --rail-w-collapsed: 56px;
  --topbar-h: 60px;
  --content-max: 1480px;

  /* ---- motion: functional only -------------------------------------------- */
  --ease: cubic-bezier(.2, 0, .2, 1);
  --dur-fast: 90ms;
  --dur: 150ms;

  --focus-ring: 0 0 0 2px var(--n-0), 0 0 0 4px var(--brand-600);

  --z-rail: 20;
  --z-topbar: 30;
  --z-drawer: 60;
  --z-dialog: 70;
  --z-toast: 80;
}

/* Density is a user preference; the rail toggle writes this attribute. */
/* --row-py is the table row density. Comfortable gives the reference's
   ~54px rows; compact is for the operator who wants a screenful. */
:root[data-density="compact"] {
  --row-py: 6px;
  --control-h: 28px;
}
:root,
:root[data-density="comfortable"] {
  --row-py: 15px;
  --control-h: 34px;
}

/* ── Dark mode ─────────────────────────────────────────────────────────────
 * New to FuelFlow: the application had no dark palette before this file.
 * A low-glare navy, not a grey — the product keeps its colour world at night.
 * Semantic hues are lifted, never merely inverted: #047857 green on a dark
 * card is unreadable, so the ramps flip which end carries the text colour.
 *
 * Explicit toggle only, matching the reference. A back-office screen is used
 * in daylight and an operator who has set their OS to dark has not thereby
 * asked for their ledger to change colour; the wallet, which lives on a
 * phone, is the surface where following the system would make sense.
 */
:root[data-theme="dark"] {
  color-scheme: dark;

  --brand-50:  #0e1c33;
  --brand-100: #142744;
  --brand-200: #1c3a63;
  --brand-300: #2b5490;
  --brand-400: #3d70bd;
  --brand-500: #5b8ed6;
  --brand-600: #7aa7e3;
  --brand-700: #9dbeeb;
  --brand-800: #c2d7f3;
  --brand-900: #e4eefb;

  --chrome:        #080f1d;
  --chrome-accent: #ff8a66;
  --chrome-text:   #d1d5db;
  --chrome-muted:  #6b7280;
  --chrome-line:   #1f2937;
  --chrome-hover:  #131c2e;
  --chrome-active: #17253f;

  --appbar-bg:    #050c18;
  --appbar-hover: #131c2e;
  --appbar-text:  #ffffff;
  --cue-bg:       #2b5490;
  --cue-bg-hover: #3d70bd;
  --cue-text:     #ffffff;

  /* Lifted for a dark card: the light series' mid tones vanish on #191d24. */
  --chart-1: #7aa7e3;
  --chart-2: #ff8a66;
  --chart-3: #a8c4ee;
  --chart-4: #4ade80;
  --chart-5: #fbbf24;
  --chart-6: #5b8ed6;
  --chart-grid:  #262d38;
  --chart-label: #9ca3af;

  --n-0:   #ffffff;
  --n-25:  #12161d;
  --n-50:  #171c24;
  --n-100: #1c222b;
  --n-150: #222933;
  --n-200: #2c3542;
  --n-300: #3d4756;
  /* Not the light ramp mirrored: on a dark ground "dimmer" means lighter,
     not darker. #6b7280 here measured 3.5:1 against the app background,
     and every de-emphasised label in the product resolves to this step. */
  --n-400: #949ba8;
  --n-500: #9ca3af;
  --n-600: #b8bfc9;
  --n-700: #d1d5db;
  --n-800: #eceef1;
  --n-900: #ffffff;

  /* Chip fills, and on a dark ground a tint has to LIFT off the card, not
     sink below it. Mirroring the light ramp put every one of these under
     the #191d24 card surface and the status pills lost their shape —
     they read as bare coloured text, which is exactly the hue-only
     signal the palette is meant to avoid. */
  --pos-50:  #13392c;
  --pos-200: #1d5a44;
  --pos-300: #34d399;
  --pos-600: #4ade80;
  --pos-700: #86efac;

  --neg-50:  #43191c;
  --neg-200: #6b2626;
  --neg-600: #f87171;
  --neg-700: #fca5a5;

  --warn-50:  #3d2c10;
  --warn-200: #6b4a1a;
  --warn-600: #fbbf24;
  --warn-700: #fcd34d;

  --info-50:  #14344d;
  --info-200: #1c4a6b;
  --info-600: #38bdf8;
  --info-700: #7dd3fc;

  --fin-bg:       #101b2e;
  --fin-bg-hover: #16253c;
  --fin-border:   #1c3a63;
  --fin-head:     #9dbeeb;

  --bg-app:      #0d1117;
  --bg-surface:  #191d24;
  --bg-sunken:   #12161d;
  --bg-hover:    #1f242d;
  --bg-selected: #0e1c33;

  --border:        #2c3542;
  --line:          var(--border);
  --surface:       var(--bg-surface);
  --surface-2:     var(--bg-sunken);
  --muted:         #b8bfc9;
  --border-strong: #3d4756;

  --text:        #eceef1;
  --text-muted:  #b8bfc9;
  --text-subtle: #9ca3af;
  --text-invert: #0a0f1e;

  --shadow-sm: 0 1px 2px rgba(0, 0, 0, .32);
  --shadow-md: 0 4px 18px rgba(0, 0, 0, .42);
  --shadow-lg: 0 18px 48px rgba(0, 0, 0, .56);

  --focus-ring: 0 0 0 2px #0d1117, 0 0 0 4px #7aa7e3;

  /* Dark's --n-400 is already an AA text step; no separate value needed. */
  --muted-2: var(--n-400);
}

/* Portal geometry must not change when the user changes colour mode. */
/* The staff portals carry the section tab strip under the top bar; the
   customer portal and the wallet do not, so the offset is per-portal. */
:root[data-portal="office"] {
  --modulebar-h: 52px;

  /* ── The Business Central palette, staff screens only ──────────────────
   *
   * Ported verbatim from the reference product: a Fluent teal ramp anchored
   * on #00B7C3, with the slate top bar Business Central uses rather than a
   * brand-coloured one.
   *
   * Scoped to [data-portal="office"] on purpose. These tokens are shared with
   * the CouponWallet, the POS and the public landing, which carry Redan's own
   * navy and orange — that is the customer's brand, not a theme, and adopting
   * Microsoft's palette there would rebrand the product to its own customers.
   * The skin is staff-only; so is its colour.
   */
  --brand-50:  #e6f6f7;
  --brand-100: #c5ecef;
  --brand-200: #8edce1;
  --brand-300: #54cbd2;
  --brand-400: #00b7c3;
  --brand-500: #009ba6;
  --brand-600: #008089;
  --brand-700: #00666d;
  --brand-800: #005158;
  --brand-900: #003d42;

  /* Business Central's top bar is near-black neutral, not a brand colour and
   * not a slate. The bar is painted as a gradient from --chrome to
   * --appbar-bg, so BOTH stops carry it — moving only one leaves the bar
   * reading as whatever the other still is. */
  --chrome:        #2b2b2b;
  --chrome-accent: #00b7c3;
  --appbar-bg:     #2b2b2b;
  --appbar-hover:  #3b3a39;
}

/* Equal specificity to the dark block would let the office block above win in
 * dark mode and paint the light ramp on a dark page, so this carries one more
 * attribute and restates every token the block above sets. */
:root[data-theme="dark"][data-portal="office"] {
  --brand-50:  #10282b;
  --brand-100: #143a3e;
  --brand-200: #17545a;
  --brand-300: #23747c;
  --brand-400: #008f99;
  --brand-500: #00a2ad;
  --brand-600: #00b7c3;
  --brand-700: #4ccbd4;
  --brand-800: #80dce2;
  --brand-900: #c5f3f5;

  --chrome:        #111111;
  --chrome-accent: #00b7c3;
  --appbar-bg:     #111111;
  --appbar-hover:  #292929;
  --chrome-text:   #c8c6c4;
  --chrome-muted:  #797775;
  --chrome-line:   #303638;
  --chrome-hover:  #1c2729;
  --chrome-active: #123b3f;

  /* The dark ring hardcoded the old navy; it has to follow the accent. */
  --focus-ring: 0 0 0 2px #0d1117, 0 0 0 4px #00b7c3;

  /* Text on a brand fill: the fill is bright in dark mode, so the ink is dark.
   * This is the reference's value, and the reason white-on-accent passes here
   * rather than failing the way an unchanged --text-invert would. */
  --text-invert: #07191b;
}

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

/* Honour a forced-colours environment rather than fighting it. */
@media (forced-colors: active) {
  .btn,
  .badge,
  .card {
    border: 1px solid ButtonBorder;
  }
}

/* ── Compatibility aliases ─────────────────────────────────────────────────
 * styles.css (1,395 lines, pre-dating this file) refers to its own token
 * names. Rather than rewrite all of it in one commit — which would put a
 * restyle and a rename in the same diff and make review impossible — those
 * names are defined here as aliases of the tokens above.
 *
 * Two things follow, both deliberate. The existing stylesheet keeps working
 * unchanged. And because these are aliases rather than copies, the existing
 * interface inherits dark mode for free: override --brand-600 once and every
 * legacy --accent-600 reference follows.
 *
 * This block shrinks as pages are converted, and should reach zero. It is the
 * migration's debt ledger, and it is visible on purpose.
 */
:root {
  --accent-50:   var(--brand-50);
  --accent-100:  var(--brand-100);
  --accent-200:  var(--brand-200);
  --accent-300:  var(--brand-300);
  --accent-400:  var(--brand-400);
  --accent-500:  var(--brand-500);
  --accent-600:  var(--brand-600);
  --accent-700:  var(--brand-700);
  --accent-800:  var(--brand-800);
  --accent-900:  var(--brand-900);
  --accent:       var(--brand-600);
  --accent-hover: var(--brand-700);
  --accent-soft:  var(--brand-50);
  --accent-soft-2: var(--brand-100);
  --accent-ring:  rgba(16, 64, 144, .16);

  --chrome-2: var(--appbar-bg);

  --slate-50:  var(--n-25);
  --slate-100: var(--n-50);
  --slate-150: var(--n-100);
  --slate-200: var(--n-150);
  --slate-300: var(--n-200);
  --slate-400: var(--n-400);
  --slate-500: var(--n-500);
  --slate-600: var(--n-600);
  --slate-700: var(--n-700);
  --slate-800: var(--n-800);
  --slate-900: var(--n-900);

  --page-bg:     var(--bg-app);
  --surface-3:   var(--bg-sunken);
  --hover:       var(--bg-hover);
  --line-2:      var(--n-100);
  --line-strong: var(--border-strong);

  --ink:     var(--n-900);
  --ink-2:   var(--n-800);
  /* Not var(--n-400) (#9ca3af), which is what this was: measured 2.54:1 on a
     white card, against 4.5 required. It carries the KPI sub-labels, the empty
     states and the "Open" links — small text, and the least readable on the
     page. #5f6673 is the lightest neutral that still carries body text at AA
     (5.78:1 on white, 5.25:1 on the sunken grey) and stays visibly lighter
     than --muted. --n-400 keeps its lighter value for icons and rules, where
     the text threshold does not apply. */
  --muted-2: #5f6673;
  --muted-3: var(--n-300);

  --success:      var(--pos-600);
  --success-soft: var(--pos-50);
  --success-text: var(--pos-700);
  --success-line: var(--pos-200);
  --warning:      var(--warn-600);
  --warning-soft: var(--warn-50);
  --warning-text: var(--warn-700);
  --warning-line: var(--warn-200);
  --danger:       var(--neg-600);
  --danger-soft:  var(--neg-50);
  --danger-text:  var(--neg-700);
  --danger-line:  var(--neg-200);
  --info:         var(--info-600);
  --info-soft:    var(--info-50);
  --info-text:    var(--info-700);
  --info-line:    var(--info-200);

  --credit: var(--pos-600);
  --debit:  var(--neg-600);

  --brand:      var(--brand-600);
  --brand-2:    var(--brand-700);
  --brand-3:    var(--brand-800);
  --brand-dark: var(--n-900);

  --fuel-diesel: var(--brand-600);
  --fuel-blend:  var(--warn-700);
  --fuel-accent: var(--brand-600);

  --radius-sm: var(--r-sm);
  --radius:    var(--r-sm);
  --radius-md: var(--r-md);
  --radius-lg: var(--r-lg);

  --shadow-none: 0 0 0 0 transparent;
  --shadow-xs:   var(--shadow-sm);
  --shadow-pop:  var(--shadow-lg);

  --glass-bg:        var(--bg-surface);
  --glass-bg-strong: var(--bg-surface);
  --glass-bg-soft:   var(--bg-sunken);
  --glass-border:    var(--border);
  --glass-shadow:    var(--shadow-sm);
  --glass-blur:      0;
}

