/* ═══════════════════════════════════════════════════════════════════════════
   Delteil-Moore — shared design system
   ───────────────────────────────────────────────────────────────────────────
   The web reading of the Life app's DESIGN.md and the DelteilMoore Brand
   Overview. The app is the source of truth for the tokens; this file is where
   they are translated into the things a website has and a phone app does not:
   a page that can be any width, a pointer, and a viewer whose colour scheme we
   only ever get to ask about.

   What is carried over unchanged:
     · the palette (DESIGN.md §3), light and dark
     · the asymmetrical leaf corner, 20/20/20/0 with the sharp stem point (§5)
     · the type ladder — Albert Sans (display + UI), Inter (body + numbers,
       kept aligned with tabular figures); Fraunces, Plus Jakarta and
       JetBrains Mono retired (§4)
     · text filters with a 2px accent underline, never pills (§5)
     · the 56px circle icon backdrop, artwork at 68% of the diameter (§5)
     · motion: 200–300ms on cubic-bezier(.16,1,.3,1), press compresses to .98

   What is deliberately different, and why:
     · **Hover exists here.** The app has no pointer, so its cards only have a
       press state. Cards and rows lift 1px on hover; the press state is still
       the app's scale(.98).
     · **Layout is fluid.** Phone screens are one column by definition; these
       pages are given a max width and a grid that collapses to one column
       under 720px, so a laptop doesn't get a phone screen stretched across it.
     · **The scheme follows the browser.** The app carries userInterfaceStyle
       "automatic"; the web equivalent is prefers-color-scheme, plus an
       explicit [data-theme] override for the header toggle.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Tokens ──────────────────────────────────────────────────────────────── */

:root {
  /* Base canvas — DESIGN.md §3 */
  --canvas: #F5F3ED;          /* Cream Linen */
  --surface: #FFFFFF;         /* Surface White */
  --surface-2: #FBFAF6;       /* Sunk surface: inputs, table stripes */
  --text: #1C2217;            /* Deep Charcoal */
  --text-muted: #606859;      /* Muted Slate */
  --border: rgba(28, 34, 23, .12);
  --border-strong: rgba(28, 34, 23, .22);

  /* Accents — DESIGN.md §3 */
  --leaf: #55632E;            /* Leaf Primary */
  --leaf-ink: #F5F3ED;        /* type that sits on Leaf Primary */
  --terracotta: #C87443;      /* Warm Clay CTA */
  --amber: #C08A2E;           /* Contract / status alert */
  --danger: #B3502F;          /* Terracotta Danger — expired / alert */
  --gold: #D9A441;            /* Pinned / starred */
  --success: #4C7A5A;         /* the recycling green, doubling as "done" */

  /* Botanical Bright — the colour-block palette (design-refresh/). Pastel fills
     stay constant across light and dark: each is a light surface that always
     carries --bright-ink, so it reads on either canvas. Additive — nothing above
     changes. Travel's own --tb-* aliases predate this and still work. */
  --sap: #C7EC5B;             /* hero lime — up next, primary "+" */
  --sky: #AEDCE6;             /* travel / motion */
  --bloom: #F4C4D4;           /* stays / people / warm */
  --fern: #BEE7CD;            /* ground / done / on-track */
  --bright-ink: #1B2416;      /* fixed dark ink for type ON a pastel */

  /* Mini-app identities — DESIGN.md §3 "Mini-App Color Palette System" */
  --todo-surface: #DCE6C8;    --todo-text: #3A4B22;  --todo-accent: #55632E;
  --key-surface: #F3D8C8;     --key-text: #6E3E26;   --key-accent: #C2A183;
  --travel-surface: #C8DCE0;  --travel-text: #23464C;--travel-accent: #23464C;
  --recipe-surface: #F5E6BF;  --recipe-text: #5C4A1C;--recipe-accent: #5C4A1C;
  --home-surface: #DDD9EA;    --home-text: #3B3252;  --home-accent: #3B3252;
  --quote-surface: #F4DCD6;   --quote-text: #7A3A2C; --quote-accent: #C87443;
  --reno-surface: #CFE0D5;    --reno-text: #2F5245;  --reno-accent: #37624F;
  --arsenal-surface: #E7CDD5; --arsenal-text: #5E1A2C; --arsenal-accent: #6E1B32;
  --matchday-surface: #D3DAE3; --matchday-text: #22303F; --matchday-accent: #2F4A63;

  /* Geometry — DESIGN.md §5. The stem point is the brand, so it is a token
     rather than four numbers repeated down the file. */
  --leaf-radius: 20px 20px 20px 0;
  --leaf-radius-sm: 12px 12px 12px 0;
  --leaf-radius-lg: 28px 28px 28px 0;
  --radius-control: 8px;      /* Brand Overview §5: buttons & badges */
  --radius-sheet: 24px;       /* modals & sheets, top corners */

  /* Elevation — Brand Overview §5, tinted charcoal rather than neutral grey */
  --shadow: 0 4px 20px rgba(28, 34, 23, .06);
  --shadow-lift: 0 8px 28px rgba(28, 34, 23, .10);
  --shadow-sheet: 0 16px 48px rgba(28, 34, 23, .18);

  /* Motion — Brand Overview §6 */
  --ease: cubic-bezier(.16, 1, .3, 1);
  --fast: 200ms;
  --slow: 300ms;

  /* Type */
  --font-display: 'Albert Sans', system-ui, sans-serif;
  --font-ui: 'Albert Sans', system-ui, sans-serif;
  --font-body: 'Inter', system-ui, sans-serif;
  /* JetBrains Mono retired — numbers and data now set in Inter, kept aligned
     with font-variant-numeric: tabular-nums wherever they line up in columns. */
  --font-mono: 'Inter', system-ui, sans-serif;

  /* Layout */
  --page-max: 1080px;
  --gutter: clamp(1.25rem, 4vw, 3rem);

  color-scheme: light dark;
}

/* Dark — "Deep Moss & Spruce". Defined once and applied from two selectors so
   the toggle wins in both directions: the media query alone can't be undone by
   a viewer who chose light, and [data-theme] alone never fires for the default
   "follow the system" state. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --canvas: #1C281C;
    --surface: #263626;
    --surface-2: #1F2D1F;
    --text: #F5F3ED;
    --text-muted: #A2AA9A;
    --border: rgba(245, 243, 237, .14);
    --border-strong: rgba(245, 243, 237, .26);
    --leaf: #92B588;           /* Soft Sage — Leaf Primary is unreadable here */
    --leaf-ink: #1C281C;
    --success: #8CBF9A;
    --shadow: 0 4px 20px rgba(0, 0, 0, .30);
    --shadow-lift: 0 8px 28px rgba(0, 0, 0, .40);
    --shadow-sheet: 0 16px 48px rgba(0, 0, 0, .55);

    --todo-surface: #243324;    --todo-text: #DCE6C8;  --todo-accent: #92B588;
    --key-surface: #382B24;     --key-text: #F3D8C8;   --key-accent: #C2A183;
    --travel-surface: #203236;  --travel-text: #C8DCE0;--travel-accent: #A9CBD3;
    --recipe-surface: #383222;  --recipe-text: #F5E6BF;--recipe-accent: #D9C185;
    --home-surface: #2C2738;    --home-text: #DDD9EA;  --home-accent: #B5ADD1;
    --quote-surface: #382426;   --quote-text: #F4DCD6; --quote-accent: #E09B70;
    --reno-surface: #1E2E27;    --reno-text: #CFE0D5;  --reno-accent: #7FB79C;
    --arsenal-surface: #321C26; --arsenal-text: #E7CDD5; --arsenal-accent: #D291A5;
    --matchday-surface: #1E2733; --matchday-text: #D3DAE3; --matchday-accent: #8FAECB;
  }
}

:root[data-theme="dark"] {
  --canvas: #1C281C;
  --surface: #263626;
  --surface-2: #1F2D1F;
  --text: #F5F3ED;
  --text-muted: #A2AA9A;
  --border: rgba(245, 243, 237, .14);
  --border-strong: rgba(245, 243, 237, .26);
  --leaf: #92B588;
  --leaf-ink: #1C281C;
  --success: #8CBF9A;
  --shadow: 0 4px 20px rgba(0, 0, 0, .30);
  --shadow-lift: 0 8px 28px rgba(0, 0, 0, .40);
  --shadow-sheet: 0 16px 48px rgba(0, 0, 0, .55);

  --todo-surface: #243324;    --todo-text: #DCE6C8;  --todo-accent: #92B588;
  --key-surface: #382B24;     --key-text: #F3D8C8;   --key-accent: #C2A183;
  --travel-surface: #203236;  --travel-text: #C8DCE0;--travel-accent: #A9CBD3;
  --recipe-surface: #383222;  --recipe-text: #F5E6BF;--recipe-accent: #D9C185;
  --home-surface: #2C2738;    --home-text: #DDD9EA;  --home-accent: #B5ADD1;
  --quote-surface: #382426;   --quote-text: #F4DCD6; --quote-accent: #E09B70;
  --reno-surface: #1E2E27;    --reno-text: #CFE0D5;  --reno-accent: #7FB79C;
  --arsenal-surface: #321C26; --arsenal-text: #E7CDD5; --arsenal-accent: #D291A5;
  --matchday-surface: #1E2733; --matchday-text: #D3DAE3; --matchday-accent: #8FAECB;
}

/* ── Reset & base ────────────────────────────────────────────────────────── */

*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; padding: 0; }

html { -webkit-text-size-adjust: 100%; }

body {
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.6;
  background: var(--canvas);
  color: var(--text);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; display: block; }

a { color: inherit; }

button, input, select, textarea { font: inherit; color: inherit; }

:focus-visible {
  outline: 2px solid var(--terracotta);
  outline-offset: 2px;
  border-radius: 2px;
}

/* ── Type ladder — DESIGN.md §4 ──────────────────────────────────────────── */

.display {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(2rem, 6vw, 3.25rem);
  line-height: 1.1;
  letter-spacing: -.01em;
}

h1, .h1 { font-family: var(--font-display); font-weight: 600; font-size: clamp(1.75rem, 4vw, 2.25rem); line-height: 1.15; }
h2, .h2 { font-family: var(--font-display); font-weight: 600; font-size: 1.5rem; line-height: 1.2; }
h3, .h3 { font-family: var(--font-ui); font-weight: 700; font-size: 1.125rem; line-height: 1.3; }

/* 10pt uppercase bold, tracking +1.5 — the app's category label. */
.eyebrow {
  font-family: var(--font-body);
  font-size: .625rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .15em;
  color: var(--text-muted);
}

.caption { font-size: .8125rem; font-weight: 500; color: var(--text-muted); }

.mono { font-family: var(--font-mono); font-weight: 700; font-variant-numeric: tabular-nums; }

.muted { color: var(--text-muted); }

/* ── Site header ─────────────────────────────────────────────────────────── */

/* The markup is rendered by assets/dm-nav.js so the menu has exactly one
   definition — a page taken offline is removed there and disappears
   site-wide, rather than being hunted down in every file. */

.site-header {
  position: sticky;
  top: 0;
  z-index: 200;
  /* Explicit, because the header is a flex item on pages whose body centres
     its children — without it the bar shrinks to the width of its contents. */
  width: 100%;
  background: color-mix(in srgb, var(--canvas) 88%, transparent);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--border);
}

.site-header-inner {
  max-width: var(--page-max);
  margin: 0 auto;
  padding: .875rem var(--gutter);
  display: flex;
  align-items: center;
  gap: 1rem;
}

.brand {
  display: flex;
  align-items: center;
  gap: .75rem;
  text-decoration: none;
  color: var(--text);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.125rem;
  letter-spacing: .01em;
}
.brand img { width: 32px; height: 32px; object-fit: contain; }
/* The brand leaf is olive line-art drawn for a light ground. On a dark header
   — anywhere in dark mode, and Matchday's navy surface in particular — that
   olive reads as a muddy blot standing off the bar, so it is lifted to a light
   tone the way .icon-circle leaves get a cream backing in dark mode (DEL-70). */
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .brand img { filter: brightness(0) invert(0.96); } }
:root[data-theme="dark"] .brand img { filter: brightness(0) invert(0.96); }

.nav-toggle {
  display: flex;
  align-items: center;
  gap: .5rem;
  background: none;
  border: none;
  cursor: pointer;
  font-family: var(--font-ui);
  font-weight: 500;
  font-size: .9375rem;
  color: var(--text-muted);
  padding: .375rem .5rem;
  border-radius: var(--radius-control);
  transition: color var(--fast) var(--ease), background var(--fast) var(--ease);
}
.nav-toggle:hover { color: var(--text); background: var(--surface-2); }
.nav-toggle svg { width: 18px; height: 18px; }

.nav-menu {
  position: absolute;
  top: 100%;
  right: var(--gutter);
  margin-top: .25rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--leaf-radius-sm);
  box-shadow: var(--shadow-lift);
  list-style: none;
  padding: .5rem;
  min-width: 260px;
  max-height: min(70vh, 520px);
  overflow-y: auto;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px);
  transition: opacity var(--fast) var(--ease), transform var(--fast) var(--ease), visibility var(--fast);
}
.nav-menu.open { opacity: 1; visibility: visible; transform: none; }

.nav-menu a {
  display: flex;
  align-items: center;
  gap: .625rem;
  padding: .5rem .75rem;
  border-radius: var(--radius-control);
  text-decoration: none;
  color: var(--text);
  font-family: var(--font-ui);
  font-size: .9375rem;
  font-weight: 500;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}
.nav-menu a:hover { background: var(--surface-2); }
.nav-menu a[aria-current="page"] { color: var(--leaf); font-weight: 700; }

/* The Life submenu. A heading with its children indented behind a hairline,
   rather than a second flyout — a hover-opened sub-flyout is a poor target on
   a touch screen, and the whole menu is already one tap deep. */
.nav-group { margin-top: .25rem; padding-top: .25rem; border-top: 1px solid var(--border); }
.nav-group:first-child { margin-top: 0; padding-top: 0; border-top: none; }
.nav-group-label {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .5rem .75rem .25rem;
  font-size: .625rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .15em;
  color: var(--text-muted);
}
.nav-sub { list-style: none; margin-left: .75rem; padding-left: .75rem; border-left: 1px solid var(--border); }
.nav-sub a { font-size: .875rem; }
.nav-sub img { width: 20px; height: 20px; object-fit: contain; flex: 0 0 20px; }

/* Matches .nav-toggle exactly — same ghost primitive, so the two header
   controls read as one system rather than a bordered box beside plain text. */
.theme-toggle {
  background: none;
  border: none;
  border-radius: var(--radius-control);
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  cursor: pointer;
  color: var(--text-muted);
  transition: color var(--fast) var(--ease), background var(--fast) var(--ease);
}
.theme-toggle:hover { color: var(--text); background: var(--surface-2); }
.theme-toggle svg { width: 17px; height: 17px; }
/* One button, two glyphs: the one that isn't the current scheme is hidden, so
   the icon always shows what tapping it would give you. */
.theme-toggle .icon-dark { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .theme-toggle .icon-light { display: none; }
  :root:not([data-theme="light"]) .theme-toggle .icon-dark { display: block; }
}
:root[data-theme="dark"] .theme-toggle .icon-light { display: none; }
:root[data-theme="dark"] .theme-toggle .icon-dark { display: block; }
:root[data-theme="light"] .theme-toggle .icon-light { display: block; }
:root[data-theme="light"] .theme-toggle .icon-dark { display: none; }

/* ── Site footer ─────────────────────────────────────────────────────────── */

.site-footer {
  border-top: 1px solid var(--border);
  padding: 2rem var(--gutter);
  text-align: center;
  font-size: .8125rem;
  color: var(--text-muted);
  position: relative;
  z-index: 1;
}

/* ── Layout ──────────────────────────────────────────────────────────────── */

.page {
  flex: 1;
  width: 100%;
  max-width: var(--page-max);
  margin: 0 auto;
  padding: clamp(1.5rem, 4vw, 3rem) var(--gutter) 4rem;
}

.page-head { margin-bottom: 2rem; }
.page-head .display { color: var(--text); }
.page-head p { color: var(--text-muted); margin-top: .5rem; max-width: 60ch; }

.stack { display: flex; flex-direction: column; gap: 1rem; }
.row { display: flex; align-items: center; gap: .75rem; flex-wrap: wrap; }
.spacer { flex: 1; }

.grid {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
}

/* ── Leaf card — DESIGN.md §5 ────────────────────────────────────────────── */

.leaf-card {
  display: block;
  background: var(--surface);
  border-radius: var(--leaf-radius);
  box-shadow: var(--shadow);
  padding: 1.25rem 1.375rem;
  border: 1px solid var(--border);
  transition: transform var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}

/* `display` is set on the plain class above, deliberately, and not on the
   element-qualified rule below: a card that wants to be a flex row says so
   with its own class, and `a.leaf-card` would outrank that on specificity and
   silently stack the row. Class beats class on source order, which is what a
   page stylesheet loaded after this one needs. */

/* Only cards that are themselves a control get the pointer states. A card that
   merely contains buttons must not lift, or the whole surface reads as a
   target it isn't. */
a.leaf-card, button.leaf-card, .leaf-card.is-interactive {
  cursor: pointer;
  text-decoration: none;
  width: 100%;
  text-align: left;
  font: inherit;
}
a.leaf-card:hover, button.leaf-card:hover, .leaf-card.is-interactive:hover {
  transform: translateY(-1px);
  box-shadow: var(--shadow-lift);
}
a.leaf-card:active, button.leaf-card:active, .leaf-card.is-interactive:active {
  transform: scale(.98);           /* DESIGN.md §7 */
  box-shadow: var(--shadow);
}

/* ── The circle icon backdrop — DESIGN.md §5 ─────────────────────────────── */

/* The circle is light in both schemes: the brand PNGs are fixed olive ink and
   cannot recolour per scheme, so the backdrop has to be the light thing behind
   dark artwork. Dark mode takes Cream Linen rather than white — pure white is
   glare on a dark canvas. */
.icon-circle {
  --circle: 56px;
  width: var(--circle);
  height: var(--circle);
  flex: 0 0 var(--circle);
  border-radius: 50%;
  background: #FFFFFF;
  display: grid;
  place-items: center;
  overflow: hidden;
}
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .icon-circle { background: #F5F3ED; } }
:root[data-theme="dark"] .icon-circle { background: #F5F3ED; }

/* The images are pre-cropped to their opaque bounds (see scripts note in
   images/), so contain-fitting a box at 68% of the diameter puts each icon's
   *longest side* at 0.68 × circle — which is the app's rule exactly, and is
   what makes eight differently-shaped icons carry the same weight. */
.icon-circle img {
  width: 68%;
  height: 68%;
  object-fit: contain;
}

/* ── Controls ────────────────────────────────────────────────────────────── */

.btn {
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: .9375rem;
  border: 1px solid transparent;
  border-radius: var(--radius-control);
  padding: .625rem 1.125rem;
  cursor: pointer;
  background: var(--terracotta);
  color: #FFFFFF;
  transition: transform var(--fast) var(--ease), opacity var(--fast) var(--ease), background var(--fast) var(--ease);
}
.btn:hover { opacity: .9; }
.btn:active { transform: scale(.98); }
.btn[disabled] { opacity: .45; cursor: not-allowed; transform: none; }

.btn-secondary { background: transparent; color: var(--text); border-color: var(--border-strong); }
.btn-secondary:hover { background: var(--surface-2); opacity: 1; }

.btn-ghost { background: transparent; color: var(--text-muted); border-color: transparent; padding: .5rem .75rem; }
.btn-ghost:hover { color: var(--text); background: var(--surface-2); opacity: 1; }

.btn-danger { background: var(--danger); color: #FFFFFF; }

/* The list-item button at control scale: a row of icon and label carrying the
   leaf's stem point at the bottom-left, exactly as the cards do. This is the
   card anatomy shrunk to a destination button — used where a page needs a set
   of places to go rather than a stack of things to read. --tint / --ink give it
   a mini-app's identity colour; left unset it is Surface White. */
.leaf-chip {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  padding: .375rem .875rem .375rem .375rem;
  background: var(--tint, var(--surface));
  color: var(--ink, var(--text));
  border: 1px solid var(--border);
  border-radius: var(--leaf-radius-sm);   /* 12/12/12/0 — the sharp corner */
  box-shadow: var(--shadow);
  text-decoration: none;
  font-family: var(--font-ui);
  font-weight: 500;
  font-size: .875rem;
  line-height: 1.2;
  white-space: nowrap;
  transition: transform var(--fast) var(--ease), box-shadow var(--fast) var(--ease);
}
.leaf-chip:hover { transform: translateY(-1px); box-shadow: var(--shadow-lift); }
.leaf-chip:active { transform: scale(.98); box-shadow: var(--shadow); }
.leaf-chip .icon-circle { --circle: 30px; box-shadow: none; }

/* Text actions and filters — DESIGN.md §5: no chips, no pills, no borders.
   Unselected is Muted Slate; selected is bold, in the ink, with a 2px accent
   underline drawn directly beneath the label. */
.filters {
  display: flex;
  gap: 1.25rem;
  flex-wrap: wrap;
  align-items: center;
  margin-bottom: 1.25rem;
}
.filter {
  font-family: var(--font-body);
  font-size: .875rem;
  font-weight: 500;
  color: var(--text-muted);
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  padding: 0 0 3px;
  cursor: pointer;
  transition: color var(--fast) var(--ease);
}
.filter:hover { color: var(--text); }
.filter[aria-pressed="true"], .filter.is-active {
  font-weight: 700;
  color: var(--text);
  border-bottom-color: var(--accent, var(--leaf));
}

/* Text entry points — the app's [ ✎ Manage ] / [ ↕ Sort by date ] vocabulary. */
.text-action {
  font-size: .8125rem;
  font-weight: 500;
  color: var(--text-muted);
  background: none;
  border: none;
  cursor: pointer;
  padding: 0;
  transition: color var(--fast) var(--ease);
}
.text-action:hover { color: var(--text); text-decoration: underline; text-underline-offset: 3px; }

.field {
  width: 100%;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-control);
  padding: .625rem .75rem;
  font-size: .9375rem;
  transition: border-color var(--fast) var(--ease);
}
.field:focus { border-color: var(--leaf); }
textarea.field { min-height: 5rem; resize: vertical; }

.field-label {
  display: block;
  font-size: .625rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .15em;
  color: var(--text-muted);
  margin-bottom: .375rem;
}

/* Status pills. Tinted at 26%, never solid — this is state, not a control
   (DESIGN.md §6.09). */
.pill {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  font-size: .6875rem;
  font-weight: 700;
  letter-spacing: .04em;
  border-radius: var(--radius-control);
  padding: .1875rem .5rem;
  background: color-mix(in srgb, var(--pill, var(--text-muted)) 26%, transparent);
  color: var(--pill-ink, var(--text));
  white-space: nowrap;
}

/* ── The leaf-tick checkbox — DESIGN.md §6.02 ────────────────────────────── */

.leaf-check {
  width: 24px;
  height: 24px;
  flex: 0 0 24px;
  border: 2px solid var(--accent, var(--leaf));
  border-radius: 7px 7px 7px 0;   /* the stem point, at checkbox scale */
  background: transparent;
  cursor: pointer;
  display: grid;
  place-items: center;
  transition: background var(--fast) var(--ease), border-color var(--fast) var(--ease);
}
.leaf-check svg { width: 14px; height: 14px; opacity: 0; transition: opacity 150ms var(--ease); }
.leaf-check[aria-checked="true"] { background: var(--accent, var(--leaf)); }
.leaf-check[aria-checked="true"] svg { opacity: 1; stroke: var(--leaf-ink); }

/* A row on its way out: struck through, faded, then collapsed. */
.is-completing { opacity: .4; text-decoration: line-through; transition: opacity 200ms var(--ease); }

/* ── Toast — the app's actionable-confirmation vocabulary (§7) ───────────── */

.toast {
  position: fixed;
  left: 50%;
  bottom: 1.5rem;
  transform: translate(-50%, 1rem);
  background: var(--text);
  color: var(--canvas);
  padding: .75rem 1.125rem;
  border-radius: var(--radius-control);
  box-shadow: var(--shadow-sheet);
  font-size: .875rem;
  font-weight: 500;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--fast) var(--ease), transform var(--fast) var(--ease);
  z-index: 900;
  max-width: calc(100vw - 2rem);
}
.toast.show { opacity: 1; transform: translate(-50%, 0); pointer-events: auto; }

/* ── Sheets — 24px top radii, Brand Overview §5 ──────────────────────────── */

.sheet-scrim {
  position: fixed;
  inset: 0;
  background: rgba(28, 34, 23, .45);
  display: none;
  align-items: flex-end;
  justify-content: center;
  z-index: 800;
}
.sheet-scrim.open { display: flex; }

.sheet {
  background: var(--surface);
  border-radius: var(--radius-sheet) var(--radius-sheet) 0 0;
  box-shadow: var(--shadow-sheet);
  width: min(560px, 100%);
  max-height: 88vh;
  overflow-y: auto;
  padding: 1.5rem var(--gutter) 2rem;
  animation: sheet-in var(--slow) var(--ease);
}
@keyframes sheet-in { from { transform: translateY(24px); opacity: 0; } to { transform: none; opacity: 1; } }

@media (min-width: 720px) {
  .sheet-scrim { align-items: center; }
  .sheet { border-radius: var(--radius-sheet); max-height: 84vh; }
}

.sheet-head { display: flex; align-items: baseline; gap: 1rem; margin-bottom: 1.25rem; }
.sheet-head h2 { flex: 1; }

/* ── Empty & loading states ──────────────────────────────────────────────── */

.empty {
  text-align: center;
  padding: 3.5rem 1.5rem;
  color: var(--text-muted);
}
.empty p + p { margin-top: .375rem; font-size: .875rem; }

/* Vein tracing — Brand Overview §6. A leaf outline drawing itself, used where
   a spinner would otherwise go. */
.vein-spinner { width: 36px; height: 36px; margin: 0 auto; display: block; }
.vein-spinner path {
  fill: none;
  stroke: var(--leaf);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-dasharray: 60;
  animation: vein 1.6s var(--ease) infinite;
}
@keyframes vein {
  0%   { stroke-dashoffset: 60; }
  55%  { stroke-dashoffset: 0; }
  100% { stroke-dashoffset: -60; }
}

/* ── Sign-in gate ────────────────────────────────────────────────────────── */

.gate {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 3rem var(--gutter);
  position: relative;
  z-index: 1;
}
.gate[hidden] { display: none; }

.gate-card {
  width: min(380px, 100%);
  display: flex;
  flex-direction: column;
  gap: .375rem;
  padding: 2rem;
}
.gate-mark { width: 48px; height: 48px; object-fit: contain; margin-bottom: .5rem; }
.gate-card .field-label { margin-top: .75rem; }
.gate-card .btn { margin-top: 1.25rem; }
.gate-error { color: var(--danger); margin-top: .75rem; }

/* ── Mini-app page chrome ────────────────────────────────────────────────── */

/* Each mini-app sets --accent and --app-surface on .app-page; everything below
   reads those, so a page's identity colour is declared once (DESIGN.md §3). */
.app-page { --accent: var(--leaf); }

.app-head {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
  margin-bottom: 1.75rem;
  flex-wrap: wrap;
}
.app-head .icon-circle { --circle: 64px; box-shadow: var(--shadow); }
.app-head-text { flex: 1; min-width: 12rem; }
.app-head h1 { color: var(--text); }
.app-head .readout { color: var(--text-muted); font-size: .9375rem; margin-top: .25rem; }

/* Botanical Bright (design-refresh/): a mini-app's header is a filled colour
   block in its own identity tint, with the leaf corner and a white icon well
   that pops on it — the app announces itself before a word is read. Scoped to
   .app-page, so the Travel hub (.travel-app, its own header) is untouched. The
   tint is set per app on .app-page, so every mini-app gets its own colour from
   one rule. Ink is forced from --app-ink so it reads on the tint in both
   schemes. */
.app-page .app-head {
  align-items: center;
  background: var(--app-surface, var(--surface));
  color: var(--app-ink, var(--text));
  border-radius: var(--leaf-radius-lg);
  padding: 1.2rem 1.4rem;
  box-shadow: var(--shadow);
}
.app-page .app-head h1,
.app-page .app-head .readout,
.app-page .app-head .eyebrow { color: var(--app-ink, var(--text)); }
.app-page .app-head .readout { opacity: .74; }
.app-page .app-head .eyebrow { opacity: .6; }

/* A mini-app's own card takes its tint rather than Surface White. */
.app-card {
  background: var(--app-surface, var(--surface));
  color: var(--app-ink, var(--text));
  border-color: transparent;
}

/* Always 2rem above, with no :first-child reset: these headings are injected
   into their own containers, so "first child" is true of every one of them and
   the reset silently removed the gap above each section instead of only the
   first on the page. */
.section-head {
  display: flex;
  align-items: baseline;
  gap: .75rem;
  margin: 2rem 0 .75rem;
}
.section-head h2 { font-size: 1.125rem; font-family: var(--font-ui); font-weight: 700; }
.section-bar { width: 3px; height: 1.25rem; border-radius: 2px; background: var(--accent); align-self: center; }
.section-count { font-size: .8125rem; color: var(--text-muted); margin-left: auto; }

/* ── Background leaves ───────────────────────────────────────────────────── */

.leaves-bg { position: fixed; inset: 0; pointer-events: none; z-index: 0; overflow: hidden; }
.bg-leaf { position: absolute; opacity: .07; filter: saturate(.4); animation: leaf-pulse var(--duration, 8s) ease-in-out var(--delay, 0s) infinite; }
@keyframes leaf-pulse {
  0%, 100% { transform: rotate(var(--rotation, 0deg)) scale(1); }
  50%      { transform: rotate(var(--rotation, 0deg)) scale(1.07); }
}

/* ── The Life assistant chat (DEL-34) ────────────────────────────────────────
   One widget for the homepage centre and the top of the Life hub. It carries
   .leaf-card for the surface, then overrides display and padding here — both
   are single-class rules, so this block, later in the file, wins. */

.dm-chat {
  display: flex;
  flex-direction: column;
  padding: 1rem 1.125rem 1.125rem;
  text-align: left;
}

.dm-chat-head { display: flex; align-items: center; gap: .75rem; margin-bottom: .875rem; }
.dm-chat-head .icon-circle { --circle: 40px; box-shadow: none; }
.dm-chat-title { font-family: var(--font-ui); font-weight: 700; font-size: 1rem; color: var(--text); }

.dm-chat-log {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  max-height: min(46vh, 22rem);
  overflow-y: auto;
  padding: .25rem;
  scroll-behavior: smooth;
}

.dm-chat-empty { display: flex; flex-direction: column; gap: .625rem; padding: .25rem 0; }
.dm-chat-empty[hidden] { display: none; }

.dm-chat-msg {
  max-width: 88%;
  padding: .5rem .75rem;
  font-size: .9375rem;
  line-height: 1.45;
  animation: rise-msg var(--fast) var(--ease) both;
}
@keyframes rise-msg { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }

.dm-chat-msg.user {
  align-self: flex-end;
  background: var(--leaf);
  color: var(--leaf-ink);
  border-radius: 14px 14px 2px 14px;
}
.dm-chat-msg.bot {
  align-self: flex-start;
  background: var(--surface-2);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 14px 14px 14px 2px;
}
.dm-chat-msg.error { color: var(--danger); }
.dm-chat-msg p { margin: 0 0 .4rem; }
.dm-chat-msg p:last-child { margin: 0; }
.dm-chat-msg ul, .dm-chat-msg ol { margin: .25rem 0; padding-left: 1.25rem; }
.dm-chat-msg li { margin: .1rem 0; }
.dm-chat-msg strong { font-weight: 700; }
.dm-chat-msg em { font-style: italic; }

/* Richer formatting (DEL-40): headings, links, inline code and fenced blocks. */
.dm-chat-msg h3, .dm-chat-msg h4, .dm-chat-msg h5, .dm-chat-msg h6 {
  font-family: var(--font-ui);
  font-weight: 700;
  line-height: 1.25;
  margin: .5rem 0 .3rem;
}
.dm-chat-msg h3 { font-size: 1.0625rem; }
.dm-chat-msg h4 { font-size: 1rem; }
.dm-chat-msg h5, .dm-chat-msg h6 { font-size: .9375rem; }
.dm-chat-msg > :first-child { margin-top: 0; }
.dm-chat-msg a { color: var(--leaf); text-decoration: underline; }
.dm-chat-msg.user a { color: var(--leaf-ink); }
.dm-chat-msg code {
  font-family: var(--font-mono, ui-monospace, monospace);
  font-size: .85em;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 5px;
  padding: .05em .35em;
}
.dm-chat-msg pre.dm-code {
  margin: .4rem 0;
  padding: .625rem .75rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow-x: auto;
}
.dm-chat-msg pre.dm-code code {
  border: 0; background: none; padding: 0;
  font-size: .8125rem; line-height: 1.5; white-space: pre;
}

/* A mermaid block (DEL-40): the raw source until the library swaps it for an
   SVG. Diagrams can be wide, so the whole bubble is allowed to fill the panel
   and the diagram scrolls sideways inside it rather than pushing the layout. */
.dm-chat-msg.has-diagram { max-width: 100%; width: 100%; }
.dm-chat-msg pre.mermaid {
  margin: .4rem 0;
  padding: .5rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 8px;
  overflow-x: auto;
  text-align: center;
  line-height: 1.4;
}
.dm-chat-msg pre.mermaid svg { max-width: 100%; height: auto; }

/* Three-dot "thinking" bubble. */
.dm-chat-typing { display: flex; gap: .25rem; align-items: center; }
.dm-chat-typing span {
  width: .4rem; height: .4rem; border-radius: 50%;
  background: var(--text-muted);
  animation: dm-dot 1s ease-in-out infinite;
}
.dm-chat-typing span:nth-child(2) { animation-delay: .15s; }
.dm-chat-typing span:nth-child(3) { animation-delay: .3s; }
@keyframes dm-dot { 0%, 60%, 100% { opacity: .3; transform: translateY(0); } 30% { opacity: 1; transform: translateY(-3px); } }

.dm-chat-form { display: flex; gap: .5rem; margin-top: .875rem; align-items: flex-end; }
/* A textarea, not an input, so a long prompt grows the box downwards (DEL-37).
   It starts one line tall and, in the centred panel, JS grows its height to the
   content; this cap is where it stops growing and starts to scroll. resize is
   off — the drag handle would fight the automatic sizing. */
textarea.dm-chat-input {
  flex: 1;
  resize: none;
  overflow-y: auto;
  min-height: 0;                 /* beat textarea.field's 5rem — start one line */
  height: 2.75rem;               /* the control height the send button matches */
  max-height: min(40vh, 15rem);  /* past this it stops growing and scrolls */
  line-height: 1.45;
  font-family: var(--font-body);
}
/* Square, and exactly as tall as the field starts out (DEL-55). The padding
   `.btn` would otherwise give it sizes the button to its 18px glyph, leaving it
   short of the 2.75rem control height; the form aligns to flex-end, so once the
   textarea grows the button stays put at the bottom, still matching line one. */
.dm-chat-send {
  flex: 0 0 auto;
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;
  display: grid;
  place-items: center;
  border-radius: var(--radius-control);
}
.dm-chat-send svg { width: 18px; height: 18px; }

/* On the homepage the card sits centred in the hero; the hero centres text, so
   the chat re-asserts its own left alignment above. Give it a workable width. */
.hero-chat {
  width: min(560px, 100%);
  margin-top: 2rem;
  /* Above the decorative launch chips, which on desktop float on their own
     layer across the hero — the interactive card must never sit under one. */
  position: relative;
  z-index: 2;
}
.hero-chat[hidden] { display: none; }

/* ── The assistant: seed, focus mode, and the site-wide dock (DEL-35) ─────────
   One conversation, three presentations. The seed is a text box in the shape of
   the homepage unlock field; focusing it grows the chat to the centre of a
   dimmed page; from there it can be sent to a leaf in the bottom-right corner
   that rides along from page to page. Phase lives on .dm-dock[data-phase]. */

/* The seed — matched to the unlock box (DEL-31): a centred field and a
   terracotta arrow, both on the sharp stem corner. No card chrome; just the box. */
.dm-chat-seed {
  width: min(360px, 100%);
  margin-inline: auto;
  display: flex;
  gap: .5rem;
}
.dm-chat-seed[hidden] { display: none; }
.dm-chat-seed .field { text-align: center; border-radius: var(--leaf-radius-sm); }
.dm-chat-seed .field::placeholder { color: var(--text-muted); opacity: 1; }
.dm-chat-seed .dm-chat-send { border-radius: var(--leaf-radius-sm); }

/* The dock is a set of fixed pieces, not a box of its own — a scrim, a corner
   leaf, and the panel — each positioned in its own right, so the panel can be
   centred or cornered without moving the others. */
.dm-dock[hidden] { display: none; }

.dm-chat-scrim {
  position: fixed;
  inset: 0;
  background: rgba(28, 34, 23, .45);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--slow) var(--ease);
  z-index: 800;
}
.dm-dock[data-phase="center"] .dm-chat-scrim { opacity: 1; pointer-events: auto; }

/* The leaf launcher — the app's icon backdrop as a floating button. */
.dm-dock-leaf {
  position: fixed;
  right: clamp(1rem, 3vw, 2rem);
  bottom: clamp(1rem, 3vw, 2rem);
  z-index: 850;
  display: none;
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  animation: dm-leaf-in var(--slow) var(--ease);
  transition: transform var(--fast) var(--ease);
}
.dm-dock[data-phase="min"] .dm-dock-leaf { display: block; }
.dm-dock-leaf .icon-circle { --circle: 56px; box-shadow: var(--shadow-lift); }
.dm-dock-leaf:hover { transform: translateY(-2px); }
.dm-dock-leaf:active { transform: scale(.96); }
@keyframes dm-leaf-in { from { opacity: 0; transform: scale(.8); } to { opacity: 1; transform: none; } }

/* The panel — the leaf-card chat, shown cornered or centred. The two-class
   selector out-ranks .dm-chat's own display, so it is hidden until phased. */
.dm-dock [data-panel] { position: fixed; z-index: 900; display: none; overflow: hidden; }
.dm-dock[data-phase="docked"] [data-panel],
.dm-dock[data-phase="center"] [data-panel] { display: flex; }

.dm-dock[data-phase="docked"] [data-panel] {
  right: clamp(1rem, 3vw, 2rem);
  bottom: clamp(1rem, 3vw, 2rem);
  width: min(380px, calc(100vw - 2rem));
  max-height: min(72vh, 34rem);
  transform-origin: bottom right;
  animation: dm-dock-in var(--slow) var(--ease);
}
@keyframes dm-dock-in {
  from { opacity: .3; transform: translateY(10px) scale(.92); }
  to   { opacity: 1; transform: none; }
}

.dm-dock[data-phase="center"] [data-panel] {
  left: 50%;
  top: 50%;
  width: min(560px, calc(100vw - 2rem));
  max-height: 88vh;
  transform: translate(-50%, -50%);
  animation: dm-chat-open var(--slow) var(--ease);
}
@keyframes dm-chat-open {
  from { opacity: .3; transform: translate(-50%, -50%) scale(.92); }
  to   { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}

/* Head controls — the move/close affordances, each shown only where it means
   something: expand-to-centre while docked, dock-to-corner while centred, close
   in both. */
.dm-chat-controls { display: flex; gap: .25rem; margin-left: auto; align-self: flex-start; }
.dm-chat-ctl {
  width: 30px;
  height: 30px;
  display: grid;
  place-items: center;
  background: none;
  border: 1px solid var(--border);
  border-radius: var(--radius-control);
  color: var(--text-muted);
  cursor: pointer;
  transition: color var(--fast) var(--ease), border-color var(--fast) var(--ease);
}
.dm-chat-ctl:hover { color: var(--text); border-color: var(--border-strong); }
.dm-chat-ctl:active { transform: scale(.96); }
.dm-chat-ctl svg { width: 15px; height: 15px; }
[data-to-center], [data-to-dock] { display: none; }
.dm-dock[data-phase="docked"] [data-to-center] { display: grid; }
.dm-dock[data-phase="center"] [data-to-dock] { display: grid; }

body.dm-chat-locked { overflow: hidden; }

/* ── Motion preference ───────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}
