/* Plain CSS, no framework and no build step.
 *
 * Ordered: tokens → base → layout → components → utilities → themes.
 *
 * Calm and considered, because of what this holds. The journal contains other
 * people's diagnoses and struggles, by name (workflows.md §Platform and trust),
 * and it is read while praying. Nothing here should compete with the sentence
 * someone is looking at.
 *
 * Two rules the palette exists to keep. Nothing turns red for being old —
 * workflows.md: "nothing turns red", and that includes the sync line. And the
 * one celebratory colour in the app belongs to answered prayers, because a
 * prayer answered is the only thing here worth celebrating.
 */

/* ── tokens ──────────────────────────────────────────────────────────────── */

:root {
  color-scheme: light dark;

  /* Type: a small scale. Titles carry weight rather than size, so a list of
     prayers reads as a list rather than as a stack of headlines. */
  --text-xs: 0.75rem;
  --text-sm: 0.85rem;
  --text-base: 1rem;
  --text-lg: 1.125rem;
  --text-xl: 1.375rem;
  --line-height: 1.5;
  --measure: 66ch;

  /* Space: one 4px scale. Vertical rhythm is most of what makes a ranking
     scannable, and most of the difference from the page this replaced. */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;

  --radius: 14px;
  --radius-sm: 8px;
  --radius-lg: 16px;
  --radius-card: 20px;
  --radius-sheet: 24px;
  --radius-pill: 999px;
  --tap: 44px;
  /* The bottom strip, whichever of the two is showing. Tall enough for the
     nav's stacked icon-over-label, which is the taller of them. */
  --bar-height: 4.75rem;

  /* The visible pill inside a 44px target. The mocks draw chips at 34px, and
     docs/ui.md §4.6's floor is about the *target*, so the target is the box and
     the pill is painted on a child of it (docs/SPEC.md §2). */
  --chip-height: 34px;

  /* The wordmark, and nothing else. A serif in a sans app is a mark rather
     than a typeface choice, which is why it is one token and one rule. */
  --serif: ui-serif, Georgia, "Times New Roman", serif;

  /* Light: a warm off-white ground with the cards raised off it, rather than
     white cards on white. */
  --bg: #f7f3ec;
  --surface: #fffdf9;
  --fg: #231f1b;
  --muted: #5d554c;
  --line: #e6ded2;
  --line-strong: #bcb0a0;

  /* Two accents, and which is which matters. Apricot is the app's accent: the
     primary action, the active tab, a selected filter. Mint is *answered*, and
     only answered — docs/ui.md §4.6's "the only celebratory colour in the app"
     is not amended, and the mock that prompted this repaint had them the other
     way round. */
  --accent: #a94f22;
  --accent-fg: #fffaf6;
  --answered: #1f6145;
  --danger: #8f2f1c;
  --focus: #a94f22;

  /* The sixteen the mocks use and the palette did not have (docs/SPEC.md §2).
     The mocks are dark only; these are the light half, derived from the values
     above that the dark block already mirrors one-to-one. */
  --surface-sunken: #efe9de;
  /* Dark raises the edited field by lightening it. Light cannot: the surface is
     already a near-white, so the field is *warmed* instead. Same job -- this is
     the one field being typed into -- reached the only way the ground allows. */
  --surface-raised: #fbf2e4;
  /* A selected chip is accent *on* this, so the wash is bounded from below by
     the 4.5 floor rather than by taste: anything warmer than this and the one
     control that says "this filter is on" stops meeting AA (ui.md §4.8). */
  --accent-wash: #f9eadf;
  --danger-wash: #fbeae5;
  --danger-line: #e8c3b8;
  --danger-quiet: #a06452;
  --nav-bg: #fffdf9;
  --line-soft: #eee7db;
  --line-inset: #e6ded2;
  --fg-dim: #3b352d;
  --fg-dimmer: #4a443c;
  --muted-2: #6b6358;
  --muted-3: #7a7266;
  --muted-4: #8a8279;
  --placeholder: #9a9186;
  --editable-line: #d2c8b8;
}

/* ── themes ──────────────────────────────────────────────────────────────── */

@media (prefers-color-scheme: dark) {
  :root {
    /* A warm charcoal, not a blue-black: this is read at night, beside a bed,
       and a cold ground makes prose look like a terminal. */
    --bg: #17140f;
    --surface: #221e19;
    --fg: #ece7e0;
    --muted: #aaa298;
    --line: #332e28;
    --line-strong: #544c43;
    --accent: #f0a875;
    --accent-fg: #241a13;
    --answered: #86c8a6;
    --danger: #e9998a;
    --focus: #f0a875;

    /* Straight from the mocks (docs/SPEC.md §2). */
    --surface-sunken: #1e1a15;
    --surface-raised: #2a251e;
    --accent-wash: #2c211a;
    --danger-wash: #241a17;
    --danger-line: #4a2f2a;
    --danger-quiet: #8f6a60;
    --nav-bg: #1a1611;
    --line-soft: #262119;
    --line-inset: #2e2922;
    --fg-dim: #c9c1b8;
    --fg-dimmer: #b8b0a6;
    --muted-2: #8a8279;
    --muted-3: #7d766c;
    --muted-4: #6f6963;
    --placeholder: #615b53;
    --editable-line: #3d3730;
  }
}

/* ── base ────────────────────────────────────────────────────────────────── */

* {
  box-sizing: border-box;
}

body {
  font-family: system-ui, -apple-system, sans-serif;
  color: var(--fg);
  background: var(--bg);
  max-width: 46rem;
  margin: 0 auto;
  padding: var(--space-4) var(--space-4) 0;
  line-height: var(--line-height);
  font-size: var(--text-base);
  -webkit-text-size-adjust: 100%;
}

h1 {
  font-size: var(--text-base);
  font-weight: 600;
  margin: 0;
}

/* System serif, letterspaced, in the accent (docs/SPEC.md §4). */
.wordmark {
  font-family: var(--serif);
  font-size: var(--text-lg);
  font-weight: 600;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--accent);
}

h2 {
  font-size: var(--text-xl);
  font-weight: 600;
  letter-spacing: -0.01em;
  margin: 0 0 var(--space-4);
}

h3 {
  font-size: var(--text-base);
  font-weight: 600;
  margin: var(--space-5) 0 var(--space-2);
}

p {
  margin: 0;
  max-width: var(--measure);
}

input,
textarea,
button,
select {
  font: inherit;
  color: inherit;
  padding: var(--space-2);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  min-height: var(--tap);
}

/* Hand-written inline SVG, drawn as strokes so one rule sizes and colours every
   icon in the app. `currentColor`, so an icon is never a second thing to
   re-theme. */
.icon {
  width: 1.25rem;
  height: 1.25rem;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

textarea {
  min-height: 4.5rem;
  resize: vertical;
}

/* A file input sizes itself to its button plus a filename, which is wider than
   a 320px phone. It is the one control that overflows if left alone. */
input[type="file"] {
  max-width: 100%;
}

button {
  cursor: pointer;
}

button:hover {
  border-color: var(--fg);
}

/* Non-negotiable, in both themes. */
:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

/* `hidden` is an attribute the app sets from JS, so it has to beat any
   `display` a component rule gives the same element. design.md §8's CSP
   (`style-src 'self'`) is why visibility is an attribute at all. */
[hidden] {
  display: none !important;
}

/* ── layout ──────────────────────────────────────────────────────────────── */

header {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  flex-wrap: wrap;
  padding-bottom: var(--space-4);
  border-bottom: 1px solid var(--line);
  margin-bottom: var(--space-5);
}

main {
  /* The nav is fixed; the last of a view has to clear it. */
  padding-bottom: calc(5rem + env(safe-area-inset-bottom));
}

.view h2:focus:not(:focus-visible) {
  outline: none;
}

.toolbar {
  display: flex;
  gap: var(--space-2);
  margin: var(--space-2) 0;
  flex-wrap: wrap;
  align-items: center;
}

.filters {
  display: flex;
  gap: var(--space-2);
  flex-wrap: wrap;
  align-items: center;
  margin-bottom: var(--space-4);
}

.filters label {
  font-size: var(--text-sm);
  color: var(--muted);
}

/* ── find row and the filter sheet (docs/SPEC.md §3.7) ───────────────────── */

.find-row {
  display: flex;
  gap: var(--space-2);
  align-items: center;
  margin-bottom: var(--space-4);
}

/* The magnifier sits inside the field rather than beside it, so the row reads
   as one control and the field keeps the whole width it can get. */
.field-icon {
  position: relative;
  flex: 1;
  min-width: 8rem;
  display: flex;
  align-items: center;
}

.field-icon > .icon {
  position: absolute;
  left: var(--space-3);
  color: var(--muted);
  pointer-events: none;
}

#browse-query {
  width: 100%;
  padding-left: calc(var(--space-3) + 1.25rem + var(--space-2));
}

#open-filters {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

/* It scrolls inside itself with a sticky action bar. A sort, three statuses, N
   tags and a date range is taller than a 320px phone, and a modal that scrolls
   the page behind it is a modal that loses its buttons. */
#filter-sheet {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0;
  width: min(30rem, calc(100vw - 2rem));
  max-height: min(40rem, calc(100vh - 2rem));
  color: var(--fg);
  background: var(--surface);
  overflow: hidden;
}

#filter-sheet::backdrop {
  background: rgb(0 0 0 / 45%);
}

#filter-form {
  display: flex;
  flex-direction: column;
  max-height: inherit;
}

.sheet-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--line);
}

.sheet-head h3 {
  font-size: var(--text-lg);
}

.sheet-body {
  overflow-y: auto;
  padding: var(--space-3) var(--space-4);
}

.sheet-group {
  border: 0;
  padding: 0;
  margin-bottom: var(--space-4);
}

.sheet-group > legend {
  font-size: var(--text-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: var(--space-2);
}

/* The four sorts as one grouped list rather than four loose rows: they are
   mutually exclusive, and a list with hairlines between the choices says that
   where four floating radios do not. */
.choice {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--tap);
  padding: 0 var(--space-3);
  font-size: var(--text-sm);
  border: 1px solid var(--line-inset);
  border-bottom-width: 0;
  background: var(--surface-sunken);
}

.choice:first-of-type {
  border-radius: var(--radius) var(--radius) 0 0;
}

.choice:last-of-type {
  border-bottom-width: 1px;
  border-radius: 0 0 var(--radius) var(--radius);
}

.choice:has(input:checked) {
  border-color: var(--accent);
  background: var(--accent-wash);
  color: var(--accent);
  font-weight: 600;
}

/* Chips over real checkboxes (docs/SPEC.md §6). The control is still an
   `<input type="checkbox">` — it is what carries the disabled state, the
   keyboard behaviour and the accessible name — and the pill is what is drawn,
   the same two-box arrangement the rhythm chips use. */
.status-chip {
  position: relative;
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  cursor: pointer;
}

.status-chip > input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.status-chip:has(input:checked) > .chip-pill {
  border-color: var(--accent);
  background: var(--accent-wash);
  color: var(--accent);
  font-weight: 600;
}

.status-chip:has(input:focus-visible) > .chip-pill {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

/* Disabled under Smart priority, and saying so rather than merely refusing:
   #smart-note is beside them whenever this is true. */
.status-chip:has(input:disabled) {
  cursor: default;
}

.status-chip:has(input:disabled) > .chip-pill {
  opacity: 0.55;
}

.chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

/* Sticky, so the two buttons are reachable however long the tag list gets. */
.sheet-actions {
  position: sticky;
  bottom: 0;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-top: 1px solid var(--line);
  background: var(--surface);
}

#apply-filters {
  flex: 1;
}

/* ── nav ─────────────────────────────────────────────────────────────────── */

/* One strip along the bottom, in two states: the nav, and the editing bar that
   stands in for it while a field has focus (docs/SPEC.md §3.6).

   The same box, and that is load-bearing rather than tidy. The two swap on a
   blur -- which is to say on the *mousedown* of whatever was pressed next -- so
   a bar that changed height would move what is under the finger between the
   press and the release, and the release would land on the bar instead of on
   the button. `--bar-height` is what keeps them the same, and appearance.spec.js
   pins it. */
#viewnav,
#editingbar {
  position: fixed;
  inset: auto 0 0 0;
  display: flex;
  align-items: center;
  min-height: calc(var(--bar-height) + env(safe-area-inset-bottom));
  background: var(--nav-bg);
  border-top: 1px solid var(--line);
}

#viewnav {
  justify-content: center;
  gap: var(--space-1);
  padding: var(--space-2) var(--space-2) calc(var(--space-2) + env(safe-area-inset-bottom));
}

#viewnav a {
  flex: 1 1 0;
  max-width: 10rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  min-height: var(--tap);
  padding: var(--space-2);
  border-radius: var(--radius);
  color: var(--muted);
  text-decoration: none;
  font-size: var(--text-xs);
}

/* Apricot, and the label goes solid: colour alone is not a state anyone can
   see in every light, and `aria-current` is what a screen reader reads. */
#viewnav a[aria-current="page"] {
  color: var(--accent);
  font-weight: 600;
  background: var(--bg);
}

/* ── the editing bar (docs/SPEC.md §3.6) ─────────────────────────────────── */

#editingbar {
  gap: var(--space-3);
  padding: var(--space-2) var(--space-4)
    calc(var(--space-2) + env(safe-area-inset-bottom));
}

#editing-what {
  flex: 1;
  font-size: var(--text-xs);
  color: var(--muted-3);
}

#done-editing {
  background: none;
  border: 1px solid transparent;
  color: var(--accent);
  font-size: var(--text-sm);
  font-weight: 600;
}

/* ── capture ─────────────────────────────────────────────────────────────── */

.fab {
  position: fixed;
  right: var(--space-4);
  bottom: calc(5rem + env(safe-area-inset-bottom));
  width: 3.5rem;
  height: 3.5rem;
  border-radius: 50%;
  border: 1px solid transparent;
  background: var(--accent);
  color: var(--accent-fg);
  font-size: var(--text-xl);
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 2px 8px rgb(0 0 0 / 18%);
}

/* Grows with what is open, and scrolls inside itself rather than off the
   screen -- the same shape as the filter sheet, for the same reason: the
   primary action has to stay reachable however tall the middle gets. */
#capture-dialog {
  border: 1px solid var(--line);
  border-radius: var(--radius-sheet);
  padding: 0;
  width: min(30rem, calc(100vw - 2rem));
  max-height: min(44rem, calc(100vh - 2rem));
  color: var(--fg);
  background: var(--surface);
  overflow: hidden;
}

#capture-dialog::backdrop {
  background: rgb(0 0 0 / 45%);
}

#capture-form {
  display: flex;
  flex-direction: column;
  max-height: inherit;
}

.sheet-head h2 {
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--muted-2);
}

.sheet-foot {
  padding: var(--space-3) var(--space-4);
  border-top: 1px solid var(--line);
}

#capture-form input,
#capture-form textarea {
  width: 100%;
  display: block;
}

/* The one field on the fast path, and the only place in the app a control is
   drawn with the accent baseline: it is where the cursor already is. */
#capture-title {
  border: 0;
  border-bottom: 2px solid var(--accent);
  border-radius: 0;
  background: none;
  font-size: var(--text-lg);
  padding: var(--space-2) 0;
}

#capture-adders {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: var(--space-3) 0;
}

/* Dashed, because each is an offer rather than a fact -- the same treatment the
   tag strip's `+ Tag` gets, for the same reason. */
.adder {
  min-height: var(--tap);
  padding: 0 12px;
  border: 1px dashed var(--line-inset);
  border-radius: var(--radius-pill);
  background: none;
  color: var(--muted-3);
  font-size: var(--text-sm);
}

.adder[aria-expanded="true"] {
  border-style: solid;
  border-color: var(--accent);
  color: var(--accent);
}

.capture-section {
  margin-bottom: var(--space-4);
}

.capture-section > .eyebrow {
  margin-bottom: var(--space-2);
}

#capture-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: var(--space-2);
}

.hint {
  font-size: var(--text-xs);
  color: var(--muted-3);
  margin-top: var(--space-2);
}

#capture {
  width: 100%;
  min-height: 50px;
  border: 1px solid transparent;
  border-radius: var(--radius);
  background: var(--accent);
  color: var(--accent-fg);
  font-size: var(--text-sm);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

#close-capture {
  background: none;
  border: 1px solid transparent;
  color: var(--muted);
  font-size: var(--text-sm);
}

.capture-status {
  padding: 0 var(--space-4) var(--space-3);
  font-size: var(--text-sm);
  color: var(--muted);
  min-height: 1.4em;
}

/* ── the mode line (docs/SPEC.md §5) ─────────────────────────────────────── */

.mode-line {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-4) var(--space-3);
}

#filter-chips {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
}

/* Pushed right, and last in the source too, so the reading order is the order
   the eye takes it in: this order, these filters, this many. */
#result-count {
  margin-left: auto;
  font-size: var(--text-xs);
  color: var(--muted-3);
}

/* A fact you can remove, so it is the accent and not `--danger`: dropping a
   filter loses nothing (docs/ui.md §4.5). */
.mode-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  min-height: var(--tap);
  padding: 0 10px;
  border: 1px solid var(--accent);
  border-radius: var(--radius-pill);
  background: var(--accent-wash);
  color: var(--accent);
  font-size: var(--text-xs);
  font-weight: 600;
}

.mode-chip .icon {
  width: 0.72rem;
  height: 0.72rem;
}

/* The one control that says the list is narrowed. It used to be a `·` appended
   to the label, which said something was on without saying what. */
#open-filters.on {
  border-color: var(--accent);
  color: var(--accent);
}

/* ── prayers: the one row (docs/SPEC.md §3) ──────────────────────────────── */

#prayers,
#tags {
  list-style: none;
  padding: 0;
  margin: 0;
}

/* Rows on the ground, separated by a line. No card, no shadow, no per-row
   background — that flattening is most of the de-clunking, and it is what lets
   the *open* row be a card without every closed one competing with it. */
#prayers li.prayer-item {
  border-top: 1px solid var(--line-soft);
}

/* Centred, and given room. An empty list is a whole screen, and a sentence
   flush left at the top of one reads as an error message. */
#prayers li.empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-5) var(--space-4);
  text-align: center;
  color: var(--muted);
}

.empty-title {
  font-family: var(--serif);
  font-size: var(--text-lg);
  color: var(--fg-dim);
}

.empty-body {
  font-size: var(--text-sm);
  color: var(--muted-3);
  max-width: 24rem;
}

/* At most one, and only where there is something to do: a filtered list has no
   single action that undoes "the filters", so it is offered none. */
.empty-action {
  margin-top: var(--space-2);
  padding: 0 var(--space-4);
  border: 1px solid var(--accent);
  border-radius: var(--radius-pill);
  background: none;
  color: var(--accent);
  font-size: var(--text-sm);
  font-weight: 600;
}

.prayer-row {
  /* A closed row is nothing at all; an open one is the card. */
  margin: 0;
}

/* The whole collapsed row is the summary, so a tap anywhere on it opens the
   card. The marker goes: the caret at the end of the action row is the
   affordance, and a second triangle beside the title says the same thing
   twice. */
.row-head {
  display: block;
  cursor: pointer;
  padding: 15px var(--space-4) 16px;
  list-style: none;
}

.row-head::-webkit-details-marker {
  display: none;
}

.prayer-title {
  font-weight: 600;
  font-size: var(--text-lg);
  letter-spacing: -0.01em;
  line-height: 1.3;
}

/* Quiet, factual, never urgent. No colour for age (docs/ui.md §4.7). */
.prayer-meta,
.card-meta {
  margin-top: var(--space-1);
  font-size: var(--text-sm);
  color: var(--muted-2);
}

.latest-note {
  margin-top: 9px;
  font-size: var(--text-sm);
  color: var(--muted-3);
  line-height: 1.5;
}

.latest-note::before {
  content: "\201C";
}

.latest-note::after {
  content: "\201D";
}

.row-actions {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  flex-wrap: wrap;
  margin-top: 10px;
}

/* The row's one primary action, and the only filled thing on a closed row. */
.prayed,
.reopen {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: var(--tap);
  padding: 0 var(--space-4);
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  background: var(--accent);
  color: var(--accent-fg);
  font-size: var(--text-sm);
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

.prayed .icon,
.reopen .icon,
.mark-prayed .icon {
  width: 0.9rem;
  height: 0.9rem;
}

/* Marked on this screen: the row does not move (workflow 2's frozen order), it
   states what happened and offers the way back. */
.prayer-item.done .prayer-title {
  font-size: var(--text-base);
  font-weight: 500;
  color: var(--muted-3);
}

.prayer-item.done > .prayer-row > .row-head {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  flex-wrap: wrap;
}

.prayer-item.done .latest-note {
  display: none;
}

.prayer-item.done .row-actions {
  margin: 0 0 0 auto;
}

.prayed[aria-pressed="true"] {
  background: none;
  border-color: transparent;
  color: var(--accent);
  font-weight: 600;
  text-transform: none;
  letter-spacing: 0;
  padding: 0 var(--space-2);
}

/* A prayer's tags, stated. Read-only here: the list is read one-handed while
   praying, and a ✕ under a resting thumb can rewrite a prayer someone is only
   looking at (docs/SPEC.md §3.3). */
.tag-facts {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
}

.row-tag {
  font-size: 0.7rem;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--muted-3);
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  padding: 5px 10px;
}

.row-caret {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-left: auto;
  width: 32px;
  height: 32px;
  color: var(--muted-4);
}

/* ── the open row, which is the card (docs/SPEC.md §3.1) ─────────────────── */

.prayer-row[open] {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-card);
  margin: var(--space-2) var(--space-3);
  padding: var(--space-4) 18px;
}

/* Open, the summary is a caret and nothing else: everything it was showing is
   now on the card, larger and editable. The caret stays because a disclosure
   you cannot close is not one — the mock's card has no way back. */
.prayer-row[open] > .row-head {
  display: flex;
  justify-content: flex-end;
  padding: 0;
  min-height: var(--tap);
  align-items: center;
}

.prayer-row[open] > .row-head > :not(.row-actions) {
  display: none;
}

.prayer-row[open] > .row-head .row-actions > :not(.row-caret) {
  display: none;
}

.prayer-row[open] > .row-head .row-actions {
  margin: 0;
}

.prayer-row[open] .row-caret {
  transform: rotate(180deg);
}

.prayer-card {
  display: none;
}

.prayer-row[open] > .prayer-card {
  display: block;
  margin-top: -8px;
}

/* Shown once, over the first card opened, until the first edit lands
   (docs/SPEC.md §3.7). */
.edit-hint {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-xs);
  color: var(--muted-4);
  margin-bottom: var(--space-3);
}

.edit-hint .icon {
  width: 0.9rem;
  height: 0.9rem;
}

.card-title-row {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
}

/* ── fields that save themselves (docs/SPEC.md §3.2) ─────────────────────── */

/* At rest, a dashed baseline and nothing else: the affordance that says this is
   a field, without a box that says it is a form. */
.editable {
  width: 100%;
  min-height: 0;
  padding: 0 0 5px;
  border: 0;
  border-bottom: 1px dashed var(--editable-line);
  border-radius: 0;
  background: none;
  color: inherit;
  caret-color: var(--accent);
  resize: none;
  font: inherit;
}

.editable::placeholder {
  color: var(--placeholder);
}

/* Being typed into: raised, with the highlight bleeding past the text, and the
   dashed rule replaced by a solid accent one. */
.editable.editing {
  background: var(--surface-raised);
  border-radius: var(--radius-sm);
  border-bottom: 2px solid var(--accent);
  margin: -4px -6px 0;
  padding: 4px 6px;
  width: calc(100% + 12px);
}

.card-title {
  font-size: 1.3rem;
  font-weight: 600;
  letter-spacing: -0.015em;
  line-height: 1.25;
}

/* `Saved`, once a write lands. --muted and not mint: mint means answered
   (docs/ui.md §4.6, docs/SPEC.md §3.4). */
.saved {
  flex: none;
  font-size: var(--text-xs);
  color: var(--muted);
}

.saved:empty {
  display: none;
}

.card-meta {
  margin-top: 6px;
}

.card-details {
  margin-top: var(--space-3);
  font-size: var(--text-sm);
  line-height: 1.55;
  color: var(--fg-dimmer);
}

.card-divider {
  height: 1px;
  background: var(--line-inset);
  margin: var(--space-4) 0 14px;
}

.eyebrow {
  font-size: 0.66rem;
  font-weight: 600;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--muted-2);
}

/* ── the note thread ─────────────────────────────────────────────────────── */

.note-thread {
  list-style: none;
  padding: 0;
  margin: var(--space-3) 0 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.note-thread .note {
  margin: 0;
  padding: 0;
}

.note-date {
  font-size: 0.72rem;
  color: var(--muted-4);
  margin-bottom: 2px;
}

.note-text {
  font-size: var(--text-sm);
  line-height: 1.5;
}

.note-new {
  margin-top: var(--space-3);
  font-size: var(--text-sm);
  line-height: 1.5;
}

/* Inside the note being edited, and nowhere else (docs/SPEC.md §3.5). */
.note-tools {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-top: 10px;
}

.done-note {
  background: none;
  border: 1px solid transparent;
  color: var(--accent);
  font-size: var(--text-sm);
  font-weight: 600;
  padding: 0 var(--space-2);
}

/* ── the card's own actions ──────────────────────────────────────────────── */

.mark-prayed {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  width: 100%;
  min-height: 50px;
  margin-top: var(--space-4);
  border: 1px solid transparent;
  border-radius: var(--radius);
  background: var(--accent);
  color: var(--accent-fg);
  font-size: var(--text-sm);
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.mark-prayed[aria-pressed="true"] {
  background: none;
  border-color: var(--line);
  color: var(--muted);
}

.card-actions {
  display: flex;
  align-items: center;
  gap: 18px;
  margin-top: var(--space-3);
  padding-top: var(--space-3);
  border-top: 1px solid var(--line-inset);
  flex-wrap: wrap;
}

/* Answered and set aside are "the distinction that matters" (workflows 4 and
   5), so they never look like the same button. Mint here is not an exception to
   §4.6: this *is* the answered action. */
.answered {
  background: none;
  border: 1px solid transparent;
  color: var(--answered);
  font-size: var(--text-sm);
  font-weight: 600;
}

.set-aside {
  background: none;
  border: 1px solid transparent;
  color: var(--muted);
  font-size: var(--text-sm);
}

.closing-form {
  display: flex;
  gap: var(--space-2);
  margin-top: var(--space-3);
  flex-wrap: wrap;
}

.closing-note-input {
  flex: 1;
  min-width: 10rem;
}

.prayer-status {
  margin-left: var(--space-2);
  font-size: var(--text-xs);
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}

.prayer-status[data-status="answered"] {
  color: var(--answered);
}

/* ── chips: one geometry, three jobs ─────────────────────────────────────── */

/* The target and the pill are two boxes (docs/SPEC.md §2). ui.md §4.6 puts a
   44px floor on anything tappable and the mocks draw chips at 34px; painting
   the pill on an inner span is how both are true at once, rather than shipping
   a 34px tap target or a 44px pill nobody asked for. */
.rhythm-chip,
.tag-chip {
  position: relative;
  display: inline-flex;
  align-items: center;
  min-height: var(--tap);
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  cursor: pointer;
}

.chip-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: var(--chip-height);
  padding: 0 13px;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  font-size: var(--text-sm);
  color: var(--fg-dim);
}

/* ── the rhythm picker ───────────────────────────────────────────────────── */

/* Six tappable choices, all visible at once (workflows.md §Setting a rhythm).
   They wrap rather than shrink below the touch target: showing all six is the
   rule, one row is only the ideal. */
.rhythm-picker {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  border: 0;
  padding: 0;
  margin: var(--space-2) 0 0;
}

.rhythm-picker legend {
  font-size: var(--text-sm);
  color: var(--muted);
  padding: 0;
}

/* The radio itself is not drawn: the pill is the control, and a dot beside it
   would say the same thing twice. It stays in the DOM because that is where the
   keyboard behaviour, the group and the accessible name come from (ui.md §2).
   Stretched over the label rather than shrunk to a pixel: a 1px control is a 1px
   hit area, and the label is what anyone is aiming at. */
.rhythm-chip > input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.rhythm-chip:has(input:checked) > .chip-pill,
.tag-chip.on > .chip-pill {
  border-color: var(--accent);
  background: var(--accent-wash);
  color: var(--accent);
  font-weight: 600;
}

.rhythm-chip:has(input:focus-visible) > .chip-pill {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}

/* ── the tag strip, on the card (docs/SPEC.md §3.3) ──────────────────────── */

/* A prayer's tags, editable where the prayer is. Only the ones it is in are
   shown; the rest are one tap behind `+ Tag`, so a row with no tags costs one
   small chip and a row with two costs three. */
.tag-strip {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 7px;
  margin-top: var(--space-3);
}

/* Deliberately not --danger: removing a tag loses nothing, and colouring it as
   destructive would put it in the same family as Delete (docs/ui.md §4.5). */
.tag-chip.on > .chip-pill {
  padding: 0 9px 0 11px;
}

.tag-add {
  display: inline-block;
}

/* `+ Tag` is the disclosure's summary, so open state and the accessibility tree
   come free -- the same reason the row itself uses a <details>. */
.tag-add > summary {
  list-style: none;
}

.tag-add > summary::-webkit-details-marker {
  display: none;
}

/* Dashed, because it is an offer rather than a fact. */
.tag-chip.add > .chip-pill {
  border-style: dashed;
  color: var(--muted-3);
}

.tag-add[open] > summary > .chip-pill {
  border-color: var(--accent);
  color: var(--accent);
}

.tag-add-panel {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
  margin-top: var(--space-2);
  padding: var(--space-2);
  border: 1px solid var(--line-inset);
  border-radius: var(--radius);
  background: var(--surface-sunken);
}

.new-tag-form {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
  width: 100%;
}

.new-tag-name {
  flex: 1;
  min-width: 8rem;
}

/* ── destructive ─────────────────────────────────────────────────────────── */

/* Visible, never easy. workflow 7: "never make it the easier button to reach."
   Quiet at rest and pushed to the far right of the card's action row, which is
   what "visible, never easy" asks for in a sentence about weight and position
   rather than about colour. */
.delete-prayer,
.delete-note {
  color: var(--danger-quiet);
  background: none;
  border: 1px solid transparent;
  font-size: var(--text-sm);
}

.delete-prayer {
  margin-left: auto;
}

.delete-prayer:hover,
.delete-note:hover {
  border-color: var(--danger);
}

.delete-prayer.confirming {
  border-color: var(--danger);
  font-weight: 600;
}

.warn {
  color: var(--danger);
  font-size: var(--text-sm);
  max-width: var(--measure);
}

.warn:empty {
  display: none;
}

.caution {
  font-size: var(--text-sm);
  color: var(--muted);
  border-left: 3px solid var(--line-strong);
  padding-left: var(--space-3);
  margin-bottom: var(--space-3);
}

.update-banner {
  border: 1px solid var(--danger);
  border-radius: var(--radius);
  padding: var(--space-3);
  font-size: var(--text-sm);
  margin-bottom: var(--space-4);
}

/* ── tags, misc ─────────────────────────────────────────────────────────── */

.tag-item {
  border-bottom: 1px solid var(--line-soft);
}

/* The whole row is the control, so the target is the row (ui.md §4.6) and the
   chevron is only where the eye goes. */
.tag-row {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  width: 100%;
  min-height: 54px;
  padding: 0 var(--space-2);
  border: 0;
  border-radius: 0;
  background: none;
  color: inherit;
  text-align: left;
}

.tag-row-name {
  flex: 1;
  font-size: var(--text-base);
}

.tag-row-count {
  font-size: var(--text-xs);
  color: var(--muted-3);
}

.tag-row .icon {
  width: 1rem;
  height: 1rem;
  color: var(--muted-4);
}

/* ── the tag sheet (docs/SPEC.md §6) ─────────────────────────────────────── */

#tag-sheet {
  border: 1px solid var(--line);
  border-radius: var(--radius-sheet);
  padding: 0;
  width: min(30rem, calc(100vw - 2rem));
  max-height: min(40rem, calc(100vh - 2rem));
  color: var(--fg);
  background: var(--surface);
  overflow: hidden;
}

#tag-sheet::backdrop {
  background: rgb(0 0 0 / 45%);
}

#tag-sheet-name {
  width: 100%;
  font-size: var(--text-lg);
  margin-bottom: var(--space-4);
}

#set-tag-rhythm {
  margin-top: var(--space-3);
}

/* The one destructive action in here, walled off rather than sitting in the
   row of ordinary ones (ui.md §4.5). */
.danger-band {
  margin-top: var(--space-5);
  padding: var(--space-3);
  border: 1px solid var(--danger-line);
  border-radius: var(--radius);
  background: var(--danger-wash);
}

.danger-band .delete-tag {
  background: none;
  border: 1px solid transparent;
  color: var(--danger-quiet);
  font-weight: 600;
  padding: 0;
}

#status,
.sync-status {
  color: var(--muted);
  font-size: var(--text-sm);
}

.undo {
  font-size: var(--text-sm);
  color: var(--muted);
  margin-bottom: var(--space-2);
}

.undo:empty {
  display: none;
}

.empty {
  color: var(--muted);
  font-style: italic;
  padding: var(--space-3) 0;
}

/* ── utilities ───────────────────────────────────────────────────────────── */

/* Visible to screen readers, not to the eye. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ── motion ──────────────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: no-preference) {
  .prayer-item,
  #viewnav a,
  .rhythm-chip {
    transition: opacity 120ms ease, background-color 120ms ease, border-color 120ms ease;
  }
}

/* ── the door (docs/ui.md §4.11) ────────────────────────────────────────── */

.door {
  max-width: 22rem;
  margin: 0 auto;
  padding: var(--space-6) var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.door-title {
  font-size: var(--text-xl);
  margin-bottom: var(--space-4);
}

.door .field-label {
  font-size: var(--text-sm);
  color: var(--muted);
}

.door input[type="email"],
.door input[type="password"] {
  width: 100%;
  min-height: var(--tap);
}

.door button[type="submit"],
.door #recovery-continue,
.door #copy-recovery {
  min-height: var(--tap);
  width: 100%;
}

.door-hint,
.door-switch {
  font-size: var(--text-sm);
  color: var(--muted);
}

/* Not red. §4.7 keeps red for genuinely destructive things, and mistyping a
   passphrase is the most ordinary event on this screen. */
.door-error {
  font-size: var(--text-sm);
  color: var(--fg);
  min-height: 1.5em;
}

.door-error:empty {
  min-height: 0;
}

/* A button that reads as a link: the mode switch is not a second primary
   action, and styling it as one would make the screen ask two questions. */
.linkish {
  background: none;
  border: 0;
  padding: 0;
  color: var(--accent);
  text-decoration: underline;
  cursor: pointer;
  font: inherit;
  min-height: var(--tap);
}

/* Monospace and generously spaced, because this gets copied onto paper. Two
   columns for the same reason: the code is seven groups, and seven groups on
   one line is a line nobody transcribes correctly. The columns break on the
   spaces the grouping already put there. */
.recovery-code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: var(--text-lg);
  letter-spacing: 0.08em;
  line-height: 2;
  column-count: 2;
  padding: var(--space-3);
  background: var(--surface-sunken);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  overflow-wrap: anywhere;
  user-select: all;
}

.door-warning {
  border-left: 3px solid var(--line-strong);
  padding-left: var(--space-3);
}

/* The one thing on this screen nobody may skim. Every word of design.md §4's
   "not even us" survives inside it; the band is what stops it reading as one
   more paragraph. */
.door-band {
  margin: var(--space-4) 0;
  padding: var(--space-3);
  border: 1px solid var(--danger-line);
  border-radius: var(--radius);
  background: var(--danger-wash);
}

.door-band-title {
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--danger-quiet);
  margin-bottom: var(--space-2);
}

.door-band .door-warning {
  border-left-color: var(--danger-line);
}

.door-promise {
  font-size: var(--text-sm);
  color: var(--muted-2);
  margin-bottom: var(--space-4);
}

/* The field and its reveal, one row, so `Show` is beside what it reveals
   rather than under it. */
.field-with-button {
  display: flex;
  align-items: stretch;
  gap: var(--space-2);
}

.field-with-button > input {
  flex: 1;
  min-width: 0;
}

#show-pass {
  flex: none;
  background: none;
  border: 1px solid transparent;
  color: var(--accent);
  font-size: var(--text-sm);
  font-weight: 600;
}

.door-confirm {
  display: flex;
  align-items: center;
  min-height: var(--tap);
}

.door-confirm label {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--tap);
}

/* Ordinary explanatory text. Distinct from `.caution`, which belongs to the two
   actions that can lose the journal and should not be spent on anything else. */
.note {
  font-size: var(--text-sm);
  color: var(--muted);
  max-width: var(--measure);
}
