/* ============================================================
   Quizsearcher — shared foundation (arXiv-inspired skin)
   Extracted from the approved search prototype. Light-only for
   now; every color is a :root token so dark can be layered later.
   System typefaces (Georgia / Arial / Courier). Do NOT add
   -webkit-font-smoothing — the approved look uses the browser
   default (heavier) rendering.

   This file carries: design tokens, global resets, the top-strip
   chrome + nav search, the footer, and the site-wide shared
   components (buttons, form controls, entity autocomplete,
   parchment panels, chips/badges, empty state, modal). Page-
   specific layout lives in per-page sheets (e.g. search.css).
   ============================================================ */

:root {
  --red: #b31b1b; --red-dark: #8f1515; --red-ink: #6d1717;
  --ink: #1a1a1a; --ink-2: #333330; --muted: #5c5c58; --faint: #7a756c;
  --paper: #ffffff; --soft: #f5f4f2; --soft-2: #eeece7; --parchment: #f7f2e7;
  --line: #d6d3cd; --line-soft: #e4e1da; --line-strong: #bdb9b0;
  --link: #0055a4; --link-visited: #6b3fa0; --mark: #fff2a8;
  --good: #2f7d32; --bad: #a52929; --warn: #9a6a15;
  --series: #7f1717; --grid: #d7cfbd; --grid-major: #bdb3a0;
  --serif: Georgia, "Times New Roman", Times, serif;
  --sans: Arial, Helvetica, "Helvetica Neue", sans-serif;
  --mono: "Courier New", Courier, monospace;
  --shell: min(1200px, calc(100% - 32px));
}

/* ---- Global resets ------------------------------------------------ */
* { box-sizing: border-box; }
html { background: var(--paper); }
/* The column that pins the footer. Without it a short page — About, Contact,
   the upgrade wall, an empty search — ends its footer wherever the content
   happens to stop, leaving bare background below it and making the page look
   truncated. `min-height` (not `height`) so a long page still grows normally;
   `.shell` takes the slack. `body.viewport` re-declares the same axis below
   with a fixed height, so the map is unaffected. */
body { margin: 0; color: var(--ink); background: var(--paper); font-family: var(--sans); font-size: 14px; line-height: 1.45; min-height: 100vh; display: flex; flex-direction: column; }
a { color: var(--link); text-decoration: none; }
a:hover { text-decoration: underline; }
a:visited { color: var(--link-visited); }
h1 { margin: 0 0 9px; font-family: var(--serif); font-size: 27px; font-weight: 400; letter-spacing: -.2px; text-wrap: balance; }
input, select, button, textarea { font: inherit; }

/* ---- Top strip / navbar ------------------------------------------ */
.top-strip { background: var(--red); color: #fff; border-bottom: 5px solid var(--soft-2); }
.top-inner { width: var(--shell); margin: 0 auto; padding: 12px 0; display: grid; grid-template-columns: auto minmax(240px, 1fr) auto; gap: 26px; align-items: center; }
.brand { display: inline-flex; align-items: center; }
.brand img { height: 30px; width: auto; display: block; }
.nav-search { display: flex; align-items: stretch; max-width: 620px; position: relative; }
.nav-search input { width: 100%; min-width: 0; border: 1px solid var(--red-dark); border-right: 0; padding: 7px 11px; font-size: 13.5px; outline: none; background: #fff; color: var(--ink); }
.nav-search select { border: 1px solid var(--red-dark); background: #fafafa; padding: 6px 8px; font-size: 12.5px; color: var(--ink); }
.nav-search button { border: 1px solid var(--red-dark); background: #efece7; padding: 6px 14px; font-size: 12.5px; font-weight: 700; cursor: pointer; color: var(--ink); }
.nav-search button:hover { background: #e3ded6; }
.header-links { display: flex; gap: 16px; justify-content: flex-end; font-size: 13px; white-space: nowrap; align-items: center; }
.header-links a, .header-links a:visited { color: #fff; }
.header-links form { margin: 0; }
.header-links .linkbtn { border: 0; background: transparent; color: #fff; cursor: pointer; font: inherit; padding: 0; }
.header-links .linkbtn:hover { text-decoration: underline; }

/* ---- Page shell -------------------------------------------------- */
/* `flex: 1 0 auto` — grow into whatever height the viewport has left over (this
   is what pushes the footer down), never shrink below the content's own height
   on a short window. The explicit `width` keeps it centred: a stretch would
   otherwise fill the body's cross axis and lose the 1200px measure. */
.shell { width: var(--shell); margin: 0 auto; padding: 22px 0 40px; flex: 1 0 auto; }
.intro { max-width: 900px; margin: 0 0 18px; color: var(--ink-2); }

/* ---- Viewport pages -----------------------------------------------
   Opt-in via base.html's `body_class` block. The page fills the window
   instead of scrolling inside the centred shell, and owns its own
   internal scrolling — the map needs the chrome and nothing else.
   `body.viewport main` (0,1,1) out-specifies `.shell` (0,1,0), so the
   shell's width and padding are overridden without !important. */
body.viewport { height: 100vh; overflow: hidden; display: flex; flex-direction: column; }
body.viewport .top-strip { flex: 0 0 auto; }
body.viewport main { flex: 1; width: 100%; min-width: 0; min-height: 0; margin: 0; padding: 0; }

/* ---- Buttons ----------------------------------------------------- */
.primary { min-height: 36px; border: 1px solid var(--red-dark); background: var(--red); color: #fff; padding: 7px 20px; font-weight: 700; cursor: pointer; white-space: nowrap; }
.primary:hover { background: var(--red-dark); }
.csv-btn { border: 1px solid var(--line-strong); background: #fff; color: var(--link); cursor: pointer; padding: 5px 10px; font-size: 12px; font-family: var(--mono); }
.csv-btn:hover { background: #f2f6fc; }

/* ---- Form controls ----------------------------------------------- */
label { display: block; font-weight: 700; font-size: 12px; margin-bottom: 4px; }
.control { width: 100%; min-height: 36px; border: 1px solid var(--line-strong); background: #fff; color: var(--ink); padding: 7px 9px; }
.control:focus { outline: 2px solid var(--red); outline-offset: -1px; }

/* ---- Entity autocomplete (shared: nav + main + pickers) ---------- */
.term-wrap { position: relative; }
/* z-index 1100 clears Leaflet, which is the only thing on the site that stacks
   high: its panes sit at 400 and its controls at 800–1000, and `#mp-map` sets
   no z-index of its own, so those numbers compete directly with this one at the
   root. At the old 40 the nav's suggestion list opened UNDERNEATH the map on
   /map/ — the box was there, the tiles were simply painted over it. Above the
   modal backdrop (100) too, which is harmless: the same outside-click that
   opens a modal closes this list. */
.suggest { position: absolute; z-index: 1100; left: 0; right: 0; top: 100%; background: #fff; border: 1px solid var(--line-strong); border-top: 0; max-height: 300px; overflow: auto; display: none; box-shadow: 0 8px 22px rgba(0,0,0,.12); }
.suggest.open { display: block; }
.suggest-item { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; padding: 8px 11px; cursor: pointer; border-bottom: 1px solid var(--line-soft); }
.suggest-item:hover, .suggest-item.active { background: #f2f6fc; }
.suggest-label { font-family: var(--serif); font-size: 15px; color: var(--ink); }
.suggest-label .kbd-ent { color: var(--red-ink); font-family: var(--mono); font-size: 11px; margin-right: 6px; }
.suggest-qid { font-family: var(--mono); font-size: 11px; color: var(--muted); white-space: nowrap; }
.suggest-hint { padding: 7px 11px; font-size: 11px; color: var(--muted); background: #fafafa; font-family: var(--mono); }

/* ---- Parchment panel (shared: search sidebar, entity detail, drill) */
.apanel { border: 1px solid #b9b3a7; border-top: 4px solid var(--red); background: var(--parchment); box-shadow: inset 0 0 22px rgba(91,68,35,.045); }
.apanel-head { position: relative; display: flex; align-items: center; gap: 8px; padding: 10px 12px; background: rgba(238,232,217,.85); border-bottom: 1px solid #c9c1b2; }
.apanel-head h2 { margin: 0; font-family: var(--serif); font-size: 18px; font-weight: 400; line-height: 1.15; }
.apanel-head .apanel-sub { color: #655f55; font-size: 10.5px; font-family: var(--mono); display: block; margin-top: 2px; }
.apanel-head .expand { margin-left: auto; border: 1px solid #c3bbaa; background: rgba(255,255,255,.5); color: var(--red-ink); font-family: var(--mono); font-size: 10px; padding: 2px 7px; cursor: pointer; }
.apanel-head .expand:hover { background: #fff; }

/* ---- Chips / badges ---------------------------------------------- */
.cat-chip { font-family: var(--mono); font-size: 11px; color: var(--red-ink); background: #f7ecec; border: 1px solid #e2c9c9; padding: 1px 7px; border-radius: 2px; white-space: nowrap; }
.source-badge { font-family: var(--mono); font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .03em; padding: 1px 6px; border: 1px solid; border-radius: 2px; white-space: nowrap; }
.source-badge.jarchive { color: #14338e; background: #eaf0ff; border-color: #c3d0f0; }
/* Only J-Archive is coloured. Everything else is neutral. */
.source-badge.quizbowl,
.source-badge.other { color: #4a4a44; background: #efefe9; border-color: #d8d5cc; }

/* ---- Entity link + highlight mark -------------------------------- */
/* An entity link is marked by its dotted underline alone — no link colour. In
   running question text the links are dense enough that colouring them turned
   the sentence into a row of blue, and the underline already says "link".
   `:visited` has to be restated: bare `a:visited` (0,1,1) outranks a lone
   `.entity-link` (0,1,0), so without it every followed entity went purple. */
.entity-link, .entity-link:visited { color: inherit; border-bottom: 1px dotted var(--faint); cursor: pointer; }
.entity-link:hover { border-bottom-style: solid; text-decoration: none; background: var(--soft-2); }
mark { background: var(--mark); padding: 0 1px; }

/* ---- Empty state ------------------------------------------------- */
.empty-state { border: 1px solid var(--line); border-top: 4px solid var(--red); background: #fff; padding: 46px 24px; text-align: center; color: var(--muted); }
.empty-state h2 { font-family: var(--serif); font-weight: 400; font-size: 22px; color: var(--ink); margin: 0 0 8px; }
.empty-state p { margin: 0 auto; max-width: 460px; }
.empty-state .hint { margin-top: 14px; font-family: var(--mono); font-size: 12px; color: var(--faint); }

/* ---- SVG plot primitives ------------------------------------------
   Shared: the search page's salience plot and the entity detail page's
   accuracy plot both draw with these. Page sheets keep only their own
   wrapper/caption/tooltip chrome. Colour tokens are in :root above. */
.occurrence-svg { display: block; width: 100%; height: auto; }
.g-paper { stroke: var(--grid); stroke-width: 1; }
.g-major { stroke: var(--grid-major); stroke-width: 1; }
.g-axis { stroke: #403c35; stroke-width: 1.35; }
.g-series { fill: none; stroke: var(--series); stroke-width: 2; stroke-linejoin: round; stroke-linecap: round; }
.g-fill { fill: rgba(127,23,23,.07); stroke: none; }
.g-point { fill: var(--parchment); stroke: var(--series); stroke-width: 1.4; cursor: pointer; }
.g-point:hover, .g-point.hot { fill: var(--series); }
.g-label { fill: #4b463e; font: 10px var(--mono); }

/* ---- Headings / text utilities ----------------------------------- */
h2 { font-family: var(--serif); font-size: 21px; font-weight: 400; line-height: 1.2; }
h3 { font-family: var(--serif); font-size: 18px; font-weight: 400; line-height: 1.2; }
.muted { color: var(--muted); }
.faint { color: var(--faint); }
.center { text-align: center; }
.mono { font-family: var(--mono); }
.narrow { max-width: 460px; margin: 0 auto; }
.medium { max-width: 820px; margin: 0 auto; }
.row { display: flex; flex-wrap: wrap; gap: 12px; }
.stack > * + * { margin-top: 16px; }

/* ---- Plain panel (white; distinct from the parchment .apanel) ----- */
/* A divider between groups inside a panel. Its top margin matches .stack's
   step and the next child supplies the gap below, so it sits evenly whichever
   rule wins — the two have equal specificity, and `margin: 0` here silently
   loses or wins by source order. The inline margin this replaces is how the
   divider ended up 2px from the button above it. */
.panel-rule { border: 0; border-top: 1px solid var(--line); margin: 16px 0 0; }
.panel { background: var(--paper); border: 1px solid var(--line); border-top: 4px solid var(--red); }
.panel-h { padding: 11px 15px; background: var(--soft); border-bottom: 1px solid var(--line); font-family: var(--serif); font-size: 18px; display: flex; justify-content: space-between; align-items: center; gap: 12px; }
.panel-b { padding: 16px; }

/* ---- Secondary / outline buttons (pairs with .primary) ------------ */
.btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px; font-size: 13px; font-weight: 700; min-height: 36px; padding: 7px 16px; border: 1px solid var(--line-strong); border-radius: 3px; background: #fff; color: var(--ink); cursor: pointer; text-decoration: none; white-space: nowrap; }
.btn:hover { background: var(--soft); text-decoration: none; }
.btn, .btn:visited { color: var(--ink); }
.btn.primary, .btn.primary:visited { background: var(--red); border-color: var(--red-dark); color: #fff; }
.btn.primary:hover { background: var(--red-dark); color: #fff; }
.btn.danger, .btn.danger:visited { border-color: var(--bad); color: var(--bad); }
.btn.danger:hover { background: var(--bad); color: #fff; }
.btn.sm { min-height: 30px; font-size: 12px; padding: 4px 11px; }
.btn:disabled, .btn.primary:disabled { opacity: .45; cursor: not-allowed; }
.btn:disabled:hover, .btn.primary:disabled:hover { background: var(--red); }
/* A file input is opened by a `<label class="btn">`. The bare-label rule above
   (block, bold, `margin-bottom: 4px`) is for stacked forms, and that 4px of
   extra box below shifts the label's centre inside a centred flex toolbar —
   it sits ~2px above the real <button> beside it. Same family as the
   `.control { width: 100% }` trap. */
label.btn { margin-bottom: 0; }

/* ---- Stat strip ---------------------------------------------------
   A row of headline figures under a page title. Promoted out of
   entities.css (where it was `.ed-stats`/`.ed-grp`) in Phase 4, when the
   drill recap, stats and category pages all needed the same thing.
   Each group is a lead figure plus a caption, optionally followed by
   `.stat-fig` rows for secondary numbers. */
.statstrip { display: grid; grid-template-columns: repeat(4, minmax(0,1fr)); border: 1px solid var(--line); border-top: 3px solid var(--red); background: #fff; margin-bottom: 18px; }
.stat-grp { padding: 12px 16px 14px; border-left: 1px solid var(--line-soft); }
.stat-grp:first-child { border-left: 0; }
.stat-grp .t { font-family: var(--mono); font-size: 10.5px; text-transform: uppercase; letter-spacing: .05em; color: var(--faint); margin-bottom: 8px; }
.stat-lead { font-family: var(--sans); font-size: 26px; font-weight: 700; color: var(--ink); line-height: 1.05; display: block; margin-bottom: 2px; }
.stat-lead.hi { color: var(--good); } .stat-lead.lo { color: var(--bad); }
.stat-sub { font-size: 12px; color: var(--faint); }
.stat-fig { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; font-size: 12.5px; color: var(--muted); padding: 1.5px 0; }
.stat-fig b { font-family: var(--mono); font-size: 13.5px; color: var(--ink); font-weight: 700; }
.stat-fig-top { margin-top: 8px; }
.stat-fig-tight { margin-top: 2px; }

/* ---- Data table + toolbar + pager ---------------------------------
   Promoted out of entities.css in Phase 5, when the Anki area became the
   third to need them (entity dashboard, custom entities, deck list, card
   browser, reconcile). Class names kept as-is so the entity templates did
   not have to change. Numeric columns right-align by default; give a
   column `.nm` to read as text — note the specificity trap below. */
.ent-bar { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; padding-bottom: 9px; border-bottom: 1px solid var(--line-strong); }
.ent-count { font-size: 13px; color: var(--muted); }
.ent-count b { color: var(--ink); }
.ent-ctrls { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; font-size: 12.5px; color: var(--muted); }
.ent-ctrls select { min-height: 28px; padding: 3px 6px; font-size: 12.5px; }
.ent-scroll { overflow-x: auto; }
table.ent-tbl { width: 100%; border-collapse: collapse; font-size: 13px; }
table.ent-tbl th, table.ent-tbl td { padding: 7px 10px; text-align: right; white-space: nowrap; }
table.ent-tbl thead th { background: var(--soft); font-size: 11.5px; font-weight: 700; text-transform: uppercase;
                         letter-spacing: .04em; color: var(--muted); cursor: pointer; user-select: none; }
table.ent-tbl thead tr.ent-cols th { border-bottom: 1px solid var(--line-soft); }
table.ent-tbl thead th:hover, table.ent-tbl thead th.on { color: var(--red-ink); }
.ent-arrow { font-size: 9px; opacity: .85; }
/* Must out-specify `table.ent-tbl th/td { text-align: right }` (0,1,2) — a bare
   `td.nm` (0,1,1) loses to it and every name column silently right-aligns. */
table.ent-tbl th.nm, table.ent-tbl td.nm { text-align: left; white-space: normal; }
table.ent-tbl tbody tr { border-bottom: 1px solid var(--line-soft); }
table.ent-tbl tbody tr:hover { background: var(--parchment); }
table.ent-tbl td { font-family: var(--mono); font-size: 12.5px; color: var(--ink-2); }
table.ent-tbl td.nm { font-family: var(--sans); font-size: 13.5px; }
table.ent-tbl td.tot { font-weight: 700; color: var(--ink); }
.ent-zero { color: #b9b4aa; }
.ent-foot { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; padding: 13px 0 0; font-size: 12.5px; color: var(--muted); }
.ent-pager { display: flex; align-items: center; gap: 7px; }
/* Only the pager's own captions ("of 14", "per page") are held on one line —
   nowrap on the container itself collapses a `<label>show <select></label>`
   onto a single line, where the select overlaps the button beside it. */
.ent-pager > span { white-space: nowrap; }
/* The pager's caption labels are inline. Left to the bare-<label> rule (block,
   bold, 4px below) "show" stacks on top of its select, which makes the pager a
   row and a half tall and throws it out of line with the button beside it. */
.ent-pager label { display: inline-flex; align-items: center; gap: 6px; margin: 0 5px 0 0; font-weight: 400; font-size: 12.5px; color: var(--muted); }
/* One height across the strip: the controls were 27px against 30px buttons. */
.ent-pager input { width: 56px; text-align: center; min-height: 30px; padding: 2px 4px; font-size: 12.5px; }
.ent-pager select { min-height: 30px; padding: 2px 6px; font-size: 12.5px; }
.ent-empty { padding: 40px 10px; text-align: center; color: var(--muted); }
/* Pager ends are links when live and inert spans when not. */
.btn.disabled { opacity: .45; pointer-events: none; }

/* ---- Segmented control -------------------------------------------
   Promoted out of drill.css in Phase 5 (drill periods, card templates). */
.dr-seg { display: inline-flex; border: 1px solid var(--line-strong); border-radius: 3px; overflow: hidden; }
.dr-seg a, .dr-seg button { border: 0; border-left: 1px solid var(--line-strong); background: #fff; color: var(--ink-2);
                            font-family: var(--mono); font-size: 12.5px; padding: 6px 14px; cursor: pointer; text-decoration: none; }
.dr-seg a:first-child, .dr-seg button:first-child { border-left: 0; }
.dr-seg a:hover, .dr-seg button:hover { background: var(--soft); text-decoration: none; }
.dr-seg a, .dr-seg a:visited { color: var(--ink-2); }
.dr-seg a.on, .dr-seg a.on:visited, .dr-seg button.on { background: var(--red); border-color: var(--red-dark); color: #fff; font-weight: 700; }

/* ---- Fields + key/value lists ------------------------------------ */
.field { margin-bottom: 16px; }
.kv { display: grid; grid-template-columns: 120px 1fr; gap: 6px 12px; font-size: 13px; margin: 0; }
.kv dt { color: var(--faint); font-family: var(--mono); font-size: 11.5px; padding-top: 2px; }
.kv dd { margin: 0; }

/* ---- Status badges ----------------------------------------------- */
.badge { display: inline-flex; align-items: center; font-family: var(--mono); font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; padding: 2px 8px; border: 1px solid var(--line-strong); border-radius: 2px; color: var(--muted); background: var(--soft); }
.badge.tier-elite { color: #6d1717; background: #f7ecec; border-color: #e2c9c9; }
.badge.tier-premium { color: #14338e; background: #eaf0ff; border-color: #c3d0f0; }
/* Inner Circle — the unlisted top tier. Distinct from the paid tiers on purpose. */
.badge.tier-inner { color: #3d2a63; background: #f1ecfa; border-color: #d3c7ea; }
.badge.good { color: var(--good); background: #eaf4ea; border-color: #bcdcbc; }
.badge.warn { color: var(--warn); background: #faf3e2; border-color: #e8d7ae; }

/* ---- Toggle switch ----------------------------------------------- */
.toggle-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 9px 0; border-bottom: 1px solid var(--line-soft); }
.toggle-row:last-child { border-bottom: 0; }
.toggle-row .t-txt { font-size: 13px; }
.toggle-row .t-sub { font-size: 11.5px; color: var(--faint); }
.toggle-row.locked { opacity: .55; }
/* Labels a run of toggle rows when one form covers more than one area. Same
   type treatment as the other group labels on the site (.stat-grp .t,
   .ep-group-title, .fe-res-group) — a heading inside a panel, not a second
   panel heading. */
.toggle-grp { font-family: var(--mono); font-size: 10.5px; text-transform: uppercase; letter-spacing: .05em; color: var(--faint); margin: 17px 0 3px; }
/* :first-of-type, not :first-child — a Django form opens with the hidden
   csrf input, so the label at the top of a form is never its first child. */
.toggle-grp:first-of-type { margin-top: 0; }
.lockchip { font-family: var(--mono); font-size: 10px; color: #14338e; border: 1px solid #c3d0f0; background: #eaf0ff; padding: 0 5px; border-radius: 2px; }
.switch { position: relative; width: 38px; height: 21px; flex-shrink: 0; margin: 0; }
.switch input { display: none; }
.switch .tk { position: absolute; inset: 0; background: var(--line-strong); border-radius: 11px; transition: .15s; cursor: pointer; }
.switch .tk::after { content: ""; position: absolute; top: 2px; left: 2px; width: 17px; height: 17px; background: #fff; border-radius: 50%; transition: .15s; }
.switch input:checked + .tk { background: var(--red); }
.switch input:checked + .tk::after { transform: translateX(17px); }
.switch input:disabled + .tk { cursor: not-allowed; }

/* ---- Alerts / form errors ---------------------------------------- */
.errors { list-style: none; margin: 6px 0 0; padding: 0; }
.errors li { font-size: 12px; color: var(--bad); }
.alert { border: 1px solid; border-left-width: 4px; padding: 10px 13px; font-size: 13px; }
.alert.bad { color: var(--bad); border-color: #e0bcbc; border-left-color: var(--bad); background: #fdf3f3; }
.alert.good { color: #235c26; border-color: #bcdcbc; border-left-color: var(--good); background: #f1f8f1; }
/* Something needs the user's attention but nothing is broken — a failed card
   while access continues. Shares the palette of `.badge.warn`. */
.alert.warn { color: var(--warn); border-color: #e8d7ae; border-left-color: var(--warn); background: #faf3e2; }

/* ---- Footer ------------------------------------------------------ */
/* `flex: 0 0 auto` so a short window compresses nothing: the default shrink
   factor would squeeze the footer's own padding before the page scrolled. */
footer { border-top: 1px solid var(--line); background: var(--soft); padding: 18px 0 30px; color: var(--muted); font-size: 12px; margin-top: 8px; flex: 0 0 auto; }
.footer-inner { width: var(--shell); margin: 0 auto; display: flex; justify-content: space-between; gap: 20px; flex-wrap: wrap; }

/* ---- Modal ------------------------------------------------------- */
.modal-backdrop { position: fixed; inset: 0; display: none; place-items: center; padding: 24px; background: rgba(20,16,12,.5); z-index: 100; }
.modal-backdrop.open { display: grid; }
.modal { width: min(780px, 100%); max-height: 86vh; overflow: auto; background: var(--paper); border-top: 6px solid var(--red); padding: 20px 22px 24px; box-shadow: 0 16px 50px rgba(0,0,0,.3); }
.modal.parch { background: var(--parchment); }
.modal h3 { margin: 0 0 14px; font-family: var(--serif); font-size: 22px; font-weight: 400; }
.modal-close { float: right; border: 1px solid var(--line-strong); background: #f3f2ee; cursor: pointer; padding: 4px 10px; font-size: 12px; }
/* ---- Entity picker -------------------------------------------------
   The shared component behind "link this to an entity" (custom entities,
   reconcile). It builds its own overlay because it stacks above whatever
   page opened it, but it is the site's modal: it used to inject a
   stylesheet of its own — system fonts, blue buttons, rules for a dark
   theme the site doesn't have — which survived every redesign phase
   because nothing on the page referenced it. Layout only lives here; the
   input is a `.control` and the buttons are `.btn`. */
/* Top-anchored, not centred: the result list grows as you type, and a centred
   modal would walk up the screen with every keystroke. */
.ep-overlay { align-items: start; padding-top: min(14vh, 110px); }
.modal.ep-modal { width: min(480px, 100%); padding: 0; max-height: 80vh; display: flex; flex-direction: column; }
.ep-head { display: flex; gap: 10px; align-items: center; padding: 14px 16px; border-bottom: 1px solid var(--line); }
.ep-head .control { flex: 1; }
.ep-modal .ep-close { float: none; flex: 0 0 auto; }
.ep-body { flex: 1; overflow-y: auto; min-height: 0; }
.ep-group-title { font-family: var(--mono); font-size: 10.5px; text-transform: uppercase; letter-spacing: .05em; color: var(--faint); padding: 11px 16px 4px; background: var(--soft); border-bottom: 1px solid var(--line-soft); }
.ep-item { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; padding: 8px 16px; cursor: pointer; border-bottom: 1px solid var(--line-soft); }
.ep-item:hover { background: var(--parchment); }
.ep-item .ep-qid { font-family: var(--mono); font-size: 11px; color: var(--muted); white-space: nowrap; }
.ep-actions { border-top: 1px solid var(--line); background: var(--soft); padding: 12px 16px; display: flex; flex-direction: column; gap: 9px; }
.ep-actions .btn { justify-content: flex-start; font-weight: 400; }
/* `.btn` is a flex row with `gap: 8px`, meant for an icon beside a word. This
   button's label is a sentence with a <b> inside it, and each bare text run is
   its own anonymous flex item — so the gap opens up either side of the name. */
.ep-novel { gap: 0; }
.ep-novel b { font-weight: 700; color: var(--red-ink); }
.ep-resolve { display: flex; gap: 7px; }
.ep-resolve .control { flex: 1; }
.ep-resolve .btn { flex: 0 0 auto; }
.ep-note { padding: 12px 16px; font-size: 12.5px; color: var(--muted); }
.ep-error { color: var(--bad); padding-top: 0; }

.meta-table { width: 100%; border-collapse: collapse; font-family: var(--mono); font-size: 12px; }
.meta-table td { border-bottom: 1px solid var(--line-soft); padding: 5px 8px; vertical-align: top; word-break: break-word; }
.meta-table td.k { color: var(--ink); width: 170px; }
.meta-table td.t { color: var(--faint); width: 100px; }
.meta-table td.v { color: var(--muted); }
.meta-table tr.null td.v { color: var(--line-strong); }

@media (max-width: 900px) {
  .top-inner { grid-template-columns: 1fr; gap: 11px; }
  .header-links { justify-content: flex-start; }
  .kv { grid-template-columns: 1fr; gap: 2px 0; }
  .kv dd { margin-bottom: 6px; }
  .statstrip { grid-template-columns: repeat(2, minmax(0,1fr)); }
  .stat-grp:nth-child(3) { border-left: 0; }
}
@media (max-width: 560px) {
  .statstrip { grid-template-columns: 1fr; }
  .stat-grp { border-left: 0; border-top: 1px solid var(--line-soft); }
  .stat-grp:first-child { border-top: 0; }
}
