/* ===== To Do — Notebook (light) + Notebook Dark =====
   Warm paper stock, slab-serif headings, forest-green ink. Hairlines carry the
   structure instead of shadows. Every color is a token here; component rules
   below never hardcode a hex, so both themes come from this one block. */

/* Bitter, self-hosted (public/fonts/) rather than pulled from Google's CDN:
   this is an installed offline-capable PWA, and a CDN font would silently fall
   back to the stack below whenever David opens it without a connection. Latin
   subset only, variable weight 600-700, cached by the service worker. */
@font-face {
  font-family: "Bitter";
  src: url("/fonts/bitter-latin.woff2") format("woff2");
  font-weight: 600 700;
  font-style: normal;
  font-display: swap;
}

:root {
  /* ---- Notebook light ---- */
  --bg: #f5f1e6;            /* page ground — warm paper */
  --bg2: #ede7d8;           /* secondary surface / tint base */
  --card: #fffdf7;          /* card surface — a shade brighter than the page */
  --ink: #22201a;           /* text */
  --ink-soft: #6f6857;      /* muted text */
  --line: #ded5c0;          /* hairline border — does the work shadows used to */

  /* Historical token NAMES kept (the whole stylesheet references them); only the
     VALUES are remapped to Notebook, exactly as the Popsicle migration did:
     --orange = primary accent (forest), --coral = danger, --teal = ink-blue for
     links/times, --green = success/money, --grape = second support hue (rust),
     --yellow = gold/warn. */
  --orange: #2f6b3f;        /* primary accent — forest ink */
  --coral: #a83232;         /* danger */
  --teal: #2c4a7c;          /* support hue #1 — ink blue (links, times) */
  --green: #2f6b3f;         /* success / money / good */
  --grape: #8a4418;         /* support hue #2 — rust (projects, birthdays) */
  --yellow: #9a7420;        /* gold / warn */

  --accent-ink: #ffffff;    /* text/icon on any bright fill */

  --accent-soft: #e2eadd;
  --teal-soft: #dde5f0;
  --grape-soft: #f2e4d6;
  --danger-soft: #f6e2e0;

  --grad: linear-gradient(135deg, #2f6b3f, #3d8450);   /* forest button fill */
  --shadow: 0 2px 6px rgba(34, 32, 26, .07);
  --shadow-soft: 0 1px 3px rgba(34, 32, 26, .05);

  --glass: rgba(245, 241, 230, .86);
  --toast-bg: #22201a;
  --toast-ink: #f5f1e6;
  --field: #fffdf7;
  --track: #ded5c0;

  /* Two roles: a slab serif for anything that titles something, a humanist
     system sans for everything read at length. Bitter is self-hosted; the
     fallbacks already ship on iPadOS/macOS/Windows, so a cold or offline
     first paint still lands in the right register. */
  --font-display: "Bitter", "Iowan Old Style", Georgia, "Times New Roman", serif;
  --font-body: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI",
    Roboto, Helvetica, Arial, sans-serif;

  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left: env(safe-area-inset-left, 0px);
  --safe-right: env(safe-area-inset-right, 0px);
}

:root[data-theme="dark"] {
  /* ---- Notebook Dark — ink on a warm-black page, not a cool one ---- */
  --bg: #1a1815;
  --bg2: #24211a;
  --card: #2b2720;
  --ink: #f0ebdd;
  --ink-soft: #a89e88;
  --line: #3d3829;

  --orange: #6aab72;        /* accent lifts to a readable sage on dark */
  --coral: #e0736a;
  --teal: #8fb3e8;
  --green: #6aab72;
  --grape: #d09154;
  --yellow: #d0a24d;

  --accent-ink: #16180f;    /* near-black on the lightened accent */

  --accent-soft: #23301f;
  --teal-soft: #1e2735;
  --grape-soft: #33261a;
  --danger-soft: #38221f;

  --grad: linear-gradient(135deg, #6aab72, #7cbc84);
  --shadow: 0 4px 14px rgba(0, 0, 0, .38);
  --shadow-soft: 0 2px 8px rgba(0, 0, 0, .30);

  --glass: rgba(26, 24, 21, .86);
  --toast-bg: #2b2720;
  --toast-ink: #f0ebdd;
  --field: #24211a;
  --track: #3d3829;
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
html, body {
  margin: 0; height: 100%;
  font-family: var(--font-body);
  color: var(--ink);
  background: radial-gradient(120% 80% at 50% 0%, var(--bg2), var(--bg));
  -webkit-font-smoothing: antialiased;
  overscroll-behavior-y: none;
}
body { transition: background-color .25s ease, color .25s ease; }
.hidden { display: none !important; }
button { font-family: inherit; cursor: pointer; border: none; background: none; color: inherit; }
input, textarea { font-family: inherit; }

/* ===== Lock screen ===== */
.lock-screen {
  position: fixed; inset: 0; z-index: 50;
  display: flex; align-items: center; justify-content: center;
  background: var(--grad);
  padding: calc(var(--safe-top) + 20px) 20px calc(var(--safe-bottom) + 20px);
}
.lock-card {
  width: 100%; max-width: 360px; text-align: center; color: #fff;
  touch-action: manipulation; -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
}
.lock-logo {
  width: 76px; height: 76px; margin: 0 auto 14px;
  background: rgba(255,255,255,.22); border-radius: 11px;
  display: flex; align-items: center; justify-content: center;
  font-size: 40px; font-weight: 800;
  box-shadow: 0 8px 24px rgba(0,0,0,.12);
}
.lock-title { margin: 0; font-size: 30px; font-weight: 800; letter-spacing: .3px; }
.lock-hint { margin: 6px 0 20px; opacity: .92; font-size: 15px; }
/* Boot splash: while we check Cloudflare Access, show only the logo/title —
   never the passcode prompt or keypad (which would flash for SSO users). */
.lock-screen.booting .lock-hint,
.lock-screen.booting .pin-dots,
.lock-screen.booting .pin-error,
.lock-screen.booting .keypad { display: none; }
.pin-dots { display: flex; gap: 16px; justify-content: center; height: 20px; margin-bottom: 6px; }
.pin-dot {
  width: 16px; height: 16px; border-radius: 50%;
  background: rgba(255,255,255,.32); transition: transform .15s, background .15s;
}
.pin-dot.filled { background: #fff; transform: scale(1.12); }
.lock-card.busy .pin-dot.filled { animation: pinpulse .9s ease-in-out infinite; }
@keyframes pinpulse { 50% { opacity: .35; } }
.lock-card.bad .pin-dots { animation: pinshake .35s; }
@keyframes pinshake { 20%, 60% { transform: translateX(-8px); } 40%, 80% { transform: translateX(8px); } }
.key:disabled { opacity: .5; }
.pin-error { min-height: 20px; font-size: 16px; color: #fff; font-weight: 600; margin-bottom: 6px; }
.keypad {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(8px, 1.8vh, 14px);
  max-width: 300px; margin: 8px auto 0; touch-action: manipulation;
}
.key {
  height: clamp(64px, 10vh, 84px); border-radius: 50%; touch-action: manipulation;
  font-size: clamp(26px, 4vh, 32px); font-weight: 600; color: #fff;
  background: rgba(255,255,255,.16);
  transition: transform .08s, background .15s;
}
.key:active { transform: scale(.92); background: rgba(255,255,255,.32); }
.key-ghost { background: transparent; font-size: 22px; }

/* ===== App shell ===== */
.app { display: flex; flex-direction: column; min-height: 100%; }
.topbar {
  position: sticky; top: 0; z-index: 35;   /* above .swipe-wrap.dragging (30) — a dragged card slides UNDER the header, never over it */
  padding: calc(var(--safe-top) + 16px) max(20px, var(--safe-right)) 12px max(20px, var(--safe-left));
  background: linear-gradient(180deg, var(--bg2) 60%, transparent);
}
.topbar-inner { width: 100%; }
.view-title { margin: 0; font-size: 26px; font-weight: 800; letter-spacing: .2px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; padding-right: 188px; }
.view-sub { color: var(--ink-soft); font-size: 14px; margin-top: 2px; font-weight: 600; }

.main {
  /* Fill the full width — no stranded centered column (§3). On phones this is one
     column; ≥700px it flows into balanced columns so wide screens fill up. */
  flex: 1; width: 100%;
  padding: 4px max(16px, var(--safe-right)) 200px max(16px, var(--safe-left)); /* room for quick-add + nav + landscape notch */
}
@media (min-width: 700px) {
  .main { column-width: 320px; column-gap: 24px; }
  .main > * { break-inside: avoid; }          /* keep a card / day-group intact in one column */
  .section-label, .proj-group-head, .day-head { break-after: avoid; } /* keep headers with their content */
  /* Today: the assistant card sits ABOVE the columns, not inside them. It used to be a
     `column-span: all` child of the multicol .main, and Safari mislays a spanner whose
     height changes after layout (the briefing collapses right after render), so on iPad
     the first task card painted on top of the assistant card (2026-10-02). Only the
     tasks flow into columns now, inside their own .today-cols wrapper. */
  .main.today-layout { column-width: auto; column-count: auto; }
  .today-cols { column-width: 320px; column-gap: 24px; }
  .today-cols > * { break-inside: avoid; }
}

/* ===== Date group ===== */
.day-group { margin-top: 18px; }
.day-head {
  display: flex; align-items: baseline; gap: 8px; margin: 0 4px 8px;
}
.day-name { font-size: 16px; font-weight: 800; }
.day-name.overdue { color: var(--coral); }
.day-date { color: var(--ink-soft); font-size: 13px; font-weight: 600; }
.day-count { margin-left: auto; color: var(--ink-soft); font-size: 13px; font-weight: 700; }

/* ===== Topbar actions ===== */
.topbar-actions {
  position: absolute; top: calc(var(--safe-top) + 14px); right: max(16px, var(--safe-right));
  display: flex; gap: 7px;
}
.icon-btn {
  width: 44px; height: 44px; border-radius: 7px; font-size: 19px;
  background: var(--card); box-shadow: var(--shadow-soft);
  display: flex; align-items: center; justify-content: center;
}
.icon-btn:active { transform: scale(.92); }
.icon-btn.spinning { animation: spin .7s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

/* ===== L / D / A theme segmented pill (Settings → Appearance) ===== */
.theme-seg { display: inline-flex; gap: 2px; background: var(--bg2); border-radius: 7px;
  padding: 3px; box-shadow: inset 0 0 0 1px var(--line); }
.theme-seg button {
  min-width: 46px; height: 36px; border-radius: 6px; font-size: 13px; font-weight: 800;
  color: var(--ink-soft); display: flex; align-items: center; justify-content: center; gap: 5px;
  transition: background .15s, color .15s;
}
.theme-seg button.active { background: var(--card); color: var(--orange); box-shadow: 0 2px 6px rgba(0,0,0,.12); }
.theme-seg .ts-ico { font-size: 14px; }

.search-overlay {
  position: fixed; inset: 0; z-index: 45;
  background: radial-gradient(120% 80% at 50% 0%, var(--bg2), var(--bg));
  display: flex; flex-direction: column;
}
.search-bar {
  display: flex; gap: 10px; align-items: center;
  padding: calc(var(--safe-top) + 14px) max(16px, var(--safe-right)) 10px max(16px, var(--safe-left));
  max-width: min(100%, 1040px); margin: 0 auto; width: 100%;
}
.search-input {
  flex: 1; height: 48px; border-radius: 8px; border: none;
  padding: 0 16px; font-size: 16px; color: var(--ink);
  background: var(--card); box-shadow: var(--shadow); outline: none;
}
.search-close { flex: 0 0 auto; font-weight: 700; font-size: 15px; color: var(--orange); padding: 6px; }
.search-results { flex: 1; overflow-y: auto; width: 100%; max-width: min(100%, 1040px); margin: 0 auto; padding: 6px max(16px, var(--safe-right)) 40px max(16px, var(--safe-left)); }
.search-head {
  font-size: 12px; font-weight: 800; letter-spacing: .5px; text-transform: uppercase;
  color: var(--ink-soft); margin: 16px 4px 8px;
}
.search-row {
  display: flex; gap: 12px; align-items: center;
  background: var(--card); border-radius: 7px; padding: 12px 14px; margin-bottom: 8px;
  box-shadow: var(--shadow-soft);
}
.search-row:active { transform: scale(.99); }
.search-row.done { opacity: .6; }
.search-row.done .sr-title { text-decoration: line-through; }
.sr-ico { font-size: 20px; flex: 0 0 auto; width: 26px; text-align: center; }
.sr-body { min-width: 0; flex: 1; }
.sr-title { font-size: 15px; font-weight: 600; word-break: break-word; }
.sr-sub { font-size: 12px; color: var(--ink-soft); margin-top: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.search-empty { text-align: center; color: var(--ink-soft); padding: 50px 24px; font-weight: 600; }

/* ===== Swipe ===== */
.swipe-wrap { position: relative; margin-bottom: 10px; border-radius: 8px; }
.swipe-wrap .task {
  margin-bottom: 0; touch-action: pan-y; will-change: transform;
  /* The long-press that arms drag-to-reorder is the same gesture iPadOS uses to
     start a text selection, and its magnifier/callout was stealing the drag.
     Links, phones and emails each still have their own one-tap copy button. */
  -webkit-touch-callout: none; -webkit-user-select: none; user-select: none;
}
.swipe-wrap.dragging { z-index: 30; }
.swipe-wrap.dragging .task { transform: scale(1.03); box-shadow: 0 14px 30px rgba(20, 10, 40, .25); opacity: .97; }
.swipe-bg {
  position: absolute; inset: 0; border-radius: 8px;
  display: flex; align-items: center; color: #fff;
  opacity: 0; transition: opacity .12s;
  font-weight: 800; font-size: 15px; gap: 8px;
}
.swipe-bg.left { justify-content: flex-start; padding-left: 22px; }
.swipe-bg.right { justify-content: flex-end; padding-right: 22px; }
.swipe-ico { font-size: 22px; }

/* ===== Task card ===== */
.task {
  display: flex; align-items: flex-start; gap: 12px;
  background: var(--card); border-radius: 8px;
  padding: 14px 14px; margin-bottom: 10px;
  box-shadow: var(--shadow-soft);
  transition: transform .12s, opacity .2s;
}
.task:active { transform: scale(.99); }
.task.done { opacity: .55; }
.checkbox {
  position: relative;
  flex: 0 0 auto; width: 26px; height: 26px; margin-top: 1px;
  border: 2.5px solid var(--orange); border-radius: 6px;
  display: flex; align-items: center; justify-content: center;
  color: var(--accent-ink); font-size: 16px; transition: background .15s, border-color .15s, transform .1s;
}
.checkbox::after { content: ""; position: absolute; inset: -12px; z-index: 2; } /* measured 44px effective target */
.checkbox:active { transform: scale(.86); }
.task.done .checkbox { background: var(--green); border-color: var(--green); }
.task-body { flex: 1; min-width: 0; }
.task-title { font-size: 16px; line-height: 1.35; word-wrap: break-word; }
.task.done .task-title { text-decoration: line-through; }
.task-note {
  color: var(--ink-soft); font-size: 13px; margin-top: 3px;
  white-space: pre-wrap; word-wrap: break-word;
  display: -webkit-box; -webkit-line-clamp: 5; -webkit-box-orient: vertical; overflow: hidden;
}
.task-note a { color: var(--teal); text-decoration: underline; word-break: break-word; }
.task-meta { display: flex; gap: 8px; margin-top: 6px; flex-wrap: wrap; }
.badge {
  font-size: 11px; font-weight: 700; padding: 3px 8px; border-radius: 999px;
  background: var(--accent-soft); color: var(--orange);
}
.badge.recur { background: var(--teal-soft); color: var(--teal); }
/* One-tap actions under each open task (2026-10-06): push out + repeat. Two groups
   that wrap as whole units, so a narrow card shows "move" on one line and "repeat"
   on the next instead of a ragged mix. Chips are 32px tall drawn, 44px to the finger
   (the ::after reaches 6px above and below; no sideways overlap between neighbors).
   Contrast: --ink on --bg2 ~13:1 both themes; the active repeat chip --orange on
   --accent-soft = 5.17:1 light (#2f6b3f on #e2eadd), 5.08:1 dark (#6aab72 on #23301f). */
.task { flex-wrap: wrap; }   /* lets .task-quick take a full-width line of its own */
.task > .task-quick { flex: 1 0 100%; }
.task-quick { display: flex; flex-wrap: wrap; gap: 8px 12px; }
.tq-group { display: inline-flex; flex-wrap: wrap; gap: 6px; }
.task-quick button, .task-quick .tq-pick {
  position: relative; min-height: 32px; padding: 0 8px; border-radius: 6px;
  display: inline-flex; align-items: center; gap: 4px; white-space: nowrap; cursor: pointer;
  font: 700 12px/1 var(--font-body); color: var(--ink); background: var(--bg2);
  box-shadow: inset 0 0 0 1px var(--line);
}
.task-quick button::after, .task-quick .tq-pick::after { content: ""; position: absolute; left: 0; right: 0; top: -6px; bottom: -6px; }
.task-quick button:active, .task-quick .tq-pick:active { transform: scale(.95); }
.task-quick button.on { background: var(--accent-soft); color: var(--orange); box-shadow: inset 0 0 0 1px var(--orange); }
.task-quick button:disabled, .task-quick .tq-pick.busy { opacity: .6; }
/* the real date input sits invisibly over the chip: a tap opens the phone's date
   wheel; 16px keeps iOS from zooming the page when it focuses */
.task-quick .tq-pick input { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; font-size: 16px; cursor: pointer; }
/* Custom repeat sheet (2026-10-06): reuses .sheet, .chip, .weekday-row and
   .interval-row. Number boxes are 16px here so iOS doesn't zoom when they focus. */
.repeat-sheet .rp-title { font-family: var(--font-display); font-weight: 700; font-size: 18px; line-height: 1.3;
  margin-bottom: 4px; overflow-wrap: anywhere; }
.repeat-sheet .rp-every { margin-top: 8px; }
.repeat-sheet .interval-row input { font-size: 16px; width: 72px; }
.repeat-sheet .rp-units { margin-top: 12px; }
.repeat-sheet .field-label { margin-top: 14px; }
.repeat-sheet .weekday-row { flex-wrap: wrap; }
.repeat-sheet .rp-preview { margin-top: 16px; font-size: 15px; font-weight: 600; color: var(--ink); }
/* Work tag (2026-10-06). Measured: --grape on --grape-soft = 5.77:1 light
   (#8a4418 on #f2e4d6), 5.48:1 dark (#d09154 on #33261a). */
.badge.work { background: var(--grape-soft); color: var(--grape); }
/* The pill as a flip button: 26px drawn, 44px to the finger (::after 9px above and
   below). Personal = --ink on --bg2 (~13:1 both themes); Work keeps the grape pair
   above (5.77 / 5.48). The inset line marks it as tappable. */
.badge.area-flip { position: relative; min-height: 26px; display: inline-flex; align-items: center;
  cursor: pointer; font-family: var(--font-body); }
.badge.area-flip::after { content: ""; position: absolute; left: 0; right: 0; top: -9px; bottom: -9px; }
.badge.area-flip.work { box-shadow: inset 0 0 0 1px var(--grape); }
.badge.area-flip.personal { background: var(--bg2); color: var(--ink); box-shadow: inset 0 0 0 1px var(--line); }
.badge.area-flip:active { transform: scale(.95); }
.badge.area-flip:disabled { opacity: .6; }
/* All / Work / Personal. Unselected labels use --ink, not --ink-soft (ink-soft is
   only 4.49:1 on --bg2 in light). Selected: --orange on --card = 6.26:1 light
   (#2f6b3f on #fffdf7), 5.43:1 dark (#6aab72 on #2b2720). */
.area-seg { display: inline-flex; gap: 2px; background: var(--bg2); border-radius: 7px;
  padding: 3px; box-shadow: inset 0 0 0 1px var(--line); margin: 0 0 12px; max-width: 100%; }
.area-seg button {
  min-height: 40px; padding: 0 14px; border-radius: 6px; font-size: 14px; font-weight: 600;
  color: var(--ink); white-space: nowrap; transition: background .15s, color .15s;
}
.area-seg button.active { background: var(--card); color: var(--orange); font-weight: 800; box-shadow: 0 2px 6px rgba(0,0,0,.12); }
/* On iPad/desktop, Upcoming and Done flow into columns, so the control sits at the top
   of the first one. Deliberately NOT column-span: Safari mislays spanners (2026-10-02). */
.badge.time { background: var(--teal-soft); color: var(--teal); }
.badge.bday { background: var(--grape-soft); color: var(--grape); }
.badge.proj { display: inline-flex; align-items: center; gap: 5px; padding: 3px 9px 3px 4px; background: var(--grape-soft); color: var(--grape); cursor: pointer; }
.badge.proj:active { filter: brightness(.96); }
.badge.proj .pb-av { width: 16px; height: 16px; border-radius: 50%; object-fit: cover; flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; font-size: 10px; background: var(--grape-soft); }

/* on-card project tag button */
.task-proj {
  flex: 0 0 auto; align-self: flex-start; margin-top: 0;
  width: 32px; height: 32px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center; background: transparent;
  transition: transform .08s;
}
.task-proj { position: relative; }
.task-proj::after { content: ""; position: absolute; inset: -6px; z-index: 2; } /* 44px touch target */
.task-proj:active { transform: scale(.9); }
.task-proj .tp-av { width: 28px; height: 28px; border-radius: 50%; object-fit: cover; display: inline-flex; align-items: center; justify-content: center; font-size: 13px; }
.task-proj .tp-add { font-size: 15px; opacity: .35; }
.task.done .task-proj { opacity: .6; }

/* quick project picker popover */
.proj-popover {
  position: fixed; z-index: 62; background: var(--card);
  border-radius: 7px; box-shadow: 0 12px 34px rgba(20, 10, 40, .28);
  padding: 6px; min-width: 180px; max-width: 250px; max-height: 56vh; overflow-y: auto;
}
.proj-popover.hidden { display: none; }
.pp-opt {
  display: flex; align-items: center; gap: 10px; padding: 9px 12px; border-radius: 6px;
  font-size: 15px; font-weight: 600; color: var(--ink); cursor: pointer; white-space: nowrap;
}
.pp-opt:active, .pp-opt.sel { background: var(--bg2); }
.pp-opt.sel { color: var(--orange); }
.pp-av { width: 24px; height: 24px; border-radius: 50%; object-fit: cover; flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; font-size: 12px; }
.pp-none { width: 24px; height: 24px; flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; font-size: 15px; }
.pp-sep { height: 1px; background: var(--line); margin: 5px 8px; }
.pp-hint { padding: 10px 12px; font-size: 13px; color: var(--ink-soft); }

/* project picker chips (task editor) */
.chip.proj { display: inline-flex; align-items: center; gap: 7px; padding: 7px 13px 7px 7px; }
.chip .chip-av { width: 22px; height: 22px; border-radius: 50%; object-fit: cover; flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; font-size: 12px; background: var(--bg2); }
.chip.proj.active .chip-av { background: rgba(255,255,255,.3); }

/* projects list (settings) */
.proj-row { cursor: pointer; }
.proj-row .avatar { width: 36px; height: 36px; }

/* projects home — groups */
.proj-group-head {
  display: flex; align-items: center; gap: 12px;
  margin: 18px 2px 8px; cursor: pointer;
}
.proj-group-head .avatar { width: 34px; height: 34px; }
.proj-group-head .pg-name { flex: 1; font-size: 17px; font-weight: 800; }
.proj-group-head .pg-count { color: var(--ink-soft); font-size: 13px; font-weight: 700; }
.proj-group-head::after { content: "›"; color: var(--ink-soft); font-size: 20px; margin-left: 2px; }
.proj-group-head.static { cursor: default; margin-top: 6px; }
.proj-group-head.static::after { content: none; }

/* ===== Notes ===== */
.note-card {
  display: flex; flex-direction: column; gap: 4px;
  background: var(--card); border-radius: 8px;
  padding: 14px 14px; margin-bottom: 10px;
  box-shadow: var(--shadow-soft);
  transition: transform .12s;
}
.note-card:active { transform: scale(.99); }
.note-card-head, .note-view-head { display: flex; align-items: flex-start; gap: 6px; }
.note-card-title { flex: 1; min-width: 0; font-size: 16px; font-weight: 700; line-height: 1.3; word-wrap: break-word; }
.note-card-time { color: var(--ink-soft); font-size: 12px; font-weight: 600; }
.note-card-preview {
  color: var(--ink-soft); font-size: 13px; margin-top: 2px;
  white-space: pre-wrap; word-wrap: break-word;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
/* Star toggle — on the card (skips opening the note, via stopPropagation in JS)
   and again in the reading view, so a note can be favorited/unfavorited from
   either place. ::after pads the tap target to ~40px without affecting layout. */
.note-star {
  position: relative; flex: 0 0 auto;
  width: 26px; height: 26px; margin: -2px -4px 0 0;
  display: flex; align-items: center; justify-content: center;
  font-size: 18px; line-height: 1; color: var(--ink-soft); opacity: .55;
  transition: transform .1s, opacity .1s, color .1s;
}
.note-star::after { content: ""; position: absolute; inset: -9px; }
.note-star:active { transform: scale(.85); }
.note-star.active { color: var(--yellow); opacity: 1; }
.proj-group-head .np-av { background: var(--bg2); }
.pg-empty { color: var(--ink-soft); font-size: 13px; padding: 2px 6px 8px; }
.pg-more {
  display: block; width: 100%; text-align: left;
  color: var(--teal); font-weight: 700; font-size: 14px; padding: 6px 8px 4px;
}

/* project drill-in view header */
.proj-view-head { display: flex; align-items: center; gap: 10px; margin: 4px 0 12px; }
.proj-back { font-weight: 700; color: var(--orange); font-size: 15px; padding: 6px 4px; }
.proj-head-mid { flex: 1; display: flex; justify-content: center; }
.proj-head-mid .avatar { width: 34px; height: 34px; }
.proj-edit {
  font-weight: 700; color: var(--teal); font-size: 14px; background: var(--card);
  padding: 8px 16px; border-radius: 7px; box-shadow: var(--shadow-soft);
}
.proj-edit:active { transform: scale(.96); }

/* ===== Avatars ===== */
.avatar {
  flex: 0 0 auto; width: 40px; height: 40px; border-radius: 50%;
  object-fit: cover; background: var(--bg2);
}
.avatar.lg { width: 56px; height: 56px; }
.avatar.xl { width: 96px; height: 96px; }
.avatar-fallback {
  display: flex; align-items: center; justify-content: center;
  font-size: 20px; font-weight: 800; color: #fff;
  background: var(--grad);
}
.avatar.lg.avatar-fallback { font-size: 22px; }
.avatar.xl.avatar-fallback { font-size: 40px; }
.person-item .task-title { padding-top: 2px; }

/* ===== Birthdays section ===== */
.person-card {
  display: flex; align-items: center; gap: 14px;
  background: var(--card); border-radius: 8px; padding: 12px 14px; margin-bottom: 10px;
  box-shadow: var(--shadow-soft);
}
.person-card:active { transform: scale(.99); }
.person-info { flex: 1; min-width: 0; }
.person-name { font-size: 16px; font-weight: 700; }
.person-sub { font-size: 13px; color: var(--ink-soft); margin-top: 2px; }
.person-when { text-align: right; flex: 0 0 auto; }
.pw-date { font-size: 14px; font-weight: 700; color: var(--orange); }
.pw-days { font-size: 12px; color: var(--ink-soft); margin-top: 2px; }

/* ===== Photo picker (person sheet) ===== */
.photo-picker { display: flex; flex-direction: column; align-items: center; gap: 10px; margin: 6px 0 16px; }
.photo-btn {
  font-size: 14px; font-weight: 700; color: var(--teal);
  background: var(--teal-soft); padding: 8px 16px; border-radius: 999px; cursor: pointer;
}
.photo-remove { font-size: 13px; font-weight: 700; color: var(--coral); }

/* ===== Gift card (person sheet) ===== */
.gift-card { background: var(--card); border-radius: 8px; padding: 14px 16px; margin-top: 18px;
  box-shadow: var(--shadow-soft); }
.gift-head { display: flex; align-items: center; gap: 12px; }
.gift-head > div:first-child { flex: 1; }
.gift-title-row { font-size: 15px; font-weight: 700; }
#giftDetail { margin-top: 12px; }

/* ===== Empty state ===== */
.empty {
  text-align: center; color: var(--ink-soft);
  padding: 60px 24px;
}
.empty .emoji { font-size: 54px; display: block; margin-bottom: 10px; }
.empty .msg { font-size: 16px; font-weight: 600; }
.empty .sub { font-size: 14px; margin-top: 4px; opacity: .85; }

/* ===== Quick add ===== */
/* live natural-language preview above the quick-add bar */
.parse-preview {
  position: fixed; left: 0; right: 0; z-index: 20;
  bottom: calc(124px + var(--safe-bottom));
  max-width: min(100%, 1040px); margin: 0 auto; padding: 0 max(18px, var(--safe-right)) 0 max(18px, var(--safe-left));
  display: flex; gap: 6px; align-items: center; flex-wrap: wrap;
  font-size: 13px; pointer-events: none;
}
.parse-preview .pp-title {
  font-weight: 700; color: var(--ink);
  background: var(--card); border-radius: 999px; padding: 4px 11px;
  box-shadow: var(--shadow-soft);
  max-width: 60%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.parse-preview .pp-chip {
  font-weight: 700; padding: 4px 10px; border-radius: 999px;
  background: var(--grad); color: var(--accent-ink);
  box-shadow: var(--shadow-soft);
}
.parse-preview .pp-chip.time { background: var(--teal); box-shadow: none; }

.dob-row { display: flex; gap: 8px; }
.dob-row #dobMonth, .dob-row #annivMonth { flex: 1.4; }
.dob-row #dobDay, .dob-row #annivDay { flex: 0.8; min-width: 0; }
.dob-row #dobYear, .dob-row #annivYear { flex: 1.4; min-width: 0; }
.time-row { display: flex; gap: 8px; align-items: center; }
.edit-time {
  border: 1px solid var(--line); border-radius: 7px; padding: 10px 12px;
  font-size: 15px; color: var(--ink); background: var(--field);
}

.quick-add {
  position: fixed; left: 0; right: 0; z-index: 20;
  bottom: calc(64px + var(--safe-bottom));
  display: flex; gap: 10px; align-items: center;
  max-width: min(100%, 1040px); margin: 0 auto; padding: 8px max(16px, var(--safe-right)) 8px max(16px, var(--safe-left));
}
/* fade scrolling content out behind the floating quick-add bar */
.quick-add::before {
  content: ""; position: absolute; left: 0; right: 0; bottom: -8px; top: -28px;
  background: linear-gradient(to top, var(--bg) 45%, transparent);
  z-index: -1; pointer-events: none;
}
.quick-input {
  flex: 1; height: 52px; border-radius: 8px; border: none;
  padding: 0 18px; font-size: 16px; color: var(--ink);
  background: var(--card); box-shadow: var(--shadow); outline: none;
}
.quick-input::placeholder { color: var(--ink-soft); opacity: .7; }
.quick-btn {
  width: 52px; height: 52px; flex: 0 0 auto; border-radius: 8px;
  font-size: 30px; font-weight: 300; color: var(--accent-ink); line-height: 0;
  background: var(--grad); box-shadow: var(--shadow);
  transition: transform .08s;
}
.quick-btn:active { transform: scale(.92); }

/* ===== Attachments (task editor) ===== */
.attach-list { display: flex; flex-direction: column; gap: 8px; margin-bottom: 10px; }
.attach-list:empty { margin-bottom: 0; }
.attach-item {
  display: flex; align-items: center; gap: 10px; padding: 8px; cursor: pointer;
  background: var(--bg2); border-radius: 7px;
}
.attach-thumb {
  width: 44px; height: 44px; flex: 0 0 auto; border-radius: 6px; object-fit: cover;
  background: var(--card); display: flex; align-items: center; justify-content: center; font-size: 22px;
}
.attach-thumb.file { box-shadow: inset 0 0 0 1px var(--line); }
.attach-meta { flex: 1; min-width: 0; }
.attach-name { font-size: 14px; font-weight: 600; color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.attach-size { font-size: 12px; color: var(--ink-soft); }
.attach-del {
  width: 30px; height: 30px; flex: 0 0 auto; border-radius: 8px; font-size: 14px;
  color: var(--ink-soft); background: var(--card); box-shadow: inset 0 0 0 1px var(--line);
}
.attach-del:active { transform: scale(.9); }
.attach-drop {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  padding: 16px; border: 2px dashed var(--line); border-radius: 7px; cursor: pointer;
  color: var(--ink-soft); font-size: 14px; font-weight: 700; transition: background .15s, border-color .15s;
}
.attach-drop.drag { border-color: var(--orange); background: var(--accent-soft); color: var(--orange); }
.attach-drop:active { background: var(--bg2); }
.badge.attach { background: var(--teal-soft); color: var(--teal); }

/* ===== Copy button (next to links/phones/emails) ===== */
.copy-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 26px; height: 26px; margin-left: 4px; vertical-align: middle;
  border-radius: 6px; font-size: 12px; line-height: 1; color: var(--teal);
  background: var(--bg2); box-shadow: inset 0 0 0 1px var(--line);
  transition: transform .08s, background .15s;
}
.copy-btn { position: relative; }
.copy-btn::after { content: ""; position: absolute; inset: -12px; z-index: 2; } /* 44px touch target; painted size stays 20px */
.copy-btn:active { transform: scale(.85); }
.copy-btn.copied { color: var(--accent-ink); background: var(--green); box-shadow: none; }

/* ===== Settings status section ===== */
.status-dim { color: var(--ink-soft); font-size: 13px; font-weight: 600; }
.status-log-row { display: flex; justify-content: space-between; gap: 10px; padding: 6px 0; font-size: 13px; border-bottom: 1px solid var(--line); }
.status-log-row:last-child { border-bottom: none; }
.status-log-row span:first-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.status-api { padding: 10px 0; border-bottom: 1px solid var(--line); }
.status-api:last-child { border-bottom: none; }
.status-api-name { font-size: 14px; font-weight: 700; color: var(--ink); }
.status-link { display: inline-block; margin-top: 3px; font-size: 13px; font-weight: 700; color: var(--teal); }
/* Reusable collapsible disclosure (collapsed by default) — used for Settings' Status
   block and Upcoming's far-future months. Summary line still shows a live hint so
   collapsing never hides the info that matters at a glance. */
.disclosure-summary {
  display: flex; align-items: center; gap: 7px; cursor: pointer; list-style: none;
}
.disclosure-summary::-webkit-details-marker { display: none; }
.disclosure-chevron { display: inline-block; font-size: 10px; transition: transform .15s; }
.disclosure[open] .disclosure-chevron { transform: rotate(90deg); }
.disclosure-sub {
  margin-left: auto; text-transform: none; letter-spacing: 0; font-weight: 600;
  color: var(--ink-soft); font-size: 12px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* ===== AI assistant card ===== */
.ai-card {
  background: var(--accent-soft);
  border: 1px solid var(--line); border-radius: 6px; padding: 12px 14px;
  margin: 2px 0 16px; box-shadow: var(--shadow-soft);
}
.ai-head { display: flex; align-items: center; gap: 10px; }
.ai-title { font-size: 15px; font-weight: 800; color: var(--grape); flex: 1; }
.ai-snap-btn {
  border-radius: 7px; padding: 8px 12px; min-height: 44px; font-size: 13px; font-weight: 700; color: var(--grape);
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--card); box-shadow: inset 0 0 0 1px var(--line);
  transition: transform .08s;
}
.ai-snap-btn:active { transform: scale(.94); }

/* ===== Snap-to-tasks review sheet ===== */
.snap-head { font-size: 20px; font-weight: 800; color: var(--ink); margin: 4px 2px 2px; }
.snap-sub { font-size: 13px; color: var(--ink-soft); margin: 0 2px 12px; font-weight: 600; }
.snap-list { display: flex; flex-direction: column; gap: 8px; max-height: 46vh; overflow-y: auto; }
.snap-row { display: flex; align-items: center; gap: 10px; background: var(--bg2); border-radius: 7px; padding: 8px 10px; }
.snap-row.off { opacity: .5; }
.snap-cb {
  width: 26px; height: 26px; flex: 0 0 auto; border-radius: 8px; font-size: 14px; color: var(--accent-ink);
  box-shadow: inset 0 0 0 2px var(--line); background: transparent; transition: background .12s;
}
.snap-cb.on { background: var(--green); box-shadow: none; }
.snap-title {
  flex: 1; min-width: 0; border: none; background: transparent; font-size: 15px; color: var(--ink);
  font-weight: 600; outline: none; padding: 4px 0;
}
.snap-when { flex: 0 0 auto; font-size: 12px; font-weight: 700; color: var(--teal); white-space: nowrap; }
.ai-out {
  margin-top: 12px; font-size: 14.5px; line-height: 1.5; color: var(--ink);
  background: var(--card); border-radius: 7px; padding: 12px 14px;
  position: relative;
}
.ai-out.hidden { display: none; }
.ai-out p { margin: 0 0 8px; }
.ai-out p:last-child, .ai-out ul:last-child { margin-bottom: 0; }
.ai-out ul { margin: 0 0 8px; padding-left: 20px; }
.ai-out li { margin: 3px 0; }
.ai-out strong { color: var(--grape); }
.ai-out a { color: var(--grape); }
/* §17: a long AI-generated block (a long answer; the daily briefing, until it was
   removed 2026-10-06) must not own the
   whole "Today" view by default — collapse to ~a paragraph, fade the cut edge, and
   let a tap reveal the rest. Measured against real content: the 2026-09-28 briefing
   rendered 893px tall on an 812px-tall iPhone viewport, so NO task was visible without
   scrolling past a wall of AI text first. .ai-out.clamped is added only when content
   actually overflows the collapsed height (never clip something that already fits). */
.ai-out.clamped:not(.expanded) { max-height: 130px; overflow: hidden; }
.ai-out.clamped:not(.expanded)::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 40px;
  background: linear-gradient(to top, var(--card), transparent); border-radius: 0 0 7px 7px;
  pointer-events: none;
}
.ai-more-btn {
  display: block; width: 100%; margin-top: 6px; padding: 11px 10px; min-height: 40px;
  background: transparent; border: none; border-radius: 6px;
  color: var(--grape); font-size: 13px; font-weight: 700; text-align: center; cursor: pointer;
}
.ai-more-btn:active { opacity: .6; }
.ai-err { color: var(--coral); }
.ai-loading { color: var(--ink-soft); font-weight: 600; }
.ai-dots { animation: aiblink 1.2s infinite; }
@keyframes aiblink { 0%, 100% { opacity: .3; } 50% { opacity: 1; } }
.ai-ask { display: flex; gap: 8px; align-items: center; margin-top: 12px; }
.ai-input {
  flex: 1; height: 42px; border-radius: 7px; border: 1px solid var(--line);
  padding: 0 14px; font-size: 15px; color: var(--ink); background: var(--field); outline: none;
}
.ai-input::placeholder { color: var(--ink-soft); opacity: .7; }
.ai-send {
  width: 42px; height: 42px; flex: 0 0 auto; border-radius: 7px; font-size: 20px; color: var(--accent-ink);
  background: var(--grad); box-shadow: var(--shadow-soft);
  transition: transform .08s;
}
.ai-send:active { transform: scale(.92); }

/* ===== Multi-select bulk bar ===== */
.bulk-bar {
  position: fixed; left: 0; right: 0; z-index: 20;
  bottom: calc(64px + var(--safe-bottom));
  display: flex; gap: 8px; align-items: stretch;
  max-width: min(100%, 1040px); margin: 0 auto; padding: 8px max(16px, var(--safe-right)) 8px max(16px, var(--safe-left));
}
.bulk-bar::before {
  content: ""; position: absolute; left: 0; right: 0; bottom: -8px; top: -28px;
  background: linear-gradient(to top, var(--bg) 45%, transparent);
  z-index: -1; pointer-events: none;
}
.bulk-bar.hidden { display: none; }
.bulk-act {
  flex: 1; display: flex; flex-direction: column; align-items: center; gap: 3px;
  background: var(--card); box-shadow: var(--shadow);
  border-radius: 8px; padding: 9px 2px; font-size: 11px; font-weight: 700;
  color: var(--ink); transition: transform .08s, opacity .15s;
}
.bulk-act .ba-ico { font-size: 19px; line-height: 1; }
.bulk-act:active:not(:disabled) { transform: scale(.93); }
.bulk-act:disabled { opacity: .42; }
.bulk-act.danger { color: var(--coral); }

/* selection-mode cards */
.task.selectmode { cursor: pointer; }
.task.selectmode .checkbox.sel { border-color: var(--orange); }
.task.selected { box-shadow: 0 0 0 2px var(--orange), var(--shadow); }
.task.selected .checkbox.sel { background: var(--orange); border-color: var(--orange); color: var(--accent-ink); }
.pp-dateinput { width: 0; height: 0; opacity: 0; position: absolute; pointer-events: none; }

/* ===== Bottom nav ===== */
.bottom-nav {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 20;
  display: flex; justify-content: space-around;
  padding: 6px max(8px, var(--safe-right)) calc(6px + var(--safe-bottom)) max(8px, var(--safe-left));
  background: var(--glass);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  border-top: 1px solid var(--line);
}
.nav-btn {
  flex: 1; min-width: 0;
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 6px 1px; border-radius: 7px; color: var(--ink-soft);
  font-size: 10px; font-weight: 700; opacity: .7; transition: opacity .15s;
}
.nav-label { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.nav-ico { font-size: 20px; }
.nav-btn.active { opacity: 1; color: var(--ink); }

/* ===== Settings ===== */
.settings-card {
  background: var(--card); border-radius: 8px; padding: 6px 16px;
  box-shadow: var(--shadow-soft); margin-top: 14px;
}
.set-row {
  display: flex; align-items: center; gap: 12px; padding: 14px 0;
  border-bottom: 1px solid var(--line);
}
.set-row:last-child { border-bottom: none; }
.set-row .set-label { font-size: 15px; font-weight: 600; flex: 1; }
.set-row .set-sub { font-size: 12px; color: var(--ink-soft); font-weight: 500; margin-top: 2px; }
.set-row input[type=text], .set-row input[type=email], .set-row input[type=time], .set-row select {
  border: 1px solid var(--line); border-radius: 6px; padding: 8px 10px;
  font-size: 14px; color: var(--ink); background: var(--field); max-width: 210px;
}
.switch { position: relative; width: 50px; height: 30px; flex: 0 0 auto; }
.switch input { display: none; }
.switch .track {
  position: absolute; inset: 0; border-radius: 999px; background: var(--track); transition: background .2s;
}
.switch .thumb {
  position: absolute; top: 3px; left: 3px; width: 24px; height: 24px; border-radius: 50%;
  background: #fff; box-shadow: 0 2px 6px rgba(0,0,0,.18); transition: transform .2s;
}
.switch input:checked + .track { background: var(--green); }
.switch input:checked + .track + .thumb { transform: translateX(20px); }
.btn-row { display: flex; gap: 10px; margin-top: 16px; }
.btn-primary {
  background: var(--grad); color: var(--accent-ink); font-weight: 700; font-size: 15px;
  padding: 13px 18px; border-radius: 7px; box-shadow: var(--shadow); flex: 1;
}
.btn-primary:active { transform: scale(.98); }
.btn-light {
  background: var(--card); color: var(--ink); font-weight: 700; font-size: 15px;
  padding: 13px 18px; border-radius: 7px; box-shadow: var(--shadow-soft); flex: 1;
}
.btn-danger {
  background: var(--danger-soft); color: var(--coral); font-weight: 700; font-size: 15px;
  padding: 13px 18px; border-radius: 7px; flex: 1;
}
.section-label { font-size: 12px; font-weight: 800; letter-spacing: .6px; text-transform: uppercase;
  color: var(--ink-soft); margin: 26px 4px 0; }

/* ===== Sheet (task editor) ===== */
.sheet-backdrop {
  position: fixed; left: 0; right: 0; z-index: 40;
  /* Bound to the app.js-tracked VISUAL viewport (--vvh/--vv-top), not the full
     layout viewport, so the sheet sits above the iOS keyboard instead of being
     partly covered by it. Falls back to the full screen before JS runs / on
     browsers without visualViewport support. */
  top: var(--vv-top, 0px); height: var(--vvh, 100dvh);
  background: rgba(15, 10, 30, .48); display: flex; align-items: flex-end;
  opacity: 0; transition: opacity .2s;
}
.sheet-backdrop.show { opacity: 1; }
.sheet {
  width: 100%; max-width: 560px; margin: 0 auto;
  background: var(--bg); border-radius: 7px 24px 0 0;
  padding: 10px 20px calc(24px + var(--safe-bottom));
  transform: translateY(100%); transition: transform .25s cubic-bezier(.2,.9,.3,1);
  max-height: min(88vh, calc(100% - 12px)); overflow-y: auto;
}
.sheet-backdrop.show .sheet { transform: translateY(0); }
/* Task + Note editors: pin Delete/Save as an always-visible footer and let the
   fields (or, for notes, the whole note body) scroll in their own region, so the
   buttons never need a scroll (or a keyboard dismiss) to reach — the #22
   iOS-keyboard-clutter fix, reused here since a saved note can run long. */
#sheet, #noteSheet {
  display: flex; flex-direction: column;
}
#sheet .sheet-scroll, #noteSheet .sheet-scroll {
  flex: 1 1 auto; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch;
}
#sheet .sheet-actions, #noteSheet .sheet-actions {
  flex: 0 0 auto; padding-top: 10px; margin-top: 10px; border-top: 1px solid var(--line);
}
.sheet-grab { width: 42px; height: 5px; border-radius: 3px; background: var(--track); margin: 4px auto 14px; }
.edit-title {
  width: 100%; border: none; background: transparent; font-size: 20px; font-weight: 700;
  color: var(--ink); outline: none; padding: 4px 0;
}
.edit-note {
  width: 100%; border: none; background: transparent; font-size: 15px; color: var(--ink);
  outline: none; resize: none; padding: 6px 0; border-bottom: 1px solid var(--line);
  line-height: 1.5; min-height: 120px; max-height: 45vh; overflow-y: auto;
}
/* Saved notes run longer than a task's note field, so give the editor more room —
   .sheet-scroll (above) is what actually makes it scroll past the viewport. */
.note-body-input { min-height: 40vh; max-height: none; border-bottom: none; }

/* Note reading view: title/timestamp + the full linkified body. */
.note-view-title { font-size: 20px; font-weight: 800; line-height: 1.3; word-wrap: break-word; margin: 4px 0 2px; }
.note-view-time { color: var(--ink-soft); font-size: 13px; font-weight: 600; margin-bottom: 16px; }
.note-view-body {
  font-size: 16px; line-height: 1.6; color: var(--ink);
  white-space: pre-wrap; word-wrap: break-word;
}
.note-view-body a { color: var(--teal); text-decoration: underline; word-break: break-word; }
.field-label { display: block; font-size: 12px; font-weight: 800; letter-spacing: .5px;
  text-transform: uppercase; color: var(--ink-soft); margin: 18px 0 8px; }
.chips { display: flex; gap: 8px; flex-wrap: wrap; }
.chip {
  padding: 9px 14px; border-radius: 999px; background: var(--card);
  font-size: 14px; font-weight: 600; color: var(--ink);
  box-shadow: var(--shadow-soft); transition: transform .08s;
}
.chip:active { transform: scale(.95); }
.chip.active { background: var(--grad); color: var(--accent-ink); }
.edit-date { margin-top: 10px; border: 1px solid var(--line); border-radius: 7px;
  padding: 10px 12px; font-size: 15px; color: var(--ink); background: var(--field); }
.recur-extra { margin-top: 10px; }
.weekday-row { display: flex; gap: 6px; }
.wd {
  flex: 1; text-align: center; padding: 9px 0; border-radius: 6px; background: var(--card);
  font-size: 13px; font-weight: 700; box-shadow: var(--shadow-soft);
}
.wd.active { background: var(--teal); color: var(--accent-ink); }
.interval-row { display: flex; align-items: center; gap: 8px; margin-top: 10px; font-size: 14px; }
.interval-row input { width: 64px; border: 1px solid var(--line); border-radius: 6px; padding: 8px; font-size: 15px; text-align: center; background: var(--field); color: var(--ink); }
.sheet-actions { display: flex; gap: 10px; margin-top: 24px; }

/* ===== Toast ===== */
.toast {
  position: fixed; left: 50%; bottom: calc(130px + var(--safe-bottom));
  transform: translateX(-50%) translateY(20px);
  background: var(--toast-bg); color: var(--toast-ink); font-size: 14px; font-weight: 600;
  padding: 11px 18px; border-radius: 7px; z-index: 60;
  opacity: 0; pointer-events: none; transition: opacity .2s, transform .2s;
  box-shadow: 0 8px 24px rgba(0,0,0,.28); max-width: 80%; text-align: center;
}
.toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }

/* ===== Undo toast ===== */
.undo-toast {
  position: fixed; left: 50%; bottom: calc(130px + var(--safe-bottom));
  transform: translateX(-50%) translateY(20px);
  display: flex; align-items: center; gap: 14px;
  background: var(--toast-bg); color: var(--toast-ink); font-size: 14px; font-weight: 600;
  padding: 10px 12px 10px 18px; border-radius: 7px; z-index: 61;
  opacity: 0; pointer-events: none; transition: opacity .2s, transform .2s;
  box-shadow: 0 8px 24px rgba(0, 0, 0, .28);
}
.undo-toast.show { opacity: 1; pointer-events: auto; transform: translateX(-50%) translateY(0); }
.undo-btn {
  font-weight: 800; font-size: 14px; color: var(--yellow);
  padding: 5px 12px; border-radius: 6px; background: rgba(255, 255, 255, .12);
}
.undo-btn:active { background: rgba(255, 255, 255, .24); }

/* ===== Confetti ===== */
.confetti { position: fixed; inset: 0; z-index: 55; pointer-events: none; }

/* ===== Desktop / iPad widen ===== */
@media (min-width: 760px) {
  .view-title { font-size: 34px; }
  .task { padding: 16px; }
}
/* responsive layout v1784318702 */
/* upcoming disclosure v1784571590 */
/* keyboard-safe editor sheet v1785505481 */
/* alarm UI v1785507750 */

/* ===== Notebook: display face + the ruled line =====
   The slab serif is reserved for things that NAME something (view titles, day
   headings, section labels, sheet + card titles). Body copy, badges, buttons and
   nav labels stay in the sans so long text keeps its plain, readable register.
   The hairline under a task title is this direction's tell: a ruled page. */
.view-title, .lock-title, .day-name, .section-label, .edit-title,
.note-view-title, .note-card-title, .pg-name, .snap-head, .empty .msg,
.set-label, .search-head {
  font-family: var(--font-display);
  letter-spacing: 0;
}
.view-title { font-weight: 700; }
.day-name, .section-label, .search-head { font-weight: 600; }

/* the ruled line — only where a title heads a card with more beneath it */
.task-title {
  font-family: var(--font-display);
  font-weight: 600;
  border-bottom: 1px solid var(--line);
  padding-bottom: 5px;
}
.task.done .task-title { border-bottom-color: transparent; }
.note-card-title { border-bottom: 1px solid var(--line); padding-bottom: 6px; }

/* Hairlines carry structure in this direction, so cards get a real edge and the
   soft Popsicle shadow steps back to almost nothing. */
.task, .note-card, .person-card, .settings-card, .ai-card, .search-row {
  border: 1px solid var(--line);
}

/* ===== Version badge (index.html, filled from /version.js) =====
   Top-left, inside the notch (safe-top), in the topbar's top padding above the view title
   and clear of the right-hand action buttons. Tiny on purpose. Measured, not eyeballed:
   --ink-soft would be only 4.49:1 on the light topbar (#ede7d8), so it uses --ink:
   13.20:1 light on #ede7d8 (16.01:1 on the #fffdf7 card), 13.49:1 dark on #24211a.
   Failure color --coral: 5.37:1 light on #ede7d8, 5.22:1 dark on #24211a.
   z-index 70 is above the lock/splash (50), full-screen views (45), menus (62), toasts (61). */
.app-version {
  position: fixed; z-index: 70; pointer-events: none;
  top: calc(var(--safe-top) + 3px);
  left: max(20px, calc(var(--safe-left) + 6px));
  font: 500 9px/9px ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  letter-spacing: .2px; color: var(--ink); white-space: nowrap;
}
.app-version.fail { color: var(--coral); font-weight: 700; }
/* The lock/boot splash paints the forest gradient (light #2f6b3f to #3d8450) or the sage one
   (dark #6aab72 to #7cbc84), where page ink would vanish. White is 6.37:1 / 4.55:1 on the
   light ends; near-black #16180f is 6.56:1 / 8.01:1 on the dark ends. The splash is also
   what stays up when app.js fails, so the failure text keeps these readable colors there
   (the words "app.js failed" carry the meaning) and goes bold. */
body:has(#lock:not(.hidden)) .app-version { color: #ffffff; }
:root[data-theme="dark"] body:has(#lock:not(.hidden)) .app-version { color: #16180f; }
