@charset "UTF-8";
/* ==========================================================================
   لوحة الإدارة — admin panel
   Self-contained. Does NOT load the public site's styles.css, because the
   panel is served from a different host (admin.syriacmu.org) and must not
   depend on the public site being up. Tokens below are copied from
   site/css/styles.css and must stay in step with it.

   Non-negotiable #2: no letter-spacing on Arabic text, anywhere.
   ========================================================================== */

/* ---------- tokens : LIGHT (default) ---------- */
:root {
  /* Native controls — the date picker, the scrollbars, the file dialog — take
     their colours from this, not from ours. Without it the date field renders
     a white calendar icon on a dark field. */
  color-scheme: light;

  --bg: #FAF8F3;
  --bg-2: #F3F0E8;
  --surface: #FFFFFF;
  --ink: #101C33;
  --ink-2: #3D4C6B;
  --muted: #6A7791;
  --line: #E5E1D6;
  --line-2: #D8D3C5;

  --navy: #193769;
  --navy-2: #24487F;
  --gold: #C9971A;
  --gold-ink: #92690A;
  --red: #C0272D;
  --green: #1F7A4D;

  --shadow-s: 0 1px 2px rgba(16, 28, 51, .05), 0 2px 8px rgba(16, 28, 51, .04);
  --shadow-m: 0 2px 4px rgba(16, 28, 51, .05), 0 14px 34px -14px rgba(16, 28, 51, .16);

  /* Same swap as the public site (site/css/styles.css, plan-v2.md §19a): the
     display face is gone and weight carries the hierarchy. The panel has no
     prose set in display, so it needs no soft tier. 600 not 700 — that is the
     heaviest weight actually loaded, and asking for 700 only gets a browser's
     synthetic bold, which smears Arabic joins. */
  --ar-display: "IBM Plex Sans Arabic", "Segoe UI", Tahoma, system-ui, sans-serif;
  --ar-display-w: 600;
  --ar-body: "IBM Plex Sans Arabic", "Segoe UI", Tahoma, system-ui, sans-serif;
  --mono: "JetBrains Mono", "Cascadia Mono", ui-monospace, Consolas, monospace;

  --s1: 5px;  --s2: 10px; --s3: 15px; --s4: 20px; --s5: 30px;
  --s6: 45px; --s7: 60px; --s8: 90px;

  --rail: 268px;
  --ease: cubic-bezier(.22, .61, .36, 1);
}

/* ---------- tokens : DARK (opt-in) ---------- */
:root[data-theme="dark"] {
  color-scheme: dark;

  --bg: #080D16;
  --bg-2: #0D1524;
  --surface: #0F1929;
  --ink: #F2ECDC;
  --ink-2: #B7C3D6;
  --muted: #8394AC;
  --line: #1E2A3F;
  --line-2: #2A3A54;

  --navy: #7DA0DA;
  --navy-2: #9DB8E6;
  --gold: #FECD07;
  --gold-ink: #FFD57A;
  --red: #ED5B60;
  --green: #4CC08A;

  --shadow-s: 0 1px 2px rgba(0, 0, 0, .4);
  --shadow-m: 0 2px 6px rgba(0, 0, 0, .45), 0 16px 40px -16px rgba(0, 0, 0, .7);
}

/* ==========================================================================
   base
   ========================================================================== */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; padding: 0; }

html { -webkit-text-size-adjust: 100%; }

body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--ar-body);
  font-size: 16px;
  line-height: 1.75;
  -webkit-font-smoothing: antialiased;
}

/* Content links. `:not(.btn)` is load-bearing, not tidiness.

   Several buttons in this panel are anchors — «راجِع وانشر» on the home
   screen, «رجوع» on the form — and a bare `a:hover { color: var(--navy-2) }`
   turned a navy button's white label navy on hover. Contrast 1.29:1: the text
   simply vanished into its own background. Reported from the live panel
   2026-08-16.

   The class-based fix rather than a stronger `.btn` colour, because the bug is
   the generic rule reaching somewhere it was never meant to reach — and it
   would have reached the next anchor-button too.

   `:not(:where(.btn))` and not `:not(.btn)`. A bare :not() adds the
   specificity of its argument, so `a:not(.btn):hover` scores (0,2,1) and
   started beating `.rail-link:hover` at (0,2,0) — the sidebar links lost their
   hover colour the moment this rule was written to fix the buttons. :where()
   is always zero, so this stays exactly as specific as the `a:hover` it
   replaces and changes nothing except which elements it matches. */
a:not(:where(.btn)) { color: var(--navy); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:not(:where(.btn)):hover { color: var(--navy-2); }

button, input, select, textarea { font: inherit; color: inherit; }

:focus-visible {
  outline: 2px solid var(--gold-ink);
  outline-offset: 2px;
  border-radius: 3px;
}

.skip {
  position: absolute;
  inset-inline-start: -9999px;
  top: 0;
  z-index: 100;
  background: var(--navy);
  color: #fff;
  padding: var(--s2) var(--s4);
}
.skip:focus { inset-inline-start: 0; }
/* Navy panel, white text — and the generic link hover would repaint that text
   navy, on navy, for anyone who moves the mouse onto the link they just
   tabbed to. Same bug as the buttons, one element further along. */
.skip:hover { color: #fff; }

.booting { display: grid; place-items: center; min-height: 100vh; }
.boot-msg { color: var(--muted); }

/* Latin strings — emails, URLs, numbers — inside an RTL document. */
.ltr { direction: ltr; text-align: left; font-family: var(--mono); font-size: .92em; }

/* ==========================================================================
   buttons
   ========================================================================== */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s2);
  border: 1px solid transparent;
  border-radius: 4px;
  padding: 9px var(--s4);
  font-size: .94rem;
  font-weight: 500;
  cursor: pointer;
  background: none;
  text-decoration: none;          /* several buttons are anchors */
  transition: background .18s var(--ease), border-color .18s var(--ease), color .18s var(--ease);
}
.btn:disabled { opacity: .5; cursor: not-allowed; }

/* Every variant restates its colour on :hover even when it does not change.
   That is deliberate belt and braces after the a:hover bug above: a button
   should carry its own contrast rather than depend on nothing else winning the
   cascade. */
.btn-p { background: var(--navy); color: #fff; }
.btn-p:hover:not(:disabled) { background: var(--navy-2); color: #fff; }
:root[data-theme="dark"] .btn-p { background: var(--navy); color: #071021; }
:root[data-theme="dark"] .btn-p:hover:not(:disabled) { color: #071021; }

.btn-s { border-color: var(--line-2); color: var(--ink); background: var(--surface); }
.btn-s:hover:not(:disabled) { border-color: var(--navy); color: var(--navy); }

.btn-ghost { color: var(--muted); }
.btn-ghost:hover:not(:disabled) { color: var(--ink); background: var(--bg-2); }

.btn-danger { border-color: var(--line-2); color: var(--red); background: var(--surface); }
.btn-danger:hover:not(:disabled) { border-color: var(--red); background: var(--red); color: #fff; }

.btn-sm { padding: 5px var(--s3); font-size: .86rem; }

/* ==========================================================================
   login
   ========================================================================== */
.login-wrap {
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: var(--s5) var(--s4);
  background: linear-gradient(180deg, var(--bg) 0%, var(--bg-2) 100%);
}
.login-card-wrap { width: 100%; max-width: 420px; }

.login-brand {
  display: flex;
  align-items: center;
  gap: var(--s3);
  justify-content: center;
  margin-bottom: var(--s5);
  text-decoration: none;
  color: var(--ink);
}
.login-brand img { display: block; width: 52px; height: auto; }
.login-brand b { display: block; font-family: var(--ar-display); font-size: 1.12rem; font-weight: var(--ar-display-w); line-height: 1.4; }
.login-brand i { display: block; font-style: normal; font-size: .84rem; color: var(--muted); }

.login-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 6px;
  box-shadow: var(--shadow-m);
  padding: var(--s5);
}

/* A modal `<dialog>` is centred by the browser's own `dialog { margin: auto }`,
   and the reset at the top of this file — `* { margin: 0 }` — wins over it,
   because a universal selector still beats a UA rule. So every confirmation in
   the panel opened pinned to the top corner: «تأكيد الحذف» sat above the rail
   with the page still readable behind it, which is where a passing glance does
   not look. The one dialog anybody had watched was the login card, which is not
   a modal and never showed the fault.

   Explicit centring, plus a `::backdrop` dark enough to say the page behind is
   not accepting clicks. `max-height` and the overflow are for the small screen:
   a dialog taller than the viewport must scroll inside itself, not push its own
   buttons off the bottom. */
dialog.login-card {
  margin: auto;
  max-height: calc(100dvh - var(--s5) * 2);
  overflow-y: auto;
}
dialog.login-card::backdrop { background: rgba(16, 28, 51, .45); }
.login-card h1 { font-family: var(--ar-display); font-size: 1.6rem; font-weight: var(--ar-display-w); margin-bottom: var(--s2); }
.login-lede { color: var(--muted); font-size: .92rem; margin-bottom: var(--s5); }

.lbl {
  font-size: .74rem;
  color: var(--gold-ink);
  font-weight: 600;
  margin-bottom: var(--s1);
}

/* ==========================================================================
   forms
   ========================================================================== */
.field { margin-bottom: var(--s4); }

/* A native date control shows the browser locale, so the parsed value is
   echoed in Arabic beneath it — see fields.js. */
.field-datetime { display: flex; flex-direction: column; gap: var(--s1); }
.field-datetime .hint { display: block; margin: 0; }

/* :not(.check) matters — a checkbox carries its label to the right of the box,
   so it must stay a flex row. Without the exclusion this rule wins on
   specificity and silently flattens it to a block. */
.field > label:not(.check) {
  display: block;
  font-size: .88rem;
  font-weight: 500;
  margin-bottom: var(--s1);
}
.field .req { color: var(--red); }
.field .hint { display: block; font-size: .8rem; color: var(--muted); font-weight: 400; margin-top: 2px; }

.input, .textarea, .select {
  width: 100%;
  background: var(--bg);
  border: 1px solid var(--line-2);
  border-radius: 4px;
  padding: 9px var(--s3);
  transition: border-color .18s var(--ease);
}
.input:focus, .textarea:focus, .select:focus { border-color: var(--navy); }
.textarea { min-height: 96px; resize: vertical; line-height: 1.7; }
.input[dir="ltr"], .textarea[dir="ltr"] { font-family: var(--mono); font-size: .9rem; }

.field-err { color: var(--red); font-size: .82rem; margin-top: var(--s1); }
.input.is-err, .textarea.is-err { border-color: var(--red); }

/* An emptied field, waiting for a second press (plan-v2.md §19p).
   Red because that is what reads as "look here", DASHED because this is a
   question and not a refusal — an error's solid outline means the save did not
   happen, and these two must never look like the same event. The written line
   under the field carries the meaning on its own, for the reader who sees no
   colour at all. */
.field.is-warn .input,
.field.is-warn .textarea,
.field.is-warn .select,
.field.is-warn .rt,
.field.is-warn .file-field {
  border-color: var(--red);
  border-style: dashed;
}
.field-warn { color: var(--red); font-size: .82rem; margin-top: var(--s1); }

/* The one line that asks. Not a toast: a toast leaves, and this has to stay on
   screen for as long as the decision is open. */
.form-warn {
  margin-top: var(--s4);
  padding: var(--s2) var(--s3);
  border: 1px dashed var(--red);
  border-radius: 6px;
  color: var(--red);
  background: color-mix(in srgb, var(--red) 6%, transparent);
  font-size: .88rem;
}

/* ==========================================================================
   «ما العمل الآن؟» — the dialog after a new row is saved
   panel/js/publish-prompt.js. Borrows .login-card, like every other modal in
   the panel, and adds only what it needs on top of it.
   ========================================================================== */

/* Wider than the confirmations, which are one sentence and two buttons: this
   one carries the two switches and their hints, and 380px wraps
   «غير المنشور لا يظهر للزوار إطلاقًا.» onto three lines. The width pair is the
   ordinary responsive-dialog one: fill a narrow screen, stop at 460 on a wide
   one. */
dialog.login-card.pp {
  width: calc(100vw - var(--s4) * 2);
  max-width: 460px;
}

/* The lede above already ends on --s5; the switches sit closer to each other
   than to it, and the last one closer still to the line that follows. */
.pp-toggles .field { margin-bottom: var(--s3); }
.pp-toggles .field:last-child { margin-bottom: 0; }

/* What else this build would carry. Muted, because it is context for the
   button rather than a warning about it — the warning above it is the one in
   red, and two red blocks in one dialog would flatten the difference. */
.pp-others {
  margin-top: var(--s3);
  font-size: .84rem;
  color: var(--muted);
  line-height: 1.6;
}

/* Wraps rather than shrinking: three Arabic labels on a phone do not fit one
   row, and a publish button squeezed to its ellipsis is the button that gets
   pressed by mistake. */
.pp-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
  margin-top: var(--s5);
}

/* checkbox */
.check { display: flex; align-items: center; gap: var(--s2); cursor: pointer; }
.check input { width: 17px; height: 17px; accent-color: var(--navy); cursor: pointer; }
.check span { font-size: .9rem; }

/* password reveal */
.pass-wrap { position: relative; }
.pass-wrap .input { padding-inline-start: 42px; }
.eye {
  position: absolute;
  inset-inline-start: var(--s1);
  top: 50%;
  transform: translateY(-50%);
  background: none;
  border: 0;
  padding: var(--s2);
  cursor: pointer;
  color: var(--muted);
  line-height: 0;
}
.eye:hover { color: var(--ink); }
.eye svg { width: 19px; height: 19px; }

/* alerts */
.alert {
  border-radius: 4px;
  padding: var(--s2) var(--s3);
  font-size: .88rem;
  margin-bottom: var(--s4);
  border: 1px solid;
}
.alert-err { color: var(--red); border-color: var(--red); background: color-mix(in srgb, var(--red) 8%, transparent); }
.alert-ok { color: var(--green); border-color: var(--green); background: color-mix(in srgb, var(--green) 8%, transparent); }
/* A locked archived article (plan-v2.md §19o). Not red: nothing is wrong and
   nothing failed — the article is simply the record now, and red would read as
   an error she caused. Gold, which is the archive's colour on the site too. */
.alert-warn {
  color: var(--ink); border-color: var(--gold);
  background: color-mix(in srgb, var(--gold) 12%, transparent);
}

/* The archived badge in a list row. */
.row-archived {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: .74rem; font-weight: 600;
  padding: 1px 7px; border-radius: 999px;
  color: var(--ink-2);
  border: 1px solid var(--gold);
  background: color-mix(in srgb, var(--gold) 14%, transparent);
}

/* ==========================================================================
   app shell
   ========================================================================== */
.shell { display: grid; grid-template-columns: var(--rail) 1fr; min-height: 100vh; }

.rail {
  background: var(--surface);
  border-inline-start: 0;
  border-inline-end: 1px solid var(--line);
  padding: var(--s4);
  display: flex;
  flex-direction: column;
  gap: var(--s4);
  position: sticky;
  top: 0;
  height: 100vh;
  overflow-y: auto;
}

.rail-brand {
  display: flex;
  align-items: center;
  gap: var(--s2);
  text-decoration: none;
  color: var(--ink);
  padding-bottom: var(--s3);
  border-bottom: 1px solid var(--line);
}
.rail-brand img { width: 34px; height: auto; }
.rail-brand b { font-family: var(--ar-display); font-weight: var(--ar-display-w); font-size: .98rem; line-height: 1.35; display: block; }
.rail-brand i { font-style: normal; font-size: .74rem; color: var(--muted); display: block; }

.rail-group { margin-bottom: var(--s3); }
.rail-group > p {
  font-size: .72rem;
  color: var(--muted);
  font-weight: 600;
  margin-bottom: var(--s1);
  padding-inline-start: var(--s2);
}

.rail-link {
  display: flex;
  align-items: center;
  gap: var(--s2);
  padding: 7px var(--s2);
  border-radius: 4px;
  text-decoration: none;
  color: var(--ink-2);
  font-size: .92rem;
  transition: background .15s var(--ease), color .15s var(--ease);
}
.rail-link:hover { background: var(--bg-2); color: var(--ink); }
.rail-link[aria-current="page"] {
  background: color-mix(in srgb, var(--navy) 10%, transparent);
  color: var(--navy);
  font-weight: 500;
}
.rail-link .count { margin-inline-start: auto; font-size: .78rem; color: var(--muted); font-family: var(--mono); }

/* A screen that is named but not yet in service. Dimmed and inert — no hover,
   no pointer — so it reads as "not yet" rather than "broken link". */
.rail-link.is-soon { opacity: .45; cursor: default; }
.rail-link.is-soon:hover { background: none; color: var(--muted); }

.rail-foot { margin-top: auto; padding-top: var(--s3); border-top: 1px solid var(--line); }
.rail-who { font-size: .82rem; color: var(--muted); margin-bottom: var(--s2); }
.rail-who b { display: block; color: var(--ink); font-weight: 500; }

.main { padding: var(--s5) var(--s6); max-width: 1000px; }

.page-head {
  display: flex;
  align-items: flex-start;
  gap: var(--s4);
  margin-bottom: var(--s5);
  padding-bottom: var(--s4);
  border-bottom: 1px solid var(--line);
}
.page-head h1 { font-family: var(--ar-display); font-size: 1.85rem; font-weight: var(--ar-display-w); line-height: 1.3; }
.page-head p { color: var(--muted); font-size: .9rem; margin-top: 2px; }
.page-head .actions { margin-inline-start: auto; display: flex; gap: var(--s2); flex-shrink: 0; }

.crumb { font-size: .84rem; color: var(--muted); margin-bottom: var(--s3); }
.crumb a { color: var(--muted); }
.crumb a:hover { color: var(--navy); }

/* ==========================================================================
   list
   ========================================================================== */
.list { border: 1px solid var(--line); border-radius: 6px; overflow: hidden; background: var(--surface); }

.row {
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: var(--s3) var(--s4);
  border-bottom: 1px solid var(--line);
  text-decoration: none;
  color: inherit;
  transition: background .15s var(--ease);
}
.row:last-child { border-bottom: 0; }
.row:hover { background: var(--bg-2); }

.row-thumb {
  width: 46px;
  height: 46px;
  border-radius: 4px;
  object-fit: cover;
  background: var(--bg-2);
  flex-shrink: 0;
  border: 1px solid var(--line);
}

/* No image yet. A real element rather than an <img> with an empty src, which
   browsers render as a broken-image icon — and "broken" is the wrong word for
   a row that simply has no photograph. */
.row-thumb-none {
  display: grid;
  place-items: center;
  color: var(--line-2);
}
.row-thumb-none::after {
  content: "";
  width: 16px;
  height: 16px;
  border-radius: 2px;
  border: 1.5px solid currentColor;
}
.row-body { min-width: 0; flex: 1; }
.row-body h3 { font-size: .98rem; font-weight: 500; line-height: 1.5; }
.row-body p { font-size: .82rem; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* The date and the byline, under the title on every row that has them.

   Deliberately not `--muted` like the subtitle above it: the request that put
   this here (plan-v2.md §19h) was about being able to SEE the date, and the
   grey line is the one people stop reading. */
.row-meta {
  display: flex;
  align-items: center;
  gap: var(--s3);
  margin-top: 3px;
  font-size: .8rem;
  color: var(--ink-2);
}

.row-date {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-variant-numeric: tabular-nums;
}

.row-date svg { opacity: .7; flex-shrink: 0; }

.row-by::before {
  content: "—";
  margin-inline-end: 5px;
  opacity: .5;
}

/* The API's own stamps, under the form heading. */
.row-stamps {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s3);
  margin-top: 6px;
  font-size: .8rem;
  color: var(--ink-2);
}

.row-stamps span + span::before {
  content: "·";
  margin-inline-end: var(--s3);
  opacity: .5;
}

/* -------------------------------------------------------------- messages -- */
/* Enquiries from the contact form, as cards; a card opens in full (§19j). */
.msg-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr));
  gap: var(--s3);
}

.msg-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: var(--s4);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 8px;
  text-decoration: none;
  color: inherit;
  transition: border-color .15s var(--ease), transform .15s var(--ease);
}

.msg-card:hover { border-color: var(--line-2); transform: translateY(-1px); }

/* Unread is carried by the gold edge AND the dot, not by colour alone: the
   difference has to survive a monochrome screen and a colour-blind reader,
   the same rule the review screen's verbs follow. */
/* No bar down the leading edge. `.msg-dot` already marks an unread enquiry,
   and it carries the accessible name; two markers for one fact was one too
   many, and against an RTL card the bar read as a stray border. */

.msg-card-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s3);
}

.msg-card-head b { font-weight: 600; }
.msg-when { font-size: .78rem; color: var(--muted); flex-shrink: 0; }
.msg-subject { font-size: .9rem; color: var(--ink-2); font-weight: 500; }
.msg-x { font-size: .84rem; color: var(--muted); line-height: 1.7; }

.msg-dot {
  position: absolute;
  inset-block-start: var(--s3);
  inset-inline-start: var(--s3);
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--gold-ink);
}

.msg-full {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: var(--s5);
}

.msg-who {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s3) var(--s6);
  margin: 0 0 var(--s4);
  padding-bottom: var(--s4);
  border-bottom: 1px solid var(--line);
}

.msg-who div { display: flex; gap: 8px; align-items: baseline; }
.msg-who dt { font-size: .8rem; color: var(--muted); }
.msg-who dd { margin: 0; font-size: .92rem; }
.msg-mail { color: var(--navy); text-decoration: underline; text-underline-offset: 3px; }

/* `white-space: pre-wrap` because the sender's line breaks are part of what
   they wrote, and this is text — never markup. */
.msg-body {
  white-space: pre-wrap;
  line-height: 1.9;
  font-size: .95rem;
  color: var(--ink);
}

.msg-actions {
  display: flex;
  gap: var(--s3);
  margin-top: var(--s5);
  padding-top: var(--s4);
  border-top: 1px solid var(--line);
}

.msg-actions .btn-danger { margin-inline-start: auto; }

/* `hidden` has to actually hide.

   The browser's own `[hidden] { display: none }` lives in the user-agent
   sheet, and ANY author declaration of `display` outranks it whatever its
   specificity — so `.btn { display: inline-flex }` quietly re-shows every
   button this panel hides by attribute. Found when the lookup control's
   «حفظ الاسم» and «إلغاء» sat there in plain sight while `el.hidden` was
   true; the file field's «إزالة» has been doing the same on rows with no
   file since it was written. One rule fixes both and everything after them.
   `!important` is the correct tool here for once: this is the browser's own
   default being restored, not a specificity war. */
[hidden] { display: none !important; }

/* ---------------------------------------------------------------- lookup -- */
/* Select, plus the two buttons that write: add a name, correct the chosen one.
   The text input takes the select's place while either is open, so the control
   never grows a second row and the form does not reflow under her hands. */
.lookup {
  display: flex;
  align-items: center;
  gap: 6px;
}

.lookup .select,
.lookup .input { flex: 1 1 auto; min-width: 120px; }

.lookup .btn { flex-shrink: 0; }

.tag {
  font-size: .74rem;
  padding: 2px var(--s2);
  border-radius: 3px;
  border: 1px solid var(--line-2);
  color: var(--muted);
  flex-shrink: 0;
}
.tag-live { color: var(--green); border-color: var(--green); }
.tag-draft { color: var(--gold-ink); border-color: var(--gold-ink); }
.tag-lead { color: var(--navy); border-color: var(--navy); }

.empty {
  text-align: center;
  padding: var(--s7) var(--s4);
  color: var(--muted);
}
.empty h3 { font-family: var(--ar-display); font-weight: var(--ar-display-w); font-size: 1.2rem; color: var(--ink); margin-bottom: var(--s1); }
.empty p { font-size: .9rem; margin-bottom: var(--s4); }

.search-bar { display: flex; gap: var(--s2); margin-bottom: var(--s4); }
.search-bar .input { flex: 1; }

/* ==========================================================================
   home
   ========================================================================== */
.cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(210px, 1fr)); gap: var(--s3); }
.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: var(--s4);
  text-decoration: none;
  color: inherit;
  transition: border-color .18s var(--ease), transform .18s var(--ease);
}
.card:hover { border-color: var(--navy); transform: translateY(-2px); }
.card h3 { font-size: 1rem; font-weight: 500; margin-bottom: 2px; }
.card p { font-size: .82rem; color: var(--muted); }

.publish-box {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 6px;
  padding: var(--s4) var(--s5);
  margin-bottom: var(--s5);
  display: flex;
  align-items: center;
  gap: var(--s4);
  flex-wrap: wrap;
}
.publish-box .txt { flex: 1; min-width: 240px; }
.publish-box h2 { font-family: var(--ar-display); font-weight: var(--ar-display-w); font-size: 1.2rem; margin-bottom: 2px; }
.publish-box p { font-size: .86rem; color: var(--muted); }
/* "٤ تعديلات بانتظار النشر" on the home screen. Muted while it says nothing is
   waiting, and coloured the moment something is. */
.publish-box .pending { margin-top: 2px; }
.publish-box .pending.has { color: var(--gold-ink); font-weight: 600; }

/* ==========================================================================
   review before publishing  —  #/changes
   ========================================================================== */
/* Pending count on the rail link. Empty when there is nothing waiting — the
   :empty rule removes the pill entirely rather than showing an empty one. */
.rail-badge {
  margin-inline-start: auto;
  min-width: 20px;
  padding: 1px 7px;
  border-radius: 999px;
  background: var(--gold);
  color: #2A1F04;
  font-size: .72rem;
  font-weight: 600;
  text-align: center;
}
.rail-badge:empty { display: none; }

.chg-stamp { font-size: .86rem; color: var(--muted); margin-top: 4px; }

/* A segmented control: a recessed track with one raised segment in it.

   The track was `--bg`, which is the page's own background — so it painted
   nothing, and what was left was three unstyled words behind a hairline with
   no hover and no hint that any of them could be pressed. `--bg-2` is the tone
   that already means "set into the page" here, and it is what makes the white
   selected segment read as raised rather than as arbitrary. */
.chg-tabs {
  display: flex;
  gap: 2px;
  background: var(--bg-2);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 3px;
}
.chg-tab {
  padding: 6px var(--s3);
  border: 1px solid transparent;
  border-radius: 999px;
  background: transparent;
  font-size: .84rem;
  color: var(--muted);
  white-space: nowrap;
  cursor: pointer;
  transition: background .2s var(--ease), color .2s var(--ease),
              border-color .2s var(--ease), box-shadow .2s var(--ease);
}
.chg-tab:hover { color: var(--ink-2); background: color-mix(in srgb, var(--ink) 6%, transparent); }

/* The global ring sits 2px outside its element, which on a segment inside a
   3px track draws over the neighbour. Tuck it inside instead, and keep the
   pill's radius — the global rule would square it off to 3px. */
.chg-tab:focus-visible { outline-offset: -2px; border-radius: 999px; }

.chg-tab[aria-selected="true"] {
  background: var(--surface);
  color: var(--ink);
  border-color: var(--line-2);
  box-shadow: var(--shadow-s);
}
/* The selected segment is already where the reader is. Lifting it further on
   hover would say it is about to do something, and it is not. */
.chg-tab[aria-selected="true"]:hover { background: var(--surface); color: var(--ink); }

.chg-total { font-size: .92rem; color: var(--ink-2); margin-bottom: var(--s4); }

.chg-group { margin-bottom: var(--s5); }
.chg-group-head { display: flex; align-items: baseline; gap: var(--s3); margin-bottom: var(--s2); }
.chg-group-head h2 { font-family: var(--ar-display); font-weight: var(--ar-display-w); font-size: 1.05rem; }
.chg-group-head p { font-size: .8rem; color: var(--muted); }
.chg-counts { display: flex; gap: var(--s3); }

.chg-list { list-style: none; border: 1px solid var(--line); border-radius: 6px; background: var(--surface); overflow: hidden; }

/* The separator moved from the row to the item when the diff arrived: an item is
   now a head line plus a field list, and a border under the head line alone drew
   a rule through the middle of one change. */
/* The start-edge border is reserved on every row and coloured only on a held
   one, so ticking a box cannot nudge the text sideways. Logical, not `inset`
   box-shadow: an inset offset is physical, and in this RTL panel it would draw
   the mark down the wrong edge. */
.chg-item { border-bottom: 1px solid var(--line); border-inline-start: 2px solid transparent; }
.chg-item:last-child { border-bottom: 0; }

.chg-row {
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: var(--s3) var(--s4);
}

/* The verb, not a colour alone — the three states have to survive a monochrome
   print and a colour-blind reader, so each one carries its word. */
.chg-chip {
  flex: none;
  font-size: .76rem;
  font-weight: 600;
  padding: 2px 10px;
  border-radius: 999px;
  border: 1px solid transparent;
}
.chg-chip.is-create { color: var(--green); border-color: var(--green); }
.chg-chip.is-update { color: var(--gold-ink); border-color: var(--gold); }
.chg-chip.is-delete { color: var(--red); border-color: var(--red); }

.chg-name { flex: 1; min-width: 0; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
a.chg-name:hover { color: var(--navy); text-decoration: underline; }
/* A deleted row has nowhere to link to. Struck through rather than hidden:
   she needs to see that it went, and its name is the only trace left. */
.chg-name.is-gone { color: var(--muted); text-decoration: line-through; }

.chg-meta { flex: none; display: flex; gap: var(--s3); align-items: baseline; font-size: .78rem; color: var(--muted); }
.chg-by { font-size: .72rem; opacity: .8; }

/* ---------- what goes out with this publish ---------- */
/* Ticked by default, so the box is a way to hold something back rather than a
   gate everything has to be let through. Sized past the 24px that a finger
   misses: this list is read on a phone, and a mis-tap here publishes something
   she meant to keep back. */
.chg-pick {
  flex: none;
  width: 18px;
  height: 18px;
  accent-color: var(--navy);
  cursor: pointer;
}

/* An unticked row is still readable — it is the one she is making a decision
   about, and fading it to grey would be hiding the thing under discussion. The
   line down the side is what marks it, and the muted name says the rest. */
.chg-item.is-held {
  background: var(--bg-2);
  border-inline-start-color: var(--gold);
}
.chg-item.is-held .chg-name { color: var(--muted); }

/* Held by an earlier publish (server/holds.mjs) — a fact about the live site,
   not a choice on this press, so it is a word beside the verb rather than
   another shade of the row. Outlined like the verbs, in the ink colour, so it
   never reads as a fourth kind of change. */
.chg-chip.is-waiting { color: var(--muted); border-color: var(--muted); border-style: dashed; }
/* On the record tabs: this row is on the site. Solid where «لم يُنشر بعد» is
   dashed, so the two read apart without the colour. */
.chg-chip.is-live { color: var(--navy); border-color: var(--navy); }

/* The two lines under a row's head: that it is held, and which rows were saved
   with it and move with its box. Indented to the text, like the no-diff note. */
.chg-held-note,
.chg-group-note { margin: 0 var(--s4) var(--s2); }

/* ---------- the diff ---------- */
/* Always visible, never a hover: hover does not exist on the phone this panel is
   read on, and it answers one field at a time when the question is about all of
   them (plan-v2.md §20). */
.chg-fields {
  list-style: none;
  margin: 0 var(--s4) var(--s3);
  border-inline-start: 2px solid var(--line-2);
  padding-inline-start: var(--s3);
  display: grid;
  gap: var(--s2);
}

.chg-field { display: flex; align-items: baseline; gap: var(--s3); }
.chg-field.is-wide { display: block; }

.chg-field-name {
  flex: none;
  width: 8.5rem;
  font-size: .8rem;
  color: var(--muted);
  line-height: 1.6;
}
.chg-field.is-wide .chg-field-name { display: block; width: auto; margin-bottom: 4px; }

/* «قبل» beside «بعد» while there is room, stacked when there is not. One rule,
   both layouts: the sides are flex children with a minimum width, so they wrap
   by themselves on a narrow screen. */
.chg-pair { flex: 1; min-width: 0; display: flex; flex-wrap: wrap; gap: var(--s2); }
.chg-side {
  flex: 1 1 46%;
  min-width: 0;
  display: flex;
  align-items: baseline;
  gap: var(--s2);
  padding: 4px var(--s2);
  border-radius: 4px;
  border: 1px solid var(--line);
  background: var(--bg);
  font-size: .88rem;
}
.chg-side.is-was { border-color: color-mix(in srgb, var(--red) 35%, var(--line)); }
.chg-side.is-now { border-color: color-mix(in srgb, var(--green) 35%, var(--line)); }

/* The word, not the colour. «قبل» and «بعد» are the signal; the tint is the
   convenience — the screen has to survive a monochrome print. */
.chg-tag {
  flex: none;
  font-size: .72rem;
  font-weight: 600;
  color: var(--muted);
}
.chg-side.is-was .chg-tag { color: var(--red); }
.chg-side.is-now .chg-tag { color: var(--green); }

.chg-val { min-width: 0; overflow-wrap: anywhere; white-space: pre-wrap; }

.chg-note { font-size: .82rem; color: var(--muted); }
.chg-nodiff { font-size: .82rem; color: var(--muted); margin: 0 var(--s4) var(--s3); }

/* Two thumbnails at the same size, so a swapped image is a comparison and not a
   guess about which one is bigger. */
.chg-thumb {
  width: 76px;
  height: 56px;
  object-fit: cover;
  border-radius: 4px;
  border: 1px solid var(--line-2);
  background: var(--bg-2);
}
.chg-noimg {
  font-size: .78rem;
  color: var(--muted);
  padding: var(--s2) 0;
}

/* A gallery on the publish screen: every photograph at the same size as a
   single file field's thumbnail, in the order it will print. Wraps rather than
   scrolls — an article with nine photographs should show all nine, because the
   question this screen answers is what the visitor will see, and a strip that
   hides the last four answers it wrongly. */
.chg-strip {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
}
.chg-shot { margin: 0; max-width: 76px; }
/* The caption is the alt text the reader will get, so it is worth showing —
   clamped to two lines, because a long one must not push the thumbnails on one
   side out of step with the other. */
.chg-shot figcaption {
  font-size: .72rem;
  line-height: 1.5;
  color: var(--muted);
  margin-top: 2px;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.chg-text { font-size: .9rem; line-height: 1.85; }
.chg-para { margin-bottom: 6px; overflow-wrap: anywhere; }
.chg-para:last-child { margin-bottom: 0; }
/* The count, not the paragraphs. A one-word correction in a long article shows
   the sentence that moved and says how much did not. */
/* No leading glyph. An "⋯" in `content` is a neutral character next to an
   Arabic-Indic digit, and the bidi algorithm put it between the number and the
   word — «٣ ⋯ فقرات» — which reads as a typo. The muted line is signal enough. */
.chg-para.is-same { font-size: .8rem; color: var(--muted); }

/* del and ins, the elements the language already has for this. Their default
   line-through and underline are the half of the signal that is not colour, so
   neither is removed. */
.chg-text del, .chg-side del {
  color: var(--red);
  background: color-mix(in srgb, var(--red) 10%, transparent);
  text-decoration-thickness: 1px;
}
.chg-text ins {
  color: var(--green);
  background: color-mix(in srgb, var(--green) 12%, transparent);
  text-decoration-thickness: 1px;
}
.chg-para.is-del, .chg-para.is-ins { display: flex; gap: var(--s2); align-items: baseline; }
.chg-para.is-del .chg-tag { color: var(--red); }
.chg-para.is-ins .chg-tag { color: var(--green); }

.chg-publish {
  display: flex;
  align-items: center;
  gap: var(--s4);
  flex-wrap: wrap;
  margin-top: var(--s5);
  padding-top: var(--s4);
  border-top: 1px solid var(--line);
}
.chg-publish .txt { flex: 1; min-width: 240px; }
.chg-publish h2 { font-family: var(--ar-display); font-weight: var(--ar-display-w); font-size: 1.1rem; margin-bottom: 2px; }
.chg-publish p { font-size: .86rem; color: var(--muted); }

/* ==========================================================================
   rich text
   ========================================================================== */
.rt { border: 1px solid var(--line-2); border-radius: 4px; background: var(--bg); overflow: hidden; }
.rt:focus-within { border-color: var(--navy); }

.rt-bar {
  display: flex;
  gap: 2px;
  padding: var(--s1);
  border-bottom: 1px solid var(--line);
  background: var(--surface);
  flex-wrap: wrap;
}
.rt-btn {
  background: none;
  border: 0;
  border-radius: 3px;
  padding: var(--s1) var(--s2);
  cursor: pointer;
  color: var(--ink-2);
  line-height: 0;
}
.rt-btn:hover { background: var(--bg-2); color: var(--ink); }
.rt-btn[aria-pressed="true"] { background: color-mix(in srgb, var(--navy) 14%, transparent); color: var(--navy); }
.rt-btn svg { width: 17px; height: 17px; }

.rt-body {
  min-height: 130px;
  padding: var(--s3);
  line-height: 1.85;
  outline: 0;
}
.rt-body:empty::before { content: attr(data-placeholder); color: var(--muted); }
.rt-body p { margin-bottom: var(--s2); }
.rt-body ul, .rt-body ol { padding-inline-start: var(--s5); margin-bottom: var(--s2); }
.rt-body a { color: var(--navy); }

/* ==========================================================================
   file field
   ========================================================================== */
.file-field {
  border: 1px dashed var(--line-2);
  border-radius: 4px;
  padding: var(--s3);
  display: flex;
  align-items: center;
  gap: var(--s3);
  background: var(--bg);
}
.file-field.is-drop { border-color: var(--navy); background: color-mix(in srgb, var(--navy) 5%, transparent); }
.file-field img { width: 62px; height: 62px; object-fit: cover; border-radius: 4px; border: 1px solid var(--line); }
.file-field .ff-body { flex: 1; min-width: 0; }
.file-field .ff-name { font-size: .86rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.file-field .ff-meta { font-size: .78rem; color: var(--muted); }

.bar { height: 4px; background: var(--line); border-radius: 2px; overflow: hidden; margin-top: var(--s1); }
.bar > i { display: block; height: 100%; background: var(--navy); transition: width .2s linear; }

/* ==========================================================================
   repeater (page sections)
   ========================================================================== */
.rep-item {
  border: 1px solid var(--line);
  border-radius: 4px;
  margin-bottom: var(--s3);
  background: var(--surface);
}
.rep-head {
  display: flex;
  align-items: center;
  gap: var(--s2);
  padding: var(--s2) var(--s3);
  border-bottom: 1px solid var(--line);
  background: var(--bg-2);
}
.rep-head b { font-size: .88rem; font-weight: 500; flex: 1; }
.rep-body { padding: var(--s3); }

/* ==========================================================================
   toast
   ========================================================================== */
.toast-wrap {
  position: fixed;
  inset-block-end: var(--s4);
  inset-inline-start: var(--s4);
  z-index: 60;
  display: flex;
  flex-direction: column;
  gap: var(--s2);
}
.toast {
  background: var(--surface);
  border: 1px solid var(--line-2);
  border-inline-start: 3px solid var(--navy);
  border-radius: 4px;
  box-shadow: var(--shadow-m);
  padding: var(--s2) var(--s4);
  font-size: .9rem;
  max-width: 380px;
}
.toast-ok { border-inline-start-color: var(--green); }
.toast-err { border-inline-start-color: var(--red); }

/* ==========================================================================
   responsive — the secretary may well be on a phone
   ========================================================================== */
@media (max-width: 900px) {
  .shell { grid-template-columns: 1fr; }

  /* The rail becomes a horizontal strip, not a stacked column.

     It used to keep its vertical layout at full width: fourteen links, 1003px
     tall on a 390px phone, so `main` began below the fold and every screen
     opened on the menu. Found on the live panel 2026-08-16 (docs/panel.md §9a).

     A scrolling strip keeps every destination reachable with no toggle to
     build, no JavaScript, and no state that can get stuck open. It costs the
     group headings, which are hidden below — "الأبرشية" above four links is
     an organising aid on a wide screen and an obstacle on a narrow one. */
  .rail {
    position: sticky;
    top: 0;
    z-index: 20;
    height: auto;
    flex-direction: row;
    align-items: center;
    gap: var(--s2);
    padding: var(--s2) var(--s3);
    border-inline-end: 0;
    border-bottom: 1px solid var(--line);
    overflow-x: auto;
    overflow-y: hidden;
    /* Momentum scrolling on iOS, and no vertical rubber-banding inside a
       strip that has nothing to scroll vertically. */
    -webkit-overflow-scrolling: touch;
    scrollbar-width: thin;
  }

  .rail::-webkit-scrollbar { height: 3px; }
  .rail::-webkit-scrollbar-thumb { background: var(--line); border-radius: 3px; }

  .rail-brand {
    flex-shrink: 0;
    padding-bottom: 0;
    border-bottom: 0;
    padding-inline-end: var(--s2);
    border-inline-end: 1px solid var(--line);
  }
  /* The two-line wordmark is the tallest thing in the strip and the least
     useful: the page it links to is also the first link. */
  .rail-brand b, .rail-brand i { display: none; }

  .rail-group {
    display: flex;
    gap: var(--s1);
    margin-bottom: 0;
    flex-shrink: 0;
  }
  .rail-group > p { display: none; }

  .rail-link { white-space: nowrap; flex-shrink: 0; }
  /* The per-collection counts double the width of every link and are already
     on the home screen's cards. */
  .rail-link .count { display: none; }

  .rail-foot {
    margin-top: 0;
    margin-inline-start: auto;
    padding-top: 0;
    padding-inline-start: var(--s2);
    border-top: 0;
    border-inline-start: 1px solid var(--line);
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: var(--s2);
  }
  /* Which account is signed in matters on a shared desktop; on her own phone
     it is a line of text pushing the logout button off screen. */
  .rail-who { display: none; }

  .main { padding: var(--s4) var(--s4) var(--s7); }
  .page-head { flex-wrap: wrap; }
  .page-head .actions { margin-inline-start: 0; width: 100%; }

  /* A change row is chip + name + time + email on one line, which is more than
     390px holds. The name goes on its own line and the metadata sits under it;
     the chip stays beside the name, because the verb is what she scans for. */
  .chg-row { flex-wrap: wrap; row-gap: 4px; }
  .chg-name { flex: 1 1 60%; white-space: normal; }
  .chg-meta { flex: 1 1 100%; padding-inline-start: 58px; }

  /* Three window tabs plus the heading do not share a line. They split the
     width evenly rather than scrolling: the labels are three words at most, and
     a segmented control you have to swipe sideways hides the segment that is
     not selected — which is the one you opened it to reach. */
  .chg-tabs { width: 100%; }
  .chg-tab { flex: 1; text-align: center; padding-inline: var(--s2); }

  /* The diff stacks. «قبل» over «بعد» rather than beside it — 390px does not
     hold two Arabic sentences side by side, and squeezing them there is how a
     comparison becomes two columns of one word each. The field name goes above
     its own comparison for the same reason. */
  .chg-field { display: block; }
  .chg-field-name { display: block; width: auto; margin-bottom: 4px; }
  .chg-side { flex: 1 1 100%; }
  .chg-fields { margin-inline: var(--s3); }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: .01ms !important; animation-duration: .01ms !important; }
}

/* Page-body editor (`pages.sections`). The index timeline paints beside its
   fields so a year typed is a year seen. */
.pb { display: flex; flex-direction: column; gap: var(--s4); }
.pb-h { font-size: 16px; font-weight: 600; margin: 0; }
.pb-sub { font-size: 13.5px; color: var(--muted); margin: 0; line-height: 1.65; }
.pb-block {
  border: 1px solid var(--line); border-radius: 12px;
  padding: var(--s4); margin: 0;
}
.pb-block legend { font-weight: 600; padding-inline: 8px; }
.pb-split {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: var(--s4); align-items: start;
}
.pb-preview-lbl { font-size: 12.5px; color: var(--muted); margin: 0 0 8px; }
.pb-tl {
  list-style: none; margin: 0; padding: var(--s4);
  background: var(--bg-2); border: 1px solid var(--line); border-radius: 12px;
}
.pb-tl li { display: grid; grid-template-columns: 4.5rem 1fr; gap: 10px; padding: 8px 0; }
.pb-tl b { color: var(--gold-ink); }
.pb-tl p { margin: 0; font-size: 13.5px; line-height: 1.55; }
.pb-tl li.is-now b { color: var(--navy); }
@media (max-width: 720px) {
  .pb-split { grid-template-columns: 1fr; }
}

/* ==========================================================================
   the history page editor (history-editor.js) and image slots (image-slot.js)

   The page map at the top, the four sections numbered as the page reads, the
   eras and events as cards that open, and — beside every picture control — a
   drawing of the section with the picture where it will land. The drawings
   (.sm) mirror site/css/page-history.css § image slots: top, side (picture on
   the left, the words on the right), bottom, and background for the hero.
   ========================================================================== */
.he { gap: var(--s5); }

/* ---------- the map of the page ---------- */
.he-outline {
  background: var(--surface); border: 1px solid var(--line-2); border-radius: 14px;
  padding: var(--s4); box-shadow: var(--shadow-s);
}
.he-ol-head { display: flex; align-items: baseline; justify-content: space-between; gap: var(--s3); }
.he-ol-head span { font-size: 12.5px; color: var(--muted); }
.he-outline > .hint { margin: 2px 0 var(--s3); font-size: .8rem; color: var(--muted); }
.he-ol { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
.he-ol-sub { margin-inline-start: 26px; margin-top: 4px; border-inline-start: 2px solid var(--line); padding-inline-start: 10px; }
.he-ol-row {
  width: 100%; display: flex; align-items: center; gap: 10px;
  padding: 6px 8px; border: 0; border-radius: 8px; background: none;
  text-align: start; font-size: 13.5px; color: var(--ink);
}
.he-ol-row:hover { background: var(--bg-2); }
.he-ol-n {
  flex: none; min-width: 26px; height: 22px; border-radius: 6px; padding-inline: 4px;
  display: grid; place-items: center; font-size: 12px; font-weight: 600;
  background: var(--bg-2); color: var(--navy);
}
.he-ol-t { flex: 1 1 auto; }
.he-ol-none { flex: none; font-size: 11.5px; color: var(--muted); }
.he-ol-chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 2px 36px 6px 0; }
.he-ol-chip {
  display: inline-flex; align-items: center; gap: 6px; max-width: 100%;
  padding: 3px 8px 3px 4px; border: 1px solid var(--line); border-radius: 999px;
  font-size: 12px; color: var(--ink-2);
}
.he-ol-chip:hover { border-color: var(--navy); color: var(--navy); }
.he-ol-chip span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 28ch; }

.he-thumb {
  flex: none; display: inline-grid; place-items: center;
  border-radius: 5px; background: var(--bg-2) center / cover no-repeat;
  border: 1px solid var(--line-2); color: var(--muted);
}
.he-thumb-sm { width: 22px; height: 16px; }
.he-thumb-md { width: 44px; height: 30px; border-radius: 6px; }

/* ---------- the four sections ---------- */
.he-sec {
  border: 1px solid var(--line); border-radius: 14px; padding: var(--s4);
  display: flex; flex-direction: column; gap: var(--s3);
  scroll-margin-top: var(--s4);
}
.he-sec-h { display: flex; align-items: center; gap: 10px; margin: 0; font-size: 16px; }
.he-sec-n {
  width: 28px; height: 28px; border-radius: 50%; display: grid; place-items: center;
  background: var(--navy); color: #fff; font-size: 13px; font-weight: 600;
}
:root[data-theme="dark"] .he-sec-n { color: #0F1929; }
.he-sec-note { margin: -6px 0 0; }
.he-flash { animation: he-flash 1.4s ease-out; }
@keyframes he-flash {
  0%, 30% { box-shadow: 0 0 0 3px color-mix(in srgb, var(--gold) 60%, transparent); }
  100% { box-shadow: 0 0 0 3px transparent; }
}

/* ---------- eras and events as cards ---------- */
.he-eras, .he-items { display: flex; flex-direction: column; gap: 8px; }
.he-card { border: 1px solid var(--line-2); border-radius: 12px; background: var(--surface); scroll-margin-top: var(--s4); }
.he-era { border-color: var(--line-2); }
.he-era > .he-card-body { background: var(--bg); }
.he-card[open] { box-shadow: var(--shadow-s); }
.he-sum {
  display: flex; align-items: center; gap: 10px; padding: 10px 12px;
  cursor: pointer; list-style: none; border-radius: 12px;
}
.he-sum::-webkit-details-marker { display: none; }
.he-sum:hover { background: var(--bg-2); }
.he-sum-date { flex: none; font-weight: 600; color: var(--gold-ink); font-size: 13.5px; min-width: 7ch; }
.he-sum-head { flex: 1 1 auto; font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.he-era-sum .he-sum-date { color: var(--navy); }
.he-era-sum .he-sum-head { font-weight: 600; }
.he-sum-thumb { flex: none; display: inline-flex; }
.he-dot { flex: none; width: 9px; height: 9px; border-radius: 50%; border: 2px solid var(--line-2); }
.he-item.is-gap .he-dot { border-style: dashed; }
.he-item.is-gap .he-sum-date { color: var(--muted); font-weight: 500; }
.he-item.is-gap .he-sum-head { color: var(--muted); }
.he-tools { flex: none; display: inline-flex; gap: 2px; }
.he-move { padding-inline: 8px; font-size: 11px; }
.he-card-body { padding: var(--s3) var(--s4) var(--s4); border-top: 1px solid var(--line); border-radius: 0 0 12px 12px; }
.he-items-h { margin: var(--s4) 0 0; font-size: 14px; }
.he-add { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; }
.he-flags { display: flex; flex-wrap: wrap; gap: 0 var(--s4); }
.he-flags .field { margin-bottom: 0; }
.he-kinds { display: inline-flex; border: 1px solid var(--line-2); border-radius: 999px; padding: 3px; margin-bottom: var(--s3); }
.he-kind { padding: 5px 14px; border-radius: 999px; font-size: 13px; color: var(--ink-2); }
.he-kind.is-on { background: var(--navy); color: #fff; }
:root[data-theme="dark"] .he-kind.is-on { color: #0F1929; }
.he-item.is-verse .he-dot { border-color: var(--gold); background: color-mix(in srgb, var(--gold) 35%, transparent); }
.he-item.is-verse .he-sum-date { color: var(--gold-ink); }
.he-fx { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 0 var(--s4); }
.he-rec .is-status { margin-bottom: 8px; }
.he-audio { display: block; width: 100%; max-width: 520px; height: 40px; }

/* ---------- an image slot ---------- */
.is {
  border: 1px solid var(--line-2); border-radius: 12px; padding: var(--s3);
  margin-bottom: var(--s4); background: var(--surface);
  transition: border-color .2s var(--ease), background-color .2s var(--ease);
}
.is.is-empty { border-style: dashed; }
.is.is-drop { border-color: var(--navy); background: color-mix(in srgb, var(--navy) 5%, transparent); }
.is-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: var(--s3); }
.is-title { display: inline-flex; align-items: center; gap: 6px; font-weight: 600; font-size: 14px; }
.is-actions { display: inline-flex; gap: 6px; flex-wrap: wrap; }
.is-body { display: grid; grid-template-columns: minmax(180px, 240px) 1fr; gap: var(--s4); align-items: start; }
.is-map-cap { margin: 6px 0 0; font-size: 12px; color: var(--muted); text-align: center; }
.is-status { margin: 0; font-size: 12.5px; color: var(--ink-2); line-height: 1.6; overflow-wrap: anywhere; }
.is-details { display: flex; flex-direction: column; gap: 6px; margin-top: var(--s3); }
.is-sub { margin: 0; font-size: 12.5px; font-weight: 600; }
.is-lbl { display: block; font-size: 13px; font-weight: 500; margin-top: 6px; }
.is-lbl .hint { display: block; font-size: .78rem; color: var(--muted); font-weight: 400; }
.is-place-hint { margin: 0; font-size: .8rem; color: var(--muted); }
.is-choices { display: flex; flex-wrap: wrap; gap: 8px; }
.is-choice {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: 6px; border: 1.5px solid var(--line-2); border-radius: 10px;
  font-size: 12px; color: var(--ink-2); width: 92px;
}
.is-choice:hover { border-color: var(--navy); }
.is-choice.is-on { border-color: var(--navy); background: color-mix(in srgb, var(--navy) 7%, transparent); color: var(--navy); font-weight: 600; }
@media (max-width: 720px) {
  .is-body { grid-template-columns: 1fr; }
}

/* ---------- the drawing of a section (.sm — "slot map") ---------- */
.sm {
  position: relative; display: flex; flex-direction: column; gap: 8px;
  padding: 12px; border-radius: 10px; overflow: hidden; isolation: isolate;
  background: var(--bg); border: 1px solid var(--line);
  min-height: 132px;
}
.sm-words { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.sm-bar { display: block; height: 5px; border-radius: 3px; background: var(--line-2); }
.sm-title { height: 9px; background: var(--ink-2); opacity: .55; }
.sm-label { height: 5px; background: var(--gold); }
.sm-button { height: 12px; border-radius: 6px; background: var(--navy); opacity: .6; margin-top: 3px; }
.sm-evrow { display: flex; align-items: center; gap: 6px; }
.sm-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--gold); flex: none; }
.sm-date { width: 18%; height: 7px; border-radius: 3px; background: var(--gold); opacity: .7; flex: none; }
.sm-pic {
  display: grid; place-items: center; color: var(--navy);
  border-radius: 6px; min-height: 46px;
  background: color-mix(in srgb, var(--navy) 12%, var(--surface)) center / cover no-repeat;
  outline: 2px solid var(--gold); outline-offset: 1px;
}
.sm-pic.has-thumb { outline-color: var(--navy); }

.sm-at-top .sm-pic { order: -1; aspect-ratio: 16 / 6; }
.sm-at-bottom .sm-pic { aspect-ratio: 16 / 6; }
.sm-at-side { display: grid; grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); align-items: center; }
.sm-at-side .sm-pic { aspect-ratio: 4 / 3; }
.sm-at-background { justify-content: center; }
.sm-at-background .sm-pic {
  position: absolute; inset: 0; z-index: -1; border-radius: 0; outline: 0;
}
.sm-at-background .sm-words { position: relative; z-index: 1; }
.sm-at-background::after {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: linear-gradient(90deg, color-mix(in srgb, var(--bg) 20%, transparent) 0%, color-mix(in srgb, var(--bg) 88%, transparent) 55%, var(--bg) 100%);
}
.sm-at-background .sm-words { width: 62%; }

/* the miniatures inside the placement buttons */
.sm-mini { min-height: 54px; width: 78px; padding: 6px; gap: 4px; border-radius: 6px; }
.sm-mini .sm-words { gap: 3px; }
.sm-mini .sm-bar { height: 3px; }
.sm-mini .sm-title { height: 5px; }
.sm-mini .sm-button { height: 6px; }
.sm-mini .sm-pic { min-height: 18px; outline-width: 1.5px; }
.sm-mini.sm-at-side { gap: 4px; }
.sm-mini .sm-dot { width: 5px; height: 5px; }
.sm-mini .sm-date { height: 4px; }
.he-to-map { margin-inline-start: auto; font-size: 12px; font-weight: 400; }
.he-outline { scroll-margin-top: var(--s4); }
