:root {
  --ink: #211D17; --muted: #8f8776; --paper: #fdfbf7; --accent: #8A6D3B;
  --line: #e4ddc9; --bg: #f2efe6; --changed: #b45309;
  --suggest-bg: #fff7e6; --suggest-bd: #e8c073; --ok: #3f7a4f; --err: #b3432b;
}
* { box-sizing: border-box; }
body {
  margin: 0; background: var(--bg); color: var(--ink);
  font-family: -apple-system, "Segoe UI", sans-serif; font-size: 14px; line-height: 1.5;
}
header {
  background: var(--paper); border-bottom: 1px solid var(--line);
  padding: 16px 32px; display: flex; align-items: baseline; gap: 16px;
  /* Wrapping whole groups beats squeezing them: at mid widths the action
     links move down as one row instead of stacking one word per line. */
  flex-wrap: wrap; row-gap: 6px;
}
header h1 { margin: 0; font-size: 18px; font-weight: 700; }
header a { color: var(--accent); text-decoration: none; font-size: 13px; }
header a:hover { text-decoration: underline; }
main { max-width: 920px; margin: 0 auto; padding: 28px 32px 80px; }
h2 { font-size: 16px; margin: 28px 0 12px; }
.flash { background: #fff7e6; border: 1px solid var(--suggest-bd); border-radius: 6px; padding: 10px 14px; margin-bottom: 16px; font-size: 13px; }
.card { background: var(--paper); border: 1px solid var(--line); border-radius: 8px; padding: 20px; margin-bottom: 20px; }
table { width: 100%; border-collapse: collapse; font-size: 13px; }
th, td { text-align: left; padding: 8px 10px; border-bottom: 1px solid var(--line); }
th { color: var(--muted); font-weight: 600; font-size: 11.5px; text-transform: uppercase; letter-spacing: 0.04em; }
tr:hover td { background: #faf7f0; }
a.proj-link { color: var(--ink); text-decoration: none; font-weight: 600; }
a.proj-link:hover { color: var(--accent); }
form.upload-form label { display: block; font-size: 12.5px; color: var(--muted); margin: 12px 0 4px; }
form.upload-form input, form.upload-form select { width: 100%; padding: 7px 9px; border: 1px solid #cabfa8; border-radius: 5px; font-size: 13.5px; background: #fff; }
.field-hint { font-size: 11.5px; color: var(--muted); margin: 4px 0 0; }
.color-mode-choice { display: flex; flex-direction: column; gap: 6px; }
.color-mode-choice .radio-inline { display: flex; align-items: flex-start; gap: 7px; font-size: 12.5px; color: var(--ink); font-weight: normal; margin: 0; }
.color-mode-choice .radio-inline input { width: auto; margin-top: 2px; }

.book-details-card .book-details-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; align-items: start; }
.book-details-card label { display: block; font-size: 12.5px; color: var(--muted); margin: 0 0 6px; }
.book-details-card input[type=text] { width: 100%; box-sizing: border-box; padding: 7px 9px; border: 1px solid #cabfa8; border-radius: 5px; font-size: 13.5px; background: #fff; }
.book-details-card input[type=file] { font-size: 12px; margin-top: 6px; }
.book-logo-preview { min-height: 40px; display: flex; align-items: center; }
.book-logo-preview img { max-height: 56px; max-width: 100%; object-fit: contain; }
.link-btn {
  background: none; border: none; padding: 0; margin-top: 6px; color: var(--accent);
  font-size: 11.5px; text-decoration: underline; cursor: pointer; display: block;
}
@media (max-width: 720px) { .book-details-card .book-details-grid { grid-template-columns: 1fr; } }
button, input[type=submit] {
  font-family: inherit; font-size: 13px; padding: 8px 16px; border-radius: 6px;
  border: 1px solid #cabfa8; background: #fff; color: var(--ink); cursor: pointer;
}
button.primary, input[type=submit].primary { background: var(--accent); color: #fff; border-color: var(--accent); }
button:disabled { opacity: 0.5; cursor: default; }
.pill { display: inline-block; font-size: 10.5px; padding: 2px 8px; border-radius: 10px; background: #ece5d3; color: #57503f; }
.pill.warn { background: var(--suggest-bd); color: #5c4415; }
.pill.edited { background: #dce9f7; color: #2c527d; }

.block { position: relative; padding: 12px 14px 12px 18px; margin-bottom: 2px; border-left: 3px solid transparent; border-radius: 3px; }
.block.suggest { background: var(--suggest-bg); }
.block.saved-flash { background: #eefaf0; }
.controls, .extra-controls { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; flex-wrap: wrap; }
.extra-controls.hidden { display: none; }
select.level-picker, select.mini-select { font-size: 12.5px; padding: 3px 6px; border: 1px solid #cabfa8; border-radius: 4px; background: #fff; }
button.font-btn { font-size: 12px; width: 22px; height: 22px; border: 1px solid #cabfa8; border-radius: 4px; background: #fff; cursor: pointer; line-height: 1; }
span.font-pct { font-size: 11px; color: #77705d; min-width: 34px; text-align: center; }
.pos { font-size: 10.5px; color: #a89f8a; }
.save-state { font-size: 10.5px; }
.save-state.saved { color: var(--ok); }
.save-state.error { color: var(--err); }
button.text-edit-btn { font-size: 11px; padding: 3px 8px; }
.text-edit-wrap { margin: 0 0 8px; padding: 8px 10px; background: #fbf9f4; border: 1px solid var(--line); border-radius: 5px; }
.text-edit-wrap.hidden { display: none; }
.text-edit-area {
  width: 100%; box-sizing: border-box; font-size: 13px; padding: 6px 8px;
  border: 1px solid #cabfa8; border-radius: 4px; font-family: Georgia, serif; resize: vertical; margin-bottom: 4px;
}
.text-edit-hint { font-size: 10.5px; color: var(--muted); margin: 0 0 6px; }
.text-revert-btn { font-size: 10.5px; padding: 3px 8px; }
.text-revert-btn.hidden { display: none; }

.preview p.body-text { font-family: Georgia, serif; font-size: 13.5pt; line-height: 1.55; text-align: justify; text-indent: 8.467mm; margin: 0; }
.preview p.body-text.indent-none { text-indent: 0; }
.preview p.body-text.indent-double { text-indent: 16.9mm; }
.preview .chapter-heading { font-family: Georgia, serif; text-align: center; letter-spacing: 0.15em; font-size: 17pt; color: var(--accent); margin: 6px 0; font-weight: 700; }
.preview .subheading { font-family: Georgia, serif; font-weight: 700; letter-spacing: 0.03em; font-size: 14pt; color: #4a3f2d; margin: 4px 0; }
.preview .subsubheading { font-family: Georgia, serif; font-style: italic; font-size: 12pt; color: #5c5648; margin: 4px 0; }
.preview .blockquote { font-family: Georgia, serif; margin: 6px 14px; font-size: 11.5pt; font-style: italic; color: #3f382c; }
.preview .verse { font-family: Georgia, serif; text-align: left; text-indent: 0; white-space: pre-line; font-size: 13.5pt; }
.preview .centered-block { font-family: Georgia, serif; text-align: center; text-indent: 0; font-style: italic; font-size: 13.5pt; margin: 6px 0; }
/* Editor/classic-view-only bullet treatment — a hanging-indent ::before
   marker on a plain <p>, not a real <ul>/<li> (this editable element IS
   the single contenteditable region for the block; nesting a <li> inside
   it would complicate the run-extraction logic for no visual gain here).
   The real render (render.py's PDF, export_docx.py, export_epub.py) uses
   an actual <ul><li> — this only has to agree with those on content, the
   same "editor markup can differ from render markup" precedent the table
   block's own editable grid already uses. */
.preview p.bullet-item { font-family: Georgia, serif; font-size: 13.5pt; line-height: 1.55; text-indent: 0; margin: 2px 0; padding-left: 1.3em; position: relative; }
.preview p.bullet-item::before { content: '•'; position: absolute; left: 0.3em; }
/* Ordered items mirror the bullet treatment, but the marker text comes from
   data-list-number (set by computeListNumbers) rather than a CSS counter —
   a counter would restart per element here, since each block is its own
   independent element, exactly the problem render.py solves differently for
   print. Drawn with ::before so the digits never enter the contenteditable
   region and get saved as the author's own text. */
.preview p.numbered-item { font-family: Georgia, serif; font-size: 13.5pt; line-height: 1.55; text-indent: 0; margin: 2px 0; padding-left: 1.9em; position: relative; }
/* `attr()` with no fallback yields the empty string when the attribute is
   absent, so a numbered item without one rendered pixel-identical to an
   ordinary paragraph — the style picker looked broken. The classic view has no
   list numbering to hand (numbers are assigned at render time), so it falls
   back to a bullet-sized marker that at least says "this is a list item". */
.preview p.numbered-item::before { content: attr(data-list-number); position: absolute; left: 0.2em; font-variant-numeric: tabular-nums; }
.preview p.numbered-item:not([data-list-number])::before { content: "1."; opacity: 0.55; }

/* Scene break: shown as a centred mark. The editor deliberately draws a
   simple glyph rather than the theme's chosen SVG ornament — the preview is
   about knowing a break is there, and which ornament prints is a book-wide
   setting shown on the Title Page panel. */
.preview p.scenebreak-item { text-align: center; text-indent: 0; margin: 14px 0; color: var(--muted); letter-spacing: 0.4em; min-height: 1em; }
.preview p.scenebreak-item:empty::before { content: '◆'; letter-spacing: normal; }

.preview p.pullquote-item { font-family: Georgia, serif; font-size: 16pt; line-height: 1.35; font-style: italic; text-align: center; text-indent: 0; margin: 12px 8%; }
.preview p.sidebar-item { font-family: Georgia, serif; font-size: 12pt; line-height: 1.45; text-indent: 0; margin: 12px 0; padding: 6px 10px; border-left: 3px solid #b9ae94; text-align: left; }
/* The book's apparatus — References, Notes, Bibliography. The editor shows
   the same three things print does, at editor scale: smaller than the text,
   ragged right, and hung from the left so the eye finds where each entry
   begins. A designer has to be able to see that they picked the right style
   without rendering the book. */
.preview p.references-heading-item { font-family: Georgia, serif; font-size: 12pt;
  font-variant: small-caps; letter-spacing: 0.09em; font-weight: 600; text-indent: 0;
  text-align: left; margin: 16px 0 4px; color: #3f382c; }
.preview p.reference-item { font-family: Georgia, serif; font-size: 11.5pt; line-height: 1.4;
  text-indent: -1.5em; padding-left: 1.5em; margin: 2px 0; text-align: left; }
.preview p.reference-numbered-item { padding-left: 2em; text-indent: 0; position: relative; }
.preview p.reference-numbered-item::before { content: attr(data-list-number); position: absolute;
  left: 0.1em; font-variant-numeric: tabular-nums; }
.preview p.reference-numbered-item:not([data-list-number])::before { content: "1."; opacity: 0.55; }
.preview p.callout-item { font-family: Georgia, serif; font-size: 12pt; line-height: 1.45; text-indent: 0; margin: 12px 0; padding: 8px 10px; border: 1px solid #cabfa8; text-align: left; }
/* The five styles added in the typesetting audit. The editor preview is not
   the printed page — it never has been, see the bullet-item note above — but
   it has to be recognisable at a glance, because the whole reason for naming
   a style is that somebody can see they applied the right one. */
.preview p.epigraph-item { font-family: Georgia, serif; font-size: 12pt; line-height: 1.45; font-style: italic; text-indent: 0; text-align: left; margin: 8px 0 2px 12%; }
.preview p.attribution-item { font-family: Georgia, serif; font-size: 11.5pt; line-height: 1.4; text-indent: 0; text-align: right; margin: 0 0 10px; }
.preview p.tablecaption-item { font-family: Georgia, serif; font-size: 11.5pt; line-height: 1.4; font-style: italic; text-indent: 0; text-align: center; margin: 8px 0 3px; }
.preview p.qa-item { font-family: Georgia, serif; font-size: 13.5pt; line-height: 1.5; text-indent: 0; text-align: left; margin: 2px 0 2px 1.7em; position: relative; }
.preview p.qa-item::before { position: absolute; left: -1.7em; font-weight: 700; }
.preview p.qa-q-item::before { content: 'Q.'; }
.preview p.qa-a-item::before { content: 'A.'; }
/* An author who typed the label keeps it; the drawn one would make it twice.
   Matched in the browser by data-qa-typed, set alongside the class. */
.preview p.qa-item[data-qa-typed]::before { content: none; }

#renderBar { position: sticky; bottom: 0; background: var(--paper); border-top: 1px solid var(--line); padding: 14px 32px; margin: 0 -32px; display: flex; align-items: center; gap: 14px;
  /* Enough links live here now that one row overflows even a wide window —
     wrapping keeps every download visible instead of pushed off the edge. */
  flex-wrap: wrap; row-gap: 10px; }
#renderBar label { white-space: nowrap; }
#renderBar a { white-space: nowrap; }

/* The project page's "On this page" bar. Stuck to the top of the window so a
   sixteen-thousand-pixel page is navigable from anywhere on it; every card
   gets scroll-margin so a jump does not land hidden under the bar itself. */
.page-jump-bar { position: sticky; top: 0; z-index: 40; background: var(--bg);
  display: flex; flex-wrap: wrap; align-items: baseline; column-gap: 14px; row-gap: 2px;
  padding: 8px 0; margin: 0 0 14px; border-bottom: 1px solid var(--line);
  font-size: 12.5px; }
.page-jump-bar .jump-label { color: var(--muted); font-size: 11px;
  text-transform: uppercase; letter-spacing: .04em; }
.page-jump-bar a { color: var(--accent); text-decoration: none; white-space: nowrap; }
.page-jump-bar a:hover { text-decoration: underline; }
.page-jump-bar a.danger-link { color: #9a3412; }
.card, #renderBar { scroll-margin-top: 64px; }

/* The classic flat block list, folded away because the Editor is the better
   place to do this work — but still one click from the person who wants it. */
.blocks-details > summary { cursor: pointer; font-size: 13.5px; }

/* The guide's reference pictures — screenshots taken from the app itself by
   tools/make_guide_shots.py, so they cannot drift from what the screens
   really look like. */
.guide-shot { margin: 14px 0 18px; }
.guide-shot img { max-width: 100%; height: auto; border: 1px solid var(--line);
  border-radius: 6px; box-shadow: 0 1px 4px rgba(60, 46, 20, .08); }
.guide-shot figcaption { font-size: 12px; color: var(--muted); margin-top: 6px; }
li .guide-shot { margin: 10px 0 6px; }
#renderStatus { font-size: 12.5px; color: var(--muted); }

/* Front/back matter (Section 9) panels */
.matter-card h3 { font-size: 15px; }
.matter-item { border: 1px solid var(--line); border-radius: 6px; padding: 10px 12px; margin-bottom: 10px; background: #fff; }
.matter-item-header { display: flex; align-items: center; gap: 12px; margin-bottom: 6px; }
.matter-item-name { font-weight: 600; font-size: 13px; color: var(--ink); }
.matter-include { display: flex; align-items: center; gap: 4px; font-size: 11.5px; color: var(--muted); cursor: pointer; }
.matter-remove { margin-left: auto; font-size: 11px; padding: 3px 8px; }
.matter-title-input {
  width: 100%; box-sizing: border-box; font-size: 12.5px; padding: 5px 8px;
  border: 1px solid #cabfa8; border-radius: 4px; margin-bottom: 6px; font-family: inherit;
}
.matter-body {
  width: 100%; box-sizing: border-box; font-size: 12.5px; padding: 6px 8px;
  border: 1px solid #cabfa8; border-radius: 4px; font-family: Georgia, serif; resize: vertical;
}
.matter-add-row { display: flex; align-items: center; gap: 8px; margin-top: 4px; }
.matter-add-row select { font-size: 12.5px; padding: 5px 6px; border: 1px solid #cabfa8; border-radius: 4px; background: #fff; flex: 1; max-width: 320px; }
.matter-add-row button { font-size: 12.5px; }

/* Typography panel (Section 8) — shared by the ingest form and the project page */
.typography-details summary { cursor: pointer; font-size: 12.5px; color: var(--muted); padding: 4px 0; }
.typography-panel { margin-top: 10px; display: flex; flex-direction: column; gap: 8px; }
.typo-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.typo-label { font-size: 12.5px; min-width: 150px; color: var(--ink); }
.typo-font-select { font-size: 12.5px; padding: 4px 6px; border: 1px solid #cabfa8; border-radius: 4px; background: #fff; min-width: 220px; }
.typo-size-input { font-size: 12.5px; padding: 4px 6px; border: 1px solid #cabfa8; border-radius: 4px; width: 70px; }
.typo-color-input { width: 32px; height: 28px; padding: 1px; border: 1px solid #cabfa8; border-radius: 4px; background: #fff; cursor: pointer; }
.typo-color-clear { font-size: 10.5px; padding: 3px 7px; }
.typo-color-clear.hidden { display: none; }
/* The typography panel covers thirty-five named elements. Flat, that is a
   wall; filed under folding groups it is a settings page. The groups a
   project has already customized open on load, so returning to a book shows
   what was done to it. */
.typo-group { border: 1px solid #e2d9c4; border-radius: 6px; margin: 8px 0; background: #fffdf8; }
.typo-group > summary { cursor: pointer; padding: 7px 10px; font-size: 12.5px; font-weight: 600; color: #57503f; list-style-position: inside; }
.typo-group > summary:hover { background: #f6f1e4; border-radius: 6px; }
.typo-group[open] > summary { border-bottom: 1px solid #ece5d3; border-radius: 6px 6px 0 0; }
.typo-group-rows { padding: 8px 10px 10px; display: flex; flex-direction: column; gap: 7px; }
.typo-row-all { padding: 8px 10px; background: #f6f1e4; border: 1px solid #e2d9c4; border-radius: 6px; margin-bottom: 4px; }
.typo-all-note { margin: 0; flex: 1 1 200px; }
.typo-clear-all { font-size: 11px; padding: 3px 9px; }
.typography-card h3 { font-size: 15px; }
.editor-switch-link {
  flex-shrink: 0; font-size: 12.5px; font-weight: 600; color: #fff; background: var(--accent);
  padding: 8px 14px; border-radius: 6px; text-decoration: none; white-space: nowrap;
}
.editor-switch-link:hover { opacity: 0.9; }

/* ---- Kindle-Create-style three-pane editor -------------------------- */
/* The editor fills exactly the space the header leaves, measured rather than
   guessed. This was `height: calc(100vh - 58px)` — a hard-coded header
   height — and the header is not 58px: it wraps at narrow widths, and it grew
   again when the signed-in account was added to it. The shell was 27–44px
   taller than its container depending on the viewport, so the bottom of the
   props panel and the last line of the preview sat below the fold with no
   way to scroll to them. A flex column cannot be wrong about this. */
/* --- The editor's toolbar -------------------------------------------------
   Sixteen controls in one non-wrapping row is what this was, sized in inline
   styles. On a laptop the labels stacked into three-line towers — "bleed / +
   / crop / marks" — and the last four items ran off the right edge where
   nothing could reach them.

   Two rules do most of the work: nothing inside a control is allowed to wrap,
   and the row may wrap between controls. Then the six things somebody goes
   looking for rather than reaches for — the other export formats, spreads,
   preflight, the cover template, the classic page — sit behind one menu
   instead of taking a third of the bar. */
body.editor-page header { flex-wrap: wrap; row-gap: 8px; padding: 10px 20px; align-items: center; }
body.editor-page header h1 { font-size: 16px; }
.ed-book-name { color: var(--muted); font-size: 13px; max-width: 190px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ed-toolbar {
  margin-left: auto; display: flex; align-items: center; flex-wrap: wrap;
  gap: 8px; row-gap: 6px; justify-content: flex-end;
}
.ed-toolbar > * { flex: none; }
.ed-tool-group { display: flex; align-items: center; gap: 6px; }
.ed-tool-sep { border-left: 1px solid var(--line); align-self: stretch; min-height: 20px; }
/* Never wraps. This is the rule the old bar was missing: a label allowed to
   break turned four words into four lines and made the bar three rows tall. */
.ed-tool-check {
  display: flex; align-items: center; gap: 5px; font-size: 12px;
  color: var(--muted); cursor: pointer; white-space: nowrap;
}
.ed-toolbar button, .ed-toolbar a { white-space: nowrap; }
/* One control, not four. The input, the match count and the two step arrows
   share a single outline, so the arrows read as belonging to the search rather
   than as two unexplained buttons sitting on the toolbar — which is how they
   were reported. */
.ed-search-group {
  border: 1px solid #cabfa8; border-radius: 5px; background: #fff;
  padding: 1px 2px 1px 0; gap: 2px;
}
.ed-search-group:focus-within { border-color: var(--accent); }
.ed-search-group input {
  width: 130px; font-size: 12px; padding: 4px 7px;
  border: none; background: none; min-width: 0; outline: none;
}
.ed-search-count { font-size: 11px; color: var(--muted); min-width: 30px;
  text-align: center; font-variant-numeric: tabular-nums; }
.ed-search-group button {
  font-size: 11px; line-height: 1; padding: 3px 6px; border-radius: 3px;
  border: 1px solid transparent; background: none; color: var(--muted); cursor: pointer;
}
.ed-search-group button:hover:not(:disabled) { border-color: #ddd0ae; color: #4a3f2d; }
.ed-search-group button:disabled { opacity: 0.32; cursor: default; }
.ed-label-short { display: none; }

.ed-more { position: relative; display: inline-flex; }
.ed-more-btn {
  font-size: 12.5px; padding: 4px 9px; border: 1px solid #cabfa8; border-radius: 5px;
  background: var(--paper); color: var(--accent); cursor: pointer;
}
.ed-more-btn:hover { border-color: var(--accent); }
.ed-more-list {
  position: absolute; top: calc(100% + 6px); right: 0; z-index: 40;
  display: flex; flex-direction: column; min-width: 190px; padding: 5px;
  background: var(--paper); border: 1px solid var(--line); border-radius: 7px;
  box-shadow: 0 6px 18px rgba(30,25,10,0.16);
}
.ed-more-list[hidden] { display: none; }
.ed-more-list a { padding: 7px 10px; border-radius: 4px; font-size: 13px; }
.ed-more-list a:hover { background: #faf7f0; text-decoration: none; }

/* The two render options are the first thing to give up their words: their
   tooltips say the whole sentence, and "Crop" beside a ticked box is not
   ambiguous when the Render button is next to it. */
@media (max-width: 1180px) {
  .ed-label-long { display: none; }
  .ed-label-short { display: inline; }
}
/* Then the search box, which is the one control that can be narrow and still
   work — you can see what you typed either way. */
@media (max-width: 900px) {
  .ed-search-group input { width: 84px; }
  .ed-book-name { display: none; }
  .ed-tool-sep { display: none; }
  .ed-toolbar { gap: 6px; }
}

body.editor-page { display: flex; flex-direction: column; height: 100vh;
  overflow: hidden; overflow-x: clip; }
.editor-page header { padding: 10px 20px; flex: 0 0 auto; }
.editor-page main { max-width: none; padding: 0; flex: 1 1 auto; min-height: 0;
  overflow: hidden; display: flex; flex-direction: column; }
.editor-page .flash { margin: 8px 20px 0; flex: 0 0 auto; }

.editor-shell { display: flex; flex: 1 1 auto; min-height: 0; min-width: 0; max-width: 100vw; }

.editor-outline { width: 250px; flex: 0 0 250px; overflow-y: auto; border-right: 1px solid var(--line); background: var(--paper); }
.outline-group-label { font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); padding: 14px 16px 6px; }
.outline-item {
  padding: 6px 16px; font-size: 13px; cursor: pointer; color: var(--ink);
  border-left: 3px solid transparent; line-height: 1.35; word-break: break-word;
  display: flex; align-items: flex-start; gap: 6px;
}
.outline-item-label { flex: 1; min-width: 0; }
/* The move arrows appear on hover or when the row is the selected one. Shown
   always, they turn a quiet map of the book into a wall of controls; hidden
   entirely, nobody finds them — so they also stay visible on whatever row is
   selected, which is the row somebody is working on. */
.outline-move { display: flex; gap: 1px; opacity: 0; transition: opacity 0.12s; flex: none; }
.outline-item:hover .outline-move,
.outline-item.selected .outline-move,
.outline-move:focus-within { opacity: 1; }
.outline-move-btn {
  font-size: 8px; line-height: 1; padding: 3px 4px; border-radius: 3px;
  border: 1px solid #ddd0ae; background: #fffdf8; color: var(--muted); cursor: pointer;
}
.outline-move-btn:hover { border-color: var(--accent); color: #4a3f2d; }
.outline-item:hover { background: #faf7f0; }
.outline-item.selected { background: var(--suggest-bg); border-left-color: var(--accent); font-weight: 600; }
.outline-item.chapter { font-weight: 600; margin-top: 2px; }
.outline-item.sub { padding-left: 30px; font-size: 12px; color: #5c5648; font-weight: 400; }
.outline-item.subsub { padding-left: 42px; font-size: 11.5px; color: #77705f; font-style: italic; font-weight: 400; }
.outline-empty-hint { padding: 6px 16px; font-size: 11.5px; color: var(--muted); font-style: italic; }
.outline-add-row { padding: 6px 12px 14px; }
.outline-add-row select { width: 100%; font-size: 11.5px; padding: 4px 5px; border: 1px solid #cabfa8; border-radius: 4px; margin-bottom: 4px; }
.outline-add-row button { width: 100%; font-size: 11.5px; padding: 4px 0; }

.editor-preview-col { flex: 1 1 auto; min-width: 0; overflow-y: auto; overflow-x: hidden; background: var(--bg); padding: 36px 24px; }
.editor-preview-page {
  /* Proportional to the book's own trim, not a fixed 560px. An 8.5x11
     textbook and a 5x8 novel were being shown at identical widths, so the
     line the designer was judging on screen was not the line that would
     print — which is most of what the preview is for. `min(…, 100%)` keeps
     it inside the column when the panels are open. */
  box-sizing: border-box; max-width: min(var(--ed-page-width, 560px), 100%);
  margin: 0 auto; background: #fff; box-shadow: 0 1px 6px rgba(30,25,10,0.08);
  padding: 54px 56px 80px; font-family: Georgia, serif; min-height: 100%;
}
.editor-el {
  cursor: pointer; border: 1.5px solid transparent; border-radius: 3px; padding: 2px 4px; margin: 0 -4px;
}
.editor-el:hover { border-color: #e8dfc4; background: #fffdf7; }
.editor-el.selected { border-color: var(--accent); background: #fff7e6; }

/* Inline (Kindle/Word-style) block editing — a persistent, low-key style
   picker in a left gutter plus a directly-typeable content element, so
   fixing a word or reclassifying a paragraph never requires a trip to the
   side panel (see mtp/webapp_templates/editor.html's wireBlockEditable). */
.editor-hintbar {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  max-width: min(var(--ed-page-width, 560px), 100%); margin: 0 auto 10px; font-size: 11.5px; color: var(--muted); line-height: 1.5;
}
.editor-hintbar strong { color: #4a3f2d; font-weight: 600; }
/* THE CONTROLS DO NOT SHARE THE MEASURE.

   This was a flex row: a gutter of controls on the left, the text on the
   right, the two dividing the page between them. Every control added to that
   gutter took width away from the text — and with a style menu, an add-picture
   button, an insert and a delete in it, the gutter had grown to a third of the
   column. The line the designer was judging on screen was nothing like the
   line that would print, which is most of what a preview is for. On an image
   block the same arithmetic had already reduced the picture to zero width.

   So the controls now float above the block they belong to, out of the flow
   entirely, and only for the block being pointed at or worked on. The text
   below is set to the page's true measure at all times, and the toolbar
   appears over the space between paragraphs rather than beside them. */
.ed-block { position: relative; cursor: default; }
.ed-block.ed-chapter-open { margin-top: 20pt; }
.ed-quickpicker {
  position: absolute; bottom: 100%; left: -6px; z-index: 6;
  display: flex; align-items: center; gap: 3px; flex-wrap: wrap;
  padding: 4px 6px; margin-bottom: 2px; max-width: calc(100% + 12px);
  background: #fdfbf4; border: 1px solid #e4d9bd; border-radius: 5px;
  box-shadow: 0 2px 7px rgba(30,25,10,0.13);
  opacity: 0; pointer-events: none; transition: opacity 0.1s;
}
/* Shown for the block under the pointer and for the block being worked on.
   Always-on turned the page into a wall of dropdowns with the book somewhere
   behind it; never-on means nobody finds them. `focus-within` keeps the
   toolbar up while a control inside it has the keyboard. */
.ed-block:hover > .ed-quickpicker,
.ed-block.selected > .ed-quickpicker,
.ed-quickpicker:focus-within,
.ed-quickpicker:hover { opacity: 1; pointer-events: auto; }
/* The first block on the page has nothing above it to float over, so its
   toolbar sits inside the page's own top padding instead of off the top. */
.editor-preview-page > .ed-block:first-child > .ed-quickpicker,
.ed-block.ed-first-on-page > .ed-quickpicker { bottom: auto; top: -4px; }
.ed-quickpicker select {
  font-size: 10px; padding: 2px 3px; border: 1px solid #ddd0ae; border-radius: 4px;
  background: #faf8f0; color: var(--muted); max-width: 118px; cursor: pointer;
}
.ed-quickpicker select:hover, .ed-quickpicker select:focus { border-color: var(--accent); color: #4a3f2d; }
.ed-insert-btn, .ed-insert-above-btn, .ed-delete-btn {
  font-size: 11px; line-height: 1; width: 18px; height: 18px; padding: 0; border-radius: 4px;
  border: 1px solid #ddd0ae; background: #faf8f0; color: var(--muted); cursor: pointer;
}
/* Two characters, so it needs the room the others don't. Sits BEFORE the
   plain + in the gutter, in the order the two things happen on the page:
   above, then below. */
.ed-insert-above-btn { width: 24px; letter-spacing: -0.5px; }
.ed-insert-btn:hover, .ed-insert-above-btn:hover { border-color: #4a7a4a; color: #2f5a2f; }
.ed-delete-btn:hover { border-color: #b23; color: #b23; }
.ed-delete-btn.armed { border-color: #b23; background: #fbe9e6; color: #b23; font-weight: 700; }
.outline-add-row:first-of-type { padding-top: 0; }
.ed-block-content { cursor: text; outline: none; border-radius: 3px; }
.ed-block-content:focus { background: #fffdf0; box-shadow: 0 0 0 2px #f0e4b8 inset; }
.ed-block-content:empty:before { content: '(empty)'; color: #bbb; font-style: italic; }
.ed-search-hit { background: #ffe58a; border-radius: 2px; }
.ed-search-hit-current { background: #ffb300; box-shadow: 0 0 0 1px #b8860b; }
/* An image block's controls sit ABOVE the picture, not beside it.
   Every other block has three things in its gutter — a style menu and two
   buttons — and the gutter is `flex: 0 0 auto`, meaning it never shrinks. An
   image block now has twelve: size, scale, alignment, replace, move up, move
   down, add, insert, delete. Left in the gutter they took 398 pixels of a
   414-pixel column and the picture itself was laid out at ZERO width — an
   empty cream box with a toolbar floating in it, and the resolution warning
   wrapped one word per line down a 20-pixel strip. Measured, not guessed.
   Stacking gives the picture the full measure back and lets the toolbar wrap
   onto a second line on a narrow page instead of crushing what it belongs to. */
/* An image block's twelve controls are the reason the gutter had to leave the
   flow at all. They wrap onto a second line inside the floating toolbar rather
   than pushing the picture off the page. */
.ed-image-block > .ed-quickpicker { max-width: 100%; }
/* --- Where the pages broke -----------------------------------------------
   A rule across the measure with the page number on it, drawn between the two
   blocks that printed on either side of a page break. The editor is one
   continuous galley, so this is a record of the last render rather than a
   live calculation — and when the text has changed since, the rule says so
   instead of quietly presenting yesterday's break as today's. */
.ed-page-break {
  display: flex; align-items: center; gap: 10px;
  margin: 18px -4px; user-select: none; cursor: default;
}
.ed-page-break::before, .ed-page-break::after {
  content: ""; flex: 1; border-top: 1px dashed #cbbf9f;
}
.ed-page-break-label {
  font-family: -apple-system, "Segoe UI", sans-serif;
  font-size: 10px; letter-spacing: 0.1em; text-transform: uppercase;
  color: #8a7c5c; white-space: nowrap;
}
.ed-page-break.is-stale::before, .ed-page-break.is-stale::after { border-top-style: dotted; opacity: 0.55; }
.ed-page-break.is-stale .ed-page-break-label { opacity: 0.6; font-style: italic; }
.ed-image-size-group { display: flex; gap: 2px; }
.ed-image-size-btn {
  font-size: 10px; line-height: 1; padding: 3px 6px; border-radius: 4px;
  border: 1px solid #ddd0ae; background: #faf8f0; color: var(--muted); cursor: pointer;
}
.ed-image-size-btn:hover { border-color: var(--accent); color: #4a3f2d; }
.ed-image-size-btn.active { border-color: var(--accent); background: var(--accent); color: #fff; font-weight: 600; }
.ed-image-body { display: flex; flex-direction: column; }
.ed-image-preview { text-align: center; padding: 6px 0; }
/* Width comes from a --img-scale custom property set per block, because it
   is now any percentage between 10 and 100 rather than one of three named
   sizes — there is no useful number of classes for that. A full-bleed plate
   sets no property and falls through to the 100% default. */
.ed-image-preview img { max-width: 100%; width: var(--img-scale, 100%);
  height: auto; display: inline-block; border-radius: 3px; }
.ed-image-preview.ed-img-left { text-align: left; }
.ed-image-preview.ed-img-center { text-align: center; }
.ed-image-preview.ed-img-right { text-align: right; }
.ed-image-scale-group, .ed-image-align-group { display: flex; align-items: center; gap: 2px; }
.ed-image-scale-value {
  font-size: 10px; color: var(--muted); min-width: 30px; text-align: center;
  font-variant-numeric: tabular-nums;
}
.ed-image-step-btn, .ed-image-align-btn, .ed-image-replace-btn {
  font-size: 10px; line-height: 1; padding: 3px 5px; border-radius: 4px;
  border: 1px solid #ddd0ae; background: #faf8f0; color: var(--muted); cursor: pointer;
}
.ed-image-step-btn:hover:not(:disabled), .ed-image-align-btn:hover,
.ed-image-replace-btn:hover { border-color: var(--accent); color: #4a3f2d; }
/* Adding a picture, and nudging one through the book. Same furniture as the
   scale/align controls beside them — they belong to the same gutter and
   should not read as a different kind of control. */
.ed-add-image-btn, .ed-move-btn {
  font-size: 11px; line-height: 1; padding: 2px 6px; border-radius: 4px;
  border: 1px solid #ddd0ae; background: #faf8f0; color: var(--muted); cursor: pointer;
}
.ed-add-image-btn:hover, .ed-move-btn:hover { border-color: var(--accent); color: #4a3f2d; }
.ed-image-move-group { display: inline-flex; gap: 2px; }
.ed-image-step-btn:disabled { opacity: 0.4; cursor: default; }
.ed-image-align-btn.active { border-color: var(--accent); background: var(--accent); color: #fff; font-weight: 600; }
.ed-image-missing {
  padding: 18px; border: 1px dashed #cabfa8; border-radius: 4px; color: var(--muted);
  font-size: 12px; font-style: italic;
}
.ed-image-caption-row { display: flex; align-items: center; gap: 6px; padding: 0 4px 4px; }
.ed-figure-label { font-size: 11px; font-style: italic; color: var(--muted); white-space: nowrap; flex-shrink: 0; }
.ed-image-caption-input {
  flex: 1; min-width: 0; font-size: 12px; font-style: italic; padding: 3px 6px;
  border: 1px solid transparent; border-radius: 3px; background: transparent; color: inherit;
}
.ed-image-caption-input:hover { border-color: #ddd0ae; }
.ed-image-caption-input:focus { outline: none; border-color: var(--accent); background: #fffdf0; }
.ed-table-block { align-items: flex-start; }
.ed-table-header-toggle { display: flex; align-items: center; gap: 4px; font-size: 11px; color: var(--muted); white-space: nowrap; cursor: pointer; }
.ed-table-header-toggle input { cursor: pointer; }
.ed-table-body { flex: 1; min-width: 0; overflow-x: auto; }
.ed-table { border-collapse: collapse; width: 100%; font-size: 13px; }
.ed-table th, .ed-table td.ed-table-cell {
  border: 1px solid #ddd0ae; padding: 4px 8px; text-align: left; vertical-align: top; min-width: 40px;
  /* Overrides this file's own dashboard-chrome `th` rule (font-size, muted
     color, uppercase, letter-spacing — meant for the app's own list tables,
     not manuscript content) — a table cell here shows the author's text
     exactly as typed, the same way an image caption or a paragraph does. */
  color: inherit; font-size: 13px; font-weight: normal; text-transform: none; letter-spacing: normal;
}
.ed-table tr.ed-table-header-row th { background: #f3ead2; font-weight: 600; }
.ed-table .ed-table-cell:focus { outline: none; background: #fffdf0; box-shadow: 0 0 0 2px #f0e4b8 inset; }
.ed-table-rowctrl, .ed-table-colctrl, .ed-table-corner { border: none !important; padding: 0 !important; width: 18px; text-align: center; vertical-align: middle; }
.ed-table-delrow-btn, .ed-table-delcol-btn {
  font-size: 10px; line-height: 1; width: 16px; height: 16px; border-radius: 50%; padding: 0;
  border: 1px solid #ddd0ae; background: #faf8f0; color: var(--muted); cursor: pointer; opacity: 0.5;
}
.ed-table-delrow-btn:hover, .ed-table-delcol-btn:hover { opacity: 1; border-color: #c0392b; color: #c0392b; }
.ed-table-toolbar { display: flex; gap: 6px; margin-top: 6px; }
.ed-table-addrow-btn, .ed-table-addcol-btn {
  font-size: 11px; padding: 3px 8px; border-radius: 4px; border: 1px solid #ddd0ae;
  background: #faf8f0; color: var(--muted); cursor: pointer;
}
.ed-table-addrow-btn:hover, .ed-table-addcol-btn:hover { border-color: var(--accent); color: #4a3f2d; }
.editor-preview-page .ed-titlepage { text-align: center; padding: 70px 0 40px; }
.editor-preview-page .ed-titlepage h1 { font-size: 26px; font-weight: 600; margin: 0 0 10px; }
.editor-preview-page .ed-titlepage .subtitle { font-style: italic; color: var(--muted); font-size: 15px; margin: 0 0 14px; }
.editor-preview-page .ed-titlepage .by { font-style: italic; color: var(--muted); font-size: 14px; }
/* The extra lines a title page carries besides title, subtitle and author —
   "Translated by …", an edition line, an imprint. Same treatment as the
   author's name, one step smaller, matching render._TITLEPAGE_BASE_CSS so the
   preview and the printed page agree. */
.editor-preview-page .ed-titlepage .tp-extra { font-style: italic; color: var(--muted); font-size: 12.5px; margin: 5px 0 0; }
.editor-preview-page .ed-titlepage .by + .tp-extra { margin-top: 14px; }
/* Alignment is applied as a modifier class rather than an inline style so the
   whole page — words and publisher mark together — moves as one. The logo
   wrapper is a flex column, so it moves by align-items; text-align alone
   would leave the mark centred under a flush-left title. */
.editor-preview-page .ed-titlepage.tp-left { text-align: left; }
.editor-preview-page .ed-titlepage.tp-left .ed-tp-logo-wrap { align-items: flex-start; }
.editor-preview-page .ed-titlepage.tp-right { text-align: right; }
.editor-preview-page .ed-titlepage.tp-right .ed-tp-logo-wrap { align-items: flex-end; }
.editor-preview-page .ed-titlepage.tp-center { text-align: center; }
.editor-preview-page .ed-titlepage.tp-center .ed-tp-logo-wrap { align-items: center; }
/* A swatch beside each colour control, so "theme default" and a chosen
   colour are told apart at a glance rather than by opening the picker. */
.tp-color-row { display: flex; align-items: center; gap: 8px; margin: 0 0 6px; }
.tp-color-row label { flex: 1; font-size: 12px; color: var(--muted); }
.tp-color-row input[type=color] { width: 34px; height: 24px; padding: 0; border: 1px solid #ddd0ae; border-radius: 4px; background: none; cursor: pointer; }
.tp-color-clear { font-size: 11px; padding: 2px 7px; border-radius: 4px; border: 1px solid #ddd0ae; background: #faf8f0; color: var(--muted); cursor: pointer; }
.tp-color-clear:hover { border-color: var(--accent); color: #4a3f2d; }
.tp-color-row.is-default input[type=color] { opacity: 0.45; }
/* The spacing form: four rows of "above / below", in points. A table rather
   than a stack of labelled fields, because the thing a designer is checking is
   the relationship between the numbers — 16/6 against 12/6 — and a column of
   figures shows that at a glance where a list of sentences does not. */
.spacing-table { margin: 0 0 8px; }
.spacing-row { display: grid; grid-template-columns: 1fr 52px 52px; gap: 5px; align-items: center; margin-bottom: 4px; }
.spacing-head { font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); margin-bottom: 2px; }
.spacing-head span { text-align: center; }
.spacing-head span:first-child { text-align: left; }
.spacing-name { font-size: 12px; color: var(--ink); }
.spacing-row input[type=number] {
  width: 100%; font-size: 12px; padding: 3px 4px; text-align: right;
  border: 1px solid #ddd0ae; border-radius: 4px; background: #fffdf8; color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.spacing-row input[type=number]:focus { border-color: var(--accent); outline: none; }
.spacing-na { text-align: center; color: #c9bfa6; font-size: 12px; }
.spacing-buttons { display: flex; gap: 6px; }
.editor-preview-page .ed-tp-logo-wrap { margin-top: 48px; display: flex; flex-direction: column; align-items: center; }
.editor-preview-page .ed-tp-logo { max-height: 40px; max-width: 60%; object-fit: contain; }
.editor-preview-page .ed-tp-logo-default { display: flex; flex-direction: column; align-items: center; gap: 4px; color: var(--muted); font-size: 10.5px; letter-spacing: 0.14em; text-transform: uppercase; }
.editor-preview-page .ed-tp-logo-mark { width: 18px; height: 18px; color: var(--muted); }
.editor-preview-page .ed-halftitle { text-align: center; padding: 80px 0 40px; font-size: 19px; font-weight: 600; letter-spacing: 0.03em; }
.editor-preview-page .ed-matter-wrap { padding: 20px 6px 30px; }
.editor-preview-page .ed-matter-heading { text-align: center; font-variant: small-caps; letter-spacing: 0.08em; color: #4a3f2d; margin: 0 0 14px; font-size: 14px; }
.editor-preview-page .ed-matter-text { font-size: 13px; line-height: 1.6; color: #3f382c; white-space: pre-line; margin: 0 0 8px; }
/* The lines the app adds to the copyright page itself — publisher, edition,
   ISBN. Set apart from the author's own text so it is obvious they come from
   the book's settings rather than from the box above, and editable from the
   panel beside them rather than nowhere at all. */
.editor-preview-page .ed-cp-extras { margin-top: 12px; padding-top: 8px; border-top: 1px dashed #ddd0ae; }
.editor-preview-page .ed-cp-extra { font-size: 12.5px; line-height: 1.55; color: #5c5648; margin: 0 0 3px; }
.editor-preview-page .ed-cp-extra.cp-publisher { font-weight: 600; color: #4a3f2d; }
.editor-preview-page .ed-dedication .ed-matter-text, .editor-preview-page .ed-epigraph .ed-matter-text { text-align: center; font-style: italic; }
.editor-toc-label {
  text-align: center; font-variant: small-caps; letter-spacing: 0.1em; color: var(--muted);
  font-size: 12px; margin: 28px 0 14px; padding: 10px 0; border-top: 1px dotted var(--line); border-bottom: 1px dotted var(--line);
}
/* The editor's live contents list. Page numbers are deliberately absent —
   they only exist once WeasyPrint has paginated the book (see
   tocPreviewHtml) — so rows are plain left-aligned lines rather than the
   rendered PDF's leader-dotted title/number pairs. */
.ed-toc-preview { padding-bottom: 18px; }
.ed-toc-row { font-family: Georgia, serif; font-size: 13px; color: #3f382c; padding: 3px 0; }
.ed-toc-row.sub { padding-left: 18px; font-size: 11.5px; font-style: italic; color: #5c5648; }
.ed-toc-row.subsub { padding-left: 34px; font-size: 10.5px; font-style: italic; color: #7a7360; }
.ed-toc-empty { font-size: 12px; color: var(--muted); font-style: italic; padding: 4px 0; }

/* The book's final page — the one render.py pads to when the interior would
   otherwise end on an odd page. Shown even when empty so the author knows it
   exists and can put something on it. */
.ed-endpage { padding-bottom: 24px; }
.ed-endpage-hint { font-size: 12px; line-height: 1.6; color: var(--muted); font-style: italic; margin: 0; padding: 4px 0; }
.ed-endpage.empty { opacity: 0.75; }

.editor-props { box-sizing: border-box; max-width: 100%; min-width: 0; width: 310px; flex: 0 0 310px; overflow-y: auto; border-left: 1px solid var(--line); background: var(--paper); padding: 16px; }
.props-empty { color: var(--muted); font-size: 12.5px; padding: 20px 4px; text-align: center; }
.props-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
.props-header-label { font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted); }
.props-type-pill { font-size: 13px; font-weight: 700; color: var(--ink); margin-top: 2px; }
.props-tabs { display: flex; border-bottom: 1px solid var(--line); margin-bottom: 14px; }
.props-tab { flex: 1; text-align: center; padding: 8px 0; font-size: 12px; cursor: pointer; color: var(--muted); border-bottom: 2px solid transparent; background: none; border-top: none; border-left: none; border-right: none; border-radius: 0; }
.props-tab.active { color: var(--ink); font-weight: 600; border-bottom-color: var(--accent); }
.props-tab-panel.hidden { display: none; }
.props-section-label { font-size: 10.5px; text-transform: uppercase; color: var(--muted); letter-spacing: 0.04em; margin: 16px 0 6px; }
.props-section-label:first-child { margin-top: 0; }
.props-row { margin-bottom: 8px; }
.props-row label { display: block; font-size: 11.5px; color: var(--muted); margin-bottom: 3px; }
.props-row select, .props-row textarea, .props-row input[type=text] {
  width: 100%; box-sizing: border-box; font-size: 12.5px; padding: 5px 7px; border: 1px solid #cabfa8; border-radius: 4px; font-family: inherit;
}
.props-row textarea { font-family: Georgia, serif; resize: vertical; }
.props-inline { display: flex; align-items: center; gap: 8px; }
.props-inline input[type=color] { width: 30px; height: 26px; padding: 1px; border: 1px solid #cabfa8; border-radius: 4px; }
.props-hint { font-size: 11px; color: var(--muted); margin: 4px 0 0; line-height: 1.4; }
.props-warn { color: #7a3908; background: #fdf0dd; border: 1px solid #e6c79a;
  border-radius: 4px; padding: 6px 8px; }
.props-image-width { display: flex; align-items: center; gap: 6px; }
.props-image-width input[type="range"] { flex: 1; min-width: 0; }
.props-step-btn {
  font-size: 12px; line-height: 1; width: 22px; height: 22px; padding: 0; flex: 0 0 auto;
  border-radius: 4px; border: 1px solid #ddd0ae; background: #faf8f0;
  color: var(--muted); cursor: pointer;
}
.props-step-btn:hover:not(:disabled) { border-color: var(--accent); color: #4a3f2d; }
.props-step-btn:disabled { opacity: 0.4; cursor: default; }
.props-step-value { font-size: 11px; color: var(--muted); min-width: 34px;
  text-align: right; font-variant-numeric: tabular-nums; }
.props-action-btn {
  font-size: 11px; padding: 5px 10px; border-radius: 4px; cursor: pointer;
  border: 1px solid #ddd0ae; background: #faf8f0; color: #4a3f2d;
}
.props-action-btn:hover { border-color: var(--accent); }
.props-note { font-size: 12px; color: var(--muted); font-style: italic; padding: 8px 0; }
.props-remove-btn { font-size: 11px; padding: 4px 9px; color: var(--err); border-color: #e0b5a8; margin-top: 4px; }

/* Part divider in the editor: a title alone, styled like the divider page it
   prints as. The Part tag sits where other blocks show their style picker,
   since a part is a block type rather than a paragraph style. */
.ed-part-block .part-title { font-family: Georgia, serif; font-size: 19pt; text-align: center;
  letter-spacing: 0.12em; text-transform: uppercase; color: var(--accent); padding: 22px 0; }
.ed-part-tag { font-size: 10px; text-transform: uppercase; letter-spacing: 0.08em;
  color: var(--muted); border: 1px solid var(--line); border-radius: 3px; padding: 2px 6px; }
.outline-item.part { font-weight: 700; text-transform: uppercase; letter-spacing: 0.05em; font-size: 11.5px; }

/* Back-of-book index controls on a block's Elements panel. */
.idx-term-list { display: flex; flex-direction: column; gap: 3px; margin-bottom: 8px; }
.idx-term-row { display: flex; align-items: center; justify-content: space-between; gap: 8px;
  font-size: 12px; background: #f7f4ec; border: 1px solid var(--line); border-radius: 4px; padding: 3px 6px; }
.idx-term-del { background: none; border: none; color: var(--muted); cursor: pointer;
  font-size: 14px; line-height: 1; padding: 0 2px; }
.idx-term-del:hover { color: var(--err); }

/* Facing-page spreads. Two leaves butted together at the gutter with a soft
   shadow between them, so the pair reads as one open book rather than two
   unrelated pages — which is the entire point of looking at spreads. */
.spread-list { display: flex; flex-direction: column; align-items: center; gap: 4px; padding-bottom: 40px; }
.spread { display: flex; justify-content: center; align-items: stretch; margin-top: 22px;
  box-shadow: 0 2px 14px rgba(33,29,23,0.18); background: #fff; }
.spread-leaf { display: flex; align-items: stretch; }
/* Cap by height, not width: a spread is only useful if both leaves are
   visible at once, and page height is what limits that. */
.spread-leaf img { display: block; max-height: 64vh; width: auto; }
.spread-leaf.verso { border-right: 1px solid #e6dfcc; }
.spread-empty { display: flex; align-items: center; justify-content: center; width: 100%; min-width: 120px;
  color: var(--muted); font-size: 11px; font-style: italic; background:
  repeating-linear-gradient(45deg, #f4f1e8, #f4f1e8 6px, #efebe0 6px, #efebe0 12px); }
.spread-label { font-size: 11px; color: var(--muted); letter-spacing: 0.04em; }
@media (max-width: 900px) { .spread { flex-direction: column; } .spread-leaf.verso { border-right: none; border-bottom: 1px solid #e6dfcc; } }

/* --- Preflight report ------------------------------------------------
   Colour carries the verdict, but never alone: each row also states
   "Problem" / "Check" / "Passed" in words, so the report survives being
   printed in black and white — which is exactly what someone assembling a
   print submission is likely to do with it. */
.pf-verdict { background: var(--paper); border: 1px solid var(--line); border-left-width: 5px;
  border-radius: 8px; padding: 18px 22px; margin-bottom: 22px; }
.pf-verdict-head { font-size: 17px; font-weight: 600; letter-spacing: -0.01em; }
.pf-verdict-sub { font-size: 12.5px; color: var(--muted); margin-top: 5px; }
.pf-verdict.pf-fail { border-left-color: #a33a2a; }
.pf-verdict.pf-warn { border-left-color: #b45309; }
.pf-verdict.pf-pass { border-left-color: #4a7c4e; }
.pf-list { display: flex; flex-direction: column; gap: 8px; }
.pf-item { display: flex; align-items: flex-start; gap: 14px; background: var(--paper);
  border: 1px solid var(--line); border-left-width: 4px; border-radius: 6px; padding: 13px 16px; }
.pf-item.pf-error { border-left-color: #a33a2a; }
.pf-item.pf-warning { border-left-color: #b45309; }
.pf-item.pf-ok { border-left-color: #cfd9c9; }
.pf-badge { flex: 0 0 62px; font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.06em;
  font-weight: 600; padding-top: 2px; }
.pf-error .pf-badge { color: #a33a2a; }
.pf-warning .pf-badge { color: #b45309; }
.pf-ok .pf-badge { color: #6f8a70; }
.pf-body { flex: 1 1 auto; min-width: 0; }
.pf-msg { font-size: 13.5px; line-height: 1.45; }
.pf-detail { font-size: 12px; color: var(--muted); margin-top: 4px; line-height: 1.5;
  overflow-wrap: anywhere; }
.pf-check { flex: 0 0 auto; font-size: 10.5px; color: var(--muted); letter-spacing: 0.05em;
  text-transform: uppercase; padding-top: 3px; }
.pf-foot { font-size: 11.5px; color: var(--muted); line-height: 1.65; margin: 22px 0 40px;
  max-width: 62ch; }
@media (max-width: 700px) {
  .pf-item { flex-wrap: wrap; }
  .pf-check { flex-basis: 100%; padding-left: 76px; }
}

/* --- Page margin controls (Book Details) ------------------------------ */
.margins-field select { margin-bottom: 6px; }
.margins-field input[type=number] { width: 100%; }
.margin-inputs { display: flex; gap: 8px; }
.margin-inputs label { display: flex; flex-direction: column; gap: 3px; flex: 1 1 0;
  font-size: 11.5px; color: var(--muted); margin: 0; }
.margin-inputs input { width: 100%; }
/* The gutter's millimetre box sits in a props-row on its own; without this it
   inherits the narrow width auto-sized number inputs get and clips the spinner. */
.editor-props .props-row input[type=number] { width: 100%; }
.editor-props .margin-inputs { margin-top: 4px; }
.pf-verdict-geometry { font-size: 12px; color: var(--muted); margin-top: 8px;
  padding-top: 8px; border-top: 1px solid var(--line); }
.pf-notes { background: var(--paper); border: 1px solid var(--line); border-radius: 6px;
  padding: 14px 18px; margin-top: 20px; }
.pf-notes-head { font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--muted); font-weight: 600; margin-bottom: 8px; }
.pf-notes ul { margin: 0; padding-left: 18px; }
.pf-notes li { font-size: 12px; color: var(--muted); line-height: 1.6; margin-bottom: 6px; }
.editor-props .props-row select { width: 100%; }

/* --- Delete a project ------------------------------------------------
   Kept visually quiet until opened, then unmistakable. The danger colour is
   only ever used here, so it can't be mistaken for ordinary emphasis. */
.delete-project { margin-top: 14px; padding: 14px 16px; border: 1px solid #e2c3c3;
  border-radius: 6px; background: #fdf6f6; max-width: 620px; }
.delete-project input { width: 100%; margin-bottom: 8px; }
button.danger { background: #a33a2a; color: #fff; border-color: #a33a2a; }
button.danger:hover { background: #8c2f21; }

/* --- Wordmark ---------------------------------------------------------
   "Clever Design" is the name; "Book Design Tool" says what it is. Set as
   one lockup so the header reads as a product name rather than a sentence. */
header h1 { display: flex; align-items: baseline; gap: 9px; white-space: nowrap; flex: 0 0 auto; }
.site-logo { width: 104px; height: 42px; object-fit: contain; object-position: left center; }
.site-tool-name { font-size: inherit; }
.wordmark-sub { font-size: 11px; font-weight: 400; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--muted); white-space: nowrap; }
.site-footer { max-width: 1400px; margin: 28px auto 0; padding: 14px 24px 22px;
  color: var(--muted); font-size: 12px; text-align: center; }
/* The editor's header is already crowded with controls, so the descriptor
   drops out well before the layout gets tight — the name alone still
   identifies the app. */
/* The editor had no breakpoints at all: three fixed-width panes plus a
   preview page meant a laptop showed a horizontal scrollbar and a tablet
   showed the outline, a sliver of text, and nothing else. The panes give way
   in the order they can be done without: the outline first (the preview is
   itself navigable), then the properties panel, which is reachable again by
   selecting a block once it has somewhere to go. */
@media (max-width: 1280px) {
  .editor-outline { width: 200px; flex: 0 0 200px; }
  .editor-props { width: 260px; flex: 0 0 260px; }
  .editor-preview-col { padding: 24px 14px; }
}
@media (max-width: 1040px) {
  .editor-outline { display: none; }
}
@media (max-width: 820px) {
  .editor-shell { flex-direction: column; }
  .editor-props { width: auto; flex: 0 0 auto; max-height: 45vh; border-left: 0;
    border-top: 1px solid var(--line); }
  .editor-preview-col { padding: 16px 10px; }
  .editor-hintbar { flex-wrap: wrap; gap: 6px; }
}
@media (max-width: 1500px) { .editor-page .wordmark-sub { display: none; } }
@media (max-width: 860px) { .wordmark-sub { display: none; } }
@media (max-width: 620px) { .site-logo { width: 72px; height: 34px; } .site-tool-name { display: none; } }

/* A link in the manuscript, shown as one in the editor so it's obvious the
   target is still there — and so a broken one is visible before the render. */
.preview a[data-mtp-link] { color: var(--accent); text-decoration: underline;
  text-underline-offset: 2px; }

/* --- Design-time warnings ---------------------------------------------
   Only ever shown in the editor. Nothing here has a counterpart in the
   rendered PDF or EPUB: the renderer doesn't read the fields that produce
   them, so a warning cannot end up in a printed book.

   Both use the same treatment so they read as one class of thing — a dotted
   amber underline for something inline, a bordered strip for something that
   belongs to a whole element. The word, not just the colour, carries the
   meaning. */
.ed-link-broken { border-bottom: 1.5px dotted #b45309; }
.ed-warn-badge { display: inline-block; margin-left: 4px; padding: 0 4px;
  font-size: 9px; font-family: system-ui, sans-serif; letter-spacing: 0.06em;
  text-transform: uppercase; vertical-align: 2px; color: #7a3908;
  background: #fdf0dd; border: 1px solid #e6c79a; border-radius: 3px;
  cursor: help; user-select: none; }
.ed-dpi-warning { margin: 6px auto 0; max-width: 90%; padding: 6px 9px;
  font-family: system-ui, sans-serif; font-size: 11px; line-height: 1.45;
  color: #7a3908; background: #fdf0dd; border: 1px solid #e6c79a;
  border-radius: 4px; text-align: left; }

/* --- Accounts ------------------------------------------------------------
   Sign-in, first-run setup and the admin screen. Deliberately plainer than
   the editor: these are pages somebody passes through, not works in, and a
   login form that tries to be interesting mostly gets in the way. */
/* The two things a page adds to the header: what you are looking at, and
   where you can go from here. Three templates each declared these inline,
   which is fine until a phone needs them to wrap — an inline style cannot be
   reached by a media query. */
/* Between full width and the 760px wrap point the flex row squeezes this
   span, and a long book title word-wrapped into a one-word-per-line column.
   Truncating with an ellipsis keeps the header one line tall at every width;
   the full title is on the page itself. */
.header-context { color: var(--muted); font-size: 13px; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; flex: 0 1 auto; min-width: 60px; }
.header-links { flex: 0 0 auto; }
.header-links a { white-space: nowrap; }
.header-links { margin-left: auto; display: flex; align-items: center; gap: 12px;
  flex-wrap: wrap; }

.header-account { margin-left: auto; display: flex; align-items: center; gap: 14px;
  font-size: 12px; }
.header-account a { color: var(--muted); }
.inline-form { display: inline-flex; align-items: center; gap: 4px; margin: 0; }
.linkish { background: none; border: 0; padding: 0; color: var(--muted); cursor: pointer;
  font: inherit; text-decoration: underline; }
.linkish:hover { color: #4a3f2d; }

.auth-card { max-width: 420px; margin: 6vh auto; padding: 26px 28px;
  border: 1px solid #e4dcc6; border-radius: 8px; background: #fffdf7; }
.auth-card h2 { margin-top: 0; }
.auth-card label { display: block; margin-top: 14px; font-size: 12px; font-weight: 600;
  color: #4a3f2d; }
.auth-card input { width: 100%; box-sizing: border-box; padding: 8px 10px; margin-top: 4px;
  border: 1px solid #ddd0ae; border-radius: 4px; background: #fff; font-size: 14px; }
.auth-card button.primary { margin-top: 20px; width: 100%; padding: 10px;
  font-size: 14px; }
.auth-note { font-size: 12px; color: var(--muted); line-height: 1.55; }
.field-hint { font-size: 11px; color: var(--muted); margin: 4px 0 0; line-height: 1.45; }

.admin-table { width: 100%; border-collapse: collapse; margin: 18px 0 30px; font-size: 13px; }
.admin-table th { text-align: left; font-size: 11px; letter-spacing: 0.06em;
  text-transform: uppercase; color: var(--muted); border-bottom: 1px solid #e4dcc6;
  padding: 6px 8px; }
.admin-table td { padding: 8px; border-bottom: 1px solid #f0e9d8; vertical-align: middle; }
.admin-table .inactive-row { opacity: 0.55; }
.admin-actions { display: flex; flex-wrap: wrap; gap: 8px; }
.admin-actions input[type="password"] { width: 150px; padding: 4px 6px; font-size: 12px;
  border: 1px solid #ddd0ae; border-radius: 4px; }
.pill { display: inline-block; font-size: 10px; padding: 1px 6px; border-radius: 8px;
  background: #f3ecd9; color: #7a6a4a; vertical-align: middle; }
.admin-create { max-width: 460px; display: flex; flex-direction: column; gap: 12px; }
.admin-create .field label { display: block; font-size: 12px; font-weight: 600; color: #4a3f2d; }
.admin-create .field input, .admin-create .field select { width: 100%; box-sizing: border-box;
  padding: 7px 9px; border: 1px solid #ddd0ae; border-radius: 4px; font-size: 13px; }

/* --- Project search ------------------------------------------------------ */
.project-search { display: flex; gap: 8px; align-items: center; margin: 0 0 16px; }
.project-search input { flex: 1; max-width: 380px; padding: 8px 10px; font-size: 13px;
  border: 1px solid #ddd0ae; border-radius: 4px; background: #fffdf7; }
.search-summary { font-size: 12px; color: var(--muted); margin: 0 0 14px; }

/* --- Editions ------------------------------------------------------------ */
.editions-list { list-style: none; padding: 0; margin: 0 0 14px; display: flex;
  flex-direction: column; gap: 8px; }
.edition-row { border: 1px solid #e4dcc6; border-radius: 6px; padding: 10px 12px;
  background: #fffdf7; font-size: 13px; }
.edition-row.primary { border-color: var(--accent); }
.edition-name { font-weight: 600; }
.edition-meta { font-size: 11px; color: var(--muted); margin-top: 3px; line-height: 1.5; }
.edition-estimate { color: #7a3908; }
/* Present for screen readers, absent for everyone else — the search field's
   label, which would otherwise be a redundant word above an obvious box. */
.visually-hidden { position: absolute; width: 1px; height: 1px; margin: -1px;
  padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.paper-choice { display: flex; flex-wrap: wrap; gap: 8px; align-items: flex-start; }
.paper-choice select, .paper-choice input { padding: 6px 8px; border: 1px solid #ddd0ae;
  border-radius: 4px; font-size: 13px; }
.paper-choice .field-hint { flex-basis: 100%; }
.ed-unpart-btn {
  font-size: 10px; line-height: 1; padding: 3px 6px; border-radius: 4px;
  border: 1px solid #ddd0ae; background: #faf8f0; color: var(--muted); cursor: pointer;
  white-space: nowrap;
}
.ed-unpart-btn:hover { border-color: #b23; color: #b23; }

/* --- Theme gallery -------------------------------------------------------
   Two pages side by side per card, because a theme's chapter opener and its
   body setting say different things and choosing on either alone is how you
   pick a design that turns out to be uncomfortable to read. */
.gallery-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
  gap: 20px; margin-top: 18px; }
.gallery-card { border: 1px solid #e4dcc6; border-radius: 8px; overflow: hidden;
  background: #fffdf7; display: flex; flex-direction: column; }
.gallery-card.current { border-color: var(--accent); box-shadow: 0 0 0 2px rgba(155,125,60,0.14); }
.gallery-pages { display: flex; gap: 2px; background: #efe9da; padding: 10px;
  align-items: flex-start; justify-content: center; min-height: 120px; }
.gallery-pages img { width: 48%; height: auto; background: #fff;
  box-shadow: 0 1px 3px rgba(0,0,0,0.14); }
.gallery-error { font-size: 11px; color: #7d1a1e; padding: 14px; text-align: center; }
.gallery-meta { padding: 10px 12px 12px; }
.gallery-name { font-weight: 600; font-size: 13.5px; }
.gallery-tagline { font-size: 11.5px; color: var(--muted); margin-top: 2px; }
.gallery-actions { display: flex; align-items: center; gap: 10px; margin-top: 8px;
  flex-wrap: wrap; }
.crumbs { font-size: 12px; margin: 0 0 10px; }
@media (max-width: 720px) { .gallery-grid { grid-template-columns: 1fr; } }

/* --- Ornaments and picture credits ------------------------------------
   The ornament preview draws the same SVG the renderer uses, so "Tapered
   rule" is a picture rather than a phrase somebody has to imagine. */
.ornament-preview { min-height: 26px; display: flex; align-items: center;
  justify-content: center; margin: 6px 0 2px; color: var(--ink); }
.ornament-preview svg { height: 20px; width: auto; }
.ornament-preview .orn.small { height: 16px; }
.ornament-preview .orn.tiny { height: 11px; }

.illus-row { display: flex; gap: 14px; padding: 12px 0; border-top: 1px solid var(--line); }
.illus-row:first-child { border-top: 0; }
.illus-thumb { flex: 0 0 120px; text-align: center; }
.illus-thumb img { max-width: 120px; max-height: 110px; border: 1px solid var(--line);
  background: #fff; }
.illus-label { font-size: 11px; color: var(--muted); margin-top: 4px; }
.illus-flag { margin-top: 4px; }
.illus-fields { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 6px; }
.illus-fields label { display: block; font-size: 11.5px; color: var(--muted); }
.illus-fields input, .illus-fields select { width: 100%; margin-top: 2px; }
.illus-pair { display: flex; gap: 10px; }
.illus-pair > label { flex: 1 1 0; min-width: 0; }
.illus-note { margin: 0; min-height: 14px; }
.illus-actions { display: flex; align-items: center; gap: 10px; margin-top: 2px; flex-wrap: wrap; }

/* --- Legacy-font conversion review ------------------------------------- */
.convert-summary { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 12px; margin: 16px 0; }
.convert-stat { border: 1px solid var(--line); border-radius: 6px; padding: 12px 14px;
  background: var(--card); }
.convert-stat .n { display: block; font-size: 26px; font-weight: 700; line-height: 1.1; }
.convert-stat .l { display: block; font-size: 12px; color: var(--muted); margin-top: 2px; }
.convert-stat p { font-size: 11.5px; color: var(--muted); margin: 8px 0 0; }
.convert-stat.ok .n { color: var(--ok); }
.convert-stat.warn .n { color: #8a6d1f; }
.convert-stat.err .n { color: var(--err); }
.convert-apply { display: flex; flex-wrap: wrap; align-items: center; gap: 14px; }
.convert-include { font-size: 12.5px; display: flex; align-items: center; gap: 6px;
  cursor: pointer; color: var(--muted); }
.convert-row { padding: 10px 0; border-top: 1px solid var(--line); }
.convert-row:first-of-type { border-top: 0; }
.convert-row.flagged { background: rgba(200, 160, 40, 0.06); padding-left: 10px;
  border-left: 3px solid var(--suggest-bd); }
.convert-why { font-size: 11.5px; color: #8a6d1f; margin-bottom: 4px; }
.convert-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 14px; }
.convert-label { display: block; font-size: 10.5px; color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 2px; }
.convert-row code { font-size: 12px; word-break: break-all; color: var(--muted); }
.convert-out { font-size: 15px; line-height: 1.6; }
@media (max-width: 640px) { .convert-pair { grid-template-columns: 1fr; } }
.legacy-banner { border-left: 3px solid var(--err); }
.legacy-banner h3 { color: var(--err); }
.primary-link { display: inline-block; font-size: 13px; font-weight: 600; }

/* --- The display heading levels, in the editor preview ------------------
   Sized between the chapter heading and the subheading, matching the print
   scale in mtp/headings.py so the preview and the PDF agree. */
.hd1 { font-size: 1.35em; font-weight: 600; margin: 1.4em 0 0.5em; line-height: 1.25; }
.hd2 { font-size: 1.18em; font-weight: 600; margin: 1.2em 0 0.4em; line-height: 1.3; }
.hd3 { font-size: 1.05em; font-weight: 600; margin: 1.05em 0 0.35em; line-height: 1.35; }
.subsubsubheading { font-size: 0.95em; font-weight: 600; font-style: italic;
  margin: 0.95em 0 0.3em; }
.toc-levels { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 2px 12px; margin: 4px 0 2px; }
.toc-level { display: flex; align-items: center; gap: 6px; font-size: 12.5px;
  cursor: pointer; }
.toc-level input[disabled] { cursor: default; }
.toc-levels-field { grid-column: 1 / -1; }

/* --- Manuscript cleanup -------------------------------------------------- */
.cleanup-list { margin: 10px 0; }
.cleanup-row { display: flex; gap: 10px; align-items: flex-start; padding: 9px 0;
  border-top: 1px solid var(--line); cursor: pointer; }
.cleanup-row:first-child { border-top: 0; }
.cleanup-row input { margin-top: 3px; }
.cleanup-nofix { color: var(--muted); width: 13px; text-align: center; }
.cleanup-body { flex: 1 1 auto; min-width: 0; }
.cleanup-why { display: block; font-size: 11px; color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.05em; }
.cleanup-detail { display: block; font-size: 12.5px; margin-top: 2px; }
/* The paragraph's own opening words, so a page of findings that all carry the
   same label can still be told apart and found in the book. */
.cleanup-excerpt { display: block; font-size: 12.5px; color: var(--ink); margin-top: 2px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cleanup-join { display: block; font-size: 13px; line-height: 1.55; margin-top: 3px; }
/* The seam is the whole point of the line — show exactly where the break is. */
.cleanup-seam { display: inline-block; background: var(--suggest-bd); color: #5c4415;
  border-radius: 3px; padding: 0 4px; margin: 0 3px; font-size: 11px; }
.cleanup-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 12px;
  margin-top: 6px; }

/* --- Editor: toast confirmations ---------------------------------------
   Saving already wrote "All changes saved ✓" into a small label in the
   toolbar, which is exactly where somebody who has just moved the mouse to
   the Save button is not looking. A toast appears where the eye already is
   and leaves on its own. */
/* Bottom LEFT, not centred: the spacing panel sits bottom-right, and on a
   1200px screen a centred toast lands underneath it. */
.ed-toasts { position: fixed; left: 22px; bottom: 22px;
  display: flex; flex-direction: column-reverse; align-items: flex-start; gap: 8px;
  z-index: 900; pointer-events: none; }
.ed-toast { pointer-events: auto; display: flex; align-items: center; gap: 9px;
  background: #2f2a20; color: #f7f2e6; font-size: 13px; line-height: 1.35;
  padding: 10px 15px; border-radius: 7px; box-shadow: 0 6px 22px rgba(0,0,0,0.24);
  max-width: 460px; animation: ed-toast-in 160ms ease-out; }
.ed-toast.ok .ed-toast-mark { color: #8fd39a; }
.ed-toast.error { background: #6d2320; }
.ed-toast.leaving { opacity: 0; transform: translateY(6px);
  transition: opacity 220ms ease, transform 220ms ease; }
.ed-toast-mark { font-size: 15px; }
@keyframes ed-toast-in { from { opacity: 0; transform: translateY(10px); } }
@media (prefers-reduced-motion: reduce) {
  .ed-toast { animation: none; }
  .ed-toast.leaving { transition: none; }
}

/* --- Editor: the spacing panel ----------------------------------------- */
.ed-count-badge:not(:empty) { display: inline-block; min-width: 16px; padding: 0 5px;
  margin-left: 4px; border-radius: 9px; background: var(--suggest-bd); color: #5c4415;
  font-size: 10.5px; font-weight: 700; }
.ed-panel { position: fixed; right: 18px; bottom: 18px; width: 400px; max-width: calc(100vw - 36px);
  background: var(--card); border: 1px solid var(--line); border-radius: 8px;
  box-shadow: 0 10px 34px rgba(0,0,0,0.18); padding: 14px 16px 16px; z-index: 880; }
.ed-panel-head { display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 6px; }
.ed-panel-close { border: 0; background: none; font-size: 18px; line-height: 1;
  cursor: pointer; color: var(--muted); padding: 0 4px; }
.ed-panel-note { font-size: 12px; color: var(--muted); margin: 0 0 8px; line-height: 1.5; }
.ed-panel-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.ed-panel-manual { border-top: 1px solid var(--line); margin-top: 12px; padding-top: 10px; }
.ed-panel-progress { font-size: 11px; color: var(--muted); text-transform: uppercase;
  letter-spacing: 0.05em; margin-bottom: 5px; }
.ed-panel-context { font-size: 13.5px; line-height: 1.6; background: #fbf8f0;
  border: 1px solid var(--line); border-radius: 5px; padding: 8px 10px;
  word-break: break-word; }
/* The whole point: make the invisible visible. */
.ed-space-mark { background: var(--err); color: #fff; border-radius: 2px;
  padding: 0 1px; margin: 0 1px; letter-spacing: 1px; }
/* The occurrence being looked at, marked in the page itself. Strong enough to
   find at a glance from across the screen — the whole difficulty with repeated
   spaces is that they are invisible, and a faint highlight reproduces the
   problem it is meant to solve. */
.ed-space-live { background: var(--err); border-radius: 2px;
  box-shadow: 0 0 0 2px var(--err); }

/* --- Formatting alerts --------------------------------------------------- */
.alert-tiers { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 12px; margin: 16px 0; }
.alert-tier { border: 1px solid var(--line); border-radius: 6px; padding: 12px 14px;
  background: var(--card); border-left-width: 3px; }
.alert-tier .n { display: block; font-size: 26px; font-weight: 700; line-height: 1.1; }
.alert-tier .l { display: block; font-size: 12px; color: var(--muted); margin-top: 2px; }
.alert-tier.high { border-left-color: var(--err); }
.alert-tier.high .n { color: var(--err); }
.alert-tier.medium { border-left-color: #b8912f; }
.alert-tier.medium .n { color: #8a6d1f; }
.alert-tier.low { border-left-color: var(--line); }
.pill.high { background: #f5dcd9; color: #7a2a24; }
.pill.medium { background: var(--suggest-bd); color: #5c4415; }
.pill.low { background: #e9e4d6; color: #5b564a; }
.alert-kinds { margin: 10px 0; }
.alert-kind { display: flex; gap: 10px; align-items: flex-start; padding: 8px 0;
  border-top: 1px solid var(--line); cursor: pointer; }
.alert-kind:first-child { border-top: 0; }
.alert-kind.reportonly { cursor: default; }
.alert-kind input { margin-top: 3px; }
.alert-nofix { width: 13px; text-align: center; color: var(--muted); }
.alert-kind-body { flex: 1 1 auto; min-width: 0; }
.alert-kind-label { display: block; font-size: 13px; }
.alert-n { display: inline-block; min-width: 18px; padding: 0 6px; margin-left: 6px;
  border-radius: 9px; background: #ece5d3; color: #57503f; font-size: 11px;
  font-weight: 700; }
.alert-why { display: block; font-size: 11.5px; color: var(--muted); margin-top: 2px; }
.alert-note { margin: 8px 0 0; }
.alert-actions { display: flex; flex-wrap: wrap; gap: 12px; align-items: center;
  margin-top: 10px; }
.alert-row { display: flex; gap: 10px; align-items: baseline; padding: 8px 0;
  border-top: 1px solid var(--line); flex-wrap: wrap; }
.alert-detail { font-size: 12.5px; color: var(--muted); flex: 1 1 260px; }
.alert-examples { margin-top: 12px; }
.alert-examples summary { cursor: pointer; font-size: 12.5px; color: var(--muted); }
.alert-samples { margin-top: 8px; max-height: 420px; overflow-y: auto; }
.alert-sample { padding: 5px 0; border-top: 1px solid var(--line); font-size: 12.5px; }
.alert-sample-kind { display: block; font-size: 10.5px; color: var(--muted);
  text-transform: uppercase; letter-spacing: 0.05em; }
.alert-sample code { word-break: break-word; }
.alert-sample mark { background: var(--err); color: #fff; border-radius: 2px;
  padding: 0 2px; }
.alert-arrow { font-size: 12.5px; color: var(--ok); margin-left: 6px; }

/* The book's house style for the parenthetical dash, under the findings it
   is measured against. */
.ed-panel-foot { margin-top: 10px; padding-top: 8px;
  border-top: 1px solid var(--line); }
.ed-dash-style { display: flex; align-items: center; gap: 8px;
  font-size: 11.5px; }
.ed-dash-style span { color: var(--muted); text-transform: uppercase;
  letter-spacing: 0.05em; font-size: 10.5px; white-space: nowrap; }
.ed-dash-style select { flex: 1; font-size: 11.5px; padding: 3px 5px; }
#edDashStyleNote { display: block; margin-top: 4px; }

/* --- The proofing rail ---------------------------------------------------
   One right-hand column with tabs rather than a second panel beside the
   first. The page in the middle is what the designer is actually reading and
   every extra rail steals width from it; paragraph settings and proofing are
   also never wanted at the same moment. */
.editor-rail { width: 320px; flex: 0 0 320px; max-width: 100%; min-width: 0; box-sizing: border-box; display: flex; flex-direction: column;
  min-height: 0; border-left: 1px solid var(--line); background: var(--paper); }
.editor-rail.wide { width: 400px; flex: 0 0 400px; }
.rail-tabs { display: flex; min-width: 0; border-bottom: 1px solid var(--line); flex: 0 0 auto; }
.rail-tab { flex: 1; border: 0; border-bottom: 2px solid transparent; background: none;
  padding: 9px 4px; font-size: 11.5px; cursor: pointer; color: var(--muted);
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  display: flex; align-items: center; justify-content: center; gap: 4px; }
.rail-tab:hover { background: rgba(0,0,0,0.03); }
.rail-tab.active { color: var(--ink); font-weight: 600;
  border-bottom-color: var(--accent, #8a6d3b); }
.rail-badge { display: none; }
.rail-badge.on { display: inline-flex; align-items: center; justify-content: center;
  min-width: 16px; height: 16px; padding: 0 4px; border-radius: 8px;
  background: #b8912f; color: #fff; font-size: 9.5px; font-weight: 700; }
.rail-pane { display: none; flex: 1 1 auto; min-height: 0; overflow-y: auto;
  flex-direction: column; }
.rail-pane.active { display: flex; }
#railProps { padding: 0; }
#railProps .editor-props { width: auto; flex: 1; border-left: 0; }

.rail-head { padding: 12px 14px 10px; border-bottom: 1px solid var(--line);
  flex: 0 0 auto; }
.rail-head button { width: 100%; margin-bottom: 7px; }
.rail-summary { font-size: 11.5px; color: var(--muted); display: block;
  line-height: 1.45; }
.rail-filters { padding: 8px 14px; border-bottom: 1px solid var(--line);
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.rail-toggle { font-size: 11px; color: var(--muted); display: flex;
  align-items: center; gap: 5px; cursor: pointer; }
.linklike { border: 0; background: none; padding: 0; font-size: 11px;
  color: var(--accent, #8a6d3b); text-decoration: underline; cursor: pointer; }
.rail-list { flex: 1 1 auto; overflow-y: auto; padding: 6px 0 14px; }
.rail-empty { font-size: 12px; color: var(--muted); padding: 18px 14px; }
.rail-subhead { font-size: 10.5px; text-transform: uppercase; letter-spacing: 0.05em;
  color: var(--muted); margin: 14px 14px 6px; }

/* A kind of finding, and the ones inside it. Grouped because that is how a
   proofreader works — all the quotation marks, then all the dashes — and
   because it is what makes "accept all" and "ignore all" mean anything. */
.rail-group { border-bottom: 1px solid var(--line); }
.rail-group-head { width: 100%; display: flex; align-items: center; gap: 7px;
  padding: 9px 14px; border: 0; background: none; cursor: pointer;
  text-align: left; font-size: 12px; border-left: 3px solid transparent; }
.rail-group-head:hover { background: rgba(0,0,0,0.03); }
.rail-group.high > .rail-group-head { border-left-color: var(--err, #a33); }
.rail-group.medium > .rail-group-head { border-left-color: #b8912f; }
.rail-group.low > .rail-group-head { border-left-color: #cfc4ae; }
.rail-caret { color: var(--muted); font-size: 10px; }
.rail-group-label { flex: 1; }
.rail-group-n { font-weight: 700; }
.rail-tag { font-size: 9px; text-transform: uppercase; letter-spacing: 0.05em;
  background: #ece5d3; color: #6b5a3a; padding: 2px 5px; border-radius: 3px; }
.rail-group-body { padding: 2px 14px 12px; }
.rail-why { font-size: 11px; color: var(--muted); line-height: 1.5;
  margin: 2px 0 9px; }
.rail-bulk { display: flex; gap: 6px; margin-bottom: 10px; flex-wrap: wrap; }
.rail-bulk button { font-size: 11px; padding: 4px 9px; }
.rail-note { font-size: 11px; color: var(--muted); font-style: italic; }

.rail-hit { border-top: 1px solid var(--line); padding: 8px 0 9px; cursor: pointer; }
.rail-hit.current { background: #fbf6e8; margin: 0 -14px; padding-left: 14px;
  padding-right: 14px; }
.rail-hit-text { font-size: 12px; line-height: 1.5; word-break: break-word; }
.rail-hit-text mark { background: #f6d98a; padding: 0 1px; border-radius: 2px; }
.rail-hit-becomes { font-size: 11px; color: var(--ok, #2a6a3a); margin-top: 3px; }
.rail-hit-actions { display: flex; gap: 5px; margin-top: 6px; flex-wrap: wrap; }
.rail-hit-actions button { font-size: 10.5px; padding: 3px 8px; }

/* Spelling: one row per distinct word, not per occurrence. A novel names its
   protagonist four hundred times and four hundred identical rows is a list
   nobody reads. */
.rail-convention { padding: 10px 14px; border-bottom: 1px solid var(--line);
  background: #faf7f0; }
.rail-conv-line { display: flex; flex-direction: column; gap: 2px;
  margin-bottom: 6px; font-size: 12px; }
.rail-convention select { width: 100%; font-size: 11.5px; padding: 3px 5px; }
.rail-word { border-bottom: 1px solid var(--line); padding: 9px 14px; }
.rail-word-head { display: flex; align-items: baseline; gap: 8px;
  font-size: 13px; margin-bottom: 4px; }
.rail-word-n { font-size: 11px; color: var(--muted); }

/* Queries. */
.rail-query { border-bottom: 1px solid var(--line); padding: 10px 14px; }
.rail-query.closed { opacity: 0.55; }
.rail-query-head { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; }
.rail-q-no { font-weight: 700; font-size: 12px; }
.rail-q-where, .rail-q-status { font-size: 10px; text-transform: uppercase;
  letter-spacing: 0.04em; color: var(--muted); }
.rail-q-status { margin-left: auto; }
.rail-q-question { font-size: 12px; line-height: 1.5; }
.rail-q-excerpt { font-size: 11px; font-style: italic; color: #555;
  border-left: 2px solid #cfc4ae; padding-left: 8px; margin-top: 5px; }
.rail-q-answer { font-size: 11.5px; margin-top: 5px; padding: 5px 7px;
  background: #eef5ee; border-radius: 3px; }

.rail-foot { flex: 0 0 auto; padding: 11px 14px; border-top: 1px solid var(--line);
  background: var(--paper); }
.rail-foot button { width: 100%; margin-bottom: 6px; }
.rail-setting { display: flex; align-items: center; gap: 8px; font-size: 11.5px; }
.rail-setting > span { color: var(--muted); text-transform: uppercase;
  letter-spacing: 0.05em; font-size: 10px; white-space: nowrap; }
.rail-setting select { flex: 1; font-size: 11.5px; padding: 3px 5px; }
.rail-proof-link { display: block; font-size: 11.5px; margin-top: 5px; }
.ed-panel-link { font-size: 11.5px; display: block; margin-top: 8px; }

/* A dot in the gutter of any paragraph with something in it: the rail says
   how many, this says where, without opening anything. */
.ed-alert-dot { display: inline-flex; align-items: center; justify-content: center;
  min-width: 14px; height: 14px; padding: 0 3px; margin-left: 4px;
  border-radius: 7px; font-size: 9.5px; font-weight: 700; cursor: pointer;
  color: #fff; vertical-align: middle; }
.ed-alert-dot.high { background: var(--err, #a33); }
.ed-alert-dot.medium { background: #b8912f; }
.ed-alert-dot.low { background: #b3a892; }

@media (max-width: 1500px) {
  .editor-rail { width: 280px; flex: 0 0 280px; }
  .editor-rail.wide { width: 340px; flex: 0 0 340px; }
}

/* --- Folding the side panels away ---------------------------------------
   The page in the middle is the thing being read; both side panels take
   width from it. On a 6x9 novel at a wide screen that is fine, on an 8.5x11
   book or a laptop it is not — the page ends up too small to judge a line
   break on, which is most of what a typesetter is doing. */
/* Wide enough to see and labelled down its length, because the first version
   was a 13px sliver with a chevron in it and a designer looking for "how do I
   hide this panel" did not find it — they asked for the feature that was
   already there. An affordance nobody can see is not an affordance. */
.rail-handle { flex: 0 0 auto; width: 22px; border: 0; padding: 8px 0; cursor: pointer;
  background: var(--paper); color: var(--muted); font-size: 12px; line-height: 1;
  display: flex; flex-direction: column; align-items: center; gap: 8px; }
.rail-handle-label { writing-mode: vertical-rl; text-orientation: mixed;
  font-size: 9.5px; letter-spacing: 0.14em; text-transform: uppercase;
  white-space: nowrap; }
.rail-handle-arrow { font-size: 13px; }
.rail-handle:hover { background: #ece5d3; color: var(--ink); }
.rail-handle.left { border-right: 1px solid var(--line); }
.rail-handle.right { border-left: 1px solid var(--line); }
.rail-handle span { display: block; }
.editor-outline, .editor-rail { transition: flex-basis 0.14s ease, width 0.14s ease; }
.editor-shell.hide-outline .editor-outline { display: none; }
.editor-shell.hide-rail .editor-rail { display: none; }
.editor-shell.hide-outline .rail-handle.left { border-right: 1px solid var(--line); }

/* A narrow viewport has no useful three-column layout. The rail becomes a
   full-width, scrollable inspector below the preview; the later max-1500 rule
   must not reintroduce its desktop fixed width. */
@media (max-width: 820px) {
  .editor-rail, .editor-rail.wide { width: 100%; max-width: 100%; flex: 0 1 auto; min-height: 240px; max-height: 48vh; border-left: 0; border-top: 1px solid var(--line); }
  .rail-handle.right { width: 100%; height: 24px; flex: 0 0 24px; flex-direction: row; justify-content: center; border-left: 0; border-bottom: 1px solid var(--line); }
  .rail-handle.right .rail-handle-label { writing-mode: horizontal-tb; }
  .editor-shell.hide-rail .rail-handle.right { width: 100%; }
}

/* The chapter-number line in the editor preview — "Chapter 1" above the
   chapter's title. Small and letterspaced, matching what render.py's
   `.chlabel` prints, so the editor shows the shape of the opener rather than
   two headings of equal weight. */
.editor-preview-page .chapter-number-line {
  text-align: center;
  font-size: 12px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 26px 0 2px;
}

/* Which code is running, beside the wordmark. Small enough to ignore, always
   there when it matters: a deployment here is a file copy, Flask caches
   templates, and a server left running after a copy serves the old page with
   nothing on screen to say so. Hovering gives the full explanation. */
.build-stamp { font-size: 9.5px; letter-spacing: 0.05em; color: var(--muted);
  margin-left: 8px; opacity: 0.65; font-weight: 400; cursor: help;
  text-transform: none; white-space: nowrap; }
.build-stamp:hover { opacity: 1; }

/* A spelling row goes to the word in the page, like a row in the Checks list.
   It has to look like it does something. */
.rail-word { cursor: pointer; }
.rail-word:hover { background: rgba(0,0,0,0.02); }
.rail-word.current { background: #fbf6e8; }

/* An error in the rail's footer. Readable, and not mistaken for a hint. */
.rail-error { color: var(--err, #a33); }

/* The render finished but the book is in the wrong typeface. Not an error —
   the file is valid — but not a success either. */
.save-state.render-warning { color: var(--err, #a33); font-weight: 600; }

/* ---------------------------------------------------------------- EPUB review
   The page that reads the exported ebook back. Two columns: what a retailer
   checks on the left, the book's own pages on the right. It needs more room
   than the 920px reading measure the rest of the app is set to — a preview at
   tablet width plus a sidebar does not fit inside it — so `main` is widened
   here rather than everywhere. */
body.epub-review-page main { max-width: 1320px; }

.ev-verdict { border-radius: 8px; padding: 16px 20px; margin-bottom: 20px;
  border: 1px solid var(--line); background: var(--paper); }
.ev-verdict.ev-pass { border-color: #bfd8c4; background: #f3f9f4; }
.ev-verdict.ev-warn { border-color: var(--suggest-bd); background: var(--suggest-bg); }
.ev-verdict.ev-fail { border-color: #e0b3a8; background: #fdf3f1; }
.ev-verdict-head { font-size: 16px; font-weight: 700; }
.ev-verdict-sub { font-size: 13px; color: var(--muted); margin-top: 4px; }
.ev-verdict-meta { font-size: 13px; margin-top: 8px; }
.ev-verdict-meta code { font-size: 12px; background: rgba(0,0,0,0.04); padding: 1px 5px;
  border-radius: 3px; word-break: break-all; }

.ev-layout { display: flex; gap: 20px; align-items: flex-start; }
.ev-side { width: 320px; flex: 0 0 320px; display: flex; flex-direction: column; gap: 16px; }
.ev-stage { flex: 1 1 auto; min-width: 0; }

.ev-panel { background: var(--paper); border: 1px solid var(--line); border-radius: 8px;
  padding: 14px 16px; }
.ev-panel-head { font-size: 11px; text-transform: uppercase; letter-spacing: 0.07em;
  color: var(--muted); margin-bottom: 8px; }
.ev-note { font-size: 12px; color: var(--muted); margin: 0 0 8px; line-height: 1.45; }

.ev-spine { list-style: none; margin: 0; padding: 0; }
.ev-page { display: block; width: 100%; text-align: left; background: none; border: 0;
  border-left: 3px solid transparent; padding: 5px 8px; font: inherit; font-size: 13px;
  color: var(--ink); cursor: pointer; border-radius: 3px; line-height: 1.35; }
.ev-page:hover { background: var(--bg); }
.ev-page.is-on { border-left-color: var(--accent); background: var(--bg); font-weight: 600; }
.ev-page.ev-aside { color: var(--muted); }
.ev-cover-btn { margin-bottom: 4px; }
.ev-tag { display: block; font-size: 10.5px; color: var(--muted); font-weight: 400; }

.ev-check { display: flex; gap: 10px; padding: 8px 0; border-top: 1px solid var(--line); }
.ev-check:first-of-type { border-top: 0; }
.ev-badge { flex: 0 0 auto; font-size: 10px; text-transform: uppercase; letter-spacing: 0.05em;
  padding: 2px 6px; border-radius: 3px; height: fit-content; margin-top: 1px; }
.ev-check.ev-ok .ev-badge { background: #e8f2ea; color: var(--ok); }
.ev-check.ev-warning .ev-badge { background: var(--suggest-bg); color: #8a6212; }
.ev-check.ev-error .ev-badge { background: #fbe9e5; color: var(--err); }
.ev-check-label { font-size: 13px; font-weight: 600; }
.ev-check-detail { font-size: 12px; color: var(--muted); line-height: 1.45; margin-top: 2px; }

.ev-links { list-style: none; margin: 0; padding: 0; }
.ev-links li { font-size: 12px; padding: 4px 0; border-top: 1px solid var(--line);
  word-break: break-all; }
.ev-links li:first-child { border-top: 0; }
.ev-link-page { display: block; color: var(--muted); font-size: 11px; }

.ev-bar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  background: var(--paper); border: 1px solid var(--line); border-radius: 8px 8px 0 0;
  border-bottom: 0; padding: 8px 12px; }
.ev-nav { background: none; border: 1px solid var(--line); border-radius: 5px;
  padding: 4px 10px; font: inherit; font-size: 12px; color: var(--ink); cursor: pointer;
  text-decoration: none; }
.ev-nav:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
.ev-nav:disabled { opacity: 0.4; cursor: default; }
.ev-now { font-size: 13px; font-weight: 600; flex: 1 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ev-widths { display: inline-flex; border: 1px solid var(--line); border-radius: 5px;
  overflow: hidden; }
.ev-width { background: none; border: 0; border-left: 1px solid var(--line); padding: 4px 10px;
  font: inherit; font-size: 12px; color: var(--muted); cursor: pointer; }
.ev-width:first-child { border-left: 0; }
.ev-width.is-on { background: var(--accent); color: #fff; }

.ev-screen { background: #dcd6c8; border: 1px solid var(--line); border-radius: 0 0 8px 8px;
  padding: 18px; display: flex; justify-content: center; }
/* The preview takes the SHAPE of the device, not just its width. A phone
   panel is roughly twice as tall as it is wide (a 6.1in screen is about
   9:19.5); a tablet is 3:4. Height from aspect-ratio, capped by the window,
   so on a wide monitor the phone is phone-shaped rather than the square the
   viewport height happened to allow. */
#ev-frame { width: 380px; max-width: 100%; border: 0;
  background: #fff; box-shadow: 0 2px 10px rgba(0,0,0,0.14); border-radius: 3px;
  height: 76vh; min-height: 420px; }
.ev-screen[data-shape="phone"] #ev-frame { aspect-ratio: 9 / 18.5; height: auto;
  max-height: 82vh; min-height: 0; }
.ev-screen[data-shape="tablet"] #ev-frame { aspect-ratio: 3 / 4; height: auto;
  max-height: 82vh; min-height: 0; }
.ev-screen[data-shape="full"] #ev-frame { height: 76vh; }
.ev-foot { margin-top: 10px; }

@media (max-width: 1000px) {
  /* Stacked, with the book itself first. The sidebar is the apparatus; the
     preview is what somebody opened this page to look at, and on a phone
     whichever comes first in the source is what they get. */
  .ev-layout { flex-direction: column; }
  .ev-side { width: 100%; flex: 1 1 auto; order: 2; }
  .ev-stage { order: 1; width: 100%; }
  .ev-screen { padding: 10px; }
  #ev-frame { height: 60vh; }
  .ev-now { flex-basis: 100%; order: -1; }
}


/* ------------------------------------------------------- phones and tablets
   The header is one non-wrapping flex row: a wordmark, a build stamp, a
   "Projects" link, whatever the page adds, and the account block pushed to
   the right with margin-left:auto. On a desktop it fits. On a 390px phone it
   was 704px wide, and because the overflow is in the header rather than in
   the content, EVERY page of the app scrolled sideways — you dragged right to
   read the end of each line of a report, then dragged back for the next one.

   It survived because a phone browser quietly widens its own layout viewport
   to fit content that overflows, so `document.scrollWidth === innerWidth`
   stayed true and nothing looked wrong to a check that compared the two.
   Measure against the device width instead (see /tmp/ui_responsive.py).

   The editor has its own header rules already (body.editor-page above); these
   are for every other page. */
/* A table of six columns has a width below which it cannot go, and a phone
   is below it. Scrolling the table sideways inside its own box is the honest
   answer: the row you are reading stays on screen, and nothing else on the
   page moves. */
.table-scroll { overflow-x: auto; }

@media (max-width: 760px) {
  header { flex-wrap: wrap; row-gap: 8px; padding: 12px 16px; align-items: center; }
  header h1 { font-size: 16px; }
  .header-context { flex-basis: 100%; order: 3; }
  .header-links { margin-left: 0; order: 4; flex-basis: 100%; }
  /* The account block is one flex item and cannot shrink, so on a narrow
     screen it has to be allowed to wrap inside itself. */
  .header-account { margin-left: auto; flex-wrap: wrap; row-gap: 4px; gap: 10px;
    justify-content: flex-end; }
  main { padding: 20px 16px 60px; }
  .card { padding: 16px; }
  /* The render bar is sticky and full-bleed: its negative margins have to
     match main's padding or it hangs off the side of the screen. */
  #renderBar { flex-wrap: wrap; row-gap: 10px; padding: 12px 16px; margin: 0 -16px; }
  table { font-size: 12.5px; }
  th, td { padding: 7px 8px; }
  /* An inline-flex form is one unbreakable row of a label, a field and a
     button. On a phone it is wider than the screen, and because it is inline
     it pushes the whole page out rather than clipping. */
  .inline-form { flex-wrap: wrap; row-gap: 6px; max-width: 100%; }
  .inline-form input, .inline-form select { min-width: 0; max-width: 100%; }
}

/* The banner that appears when a save has failed. Deliberately immovable and
   across the whole width: the thing it is preventing is somebody carrying on
   typing into a page that is no longer connected to the database, and a small
   red word next to the preview did not prevent it. */
.ed-halt {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 9999;
  background: #7d2a1a; color: #fff; padding: 14px 20px; font-size: 13.5px;
  line-height: 1.5; box-shadow: 0 -2px 14px rgba(0,0,0,0.28);
}
.ed-halt strong { font-weight: 700; }
.ed-halt a { color: #ffd9b0; text-decoration: underline; }

/* Bringing an archived book back. Folded away by default: it is the rarer of
   the two ways a book arrives, and putting it beside "Ingest manuscript" as
   an equal would suggest they are alternatives for the same job. */
.import-archive { margin-top: 18px; border-top: 1px solid var(--line); padding-top: 14px; }
/* The shelf-first home page: the upload form and the package import each sit
   in their own collapsed card below the list of books, so a returning person
   sees their books without scrolling and a new person sees an open form on an
   otherwise empty page. */
.new-project-card > summary { cursor: pointer; font-size: 14px; padding: 2px 0; }
.new-project-card > summary strong { color: var(--ink); }
.new-project-card[open] > summary { margin-bottom: 14px; }
.summary-hint { color: var(--muted); font-weight: 400; font-size: 13px; }
.import-card .import-archive { margin-top: 0; border-top: 0; padding-top: 0; }
.paper-choice .affix-label { font-size: 12px; color: var(--muted); align-self: center; }
.import-archive summary { cursor: pointer; font-size: 13px; color: var(--accent); }
.import-archive .field-hint { margin: 10px 0; max-width: 60ch; }

/* ---------------------------------------------------------- server setup
   The band that appears when the installation itself is wrong. Across the top
   rather than tucked away, because every fault it reports is invisible from
   inside the app: a missing proxy setting looks like the app refusing to save,
   a missing backup looks like nothing at all. */
.setup-alarm {
  background: #7d2a1a; color: #fff; padding: 10px 20px; font-size: 13px;
  line-height: 1.5;
}
.setup-alarm strong { font-weight: 700; }
.setup-alarm a { color: #ffd9b0; text-decoration: underline; margin-left: 6px; }

.setup-fix {
  margin-top: 8px; display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
}
.setup-fix span {
  font-size: 10px; letter-spacing: .08em; text-transform: uppercase;
  color: var(--muted); font-weight: 600;
}
.setup-fix code {
  font-size: 12px; background: var(--bg); border: 1px solid var(--line);
  border-radius: 4px; padding: 3px 8px; word-break: break-all;
}

/* "hyphen → em dash", under a dash suggestion. The three marks are three
   lengths of the same short line and at this size they are indistinguishable;
   a designer accepting a correction should be able to read which mark they
   are accepting rather than measure it. */
.rail-hit-marks {
  margin-top: 3px; font-size: 11px; letter-spacing: .04em;
  text-transform: uppercase; color: var(--muted);
}
.rail-hit-marks span { opacity: .6; margin: 0 2px; }

/* The bar that appears beside a selection inside a paragraph, for correcting
   a link. Manuscripts arrive with Word's link runs, and Word's are often
   wrong at the edges — an email address whose link has swallowed the full
   stop and the next word. Until this there was no way to say so. */
/* Two sizes. The chip is what a selection gets — small enough to sit beside
   the words rather than over them — and the form only appears once somebody
   has pressed Link. `fixed`, because the page being edited scrolls inside its
   own pane, where window.scrollY is always 0. */
.ed-linkbar {
  position: fixed; z-index: 9998; background: var(--paper);
  border: 1px solid var(--line); border-radius: 6px;
  box-shadow: 0 6px 22px -10px rgba(31,27,22,.5);
}
.ed-linkbar-chip, .ed-linkbar-form, .ed-linkbar-cases {
  display: flex; gap: 4px; align-items: center; padding: 4px;
}
/* `display: flex` in a stylesheet beats the browser's own `[hidden] {display:none}`,
   so an element hidden from JavaScript by setting .hidden stays on screen and
   nothing in the code looks wrong. Both of these are toggled that way. */
.ed-linkbar[hidden], .ed-linkbar-chip[hidden], .ed-linkbar-form[hidden],
.ed-linkbar-cases[hidden], .ed-linkbar button[hidden] { display: none; }
.ed-linkbar-form { gap: 6px; padding: 6px 8px; }
.ed-linkbar input {
  width: 260px; max-width: 46vw; font-size: 12.5px; padding: 4px 8px;
  border: 1px solid var(--line); border-radius: 4px; background: #fff; color: var(--ink);
}
.ed-linkbar button { font-size: 12px; padding: 4px 10px; }
.ed-linkbar-chip button, .ed-linkbar-cases button {
  font-size: 11.5px; padding: 3px 9px; line-height: 1.5;
}
/* The one control on the chip that is a mark rather than a word — it opens
   the four capital choices, and spelling them all out on every selection is
   the clutter the chip exists to remove. */
.ed-linkbar-chip [data-act="cases"] { font-family: Georgia, serif; font-size: 12.5px; }
.ed-linkbar-form button[data-act="cancel"] { padding: 4px 8px; line-height: 1; }
.ed-linkbar button:disabled { opacity: .45; cursor: default; }

/* The guide. Deliberately plain: it is read once and referred to, and the
   thing that makes it useful is that the key and what it does sit on one
   line together. */
.guide-keys td:first-child, .guide-keys td:nth-child(2) { white-space: nowrap; width: 1%; }
.guide-keys kbd {
  font: 11.5px/1.5 ui-monospace, SFMono-Regular, Menlo, monospace;
  background: #faf8f0; border: 1px solid #ddd0ae; border-bottom-width: 2px;
  border-radius: 4px; padding: 2px 6px; white-space: nowrap; color: #4a3f2d;
}
.guide-steps { margin: 0 0 18px 18px; line-height: 1.6; }
.guide-steps li { margin-bottom: 6px; }
.guide-styles { list-style: none; padding: 0; margin: 0 0 18px;
                display: flex; flex-wrap: wrap; gap: 6px; }
.guide-styles li code { background: #faf8f0; border: 1px solid #eadfc4;
                        border-radius: 4px; padding: 2px 7px; font-size: 12px; }

/* Choosing several paragraphs at once. The tick boxes only exist while Select
   is on, and the bar sits along the bottom where it cannot cover the text
   being chosen. */
/* In the block's own left margin, always visible while Select is on. The page
   indents to make room rather than the boxes floating over the text — a tick
   box you cannot see is not a tick box. */
body.picking .editor-preview-page .ed-block { padding-left: 26px; }
.ed-pick {
  position: absolute; left: 2px; top: 4px; z-index: 7;
  margin: 0; width: 15px; height: 15px; cursor: pointer; accent-color: var(--accent);
}
body.picking .ed-block.ed-picked > .ed-block-content { background: #f3efdf; }
.ed-pickbar {
  position: fixed; left: 50%; transform: translateX(-50%); bottom: 18px;
  z-index: 9997; display: flex; gap: 8px; align-items: center;
  background: var(--paper); border: 1px solid var(--line); border-radius: 8px;
  padding: 8px 12px; box-shadow: 0 10px 30px -12px rgba(31,27,22,.55);
  max-width: calc(100vw - 32px); flex-wrap: wrap;
}
.ed-pickbar[hidden] { display: none; }
.ed-pickbar .ed-pick-count { font-size: 12.5px; color: var(--muted); min-width: 140px; }
.ed-pickbar select { font-size: 12.5px; padding: 4px 6px; max-width: 40vw; }
.ed-pickbar button { font-size: 12px; padding: 4px 10px; }
.ed-pickbar button:disabled { opacity: .45; cursor: default; }
.ed-pick-sep { width: 1px; align-self: stretch; background: var(--line); margin: 0 2px; }
#edSelectBtn.active { background: var(--accent); color: #fff; border-color: var(--accent); }
.plain-guide { margin: 0 0 14px 18px; line-height: 1.6; color: var(--muted); }
.plain-guide li { margin-bottom: 5px; }
.plain-guide strong { color: var(--ink); }

/* The inline marks in the Formatting panel: small, square, and wrapping onto
   a second row rather than pushing the panel wider. */
.props-marks { flex-wrap: wrap; gap: 4px; margin-bottom: 6px; }
.props-marks button { min-width: 30px; padding: 4px 8px; font-size: 12.5px; line-height: 1.3; }

/* The house's named spacing sets. Each is a card, because a list of four
   number pairs with no boundary between one set and the next is unreadable. */
.preset-list { display: flex; flex-direction: column; gap: 18px; margin-bottom: 16px; }
.preset { border: 1px solid var(--line); border-radius: 6px; padding: 12px 14px; background: #fdfbf4; }
.preset-head { display: flex; gap: 12px; align-items: center; flex-wrap: wrap; margin-bottom: 10px; }
.preset-head input[type="text"] { flex: 1 1 200px; min-width: 160px; font-size: 13.5px; padding: 5px 8px; }
.preset-default { font-size: 12.5px; color: var(--muted); display: flex; gap: 5px; align-items: center; white-space: nowrap; }
.preset-remove { font-size: 13px; line-height: 1; padding: 4px 9px; }
.props-hint.props-warn { color: #a8442a; }
.props-rule { border: 0; border-top: 1px solid var(--line); margin: 18px 0 14px; }

/* Running heads. Same row shape as the typography panel, so the two cards
   read as the same kind of control. */
.running-heads-rows { display: flex; flex-direction: column; gap: 8px; }
.rh-text { font-size: 12.5px; padding: 4px 7px; border: 1px solid #cabfa8; border-radius: 4px; min-width: 220px; }
.rh-text[hidden] { display: none !important; }

/* Specimen books — every theme as a small book in dummy text. Cards rather
   than a table because the thing being chosen is a design, and a design is
   chosen by name and tagline together. */
.specimen-bar { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin: 14px 0 6px; }
.specimen-bar label { font-size: 12.5px; color: var(--muted); }
.specimen-bar select { font-size: 13px; padding: 5px 8px; border: 1px solid #cabfa8; border-radius: 5px; background: #fff; }
.specimen-group { font-size: 13px; text-transform: uppercase; letter-spacing: 0.07em; color: var(--muted); margin: 26px 0 10px; }
.specimen-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 12px; }
.specimen-card { border: 1px solid #e2d9c4; border-radius: 6px; padding: 12px 14px; background: #fffdf8; display: flex; flex-direction: column; gap: 4px; }
.specimen-name { font-weight: 600; font-size: 14px; }
.specimen-tagline { font-size: 12.5px; color: var(--muted); flex: 1; }
.specimen-card .proj-link { margin-top: 6px; font-size: 12.5px; }

/* Keeping or deleting a book. Its own card, because it is its own subject —
   it used to be a link at the far end of the Book details row, which is how
   somebody who had used it before came back and reported it as missing. */
.row-actions { white-space: nowrap; }
.row-actions .proj-link + .proj-link { margin-left: 10px; }
.proj-link.subtle { font-size: 12px; color: var(--muted); }
.proj-link.subtle:hover { color: var(--ink); }
.danger-link { color: #9a3412; }
.danger-link:hover { color: #7c2d12; }
.keep-row { display: flex; align-items: flex-start; gap: 18px; padding: 12px 0; border-top: 1px solid #ece5d3; }
.keep-row:first-of-type { border-top: none; padding-top: 4px; }
.keep-row > div { flex: 1; min-width: 0; }
.keep-title { font-size: 13.5px; font-weight: 600; }
.keep-row > a, .keep-row > button { flex: 0 0 auto; align-self: center; }
.primary-link { font-weight: 600; }
/* The panel keeps the red treatment it already had a hundred lines above —
   only its hiding changes. `[hidden]` needs saying explicitly because the
   rule up there sets padding and a border on the same element, and any
   author rule with a display value would beat the UA's own
   `[hidden] { display: none }`. Same trap the editor's link bar fell into. */
.delete-project[hidden] { display: none !important; }

/* The house logos, offered as pictures rather than as names in a list — a
   logo is chosen by looking at it. */
.logo-choices { display: flex; gap: 10px; flex-wrap: wrap; margin: 6px 0 4px; }
.logo-choice { display: flex; flex-direction: column; align-items: center; gap: 5px;
  width: 132px; padding: 8px; border: 1px solid #cabfa8; border-radius: 6px;
  background: #fff; cursor: pointer; font: inherit; }
.logo-choice img { max-width: 100%; max-height: 54px; object-fit: contain; }
.logo-choice span { font-size: 11px; color: var(--muted); line-height: 1.3; text-align: center; }
.logo-choice:hover { border-color: #8a7f63; }
.logo-choice.chosen { border-color: var(--accent); border-width: 2px; padding: 7px;
  background: #f6f1e4; }
.logo-choice.chosen span { color: var(--ink); font-weight: 600; }

/* Ebook styling panel on the EPUB review page. */
.ev-style-state { font-weight: 400; font-size: 11px; color: var(--muted); margin-left: 8px; }
.ev-style-row { padding: 7px 0 2px; border-top: 1px solid #ece5d3; }
.ev-style-row label { display: block; font-size: 12.5px; font-weight: 600; margin-bottom: 3px; }
.ev-style-row select { width: 100%; font-size: 12px; padding: 4px 6px; border: 1px solid #cabfa8; border-radius: 4px; background: #fff; }
.ev-style-num { display: flex; align-items: center; gap: 8px; }
.ev-style-num input[type=range] { flex: 1; }
.ev-style-num output { font-size: 12px; min-width: 34px; text-align: right; font-variant-numeric: tabular-nums; }
.ev-style-help { font-size: 11px; color: var(--muted); margin: 3px 0 4px; line-height: 1.45; }
#epubStyleReset { margin-top: 10px; font-size: 12px; }

/* The ebook cover upload on the review page. */
.ev-cover-form { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin: 6px 0 2px; }
.ev-cover-form input[type=file] { font-size: 11.5px; max-width: 200px; }
.ev-cover-form button { font-size: 12px; padding: 4px 10px; }

/* The book's own display lines, typed as paragraphs. */
.preview p.booktitle-item { font-family: Georgia, serif; font-size: 20pt; line-height: 1.25; font-weight: 700; text-align: center; text-indent: 0; margin: 16px 0 4px; }
.preview p.booksubtitle-item { font-family: Georgia, serif; font-size: 13.5pt; font-style: italic; text-align: center; text-indent: 0; margin: 0 0 6px; }
.preview p.authorname-item { font-family: Georgia, serif; font-size: 13pt; text-align: center; text-indent: 0; margin: 0 0 12px; }

/* A waived preflight finding: still visible, clearly decided, signed. */
.pf-item.pf-waived { opacity: 0.75; border-left-color: #8a7f63; }
.pf-item.pf-waived .pf-badge { background: #ece5d3; color: #57503f; }
.pf-waiver-note { font-size: 11.5px; color: var(--muted); margin-top: 3px; font-style: italic; }
.pf-waive-form { align-self: center; margin-right: 10px; }
.pf-waive-form button { font-size: 11.5px; padding: 3px 9px; white-space: nowrap; }
