:root {
  --bg: #f7f5f0;
  --surface: #ffffff;
  --text: #1c1b19;
  --text-2: #4a4842;
  --muted: #77746c;
  --faint: #8d897f;
  --border: #e6e2d9;
  --hairline: #eeeae2;
  /* One step down the mark's own ramp. The tile's #0d9488 is only 3.4:1 against this paper, and the accent
     has small text to carry — the Inbox count, a link in a reply, Learn, a pile's name — where the ink blue
     it replaces managed 8.3. This reads as the same teal and manages 5.0, with white on it at 5.5. */
  --accent: #0f766e;
  --accent-text: #ffffff;
  --danger: #a3402f;
  --user-bubble: #ebe7df;
  /* The mark's own two colours, the same in both schemes because the icon is: the teal of the trees app's
     tile and the paper cream of the v on it. Send is painted in them, so the button reads as the mark
     itself. The accent above is the same teal a step darker, because it has small text to carry and this
     one does not — a 34px disc and a 180px tile can be as bright as they like. */
  --mark: #0d9488;
  --mark-ink: #f7f5f0;
  --placeholder: #a29e95;
  --serif: "Newsreader", Georgia, serif;
  color-scheme: light dark;
}
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #18181a;
    --surface: #222225;
    --text: #ecebe8;
    --text-2: #c9c7c1;
    --muted: #9c9a94;
    --faint: #77756f;
    --border: #333336;
    --hairline: #2c2c2f;
    /* The light teal that the accent becomes on a dark ground, derived the way the old blue's was: same hue
       as the mark, the saturation and the brightness of the blue it replaces, so it sits at the same 8.4:1. */
    --accent: #67c1b9;
    --accent-text: #121418;
    --danger: #e08a7a;
    --user-bubble: #2c2c30;
    --placeholder: #77756f;
  }
}

* { box-sizing: border-box; }
[hidden] { display: none !important; }
/* Text size, chosen in the Workspaces sheet and kept per device: it is about the eyes and the phone, not about
   the language pair. Every font-size in this file is in rem, so this one number scales all of them — and only
   them, since the spacing, the icons and the layout are still in px and stay where they are. */
html { height: 100%; -webkit-text-size-adjust: 100%; font-size: 16px; }
html[data-text="small"] { font-size: 15px; }
html[data-text="large"] { font-size: 18px; }
/* The app is a column the height of the screen: a header, one scrolling middle, and the tabs. Nothing is fixed or
   floating, so the tabs are part of the layout and cannot drift, and the page itself never scrolls — which is also
   what stops the phone's address bar from sliding in and out underneath everything. --shell-h is the part of the
   screen actually visible, which the keyboard changes; see app.js. */
body {
  margin: 0;
  height: var(--shell-h, 100%);
  display: flex; flex-direction: column;
  overflow: hidden; overscroll-behavior: none;
  background: var(--bg);
  color: var(--text);
  font: 1rem/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
}

/* One rule for the two faces: what the app has written — a construction, a meaning, an example, a word's notes,
   a reply in the chat — is set in the serif, and reads the same on a card, in a list and in the chat. The app's own
   furniture — labels, counts, tabs, buttons, forms, and what you type into them — is the UI sans. */
.construction, .pattern, .summary-gloss, .gloss, .senses, .examples li, .hook, .tl,
.related b, .related li, .entry h4 + p, .list-row .target, .list-row .base, .msg.bot .text, .msg.user i {
  font-family: var(--serif);
}
/* A meaning in the base language is the serif italic, on a card and under a row alike. */
.summary-gloss, .list-row .base { font-style: italic; }

header {
  flex: none;
  background: var(--bg);
  padding: calc(env(safe-area-inset-top) + 14px) 22px 14px;
}
h1 { margin: 0; font-family: var(--serif); font-size: 1.3125rem; font-weight: 500; }
/* The mark, at the size of the title next to it */
.brand { flex: none; align-self: center; margin-right: -4px; border-radius: 5px; }
main {
  flex: 1; min-height: 0; width: 100%; max-width: 720px; margin: 0 auto;
  overflow-y: auto; overscroll-behavior: contain;
}
.view { padding: 4px 16px 20px; }

nav {
  flex: none;
  display: flex;
  /* Space the words, not four equal boxes. Equal boxes space the boxes: each label is centred in its own, so
     what you read as the gap between two of them is whatever their lengths leave over — Home and Inbox are
     short, so they drift apart; Practice is long, so it crowds Vocab. A count in the Inbox tab pushed its
     label off centre too, and the whole row shifted the moment a draft arrived. */
  justify-content: space-between;
  background: var(--bg);
  border-top: 1px solid var(--border);
  /* A fixed clearance rather than the safe-area inset: the phone reports that inset as 0 while its own toolbar
     is up and as the whole home indicator when it hides, which made the tabs grow and shrink underneath you.
     12px keeps the labels clear of the indicator, and the bar is the same height everywhere, always. The side
     inset is about half a gap, so the row does not look like it begins and ends in mid-air. */
  padding: 0 14px 12px;
}
nav button {
  /* The padding is the tap target, and it is part of the gap: every pair ends up the same distance apart. */
  flex: 0 1 auto; white-space: nowrap;
  border: 0; background: none; color: var(--faint);
  padding: 14px 12px; font-family: var(--serif); font-size: 1rem; border-radius: 0;
  transition: color .15s ease;
}
nav button.on { color: var(--text); font-weight: 500; }
/* Not a pill: just the number, after the label. */
.badge { color: var(--accent); font-weight: 500; }

button, input, textarea, select { font: inherit; color: inherit; }
button {
  border: 1px solid var(--border); background: var(--surface);
  border-radius: 9px; padding: 8px 14px; font-size: 0.875rem; cursor: pointer;
  transition: background-color .15s ease, border-color .15s ease, color .15s ease;
}
button.primary { background: var(--accent); border-color: var(--accent); color: var(--accent-text); font-weight: 600; }
button.danger { color: var(--danger); }
button:disabled { opacity: .5; }
/* Secondary actions are text, not boxes. */
button.text, .seg button, .icon-btn, .pill-btn, nav button, .ws-button,
.msg button.small, #delete-go, .danger-zone button.small {
  border: 0; background: none;
}
button.text { padding: 0; color: var(--text-2); }
button.text.danger { color: var(--danger); }
button.text.accent { color: var(--accent); }
button.text.faint { color: var(--faint); }
button.text:active, .seg button:active, .icon-btn:active, .msg button.small:active { opacity: .6; }

input, textarea, select {
  width: 100%; border: 1px solid var(--border); background: var(--surface);
  border-radius: 12px; padding: 10px 12px; font-size: 1rem; /* 16px stops iOS zooming */
}
input[type="search"] { border-color: transparent; }
input:focus, textarea:focus, select:focus { outline: none; border-color: var(--accent); }
textarea { resize: vertical; }
::placeholder { color: var(--placeholder); }

.row { display: flex; gap: 12px; align-items: center; }
.row > input, .row > textarea { flex: 1; }
.empty { color: var(--muted); }
.count { color: var(--faint); font-size: 0.8125rem; margin: 6px 0 2px; }

/* Header: title, the review counter and the workspace switcher */
.header-row { display: flex; align-items: baseline; gap: 12px; }
.header-row h1 { margin-right: auto; }
.header-count { font-size: 0.8125rem; color: var(--muted); white-space: nowrap; }
/* The header-row is laid out on the baseline for the title and the count beside it, so the gear has to centre
   itself; the padding is touch target rather than looks, and the negative margin keeps it on the 22px gutter. */
.ws-button {
  flex: none; align-self: center; display: flex; padding: 6px; margin: -6px -6px -6px 0;
  color: var(--muted);
}

/* Add / chat */
#view-add { padding: 0; }
#chat { padding: 8px 22px 0; }
#add-form {
  position: sticky; bottom: 0;
  background: var(--bg); padding: 10px 16px 12px;
}
/* What you sent is a soft pill on the right; the reply is plain text on the page, with no bubble around it. */
.msg { margin: 22px 0; overflow-wrap: anywhere; text-wrap: pretty; }
.msg.user {
  width: fit-content; max-width: 80%; margin-left: auto;
  padding: 9px 16px; border-radius: 18px;
  background: var(--user-bubble); white-space: pre-wrap;
}
.msg.bot.error { color: var(--danger); }
.msg a { color: var(--accent); text-decoration: none; }
/* Target-language words Claude marks up in its reply: the reply is the serif already, so this is just an italic */
.tl { font-style: italic; }
.spinner {
  display: inline-block; width: 12px; height: 12px; border-radius: 50%;
  border: 1.5px solid var(--border); border-top-color: var(--accent);
  animation: spin 1s linear infinite; vertical-align: -1px;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* The input pill: the box with the mic and send buttons sitting inside it */
.input-pill {
  display: flex; align-items: center; gap: 6px;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: 22px; padding: 5px 5px 5px 16px;
}
.input-pill textarea {
  flex: 1; border: 0; border-radius: 0; background: none;
  padding: 6px 0; max-height: 40vh; resize: none;
}
.input-pill textarea:focus { outline: none; }
.pill-btn {
  flex: none; width: 34px; height: 34px; padding: 0; border-radius: 50%;
  color: var(--muted);
  display: inline-flex; align-items: center; justify-content: center;
}
#send-btn { background: var(--mark); color: var(--mark-ink); }
#mic-btn.on { color: var(--danger); animation: blink 1.2s infinite; }
@keyframes blink { 50% { opacity: .25; } }
#mic-status { font-size: 0.8125rem; color: var(--faint); text-align: center; margin: 0 0 6px; }
#mic-status:empty { display: none; }
.msg button.small { margin-left: 8px; padding: 0; font-size: 0.875rem; color: var(--accent); }
.msg.bot .text { white-space: pre-wrap; font-size: 1.0625rem; line-height: 1.55; }
.msg.bot .meta {
  margin: 10px 0 0; font-size: 0.875rem; color: var(--muted);
  text-transform: none; letter-spacing: normal;
}
.msg.bot .meta.error { color: var(--danger); }
.msg.bot .meta a, .msg.bot .meta button.small { margin-left: 10px; }
.msg.bot .cards { margin-top: 12px; }
.msg.bot .actions { margin-top: 12px; }
/* An entry in a reply: a row between hairlines, not a box. */
.msg.bot .cards .list-row {
  display: flex; justify-content: space-between; align-items: baseline; gap: 12px;
  border-top: 1px solid var(--border); border-bottom: 0;
  border-radius: 0; background: none; margin: 0; padding: 12px 0;
}
.msg.bot .cards .list-row:last-child { border-bottom: 1px solid var(--border); }
.msg.bot .cards .list-row .target { font-size: 1.1875rem; font-weight: 400; }
.msg.bot .cards .list-row .base { color: var(--muted); font-size: 0.9375rem; }
.msg.bot .cards .list-row .status { color: var(--muted); white-space: nowrap; }

/* Entries and cards */
.card {
  background: var(--surface); border: 0;
  border-radius: 16px; box-shadow: 0 1px 0 var(--border);
  padding: 18px; margin: 12px 0;
}
/* The one uppercase label: section headings, the meta line, status words, the kind on a review card.
   Form fields use sentence case instead, so uppercase means exactly one thing: a label on content. */
.entry h4, .meta, .tag, .status, .swipe-mark, .word-notes > summary, dialog h4 {
  font-size: 0.6875rem; font-weight: 400; text-transform: uppercase;
  letter-spacing: .08em; color: var(--faint);
}
.entry h4 { margin: 18px 0 4px; }
.entry h4 + p { font-size: 1rem; color: var(--text-2); }
.entry p, .entry ol, .entry ul { margin: 4px 0; }
.entry ol, .entry ul { padding-left: 20px; }
.construction { font-size: 1.625rem; line-height: 1.1; font-weight: 400; }
.gloss { margin-top: 6px; font-style: italic; font-size: 1.0625rem; color: var(--text-2); }
.gloss.big { font-size: 1.625rem; font-style: normal; font-weight: 400; color: var(--text); }
.hook { font-style: italic; font-size: 1rem; color: var(--text-2); margin-top: 12px; }

/* A construction is one unit of decision: its own row, its own detail, its own buttons at the foot.
   A hairline starts each one after the first, so a card never runs two of them together. */
.pattern-block { margin: 16px 0 0; }
.pattern-block + .pattern-block { border-top: 1px solid var(--hairline); padding-top: 14px; margin-top: 18px; }
.pattern-block > summary, .word-notes > summary {
  list-style: none; cursor: pointer;
  display: flex; align-items: flex-start; gap: 8px;
}
.pattern-block > summary::-webkit-details-marker, .word-notes > summary::-webkit-details-marker { display: none; }
.pattern-block > summary .row-main { flex: 1; min-width: 0; }
/* The mark keeps the left edge; what it opens is indented under it, the way a disclosure should read. */
.block-body { margin-left: 20px; }
.pattern { font-weight: 500; font-size: 1.1875rem; }
.summary-gloss { display: block; color: var(--muted); font-size: 0.875rem; font-family: var(--serif); }
.pattern-block:not([open]) .pattern { font-weight: 400; font-size: 1.0625rem; }
/* Suggestions sit under their own heading, so they need no rule of their own. */
.pattern-block.suggested { border-top: 0; padding-top: 0; margin-top: 12px; }
.entry h4 + .pattern-block.suggested { margin-top: 8px; }
.row-actions { display: flex; gap: 14px; align-items: baseline; white-space: nowrap; }
.row-actions.marks { gap: 2px; align-items: center; margin: -4px -4px 0 0; }
/* The one mark that says "this opens" */
.chev { flex: none; margin-top: 5px; color: var(--faint); transition: transform .15s ease; }
details[open] > summary > .chev { transform: rotate(90deg); }

/* In the Inbox the word's own notes fold away, so each card ends on its decision, not on an essay. */
.word-notes { margin-top: 20px; }
.word-notes > summary { color: var(--faint); }
.word-notes > summary:active { opacity: .6; }
.word-notes > h4:first-of-type { margin-top: 12px; }

/* The translation leads the card, set like the gloss elsewhere, because that is what it is. */
.entry .translation { margin: 10px 0 0; font-size: 1.0625rem; font-style: italic; color: var(--text-2); }

/* The meaning: one line, or numbered lines when the construction has more than one. Under the translation it is
   what that line does not say, so it sits a step quieter. */
.entry .senses { margin: 10px 0 0; font-size: 1.0625rem; font-style: italic; color: var(--text-2); }
.entry .translation + .senses { margin-top: 6px; font-size: 1rem; color: var(--faint); }
.entry ol.senses { padding-left: 20px; }
.entry ol.senses li { margin-bottom: 2px; }
.entry ol.senses li::marker { font-style: normal; font-size: 0.875rem; color: var(--faint); }
.pattern-block .examples { margin-top: 12px; }
/* Hearing a word (BACKLOG 5). The speaker rides next to the thing it says and is deliberately quiet: faint
   until it is touched, because on a card that is mostly words a second dark mark next to the headword would
   read as a second decision to make. `blink` is the mic's own animation, borrowed: one idea, two places.

   It is sized in `em`, so it grows with whatever it is standing beside rather than being one size in five
   places — a fixed 16px mark looks pinned on next to a 2.125rem word on the face of a practice card, and the
   same mark is right next to an example sentence. The two limits are what keep that honest: never under a
   32px box, which is the tap target a phone needs, and never over a 28px glyph, past which it stops reading
   as a mark beside the word and starts reading as a button of its own.

   Inline-flex and vertical-align rather than a flex parent, because the same button sits in five places with
   five different layouts — the headword (1.625rem serif), the face of a practice card (2.125rem), an Inbox
   summary that is a baseline flex row, an example sentence that can wrap, and the back of a review card. One
   rule that behaves in all of them beats a nudge per surface. The vertical centring is the thing to look at
   first on a real phone. */
.say {
  display: inline-flex; align-items: center; justify-content: center;
  /* `button` sets font-size: 0.875rem two rules above, which would make every `em` here 14px and every
     speaker the same size whatever it stands next to. The point of this rule is the text beside it. */
  font-size: inherit;
  width: max(32px, 1.3em); height: max(32px, 1.3em); padding: 0; margin-left: 2px;
  color: var(--faint); vertical-align: middle; flex: 0 0 auto;
  /* `middle` centres on the x-height midline, which is what it is defined to do and which lands low beside a
     serif face with tall ascenders: measured 1.9px at 17px text, 3.0 at 26px, 3.6 at 34px -- 0.11em each
     time, so one nudge is right at every size. A transform rather than a margin, so the line box does not
     move with it. */
  transform: translateY(-0.11em);
}
.say svg { width: clamp(16px, 0.8em, 28px); height: clamp(16px, 0.8em, 28px); }
/* The last word of a sentence and its speaker, kept on one line: see sayAfter() in static/app.js. */
.say-with { white-space: nowrap; }
.say:hover { color: var(--accent); }
.say.busy { color: var(--accent); animation: blink 1.2s infinite; }
.say.failed { color: var(--danger); }

.examples { list-style: none; padding-left: 0; }
.examples li { margin-bottom: 10px; }
.examples li { font-size: 1.0625rem; }
.related li { margin-bottom: 6px; font-size: 1rem; color: var(--text-2); }
.related b { font-weight: 400; font-size: 1.0625rem; color: var(--text); }
.tag { white-space: nowrap; }
.source { color: var(--faint); font-size: 0.8125rem; }
.warn {
  background: var(--bg); border: 1px solid var(--border); border-radius: 10px;
  padding: 10px 12px; margin: 10px 0 12px; font-size: 0.875rem; color: var(--text-2);
}
.actions { display: flex; flex-wrap: wrap; gap: 18px; align-items: center; margin-top: 16px; }

/* Lists (Browse, the review list, workspaces): hairlines, no boxes.
   `.target` is the line in the language being learned and `.base` the line in the language it is explained in.
   They were `.fr` and `.en` until a workspace could be Spanish explained in Italian, which is the sort of name
   that is only right until the thing it describes grows. */
.list-row {
  display: block; background: none; border: 0; border-top: 1px solid var(--hairline);
  border-radius: 0; padding: 12px 0; margin: 0; cursor: pointer;
}
.list-row .target { font-size: 1.1875rem; }
.list-row .base { color: var(--muted); font-size: 0.9375rem; }
.list-row .sub { color: var(--muted); font-size: 0.875rem; }
details.list-row summary { list-style: none; display: flex; align-items: flex-start; gap: 12px; }
details.list-row summary .row-main { flex: 1; min-width: 0; }
details.list-row[open] summary { margin-bottom: 10px; }
#browse + p { margin-top: 22px; }

/* Collections: the stacks you put together, chosen at the top of Practice and of Vocab */
.chips { display: flex; gap: 8px; overflow-x: auto; margin: 0 0 12px; padding-bottom: 2px; scrollbar-width: none; }
/* Practice has no padding of its own, so the chips take the toolbar's. */
#view-review .chips { padding-left: 22px; padding-right: 22px; }
.chips::-webkit-scrollbar { display: none; }
.chip {
  flex: none; padding: 5px 12px; border-radius: 14px; font-size: 0.8125rem;
  border: 1px solid var(--border); background: none; color: var(--muted); white-space: nowrap;
}
.chip.on { background: var(--surface); color: var(--text); border-color: var(--surface); font-weight: 600; }
.chip-count { margin-left: 6px; color: var(--faint); }
.chip.on .chip-count { color: var(--muted); }
/* A row with a mark on the right of it: a card in a collection and its way out of the stack, or a word in
   Words and its way into one. The same three rules, because they are the same shape. */
.pile-row, .word-row { display: flex; align-items: flex-start; gap: 12px; }
.pile-row .row-main, .word-row .row-main { flex: 1; min-width: 0; }
.pile-row .target, .pile-row .base, .word-row .target { display: block; }
.count .text { margin-left: 14px; font-size: 0.8125rem; }
/* The tray: every collection as a square, ticked when the card is in it */
.tray { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 10px; margin: 14px 0 18px; }
.pile {
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px; min-height: 68px;
  padding: 12px 14px; border-radius: 12px; text-align: left;
}
.pile-name { font-family: var(--serif); font-size: 1.0625rem; }
.pile-count { font-size: 0.75rem; color: var(--faint); }
.pile.in { border-color: var(--accent); color: var(--accent); }
.pile.in .pile-name::after { content: " ✓"; }
.pile.in .pile-count { color: var(--accent); }

/* Review */
#view-review { padding: 0; }
.toolbar { display: flex; justify-content: space-between; gap: 14px; padding: 0 22px 12px; }
.seg { display: flex; gap: 14px; align-items: baseline; }
.seg button { padding: 0; font-size: 0.8125rem; color: var(--faint); border-radius: 0; }
.seg button.on { color: var(--text); font-weight: 600; }
.progress { height: 2px; margin: 0 22px; background: var(--border); border-radius: 2px; }
.progress span { display: block; height: 2px; background: var(--accent); border-radius: 2px; transition: width .15s ease; }
#review { padding: 16px 16px 20px; }
/* The lead of a row in the list is what the card asks, not a gloss beside a construction: it stays upright. */
#review .list-row .lead { font-size: 1.0625rem; color: var(--text); font-style: normal; }
.flash { position: relative; min-height: 180px; cursor: pointer; border-radius: 18px; padding: 30px 22px 20px; margin: 0; }
/* A revealed card is swiped away; the browser keeps the up-and-down, we take the sideways. The card is given a
   layer of its own while it is being dragged (in app.js), so moving it costs no repaint. */
/* pan-y leaves the up-and-down to the browser and the sideways to us; nothing on the card may start a text
   selection, which on a phone takes the gesture away mid-drag. */
.flash.revealed { touch-action: pan-y; -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; }
.flash.arriving { animation: card-in .2s cubic-bezier(.22, 1, .36, 1); }
@keyframes card-in { from { opacity: 0; transform: translate3d(0, 10px, 0); } }
/* The word stays at the edge the card is leaving towards, so it is still there to read as the card goes. Its
   opacity is set as the card moves (app.js), which touches this element alone. */
.swipe-mark { position: fixed; top: 46%; opacity: 0; pointer-events: none; }
.swipe-mark.knew { right: 20px; }
.swipe-mark.again { left: 20px; }
.swipe-hint {
  position: sticky; bottom: 0; margin: 0; padding: 12px 16px 14px;
  background: var(--bg); text-align: center; color: var(--faint); font-size: 0.8125rem;
}
.flash .front { text-align: center; }
.flash .front .construction { font-size: 2.125rem; }
/* The face is centred, so the speaker is centred under nothing: it sits on the baseline beside the word and
   keeps its own tap target rather than growing with the 2.125rem text around it. */
.flash .front .construction .say { margin-left: 6px; }
.flash .front .gloss { margin-top: 0; }
.flash .tap { text-align: center; color: var(--faint); font-size: 0.8125rem; margin: 28px 0 0; }
.flash hr { border: 0; border-top: 1px solid var(--hairline); margin: 24px 0 18px; }
/* The front already says the construction, so the back starts at the meaning. */
.flash .entry > .construction, .flash .pattern-block.focus > summary { display: none; }
.flash .pattern-block.focus .block-body { margin-left: 0; }
.flash .pattern-block.focus { margin-top: 0; }
.flash .pattern-block.focus .block-body > .translation,
.flash .pattern-block.focus .block-body > .senses {
  margin-top: 0; font-style: normal; font-size: 1.3125rem; color: var(--text);
}
/* With the translation above them, the senses are the remark under it, not the answer. */
.flash .pattern-block.focus .block-body > .translation + .senses {
  margin-top: 10px; font-size: 1.0625rem; font-style: italic; color: var(--text-2);
}
.flash .pattern-block.focus .block-body > ol.senses { padding-left: 24px; }
.grades {
  position: sticky; bottom: 0;
  display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 8px;
  padding: 8px 16px 14px; background: var(--bg);
}
.grades button { padding: 12px 0; font-size: 0.9375rem; border-radius: 11px; background: var(--bg); }
.grades button.primary { background: var(--accent); border-color: var(--accent); color: var(--accent-text); }

/* The end of a sitting: what you got through, what is still waiting, and the way on. Not an empty state — the
   point of it is that there is more, which is what "nothing due" used to say instead. */
.sitting-end { margin-top: 32px; text-align: center; }
.sitting-end .empty { color: var(--text-2); }
.sitting-end .still-due { margin: 4px 0 20px; font-size: 0.875rem; color: var(--faint); }
.sitting-end button { padding: 11px 22px; }

/* Inbox: one card per word */
.inbox-word > summary {
  list-style: none; cursor: pointer;
  display: flex; justify-content: space-between; align-items: baseline; gap: 12px;
}
.inbox-word > summary::-webkit-details-marker { display: none; }
.inbox-word .entry > .construction { display: none; }
.inbox-count { font-size: 0.8125rem; color: var(--faint); white-space: nowrap; }
/* A draft's row carries its decision, so it stays put under the header while you read the card. */
.inbox-word .pattern-block.draft > summary {
  position: sticky; top: 0; z-index: 1;
  background: var(--surface); padding-bottom: 6px;
}

/* Entry icon buttons (edit / delete / close) */
.entry-icons { display: flex; justify-content: flex-end; align-items: center; gap: 10px; margin-bottom: 6px; }
/* How the card has been going lately, which is what decides when it comes round again */
.record { margin-right: auto; font-size: 0.75rem; color: var(--faint); }
dialog .entry-icons {
  position: sticky; top: 0; z-index: 1; background: var(--surface);
  margin: -18px -18px 0; padding: 14px 18px 8px;
}
.icon-btn {
  padding: 4px; border-radius: 8px; cursor: pointer; color: var(--faint);
  display: inline-flex; align-items: center; justify-content: center;
}
.icon-btn.danger { color: var(--faint); }
.icon-btn:active { opacity: .6; }

/* Modal */
dialog {
  width: min(680px, calc(100vw - 16px)); max-height: calc(100dvh - 32px);
  border: 0; border-radius: 16px;
  background: var(--surface); color: var(--text); padding: 0;
}
#modal-body { padding: 18px; }
dialog::backdrop { background: rgba(20, 19, 17, .35); }
dialog h3 { margin: 0 0 12px; font-size: 1.0625rem; font-weight: 600; }
dialog h4 { margin: 20px 0 6px; }
#editor label { display: block; margin: 12px 0; font-size: 0.8125rem; color: var(--muted); }
#editor label small { font-size: 0.75rem; color: var(--faint); }
#editor input, #editor textarea, #editor select { margin-top: 4px; color: var(--text); }

/* Workspace rows keep the UI font: a workspace is furniture, not a word. */
.list-row[data-ws] .target, .list-row[data-ws] .base { font-family: inherit; font-style: normal; }
.list-row[data-ws] .target { font-size: 1rem; }
.list-row[data-ws] .base { font-size: 0.875rem; }
.list-row.current .target { font-weight: 600; }
#ws-form { margin-top: 18px; }
#ws-form label, #email-form label { display: block; margin: 12px 0; font-size: 0.8125rem; color: var(--muted); }
#ws-form label small, #email-form label small { color: var(--faint); }
#ws-form select, #ws-form input, #email-form input { margin-top: 4px; color: var(--text); }

/* Settings (BACKLOG 1a): a sentence that explains a control sits with it, at the size of the furniture rather
   than of the vocabulary. */
.setting-line { margin: 8px 0; font-size: 0.875rem; line-height: 1.5; color: var(--text-2); }
.setting-line b { font-weight: 600; }
#email-detail > summary { list-style: none; cursor: pointer; font-size: 0.875rem; color: var(--accent); }
#email-detail > summary::-webkit-details-marker { display: none; }
#email-detail > summary:active { opacity: .6; }
/* What came back from a send, next to the button that asked for it. */
.said { font-size: 0.8125rem; color: var(--muted); }

/* Login, and the screens before there is a session: signing up, the waiting list, the two pages behind an
   emailed link, and the privacy note. They share the login column, so they read as one place rather than as
   the app and then a form bolted to the side of it. */
.login { flex: 1; overflow-y: auto; padding: 48px 22px; max-width: 420px; margin: 0 auto; }
.login .card { box-shadow: none; background: none; padding: 0; }
.login h3 { margin: 28px 0 10px; font-size: 1.0625rem; font-weight: 600; }
/* Prose on these screens: a paragraph someone reads once, before they have decided anything, so it is set at
   the reading size rather than at the size of a form label. */
.login .lead { margin: 0 0 14px; font-size: 1rem; line-height: 1.55; color: var(--text-2); }
.login .fine { margin: 20px 0 0; font-size: 0.8125rem; line-height: 1.5; color: var(--faint); }
.login .fine a { color: var(--accent); }
.login-alt { display: flex; flex-wrap: wrap; gap: 18px; margin: 22px 0 0; font-size: 0.875rem; }
/* The wordmark: the italic v of the icon, then the word upright */
.wordmark { margin: 0; font-family: var(--serif); font-size: 2.5rem; line-height: 1.1; font-weight: 400; color: var(--text); }
.wordmark i { font-style: italic; }
.tagline { margin: 6px 0 28px; font-family: var(--serif); font-style: italic; font-size: 1rem; color: var(--muted); }
.login label { display: block; margin: 14px 0; font-size: 0.8125rem; color: var(--muted); }
.login input { margin-top: 4px; color: var(--text); }
.login button { width: 100%; margin-top: 16px; padding: 12px 14px; }
.error { color: var(--danger); font-size: 0.875rem; }

/* Forms worth knowing on a card ("an|rufen, rief an, hat angerufen"): target language, so serif */
.forms { font-size: 0.9375rem; margin-top: 4px; color: var(--text-2); font-family: var(--serif); }

/* The privacy note is one text shown in two places — the /privacy page and the Settings sheet — so its
   paragraphs read the same in the modal as they do in the login column. */
dialog .lead { margin: 0 0 14px; font-size: 1rem; line-height: 1.55; color: var(--text-2); }

/* Deleting a workspace or an account: kept apart, behind a warning. Two of them now, so they space rather
   than stack. */
.danger-zone { margin-top: 26px; padding-top: 14px; border-top: 1px solid var(--hairline);
  display: flex; flex-wrap: wrap; gap: 18px; justify-content: flex-end; }
.danger-zone button.small { padding: 0; font-size: 0.875rem; color: var(--danger); }
.danger-box { background: none; border-color: var(--danger); }
.danger-box p { margin: 4px 0; }
#delete-go { padding: 0; color: var(--danger); font-weight: 600; }
.confirm-name { display: block; margin: 16px 0; font-size: 0.8125rem; color: var(--muted); }
.confirm-name input { margin-top: 4px; color: var(--text); }
.confirm-name b { font-family: var(--serif); font-size: 1rem; font-weight: 400; }

/* The help (BACKLOG 3d): the sheet the `?` button in the header opens. The `?` marks that used to be placed
   around the app went on 2026-10-25 (app/help.py says why), and their rules went with them. */

/* The drawer: a sheet at the foot of the screen. This app is used on a phone in one hand, and a note about the
   thing you have just tapped belongs under your thumb — not in a box over the middle of what you were reading,
   which is what the modal in the middle is for (a decision, taken with both eyes on it). */
dialog.sheet {
  width: 100%; max-width: 720px; max-height: 84dvh;
  margin: auto auto 0; padding: 0;
  border: 0; border-radius: 18px 18px 0 0;
  background: var(--surface); color: var(--text);
  overflow-y: auto; overscroll-behavior: contain;
}
dialog.sheet::backdrop { background: rgba(20, 19, 17, .35); }
.help-body { padding: 18px 20px calc(env(safe-area-inset-bottom) + 22px); }
.help-head {
  position: sticky; top: 0; z-index: 1; background: var(--surface);
  display: flex; align-items: baseline; gap: 12px;
  margin: -18px -20px 0; padding: 16px 20px 8px;
}
.help-head h3 { margin: 0 auto 0 0; font-size: 1.0625rem; font-weight: 600; }
.help-count { font-size: 0.6875rem; text-transform: uppercase; letter-spacing: .08em; color: var(--faint); }
/* Prose in the sheet reads at the size of the login column's paragraphs: it is something you read once, not a
   label on a control.

   One colour for all of it, which is the rule the guide page already keeps (static/guide.html, `section p,
   section p.lede`). The first sentence of an entry used to be set in --text and the ones after it in
   --text-2, which on "Collections" reads as the second paragraph being an aside about the first rather than
   the rest of the same note. The two greys are a step apart, so it does not look deliberate — it looks like
   a mistake. The heading is the hierarchy; the prose under it is one voice. */
.help-body .lede,
.help-body p { margin: 0 0 12px; font-size: 1rem; line-height: 1.55; color: var(--text); }
.help-body .lede { margin-top: 10px; }
.help-body p b { font-weight: 600; color: var(--text); }
.help-body h4 { margin: 18px 0 2px; }
/* The index: every entry under its area, as rows rather than a paragraph of links. */
.help-list { list-style: none; margin: 0; padding: 0; }
.help-list li { border-bottom: 1px solid var(--hairline); }
.help-list button { padding: 10px 0; font-family: var(--serif); font-size: 1.0625rem; text-align: left; }
/* The three ways on, at the top of the index: the tour, the guide and the marks switch, as rows the size of
   the entries under them. They are what the header's help button is for, so they come before the twelve
   entries rather than after them. */
.help-ways { list-style: none; margin: 12px 0 4px; padding: 0; }
.help-ways li { border-bottom: 1px solid var(--hairline); }
.help-ways li:first-child { border-top: 1px solid var(--hairline); }
.help-ways a, .help-ways button {
  display: block; width: 100%; padding: 11px 0;
  font-size: 0.9375rem; text-align: left; color: var(--accent); text-decoration: none;
}
.help-ways a:active { opacity: .6; }

/* What to read next, which is the whole reason the marks are worth having over a page of prose: you are told
   the one thing you asked about, and then where the rest of it is. */
.help-see { display: flex; flex-wrap: wrap; gap: 16px; margin: 14px 0 0; font-size: 0.875rem; }
.help-foot {
  display: flex; flex-wrap: wrap; gap: 18px; align-items: center;
  margin-top: 22px; padding-top: 14px; border-top: 1px solid var(--hairline); font-size: 0.875rem;
}
.help-foot a { color: var(--accent); text-decoration: none; }
.help-foot button.text { color: var(--text-2); }
