/* Whiteboard — personal dashboard
   Dark-first glass UI. Class names here match the DOM rendered by
   app.jsx, components.jsx and academic.jsx. The tweaks panel injects
   its own styles (tweaks-panel.jsx) and is not styled here. */

:root {
  /* Type */
  --font-serif: "Newsreader", "Source Serif 4", Georgia, serif;
  --font-sans: "Geist", "Inter Tight", system-ui, -apple-system, sans-serif;
  --font-mono: "Geist Mono", ui-monospace, monospace;
  --font-size-base: 14px;

  /* Surfaces — warm paper (light defaults; dark mode overrides below).
     The `-raw` aliases hold the untinted base so the per-tab tint (applied on
     .app-main) can color-mix against them without a self-referential cycle. */
  --bg: oklch(0.971 0.005 75);
  --surface-raw: oklch(0.995 0.003 75);
  --surface-2-raw: oklch(0.948 0.006 72);
  --surface: var(--surface-raw);
  --surface-2: var(--surface-2-raw);
  --ink: oklch(0.26 0.012 60);
  --ink-2: oklch(0.45 0.012 62);
  --muted: oklch(0.605 0.012 65);
  --line: oklch(0.9 0.006 70);
  --line-2: oklch(0.845 0.009 70);

  /* Category accents — muted jewel tones at equal visual weight.
     Defined as strings shared with app.jsx / academic.jsx inline styles. */
  --academic: oklch(0.6 0.115 250);
  --household: oklch(0.61 0.095 158);
  --health: oklch(0.63 0.13 38);
  --finance: oklch(0.6 0.10 195);
  --travel: oklch(0.6 0.15 300);
  --academic-soft: oklch(0.6 0.115 250 / 0.13);
  --household-soft: oklch(0.61 0.095 158 / 0.13);
  --health-soft: oklch(0.63 0.13 38 / 0.13);
  --finance-soft: oklch(0.6 0.10 195 / 0.13);
  --travel-soft: oklch(0.6 0.15 300 / 0.13);

  /* Money figures */
  --gain: oklch(0.6 0.14 150);
  --loss: oklch(0.58 0.18 25);

  /* Active accent — overridden at runtime from the Hue tweak (app.jsx) */
  --accent: hsl(268, 48%, 56%);
  --accent-soft: hsla(268, 48%, 56%, 0.14);

  /* Danger */
  --danger: oklch(0.56 0.17 25);
  --danger-soft: oklch(0.94 0.035 25);

  /* Panel surface — overridden at runtime (opacity tweak) */
  --panel-bg: var(--surface);
  --panel-radius: 14px;

  /* Layered panel shadows (light defaults; dark mode deepens them below). */
  --panel-shadow:
    0 1px 2px oklch(0.3 0.02 60 / 0.04),
    0 4px 14px oklch(0.3 0.02 60 / 0.05);
  --panel-shadow-raised:
    0 1px 3px oklch(0.3 0.02 60 / 0.05),
    0 8px 24px oklch(0.3 0.02 60 / 0.07);
  --panel-shadow-hover:
    0 3px 8px oklch(0.3 0.02 60 / 0.06),
    0 14px 32px oklch(0.3 0.02 60 / 0.1);

  /* Spacing scale */
  --gap: 18px;
  --pad: 20px;
  --radius: 12px;
  --radius-sm: 9px;
}

/* ── Dark mode (warm ink — switched on by time of day or the tweak) ─────── */
html.dark {
  --bg: oklch(0.175 0.008 65);
  --surface-raw: oklch(0.218 0.009 65);
  --surface-2-raw: oklch(0.265 0.011 65);
  --surface: var(--surface-raw);
  --surface-2: var(--surface-2-raw);
  --ink: oklch(0.95 0.005 75);
  --ink-2: oklch(0.78 0.009 72);
  --muted: oklch(0.605 0.013 70);
  --line: oklch(1 0 0 / 0.085);
  --line-2: oklch(1 0 0 / 0.155);
  --academic: oklch(0.7 0.12 250);
  --household: oklch(0.72 0.1 158);
  --health: oklch(0.72 0.13 40);
  --finance: oklch(0.72 0.10 195);
  --travel: oklch(0.7 0.15 300);
  --academic-soft: oklch(0.7 0.12 250 / 0.16);
  --household-soft: oklch(0.72 0.1 158 / 0.16);
  --health-soft: oklch(0.72 0.13 40 / 0.16);
  --finance-soft: oklch(0.72 0.10 195 / 0.16);
  --travel-soft: oklch(0.7 0.15 300 / 0.16);
  --gain: oklch(0.74 0.15 150);
  --loss: oklch(0.72 0.18 25);
  --danger: oklch(0.72 0.17 25);
  --danger-soft: oklch(0.42 0.12 25 / 0.25);
  --panel-shadow:
    0 1px 2px oklch(0 0 0 / 0.25),
    0 8px 22px oklch(0 0 0 / 0.28);
  --panel-shadow-raised:
    0 2px 6px oklch(0 0 0 / 0.3),
    0 14px 34px oklch(0 0 0 / 0.38);
  --panel-shadow-hover:
    0 6px 14px oklch(0 0 0 / 0.32),
    0 22px 48px oklch(0 0 0 / 0.45);
}

/* ── Density (set on <html> by app.jsx) ───────────────────────────────── */
html[data-density="compact"]     { --gap: 14px; --pad: 16px; }
html[data-density="comfortable"] { --gap: 28px; --pad: 30px; }

/* ── Font family (set on <html> by app.jsx) ───────────────────────────── */
html[data-font="serif"] body { font-family: var(--font-serif); }
html[data-font="mono"]  body { font-family: var(--font-mono); }

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  font-family: var(--font-sans);
  font-size: var(--font-size-base);
  color: var(--ink);
  background:
    radial-gradient(1200px 600px at 80% -10%, color-mix(in oklch, var(--accent) 14%, transparent), transparent 70%),
    var(--bg);
  background-attachment: fixed;
  min-height: 100vh;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

button { font-family: inherit; }
input, textarea, select { font-family: inherit; color: inherit; }
a { color: var(--accent); }

::selection { background: var(--accent-soft); }

/* Shared scrollbars */
* { scrollbar-width: thin; scrollbar-color: var(--line-2) transparent; }
*::-webkit-scrollbar { width: 8px; height: 8px; }
*::-webkit-scrollbar-thumb { background: var(--line-2); border-radius: 8px; }

/* ── App shell ────────────────────────────────────────────────────────── */
.app {
  max-width: 1180px;
  margin: 0 auto;
  padding: 44px 40px 120px;
}

/* ── Header ───────────────────────────────────────────────────────────── */
.app-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 32px;
  margin-bottom: 26px;
  padding-bottom: 22px;
  border-bottom: 1px solid var(--line);
}
.header-left { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.greeting {
  margin: 0;
  font-family: var(--font-serif);
  font-weight: 400;
  font-size: 44px;
  line-height: 1.12;
  letter-spacing: -0.02em;
  color: var(--ink);
  text-wrap: balance;
}
.greeting-name {
  font-style: italic;
  color: var(--accent);
}
/* Sub-line under the greeting: date + an at-a-glance tally. */
.header-sub {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
}

/* When header-sub is used in the right header, stack date above stats */
.header-sub.header-sub-right {
  flex-direction: column;
  align-items: flex-end;
  gap: 6px;
}
.header-date {
  font-size: 16px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  white-space: nowrap;
}
.header-stats { display: flex; align-items: center; gap: 8px; }
.stat-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11.5px;
  font-weight: 500;
  padding: 3px 11px;
  border-radius: 999px;
  white-space: nowrap;
}
.stat-pill::before {
  content: "";
  width: 5px; height: 5px;
  border-radius: 50%;
  background: currentColor;
}
.stat-overdue { color: var(--danger); background: var(--danger-soft); }
.stat-week {
  color: var(--ink-2);
  background: var(--surface-2);
  border: 1px solid var(--line);
}

.header-right {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 8px;
  flex-shrink: 0;
}
.sync-status {
  font-size: 12px;
  color: var(--muted);
  letter-spacing: 0.02em;
  padding: 4px 10px;
  border: 1px solid var(--line);
  border-radius: 999px;
  white-space: nowrap;
}
/* Quiet sync indicator: holds its space and gently fades, so the view below
   never jumps as the status cycles Syncing… → Synced → (gone). */
.sync-status-quiet {
  opacity: 0;
  transition: opacity 0.5s ease;
}
.sync-status-quiet.is-visible {
  opacity: 0.7;
}
.sync-status-error {
  color: var(--danger);
  border-color: color-mix(in oklch, var(--danger) 40%, transparent);
  max-width: 280px;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Clock — monospaced, right-aligned, kept clear of the greeting. */
.clock { display: flex; flex-direction: column; align-items: flex-end; gap: 2px; }
.clock-time {
  font-family: var(--font-mono);
  font-size: 30px;
  font-weight: 400;
  letter-spacing: -0.02em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
.clock-meridiem {
  font-size: 0.5em;
  color: var(--muted);
  margin-left: 2px;
  letter-spacing: 0;
}

/* ── Next-up banner ───────────────────────────────────────────────────── */
/* --next-up-tone drives the accent; each urgency level overrides it so the
   banner gets louder as the deadline gets closer. */
.next-up {
  --next-up-tone: var(--next-up-cat, var(--accent));
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 13px 18px;
  margin-bottom: 24px;
  border: 1px solid var(--line);
  border-left: 3px solid var(--next-up-tone);
  border-radius: var(--radius-sm);
  background: var(--panel-bg);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  transition: border-color 0.2s ease, box-shadow 0.2s ease, background 0.2s ease;
}
/* Calm: far out — quiet, no tint. */
.next-up-calm { --next-up-tone: var(--muted); }
/* Soon: within a day — accent border, a soft glow, faint tinted fill. */
.next-up-soon {
  --next-up-tone: var(--accent);
  border-left-width: 4px;
  background:
    linear-gradient(to right, var(--accent-soft), transparent 40%),
    var(--panel-bg);
}
/* Overdue: loud — danger border, stronger ring, danger label. */
.next-up-overdue {
  --next-up-tone: var(--danger);
  border-color: color-mix(in oklch, var(--danger) 35%, transparent);
  border-left-width: 4px;
  box-shadow: 0 0 0 1px color-mix(in oklch, var(--danger) 22%, transparent);
  background:
    linear-gradient(to right, var(--danger-soft), transparent 45%),
    var(--panel-bg);
}
.next-up-label {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
  flex-shrink: 0;
}
.next-up-overdue .next-up-label { color: var(--danger); font-weight: 600; }
.next-up-kind {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--next-up-tone);
  flex-shrink: 0;
}
.next-up-text {
  flex: 1;
  min-width: 0;
  font-family: var(--font-serif);
  font-size: 17px;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.next-up-time {
  font-size: 13px;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
}
.next-up-soon .next-up-time { color: var(--accent); font-weight: 500; }
.next-up-overdue .next-up-time { color: var(--danger); font-weight: 600; }

/* ── Tabs + inline search ─────────────────────────────────────────────── */
/* The tab bar is sticky: it sits under the greeting at rest and pins to the top
   of the viewport once you scroll, so navigation is always one tap away. The
   frosted background covers panel content scrolling beneath it. (It spans the
   same 90vw column as the panels, so its side gutters are page background — no
   content leaks past its edges.) */
.tab-nav {
  display: flex;
  align-items: center;
  gap: 2px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 28px;
  position: sticky;
  top: 0;
  z-index: 30;
  background: color-mix(in oklch, var(--bg) 86%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.tab-btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  padding: 11px 16px 13px;
  font-size: 14px;
  font-weight: 500;
  color: var(--muted);
  cursor: pointer;
  transition: color 0.18s ease, border-color 0.18s ease;
}
.tab-btn:hover { color: var(--ink-2); }
.tab-btn.active { color: var(--ink); }
/* Icon leads; it inherits the button's color, so it accent-tints when active. */
.tab-icon { width: 18px; height: 18px; flex-shrink: 0; }
.tab-label { white-space: nowrap; }
.tab-search { margin-left: auto; flex: 0 1 280px; }
.tab-search .search-input { width: 100%; }

.search-input {
  padding: 9px 14px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 13px;
  color: var(--ink);
  outline: none;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.search-input::placeholder { color: var(--muted); }
.search-input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}

/* ── Main / panel layout ────────────────────────────────────────────────── */
/* Each tab carries a hint of its category color: --tab-tint (the active
   category accent) is set inline on .app-main, then mixed into the card and
   item surfaces here so a tab's cards read as belonging together — instead of
   a uniform gray shared across every tab. --tab-fill is the translucent
   overlay laid over the (opacity-tweakable) panel background. */
.app-main {
  min-height: 200px;
  --surface:   color-mix(in oklch, var(--tab-tint, transparent) 5%, var(--surface-raw));
  --surface-2: color-mix(in oklch, var(--tab-tint, transparent) 9%, var(--surface-2-raw));
  --tab-fill:  color-mix(in oklch, var(--tab-tint, transparent) 6%, transparent);
}
/* Dark mode reads tint at lower contrast, so push the mixes a little harder. */
html.dark .app-main {
  --surface:   color-mix(in oklch, var(--tab-tint, transparent) 9%,  var(--surface-raw));
  --surface-2: color-mix(in oklch, var(--tab-tint, transparent) 14%, var(--surface-2-raw));
  --tab-fill:  color-mix(in oklch, var(--tab-tint, transparent) 11%, transparent);
}

/* Layout lives entirely on the per-tab .panels-* modifiers below: a 2-col grid
   with full-width breakouts for Academic, a full-width anchor + sub-columns for
   Research, and two flex columns for Household / Health / Finance / Travel. The
   bare .panels class carries no layout of its own. */
/* Household & Health use two flex columns: panel tops stay aligned (no multicol
   balancing gap), and panels stack from the top filling space within a column. */
.panels-household,
.panels-health {
  column-count: unset;
  display: flex;
  align-items: flex-start;
  gap: var(--gap);
}
.panels-col {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--gap);
}
.panels-col > .panel { margin-bottom: 0; }

/* Keep the two columns roughly balanced: a single long list scrolls within its
   panel instead of stretching its column far past the other. */
.panels-household .chore-list,
.panels-household .todo-list,
.panels-household .goal-list,
.panels-health .habits-list,
.panels-health .todo-list,
.panels-health .goal-list {
  max-height: 52vh;
  overflow-y: auto;
  /* room so the scrollbar doesn't overlap item content */
  padding-right: 4px;
  scrollbar-width: thin;
}

/* Academic uses a deliberate 2-column grid rather than masonry: Deadlines and
   Goals share the top row at half width each; Teaching and Service share the
   next row at half width; Projects and the Reading list each break out full. */
.panels-academic {
  column-count: unset;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--gap);
  align-items: start;
}
/* min-width:0 lets a grid child shrink below its content's intrinsic size, so a
   long deadline/course title can't force the 1fr track wider than the viewport
   (the academic tab is the only grid layout — see DESIGN.md §8). */
.panels-academic > .panel { margin-bottom: 0; min-width: 0; }
.panels-academic > .panel:nth-child(5),  /* Projects */
.panels-academic > .panel:nth-child(6) { /* Reading  */
  grid-column: 1 / -1;
}

/* Single-column collapse for every tab is standardized in the "Small screens"
   section near the end of this file — don't add per-tab breakpoints here. */

/* ── Panel ────────────────────────────────────────────────────────────── */
.panel {
  /* Tab tint overlaid on the (opacity-tweakable) panel-bg, so cards on each
     tab carry a hint of the category color without losing translucency. */
  background: linear-gradient(var(--tab-fill, transparent), var(--tab-fill, transparent)), var(--panel-bg);
  border: 1px solid color-mix(in oklch, var(--tab-tint, transparent) 15%, var(--line));
  border-radius: var(--panel-radius);
  padding: var(--pad);
  display: flex;
  flex-direction: column;
  gap: 14px;
  box-shadow: var(--panel-shadow);
  isolation: isolate;
  transition: box-shadow 0.2s ease, border-color 0.2s ease;
}
.panel:hover {
  box-shadow: var(--panel-shadow-hover);
  border-color: color-mix(in oklch, var(--tab-tint, transparent) 22%, var(--line-2));
}
/* One anchor per tab: the heaviest panel gets a touch more lift so every tab
   has a single visual entry point rather than reading as N equal cards
   (see DESIGN.md §5). Academic → Projects; Research → Projects (full-width
   first child); the flex-column tabs → the first panel of their left column
   (Chores / Habits / Grants / Trips). */
.panels-academic > .panel:nth-child(5),
.panels-research > .panel:first-child,
.panels-finance  > .panels-col:first-child > .panel:first-child,
.panels-household > .panels-col:first-child > .panel:first-child,
.panels-health   > .panels-col:first-child > .panel:first-child,
.panels-travel   > .panels-col:first-child > .panel:first-child {
  box-shadow: var(--panel-shadow-raised);
}
.panel-header {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-serif);
  font-size: 18px;
  font-weight: 500;
  letter-spacing: -0.01em;
  color: var(--ink);
}
/* A small accent tick anchors each panel title without adding chrome. */
.panel-header::before {
  content: "";
  flex-shrink: 0;
  width: 3px;
  height: 16px;
  margin-right: -1px;
  border-radius: 999px;
  background: var(--tab-tint, var(--accent));
  opacity: 0.7;
}
/* Push any trailing control (add / clear button) to the right edge. */
.panel-header > button { margin-left: auto; }
/* When several controls share the header, group them at the right edge. */
.panel-header-actions {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 8px;
}
.panel-empty {
  color: var(--muted);
  font-size: 13px;
  font-style: italic;
  padding: 4px 2px;
}
.btn-add-inline {
  width: 24px;
  height: 24px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--line);
  border-radius: 7px;
  background: var(--surface-2);
  color: var(--ink-2);
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.btn-add-inline:hover { color: var(--accent); border-color: var(--accent); }
/* Small, low-chrome text button used for inline actions (Collapse all, Save…). */
.panel-text-btn {
  border: 1px solid var(--line);
  border-radius: 7px;
  background: var(--surface-2);
  color: var(--ink-2);
  font-size: 12px;
  line-height: 1;
  padding: 5px 9px;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.panel-text-btn:hover { color: var(--accent); border-color: var(--accent); }

/* ── Add-row inputs ───────────────────────────────────────────────────── */
.todo-input-row {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.packing-trip-select {
  width: 100%;
  margin-bottom: 8px;
}
.todo-input {
  flex: 1;
  min-width: 120px;
  padding: 9px 12px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  font-size: 13.5px;
  color: var(--ink);
  outline: none;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.todo-input::placeholder { color: var(--muted); }
.todo-input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.datetime-input { flex: 1 1 auto; min-width: 150px; color-scheme: dark; }
html:not(.dark) .datetime-input { color-scheme: light; }
.btn-add {
  flex-shrink: 0;
  width: 34px;
  height: 34px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: var(--radius-sm);
  background: var(--accent);
  color: #fff;
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  transition: filter 0.15s ease;
}
.btn-add:hover { filter: brightness(1.1); }

/* ── Lists & items (todo / reminder / reading / shopping) ─────────────── */
.todo-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.todo-item,
.reminder-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 8px 8px 6px;
  border-radius: var(--radius-sm);
  transition: background 0.12s ease;
}
.todo-item:hover,
.reminder-item:hover { background: var(--surface-2); }
.todo-item input[type="checkbox"],
.reminder-item input[type="checkbox"],
.meta-row input[type="checkbox"],
.project-task-list input[type="checkbox"] {
  width: 17px;
  height: 17px;
  flex-shrink: 0;
  accent-color: var(--accent);
  cursor: pointer;
}
.todo-text {
  flex: 1;
  min-width: 0;
  font-size: 14px;
  line-height: 1.4;
  color: var(--ink);
  overflow-wrap: break-word;
}
.todo-item.done .todo-text,
.reminder-item.done .todo-text {
  color: var(--muted);
  text-decoration: line-through;
}
.btn-delete {
  flex-shrink: 0;
  background: none;
  border: none;
  color: var(--muted);
  font-size: 17px;
  line-height: 1;
  padding: 2px 6px;
  border-radius: 6px;
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.15s ease, color 0.15s ease, background 0.15s ease;
}
.todo-item:hover .btn-delete,
.reminder-item:hover .btn-delete,
.reading-item:hover .btn-delete,
.project-title-row:hover .btn-delete,
.project-card:has(.project-details) .project-title-row .btn-delete,
.habit-card:hover .btn-delete,
.chore-item:hover .btn-delete { opacity: 1; }
.btn-delete:hover { color: var(--danger); background: var(--danger-soft); }

/* Edit (pen) button — mirrors .btn-delete: icon-only, ghost, reveals on
   row hover, tints to the accent colour on hover. */
.btn-edit {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  color: var(--muted);
  padding: 4px;
  border-radius: 6px;
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.15s ease, color 0.15s ease, background 0.15s ease;
}
.btn-edit svg { display: block; }
.btn-edit:hover { color: var(--accent); background: var(--accent-soft, var(--surface-2)); }
.teaching-course-head .btn-edit,
.chore-item .btn-edit,
.reading-item .btn-edit,
.service-card .btn-edit { opacity: 0.5; }
.teaching-course-head:hover .btn-edit,
.chore-item:hover .btn-edit,
.reading-item:hover .btn-edit,
.service-card:hover .btn-edit { opacity: 1; }

/* ── Meta-when ────────────────────────────────────────────────────────── */
/* The trailing "Mon 5 · 2d" date stamp shared by every dated row. One base
   definition for eight historical class names (…-due / -time / -expiry / -range);
   urgency is driven by the .overdue/.soon class the row already carries
   (overdue→danger, soon→accent). New dated panels should reuse these hooks
   rather than coin a ninth name. See DESIGN.md §3 "meta-when". */
.reminder-time,
.meta-row-when,
.service-due,
.grant-due,
.trip-range {
  flex-shrink: 0;
  font-size: 11.5px;
  color: var(--muted);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
.reminder-item.overdue .reminder-time,
.reminder-item.overdue .meta-row-when,
.grant-card.overdue .grant-due,
.meta-row.overdue .meta-row-when { color: var(--danger); }
.reminder-item.soon .reminder-time,
.reminder-item.soon .meta-row-when,
.grant-card.soon .grant-due,
.meta-row.soon .meta-row-when { color: var(--accent); }

/* ── Reminders ────────────────────────────────────────────────────────── */
.reminder-item.overdue { background: var(--danger-soft); }

/* ── Auto-textarea ────────────────────────────────────────────────────── */
.auto-textarea {
  width: 100%;
  background: transparent;
  border: none;
  outline: none;
  resize: none;
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink);
  overflow: hidden;
  min-height: 20px;
}
.auto-textarea::placeholder { color: var(--muted); }

/* ── Projects ─────────────────────────────────────────────────────────── */
/* In the full-width Projects panel, cards tile into two compact columns. An open
   card holds a lot (tasks, collaborators, notes, links) but stays in its own
   column, growing taller, so expanding one card never disturbs the other. */
.projects-list {
  display: grid;
  grid-template-columns: repeat(2, minmax(min(100%, 260px), 1fr));
  grid-auto-flow: dense;
  gap: 9px;
  align-items: start;
}
/* An open card stays within its own column and simply grows taller; its detail
   sections stack vertically (see base .project-details) rather than breaking out
   across the full panel width. */
.project-card {
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  overflow: hidden;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.project-card:not(.open):hover {
  border-color: var(--line-2);
  background: color-mix(in oklch, var(--surface-2) 55%, var(--surface));
}
.project-card.done:not(.open) .project-name-label { color: var(--muted); }
.project-collab-count {
  flex-shrink: 0;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 10.5px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.project-done-toggle {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: transparent;
  color: transparent;
  font-size: 11px;
  line-height: 1;
  cursor: pointer;
  transition: background 0.12s ease, color 0.12s ease, border-color 0.12s ease;
}
.project-done-toggle:hover {
  border-color: var(--line-2);
  color: var(--muted);
}
.project-done-toggle.done {
  border-color: var(--household);
  background: var(--household);
  color: #fff;
}
.project-title-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
}

/* ── Drag-to-reorder ── */
.project-drag-handle {
  flex-shrink: 0;
  cursor: grab;
  color: var(--line-2);
  font-size: 12px;
  line-height: 1;
  letter-spacing: -2px;
  user-select: none;
  opacity: 0;
  transition: opacity 0.12s ease, color 0.12s ease;
}
.project-card:hover .project-drag-handle,
.project-card.open .project-drag-handle {
  opacity: 1;
}
.project-drag-handle:hover { color: var(--muted); }
.project-card:not(.open) { cursor: default; }
.project-card.dragging {
  opacity: 0.5;
}
.project-card.drag-over {
  border-color: var(--accent);
  box-shadow: inset 0 2px 0 var(--accent);
}

/* ── Priority flare ── */
.project-flare {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  padding: 0;
  border: none;
  border-radius: 6px;
  background: transparent;
  color: var(--line-2);
  font-size: 12px;
  line-height: 1;
  cursor: pointer;
  transition: color 0.12s ease, background 0.12s ease, transform 0.12s ease;
}
.project-flare:hover { background: color-mix(in oklch, currentColor 14%, transparent); transform: scale(1.12); }
.project-flare.prio-low  { color: oklch(0.72 0.14 150); }
.project-flare.prio-med  { color: oklch(0.76 0.16 75); }
.project-flare.prio-high { color: oklch(0.65 0.22 25); }

/* Card edge accent + soft glow per priority */
.project-card.prio-low  { border-left: 3px solid oklch(0.72 0.14 150); }
.project-card.prio-med  { border-left: 3px solid oklch(0.76 0.16 75); }
.project-card.prio-high {
  border-left: 3px solid oklch(0.65 0.22 25);
  box-shadow: 0 0 0 1px color-mix(in oklch, oklch(0.65 0.22 25) 30%, transparent);
}
.expand-icon-btn {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  padding: 0;
  border: none;
  border-radius: 6px;
  background: transparent;
  color: var(--muted);
  font-size: 10px;
  cursor: pointer;
  transition: background 0.12s ease, color 0.12s ease;
}
.expand-icon-btn:hover {
  background: color-mix(in oklch, var(--accent) 12%, transparent);
  color: var(--ink);
}
.project-name-label {
  flex: 1;
  min-width: 0;
  font-size: 14.5px;
  font-weight: 500;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.project-name-label[role="button"] {
  cursor: pointer;
}
.project-name-label[role="button"]:hover {
  color: var(--accent);
}
.project-name-edit {
  font-size: 14.5px;
  font-weight: 500;
}
.project-details {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 4px 12px 14px;
  border-top: 1px solid var(--line);
}
.project-section { display: flex; flex-direction: column; gap: 6px; }
.project-section > label {
  font-size: 10.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
}
.project-collab-input,
.project-link-input {
  width: 100%;
  padding: 7px 10px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 6px;
  font-size: 13px;
  color: var(--ink);
  outline: none;
  transition: border-color 0.15s ease;
}
.project-collab-input:focus,
.project-link-input:focus { border-color: var(--accent); }
.project-link-input { font-family: var(--font-mono); font-size: 12px; }
.project-links { display: flex; flex-direction: column; gap: 6px; }
.project-external-links { flex-direction: row; gap: 8px; }
.external-link {
  display: inline-flex;
  align-items: center;
  padding: 4px 12px;
  border-radius: 999px;
  font-size: 12px;
  text-decoration: none;
  border: 1px solid var(--line);
  color: var(--ink-2);
  transition: border-color 0.15s ease, color 0.15s ease;
}
.external-link:hover { border-color: var(--accent); color: var(--accent); }
.contact-icon { flex-shrink: 0; display: inline-flex; align-items: center; padding: 0 3px; color: var(--muted); text-decoration: none; transition: color 0.15s ease; }
.contact-icon:hover { color: var(--accent); }
.contact-item .meta-row-title { flex-basis: 60%; overflow-wrap: anywhere; }
.project-task-list { display: flex; flex-direction: column; gap: 6px; }
.project-task-list .todo-list { gap: 0; }

/* ── Reading list ─────────────────────────────────────────────────────── */
.reading-item .external-badge {
  flex-shrink: 0;
  text-decoration: none;
  color: var(--muted);
  font-size: 14px;
  padding: 0 4px;
  transition: color 0.15s ease;
}
.reading-item .external-badge:hover { color: var(--accent); }

/* ── Shopping ─────────────────────────────────────────────────────────── */
.btn-clear-bought {
  background: none;
  border: none;
  color: var(--muted);
  font-size: 12px;
  cursor: pointer;
  padding: 0;
  transition: color 0.15s ease;
}
.btn-clear-bought:hover { color: var(--ink); }

/* ── Habits ───────────────────────────────────────────────────────────── */
.habits-list { display: flex; flex-direction: column; gap: 12px; }
.habit-card {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 13px 14px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
}
.habit-title-row { display: flex; align-items: center; gap: 10px; }
.habit-name { flex: 1; min-width: 0; font-size: 14px; font-weight: 500; color: var(--ink); }
.habit-streak {
  display: inline-flex;
  align-items: baseline;
  gap: 7px;
  flex-shrink: 0;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.01em;
  color: var(--muted);
  padding: 3px 9px;
  border-radius: 999px;
  background: var(--surface);
  border: 1px solid var(--line);
  font-variant-numeric: tabular-nums;
}
.habit-streak.active {
  color: var(--accent);
  background: var(--accent-soft);
  border-color: color-mix(in oklch, var(--accent) 28%, transparent);
}
.habit-streak-best {
  font-size: 10px;
  font-weight: 500;
  color: var(--muted);
}
.habit-days { display: flex; gap: 5px; }
.habit-day-btn {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 6px 0 5px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: var(--surface);
  color: var(--muted);
  cursor: pointer;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.habit-day-dow {
  font-size: 9px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  opacity: 0.8;
}
.habit-day-num { font-size: 12px; font-weight: 500; font-variant-numeric: tabular-nums; }
.habit-day-btn:hover { border-color: var(--line-2); color: var(--ink-2); }
.habit-day-btn.today {
  border-color: color-mix(in oklch, var(--accent) 45%, var(--line));
}
.habit-day-btn.active {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
.habit-day-btn.active .habit-day-dow { opacity: 0.85; }

/* ── Chores ───────────────────────────────────────────────────────────── */
.chore-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 5px; }
.chore-item {
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-left: 3px solid var(--line-2);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  transition: border-color 0.15s ease, background 0.15s ease;
}
.chore-item:hover { background: color-mix(in oklch, var(--surface-2) 60%, var(--surface)); }
.chore-main-row { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
.chore-name { flex: 1 1 140px; min-width: 140px; font-size: 13.5px; color: var(--ink); overflow-wrap: break-word; }
/* Keep the row's controls together and hard against the right edge so that when
   the row wraps on a narrow card no single button orphans onto its own line. */
.chore-actions { display: flex; align-items: center; gap: 6px; margin-left: auto; flex-shrink: 0; }
.chore-freq-menu {
  flex-shrink: 0;
  padding: 3px 6px;
  background: transparent;
  border: 1px solid transparent;
  border-radius: 6px;
  color: var(--muted);
  font-size: 11px;
  cursor: pointer;
  outline: none;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.chore-freq-menu:hover,
.chore-freq-menu:focus { background: var(--surface); border-color: var(--line); color: var(--ink-2); }
.chore-status-badge {
  flex-shrink: 0;
  font-size: 9.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 2px 8px;
  border-radius: 999px;
  background: color-mix(in oklch, currentColor 12%, transparent);
  color: var(--muted);
}
.btn-chore-done,
.btn-chore-undo {
  flex-shrink: 0;
  width: 27px;
  height: 27px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--line);
  border-radius: 7px;
  background: var(--surface);
  color: var(--ink-2);
  font-size: 13px;
  cursor: pointer;
  transition: all 0.15s ease;
}
.btn-chore-done:hover {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
.btn-chore-undo { opacity: 0; }
.chore-item:hover .btn-chore-undo { opacity: 1; }
.btn-chore-undo:hover { color: var(--ink); border-color: var(--line-2); }
.chore-meta { margin-top: 7px; font-size: 10.5px; color: var(--muted); letter-spacing: 0.01em; }

/* Chore status colours (className: chore-item chore-<status>) */
.chore-overdue { border-left-color: var(--danger); }
.chore-overdue .chore-status-badge { background: var(--danger-soft); color: var(--danger); }
.chore-due { border-left-color: oklch(0.72 0.12 75); }
.chore-due .chore-status-badge { color: oklch(0.62 0.11 70); }
html.dark .chore-due .chore-status-badge { color: oklch(0.78 0.12 78); }
.chore-soon { border-left-color: var(--accent); }
.chore-soon .chore-status-badge { color: var(--accent); }
.chore-fresh { border-left-color: var(--household); }
.chore-fresh .chore-status-badge { color: var(--household); }
.chore-done-today { opacity: 0.55; }
.chore-done-today .chore-name { text-decoration: line-through; color: var(--muted); }

/* ── Academic tab (academic.jsx) ──────────────────────────────────────── */
/* The one doorway per panel: a square "+" icon (→ "×" while the form is open),
   identical to the inline .btn-add-inline used by the list panels so every
   panel's add affordance reads the same. */
.academic-add-btn {
  width: 24px;
  height: 24px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--line);
  border-radius: 7px;
  background: var(--surface-2);
  color: var(--ink-2);
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.academic-add-btn:hover { border-color: var(--accent); color: var(--accent); }
.academic-form {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
}
.academic-input,
.academic-select {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  padding: 8px 10px;
  background-color: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 6px;
  font-size: 13px;
  color: var(--ink);
  outline: none;
  cursor: pointer;
  transition: border-color 0.15s ease;
  color-scheme: dark;
}
/* Only the <select> carries the dropdown chevron. */
.academic-select {
  padding-right: 30px;
  background-image: url("data:image/svg+xml,%3Csvg width='10' height='6' viewBox='0 0 10 6' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1L5 5L9 1' stroke='%2371717a' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 10px center;
  background-size: 10px;
}
html:not(.dark) .academic-input,
html:not(.dark) .academic-select { color-scheme: light; }
.academic-input { flex: 1; min-width: 110px; }
.academic-input.sm { flex: 0 0 70px; min-width: 0; }
.academic-input:focus,
.academic-select:focus { border-color: var(--accent); }
.academic-submit {
  padding: 8px 14px;
  border: none;
  border-radius: 6px;
  background: var(--accent);
  color: #fff;
  font-size: 13px;
  cursor: pointer;
  transition: filter 0.15s ease;
}
.academic-submit:hover { filter: brightness(1.1); }

/* Kind / type chip (rendered by KindChip with an inline --chip colour) */
.kind-chip {
  --chip: var(--muted);
  display: inline-flex;
  align-items: center;
  padding: 2px 10px;
  border-radius: 999px;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.02em;
  white-space: nowrap;
  flex-shrink: 0;
  background: color-mix(in oklch, var(--chip) 15%, transparent);
  color: color-mix(in oklch, var(--chip) 72%, var(--ink));
  border: 1px solid color-mix(in oklch, var(--chip) 30%, transparent);
}

/* Deadlines */
.deadline-buckets { display: flex; flex-direction: column; gap: 14px; }
.service-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 205px), 1fr));
  gap: 8px;
  align-items: start;
}
.deadline-bucket { display: flex; flex-direction: column; gap: 5px; }
.deadline-bucket-title {
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--muted);
}
/* ── Meta-row — the one shared "tagged dated row" ──────────────────────────
   Deadlines, bills, claims, documents, submissions, proposals, calls, contacts
   all render through it (component: MetaRow). A flat, quiet row that reveals its
   background and its edit/delete on hover. The leading tag — a coloured chip or
   the status-pill — carries the category; urgency rides the date stamp
   (soon→accent, overdue→danger, plus a faint danger wash on the row), per the
   three-note scale; done/received dims and strikes the title. Trailing metadata
   wraps to a calm second line when the column is narrow — the title's min-width
   is the wrap threshold. One ruleset for what used to be five (.deadline-row,
   .bill-item, .reimb-item, .doc-item, and the .reminder-item reuse).
   See DESIGN.md §3 "meta-row". */
.meta-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 3px; }
.meta-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 9px;
  row-gap: 4px;
  padding: 8px 9px 8px 7px;
  border-radius: var(--radius-sm);
  transition: background 0.12s ease;
}
.meta-row:hover { background: var(--surface-2); }
.meta-row.overdue { background: var(--danger-soft); }
.meta-row.done,
.meta-row.received { opacity: 0.6; }
.meta-row.done .meta-row-title,
.meta-row.received .meta-row-title { color: var(--muted); text-decoration: line-through; }
.meta-row-title { flex: 1 1 auto; min-width: 9ch; font-size: 14px; color: var(--ink); overflow-wrap: break-word; }
.meta-row-sub { color: var(--muted); font-size: 12px; }
.meta-row-mono { flex-shrink: 0; font-family: var(--font-mono); font-size: 11.5px; color: var(--muted); }
.meta-row-value { flex-shrink: 0; font-size: 13px; color: var(--ink-2); }
.meta-row .btn-edit,
.meta-row .btn-delete { opacity: 0.5; }
.meta-row:hover .btn-edit,
.meta-row:hover .btn-delete { opacity: 1; }

/* Service — institutional service items as cards whose title can wrap to two
   lines without crowding the chip and due date. */
.service-card {
  display: flex;
  flex-direction: column;
  gap: 9px;
  padding: 11px 12px;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-left: 3px solid var(--row-accent, var(--line-2));
  transition: border-color 0.15s ease, background 0.15s ease;
}
.service-card:hover {
  background: color-mix(in oklch, var(--surface-2) 55%, var(--surface));
  border-color: var(--line-2);
}
/* Card layout: chip + actions on top, the title as the primary line, the due
   date as a muted footer. Actions hug the right edge and reveal on hover. */
.service-card-top { display: flex; align-items: center; gap: 8px; min-width: 0; }
.service-card-actions { margin-left: auto; display: flex; align-items: center; gap: 2px; flex-shrink: 0; }
.service-card .service-title {
  font-size: 13.5px;
  line-height: 1.4;
  color: var(--ink);
  overflow-wrap: break-word;
  text-wrap: pretty;
}
.service-card .btn-delete { opacity: 0.5; }
.service-card:hover .btn-delete { opacity: 1; }
/* Inline editor: stack the fields and right-align the Save/Cancel actions. */
.service-card-edit { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.service-card-edit .academic-input,
.service-card-edit .academic-select { width: 100%; }
.service-card-edit-actions { display: flex; gap: 6px; justify-content: flex-end; }

/* Generic inline-row editor (deadlines, reading list, …). An edit form packs a
   select + text input + date picker + buttons; in a row that's a guaranteed
   horizontal overflow on any narrow card. So the editor ALWAYS stacks its fields
   into a full-width column (at every viewport, not just mobile — the same fields
   never fit a half-panel either) with the actions right-aligned beneath. It fills
   the row via flex:1, so any sibling checkbox keeps its place to the left. */
.row-edit { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 8px; }
.row-edit .academic-input,
.row-edit .academic-select,
.row-edit .todo-input,
.row-edit .dp-wrap { flex: none; width: 100%; }
.row-edit-actions { display: flex; gap: 6px; justify-content: flex-end; }

/* Teaching — each course is a group: a header (label + progress) sits above an
   indented checklist of its tasks, with a compact add row at the foot. */
.teaching-course {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 12px 14px;
  margin-bottom: 10px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
}
/* flex-wrap + a wrappable pill keep a long course name from pushing the
   done/percent count off the right edge in a narrow (single-column) panel. */
.teaching-course-head { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.teaching-course-rename { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; width: 100%; }
/* Let the rename field grow to the row width (overriding .academic-input.sm's
   fixed 70px) so it isn't a cramped sliver beside the Save/Cancel buttons. */
.teaching-course-rename .academic-input { flex: 1 1 120px; min-width: 0; }
.course-pill {
  flex-shrink: 0;
  min-width: 0;
  white-space: normal;
  overflow-wrap: anywhere;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 3px 9px;
  border-radius: 6px;
  background: var(--accent);
  color: #fff;
  cursor: default;
}
.teaching-count {
  margin-left: auto;
  display: flex;
  align-items: baseline;
  gap: 7px;
  flex-shrink: 0;
  font-variant-numeric: tabular-nums;
}
.teaching-count-frac { font-size: 11.5px; color: var(--muted); }
.teaching-count-pct { font-size: 12.5px; font-weight: 600; color: var(--ink-2, var(--ink)); }
.teaching-progress {
  width: 100%;
  height: 5px;
  background: color-mix(in oklch, var(--surface) 60%, var(--line));
  border-radius: 999px;
  overflow: hidden;
}
.teaching-progress-fill { height: 100%; background: var(--accent); border-radius: 999px; transition: width 0.3s ease; }

/* Task checklist inside a course */
.teaching-task-list { display: flex; flex-direction: column; gap: 2px; margin-top: 2px; }
.teaching-task-list .todo-list { gap: 0; }
.teaching-task {
  display: flex;
  align-items: center;
  gap: 9px;
  padding: 4px 6px;
  border-radius: 6px;
  transition: background 0.12s ease;
}
.teaching-task:hover { background: color-mix(in oklch, var(--surface) 55%, transparent); }
.teaching-task input[type="checkbox"] {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  accent-color: var(--accent);
  cursor: pointer;
}
.teaching-task-input {
  flex: 1;
  min-width: 0;
  background: none;
  border: none;
  outline: none;
  padding: 2px 0;
  font-size: 13.5px;
  line-height: 1.4;
  color: var(--ink);
  border-bottom: 1px solid transparent;
  transition: border-color 0.15s ease;
}
.teaching-task-input::placeholder { color: var(--muted); }
.teaching-task-input:focus { border-bottom-color: var(--accent); }
.teaching-task.done .teaching-task-input { color: var(--muted); text-decoration: line-through; }
.teaching-task:hover .btn-delete { opacity: 0.6; }
.teaching-task:hover .btn-delete:hover { opacity: 1; }

/* Compact add row at the foot of the checklist */
.teaching-add-row { display: flex; align-items: center; gap: 7px; margin-top: 4px; padding-left: 6px; }
.teaching-add-input {
  flex: 1;
  min-width: 0;
  background: none;
  border: none;
  outline: none;
  padding: 4px 0;
  font-size: 13px;
  color: var(--ink);
  border-bottom: 1px solid var(--line);
  transition: border-color 0.15s ease;
}
.teaching-add-input::placeholder { color: var(--muted); }
.teaching-add-input:focus { border-bottom-color: var(--accent); }
.teaching-add-btn-icon {
  flex-shrink: 0;
  width: 24px;
  height: 24px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 6px;
  background: var(--accent-soft);
  color: var(--accent);
  font-size: 16px;
  line-height: 1;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}
.teaching-add-btn-icon:hover { background: var(--accent); color: #fff; }

/* ── Search results ───────────────────────────────────────────────────── */
.search-results { display: flex; flex-direction: column; gap: 6px; }
.search-result-item {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 11px 14px;
  background: var(--panel-bg);
  border: 1px solid var(--line);
  border-left: 3px solid var(--line-2);
  border-radius: var(--radius-sm);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  transition: background 0.15s ease, border-color 0.15s ease;
}
.search-result-item:hover { background: var(--surface-2); }
.search-highlight {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}
.search-result-cat {
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  flex-shrink: 0;
  width: 80px;
}
.search-result-type {
  font-size: 11px;
  color: var(--muted);
  flex-shrink: 0;
  width: 70px;
}
.search-result-text { flex: 1; min-width: 0; font-size: 14px; color: var(--ink); overflow-wrap: break-word; }
.search-empty {
  padding: 40px;
  text-align: center;
  color: var(--muted);
  font-style: italic;
}

/* ── Sync bar (footer) ────────────────────────────────────────────────── */
.sync-bar {
  display: flex;
  gap: 6px;
  align-items: center;
  margin-top: 36px;
  padding-top: 18px;
  border-top: 1px solid var(--line);
}
.sync-btn {
  padding: 6px 14px;
  background: none;
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--ink-2);
  font-size: 12.5px;
  cursor: pointer;
  transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease;
}
.sync-btn:hover { border-color: var(--line-2); color: var(--ink); background: var(--surface-2); }
.sync-btn.sync-btn-primary {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
.sync-btn.sync-btn-primary:hover { filter: brightness(1.1); }

/* ── Keyboard hints ───────────────────────────────────────────────────── */
.keyboard-hints {
  position: fixed;
  bottom: 16px;
  left: 16px;
  display: flex;
  align-items: baseline;
  gap: 14px;
  font-size: 11px;
  color: var(--muted);
  opacity: 0.5;
  transition: opacity 0.2s ease;
  z-index: 50;
}
.keyboard-hints:hover { opacity: 1; }

/* ── Undo toast ───────────────────────────────────────────────────────── */
.undo-toast {
  position: fixed;
  bottom: 24px;
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 10px 18px;
  background: var(--ink);
  color: var(--bg);
  border-radius: 999px;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  z-index: 200;
  box-shadow: 0 10px 30px oklch(0 0 0 / 0.35);
  animation: toastIn 0.25s ease;
}
@keyframes toastIn {
  from { transform: translateX(-50%) translateY(16px); opacity: 0; }
  to   { transform: translateX(-50%) translateY(0); opacity: 1; }
}
.undo-toast-btn {
  background: transparent;
  border: 1px solid color-mix(in oklch, var(--bg) 35%, transparent);
  color: var(--bg);
  padding: 3px 12px;
  border-radius: 999px;
  font-size: 12px;
  cursor: pointer;
}

/* ── Modals ───────────────────────────────────────────────────────────── */
.modal-overlay {
  position: fixed;
  inset: 0;
  z-index: 300;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: oklch(0 0 0 / 0.55);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}
.modal {
  width: 100%;
  max-width: 440px;
  max-height: 88vh;
  overflow-y: auto;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 26px;
  box-shadow: 0 24px 60px oklch(0 0 0 / 0.4);
}
.modal-header {
  font-family: var(--font-serif);
  font-size: 24px;
  font-weight: 400;
  letter-spacing: -0.01em;
  margin-bottom: 18px;
  color: var(--ink);
}
.modal-field { display: flex; flex-direction: column; gap: 6px; margin-bottom: 14px; position: relative; }
.modal-field label { font-size: 12.5px; font-weight: 500; color: var(--ink-2); }

/* Help hint (?) with hover tooltip */
.help-hint {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 15px;
  height: 15px;
  margin-left: 6px;
  border-radius: 50%;
  background: var(--surface-2);
  border: 1px solid var(--line);
  color: var(--muted);
  font-size: 10px;
  font-weight: 600;
  cursor: help;
  outline: none;
  vertical-align: middle;
}
.help-hint:hover, .help-hint:focus { border-color: var(--accent); color: var(--accent); }
.help-tooltip {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  z-index: 50;
  width: auto;
  padding: 10px 12px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
  color: var(--ink-2);
  font-size: 12px;
  font-weight: 400;
  line-height: 1.5;
  text-align: left;
  white-space: normal;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition: opacity 0.15s ease, transform 0.15s ease, visibility 0.15s;
}
.help-hint:hover .help-tooltip, .help-hint:focus .help-tooltip {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}
.help-tooltip ol { margin: 6px 0 6px 16px; padding: 0; }
.help-tooltip li { margin-bottom: 4px; }
.help-tooltip code {
  background: var(--surface-2);
  padding: 1px 4px;
  border-radius: 3px;
  font-size: 11px;
}
.modal-input {
  width: 100%;
  padding: 10px 12px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  font-size: 14px;
  color: var(--ink);
  outline: none;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.modal-input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.modal-security-note {
  font-size: 12px;
  line-height: 1.5;
  color: var(--muted);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 10px 12px;
  margin-bottom: 14px;
}

.modal-gist-link {
  font-size: 11.5px;
  color: var(--accent);
  text-decoration: none;
  margin-top: 2px;
}

.modal-gist-link:hover { text-decoration: underline; }
.modal-error {
  font-size: 13px;
  color: var(--danger);
  background: var(--danger-soft);
  border-radius: var(--radius-sm);
  padding: 8px 12px;
  margin-bottom: 14px;
}
.modal-actions { display: flex; justify-content: flex-end; gap: 10px; margin-top: 20px; }
.modal-btn {
  padding: 9px 16px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--ink);
  font-size: 13.5px;
  cursor: pointer;
  transition: background 0.15s ease, filter 0.15s ease;
}
.modal-btn-cancel:hover { background: var(--surface); }
.modal-btn-primary {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}
.modal-btn-primary:hover { filter: brightness(1.1); }

/* ── Welcome / help guide ─────────────────────────────────────────────── */
.modal-welcome { max-width: 520px; }
.welcome-lede {
  margin: 0 0 18px;
  font-size: 14px;
  line-height: 1.6;
  color: var(--ink-2);
}
.welcome-section-label {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 18px 0 8px;
}
.welcome-tabs { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 7px; }
.welcome-tab {
  display: grid;
  grid-template-columns: auto auto 1fr;
  align-items: baseline;
  gap: 10px;
  padding: 8px 11px;
  border: 1px solid var(--line);
  border-left: 3px solid var(--cat);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
}
.welcome-tab-key {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border-radius: 5px;
  background: var(--cat);
  color: #fff;
  font-size: 11px;
  font-weight: 600;
}
.welcome-tab-name { font-weight: 600; font-size: 13.5px; color: var(--ink); }
.welcome-tab-desc { font-size: 12.5px; color: var(--muted); }
.welcome-points { margin: 0; padding-left: 18px; display: flex; flex-direction: column; gap: 7px; }
.welcome-points li { font-size: 13px; line-height: 1.55; color: var(--ink-2); }
.welcome-points kbd {
  font-family: var(--font-mono, monospace);
  font-size: 11px;
  padding: 1px 5px;
  border: 1px solid var(--line);
  border-bottom-width: 2px;
  border-radius: 4px;
  background: var(--surface-2);
  color: var(--ink);
}
.welcome-gear { font-size: 13px; }

/* ── Help FAB (sits beside the settings gear) ─────────────────────────── */
/* The help (?) FAB sits beside the Tweaks (⚙) launcher; both are a matched pair
   of floating glass buttons. They share theme/hue-aware tokens so they adapt to
   light/dark and the accent hue instead of being pinned to a dark-glass look. */
.help-fab {
  position: fixed;
  bottom: 20px;
  right: 68px;
  width: 40px;
  height: 40px;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: var(--panel-bg);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  color: var(--accent);
  font-size: 18px;
  font-weight: 600;
  cursor: pointer;
  z-index: 99998;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: var(--panel-shadow);
  transition: border-color 0.15s ease, filter 0.15s ease;
}
.help-fab:hover { border-color: var(--line-2); filter: brightness(1.12); }

/* ── DatePicker ──────────────────────────────────────────────────────────── */
/* When the .academic-input class is applied to the dp-wrap, suppress the
   select-arrow background-image and extra padding that class normally adds. */
.dp-wrap.academic-input {
  background-image: none;
  padding: 0;
  cursor: default;
  flex: 0 0 auto;
  min-width: 0;
}
.dp-wrap { position: relative; display: inline-flex; }
.dp-trigger {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 10px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 6px;
  color: var(--ink);
  font-size: 13px;
  cursor: pointer;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
  white-space: nowrap;
  min-width: 120px;
  text-align: left;
}
.dp-small .dp-trigger { font-size: 12px; padding: 5px 8px; min-width: 0; }
/* Empty state shows the field's purpose (e.g. "Abstract due"), so render it at
   ink-2 — legible as a label, not a faint placeholder. */
.dp-trigger--empty .dp-value { color: var(--ink-2); }
.dp-trigger--open { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-soft); }
.dp-trigger:hover:not(.dp-trigger--open) { border-color: var(--ink-3, var(--muted)); }
.dp-icon { display: flex; align-items: center; color: var(--muted); flex-shrink: 0; }
.dp-trigger--open .dp-icon { color: var(--accent); }
.dp-value { flex: 1; }
.dp-clear {
  margin-left: 2px;
  color: var(--muted);
  font-size: 15px;
  line-height: 1;
  padding: 0 2px;
  border-radius: 3px;
  cursor: pointer;
  transition: color 0.1s;
}
.dp-clear:hover { color: var(--danger); }

/* popover card */
.dp-popover {
  position: fixed;
  z-index: 9999;
  width: 240px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 10px;
  box-shadow: 0 12px 32px oklch(0 0 0 / 0.28);
  padding: 10px;
  animation: dp-in 0.12s ease;
}
@keyframes dp-in {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* header row: < Month Year > */
.dp-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
}
.dp-nav {
  background: none;
  border: none;
  color: var(--muted);
  font-size: 18px;
  line-height: 1;
  cursor: pointer;
  padding: 2px 6px;
  border-radius: 5px;
  transition: background 0.1s, color 0.1s;
}
.dp-nav:hover { background: var(--surface-2); color: var(--ink); }
.dp-month-label {
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
  letter-spacing: 0.01em;
}

/* day grid */
.dp-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 2px;
}
.dp-dayname {
  font-size: 10px;
  font-weight: 600;
  color: var(--muted);
  text-align: center;
  padding: 2px 0 5px;
  letter-spacing: 0.04em;
}
.dp-day {
  background: none;
  border: none;
  border-radius: 6px;
  font-size: 12.5px;
  color: var(--ink-2);
  cursor: pointer;
  padding: 5px 0;
  text-align: center;
  transition: background 0.1s, color 0.1s;
}
.dp-day:hover { background: var(--surface-2); color: var(--ink); }
.dp-day--today {
  font-weight: 700;
  color: var(--accent);
}
.dp-day--selected {
  background: var(--accent) !important;
  color: #fff !important;
  font-weight: 600;
}

/* time row shown when DatePicker is used with `withTime` */
.dp-time-row {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid var(--line);
}
.dp-time-icon { display: inline-flex; color: var(--muted); flex-shrink: 0; }
.dp-time-select {
  padding: 5px 7px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 7px;
  font: inherit;
  font-size: 12.5px;
  color: var(--ink);
  cursor: pointer;
  font-variant-numeric: tabular-nums;
}
.dp-time-select:focus { outline: none; border-color: var(--accent); }
.dp-time-colon { color: var(--muted); font-weight: 600; }
.dp-done {
  margin-left: auto;
  padding: 5px 12px;
  background: var(--accent);
  color: #fff;
  border: none;
  border-radius: 7px;
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
}
.dp-done:hover { filter: brightness(1.06); }

/* ── Goals ────────────────────────────────────────────────────────────── */
.goal-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.goal-item {
  padding: 9px 10px;
  border: 1px solid var(--line);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  transition: opacity 0.15s ease, border-color 0.15s ease;
}
.goal-item.achieved {
  opacity: 0.6;
  border-left-color: var(--accent-soft);
}
.goal-row {
  display: flex;
  align-items: center;
  gap: 8px;
}
.goal-star {
  flex-shrink: 0;
  background: none;
  border: none;
  padding: 0;
  font-size: 17px;
  line-height: 1;
  color: var(--muted);
  cursor: pointer;
  transition: color 0.12s ease, transform 0.12s ease;
}
.goal-star:hover { transform: scale(1.15); }
.goal-star.achieved { color: var(--accent); }
.goal-text-input {
  flex: 1;
  min-width: 0;
  background: none;
  border: none;
  padding: 2px 0;
  font-size: 14.5px;
  font-weight: 500;
  color: var(--ink);
}
.goal-text-input:focus { outline: none; }
.goal-item.achieved .goal-text-input {
  text-decoration: line-through;
  color: var(--muted);
}
.goal-item .auto-textarea {
  margin-top: 4px;
  font-size: 12.5px;
  color: var(--muted);
}

/* ── Mobile menu: hamburger + right slide-out drawer ──────────────────────
   The trigger, overlay and drawer exist at all sizes but only surface on mobile
   (the hamburger is display:none on desktop, so the drawer is never opened there
   and just rests off-screen). The drawer collects everything the desktop keeps
   in its top bar / footer / FABs: search, the data actions, help and tweaks.
   Defined BEFORE the Small-screens block so that block's `display:` overrides
   win on source order (media queries add no specificity). */
.menu-fab {
  display: none;  /* shown only ≤900px (see Small screens) */
  position: absolute;
  top: 0;
  right: 0;
  width: 40px;
  height: 40px;
  align-items: center;
  justify-content: center;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: var(--panel-bg);
  color: var(--ink-2);
  cursor: pointer;
  transition: border-color 0.15s ease, color 0.15s ease;
}
.menu-fab:hover { border-color: var(--line-2); color: var(--ink); }

.menu-overlay {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: color-mix(in oklch, var(--bg) 45%, transparent);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.2s ease, visibility 0.2s ease;
}
.menu-overlay.open { opacity: 1; visibility: visible; }

.menu-drawer {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  z-index: 201;
  width: min(82vw, 320px);
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: calc(16px + env(safe-area-inset-top)) 16px calc(20px + env(safe-area-inset-bottom));
  background: var(--surface);
  border-left: 1px solid var(--line);
  box-shadow: var(--panel-shadow-raised);
  transform: translateX(100%);
  transition: transform 0.24s cubic-bezier(0.4, 0, 0.2, 1);
  overflow-y: auto;
}
.menu-drawer.open { transform: translateX(0); }

.menu-drawer-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.menu-drawer-title { font-family: var(--font-serif); font-size: 20px; color: var(--ink); }
.menu-close {
  width: 34px;
  height: 34px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 8px;
  border: 1px solid var(--line);
  background: none;
  color: var(--muted);
  cursor: pointer;
  transition: border-color 0.15s ease, color 0.15s ease;
}
.menu-close:hover { border-color: var(--line-2); color: var(--ink); }

.menu-search {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 12px;
  border-radius: var(--radius);
  background: var(--surface-2);
  border: 1px solid var(--line);
  color: var(--muted);
  transition: border-color 0.15s ease;
}
.menu-search:focus-within { border-color: var(--accent); color: var(--accent); }
.menu-search-input {
  flex: 1;
  min-width: 0;
  background: none;
  border: none;
  outline: none;
  font: inherit;
  font-size: 14px;
  color: var(--ink);
}

.menu-actions { display: flex; flex-direction: column; gap: 6px; margin-top: 2px; }
.menu-action {
  text-align: left;
  padding: 11px 13px;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--ink-2);
  font: inherit;
  font-size: 14px;
  cursor: pointer;
  transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease;
}
.menu-action:hover { border-color: var(--line-2); color: var(--ink); }
.menu-action-primary { background: var(--accent); border-color: var(--accent); color: #fff; }
.menu-action-primary:hover { filter: brightness(1.08); color: #fff; }

/* ── Responsive ───────────────────────────────────────────────────────── */
/* ══ Small screens ════════════════════════════════════════════════════════
   ONE breakpoint, and only one — never add an ad-hoc per-tab breakpoint
   elsewhere (see DESIGN.md §8). This is the single source of truth for how the
   board reflows narrow, and it is exactly what the iOS app (a WKWebView of these
   same files) renders at phone width.

   Below 900px the whole desktop layout — multi-column panels AND the horizontal
   top chrome (the six-tab bar + right-aligned search) — gives way together to
   the single-column mobile layout. They share a breakpoint deliberately: the
   width where two columns stop fitting is the same width where the tab bar stops
   fitting, so splitting them only ever reopened a zone where one had collapsed
   but the other still overflowed.

   The mobile layout is two promises:
   1. EVERY panel is a single full-width column, one per row, in source order.
   2. That column is sized to 90% of the viewport — 5vw gutters either side —
      with the chrome (header, nav, search, toolbar) stacked/wrapped to match. */

@media (max-width: 900px) {
  /* ── 1 · Single column: every tab's multi-column layout collapses ──────── */
  .panels-academic { grid-template-columns: 1fr; }
  .panels-academic > .panel { grid-column: 1 / -1; }
  /* flex-direction:column + stretch so each stacked column (and the panels in
     it) fills the full width — otherwise the inherited align-items:flex-start
     shrinks every panel to its content width instead of the 90% column. */
  .panels-household,
  .panels-health,
  .panels-finance,
  .panels-travel { flex-direction: column; align-items: stretch; }
  .research-columns { flex-direction: column; }
  .panels-col { width: 100%; }

  /* The two-column balance caps (lists scroll within their panel so one long
     column doesn't tower over its neighbour) have no neighbour once stacked —
     release them so the page scrolls as one, avoiding nested scroll on touch. */
  .panels-household .chore-list,
  .panels-household .todo-list,
  .panels-household .goal-list,
  .panels-health .habits-list,
  .panels-health .todo-list,
  .panels-health .goal-list { max-height: none; }

  /* ── 2 · Compact mobile chrome ─────────────────────────────────────────── */
  /* 5vw gutters ⇒ panels span 90vw; bottom padding clears the fixed tab bar. */
  .app { padding: 24px 5vw calc(80px + env(safe-area-inset-bottom)); }
  .greeting { font-size: 28px; }
  /* Kill rubber-band overscroll so it can't drag the fixed bottom bar with it
     (the bar appearing to un-stick on an upward bounce). */
  html, body { overscroll-behavior-y: none; }
  /* The Projects panel tiles cards into two columns on the wide desktop panel;
     in the single-column mobile panel that grid can't fit (two 260px-min tracks
     in a ~90vw panel) and the cards squeeze/overflow — collapse to one column. */
  .projects-list { grid-template-columns: 1fr; }
  /* Time and date step down so they sit quietly beside the greeting rather than
     rivalling it once the header is stacked. */
  .clock-time { font-size: 22px; }
  .header-date { font-size: 13px; letter-spacing: 0.06em; }
  /* Stack the header; the hamburger pins to its top-right corner (header-left
     reserves room for it so the greeting wraps before reaching it). */
  .app-header { position: relative; flex-direction: column; align-items: flex-start; gap: 12px; }
  .header-left { width: 100%; padding-right: 48px; }
  .header-right { width: 100%; align-items: flex-start; }
  .header-sub.header-sub-right { align-items: flex-start; }
  .menu-fab { display: inline-flex; }

  /* Tabs become a fixed bottom bar (native-app style): six evenly-spread icons,
     no labels, no search — so navigation is always on screen and never scrolls
     away. Active state is the accent-tinted icon (no border indicator).
     NB: an OPAQUE background, not the frosted backdrop-filter used elsewhere —
     `backdrop-filter` on a `position: fixed` element is a known iOS WebKit bug
     that detaches it and lets it scroll with the page (the "tab bar isn't sticky
     going up" symptom). The solid fill sidesteps it. */
  .tab-nav {
    position: fixed;
    inset: auto 0 0 0;
    margin: 0;
    z-index: 40;
    gap: 0;
    border-top: 1px solid var(--line);
    border-bottom: none;
    background: var(--surface);
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    padding-bottom: env(safe-area-inset-bottom);
  }
  .tab-btn { flex: 1; justify-content: center; gap: 0; padding: 11px 0; border: none; }
  .tab-icon { width: 23px; height: 23px; }
  .tab-label,
  .tab-search { display: none; }

  /* Help, Tweaks, the search and the data actions all move into the drawer. */
  .help-fab,
  .sync-bar,
  .keyboard-hints { display: none; }
  /* The Tweaks launcher toggles its own display inline, so override with
     !important to keep it out of the mobile chrome (it lives in the drawer). */
  .tw-fab { display: none !important; }

  /* ── 3 · Expanded-card rows: stack label + fixed-width controls ───────────
     A flex row pairing a flexible text label with fixed-width controls (money
     inputs, paired date pickers) squeezes the label to a one-character vertical
     sliver at phone width — the "Travel"/"Equipment" budget heads rendered as a
     column of letters. Stack them instead: the label takes its own line and the
     controls flow onto the next, each control flexing to share the width. */
  .grant-head-top,
  .budget-top { flex-wrap: wrap; }
  .grant-head-name,
  .budget-cat { flex-basis: 100%; }
  .grant-head-figures { width: 100%; }
  .grant-head-field { flex: 1; min-width: 0; }
  .grant-head-amount,
  .budget-spent { flex: 1; width: auto; min-width: 0; }

  /* Trip start/end pickers can't sit side by side at 90vw — stack them, and
     turn the "→" separator to point down between the two fields. */
  .trip-date-row { flex-direction: column; align-items: stretch; }
  .trip-date-sep { align-self: center; transform: rotate(90deg); }

  /* Chore name takes its own line; frequency, status and the action cluster
     (.chore-actions) then share the next line without a button orphaning. */
  .chore-name { flex-basis: 100%; }

  /* ── 4 · Touch has no hover: surface the actions desktop reveals on hover ──
     Edit/delete/undo idle at opacity 0 (or 0.5) and appear on row hover; a
     phone has no hover, so they'd be invisible/unreachable. Show them always. */
  .btn-edit,
  .btn-delete,
  .btn-chore-undo,
  .service-card .btn-edit,
  .budget-item .btn-delete,
  .invest-item .btn-delete,
  .grant-head-item .btn-delete { opacity: 1; }
}

/* ══ Finance & Travel tabs (finance.jsx / travel.jsx) ═════════════════════ */

/* Both tabs use the two-column flex layout, like Household / Health. */
.panels-finance,
.panels-travel {
  column-count: unset;
  display: flex;
  align-items: flex-start;
  gap: var(--gap);
}
.panels-travel-wrap { display: flex; flex-direction: column; gap: var(--gap); }
/* Single-column collapse is standardized in the "Small screens" section. */

/* Shared money styling */
.money { font-variant-numeric: tabular-nums; }
.money-pos { color: var(--gain); }
.money-neg { color: var(--loss); }
.money-input { font-variant-numeric: tabular-nums; text-align: right; }
.money-input::-webkit-outer-spin-button,
.money-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.money-input { -moz-appearance: textfield; }
.todo-input.money-input { flex: 0 0 96px; min-width: 0; text-align: left; }

/* A muted summary line under a panel's add row (totals, portfolio, etc.). */
.fin-summary {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  font-size: 12px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  padding: 2px 2px 4px;
  border-bottom: 1px solid var(--line);
}
.fin-summary.invest-summary { flex-wrap: wrap; }
.fin-summary .money { color: var(--ink-2); font-weight: 600; }

/* ── Grants ── */
.grant-list { display: flex; flex-direction: column; gap: 9px; }
.grant-title { flex: 1; min-width: 0; }
.grant-remaining { flex-shrink: 0; font-size: 13px; color: var(--ink-2); font-variant-numeric: tabular-nums; }
.grant-details { display: flex; flex-direction: column; gap: 12px; }
.grant-fields { display: flex; flex-wrap: wrap; gap: 10px; }
.grant-fields label { display: flex; flex-direction: column; gap: 4px; font-size: 11.5px; color: var(--muted); }
.grant-fields label:first-child { flex: 1 1 100%; }
.grant-input {
  width: 110px;
  padding: 5px 8px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 6px;
  color: var(--ink);
  font-size: 12.5px;
  outline: none;
  transition: border-color 0.15s ease;
}
.grant-input:focus { border-color: var(--accent); }
.grant-summary { display: flex; gap: 14px; flex-wrap: wrap; font-size: 12px; color: var(--ink-2); font-variant-numeric: tabular-nums; }
.grant-heads-label { font-size: 11.5px; color: var(--muted); margin-bottom: 6px; }
.grant-head-list { list-style: none; margin: 6px 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.grant-head-item { display: flex; flex-direction: column; gap: 6px; padding: 7px 8px; border-radius: var(--radius-sm); transition: background 0.12s ease; }
.grant-head-item:hover { background: var(--surface-2); }
.grant-head-top { display: flex; align-items: center; gap: 9px; }
.grant-head-figures { display: flex; align-items: center; gap: 6px; font-size: 11.5px; color: var(--muted); }
.grant-head-field { display: inline-flex; align-items: center; gap: 4px; }
.grant-head-sep { color: var(--muted); }
.grant-head-item.over .grant-head-name { color: var(--loss); }
.grant-head-name { flex: 1; min-width: 0; font-size: 13.5px; color: var(--ink); overflow-wrap: break-word; }
.grant-head-amount {
  width: 100px;
  padding: 4px 7px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 6px;
  color: var(--ink);
  font-size: 12.5px;
  outline: none;
  text-align: right;
  transition: border-color 0.15s ease;
}
.grant-head-amount:focus { border-color: var(--accent); }
.grant-head-item .btn-delete { opacity: 0; }
.grant-head-item:hover .btn-delete { opacity: 1; }

/* ── Budgets & Savings ── */
.budget-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 9px; }
.budget-item {
  display: flex;
  flex-direction: column;
  gap: 7px;
  padding: 10px 12px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
}
.budget-top { display: flex; align-items: center; gap: 8px; }
.budget-cat { flex: 1; min-width: 0; font-size: 13.5px; color: var(--ink); overflow-wrap: break-word; }
.budget-figures {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
  font-size: 12px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.budget-spent,
.invest-input {
  width: 88px;
  padding: 5px 8px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 6px;
  color: var(--ink);
  font-size: 12.5px;
  outline: none;
  transition: border-color 0.15s ease;
}
.budget-spent:focus,
.invest-input:focus { border-color: var(--accent); }
.budget-sep { white-space: nowrap; }
.budget-pct { font-weight: 600; color: var(--ink-2); min-width: 34px; text-align: right; }
.budget-item .btn-delete { opacity: 0.5; }
.budget-item:hover .btn-delete { opacity: 1; }
.budget-bar {
  width: 100%;
  height: 6px;
  background: color-mix(in oklch, var(--surface) 60%, var(--line));
  border-radius: 999px;
  overflow: hidden;
}
.budget-bar-fill { height: 100%; background: var(--finance); border-radius: 999px; transition: width 0.3s ease; }
.budget-bar-fill.over { background: var(--loss); }
.budget-bar-fill.savings { background: var(--accent); }
.budget-bar-fill.savings.done { background: var(--gain); }
.budget-bar-fill.done { background: var(--gain); }
.budget-item.over .budget-cat { color: var(--loss); }
.savings-item.done .budget-cat { color: var(--gain); }

/* ── Loans ── */
.loan-name { flex: 1; min-width: 0; font-size: 14px; color: var(--ink); overflow-wrap: break-word; }
.loan-lender { color: var(--muted); font-size: 12px; }
.loan-item.done .loan-name { color: var(--gain); }
.loan-meta { display: flex; flex-wrap: wrap; gap: 10px; font-size: 11.5px; color: var(--muted); font-variant-numeric: tabular-nums; }
.loan-paid { margin-left: auto; }
.loan-due.overdue { color: var(--danger); }
.loan-due.soon { color: var(--accent); }

/* ── Bills ── */
/* Status pill — a chip that is also a button: it cycles a workflow state
   (reimbursement status, submission stage, proposal status). Lives in a
   meta-row's leading slot. Visually a chip, behaviourally a button — one
   pattern, reused. See DESIGN.md §3. */
.reimb-status-btn {
  --chip: var(--muted);
  flex-shrink: 0;
  padding: 2px 10px;
  border-radius: 999px;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.02em;
  white-space: nowrap;
  cursor: pointer;
  background: color-mix(in oklch, var(--chip) 15%, transparent);
  color: color-mix(in oklch, var(--chip) 72%, var(--ink));
  border: 1px solid color-mix(in oklch, var(--chip) 30%, transparent);
  transition: filter 0.15s ease;
}
.reimb-status-btn:hover { filter: brightness(1.08); }

/* ── Investments ── */
.invest-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 9px; }
.invest-item {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 10px 12px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
}
.invest-row { display: flex; align-items: center; gap: 8px; }
.invest-name { flex: 1; min-width: 0; font-size: 13.5px; color: var(--ink); overflow-wrap: break-word; }
.invest-gain { flex-shrink: 0; font-size: 12px; font-weight: 600; }
.invest-item .btn-delete { opacity: 0.5; }
.invest-item:hover .btn-delete { opacity: 1; }
.invest-figures { display: flex; flex-wrap: wrap; gap: 12px; }
.invest-figures label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11.5px;
  color: var(--muted);
}

/* ── Trip action cards (TripAlerts) ── */
.trip-alerts { display: flex; flex-wrap: wrap; gap: 12px; }
.trip-alert {
  --trip-tone: var(--accent);
  flex: 1 1 240px;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 9px;
  padding: 12px 14px;
  background: color-mix(in oklch, var(--trip-tone) 8%, var(--panel-bg));
  border: 1px solid color-mix(in oklch, var(--trip-tone) 28%, transparent);
  border-left: 3px solid var(--trip-tone);
  border-radius: var(--radius-sm);
  box-shadow: var(--panel-shadow);
}
.trip-alert-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.trip-alert-dest { font-size: 15px; font-weight: 600; color: var(--ink); overflow-wrap: break-word; }
.trip-alert-countdown {
  flex-shrink: 0;
  font-size: 12px;
  font-weight: 600;
  color: var(--trip-tone);
  font-variant-numeric: tabular-nums;
}
.trip-alert-actions { display: flex; flex-wrap: wrap; gap: 6px; }
.trip-action-chip {
  padding: 4px 10px;
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 500;
  cursor: pointer;
  background: var(--surface-2);
  border: 1px solid var(--line);
  color: var(--ink-2);
  transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease;
}
.trip-action-chip:hover { border-color: var(--trip-tone); color: var(--trip-tone); }
.trip-action-chip.todo { cursor: default; color: var(--muted); }
.trip-action-chip.todo:hover { border-color: var(--line); color: var(--muted); }
.trip-alert-allset { font-size: 12.5px; font-weight: 600; color: var(--gain); }

/* ── Trips ── */
.trips-list { display: flex; flex-direction: column; gap: 9px; }
.trip-card .project-title-row { display: flex; align-items: center; gap: 8px; padding: 9px 11px; }
.trip-dest { flex: 1; min-width: 0; }
.trip-booked-count {
  flex-shrink: 0;
  font-size: 10.5px;
  font-weight: 600;
  color: var(--ink-2);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 1px 7px;
  font-variant-numeric: tabular-nums;
}
.trip-date-row { display: flex; align-items: center; gap: 8px; }
.trip-date-sep { color: var(--muted); }
.trip-bookings { display: flex; flex-wrap: wrap; gap: 7px; }
.trip-booking-toggle {
  padding: 5px 12px;
  border-radius: 999px;
  font-size: 12px;
  cursor: pointer;
  background: var(--surface);
  border: 1px solid var(--line);
  color: var(--ink-2);
  transition: all 0.15s ease;
}
.trip-booking-toggle:hover { border-color: var(--travel); color: var(--travel); }
.trip-booking-toggle.booked {
  background: color-mix(in oklch, var(--gain) 16%, transparent);
  border-color: color-mix(in oklch, var(--gain) 40%, transparent);
  color: var(--gain);
}

/* ── Wishlist ── */
.wishlist-note { color: var(--muted); font-size: 13px; }


/* Overleaf quick-link icon on collapsed project cards */
.project-overleaf-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  border-radius: 5px;
  color: oklch(0.62 0.17 145);
  text-decoration: none;
  opacity: 0.85;
  transition: opacity 0.15s ease, background 0.15s ease;
}
.project-overleaf-icon:hover {
  opacity: 1;
  background: oklch(0.62 0.17 145 / 0.14);
}


/* ════════════════ Research tab + current-view additions ════════════════ */

.panels-research {
  column-count: unset;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: var(--gap);
}
.panels-research > .panel { margin-bottom: 0; }
.research-columns {
  display: flex;
  align-items: flex-start;
  gap: var(--gap);
  width: 100%;
}
/* Single-column collapse is standardized in the "Small screens" section. */

/* muted "all deadlines passed" note on CFP cards */
.grant-due.muted { color: var(--muted); }

/* inline status selector on review / letter rows */
.status-select {
  appearance: none;
  -webkit-appearance: none;
  font: inherit;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.02em;
  background: transparent;
  border: 1px solid var(--line-2);
  border-radius: 999px;
  padding: 2px 8px;
  cursor: pointer;
}

/* advisee milestones */
.milestone-list { list-style: none; margin: 8px 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.milestone-item { display: flex; align-items: center; gap: 6px; }
.milestone-item.done .milestone-label { text-decoration: line-through; color: var(--muted); }
.milestone-label {
  flex: 1 1 auto;
  min-width: 0;
  font: inherit;
  font-size: 13px;
  color: var(--ink);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: 6px 8px;
  outline: none;
}
.milestone-label:focus { border-color: var(--accent); }

/* contacts */
.contact-list { display: flex; flex-direction: column; gap: 6px; margin-top: 8px; }
.contact-card {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: 8px;
}
.contact-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.contact-name { font-weight: 600; font-size: 13px; color: var(--ink); }
.contact-aff { font-size: 11px; color: var(--muted); }
.contact-note { font-size: 11px; color: var(--ink-2); }

/* weekly timetable */
.timetable-form { row-gap: 8px; }
.timetable { display: flex; flex-direction: column; gap: 12px; margin-top: 8px; }
.timetable-day { display: flex; flex-direction: column; gap: 6px; }
.timetable-day-name {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
}
.timetable-day.is-today .timetable-day-name { color: var(--accent); }
.timetable-slots { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.timetable-slot {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 10px;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-left: 3px solid var(--row-accent, var(--line-2));
  border-radius: 6px;
}
.timetable-time { font-variant-numeric: tabular-nums; font-size: 12px; font-weight: 600; color: var(--ink); white-space: nowrap; }
.timetable-course { flex: 1 1 auto; min-width: 0; font-size: 13px; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.timetable-room { font-size: 11px; color: var(--muted); white-space: nowrap; }

/* credits — sticky footer pinned to the bottom of the viewport. Sits below the
   corner fabs (z 50+) and pads its sides so the centred text clears them. */
/* In normal flow at the foot of the page. It used to be position:fixed, which
   floated it permanently over content and collided with the bottom-right FABs on
   narrow screens; as a static footer it sits above the page's bottom padding, so
   the FABs float in the empty space below it instead of on top of it. */
.app-credits {
  text-align: center;
  margin-top: 40px;
  padding: 16px 0 4px;
  border-top: 1px solid var(--line);
  font-size: 11px;
  color: var(--muted);
  letter-spacing: 0.02em;
}
.app-credits a {
  color: inherit;
  text-decoration: none;
  border-bottom: 1px solid var(--line-2);
  transition: color 0.15s ease, border-color 0.15s ease;
}
.app-credits a:hover { color: var(--ink); border-bottom-color: currentColor; }
.app-credits-sep { opacity: 0.5; margin: 0 6px; }
.welcome-credits {
  margin-top: 14px;
  text-align: center;
  font-size: 11px;
  color: var(--muted);
  letter-spacing: 0.02em;
}

/* ══ Reduced motion ═══════════════════════════════════════════════════════ */
/* Honour the OS "reduce motion" setting (DESIGN.md §6): keep state changes
   instant rather than animating toasts, popovers, and transitions. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
