/* Self-hosted, not a CDN call: the app has to render offline and inside a WebView, and a webfont
   request that fails leaves the whole interface in a fallback nobody chose. `--font` has named
   Nunito since Gate 0 with no @font-face behind it, so every screen so far has actually been
   system sans. Variable 400..800 in two subsets, 30 KB total.
   Figtree, SIL OFL 1.1 — see assets/fonts/OFL.txt. */
@font-face {
  font-family: 'Figtree';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url('assets/fonts/figtree-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
                 U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191,
                 U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Figtree';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url('assets/fonts/figtree-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02AF, U+0304, U+0308, U+0329, U+1E00-1E9F, U+1EF2-1EFF,
                 U+2020, U+20A0-20AB, U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* Design tokens — DESIGN_MOTION_SPEC §1 (motion) and §2 (visual). Single source of truth. */
:root {
  /* Easing — custom curves; built-ins are too weak */
  --ease-out:    cubic-bezier(0.23, 1, 0.32, 1);     /* enter, response — default */
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);    /* on-screen movement/morph */
  --ease-drawer: cubic-bezier(0.32, 0.72, 0, 1);     /* sheets (iOS drawer curve) */
  --spring-pop:  cubic-bezier(0.22, 1.4, 0.36, 1);   /* overshoot — rewards ONLY */

  /* Durations — UI stays under 300ms; ceremonies are the exception */
  --t-press: 120ms;
  --t-fast:  180ms;
  --t-ui:    240ms;
  --t-sheet: 320ms;
  --t-beat:  600ms;

  /* Z-index scale */
  --z-widget-fx: 10;
  --z-sheet: 20;
  --z-banner: 30;
  --z-toast: 40;

  /* Surfaces — warm neutral, not navy. Navy is the colour every habit and AI app already ships,
     and it tinted eleven creatures that span orange, violet, cyan, green and iridescent. A neutral
     ground is the only one that lets all of them read as lit rather than as competing accents. */
  --bg: #141519;
  --bg-glow: #1e1f27;
  --surface: #1c1d23;
  --surface-raised: #26272f;
  --border: #34353f;

  --text: #f3f2f4;
  --text-muted: #a5a3ad;      /* 6.76:1 on surface */

  /* One brand colour, used solid. A gradient spread over every control is what made the old
     palette read as a template rather than as an identity. Deep indigo is the one hue the
     creature cast does not already occupy, and its depth separates it from all of them. */
  --brand: #4c5bd4;
  --brand-strong: #5b69e0;
  --brand-ink: #a5aeff;       /* 8.08:1 on surface */
  --brand-soft: rgba(124, 138, 255, 0.16);
  --brand-line: rgba(124, 138, 255, 0.5);

  /* Kept for the components that already read them. Solid, not a gradient. */
  --accent-gradient: var(--brand);
  --accent-soft: var(--brand-soft);
  --accent-line: var(--brand-line);
  --accent-ink: var(--brand-ink);

  /* Data colours. These carry meaning, never decoration: mind, body, order, streak.
     They are the only saturated things allowed beside the creature. */
  --violet: #8b7cf0;          /* mind */
  --flame: #f0a63c;           /* the streak flame, and body */
  --mint: #3fb98f;            /* order, and anything that means "kept" */
  --blush: #f2764b;

  /* Destructive actions get their own token. Borrowing a data colour meant the delete button
     inherited whatever the palette needed for decor, and in light mode that landed at 4.09:1. */
  /* Awards. The disc carries a data colour that already means something — the flame is the streak
     flame, mint is "kept", violet is mind — and the glyph inside is the page's own ground, which
     inverts with the theme and so stays legible on every disc in both. */
  --award-ink: #141519;
  --award-brand: #5b69e0;
  --danger: #f2764b;        /* 5.98:1 on surface */
  --danger-soft: rgba(242, 118, 75, 0.14);
  --danger-line: rgba(242, 118, 75, 0.45);

  /* Translucent sheet material, themed so light mode gets a light glass instead of a dark slab */
  --sheet-bg: rgba(22, 23, 28, 0.78);
  --sheet-edge: #3d3e49;

  /* The glade (world.js). Themed, or the ground renders as a slab in light mode. */
  --world-ground: #2f313d;
  --world-rim: #4e9b7c;
  --world-post: #55483c;
  --world-leaf: #487f61;
  --world-leaf-dark: #3d6e53;
  --world-leaf-light: #55916d;
  --world-shade: #08080a;

  /* Type — 3 sizes only */
  --font: 'Figtree', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --size-title: 1.5rem;
  --size-body: 1rem;    /* 16px floor */
  --size-small: 0.875rem;

  --radius: 18px;
  --radius-sm: 12px;
  --tap: 44px;          /* minimum touch target */
}

/* Light theme — set by data-theme on <html>. Only the ground and text invert; the brand and the
   data colours hold their meaning across both, which is what makes them read as a system. */
:root[data-theme='light'] {
  --bg: #faf9f8;
  --bg-glow: #f2f1f0;
  --surface: #ffffff;
  --surface-raised: #f2f1f0;
  --border: #e2e0de;
  --text: #1a1a20;
  --text-muted: #5e5c66;      /* 6.57:1 on surface */

  /* The indigo has to darken to stay legible as text on white: the dark-mode ink is 1.9:1 here. */
  --brand-ink: #4450bf;       /* 6.68:1 on white, 5.92:1 on the raised surface */
  --brand-soft: rgba(76, 91, 212, 0.12);
  --brand-line: rgba(76, 91, 212, 0.45);

  --violet: #6d5bd0;
  --flame: #c47e18;
  --mint: #1f8f68;
  --blush: #d4552b;
  --award-ink: #ffffff;
  --award-brand: #4c5bd4;
  --danger: #b53d18;        /* 5.76:1 on white, 5.11:1 on the raised surface */
  --danger-soft: rgba(181, 61, 24, 0.1);
  --danger-line: rgba(181, 61, 24, 0.42);

  --sheet-bg: rgba(255, 255, 255, 0.85);
  --sheet-edge: #e2e0de;

  --world-ground: #cfccc6;
  --world-rim: #5f9c7f;
  --world-post: #8a7a68;
  --world-leaf: #6fa587;
  --world-leaf-dark: #5c9174;
  --world-leaf-light: #86b89b;
  --world-shade: #8a8780;
}
