/* ══════════════════════════════════════════════════════════════
   TRIPDECK — styles
   §1 tokens are transcribed VERBATIM from SPEC-UX.md; the designer
   owns them. Everything below §1 implements the §3 class inventory,
   §2 card anatomy, §4 interaction states, §5 flows and §6 chrome.
   Mobile-first: the phone is the default, the board layers on at
   ≥1024px (where app.js routes to it).
══════════════════════════════════════════════════════════════ */

:root {
  /* ===== SURFACES (light — paper-warm) ===== */
  --bg:            #FBF6EE;   /* app background — warm sand */
  --surface:       #FFFFFF;   /* cards, sheets, popovers */
  --surface-2:     #F3EADC;   /* sunken shelf rail */
  --surface-3:     #ECE0CE;   /* slot-cell inset */
  --scrim:         rgba(43,32,24,.44);

  /* ===== INK ===== */
  --text:          #2B2018;
  --text-muted:    #6E6157;
  --text-faint:    #94867A;
  --text-on-accent:#FFFFFF;

  /* ===== LINES ===== */
  --border:        #E7DCCB;
  --border-strong: #D8C9B2;
  --hairline:      #EFE7DA;

  /* ===== BRAND (sunset coral) ===== */
  --primary:       #C64A28;
  --primary-hover: #B23F20;
  --primary-press: #9E3819;
  --primary-bright:#E8663C;
  --primary-weak:  #FBE7DE;
  --primary-weak-bd:#F3C9B8;
  --primary-ink:   #FFFFFF;

  /* ===== FEEDBACK ===== */
  --focus:         #0B6BCB;
  --danger:        #C1362B;   --danger-weak:#FBE4E1;
  --success:       #2E7D4F;
  --warn:          #B5711A;

  /* ===== MEMBER IDENTITY ===== */
  --m-isabelle:    #C43E6D;   /* berry   */
  --m-prem:        #3B6FE0;   /* cobalt  */
  --m-kai:         #28A05F;   /* green   */
  --m-neena:       #9B51E0;   /* violet  */
  --m-marco:       #BE8A2E;   /* concierge brass — always attributed */
  --m-marco-ink:   #8A6114;   /* brass for TEXT: 5.5:1 on --surface (the
                                 6px dot and the toast bar keep --m-marco,
                                 which is only 3.1:1 and fails as type) */
  --m-table:       #5B6B79;

  /* ===== CARD-TYPE ACCENTS (structural, muted) ===== */
  --type-activity: #D9662E;   /* 🎡 */
  --type-food:     #C6413E;   /* 🍜 */
  --type-stay:     #7A4F9E;   /* 🏨 */
  --type-transport:#3D6E9E;   /* 🚆 */
  --type-note:     #93826E;   /* 📝 */
  --type-question: #2C8C8C;   /* ❓ */
  --type-unfiled:  #B5A692;   /* inbox, not yet filed */

  /* ===== TYPE SCALE ===== */
  --fs-2xs:.6875rem; --fs-xs:.75rem; --fs-sm:.875rem; --fs-base:1rem;
  --fs-md:1.125rem; --fs-lg:1.375rem; --fs-xl:1.75rem; --fs-2xl:2.25rem;
  --lh-tight:1.15; --lh-body:1.45;
  --fw-reg:400; --fw-med:550; --fw-semi:650; --fw-bold:750;
  --font:-apple-system,BlinkMacSystemFont,"Segoe UI",system-ui,sans-serif;

  /* ===== SPACING / TAP ===== */
  --sp-1:.25rem; --sp-2:.5rem; --sp-3:.75rem; --sp-4:1rem;
  --sp-5:1.5rem; --sp-6:2rem; --sp-7:3rem; --sp-8:4rem;
  --tap:44px;

  /* ===== RADII ===== */
  --r-sm:6px; --r-md:10px; --r-lg:14px; --r-xl:20px; --r-pill:999px;

  /* ===== SHADOWS (warm-tinted) ===== */
  --shadow-1:0 1px 2px rgba(67,44,24,.08),0 1px 1px rgba(67,44,24,.06);
  --shadow-2:0 4px 10px rgba(67,44,24,.12),0 1px 3px rgba(67,44,24,.10);
  --shadow-3:0 12px 28px rgba(67,44,24,.22),0 4px 8px rgba(67,44,24,.16);
  --shadow-sheet:0 -8px 30px rgba(43,32,24,.18);

  /* ===== MOTION ===== */
  --dur-1:120ms; --dur-2:180ms; --dur-3:240ms; --dur-4:320ms;
  --ease-out:cubic-bezier(.22,1,.36,1);
  --ease-in-out:cubic-bezier(.65,0,.35,1);
  --ease-spring:cubic-bezier(.34,1.56,.64,1);

  /* ===== BOARD METRICS ===== */
  /* gutter 72 (spec said 64): sentence-case "Afternoon" at --fs-xs measures
     ~66px, and 64 forced the label down to 11px. 8px buys the spec's size. */
  --shelf-w:320px; --shelf-w-collapsed:56px; --gutter-w:72px;
  --daycol-min:240px; --daycol-max:300px; --dayhead-h:56px; --slot-min-h:112px;
  --z-ghost:9999; --z-toast:9000; --z-sheet:8000; --z-scrim:7900; --z-sticky:50;
}

/* ===== PROJECTOR: dark, high-contrast, couch-distance ===== */
body.projector {
  --bg:#14110D; --surface:#221C15; --surface-2:#1B1610; --surface-3:#2A2219;
  --scrim:rgba(0,0,0,.62);
  --text:#FBF3E6; --text-muted:#C9BBA8; --text-faint:#9C8E7C; --text-on-accent:#14110D;
  --border:#3A3025; --border-strong:#4C4030; --hairline:#2A2219;

  --primary:#F0764A; --primary-hover:#F58A5F; --primary-press:#D9603A;
  --primary-bright:#FF8B5E; --primary-weak:#3A2418; --primary-weak-bd:#5A3624;
  --primary-ink:#201810; --focus:#7FB2FF;

  /* The feedback trio has to flip too — the light-theme greens and ambers
     land at 3.2–3.8:1 on these darks, which is a fail for a pill you're
     meant to read from the couch. */
  --danger:#F0837A; --danger-weak:#3A1D1A;
  --success:#63C98D;
  --warn:#E5A94F;

  --m-isabelle:#F26A96; --m-prem:#6E9BFF; --m-kai:#4FD08A; --m-neena:#C08BF0;
  --m-marco:#E8B44E; --m-marco-ink:#E8B44E; --m-table:#93A7B5;

  --type-activity:#F1854B; --type-food:#EE6B66; --type-stay:#B588E0;
  --type-transport:#6FA6D8; --type-note:#C4B199; --type-question:#4FBEBE;
  --type-unfiled:#8B7D69;

  /* scale bumped ~1.25–1.35× for legibility from the couch */
  --fs-2xs:.8125rem; --fs-xs:.9375rem; --fs-sm:1.0625rem; --fs-base:1.1875rem;
  --fs-md:1.4375rem; --fs-lg:1.75rem; --fs-xl:2.25rem; --fs-2xl:3rem;

  /* gutter 112 (not 88): the slot labels are what orient the whole wall, so
     they get --fs-xs (15px here) rather than 13px, and "Afternoon" at 15px
     needs ~82px of the 88 — no slack at all. The timeline scrolls anyway. */
  --shelf-w:360px; --gutter-w:112px; --daycol-min:280px; --daycol-max:360px;
  --dayhead-h:72px; --slot-min-h:132px;

  /* on dark, lift reads via glow + rim, not soft shadow */
  --shadow-1:0 0 0 1px rgba(255,255,255,.05);
  --shadow-2:0 6px 16px rgba(0,0,0,.5),0 0 0 1px rgba(255,255,255,.06);
  --shadow-3:0 18px 40px rgba(0,0,0,.6),0 0 0 1px rgba(255,255,255,.10);
}

/* ===== REDUCED MOTION POLICY ===== */
@media (prefers-reduced-motion: reduce) {
  :root { --dur-1:1ms; --dur-2:1ms; --dur-3:1ms; --dur-4:1ms; --ease-spring:var(--ease-out); }
  *,*::before,*::after {
    animation-duration:.001ms!important; animation-iteration-count:1!important;
    transition-duration:.001ms!important; scroll-behavior:auto!important;
  }
  /* Keep: opacity cross-fades. Drop: transforms, tilt, scale, spring overshoot.
     Drag ghost = no rotate/scale (opacity only). Autoscroll stays (functional)
     but caps at 10px/frame. Card-landing = 120ms fade-in, no bounce. */
}

/* ══════════════════ BASE ══════════════════ */
*, *::before, *::after { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0;
  font-family: var(--font);
  font-size: var(--fs-base);
  line-height: var(--lh-body);
  color: var(--text);
  background: var(--bg);
  -webkit-text-size-adjust: 100%;
  overscroll-behavior-y: none;
}
h1, h2, h3, p { margin: 0; }
button, input, select, textarea { font: inherit; color: inherit; }
/* Inputs pinned to 16px to defeat iOS focus-zoom (§1). */
input, select, textarea { font-size: var(--fs-base); }
:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; border-radius: var(--r-sm); }
.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;
}
.scrim { position: fixed; inset: 0; background: var(--scrim); z-index: var(--z-scrim); }

.app { display: flex; flex-direction: column; min-height: 100dvh; }
.app--pocket { padding-bottom: calc(56px + env(safe-area-inset-bottom)); }
.boot {
  display: flex; flex-direction: column; gap: var(--sp-4);
  align-items: center; justify-content: center; min-height: 100dvh;
  color: var(--text-muted); padding: var(--sp-5); text-align: center;
}
.boot--error { color: var(--text); }

/* ══════════════════ SHARED ATOMS ══════════════════ */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  min-height: var(--tap); padding: 0 var(--sp-4);
  border: 1px solid var(--border-strong); border-radius: var(--r-md);
  background: var(--surface); color: var(--text);
  font-weight: var(--fw-med); cursor: pointer;
  transition: background var(--dur-1) var(--ease-out), border-color var(--dur-1) var(--ease-out);
}
.btn:hover { background: var(--surface-2); }
.btn:disabled { opacity: .45; cursor: not-allowed; }
.btn--primary {
  background: var(--primary); border-color: var(--primary);
  color: var(--primary-ink); font-weight: var(--fw-semi);
}
.btn--primary:hover { background: var(--primary-hover); border-color: var(--primary-hover); }
.btn--primary:active { background: var(--primary-press); }
.btn--ghost { background: transparent; border-color: transparent; color: var(--text-muted); }
.btn--ghost:hover { background: var(--surface-2); color: var(--text); }
.btn--icon {
  min-height: var(--tap); min-width: var(--tap); padding: 0;
  background: transparent; border-color: transparent; color: var(--text-muted);
  font-size: var(--fs-md); line-height: 1;
}
.btn--icon:hover { background: var(--surface-2); color: var(--text); }

.chip {
  display: inline-flex; align-items: center; gap: var(--sp-1);
  padding: var(--sp-1) var(--sp-3); border: 1px solid var(--border);
  border-radius: var(--r-pill); background: var(--surface);
  font-size: var(--fs-sm); color: var(--text-muted);
}
/* A chip that DOES something is a tap target (the detail's type selector and
   the wizard's "who's coming" are both kid-facing); a chip that merely
   labels something stays compact and isn't clickable-looking. */
button.chip { min-height: var(--tap); padding-inline: var(--sp-4); cursor: pointer; }
.chip--on { background: var(--primary-weak); border-color: var(--primary-weak-bd); color: var(--text); font-weight: var(--fw-med); }
/* Member chips carry --mc (their identity colour) inline. --text-on-accent
   flips white→near-black on the projector, so the label reads either way. */
.chip--member { border-color: color-mix(in srgb, var(--mc) 45%, var(--border)); }
/* Selected member chips wear their colour as a tint + ring rather than a
   solid fill: the light-theme member hues are mid-tone, and white 14px type
   on them lands at 3.2–4.3:1 (Kai's green is the worst). Tint + --text keeps
   "that's my colour" and reads at 15:1 in both themes. */
.chip--member.chip--on {
  background: color-mix(in srgb, var(--mc) 20%, var(--surface));
  border-color: var(--mc); box-shadow: inset 0 0 0 1px var(--mc);
  color: var(--text); font-weight: var(--fw-semi);
}
.pill {
  display: inline-flex; align-items: center; padding: 2px var(--sp-3);
  border-radius: var(--r-pill); font-size: var(--fs-xs); font-weight: var(--fw-med);
  background: var(--surface-2); color: var(--text-muted);
}
/* Tinted pills: the ink is the hue pulled 35% toward --text so 12px type on
   a 16% wash still clears AA (the flat hue was 3.7:1). Works in both themes
   because --text itself flips. */
.pill--warn {
  background: color-mix(in srgb, var(--warn) 16%, var(--surface));
  color: color-mix(in srgb, var(--warn) 65%, var(--text));
}
.pill--ok {
  background: color-mix(in srgb, var(--success) 16%, var(--surface));
  color: color-mix(in srgb, var(--success) 65%, var(--text));
}
.count-badge {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 20px; height: 20px; padding: 0 6px; border-radius: var(--r-pill);
  background: var(--surface-2); color: var(--text-muted);
  font-size: var(--fs-xs); font-weight: var(--fw-med); font-variant-numeric: tabular-nums;
}

.avatar {
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--r-pill); color: #fff; font-weight: var(--fw-semi);
  width: 32px; height: 32px; font-size: var(--fs-sm);
}
.avatar--sm { width: 24px; height: 24px; font-size: var(--fs-xs); }
.avatar--md { width: 32px; height: 32px; }
.avatar--lg { width: 48px; height: 48px; font-size: var(--fs-md); }
.avatar--isabelle { background: var(--m-isabelle); }
.avatar--prem     { background: var(--m-prem); }
.avatar--kai      { background: var(--m-kai); }
.avatar--neena    { background: var(--m-neena); }
.avatar--marco    { background: var(--m-marco); }
.avatar--table    { background: var(--m-table); }

/* ══════════════════ TOASTS (§4) ══════════════════ */
.toast-host {
  position: fixed; z-index: var(--z-toast); pointer-events: none;
  left: 0; right: 0; bottom: calc(56px + env(safe-area-inset-bottom) + var(--sp-3));
  display: flex; flex-direction: column; align-items: center; gap: var(--sp-2);
  padding: 0 var(--sp-4);
}
/* Board / projector: centre-top, larger — a wall toast at ankle height is
   a toast nobody reads. */
body.is-board .toast-host, body.projector .toast-host { top: var(--sp-5); bottom: auto; }
.toast {
  pointer-events: auto; display: flex; align-items: center; gap: var(--sp-3);
  max-width: min(560px, 100%); padding: var(--sp-3) var(--sp-4);
  border-radius: var(--r-md); background: var(--surface); color: var(--text);
  box-shadow: var(--shadow-2); border: 1px solid var(--border);
  opacity: 0; transform: translateY(12px);
  transition: opacity var(--dur-2) var(--ease-out), transform var(--dur-2) var(--ease-out);
}
body.is-board .toast, body.projector .toast { transform: translateY(-12px); font-size: var(--fs-md); }
.toast--in { opacity: 1; transform: translateY(0); }
.toast--out { opacity: 0; }
.toast--revert { border-left: 4px solid var(--m-marco); }
.toast__msg { flex: 1; }
.toast__action {
  border: 0; background: transparent; color: var(--primary);
  font-weight: var(--fw-semi); cursor: pointer; padding: var(--sp-1) var(--sp-2);
  min-height: var(--tap);
}

/* ══════════════════ TOPBAR (§3) ══════════════════ */
.topbar {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  padding-top: calc(var(--sp-2) + env(safe-area-inset-top));
  border-bottom: 1px solid var(--hairline); background: var(--bg);
  position: sticky; top: 0; z-index: calc(var(--z-sticky) + 10);
}
.topbar__title {
  flex: 1; font-size: var(--fs-md); font-weight: var(--fw-semi);
  line-height: var(--lh-tight);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
body.projector .topbar__title { font-size: var(--fs-xl); }
.topbar__actions { display: flex; align-items: center; gap: var(--sp-1); }

/* ══════════════════ CARD (§2) ══════════════════ */
/* touch-action:none on .card ONLY — putting it on a container kills
   scrolling for the whole board (the iOS trap in CLAUDE.md). */
.card {
  touch-action: none;
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  cursor: grab;
  --accent: var(--type-note);
}
.card:active { cursor: grabbing; }
.card--type-activity  { --accent: var(--type-activity); }
.card--type-food      { --accent: var(--type-food); }
.card--type-stay      { --accent: var(--type-stay); }
.card--type-transport { --accent: var(--type-transport); }
.card--type-note      { --accent: var(--type-note); }
.card--type-question  { --accent: var(--type-question); }
.card--unfiled        { --accent: var(--type-unfiled); }
.card--ghost { border-style: dashed; opacity: .82; }

/* ── (a) board chip ── */
/* min-height --tap: board mode starts at 1024px, which is an iPad in
   landscape — chips are a FINGER target there, not just a mouse one. A
   1-line chip came out 40px. align-content centres the short ones in the
   44px so they don't sit with dead space under them. */
.card--chip {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: start; align-content: center;
  gap: var(--sp-1) var(--sp-2);
  min-height: var(--tap);
  padding: var(--sp-2) var(--sp-3) var(--sp-2) calc(var(--sp-3) + 3px);
  box-shadow: var(--shadow-1);
  transition: box-shadow var(--dur-1) var(--ease-out), transform var(--dur-1) var(--ease-out);
}
.card__accent {
  position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  background: var(--accent);
  border-radius: var(--r-md) 0 0 var(--r-md);
}
/* 1.125em, not a hard 18px: that resolves to exactly the spec's 18px on the
   light theme and scales with the chip on the projector (21px), instead of
   the type growing 1.2× around a fixed-size glyph. */
.card--chip .card__emoji { font-size: 1.125em; line-height: 1.2; grid-row: 1; }
.card--chip .card__title {
  grid-row: 1; grid-column: 2;
  font-size: var(--fs-base); font-weight: var(--fw-med); line-height: var(--lh-tight);
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
}
/* Spec §2a said 1 line on the projector, for a tidy uniform grid. On the wall
   that turned almost every real title into "Fushimi Inari shrine a…" — a card
   you can't read is worse than a ragged row. Two lines, and the row grows. */
body.projector .card--chip .card__title { -webkit-line-clamp: 2; }
.card__meta {
  grid-column: 2; display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-sm); color: var(--text-muted);
}
.card__glyphs { grid-column: 2; display: flex; gap: var(--sp-1); font-size: var(--fs-xs); }
.card__badge--book { color: var(--warn); }
.card__marco {
  position: absolute; top: 6px; right: 6px;
  width: 6px; height: 6px; border-radius: 50%; background: var(--m-marco);
}
/* Collapse ladder (§2a): meta drops, then glyphs; the floor is emoji +
   1-line title + Marco dot. Never the title, never the accent. */
.slot, .shelf__list { container-type: inline-size; }
@container (max-width: 210px) { .card--chip .card__meta { display: none; } }
@container (max-width: 160px) {
  .card--chip .card__glyphs { display: none; }
  .card--chip .card__title { -webkit-line-clamp: 1; }
}

/* ── (b) phone list row ── */
.card--row {
  display: flex; align-items: center; gap: var(--sp-3);
  min-height: 64px; width: 100%;
  padding: var(--sp-2) var(--sp-3);
  border-radius: 0; border-width: 0 0 1px 0; border-color: var(--hairline);
  cursor: pointer;
}
.card--row:first-child { border-top-left-radius: var(--r-md); border-top-right-radius: var(--r-md); }
.card--row:last-child { border-bottom: 0; border-bottom-left-radius: var(--r-md); border-bottom-right-radius: var(--r-md); }
.card__tile {
  flex: 0 0 40px; width: 40px; height: 40px;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--r-md); font-size: 20px;
  background: color-mix(in srgb, var(--accent) 12%, var(--surface));
}
.card__body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.card--row .card__title {
  font-size: var(--fs-base); font-weight: var(--fw-med); line-height: var(--lh-tight);
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden;
}
.card--row .card__meta { font-size: var(--fs-sm); color: var(--text-muted); }
.card__meta-dot { color: var(--text-faint); }
.card__marco-tag { font-size: var(--fs-2xs); color: var(--m-marco-ink); font-weight: var(--fw-med); }
.card__chevron { color: var(--text-faint); font-size: var(--fs-md); }
/* The unfiled "·" is a deliberate absence (§1) — but at 18px in a 40px tile
   it read as a rendering failure. Sized and tinted so it reads as a
   placeholder waiting for Marco. */
.card--unfiled .card__emoji { color: var(--type-unfiled); font-size: 26px; line-height: .7; }

/* ── (§4) drag states ── */
.card--lifting { transform: scale(1.03); box-shadow: var(--shadow-2); transition: transform var(--dur-2) var(--ease-out); }
.card--dragging {
  opacity: .35;
  min-height: var(--drag-h, auto);   /* same-height placeholder: nothing collapses */
}
.card__ghost-clone {
  position: fixed; left: 0; top: 0; z-index: var(--z-ghost);
  pointer-events: none; opacity: .96; box-shadow: var(--shadow-3);
  transform-origin: top left; will-change: transform;
}
.card__ghost-clone--invalid { opacity: .8; }
/* The ghost is pointer-events:none, so a `cursor` on IT can never win — the
   cursor over dead space has to come from the element actually under the
   pointer. The ghost lives on <body>, so :has() reads its invalid state. */
body.is-dragging:has(.card__ghost-clone--invalid),
body.is-dragging:has(.card__ghost-clone--invalid) .card { cursor: not-allowed; }
.card--landing { animation: card-settle 160ms var(--ease-out); }
@keyframes card-settle { from { transform: scale(1.05); } to { transform: scale(1); } }
@media (prefers-reduced-motion: reduce) {
  .card--landing { animation: card-fade 120ms linear; }
  @keyframes card-fade { from { opacity: .4; } to { opacity: 1; } }
}
.drop-indicator {
  height: 3px; margin: 6px 0; border-radius: var(--r-pill);
  background: var(--primary);
  animation: indicator-in var(--dur-1) var(--ease-out);
}
@keyframes indicator-in { from { opacity: 0; } to { opacity: 1; } }
body.is-dragging { cursor: grabbing; user-select: none; }

/* ══════════════════ BOARD (§3) ══════════════════ */
.board { display: flex; flex: 1; min-height: 0; }
.board__shelf {
  flex: 0 0 auto; width: var(--shelf-w); min-width: 0;
  background: var(--surface-2); border-right: 1px solid var(--border);
  overflow-y: auto; overscroll-behavior: contain;
}
.board__shelf:has(.shelf--collapsed) { width: var(--shelf-w-collapsed); }
/* The board's right-hand column: the first-run banner strip (while it's
   there) stacked ABOVE the day grid. .board itself is a row — the shelf sits
   beside this — so the stacking needs its own column context, and the
   min-*:0 pair is what lets the timeline inside actually scroll. */
.board__stage { flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column; }

/* ── shelf rail ── */
.shelf { display: flex; flex-direction: column; gap: var(--sp-1); padding: var(--sp-3); }
.shelf__head { display: flex; align-items: center; gap: var(--sp-2); }
.shelf__title { flex: 1; font-size: var(--fs-sm); font-weight: var(--fw-semi); color: var(--text-muted); text-transform: uppercase; letter-spacing: .04em; }
.shelf--collapsed { align-items: center; padding: var(--sp-2); gap: var(--sp-3); }
.shelf--collapsed .shelf__stub {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  width: 40px; padding: var(--sp-2) 0; border-radius: var(--r-md);
  background: var(--surface); border: 1px solid var(--border);
}
.shelf__expand { min-height: var(--tap); min-width: 40px; border: 0; background: transparent; color: var(--text-muted); cursor: pointer; }

.shelf__section { display: flex; flex-direction: column; }
.shelf__section-head {
  display: flex; align-items: center; gap: var(--sp-2);
  min-height: var(--tap); padding: var(--sp-1) var(--sp-1);
  cursor: pointer; user-select: none;
}
.shelf__caret { color: var(--text-faint); transition: transform var(--dur-1) var(--ease-out); }
.shelf__caret--open { transform: rotate(90deg); }
.shelf__section-title { flex: 1; font-size: var(--fs-base); font-weight: var(--fw-semi); }
body.projector .shelf__section-title { font-size: var(--fs-lg); }
/* Was unstyled entirely, so section counts rendered at inherited 16px and
   competed with their own titles. §1 type map: shelf counts = --fs-xs. */
.shelf__count {
  font-size: var(--fs-xs); font-weight: var(--fw-med); color: var(--text-muted);
  font-variant-numeric: tabular-nums; min-width: 1.25em; text-align: right;
}
.shelf__list {
  display: flex; flex-direction: column; gap: var(--sp-2);
  padding: var(--sp-1) 0 var(--sp-3);
  min-height: 44px; border-radius: var(--r-md);
}
.shelf__list--closed { display: none; }
/* Empty states are INSTRUCTIONS, not decoration — they carry the only copy
   on a blank board — so they run at --text-muted (5.0:1 on the shelf rail),
   not --text-faint (2.96:1, which §1 reserves for non-essential glyphs). */
.shelf__empty {
  display: flex; flex-direction: column; gap: 2px;
  padding: var(--sp-3); font-size: var(--fs-sm); color: var(--text-muted);
}
.shelf__empty-sub { color: var(--text-faint); }
.shelf__empty--all { border: 1px dashed var(--border-strong); border-radius: var(--r-md); }
.shelf__quickadd, .shelf__themeadd { display: flex; gap: var(--sp-2); padding: var(--sp-2) 0; }
.shelf__quickadd .add__input, .shelf__themeadd .add__input { flex: 1; min-width: 0; }
.shelf__theme-new { align-self: flex-start; }

/* ── the grid: ONE grid so the slot bands line up across every day ── */
.board__timeline {
  flex: 1; min-width: 0; overflow: auto; overscroll-behavior: contain;
  display: grid;
  grid-template-columns: var(--gutter-w) repeat(var(--daycount, 1), minmax(var(--daycol-min), var(--daycol-max)));
  /* Row sizing is load-bearing for §3's "a row grows to the fullest day".
     minmax(--slot-min-h, auto) — and plain `auto` — both size the track from
     the cell's MIN-content, which for these flex-column cells collapses; the
     content only raised the growth limit, which a definite-height timeline
     then funded out of leftover space and ran dry. Measured: a 6-card
     afternoon needed 526px, got 332px, and spilled its last two cards
     straight through the Evening and Night bands (covering their drop
     targets). minmax(max-content, 1fr) sizes the base from the real stack
     and lets 1fr hand out any SPARE height, so four sparse rows still fill a
     tall wall and a crowded one scrolls the timeline instead of overlapping.
     The --slot-min-h floor lives on .slot itself now. */
  grid-template-rows: var(--dayhead-h) repeat(4, minmax(max-content, 1fr));
  justify-content: start;
}
.board__timeline--nodays { display: grid; place-items: center; padding: var(--sp-6); }
/* display:contents lets the semantic header row keep its class while its
   children participate in the one grid above. */
.board__dayhead-row { display: contents; }
/* z-order, bottom → top: cards · sticky gutter · sticky day headers · corner.
   The gutter must sit UNDER the header row, or a slot label scrolling up
   paints over the dates (visible as soon as a crowded slot makes the
   timeline scroll vertically at all). */
.board__gutter {
  position: sticky; left: 0; z-index: var(--z-sticky);
  background: var(--bg); border-right: 1px solid var(--hairline);
  display: flex; align-items: flex-start; justify-content: center; padding: var(--sp-2) 0;
  overflow: hidden;   /* the gutter is a fixed --gutter-w — never bleed into the cells */
}
.board__gutter--corner { top: 0; z-index: calc(var(--z-sticky) + 2); border-bottom: 1px solid var(--hairline); }

/* Sentence case, not uppercase: "AFTERNOON" at --fs-xs is wider than any
   sane gutter. But the SIZE stays --fs-xs (12px / 15px projector) per the
   §1 type map — these four words are the board's vertical legend and 11px
   is not couch-legible. The gutter was widened to 72/112px to fit. */
.slotgutter__label {
  font-size: var(--fs-xs); font-weight: var(--fw-semi);
  color: var(--text-muted);
  padding: var(--sp-1) var(--sp-1); border-radius: var(--r-sm);
  text-align: center; width: 100%;
  white-space: nowrap;
}
/* soft per-slot tint band, morning warm-gold → night indigo */
.slot-label--morning   { background: color-mix(in srgb, #E9A23B 18%, transparent); }
.slot-label--afternoon { background: color-mix(in srgb, #E8663C 14%, transparent); }
.slot-label--evening   { background: color-mix(in srgb, #8A5BB5 16%, transparent); }
.slot-label--night     { background: color-mix(in srgb, #3D4C9E 18%, transparent); }

.dayhead {
  position: sticky; top: 0; z-index: calc(var(--z-sticky) + 1);
  display: grid; grid-template-columns: auto 1fr auto; align-items: center;
  gap: var(--sp-1) var(--sp-2);
  padding: var(--sp-2) var(--sp-3);
  background: var(--bg); border-bottom: 1px solid var(--hairline); border-right: 1px solid var(--hairline);
}
.dayhead__index { grid-column: 1; font-size: var(--fs-sm); font-weight: var(--fw-bold); color: var(--primary); }
.dayhead__weekday { grid-column: 2; font-size: var(--fs-sm); color: var(--text-muted); }
.dayhead__date { grid-column: 2; grid-row: 2; font-size: var(--fs-base); font-weight: var(--fw-semi); }
body.projector .dayhead__date { font-size: var(--fs-md); }
.dayhead__count {
  grid-column: 3; grid-row: 1 / span 2;
  font-size: var(--fs-xs); color: var(--text-muted);
  min-width: 20px; height: 20px; border-radius: var(--r-pill);
  background: var(--surface-2); display: inline-flex; align-items: center; justify-content: center;
}

.slot {
  padding: var(--sp-2);
  min-height: var(--slot-min-h);   /* the band floor, now that rows are `auto` */
  display: flex; flex-direction: column; gap: var(--sp-2);
  border-right: 1px solid var(--hairline); border-bottom: 1px solid var(--hairline);
  position: relative;
  transition: background var(--dur-1) var(--ease-out), box-shadow var(--dur-1) var(--ease-out);
}
/* flex: 1 0 auto, not flex: 1 — a 0% basis lets the browser under-report this
   box's contribution to the slot's intrinsic height, which is the other half
   of why a crowded band didn't grow. */
.slot__cards { display: flex; flex-direction: column; gap: var(--sp-2); flex: 1 0 auto; }
.slot--morning   { background: color-mix(in srgb, #E9A23B 5%, transparent); }
.slot--afternoon { background: color-mix(in srgb, #E8663C 4%, transparent); }
.slot--evening   { background: color-mix(in srgb, #8A5BB5 5%, transparent); }
.slot--night     { background: color-mix(in srgb, #3D4C9E 6%, transparent); }
.slot--empty .slot__cards {
  border: 1px dashed var(--border); border-radius: var(--r-md); min-height: 56px;
}
/* Every legal target lights up for the WHOLE drag — no hover-only
   affordances on a wall nobody is mousing over. */
.slot--dropok { background: color-mix(in srgb, var(--primary-weak) 55%, transparent); }
.slot--dropactive {
  background: var(--primary-weak);
  box-shadow: inset 0 0 0 2px var(--primary);
  border-radius: var(--r-md);
}
.slot--dropactive .slot__cards { border-style: none; }
.slot__drophint {
  position: absolute; inset: 0; display: none;
  align-items: center; justify-content: center;
  color: var(--primary); font-weight: var(--fw-semi); font-size: var(--fs-sm);
  pointer-events: none;
}
.slot--dropactive.slot--empty .slot__drophint { display: flex; animation: indicator-in var(--dur-1) var(--ease-out); }
.slot__empty-msg { font-size: var(--fs-sm); color: var(--text-muted); padding: var(--sp-2); }

/* ══════════════════ DETAIL (§2c) ══════════════════ */
.detail {
  background: var(--surface); color: var(--text);
  display: flex; flex-direction: column; gap: var(--sp-3);
}
.detail--popover {
  position: fixed; width: 360px; max-height: 70vh; overflow-y: auto;
  z-index: var(--z-sheet); padding: var(--sp-4);
  border: 1px solid var(--border); border-radius: var(--r-lg); box-shadow: var(--shadow-3);
}
.detail__close { position: absolute; top: var(--sp-1); right: var(--sp-1); }
.detail__scrim { position: fixed; inset: 0; background: var(--scrim); z-index: var(--z-scrim); }
.detail--sheet {
  position: fixed; left: 0; right: 0; bottom: 0;
  max-height: 88vh; overflow-y: auto; z-index: var(--z-sheet);
  padding: var(--sp-3) var(--sp-4) calc(var(--sp-5) + env(safe-area-inset-bottom));
  border-radius: var(--r-xl) var(--r-xl) 0 0; box-shadow: var(--shadow-sheet);
  animation: sheet-in var(--dur-3) var(--ease-out);
  transition: transform var(--dur-2) var(--ease-out);
}
@keyframes sheet-in { from { transform: translateY(100%); } to { transform: translateY(0); } }
.detail__handle {
  width: 36px; height: 4px; border-radius: var(--r-pill);
  background: var(--border-strong); margin: 0 auto var(--sp-2);
  touch-action: none; cursor: grab;
}
.detail__head { display: flex; align-items: center; gap: var(--sp-3); }
.detail__emoji {
  font-size: var(--fs-xl); line-height: 1; min-width: var(--tap); min-height: var(--tap);
  border: 1px solid var(--border); border-radius: var(--r-md);
  background: var(--surface); cursor: pointer;
}
.detail__title {
  flex: 1; min-width: 0; min-height: var(--tap);
  font-size: var(--fs-md); font-weight: var(--fw-semi);
  border: 1px solid transparent; border-radius: var(--r-sm);
  background: transparent; padding: var(--sp-1) var(--sp-2);
}
.detail__title:hover, .detail__title:focus { border-color: var(--border); background: var(--bg); }
.detail__type { display: flex; flex-wrap: wrap; gap: var(--sp-1); }
.detail__themes { display: flex; flex-wrap: wrap; gap: var(--sp-1); }
.detail__theme {
  font-size: var(--fs-xs); padding: 2px var(--sp-2);
  border-radius: var(--r-pill); background: var(--surface-2); color: var(--text-muted);
}
.detail__section {
  display: flex; flex-direction: column; gap: var(--sp-2);
  padding-top: var(--sp-3); border-top: 1px solid var(--hairline);
}
.detail__row { display: flex; align-items: center; gap: var(--sp-3); }
/* The flex sizing is scoped to .detail__row on purpose: the sections are
   COLUMN flex containers, where a flex-basis of 92px would set the label's
   HEIGHT and leave a 92px hole above the field. */
.detail__row > .detail__label { flex: 0 0 92px; }
.detail__row > .detail__value { flex: 1; min-width: 0; }
.detail__label { font-size: var(--fs-sm); color: var(--text-muted); }
.detail__value { font-size: var(--fs-base); }
select.detail__value, textarea.detail__value {
  min-height: var(--tap); padding: var(--sp-2);
  border: 1px solid var(--border); border-radius: var(--r-md); background: var(--surface);
}
textarea.detail__value { resize: vertical; }
.detail__meta { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-2) var(--sp-4); }
.detail__meta .detail__row { flex-direction: column; align-items: flex-start; gap: 0; }
.detail__meta .detail__label { flex: none; }
.detail__loc { font-size: var(--fs-base); }
.detail__links { flex-direction: row; flex-wrap: wrap; }
.detail__link {
  font-size: var(--fs-sm); padding: var(--sp-1) var(--sp-3);
  border: 1px solid var(--border); border-radius: var(--r-pill);
  color: var(--primary); text-decoration: none;
}
.detail__book { flex-direction: row; align-items: center; flex-wrap: wrap; }
.detail__field--empty { color: var(--text-muted); font-style: italic; }
.detail__provenance {
  display: flex; flex-wrap: wrap; gap: var(--sp-3);
  padding-top: var(--sp-3); border-top: 1px solid var(--hairline);
  font-size: var(--fs-xs); color: var(--text-muted);
}
.detail__provenance-marco { color: var(--m-marco-ink); font-weight: var(--fw-med); }
/* the inline 6px brass dot: "Marco supplied this value" */
.detail__marco {
  display: inline-block; width: 6px; height: 6px; margin-left: var(--sp-1);
  border-radius: 50%; background: var(--m-marco); vertical-align: middle;
}
.detail__actions { display: flex; justify-content: flex-end; gap: var(--sp-2); }

/* ══════════════════ POCKET (§2b, §5c, §6) ══════════════════ */
.pocket { flex: 1; padding: var(--sp-3); display: flex; flex-direction: column; gap: var(--sp-3); }
.pocket__segs {
  display: flex; gap: var(--sp-1); padding: var(--sp-1);
  background: var(--surface-2); border-radius: var(--r-pill);
}
.pocket__seg {
  flex: 1; min-height: var(--tap); border: 0; border-radius: var(--r-pill);
  background: transparent; color: var(--text-muted);
  font-size: var(--fs-sm); font-weight: var(--fw-med); cursor: pointer;
}
.pocket__seg--on { background: var(--surface); color: var(--text); box-shadow: var(--shadow-1); }
.pocket__body { display: flex; flex-direction: column; gap: var(--sp-4); }
.pocket__list {
  display: flex; flex-direction: column;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-md);
  overflow: hidden;
}
.pocket__group { display: flex; flex-direction: column; gap: var(--sp-2); }
.pocket__group-title {
  display: flex; align-items: center; gap: var(--sp-2);
  font-size: var(--fs-sm); font-weight: var(--fw-semi); color: var(--text-muted);
}

.add { display: flex; flex-direction: column; gap: var(--sp-3); }
.add__field { position: relative; display: flex; flex-wrap: wrap; gap: var(--sp-2); }
/* Row 1 = input + emoji side by side; row 2 = the full-width Add (§5c). */
.add__input {
  flex: 1 1 auto; min-width: 0; min-height: var(--tap);
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--border-strong); border-radius: var(--r-md); background: var(--surface);
}
.add__emoji-btn {
  flex: 0 0 auto; min-width: var(--tap); min-height: var(--tap); font-size: var(--fs-md);
  border: 1px solid var(--border); border-radius: var(--r-md); background: var(--surface); cursor: pointer;
}
.add__emoji-pop {
  position: absolute; top: calc(var(--tap) + var(--sp-2) + var(--sp-2)); left: 0; z-index: var(--z-sheet);
  display: flex; flex-wrap: wrap; gap: var(--sp-1); max-width: 280px; padding: var(--sp-2);
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--r-md); box-shadow: var(--shadow-2);
}
/* Inside the detail, the same quick-row sits in normal flow under the head. */
.add__emoji-pop--inline { position: static; max-width: none; box-shadow: none; }
.add__emoji-opt { min-width: 40px; min-height: 40px; font-size: var(--fs-md); border: 0; background: transparent; cursor: pointer; border-radius: var(--r-sm); }
.add__emoji-opt:hover { background: var(--surface-2); }
.add__submit { flex: 1 1 100%; min-height: var(--tap); }
.add__hint { font-size: var(--fs-sm); color: var(--text-muted); }
.add__justadded { display: flex; flex-direction: column; }
.add__justadded .card--row { animation: justadded-in var(--dur-3) var(--ease-out); }
@keyframes justadded-in { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; transform: translateY(0); } }

.tabbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: calc(var(--z-sticky) + 20);
  display: flex; align-items: flex-start; justify-content: space-around;
  height: calc(56px + env(safe-area-inset-bottom));
  padding-bottom: env(safe-area-inset-bottom);
  background: var(--surface); border-top: 1px solid var(--border);
}
.tabbar__item {
  flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 2px; min-height: 56px; min-width: var(--tap);
  border: 0; background: transparent; color: var(--text-muted); cursor: pointer;
}
.tabbar__item--active { color: var(--primary); }
.tabbar__item--reserved { pointer-events: none; }   /* holds a later phase's slot */
.tabbar__icon { width: 24px; height: 24px; }
.tabbar__label { font-size: var(--fs-xs); }
/* Raised coral hero, overlapping the bar's top edge (§6). */
.tabbar__item--hero {
  flex: 0 0 56px; width: 56px; height: 56px; min-height: 56px;
  margin-top: -20px; border-radius: 50%;
  background: var(--primary); color: var(--primary-ink);
  box-shadow: var(--shadow-2);
}
.tabbar__item--hero.tabbar__item--active { background: var(--primary-press); color: var(--primary-ink); }
.tabbar__item--hero .tabbar__icon { width: 28px; height: 28px; }

/* ══════════════════ PIN (§5a) ══════════════════ */
.pin {
  flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--sp-4); padding: var(--sp-5); min-height: 100dvh; text-align: center;
}
.pin__title { font-size: var(--fs-lg); font-weight: var(--fw-semi); }
.pin__sub { color: var(--text-muted); }
.pin__who { width: 72px; height: 72px; font-size: var(--fs-xl); }
.pin__profiles {
  display: grid; grid-template-columns: repeat(2, 1fr);
  gap: var(--sp-5); width: min(360px, 100%);
}
.profile {
  display: flex; flex-direction: column; align-items: center; gap: var(--sp-2);
  padding: var(--sp-3); border: 0; background: transparent; cursor: pointer;
  border-radius: var(--r-lg);
}
.profile:hover { background: var(--surface-2); }
.profile__avatar {
  display: flex; align-items: center; justify-content: center;
  width: 88px; height: 88px; border-radius: 50%;
  color: #fff; font-size: var(--fs-xl); font-weight: var(--fw-bold);
}
.profile__name { font-size: var(--fs-base); font-weight: var(--fw-med); }
.pin__projector, .pin__back {
  border: 0; background: transparent; color: var(--text-muted);
  font-size: var(--fs-sm); text-decoration: underline; cursor: pointer; min-height: var(--tap);
}
.pinpad { display: flex; flex-direction: column; align-items: center; gap: var(--sp-4); }
.pinpad__dots { display: flex; gap: var(--sp-3); }
.pinpad__dot {
  width: 14px; height: 14px; border-radius: 50%;
  border: 2px solid var(--border-strong); background: transparent;
  transition: background var(--dur-1) var(--ease-out);
}
.pinpad__dot--on { background: var(--primary); border-color: var(--primary); }
.pinpad__dots--shake { animation: pin-shake 300ms var(--ease-in-out); }
@keyframes pin-shake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-8px); }
  40% { transform: translateX(8px); }
  60% { transform: translateX(-8px); }
  80% { transform: translateX(8px); }
}
.pinpad__keys { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-3); }
.pinpad__key {
  width: 64px; height: 64px; min-width: 64px; min-height: 64px;
  border: 1px solid var(--border); border-radius: 50%;
  background: var(--surface); font-size: var(--fs-md); font-weight: var(--fw-med); cursor: pointer;
}
.pinpad__key:hover { background: var(--surface-2); }
.pinpad__key:disabled { opacity: .4; cursor: not-allowed; }
.pinpad__key--blank { border: 0; background: transparent; }
.pin__error { color: var(--danger); font-size: var(--fs-sm); max-width: 280px; }

/* ══════════════════ WIZARD (§5b) ══════════════════ */
.wizard {
  flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--sp-4); padding: var(--sp-5); min-height: 100dvh;
}
.wizard__progress { font-size: var(--fs-sm); color: var(--text-muted); letter-spacing: .04em; }
.wizard__step { display: flex; flex-direction: column; gap: var(--sp-4); width: min(420px, 100%); }
.wizard__headline { font-size: var(--fs-xl); font-weight: var(--fw-bold); line-height: var(--lh-tight); }
.wizard__field { display: flex; flex-direction: column; gap: var(--sp-2); }
.wizard__label { font-size: var(--fs-sm); font-weight: var(--fw-med); color: var(--text-muted); }
.wizard__input {
  min-height: var(--tap); padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--border-strong); border-radius: var(--r-md); background: var(--surface);
}
.wizard__chips { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.wizard__span { font-size: var(--fs-md); font-weight: var(--fw-semi); color: var(--primary); }
.wizard__help { font-size: var(--fs-sm); color: var(--text-muted); }
.wizard__nav { display: flex; gap: var(--sp-2); justify-content: flex-end; flex-wrap: wrap; }
.wizard__nav .wizard__back { margin-right: auto; }
/* Three buttons don't fit 390px, so the primary wraps anyway — give it the
   whole line instead of letting it land under "Skip for now" at half width. */
@media (max-width: 480px) { .wizard__nav .btn--primary { flex: 1 1 100%; order: 3; } }

/* ══════════════════ SETTINGS / FIRST RUN ══════════════════ */
.settings {
  flex: 1; display: flex; flex-direction: column; gap: var(--sp-3);
  padding: var(--sp-5); width: min(520px, 100%); margin: 0 auto;
}
.settings__title { font-size: var(--fs-lg); font-weight: var(--fw-semi); }
.settings__row {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-3) 0; border-bottom: 1px solid var(--hairline);
}
.settings__actions { display: flex; justify-content: space-between; gap: var(--sp-2); margin-top: var(--sp-4); }
.settings__signout { color: var(--danger); }

.firstrun {
  display: flex; flex-direction: column; align-items: center; gap: var(--sp-4);
  text-align: center; padding: var(--sp-6) var(--sp-4); max-width: 46ch; margin: 0 auto;
}
/* Board variant: a strip ABOVE the day grid, never instead of it. The grid is
   the reassurance ("yes, all 8 days are here"), and the hero's own copy talks
   about a calendar it must therefore be standing next to, not covering. */
.firstrun--banner {
  flex-direction: row; align-items: center; text-align: left;
  gap: var(--sp-4); max-width: none; width: 100%;
  padding: var(--sp-3) var(--sp-5);
  background: var(--primary-weak); border-bottom: 1px solid var(--primary-weak-bd);
}
.firstrun--banner .firstrun__headline { font-size: var(--fs-lg); white-space: nowrap; }
.firstrun--banner .firstrun__body { flex: 1; font-size: var(--fs-sm); }
.firstrun--banner .firstrun__hint { display: none; }
body.projector .firstrun--banner .firstrun__headline { font-size: var(--fs-xl); }
.firstrun__headline { font-size: var(--fs-2xl); font-weight: var(--fw-bold); line-height: var(--lh-tight); }
.firstrun__body { color: var(--text-muted); }
.firstrun__hint { font-size: var(--fs-sm); color: var(--text-muted); }

/* ══════════════════ RESPONSIVE ══════════════════ */
@media (min-width: 1024px) {
  .app--board { height: 100dvh; overflow: hidden; }
  .board { overflow: hidden; }
  .detail--sheet { display: none; }
}
@media (max-width: 1023px) {
  .board { flex-direction: column; }
  .board__shelf { width: 100%; }
}
