/* ==========================================================================
   FLEXO DESIGN TOKENS — light and dark, one contract
   GENERATED FROM "Flexo Tokens.md". Do not hand-edit; edit the spec and
   regenerate, or the two disagree and the spec wins.

   Version:  see handoff/VERSION
   Install:  load once at the root of the app, before any component CSS.
   Theme:    set data-theme="dark" on <html>. Nothing else switches.

   Rule: every colour, rule and ink in product code is var(--role).
   A hex literal in a component is a bug — it cannot follow the theme.
   The four documented exceptions are listed at the bottom of this file.
   ========================================================================== */

:root {
  /* ---- Neutral ramp — the only greys that exist ------------------------ */
  --n-000:  #ffffff;
  --n-025:  #fafafa;
  --n-050:  #f5f5f5;
  --n-100:  #ebebeb;
  --n-200:  #dcdcdc;
  --n-300:  #c4c4c4;
  --n-400:  #9e9e9e;
  --n-500:  #757575;
  --n-600:  #545454;
  --n-700:  #383838;
  --n-800:  #232323;
  --n-900:  #141414;
  --n-1000: #000000;   /* thirteen steps, named as §5 names them (fixed in 1.5.0:
                          300–800 had been shifted one step and 300/1000 were missing) */

  /* ---- Surfaces -------------------------------------------------------- */
  --desk:   #232323;   /* the surround the app frame sits on */
  --app:    #ffffff;   /* the frame's own base */
  --field:  #fafafa;   /* the working area behind cards, and a header bar's ground */
  --cell:   #f5f5f5;   /* a header's 44px icon cell — one ramp step past --field */
  --card:   #ffffff;   /* card, popover, dialog surface */

  /* ---- Lines — three weights, never invent a fourth ------------------- */
  --hairline: #f5f5f5; /* divisions inside a component */
  --rule:     #ebebeb; /* card borders, header and footer rules */
  --border:   #dcdcdc; /* inputs and containers — anything that reads as an edge */
  --track:    #f5f5f5; /* a bar's empty track, a disabled fill */

  /* ---- Ink ------------------------------------------------------------- */
  --ink:       #141414; /* primary text, filled tiles, primary buttons */
  --on-ink:    #ffffff; /* anything sitting on --ink */
  --ink-ghost: #c4c4c4; /* secondary chart series, a staged row's status */

  /* Dimmed text is opacity on inherited colour, never a grey token:
     0.7 secondary · 0.62 mono detail · 0.45 labels · 0.3 ghost.
     One value serves both themes, and it lets --tint invert a whole row. */

  /* ---- Identity tile — a monogram square, never a button -------------- */
  --tile:           #141414;
  --tile-ink:       #ffffff;
  --tile-knockout:  #ffffff; /* the surface a knocked-out glyph shows through
                                to; a tinted row must reset it */

  /* ---- Brand and status ----------------------------------------------- */
  --brand:   #1b3aff; /* the corporate blue: the field's signal line. NEVER
                         changes with the theme. */
  --signal:  #1b3aff; /* the interface accent: links, focus, action verbs,
                         the code countdown, an available balance */
  --credit:  #009e4c;
  --debit:   #e62200;
  --pending: #f59e0b;  /* the amber. Called "amber" in conversation; the ROLE is
                          --pending because it names the pending outcome. */
  --info:    #757575;

  /* ---- Status cell pairs — wash + full-contrast ink ------------------- */
  /* --*-ink are ALIASES of --credit/--pending/--debit/--info and hold the same value in
     both themes (v1.8: one status, one colour). Prefer the plain token; the aliases exist
     so older markup keeps resolving, and must never be given a different value. */
  --credit-wash:  rgba(0,158,76,0.1);
  --credit-ink:   #009e4c;
  --pending-wash: rgba(245,158,11,0.14);
  --pending-ink:  #f59e0b;  /* not the amber itself: #f59e0b on its own pale wash
                               lands near 2:1. #f59e0b is ~5:1. */
  --debit-wash:   rgba(230,34,0,0.1);
  --debit-ink:    #e62200;
  --info-wash:    rgba(117,117,117,0.12);
  --info-ink:     #757575;

  /* ---- Interaction feedback — one tint, never grey, never a shadow ---- */
  --tint:       #eef1ff;
  --tint-press: #e4e9ff;
  --tint-ink:   #141414;

  /* ---- Drawer surface ramp -------------------------------------------- */
  /* A drawer floats over the 56% curtain, so in dark mode it steps one rung
     lighter than a card. Declare these four ON THE DRAWER ROOT as --card /
     --rule / --hairline / --border — plus --field / --cell from the two
     -field/-cell entries — so the whole subtree steps with it. */
  --drawer:          #ffffff;
  --drawer-rule:     #ebebeb;
  --drawer-hairline: #f5f5f5;
  --drawer-border:   #dcdcdc;
  --drawer-field:    #fafafa;   /* the drawer header bar */
  --drawer-cell:     #f5f5f5;   /* its icon cell */

  /* ---- Elevation — Flexo is flat and ruled; used almost nowhere ------- */
  --shadow-1: 0 1px 2px rgba(0,0,0,0.06);
  --shadow-2: 0 8px 24px rgba(0,0,0,0.18);
  --shadow-drawer: 0 8px 24px rgba(0,0,0,0.28);

  /* ---- Motion ---------------------------------------------------------- */
  --ease:        cubic-bezier(0.2,0,0,1);      /* anything the user caused */
  --ease-drawer: cubic-bezier(0.2,0.9,0.24,1); /* a surface entering */
  --t-feedback: 420ms;  /* hover in AND out, rail, drawer, collapse */
  --t-enter:    320ms;  /* toast, dialog, QR to check */
  --t-touch:    120ms;  /* press-in on touch */

  /* ---- Radius ---------------------------------------------------------- */
  --radius:       0;   /* Flexo has square corners */
  --radius-input: 1px; /* the only rounding in the system: token fields */
  --radius-toast: 2px;

  /* ---- Type ------------------------------------------------------------ */
  --font-display: 'Space Grotesk', sans-serif; /* display + all numerals */
  --font-body:    'IBM Plex Sans', system-ui, sans-serif;
  --font-mono:    'JetBrains Mono', monospace; /* labels and machine text */

  /* The scale is CLOSED (§1c). A size that is not here is a bug, not a choice.
     A numeral never sets in the body face; body copy never sets in the display face. */
  --t-display-xl: 96px;  /* site hero figure */
  --t-display-l:  54px;  /* page headline */
  --t-display-m:  34px;  /* typed amount, in-page section head */
  --t-figure-xl:      88px;  /* the one display figure on a product or console screen */
  --t-figure-display: 64px;  /* a display figure beside an alert band */
  --t-figure-inline:  32px;  /* a figure inside a panel or a row of vitals */
  --t-title-l:    22px;  /* announcement headline */
  --t-title-m:    16px;  /* card title, drawer subject */
  --t-body:       14px;  /* default UI text */
  --t-body-s:     13px;  /* THE record size: rows, values, status labels */
  --t-body-xs:    12px;  /* a row's second line, supporting copy */
  --t-mono-value: 13px;  /* amount, CLABE, date, tracking key */
  --t-mono-meta:  11px;  /* mono detail line, chart ticks */
  --t-mono-label: 10px;  /* card eyebrow, overlay header, column head, chip */
  --t-mono-micro:  9px;  /* inside a drawer: labels, column heads, footer. FLOOR. */

  /* Weights: three, and there is no 600. 'Bold' in product means 500. */
  --w-regular: 400;
  --w-medium:  500;
  --w-bold:    700;  /* marketing headlines only */

  /* THE HEIGHT LAW (§1c): a single line of UI text has line-height 1; only prose
     gets 1.45–1.65. Then row height = 2 × padding + font-size, which is why the
     three paddings below produce exactly three row heights: 33 / 35 / 41.
     An unpinned line-height is font- and platform-dependent — it is the reason
     'the same' row comes out at different heights on different screens. */
  --pad-row-tight: 11px;  /* a run's child row                           → 35px (25 retired, v1.9a) */
  --pad-row:      10px;   /* a drawer's fact and list rows              → 33px */
  --pad-row-card: 14px;   /* a card table's body rows                   → 41px */
  --lh-ui:    1;          /* every single-line UI string */
  --lh-prose: 1.55;       /* paragraphs only */
}

[data-theme="dark"] {
  --desk:   #ffffff;  /* THE DESK INVERTS — never a dark app on a dark desk */
  --app:    #000000;
  --field:  #000000;  /* the working area IS the app ground on dark */
  --cell:   #141414;  /* the bar is at the ramp floor, so the cell steps toward the card */
  --card:   #232323;

  --hairline: #383838;
  --rule:     #383838;
  --border:   #545454;
  --track:    #383838;

  --ink:    #fafafa;
  --on-ink: #141414;

  --tile:          #757575; /* neutral-500, not 700: 700 is invisible on a
                               drawer and one rung off a card */
  --tile-ink:      #fafafa;
  --tile-knockout: #232323;

  --brand:   #1b3aff; /* unchanged, deliberately */
  --signal:  #a8b6ff; /* lifted from #8092FF: accent text on dark is 10px mono */
  --credit:  #00c257;
  --debit:   #ff6a4d;
  --pending: #f59e0b;
  --info:    #757575;

  --credit-wash:  rgba(0,194,87,0.16);
  --credit-ink:   #00c257;
  --pending-wash: rgba(245,158,11,0.18);
  --pending-ink:  #f59e0b;  /* on dark the amber IS readable on its own wash */
  --debit-wash:   rgba(255,106,77,0.16);
  --debit-ink:    #ff6a4d;
  --info-wash:    rgba(117,117,117,0.12);
  --info-ink:     #757575;

  --tint:       #eef1ff; /* one value in both themes; ink inverts to 900 */
  --tint-press: #e4e9ff;
  --tint-ink:   #141414;

  --drawer:          #383838;
  --drawer-rule:     #545454;
  --drawer-hairline: #545454;
  --drawer-border:   #757575;
  --drawer-field:    #545454;   /* the drawer header bar — the band ground */
  --drawer-cell:     #757575;   /* its icon cell, one step further from the drawer */

  --shadow-1: 0 1px 2px rgba(0,0,0,0.5);
  --shadow-2: 0 8px 24px rgba(0,0,0,0.6);
  --shadow-drawer: 0 8px 24px rgba(0,0,0,0.7);
}

/* ==========================================================================
   The four places a literal is allowed, because they sit over the always-black
   company field and must not follow a surface role:
     1. the field's own ground        #000000
     2. the glass panel over it       rgba(0,0,0,0.25) + blur(2px),
                                      border rgba(255,255,255,0.14)
     3. the drawer/dialog curtain     rgba(0,0,0,0.56)
     4. the notification toast        #141414 surface, white ink, BOTH themes
   Nothing else.
   ========================================================================== */

html, body {
  margin: 0;
  min-height: 100%;
  background: var(--desk);
  color: var(--ink);
  font-family: var(--font-body);
  -webkit-font-smoothing: antialiased;
}

*, *::before, *::after { box-sizing: border-box; }

a       { color: var(--signal); text-decoration: none; }
a:hover { color: var(--ink); }

button  { font-family: inherit; color: var(--ink); }
/* A <button> does not inherit ink: the UA sets color: buttontext, so a glyph
   drawn with stroke="currentColor" renders near-black on a dark surface and
   disappears. Every button sets color explicitly. */

.tnum, [data-figure] { font-variant-numeric: tabular-nums; }

/* Focus is a border colour change, never a ring. A control that owns its own
   border state (the amount input over balance) opts out with data-own-focus. */
:where(input, textarea, select):focus { outline: none; }
div:has(> input:focus):not([data-own-focus]) { border-color: var(--brand) !important; }

::selection { background: var(--tint); color: var(--tint-ink); }

/* The skeleton breathes — one phase per group, so put the animation on the
   CONTAINER, never the block. It breathes; it does not sweep. */
/* The status block — ONE geometry everywhere (§9 v1.5–v1.9). 5px 8px + a 9px pinned
   line + a 1px border = 21px, shorter than every row (33 / 35 / 41), so a status never
   changes a row. One status is one colour: wash, square, border and label. The canonical
   class is .flx-status in flexo-components.css; this attribute form is the same block. */
[data-status] {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 5px 8px; line-height: 1;
  border: 1px solid currentColor; border-radius: 0;
}
[data-status] > i { width: 6px; height: 6px; flex-shrink: 0; background: currentColor; }
[data-status] > span { font-family: var(--font-mono); font-size: var(--t-mono-micro); font-weight: 500;
  letter-spacing: 0.14em; text-transform: uppercase; line-height: var(--lh-ui); white-space: nowrap; }
[data-status="credit"]  { background: var(--credit-wash);  color: var(--credit) }
[data-status="pending"] { background: var(--pending-wash); color: var(--pending) }
[data-status="debit"]   { background: var(--debit-wash);   color: var(--debit) }
[data-status="info"]    { background: var(--info-wash);    color: var(--info) }

@keyframes flexo-breathe { 0%,100% { opacity: 1 } 50% { opacity: 0.45 } }
[data-skeleton] { animation: flexo-breathe 1400ms cubic-bezier(0.4,0,0.6,1) infinite; }
[data-skeleton] > * { background: var(--rule); border-radius: 0; }
