/* To-do. Tokens from the approved Claude Design canvas, Sage green accent. */
:root {
  --bg: #FFFFFF;
  --surface: #F5F5F7;
  --field: #F5F5F7;
  --sheet: #FFFFFF;
  --text: #1C1C1E;
  --secondary: #6E6E73;
  --sep: #E5E5EA;
  --ring: #88888D;          /* the circle is the main control: 3.5:1 on white, 3.2:1 on the surface (WCAG 1.4.11) */
  --accent: #3F7D5C;        /* fills: add button, active segment, swipe, done check */
  --accent-text: #3F7D5C;   /* text, focus rings, caret */
  --accent-soft: rgba(63, 125, 92, 0.14);
  --on-accent: #FFFFFF;
  --danger: #C62828;
  --toast: #1C1C1E;
  --toast-text: #F2F2F7;
  --toast-accent: #7DBF98;
  --scrim: rgba(0, 0, 0, 0.28);
  --shadow: 0 8px 30px rgba(0, 0, 0, 0.12);
  --hover: rgba(127, 127, 127, 0.08); /* desktop hover wash */
  --amber-bg: #FBEFD9;      /* a letter card's days left */
  --amber-ink: #80520A;
  --late-bg: #FBE3E3;

  --top: max(24px, calc(env(safe-area-inset-top) + 15px));
  --bottom: max(16px, env(safe-area-inset-bottom));
  /* Side gutters clear the notch and the rounded corners in landscape. */
  --gut-l: max(16px, env(safe-area-inset-left));
  --gut-r: max(16px, env(safe-area-inset-right));
  /* Motion: app.js reads these into M. Calm first: nothing bounces, moves ease out. */
  --ease: cubic-bezier(0.2, 0.8, 0.2, 1);
  --dur-press: 140ms;  /* colour and state changes */
  --dur-move: 220ms;   /* rows, sheets, entrances */
  --dur-exit: 180ms;   /* things leaving */
  --dist: 1;           /* 0 under reduced motion: slides become fades */
  /* Three type sizes per screen; weight and colour carry the rest. */
  --fs-title: 28px;
  --fs-body: 17px;
  --fs-meta: 13px;
  color-scheme: light dark;
}
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #000000;
    --surface: #1C1C1E;
    --field: #2C2C2E;
    --sheet: #1C1C1E;
    --text: #F2F2F7;
    --secondary: #8E8E93;
    --sep: #2C2C2E;
    --ring: #636366;          /* 3.5:1 on black */
    --accent: #7DBF98;        /* one green in dark: fills match the text (C10a) */
    --accent-text: #7DBF98;
    --on-accent: #000000;     /* white on #7DBF98 is about 2:1 */
    --accent-soft: rgba(125, 191, 152, 0.16);
    --danger: #FF6B60;
    --toast: #2C2C2E;
    --scrim: rgba(0, 0, 0, 0.5);
    --shadow: 0 8px 30px rgba(0, 0, 0, 0.6);
    --amber-bg: #3A2E1A;
    --amber-ink: #F0C27A;
    --late-bg: #3A1D20;
  }
}

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  min-height: 100vh;
  background: var(--bg);
  color: var(--text);
  font: var(--fs-body)/1.35 -apple-system, BlinkMacSystemFont, "SF Pro Text", "Helvetica Neue", system-ui, sans-serif;
  -webkit-tap-highlight-color: transparent;
  -webkit-font-smoothing: antialiased;
}
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; touch-action: manipulation; }
input, textarea { font: inherit; color: inherit; }
[hidden] { display: none !important; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
::placeholder { color: var(--secondary); opacity: 1; }
.ic { fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; flex-shrink: 0; }
.ic-2 { stroke-width: 2; }
.meta { font-size: var(--fs-meta); color: var(--secondary); }
:focus { outline: none; }
:focus-visible { outline: 2px solid var(--accent-text); outline-offset: 2px; border-radius: 10px; }

/* Which bits show where. */
.desk-only, .sidebar { display: none; }
body.view-done .list-only, body.view-list .done-only { display: none !important; }

/* ---------- Header ---------- */
.top { padding: var(--top) var(--gut-r) 8px var(--gut-l); display: flex; flex-direction: column; }
.title-row { display: flex; align-items: center; justify-content: space-between; min-height: 44px; }
h1 { margin: 0; font-size: var(--fs-title); font-weight: 600; letter-spacing: -0.3px; }
.icon-btn { width: 44px; height: 44px; display: flex; align-items: center; justify-content: center; color: var(--secondary); margin-right: -10px; }
.text-btn { height: 44px; padding: 0 4px; color: var(--accent-text); font-size: var(--fs-body); font-weight: 600; }
/* Press feedback (a touchstart listener in app.js lets WebKit apply :active on touch). */
.seg button, .text-btn, .icon-btn, .toast button, .danger-btn { transition: opacity var(--dur-press) ease; }
.seg button:active, .text-btn:active, .icon-btn:active, .toast button:active, .danger-btn:active { opacity: 0.55; }

/* The pill and the banner each open in a grid slot under the title (0fr to 1fr, app.js), so the
   list makes room with a glide and never jumps. The pill does not fit beside "Someday" and the
   clock at 390px. */
.slot { display: grid; grid-template-rows: 1fr; }
.slot-clip { min-height: 0; overflow: hidden; }
.pill {
  display: flex; width: fit-content; align-items: center; gap: 6px; height: 28px; margin-top: 8px; padding: 0 10px;
  border-radius: 14px; background: var(--surface); color: var(--secondary); font-size: var(--fs-meta);
}
.banner { display: flex; align-items: center; gap: 10px; margin-top: 8px; padding: 0 8px 0 14px; min-height: 44px; border-radius: 12px; background: var(--surface); }
.banner span { flex: 1; font-size: var(--fs-meta); padding: 10px 0; }

/* ---------- Rows ---------- */
.list {
  list-style: none; margin: 0; padding: 2px 0 calc(var(--bottom) + 44px + 16px + 56px + 32px);
}
.list:empty { padding-bottom: 0; }
.row { position: relative; overflow: hidden; -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
/* Hairlines start at the text, and stay there while a row swipes. */
.row + .row::before { content: ""; position: absolute; z-index: 2; left: calc(var(--gut-l) + 38px); right: var(--gut-r); top: 0; border-top: 0.5px solid var(--sep); pointer-events: none; }
.row-inner {
  position: relative; z-index: 1; display: flex; align-items: flex-start; gap: 14px;
  min-height: 52px; padding: 14px var(--gut-r) 14px var(--gut-l); background: var(--bg); touch-action: pan-y;
}
/* The plain iOS cell highlight: on after a still press, and on while the move menu is open. */
.row.pressing .row-inner, .row.menu-open .row-inner { background: var(--surface); }
@media (hover: none) {
  .row-inner { transition: background-color var(--dur-press) ease; } /* fades off when the finger lifts */
  .row.pressing .row-inner { transition: none; }
}
.row .text {
  flex: 1; min-width: 0; font-size: var(--fs-body); line-height: 1.35; overflow-wrap: anywhere; cursor: default;
  display: flex; align-items: baseline; gap: 8px;
  transition: color var(--dur-press) ease;
}
.row .text .tname { flex: 1; min-width: 0; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
/* A date and the Apply tag sit at the right of the name, small (app.js textHtml). */
.tmeta { flex-shrink: 0; display: inline-flex; align-items: baseline; gap: 6px; }
.dtext .tmeta { margin-left: 8px; }
/* Hiscores skill icons (OSRS pixel art): kept crisp, sized by their box. */
.skill { display: block; width: 18px; height: 18px; object-fit: contain; image-rendering: pixelated; flex-shrink: 0; }
.tskill { align-self: center; opacity: 0.9; }
.dbtn .tskill { align-self: flex-start; padding-top: 3px; }
/* Today cleared with its rewards: the block starts higher so the list of skills fits above the switcher. */
.empty.all-done:has(.rewards:not([hidden])) { margin-top: max(24px, calc(140px - var(--top))); }
.tdue { color: var(--secondary); font-size: var(--fs-meta); white-space: nowrap; font-variant-numeric: tabular-nums; }
/* Soon is amber, passed is red: the same two colours as a letter card's days left. */
.tdue.near { color: var(--amber-ink); font-weight: 600; }
.tdue.late { color: var(--danger); font-weight: 600; }
/* A link the hub set (a vacancy's page): a quiet icon with a 44px target that keeps the row's height. */
.row .link {
  flex-shrink: 0; display: flex; align-items: center; justify-content: center; width: 44px; height: 44px;
  margin: -10px calc(-1 * var(--gut-r) + 4px) -10px -10px; color: var(--secondary); border-radius: 10px;
  -webkit-tap-highlight-color: transparent;
}
.row .link:active { color: var(--accent-text); }
/* The check moment: the text dims and is struck through while the row rests (the strike fades in from app.js). */
.row.ticked .text { color: var(--secondary); text-decoration: line-through; }
.circle {
  flex-shrink: 0; width: 24px; height: 24px; border-radius: 12px; border: 1.5px solid var(--ring);
  display: flex; align-items: center; justify-content: center; color: var(--on-accent); position: relative;
  transition: background var(--dur-press) ease, border-color var(--dur-press) ease;
}
.circle::before { content: ""; position: absolute; inset: -10px; } /* 44px hit area */
.circle .ic { opacity: 0; transform: scale(0.6); stroke-dasharray: 20; transition: opacity var(--dur-press) ease, transform var(--dur-press) var(--ease); }
.circle.checked { background: var(--accent); border-color: var(--accent); }
.circle.checked .ic { opacity: 1; transform: none; }
/* A tap draws the tick (path about 19.8 long, dashed at 20) instead of growing it. */
.row.ticked .circle .ic { opacity: 1; transform: none; transition: none; }
.circle-static { flex-shrink: 0; width: 24px; height: 24px; border-radius: 12px; border: 1.5px solid var(--ring); }
/* On the phone the move button is there for VoiceOver only; a finger swipes left instead. */
@media (max-width: 899px) {
  .move-btn { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
}

/* Swipe backgrounds sit under the row and show as it slides. */
.swipe-done, .swipe-move { position: absolute; inset: 0; display: none; align-items: center; }
/* Soft until the swipe would finish the task, then solid with the check popping (approved). */
.swipe-done {
  background: var(--accent-soft); color: var(--accent-text); padding-left: calc(var(--gut-l) + 4px);
  transition: background-color var(--dur-press) ease, color var(--dur-press) ease;
}
.row.armed .swipe-done { background: var(--accent); color: var(--on-accent); }
.swipe-done .ic { transition: transform var(--dur-press) var(--ease); }
.row.armed .swipe-done .ic { transform: scale(1.25); }
.row.swipe-r .swipe-done, .row.swipe-l .swipe-move { display: flex; }
.swipe-move { justify-content: flex-end; padding-right: calc(var(--gut-r) - 4px); background: var(--bg); }
.move-group { display: flex; gap: 6px; }
/* Where a task can go is neutral; where it is now is dimmed, as in the menu. 13px semibold (the
   meta size) leaves about 150px of task text at 390px; 17px would leave about 110px. */
.swipe-move button {
  position: relative; height: 36px; padding: 0 12px; border-radius: 9px; background: var(--surface); color: var(--text);
  font-size: var(--fs-meta); font-weight: 600;
}
.swipe-move button[aria-current] { color: var(--secondary); cursor: default; }
.swipe-move button::before { content: ""; position: absolute; inset: -8px -3px; } /* the whole row height, and the gaps */
/* .sliding and .collapsing mark rows on their way out; app.js animates them. */
.row.dragging { opacity: 0.4; }

.row.enter { animation: row-in var(--dur-move) var(--ease); }
@keyframes row-in { from { opacity: 0; transform: translateY(calc(-8px * var(--dist))); } }
.row.nudge .row-inner { animation: nudge 900ms var(--ease) 400ms; }
.row.nudge .swipe-done { display: flex; } /* the soft fill a real swipe shows first */
@keyframes nudge { 0%, 100% { transform: none; } 35%, 55% { transform: translateX(24px); } }

.skeleton .row-inner { align-items: center; }
.skeleton .bar { height: 14px; margin: 5px 0; border-radius: 7px; background: var(--surface); width: 70%; }
.skeleton:nth-child(2) .bar { width: 52%; }
.skeleton:nth-child(3) .bar { width: 62%; }

/* ---------- Done history ---------- */
.dhead { display: flex; justify-content: space-between; padding: 18px var(--gut-r) 6px var(--gut-l); font-size: var(--fs-meta); font-weight: 600; color: var(--secondary); }
/* The day's XP (app.js doneRows), outside the text so the header still reads as its label. */
.dhead[data-xp]::after { content: attr(data-xp); font-weight: 400; font-variant-numeric: tabular-nums; }
.drow { position: relative; margin: 0 var(--gut-r) 0 var(--gut-l); cursor: pointer; content-visibility: auto; contain-intrinsic-size: auto 48px; }
.dbtn { display: flex; align-items: flex-start; gap: 14px; width: 100%; padding: 12px 0; text-align: left; }
/* No line under a day header; the line starts at the text. */
.drow + .drow::before { content: ""; position: absolute; left: 38px; right: 0; top: 0; border-top: 0.5px solid var(--sep); pointer-events: none; }
.dcheck {
  flex-shrink: 0; width: 24px; height: 24px; border-radius: 12px; background: var(--accent); border: 1.5px solid var(--accent);
  color: var(--on-accent); display: flex; align-items: center; justify-content: center;
  transition: background-color var(--dur-press) ease, border-color var(--dur-press) ease;
}
.dcheck .ic { transition: opacity var(--dur-press) ease; }
.dbody { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.dtime { display: block; }
/* The section a done task came from stays for screen readers (aria-describedby) only. */
.dbody > .meta { display: none; }
.dtext {
  /* Done is a record, not a bin: plain text, the green check already says done. */
  font-size: var(--fs-body); line-height: 1.35; color: var(--text); overflow-wrap: anywhere;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
/* Reopen: the tick drains to an empty ring and the text comes back, then the row closes. */
.drow.reopening .dcheck { background: transparent; border-color: var(--ring); }
.drow.reopening .dcheck .ic { opacity: 0; }
.drow.collapsing, .dhead.collapsing { overflow: hidden; }
.dtime { padding-top: 3px; }
body.view-done .list { padding-bottom: calc(var(--bottom) + 72px); }

/* ---------- Empty, install, no code ---------- */
.empty { display: flex; flex-direction: column; align-items: center; gap: 12px; color: var(--secondary); padding: 0 32px; margin-top: max(40px, calc(238px - var(--top))); }
.ic-glyph { stroke-width: 1.25; }
.empty.all-done .ic-glyph { color: var(--accent-text); } /* Today cleared: the one green, Paul's call */
.empty p { margin: 0; font-size: var(--fs-body); text-align: center; }
.install { margin: 40px var(--gut-r) 0 var(--gut-l); padding: 16px; border-radius: 14px; background: var(--surface); display: flex; gap: 12px; align-items: flex-start; }
.install-body { flex: 1; display: flex; flex-direction: column; gap: 6px; }
.install-title { font-size: var(--fs-body); font-weight: 600; }
/* Running text: each glyph keeps its comma or full stop on its line. */
.install-text { font-size: var(--fs-body); line-height: 1.4; color: var(--secondary); }
.install-text .glyph { color: var(--accent-text); display: inline-flex; vertical-align: -3px; }
.nowrap { white-space: nowrap; }
.install-close { width: 44px; height: 44px; margin: -10px -10px 0 0; }
.empty:not([hidden]) + .install { margin-top: 144px; }
.list:not(:empty) ~ .install { margin-top: 8px; margin-bottom: 200px; }
.nocode { position: fixed; inset: 0; z-index: 50; background: var(--bg); display: flex; align-items: center; justify-content: center; padding: 32px; }
.nocode p { margin: 0; max-width: 320px; text-align: center; color: var(--secondary); }

/* ---------- Bottom bar ---------- */
/* One thumb slides under the labels to the section that is on. --i is its place (0, 1, 2), from
   aria-selected, aria-checked or aria-current. It only glides once the first paint is done (body.ready),
   and .instant puts it in place for one frame (the edit sheet opening on another task). */
.seg { position: relative; display: flex; gap: 4px; height: 44px; padding: 4px; border-radius: 12px; background: var(--surface); --i: 0; }
.seg:has(> :nth-child(2):is([aria-selected="true"], [aria-checked="true"], [aria-current="page"])) { --i: 1; }
.seg:has(> :nth-child(3):is([aria-selected="true"], [aria-checked="true"], [aria-current="page"])) { --i: 2; }
.seg::before {
  content: ""; position: absolute; top: 4px; left: 4px; height: 36px; width: calc((100% - 16px) / 3); border-radius: 9px;
  background: var(--accent); transform: translateX(calc(var(--i) * (100% + 4px)));
}
.seg button { position: relative; flex: 1; height: 36px; border-radius: 9px; font-size: var(--fs-body); color: var(--text); }
.seg button::after { content: ""; position: absolute; inset: -4px -2px; } /* the full bar height, and the gaps */
.seg button:is([aria-selected="true"], [aria-checked="true"], [aria-current="page"]) { color: var(--on-accent); font-weight: 600; }
/* The label turns with the thumb, on the same curve, so it never shows white on grey. */
body.ready .seg::before { transition: transform var(--dur-move) var(--ease); }
body.ready .seg button { transition: opacity var(--dur-press) ease, color var(--dur-move) var(--ease); }
body.ready .seg.instant::before, body.ready .seg.instant button { transition: none; }
.switcher { position: fixed; left: var(--gut-l); right: var(--gut-r); bottom: var(--bottom); z-index: 10; }
.fab {
  position: fixed; right: var(--gut-r); bottom: calc(var(--bottom) + 60px); z-index: 11; width: 56px; height: 56px; border-radius: 28px;
  background: var(--accent); color: var(--on-accent); display: flex; align-items: center; justify-content: center;
  transition: transform var(--dur-press) ease;
}
.fab:active { transform: scale(0.94); }
/* Done opening: the add button and the switcher stay shown while they fade out (app.js). */
@media (max-width: 899px) {
  body.view-done #fab.layer-out, body.view-done #switcher.layer-out { display: flex !important; pointer-events: none; }
}
/* Done closing: a still copy of it sinks away over the list. */
.col-ghost { position: fixed; z-index: 5; margin: 0; overflow: hidden; background: var(--bg); pointer-events: none; }
.toast {
  position: fixed; left: var(--gut-l); right: calc(var(--gut-r) + 68px); bottom: calc(var(--bottom) + 60px); z-index: 12; height: 56px; padding: 0 8px 0 16px;
  border-radius: 14px; background: var(--toast); color: var(--toast-text); display: flex; align-items: center; justify-content: space-between;
  font-size: var(--fs-body); animation: toast-in var(--dur-move) var(--ease);
}
.toast button { height: 44px; padding: 0 12px; color: var(--toast-accent); font-size: var(--fs-body); font-weight: 600; }
body.view-done .toast { bottom: var(--bottom); right: var(--gut-r); } /* no add button in Done */
/* On translate, so the desktop centring (transform) is never touched. */
@keyframes toast-in { from { opacity: 0; translate: 0 calc(12px * var(--dist)); } }
.toast.leaving, .menu.leaving { pointer-events: none; }

/* ---------- Sheets and dialogs ---------- */
.sheet-wrap, .dialog-wrap { position: fixed; inset: 0; z-index: 30; }
.scrim { position: absolute; inset: 0; background: var(--scrim); animation: fade-in var(--dur-move) ease; touch-action: none; }
.sheet {
  position: absolute; left: 0; right: 0; bottom: 0; background: var(--sheet); border-radius: 16px 16px 0 0;
  padding: 10px var(--gut-r) calc(16px + env(safe-area-inset-bottom)) var(--gut-l); display: flex; flex-direction: column; gap: 10px;
  animation: sheet-in var(--dur-move) var(--ease); touch-action: none;
  translate: 0 var(--kb, 0px); transition: translate 240ms var(--ease); /* rides above the keyboard */
}
.sheet.dragging { transition: none; } /* app.js ends the entry at the grab, so it never replays */
/* The page panned under the keyboard: the offset follows at once. */
.sheet.kb-snap { transition-property: transform; }
.grabber { align-self: center; width: 36px; height: 5px; border-radius: 3px; background: var(--ring); }
.cap-row { display: flex; align-items: center; gap: 14px; min-height: 52px; }
.cap-row input, .inline-add input { flex: 1; min-width: 0; border: 0; outline: none; background: transparent; font-size: var(--fs-body); padding: 0; caret-color: var(--accent-text); }
.capture-sheet { padding-bottom: 16px; }
/* One header for both sheets: what it is on the left, Close on the right, at the same place. */
.sheet-head { display: flex; align-items: center; justify-content: space-between; min-height: 44px; margin: -6px 0 -10px; }
.edit-sheet .sheet-head { margin: -12px 0 -8px; } /* the edit sheet has a wider gap */
.cap-added { list-style: none; margin: 0; padding: 2px 0 0; display: flex; flex-direction: column; }
.cap-added:empty { display: none; }
.cap-added li { display: flex; align-items: center; gap: 14px; min-height: 30px; color: var(--secondary); overflow: hidden; } /* app.js grows each new line */
.cap-added .ok { width: 24px; display: flex; justify-content: center; color: var(--accent-text); }
.cap-added .t { flex: 1; min-width: 0; font-size: var(--fs-body); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* A tidied line's own Undo (app.js capTidied): quiet text, the whole line's height to tap. */
.cap-undo {
  flex-shrink: 0; align-self: stretch; min-width: 56px; margin-right: -8px; padding: 0 8px; border: 0; border-radius: 8px;
  background: none; color: var(--accent-text); font: inherit; font-size: var(--fs-meta); font-weight: 600; cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.cap-undo:focus-visible { outline: 2px solid var(--accent-text); outline-offset: -2px; }
.edit-sheet { gap: 16px; min-height: min(460px, 70vh); padding-bottom: calc(24px + env(safe-area-inset-bottom)); }
/* Keyboard up: the sheet fits in what is left of the screen, so Close stays on it. */
.edit-sheet.kb { min-height: 0; max-height: calc(var(--vvh) - env(safe-area-inset-top) - 12px); padding-bottom: 16px; }
.edit-sheet > .meta { margin-bottom: -8px; }
textarea#editText {
  border: 0; outline: none; resize: none; font-size: var(--fs-body); line-height: 1.35; background: var(--field); border-radius: 12px; padding: 12px 14px;
  caret-color: var(--accent-text); touch-action: auto;
}
textarea#editText:focus-visible { outline: 2px solid var(--accent-text); outline-offset: 0; }
.grow { flex: 1; }
.danger-btn { align-self: center; height: 44px; padding: 0 12px; color: var(--danger); font-size: var(--fs-body); }
.dialog {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); width: min(300px, calc(100vw - 48px));
  background: var(--sheet); border-radius: 14px; padding: 20px 16px 8px; text-align: center; box-shadow: var(--shadow);
  animation: fade-in var(--dur-move) ease;
}
.dialog p { margin: 0 0 12px; font-size: var(--fs-body); }
.dialog-actions { display: flex; border-top: 0.5px solid var(--sep); margin: 0 -16px; }
.dialog-actions button { flex: 1; height: 48px; font-size: var(--fs-body); color: var(--accent-text); }
.dialog-actions button + button { border-left: 0.5px solid var(--sep); }
.dialog-actions .danger { color: var(--danger); font-weight: 600; }
/* From below the screen, whatever keyboard offset is already on the sheet. */
@keyframes sheet-in { from { transform: translateY(calc(100% - var(--kb, 0px))); } }
@keyframes fade-in { from { opacity: 0; } }
/* Desktop sheets are centred with transform, so they grow on the scale property. */
@keyframes sheet-pop { from { opacity: 0; scale: 0.98; } }

.menu {
  position: fixed; z-index: 40; min-width: 200px; padding: 6px; border-radius: 14px; background: var(--sheet);
  box-shadow: var(--shadow); border: 0.5px solid var(--sep); display: flex; flex-direction: column; gap: 4px;
}
.menu .menu-title { padding: 6px 8px 2px; }
.menu button.sec { height: 44px; text-align: left; padding: 0 12px; border-radius: 9px; font-size: var(--fs-body); color: var(--text); }
.menu button.sec:hover, .menu button.sec:focus-visible { background: var(--surface); outline: none; }
.menu button.sec[aria-current] { color: var(--secondary); cursor: default; }
.menu button.sec[aria-current]:hover { background: none; }

/* ---------- Desktop ---------- */
@media (min-width: 900px) {
  :root { --fs-title: 24px; }
  .phone-only { display: none !important; }
  .desk-only { display: flex; }
  .sidebar {
    display: flex; flex-direction: column; gap: 4px; position: fixed; left: 0; top: 0; bottom: 0; width: 240px;
    padding: 32px 16px; background: var(--surface);
  }
  .brand { padding: 0 12px 16px; font-size: var(--fs-meta); font-weight: 600; color: var(--secondary); }
  .nav-item {
    display: flex; align-items: center; justify-content: space-between; height: 40px; padding: 0 12px; border-radius: 10px;
    font-size: var(--fs-body); text-align: left;
  }
  .nav-item:hover { background: var(--hover); }
  .nav-item[aria-current="page"] { background: var(--accent-soft); color: var(--accent-text); font-weight: 600; }
  .nav-item.drop { outline: 2px solid var(--accent-text); outline-offset: -2px; }
  .nav-item .count { font-size: var(--fs-meta); color: var(--secondary); font-weight: 400; }
  .nav-done { justify-content: flex-start; gap: 8px; }
  .nav-sep { height: 1px; margin: 12px; background: var(--sep); }

  .main { margin-left: 240px; display: flex; justify-content: center; }
  .col { width: 640px; max-width: calc(100vw - 240px - 48px); padding-top: 56px; }
  .top { padding: 0 12px 12px; }
  h1 { letter-spacing: 0; }
  .add-desk { width: 36px; height: 36px; border-radius: 18px; background: var(--accent); color: var(--on-accent); align-items: center; justify-content: center; }
  .kbd-hint { padding: 24px 12px 48px; margin: 0; font-size: var(--fs-meta); color: var(--secondary); }

  /* Cards with no hairlines. The 8px between them is the row's own margin, which a collapse
     closes with the row, so the rows below never hop 8px when it goes. */
  .list { margin: 0; padding: 0; display: flex; flex-direction: column; }
  body.view-list .list:not(:empty) { margin-bottom: -8px; }
  .row { margin-bottom: 8px; }
  body.view-done .list { display: block; }
  body.view-done .list { padding: 0 12px 48px; }
  .row { border-radius: 10px; }
  .row + .row::before { display: none; }
  /* The hover card reaches 12px past the check, like a list row's. */
  .drow { margin: 0 -12px; border-radius: 10px; }
  .dbtn { padding: 12px; }
  .drow + .drow::before { left: 48px; right: 12px; transition: opacity var(--dur-press) ease; }
  .drow:hover { background: var(--surface); }
  .drow:hover::before, .drow:hover + .drow::before { opacity: 0; transition-duration: 0ms; }
  .dhead { padding-left: 0; }
  .row-inner { align-items: center; padding: 0 12px; border-radius: 10px; min-height: 52px; }
  .row .text { padding: 14px 0; cursor: pointer; }
  .circle, .circle-static, .dcheck { width: 22px; height: 22px; border-radius: 11px; }
  .dcheck .ic { width: 14px; height: 14px; }
  .row:hover .row-inner, .row:focus-visible .row-inner { background: var(--surface); }
  .row:hover .circle:not(.checked) { border-color: var(--accent-text); }
  .row:focus-visible { outline: 2px solid var(--accent-text); outline-offset: -2px; }
  .row .link { width: 36px; height: 36px; margin: 0; border-radius: 8px; }
  .row .link:hover { color: var(--accent-text); background: var(--bg); }
  .move-btn { display: flex; visibility: hidden; width: 36px; height: 36px; align-items: center; justify-content: center; color: var(--secondary); border-radius: 8px; }
  .row:hover .move-btn, .row:focus-within .move-btn, .row.menu-open .move-btn { visibility: visible; }
  /* Calm hovers: in at once, out softly. */
  .row-inner, .nav-item, .drow { transition: background-color var(--dur-press) ease; }
  .row:hover .row-inner, .nav-item:hover, .drow:hover { transition-duration: 0ms; }
  .inline-slot { display: grid; grid-template-rows: 1fr; }
  .inline-clip { min-height: 0; overflow: hidden; }
  .inline-add { display: flex; align-items: center; gap: 14px; min-height: 52px; padding: 0 12px; margin-bottom: 8px; border-radius: 10px; border: 1.5px solid var(--accent-text); }
  .empty { margin-top: 120px; }
  .install { display: none !important; }

  .toast { left: calc(50% + 120px); right: auto; bottom: 24px; transform: translateX(-50%); width: 360px; }
  body.view-done .toast { bottom: 24px; right: auto; }

  /* The centring transform puts the centre on the top left corner of the box, so the scale grows from there. */
  .sheet { left: 50%; right: auto; bottom: auto; top: 50%; width: 440px; transform: translate(-50%, -50%); border-radius: 14px; box-shadow: var(--shadow); padding: 12px 20px 16px; animation: sheet-pop var(--dur-move) var(--ease); translate: none; transform-origin: 0 0; }
  .grabber { display: none; }
  .edit-sheet { min-height: 0; }
  .edit-sheet .grow { flex: 0 0 8px; }
  .edit-sheet .sheet-head { margin-top: -6px; }
}

/* ---------- Letter cards (app.js, Letter cards) ---------- */
.card-sheet { max-height: 92vh; max-height: 92dvh; overflow-y: auto; overscroll-behavior: contain; touch-action: pan-y; gap: 14px; padding-bottom: calc(20px + env(safe-area-inset-bottom)); }
.card-body { display: flex; flex-direction: column; gap: 14px; }
.card-want { margin: 4px 0 0; font-size: 22px; font-weight: 650; line-height: 1.2; letter-spacing: -0.01em; text-wrap: balance; }
.card-due { display: flex; flex-wrap: wrap; align-items: baseline; gap: 10px; font-size: 15px; }
.card-left { padding: 3px 9px; border-radius: 99px; background: var(--amber-bg); color: var(--amber-ink); font-size: var(--fs-meta); font-weight: 650; }
.card-left.late { background: var(--late-bg); color: var(--danger); }
.card-facts { display: flex; flex-direction: column; border-radius: 12px; background: var(--field); }
.card-fact { display: grid; grid-template-columns: 96px minmax(0, 1fr) auto; align-items: center; gap: 10px; min-height: 52px; padding: 6px 8px 6px 14px; }
.card-fact + .card-fact { border-top: 1px solid var(--sep); }
.card-k { font-size: var(--fs-meta); color: var(--secondary); }
.card-k small { display: block; font-size: 11px; }
.card-v { min-width: 0; font-size: 16px; font-variant-numeric: tabular-nums; overflow-wrap: anywhere; user-select: text; -webkit-user-select: text; }
.card-v.none { color: var(--secondary); font-style: italic; font-size: 15px; }
.card-copy { min-width: 64px; min-height: 40px; padding: 0 12px; border-radius: 99px; background: var(--accent-soft); color: var(--accent-text); font-size: 14px; font-weight: 600; }
.card-copy.ok { background: var(--accent); color: var(--on-accent); }
.card-opts { display: flex; flex-direction: column; gap: 8px; margin-top: -8px; }
.card-opt { display: grid; grid-template-columns: 22px minmax(0, 1fr); gap: 10px; align-items: start; padding: 12px 14px; border: 1.5px solid var(--sep); border-radius: 12px; text-align: left; color: var(--text); }
.card-opt b { display: block; font-size: 16px; font-weight: 600; }
.card-opt span span { font-size: 14px; color: var(--secondary); }
.card-dot { width: 20px; height: 20px; margin-top: 1px; border: 1.5px solid var(--ring); border-radius: 50%; }
.card-opt[aria-checked="true"] { border-color: var(--accent-text); background: var(--accent-soft); }
.card-opt[aria-checked="true"] .card-dot { border: 6px solid var(--accent); }
.card-portal { display: flex; justify-content: space-between; align-items: center; gap: 10px; min-height: 52px; padding: 6px 14px; border-radius: 12px; background: var(--field); color: var(--text); text-decoration: none; font-size: 16px; }
.card-portal small { display: block; font-size: var(--fs-meta); color: var(--secondary); }
.card-open { color: var(--accent-text); font-weight: 600; }
.card-done { min-height: 52px; border-radius: 14px; background: var(--accent); color: var(--on-accent); font-size: var(--fs-body); font-weight: 650; }
.card-note { margin: -4px 0 0; font-size: var(--fs-meta); color: var(--secondary); text-align: center; }
.card-ask { display: flex; flex-direction: column; gap: 8px; padding: 14px; border-radius: 14px; background: var(--field); }
.card-ask input { min-height: 44px; padding: 0 12px; border: 1px solid var(--sep); border-radius: 10px; background: var(--sheet); color: var(--text); font: inherit; font-size: 16px; }
.card-hows { display: flex; flex-wrap: wrap; gap: 8px; }
.card-hows button { min-height: 44px; padding: 0 16px; border: 1.5px solid var(--sep); border-radius: 99px; background: var(--sheet); color: var(--text); font-size: 15px; font-weight: 600; }
.card-hows button[aria-pressed="true"] { border-color: var(--accent-text); background: var(--accent-soft); color: var(--accent-text); }
.card-ask-row { display: flex; gap: 8px; margin-top: 4px; }
.card-ask-row button { flex: 1; min-height: 48px; border-radius: 12px; font-size: var(--fs-body); font-weight: 650; }
.card-save { background: var(--accent); color: var(--on-accent); }
.card-save:disabled { opacity: 0.45; }
.card-cancel { border: 1px solid var(--sep); color: var(--text); }
.card-stamp { padding: 14px; border-radius: 14px; background: var(--accent-soft); color: var(--accent-text); font-size: 16px; font-weight: 600; }
.card-edit { align-self: center; min-height: 44px; padding: 0 12px; color: var(--secondary); font-size: 15px; }
.card-copy, .card-opt, .card-hows button { transition: background-color var(--dur-press) ease, border-color var(--dur-press) ease; }
.card-sheet button:focus-visible, .card-portal:focus-visible, .card-ask input:focus-visible { outline: 2px solid var(--accent-text); outline-offset: 2px; }
@media (min-width: 900px) { .card-sheet { width: 480px; max-height: 88vh; } }

/* Applications: an Apply task's vacancy against the CV. The sheet reuses the letter card's parts. */
.apply-open { display: flex; justify-content: space-between; align-items: center; gap: 10px; min-height: 56px; padding: 8px 14px; border-radius: 12px; background: var(--field); color: var(--text); font-size: var(--fs-body); text-align: left; }
.apply-open[hidden] { display: none; }
.apply-open small { display: block; font-size: var(--fs-meta); color: var(--secondary); }
.apply-open:focus-visible { outline: 2px solid var(--accent-text); outline-offset: 2px; }
.ap-wait, .ap-say { margin: 0; font-size: var(--fs-body); line-height: 1.4; color: var(--secondary); }
.ap-text { min-height: 140px; padding: 12px 14px; border: 0; border-radius: 12px; background: var(--field); color: var(--text); font: inherit; font-size: 16px; line-height: 1.4; resize: vertical; }
.ap-text:focus-visible { outline: 2px solid var(--accent-text); outline-offset: 0; }
.ap-fit { display: flex; flex-direction: column; gap: 3px; padding: 12px 14px; border-radius: 12px; background: var(--accent-soft); }
.ap-fit b { font-size: 20px; font-weight: 650; color: var(--accent-text); }
.ap-fit span { font-size: 15px; line-height: 1.4; }
.ap-fit small { font-size: var(--fs-meta); color: var(--secondary); }
.ap-fit.fit-fair { background: var(--amber-bg); }
.ap-fit.fit-fair b { color: var(--amber-ink); }
.ap-fit.fit-weak { background: var(--late-bg); }
.ap-fit.fit-weak b { color: var(--danger); }
.ap-gaps { margin: -6px 0 0; padding-left: 20px; display: flex; flex-direction: column; gap: 6px; font-size: 15px; line-height: 1.4; }
.ap-letter { white-space: pre-wrap; font-size: 15px; }
.ap-fit.fit-queued { background: var(--field); }
.ap-fit.fit-queued b { color: var(--text); font-size: 18px; }
.ap-folder { display: flex; flex-direction: column; gap: 3px; padding: 12px 14px; border-radius: 12px; border: 1px solid var(--sep); }
.ap-folder b { font-size: 15px; font-weight: 600; overflow-wrap: anywhere; }
.ap-folder small { font-size: var(--fs-meta); color: var(--secondary); }
.ap-more { display: flex; flex-direction: column; gap: 10px; }
.ap-more > summary { min-height: 44px; display: flex; align-items: center; font-size: var(--fs-body); font-weight: 600; color: var(--accent-text); cursor: pointer; list-style: none; }
.ap-more > summary::-webkit-details-marker { display: none; }
.ap-more > summary::after { content: '›'; margin-left: 8px; }
.ap-more[open] > summary::after { content: '⌄'; margin-left: 8px; }
.ap-more[open] > .hb-draft { margin-bottom: 10px; }
#apBody button:focus-visible, #apBody a:focus-visible { outline: 2px solid var(--accent-text); outline-offset: 2px; }

/* Increase Contrast (iOS and macOS): darker rings, secondary text and lines. The default look is unchanged. */
@media (prefers-contrast: more) {
  :root { --ring: #6E6E73; --secondary: #545458; --sep: #C6C6C8; }
}
@media (prefers-contrast: more) and (prefers-color-scheme: dark) {
  :root { --ring: #6E6E73; --secondary: #AEAEB2; --sep: #48484A; }
}
/* Forced colours drop backgrounds, so the selected section and the check use system colours. */
@media (forced-colors: active) {
  .seg button:is([aria-selected="true"], [aria-checked="true"], [aria-current="page"]), .nav-item[aria-current="page"] { outline: 2px solid Highlight; outline-offset: -2px; }
  .circle.checked { forced-color-adjust: none; background: Highlight; border-color: Highlight; color: HighlightText; }
}

/* Reduced motion: slides become fades, nothing bounces. --dist only reaches keyframes written
   with it, so each transform transition has its own rule here; app.js reads M.reduced and M.dist.
   Durations stay, so fades keep their pace. */
@media (prefers-reduced-motion: reduce) {
  :root { --dist: 0; }
  .sheet, .toast { animation: fade-in var(--dur-move) ease !important; }
  .sheet { transition: none; } /* the keyboard offset (translate) moves at once */
  .row.enter { animation: fade-in var(--dur-move) ease; }
  .fab { transition: opacity var(--dur-press) ease; }
  .fab:active { transform: none; opacity: 0.55; }
  .row.nudge .row-inner { animation: none; }
  .circle .ic, .row.armed .swipe-done .ic { transition: opacity var(--dur-press) ease; transform: none !important; }
  /* The thumb is placed at once (--dist does not reach var(--i)), and its label with it. */
  body.ready .seg::before { transition: none; }
  body.ready .seg button { transition: opacity var(--dur-press) ease; }
}

/* ---------- Intake: the paper-clip ---------- */
/* Same 44px hit area as the other icon buttons; in the desktop add row it sits inside the border. */
.cap-row .clip { margin-right: -10px; }
.inline-add .clip { width: 36px; height: 36px; margin-right: -8px; }
.clip:hover { color: var(--text); }
/* "Reading brief.pdf" under the title while the Worker asks Claude. The icon turns; not under reduced motion. */
.pill.reading .spin { animation: spin 1.2s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .pill.reading .spin { animation: none; } }
/* A task that came from a letter carries a small clip after its text, instead of the raw [intake] mark. */
/* ---------- Hiscores layer (app.js, Hiscores) ---------- */
/* Today's progress under the title: a line of text and a thin bar that fills by transform. */
.progress { display: flex; flex-direction: column; gap: 8px; margin: 2px 0 6px; }
.pbar { display: block; height: 4px; border-radius: 2px; background: var(--sep); overflow: hidden; }
#progressFill { display: block; height: 100%; border-radius: 2px; background: var(--accent); transform-origin: left center; transform: scaleX(0); }
body.ready #progressFill { transition: transform var(--dur-move) var(--ease); }
#progressText { font-variant-numeric: tabular-nums; }
/* The XP drop: rises from the row's right edge and fades (app.js xpDrop). */
.xpdrop {
  position: fixed; z-index: 13; display: flex; align-items: center; gap: 5px; pointer-events: none;
  font-size: 15px; font-weight: 700; color: var(--accent-text); font-variant-numeric: tabular-nums;
}
.xpdrop .skill { width: 16px; height: 16px; }
/* Today cleared: the day's XP by skill. */
.rewards { width: 100%; max-width: 360px; display: flex; flex-direction: column; align-items: center; gap: 14px; margin-top: 2px; }
.empty .rewards .rsum { font-size: 15px; }
.rlist { list-style: none; margin: 0; padding: 4px 0; width: 100%; border-radius: 14px; background: var(--surface); color: var(--text); }
.rlist li { display: flex; align-items: center; gap: 12px; min-height: 44px; padding: 0 16px; font-size: 15px; }
.rlist .rname { flex: 1; }
.rlist b { font-weight: 600; font-variant-numeric: tabular-nums; }
.rlist .rlevel { min-width: 60px; text-align: right; font-size: var(--fs-meta); color: var(--secondary); }
/* Done opens on the week (app.js renderWeek). */
.week { margin: 6px var(--gut-r) 4px var(--gut-l); padding: 14px 16px; border-radius: 14px; background: var(--surface); display: flex; flex-direction: column; gap: 12px; }
.wk-head { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; font-size: 15px; font-weight: 600; }
.wk-head .meta { font-weight: 400; font-variant-numeric: tabular-nums; }
.wk-bars { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 8px; align-items: end; height: 76px; }
.wk-day { display: flex; flex-direction: column; align-items: center; justify-content: flex-end; gap: 5px; height: 100%; }
.wk-n { font-size: 11px; color: var(--secondary); font-variant-numeric: tabular-nums; min-height: 13px; }
.wk-bar { display: block; width: 100%; max-width: 26px; border-radius: 4px; background: var(--accent); opacity: 0.35; }
.wk-day.now .wk-bar { opacity: 1; }
.wk-l { font-size: 11px; color: var(--secondary); }
.wk-day.now .wk-l { color: var(--text); font-weight: 600; }
.wk-skills { display: flex; flex-wrap: wrap; gap: 6px 14px; }
.wk-skills span { display: inline-flex; align-items: center; gap: 5px; font-size: var(--fs-meta); color: var(--secondary); font-variant-numeric: tabular-nums; }
.wk-skills .skill { width: 14px; height: 14px; }
/* The phone switcher's counts for Soon and Someday. */
.scount { margin-left: 5px; color: var(--secondary); font-weight: 400; }
.scount:empty { display: none; }
.seg button[aria-current="page"] .scount { color: inherit; opacity: 0.75; }
/* The edit sheet shows what the letter said, under the section picker. */
.edit-from { background: var(--field); border-radius: 12px; padding: 12px 14px; display: flex; flex-direction: column; gap: 6px; }
.edit-from p { margin: 0; font-size: var(--fs-body); line-height: 1.35; }
.edit-from ul { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 4px; }
.edit-from li { font-size: var(--fs-meta); color: var(--secondary); padding-left: 10px; border-left: 2px solid var(--sep); line-height: 1.35; }
/* Desktop: a file dragged over the list can be dropped on it. */
main.drop-files .list { outline: 2px dashed var(--accent-text); outline-offset: -2px; border-radius: 12px; min-height: 120px; }
