/* AYFI design tokens, direction "Blanco" v5 (approved by Nikita 16.09.2026).
   Single source of truth for apps/app, apps/admin and @ayfi/ui; docs/design/ayfi-app-v5-blanco.html
   links this file directly so the concept and the code cannot drift apart.

   The direction. Round 3 put five genuinely different designs side by side
   (docs/design/2026-09-15-design-directions.md, stand ayfi-app-v5-directions.html). Nikita chose
   Blanco, the Wise/N26 school: clarity by subtraction. White ground, near-black text, no cards at
   all: 1px dividers and air are the only structure. The amount carries the row at 28/800, totals
   at 38/800, the status sits above the amount at 12/700. One round action (the scan FAB) per
   screen. Nothing else competes.

   What this replaces. v4.2 was a grouped-list design (grey ground #EFEFF4, white cards, scale
   14->34, status right under the amount). Its A-D variants were deltas of that one chassis, which
   is why they "почти не отличались". Blanco changes the chassis: ground, cards, scale, row
   grammar and typeface all differ.

   Font. Manrope, one family, 400-800. Familjen Grotesk is gone for a measured reason, not taste:
   Google Fonts serves it as latin / latin-ext / vietnamese only, so the Russian UI was silently
   falling back to system-ui (found in round 3, verified over HTTP). Manrope ships cyrillic and
   cyrillic-ext. No serif anywhere (focus group 15.09: the one serif sentence read as a pasted
   disclaimer).

   Dark theme. OLED black, neutral. This also settles the question left open on 15.09 (respondents
   5:0 for a neutral dark "like Telegram", three juries for a warm one): Blanco's dark is neutral
   by construction, so the warm-charcoal tokens are gone. Warmth now lives only in the landing.

   Every text/background pair was measured, not assumed (scratch: blanco.py, WCAG 2.x):
   light  ink/white 19.7, ink/surface-2 17.6, ink-2/white 6.6, ink-2/surface-2 5.9,
          line-ui/white 4.3, emerald/white 6.1, white/emerald 6.1, emerald-ink/white 8.6,
          terracotta-ink/white 7.6, terracotta-glyph/white 4.5, gold-text/white 6.3,
          gold-glyph/white 4.3, gold-outline/white 3.4;
   dark   text/bg 17.4, text/surface-2 15.4, text-2/bg 7.8, text-2/surface-2 6.9, line-ui/bg 4.0,
          emerald-d/bg 7.9, bg/emerald-d 7.9, terracotta-d/bg 8.7, gold-d/bg 10.4.
   Gold on white is 2.6, so gold is still never plain text: the gold that speaks is #805800. */

:root {
  color-scheme: light dark;

  /* ---- Primitives. Hex first as the fallback, OKLCH wins where supported. ---- */
  --c-white: #ffffff;
  --c-surface-2: #f2f2f2; /* pressed row, sheet ground, evidence frame */
  --c-surface-2: oklch(96% 0 0);
  --c-hairline: #d7d7d7; /* the 1px divider: 1.44 on white, decorative, never carries meaning */
  --c-hairline: oklch(88% 0 0);
  --c-line-ui: #7a7a7a; /* input borders and control outlines: 4.3 on white */
  --c-line-ui: oklch(58% 0 0);
  --c-ink: #0b0b0b; /* 19.7 on white: the near-black of the Swiss school, not pure #000 */
  --c-ink: oklch(15% 0 0);
  --c-ink-2: #5d5d5d; /* 6.6 on white; also placeholders, not the usual pale grey */
  --c-ink-2: oklch(48% 0 0);
  --c-emerald: #0f6f5a;
  --c-emerald: oklch(48.5% 0.089 173);
  --c-emerald-ink: #005740; /* pressed state and emerald text on a wash: 8.6 on white */
  --c-emerald-ink: oklch(40% 0.09 170);
  --c-emerald-wash: #eaf6f1;
  --c-emerald-wash: oklch(96% 0.02 170);
  --c-gold: #c9993a; /* fills and nothing else: 2.6 on white */
  --c-gold: oklch(71.1% 0.124 81);
  --c-gold-text: #805800; /* the only gold that is allowed to be a word: 6.3 on white */
  --c-gold-text: oklch(49% 0.102 78);
  --c-gold-glyph: #9f7100; /* 4.3 on white: glyphs and 12px+ marks */
  --c-gold-glyph: oklch(58% 0.12 80);
  --c-gold-outline: #b2831c; /* 3.4 on white: the only gold that passes as a UI border */
  --c-gold-outline: oklch(64% 0.124 81);
  --c-gold-wash: #fdefd2;
  --c-gold-wash: oklch(95.6% 0.041 85);
  --c-terracotta: #b85c38; /* glyph only: 4.5 on white */
  --c-terracotta: oklch(57.9% 0.129 41);
  --c-terracotta-ink: #923719; /* the word "No deducible": 7.6 on white */
  --c-terracotta-ink: oklch(46% 0.13 38);

  /* Dark ground: neutral OLED black. Depth comes from surface lightness, never from shadow. */
  --c-bg-d: #0d0d0d;
  --c-bg-d: oklch(16% 0 0);
  --c-surface-2-d: #1b1b1b;
  --c-surface-2-d: oklch(22% 0 0);
  --c-hairline-d: #2e2e2e;
  --c-hairline-d: oklch(30% 0 0);
  --c-line-ui-d: #717171;
  --c-line-ui-d: oklch(55% 0 0);
  --c-text-d: #f2f2f2;
  --c-text-d: oklch(96% 0 0);
  --c-text-2-d: #a4a4a4;
  --c-text-2-d: oklch(72% 0 0);
  --c-emerald-d: #4fb79a;
  --c-emerald-d: oklch(71% 0.106 172);
  --c-emerald-wash-d: #0e2a22;
  --c-emerald-wash-d: oklch(27% 0.04 170);
  --c-gold-d: #e0b860;
  --c-gold-d: oklch(80% 0.116 85);
  --c-gold-wash-d: #342707;
  --c-gold-wash-d: oklch(28% 0.05 86);
  --c-terracotta-d: #f29676;
  --c-terracotta-d: oklch(76% 0.12 40);

  /* ---- Semantic: light. Ground and rows are the same white; only dividers separate them.
     There is no card surface in this design: --surface exists so that a sheet, an input or a
     pressed row can step away from the ground, not so that content can sit in a box. ---- */
  --bg: var(--c-white);
  --surface: var(--c-white);
  --surface-2: var(--c-surface-2);
  --line: var(--c-hairline);
  --line-input: var(--c-line-ui);
  --text: var(--c-ink);
  --text-2: var(--c-ink-2);
  --primary: var(--c-emerald);
  --primary-pressed: var(--c-emerald-ink);
  --on-primary: var(--c-white);
  --primary-wash: var(--c-emerald-wash);
  --attention-wash: var(--c-gold-wash);
  --attention-glyph: var(--c-gold-glyph);
  --negative-text: var(--c-terracotta-ink);
  --negative-glyph: var(--c-terracotta);
  --focus: var(--c-emerald);
  --scrim: rgb(0 0 0 / 0.4);
  --shadow-sheet: 0 -8px 32px rgb(0 0 0 / 0.12);
  --shadow-fab: 0 6px 20px rgb(0 0 0 / 0.18); /* the one raised object on the screen */
  /* "Selected" (filter tab, segmented indicator): ink on light, the ground inverted. */
  --selected-bg: var(--c-ink);
  --selected-text: var(--c-white);
  --wordmark: var(--c-ink);

  /* Six deduction statuses, set above the amount at 12/700. Colour is never the only carrier:
     StatusChip adds a glyph and the row composition differs per status. */
  --status-deductible: var(--primary);
  --status-partial: var(--primary);
  --status-not: var(--negative-text);
  --status-fact: var(--c-gold-text); /* a question is not "positive": gold, never emerald */
  --status-fact-bg: transparent; /* Blanco has no row fills; the word and glyph carry it */
  --status-fact-outline: var(--c-gold-outline);
  --status-review: var(--text-2);
  --status-special: var(--text);

  /* ---- Typography. One family, four weights, a scale that jumps instead of stepping:
     the amount is meant to be three sizes away from its own caption. ---- */
  --font-sans:
    'Manrope Variable', 'Manrope', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --text-xs: 0.75rem; /* 12: status above the amount, legal, norm references */
  --text-sm: 0.875rem; /* 14: captions, second line of a row */
  --text-md: 1rem; /* 16: body, row title */
  --text-lg: 1.25rem; /* 20: screen title */
  --text-xl: 1.75rem; /* 28: amount of one document, amount in a feed row */
  --text-2xl: 2.375rem; /* 38: quarter result, the deducible hero */
  --leading-tight: 1.05; /* display numbers */
  --leading-heading: 1.2;
  --leading-body: 1.5;
  --tracking-display: -0.03em;
  --tracking-body: 0;
  --weight-regular: 400;
  --weight-medium: 500;
  --weight-semibold: 600;
  --weight-bold: 700;
  --weight-extrabold: 800; /* display amounts and screen titles */

  /* ---- Space (4pt). Blanco pays for the missing cards with margin: 24px side padding. ---- */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-7: 32px;
  --space-8: 40px;
  --gutter: 24px; /* screen side padding: the Swiss margin, not the iOS 16 */
  --tap: 44px; /* minimum hit area, one hand, at the till */
  --row-min: 64px; /* two-line list row; 80 with an action line */

  /* ---- Icons: one stroke language. 24px tab icons, 16px status glyphs, 26px in the FAB. ---- */
  --stroke-icon: 1.75;

  /* ---- Shape lock: interactive is a pill, structural is square. Rows, sections and inputs
     have no radius at all, because nothing in this design is a card. ---- */
  --radius-row: 0;
  --radius-input: 0;
  --radius-control: 999px;
  --radius-pill: 999px;
  --radius-sheet: 16px; /* the one exception: a sheet is a moving object, not a box */

  /* ---- Motion (emil pass): transform/opacity only, product register ---- */
  --dur-press: 120ms; /* button :active */
  --dur-fast: 160ms; /* crossfades, status swap */
  --dur-base: 200ms; /* reveals, segmented indicator, backdrop */
  --dur-sheet: 250ms; /* bottom sheet enter; exit uses --dur-base */
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
  --ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);

  /* ---- Layers ---- */
  --z-sticky: 10;
  --z-fab: 15;
  --z-scrim: 20;
  --z-sheet: 30;
  --z-toast: 40;

  /* ---- Telegram / device safe areas. Telegram exposes its own insets as CSS variables
     (7.10+); outside Telegram the env() values apply; a plain browser gets 0. ---- */
  --safe-top: calc(
    var(--tg-safe-area-inset-top, env(safe-area-inset-top, 0px)) +
      var(--tg-content-safe-area-inset-top, 0px)
  );
  --safe-bottom: var(--tg-safe-area-inset-bottom, env(safe-area-inset-bottom, 0px));
}

/* ---- Telegram theme parity. Blanco's ground is white, which is exactly Telegram iOS light
   (bg_color #FFFFFF), so in the light scheme there is nothing to reconcile: the app sets
   data-tg-ground="on" at boot when Telegram.WebApp.colorScheme is "light" and themeParams.bg_color
   is near-white (OKLCH L > 0.9), and only borrows the separator. A custom pale-blue or grey theme
   keeps our own neutrals so the measured contrast survives. Header and bottom bar follow
   themeParams in every case (setHeaderColor / setBottomBarColor, updated on themeChanged).
   The dark scheme always uses our OLED theme below: Telegram's three dark themes are all lighter,
   and matching them would cost the 17.4 text contrast this design is built on. ---- */
:root[data-tg-ground='on'] {
  --line: var(--tg-theme-section-separator-color, var(--c-hairline));
}

/* ---- Semantic: dark. Neutral OLED, not an inversion of warmth: the ground goes black, the
   dividers stay one step above it, and the accents are the lighter emerald/gold measured for
   black. Body text gets a touch of tracking because light-on-dark reads thinner. ---- */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) {
    --bg: var(--c-bg-d);
    --surface: var(--c-bg-d);
    --surface-2: var(--c-surface-2-d);
    --line: var(--c-hairline-d);
    --line-input: var(--c-line-ui-d);
    --text: var(--c-text-d);
    --text-2: var(--c-text-2-d);
    --primary: var(--c-emerald-d);
    --primary-pressed: var(--c-emerald);
    --on-primary: var(--c-bg-d);
    --primary-wash: var(--c-emerald-wash-d);
    --attention-wash: var(--c-gold-wash-d);
    --attention-glyph: var(--c-gold-d);
    --negative-text: var(--c-terracotta-d);
    --negative-glyph: var(--c-terracotta-d);
    --focus: var(--c-emerald-d);
    --scrim: rgb(0 0 0 / 0.6);
    --shadow-sheet: none;
    --shadow-fab: none;
    --tracking-body: 0.01em;
    --selected-bg: var(--c-text-d);
    --selected-text: var(--c-bg-d);
    --wordmark: var(--c-text-d);
    --status-fact: var(--c-gold-d);
    --status-fact-outline: var(--c-gold-d);
  }
}
:root[data-theme='light'] {
  color-scheme: light;
}
:root[data-theme='dark'] {
  color-scheme: dark;
  --bg: var(--c-bg-d);
  --surface: var(--c-bg-d);
  --surface-2: var(--c-surface-2-d);
  --line: var(--c-hairline-d);
  --line-input: var(--c-line-ui-d);
  --text: var(--c-text-d);
  --text-2: var(--c-text-2-d);
  --primary: var(--c-emerald-d);
  --primary-pressed: var(--c-emerald);
  --on-primary: var(--c-bg-d);
  --primary-wash: var(--c-emerald-wash-d);
  --attention-wash: var(--c-gold-wash-d);
  --attention-glyph: var(--c-gold-d);
  --negative-text: var(--c-terracotta-d);
  --negative-glyph: var(--c-terracotta-d);
  --focus: var(--c-emerald-d);
  --scrim: rgb(0 0 0 / 0.6);
  --shadow-sheet: none;
  --shadow-fab: none;
  --tracking-body: 0.01em;
  --selected-bg: var(--c-text-d);
  --selected-text: var(--c-bg-d);
  --wordmark: var(--c-text-d);
  --status-fact: var(--c-gold-d);
  --status-fact-outline: var(--c-gold-d);
}

/* ---- Base ---- */
body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: var(--text-md);
  line-height: var(--leading-body);
  letter-spacing: var(--tracking-body);
  font-kerning: normal;
  font-optical-sizing: auto;
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation; /* no 300ms tap delay in WebViews */
  overscroll-behavior: none; /* scroll chaining would hand the gesture to Telegram's swipe-to-close */
}

/* Pressables: press feedback is instant, release fades (iOS table rhythm). */
button,
[role='button'],
a {
  touch-action: manipulation;
}

/* Money is the main content; it has to line up. Applied by class so that prose keeps
   proportional figures. */
.num,
[data-amount] {
  font-variant-numeric: tabular-nums lining-nums;
}

/* Evidence (receipt photos, vendor logos) always sits on white, whatever the ground. On a white
   ground it needs an edge, which is the one place a 1px line means "this is a document". */
.evidence {
  background: var(--c-white);
  border: 1px solid var(--line);
  border-radius: var(--radius-input);
}

:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-press: 0ms;
    --dur-fast: 120ms; /* crossfades stay: they aid comprehension */
    --dur-base: 120ms;
    --dur-sheet: 120ms;
  }
}
