/* ─────────────────────────────────────────────────────────────
   Cotrugli — Colors & Type (design tokens)
   One brand. Two themes. Components reference tokens, never raw hex.
   Dark is default. Light is the inverted alternative.

   THE one token sheet: every surface (the gate at /, auth, marketing,
   the console) loads this file through the ds_root layout. There is no
   second copy anywhere; if a value changes, it changes here.
   @font-face paths point at /fonts/ (served from priv/static/fonts by
   the Phoenix endpoint).
   ───────────────────────────────────────────────────────────── */

/* ─── Brand fonts — variable, self-hosted ─── */
@font-face {
  font-family: "Inter Tight";
  src: url("/fonts/InterTight-VariableFont_wght-3cdfc5dab0621f61ef1f9ace2ac1a3a9.ttf?vsn=d") format("truetype-variations");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Inter Tight";
  src: url("/fonts/InterTight-Italic-VariableFont_wght-b943a16806dfc4772ed712a38b79a4a6.ttf?vsn=d") format("truetype-variations");
  font-weight: 100 900;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: "JetBrains Mono";
  src: url("/fonts/JetBrainsMono-VariableFont_wght-514bb1da4b5d654b134572435ffcfea7.ttf?vsn=d") format("truetype-variations");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "JetBrains Mono";
  src: url("/fonts/JetBrainsMono-Italic-VariableFont_wght-85cc70f51b722cc2618ab156b5bd5e5d.ttf?vsn=d") format("truetype-variations");
  font-weight: 100 900;
  font-style: italic;
  font-display: swap;
}

/* .light .mkt-invert: the marketing inversion band. A .mkt-invert subtree
   carries the OPPOSITE theme's tokens; custom properties set directly on
   the band element beat the ones inherited from <html>, so the flip is
   total. Selector lists only — the values are the one palette, unchanged. */
:root,
.light .mkt-invert {
  /* ── Type families ── */
  --font-sans: "Inter Tight", "Inter", -apple-system, BlinkMacSystemFont, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  /* ── Type roles (font shorthand: weight size/line-height family) ── */
  --t-display:    500 48px/1.05 var(--font-sans);  /* tracking -0.03em  */
  --t-h1:         500 32px/1.10 var(--font-sans);  /* tracking -0.025em */
  --t-h2:         500 22px/1.20 var(--font-sans);  /* tracking -0.02em  */
  --t-h3:         500 18px/1.30 var(--font-sans);  /* tracking -0.015em */
  --t-body:       400 15px/1.55 var(--font-sans);
  --t-body-sm:    400 13px/1.50 var(--font-sans);
  --t-mono-data:  500 13px/1.50 var(--font-mono);
  --t-mono-label: 500 10px/1.40 var(--font-mono);  /* 0.12em UPPER     */
  --t-micro:      400 11px/1.40 var(--font-sans);
  /* The touch body role. DESIGN.md has documented body-touch since the scale
     was written; it never had a token. 16px is not a taste here, it is the
     floor under which iOS scales the page on focus - and this shell cannot
     pan back - so every field takes it on a coarse pointer. */
  --t-body-touch: 400 16px/1.5 var(--font-sans);

  /* ── Tracking helpers (apply alongside the role) ── */
  --tr-display: -0.03em;
  --tr-h1:      -0.025em;
  --tr-h2:      -0.02em;
  --tr-h3:      -0.015em;
  --tr-label:    0.12em;

  /* ── Spacing scale (4px base) ── */
  --sp-1:  4px;
  --sp-2:  8px;
  --sp-3:  12px;
  --sp-4:  16px;
  --sp-5:  20px;
  --sp-6:  24px;
  --sp-8:  32px;
  --sp-10: 40px;
  --sp-12: 48px;
  --sp-16: 64px;
  --sp-20: 80px;
  --sp-24: 96px;

  /* ── Corner radius (tight — system feeling) ── */
  --r-0: 0;
  --r-1: 2px;
  --r-2: 4px;
  --r-3: 6px;
  --r-4: 8px;

  /* ── Layout ── */
  --topbar-h: 56px;   /* the console topbar; the chat drawer hangs beneath it */
  --control-h: 32px;  /* one height for every chrome control (topbar, filters) */
  --tabbar-h: 56px;   /* the phone's bottom tab bar, above the home indicator */

  /* ── Safe area — the notch, the island, the home indicator ──
     ds_root opts into viewport-fit=cover and the manifest is standalone, so
     these are real on every installed console. Named once here: a component
     that writes env() inline is a component that will miss one of the four. */
  --safe-t: env(safe-area-inset-top, 0px);
  --safe-r: env(safe-area-inset-right, 0px);
  --safe-b: env(safe-area-inset-bottom, 0px);
  --safe-l: env(safe-area-inset-left, 0px);

  /* ── Touch ──
     44px is the floor, which is what marketing.css's own coarse-pointer
     rules already use; the console shipped 40 and two doctrines in one
     system is one too many. --tap-dense is the ONE exception: a control
     inside a scrolling register row, where 44 would double the row's height.
     Never for a destructive verb. --tap-slop expands an inline word-target
     through an ::after inset without growing its box. */
  --tap-min:   44px;
  --tap-dense: 36px;
  --tap-slop:  10px;   /* 16px of line + 2x10 = the --tap-dense floor */

  /* ── Gutters — two shared left edges ──
     Panels (head rows, table edge cells) sit on one; card interiors on the
     other. A head 2px off its first column is the wobble that reads homemade.
     --pad-view is the page gutter: a token so the phone step moves it once
     instead of every surface overriding it. */
  --pad-panel: 16px;  /* panel heads, register edge cells */
  --pad-card:  20px;  /* card interiors */
  --pad-view:  32px;  /* page gutter: .page-header, .view-body */

  /* ── Tracking (two jobs, two tokens) ── */
  --tr-wide: 0.08em;  /* inline chips/badges; --tr-label (0.12em) is 10px labels */

  /* ── Layer scale — the one z-index vocabulary ──
     In-flow surfaces stack at field/raised; sticky headers hold their rows;
     floating chrome climbs drawer → menu → chrome → backdrop → scrim →
     sidebar. If a layer needs a number outside this scale, the layer is
     wrong, not the scale. */
  --z-field: 0;      /* canvas fields, in-flow base layers */
  --z-raised: 1;     /* raised in-flow elements */
  --z-sticky: 2;     /* sticky table headers */
  --z-meter: 6;      /* in-row meter bars */
  --z-nav: 30;       /* the marketing nav pill */
  --z-drawer: 60;    /* the chat panel drawer */
  --z-menu: 70;      /* menus and popovers (user menu, chat history) */
  --z-tip: 90;       /* tooltips */
  --z-chrome: 100;   /* skip link, flash stack */
  --z-backdrop: 200; /* command palette backdrop */
  --z-scrim: 290;    /* mobile sidebar scrim */
  --z-sidebar: 300;  /* mobile sidebar */

  /* ── Motion ──
     Durations are a ramp by element size; easing is a contract:
     movement (transform, size, position) rides --ease-out; pure linear is
     reserved for opacity/color fades and progress loops. Linear movement is
     the single biggest machine-made tell. */
  --easing: linear;            /* fades and color shifts only */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);  /* movement: enter, press, nudge */
  --t-quick: 120ms;   /* press feedback, micro shifts */
  --t-base:  160ms;   /* hovers, small pops */
  --t-menu:  200ms;   /* dropdowns, popovers */
  --t-panel: 280ms;   /* side panels, large surfaces */
  --t-slow:  240ms;

  /* ─────────── DARK THEME — default ─────────── */
  /* The surface ladder is OKLCH, hue-tinted toward the signal (hue 125 at
     whisper chroma) so the neutrals agree with the accent; depth = one step
     up the ladder + an alpha-white hairline, never a shadow (in-flow).
     Floating chrome is different physics: --surface-overlay + --shadow-overlay. */
  --surface:        oklch(0.12 0.004 125);   /* mono ink — page bg */
  --surface-elev:   oklch(0.175 0.006 125);  /* cards, panels */
  --surface-overlay: oklch(0.215 0.008 125); /* floating chrome only */
  --surface-rule:   rgba(255, 255, 255, 0.07);  /* hairline — works on every step */
  --line-strong:    rgba(255, 255, 255, 0.16);  /* interactive/emphasized edges */

  /* Ledger-paper ruling inks (marketing field bands, the gate's canvas):
     verticals faintest, horizontals a touch more present. The solid ink is
     read by page-js for the canvas field, where alpha lines multiply into
     nothing; warm, on the ladder's hue axis. */
  --field-v:          rgba(255, 255, 255, 0.040);
  --field-h:          rgba(255, 255, 255, 0.065);
  --field-rule-solid: #262724;

  /* State overlays: dark-UI hovers LIGHTEN, never darken. */
  --surface-hover:  rgba(255, 255, 255, 0.035);
  --surface-active: rgba(255, 255, 255, 0.06);

  /* The one sanctioned shadow: floating layers only (palette, menus,
     flashes, tooltips), always paired with a hairline border. */
  --shadow-overlay: 0 1px 1px rgba(0, 0, 0, 0.3),
                    0 8px 24px -6px rgba(0, 0, 0, 0.5),
                    0 24px 48px -12px rgba(0, 0, 0, 0.5),
                    inset 0 1px 0 rgba(255, 255, 255, 0.04);

  /* The ground under a cover: the drawer's scrim and the palette's backdrop
     are the same physics, so they are one token. DESIGN.md has named it
     since the palette shipped; the two overlays each hardcoded their own. */
  --scrim:          rgba(0, 0, 0, 0.5);

  /* Human focus is neutral (chartreuse focus would claim the agent's voice). */
  --focus-ring:     rgba(250, 250, 250, 0.55);

  --text:           #fafaf7;  /* primary text — paper, a whisper warm on the ladder's axis */
  --text-hover:     #e4e4e1;  /* primary-button hover: one step off paper, never a dim */
  /* The muted ramp holds WCAG AA (4.5:1+) for small text on both --surface
     and --surface-elev; hierarchy below --text-muted leans on size and case,
     not on dropping below readable contrast. Same lightness as the old hexes,
     retinted to the ladder's hue. */
  --text-muted:     oklch(0.72 0.006 125);  /* de-emphasized */
  --text-subtle:    oklch(0.63 0.006 125);  /* labels, captions */
  --text-faint:     oklch(0.61 0.006 125);  /* micro hints */

  --signal:         #c4f000;  /* chartreuse — AGENT ONLY */
  --signal-text:    #c4f000;  /* signal as TEXT on a surface (light theme darkens it) */
  --signal-soft:    #d8f566;  /* hover on signal */
  --signal-ink:     #2a3300;  /* text on signal fill */

  --success:        #4ade80;
  --danger:         #f87171;
  --warning:        #fbbf24;
  --info:           #60a5fa;
}

/* ─────────── LIGHT THEME — inverted ─────────── */
/* .mkt-invert alone (dark theme): the band renders as paper. Inside a
   .light page the dark block's .light .mkt-invert selector outranks this. */
.light,
.mkt-invert {
  --surface:        oklch(0.98 0.002 125);
  /* The paper band step, taken as deep as AA allows: --text-faint (0.54)
     pins the floor at L 0.961 (4.53:1); deeper fails 4.5:1 for faint text
     on elevated cards. Band architecture on paper leans on the hairline
     edges elevated bands carry (marketing.css), not on this step alone. */
  --surface-elev:   oklch(0.961 0.004 125);
  --surface-overlay: #fefefb;  /* warm white, same axis as the ladder */
  --surface-rule:   rgba(0, 0, 0, 0.08);
  --line-strong:    rgba(0, 0, 0, 0.18);

  --field-v:          rgba(0, 0, 0, 0.045);
  --field-h:          rgba(0, 0, 0, 0.070);
  --field-rule-solid: #dcdcd8;

  --surface-hover:  rgba(0, 0, 0, 0.03);
  --surface-active: rgba(0, 0, 0, 0.05);

  --shadow-overlay: 0 1px 1px rgba(0, 0, 0, 0.03),
                    0 8px 16px -4px rgba(0, 0, 0, 0.08),
                    0 24px 32px -8px rgba(0, 0, 0, 0.10);

  /* Paper's cover is lighter: a 50% black over white reads as a bruise. */
  --scrim:          rgba(10, 10, 10, 0.38);

  --focus-ring:     rgba(10, 10, 10, 0.5);

  --text:           #0a0a0a;
  --text-hover:     #27272a;
  --text-muted:     oklch(0.44 0.006 125);
  --text-subtle:    oklch(0.51 0.006 125);
  --text-faint:     oklch(0.54 0.006 125);

  /* signal-deep — darker chartreuse so the signal survives on paper. Ink on
     a signal fill is dark here (paper ink washed out at 2.5:1, failing AA on
     the Approve button); hover steps LIGHTER, mirroring dark theme, so the
     dark ink keeps >= 4.5:1 on both fills (6.38:1 rest, 7.45:1 hover). */
  --signal:         #8aac00;
  --signal-soft:    #96ba05;
  --signal-ink:     #1a2000;
  /* Signal as text needs more depth than the fill: #8aac00 reads 2.5:1 on
     paper; this holds 4.96:1. Fills keep --signal; prose keeps this. */
  --signal-text:    #5d7500;

  --success:        #15803d;
  --danger:         #b91c1c;
  --warning:        #b45309;
  --info:           #1d4ed8;
}

/* ── Breakpoint ladder — THREE steps, max-width, desktop-first ──
   Custom properties do not resolve inside a media query and there is no
   build step, so the ladder is a contract stated here and enforced in
   review, not a token.

     sm   560px   phone portrait. One column, one register per screen.
     md   900px   phone landscape + tablet portrait. The shell's drawer and
                  tab-bar boundary: below md the sidebar is off-canvas.
     lg  1200px   desktop. Sidebar docked, chat panel docked beside content.

   Nothing else. A rule reaching for 820 or 1100 is a rule that has not
   decided which of the three steps it belongs to. */

/* ── The coarse-pointer step ──
   Deliberately not a width query: a 900px phone in landscape needs thumb-
   sized chrome and a 900px laptop window does not. Stepping --control-h
   here lifts every control already reading the token (the icon buttons, the
   theme toggle, the register filters, the onboarding fields) in one move,
   and the type roles step with it so a phone stops speaking in 10px. */
@media (pointer: coarse) {
  :root,
  .light .mkt-invert {
    --t-body:       400 16px/1.55 var(--font-sans);
    --t-body-sm:    400 14px/1.50 var(--font-sans);
    --t-mono-data:  500 14px/1.50 var(--font-mono);
    --t-mono-label: 500 12px/1.40 var(--font-mono);
    --t-micro:      400 13px/1.40 var(--font-sans);

    /* 0.12em is a display-caps value. On 10px it was 1.2px of air between
       letters on the app's DEFAULT label face, which is most of the text on
       a phone: legible as a texture, not as words. Caps still need more than
       zero, so it halves rather than going away. */
    --tr-label: 0.06em;

    --control-h: var(--tap-min);
    --pad-card:  16px;
    --pad-view:  16px;
  }
}
