/*
 * Design tokens — copied verbatim from the LocoLedger app.
 *
 * Source of truth: locoledger-private, app/src/styles/tokens.css
 * Copied 17 Sep 2026. This file is a copy, not an original. If a colour
 * changes in the app, change it there first and re-copy — never edit here
 * and never let the two drift, because the page and the product looking
 * like two different things is the one failure this file exists to prevent.
 *
 * The comments below are the app's own, including the measured contrast
 * figures. They are kept because the reasoning is the valuable part.
 */


:root {
  /* Tells the browser this document is light, so native form controls
   * (a raw <button>, a scrollbar, a checkbox) pick light-appropriate
   * defaults on their own. Without this, a vendored component that renders
   * a bare native element and sets no background of its own keeps showing
   * *light* UA chrome even while every dark token below is active — the
   * app's own colours are invisible to native rendering, which only reads
   * this property. Found live: a tool-call's collapsible trigger (built on
   * a raw Radix button, no background of its own) rendered as a pale box
   * floating on the dark theme for exactly this reason.
   */
  color-scheme: light;

  /* --- surfaces ---------------------------------------------------------
   * Three levels: the page, things sitting on it, and things recessed into
   * it. Depth comes from these plus a whisper of shadow, never from borders.
   */
  --bg: #faf7f2;
  --surface: #fffdfa;
  --surface-sunken: #f2ece3;
  --surface-hover: #f5efe6;
  --surface-active: #ece4d8;

  /* --- lines ------------------------------------------------------------
   * Barely there by design. A visible grid of dividers is what makes an app
   * feel like a spreadsheet.
   */
  --border: #e9e0d3;
  --border-strong: #d8ccb190;

  /* --- text -------------------------------------------------------------
   * Warm near-black, never #000. Pure black on warm paper looks like a
   * printing error.
   */
  --text: #2e2822;
  --text-muted: #7b7166;
  /* Between --text and --text-muted: a description someone has to read to
   * choose, rather than a hint they may skip. The Sharing rungs and their
   * hints were in --text-muted and read as small print on the one screen
   * where the small print is the decision. 6.1:1 on --bg, 5.6:1 on
   * --surface-sunken (measured 15 Sep 2026). */
  --text-detail: #655c52;
  /* Decoration, placeholders, and disabled states only.
   *
   * Never on a control, and never on text the user has to read — hints and
   * labels use --text-muted. This value clears 3:1 against every surface
   * (WCAG 1.4.11), which is the floor for anything meaningful; it was #a89d8f
   * and measured 2.3:1, which looked calm and was simply too pale to see. */
  --text-faint: #8f8476;
  --text-on-accent: #fffdfa;

  /* --- accent -----------------------------------------------------------
   * A muted clay. Used sparingly: selection, primary action, focus. If more
   * than one accent element is visible at a time, something is wrong.
   */
  --accent: #a86b45;
  /* A dedicated token, not a reuse of --accent-soft — that one is tuned to
   * sit quietly *behind* text you're already reading (a badge wash), and
   * measured 1.0-1.2:1 against every surface in the app when tried here,
   * which is invisible for a highlight whose whole job is to stand out from
   * the surface around it. `color-mix` rather than a flat hex: it recomputes
   * from whatever --accent resolves to, so light/dark/composer surfaces all
   * get a real, visible warm tint without four separate tuned values. */
  --selection: color-mix(in srgb, var(--accent) 35%, transparent);
  /* Money arriving, on a document. A shade darker than the accent so it clears
   * 4.5:1 as text on a sheet — the accent itself measures 4.26:1 there, which
   * is fine for a control's boundary and short of the floor for a figure
   * somebody has to read. Semantic, not decorative: it is separate from the
   * brand hue on purpose, so retuning one never quietly changes the other. */
  --money-in: #a26742;
  --accent-hover: #96603e;
  --accent-soft: #f6ece2;
  --accent-line: #e0c9b3;

  /* --- status -----------------------------------------------------------
   * Desaturated to sit inside the warm palette. Loud red on this background
   * reads as an emergency, and most of what we report is not one.
   */
  --danger: #a34a3a;
  --danger-soft: #f9ebe7;
  --success: #5d7a51;
  --success-soft: #eef2e9;
  --warning: #9a7430;
  --warning-soft: #f9f0dd;

  /* --- type -------------------------------------------------------------
   * A serif for display text — space names, page titles, empty states. It is
   * the single strongest cue that this is a personal document, and it costs
   * nothing since both stacks are already on the system.
   */
  --font-display: ui-serif, Georgia, "Iowan Old Style", "Palatino Linotype",
    serif;
  --font-sans: system-ui, -apple-system, "Segoe UI", Inter, Roboto, sans-serif;
  --font-mono: ui-monospace, "Cascadia Code", "SF Mono", Menlo, monospace;

  --text-xs: 0.75rem;
  --text-sm: 0.8125rem;
  --text-base: 0.875rem;
  --text-md: 1rem;
  --text-lg: 1.25rem;
  --text-xl: 1.625rem;

  --leading-tight: 1.25;
  --leading-normal: 1.55;

  /* --- space ------------------------------------------------------------
   * A 4px scale. Generous by default: air is the main tool for calm.
   */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 3rem;
  --space-8: 4rem;

  /* --- shape ------------------------------------------------------------ */
  --radius-sm: 6px;
  --radius: 10px;
  --radius-lg: 16px;
  --radius-full: 999px;

  /* Soft and warm-tinted, so shadows read as light rather than as grey. */
  --shadow-sm: 0 1px 2px rgba(70, 55, 40, 0.05);
  --shadow: 0 2px 8px rgba(70, 55, 40, 0.07);
  --shadow-lg: 0 12px 32px rgba(70, 55, 40, 0.13);

  /* --- layout ----------------------------------------------------------- */
  /* Also the only place this is written. `lib/panel.ts` measures it, because
   * the panel's limits are arithmetic on the space the rail leaves behind. */
  --rail-width: 11.875rem;
  /*
   * The side panel, when it is open.
   *
   * 22rem because that is what the space actually is. Measured on a maximised
   * 2046 CSS px window: rail 190 + content cap 1200 leaves 656px going spare,
   * so a panel this wide costs the document list nothing at all there. Below
   * about 1390px there is no spare space and the content gives way instead —
   * which is why the panel is closed until someone opens it.
   */
  /*
   * The side panel, and the two floors either side of it.
   *
   * **In rem, and only written here.** `lib/panel.ts` measures them. All three
   * were previously also written in that file as raw pixels — 352, 272, 544 —
   * which are exactly these values at a 16px root, kept in step by nobody.
   *
   * rem rather than px for the same reason as everything else in this block:
   * someone running their system at 125% text scaling should get a wider panel
   * and a wider content floor, because their text is bigger. Pixels ignore
   * that, and a content floor sized for 16px text is not a floor at 20px.
   *
   * They are *not* percentages of the window, deliberately. A reading panel's
   * useful width is set by the text inside it, not by the monitor around it —
   * a quarter of a 4K screen is about 120 characters a line, well past where
   * prose stops being readable. The content column absorbs a wide window; the
   * panel keeps the width it was given.
   */
  --panel-width: 22rem;
  /* Narrower than this and the panel is a column of single words. */
  --panel-min: 17rem;
  /* What the document list needs before it stops being usable: a file name, a
   * few facts, and a row of controls. Below it the controls start overlapping
   * the name they belong to. */
  --content-min: 34rem;
  /*
   * How wide a page gets, however wide the window is.
   *
   * One number for the title and the content under it. They were two before —
   * the header spanned the whole window and the list stopped at 880px, left
   * aligned — and on a maximised window that reads as a bug rather than as a
   * choice, because the title's right edge is a thousand pixels past the
   * list's.
   *
   * 75rem rather than the old 55rem because these screens are *tables*: a
   * name, three or four facts, and a set of controls. 55rem is a reading
   * width, and squeezing a row of controls into one is what pushed the buttons
   * up against the text. It is still a cap, because a row whose name is at the
   * far left and whose Delete button is at the far right of a 2300px screen is
   * a row nobody can read across.
   *
   * A cap, not a width. Below it everything is fluid; it only stops the page
   * growing past the point where reading across a row gets hard.
   *
   * In `rem`, so it scales with the reader's own font size. Someone who has
   * set their text larger needs the cap larger too — a fixed pixel ceiling
   * would fit fewer and fewer words as their type grew, which is the opposite
   * of what they asked for. Every size in this file works that way; only
   * radii and shadows stay in pixels, because a 10px corner is a 10px corner
   * however big the text inside it is.
   */
  /* A checkbox, and the gap a list header has to leave for one. Written here
   * because two places need the same number: the control itself, and the
   * spacer that lines a column heading up over the titles beside it. */
  --checkbox-size: 1.05rem;

  /* The strip at the end of a row where its three-dot menu sits. Fixed, and
   * that is the point: a column heading can only line up over its values if
   * every row's grid is exactly as wide as the header's, so what trails the
   * grid has to be a width both of them can reserve. */
  --row-tail: 2rem;

  /* How much room a three-dot menu wants below it before it gives up and opens
   * upwards. A guess at its height, made before it has one — the menu has not
   * been laid out at the moment the decision is taken. Here rather than in the
   * component because it is a length, and lengths are the stylesheet's. */
  --menu-clearance: 15rem;

  --page-max: 75rem;
  /* Running text, held near 70 characters. Much narrower than --page-max: a
   * line of prose the full width of this window is measurably harder to read,
   * and notes are the one place people write. */
  --measure: 42rem;
  /* A sheet of figures, not of prose. The ledger is five columns wide and is
   * read *across* — item, out, in, balance — so the prose measure, which
   * exists to keep a line short, works against it: the amounts get squeezed
   * and the descriptions wrap. Wider than --measure, still under --page-max so
   * the sheet never fills a maximised window edge to edge. */
  --sheet-measure: 60rem;

  /* --- motion -----------------------------------------------------------
   * Fast enough to feel responsive, slow enough not to snap.
   */
  --ease: cubic-bezier(0.2, 0, 0.2, 1);
  --duration: 140ms;
}

/*
 * Dark, for the system preference. Guarded so an explicit light choice wins.
 *
 * Warm dark, not black: the same paper viewed at night. A neutral #111 under
 * a warm accent looks broken.
 */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
    --bg: #191512;
    --surface: #221d19;
    --surface-sunken: #141110;
    --surface-hover: #292420;
    --surface-active: #322b25;

    --border: #342d26;
    --border-strong: #4a4038;

    --text: #ece4d9;
    --text-muted: #9d9287;
    --text-detail: #b3a99d;
    --text-faint: #7d7469;
    --text-on-accent: #1a1512;

    --accent: #cf9264;
  --money-in: #cf9264;
    --accent-hover: #dda275;
    --accent-soft: #2b2119;
    --accent-line: #4a382a;

    --danger: #cf8272;
    --danger-soft: #2e1e19;
    --success: #94ac86;
    --success-soft: #1f261c;
    --warning: #c9a462;
    --warning-soft: #2a2115;

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
    --shadow: 0 2px 8px rgba(0, 0, 0, 0.35);
    --shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.45);
  }
}

/* The manual toggle. Duplicated deliberately: a media query cannot express
 * "the user chose dark on a light system". */
:root[data-theme="dark"] {
  color-scheme: dark;
  --bg: #191512;
  --surface: #221d19;
  --surface-sunken: #141110;
  --surface-hover: #292420;
  --surface-active: #322b25;

  --border: #342d26;
  --border-strong: #4a4038;

  --text: #ece4d9;
  --text-muted: #9d9287;
  --text-detail: #b3a99d;
  --text-faint: #7d7469;
  --text-on-accent: #1a1512;

  --accent: #cf9264;
  --money-in: #cf9264;
  --accent-hover: #dda275;
  --accent-soft: #2b2119;
  --accent-line: #4a382a;

  --danger: #cf8272;
  --danger-soft: #2e1e19;
  --success: #94ac86;
  --success-soft: #1f261c;
  --warning: #c9a462;
  --warning-soft: #2a2115;

  --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
  --shadow: 0 2px 8px rgba(0, 0, 0, 0.35);
  --shadow-lg: 0 12px 32px rgba(0, 0, 0, 0.45);
}

/* ---------------------------------------------------------------------------
 * shadcn / Tailwind bridge — the mapping itself lives in app.css.
 *
 * It has to: Tailwind resolves `@theme` only inside a file that imports it,
 * and this file deliberately does not. Colours are still only *defined* here;
 * app.css only points Tailwind's names at them.
 * ------------------------------------------------------------------------ */

/* A bare `border` utility sets width only; Tailwind v4 leaves the colour as
 * currentColor, which draws menu borders in the text colour. Scoped to the
 * editor's own root so it cannot reach our components. */
.bn-shadcn *,
.bn-shadcn *::before,
.bn-shadcn *::after {
  border-color: var(--border);
}
