/* App shell + view layout skeleton. */

.app-shell {
  display: grid;
  grid-template-columns: var(--sidebar-width) 1fr;
  min-height: 100vh;
}
.app-shell--focus .sidebar { display: none; }
.app-shell--focus { grid-template-columns: 1fr; }
body.is-focus-mode #quick-add-root { display: none; }
/* Onboarding is full screen too: no sidebar or tab bar, no Quick Add, no
   Active Task indicator. */
.app-shell--onboarding .sidebar { display: none; }
.app-shell--onboarding { grid-template-columns: 1fr; }
body.is-onboarding #quick-add-root, body.is-onboarding #active-task-indicator-root { display: none; }

/* ---- Sidebar (Design Sprint 2). Sits on its own "chrome" neutral, a
   step below the canvas, so it recedes behind the work instead of being
   the brightest surface on screen. Rhythm is set by explicit margins
   (brand, nav, utility cluster) rather than one uniform gap. ---- */
.sidebar {
  background: var(--color-chrome);
  border-right: 1px solid var(--color-border);
  padding: var(--space-4) var(--space-3);
  display: flex;
  flex-direction: column;
  gap: 0;
  position: sticky;
  top: 0;
  height: 100vh;
}

/* Lockup: company mark | product name over a quiet descriptor. The hairline
   separates the TwoDot mark from the Flow product name without enlarging
   the brand area. */
.sidebar__brand {
  display: flex; align-items: center; gap: var(--space-3);
  min-height: 48px; padding: 0 var(--space-3); margin-bottom: var(--space-5);
}
.brand-text { display: flex; flex-direction: column; padding-left: var(--space-3); border-left: 1px solid var(--color-border-strong); }

/* Real TwoDot wordmark, swapped for a light/dark-legible variant
   depending on theme — same pattern as the color tokens in variables.css. */
.brand-logo { height: var(--icon-md); width: auto; display: block; }
.brand-logo--light { display: none; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .brand-logo--dark { display: none; }
  :root:not([data-theme="light"]) .brand-logo--light { display: block; }
}
:root[data-theme="dark"] .brand-logo--dark { display: none; }
:root[data-theme="dark"] .brand-logo--light { display: block; }

.brand-name { font-weight: var(--weight-bold); font-size: var(--text-md); letter-spacing: var(--tracking-title); line-height: 20px; }
.brand-tagline { font-size: var(--text-2xs); line-height: 16px; color: var(--color-text-faint); }

.sidebar__nav { display: flex; flex-direction: column; gap: 2px; }

/* One row height for every navigation entry, links and buttons alike
   (Sign In, the mobile More tab). The active row is a calm ink fill plus
   semibold text; only its icon takes the accent, so the current page is
   clear without colour carrying it alone, and nothing glows. */
.nav-item {
  display: flex; align-items: center; gap: var(--space-3);
  min-height: var(--control-sm); padding: 6px var(--space-3); border-radius: var(--radius-sm);
  color: var(--color-text-muted); font-size: var(--text-sm); font-weight: var(--weight-medium); line-height: var(--leading-control);
  transition: background-color var(--transition-fast), color var(--transition-fast);
}
button.nav-item {
  appearance: none; background: none; border: 0; width: 100%; font-family: inherit;
  text-align: left; cursor: pointer;
}
.nav-item:hover { background-color: var(--nav-ink-hover); color: var(--color-text); }
.nav-item--active, .nav-item--active:hover { background-color: var(--nav-ink-active); color: var(--color-text); font-weight: var(--weight-semibold); }
.nav-item--active .nav-icon { color: var(--color-accent); }
.nav-item:focus-visible { box-shadow: var(--shadow-focus); border-radius: var(--radius-sm); }
.nav-icon { width: var(--icon-sm); height: var(--icon-sm); flex-shrink: 0; }
.nav-item--more { display: none; } /* mobile tab bar only */

/* Utility cluster: Settings, Backup and the account entry read as one
   group anchored to the bottom, under a single hairline, rather than two
   separately divided blocks drifting apart. */
.sidebar__nav--secondary { margin-top: auto; border-top: 1px solid var(--color-border); padding-top: var(--space-3); }

/* ---- Active Task indicator docked in the sidebar (desktop shell). It
   lives in navigation chrome, so it can never cover a page; app.js moves
   the one indicator element here on desktop and back to the phone strip
   below 900px. Two quiet lines on the same translucent ink as nav rows:
   state and time, then the task. ---- */
.sidebar__now { margin-top: auto; }
.sidebar__now + .sidebar__nav--secondary { margin-top: 0; }
.sidebar__now:has(.active-task-indicator) { margin-bottom: var(--space-3); }
.sidebar__now .active-task-indicator {
  position: relative; inset: auto; width: 100%;
  flex-wrap: wrap; column-gap: var(--space-2); row-gap: 2px;
  padding: var(--space-2) var(--space-3); border: 0; border-radius: var(--radius-sm);
  background: var(--nav-ink-hover); box-shadow: none; font-size: var(--text-xs); line-height: 16px;
}
.sidebar__now .active-task-indicator:hover { background: var(--nav-ink-active); box-shadow: none; }
.sidebar__now .active-task-indicator:focus-visible { box-shadow: var(--shadow-focus); }
.sidebar__now .active-task-indicator__time { margin-left: auto; }
.sidebar__now .active-task-indicator__title {
  order: 3; flex-basis: 100%; max-width: none; margin-left: calc(7px + var(--space-2));
  font-size: var(--text-sm); font-weight: var(--weight-medium); line-height: 20px; color: var(--color-text);
}
.sidebar__now .active-task-indicator__popover { left: calc(var(--sidebar-width) + var(--space-3)); right: auto; bottom: var(--space-6); }
.sidebar__account { margin-top: 2px; }

/* Signed in: a compact identity row whose avatar centres on the same
   column as the nav icons above it. */
.account-row { display: flex; align-items: center; gap: var(--space-3); min-height: 40px; padding: 4px var(--space-2); }
.account-avatar {
  width: 24px; height: 24px; border-radius: var(--radius-pill); flex-shrink: 0;
  background: var(--color-accent-soft); color: var(--color-accent-soft-text);
  display: flex; align-items: center; justify-content: center;
  font-size: var(--text-xs); font-weight: 700;
}
.account-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 1px; }
.account-email {
  font-size: var(--text-sm); color: var(--color-text-muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Sync status — one small line, never per-task noise. A plain label with a
   colored dot reads at a glance without competing with the account row. */
.sync-indicator {
  all: unset; box-sizing: border-box; display: flex; align-items: center; gap: 5px;
  cursor: pointer; font-size: var(--text-2xs); color: var(--color-text-faint);
}
.sync-indicator:disabled { cursor: default; }
.sync-indicator:focus-visible { box-shadow: var(--shadow-focus); border-radius: var(--radius-xs); }
.sync-dot { width: 6px; height: 6px; border-radius: var(--radius-pill); flex-shrink: 0; }
.sync-dot--synced { background: var(--color-success); }
.sync-dot--syncing { background: var(--color-accent); animation: sync-pulse 1.1s ease-in-out infinite; }
.sync-dot--offline { background: var(--color-text-faint); }
.sync-dot--pending { background: var(--color-warning); }
.sync-dot--error { background: var(--color-danger); }
@keyframes sync-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.35; } }

/* Active Task indicator (PDR-001 Phase 3, live time added in Phase 5) --
   fixed so it stays visible and in a stable position across every route,
   including Focus Mode's entirely different single-column layout, without
   depending on either grid. See active-task-indicator.js for what state it
   shows and owns (as of Phase 5: Active/Paused, a compact elapsed-time
   readout, and this app's one heartbeat() caller). Anchored bottom-right,
   stacked directly above the existing Quick Add FAB (same right offset,
   one FAB-height plus a gap above it) rather than a top corner -- every
   view header uses its own top-right area for local actions (Brain Dump,
   + Urgent Task, etc.), so top placement collided with per-view content;
   bottom-right next to the FAB is this codebase's one already-proven
   collision-free fixed zone. */
#active-task-indicator-root:empty { display: none; }
.active-task-indicator {
  all: unset; box-sizing: border-box; position: fixed; bottom: calc(var(--space-6) + var(--fab-size) + var(--space-3)); right: var(--space-6); z-index: 40;
  display: flex; align-items: center; gap: 7px; padding: 7px 14px; border-radius: var(--radius-pill);
  background: var(--color-surface-raised); border: 1px solid var(--color-border); box-shadow: var(--shadow-xs);
  font-size: var(--text-2xs); font-weight: 650; color: var(--color-text-muted); cursor: pointer;
  transition: box-shadow var(--transition-fast);
}
.active-task-indicator:hover, .active-task-indicator:focus-visible { box-shadow: var(--shadow-focus); }
.active-task-indicator__dot { width: 7px; height: 7px; border-radius: var(--radius-pill); flex-shrink: 0; }
.active-task-indicator--active .active-task-indicator__dot { background: var(--color-accent); animation: sync-pulse 1.6s ease-in-out infinite; }
.active-task-indicator--paused .active-task-indicator__dot { background: var(--color-warning); }
/* Recover Momentum (PDR-001 Phase 6): calm, not alarming -- the same
   accent tone as Active, deliberately NOT the warning color Paused uses,
   and no pulse animation, since nothing here is "live" until the user
   decides how to continue. */
.active-task-indicator--recovery .active-task-indicator__dot { background: var(--color-accent); }
/* Finish Day invitation (PDR-001 Phase 8): calm, not alarming, and
   deliberately distinct from both Active's accent and Paused's warning
   tone -- this isn't a state that needs attention, only an offer. No
   pulse: nothing here is urgent. */
.active-task-indicator--invitation .active-task-indicator__dot { background: var(--color-accent-soft-text); }
.active-task-indicator__label { color: var(--color-text); }
.active-task-indicator__title { color: var(--color-text-faint); max-width: 160px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Tabular figures so the digits don't jitter the pill's width as they
   change every second (PDR-001 Phase 5). */
.active-task-indicator__time { color: var(--color-text-faint); font-variant-numeric: tabular-nums; }

/* Recover Momentum popover (PDR-001 Phase 6) -- anchored above the
   indicator pill, same right offset, never a full-screen backdrop-blocking
   modal. Compact by design: this is the "lighter interaction" this phase
   prefers over a large dialog. */
.active-task-indicator__popover {
  position: fixed; bottom: calc(var(--space-6) + var(--fab-size) + var(--space-3) + 44px + var(--space-2)); right: var(--space-6);
  width: min(320px, calc(100vw - var(--space-8))); z-index: 41;
  background: var(--color-surface-raised); border: 1px solid var(--color-border); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg); padding: var(--space-5);
  animation: recover-pop-in var(--transition-base) both;
}
@keyframes recover-pop-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }

/* Recover Momentum content (PDR-001 Phase 6) -- shared between the inline
   Focus Mode placement and this popover. Calm on purpose: no red, no
   warning iconography, generous line-height, short copy. */
.recover-momentum__eyebrow { font-size: var(--text-sm); font-weight: 650; color: var(--color-text); margin-bottom: 2px; }
.recover-momentum__question { font-size: var(--text-sm); color: var(--color-text-muted); margin-bottom: var(--space-4); line-height: 1.5; }
.recover-momentum__choices { display: flex; flex-direction: column; gap: var(--space-2); }
.recover-momentum__choices--adjust { flex-direction: row; flex-wrap: wrap; }
.recover-momentum__choices[hidden] { display: none; } /* the plain `display: flex` above otherwise wins over the `hidden` attribute's own UA rule */
.recover-momentum__choices--adjust .btn { flex: 1; min-width: 64px; }

/* ---- Page shell (Design Sprint 2): one rule for every route. A single
   content column (--shell-content), centred in the canvas beside the
   sidebar so wide windows don't leave a lopsided empty band on one side;
   the same top offset and gutter everywhere; and one title block
   (eyebrow, title, actions) with a fixed gap to the content below. ---- */
/* Reserve the scrollbar's space on every route, so short and long pages
   centre the column at the same x (classic, non-overlay scrollbars). */
html { scrollbar-gutter: stable; }
.view-root {
  width: 100%; max-width: calc(var(--shell-content) + 2 * var(--shell-gutter)); margin-inline: auto;
  padding: var(--shell-top) var(--shell-gutter) var(--space-8);
}

.view-header {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: var(--space-4); margin-bottom: var(--space-6);
}
.view-header__eyebrow { font-size: var(--text-sm); line-height: 20px; color: var(--color-text-faint); margin-bottom: var(--space-1); }
.view-header__actions { display: flex; gap: var(--space-2); flex-shrink: 0; }

/* Global top actions are neutral secondaries: none of them is the page's
   primary action (that lives in the content, e.g. the Next card). Urgent
   keeps a semantic cue through a calmer, deeper red on its label only,
   never a red wash or fill, so it registers without reading as an alarm. */
.view-header__actions .btn--urgent { color: var(--color-danger-text); }
.view-header__actions .btn--urgent:hover:not(:disabled) {
  background-color: var(--color-surface); border-color: var(--color-border-strong);
  box-shadow: var(--shadow-sm); color: var(--color-danger-text);
}

.back-link {
  display: inline-flex; align-items: center; gap: 4px;
  color: var(--color-text-faint); font-size: var(--text-sm); margin-bottom: var(--space-3);
  transition: color var(--transition-fast);
}
.back-link:hover { color: var(--color-accent); }

section + section, .settings-section + .settings-section { margin-top: var(--space-6); }

/* ---- Quick Add FAB (Design Sprint 2). A soft rounded square on the
   control scale (--fab-size = --control-lg) rather than a generic circle:
   it reads as part of the same component family as the product's buttons.
   Elevation comes from an accent-tinted shadow that lifts slightly on
   hover; press scales down; keyboard focus gets a canvas-gapped ring that
   stays visible against the accent fill. No decorative motion. ---- */
.fab {
  position: fixed; bottom: var(--space-6); right: var(--space-6);
  width: var(--fab-size); height: var(--fab-size); border-radius: var(--radius-md); border: none;
  background-color: var(--color-accent); color: var(--color-on-accent);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18),
              0 2px 4px rgba(var(--color-accent-rgb), 0.18), 0 8px 24px rgba(var(--color-accent-rgb), 0.26);
  display: flex; align-items: center; justify-content: center; cursor: pointer;
  transition: transform var(--transition-fast), background-color var(--transition-fast), box-shadow var(--transition-fast);
  z-index: 40;
}
.fab:hover {
  background-color: var(--color-accent-hover); transform: translateY(-1px);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2),
              0 4px 8px rgba(var(--color-accent-rgb), 0.22), 0 14px 32px rgba(var(--color-accent-rgb), 0.32);
}
.fab:active { transform: scale(0.96); background-color: var(--color-accent-active); }
.fab:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px var(--color-bg), 0 0 0 5px var(--color-accent), 0 8px 24px rgba(var(--color-accent-rgb), 0.26);
}
.fab svg { width: var(--icon-md); height: var(--icon-md); }

/* ---- Mobile "More" sheet (Design Sprint 2): a bottom sheet with the same
   entry motion as the product's mobile dialogs. Hidden entirely on desktop,
   where every destination is already in the sidebar. ---- */
.nav-sheet-layer { position: fixed; inset: 0; z-index: 80; display: flex; flex-direction: column; justify-content: flex-end; }
.nav-sheet-backdrop { position: absolute; inset: 0; background: rgba(15, 13, 20, 0.45); animation: overlay-in var(--transition-base) both; }
.nav-sheet {
  position: relative; background: var(--color-surface-raised);
  border-radius: var(--radius-lg) var(--radius-lg) 0 0; box-shadow: var(--shadow-lg);
  padding: var(--space-2) var(--space-3) calc(var(--space-4) + env(safe-area-inset-bottom));
  max-height: 85vh; overflow-y: auto;
  animation: sheet-in var(--transition-slow) both;
}
.nav-sheet__header { display: flex; align-items: center; justify-content: space-between; padding: var(--space-2) var(--space-3) var(--space-3); }
.nav-sheet__title { font-size: var(--text-md); }
/* Close meets the touch minimum; the negative margin keeps its glyph
   aligned with the row icons below. */
.nav-sheet__header .icon-btn { width: var(--touch-min); height: var(--touch-min); margin-right: calc(-1 * var(--space-3)); }
.nav-sheet__nav { display: flex; flex-direction: column; gap: 2px; }
.nav-sheet__nav--utility { margin-top: var(--space-2); padding-top: var(--space-2); border-top: 1px solid var(--color-border); }
.nav-sheet__account { margin-top: 2px; }
/* Sheet rows are touch targets first: 48px tall, 16px text. */
.nav-sheet .nav-item { min-height: var(--control-lg); font-size: var(--text-md); }
.nav-sheet .nav-icon { width: var(--icon-md); height: var(--icon-md); }

/* Today's top actions (Design Sprint 3) step down to the ghost tier: they
   stay one tap away but never compete with the execution surface. The row
   is pulled out by the buttons' own padding so their labels line up with
   the content edge. */
.view--today .view-header__actions { margin-inline: calc(-1 * var(--space-4)); }
/* The date is the page title: it stays on one line, and the actions wrap
   beneath it when both can't share a row (instead of breaking the date
   into "Saturday, 26 / September"). Below 560px the header already
   stacks, and the date may wrap on the narrowest phones. */
@media (min-width: 561px) {
  .view--today .view-header { flex-wrap: wrap; row-gap: var(--space-2); }
  .view--today .view-header h1 { white-space: nowrap; }
}
.view--today .view-header__actions .btn--urgent:hover:not(:disabled) {
  background-color: var(--color-surface-2); border-color: transparent; box-shadow: none;
}


.toast-host { position: fixed; bottom: var(--space-6); left: 50%; transform: translateX(-50%); z-index: 100; }
