
html {
  /* Calm, flat, light-first. Reference points are Apple, Linear and Raycast:
     paper-white surfaces, hairline borders, one accent, and type doing the
     work that colour used to. The old glass-over-photography treatment is
     gone — it read as "futuristic", which is exactly what this product is not.

     The --glass-* names are kept because ~90 existing rules reference them.
     They no longer describe glass: they are now the surface tokens, so every
     screen inherits this palette without rewriting its rules. */
  color-scheme: light dark;

  --aos-color-bg: #f6f6f4;
  --aos-color-text: #17181b;
  --aos-color-text-muted: rgba(23, 24, 27, 0.62);   /* 4.96:1 on white — AA body */
  --aos-color-text-faint: rgba(23, 24, 27, 0.60);   /* 4.65:1 on white — AA at 12px */

  /* Was "exactly three things: the primary action, the current selection,
     and the focus ring — never for decoration," until a deliberate,
     explicit exception: a low-opacity ambient wash and border treatment
     (see "Ambient" below), kept restrained on purpose so it doesn't repeat
     the earlier glow/glass pass that read as "futuristic" and got removed.
     Interactive uses of accent are unaffected by this — still exactly
     those three things. */
  --aos-color-accent: #6d28d9;          /* 7.10:1 on white, 6.57:1 on the page */
  --aos-color-accent-strong: #5b21b6;   /* 8.98:1 against its own white label */
  --aos-color-accent-contrast: #ffffff;
  --aos-color-accent-soft: rgba(109, 40, 217, 0.09);
  --aos-color-accent-veil: rgba(109, 40, 217, 0.14);
  --aos-color-accent-glow: rgba(109, 40, 217, 0.28);
  --aos-color-danger: #c0362f;
  --aos-color-focus-ring: #6d28d9;

  /* Kept for compatibility with older rules; all but amber now resolve to
     neutral text so no screen paints itself in four colours by accident. */
  --aos-tone-violet: var(--aos-color-text-muted);
  --aos-tone-green: var(--aos-color-accent);
  --aos-tone-blue: var(--aos-color-text-muted);
  --aos-tone-amber: #a2620b;
  --aos-tone-amber-soft: rgba(162, 98, 11, 0.08);

  /* Ambient background wash only — deliberately far stronger than
     -soft/-veil above, which stay untouched because they're load-bearing
     for ~50 hover/selected states elsewhere. Kept as their own tokens so
     "make the wash more visible" never means "every hover state gets
     stronger too." See "Ambient" in DESIGN_SYSTEM.md. */
  --aos-ambient-accent: rgba(109, 40, 217, 0.20);
  --aos-ambient-amber: rgba(162, 98, 11, 0.16);

  --aos-glass-bg: #ffffff;
  --aos-glass-bg-hero: #ffffff;
  --aos-glass-bg-raised: #ffffff;
  --aos-glass-border: rgba(23, 24, 27, 0.09);
  --aos-glass-border-strong: rgba(23, 24, 27, 0.16);
  --aos-glass-blur: 0px;
  --aos-glass-saturate: 100%;

  /* Interaction washes. These exist because ~50 rules across the other
     screens hardcoded var(--aos-hover-wash) for a hover and rgba(0,0,0,.28)
     for an inset field — both of which assume a dark background and turn into
     an invisible hover and a grey box once the page is white. Naming them is
     what lets the whole app follow the theme instead of just this screen. */
  --aos-hover-wash: rgba(23, 24, 27, 0.035);
  --aos-control-bg: rgba(23, 24, 27, 0.045);
  --aos-control-bg-hover: rgba(23, 24, 27, 0.09);
  --aos-surface-sunken: #f0f0ed;

  --aos-space-05: 2px;
  --aos-space-1: 4px;
  --aos-space-2: 8px;
  --aos-space-3: 12px;
  --aos-space-4: 16px;
  --aos-space-5: 24px;
  --aos-space-6: 32px;
  --aos-space-7: 48px;
  --aos-space-8: 64px;

  --aos-font-sans: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Segoe UI", system-ui, sans-serif;
  --aos-font-serif: "Iowan Old Style", "Palatino Linotype", Georgia, serif;

  /* The type ramp, rebuilt on Apple's iOS scale (11/13/15/17/20/22/28/34)
     rather than the web's 12/14/16. This is the single highest-leverage change
     in the system: the reason iOS reads comfortably at arm's length on a
     moving train is that its body size is 17px, not 16, and its secondary text
     is 15, not 14. Every list row in this product was set at 14.
     Names are unchanged so all existing CSS inherits the new ramp. */
  --aos-font-size-xs: 0.75rem;      /* 12 — labels, section headers, metadata */
  --aos-font-size-sm: 0.9375rem;    /* 15 — secondary text, list rows */
  --aos-font-size-base: 1.0625rem;  /* 17 — body, primary row text */
  --aos-font-size-lg: 1.25rem;      /* 20 */
  --aos-font-size-xl: 1.375rem;     /* 22 — section titles */
  --aos-font-size-2xl: 1.75rem;     /* 28 — page titles */
  --aos-font-size-3xl: 2.125rem;    /* 34 — the one large title per screen */
  --aos-font-weight-regular: 400;
  --aos-font-weight-medium: 500;
  --aos-font-weight-bold: 600;
  /* Reserved for Display only. iOS's Large Title is genuinely Bold, not
     Semibold — the weight step between it and everything under it is part
     of what makes it read as the one thing on the screen, not just the
     biggest thing. */
  --aos-font-weight-heavy: 700;
  --aos-line-height-base: 1.47;
  /* Optical tracking, one value per role rather than one value for
     everything: heavier/larger type needs more negative tracking to stop
     looking loose, a small bold sentence-case title needs only a touch,
     small caps-y labels need positive tracking to stay legible at all. */
  --aos-tracking-display: -0.025em;  /* Display: page-title, greeting, NOW card */
  --aos-tracking-tight: -0.021em;    /* Section: 20-22px/600 headings */
  --aos-tracking-card: -0.006em;     /* Card Title: small bold sentence-case */
  --aos-tracking-label: 0.06em;      /* Micro labels: uppercase, tracked out */
  /* Seven roles, not seven sizes — the same 12/15/17/20/22/28/34 ramp above
     serves all of them; what actually separates a role is weight, tracking
     and line-height, which is why those get named per-role tokens instead
     of being hand-picked per component:
       Display     — 28px, heavy, tracking-display, 1.1 lh. One per screen:
                      .page-title, .greeting-title/.today-hello, .now-title.
       Section     — 20-22px, bold, tracking-tight. .search-results h1,
                      .project-page h1, .day-caption.
       Card Title  — 15px, bold, tracking-card. .widget h2, .widget-head h2.
       Body        — 17px, regular, line-height-base. The <body> default.
       Caption     — 12-15px, regular, muted/faint color. .page-sub,
                      .widget-meta, .hint, .now-sub and similar secondary text.
       Micro label — 12px, bold, tracking-label, uppercase. .section-label,
                      .plan-label, .today-date, .cal-dow.
       Numbers     — font-variant-numeric: tabular-nums, wherever a figure is
                      read at a glance rather than as prose: counts, dates,
                      durations, macros. Never its own size — it rides
                      whatever role the number's context already has. */

  /* Motion. One duration for state changes, one slightly longer for things
     that move through space, one easing that decelerates. Anything that
     bounces or overshoots reads as a toy. */
  --aos-transition-fast: 140ms;
  --aos-transition-spatial: 260ms;

  /* Minimum comfortable target. Apple's HIG floor is 44pt and it is a floor,
     not a goal — this product is used one-handed, walking. */
  --aos-tap-min: 44px;
  /* The comfortable size, for a screen's primary action and for controls
     you hit repeatedly without looking. */
  --aos-tap-lg: 48px;

  --aos-radius-xs: 6px;   /* small chips + checkboxes: 10px domes at 20px square */
  --aos-radius-sm: 10px;
  --aos-radius-md: 14px;
  --aos-radius-lg: 18px;
  --aos-radius-xl: 24px;

  /* The measure. Every screen is laid out inside one of these two widths, so
     the app has a single column and a single alignment instead of each screen
     inventing its own. Today used to stop at 965px on a 1440px window while
     Plan ran the full 1420 — same app, two layouts, and a Plan row whose
     actions sat 900px from its title. */
  --aos-measure: 760px;
  --aos-measure-wide: 1080px;

  /* Barely-there elevation. On a flat light UI a heavy shadow reads as cheap.
     Four tiers, not five: the sidebar is chrome (no shadow, flush to the
     edge — see .sidebar's own comment), .widget cards get sm resting / md
     hover, floating dialogs (.search-results-panel, .palette-panel, .toast,
     .fab) sit at lg, and .sheet-panel — every bottom sheet in the app,
     including Quick Capture's, which shares this exact component rather than
     getting a visually distinct "modal" of its own — gets the deepest tier,
     xl, since it's the one surface that's genuinely modal (aria-modal="true")
     and blocks everything else. No blur anywhere in this ladder: depth here
     comes from shadow alone, deliberately, on opaque surfaces. */
  --aos-shadow-sm: 0 1px 2px rgba(23, 24, 27, 0.05);
  --aos-shadow-md: 0 2px 8px rgba(23, 24, 27, 0.06);
  --aos-shadow-lg: 0 8px 28px rgba(23, 24, 27, 0.10);
  --aos-shadow-xl: 0 16px 48px rgba(23, 24, 27, 0.14);

  /* Subtle and quick. Anything slower than this feels like waiting. */
  --aos-transition-duration: 180ms;
  --aos-transition-easing: cubic-bezier(0.32, 0.72, 0, 1);
}

/* Dark mode follows the system unless the toggle has pinned a choice. The
   values are duplicated rather than shared because plain CSS has no way to
   name a token set — see the theme toggle in DASHBOARD_SCRIPT. */
@media (prefers-color-scheme: dark) {
  html:not([data-theme="light"]) {
    --aos-color-bg: #0d0e10;
    --aos-color-text: #f2f3f2;
    --aos-color-text-muted: rgba(242, 243, 242, 0.58);
    --aos-color-text-faint: rgba(242, 243, 242, 0.50);   /* 4.82:1 on surface — AA at 12px */
    --aos-color-accent: #b9a5fc;          /* 9.06:1 on the dark page */
    --aos-color-accent-strong: #a78bfa;
    --aos-color-accent-contrast: #150524; /* 7.15:1 on accent-strong */
    --aos-color-accent-soft: rgba(185, 165, 252, 0.12);
    --aos-color-accent-veil: rgba(185, 165, 252, 0.20);
    --aos-color-accent-glow: rgba(139, 92, 246, 0.36);
    --aos-color-danger: #f0716a;
    --aos-color-focus-ring: #b9a5fc;
    --aos-tone-amber: #e0a341;
    --aos-tone-amber-soft: rgba(224, 163, 65, 0.10);
    --aos-ambient-accent: rgba(139, 92, 246, 0.30);
    --aos-ambient-amber: rgba(224, 163, 65, 0.22);
    --aos-glass-bg: #17191c;
    --aos-glass-bg-hero: #17191c;
    --aos-glass-bg-raised: #1e2125;
    --aos-glass-border: rgba(255, 255, 255, 0.09);
    --aos-glass-border-strong: rgba(255, 255, 255, 0.16);
    --aos-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
    --aos-shadow-md: 0 2px 8px rgba(0, 0, 0, 0.45);
    --aos-shadow-lg: 0 8px 28px rgba(0, 0, 0, 0.55);
  --aos-shadow-xl: 0 16px 48px rgba(0, 0, 0, 0.62);
    --aos-hover-wash: rgba(255, 255, 255, 0.04);
    --aos-control-bg: rgba(255, 255, 255, 0.06);
    --aos-control-bg-hover: rgba(255, 255, 255, 0.12);
    --aos-surface-sunken: #101215;
  }
}
html[data-theme="dark"] {
  --aos-color-bg: #0d0e10;
  --aos-color-text: #f2f3f2;
  --aos-color-text-muted: rgba(242, 243, 242, 0.58);
  --aos-color-text-faint: rgba(242, 243, 242, 0.50);   /* 4.82:1 on surface — AA at 12px */
  --aos-color-accent: #b9a5fc;
  --aos-color-accent-strong: #a78bfa;
  --aos-color-accent-contrast: #150524;
  --aos-color-accent-soft: rgba(185, 165, 252, 0.12);
  --aos-color-accent-veil: rgba(185, 165, 252, 0.20);
  --aos-color-accent-glow: rgba(139, 92, 246, 0.36);
  --aos-color-danger: #f0716a;
  --aos-color-focus-ring: #b9a5fc;
  --aos-tone-amber: #e0a341;
  --aos-tone-amber-soft: rgba(224, 163, 65, 0.10);
  --aos-ambient-accent: rgba(139, 92, 246, 0.30);
  --aos-ambient-amber: rgba(224, 163, 65, 0.22);
  --aos-glass-bg: #17191c;
  --aos-glass-bg-hero: #17191c;
  --aos-glass-bg-raised: #1e2125;
  --aos-glass-border: rgba(255, 255, 255, 0.09);
  --aos-glass-border-strong: rgba(255, 255, 255, 0.16);
  --aos-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.4);
  --aos-shadow-md: 0 2px 8px rgba(0, 0, 0, 0.45);
  --aos-shadow-lg: 0 8px 28px rgba(0, 0, 0, 0.55);
  --aos-shadow-xl: 0 16px 48px rgba(0, 0, 0, 0.62);
  --aos-hover-wash: rgba(255, 255, 255, 0.04);
  --aos-control-bg: rgba(255, 255, 255, 0.06);
  --aos-control-bg-hover: rgba(255, 255, 255, 0.12);
  --aos-surface-sunken: #101215;
}
*, *::before, *::after { box-sizing: border-box; }
body {
  margin: 0;
  min-height: 100vh;
  font-family: var(--aos-font-sans);
  font-size: var(--aos-font-size-base);
  line-height: var(--aos-line-height-base);
  color: var(--aos-color-text);
  -webkit-font-smoothing: antialiased;
  /* Ambient wash, not a wallpaper: two soft colour pools (accent, amber)
     on the flat base, barely-there and slow enough that you feel it more
     than see it move. Behind every surface — cards stay opaque on top of
     it exactly as they did on the flat colour, so nothing about legibility
     changes, only what shows in the gaps between them. */
  background:
    radial-gradient(900px circle at 10% -5%, var(--aos-ambient-accent), transparent 48%),
    radial-gradient(800px circle at 105% 100%, var(--aos-ambient-amber), transparent 48%),
    var(--aos-color-bg);
  background-size: 200% 200%, 200% 200%, auto;
  background-attachment: fixed;
  animation: ambient-drift 100s ease-in-out infinite alternate;
}
@keyframes ambient-drift {
  from { background-position: 0% 0%, 100% 100%, 0 0; }
  to   { background-position: 25% 15%, 75% 85%, 0 0; }
}
a { color: inherit; }
button { font: inherit; color: inherit; }
.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}
/* Focus is keyboard-only (:focus-visible), never on mouse click, and always
   the same ring everywhere. The offset is what stops it colliding with the
   element's own border on rounded controls. */
:focus-visible {
  outline: 2px solid var(--aos-color-focus-ring);
  outline-offset: 2px;
  border-radius: var(--aos-radius-sm);
}
/* Hit-area expansion.
   Measured: eight interactive controls shipped under the 44px floor — the
   complete-task check at 24, postpone at 32, the priority chip at 22, clear
   and add at 36, the sidebar tools at 34. A 24px target is the *drawn* size
   that looks right; it is not the size a thumb needs on a moving train.
   The transparent pseudo-element grows the touch target to 44 without moving
   anything, which is how the same problem is solved natively. */
.row-check, .row-more, .pick-add, .reminder-clear, .pri, .tool-button,
/* The planner's own controls. This is the screen used one-handed at 11:30 PM,
   and every one of these was between 18px and 36px — the check on a plan row
   was 18x18, which is a target you miss standing still. */
.ws-check, .carry-btn, .pull-add, .time-btn, .task-done { position: relative; }
.row-check::before, .row-more::before, .pick-add::before,
.reminder-clear::before, .pri::before, .tool-button::before,
.ws-check::before, .carry-btn::before, .pull-add::before, .time-btn::before,
.task-done::before {
  content: ""; position: absolute; top: 50%; left: 50%;
  width: max(100%, var(--aos-tap-min)); height: max(100%, var(--aos-tap-min));
  transform: translate(-50%, -50%);
}
/* Rows that host an expanded target must be at least as tall as it, or the
   target bleeds into its neighbour and taps land on the wrong row. */
.pick-row, .reminder-row, .today-row, .glance-row, .pull-row { min-height: var(--aos-tap-min); }

/* Measured in the rendered DOM, not the stylesheet: these shipped under the
   floor because nothing set a height on them and their content is short.
   The search input was 19px tall — the tallest-value target on the screen and
   the one hardest to hit while walking. */
.brand { min-height: var(--aos-tap-min); display: inline-flex; align-items: center; }
.search input, .search-box, input[type="search"] { min-height: var(--aos-tap-min); }
.now-open { min-height: var(--aos-tap-min); display: inline-flex; align-items: center; padding-left: var(--aos-space-2); }
.reminder-dismiss, .reminder-snooze { min-height: var(--aos-tap-min); padding: 0 var(--aos-space-3); }
/* A link inside a list row inherits the row's 44px target; give it the full
   row height so the whole line is tappable rather than just the glyphs. */
.today-title { display: flex; align-items: center; align-self: stretch; }
/* UA-default button padding is not a decision this system made. */
.tool-button, .row-more { padding: 0; }
.search input { padding-top: 0; padding-bottom: 0; }

/* Anything tappable states so to the pointer and to assistive tech. */
button, a, [role="button"], summary { -webkit-tap-highlight-color: transparent; }
button:not(:disabled), a[href], summary { cursor: pointer; }
button:disabled { cursor: default; opacity: .5; }
/* Numbers that sit in a column must not jitter as they change. */
.progress-count, .project-item-count, .glance-time, .next-when, .today-when { font-variant-numeric: tabular-nums; }
/* Text should be selectable; controls should not be — dragging a button and
   selecting its label is a small thing that reads as unfinished. */
button, .tab, .nav-link, .section-label, .chip-box { user-select: none; }
/* ---- Wallpaper -------------------------------------------------------- */
/* Deliberately empty. The wallpaper, its mist layer and its vignette were the
   whole reason surfaces had to be translucent and type had to carry a shadow.
   The background is now a single flat colour, so all three are gone and the
   elements they styled render as no-ops if any page still emits them. */

/* ---- Fairy lights ------------------------------------------------------ */
/* Fixed to the viewport, not the page, so it frames the window rather than
   scrolling away with the content. Every card still sits on top of it at
   full opacity — this traces the edge nothing else reaches, never the
   content itself. */
.fairy-lights { position: fixed; inset: 0; z-index: 500; pointer-events: none; animation: fairy-breathe 5s ease-in-out infinite; }
/* A thin cord in the same neutral as the glass borders, laid under the
   bulbs on every edge — the detail that reads "hung string of lights"
   instead of "row of blobs." */
.fairy-lights-edge { position: absolute; }
.fairy-lights-edge--top, .fairy-lights-edge--bottom {
  left: 0; right: 0; height: 30px;
  background-image: var(--bulb-strip-h);
  background-repeat: repeat-x;
  background-size: 120px 30px;
  background-position: center;
}
.fairy-lights-edge--top::before, .fairy-lights-edge--bottom::before {
  content: ""; position: absolute; left: 0; right: 0; height: 1px;
  background: var(--aos-glass-border-strong);
}
.fairy-lights-edge--top { top: 0; }
.fairy-lights-edge--top::before { top: 3px; }
.fairy-lights-edge--bottom { bottom: 0; }
.fairy-lights-edge--bottom::before { bottom: 3px; }
.fairy-lights-edge--left, .fairy-lights-edge--right {
  top: 0; bottom: 0; width: 30px;
  background-image: var(--bulb-strip-v);
  background-repeat: repeat-y;
  background-size: 30px 120px;
  background-position: center;
}
.fairy-lights-edge--left::before, .fairy-lights-edge--right::before {
  content: ""; position: absolute; top: 0; bottom: 0; width: 1px;
  background: var(--aos-glass-border-strong);
}
.fairy-lights-edge--left { left: 0; }
.fairy-lights-edge--left::before { left: 3px; }
.fairy-lights-edge--right { right: 0; }
.fairy-lights-edge--right::before { right: 3px; }
@keyframes fairy-breathe { 0%, 100% { opacity: .82; } 50% { opacity: 1; } }
/* One-shot burst at the Done button you just tapped — see celebrate() in
   the script. Fixed + pointer-events:none, same as the lights, so it can
   never intercept the next click while it fades. */
.celebrate-particle {
  position: fixed; width: 7px; height: 7px; border-radius: 50%;
  pointer-events: none; z-index: 1000; transform: translate(-50%, -50%);
  animation: celebrate-burst 700ms cubic-bezier(0.2, 0.8, 0.4, 1) forwards;
}
@keyframes celebrate-burst {
  0% { transform: translate(-50%, -50%) scale(1); opacity: 1; }
  100% { transform: translate(calc(-50% + var(--dx)), calc(-50% + var(--dy))) scale(0); opacity: 0; }
}
/* ---- OS shell --------------------------------------------------------- */

.os-shell {
  display: grid;
  grid-template-columns: 236px minmax(0, 1fr);
  min-height: 100vh;
  align-items: start;
}
.sidebar {
  position: sticky;
  top: 0;
  display: flex;
  flex-direction: column;
  gap: var(--aos-space-5);
  height: 100vh;
  padding: var(--aos-space-5) var(--aos-space-3);
  /* Chrome, not a widget. This used to be a rounded, bordered, shadowed card
     floating inset from the window edge, which read as one more pane on the
     page rather than the frame around it. Apple, Linear, Raycast and Notion
     all run the sidebar flush to the edge with a single hairline. */
  border-right: 1px solid var(--aos-glass-border);
}
.brand {
  display: flex; align-items: center; gap: var(--aos-space-3);
  padding: 0 var(--aos-space-2);
  font-size: var(--aos-font-size-lg);
  font-weight: var(--aos-font-weight-bold);
  letter-spacing: -0.01em;
  text-decoration: none;
}
.brand-mark { display: inline-flex; width: 22px; height: 22px; color: var(--aos-tone-amber); }
.brand-mark svg { width: 100%; height: 100%; }
.nav { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--aos-space-05); }
.nav-link {
  display: flex; align-items: center; gap: var(--aos-space-3);
  min-height: var(--aos-tap-min); padding: var(--aos-space-3);
  border-radius: var(--aos-radius-md);
  color: var(--aos-color-text-muted);
  text-decoration: none;
  font-size: var(--aos-font-size-sm);
  font-weight: var(--aos-font-weight-medium);
  border: 1px solid transparent;
  transition: background var(--aos-transition-duration) var(--aos-transition-easing),
              color var(--aos-transition-duration) var(--aos-transition-easing);
}
.nav-link:hover, .nav-link:focus-visible {
  background: var(--aos-control-bg);
  border-color: var(--aos-glass-border);
  color: var(--aos-color-text);
}
.nav-link--active {
  background: var(--aos-control-bg);
  border-color: var(--aos-glass-border-strong);
  color: var(--aos-color-text);
}
.nav-link--active .icon { color: var(--aos-color-accent); }
.nav-link .icon { width: 18px; height: 18px; }
.sidebar-foot { margin-top: auto; display: flex; flex-direction: column; gap: var(--aos-space-4); }
.sidebar-account {
  display: flex; align-items: center; gap: var(--aos-space-3);
  padding: var(--aos-space-3);
  border-radius: var(--aos-radius-md);
  background: var(--aos-control-bg);
  border: 1px solid var(--aos-glass-border);
}
/* The ring sits just outside the avatar circle rather than around it as a
   border, so it reads as progress you're tracking, not decoration on the
   avatar itself — same idiom as a watch face's activity ring around, not
   on, the face. Empty by default (dashoffset == the full circumference);
   /sidebar/progress fills it in after load, same progressive-enhancement
   shape as the NOW card's own fetch. No ring at all — no JS, signed out,
   fetch failed — reads as "nothing tracked yet," never as broken. */
.avatar-wrap { position: relative; display: inline-flex; width: 40px; height: 40px; flex: 0 0 40px; }
.avatar-ring { position: absolute; inset: 0; width: 40px; height: 40px; transform: rotate(-90deg); }
.avatar-ring-track { fill: none; stroke: var(--aos-glass-border); stroke-width: 2; }
.avatar-ring-fill {
  fill: none; stroke: var(--aos-color-accent); stroke-width: 2; stroke-linecap: round;
  stroke-dasharray: 113.1; stroke-dashoffset: 113.1;
  transition: stroke-dashoffset 500ms var(--aos-transition-easing);
}
.avatar {
  position: absolute; inset: 3px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--aos-color-accent);
  color: var(--aos-color-accent-contrast);
  font-weight: var(--aos-font-weight-bold);
  font-size: var(--aos-font-size-sm);
}
.account-text { display: flex; flex-direction: column; min-width: 0; }
.account-name {
  font-size: var(--aos-font-size-sm); font-weight: var(--aos-font-weight-medium);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.account-tag { font-size: var(--aos-font-size-xs); color: var(--aos-color-text-faint); }
.sidebar-tools { display: flex; align-items: center; gap: var(--aos-space-2); }
.sidebar-tools form { margin: 0; }
.tool-button {
  display: grid; place-items: center;
  width: 34px; height: var(--aos-tap-min);
  border-radius: var(--aos-radius-sm);
  background: var(--aos-hover-wash);
  border: 1px solid var(--aos-glass-border);
  color: var(--aos-color-text-muted);
  cursor: pointer;
  transition: background var(--aos-transition-duration) var(--aos-transition-easing),
              color var(--aos-transition-duration) var(--aos-transition-easing);
}
.tool-button:hover { background: var(--aos-control-bg-hover); color: var(--aos-color-text); }
.tool-button:active { transform: scale(.94); }
.tool-button .icon { width: 16px; height: 16px; }
.workspace {
  display: flex; flex-direction: column; gap: var(--aos-space-5); min-width: 0;
  padding: var(--aos-space-5) var(--aos-space-6);
}
/* ---- Top rail --------------------------------------------------------- */

.topbar {
  display: flex; align-items: center; justify-content: flex-end;
  gap: var(--aos-space-5); flex-wrap: wrap;
  /* Lives inside .page now, so it inherits the column instead of floating off
     to the left of the content it belongs to. */
  padding: 0 0 var(--aos-space-5);
}
.topbar-greeting { min-width: 0; }
.greeting-title {
  margin: 0;
  font-size: var(--aos-font-size-2xl);
  line-height: 1.1;
  font-weight: var(--aos-font-weight-heavy);
  letter-spacing: var(--aos-tracking-display);
}
.greeting-summary {
  margin: var(--aos-space-1) 0 0;
  color: var(--aos-color-text-muted);
  font-size: var(--aos-font-size-sm);
  font-style: italic;
}
.topbar-actions { display: flex; align-items: center; gap: var(--aos-space-3); }
/* ---- Search ----------------------------------------------------------- */

.search-toggle { display: none; }
.search {
  position: relative;
  display: flex; align-items: center; gap: var(--aos-space-2);
  padding: 0 var(--aos-space-3) 0 var(--aos-space-4);
  min-height: var(--aos-tap-min);
  min-width: 260px; max-width: 420px; width: 100%;
  border-radius: 999px;
  background: var(--aos-glass-bg);
  border: 1px solid var(--aos-glass-border);
}
.search label { display: inline-flex; color: var(--aos-color-text-faint); }
.search label .label-text { display: none; }
.search label .icon { width: 16px; height: 16px; }
.search input {
  flex: 1; min-width: 0;
  background: none; border: 0; outline: none;
  color: var(--aos-color-text);
  font-size: var(--aos-font-size-sm);
}
.search input::placeholder { color: var(--aos-color-text-faint); }
.search-kbd {
  font-family: var(--aos-font-sans); font-size: var(--aos-font-size-xs);
  color: var(--aos-color-text-faint);
  padding: var(--aos-space-05) var(--aos-space-2);
  border-radius: var(--aos-radius-xs);
  border: 1px solid var(--aos-glass-border);
  background: var(--aos-hover-wash);
}
.search-submit, .search .hint { display: none; }
.search-results-panel {
  position: absolute; top: calc(100% + var(--aos-space-2)); right: 0;
  width: min(560px, 80vw);
  max-height: 60vh; overflow-y: auto;
  padding: var(--aos-space-3);
  display: grid; gap: var(--aos-space-3);
  background: var(--aos-glass-bg-raised);
  border: 1px solid var(--aos-glass-border-strong);
  border-radius: var(--aos-radius-lg);
  box-shadow: var(--aos-shadow-lg);
  z-index: 20;
}
/* An author `display` beats the UA stylesheet's [hidden] rule, so the panel
   has to opt back out explicitly or it renders as an empty bar on every page. */
.search-results-panel[hidden] { display: none; }
.search-results-panel .widget { background: none; border: 0; box-shadow: none; padding: 0; }
.search-results-panel li { cursor: pointer; }
/* ---- Widget grid ------------------------------------------------------ */

/* The bottom padding is for the capture button: without it the last row of
   any long list sits underneath a 56px circle you cannot scroll past. 56 is
   the button, space-5 its inset from the edge, space-6 breathing room. */
main {
  min-width: 0;
  padding-bottom: calc(56px + var(--aos-space-5) + var(--aos-space-6));
}
/* One column, centred, for every screen. .page--wide is for the workspaces
   that genuinely need columns (Projects, Files, Tasks); everything else reads
   better at the narrower measure. */
.page { width: 100%; max-width: var(--aos-measure); margin-inline: auto; }
.page--wide { max-width: var(--aos-measure-wide); }
.grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: var(--aos-space-4);
  align-items: start;
}
.widget {
  grid-column: span 4;
  display: flex; flex-direction: column; gap: var(--aos-space-3);
  min-width: 0;
  /* The border and top-edge gradient of the old "pane of glass" treatment
     are still gone — a flat editorial surface reads fine without them. A
     restrained resting/hover shadow stays, though: it's the one cue that a
     .widget is a card you can interact with, distinct from .ui-section's
     chrome-less grouping. */
  box-shadow: var(--aos-shadow-sm);
  transition: box-shadow var(--aos-transition-duration) var(--aos-transition-easing),
              transform var(--aos-transition-duration) var(--aos-transition-easing);
}
.widget:hover { box-shadow: var(--aos-shadow-md); transform: translateY(-2px); }
.widget h2, .widget-head h2 {
  display: flex; align-items: center; gap: var(--aos-space-2);
  margin: 0;
  font-size: var(--aos-font-size-sm);
  font-weight: var(--aos-font-weight-bold);
  letter-spacing: var(--aos-tracking-card);
}
.widget-head { display: flex; align-items: center; justify-content: space-between; gap: var(--aos-space-3); }
.widget-meta { font-size: var(--aos-font-size-xs); color: var(--aos-color-text-faint); }
.icon { display: inline-flex; width: 15px; height: 15px; color: var(--aos-color-text-muted); flex: 0 0 auto; }
.icon svg { width: 100%; height: 100%; }
.widget ul, .widget ol { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.widget li { font-size: var(--aos-font-size-sm); }
.empty { margin: 0; color: var(--aos-color-text-faint); font-size: var(--aos-font-size-sm); }
.empty a { color: var(--aos-color-accent); text-decoration: none; }
.empty a:hover { text-decoration: underline; }
.hint { margin: 0; color: var(--aos-color-text-faint); font-size: var(--aos-font-size-xs); }
.error { margin: 0; color: var(--aos-color-danger); font-size: var(--aos-font-size-sm); }
.error:empty { display: none; }
/* ---- Today's Plan timeline -------------------------------------------- */

.hero-schedule { display: flex; flex-direction: column; gap: var(--aos-space-2); }
.timeline-item {
  display: grid;
  grid-template-columns: 20px 62px minmax(0, 1fr) 16px;
  align-items: center;
  gap: var(--aos-space-3);
  min-height: var(--aos-tap-min); padding: var(--aos-space-3) var(--aos-space-2);
  border-radius: var(--aos-radius-sm);
  transition: background var(--aos-transition-duration) var(--aos-transition-easing);
}
.timeline-item:hover { background: var(--aos-hover-wash); }
.timeline-dot {
  width: 8px; height: 8px; margin: 0 6px;
  border-radius: 50%;
  background: var(--aos-tone-blue);
  box-shadow: 0 0 0 3px rgba(96, 165, 250, 0.16);
}
.timeline-item--reminder .timeline-dot { background: var(--aos-tone-amber); box-shadow: 0 0 0 3px rgba(251, 191, 36, 0.16); }
.timeline-check {
  width: 18px; height: 18px; padding: 0;
  border-radius: 50%;
  border: 1.5px solid var(--aos-color-text-faint);
  background: none;
  cursor: pointer;
  transition: border-color var(--aos-transition-duration) var(--aos-transition-easing),
              background var(--aos-transition-duration) var(--aos-transition-easing);
}
.timeline-check:hover { border-color: var(--aos-color-accent); }
.timeline-time { font-size: var(--aos-font-size-xs); color: var(--aos-color-text-muted); font-variant-numeric: tabular-nums; }
.timeline-title { font-size: var(--aos-font-size-sm); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.timeline-chevron { display: inline-flex; width: 14px; height: 14px; color: var(--aos-color-text-faint); opacity: 0; transition: opacity var(--aos-transition-duration); }
.timeline-chevron svg { width: 100%; height: 100%; }
.timeline-item:hover .timeline-chevron { opacity: 1; }
/* ---- Tasks ------------------------------------------------------------ */

.task-item {
  display: flex; align-items: center; justify-content: space-between; gap: var(--aos-space-3);
  min-height: var(--aos-tap-min); padding: 8px var(--aos-space-2);
  border-radius: var(--aos-radius-sm);
  transition: background var(--aos-transition-duration) var(--aos-transition-easing);
}
.task-item:hover { background: var(--aos-hover-wash); }
.task-item--done .task-open { color: var(--aos-color-text-faint); text-decoration: line-through; }
.task-state { flex: 0 0 auto; font-size: var(--aos-font-size-xs); color: var(--aos-color-text-faint); }
.task-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.task-due { font-size: var(--aos-font-size-xs); color: var(--aos-color-text-faint); font-variant-numeric: tabular-nums; white-space: nowrap; }
.task-done {
  padding: var(--aos-space-1) var(--aos-space-3);
  border-radius: 999px;
  border: 1px solid var(--aos-glass-border);
  background: var(--aos-hover-wash);
  color: var(--aos-color-text-muted);
  font-size: var(--aos-font-size-xs);
  cursor: pointer;
  transition: background var(--aos-transition-duration) var(--aos-transition-easing),
              color var(--aos-transition-duration) var(--aos-transition-easing);
}
.task-done:hover { background: var(--aos-color-accent-strong); color: var(--aos-color-accent-contrast); border-color: transparent; }
.task-done:active { transform: scale(.96); }
.item-time { color: var(--aos-color-text-faint); font-size: var(--aos-font-size-xs); margin-right: var(--aos-space-2); }
/* ---- Projects --------------------------------------------------------- */
.progress-track, .meter-track {
  display: block; height: 4px; border-radius: 999px;
  background: var(--aos-control-bg);
  overflow: hidden;
}
/* The fill belongs to the primitive, not to one screen. It used to be scoped
   to `.today-progress`, which left every other track in the product — the
   project workspace's, and now Nutrition's — drawing an empty groove. */
.progress-fill { display: block; height: 100%; border-radius: 999px; background: var(--aos-color-accent); }
/* ---- Daily Decisions ---------------------------------------------------- */
.decide-list { display: flex; flex-direction: column; gap: var(--aos-space-5); }
.decide-slot { display: flex; flex-direction: column; gap: var(--aos-space-2); }
.decide-head { display: flex; align-items: center; gap: var(--aos-space-2); }
.decide-name { margin: 0; font-size: var(--aos-font-size-sm); font-weight: var(--aos-font-weight-medium); }
.decide-meta { font-size: var(--aos-font-size-xs); color: var(--aos-color-text-muted); }
.decide-answer { flex: 1; min-width: 0; font-size: var(--aos-font-size-sm); color: var(--aos-color-accent);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.decide-chips { display: flex; flex-wrap: wrap; gap: var(--aos-space-2); }
.decide-chips form { margin: 0; }
.decide-chip {
  min-height: var(--aos-tap-min); padding: 0 var(--aos-space-4);
  border-radius: var(--aos-radius-md); border: 1px solid var(--aos-glass-border);
  background: var(--aos-glass-bg); color: var(--aos-color-text); font-size: var(--aos-font-size-sm);
}
.decide-chip:hover { border-color: var(--aos-color-accent); }
.decide-chip.is-chosen { border-color: var(--aos-color-accent); background: var(--aos-color-accent-soft); color: var(--aos-color-accent); }
.decide-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--aos-space-3); }
.decide-row form { margin: 0; }
.decide-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--aos-space-05); }
/* The morning strip: one line, quiet, tappable to the full list. It sits
   directly under the answer to "what now?" because it is reference, not work. */
.decided-strip {
  display: flex; align-items: center; min-height: var(--aos-tap-min);
  color: var(--aos-color-text-muted); text-decoration: none;
}
.decided-line { font-size: var(--aos-font-size-sm); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.decided-strip:hover .decided-line { color: var(--aos-color-text); }
/* ---- Shopping ---------------------------------------------------------- */
.shop-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--aos-space-3); }
.shop-row form { margin: 0; }
/* The row is the button. In a shop you are walking, holding a basket, aiming
   with a thumb — so the tap target is the whole line, not a 20px box. */
.shop-tap { flex: 0 0 auto; }
.shop-check {
  display: grid; place-items: center; padding: 0; background: none; border: 0;
  width: var(--aos-tap-min); height: var(--aos-tap-min); flex: 0 0 var(--aos-tap-min);
  margin-left: calc(var(--aos-space-3) * -1);
}
.shop-check::before {
  content: ""; width: 20px; height: 20px; border-radius: 50%;
  border: 1.5px solid var(--aos-color-text-faint);
}
.shop-check:hover::before { border-color: var(--aos-color-accent); background: var(--aos-color-accent-soft); }
.shop-text { flex: 1; min-width: 0; display: flex; align-items: baseline; gap: var(--aos-space-2); }
.shop-name { font-size: var(--aos-font-size-sm); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.shop-qty { font-size: var(--aos-font-size-xs); color: var(--aos-color-text-muted); }
/* Drawn, not typed: as a glyph this needed an 8px font-size, which is off the
   type ramp and unreadable as text anyway. */
.shop-staple {
  display: grid; place-items: center; padding: 0; background: none; border: 0;
  width: var(--aos-tap-min); height: var(--aos-tap-min); flex: 0 0 var(--aos-tap-min);
  margin-right: calc(var(--aos-space-3) * -1);
}
.shop-staple::before {
  content: ""; width: 8px; height: 8px; border-radius: 50%;
  border: 1.5px solid var(--aos-color-text-faint);
}
.shop-staple.is-staple::before { background: var(--aos-color-accent); border-color: var(--aos-color-accent); }
.shop-staple:hover::before { border-color: var(--aos-color-accent); }
.shop-row.is-bought .shop-name { text-decoration: line-through; opacity: .5; }
.shop-row.is-bought .shop-check::before { background: var(--aos-color-accent); border-color: var(--aos-color-accent); }
.shop-actions { display: flex; gap: var(--aos-space-3); margin-top: var(--aos-space-3); }
.shop-actions form { margin: 0; }
/* Rename/delete: a disclosure rather than a second always-visible row of
   controls — the primary tap targets (buy, staple) stay exactly as they were
   (D-026), and this drops to its own full-width line only once opened. */
.shop-more { flex: 0 0 auto; }
.shop-more > summary {
  list-style: none; cursor: pointer; min-height: var(--aos-tap-min); min-width: var(--aos-tap-min);
  display: flex; align-items: center; justify-content: center; color: var(--aos-color-text-muted);
  border-radius: var(--aos-radius-md);
  transition: background var(--aos-transition-fast) var(--aos-transition-easing),
              color var(--aos-transition-fast) var(--aos-transition-easing);
}
.shop-more > summary::-webkit-details-marker { display: none; }
.shop-more > summary:hover { background: var(--aos-hover-wash); color: var(--aos-color-text); }
.shop-more[open] { flex-basis: 100%; }
.shop-more[open] > summary { margin-bottom: var(--aos-space-2); }
.shop-rename { display: flex; gap: var(--aos-space-2); flex: 1; margin-right: var(--aos-space-2); }
.shop-rename input { flex: 1; min-width: 0; }
/* The Save/Set button next to that input rendered as a bare, unstyled OS
   button — nothing in this system's cascade reached it. Small and quiet
   to match the row it sits in, not a full-size accent button. */
.shop-rename button {
  flex: 0 0 auto; padding: 0 var(--aos-space-3); min-height: var(--aos-tap-min);
  border-radius: var(--aos-radius-sm); border: 1px solid var(--aos-glass-border);
  background: var(--aos-hover-wash); color: var(--aos-color-text);
  font-size: var(--aos-font-size-sm); cursor: pointer;
  transition: filter var(--aos-transition-fast) var(--aos-transition-easing);
}
.shop-rename button:hover { filter: brightness(.95); }
.shop-rename button:active { transform: scale(.96); }
.subject-rename { margin-bottom: var(--aos-space-4); }
.subject-rename > summary { font-size: var(--aos-font-size-sm); color: var(--aos-color-accent); cursor: pointer; }
/* ---- Academics --------------------------------------------------------- */
.due-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--aos-space-3); }
.due-row form { margin: 0; }
/* The box reads as 20px; the thing you tap is 44px. Same trick the habit
   chips use — a checkbox drawn at finger size looks like a bug, and one drawn
   at 20px cannot be hit on a phone. */
.due-check {
  display: grid; place-items: center; padding: 0; background: none; border: 0;
  width: var(--aos-tap-min); height: var(--aos-tap-min); flex: 0 0 var(--aos-tap-min);
  margin-left: calc(var(--aos-space-3) * -1);
}
.due-check::before {
  content: ""; width: 20px; height: 20px; border-radius: var(--aos-radius-xs);
  border: 1.5px solid var(--aos-color-text-faint);
  transition: background var(--aos-transition-duration) var(--aos-transition-easing);
}
.due-check:hover::before { border-color: var(--aos-color-accent); background: var(--aos-color-accent-soft); }
.due-text { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--aos-space-05); }
.due-title { font-size: var(--aos-font-size-sm); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.due-meta { font-size: var(--aos-font-size-xs); color: var(--aos-color-text-muted); text-transform: capitalize; }
.due-subject { text-transform: none; }
.due-when { flex: 0 0 auto; font-size: var(--aos-font-size-xs); color: var(--aos-color-text-muted); }
/* A missed deadline is the most important thing on the screen, so it is the
   one place in this module that spends colour. */
.due-when.is-late { color: var(--aos-tone-amber); }
.due-row.is-done .due-title { text-decoration: line-through; opacity: .55; }
/* ---- Nutrition --------------------------------------------------------- */
/* Protein is the only figure with a bar under it. The other three are plain
   numbers on purpose — see _macro_breakdown_html. */
.macro-block { display: flex; flex-direction: column; gap: var(--aos-space-4); }
.macro-primary { display: flex; flex-direction: column; gap: var(--aos-space-2); }
.macro-primary-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--aos-space-3); }
.macro-name { font-size: var(--aos-font-size-sm); color: var(--aos-color-text-muted); }
.macro-value { font-size: var(--aos-font-size-lg); font-weight: var(--aos-font-weight-bold); font-variant-numeric: tabular-nums; }
.macro-of { font-size: var(--aos-font-size-sm); font-weight: var(--aos-font-weight-regular); color: var(--aos-color-text-muted); font-variant-numeric: tabular-nums; }
.macro-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--aos-space-3); }
.macro-cell { display: flex; flex-direction: column; gap: var(--aos-space-05); }
.macro-cell-value { font-size: var(--aos-font-size-base); font-weight: var(--aos-font-weight-medium); font-variant-numeric: tabular-nums; }
.macro-cell-name { font-size: var(--aos-font-size-xs); color: var(--aos-color-text-muted); }

.meal-groups { display: flex; flex-direction: column; gap: var(--aos-space-5); }
.meal-name { margin: 0 0 var(--aos-space-2); font-size: var(--aos-font-size-xs); font-weight: var(--aos-font-weight-medium);
  text-transform: capitalize; color: var(--aos-color-text-muted); }
.option-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: var(--aos-space-2); list-style: none; margin: 0; padding: 0; }
.option-row { display: flex; align-items: center; gap: var(--aos-space-2); }
.option-row form { margin: 0; }
.option-row form:first-child { flex: 1; min-width: 0; }
.option-log {
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--aos-space-05);
  width: 100%; min-height: var(--aos-tap-lg); padding: var(--aos-space-2) var(--aos-space-3);
  border-radius: var(--aos-radius-md); border: 1px solid var(--aos-glass-border);
  background: var(--aos-glass-bg); color: var(--aos-color-text); text-align: left;
  transition: border-color var(--aos-transition-duration) var(--aos-transition-easing);
}
.option-log:hover { border-color: var(--aos-color-accent); }
.option-name { font-size: var(--aos-font-size-sm); }
.option-macro { font-size: var(--aos-font-size-xs); color: var(--aos-color-text-muted); }
/* Logging is the verb this section exists for; removing an option is
   housekeeping done twice a year. They must not look like siblings — so the
   remove control keeps its 44px target but gives up all of its colour. */
.icon-remove {
  display: grid; place-items: center; flex: 0 0 var(--aos-tap-min);
  width: var(--aos-tap-min); height: var(--aos-tap-min); padding: 0;
  border: 0; background: none; border-radius: var(--aos-radius-md);
  color: var(--aos-color-text-faint); font-size: var(--aos-font-size-base); line-height: 1;
  transition: background var(--aos-transition-fast) var(--aos-transition-easing),
              color var(--aos-transition-fast) var(--aos-transition-easing);
}
.icon-remove:hover { color: var(--aos-color-text); background: var(--aos-hover-wash); }
.icon-remove:active { transform: scale(.9); }
.option-add { margin-top: var(--aos-space-3); }
.option-add summary { min-height: var(--aos-tap-min); display: flex; align-items: center; font-size: var(--aos-font-size-sm); color: var(--aos-color-accent); }
.option-add form, .ask-form, .food-form { display: flex; flex-direction: column; gap: var(--aos-space-2); margin-top: var(--aos-space-2); }
.option-add label, .ask-form label, .food-form label { font-size: var(--aos-font-size-sm); color: var(--aos-color-text-muted); }
.option-add input, .ask-form input, .ask-form select, .food-form textarea {
  min-height: var(--aos-tap-min); padding: var(--aos-space-2) var(--aos-space-3);
  border-radius: var(--aos-radius-md); background: var(--aos-surface-sunken);
  border: 1px solid var(--aos-glass-border); color: var(--aos-color-text);
  font-size: var(--aos-font-size-base); font-family: inherit; outline: none;
}
.food-form textarea { resize: vertical; line-height: 1.55; }
.option-add input:focus, .ask-form input:focus, .ask-form select:focus, .food-form textarea:focus { border-color: var(--aos-color-accent); }
.option-add button, .ask-form button, .food-form button {
  align-self: flex-start; min-height: var(--aos-tap-min); padding: 0 var(--aos-space-5);
  border-radius: var(--aos-radius-md); border: 0; background: var(--aos-color-accent-strong);
  color: var(--aos-color-accent-contrast); font-weight: var(--aos-font-weight-medium);
}
.ask-form { padding-bottom: var(--aos-space-4); }
/* The submit button in every "Add X" form here — decisions, deadlines,
   reminders, contacts, subjects — had nothing in the cascade reaching it and
   rendered as a bare OS button. Same treatment as .inline-create's, since
   both are "create one thing" submits of equal weight. */
.ask-form button, .food-form button {
  min-height: var(--aos-tap-min); padding: 0 var(--aos-space-5); border: 0; cursor: pointer;
  border-radius: var(--aos-radius-md); background: var(--aos-color-accent);
  color: var(--aos-color-accent-contrast); font-size: var(--aos-font-size-sm);
  font-weight: var(--aos-font-weight-medium);
  transition: background var(--aos-transition-fast) var(--aos-transition-easing);
}
.ask-form button:hover, .food-form button:hover { background: var(--aos-color-accent-strong); }
.ask-form button:active, .food-form button:active { transform: scale(.98); }
.ask-question { margin: 0; font-size: var(--aos-font-size-sm); }
.ask-fields { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: var(--aos-space-3); align-items: end; }
/* Each label travels with its own control. Left as loose grid children they
   wrap independently and a label ends up captioning the wrong field. */
.ask-field { display: flex; flex-direction: column; gap: var(--aos-space-05); min-width: 0; }
.ask-fields label { display: block; }
.ask-fields input, .ask-fields select { width: 100%; }

.log-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--aos-space-3); }
.log-row form { margin: 0; }
.log-text { flex: 1; min-width: 0; font-size: var(--aos-font-size-sm); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.log-protein { font-size: var(--aos-font-size-xs); color: var(--aos-color-text-muted); font-variant-numeric: tabular-nums; }
.nutrition-line { display: flex; flex-direction: column; gap: var(--aos-space-2); min-height: var(--aos-tap-min); justify-content: center; color: inherit; text-decoration: none; }
.nutrition-figure { font-size: var(--aos-font-size-base); font-weight: var(--aos-font-weight-medium); }
/* ---- Today's Progress meters ------------------------------------------ */

.meter-list { gap: var(--aos-space-4); }
.meter-fill--violet { background: var(--aos-tone-violet); }
.meter-fill--green { background: var(--aos-tone-green); }
.meter-fill--blue { background: var(--aos-tone-blue); }
/* ---- Upcoming --------------------------------------------------------- */

.upcoming-list { gap: var(--aos-space-05); }
.upcoming-dot--event { background: var(--aos-tone-blue); }
.upcoming-dot--reminder { background: var(--aos-tone-amber); }
/* ---- Toast ------------------------------------------------------------ */

.toast {
  position: fixed; bottom: var(--aos-space-5); left: 50%; transform: translateX(-50%);
  z-index: 40;
  display: flex; align-items: center; gap: var(--aos-space-3);
  max-width: min(560px, 90vw);
  padding: var(--aos-space-3) var(--aos-space-5);
  background: var(--aos-glass-bg-raised);
  color: var(--aos-color-text);
  border: 1px solid var(--aos-glass-border-strong);
  border-radius: 999px;
  box-shadow: var(--aos-shadow-lg);
  font-size: var(--aos-font-size-sm);
}
.toast[hidden] { display: none; }
.toast button {
  padding: var(--aos-space-1) var(--aos-space-3);
  border-radius: 999px;
  border: 1px solid var(--aos-glass-border);
  background: var(--aos-control-bg);
  font-size: var(--aos-font-size-xs);
  cursor: pointer;
  transition: background var(--aos-transition-fast) var(--aos-transition-easing),
              color var(--aos-transition-fast) var(--aos-transition-easing);
}
.toast button:hover { background: var(--aos-color-accent-strong); color: var(--aos-color-accent-contrast); }
.toast button:active { transform: scale(.96); }
/* ---- Auth pages ------------------------------------------------------- */

.auth-page { display: flex; justify-content: center; align-items: center; min-height: 100vh; padding: var(--aos-space-7) var(--aos-space-4); }
.auth-card {
  max-width: 400px; width: 100%;
  padding: var(--aos-space-6);
  background: var(--aos-glass-bg-hero);
  border: 1px solid var(--aos-glass-border);
  border-radius: var(--aos-radius-xl);
  box-shadow: var(--aos-shadow-lg);
}
.auth-card h1 {
  margin: 0;
  font-family: var(--aos-font-serif);
  font-weight: var(--aos-font-weight-regular);
  font-size: var(--aos-font-size-2xl);
  letter-spacing: -0.01em;
}
.auth-card form, .auth-card .oauth-buttons {
  display: flex; flex-direction: column; gap: var(--aos-space-3); margin-top: var(--aos-space-4);
}
.auth-card label { display: flex; flex-direction: column; gap: var(--aos-space-2); font-size: var(--aos-font-size-sm); color: var(--aos-color-text-muted); }
.auth-card input {
  height: var(--aos-tap-min); padding: 0 var(--aos-space-4);
  border-radius: var(--aos-radius-md);
  background: var(--aos-surface-sunken);
  border: 1px solid var(--aos-glass-border);
  color: var(--aos-color-text);
  outline: none;
}
.auth-card input:focus { border-color: var(--aos-color-accent); }
.auth-card button {
  height: var(--aos-tap-min);
  border-radius: var(--aos-radius-md);
  border: 1px solid var(--aos-glass-border);
  background: var(--aos-control-bg);
  cursor: pointer;
  font-size: var(--aos-font-size-sm);
  font-weight: var(--aos-font-weight-medium);
  transition: background var(--aos-transition-duration) var(--aos-transition-easing);
}
.auth-card button:hover { background: var(--aos-control-bg-hover); }
.auth-card button:active { transform: scale(.98); }
.auth-card form button[type="submit"] { background: var(--aos-color-accent-strong); color: var(--aos-color-accent-contrast); border-color: transparent; }
.auth-card form button[type="submit"]:hover { background: var(--aos-color-accent); }
.auth-card a { color: var(--aos-color-accent); }
/* ---- Aux pages -------------------------------------------------------- */

.search-results h1, .project-page h1 {
  margin: 0 0 var(--aos-space-4);
  font-size: var(--aos-font-size-xl);
  font-weight: var(--aos-font-weight-bold);
  letter-spacing: var(--aos-tracking-tight);
}
.project-page a, .search-results a { color: var(--aos-color-accent); }
/* ---- Sprint 1: reference-match additions ------------------------------ */

.topbar { flex-direction: column; align-items: stretch; gap: var(--aos-space-4); }
.topbar-row { display: flex; align-items: center; justify-content: space-between; gap: var(--aos-space-5); flex-wrap: wrap; }
.topbar-row--actions { justify-content: flex-end; }

.card-action {
  display: inline-flex; align-items: center; gap: var(--aos-space-2);
  min-height: var(--aos-tap-min); margin-top: auto; padding-top: var(--aos-space-2);
  font-size: var(--aos-font-size-sm);
  color: var(--aos-color-accent);
  text-decoration: none;
  transition: color var(--aos-transition-fast) var(--aos-transition-easing);
}
.card-action .icon { width: 14px; height: 14px; color: currentColor; }
.card-action:hover { color: var(--aos-color-text); }
/* Sidebar rhythm for a 17-item list */
.sidebar { gap: var(--aos-space-4); overflow: hidden; }
.sidebar nav { flex: 1; min-height: 0; overflow-y: auto; scrollbar-width: thin; }
.sidebar nav::-webkit-scrollbar { width: 4px; }
.sidebar nav::-webkit-scrollbar-thumb { background: var(--aos-control-bg-hover); border-radius: 999px; }
.nav-link { padding: 8px var(--aos-space-3); font-size: var(--aos-font-size-sm); }
/* ---- Sprint 2: workflow surfaces -------------------------------------- */

.habit-list { gap: var(--aos-space-05); }
.habit-row {
  display: flex; align-items: center; gap: var(--aos-space-3);
  min-height: var(--aos-tap-min); padding: var(--aos-space-3) var(--aos-space-2); border-radius: var(--aos-radius-sm);
}
.habit-row:hover { background: var(--aos-hover-wash); }
.habit-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.habit-check {
  width: 20px; height: 20px; flex: 0 0 20px; padding: 0;
  border-radius: 50%;
  border: 1.5px solid var(--aos-color-text-faint);
  background: none; cursor: pointer;
  transition: background var(--aos-transition-duration), border-color var(--aos-transition-duration);
}
.habit-check:hover { border-color: var(--aos-color-accent); }
.habit-check.is-done {
  background: var(--aos-color-accent-strong); border-color: var(--aos-color-accent-strong);
  box-shadow: inset 0 0 0 3px rgba(6, 33, 15, 0.55);
}
.focus-picker-empty { margin-top: var(--aos-space-3); }
.task-open, .note-link { color: inherit; text-decoration: none; }
/* Full row height, like .plan-title: the title is what you aim at. */
.task-open {
  display: flex; align-items: center; flex: 1; min-width: 0; min-height: var(--aos-tap-min);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.task-open:hover, .note-link:hover .note-title { color: var(--aos-color-accent); }
.note-row { border-radius: var(--aos-radius-sm); }
.note-row:hover { background: var(--aos-hover-wash); }
.note-link { display: flex; align-items: center; gap: var(--aos-space-3); padding: 8px var(--aos-space-2); }
.note-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.note-link .timeline-chevron { opacity: 0; }
.note-row:hover .timeline-chevron { opacity: 1; }
a.timeline-title { text-decoration: none; }
a.timeline-title:hover { color: var(--aos-color-accent); }
/* Detail pages */
.detail-page { display: flex; flex-direction: column; gap: var(--aos-space-4); }
.detail-back { margin: 0; }
.detail-back a {
  min-height: var(--aos-tap-min); display: inline-flex; align-items: center; gap: var(--aos-space-1);
  margin-left: calc(var(--aos-space-2) * -1); padding-right: var(--aos-space-2);
  color: var(--aos-color-accent); text-decoration: none; font-size: var(--aos-font-size-sm);
}
.detail-back a:hover { opacity: .75; }
.back-chevron { display: flex; }
/* ICONS["chevron"] is drawn pointing right (it's also .project-item-go's
   "go into this" arrow) — a back link needs it flipped, which this rule
   was missing entirely; the rotation had drifted onto .project-item-go
   instead, of all places, pointing the wrong way in both spots at once. */
.back-chevron svg { width: 20px; height: 20px; transform: rotate(180deg); }
.detail-card { max-width: 760px; }
.detail-card h1 {
  display: flex; align-items: center; gap: var(--aos-space-2);
  margin: 0; font-size: var(--aos-font-size-lg); font-weight: var(--aos-font-weight-bold);
}
.detail-card form { display: flex; flex-direction: column; gap: var(--aos-space-4); margin-top: var(--aos-space-3); }
/* A capture-style bar is a row wherever it appears. Inside a detail card the
   column rule above out-specified .dump-form, which left the Habits add bar
   as a stack with its checkbox stranded on a line of its own. */
.detail-card form.dump-form { flex-direction: row; align-items: center; gap: var(--aos-space-2); }
/* Likewise `.detail-card label`, which stacks a field over its caption — right
   for a form field, wrong for a checkbox that sits beside its own word. */
.detail-card label.baseline-toggle { flex-direction: row; }
.detail-card label { display: flex; flex-direction: column; gap: var(--aos-space-2); font-size: var(--aos-font-size-sm); color: var(--aos-color-text-muted); }
.detail-card input, .detail-card select, .detail-card textarea {
  min-height: var(--aos-tap-min); padding: 0 var(--aos-space-4);
  border-radius: var(--aos-radius-md);
  background: var(--aos-surface-sunken); border: 1px solid var(--aos-glass-border);
  color: var(--aos-color-text); font-size: var(--aos-font-size-base); font-family: inherit; outline: none;
}
.detail-card textarea { resize: vertical; line-height: 1.55; }
.detail-card input:focus, .detail-card select:focus, .detail-card textarea:focus { border-color: var(--aos-color-accent); }
.detail-actions { display: flex; gap: var(--aos-space-3); }
.detail-actions button {
  min-height: var(--aos-tap-min); padding: 0 var(--aos-space-5); border-radius: var(--aos-radius-md); border: 0;
  background: var(--aos-color-accent-strong); color: var(--aos-color-accent-contrast);
  font-weight: var(--aos-font-weight-medium); cursor: pointer;
  transition: background var(--aos-transition-fast) var(--aos-transition-easing);
}
.detail-actions button:hover { background: var(--aos-color-accent); }
.detail-actions button:active { transform: scale(.98); }
.detail-secondary { margin-top: var(--aos-space-3); }
.detail-complete {
  min-height: var(--aos-tap-min); padding: 0 var(--aos-space-5); border-radius: var(--aos-radius-md);
  border: 1px solid var(--aos-glass-border); background: var(--aos-control-bg);
  color: var(--aos-color-text); cursor: pointer;
  transition: background var(--aos-transition-fast) var(--aos-transition-easing);
}
.detail-complete:hover { background: var(--aos-control-bg-hover); }
.detail-complete:active { transform: scale(.98); }
.detail-destructive {
  min-height: var(--aos-tap-min); padding: 0 var(--aos-space-5); border-radius: var(--aos-radius-md);
  border: 1px solid rgba(248, 113, 113, 0.4); background: var(--aos-control-bg);
  color: var(--aos-color-danger); cursor: pointer;
  transition: background var(--aos-transition-fast) var(--aos-transition-easing);
}
.detail-destructive:hover { background: rgba(248, 113, 113, 0.16); }
.detail-destructive:active { transform: scale(.98); }
.notice {
  margin: 0; padding: var(--aos-space-3) var(--aos-space-4);
  border-radius: var(--aos-radius-md);
  background: var(--aos-color-accent-soft); border: 1px solid var(--aos-color-accent-veil);
  color: var(--aos-color-accent); font-size: var(--aos-font-size-sm);
}
/* The project's own header. The name is a field rather than a heading because
   renaming is a thing you do to a project, and a pencil that opens a dialog to
   edit one line is three interactions for one word. */
.project-hero { display: flex; flex-direction: column; gap: var(--aos-space-2); margin-bottom: var(--aos-space-4); }
.project-title-row { display: flex; align-items: center; justify-content: space-between; gap: var(--aos-space-3); }
.project-name {
  margin: 0; min-width: 0; font-size: var(--aos-font-size-2xl); line-height: 1.15;
  font-weight: var(--aos-font-weight-bold); letter-spacing: var(--aos-tracking-tight);
}
.project-rename { display: flex; align-items: center; gap: var(--aos-space-2); }
.project-rename input {
  flex: 1; min-width: 0; min-height: var(--aos-tap-min); padding: 0 var(--aos-space-3);
  border: 1px solid var(--aos-color-accent); border-radius: var(--aos-radius-sm);
  background: var(--aos-surface-sunken); color: var(--aos-color-text);
  font-size: var(--aos-font-size-lg); font-weight: var(--aos-font-weight-bold);
  letter-spacing: var(--aos-tracking-tight); outline: none;
}
.project-rename button {
  min-height: var(--aos-tap-min); padding: 0 var(--aos-space-4); border: 0; cursor: pointer;
  border-radius: var(--aos-radius-md); background: var(--aos-color-accent-strong);
  color: var(--aos-color-accent-contrast); font-size: var(--aos-font-size-sm);
  transition: background var(--aos-transition-fast) var(--aos-transition-easing);
}
.project-rename button:hover { background: var(--aos-color-accent); }
.project-rename button:active { transform: scale(.98); }
.project-detail { margin: 0; font-size: var(--aos-font-size-sm); color: var(--aos-color-text-muted); }
.project-add { margin-top: var(--aos-space-3); }
.upload-inline { display: flex; flex-wrap: wrap; align-items: center; gap: var(--aos-space-2); margin-top: var(--aos-space-3); }
.upload-inline input[type="file"] { flex: 1; min-width: 0; min-height: var(--aos-tap-min); font-size: var(--aos-font-size-xs); color: var(--aos-color-text-muted); }
.project-status { margin-top: var(--aos-space-5); }
/* A <button class="quiet-action"> keeps the UA's grey button background
   otherwise, which put muted text on light grey at 2.7:1 in dark mode. */
button.quiet-action {
  border: 1px solid var(--aos-glass-border); background: none;
  color: var(--aos-color-text-muted); cursor: pointer;
}
button.quiet-action:hover { color: var(--aos-color-text); background: var(--aos-hover-wash); }
.file-row { gap: var(--aos-space-3); }
.file-row .ws-title {
  display: flex; align-items: center; flex: 1; min-width: 0; min-height: var(--aos-tap-min);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.file-row .ws-inline-form { flex: 0 0 auto; margin: 0; }
/* The project timeline, on the same list primitive as everything else. */
.timeline-row { align-items: baseline; }
.timeline-when {
  flex: 0 0 auto; font-size: var(--aos-font-size-xs); color: var(--aos-color-text-faint);
  font-variant-numeric: tabular-nums;
}
.timeline-what { flex: 1; min-width: 0; font-size: var(--aos-font-size-sm); }
.detail-page .grid .widget { grid-column: span 6; }
/* The shell wraps every page body in the 12-column .grid, so a full-page
   section is itself a grid item — without this it collapses to one column. */
.detail-page, .project-page, .search-results { grid-column: 1 / -1; min-width: 0; }
/* ---- Sprint 3: workspaces --------------------------------------------- */

.workspace-page { grid-column: 1 / -1; min-width: 0; display: flex; flex-direction: column; gap: var(--aos-space-5); max-width: 760px; }
/* .workspace-head is gone — every screen uses .page-head from the primitives. */
.workspace-sub { margin: var(--aos-space-1) 0 0; font-size: var(--aos-font-size-sm); color: var(--aos-color-text-muted); }
.workspace-toolbar, .workspace-body {
  padding: var(--aos-space-4);
  background: var(--aos-glass-bg);
  border: 1px solid var(--aos-glass-border);
  border-radius: var(--aos-radius-lg);
}
.workspace-body { padding: 0 var(--aos-space-4); }
.toolbar { display: flex; align-items: center; gap: var(--aos-space-3); flex-wrap: wrap; }
/* The toolbar was built at 38px and missed the pass that lifted every other
   control to the 44px floor. On a phone a 38px select is a control you aim at
   twice. */
.toolbar-search {
  display: flex; align-items: center; gap: var(--aos-space-2);
  flex: 1; min-width: 200px; height: var(--aos-tap-min); padding: 0 var(--aos-space-4);
  border-radius: 999px; background: var(--aos-surface-sunken); border: 1px solid var(--aos-glass-border);
}
.toolbar-search .icon { width: 15px; height: 15px; color: var(--aos-color-text-faint); }
.toolbar-search input { flex: 1; min-width: 0; padding: 0; background: none; border: 0; outline: none; color: var(--aos-color-text); font-size: var(--aos-font-size-sm); }
.toolbar-select select {
  height: var(--aos-tap-min); padding: 0 var(--aos-space-3); border-radius: var(--aos-radius-md);
  background: var(--aos-surface-sunken); border: 1px solid var(--aos-glass-border);
  color: var(--aos-color-text); font-size: var(--aos-font-size-sm);
}
.toolbar-apply {
  height: var(--aos-tap-min); padding: 0 var(--aos-space-5); border-radius: var(--aos-radius-md); border: 0;
  background: var(--aos-control-bg); color: var(--aos-color-text);
  font-size: var(--aos-font-size-sm); cursor: pointer;
  transition: background var(--aos-transition-fast) var(--aos-transition-easing);
}
.toolbar-apply:hover { background: var(--aos-control-bg-hover); }
.toolbar-apply:active { transform: scale(.98); }
.ws-create { display: flex; align-items: center; gap: var(--aos-space-2); }
.ws-create input {
  height: var(--aos-tap-min); width: 240px; padding: 0 var(--aos-space-4);
  border-radius: var(--aos-radius-md); background: var(--aos-surface-sunken);
  border: 1px solid var(--aos-glass-border); color: var(--aos-color-text);
  font-size: var(--aos-font-size-sm); outline: none;
}
.ws-create input:focus { border-color: var(--aos-color-accent); }
.ws-create button {
  display: grid; place-items: center; padding: 0;
  width: var(--aos-tap-min); height: var(--aos-tap-min);
  border-radius: var(--aos-radius-md); border: 0;
  background: var(--aos-color-accent-strong); color: var(--aos-color-accent-contrast); cursor: pointer;
}
.ws-create button .icon { width: 16px; height: 16px; color: currentColor; }
.ws-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.ws-row {
  display: grid;
  grid-template-columns: 22px minmax(0, 1fr) 150px 130px 24px;
  align-items: center; gap: var(--aos-space-3);
  min-height: var(--aos-tap-min); padding: var(--aos-space-3) var(--aos-space-2);
  border-radius: var(--aos-radius-sm);
  border-bottom: 1px solid var(--aos-hover-wash);
}
.ws-row:last-child { border-bottom: 0; }
.ws-row:hover { background: var(--aos-hover-wash); }
/* Same reasoning as .plan-title: a row's title is the easiest thing to aim at,
   so it takes the row's height rather than the 22px its text occupies. */
.ws-title { display: flex; align-items: center; min-height: var(--aos-tap-min);
  font-size: var(--aos-font-size-sm); text-decoration: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ws-title:hover { color: var(--aos-color-accent); }
.ws-meta { font-size: var(--aos-font-size-xs); color: var(--aos-color-text-faint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* 14px of ink, but the thing you tap is the row's full height. Drawing the
   target at 14px made "open this task" a control you aim at. */
.ws-go {
  display: grid; place-items: center; width: var(--aos-tap-min); height: var(--aos-tap-min);
  margin: calc(var(--aos-space-3) * -1) calc(var(--aos-space-2) * -1) calc(var(--aos-space-3) * -1) 0;
  color: var(--aos-color-text-faint); opacity: 0;
}
.ws-go svg { width: 14px; height: 14px; }
.ws-row:hover .ws-go { opacity: 1; }
.ws-check {
  width: 18px; height: 18px; padding: 0; border-radius: 50%;
  border: 1.5px solid var(--aos-color-text-faint); background: none; cursor: pointer;
}
.ws-check:hover { border-color: var(--aos-color-accent); }
.ws-check.is-done { background: var(--aos-color-accent-strong); border-color: var(--aos-color-accent-strong); }
.ws-inline-form { margin: 0; justify-self: end; }
.ws-danger {
  padding: var(--aos-space-1) var(--aos-space-3); border-radius: 999px;
  border: 1px solid var(--aos-glass-border); background: var(--aos-hover-wash);
  color: var(--aos-color-text-faint); font-size: var(--aos-font-size-xs); cursor: pointer;
}
.ws-danger:hover { background: rgba(248, 113, 113, 0.16); color: var(--aos-color-danger); border-color: rgba(248, 113, 113, 0.4); }
/* Files */
.file-row { grid-template-columns: 26px minmax(0, 1fr) 90px 110px auto; }
.file-kind { display: inline-flex; width: 20px; height: 20px; color: var(--aos-color-text-muted); }
.file-kind svg { width: 100%; height: 100%; }
.file-kind--image { color: var(--aos-tone-violet); }
.file-kind--document { color: var(--aos-tone-blue); }
.file-kind--sheet { color: var(--aos-tone-green); }
.file-kind--slides { color: var(--aos-tone-amber); }
.file-kind--video, .file-kind--audio { color: #f472b6; }
.file-kind--archive { color: var(--aos-color-text-muted); }
.upload-zone {
  display: flex; align-items: center; gap: var(--aos-space-4); flex-wrap: wrap;
  padding: var(--aos-space-5);
  margin-bottom: var(--aos-space-4);
  border: 1.5px dashed var(--aos-glass-border-strong);
  border-radius: var(--aos-radius-lg);
  background: var(--aos-hover-wash);
  transition: border-color var(--aos-transition-duration), background var(--aos-transition-duration);
}
.upload-zone.is-dragging { border-color: var(--aos-color-accent); background: var(--aos-color-accent-soft); }
.upload-label { display: flex; flex-direction: column; gap: var(--aos-space-05); flex: 1; min-width: 220px; font-size: var(--aos-font-size-sm); cursor: pointer; }
.upload-label > span:first-of-type { display: flex; align-items: center; gap: var(--aos-space-2); }
.upload-label .icon { width: 16px; height: 16px; color: var(--aos-color-accent); }
/* The file input's own button is drawn by the browser and cannot be given a
   height, so the control gets the floor around it. */
.upload-zone input[type="file"] { flex: 1; min-width: 200px; min-height: var(--aos-tap-min); font-size: var(--aos-font-size-sm); color: var(--aos-color-text-muted); }
.upload-zone button {
  min-height: var(--aos-tap-min); padding: 0 var(--aos-space-5); border-radius: var(--aos-radius-md); border: 0;
  background: var(--aos-color-accent-strong); color: var(--aos-color-accent-contrast);
  font-weight: var(--aos-font-weight-medium); cursor: pointer;
  transition: background var(--aos-transition-fast) var(--aos-transition-easing);
}
.upload-zone button:hover { background: var(--aos-color-accent); }
.upload-zone button:active { transform: scale(.98); }
/* ---- LifeOS V1: Plan + Today, mobile first ---------------------------- */

.plan-page { grid-column: 1 / -1; min-width: 0; display: flex; flex-direction: column; gap: var(--aos-space-4); }
.day-nav { display: flex; align-items: center; gap: var(--aos-space-3); }
/* The SVG here carries no width/height attribute (it's ICONS["chevron"]
   used raw, not through .icon) — inside a flex row that's a real bug, not
   a styling gap: browsers size a dimensionless replaced element to 0x0 as
   a flex item rather than falling back to any intrinsic size, so both
   arrows were rendering invisible at zero size before this rule gave them
   one. Previous points left (the icon itself draws pointing right, hence
   the flip); Next cancels that flip back to the drawn direction. */
.day-arrow {
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--aos-tap-min); height: var(--aos-tap-min); flex: 0 0 auto;
  color: var(--aos-color-text-muted); border-radius: var(--aos-radius-sm);
  transition: background var(--aos-transition-fast) var(--aos-transition-easing);
}
.day-arrow svg { width: 20px; height: 20px; transform: rotate(180deg); }
.day-arrow:hover { background: var(--aos-hover-wash); }
.day-arrow:active { transform: scale(.9); }
.day-arrow.is-disabled { opacity: .35; pointer-events: none; }
.day-arrow--next svg { transform: none; }
.day-heading { display: flex; flex-direction: column; align-items: flex-start; flex: 1; min-width: 0; }
.day-caption { margin: 0; font-size: var(--aos-font-size-lg); font-weight: var(--aos-font-weight-bold); letter-spacing: var(--aos-tracking-tight); }
/* How the day you are leaving actually went, and how full the one you are
   planning already is. Both are quiet by design: they are the context you
   plan against, not the thing you came here to do. */
.day-review { gap: var(--aos-space-2); }
.review-line { margin: 0; font-size: var(--aos-font-size-sm); color: var(--aos-color-text-muted); }
.load-line { margin: 0; font-size: var(--aos-font-size-xs); color: var(--aos-color-text-faint); }
.load-line.has-conflict { color: var(--aos-tone-amber); }
.day-date { font-size: var(--aos-font-size-xs); color: var(--aos-color-text-muted); }
.readonly-note { margin: 0; font-size: var(--aos-font-size-xs); color: var(--aos-tone-amber); }
.plan-block {
  /* Layout only. This was a bordered, shadowed card, which stacked three of
     them down Plan and four down Today — a box around every single row.
     _section_block's own docstring already stated the rule this now follows:
     sections are separated by whitespace and a small label, not by cards. */
  display: flex; flex-direction: column; gap: var(--aos-space-3);
}
/* .plan-label is styled with .section-label below — one section header. */

.plan-more { font-size: var(--aos-font-size-xs); color: var(--aos-color-accent); text-decoration: none; align-self: flex-start; }
.fixed-list, .carry-list, .pull-list, .plan-list, .ready-list, .more-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.fixed-row { display: grid; grid-template-columns: 54px minmax(0,1fr) auto; align-items: center; gap: var(--aos-space-3); padding: 8px 0; }
.fixed-time { font-size: var(--aos-font-size-xs); color: var(--aos-color-text-muted); font-variant-numeric: tabular-nums; }
.fixed-title { font-size: var(--aos-font-size-sm); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.carry-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--aos-space-2); min-height: var(--aos-tap-min); padding: var(--aos-space-3) 0; border-bottom: 1px solid var(--aos-hover-wash); }
.carry-row:last-child { border-bottom: 0; }
.carry-title { flex: 1; min-width: 120px; font-size: var(--aos-font-size-sm); }
.carry-actions { display: flex; align-items: center; gap: var(--aos-space-2); }
.carry-inline { margin: 0; display: inline-flex; }
.carry-btn {
  padding: var(--aos-space-2) var(--aos-space-3); border-radius: 999px; cursor: pointer;
  border: 1px solid var(--aos-glass-border); background: var(--aos-hover-wash);
  color: var(--aos-color-text-muted); font-size: var(--aos-font-size-xs);
  transition: background var(--aos-transition-fast) var(--aos-transition-easing);
}
.carry-btn--primary { border-color: var(--aos-color-accent); color: var(--aos-color-accent); }
.carry-btn--quiet { color: var(--aos-color-text-faint); }
.carry-btn:hover { background: var(--aos-control-bg-hover); }
.carry-btn:active { transform: scale(.96); }
.reason-menu { flex-basis: 100%; padding: var(--aos-space-2) 0 var(--aos-space-3); }
.reason-menu form { display: flex; flex-wrap: wrap; gap: var(--aos-space-2); align-items: center; }
.reason-prompt { margin: 0 var(--aos-space-2) 0 0; font-size: var(--aos-font-size-xs); color: var(--aos-color-text-faint); }
.reason-option, .reason-skip {
  padding: var(--aos-space-2) var(--aos-space-3); border-radius: 999px; cursor: pointer;
  border: 1px solid var(--aos-glass-border); background: var(--aos-hover-wash);
  color: var(--aos-color-text-muted); font-size: var(--aos-font-size-xs);
  transition: border-color var(--aos-transition-fast) var(--aos-transition-easing),
              color var(--aos-transition-fast) var(--aos-transition-easing);
}
.reason-option:hover { border-color: var(--aos-color-accent); color: var(--aos-color-accent); }
.reason-option:active, .reason-skip:active { transform: scale(.96); }
.reason-skip { color: var(--aos-color-text-faint); border-style: dashed; }
.pull-row { display: flex; align-items: center; gap: var(--aos-space-3); padding: 8px 0; border-bottom: 1px solid var(--aos-hover-wash); }
.pull-row:last-child { border-bottom: 0; }
/* The title is the easiest thing to aim at on the row, so it takes the row's
   height rather than the 22px its text happens to occupy. */
.pull-title { flex: 1; min-width: 0; display: flex; align-items: center; min-height: var(--aos-tap-min);
  font-size: var(--aos-font-size-sm); color: inherit; text-decoration: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pull-add {
  display: grid; place-items: center; padding: 0;
  width: 32px; height: 32px; flex: 0 0 32px; border-radius: 50%; cursor: pointer;
  border: 1px solid var(--aos-color-accent); background: var(--aos-color-accent-soft);
  color: var(--aos-color-accent); font-size: var(--aos-font-size-base); line-height: 1;
  transition: filter var(--aos-transition-fast) var(--aos-transition-easing);
}
.pull-add:hover { filter: brightness(.95); }
.pull-add:active { transform: scale(.94); }
.dump-form { display: flex; align-items: center; gap: var(--aos-space-2); }
.dump-form input {
  flex: 1; min-width: 0; height: 46px; padding: 0 var(--aos-space-4);
  border-radius: var(--aos-radius-md); background: var(--aos-surface-sunken);
  border: 1px solid var(--aos-glass-border); color: var(--aos-color-text);
  font-size: var(--aos-font-size-base); /* >=16px stops iOS zooming the page on focus */
  outline: none;
}
.dump-form input:focus { border-color: var(--aos-color-accent); }
.dump-form button {
  display: grid; place-items: center; padding: 0; width: 46px; height: 46px; flex: 0 0 46px;
  border-radius: var(--aos-radius-md); border: 0; cursor: pointer;
  background: var(--aos-color-accent-strong); color: var(--aos-color-accent-contrast);
}
.dump-form button .icon { width: 18px; height: 18px; color: currentColor; }
.plan-row {
  display: grid; grid-template-columns: 20px 30px minmax(0,1fr) auto;
  align-items: center; gap: var(--aos-space-3);
  min-height: var(--aos-tap-min); padding: var(--aos-space-3) 0; border-bottom: 1px solid var(--aos-hover-wash);
}
.plan-row:last-child { border-bottom: 0; }
.plan-row.is-done { opacity: .45; }
.plan-row.is-done .plan-title { text-decoration: line-through; }
/* A row's title is the easiest thing to aim at, so it gets the row's full
   height rather than the 22px its text happens to occupy. It cannot use the
   ::before trick — a pseudo-element that wide would sit over the check and
   the priority chip beside it and swallow their taps. */
.plan-title {
  display: flex; align-items: center; min-height: var(--aos-tap-min);
  font-size: var(--aos-font-size-sm); color: inherit; text-decoration: none;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.pri {
  /* padding: 0 because a UA-default 1px/6px on a fixed-size grid button is
     both meaningless and the only thing on this screen off the 4px grid. */
  display: inline-grid; place-items: center; padding: 0; width: 30px; height: 22px;
  border-radius: var(--aos-radius-xs); font-size: var(--aos-font-size-xs); font-weight: var(--aos-font-weight-bold);
  border: 1px solid transparent; cursor: pointer;
}
/* Only P1 gets colour. P2/P3 in red and blue meant three hues fighting on
   every row for information you can read from the label — and #fca5a5 on a
   pale-red wash was designed against a near-black background, so on paper
   white it was close to invisible. "Important" is the only distinction the
   eye needs at a glance; the rest is text. */
.pri--1 { background: var(--aos-control-bg); color: var(--aos-color-danger); border-color: currentColor; }
.pri--2 { background: var(--aos-control-bg); color: var(--aos-color-text-muted); border-color: var(--aos-glass-border); }
.pri--3 { background: transparent; color: var(--aos-color-text-faint); border-color: var(--aos-glass-border); }
.time-btn {
  padding: var(--aos-space-2) var(--aos-space-3); border-radius: 999px; cursor: pointer; white-space: nowrap;
  border: 1px dashed var(--aos-glass-border); background: none;
  color: var(--aos-color-text-faint); font-size: var(--aos-font-size-xs);
  transition: filter var(--aos-transition-fast) var(--aos-transition-easing);
}
.time-btn:hover { filter: brightness(.95); }
.time-btn:active { transform: scale(.96); }
.time-btn.is-set { border-style: solid; border-color: var(--aos-glass-border-strong); color: var(--aos-color-text); }
.conflict { grid-column: 3 / -1; margin: 2px 0 0; font-size: var(--aos-font-size-xs); color: var(--aos-tone-amber); }
.ready-block { gap: var(--aos-space-2); }
.ready-track { display: block; height: 6px; border-radius: 999px; background: var(--aos-control-bg); overflow: hidden; }
.ready-fill { display: block; height: 100%; border-radius: 999px; background: var(--aos-color-accent); transition: width 500ms var(--aos-transition-easing); }
.ready-row { display: grid; grid-template-columns: 18px minmax(0,1fr) auto; align-items: center; gap: var(--aos-space-3); padding: var(--aos-space-2) 0; }
.ready-mark { display: grid; place-items: center; width: 18px; height: 18px; border-radius: 50%; background: var(--aos-control-bg); color: var(--aos-color-text-faint); font-size: var(--aos-font-size-xs); }
.ready-mark.is-ok { background: var(--aos-color-accent-veil); color: var(--aos-color-accent); }
.ready-label { font-size: var(--aos-font-size-sm); }
.ready-detail { font-size: var(--aos-font-size-xs); color: var(--aos-color-text-faint); }
.ready-verdict { margin: var(--aos-space-2) 0 0; font-size: var(--aos-font-size-sm); color: var(--aos-color-text-muted); }
.ready-verdict.is-ready { color: var(--aos-color-accent); font-weight: var(--aos-font-weight-medium); }
.plan-done {
  display: block; text-align: center; min-height: var(--aos-tap-min); padding: var(--aos-space-3) var(--aos-space-5);
  border-radius: var(--aos-radius-md); background: var(--aos-color-accent-strong);
  color: var(--aos-color-accent-contrast); text-decoration: none;
  font-weight: var(--aos-font-weight-medium);
  box-shadow: 0 8px 24px var(--aos-color-accent-glow);
}
.more-row { display: flex; align-items: center; gap: var(--aos-space-3); min-height: var(--aos-tap-min); padding: var(--aos-space-3) var(--aos-space-2); border-bottom: 1px solid var(--aos-hover-wash); text-decoration: none; color: inherit; }
.more-text { display: flex; flex-direction: column; flex: 1; min-width: 0; }
.more-title { font-size: var(--aos-font-size-sm); }
.more-sub { font-size: var(--aos-font-size-xs); color: var(--aos-color-text-faint); }
.more-go { display: inline-flex; width: 14px; height: 14px; color: var(--aos-color-text-faint); }
.more-go svg { width: 100%; height: 100%; }
.more-logout button {
  width: 100%; min-height: var(--aos-tap-min); padding: 0 var(--aos-space-5);
  border-radius: var(--aos-radius-md); border: 1px solid var(--aos-glass-border);
  background: var(--aos-hover-wash); color: var(--aos-color-text); cursor: pointer;
  transition: background var(--aos-transition-fast) var(--aos-transition-easing);
}
.more-logout button:hover { background: var(--aos-control-bg-hover); }
.more-logout button:active { transform: scale(.98); }
/* Bottom sheet — never lose your place in the scroll */
.sheet { position: fixed; inset: 0; z-index: 60; display: flex; align-items: flex-end; }
.sheet[hidden] { display: none; }
.sheet-backdrop { position: absolute; inset: 0; background: rgba(0,0,0,.55); }
.sheet-panel {
  position: relative; width: 100%; max-height: 80vh; overflow-y: auto;
  padding: var(--aos-space-3) var(--aos-space-5) calc(var(--aos-space-6) + env(safe-area-inset-bottom));
  background: var(--aos-glass-bg-raised); border-top: 1px solid var(--aos-glass-border-strong);
  border-radius: var(--aos-radius-xl) var(--aos-radius-xl) 0 0; box-shadow: var(--aos-shadow-xl);
  animation: sheet-up 240ms var(--aos-transition-easing);
}
@keyframes sheet-up { from { transform: translateY(100%); }
to { transform: translateY(0); }
}
.sheet-grip { width: 40px; height: 4px; border-radius: 999px; background: var(--aos-glass-border-strong); margin: 0 auto var(--aos-space-4); }
.sheet-panel h3 { margin: 0 0 var(--aos-space-4); font-size: var(--aos-font-size-lg); }
.time-fields { display: flex; gap: var(--aos-space-3); }
.time-fields label { flex: 1; display: flex; flex-direction: column; gap: var(--aos-space-2); font-size: var(--aos-font-size-sm); color: var(--aos-color-text-muted); }
.time-fields input, .time-fields select {
  height: 46px; padding: 0 var(--aos-space-3); border-radius: var(--aos-radius-md);
  background: var(--aos-surface-sunken); border: 1px solid var(--aos-glass-border);
  color: var(--aos-color-text); font-size: var(--aos-font-size-base);
}
.repeat-toggle {
  display: flex; align-items: center; gap: var(--aos-space-2); margin-top: var(--aos-space-3);
  font-size: var(--aos-font-size-sm); color: var(--aos-color-text-muted);
}
.sheet-actions { display: flex; gap: var(--aos-space-3); margin-top: var(--aos-space-5); }
.sheet-primary { flex: 1; min-height: var(--aos-tap-min); padding: 0 var(--aos-space-5); border-radius: var(--aos-radius-md); border: 0; background: var(--aos-color-accent-strong); color: var(--aos-color-accent-contrast); font-weight: var(--aos-font-weight-medium); cursor: pointer; transition: filter var(--aos-transition-fast) var(--aos-transition-easing); }
.sheet-quiet { min-height: var(--aos-tap-min); padding: 0 var(--aos-space-5); border-radius: var(--aos-radius-md); border: 1px solid var(--aos-glass-border); background: none; color: var(--aos-color-text-muted); cursor: pointer; transition: filter var(--aos-transition-fast) var(--aos-transition-easing); }
.sheet-primary:hover, .sheet-quiet:hover { filter: brightness(.95); }
.sheet-primary:active, .sheet-quiet:active { transform: scale(.98); }
/* The week. Seven columns on a laptop, seven stacked days on a phone —
   a 7-column grid at 390px is unreadable. Fixed things and the gaps between
   them share one list, in clock order, because the whole point is seeing them
   against each other. */
.calendar-page { grid-column: 1 / -1; min-width: 0; display: flex; flex-direction: column; gap: var(--aos-space-5); }
.cal-notice { display: flex; flex-direction: column; align-items: flex-start; gap: var(--aos-space-2); }
.cal-notice p { margin: 0; font-size: var(--aos-font-size-sm); color: var(--aos-tone-amber); }
.cal-connect {
  min-height: var(--aos-tap-min); display: inline-flex; align-items: center;
  padding: 0 var(--aos-space-4); border-radius: var(--aos-radius-md);
  border: 1px solid var(--aos-color-accent); color: var(--aos-color-accent);
  font-size: var(--aos-font-size-sm); text-decoration: none;
  transition: background var(--aos-transition-fast) var(--aos-transition-easing);
}
.cal-connect:hover { background: var(--aos-color-accent-soft); }
.cal-connect:active { transform: scale(.98); }

/* The week grid: one CSS Grid shared by the hour gutter and all seven days,
   so every column's row lines are the same row lines — the only way "3 PM"
   in the gutter and "3 PM" in Saturday's column are guaranteed to be the same
   height down the page. Placement below is by grid line (row/column numbers
   set inline per cell), not percentage or pixel math, so this stylesheet
   never has to agree with dashboard.py's row-height in two places — only
   --cal-row-h does, and dashboard.py sets it as a CSS variable.
   grid-template-rows: header row, all-day row, then --cal-rows quarter-hour
   rows (18h * 4 = 72 by default) at --cal-row-h each. */
.cal-grid {
  display: grid;
  grid-template-columns: 44px repeat(7, minmax(0, 1fr));
  grid-template-rows: auto auto repeat(var(--cal-rows), var(--cal-row-h));
  column-gap: var(--aos-space-2);
  background: var(--aos-glass-bg); border-radius: var(--aos-radius-md);
  padding: var(--aos-space-3);
}
/* Centred within its own hour-tall grid area (it spans the same 4 quarter-rows
   the hour occupies) rather than nudged up with a negative margin — a margin
   in em resolves to an arbitrary off-grid px value the same way `margin-top:
   auto` already does elsewhere in this file; flex centering needs neither. */
.cal-hour-label {
  grid-column: 1; display: flex; align-items: center;
  font-size: var(--aos-font-size-xs); color: var(--aos-color-text-faint);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}
/* Vertical rule on every day cell (header, all-day, hours) so the grid reads
   as one structure top to bottom, not horizontal lines floating over
   unbounded columns — Jakob's Law: every calendar app has grid lines, and a
   whitespace-only gap between days breaks that expectation on sight. Applied
   per-cell rather than as one border spanning the whole column because the
   day-head/all-day/hours-bg are three separate grid items, not one box. */
.cal-day-head, .cal-allday, .cal-hours-bg { border-left: 1px solid var(--aos-glass-border); }
/* cursor: pointer signals the whole area opens the add-event sheet; the tint
   on hover is a coarse (whole-column, not exact-row) confirmation that a
   click here does something — a per-row highlight would need JS tracking
   mouse position continuously, which isn't worth it for a hover hint alone. */
.cal-hours-bg {
  grid-row: 3 / -1; cursor: pointer;
  background-image: repeating-linear-gradient(
    to bottom, var(--aos-glass-border) 0 1px, transparent 1px calc(var(--cal-row-h) * 4)
  );
  transition: background-color var(--aos-transition-duration) var(--aos-transition-easing);
}
.cal-hours-bg:hover { background-color: var(--aos-hover-wash); }
/* space-between, not margin-left: auto on the last child — an auto margin
   resolves to an arbitrary px value, which is exactly the thing the token
   audit exists to catch (see the same note this file already carried for
   the old .cal-day-foot). */
.cal-day-head {
  grid-row: 1; display: flex; align-items: baseline; justify-content: space-between; gap: var(--aos-space-2);
  padding-bottom: var(--aos-space-2); border-bottom: 1px solid var(--aos-glass-border);
}
.cal-dow { font-size: var(--aos-font-size-xs); font-weight: var(--aos-font-weight-bold); text-transform: uppercase; letter-spacing: var(--aos-tracking-label); color: var(--aos-color-text-faint); }
.cal-date { font-size: var(--aos-font-size-base); font-weight: var(--aos-font-weight-bold); }
.cal-day-head.is-today .cal-date { color: var(--aos-color-accent); }
/* One trailing group (add + plan) so space-between splits the header into
   exactly two clusters — identity, then actions — rather than spacing all
   four children apart individually and breaking the dow/date pairing. */
.cal-day-actions { display: flex; align-items: center; }
.cal-day-head .cal-plan {
  min-width: var(--aos-tap-min); min-height: var(--aos-tap-min);
  display: flex; align-items: center; justify-content: center;
  font-size: var(--aos-font-size-xs); color: var(--aos-color-accent); text-decoration: none;
}
/* Five explicit states — default, hover, focus, active, disabled aren't
   needed here since the button is never disabled, but the other four are
   spelled out rather than left to the browser default, per Fitts's Law: a
   target should look tappable before it's tapped, not just after. */
.cal-add {
  width: var(--aos-tap-min); height: var(--aos-tap-min); min-width: var(--aos-tap-min);
  display: grid; place-items: center; padding: 0; margin: 0; border: 0; border-radius: 50%;
  background: none; color: var(--aos-color-text-faint);
  transition: background var(--aos-transition-duration) var(--aos-transition-easing),
              color var(--aos-transition-duration) var(--aos-transition-easing),
              transform 120ms var(--aos-transition-easing);
}
.cal-add .icon { width: 16px; height: 16px; }
.cal-add:hover { background: var(--aos-hover-wash); color: var(--aos-color-accent); }
.cal-add:focus-visible { outline: 2px solid var(--aos-color-focus-ring); outline-offset: 2px; }
.cal-add:active { transform: scale(0.92); background: var(--aos-color-accent-soft); }
.cal-allday {
  grid-row: 2; min-height: 22px; display: flex; align-items: center;
  padding: 2px var(--aos-space-2); margin-top: var(--aos-space-1);
  border-radius: var(--aos-radius-xs); background: var(--aos-hover-wash);
  border: 1px solid var(--aos-glass-border); color: var(--aos-tone-amber);
  font-size: var(--aos-font-size-xs); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* An empty day reserves the row's height, silently — no border, no fill —
   so every column's hour track still starts on the same line. */
.cal-allday--empty { background: none; border-color: transparent; }
.cal-event {
  align-self: stretch; margin: 0 2px; padding: 2px var(--aos-space-2);
  border-radius: var(--aos-radius-xs); background: var(--aos-color-accent-soft);
  overflow: hidden; font-size: var(--aos-font-size-xs); line-height: 1.3;
}
.cal-event-time { color: var(--aos-color-text-faint); font-variant-numeric: tabular-nums; }
.cal-event-title { color: var(--aos-color-text); }
.cal-now-line {
  grid-column-end: span 1; align-self: start; height: 2px; background: var(--aos-color-danger);
  position: relative;
}
.cal-now-line::before {
  content: ""; position: absolute; left: -4px; top: -3px;
  width: 8px; height: 8px; border-radius: 50%; background: var(--aos-color-danger);
}
/* The mobile single-day nav is the desktop week-nav's twin — see
   .cal-week-nav / .cal-day-nav below for which one a given viewport sees. */
.cal-day-nav { display: none; }

/* The command palette. Raycast's shape: one field, one list, keyboard only.
   Sits above every other layer including the sheets, because it is the thing
   you open on top of whatever you were doing. */
.palette { position: fixed; inset: 0; z-index: 80; display: flex; justify-content: center; align-items: flex-start; }
.palette[hidden] { display: none; }
.palette-backdrop { position: absolute; inset: 0; background: rgba(0,0,0,.45); }
.palette-panel {
  position: relative; width: min(92vw, 640px); margin-top: 12vh;
  background: var(--aos-glass-bg-raised); border: 1px solid var(--aos-glass-border-strong);
  border-radius: var(--aos-radius-lg); box-shadow: var(--aos-shadow-lg); overflow: hidden;
}
.palette-panel input {
  width: 100%; min-height: 56px; padding: 0 var(--aos-space-5);
  border: 0; border-bottom: 1px solid var(--aos-glass-border); background: none;
  color: var(--aos-color-text); font-size: var(--aos-font-size-lg); outline: none;
}
.pal-list { list-style: none; margin: 0; padding: var(--aos-space-2); max-height: 46vh; overflow-y: auto; }
.pal-row {
  display: flex; align-items: center; gap: var(--aos-space-3);
  min-height: 48px; padding: 0 var(--aos-space-3); border-radius: var(--aos-radius-sm);
  cursor: pointer; outline: none;
}
.pal-row:hover, .pal-row:focus { background: var(--aos-hover-wash); }
.pal-row:focus { box-shadow: inset 0 0 0 2px var(--aos-color-focus-ring); }
.pal-row--capture .pal-kind { color: var(--aos-color-accent); }
.pal-kind {
  flex: 0 0 auto; min-width: 56px; font-size: var(--aos-font-size-xs);
  text-transform: uppercase; letter-spacing: var(--aos-tracking-label);
  color: var(--aos-color-text-faint);
}
.pal-title { flex: 1; min-width: 0; font-size: var(--aos-font-size-sm); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pal-hint { flex: 0 0 auto; color: var(--aos-color-text-faint); font-size: var(--aos-font-size-xs); }
.pal-empty { margin: 0; padding: var(--aos-space-5); color: var(--aos-color-text-faint); font-size: var(--aos-font-size-sm); }
.palette-foot {
  margin: 0; padding: var(--aos-space-2) var(--aos-space-5);
  border-top: 1px solid var(--aos-glass-border);
  color: var(--aos-color-text-faint); font-size: var(--aos-font-size-xs);
}
.palette-foot kbd {
  padding: 1px 5px; border-radius: var(--aos-radius-xs);
  background: var(--aos-control-bg); font-family: inherit;
}

/* Universal Quick Capture — the one control that is on every screen.
   Bottom-right, above everything except the sheet it opens, and clear of the
   tab bar on a phone (see the mobile block below). Sized past the 44px floor
   because it is hit one-handed, walking, without looking. */
.fab {
  /* On every screen and every width. It was briefly desktop-hidden on the
     grounds that ⌘K replaced it — it doesn't: one is a keyboard path, the
     other is the thing you point at. The overlap that prompted hiding it is
     fixed properly below, with real clearance under `main`. */
  display: grid;
  position: fixed; z-index: 55;
  right: var(--aos-space-5); bottom: calc(var(--aos-space-5) + env(safe-area-inset-bottom, 0px));
  place-items: center; width: 56px; height: 56px;
  border-radius: 50%; border: 0; cursor: pointer; text-decoration: none;
  background: var(--aos-color-accent-strong); color: var(--aos-color-accent-contrast);
  box-shadow: var(--aos-shadow-lg);
  transition: transform var(--aos-transition-fast) var(--aos-transition-easing);
}
.fab .icon { width: 24px; height: 24px; color: currentColor; }
.fab:hover { background: var(--aos-color-accent); }
.fab:active { transform: scale(.94); }
@media (prefers-reduced-motion: reduce) { .fab { transition: none; } }
/* The capture sheet's field is the only thing in it — give it room and let
   the hint sit under the bar rather than beside it. */
#capture-sheet .dump-form { margin-bottom: var(--aos-space-3); }
#capture-sheet .error:empty { display: none; }
.capture-page { display: flex; flex-direction: column; gap: var(--aos-space-4); }

/* Captures — the pile, and the four things anything in it can become. */
.capture-list { display: flex; flex-direction: column; gap: var(--aos-space-3); list-style: none; margin: 0; padding: 0; }
.capture-row {
  display: flex; flex-direction: column; gap: var(--aos-space-3);
  padding: var(--aos-space-4);
  background: var(--aos-glass-bg); border: 1px solid var(--aos-glass-border);
  border-radius: var(--aos-radius-lg); box-shadow: var(--aos-shadow-sm);
}
.capture-text { margin: 0; font-size: var(--aos-font-size-base); line-height: var(--aos-line-height-base); }
.tag-row { display: flex; flex-wrap: wrap; gap: var(--aos-space-2); margin: 0; }
.tag-btn {
  min-height: var(--aos-tap-min); padding: 0 var(--aos-space-4);
  border-radius: 999px; cursor: pointer;
  border: 1px solid var(--aos-glass-border); background: var(--aos-hover-wash);
  color: var(--aos-color-text-muted); font-size: var(--aos-font-size-sm);
  transition: border-color var(--aos-transition-fast) var(--aos-transition-easing),
              color var(--aos-transition-fast) var(--aos-transition-easing);
}
.tag-btn:hover { border-color: var(--aos-color-accent); color: var(--aos-color-accent); }
.tag-btn:active { transform: scale(.96); }
/* The parser's guess. Marked, never applied — see _capture_row_html. */
.tag-btn.is-suggested {
  border-color: var(--aos-color-accent); background: var(--aos-color-accent-soft);
  color: var(--aos-color-accent); font-weight: var(--aos-font-weight-medium);
}
.capture-echo {
  margin: 0 0 var(--aos-space-4); font-size: var(--aos-font-size-sm);
  color: var(--aos-color-text-muted);
}
/* Deliberately lighter than the to-sort cards above — a flat row, no shadow,
   no card border — so History reads as a log you skim, not a second pile of
   decisions to make. The two sections should never look like the same job. */
.capture-row--sorted {
  flex-direction: row; align-items: center; justify-content: space-between;
  gap: var(--aos-space-3); padding: var(--aos-space-3) var(--aos-space-2);
  background: none; border: 0; border-radius: 0; box-shadow: none;
  border-bottom: 1px solid var(--aos-glass-border);
}
.capture-row--sorted:last-child { border-bottom: 0; }
.capture-row--sorted .capture-text {
  flex: 1; min-width: 0; font-size: var(--aos-font-size-sm);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.capture-kind {
  flex: 0 0 auto; min-height: var(--aos-tap-min); display: inline-flex; align-items: center;
  padding: 0 var(--aos-space-3); border-radius: 999px;
  background: var(--aos-hover-wash); color: var(--aos-color-text-muted);
  font-size: var(--aos-font-size-xs); text-decoration: none;
}
.capture-kind--linked {
  color: var(--aos-color-accent);
  transition: background var(--aos-transition-fast) var(--aos-transition-easing);
}
.capture-kind--linked:hover { background: var(--aos-color-accent-soft); }
/* Bottom tab bar — four, thumb-reachable, no hamburger anywhere */
.tabbar { display: none; }
/* The phone layout. One navigation (the tab bar), no sidebar, no search rail,
   and the page itself gets the rest of the screen. */
@media (max-width: 900px) {
  .tabbar {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 50;
    display: grid; grid-template-columns: repeat(4, 1fr);
    padding: var(--aos-space-1) var(--aos-space-1) calc(var(--aos-space-1) + env(safe-area-inset-bottom, 0px));
    background: var(--aos-glass-bg); border-top: 1px solid var(--aos-glass-border);
  }
.tab {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: var(--aos-space-1); min-height: 50px; padding: var(--aos-space-2) 0;
    text-decoration: none; color: var(--aos-color-text-faint);
    font-size: var(--aos-font-size-xs); letter-spacing: .02em;
    border-radius: var(--aos-radius-sm);
    transition: color var(--aos-transition-fast) var(--aos-transition-easing),
                background var(--aos-transition-fast) var(--aos-transition-easing),
                transform var(--aos-transition-fast) var(--aos-transition-easing);
  }
.tab:hover, .tab:focus-visible { color: var(--aos-color-text); background: var(--aos-hover-wash); }
.tab:active { transform: scale(.96); }
.tab .icon { width: 22px; height: 22px; }
.tab.is-active { color: var(--aos-color-accent); }
.tab.is-active .icon { color: var(--aos-color-accent); }
/* The week grid becomes a single day, the same way the sidebar becomes the
   tab bar above: both nav bars and all seven days are always rendered server
   side; this media query is the only thing that decides which one a given
   screen sees. Every day column keeps the grid-column dashboard.py gave it
   inline (Friday is still column 6) so a !important override is the only way
   to actually move the selected day into the one visible slot — the same
   justification the reduced-motion override above already uses. */
.cal-week-nav { display: none; }
.cal-day-nav { display: flex; }
.cal-grid { grid-template-columns: 44px 1fr; }
.cal-day-head, .cal-allday, .cal-hours-bg, .cal-event, .cal-now-line { display: none; }
.cal-day-head[data-selected], .cal-allday[data-selected], .cal-hours-bg[data-selected],
.cal-event[data-selected], .cal-now-line[data-selected] {
  display: flex; grid-column: 2 !important;
}
.cal-hours-bg[data-selected] { display: block; }
.sidebar, .topbar { display: none; }
/* One column. Cards kept spanning half the 12-column grid all the way down to
   a 390px phone, which put two cards side by side at ~170px each: task titles
   truncated to "Read chapt…", a filename rendered as four pixels, and a
   timeline date running into its own label. */
.widget, .detail-page .grid .widget { grid-column: 1 / -1; }
.os-shell { grid-template-columns: minmax(0,1fr); padding: var(--aos-space-4) var(--aos-space-4) 0; }
/* Room for the tab bar, and for the capture button that floats above it. */
main { padding-bottom: calc(140px + env(safe-area-inset-bottom, 0px)); }
.fab { display: grid; right: var(--aos-space-4); bottom: calc(80px + env(safe-area-inset-bottom, 0px)); }
.today-page { gap: var(--aos-space-5); }
.now-primary { flex: 1 1 auto; }
/* Stacked on a phone, primary first: column-reverse put Postpone above Done,
   which made the secondary action read as the primary one. */
.now-actions { flex-direction: column; align-items: stretch; }
}
/* ---- Today: one question, one answer ---------------------------------- */

/* ---- Design system primitives ----------------------------------------- */

/* One page title per screen. Large, plain, left-aligned, nothing beside it
   except (optionally) one quiet action. */
.page-head {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: var(--aos-space-4); margin-bottom: var(--aos-space-2);
}
.page-heading { min-width: 0; }
.page-title {
  margin: 0; font-size: var(--aos-font-size-2xl); line-height: 1.1;
  font-weight: var(--aos-font-weight-heavy); letter-spacing: var(--aos-tracking-display);
}
.page-sub { margin: var(--aos-space-1) 0 0; font-size: var(--aos-font-size-sm); color: var(--aos-color-text-muted); }
.page-actions { display: flex; align-items: center; gap: var(--aos-space-2); flex: 0 0 auto; }

/* Section headers label, they never shout. */
.ui-section { display: flex; flex-direction: column; gap: var(--aos-space-3); }
/* Air between sections is what separates them — see .plan-block. The phone
   block below tightens this; a laptop has room to breathe and a phone doesn't. */
.plan-page { gap: var(--aos-space-6); }
/* The hairline is the block boundary Miller's Law asks for — a page reads as
   a handful of named sections rather than one undifferentiated scroll faster
   with a line under each name than with whitespace and a label alone. Shared
   by .section-label and .plan-label on purpose: the two are already one
   visual language (this rule has always been joint), so both get it from
   one change rather than needing the same edit made twice. */
.section-label, .plan-label {
  display: flex; align-items: center; gap: var(--aos-space-2); margin: 0;
  padding-bottom: var(--aos-space-2); border-bottom: 1px solid var(--aos-glass-border);
  font-size: var(--aos-font-size-xs); font-weight: var(--aos-font-weight-bold);
  letter-spacing: var(--aos-tracking-label); text-transform: uppercase;
  color: var(--aos-color-text-faint);
}
.section-label .icon, .plan-label .icon { width: 14px; height: 14px; }
.section-count, .plan-count {
  font-weight: var(--aos-font-weight-regular); letter-spacing: 0;
  color: var(--aos-color-text-faint); font-variant-numeric: tabular-nums;
}

/* The grouped inset list. The separator inset — starting at the text origin
   rather than the card edge — is the detail that separates a list that was
   designed from one that was merely built. Implemented with a border on the
   row plus a matching pseudo-element inset so it survives any row layout. */
.list-group, .today-list, .glance-list, .reminder-list {
  list-style: none; margin: 0; padding: 0;
  display: flex; flex-direction: column;
  background: var(--aos-glass-bg); border: 1px solid var(--aos-glass-border);
  border-radius: var(--aos-radius-xl); overflow: hidden;
}
.list-group > li, .list-group > .list-row {
  position: relative;
  display: flex; align-items: center; gap: var(--aos-space-3);
  /* 44px is the touch floor, not the resting size. Editorial density: rows
     sit at 60 and breathe. */
  min-height: 60px; padding: var(--aos-space-4);
}
/* The separator, inset to the text origin. Drawn as a pseudo-element rather
   than a border so the row keeps full-bleed padding for its hover state. */
.list-group > li:not(:last-child)::after,
.list-group > .list-row:not(:last-child)::after,
.today-list > li:not(:last-child)::after,
.glance-list > li:not(:last-child)::after,
.reminder-list > li:not(:last-child)::after {
  content: ""; position: absolute; left: var(--aos-space-4); right: 0; bottom: 0;
  height: 1px; background: var(--aos-glass-border);
}
a.list-row { text-decoration: none; color: inherit; }
.list-group > a.list-row:hover, .list-group > li:hover { background: var(--aos-hover-wash); }

/* An empty state is a sentence and one action. */
.empty-state {
  display: flex; flex-direction: column; align-items: flex-start; gap: var(--aos-space-2);
  padding: var(--aos-space-6) var(--aos-space-5);
  background: var(--aos-glass-bg); border: 1px solid var(--aos-glass-border);
  border-radius: var(--aos-radius-xl);
}
.empty-title { margin: 0; font-size: var(--aos-font-size-base); font-weight: var(--aos-font-weight-medium); }
.empty-body { margin: 0; font-size: var(--aos-font-size-sm); color: var(--aos-color-text-muted); max-width: 46ch; }
.empty-action {
  margin-top: var(--aos-space-2); min-height: var(--aos-tap-min);
  display: inline-flex; align-items: center; padding: 0 var(--aos-space-5);
  border-radius: var(--aos-radius-md); background: var(--aos-color-accent);
  color: var(--aos-color-accent-contrast); text-decoration: none;
  font-size: var(--aos-font-size-sm); font-weight: var(--aos-font-weight-medium);
  transition: background var(--aos-transition-fast) var(--aos-transition-easing);
}
.empty-action:hover { background: var(--aos-color-accent-strong); }
.empty-action:active { transform: scale(.98); }

/* Quiet secondary action — sits beside a page title without competing. */
.quiet-action {
  min-height: var(--aos-tap-min); display: inline-flex; align-items: center;
  padding: 0 var(--aos-space-3); border-radius: var(--aos-radius-sm);
  font-size: var(--aos-font-size-sm); color: var(--aos-color-text-muted); text-decoration: none;
  transition: color var(--aos-transition-fast) var(--aos-transition-easing),
              background var(--aos-transition-fast) var(--aos-transition-easing);
}
.quiet-action:hover { color: var(--aos-color-text); background: var(--aos-hover-wash); }

/* Inline create: a link that becomes the field it opens, rather than a modal.
   One tap to open, type, one tap to commit — a dialog for a single text field
   is three interactions and a context switch. */
.inline-create-link {
  min-height: var(--aos-tap-min); display: inline-flex; align-items: center; gap: var(--aos-space-2);
  font-size: var(--aos-font-size-sm); color: var(--aos-color-accent); text-decoration: none;
}
.inline-create { display: flex; gap: var(--aos-space-2); }
.inline-create input {
  flex: 1; min-width: 0; min-height: var(--aos-tap-min);
  padding: 0 var(--aos-space-4); border-radius: var(--aos-radius-md);
  border: 1px solid var(--aos-glass-border-strong); background: var(--aos-glass-bg);
  color: var(--aos-color-text); font: inherit; font-size: var(--aos-font-size-base);
}
.inline-create input:focus-visible { border-color: var(--aos-color-accent); }
.inline-create button {
  min-height: var(--aos-tap-min); padding: 0 var(--aos-space-5); border: 0; cursor: pointer;
  border-radius: var(--aos-radius-md); background: var(--aos-color-accent);
  color: var(--aos-color-accent-contrast); font-size: var(--aos-font-size-sm);
  font-weight: var(--aos-font-weight-medium);
  transition: background var(--aos-transition-fast) var(--aos-transition-easing);
}
.inline-create button:hover { background: var(--aos-color-accent-strong); }
.inline-create button:active { transform: scale(.98); }

/* Projects list. Two-line row, a progress hairline, a count, a chevron. */
.project-item { gap: var(--aos-space-4); }
.project-item-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--aos-space-05); }
.project-item-name {
  font-size: var(--aos-font-size-base); font-weight: var(--aos-font-weight-medium);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.project-item-detail { font-size: var(--aos-font-size-sm); color: var(--aos-color-text-muted); }
.project-item-track {
  flex: 0 0 64px; height: 4px; border-radius: 999px;
  background: var(--aos-glass-border); overflow: hidden;
}
.project-item-fill { display: block; height: 100%; background: var(--aos-color-accent); border-radius: 999px; }
.project-item-count {
  flex: 0 0 auto; font-size: var(--aos-font-size-xs); color: var(--aos-color-text-muted);
  font-variant-numeric: tabular-nums;
}
.project-item-go { flex: 0 0 auto; display: flex; color: var(--aos-color-text-faint); }
.project-item-go svg { width: 18px; height: 18px; }
@media (max-width: 560px) {
  /* The progress bar is the first thing to go on a narrow screen — the count
     beside it carries the same information in less space. */
  .project-item-track { display: none; }
}

/* ---- Today ------------------------------------------------------------ */
/* Written phone-first: every value here is the phone value, and the only
   desktop adjustments are at the bottom of this block. Sections are separated
   by whitespace and a small label rather than by nested cards. */

.today-page {
  grid-column: 1 / -1; min-width: 0;
  display: flex; flex-direction: column; gap: var(--aos-space-6);
}
.today-head { display: flex; flex-direction: column; gap: var(--aos-space-1); }
.today-date {
  margin: 0; font-size: var(--aos-font-size-xs); font-weight: var(--aos-font-weight-bold);
  letter-spacing: var(--aos-tracking-label); text-transform: uppercase; color: var(--aos-color-text-faint);
}
.today-hello {
  margin: 0; font-size: var(--aos-font-size-2xl); line-height: 1.1;
  font-weight: var(--aos-font-weight-heavy); letter-spacing: var(--aos-tracking-display);
}
/* The NOW card is the product. It gets the whole top of the screen. */
.now-card {
  position: relative;
  display: flex; flex-direction: column; gap: var(--aos-space-2);
  padding: var(--aos-space-5);
  background: var(--aos-glass-bg-hero); border: 1px solid var(--aos-glass-border);
  border-radius: var(--aos-radius-xl); box-shadow: var(--aos-shadow-md);
}
/* Live is signalled by one hairline of accent down the edge. The old version
   ringed the whole card in green glow, which is the look this product is
   explicitly not going for. */
.now-card.is-live { border-color: var(--aos-glass-border-strong); box-shadow: inset 3px 0 0 var(--aos-color-accent), var(--aos-shadow-md); }
.now-kicker {
  display: flex; align-items: center; gap: var(--aos-space-2); margin: 0;
  font-size: var(--aos-font-size-xs); font-weight: var(--aos-font-weight-bold);
  letter-spacing: .09em; color: var(--aos-color-text-faint);
}
.now-kicker.is-live { color: var(--aos-color-accent); }
.now-kicker.is-overdue { color: var(--aos-tone-amber); }
.live-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--aos-color-accent); animation: live-pulse 2.4s ease-in-out infinite; }
/* Opacity only. The old keyframe fired an expanding box-shadow ring twice a
   second, three inches from where the eye is trying to read. */
@keyframes live-pulse { 0%,100% { opacity: 1; } 50% { opacity: .45; } }
.now-title {
  margin: 0; font-size: var(--aos-font-size-2xl); line-height: 1.1;
  font-weight: var(--aos-font-weight-heavy); letter-spacing: var(--aos-tracking-display); text-wrap: balance;
}
.now-meta { margin: 0; font-size: var(--aos-font-size-sm); color: var(--aos-color-text-muted); font-variant-numeric: tabular-nums; }
.now-sub { margin: 0; font-size: var(--aos-font-size-sm); color: var(--aos-color-text-faint); }
.now-actions { display: flex; gap: var(--aos-space-3); margin-top: var(--aos-space-4); }
/* 48px minimum on every primary control: this is used one-handed, walking. */
.now-primary {
  flex: 0 1 auto; min-height: var(--aos-tap-lg); padding: var(--aos-space-3) var(--aos-space-6);
  display: inline-flex; align-items: center; justify-content: center;
  border: 0; border-radius: var(--aos-radius-md); cursor: pointer;
  background: var(--aos-color-accent); color: var(--aos-color-accent-contrast);
  font-size: var(--aos-font-size-base); font-weight: var(--aos-font-weight-medium);
  text-align: center; text-decoration: none;
  transition: background var(--aos-transition-duration) var(--aos-transition-easing);
}
.now-primary:hover { background: var(--aos-color-accent-strong); }
.now-primary:active { transform: scale(.985); }
.now-secondary {
  min-height: var(--aos-tap-lg); padding: var(--aos-space-3) var(--aos-space-5);
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: var(--aos-radius-md); cursor: pointer;
  border: 1px solid var(--aos-glass-border-strong); background: transparent;
  color: var(--aos-color-text-muted); font-size: var(--aos-font-size-sm); text-decoration: none;
  transition: color var(--aos-transition-duration) var(--aos-transition-easing);
}
.now-secondary:hover { color: var(--aos-color-text); }
.now-secondary:active { transform: scale(.98); }
.now-secondary--block { width: 100%; margin-top: var(--aos-space-2); }
.now-open {
  /* Pinned to the card corner, but still a full 44px target: the earlier rule
     gives it the height, this gives it the width it was missing. */
  position: absolute; top: var(--aos-space-4); right: var(--aos-space-5);
  min-width: var(--aos-tap-min); justify-content: flex-end;
  font-size: var(--aos-font-size-xs); color: var(--aos-color-text-faint); text-decoration: none;
  transition: color var(--aos-transition-fast) var(--aos-transition-easing);
}
.now-open:hover { color: var(--aos-color-accent); }
.now-card--clear, .now-card--empty { align-items: stretch; }
.now-card--clear .now-primary { flex: 0 0 auto; margin-top: var(--aos-space-4); }
/* The pick list: an unplanned day's first decision, one tap per row. */
.pick-list { list-style: none; margin: var(--aos-space-4) 0 0; padding: 0; display: flex; flex-direction: column; }
.pick-row {
  display: flex; align-items: center; gap: var(--aos-space-3);
  padding: var(--aos-space-2) 0; border-bottom: 1px solid var(--aos-glass-border);
}
.pick-row:last-child { border-bottom: 0; }
.pick-row form { margin: 0; }
.pick-title { flex: 1; min-width: 0; font-size: var(--aos-font-size-sm); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pick-add {
  min-height: 36px; padding: 0 var(--aos-space-4); border-radius: 999px; cursor: pointer;
  border: 1px solid var(--aos-glass-border-strong); background: transparent;
  color: var(--aos-color-accent); font-size: var(--aos-font-size-xs); font-weight: var(--aos-font-weight-medium);
  transition: background var(--aos-transition-duration) var(--aos-transition-easing);
}
.pick-add:hover { background: var(--aos-color-accent-soft); }
/* NOW, THEN and progress are three separate beats, not one block. Without
   this they rendered flush against the card with the progress bar overlapping
   the THEN line. */
#today-core { display: flex; flex-direction: column; gap: var(--aos-space-4); }
.next-line {
  display: grid; grid-template-columns: auto 48px minmax(0,1fr); align-items: center; gap: var(--aos-space-3);
  padding: 0 var(--aos-space-1);
}
.next-kicker { font-size: var(--aos-font-size-xs); font-weight: var(--aos-font-weight-bold); letter-spacing: .09em; color: var(--aos-color-text-faint); }
.next-when { font-size: var(--aos-font-size-xs); color: var(--aos-color-text-muted); font-variant-numeric: tabular-nums; }
.next-title { font-size: var(--aos-font-size-sm); color: var(--aos-color-text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.today-progress { display: flex; align-items: center; gap: var(--aos-space-3); padding: 0 var(--aos-space-1); }
.today-progress .progress-track { flex: 1; height: 4px; border-radius: 999px; background: var(--aos-glass-border); overflow: hidden; }
.today-progress .progress-fill { display: block; height: 100%; background: var(--aos-color-accent); border-radius: 999px; }
.progress-count { font-size: var(--aos-font-size-xs); color: var(--aos-color-text-muted); font-variant-numeric: tabular-nums; }

/* A section is a label and its content. No pane, no border, no nesting. */
/* Section + label now come from the design system primitives above. */
/* Today's lists share the .list-group surface defined above. */
.foundation-grid, .habit-strip {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: var(--aos-space-2);
}
.foundation-chip, .habit-chip {
  display: flex; align-items: center; gap: var(--aos-space-3); min-height: var(--aos-tap-lg);
  padding: var(--aos-space-2) var(--aos-space-3); border-radius: var(--aos-radius-md); cursor: pointer;
  border: 1px solid var(--aos-glass-border); background: var(--aos-glass-bg);
  color: var(--aos-color-text); font-size: var(--aos-font-size-sm); text-align: left;
  transition: border-color var(--aos-transition-duration) var(--aos-transition-easing);
}
.chip-box {
  width: 20px; height: 20px; flex: 0 0 20px; border-radius: var(--aos-radius-xs);
  border: 1.5px solid var(--aos-color-text-faint); position: relative;
  transition: background var(--aos-transition-duration) var(--aos-transition-easing);
}
.foundation-chip.is-done, .habit-chip.is-done { border-color: var(--aos-color-accent); background: var(--aos-color-accent-soft); }
.foundation-chip.is-done .chip-box, .habit-chip.is-done .chip-box { background: var(--aos-color-accent); border-color: var(--aos-color-accent); }
.foundation-chip.is-done .chip-box::after, .habit-chip.is-done .chip-box::after {
  content: ""; position: absolute; left: 6px; top: 2.5px;
  width: 5px; height: 10px; border: solid var(--aos-color-accent-contrast); border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
.baseline-toggle { display: flex; align-items: center; flex: 0 0 auto; white-space: nowrap; gap: var(--aos-space-2); min-height: var(--aos-tap-min); font-size: var(--aos-font-size-xs); color: var(--aos-color-text-muted); }
/* A native checkbox renders ~13px whatever you ask of it, so the label carries
   the target: the whole "Foundation" row is tappable, not just the box. */
.baseline-toggle input[type="checkbox"] {
  appearance: none; -webkit-appearance: none;
  display: grid; place-items: center; margin: 0; padding: 0;
  width: var(--aos-tap-min); height: var(--aos-tap-min);
  margin-left: calc(var(--aos-space-3) * -1); background: none; border: 0;
}
.baseline-toggle input[type="checkbox"]::before {
  content: ""; width: 20px; height: 20px; border-radius: var(--aos-radius-xs);
  border: 1.5px solid var(--aos-color-text-faint);
}
.habit-manage-row {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--aos-space-3);
  padding: var(--aos-space-2) var(--aos-space-3);
}
.habit-manage-name { flex: 1; min-width: 0; font-size: var(--aos-font-size-sm); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.habit-manage-progress { font-size: var(--aos-font-size-xs); color: var(--aos-color-text-muted); font-variant-numeric: tabular-nums; }
/* Always its own line, never squeezed next to the name — a milestone is
   quieter than the row's own working data (name, weekly count), not
   competing with it for space. */
.habit-manage-milestone {
  flex-basis: 100%; display: flex; align-items: center; gap: var(--aos-space-2);
  font-size: var(--aos-font-size-xs); color: var(--aos-color-text-faint); font-style: italic;
  font-variant-numeric: tabular-nums;
}
.habit-manage-milestone .icon { width: 12px; height: 12px; }
.baseline-toggle input[type="checkbox"]:checked::before {
  background: var(--aos-color-accent); border-color: var(--aos-color-accent);
}
.today-row {
  display: grid; grid-template-columns: 24px 30px minmax(0,1fr) auto 32px;
  align-items: center; gap: var(--aos-space-3);
  padding: var(--aos-space-3) var(--aos-space-4);
  transition: opacity 240ms var(--aos-transition-easing), transform 240ms var(--aos-transition-easing),
              max-height 240ms var(--aos-transition-easing), padding 240ms var(--aos-transition-easing);
  max-height: 64px;
}
.row-check {
  width: 24px; height: 24px; padding: 0; border-radius: 50%; cursor: pointer;
  border: 1.5px solid var(--aos-color-text-faint); background: none;
  transition: border-color var(--aos-transition-duration) var(--aos-transition-easing);
}
.row-check:hover { border-color: var(--aos-color-accent); }
.today-title {
  min-height: var(--aos-tap-min);
  font-size: var(--aos-font-size-sm); color: inherit; text-decoration: none;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.today-when { font-size: var(--aos-font-size-xs); color: var(--aos-color-text-faint); font-variant-numeric: tabular-nums; }
.row-more {
  width: 32px; height: 32px; border: 0; background: none; color: var(--aos-color-text-faint);
  cursor: pointer; font-size: var(--aos-font-size-base); line-height: 1;
  transition: color var(--aos-transition-fast) var(--aos-transition-easing);
}
.row-more:hover { color: var(--aos-color-text); }
.row-more:active { transform: scale(.9); }
/* Calendar glance — time first, because that is what you are scanning for. */
.glance-row, .reminder-row {
  display: flex; align-items: center; gap: var(--aos-space-4);
  padding: var(--aos-space-3) var(--aos-space-4);
}
.glance-time { flex: 0 0 46px; font-size: var(--aos-font-size-xs); color: var(--aos-color-text-muted); font-variant-numeric: tabular-nums; }
.glance-title, .reminder-text { flex: 1; min-width: 0; font-size: var(--aos-font-size-sm); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.reminder-clear {
  min-height: 36px; padding: 0 var(--aos-space-3); border: 0; background: none; cursor: pointer;
  color: var(--aos-color-text-faint); font-size: var(--aos-font-size-xs);
}
.reminder-clear:hover { color: var(--aos-color-text); }
.reminder-row.is-clearing { opacity: 0; transition: opacity 200ms var(--aos-transition-easing); }
/* Current project — one line, one number, one bar. */
.project-row {
  display: grid; grid-template-columns: minmax(0,1fr) auto; gap: var(--aos-space-2) var(--aos-space-4);
  align-items: center; padding: var(--aos-space-4);
  background: var(--aos-glass-bg); border: 1px solid var(--aos-glass-border);
  border-radius: var(--aos-radius-lg); text-decoration: none; color: inherit;
}
.project-name { font-size: var(--aos-font-size-base); font-weight: var(--aos-font-weight-medium); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.project-count { font-size: var(--aos-font-size-xs); color: var(--aos-color-text-muted); font-variant-numeric: tabular-nums; }
.project-track { grid-column: 1 / -1; height: 4px; border-radius: 999px; background: var(--aos-glass-border); overflow: hidden; }
.project-fill { display: block; height: 100%; background: var(--aos-color-accent); border-radius: 999px; }
/* Completing something should feel like something. The row collapses upward
   and everything beneath slides into its place — no reload, no flicker. */
.today-row.is-completing {
  opacity: 0; transform: translateX(14px);
  max-height: 0; padding-top: 0; padding-bottom: 0;
  overflow: hidden;
}
.now-card.is-completing { opacity: 0; transform: scale(.99); transition: opacity 180ms, transform 180ms; }
.today-plan-link {
  align-self: center; min-height: var(--aos-tap-lg); display: inline-flex; align-items: center;
  padding: var(--aos-space-3) var(--aos-space-5);
  font-size: var(--aos-font-size-sm); color: var(--aos-color-text-muted); text-decoration: none;
}
.today-plan-link:hover { color: var(--aos-color-accent); }
.plan-food-link {
  display: inline-flex; align-items: center; min-height: var(--aos-tap-min);
  font-size: var(--aos-font-size-sm); color: var(--aos-color-text-muted); text-decoration: none;
}
.plan-food-link:hover { color: var(--aos-color-accent); }
.postpone-choices { display: flex; gap: var(--aos-space-3); }
.reason-row { display: flex; flex-wrap: wrap; gap: var(--aos-space-2); }
/* Desktop is an adaptation of the above, not a separate design: a measure to
   stop the column sprawling, and room for the foundation chips to sit in one
   row. Nothing is added that the phone does not get. */
@media (min-width: 760px) {
  /* .today-page's own max-width lived here — the per-screen width hack that
     left 480px of dead space beside it while Plan ran full-bleed. The .page
     wrapper now sets one measure for every screen. */
  .today-hello { font-size: var(--aos-font-size-3xl); }
  .now-title { font-size: var(--aos-font-size-3xl); }
  .now-card { padding: var(--aos-space-6); }
}
/* ---- Responsive ------------------------------------------------------- */

@media (max-width: 1180px) {
  .widget { grid-column: span 6; }
}
/* Folded into the 900px phone block above — the sidebar used to collapse into
   a horizontal icon strip here, which stacked two navigations above the
   content. There is one navigation on a phone now, and it is the tab bar. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) {
    animation: none !important;
  }
}
/* One line, not a router: this is a plain multi-page app (D-013), and
   cross-document view transitions are a browser-native no-JS way to still
   get a soft crossfade between pages instead of a hard flash — supporting
   browsers animate it, everyone else just navigates normally. Duration
   matches the app's own --aos-transition-duration rather than the browser
   default (~250ms) so it feels like the same motion system, not a bolted-on
   effect. */
@view-transition { navigation: auto; }
::view-transition-old(root), ::view-transition-new(root) {
  animation-duration: var(--aos-transition-duration);
  animation-timing-function: var(--aos-transition-easing);
}
/* The backdrop-filter fallback and the [data-solid] "more opaque" mode both
   existed to keep text legible over photography. Every surface is opaque now,
   so both are gone and the sidebar toggle they served drives light/dark. */
