/*
 * Tresi design tokens.
 *
 * One file, consumed identically by the web build and the Tauri shell. Every
 * colour, radius, and duration in the app resolves through a token here — if
 * you find yourself writing a literal hex value in a component, add a token
 * instead, or the light/dark pairing will drift.
 *
 * Palette: soft pastels on a warm neutral. Cute, but the money colours are
 * deliberately restrained — spending is not an error state and should not be
 * rendered in alarm red.
 */

:root {
  color-scheme: light;

  /* ---- Warm neutral base -------------------------------------------------
   * Warm rather than blue-grey. A cool grey reads clinical, which is the
   * opposite of the tone we want around someone's personal finances. */
  --c-bg: #fdfbf7;
  --c-surface: #ffffff;
  --c-surface-sunken: #f6f2ec;
  --c-border: #e8e0d5;
  --c-border-strong: #d6cabb;

  --c-text: #2e2a26;
  --c-text-muted: #6f665d;
  --c-text-faint: #9c9188;

  /* ---- Pastel accents ---------------------------------------------------- */
  --c-accent: #7c6bd4; /* periwinkle — primary actions, the bunny's bow */
  --c-accent-soft: #ece8fb;
  --c-accent-text: #ffffff;

  --c-mint: #5fb49c;
  --c-mint-soft: #e2f3ee;
  --c-peach: #e8956b;
  --c-peach-soft: #fbeadf;
  --c-rose: #d47a8c;
  --c-rose-soft: #fae7eb;
  --c-butter: #e0b357;
  --c-butter-soft: #fbf1dc;

  /* ---- Money semantics ---------------------------------------------------
   * Outflow is the *default* text colour, not a warning. Most transactions are
   * spending; painting them all red would make the whole app feel like a
   * problem. Only genuine overspend gets a warm alert colour. */
  --c-money-out: var(--c-text);
  --c-money-in: #3f8f76;
  --c-money-pending: var(--c-text-muted);

  /* Budget states. `over` is peach, not red — see the tone rule in the plan:
   * the app never scolds. Red is reserved for destructive confirmations. */
  --c-budget-ok: var(--c-mint);
  --c-budget-near: var(--c-butter);
  --c-budget-over: var(--c-peach);

  --c-danger: #c4566b; /* destructive actions only */

  /* ---- Bunny -------------------------------------------------------------
   * The bunny needs its own fill rather than reusing --c-surface: it is almost
   * always drawn *on* a surface, so sharing the token leaves only a hairline
   * stroke separating the two. That reads acceptably on white and badly in
   * dark mode, where the silhouette all but disappears. */
  --c-bunny-fill: #fffdfa;
  --c-bunny-line: #cdbfae;

  /* ---- Typography --------------------------------------------------------
   * `--font-numeric` is not optional decoration. Tabular figures keep amounts
   * aligned column-to-column and stop digits jittering when a value updates
   * live over SSE. Every monetary figure must use `.money`. */
  --font-sans: "Nunito", ui-rounded, "SF Pro Rounded", system-ui, -apple-system,
    "Segoe UI", sans-serif;
  --font-numeric: ui-monospace, "SF Mono", "Cascadia Mono", "Roboto Mono",
    monospace;

  --text-xs: 0.75rem;
  --text-sm: 0.875rem;
  --text-base: 1rem;
  --text-lg: 1.25rem;
  --text-xl: 1.75rem;
  --text-2xl: 2.5rem;

  /* ---- Shape ------------------------------------------------------------- */
  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 20px;
  --radius-full: 999px;

  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;

  --shadow-sm: 0 1px 2px rgb(46 42 38 / 6%);
  --shadow-md: 0 4px 12px rgb(46 42 38 / 8%);

  /* ---- Motion ------------------------------------------------------------
   * Spring easing for anything the bunny does; plain ease-out for utility. */
  --ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --dur-fast: 120ms;
  --dur-base: 240ms;
  --dur-slow: 420ms;

  /* Minimum interactive size. Referenced rather than repeated so it cannot
   * silently drift below the accessibility floor. */
  --touch-target: 44px;
}

/* ---- Dark theme ----------------------------------------------------------
 *
 * Exactly ONE dark block, keyed on `[data-theme="dark"]`. It is deliberately
 * not duplicated into a `@media (prefers-color-scheme: dark)` rule.
 *
 * The usual pattern — a media query for the system preference *plus* an
 * attribute rule so a manual toggle can win — requires maintaining the same
 * twenty declarations in two places. That drifts: the first version of this
 * file added `--c-bunny-*` to the media block and silently missed the
 * attribute block, so a user who had ever touched the theme toggle got an
 * invisible bunny.
 *
 * Instead, `data-theme` is *always* set, by a boot script that reads the stored
 * preference and falls back to `matchMedia("(prefers-color-scheme: dark)")`.
 * That collapses the two rules into one and makes drift impossible. It costs a
 * dependency on the script running before first paint — acceptable here,
 * because the app is WASM and does not render at all without its runtime.
 *
 * Put this in <head>, before the first paint:
 *
 *   <script>
 *     (() => {
 *       const stored = localStorage.getItem("tresi-theme");
 *       const dark = stored
 *         ? stored === "dark"
 *         : matchMedia("(prefers-color-scheme: dark)").matches;
 *       document.documentElement.dataset.theme = dark ? "dark" : "light";
 *     })();
 *   </script>
 *
 * `color-scheme` below keeps native form controls, scrollbars, and the
 * caret in step with the palette. */
:root[data-theme="dark"] {
  color-scheme: dark;

  --c-bg: #191714;
  --c-surface: #232019;
  --c-surface-sunken: #14120f;
  --c-border: #3a352d;
  --c-border-strong: #4f483d;

  --c-text: #f2ede5;
  --c-text-muted: #a89e92;
  --c-text-faint: #7a7167;

  --c-accent: #9d8ef0;
  --c-accent-soft: #2b2545;
  --c-accent-text: #17141f;

  --c-mint: #74c9b0;
  --c-mint-soft: #1c2f2a;
  --c-peach: #f0a87f;
  --c-peach-soft: #33251c;
  --c-rose: #e295a5;
  --c-rose-soft: #331f25;
  --c-butter: #eec570;
  --c-butter-soft: #332b18;

  --c-money-in: #74c9b0;
  --c-danger: #e0798c;

  /* Lighter than --c-surface so the silhouette separates from the card
   * behind it. Sharing --c-surface leaves only a hairline stroke. */
  --c-bunny-fill: #37312a;
  --c-bunny-line: #7d7365;

  --shadow-sm: 0 1px 2px rgb(0 0 0 / 40%);
  --shadow-md: 0 4px 12px rgb(0 0 0 / 45%);
}

/* ---- Base ---------------------------------------------------------------- */

body {
  margin: 0;
  background: var(--c-bg);
  color: var(--c-text);
  font-family: var(--font-sans);
  font-size: var(--text-base);
  -webkit-font-smoothing: antialiased;
  /* Never let the page itself scroll sideways; wide content scrolls in its
   * own container instead. */
  overflow-x: hidden;
}

/* ---- Money --------------------------------------------------------------
 * Apply `.money` to every monetary figure without exception.
 *
 * - `tabular-nums` aligns digits into columns and stops live-updating values
 *   from shifting width mid-animation.
 * - `white-space: nowrap` because a wrapped amount is a misread amount.
 * - No `text-overflow: ellipsis` anywhere near this class. A truncated balance
 *   is worse than a horizontally scrolling one — "$1,2…" is actively
 *   misleading in a way that a scrollbar is not. */
.money {
  font-family: var(--font-numeric);
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
  white-space: nowrap;
  text-align: right;
  color: var(--c-money-out);
}

.money--in {
  color: var(--c-money-in);
}

/* Pending transactions are visually distinct but still fully legible — this is
 * a state, not a disabled control, so it keeps AA contrast. */
.money--pending,
.tx--pending .money {
  color: var(--c-money-pending);
  font-style: italic;
}

/* ---- Interactive --------------------------------------------------------- */

button,
.tappable {
  min-height: var(--touch-target);
  min-width: var(--touch-target);
  border-radius: var(--radius-md);
  font-family: inherit;
  cursor: pointer;
}

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

/* ---- Motion preference ---------------------------------------------------
 * Drop decorative motion, keep state changes visible. The bunny's *pose* is
 * information; only its animation is decoration, so we shorten transitions
 * rather than removing them and losing the state signal entirely. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: var(--dur-fast) !important;
    scroll-behavior: auto !important;
  }
}

/* Screen-reader-only text. Every bunny state pairs with one of these so that
 * status is never conveyed by the illustration alone. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
