/* gtd-app's stylesheet, the one base.html links. It is the design system
   (design/, whose rules are docs/design-system/README.md and whose layout
   reference is docs/design-system/screens.html), the self-hosted fonts,
   then what the design system leaves to the app: the page frame, the
   capture box, forms, and the pages it has no component for. Everything
   here takes its colours, sizes, spacing and corners from its tokens. */

@import "fonts/fonts.css";
@import "design/styles.css";

*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }
body { margin: 0; min-height: 100vh; background: var(--bg-page); color: var(--text-title); font-size: var(--size-body); }
input, select, textarea { font: inherit; color: var(--text-title); }
a { color: inherit; }
q { quotes: none; font-weight: var(--weight-semibold); }
/* The focus ring follows the space's accent. A custom property is computed
   where it is declared, so --ring is declared again where the accent is set. */
body { --ring: 2px solid var(--accent); }

/* The accessibility floor (README, Type): 13px for anything a person reads.
   Mono labels and keycaps keep their 11px; counts and capsules come up. */
.lists .count, .item .meta .deadline { font-size: var(--size-meta); }

/* --- The frame: a 238px rail, then the capture bar over the page. ------ */
.frame { display: grid; grid-template-columns: var(--rail-width) minmax(0, 1fr); min-height: 100vh; }
.rail { position: sticky; top: 0; height: 100vh; overflow-y: auto; display: flex; flex-direction: column;
        gap: var(--s-8); padding: var(--s-7) var(--s-5); background: var(--bg-rail);
        border-right: 1px solid var(--border-card); }
.rail .lists { flex: 1; width: auto; padding: 0; background: none; border: 0; }
.rail .logout button { width: 100%; padding: 7px var(--s-5); text-align: left; background: none;
                       border-color: transparent; color: var(--text-muted); font-weight: var(--weight-regular); }
.rail .logout button:hover { border-color: var(--accent); }
.content { min-width: 0; display: flex; flex-direction: column; }
#page { width: 100%; max-width: 60rem; padding: var(--page-pad); }
#page.solo { max-width: none; }

/* The lists, in three groups (screens.html): Today and the GTD lists; after
   a rule, the containers; at the foot, quieter, Done and the Trash. A dot
   marks a list of items, a square a container (README, Iconography). */
.lists a::before { content: ""; flex: none; width: 7px; height: 7px; background: var(--line-3); }
.lists a.list::before { border-radius: var(--r-round); }
.lists a.container::before { border-radius: var(--r-dot); }
.lists a[aria-current="page"]::before { background: currentColor; }
.lists hr { width: calc(100% - 2 * var(--s-4)); height: 1px; margin: var(--s-6) auto; border: 0; background: var(--border-card); }
.lists a.states { margin-top: auto; }
.lists a.states, .lists a.states ~ a { color: var(--text-muted); }
.lists a.states:not([aria-current])::before, .lists a.states ~ a:not([aria-current])::before { background: var(--line-4); }
.lists a.states[aria-current], .lists a.states ~ a[aria-current] { color: var(--accent); }

/* --- Capture: a quiet bar that opens into a card over the page. -------- */
.capture { position: sticky; top: 0; z-index: 5; height: calc(var(--capture-line) + 1px); padding: 0; border: 0; background: none; }
.capture:focus-within { background: none; }
:root { --capture-line: 46px; }
.capture-box { position: absolute; inset: 0 0 auto; background: var(--bg-page); border-bottom: 1px solid var(--border-row);
               transition: border-color var(--fast) var(--ease); }
.capture:focus-within .capture-box { border-bottom-color: var(--accent); }
#capture { display: block; }
.capture-line { display: flex; align-items: center; gap: var(--s-6); height: var(--capture-line); padding: 0 var(--s-12); }
/* The bar's accent line, or the open card's border, shows the focus. */
#capture-title:focus-visible { outline: none; }
.capture-line .check { width: 16px; height: 16px; cursor: default; }
.capture-line .check:hover { border-color: var(--border-check); }
.capture-line kbd { flex: none; }
.capture-where { display: none; align-items: flex-end; gap: var(--s-5); padding: var(--s-6) var(--s-12);
                 background: var(--bg-page); }
.capture-where .where { flex: 1; min-width: 0; }
.capture-where > button[type="submit"] { flex: none; }
/* Open: something typed, a choice being made, or a pasted list to check. */
#capture:has(#capture-title:not(:placeholder-shown)) .capture-where,
#capture:has(.capture-where :focus) .capture-where { display: flex; }
.capture-box:has(#capture-title:not(:placeholder-shown)),
.capture-box:has(.capture-where :focus),
.capture-box:has(#capture-preview > *) {
  inset: 0 var(--s-8) auto; background: var(--bg-card); border: 1px solid var(--accent);
  border-radius: var(--r-card); box-shadow: var(--shadow-modal); overflow: hidden; }
.capture-box:has(#capture-title:not(:placeholder-shown)) .capture-line,
.capture-box:has(.capture-where :focus) .capture-line,
.capture-box:has(#capture-preview > *) .capture-line { padding: 0 calc(var(--s-12) - var(--s-8) - 1px); border-bottom: 1px solid var(--border-row); }
.capture-box:has(#capture-title:not(:placeholder-shown)) .capture-line .check,
.capture-box:has(.capture-where :focus) .capture-line .check { border-color: var(--accent); }
.capture-box .capture-where { padding-inline: calc(var(--s-12) - var(--s-8) - 1px); }
.capture-box .preview { margin: 0; border: 0; border-top: 1px solid var(--border-row); border-radius: 0; box-shadow: none;
                        padding: var(--s-8) calc(var(--s-12) - var(--s-8) - 1px); max-height: 70vh; overflow-y: auto; }
.capture-box #capture-preview > .hint, .capture-box #capture-preview > .error { margin: 0; padding: var(--s-6) calc(var(--s-12) - var(--s-8) - 1px); }
#capture-preview > button { margin: 0 0 var(--s-5) var(--s-5); }

/* Where to?: chips, Project last with its picker joined on. */
.where label { position: relative; }
/* The hidden radio covers its chip, so a press lands on the radio itself. */
.where input[type="radio"] { inset: 0; width: 100%; height: 100%; margin: 0; pointer-events: auto; cursor: pointer; }
.where label:has(:focus-visible) { outline: var(--ring); outline-offset: var(--ring-offset); }
.where label:has(input[value="project"]) { border-radius: var(--r-control) 0 0 var(--r-control); border-right: 0; }
.where label:has(input[value="project"]) + select { margin-left: calc(-1 * var(--s-4)); border-radius: 0 var(--r-control) var(--r-control) 0; }
.where label:has(input[value="project"]:checked) + select { border-color: var(--accent); }
/* A choice's details, each on a line of its own under the chips: shown
   once they apply. */
.where .detail, .where .note, .where .missing { flex-basis: 100%; order: 1; margin: 0; }
.where .detail { display: none; }
.where input.detail { font: var(--size-body) var(--font-sans); padding: var(--s-4) var(--s-6);
                      border: 1px solid var(--border-card); border-radius: var(--r-field); background: var(--paper-0); color: var(--text-title); }
.where input.detail::placeholder { color: var(--text-placeholder); }
.where .dates { flex-wrap: wrap; gap: var(--s-4); }
.where .date { display: flex; align-items: center; gap: var(--s-5); padding: var(--s-2) var(--s-2) var(--s-2) var(--s-6);
               border: 1px solid var(--border-card); border-radius: var(--r-field); background: var(--paper-0);
               font-size: var(--size-meta); color: var(--text-muted); }
.where .date input { font: var(--size-body) var(--font-sans); padding: var(--s-2) var(--s-4); border: 0; background: none; color: var(--text-title); }
.where:has(input[name="to"][value="waiting"]:checked) .detail[name="waiting_on"],
.where:has(input[name="to"][value="project"]:checked):has(option[value="new"]:checked) .detail[name="project_name"] { display: block; }
.where:has(input[name="to"][value="next"]:checked) .dates,
.where:has(input[name="to"][value="waiting"]:checked) .dates,
.where:has(input[name="to"][value="project"]:checked) .dates { display: flex; }
.where:has(input[name="to"][value="waiting"]:checked) .date.day { display: none; }
/* Calendar asks when it happens instead of the two plain days: the day, All
   day, and, unless that is ticked, the time it starts and how long it runs
   (space.When). The same block is a row's File as Calendar, so the rule
   that takes the time away is written on the block itself. */
.where .when { flex-wrap: wrap; gap: var(--s-4); }
.where:has(input[name="to"][value="calendar"]:checked) .when { display: flex; }
.when:has(input[name="all_day"]:checked) .at,
.when:has(input[name="all_day"]:checked) .runs { display: none; }
.where .when .runs input { width: 6ch; }
/* The same block in a row's File as, where it takes a line of its own under
   the deadline, labelled as the deadline is. */
.popover .pick.when { flex-wrap: wrap; font-size: var(--size-meta); color: var(--text-muted); }
.popover .pick.when .all-day { display: flex; align-items: center; gap: var(--s-3); white-space: nowrap; }
.popover .pick.when .when-label { flex-basis: 100%; }
.popover .pick.when .runs { display: flex; align-items: center; gap: var(--s-2); }
.popover .pick.when .runs input { flex: none; width: 4.5rem; }
/* With nothing chosen, one quiet line says where the capture goes; once a
   choice lacks what it needs, the line under it says what. */
.where .note { display: none; font-size: var(--size-meta); color: var(--text-muted); }
.where:not(:has(input[name="to"]:checked)) .note { display: block; }
.where .missing { font-size: var(--size-meta); color: var(--deadline); }
.where [aria-invalid="true"] { border-color: var(--deadline); }
.preview .where { margin-top: var(--s-7); }
.preview li { display: flex; align-items: center; gap: var(--s-4); }
.preview li input[name="title"] { min-width: 0; color: var(--text-title); }
.preview li input:disabled { color: var(--text-muted); text-decoration: line-through; }
.preview input[type="checkbox"] { accent-color: var(--accent); width: 16px; height: 16px; margin: 0; }
.preview .hint { margin-top: 0; }
.outbox { margin: 0; padding: var(--s-4) var(--s-12) 0; }
.outbox li { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-4); padding: var(--s-2) 0; }
.outbox .what { max-width: 60%; overflow: hidden; color: var(--text-title); text-overflow: ellipsis; white-space: nowrap; }

/* --- Buttons and fields. ------------------------------------------------ */
button[type="submit"].primary:hover, #capture button[type="submit"]:hover {
  background: color-mix(in srgb, var(--accent) 94%, var(--ink-0)); }
.buttons { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-5); }
.buttons a { font-size: var(--size-meta); color: var(--text-body); }
.editor input:not([type]), .editor input[type="date"], .editor input[type="number"], .editor input[type="url"], .editor select, .editor textarea, .login input {
  font: var(--size-body) var(--font-sans); padding: var(--s-3) var(--s-5); border: 1px solid var(--border-control);
  border-radius: var(--r-field); background: var(--paper-0); color: var(--text-title); }
.editor textarea { resize: vertical; line-height: var(--leading-body); }
.error:not(.toast) { margin: 0 0 var(--s-5); font-size: var(--size-meta); color: var(--deadline); }
.status { font-weight: var(--weight-semibold); color: var(--text-body); }

/* --- Rows. --------------------------------------------------------------- */
.item .line { flex-wrap: wrap; row-gap: var(--s-2); }
.item .title { min-width: 0; overflow-wrap: anywhere; }
.item .meta { flex-wrap: wrap; justify-content: flex-end; }
.item .meta a { text-decoration: underline; text-decoration-color: var(--border-control); text-underline-offset: 0.2em; }
.check { display: flex; align-items: center; justify-content: center; }
.check--square { border-radius: 3px; }
span.check { cursor: default; }
span.check:hover:not(.check--done) { border-color: var(--border-check); }
.confirm { display: flex; align-items: center; gap: var(--s-2); }
.confirm summary::-webkit-details-marker { display: none; }
.confirm summary:hover { border-color: var(--accent); }

/* A passed planned day is quiet: plain grey text that opens the
   reschedule choices, never red. Only a deadline shouts. */
.rolled { padding: 0 var(--s-3); font: var(--size-meta) var(--font-sans); color: var(--text-muted);
          background: none; border: 1px solid var(--border-control); border-radius: var(--r-capsule); }
.item:has(> .popover:popover-open) .rolled { border-color: var(--accent); color: var(--text-title); }

/* A stalled project is flagged the way the project page flags it. */
.meta .flag { font-family: var(--font-mono); font-size: var(--size-label); letter-spacing: var(--tracking-label);
              text-transform: uppercase; color: var(--deadline); }

/* --- Goals (the captain, 2026-09-15), GTD's Horizon 3. Quiet throughout:
   a goal between projects is normal, not late, so nothing here is rust. -- */

/* A project's goal on its page, named the way a row names its project:
   quiet text with an underlined link, never the accent. */
.about .goal a { color: var(--text-body); text-decoration: underline;
                 text-decoration-color: var(--border-control); text-underline-offset: 0.2em; }
.about .goal a:hover { color: var(--text-title); }

/* The goal page's Link a project: a picker and its button on one line. */
.link-project { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-4); padding: var(--s-2) var(--s-2) var(--s-4); }
.link-project select { flex: 1 1 14rem; min-width: 0; font: var(--size-body) var(--font-sans); padding: var(--s-3) var(--s-5);
                       border: 1px solid var(--border-control); border-radius: var(--r-field); background: var(--paper-0);
                       color: var(--text-title); }

/* The Goals page's quarterly review, at its foot. */
.goals-review { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-4) var(--s-7);
                margin-top: var(--section-gap); padding-top: var(--s-8); border-top: 1px solid var(--border-row);
                font-size: var(--size-meta); color: var(--text-muted); }
.goals-review p { flex: 1; min-width: 14rem; margin: 0; }

/* The goal editor's Move to Trash, apart from Save. */
.goal-trash { max-width: 36rem; margin-top: var(--section-gap); padding-top: var(--s-8); border-top: 1px solid var(--border-row); }
.goal-trash .hint { margin: 0 0 var(--s-5); }

/* --- Toasts float over the page. --------------------------------------- */
.toasts { position: fixed; left: 50%; bottom: var(--s-9); z-index: 10; width: max-content;
          max-width: calc(100vw - 2 * var(--s-8)); transform: translateX(-50%); }
.toast { box-shadow: var(--shadow-pop); }
.toast q { display: inline-block; max-width: 18rem; overflow: hidden; text-overflow: ellipsis;
           white-space: nowrap; vertical-align: bottom; }
.toast form { margin: 0; }

/* --- Pages. -------------------------------------------------------------- */
#page > section + section, #page > section + .footer { margin-top: var(--section-gap); }
.heading { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s-2) var(--s-7); margin-bottom: var(--section-gap); }
.heading h1 { margin: 0; }
.heading .date { margin: 0; font-size: var(--size-row); color: var(--text-muted); }

.heading .total { margin: 0; font-size: var(--size-row); color: var(--text-muted); }

/* The Library: the books read, a wall of covers by the year they were read
   (README, Imagery: covers are the captain's own content, the one kind of
   picture the app shows). A cover is 2:3 on a card's border and corner; a
   book with none is a plain card with its title set in type, never broken
   image art. */
.books { list-style: none; margin: var(--s-4) 0 0; padding: 0; display: grid;
         grid-template-columns: repeat(auto-fill, minmax(112px, 1fr)); gap: var(--s-9) var(--s-8); }
.book { display: flex; flex-direction: column; gap: var(--s-4); color: var(--text-title); text-decoration: none; }
.book:hover .book-title { text-decoration: underline; }
.book:focus-visible { outline: none; }
.book:focus-visible .cover { outline: var(--ring); outline-offset: var(--ring-offset); }
.book-title { font-size: var(--size-meta); line-height: var(--leading-snug); overflow-wrap: break-word; hyphens: auto; }
.cover { display: block; aspect-ratio: 2 / 3; overflow: hidden; background: var(--bg-rail);
         border: 1px solid var(--border-card); border-radius: var(--r-capsule); box-shadow: var(--shadow-raise); }
.cover img { display: block; width: 100%; height: 100%; object-fit: cover; }
.cover--plain { display: flex; flex-direction: column; justify-content: space-between; gap: var(--s-4);
                padding: var(--s-6) var(--s-5); background: var(--bg-card); }
.cover-title { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 6; overflow: hidden;
               font-size: var(--size-body); font-weight: var(--weight-semibold); line-height: var(--leading-snug);
               letter-spacing: var(--tracking-hero); color: var(--text-title); overflow-wrap: break-word; hyphens: auto; }
.cover-author { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden;
                font-family: var(--font-mono); font-size: var(--size-label); letter-spacing: var(--tracking-label);
                text-transform: uppercase; color: var(--text-muted); overflow-wrap: break-word; hyphens: auto; }
#page code { font-family: var(--font-mono); font-size: var(--size-capsule); color: var(--text-body); }

/* The Library's Add book: the title with Look up beside it, then what the
   lookup found as smaller covers to pick from, the one picked marked in the
   accent as a chosen Where to? chip is. */
.book-form { margin-bottom: var(--section-gap); }
.book-form .lookup { display: flex; gap: var(--s-3); }
.book-form .lookup input { flex: 1; min-width: 0; }
.book-form input[type="number"] { width: 7rem; }
.found:empty { display: none; }
.found .hint, .found .error { margin: var(--s-2) 0; }
.found-books { grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: var(--s-8) var(--s-6); margin: var(--s-3) 0 0; }
button.book { width: 100%; padding: 0; border: 0; background: none; font: inherit; text-align: left; cursor: pointer; }
.book-by { font-size: var(--size-meta); color: var(--text-muted); overflow-wrap: break-word; }
button.book[aria-pressed="true"] .cover { border-color: var(--accent); outline: 1px solid var(--accent); }
button.book[aria-pressed="true"] .book-title { color: var(--accent); font-weight: var(--weight-semibold); }

/* A book's page: its cover beside its title, author, year and thoughts. */
.back { margin: 0 0 var(--s-8); font-size: var(--size-meta); }
.back a { color: var(--text-muted); text-decoration: none; }
.back a:hover { text-decoration: underline; }
.book-page { display: grid; grid-template-columns: 180px minmax(0, 1fr); gap: var(--s-12); align-items: start; }
.book-page h1 { overflow-wrap: anywhere; }
.thoughts p:not(.empty):not(.buttons) { max-width: 42rem; margin: 0 0 var(--s-6); font-size: var(--size-row);
                                        color: var(--text-body); white-space: pre-wrap; overflow-wrap: anywhere; }
.thoughts .buttons a { display: inline-flex; align-items: center; gap: 7px; color: var(--accent); text-decoration: none; }
.thoughts .buttons a:hover { text-decoration: underline; }
.editor #thoughts { min-height: 18rem; }

/* Today: the One Thing is the page's one card. */
.hero { margin-bottom: var(--section-gap); }
.hero .check--hero { margin-top: var(--s-1); }
.hero-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--s-3); }
.hero .kicker { margin: 0; }
.hero .item { padding: 0; border: 0; }
.hero .item:hover, .hero .item:focus-within { background: none; }
.hero .item .line { align-items: baseline; }
.hero .outcome { color: var(--text-title); line-height: var(--leading-snug); }
.hero .add { padding: 0; }
.hero .add input { font-size: var(--size-hero); font-weight: var(--weight-semibold); letter-spacing: var(--tracking-hero); }
.hero .hint { margin: 0; }
.carry { margin-top: var(--s-3); padding: var(--s-6) var(--s-7); border: 1px solid var(--border-card);
         border-radius: var(--r-control); font-size: var(--size-body); color: var(--text-body); }
.carry p { margin: 0 0 var(--s-5); }
.carry form { margin: 0; }
.done-today { margin-top: var(--s-8); }
.done-today summary { cursor: pointer; font-family: var(--font-mono); font-size: var(--size-label);
                      letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-muted); }
.done-today summary .count { font-size: var(--size-meta); letter-spacing: 0; }
.done-today .items { margin-top: var(--s-3); }
.footer { font-size: var(--size-meta); color: var(--text-muted); }
.footer--links { display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-8); }

/* Today's actions, with the calendar column beside them (screens.html):
   the hard landscape, loaded right after the page appears. */
.today-split { display: flex; gap: var(--s-11); align-items: flex-start; }
.today-split > section:first-child { flex: 1; min-width: 0; }
.today-split + section, .today-split + .footer { margin-top: var(--section-gap); }

/* A calendar, on Today and the Calendar page: a time column wide enough
   for "All day", and a deadline mark's capsule, the one loud thing in it.
   Its label is the design system's h2, as the actions' is. */
.calendar ul { list-style: none; margin: 0; padding: 0; }
.calendar li { align-items: baseline; font-size: var(--size-body); color: var(--text-title); }
.calendar li:last-child { border-bottom: none; }
.calendar time { width: auto; min-width: 44px; }
.calendar .what { min-width: 0; overflow-wrap: anywhere; }
.calendar li a { color: inherit; text-decoration: none; }
.calendar li a:hover { text-decoration: underline; }
.calendar .location, .calendar .length { color: var(--text-muted); }
.calendar .unsent { color: var(--text-muted); font-style: italic; }
/* A calendar item of the app's own, beside Google's events: the accent
   marks it as ours, in the time column alone, so the day still reads as
   one list. */
.calendar li.mine time { color: var(--accent); font-weight: var(--weight-semibold); }
.calendar .deadline { flex: none; background: var(--deadline-wash); color: var(--deadline); font-size: var(--size-meta);
                      font-weight: var(--weight-semibold); padding: var(--s-1) var(--s-4); border-radius: var(--r-capsule); }
.calendar .notice { margin: 0 0 var(--s-4); font-size: var(--size-meta); color: var(--text-muted); }
.calendar .notice--alert { color: var(--text-title); font-weight: var(--weight-semibold); }
.calendar .hint { margin-top: 0; }
.calendar .refresh { margin-top: var(--s-5); font-weight: var(--weight-regular); }
.calendar--page { width: auto; border-left: 0; padding-left: 0; }
.calendar--page .day + .day { margin-top: var(--s-9); }
.calendar--page .day h2 .date { margin-left: var(--s-3); font-family: var(--font-sans); font-size: var(--size-meta);
                                letter-spacing: 0; text-transform: none; }
.calendar--page .empty { margin: 0; }

/* A space whose Google grant is broken says so on every one of its pages,
   and on no page of another space. */
.banner { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-4) var(--s-7); margin-bottom: var(--section-gap);
          padding: var(--s-6) var(--s-7); background: var(--bg-card); border: 1px solid var(--accent); border-radius: var(--r-card);
          font-size: var(--size-body); color: var(--text-body); }
.banner p { flex: 1; min-width: 12rem; margin: 0; }
.banner form { margin: 0; }

/* Settings: at the foot of the rail, and the page's Google Calendar. */
.rail .settings { padding: 7px var(--s-5); border: 1px solid transparent; border-radius: var(--r-control);
                  font-size: var(--size-meta); color: var(--text-muted); text-decoration: none; }
.rail .settings:hover { border-color: var(--accent); }
.rail .settings[aria-current="page"] { background: var(--paper-0); color: var(--accent); font-weight: var(--weight-semibold);
                                       box-shadow: var(--shadow-lift); }
.settings h2 { margin-top: 0; }
.settings .said { font-size: var(--size-meta); color: var(--text-body); }
.settings .banner { margin: var(--s-7) 0; }
.settings form { margin-top: var(--s-7); }
.settings .writes { margin-top: var(--s-7); }
.settings .writes h3 { margin: 0; }
.choices fieldset { display: grid; gap: var(--s-4); margin: 0; padding: 0; border: 0; }
.choices legend { margin-bottom: var(--s-4); padding: 0; font-size: var(--size-meta); font-weight: var(--weight-semibold); color: var(--text-body); }
.choices label { display: flex; align-items: center; gap: var(--s-4); font-size: var(--size-body); color: var(--text-title); }
.choices input[type="checkbox"] { accent-color: var(--accent); width: 16px; height: 16px; margin: 0; }
.choices .hint { margin: 0; }

/* About: the one page for anyone, with no rail. */
.about-page { max-width: 42rem; margin: var(--s-12) auto; padding-inline: var(--s-8); font-size: var(--size-row);
              line-height: var(--leading-body); color: var(--text-body); }
.about-page .kicker { margin: 0; font-family: var(--font-mono); font-size: var(--size-label); letter-spacing: var(--tracking-caps);
                      text-transform: uppercase; color: var(--text-muted); }
.about-page h1 { margin: var(--s-2) 0 var(--s-7); color: var(--text-title); }
.about-page h2 { margin-top: var(--s-10); }
.about-page h3 { margin: var(--s-7) 0 var(--s-3); font-size: var(--size-row); color: var(--text-title); }
.about-page a { color: var(--text-title); }

/* The One Thing's history: a row per day. */
.days { list-style: none; margin: 0; padding: 0; }
.days li { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s-2) var(--s-6);
           padding: var(--s-4) var(--s-2); border-bottom: 1px solid var(--border-row); font-size: var(--size-body); }
.days li:last-child { border-bottom: none; }
.days .when { width: 7.5rem; flex: none; font-family: var(--font-mono); font-size: var(--size-meta); color: var(--text-muted); }
.days a { text-decoration: none; }
.days a:hover { text-decoration: underline; }
.days .meta { margin-left: auto; font-size: var(--size-meta); color: var(--text-muted); }

/* A project's page: the outcome, its status and notes, a section per list,
   each with its own Add box. */
.about { flex-wrap: wrap; }
.about a { color: var(--accent); text-decoration: none; }
.about a:hover { text-decoration: underline; }
.notes { white-space: pre-wrap; overflow-wrap: anywhere; }
#page section > .add::before { content: ""; width: 18px; height: 18px; flex: none; border: 1.5px dashed var(--border-check);
                               border-radius: var(--r-round); }
#page section > .add { gap: var(--row-gap); padding-block: var(--s-5); }
#page section > .add input { font-size: var(--size-body); }

/* The editors. */
.editor { display: grid; gap: var(--s-3); max-width: 36rem; }
.editor > label, .editor legend { margin-top: var(--s-5); font-size: var(--size-meta);
                                  font-weight: var(--weight-semibold); color: var(--text-body); }
.editor .hint { font-weight: var(--weight-regular); }
.editor .date, .editor .repeat, .editor .repeat fieldset, .editor .chips, .editor .target {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-3); margin: 0; padding: 0; border: 0; }
.editor .date legend, .editor .repeat legend, .editor .chips legend, .editor .target legend { float: left; width: 100%; padding: 0; }
.editor .quick { display: inline-flex; flex-wrap: wrap; gap: var(--s-3); }
.editor .quick button { font-weight: var(--weight-regular); }
/* A calendar item's editor asks when it happens instead of the two days and
   the repeat, in the shared When fields. The rule that takes the time and
   the length away once All day is ticked is written on .when itself, so it
   holds here as it does in the capture box and in a row's File as. */
.editor .when { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-5); margin: 0; padding: 0; border: 0; }
.editor .when legend { float: left; width: 100%; padding: 0; }
.editor .when .date, .editor .when .all-day { display: flex; align-items: center; gap: var(--s-3);
                                              font-size: var(--size-meta); color: var(--text-muted); }
.editor .when input[type="number"] { width: 6rem; }
/* The Repeat rule: every N units, then its weekdays and how it counts as
   chips, each a label round a hidden input, as Where to? is. */
.editor .repeat .hint { margin: 0; }
.editor #repeat-rule > label { font-size: var(--size-meta); color: var(--text-body); }
.editor #repeat-every { width: 5rem; font: var(--size-body) var(--font-sans); padding: var(--s-3) var(--s-5);
                        border: 1px solid var(--border-control); border-radius: var(--r-field); background: var(--paper-0); }
.editor .repeat .quick label, .editor .chips label { position: relative; display: flex; align-items: center; padding: var(--s-3) 11px;
      border: 1px solid var(--border-control); border-radius: var(--r-control); background: var(--bg-page);
      font-size: var(--size-meta); color: var(--text-body); cursor: pointer; }
.editor .repeat .quick label:hover, .editor .chips label:hover { border-color: var(--accent); }
.editor .repeat .quick label:has(:checked), .editor .chips label:has(:checked) { border-color: var(--accent); background: var(--paper-0);
      color: var(--accent); font-weight: var(--weight-semibold); }
.editor .repeat .quick label:has(:focus-visible), .editor .chips label:has(:focus-visible) { outline: var(--ring); outline-offset: var(--ring-offset); }
.editor .repeat .quick label input, .editor .chips label input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }

/* A repeating action's mark: a small ring before its rule, a CSS shape as
   the README's iconography asks, not a glyph. */
.meta .repeats { display: inline-flex; align-items: center; gap: var(--s-3); }
.meta .repeats::before { content: ""; width: 7px; height: 7px; border: 1.5px solid currentColor; border-radius: var(--r-round); }
.editor .buttons { margin-top: var(--s-8); }

/* Habits (design section 11). Today's card is the design system's .habits:
   two columns under a label for each time of day, its heading across the
   top as screens.html has it. */
.habits-head { grid-column: 1 / -1; display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--s-2) var(--s-6); }
.habits-head h2 { margin: 0; font-family: var(--font-mono); font-size: var(--size-label); font-weight: var(--weight-regular);
                  letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-muted); }
.habits-head .tally, .habits-head .last, .habits-head .streak-count { font-size: var(--size-meta); color: var(--text-muted); }
.habits-head .last { margin-left: auto; }
.habits-head .streak-count { display: none; }
.habits .group { margin: 0; font-weight: var(--weight-regular); }
.habits .empty { grid-column: 1 / -1; margin: 0; }
.habit .check-in { display: flex; margin: 0; }
.habit .check { width: 17px; height: 17px; }
.habit .name { min-width: 0; color: inherit; text-decoration: none; overflow-wrap: anywhere; }
.habit .name:hover { text-decoration: underline; }
.habit .meta { display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-4); font-size: var(--size-meta); color: var(--text-muted); }
/* The Habits page: a group for each time of day, a row for each habit. */
.habit-list { list-style: none; margin: 0; padding: 0; }
.habit-list > li { border-bottom: 1px solid var(--border-row); }
.habit-list > li:last-child { border-bottom: none; }
.habit-list .habit { flex-wrap: wrap; padding: var(--row-pad-y) var(--s-2); font-size: var(--size-row); color: var(--text-title); }
.heading [data-reveal] { margin-left: auto; }
.habit-form { margin-bottom: var(--section-gap); }
/* The weekday picker and the count per week show only for their schedule
   (the captain, on prototype A). */
.habit-form .weekdays, .habit-form .per-week { display: none; }
.habit-form:has(input[name="kind"][value="weekdays"]:checked) .weekdays,
.habit-form:has(input[name="kind"][value="per_week"]:checked) .per-week { display: flex; }
.habit-form .per-week { flex-wrap: wrap; align-items: center; gap: var(--s-3); margin: var(--s-5) 0 0; }
.habit-form .per-week label { font-size: var(--size-meta); font-weight: var(--weight-semibold); color: var(--text-body); }
.habit-form input[type="number"] { width: 7rem; }
.archived { margin-top: var(--section-gap); }
.archived summary { cursor: pointer; font-family: var(--font-mono); font-size: var(--size-label);
                    letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-muted); }
.archived summary .count { font-size: var(--size-meta); letter-spacing: 0; }
/* A habit's recent days: each checked in, skipped or cleared on its row. */
.habit-days .state { font-size: var(--size-meta); color: var(--text-body); }
.habit-days .record { margin: 0 0 0 auto; display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); }
.habit-days .record input { width: 6rem; font: var(--size-meta) var(--font-sans); padding: var(--s-3) var(--s-5);
                            border: 1px solid var(--border-card); border-radius: var(--r-field); background: var(--paper-0); }
.habit-days .record button { font-weight: var(--weight-regular); }
.archive { margin-top: var(--section-gap); }

/* The Weekly Review (phase 10): a phase's label, then its steps, each a
   round tick (a habit's check-in, a toggle) beside the step's name, what
   it asks in the David Allen Company's words, and what it looks at in the
   space: the pages it goes through, and the rows and calendar it brings
   up. A ticked step keeps its colour: nothing is greyed out as done. */
.heading .heading-action { margin: 0 0 0 auto; }
.review-phase + .review-phase { margin-top: var(--section-gap); }
.review-steps { list-style: none; margin: 0; padding: 0; }
.review-step { display: flex; gap: var(--row-gap); align-items: flex-start; padding: var(--s-7) var(--s-2);
               border-bottom: 1px solid var(--border-row); }
.review-step:last-child { border-bottom: none; }
.review-step .check-in { display: flex; margin: 3px 0 0; }
.review-step .step { flex: 1; min-width: 0; }
.review-step h3 { margin: 0; font-size: var(--size-row); font-weight: var(--weight-semibold); color: var(--text-title); }
.review-step .asks { margin: var(--s-2) 0 0; font-size: var(--size-body); color: var(--text-body); }
.review-step .hint { margin: var(--s-3) 0 0; }
.step-links { list-style: none; display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-8); margin: var(--s-4) 0 0; padding: 0;
              font-size: var(--size-meta); color: var(--text-muted); }
.step-links a { font-weight: var(--weight-semibold); color: var(--text-title); text-decoration: none; }
.step-links a:hover { text-decoration: underline; }
.step-links span::before { content: "· "; }
.review-step .step-label { margin: var(--s-7) 0 var(--s-2); font-family: var(--font-mono); font-size: var(--size-label);
                           letter-spacing: var(--tracking-label); text-transform: uppercase; color: var(--text-muted); }
.review-step .items { margin: 0; }
.review-step > .step > .empty { margin: var(--s-4) 0 0; }
.calendar--review { margin-top: var(--s-5); }
.calendar--review .day + .day { margin-top: var(--s-6); }
.calendar--review .day h4 { margin: 0 0 var(--s-1); font-size: var(--size-meta); font-weight: var(--weight-semibold); color: var(--text-body); }
.calendar--review .day h4 .date { margin-left: var(--s-3); font-weight: var(--weight-regular); color: var(--text-muted); }
.calendar--review li { padding: var(--s-3) 0; }
.review-complete { margin-top: var(--section-gap); }

/* Plan Tomorrow: the day's One Thing, the page's one card as on Today;
   then its actions beside its calendar column, laid out as Today's are;
   then the Waiting For items to chase. How late one is stays plain text:
   its deadline capsule is the loud part. */
.heading p.heading-action { font-size: var(--size-meta); }
.heading-action a { color: var(--text-muted); }
.plan-split { display: flex; gap: var(--s-11); align-items: flex-start; }
.plan-lists { flex: 1; min-width: 0; }
.plan-lists > section + section { margin-top: var(--section-gap); }
.plan-lists .hint { margin-top: 0; }
.plan-split + section { margin-top: var(--section-gap); }
#chase .hint { margin-bottom: 0; }

/* A habit's metrics (the captain, 2026-09-14): its streaks, its days done
   and its consistency, on the habits card's quieter paper. */
.metrics { margin: var(--section-gap) 0; padding: var(--s-6) var(--s-7); background: var(--paper-4);
           border: 1px solid var(--border-card); border-radius: var(--r-card); }
.metrics dl { display: flex; flex-wrap: wrap; gap: var(--s-4) var(--s-9); margin: var(--s-4) 0 0; }
.metrics dl > div { display: flex; flex-direction: column; gap: var(--s-2); min-width: 8rem; }
.metrics dt { font-size: var(--size-meta); color: var(--text-muted); }
.metrics dd { margin: 0; font-size: var(--size-row); color: var(--text-title); }

/* The Habits page's overall activity, and a habit's own calendar of done,
   missed and skipped days: a week per column, a day per row, shaded like
   GitHub's contribution graph. The grid scrolls on its own so the page
   never does (phone width). */
.activity { margin: var(--section-gap) 0; padding: var(--s-6) var(--s-7); background: var(--paper-4);
            border: 1px solid var(--border-card); border-radius: var(--r-card); }
.cal-scroll { overflow-x: auto; margin-top: var(--s-4); padding-bottom: var(--s-2); }
.cal-grid { display: inline-flex; gap: 3px; }
.cal-week { display: flex; flex-direction: column; gap: 3px; }
.cell { display: block; width: 10px; height: 10px; border-radius: var(--r-dot); background: var(--line-4); }
.cell.blank { background: transparent; }
/* The overall heatmap: none, then four tints of the space's accent. */
.cell.heat-0 { background: var(--line-4); }
.cell.heat-1 { background: color-mix(in srgb, var(--accent) 25%, var(--paper-3)); }
.cell.heat-2 { background: color-mix(in srgb, var(--accent) 50%, var(--paper-3)); }
.cell.heat-3 { background: var(--ochre-streak); }
.cell.heat-4 { background: var(--ochre-tick); }
/* A habit's own calendar: done fills, missed is only a ring (never rust:
   that means a deadline), skipped and pending stay quiet. */
.cell.done { background: var(--ochre-tick); }
.cell.skipped { background: var(--paper-3); border: 1px solid var(--line-2); }
.cell.missed { background: var(--paper-0); border: 1px solid var(--line-3); }
.cell.pending { background: transparent; border: 1px solid var(--line-0); }
.legend { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); }
.legend .cell { margin: 0 var(--s-2); }
.legend .consistency { margin-left: auto; color: var(--text-body); }

/* Logging in: the one page with no rail, in Personal's ochre since no
   space is chosen yet (the captain, 2026-09-12). A field in focus takes
   the accent on its border as well as its ring. */
.login { max-width: 22rem; margin: 12vh auto 0; padding: var(--card-pad); background: var(--bg-card);
         border: 1px solid var(--border-card); border-radius: var(--r-card); box-shadow: var(--shadow-raise); }
.login form { display: grid; gap: var(--s-3); }
.login label { margin-top: var(--s-4); font-size: var(--size-meta); font-weight: var(--weight-semibold); color: var(--text-body); }
.login input:focus { border-color: var(--accent); }
.login .kicker { margin: 0; font-family: var(--font-mono); font-size: var(--size-label); letter-spacing: var(--tracking-caps);
                text-transform: uppercase; color: var(--text-muted); }
.login h1 { margin: var(--s-2) 0 var(--s-4); }
.login button { margin-top: var(--s-8); padding: var(--s-4) var(--s-7); }
.bar { display: flex; justify-content: flex-end; padding: var(--s-6) var(--s-12); border-bottom: 1px solid var(--border-row); }

/* --- The phone nav and Today's habits disclosure, at every width: the
   drawer button stays off unless a phone-width media query below turns it
   on. today.html always renders <details class="habits" open>, which a
   closed <details>'s own UA behaviour (Chromium skips its content for
   layout, paint and the accessibility tree alike, not just display:none
   on each child, so no author CSS on the children can override it) makes
   the only reliable way to keep desktop's habits card always expanded
   without JavaScript; app.js closes it again on a phone-width viewport,
   after the initial load and after every reload() swap (its open
   attribute is server-rendered afresh each time). */
.nav-toggle { display: none; }
.habits summary { list-style: none; cursor: default; pointer-events: none; }
.habits summary::-webkit-details-marker { display: none; }
.habits .disclose { display: none; }
.sort-count { display: none; }
.label-phone { display: none; }
.countdown { display: none; }

/* --- Narrow screens: the rail goes above the page. ---------------------- */
@media (max-width: 760px) {
  .frame { grid-template-columns: minmax(0, 1fr); }
  .rail { position: static; height: auto; gap: var(--s-5); border-right: 0; border-bottom: 1px solid var(--border-card); }
  .rail .lists { flex-direction: row; flex-wrap: wrap; }
  .lists hr { display: none; }
  .lists a.states { margin-top: 0; }
  .capture-line, .capture-where, .outbox { padding-inline: var(--s-8); }
  .capture-box:has(#capture-title:not(:placeholder-shown)), .capture-box:has(.capture-where :focus),
  .capture-box:has(#capture-preview > *) { inset: 0 var(--s-2) auto; }
  #page { padding: var(--s-9) var(--s-8); }
  .books { grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: var(--s-8) var(--s-6); }
  .book-page { grid-template-columns: minmax(0, 1fr); gap: var(--s-9); }
  .book-page > .cover { width: 140px; }
  .habits { grid-template-columns: minmax(0, 1fr); }
  .today-split { flex-direction: column; }
  .today-split > .calendar { width: auto; border-left: 0; padding-left: 0; }
  /* Plan Tomorrow's calendar goes first once the column is gone: the hard
     landscape is what the rest of the day is planned around. */
  .plan-split { flex-direction: column; align-items: stretch; }
  .plan-split > .calendar { order: -1; width: auto; border-left: 0; padding-left: 0; }
}

/* --- Phone: one screen, no tab bar (mobile.html, "What changes from
   desktop"). Measurements below are mobile.html's own table; a 480px cut
   comfortably covers the 390/375px frames it was drawn at. Colour, spacing
   scale, radii and shadows are untouched — only sizes named there change,
   most of them by redeclaring the same tokens desktop already uses. --------- */
@media (max-width: 480px) {
  :root {
    --size-page-title: 30px;
    --size-row: 16px;
    --r-card: var(--r-frame);
  }

  /* The three lines: everything but Today lives behind them (rule 1). A
     CSS shape, not a glyph or an SVG (README, Iconography). */
  .nav-toggle { display: flex; align-items: center; justify-content: center;
    position: fixed; top: var(--s-6); right: var(--s-6); z-index: 30;
    width: 44px; height: 44px; padding: 0; border: 1px solid var(--border-control);
    border-radius: var(--r-control); background: var(--bg-card); box-shadow: var(--shadow-raise); }
  .nav-toggle span, .nav-toggle span::before, .nav-toggle span::after {
    content: ""; display: block; width: 18px; height: 1.5px; background: var(--text-title); }
  .nav-toggle span::before { transform: translateY(-5px); }
  .nav-toggle span::after { transform: translateY(3.5px); }
  .nav-toggle span { position: relative; background: var(--text-title); }

  /* The rail becomes the menu screen: off-canvas until the three lines, or
     a link in it, open it (rule 1: no tab bar, no bottom bar). */
  .frame { position: relative; }
  .rail { position: fixed; inset: 0 0 0 auto; width: 86%; z-index: 20; height: 100vh;
    max-width: 340px; border-right: 0; box-shadow: var(--shadow-pop);
    transform: translateX(100%); transition: transform var(--base) var(--ease);
    padding-top: calc(var(--s-7) + 52px); }
  .rail.open { transform: translateX(0); }
  .nav-scrim { position: fixed; inset: 0; z-index: 15; background: rgba(27, 26, 24, 0.35); }
  .rail .lists { flex-direction: column; flex-wrap: nowrap; }

  /* Menu / nav rows: 48px min, 16px label (mobile.html Measurements). */
  .lists a, .rail .settings, .spaces .space { min-height: 48px; font-size: 16px; }
  .lists a { padding-inline: var(--s-6); }

  /* Frame: 22px side padding, everywhere (mobile.html Measurements). */
  #page { padding-inline: 22px; }
  .capture-line, .capture-where, .outbox { padding-inline: 22px; }
  .capture-box:has(#capture-title:not(:placeholder-shown)), .capture-box:has(.capture-where :focus),
  .capture-box:has(#capture-preview > *) { inset: 0 var(--s-4) auto; }
  /* The three lines sit fixed at the top right of every page (44x44, top
     and right var(--s-6)): a heading's own right-aligned control (Add
     habit, Add book) stops clear of that corner instead of sitting under it. */
  .heading { padding-right: 60px; }

  /* Task row: 66px min, 22px checkbox, the whole row is the target
     (Measurements; Rules worth keeping, #1). A transparent hit-slop takes
     the check itself past 44x44 without inflating the visible ring. */
  .item .line { min-height: 66px; }
  .item .check, .habit .check { width: 22px; height: 22px; position: relative; }
  .item .check::before, .habit .check::before { content: ""; position: absolute; inset: -11px; }

  /* Habit row: 44px min, 22px checkbox. */
  .habit { min-height: 44px; }

  /* Habits close to one line (rule 3): the closed row is 48px, and its
     disclosure reads Show / Hide, never a bare triangle. */
  .habits summary { pointer-events: auto; cursor: pointer; min-height: 48px; }
  .habits .disclose { display: inline-flex; margin-left: auto; font-size: var(--size-meta);
    font-weight: var(--weight-semibold); color: var(--accent); }
  .habits .disclose::after { content: "Show"; }
  details.habits[open] .disclose::after { content: "Hide"; }
  .habits-head .last { display: none; }
  .habits-head .streak-count { display: inline; }

  /* One event, not a day (rule 4): Today's calendar shows only the next
     event, computed in Go (calendar.go, nextEntryIndex) so a past one is
     never the one kept, with a countdown; deadline marks (rust, rule 5)
     stay regardless of how many there are. Once nothing is left and there
     is no deadline either, calendar.go marks the day with a hidden
     .day-empty (NothingLeft), and the whole section, heading included,
     goes with it. */
  .today-split #calendar .label-desktop { display: none; }
  .today-split #calendar .label-phone { display: inline; }
  .today-split > .calendar li:not(.mark):not(.next) { display: none; }
  .today-split .countdown { display: inline; margin-left: auto; flex: none;
    font-size: var(--size-meta); color: var(--text-muted); }
  .today-split .countdown::before { content: attr(data-countdown); }
  .today-split > .calendar:has(.day-empty) { display: none; }

  /* Chip / button: 44px min tap target (Measurements; Rules worth keeping,
     #1 — nothing tappable goes under it), every button (a habit's Recent
     days: Done, Skip, Clear; Today's Carry over card; and the rest) except
     the round check, which keeps its own 22px ring and hit-slop above, and
     a found book's whole-cover choice, already far taller than that. */
  button:not(.check):not(.book), .button { min-height: 44px; }
  .where label, .editor .repeat .quick label, .editor .chips label { min-height: 44px; }
  button[type="submit"].primary, .primary, #capture button[type="submit"] { padding-inline: 18px; }

  /* Sorting is one card at a time (rule 5): the Inbox shows the first open
     item; the rest wait, and "N to sort" above already names how many
     (list.html) — a card generating display:none produces no box, so a
     counter incremented on the same rule would never advance; the count
     already on the page makes one unnecessary anyway. */
  .sort-count { display: block; margin: 0 0 var(--s-4); font-size: var(--size-meta); color: var(--text-muted); }
  .items--inbox .item:not([hidden]) ~ .item:not([hidden]) { display: none; }

  /* Goals (the captain, 2026-09-15). The whole row is the target (Rules
     worth keeping #1): a goal's or a project's row is one link from edge
     to edge, so the link covers the 66px row rather than only its words.
     The rest is the 44px floor applied to the controls Goals adds. */
  .items--links .item { position: relative; }
  .items--links .title::after { content: ""; position: absolute; inset: 0; }
  .about--goal a, .about .goal a { display: inline-flex; align-items: center; min-height: 44px; }
  #add-goal-project { min-height: 44px; }
  .link-project select { flex-basis: 100%; min-height: 44px; }
  .link-project button { flex: 1; }
  .goal-form input, .goal-form select { min-height: 44px; }

  /* The Weekly Review: the tick is the 22px ring with its hit-slop, as a
     row's is; a step's page links take the 44px floor. */
  .review-step .check { width: 22px; height: 22px; position: relative; }
  .review-step .check::before { content: ""; position: absolute; inset: -11px; }
  .review-step .check-in { margin-top: 1px; }
  .step-links a { display: inline-flex; align-items: center; min-height: 44px; }
  .step-links { row-gap: 0; }
  .review-complete button { width: 100%; }

  /* Plan Tomorrow and Today's links to what waits: each link takes the
     44px floor. */
  .heading p.heading-action { flex-basis: 100%; margin-left: 0; }
  .heading-action a, .footer--links a, #chase .hint a { display: inline-flex; align-items: center; min-height: 44px; }
  .footer--links { row-gap: 0; }
}
