/* ═══════════════════════════════════════════════════════════════════════
   Snapstack — Wispr Flow language
   ───────────────────────────────────────────────────────────────────────
   Three depth levels, cream/white alternating: a warm cream ground the
   sidebar sits on, a white rounded sheet floating over it that holds each
   page, and cream-tinted cards resting on the sheet. Elevation is still
   reserved for floating things (the HUD, popovers, the selection bar).

   Type: Fraunces (bundled, variable) for titles and big numerals; the
   system face for everything else, so the app still feels native.

   Light is the primary look; dark follows the OS unless the user pins a
   theme (data-theme on :root, set by the Appearance setting).
   ═══════════════════════════════════════════════════════════════════════ */

@font-face {
  font-family: "Fraunces";
  src: url("/fonts/Fraunces-variable.ttf") format("truetype-variations");
  font-weight: 100 900;
  font-display: swap;
}

:root {
  --bg: #f7f6f3;
  --surface: #ffffff;
  --surface-2: #efede8;
  /* Cards resting on the white sheet — the cream inversion. */
  --card: #fbfaf8;
  /* Recessed wells *on* those cream cards (bar tracks, empty heat cells) —
     ink-based so it stays visible on --card in both themes. */
  --well: rgba(0, 0, 0, 0.05);
  --border: rgba(0, 0, 0, 0.08);
  --ink: #1a1a18;
  --ink-2: #6f6d66;
  --ink-3: #a6a49c;
  --accent: #0f6b5c;
  --accent-soft: #ddeae6;
  --accent-ink: #ffffff;
  --danger: #d5453c;
  --shadow-pop: 0 8px 30px rgba(0, 0, 0, 0.12), 0 2px 8px rgba(0, 0, 0, 0.06);

  /* Pastel tints — small colored moments (stat icons, folder covers). */
  --tint-teal: #e4efeb;
  --tint-teal-ink: #0f6b5c;
  --tint-amber: #f6ead3;
  --tint-amber-ink: #92600e;
  --tint-lilac: #eae4f6;
  --tint-lilac-ink: #6a51a8;
  --tint-rose: #f9e4dd;
  --tint-rose-ink: #b04f36;
  --tint-slate: #e7eaf0;
  --tint-slate-ink: #48597c;

  --font: -apple-system, "SF Pro Text", "Helvetica Neue", sans-serif;
  --font-display: "Fraunces", "New York", ui-serif, Georgia, serif;

  --r-control: 10px;
  --r-card: 14px;
  --r-hud: 18px;
  --r-sheet: 18px;
  --r-pill: 999px;

  --ease: cubic-bezier(0.32, 0.72, 0, 1);
  --t-fast: 160ms var(--ease);
  --t-hud: 260ms var(--ease);

  color-scheme: light dark;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #191917;
    --surface: #232320;
    --surface-2: #2c2c28;
    --card: #2a2a26;
    --well: rgba(255, 255, 255, 0.08);
    --border: rgba(255, 255, 255, 0.09);
    --ink: #f1efea;
    --ink-2: #a6a49c;
    --ink-3: #6f6d66;
    --accent: #3fa08d;
    --accent-soft: rgba(63, 160, 141, 0.18);
    --shadow-pop: 0 8px 30px rgba(0, 0, 0, 0.45), 0 2px 8px rgba(0, 0, 0, 0.3);

    --tint-teal: rgba(63, 160, 141, 0.16);
    --tint-teal-ink: #4fb39e;
    --tint-amber: rgba(214, 158, 46, 0.16);
    --tint-amber-ink: #d9a84e;
    --tint-lilac: rgba(140, 110, 220, 0.16);
    --tint-lilac-ink: #a68fd8;
    --tint-rose: rgba(224, 108, 74, 0.16);
    --tint-rose-ink: #d8896f;
    --tint-slate: rgba(120, 140, 190, 0.16);
    --tint-slate-ink: #93a5c8;
  }
}

:root[data-theme="dark"] {
  --bg: #191917;
  --surface: #232320;
  --surface-2: #2c2c28;
  --card: #2a2a26;
  --well: rgba(255, 255, 255, 0.08);
  --border: rgba(255, 255, 255, 0.09);
  --ink: #f1efea;
  --ink-2: #a6a49c;
  --ink-3: #6f6d66;
  --accent: #3fa08d;
  --accent-soft: rgba(63, 160, 141, 0.18);
  --shadow-pop: 0 8px 30px rgba(0, 0, 0, 0.45), 0 2px 8px rgba(0, 0, 0, 0.3);
}

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html,
body,
#root {
  height: 100%;
}

body {
  font-family: var(--font);
  font-size: 13px;
  color: var(--ink);
  background: transparent;
  -webkit-font-smoothing: antialiased;
  user-select: none;
  cursor: default;
  overflow: hidden;
}

button {
  font: inherit;
  color: inherit;
  background: none;
  border: none;
  cursor: default;
}

button:focus-visible,
select:focus-visible,
input:focus-visible,
textarea:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

img {
  max-width: 100%;
}

/* Uppercase micro-label. */
.micro {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* ══ Primitives ═════════════════════════════════════════════════════ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 7px 14px;
  border-radius: var(--r-pill);
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
  transition: background var(--t-fast), color var(--t-fast), opacity var(--t-fast);
}

/* The "opens a menu" mark. Quiet enough to stay an affordance rather than
   punctuation, and it sits inside the button's own gap. */
.btn__caret {
  font-size: 9px;
  line-height: 1;
  opacity: 0.5;
  margin-left: -2px;
}

.btn--primary {
  background: var(--accent);
  color: var(--accent-ink);
}

.btn--primary:hover {
  opacity: 0.9;
}

.btn--secondary {
  background: var(--surface);
  color: var(--ink);
  box-shadow: inset 0 0 0 1px var(--border);
}

.btn--secondary:hover {
  background: var(--surface-2);
}

.btn--ghost {
  background: transparent;
  color: var(--ink-2);
}

.btn--ghost:hover {
  background: var(--surface-2);
  color: var(--ink);
}

.btn--danger {
  background: transparent;
  color: var(--danger);
}

.btn--danger:hover {
  background: color-mix(in srgb, var(--danger) 10%, var(--surface));
}

.btn:disabled {
  opacity: 0.45;
  pointer-events: none;
}

/* A leading glyph does the work an ellipsis used to: it says "this opens
   something" without the trailing dots. Tightened on the left so the icon reads
   as part of the label rather than a second control. */
.btn--icon {
  gap: 5px;
  padding-left: 11px;
}

/* Icon-only ghost button. */
.iconbtn {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border-radius: 8px;
  color: var(--ink-2);
  transition: background var(--t-fast), color var(--t-fast);
}

.iconbtn:hover {
  background: var(--surface-2);
  color: var(--ink);
}

.iconbtn--danger:hover {
  background: color-mix(in srgb, var(--danger) 12%, var(--surface));
  color: var(--danger);
}

/* Popover + Menu — the native-select replacement. */
.popwrap {
  position: relative;
}

.popover {
  position: absolute;
  z-index: 30;
  min-width: 180px;
  max-height: 280px;
  overflow-y: auto;
  padding: 6px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-hud);
  box-shadow: var(--shadow-pop);
  animation: pop-in 160ms var(--ease);
}

/* A popover with a ceiling stops scrolling as a whole and becomes a frame its
   contents scroll inside — otherwise a pinned header scrolls away with
   everything else, which is the one thing pinning it was for. */
.popover--capped {
  display: flex;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
}

.popover--up {
  bottom: calc(100% + 8px);
  right: 0;
}

.popover--down {
  top: calc(100% + 8px);
  right: 0;
}

.popover--left {
  right: auto;
  left: 0;
}

@keyframes pop-in {
  from {
    opacity: 0;
    transform: translateY(3px);
  }
}

.menu__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  width: 100%;
  text-align: left;
  padding: 7px 10px;
  border-radius: 8px;
  font-size: 13px;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.menu__item:hover {
  background: var(--surface-2);
}

.menu__item--on {
  color: var(--accent);
  font-weight: 600;
}

.menu__item--quiet {
  color: var(--ink-2);
}

.menu__input {
  width: 100%;
  margin-top: 4px;
  padding: 7px 10px;
  font: inherit;
  font-size: 13px;
  color: var(--ink);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
}

.menu__input:focus-visible {
  outline: none;
  border-color: var(--accent);
}

/* Chip — status tag on cards. */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 8px;
  border-radius: var(--r-pill);
  font-size: 11px;
  font-weight: 600;
  background: var(--surface-2);
  color: var(--ink-2);
  white-space: nowrap;
}

.chip--kept {
  background: var(--accent-soft);
  color: var(--accent);
}

/* Round checkbox with an ordinal number when selected. */
.check {
  display: grid;
  place-items: center;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  border: 1.5px solid var(--ink-3);
  background: var(--surface);
  font-size: 10px;
  font-weight: 700;
  color: transparent;
  transition: background var(--t-fast), border-color var(--t-fast);
  flex: none;
}

.check--on {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
}

/* Segmented control. */
.seg {
  display: inline-flex;
  gap: 2px;
  padding: 2px;
  background: var(--surface-2);
  border-radius: var(--r-control);
}

.seg__opt {
  padding: 5px 12px;
  border-radius: 8px;
  font-size: 13px;
  font-weight: 500;
  color: var(--ink-2);
  transition: background var(--t-fast), color var(--t-fast);
}

.seg__opt--on {
  background: var(--surface);
  color: var(--ink);
  font-weight: 600;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
}

/* Styled switch. */
.switch {
  appearance: none;
  -webkit-appearance: none;
  position: relative;
  width: 40px;
  height: 24px;
  flex: none;
  border-radius: var(--r-pill);
  background: var(--surface-2);
  border: 1px solid var(--border);
  transition: background var(--t-fast);
}

.switch::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--surface);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
  transition: transform var(--t-fast);
}

.switch:checked {
  background: var(--accent);
}

.switch:checked::after {
  transform: translateX(16px);
}

/* Stacked deck of thumbnails. */
.deck {
  position: relative;
  flex: none;
}

.deck__thumb {
  position: absolute;
  top: 0;
  border-radius: 6px;
  object-fit: cover;
  border: 1.5px solid var(--surface);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.18);
  background: var(--surface-2);
}

/* Stat card. */
.statcard {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--r-card);
  padding: 18px 20px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}

.statcard__num {
  font-family: var(--font-display);
  font-size: 34px;
  font-weight: 580;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
  color: var(--ink);
  white-space: nowrap;
}

.statcard__sub {
  font-size: 13px;
  color: var(--ink-2);
}

.statcard__head {
  display: flex;
  align-items: center;
  gap: 8px;
}

.statcard__icon {
  width: 26px;
  height: 26px;
  border-radius: 8px;
  display: grid;
  place-items: center;
  flex: none;
}

.statcard__icon--teal  { background: var(--tint-teal);  color: var(--tint-teal-ink); }
.statcard__icon--amber { background: var(--tint-amber); color: var(--tint-amber-ink); }
.statcard__icon--lilac { background: var(--tint-lilac); color: var(--tint-lilac-ink); }
.statcard__icon--rose  { background: var(--tint-rose);  color: var(--tint-rose-ink); }
.statcard__icon--slate { background: var(--tint-slate); color: var(--tint-slate-ink); }

/* ══ HUD — pill + expanded panel ════════════════════════════════════ */

.hud {
  position: relative;
  height: 100%;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  overflow: hidden;
}

.hud--pill {
  flex-direction: row;
  align-items: center;
  gap: 8px;
  border-radius: var(--r-pill);
  padding: 0 13px 0 10px;
  transition: border-radius var(--t-hud);
}

.hud--panel {
  border-radius: var(--r-hud);
}

/* macOS-style red traffic-light dot. */
.tldot {
  position: relative;
  width: 12px;
  height: 12px;
  flex: none;
  border-radius: 50%;
  background: var(--danger);
  display: grid;
  place-items: center;
  color: transparent;
  transition: opacity var(--t-fast);
}

.tldot:hover {
  color: rgba(0, 0, 0, 0.55);
}

.tldot svg {
  width: 8px;
  height: 8px;
}

.hud--pill .tldot {
  opacity: 0;
}

.hud--pill:hover .tldot {
  opacity: 1;
}

.pill__count {
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
}

.pill__expiry {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 11px;
  color: var(--ink-3);
  white-space: nowrap;
}

.pill__expiry i {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--ink-3);
}

.pill__flash {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 12px;
  font-weight: 600;
  color: var(--accent);
  white-space: nowrap;
  animation: pop-in 160ms var(--ease);
}

/* Heights are pinned rather than derived: `Hud.tsx` sizes the window from
   HEAD_H/ROW_H/FOOT_H, and a box that grows past its constant is a control
   clipped off the bottom of a borderless window. */
.hud__head {
  display: flex;
  align-items: center;
  gap: 9px;
  height: 38px;
  padding: 0 8px 0 11px;
  flex: none;
}

.hud__title {
  font-size: 13px;
  font-weight: 600;
  flex: 1;
}

.hud__count {
  font-size: 12px;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}

.hud__rows {
  position: relative;
  flex: 1;
  overflow-y: auto;
  /* The 5px matches ROWS_PAD in `Hud.tsx`, which budgets for it in the window
     height. Padding here that the constant doesn't know about is a scrollbar on
     a list that fits. */
  padding: 5px 7px;
  display: flex;
  flex-direction: column;
}

/* Input pinned, list scrolling under it. `min-height: 0` on both is what lets
   the list actually shrink and scroll inside a flex parent instead of pushing
   the input out of the box. */
.folderpick {
  display: flex;
  flex-direction: column;
  min-height: 0;
  height: 100%;
  gap: 4px;
}

/* Compact, because the box it lives in can be as short as a single row and the
   list underneath still has to get a usable share of it. */
.folderpick__new {
  flex: none;
  margin-top: 0;
  padding: 5px 9px;
  font-size: 12.5px;
}

.folderpick__list {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
}

/* The sweep band — the list's answer to the Canvas lasso. */
.hud__band {
  position: absolute;
  left: 4px;
  right: 4px;
  z-index: 2;
  pointer-events: none;
  border: 1px solid var(--accent);
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  border-radius: 6px;
}

/* One shot row. */
.shotrow {
  display: flex;
  align-items: center;
  gap: 9px;
  height: 46px;
  padding: 0 7px;
  border-radius: var(--r-control);
  flex: none;
  transition: background var(--t-fast);
}

.shotrow:hover {
  background: var(--surface-2);
}

.shotrow--on,
.shotrow--on:hover {
  background: var(--accent-soft);
}

.shotrow .check {
  visibility: hidden;
}

.shotrow:hover .check,
.shotrow .check--on,
.hud--selecting .shotrow .check,
.drawer--selecting .shotrow .check {
  visibility: visible;
}

.shotrow__thumb {
  width: 58px;
  height: 36px;
  flex: none;
  border-radius: 6px;
  object-fit: cover;
  background: var(--surface-2);
  border: 1px solid var(--border);
}

.shotrow__meta {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.shotrow__time {
  font-size: 13px;
  font-weight: 500;
  color: var(--ink);
}

.shotrow__age {
  font-size: 11px;
  color: var(--ink-3);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.shotrow__acts {
  display: none;
  gap: 2px;
}

.shotrow:hover .shotrow__acts {
  display: inline-flex;
}

/* Fold between the current batch and the shots already copied out of it. */
.hud__divider {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  height: 34px;
  flex: none;
  margin: 2px 8px;
  padding: 0 8px;
  border-radius: 8px;
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-3);
  transition: background var(--t-fast), color var(--t-fast);
}

.hud__divider:hover {
  background: var(--surface-2);
  color: var(--ink-2);
}

.hud__divider svg {
  transition: transform var(--t-fast);
}

.hud__divider--open svg {
  transform: rotate(90deg);
}

/* Already copied: present, but visibly not the thing you're working on. */
.hud__divider--open ~ .shotrow {
  opacity: 0.62;
}

.hud__divider--open ~ .shotrow:hover {
  opacity: 1;
}

.hud__foot {
  display: flex;
  align-items: center;
  gap: 4px;
  height: 44px;
  padding: 0 8px;
  border-top: 1px solid var(--border);
  flex: none;
}

/* Four buttons and a spacer inside 356px: the footer sets its own scale. */
.hud__foot .btn {
  padding: 5px 10px;
  font-size: 12.5px;
}

.hud__foot .spacer {
  flex: 1;
}

.hud__notice {
  margin: 0 12px 8px;
  padding: 10px 12px;
  font-size: 12px;
  line-height: 1.45;
  color: var(--ink);
  background: var(--surface-2);
  border-radius: var(--r-control);
  flex: none;
}

.hud__notice .btn {
  margin-top: 6px;
}

/* ══ Shell — main window ════════════════════════════════════════════ */

.shell {
  display: grid;
  grid-template-columns: 232px 1fr;
  height: 100%;
  background: var(--bg);
}

.side {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 52px 12px 16px;
}

.side__mark {
  font-family: var(--font-display);
  font-size: 21px;
  font-weight: 600;
  letter-spacing: -0.01em;
  padding: 0 10px 18px;
}

.side__item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: var(--r-control);
  font-size: 14px;
  font-weight: 500;
  color: var(--ink-2);
  transition: background var(--t-fast), color var(--t-fast);
}

.side__item:hover {
  color: var(--ink);
  /* Mixed toward the page, not toward `transparent` — `transparent` is
     rgba(0,0,0,0), so mixing with it in sRGB drags the colour to black and the
     hover pill comes out darker than the active one. */
  background: color-mix(in srgb, var(--surface-2) 60%, var(--bg));
}

.side__item--on,
.side__item--on:hover {
  background: var(--surface-2);
  color: var(--ink);
  font-weight: 600;
}

.side__foot {
  margin-top: auto;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.side__foot .kbd {
  margin-left: auto;
  font-size: 11px;
  color: var(--ink-3);
}

/* The floating white sheet each page lives on. The sidebar sits directly on
   the cream ground; this is what separates the two. */
.page {
  overflow-y: auto;
  padding: 44px 28px 28px;
  display: flex;
  flex-direction: column;
  gap: 20px;
  position: relative;
  margin: 10px 10px 10px 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-sheet);
}

.page__head {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  flex: none;
}

.page__title {
  font-family: var(--font-display);
  font-size: 34px;
  font-weight: 560;
  letter-spacing: -0.01em;
  margin-right: auto;
}

.page__crumb {
  font-family: var(--font-display);
  font-size: 34px;
  font-weight: 560;
  letter-spacing: -0.01em;
  color: var(--ink-3);
}

.page__crumb:hover {
  color: var(--ink-2);
}

.pageerror {
  align-items: center;
  justify-content: center;
}

.pageerror__body {
  max-width: 440px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
}

.pageerror__body strong {
  font-family: var(--font-display);
  font-size: 25px;
  font-weight: 560;
}

.pageerror__body p {
  color: var(--ink-2);
  line-height: 1.5;
  user-select: text;
}

.search {
  padding: 7px 12px;
  font: inherit;
  font-size: 13px;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-pill);
  width: 180px;
}

.search:focus-visible {
  outline: none;
  border-color: var(--accent);
}

/* ── Folder cards row ── */

.folders {
  display: flex;
  gap: 12px;
  overflow-x: auto;
  padding-bottom: 4px;
  /* Never shrink: `.page` is a column flex container, so without this a tall
     shot grid squeezes the folder row down to a sliver of its 120px. */
  flex: none;
}

.foldercard {
  width: 168px;
  height: 120px;
  flex: none;
  display: flex;
  flex-direction: column;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--r-card);
  overflow: hidden;
  text-align: left;
  transition: border-color var(--t-fast), background var(--t-fast);
}

.foldercard:hover {
  border-color: var(--ink-3);
}

.foldercard__cover {
  flex: 1;
  position: relative;
  background: var(--surface-2);
  display: grid;
  place-items: center;
  color: var(--ink-3);
  overflow: hidden;
}

.foldercard__cover--teal  { background: var(--tint-teal);  color: var(--tint-teal-ink); }
.foldercard__cover--amber { background: var(--tint-amber); color: var(--tint-amber-ink); }
.foldercard__cover--lilac { background: var(--tint-lilac); color: var(--tint-lilac-ink); }
.foldercard__cover--rose  { background: var(--tint-rose);  color: var(--tint-rose-ink); }
.foldercard__cover--slate { background: var(--tint-slate); color: var(--tint-slate-ink); }

.foldercard__meta {
  padding: 8px 12px 10px;
  border-top: 1px solid var(--border);
  flex: none;
}

.foldercard__name {
  display: block;
  font-size: 14px;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.foldercard__count {
  display: block;
  font-size: 12px;
  color: var(--ink-3);
}

.foldercard--new {
  border-style: dashed;
  align-items: center;
  justify-content: center;
  gap: 6px;
  color: var(--ink-2);
  font-size: 13px;
  font-weight: 500;
}

.foldercard--new:hover {
  color: var(--ink);
}

/* The one-tap "file new captures here" pin, tucked in the cover corner. Shows
   on hover, or stays lit on the folder that's currently the default. */
.foldercard__pin {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 24px;
  height: 24px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  color: var(--ink-2);
  background: color-mix(in srgb, var(--surface) 78%, transparent);
  backdrop-filter: blur(2px);
  opacity: 0;
  cursor: pointer;
  transition: opacity var(--t-fast), color var(--t-fast), background var(--t-fast);
}

.foldercard:hover .foldercard__pin,
.foldercard__pin:focus-visible {
  opacity: 1;
}

.foldercard__pin:hover {
  color: var(--ink);
}

.foldercard__pin--on {
  opacity: 1;
  color: var(--accent);
  background: var(--card);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.14);
}

/* Header control: where new captures file themselves, set from the Library. */
.savepill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  font-size: 13px;
  color: var(--ink-2);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-pill);
  transition: border-color var(--t-fast), color var(--t-fast);
}

.savepill:hover {
  border-color: var(--ink-3);
  color: var(--ink);
}

.savepill__pin {
  display: inline-flex;
  color: var(--accent);
}

.savepill__label {
  color: var(--ink-3);
}

.savepill__folder {
  font-weight: 560;
  color: var(--ink);
}

.savepill__caret {
  font-size: 11px;
  color: var(--ink-3);
}

/* ── Day groups ── */

.daygroup {
  display: flex;
  flex-direction: column;
  gap: 12px;
  flex: none;
}

.daygroup__head {
  display: flex;
  align-items: baseline;
  gap: 10px;
  position: sticky;
  /* -1px, not 0: at fractional scroll positions a top:0 sticky header can let a
     hairline of the row beneath bleed above it. */
  top: -1px;
  z-index: 4;
  /* Full-bleed past the page's 28px gutters, so cards scrolling underneath are
     covered edge to edge rather than peeking out beside the heading. */
  margin: 0 -28px;
  padding: 12px 28px 10px;
  background: var(--surface);
}

.daygroup__title {
  font-size: 15px;
  font-weight: 650;
}

.daygroup__count {
  font-size: 12px;
  color: var(--ink-3);
  margin-right: auto;
}

.daygroup__all {
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-3);
  padding: 3px 8px;
  border-radius: var(--r-pill);
  opacity: 0;
  transition: opacity var(--t-fast), background var(--t-fast), color var(--t-fast);
}

.daygroup:hover .daygroup__all {
  opacity: 1;
}

.daygroup__all:hover {
  background: var(--surface-2);
  color: var(--ink);
}

/* ── Shot grid ── */

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 18px;
  align-content: start;
}

.daygroup:last-of-type {
  padding-bottom: 90px;
}

/* ── Day cover cards ── */

.daycards {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(184px, 1fr));
  gap: 16px;
  align-content: start;
  padding-bottom: 90px;
}

.daycard {
  height: 152px;
  display: flex;
  flex-direction: column;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--r-card);
  overflow: hidden;
  text-align: left;
  transition: border-color var(--t-fast), transform var(--t-fast), box-shadow var(--t-fast);
}

.daycard:hover {
  border-color: var(--ink-3);
  transform: translateY(-2px);
  box-shadow: var(--shadow-pop);
}

.daycard__cover {
  flex: 1;
  position: relative;
  display: grid;
  place-items: center;
  background: var(--surface-2);
  color: var(--ink-3);
  overflow: hidden;
}

.daycard__meta {
  padding: 9px 13px 11px;
  border-top: 1px solid var(--border);
  flex: none;
}

.daycard__name {
  display: block;
  font-size: 14px;
  font-weight: 650;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.daycard__count {
  display: block;
  font-size: 12px;
  color: var(--ink-3);
}

/* ── Day pop-up ── */

.daymodal {
  position: fixed;
  inset: 0;
  z-index: 30;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 40px;
  background: rgba(0, 0, 0, 0.4);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  animation: pop-in 160ms var(--ease);
}

/* The selection bar floats over this pop-up rather than under it, so the panel
   gives up the room instead of hiding Copy and Delete behind itself. */
.daymodal--selecting {
  padding-bottom: 104px;
}

.daymodal__panel {
  width: min(1040px, 100%);
  max-height: 100%;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-card);
  box-shadow: var(--shadow-pop);
  overflow: hidden;
}

.daymodal__head {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 16px 20px;
  border-bottom: 1px solid var(--border);
  flex: none;
}

.daymodal__title {
  font-size: 17px;
  font-weight: 680;
}

.daymodal__count {
  font-size: 13px;
  color: var(--ink-3);
  margin-right: auto;
}

.daymodal__all {
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-3);
  padding: 4px 10px;
  border-radius: var(--r-pill);
  transition: background var(--t-fast), color var(--t-fast);
}

.daymodal__all:hover {
  background: var(--surface-2);
  color: var(--ink);
}

.daymodal__body {
  padding: 22px;
  overflow-y: auto;
}

.card {
  position: relative;
  text-align: left;
}

.card__imgwrap {
  position: relative;
  aspect-ratio: 4 / 3;
  border-radius: var(--r-control);
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--border);
  transition: box-shadow var(--t-fast);
}

.card--on .card__imgwrap {
  box-shadow: 0 0 0 2.5px var(--accent);
}

.card__imgwrap img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  pointer-events: none;
}

.card .check {
  position: absolute;
  top: 8px;
  left: 8px;
  z-index: 2;
}

.card__acts {
  position: absolute;
  right: 6px;
  bottom: 6px;
  z-index: 2;
  display: none;
  gap: 4px;
  padding: 3px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-control);
  box-shadow: var(--shadow-pop);
}

.card__notes {
  position: absolute;
  top: 7px;
  right: 7px;
  z-index: 2;
  min-width: 22px;
  height: 22px;
  padding: 0 7px;
  display: grid;
  place-items: center;
  border-radius: var(--r-pill);
  color: #fff;
  background: var(--accent);
  border: 2px solid var(--surface);
  font-size: 11px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.card:hover .card__acts {
  display: inline-flex;
}

.card__meta {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 2px 0;
}

.card__time {
  font-size: 13px;
  color: var(--ink-2);
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Floating selection bar.

   It has to survive the narrowest window the app allows. Wrapping is what makes
   that safe: the bar grows a second row instead of running past the right edge,
   which is where Delete used to end up — present, but unreachable. The pill
   corners follow, so a two-row bar still reads as one object. */
.selbar {
  position: fixed;
  bottom: 22px;
  left: calc(232px + (100vw - 232px) / 2);
  transform: translateX(-50%);
  /* Above the day pop-up (30), below the lightbox (40). Selecting inside the
     pop-up used to put Copy, Move and Delete behind its backdrop: on screen,
     un-clickable, and only reachable by closing the thing you were selecting in.
     The lightbox stays on top — it owns the screen while it is open. */
  z-index: 35;
  display: flex;
  flex-wrap: nowrap;
  justify-content: center;
  align-items: center;
  gap: 6px;
  padding: 8px 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 22px;
  box-shadow: var(--shadow-pop);
  animation: pop-in 200ms var(--ease);
  max-width: calc(100vw - 232px - 40px);
}

/* One row, always. The bar wrapping to a second line looked like a mistake and
   moved Delete somewhere different depending on the window width; the actions
   are short enough now — and the drag hint drops out first — that they fit. */
.selbar > * {
  flex: 0 0 auto;
  white-space: nowrap;
}

.selbar__count {
  font-size: 13px;
  font-weight: 600;
  padding: 0 6px;
  white-space: nowrap;
}

/* ── Lightbox preview ── */

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 40;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 16px;
  padding: 44px 40px 24px;
  background: rgba(0, 0, 0, 0.45);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  animation: pop-in 160ms var(--ease);
}

.lightbox__img {
  max-width: 100%;
  max-height: calc(100% - 64px);
  border-radius: 12px;
  box-shadow: var(--shadow-pop);
  background: var(--surface);
}

.lightbox__img--blank {
  width: 320px;
  height: 220px;
}

.lightbox__bar {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-pill);
  box-shadow: var(--shadow-pop);
  max-width: 100%;
}

/* ══ Batch markup ═══════════════════════════════════════════════════
   The editor stays inside the normal app shell. Comments are entered on the
   screenshot itself and the filmstrip preserves the eventual paste order. */

.markup {
  position: relative;
  min-width: 0;
  min-height: 0;
  margin: 10px 10px 10px 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-sheet);
}

.markup--empty {
  align-items: center;
  justify-content: center;
  gap: 14px;
  font-size: 14px;
  color: var(--ink-2);
}

.markup__top {
  min-height: 58px;
  padding: 8px 12px 8px 14px;
  display: flex;
  align-items: center;
  gap: 10px;
  border-bottom: 1px solid var(--border);
  flex: none;
}

.markup__heading {
  min-width: 116px;
  display: flex;
  flex-direction: column;
  gap: 1px;
}

.markup__heading strong {
  font-size: 13px;
  font-weight: 650;
}

.markup__heading span {
  font-size: 11px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}

.markup__tools {
  display: flex;
  align-items: center;
  gap: 3px;
  margin: 0 auto;
  padding: 3px;
  background: var(--surface-2);
  border-radius: var(--r-control);
}

.markup__tool {
  width: 30px;
  height: 30px;
  display: grid;
  place-items: center;
  border-radius: 8px;
  color: var(--ink-2);
  transition: color var(--t-fast), background var(--t-fast), box-shadow var(--t-fast);
}

.markup__tool:hover:not(:disabled) {
  color: var(--ink);
  background: color-mix(in srgb, var(--surface) 70%, transparent);
}

.markup__tool--on {
  color: var(--accent);
  background: var(--surface);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.1);
}

.markup__tool:disabled {
  opacity: 0.32;
}

.markup__tool--danger:hover:not(:disabled) {
  color: var(--danger);
  background: color-mix(in srgb, var(--danger) 12%, transparent);
}

.markup__divider {
  width: 1px;
  height: 20px;
  margin: 0 2px;
  background: var(--border);
}

.markup__colors {
  display: flex;
  align-items: center;
  gap: 5px;
}

.markup__actions {
  display: flex;
  align-items: center;
  gap: 6px;
}

.markup__color {
  width: 16px;
  height: 16px;
  border-radius: 50%;
  border: 1px solid rgba(0, 0, 0, 0.18);
  box-shadow: 0 0 0 1px var(--surface);
  transition: transform var(--t-fast), box-shadow var(--t-fast);
}

.markup__color:hover {
  transform: scale(1.14);
}

.markup__color--on {
  box-shadow: 0 0 0 2px var(--surface), 0 0 0 3px var(--ink-2);
}

.markup__body {
  min-height: 0;
  flex: 1;
  display: grid;
  grid-template-columns: 112px minmax(0, 1fr);
}

.markup__film {
  min-height: 0;
  overflow-y: auto;
  padding: 12px 10px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  background: color-mix(in srgb, var(--surface-2) 52%, var(--surface));
  border-right: 1px solid var(--border);
}

.markup__thumb {
  position: relative;
  width: 100%;
  padding: 5px;
  text-align: left;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 11px;
  transition: border-color var(--t-fast), box-shadow var(--t-fast), transform var(--t-fast);
}

.markup__thumb:hover {
  border-color: var(--ink-3);
  transform: translateY(-1px);
}

.markup__thumb--on {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent-soft);
}

.markup__thumb img,
.markup__thumb-blank {
  width: 100%;
  height: 58px;
  display: block;
  object-fit: cover;
  background: var(--surface-2);
  border-radius: 7px;
}

.markup__thumb-order {
  position: absolute;
  top: 9px;
  left: 9px;
  z-index: 1;
  width: 20px;
  height: 20px;
  display: grid;
  place-items: center;
  color: #fff;
  background: rgba(20, 20, 18, 0.78);
  border-radius: 50%;
  font-size: 10px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.markup__thumb-count {
  display: block;
  padding: 5px 2px 1px;
  color: var(--ink-3);
  font-size: 10px;
  font-weight: 600;
}

.markup__thumb--on .markup__thumb-count {
  color: var(--accent);
}

.markup__stage {
  position: relative;
  min-width: 0;
  min-height: 0;
  padding: 42px 18px 14px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  overflow: hidden;
  background: #232321;
}

.markup__stage-nav {
  position: absolute;
  top: 8px;
  left: 50%;
  transform: translateX(-50%);
  z-index: 2;
  height: 28px;
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 2px 5px;
  color: #eceae5;
  background: rgba(0, 0, 0, 0.48);
  border-radius: var(--r-pill);
}

.markup__stage-nav span {
  min-width: 86px;
  text-align: center;
  font-size: 11px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.markup__stage-nav .iconbtn {
  color: #eceae5;
}

.markup__imagebox {
  flex: 1;
  min-width: 0;
  min-height: 0;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.markup__imagewrap {
  position: relative;
  display: inline-block;
  max-width: 100%;
  max-height: 100%;
  box-shadow: 0 14px 44px rgba(0, 0, 0, 0.36), 0 2px 8px rgba(0, 0, 0, 0.3);
  line-height: 0;
}

.markup__image {
  display: block;
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: calc(100vh - 150px);
  user-select: none;
}

.markup__overlay {
  position: absolute;
  inset: 0;
  touch-action: none;
  cursor: crosshair;
}

.markup__inline {
  --mark-color: var(--accent);
  position: absolute;
  z-index: 3;
  display: flex;
  align-items: flex-start;
  max-width: 45%;
  line-height: normal;
  cursor: text;
  user-select: text;
}

.markup__inline--comment {
  width: min(280px, 42%);
  gap: 7px;
  padding: 6px 8px 6px 6px;
  background: rgba(250, 249, 246, 0.96);
  border: 1px solid color-mix(in srgb, var(--mark-color) 72%, #fff);
  border-radius: 10px;
  box-shadow: 0 4px 18px rgba(0, 0, 0, 0.28);
}

.markup__inline--on {
  box-shadow: 0 0 0 2px var(--mark-color), 0 5px 20px rgba(0, 0, 0, 0.32);
}

.markup__inline-number {
  flex: none;
  width: 22px;
  height: 22px;
  display: grid;
  place-items: center;
  color: #fff;
  background: var(--mark-color);
  border-radius: 50%;
  font-size: 11px;
  font-weight: 750;
  font-variant-numeric: tabular-nums;
  cursor: grab;
}

.markup__inline-number:active,
.markup__inline-grip:active {
  cursor: grabbing;
}

.markup__inline-grip {
  flex: none;
  width: 22px;
  height: 30px;
  display: grid;
  place-items: center;
  color: rgba(255, 255, 255, 0.76);
  background: rgba(20, 20, 18, 0.72);
  border-radius: 6px 0 0 6px;
  cursor: grab;
}

.markup__inline textarea {
  min-width: 0;
  width: 100%;
  min-height: 22px;
  max-height: 88px;
  padding: 1px 0;
  resize: none;
  overflow-y: auto;
  color: #1a1a18;
  background: transparent;
  border: 0;
  outline: 0;
  font: inherit;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.45;
}

.markup__inline textarea::placeholder {
  color: #77746c;
}

.markup__inline--text {
  width: min(280px, 45%);
}

.markup__inline--text textarea {
  min-height: 30px;
  padding: 4px 7px;
  color: var(--mark-color);
  background: rgba(20, 20, 18, 0.72);
  border-radius: 0 6px 6px 0;
  font-size: 15px;
  font-weight: 750;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.7);
}

.markup__inline--text textarea::placeholder {
  color: rgba(255, 255, 255, 0.68);
}

.markup__imagebox--select .markup__overlay {
  cursor: default;
}

.markup__svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}

.markup__shape,
.markup__marker {
  pointer-events: all;
  cursor: pointer;
}

.markup__shape--on {
  filter: drop-shadow(0 0 2px rgba(255, 255, 255, 0.95));
}

.markup__resize {
  position: absolute;
  width: 13px;
  height: 13px;
  transform: translate(-50%, -50%);
  border: 2px solid #fff;
  border-radius: 4px;
  background: var(--accent);
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.45);
  cursor: nwse-resize;
}

.markup__loading {
  color: rgba(255, 255, 255, 0.65);
  font-size: 13px;
}

.markup__hint {
  flex: none;
  min-height: 17px;
  color: rgba(255, 255, 255, 0.58);
  font-size: 11px;
  text-align: center;
}

.markup__notice {
  position: absolute;
  right: 14px;
  bottom: 38px;
  z-index: 5;
  max-width: 320px;
  padding: 9px 11px;
  color: var(--accent);
  background: color-mix(in srgb, var(--accent-soft) 94%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--accent) 28%, transparent);
  border-radius: 9px;
  box-shadow: 0 6px 22px rgba(0, 0, 0, 0.24);
  font-size: 11px;
  line-height: 1.4;
  cursor: pointer;
}

@media (max-width: 980px) {
  .markup__body {
    grid-template-columns: 90px minmax(0, 1fr);
  }
  .markup__heading {
    min-width: 94px;
  }
  .markup__colors {
    display: none;
  }
  .markup__thumb img,
  .markup__thumb-blank {
    height: 48px;
  }
}

.lightbox__bar .iconbtn:disabled {
  opacity: 0.35;
  pointer-events: none;
}

.lightbox__counter {
  font-size: 12px;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.lightbox__meta {
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 0 12px;
  min-width: 0;
}

.lightbox__time {
  font-size: 13px;
  font-weight: 600;
  white-space: nowrap;
}

.lightbox__status {
  font-size: 12px;
  color: var(--ink-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Empty state. */
.empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 60px 20px;
  color: var(--ink-2);
  text-align: center;
}

.empty__title {
  font-size: 15px;
  font-weight: 600;
  color: var(--ink);
}

/* ══ Insights ═══════════════════════════════════════════════════════ */

.statrow {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(168px, 1fr));
  gap: 14px;
}

/* The one footnote a stat card is allowed. */
.statnote {
  font-size: 12px;
  color: var(--ink-3);
  margin-top: -12px;
}

.pipeline__line {
  font-size: 14px;
  color: var(--ink);
}

.pipeline__line--muted {
  color: var(--ink-2);
}

/* Right now — two neutral tiles plus a clocked cleanup line. */
.rightnow__tiles {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}

.minitile--neutral {
  background: var(--well);
}

.minitile--neutral .minitile__num {
  color: var(--ink);
}

/* Pinned to the bottom of the card. "Right now" holds less than the card beside
   it, and in a stretched row the difference used to read as a hole under the
   tiles rather than as breathing room. */
.rightnow__when {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: auto;
  font-size: 13px;
  color: var(--ink-2);
}

.insight-row2 {
  display: grid;
  grid-template-columns: 1.2fr 1fr;
  gap: 14px;
}

.widecard {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--r-card);
  padding: 18px 20px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-width: 0;
}

.widecard__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}

.widecard__title {
  font-family: var(--font-display);
  font-size: 21px;
  font-weight: 560;
}

/* The one colored card on the page — the payoff story. */
.widecard--teal {
  background: var(--tint-teal);
  border-color: transparent;
}

.widecard--teal .widecard__head {
  color: var(--tint-teal-ink);
}

.timesaved__num {
  font-family: var(--font-display);
  font-size: 34px;
  font-weight: 580;
  line-height: 1.1;
  color: var(--tint-teal-ink);
}

/* The total says what the app has done; the rate says whether it is worth
   keeping. Set quietly under the number — it is the sentence you repeat to
   someone else, not the headline. */
.timesaved__rate {
  margin: 2px 0 0;
  font-size: 12px;
  line-height: 1.45;
  color: color-mix(in srgb, var(--tint-teal-ink) 72%, transparent);
}

/* The split is a shape, not five more numbers. One bar and a legend say what
   five stat tiles inside a stat card were saying at five times the height. */
.timesaved__bar {
  display: flex;
  height: 10px;
  border-radius: 5px;
  overflow: hidden;
  background: color-mix(in srgb, var(--tint-teal-ink) 8%, transparent);
}

.timesaved__seg {
  height: 100%;
  background: var(--tint-teal-ink);
  /* A slice worth 15s of 24 min is a hairline. Still draw it — a segment in the
     legend that isn't in the bar reads as a bug. */
  min-width: 2px;
}

/* One hue, stepped down — the parts of a single total, not five categories. */
.timesaved__seg--auto { opacity: 0.7; }
.timesaved__seg--hand { opacity: 0.55; }
.timesaved__seg--stack { opacity: 0.4; }
.timesaved__seg--import { opacity: 0.26; }

.timesaved__legend {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 16px;
  font-size: 12.5px;
  color: var(--ink-2);
}

.timesaved__key {
  display: inline-flex;
  align-items: center;
  gap: 6px;
}

.timesaved__key b {
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}

.timesaved__dot {
  width: 8px;
  height: 8px;
  flex: none;
  border-radius: 50%;
  background: var(--tint-teal-ink);
}

/* Held higher than the bar segments: an 8px dot at 0.22 disappears entirely,
   and the legend is the part that has to stay readable. */
.timesaved__dot--auto { opacity: 0.78; }
.timesaved__dot--hand { opacity: 0.66; }
.timesaved__dot--stack { opacity: 0.54; }
.timesaved__dot--import { opacity: 0.42; }

/* The working, folded away behind the eye. Every rate is still here — it just
   isn't standing in front of the answer. */
.timesaved__working {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding-top: 12px;
  border-top: 1px solid color-mix(in srgb, var(--tint-teal-ink) 14%, transparent);
  font-size: 12px;
  line-height: 1.45;
}

.timesaved__working dt {
  font-weight: 600;
  color: var(--ink);
}

.timesaved__working dd {
  color: var(--ink-2);
}

.minitile {
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding: 10px 12px;
  border-radius: var(--r-card);
  background: color-mix(in srgb, var(--tint-teal-ink) 8%, transparent);
}

.minitile__num {
  font-family: var(--font-display);
  font-size: 22px;
  font-weight: 580;
  font-variant-numeric: tabular-nums;
  line-height: 1.15;
  color: var(--tint-teal-ink);
}

.minitile__label {
  font-size: 12.5px;
  font-weight: 560;
  color: var(--ink);
}

.minitile__sub {
  font-size: 11.5px;
  color: var(--ink-2);
}

.hbar {
  display: flex;
  align-items: center;
  gap: 10px;
}

.hbar__label {
  width: 168px;
  flex: none;
  font-size: 13px;
  color: var(--ink-2);
  line-height: 1.3;
}

.hbar__track {
  flex: 1;
  height: 22px;
  border-radius: 6px;
  background: var(--well);
  overflow: hidden;
  position: relative;
}

.hbar__fill {
  height: 100%;
  border-radius: 6px;
  background: var(--accent);
  display: flex;
  align-items: center;
  min-width: 0;
  transition: width var(--t-hud);
}

.hbar__pct {
  padding-left: 8px;
  font-size: 11px;
  font-weight: 600;
  color: var(--accent-ink);
  white-space: nowrap;
}

.hbar__count {
  width: 44px;
  flex: none;
  text-align: right;
  font-size: 13px;
  color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}

/* Streak heatmap. */
.heatmap {
  display: flex;
  flex-direction: column;
  gap: 4px;
  overflow-x: auto;
}

.heatmap__months {
  display: flex;
  font-size: 11px;
  color: var(--ink-3);
  padding-left: 0;
}

.heatmap__grid {
  display: grid;
  grid-auto-flow: column;
  grid-template-rows: repeat(7, 12px);
  gap: 3px;
}

.heatcell {
  width: 12px;
  height: 12px;
  border-radius: 3px;
  background: var(--well);
  padding: 0;
}

.heatcell--1 {
  background: var(--accent-soft);
}

.heatcell--2 {
  background: color-mix(in srgb, var(--accent) 45%, var(--accent-soft));
}

.heatcell--3 {
  background: color-mix(in srgb, var(--accent) 75%, var(--accent-soft));
}

.heatcell--4 {
  background: var(--accent);
}

/* ══ Calendar ═══════════════════════════════════════════════════════ */

.cal {
  display: flex;
  flex-direction: column;
  gap: 10px;
  flex: 1;
}

.cal__nav {
  display: flex;
  align-items: center;
  gap: 8px;
}

.cal__month {
  font-family: var(--font-display);
  font-size: 21px;
  font-weight: 560;
  min-width: 150px;
}

.cal__dow {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 8px;
}

.cal__dow span {
  font-size: 11px;
  font-weight: 600;
  color: var(--ink-3);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  padding: 0 4px;
}

.cal__grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 8px;
}

.daycell {
  min-height: 96px;
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--r-control);
  padding: 8px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  align-items: flex-start;
  text-align: left;
  transition: border-color var(--t-fast);
}

.daycell:hover {
  border-color: var(--ink-3);
}

.daycell--out {
  opacity: 0.4;
}

/* Selected by drag or shift-click, for a bulk action across days. */
.daycell--on {
  background: var(--accent-soft);
  border-color: var(--accent);
}

/* The single day whose drawer is open. */
.daycell--open {
  border-color: var(--ink-3);
}

/* A drag across the grid shouldn't paint the OS text selection over it. */
.cal__grid {
  user-select: none;
}

.daycell--today .daycell__num {
  background: var(--accent);
  color: var(--accent-ink);
}

.daycell__num {
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-2);
  width: 22px;
  height: 22px;
  display: grid;
  place-items: center;
  border-radius: 50%;
}

.daycell__more {
  font-size: 11px;
  color: var(--ink-3);
  font-weight: 600;
}

/* Day drawer. */
.drawer {
  /* Pinned to the sheet, not the scrolling page content. `.page` is the scroll
     container, so an absolutely-positioned drawer scrolled with the calendar:
     scroll down to a lower week, open a day, and the drawer's bottom lifted away
     from the sheet floor, leaving a gap where the grid showed through. Fixed to
     the viewport keeps it flush with the sheet. The 11px insets track `.page`'s
     10px margin + 1px border so it sits just inside the sheet edge. */
  position: fixed;
  top: 11px;
  right: 11px;
  bottom: 11px;
  width: 360px;
  z-index: 15;
  background: var(--surface);
  border-left: 1px solid var(--border);
  /* Hug the sheet's rounded right edge instead of poking square corners out. */
  border-radius: 0 var(--r-sheet) var(--r-sheet) 0;
  display: flex;
  flex-direction: column;
  animation: drawer-in 260ms var(--ease);
}

@keyframes drawer-in {
  from {
    transform: translateX(24px);
    opacity: 0;
  }
}

.drawer__head {
  padding: 18px 16px 10px;
  display: flex;
  align-items: flex-start;
  gap: 10px;
}

.drawer__title {
  font-size: 17px;
  font-weight: 650;
  flex: 1;
}

.drawer__sub {
  font-size: 12px;
  color: var(--ink-2);
  margin-top: 2px;
}

.drawer__rows {
  flex: 1;
  overflow-y: auto;
  padding: 0 8px;
}

.drawer__foot {
  display: flex;
  align-items: center;
  gap: 6px;
  flex-wrap: wrap;
  padding: 10px 12px;
  border-top: 1px solid var(--border);
}

/* ══ Settings page ══════════════════════════════════════════════════ */

.setgroup {
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--r-card);
  padding: 6px 18px;
  max-width: 640px;
}

.setgroup__title {
  font-size: 15px;
  font-weight: 650;
  padding: 14px 0 6px;
}

.setrow {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 12px 0;
  border-top: 1px solid var(--border);
}

.setrow:first-of-type {
  border-top: none;
}

.setrow__label {
  flex: 1;
  min-width: 0;
}

.setrow__name {
  display: block;
  font-size: 14px;
  font-weight: 500;
}

.setrow__hint {
  display: block;
  font-size: 12px;
  color: var(--ink-2);
  margin-top: 2px;
  line-height: 1.45;
}

.setrow__path {
  display: block;
  font-size: 12px;
  color: var(--ink-2);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  /* Truncates from the *left*, so a deep path keeps its filename visible. Only
     ever put a path in here — it reverses the reading order of anything else. */
  direction: rtl;
  text-align: left;
  max-width: 260px;
}

/* A read-only value on the right of a settings row (a shortcut, a version). */
.setrow__value {
  font-size: 13px;
  color: var(--ink-2);
  white-space: nowrap;
}

/* An editable accelerator on the right of a settings row. Monospaced and
   right-aligned so the five of them read as a column of combos rather than a
   column of text fields. */
.input--accel {
  width: 168px;
  padding: 6px 10px;
  font: inherit;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px;
  text-align: right;
  color: var(--ink);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
}

.input--accel:focus-visible {
  outline: none;
  border-color: var(--accent);
}

/* Radio list (expiry policy). */
.radio {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  width: 100%;
  text-align: left;
  padding: 10px 10px;
  border-radius: var(--r-control);
  transition: background var(--t-fast);
}

.radio:hover {
  background: var(--surface-2);
}

.radio__dot {
  width: 16px;
  height: 16px;
  margin-top: 1px;
  flex: none;
  border-radius: 50%;
  border: 1.5px solid var(--ink-3);
  display: grid;
  place-items: center;
}

.radio--on .radio__dot {
  border-color: var(--accent);
}

.radio--on .radio__dot::after {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent);
}

.radio__name {
  display: block;
  font-size: 14px;
  font-weight: 500;
}

.radio__hint {
  display: block;
  font-size: 12px;
  color: var(--ink-2);
  margin-top: 1px;
}

/* Window drag strip for the overlay title bar. */
.drag {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 34px;
  z-index: 5;
}

/* ══ Canvas — the free-form board ═══════════════════════════════════ */

.canvaspage {
  /* The board owns its own scrolling; the page mustn't add a second one. */
  overflow: hidden;
  /* The canvas is the one page whose content wants every pixel — a board you
     arrange things on is only as good as the room it gives you. So the sheet's
     usual generous padding is pulled in, and the gap under the header with it. */
  padding: 40px 14px 14px;
  gap: 12px;
}

.canvaspage .page__title {
  font-size: 28px;
}

.canvas__hint {
  font-size: 12.5px;
  color: var(--ink-3);
  margin-right: auto;
}

/* ── Canvas overview: groupings live on the pan/zoom board ── */

/* The stage holds the scrollable canvas plus the controls that float over it. */
.canvasstage {
  position: relative;
  flex: 1;
  min-height: 0;
  display: flex;
  gap: 12px;
  /* The floating tool bars answer to the canvas's width, not the window's —
     the sidebar and the inspector both take from it. */
  container-type: inline-size;
  container-name: stage;
}

/* Opening a group onto its own board settles in from a hair smaller and lower,
   so the click reads as the board rising up out of the grouping. */
.canvasstage--enter {
  animation: canvas-open 260ms cubic-bezier(0.22, 1, 0.36, 1);
}

@keyframes canvas-open {
  from {
    opacity: 0;
    transform: translateY(8px) scale(0.985);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

/* Base-sized layer the scale transform is applied to, so every grouping —
   decks, labels, buttons — zooms as one board. */
.canvasgrid {
  position: relative;
  transform-origin: 0 0;
}

/* A group is not a card — no box, no border, no tint. Just the deck of
   screenshots and its label, so the eye reads the pictures, not the chrome.
   Placed absolutely on the board so it pans and zooms with everything else. */
.cgroup {
  position: absolute;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
  padding: 12px 8px 8px;
  border-radius: var(--r-card);
  transition: background var(--t-fast);
}

.cgroup:hover {
  background: var(--surface-2);
}

.cgroup__open {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  width: 100%;
}

.cgroup__deck {
  height: 128px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform var(--t-fast);
}

.cgroup:hover .cgroup__deck {
  transform: translateY(-2px);
}

.cgroup__meta {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  max-width: 100%;
  text-align: center;
}

.cgroup__name {
  max-width: 100%;
  font-size: 14px;
  font-weight: 560;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cgroup__count {
  font-size: 12px;
  color: var(--ink-3);
}

/* Bulk actions stay out of the way until you reach for the group. */
.cgroup__actions {
  display: flex;
  gap: 6px;
  opacity: 0;
  transition: opacity var(--t-fast);
}

.cgroup:hover .cgroup__actions,
.cgroup:focus-within .cgroup__actions {
  opacity: 1;
}

.cgroup__act {
  padding: 4px 11px;
  font-size: 12px;
  font-weight: 520;
  color: var(--ink-2);
  background: var(--card);
  border: 1px solid var(--border);
  border-radius: var(--r-pill);
  transition: background var(--t-fast), color var(--t-fast), border-color var(--t-fast);
}

.cgroup__act:hover:not(:disabled) {
  color: var(--ink);
  border-color: var(--ink-3);
}

.cgroup__act:disabled {
  opacity: 0.5;
  cursor: default;
}

.cgroup__act--danger,
.cgroup__act--danger:hover:not(:disabled) {
  color: var(--danger, #d1495b);
  border-color: color-mix(in srgb, var(--danger, #d1495b) 45%, transparent);
  background: color-mix(in srgb, var(--danger, #d1495b) 12%, transparent);
}

/* ── Overview: group-by dimension switch (on the board, not the header) ── */

.canvastools {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: none;
}

.canvasdim {
  padding: 4px 12px;
  font-size: 12.5px;
  font-weight: 520;
  color: var(--ink-3);
  border-radius: var(--r-pill);
  transition: background var(--t-fast), color var(--t-fast);
}

.canvasdim:hover {
  color: var(--ink);
}

.canvasdim--on {
  background: var(--card);
  color: var(--ink);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
}

/* Floats over the top-left of the canvas rather than sitting in page flow. */
.canvastools--float {
  position: absolute;
  top: 14px;
  left: 14px;
  z-index: 5;
  padding: 6px 12px;
  background: color-mix(in srgb, var(--surface) 84%, transparent);
  backdrop-filter: blur(8px);
  border: 1px solid var(--border);
  border-radius: var(--r-pill);
  box-shadow: var(--shadow-pop);
}

/* ── Zoom control ── */

.canvaszoom {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 2px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r-pill);
}

.canvaszoom .iconbtn {
  font-size: 17px;
  line-height: 1;
}

.canvaszoom__pct {
  min-width: 44px;
  font-size: 12px;
  font-variant-numeric: tabular-nums;
  color: var(--ink-2);
  text-align: center;
}

.canvaszoom__pct:hover {
  color: var(--ink);
}

/* Floats over the bottom-right of the canvas. */
.canvaszoom--float {
  position: absolute;
  right: 14px;
  bottom: 14px;
  z-index: 5;
  background: color-mix(in srgb, var(--surface) 84%, transparent);
  backdrop-filter: blur(8px);
  box-shadow: var(--shadow-pop);
}

.canvas {
  position: relative;
  flex: 1;
  min-height: 0;
  overflow: auto;
  border: 1px solid var(--border);
  border-radius: var(--r-card);
  background: var(--bg);
  /* A faint dot grid, so the surface reads as a place to arrange things. */
  background-image: radial-gradient(
    var(--border) 1px,
    transparent 1px
  );
  background-size: 22px 22px;
  background-position: 14px 14px;
  touch-action: none;
}

/* The overview panning surface: an inner layer is translated/scaled, so the
   canvas itself never native-scrolls — it owns wheel + drag for pan and zoom. */
.canvas--pan {
  overflow: hidden;
  cursor: grab;
}

.canvas--panning {
  cursor: grabbing;
}

.canvas__surface {
  position: relative;
  /* Room to spread out; the board scrolls past the viewport. */
  width: 2600px;
  height: 1700px;
}

.snap {
  position: absolute;
  border-radius: var(--r-control);
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-pop);
  /* The knot and a stack's count badge hang off the edge; the image is
     clipped by .snap__face instead, so nothing here needs to clip. */
  overflow: visible;
  cursor: grab;
  transition: box-shadow var(--t-fast), transform var(--t-fast);
}

.snap:active {
  cursor: grabbing;
}

.snap--on {
  box-shadow: 0 0 0 2.5px var(--accent), var(--shadow-pop);
}

.snap__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  pointer-events: none;
  -webkit-user-select: none;
  user-select: none;
}

.snap__check {
  position: absolute;
  top: 7px;
  left: 7px;
  z-index: 2;
  opacity: 0;
  transition: opacity var(--t-fast);
}

.snap:hover .snap__check,
.snap--on .snap__check {
  opacity: 1;
}

.snap__grip {
  position: absolute;
  top: 6px;
  right: 6px;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: var(--r-control);
  color: var(--ink-2);
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-pop);
  cursor: grab;
  opacity: 0;
  transition: opacity var(--t-fast), color var(--t-fast);
}

.snap:hover .snap__grip {
  opacity: 1;
}

.snap__grip:hover {
  color: var(--accent);
}

.snap__grip:active {
  cursor: grabbing;
}

/* ── Stacks and strings ───────────────────────────────────────────────
   The board is a work surface, so nothing on it competes with the screenshots
   themselves. A stack is told apart by its depth, its count and its name — not
   by a colour — and a string is ink, because it belongs to neither end and has
   no business picking a side. Colour on this page means one thing only: the
   accent, on whatever the pointer is about to act on. */

.strings {
  position: absolute;
  top: 0;
  left: 0;
  overflow: visible;
  /* The layer is see-through to the pointer; only the strings' hit paths
     below opt back in, so the surface underneath still lassoes. */
  pointer-events: none;
}

.strings__line {
  fill: none;
  stroke: var(--ink-3);
  stroke-width: 1.5;
  stroke-linecap: round;
  transition: stroke var(--t-fast), stroke-width var(--t-fast);
}

/* The dot sits where the curve meets the card's edge, so the join reads as
   deliberate rather than as a line sliding under the artwork. */
.strings__end {
  fill: var(--surface);
  stroke: var(--ink-3);
  stroke-width: 1.5;
  transition: stroke var(--t-fast);
}

.strings__line--rubber {
  stroke: var(--accent);
  stroke-dasharray: 5 4;
}

.strings__line--catch {
  stroke-dasharray: none;
  stroke-width: 2;
}

/* A generous invisible stroke, so a 1.5px string is still an easy click. */
.strings__hit {
  fill: none;
  stroke: transparent;
  stroke-width: 20;
  pointer-events: stroke;
  cursor: pointer;
}

.strings__tie:hover .strings__line,
.strings__tie:hover .strings__end {
  stroke: var(--accent);
  stroke-width: 2;
}

.strings__cut {
  opacity: 0;
  pointer-events: none;
  cursor: pointer;
  transition: opacity var(--t-fast);
}

.strings__tie:hover .strings__cut {
  opacity: 1;
  pointer-events: auto;
}

.strings__cutdisc {
  fill: var(--surface);
  stroke: var(--border);
}

.strings__cutmark {
  stroke: var(--ink-2);
  stroke-width: 1.6;
  stroke-linecap: round;
}

.strings__cut:hover .strings__cutdisc {
  fill: var(--danger);
  stroke: var(--danger);
}

.strings__cut:hover .strings__cutmark {
  stroke: #fff;
}

/* ── Cards ─────────────────────────────────────────────────────────── */

/* The face carries the image and the card's own rounding, so the leaves of a
   stack can sit outside it without being clipped away. */
.snap__face {
  position: absolute;
  inset: 0;
  z-index: 1;
  border-radius: var(--r-control);
  overflow: hidden;
  background: var(--surface);
}

/* A stack shows its depth: two leaves of paper fanned behind the cover. */
.snap--stack {
  overflow: visible;
  background: transparent;
  border: 0;
  box-shadow: none;
}

.snap--stack .snap__face {
  border: 1px solid var(--border);
  box-shadow: var(--shadow-pop);
}

.snap__leaf {
  position: absolute;
  inset: 0;
  border-radius: var(--r-control);
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-pop);
}

.snap__leaf--mid {
  transform: translate(4px, 4px) rotate(1.1deg);
  z-index: 0;
}

.snap__leaf--back {
  transform: translate(8px, 8px) rotate(2.2deg);
  background: var(--surface-2);
  z-index: 0;
}

/* Borderless: the count is a quiet numeral on the paper, and an outline around
   it only adds a second edge next to the card's own. */
.snap__count {
  position: absolute;
  right: -6px;
  top: -6px;
  z-index: 3;
  min-width: 22px;
  height: 22px;
  padding: 0 6px;
  border-radius: 11px;
  background: var(--surface);
  color: var(--ink-2);
  font-size: 11.5px;
  font-weight: 600;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  box-shadow: var(--shadow-pop);
  cursor: pointer;
  transition: color var(--t-fast);
}

.snap__count:hover {
  color: var(--ink);
}

/* The stack's name sits under the card, where a label on a pile would be, and
   is the fastest place to change it — clicking it edits in place. */
.snap__label {
  position: absolute;
  top: calc(100% + 14px);
  left: 0;
  width: 100%;
  padding: 2px 4px;
  border-radius: 6px;
  text-align: center;
  font-size: 12px;
  font-weight: 550;
  color: var(--ink-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  cursor: text;
  transition: background var(--t-fast), color var(--t-fast);
}

.snap__label:hover {
  background: var(--surface-2);
  color: var(--ink);
}

/* An unnamed pile shows its capture time, which is a placeholder, not a name —
   so it reads lighter until it has one. */
.snap__label--unnamed {
  color: var(--ink-3);
  font-weight: 500;
}

.snap__rename {
  position: absolute;
  top: calc(100% + 14px);
  left: 0;
  padding: 2px 4px;
  border: 1px solid var(--accent);
  border-radius: 6px;
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 12px;
  font-weight: 550;
  text-align: center;
}

.snap__rename:focus {
  outline: none;
}

/* Ring rather than shadow, so a card that is both selected and a drop target
   can show both at once. */
.snap--catch {
  outline: 2.5px solid var(--accent);
  outline-offset: 4px;
  border-radius: var(--r-control);
}

.snap__knot {
  position: absolute;
  right: -7px;
  top: 50%;
  z-index: 3;
  width: 13px;
  height: 13px;
  margin-top: -6.5px;
  border-radius: 50%;
  background: var(--surface);
  border: 2px solid var(--ink-3);
  box-shadow: var(--shadow-pop);
  cursor: crosshair;
  opacity: 0;
  transition: opacity var(--t-fast), transform var(--t-fast), border-color var(--t-fast);
}

.snap:hover .snap__knot {
  opacity: 1;
}

.snap__knot:hover {
  transform: scale(1.4);
  border-color: var(--accent);
}

/* A stack's knot clears its count badge. */
.snap--stack .snap__knot {
  top: auto;
  bottom: -6.5px;
  right: 50%;
  margin: 0 -6.5px 0 0;
}

/* ── A stack, opened ──────────────────────────────────────────────── */

.stackpanel {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: grid;
  place-items: center;
  padding: 32px;
  background: color-mix(in srgb, var(--ink) 22%, transparent);
  backdrop-filter: blur(3px);
}

.stackpanel__sheet {
  display: flex;
  flex-direction: column;
  gap: 16px;
  width: min(760px, 100%);
  max-height: 100%;
  padding: 18px;
  border-radius: var(--r-card);
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-lift, 0 18px 48px rgba(0, 0, 0, 0.18));
}

.stackpanel__head {
  display: flex;
  align-items: center;
  gap: 12px;
}

.stackpanel__name {
  flex: 1;
  min-width: 0;
  padding: 4px 0;
  border: 0;
  border-bottom: 1px solid transparent;
  background: transparent;
  color: var(--ink);
  font-family: inherit;
  font-size: 19px;
  font-weight: 600;
}

.stackpanel__name:hover {
  border-bottom-color: var(--border);
}

.stackpanel__name:focus {
  outline: none;
  border-bottom-color: var(--accent);
}

.stackpanel__count {
  font-size: 12px;
  color: var(--ink-3);
  white-space: nowrap;
}

.stackpanel__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(148px, 1fr));
  gap: 12px;
  overflow: auto;
  padding: 2px;
}

.stackpanel__item {
  position: relative;
  aspect-ratio: 4 / 3;
  border-radius: var(--r-control);
  border: 1px solid var(--border);
  background: var(--bg);
  overflow: hidden;
}

.stackpanel__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.stackpanel__pull {
  position: absolute;
  top: 6px;
  right: 6px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--ink-2);
  box-shadow: var(--shadow-pop);
  opacity: 0;
  cursor: pointer;
  transition: opacity var(--t-fast);
}

.stackpanel__item:hover .stackpanel__pull {
  opacity: 1;
}

.stackpanel__foot {
  display: flex;
  align-items: center;
  gap: 10px;
}

.stackpanel__hint {
  font-size: 12px;
  color: var(--ink-3);
}

/* The wide variant of a dim chip, for the actions that read as sentences
   ("Show all 34", "Group by sitting · 7") rather than one-word tabs. */
.canvasdim--wide {
  white-space: nowrap;
}

/* The shelf is a way back, not a destination — it shouldn't compete with the
   dimensions for attention. */
.canvasdim--quiet {
  color: var(--ink-3);
}

.canvasfind {
  width: 150px;
  padding: 5px 10px;
  border: 1px solid var(--border);
  border-radius: var(--r-pill);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 12.5px;
}

.canvasfind::placeholder {
  color: var(--ink-3);
}

.canvasfind:focus {
  outline: none;
  border-color: var(--accent);
}

/* ── The filter column beside the board ── */
.canvasfilter {
  flex: none;
  width: 184px;
  min-height: 0;
  overflow-y: auto;
  padding: 12px 10px 14px;
  border: 1px solid var(--border);
  border-radius: var(--r-card);
  background: var(--surface);
}

.canvasfilter__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  padding: 0 6px 6px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--ink);
}

.canvasfilter__head .linkbtn {
  font-size: 11.5px;
}

.canvasfilter__group {
  padding-top: 10px;
}

.canvasfilter__group + .canvasfilter__group {
  margin-top: 6px;
  border-top: 1px solid var(--border);
}

.canvasfilter__group h4 {
  margin: 0 0 4px;
  padding: 0 6px;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.filterrow {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 5px 6px;
  border-radius: 7px;
  font-size: 12.5px;
  color: var(--ink-2);
  text-align: left;
  transition: background var(--t-fast), color var(--t-fast);
}

.filterrow:hover {
  background: var(--surface-2);
  color: var(--ink);
}

.filterrow--on {
  color: var(--ink);
}

.filterrow--quiet:not(.filterrow--on) {
  color: var(--ink-3);
}

.filterrow .check {
  flex: none;
  pointer-events: none;
}

.filterrow__label {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.filterrow__n {
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  color: var(--ink-3);
}

/* The filter hides; it never repacks. When it hides everything, say so on the
   board itself rather than showing an empty dot grid. */
.canvas__none {
  position: absolute;
  top: 40%;
  left: 50%;
  transform: translate(-50%, -50%);
  font-size: 13px;
  color: var(--ink-3);
  pointer-events: none;
}

/* A card taken off the canvas, shown because the filter asked for it. */
.snap--off {
  opacity: 0.55;
}

@container stage (max-width: 860px) {
  .canvasfilter {
    width: 148px;
  }

  .canvasfind {
    width: 110px;
  }
}

/* Narrower still: the search field gives up width rather than disappearing —
   typing a pile's name is the only way to a pile you can't see. */
@container stage (max-width: 620px) {
  .canvasfind {
    width: 84px;
  }
}

.canvasgrid__none {
  position: absolute;
  left: 48px;
  top: 104px;
  font-size: 13px;
  color: var(--ink-3);
}

/* A button that reads as prose — used inside empty-state sentences. */
.linkbtn {
  color: var(--accent);
  font: inherit;
  font-weight: 600;
  text-decoration: underline;
  text-underline-offset: 2px;
  cursor: pointer;
}


.canvas__marquee {
  position: absolute;
  z-index: 3;
  pointer-events: none;
  border: 1px solid var(--accent);
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  border-radius: 4px;
}

.selbar__hint {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 12px;
  color: var(--ink-3);
  padding: 0 4px;
  white-space: nowrap;
}

/* The drag hint is the one thing on the bar that isn't an action, so it is the
   first thing to go when there isn't room for everything. */
@media (max-width: 1120px) {
  .selbar__hint {
    display: none;
  }
}

.shell__paste-error {
  cursor: pointer;
}

/* ══ Motion preferences ═════════════════════════════════════════════ */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

/* ══ Import ════════════════════════════════════════════════════════ */

.import {
  width: min(560px, 100%);
}

.import__body {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.import__row {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.import__source {
  display: flex;
  align-items: center;
  gap: 8px;
}

.import__path {
  flex: 1;
  min-width: 0;
  padding: 7px 12px;
  font-size: 12px;
  color: var(--ink-2);
  background: var(--surface-2);
  border-radius: var(--r-pill);
  /* A long path truncates at the front — the folder name is the part that
     identifies it, and it is at the end. */
  direction: rtl;
  text-align: left;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The headline number: what the scan found, stated plainly. */
.import__found {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 16px 18px;
  background: var(--accent-soft);
  border-radius: var(--r-card);
}

.import__count {
  font-size: 21px;
  font-weight: 680;
  color: var(--ink);
}

.import__sub {
  font-size: 12px;
  color: var(--ink-2);
}

.import__holds {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.import__hold {
  padding: 7px 13px;
  font-size: 12.5px;
  font-weight: 560;
  color: var(--ink-2);
  background: var(--surface-2);
  border: 1px solid transparent;
  border-radius: var(--r-pill);
  transition:
    background var(--t-fast),
    color var(--t-fast),
    border-color var(--t-fast);
}

.import__hold:hover {
  color: var(--ink);
}

.import__hold--on {
  color: var(--accent-ink);
  background: var(--accent);
  border-color: var(--accent);
}

.import__hint,
.import__note {
  font-size: 12px;
  line-height: 1.5;
  color: var(--ink-3);
}

.import__note {
  margin: 0;
}

.import__folder {
  flex: 1;
  min-width: 0;
  width: auto;
}

.import__foot {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  padding: 14px 20px;
  border-top: 1px solid var(--border);
  flex: none;
}

/* ══ Activate — the licence gate ════════════════════════════════════
   The whole window until the app is activated, so it has no sidebar and
   the single column runs the full width. One field, centred, with the
   two sentences that answer the only two people who can be standing
   here: someone who has a key, and someone who has not bought yet. */

.shell--bare {
  grid-template-columns: 1fr;
}

.activate {
  align-items: center;
  justify-content: center;
}

.activate__body {
  width: 100%;
  max-width: 420px;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 10px;
}

.activate__title {
  font-family: var(--font-display);
  font-size: 25px;
  font-weight: 560;
  margin: 0;
}

.activate__line {
  color: var(--ink-2);
  line-height: 1.5;
  margin: 0;
}

.activate__line--buy {
  margin-top: 6px;
}

.activate__row {
  display: flex;
  gap: 8px;
  margin-top: 6px;
}

.activate__input {
  flex: 1;
  /* The key is read off a receipt email and typed character by character, so
     it gets a face where 0 and O are different shapes. */
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  letter-spacing: 0.02em;
}

.activate__error {
  color: var(--danger);
  line-height: 1.5;
  margin: 0;
  user-select: text;
}

/* The masked key in Settings, which is there to be read and compared against
   a receipt, so it gets the same face as the field that took it. */
.setrow__key {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 12px;
  color: var(--ink-2);
  user-select: text;
}

/* ══ Update sheet ═══════════════════════════════════════════════════
   Floating, bottom-right, and never modal: an available update is not
   urgent, and the app has to stay usable behind it. Elevation is what
   the rest of the app already reserves for floating things. */

.updatesheet {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 40;
  width: 320px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-card);
  box-shadow: var(--shadow-pop);
}

.updatesheet__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}

.updatesheet__notes {
  margin: 0;
  color: var(--ink-2);
  font-size: 12px;
  line-height: 1.5;
  max-height: 120px;
  overflow-y: auto;
  user-select: text;
  white-space: pre-wrap;
}

.updatesheet__error {
  margin: 0;
  color: var(--danger);
  font-size: 12px;
  line-height: 1.5;
  user-select: text;
}

.updatesheet__row {
  display: flex;
  gap: 8px;
}

.updatesheet__progress {
  height: 4px;
  border-radius: 2px;
  background: var(--well);
  overflow: hidden;
}

.updatesheet__bar {
  height: 100%;
  background: var(--accent);
  border-radius: 2px;
  transition: width 120ms linear;
}

/* No content length from the server, so no honest percentage to draw. A bar
   that sweeps says "working" without inventing a number. */
.updatesheet__bar--unknown {
  width: 35%;
  animation: updatesweep 1.1s ease-in-out infinite;
}

@keyframes updatesweep {
  0% { margin-left: -35%; }
  100% { margin-left: 100%; }
}
