/* ============================================================================
   Obsidian design system — CSS custom properties
   Web port of apps/budget/views/obsidian/ (the authoritative design contract).

   Source of truth per token is cited inline:
     palette.py    — colours + blend()/mix()/badge_bg() colour math
     fonts.py      — the role scale (point sizes; converted here at 96 dpi,
                     1pt = 4/3 px, matching Qt/Tk on Windows)
     icons.py      — Fluent glyph tables (fonts only; codepoints live in HTML)
     primitives.py — pill / bar / light-leak / icon-tile metrics
     cards.py      — stat-card / KPI-tile metrics
     chrome.py     — title bar / sidebar / nav pill / brand lockup metrics
     modal.py      — dialog button radii

   Derived tones: Classic (tkinter) has no alpha channel, so every "translucent"
   tone is pre-blended with palette.blend(fg, bg, alpha) — linear interpolation
   of 8-bit sRGB components, which is exactly what CSS color-mix(in srgb, ...)
   computes. Each derived token below carries BOTH:
     - the precomputed hex (authoritative — byte-identical to the Python math),
     - its color-mix() recipe in a comment (for future theming, where the web
       build re-derives tones from user-customised bases like _derive_theme()).
   ========================================================================== */

:root {
  /* ── Base palette — palette.py 14-23 ─────────────────────────────────── */
  --bg-dark:     #0A0A0F;  /* BG_DARK — app background, near-black foundation */
  --bg-card:     #16161E;  /* BG_CARD — elevated card / surface containers */
  --bg-topbar:   #0C0C13;  /* BG_TOPBAR — chrome layer, darkest band */
  --accent:      #7C5CFF;  /* ACCENT — electric violet, gradient start */
  --accent-cyan: #38E1FF;  /* ACCENT_CYAN — gradient end */
  --mint:        #3DDC97;  /* ACCENT2 — income / paid / funded / positive */
  --danger:      #FF5C7A;  /* DANGER — debt / overdue / negative / delete */
  --warn:        #FFB454;  /* WARN — due soon / mid utilization */
  --text-main:   #EAEFF9;  /* TEXT_MAIN — primary text */
  --text-dim:    #8794B2;  /* TEXT_DIM — secondary text / quiet labels */

  /* ── Derived surface tones — palette.py _derive_theme() 54-66 ────────── */
  --border:  #282830;  /* BORDER  = blend(#FFF, BG_CARD, .08)
                          = color-mix(in srgb, #FFFFFF 8%, var(--bg-card)) */
  --sunken:  #0D0D12;  /* SUNKEN  = blend(#000, BG_CARD, .38)
                          = color-mix(in srgb, #000000 38%, var(--bg-card)) */
  --hover:   #202028;  /* HOVER   = blend(#FFF, BG_CARD, .045)
                          = color-mix(in srgb, #FFFFFF 4.5%, var(--bg-card)) */
  --bg-head: #212129;  /* BG_HEAD = blend(#FFF, BG_CARD, .05) — table header
                          = color-mix(in srgb, #FFFFFF 5%, var(--bg-card)) */

  /* Button hover states — palette.py 63-66 */
  --accent-hover:      #8E72FF;  /* mix(ACCENT,      #FFF, .14) */
  --accent-cyan-hover: #53E5FF;  /* mix(ACCENT_CYAN, #FFF, .14) — gradient end
                                    stop under hover, same .14-to-white mix
                                    GradientButton applies to both stops
                                    (primitives.py 167-170) */
  --mint-hover:        #58E0A5;  /* mix(ACCENT2, #FFF, .14) */
  --danger-hover:      #D14B64;  /* mix(DANGER,  #000, .18) */

  /* ── badge_bg(color) — palette.py 50-52: pill-badge backgrounds ───────
     Formula: blend(color, BG_CARD, 0.15)
            = color-mix(in srgb, <color> 15%, var(--bg-card))
     components.css uses live color-mix() for arbitrary --pill-color values;
     these precomputed hexes are the palette-accent set + fallbacks. */
  --badge-bg-accent:   #25203F;  /* badge_bg(ACCENT)      */
  --badge-bg-cyan:     #1B343F;  /* badge_bg(ACCENT_CYAN) */
  --badge-bg-mint:     #1B3330;  /* badge_bg(ACCENT2)     */
  --badge-bg-danger:   #38202B;  /* badge_bg(DANGER)      */
  --badge-bg-warn:     #382D26;  /* badge_bg(WARN)        */
  --badge-bg-lavender: #2B273F;  /* badge_bg(#A78BFA)     */
  --badge-bg-sky:      #1B2F3E;  /* badge_bg(#38BDF8)     */

  /* ── Other blended tones used by the component vocabulary ─────────────── */
  --area-fill:       #241F3D;  /* blend(ACCENT, BG_CARD, .14) — area-chart fill
                                  under the curve (charts.py 201) */
  --marker-halo:     #1E4856;  /* blend(ACCENT_CYAN, BG_CARD, .25) — glow ring
                                  around the area chart's last point
                                  (charts.py 215) */
  --icon-tile-idle:  #26262D;  /* blend(#FFF, BG_CARD, .07) — untinted icon
                                  tile fill (primitives.py 481) */
  --zebra-alt:       #1B1B23;  /* blend(#FFF, BG_CARD, .025) — odd table rows
                                  (_ledger_kit.zebra_bg; debt.md/assets.md §4.2.
                                  Deliberately NOT --hover.) */
  --nav-hover:       #16161B;  /* blend(#FFF, BG_DARK, .05) — sidebar nav hover
                                  pill (chrome.py NavItem 183) */
  --nav-danger-idle: #C1475F;  /* blend(DANGER, BG_DARK, .75) — Admin nav item
                                  idle text (chrome.py 186) */
  --menu-border:     #2C2C30;  /* blend(#FFF, BG_DARK, .14) — AccountMenu /
                                  popover outline (chrome.py 639) */
  --separator:       #26262D;  /* blend(#FFF, BG_CARD, .07) — menu separators
                                  (chrome.py 715) */

  /* ── Signature gradient — palette.py 46-48 grad_color() ────────────────
     Horizontal violet -> cyan; grad_color(t) = mix(ACCENT, ACCENT_CYAN, t).
     Linear sRGB-component interpolation == CSS default gradient math, so a
     plain two-stop linear-gradient reproduces every intermediate exactly
     (verified midpoints: t=.25 #6B7DFF, t=.5 #5A9EFF, t=.75 #49BFFF). */
  --gradient-brand: linear-gradient(90deg, var(--accent), var(--accent-cyan));
  --gradient-brand-hover: linear-gradient(90deg, var(--accent-hover), var(--accent-cyan-hover));

  /* ── Light leak — primitives.py LightLeak 420-447 ──────────────────────
     2px-tall strip; colour grad_color(t) across the width; alpha ramps
     0 -> 0.55 -> 0 linearly, peaking at centre: a(t) = (1-|2t-1|) * 0.55.
     CSS: paint the brand gradient, then mask with a linear alpha ramp —
     mask-image: linear-gradient(90deg, transparent, rgb(0 0 0 / .55) 50%, transparent).
     (No single-property fallback exists; without mask support, fall back to
     showing the gradient at 55% opacity via the same variables.) */
  --light-leak-height: 2px;
  --light-leak-peak-alpha: 0.55;

  /* ── Typography — fonts.py _ROLE_SPECS 31-44 (pt -> px at 96 dpi) ──────
     Classic prefers Geist when installed, else Segoe UI; "semibold" is a
     family swap (Segoe UI Semibold), which maps to weight 600 on the web. */
  --font-sans: "Geist", "Segoe UI Variable Text", "Segoe UI", system-ui,
               -apple-system, sans-serif;
  --font-mono: "Consolas", ui-monospace, monospace;   /* fonts.py 28 */
  --font-icons: "Segoe Fluent Icons", "Segoe MDL2 Assets", "Segoe UI Emoji";
               /* fonts.py 74-77 resolution order; emoji = Classic's fallback */
  --weight-regular: 400;
  --weight-semibold: 600;    /* Segoe UI Semibold / Geist SemiBold */

  --font-title:  28px;     /* title  21pt semibold — page headings */
  --font-hero:   36px;     /* hero   27pt semibold — the hero figure */
  --font-head:   17.33px;  /* head   13pt semibold — card headings */
  --font-sub:    14.67px;  /* sub    11pt semibold — buttons, row titles */
  --font-body:   13.33px;  /* body   10pt regular */
  --font-small:  12px;     /* small   9pt regular */
  --font-tiny:   10.67px;  /* tiny    8pt regular */
  --font-nav:    13.33px;  /* nav    10pt semibold — sidebar labels */
  --font-label:  10.67px;  /* label   8pt semibold — caps labels, badges */
  --font-num:    18.67px;  /* num    14pt semibold — row figures */
  --font-num-lg: 22.67px;  /* num_lg 17pt semibold — stat-card figures */

  /* Literal (non-role) font sizes Classic hardcodes at specific call sites */
  --font-kpi-whole:   28px;     /* (FONT_FAMILY_SEMI, 21) — cards.py 215 */
  --font-kpi-frac:    13.33px;  /* (FONT_FAMILY_SEMI, 10) — cards.py 220 */
  --font-bar-value:   12px;     /* (FONT_FAMILY_SEMI,  9) — charts.py 240 */
  --font-brand-title: 16px;     /* (semibold, 12) — chrome.py 218 */
  --font-brand-sub:   9.33px;   /* (semibold,  7) — chrome.py 219 */

  /* ── Radii ──────────────────────────────────────────────────────────────
     Cards are SQUARE in Classic (_BorderCard is a plain Frame reveal —
     cards.py 70-97): no radius token for cards, on purpose. */
  --radius-pill: 999px;  /* h/2 full pill — primitives.py _gradient_pill 74 */
  --radius-chip: 5px;    /* category chip — cards.py 395 */
  --radius-tile: 8px;    /* icon tile default — primitives.py 461 */
  --radius-nav:  17px;   /* nav pill: (38px row − 2·2px inset)/2 — chrome.py 171-179 */
  --radius-menu: 14px;   /* AccountMenu card — chrome.py 505; modal card matches */
  --radius-btn-modal: 10px;      /* modal footer buttons — modal.py 301-305 */
  --radius-btn-modal-lg: 12px;   /* modal primary CTA — modal.py 329, 358 */

  /* ── Component metrics ────────────────────────────────────────────────── */
  --sidebar-w: 230px;        /* SIDEBAR_W — palette.py 24 */
  --titlebar-h: 44px;        /* _TitleBar.HEIGHT — chrome.py 400 */
  --nav-item-h: 38px;        /* NavItem.HEIGHT — chrome.py 135 */
  --btn-h: 32px;             /* GradientButton default — primitives.py 91 */
  --btn-padx: 18px;          /* GradientButton padx — primitives.py 91 */
  --pill-badge-h: 20px;      /* PillBadge/DotPill — primitives.py 222, 246 */
  --pill-badge-padx: 9px;    /* primitives.py 223, 247 */
  --chip-h: 18px;            /* category chip — cards.py 384 */
  --bar-h: 8px;              /* RoundedBar default — primitives.py 276 */
  --flat-bar-h: 12px;        /* FlatBar default — primitives.py 334 */
  --stat-strip-h: 3px;       /* stat_card accent strip — cards.py 144 */
  --card-pad-x: 13px;        /* stat/KPI interior padx — cards.py 149, 181 */
  --hairline: 1px;           /* Hairline / BORDER reveal — chrome.py 97-112 */
  --donut-size: 165px;       /* Dashboard donut SIZE — charts.py 9, 79 */
  --donut-thickness: 13px;   /* ring width at SIZE 165 — charts.py 89 */
  --icon-tile-size: 30px;    /* IconTile default — primitives.py 461 */
  --dot-size: 8px;           /* legend dot — cards.py _Dot 112-125 */
}
