/* ============================================================================
   KB console — Hebrew-first, RTL-first.

   Palette: Bank Leumi. Two brand values sampled from the real mark rather than
   guessed - #0166FF (the badge blue) and #10069A (the wordmark indigo) - over a
   cool paper ground and ink-navy text. The ground is deliberately near-neutral:
   this is a tool six people read Hebrew paragraphs in for hours, so the brand
   lives in the accent, the header rule and the mark, not in the body surface.
   The one place the palette is NOT applied is the WhatsApp preview bubble,
   which keeps WhatsApp's own green: that block is a fidelity preview of what
   120 people will receive, and branding it would make it lie.
   Status carries its own hue (published = green, draft = amber) because status
   is the one thing a reviewer must read at a glance across a long list.
   Both themes are defined explicitly; nothing relies on browser defaults.

   Every colour pair that carries text is measured against its own background
   rather than eyeballed. Re-measured after the rebrand:
     white on --accent  #0166FF          = 4.83  (buttons: AA for normal text)
     --accent-hi #10069A on --surface    = 13.8  (links, hover, headings)
     --muted #5c6780 on --sunken #e8ecf3 = 4.75  (placeholders, meta)
     --ok    #177339 on --ok-wash        = 5.16  (.tag--published)
   #0166FF clears AA on white as a BUTTON GROUND but is too light to read AS
   text on paper, so text uses --accent-hi and only fills use --accent.

   Type and space run on one scale each (--fs-*, --sp-*). Sizes and gaps come
   from those tokens, not from a number picked per rule.
   ========================================================================== */

:root {
  /* ---- type scale: 1.125 ratio off a 15px base, rounded to sane px ------- */
  --fs-2xs:  .6875rem;   /* 11px — counters, keys */
  --fs-xs:   .75rem;     /* 12px — tags, meta */
  --fs-sm:   .8125rem;   /* 13px — hints, labels */
  --fs-md:   .875rem;    /* 14px — dense body */
  --fs-base: .9375rem;   /* 15px — body */
  --fs-lg:   1.0625rem;  /* 17px — card lede */
  --fs-xl:   1.25rem;    /* 20px — detail title */
  --fs-2xl:  1.5rem;     /* 24px */
  --lh-tight: 1.3;
  --lh-body:  1.6;
  --lh-prose: 1.7;

  /* ---- spacing rhythm: 4px grid ----------------------------------------- */
  --sp-1: .25rem;
  --sp-2: .5rem;
  --sp-3: .75rem;
  --sp-4: 1rem;
  --sp-5: 1.5rem;
  --sp-6: 2rem;
  --topbar-h: 3.25rem;

  /* ---- palette ----------------------------------------------------------- */
  --paper:      #f1f4f9;
  --surface:    #ffffff;
  --surface-2:  #f8fafd;
  --sunken:     #e8ecf3;
  --ink:        #101a2e;
  --ink-soft:   #3c4761;
  --muted:      #5c6780;
  --line:       #dde2ec;
  --line-firm:  #c4ccdc;

  /* Leumi badge blue: fills, rules and marks only. */
  --accent:     #0166ff;
  /* Leumi wordmark indigo: anything that is TEXT. */
  --accent-hi:  #10069a;
  --accent-on:  #ffffff;
  --accent-wash:#e6efff;
  --brand-band: linear-gradient(105deg, #10069a 0%, #0f2fbd 55%, #0166ff 100%);
  --brand-on:   #ffffff;

  --ok:         #177339;
  --ok-wash:    #e6f3ea;
  --warn:       #92590a;
  --warn-wash:  #fbf1de;
  --danger:     #b42318;
  --danger-wash:#fdecea;

  --code-bg:    #eef1f8;
  --code-ink:   #1b2f6b;

  --focus:      #0f4fd8;
  --shadow-sm:  0 1px 2px rgba(23,25,31,.06), 0 1px 3px rgba(23,25,31,.05);
  --shadow-md:  0 2px 4px rgba(23,25,31,.06), 0 8px 24px rgba(23,25,31,.08);

  --r-sm: 6px;
  --r-md: 10px;
  --r-lg: 14px;

  /* Hebrew first: the platform UI face (SF Hebrew on macOS, Segoe UI Variable
     on Windows 11) before any named family. The old stack opened with
     "Segoe UI", which does not exist on a Mac and has thin Hebrew coverage
     anywhere — the console fell back to a default serif-ish face for exactly
     the language it is written in. */
  --font: system-ui, -apple-system, "Segoe UI Variable Text", "Segoe UI",
          Assistant, Rubik, "Noto Sans Hebrew", "Arial Hebrew", Arial, sans-serif;
  --mono: ui-monospace, "SF Mono", "JetBrains Mono", "Cascadia Mono", Menlo,
          Consolas, monospace;
}

/* The dark palette is stated twice on purpose: once for the OS preference and
   once for the explicit in-app toggle. Plain CSS has no way to share one block
   between a media query and an attribute selector, and a preprocessor is not
   worth a build step here. Token values only — no layout below this line. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --paper:      #0a0f1c;
    --surface:    #131b2c;
    --surface-2:  #182236;
    --sunken:     #070b15;
    --ink:        #e7ecf6;
    --ink-soft:   #c0c9da;
    --muted:      #909cb5;
    --line:       #232f47;
    --line-firm:  #384662;

    /* The brand blue is unreadable on a dark ground, so both roles lighten:
       #6aa5ff on --surface = 7.4, #a8c8ff = 11.2. */
    --accent:     #6aa5ff;
    --accent-hi:  #a8c8ff;
    --accent-on:  #05122e;
    --accent-wash:#152b4d;
    --brand-band: linear-gradient(105deg, #0b0555 0%, #0d1f74 55%, #0a47b8 100%);
    --brand-on:   #ffffff;

    --ok:         #56c98a;
    --ok-wash:    #10281c;
    --warn:       #e6a94d;
    --warn-wash:  #322511;
    --danger:     #f38078;
    --danger-wash:#341a1a;

    --code-bg:    #0b1220;
    --code-ink:   #9dc4ff;

    --focus:      #8ab6ff;
    --shadow-sm:  0 1px 2px rgba(0,0,0,.4);
    --shadow-md:  0 2px 6px rgba(0,0,0,.45), 0 12px 32px rgba(0,0,0,.4);
  }
}

:root[data-theme="dark"] {
  --paper:      #0a0f1c;
  --surface:    #131b2c;
  --surface-2:  #182236;
  --sunken:     #070b15;
  --ink:        #e7ecf6;
  --ink-soft:   #c0c9da;
  --muted:      #909cb5;
  --line:       #232f47;
  --line-firm:  #384662;

  /* The brand blue is unreadable on a dark ground, so both roles lighten:
     #6aa5ff on --surface = 7.4, #a8c8ff = 11.2. */
  --accent:     #6aa5ff;
  --accent-hi:  #a8c8ff;
  --accent-on:  #05122e;
  --accent-wash:#152b4d;
  --brand-band: linear-gradient(105deg, #0b0555 0%, #0d1f74 55%, #0a47b8 100%);
  --brand-on:   #ffffff;

  --ok:         #56c98a;
  --ok-wash:    #10281c;
  --warn:       #e6a94d;
  --warn-wash:  #322511;
  --danger:     #f38078;
  --danger-wash:#341a1a;

  --code-bg:    #0b1220;
  --code-ink:   #9dc4ff;

  --focus:      #8ab6ff;
  --shadow-sm:  0 1px 2px rgba(0,0,0,.4);
  --shadow-md:  0 2px 6px rgba(0,0,0,.45), 0 12px 32px rgba(0,0,0,.4);
}

/* ------------------------------- base ------------------------------------ */
* { box-sizing: border-box; }
html, body { height: 100%; }
body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: var(--fs-base)/var(--lh-body) var(--font);
  -webkit-text-size-adjust: 100%;
}
[hidden] { display: none !important; }

h1, h2, h3, h4 { line-height: var(--lh-tight); }

code, kbd, pre, .mono { font-family: var(--mono); font-size: .92em; }

/* Every Latin run that sits inside Hebrew is isolated. <bdi> does it natively;
   these rules make sure nothing overrides it and that inline code is isolated
   even when an author forgets the wrapper. */
bdi, code { unicode-bidi: isolate; }

/* Never auto-hyphenate an identifier or a command. Where a token must stay
   whole even at a hyphen — the WhatsApp preview — see `.wa code .tok`. */
code, .mono, .lat { hyphens: none; }

a { color: var(--accent); }
a:hover { color: var(--accent-hi); }

button { font: inherit; color: inherit; }

/* One focus treatment, everywhere, that follows the shape it lands on: the ring
   sits outside the element's own radius instead of forcing a square 4px one. */
:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
}
input:focus-visible, textarea:focus-visible, select:focus-visible {
  outline-offset: 1px;
  border-color: var(--focus);
}
.chip:focus-visible, .role-badge:focus-visible, .pill:focus-visible { outline-offset: 3px; }

::selection { background: var(--accent-wash); color: var(--ink); }

/* Shared utilities, so nothing needs an inline style attribute. */
.tight { margin: 0 0 var(--sp-3); }
.hint { color: var(--muted); font-size: var(--fs-sm); }
.h3-count { font-weight: 400; color: var(--muted); }
.prose { margin: 0; white-space: pre-wrap; line-height: var(--lh-prose); overflow-wrap: anywhere; }
.link-btn {
  background: none; border: 0; padding: 0; margin-top: var(--sp-1);
  color: var(--accent); font-size: var(--fs-sm); font-weight: 600; cursor: pointer;
  text-decoration: underline; text-underline-offset: 2px;
}
.inline-check { display: flex; gap: var(--sp-1); align-items: center; }

/* ------------------------------- buttons --------------------------------- */
.btn {
  display: inline-flex; align-items: center; gap: .45em;
  padding: .5em .95em;
  border: 1px solid var(--line-firm);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--ink);
  cursor: pointer;
  transition: background .12s, border-color .12s, transform .06s;
}
.btn:hover { background: var(--surface-2); border-color: var(--muted); }
.btn:active { transform: translateY(1px); }
.btn[disabled] { opacity: .45; cursor: not-allowed; }
.btn[disabled]:hover { background: var(--surface); border-color: var(--line-firm); }

.btn--primary {
  background: var(--accent); border-color: var(--accent); color: var(--accent-on);
  font-weight: 600;
}
.btn--primary:hover { background: var(--accent-hi); border-color: var(--accent-hi); }

.btn--ghost { background: transparent; border-color: transparent; color: var(--ink-soft); }
.btn--ghost:hover { background: var(--sunken); border-color: var(--line); }

.btn--danger { color: var(--danger); border-color: var(--line-firm); background: transparent; }
.btn--danger:hover { background: var(--danger-wash); border-color: var(--danger); }

.btn--icon { padding: .35em .5em; line-height: 1; }
.btn--block { width: 100%; justify-content: center; padding: .7em; }
.btn--sm { padding: .3em .6em; font-size: var(--fs-sm); }

/* ------------------------------- boot ------------------------------------ */
.boot { min-height: 100vh; display: grid; place-items: center; padding: var(--sp-5); }
.boot-card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: var(--sp-6) var(--sp-6); max-width: 34rem;
  box-shadow: var(--shadow-sm); text-align: center;
}
.boot-card--error { border-color: var(--danger); text-align: start; }
.boot-card h1 { margin: 0 0 var(--sp-2); font-size: var(--fs-lg); }
.spinner {
  width: 22px; height: 22px; margin: 0 auto var(--sp-3);
  border: 2px solid var(--line-firm); border-top-color: var(--accent);
  border-radius: 50%; animation: spin .8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .spinner { animation-duration: 3s; }
  .btn, .entry-btn { transition: none; }
}

/* ------------------------------- brand ----------------------------------- */
.brand { display: flex; align-items: center; gap: .6em; }
/* The real Leumi mark, served from this bucket. Its own corners are already
   transparent and its badge is already rounded, so no background, no radius and
   no filter here — anything else would put a second badge behind the badge.
   Width and height are set in the markup too, so the header does not reflow
   while the PNG loads. */
.brand-mark {
  width: 2em; height: 2em; flex: none;
  object-fit: contain; display: block;
}
.brand-text { display: flex; flex-direction: column; line-height: 1.25; }
.brand-text small { color: var(--muted); font-size: var(--fs-xs); }
.brand--lg { margin-bottom: var(--sp-5); }
.brand--lg .brand-mark { width: 3rem; height: 3rem; }

/* ------------------------------- login ----------------------------------- */
.login {
  min-height: 100vh; display: grid; place-items: center; padding: var(--sp-5);
  background:
    radial-gradient(1200px 560px at 100% -15%, var(--accent-wash), transparent 62%),
    var(--paper);
}
/* This screen is the first thing six new editors see, so it states plainly
   whose system this is and who runs it, above the form rather than in fine
   print under it. The band is the only place the full brand gradient is used;
   text on it is white on #10069A-to-#0166FF, i.e. 4.8:1 at the lightest end. */
.login-card {
  width: 100%; max-width: 27rem;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); box-shadow: var(--shadow-md);
  overflow: hidden;
}
.login-band {
  background: var(--brand-band); color: var(--brand-on);
  padding: var(--sp-5) var(--sp-5) var(--sp-4);
  display: flex; align-items: center; gap: var(--sp-3);
}
.login-band .brand-mark {
  width: 3.25rem; height: 3.25rem;
  /* The mark's own badge is Leumi blue and would disappear into the gradient,
     so it sits on a white plate — the same way it appears on bank stationery. */
  background: #fff; border-radius: 12px; padding: 4px;
}
.login-band-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.login-band-org { font-size: var(--fs-lg); font-weight: 700; letter-spacing: .01em; }
.login-band-sys { font-size: var(--fs-sm); opacity: .92; }
.login-body { padding: var(--sp-5) var(--sp-5) var(--sp-6); }
.login-lede { color: var(--ink-soft); font-size: var(--fs-md); margin: 0 0 var(--sp-5); line-height: var(--lh-prose); }
.login-foot { color: var(--muted); font-size: var(--fs-sm); margin: var(--sp-5) 0 0; }
.newpass { border-top: 1px dashed var(--line-firm); margin-top: var(--sp-4); padding-top: var(--sp-4); }
.newpass-note { color: var(--warn); font-size: var(--fs-sm); margin: 0 0 var(--sp-3); }

/* ------------------------------- fields ---------------------------------- */
.field { display: block; margin-bottom: var(--sp-4); }
.field .label, .field > label.label {
  display: block; font-size: var(--fs-sm); font-weight: 600;
  color: var(--ink-soft); margin-bottom: var(--sp-1);
}
.field-hint { margin: var(--sp-1) 0 0; font-size: var(--fs-xs); }
input[type=text], input[type=email], input[type=password], input[type=search],
select, textarea {
  width: 100%; padding: .55em .7em;
  background: var(--surface); color: var(--ink);
  border: 1px solid var(--line-firm); border-radius: var(--r-sm);
  font: inherit;
}
textarea { resize: vertical; min-height: 4em; line-height: var(--lh-prose); }
input::placeholder, textarea::placeholder { color: var(--muted); }
input:disabled, textarea:disabled, select:disabled {
  background: var(--sunken); color: var(--ink-soft); cursor: not-allowed; border-style: dashed;
}
input.is-bad, textarea.is-bad { border-color: var(--danger); background: var(--danger-wash); }

.form-error {
  background: var(--danger-wash); border: 1px solid var(--danger);
  color: var(--danger); border-radius: var(--r-sm);
  padding: .6em .8em; margin: 0 0 var(--sp-4); font-size: var(--fs-md);
}

/* ------------------------------- topbar ---------------------------------- */
.app { min-height: 100vh; display: flex; flex-direction: column; }
.topbar {
  display: flex; align-items: center; gap: .7em; flex-wrap: wrap;
  min-height: var(--topbar-h);
  padding: var(--sp-2) var(--sp-4);
  background: var(--surface); border-bottom: 1px solid var(--line);
  position: sticky; top: 0; z-index: 20;
  /* The brand appears as a rule, not as a coloured band. A saturated header
     behind Hebrew UI text costs contrast all day for one second of
     recognition; the mark and this 3px edge carry it instead. */
  box-shadow: inset 0 3px 0 0 var(--accent);
}
.topbar .brand-text strong { font-size: var(--fs-md); }
.topbar .brand-org {
  color: var(--muted); font-size: var(--fs-2xs); letter-spacing: .02em;
}
.topbar-spacer { flex: 1; }
.whoami { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--fs-sm); }
.whoami-user { color: var(--ink-soft); max-width: 16rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.role-badge {
  padding: .18em .6em; border-radius: 999px; font-size: var(--fs-xs); font-weight: 700;
  white-space: nowrap;
  border: 1px solid transparent; letter-spacing: .01em;
}
.role-badge--editor { background: var(--accent-wash); color: var(--accent-hi); border-color: var(--accent); }
.role-badge--viewer { background: var(--sunken); color: var(--ink-soft); border-color: var(--line-firm); }

.pill { padding: .18em .6em; border-radius: 999px; font-size: var(--fs-xs); border: 1px solid var(--line-firm); white-space: nowrap; color: var(--muted); }
.pill--bad { color: var(--danger); border-color: var(--danger); background: var(--danger-wash); }
.pill--warn { color: var(--warn); border-color: var(--warn); background: var(--warn-wash); font-weight: 700; }

/* ------------------------------- banners --------------------------------- */
.banner-slot:empty { display: none; }
.banner {
  display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap;
  padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--line);
  background: var(--warn-wash); color: var(--ink);
}
.banner--conflict { background: var(--danger-wash); }
.banner strong { font-weight: 700; }

/* ------------------------------- layout ---------------------------------- */
.layout {
  flex: 1; display: grid;
  grid-template-columns: minmax(300px, 26rem) 1fr;
  min-height: 0;
}
.pane { min-width: 0; }
.pane--list {
  border-inline-end: 1px solid var(--line);
  background: var(--surface-2);
  display: flex; flex-direction: column;
  /* Tied to the topbar token rather than a magic 3.2em that no longer matched
     the header it was meant to clear. */
  max-height: calc(100vh - var(--topbar-h));
  position: sticky; top: var(--topbar-h);
}
.pane--detail { padding: var(--sp-5) var(--sp-5) var(--sp-6); min-height: 0; }

/* ------------------------------- list ------------------------------------ */
.list-head { padding: var(--sp-3) var(--sp-3) var(--sp-2); border-bottom: 1px solid var(--line); background: var(--surface-2); }
.search { position: relative; }
.search input { padding-inline-end: 2em; }
.search-clear {
  position: absolute; inset-inline-end: .35em; top: 50%; transform: translateY(-50%);
  background: none; border: 0; color: var(--muted); cursor: pointer; padding: .25em;
}
.filters { display: flex; flex-wrap: wrap; gap: var(--sp-1); margin-top: var(--sp-2); }
.chip {
  padding: .25em .7em; border-radius: 999px; font-size: var(--fs-sm);
  background: transparent; border: 1px solid var(--line-firm); color: var(--ink-soft);
  cursor: pointer;
}
.chip:hover { background: var(--sunken); }
.chip.is-on { background: var(--accent); border-color: var(--accent); color: var(--accent-on); font-weight: 600; }
.list-meta {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2);
  margin-top: var(--sp-3); color: var(--muted); font-size: var(--fs-sm);
}

.entry-list { list-style: none; margin: 0; padding: var(--sp-1); overflow-y: auto; flex: 1; }
.entry-item { margin-bottom: var(--sp-1); }
.entry-btn {
  width: 100%; text-align: start; cursor: pointer;
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-md); padding: var(--sp-2) var(--sp-3);
  display: grid; gap: var(--sp-1);
  border-inline-start: 3px solid var(--line-firm);
  transition: border-color .12s, box-shadow .12s, background .12s;
}
.entry-btn:hover { border-color: var(--line-firm); box-shadow: var(--shadow-sm); }
.entry-btn.is-published { border-inline-start-color: var(--ok); }
.entry-btn.is-draft { border-inline-start-color: var(--warn); }
.entry-btn.is-active { background: var(--accent-wash); border-color: var(--accent); }

.entry-top { display: flex; align-items: baseline; gap: var(--sp-2); }
.entry-id { font-family: var(--mono); font-size: var(--fs-md); font-weight: 600; color: var(--ink); }
.entry-cat { color: var(--muted); font-size: var(--fs-xs); }
/* The gloss is a Hebrew sentence, always. Ten of the thirty-four live answers
   open with a Latin error string, and `dir="auto"` turned those rows into
   left-to-right paragraphs that read from the wrong edge. The element is
   dir="rtl" in the markup; this makes it a real isolate so the row's own
   direction can neither leak out nor be inherited away. */
.entry-gloss {
  direction: rtl;
  unicode-bidi: isolate;
  text-align: start;
  color: var(--ink-soft); font-size: var(--fs-md);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.entry-foot { display: flex; align-items: center; gap: var(--sp-1); flex-wrap: wrap; font-size: var(--fs-xs); color: var(--muted); }

.tag {
  padding: .1em .5em; border-radius: 999px; border: 1px solid var(--line-firm);
  font-size: 1em; white-space: nowrap;
}
/* --ok was #1a7f43: 4.44 against --ok-wash, i.e. below AA on the pill a
   reviewer scans hardest. Now 5.21. */
.tag--published { background: var(--ok-wash); color: var(--ok); border-color: var(--ok); font-weight: 700; }
.tag--draft { background: var(--warn-wash); color: var(--warn); border-color: var(--warn); font-weight: 700; }
.tag--err { background: var(--accent-wash); color: var(--accent-hi); border-color: var(--accent); }
.tag--img { background: var(--sunken); color: var(--ink-soft); }
.tag--stale { color: var(--warn); border-color: var(--warn); }

.empty { color: var(--muted); text-align: center; padding: var(--sp-6) var(--sp-4); }

/* ------------------------------- detail ---------------------------------- */
.detail-head { display: flex; align-items: flex-start; gap: var(--sp-3); flex-wrap: wrap; margin-bottom: var(--sp-4); }
.detail-title { margin: 0; font-size: var(--fs-xl); }
.detail-title bdi { font-family: var(--mono); }
.detail-actions { display: flex; gap: var(--sp-1); margin-inline-start: auto; flex-wrap: wrap; }

.card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--r-lg); padding: var(--sp-4) var(--sp-4);
  margin-bottom: var(--sp-4);
  box-shadow: var(--shadow-sm);
}
.card > h3 {
  margin: 0 0 var(--sp-3); font-size: var(--fs-xs); text-transform: uppercase;
  letter-spacing: .06em; color: var(--muted); font-weight: 700;
}
.card--accent { border-inline-start: 3px solid var(--accent); }

.kv { display: grid; grid-template-columns: max-content 1fr; gap: var(--sp-1) var(--sp-4); font-size: var(--fs-md); }
.kv dt { color: var(--muted); }
/* `source` and `verified_against` are provenance prose, not a token: let them
   wrap over as many lines as they need. */
.kv dd { margin: 0; overflow-wrap: anywhere; }

.chiplist { display: flex; flex-wrap: wrap; gap: var(--sp-1); margin: 0; padding: 0; }
.chiplist li {
  list-style: none; padding: .2em .6em; border-radius: var(--r-sm);
  background: var(--sunken); border: 1px solid var(--line);
  font-size: var(--fs-md); max-width: 100%; overflow-wrap: anywhere;
}
.chiplist--err li { background: var(--code-bg); font-family: var(--mono); font-size: var(--fs-sm); color: var(--code-ink); }
.envs-boxes { margin-top: var(--sp-2); }

/* --------------------- WhatsApp answer preview --------------------------- */
/* The bot sends KB text verbatim, so this block is the product surface. Each
   line is its own RTL paragraph — that mirrors the RIGHT-TO-LEFT MARK the brain
   prepends per line — and every code span is direction-isolated so the
   punctuation around it stays where the author typed it. */
.wa {
  background: #d9fdd3; color: #111b21;
  border-radius: 12px 12px 12px 4px;
  padding: .7em .85em; margin: 0;
  max-width: 34rem; box-shadow: var(--shadow-sm);
  border: 1px solid rgba(0,0,0,.06);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .wa { background: #005c4b; color: #e9edef; border-color: rgba(255,255,255,.07); }
  :root:not([data-theme="light"]) .wa code { background: rgba(0,0,0,.28); color: #d7f5ee; }
  :root:not([data-theme="light"]) .wa .wa-marks { color: #ffc9c2; }
  :root:not([data-theme="light"]) .wa .wa-star { background: rgba(255,120,110,.25); color: #ffd9d5; }
}
:root[data-theme="dark"] .wa { background: #005c4b; color: #e9edef; border-color: rgba(255,255,255,.07); }
:root[data-theme="dark"] .wa code { background: rgba(0,0,0,.28); color: #d7f5ee; }
:root[data-theme="dark"] .wa .wa-marks { color: #ffc9c2; }
:root[data-theme="dark"] .wa .wa-star { background: rgba(255,120,110,.25); color: #ffd9d5; }

.wa-frame { display: flex; }
.wa-line { direction: rtl; unicode-bidi: isolate; min-height: 1.55em; overflow-wrap: anywhere; }
.wa-line--blank { min-height: .7em; }
.wa code {
  font-family: var(--mono); font-size: .88em;
  background: rgba(0,0,0,.07); border-radius: 4px; padding: .05em .35em;
  unicode-bidi: isolate; direction: ltr;
  /* A 50-character Windows path has to be allowed to break somewhere, or it
     pushes the whole bubble — and the page — sideways. Short tokens are held
     together by `.tok` below instead. */
  overflow-wrap: anywhere; hyphens: none;
}
/* One token of a command, kept whole: a hyphen inside it is not a place to
   break. `word-break: keep-all` does not deliver this in Chrome — nowrap on the
   token does, and the spaces between tokens stay breakable. */
.wa code .tok { white-space: nowrap; }
.wa-header { font-weight: 700; }
.wa-marks { color: #9a1b12; font-family: var(--mono); font-size: var(--fs-xs); opacity: .9; }
/* A `*` that survived bold matching is one WhatsApp will print. Show it. */
.wa-star {
  background: rgba(180,35,24,.14); color: #8f1c12;
  border-radius: 3px; font-weight: 700; padding: 0 .1em;
}
.wa-warn {
  margin: 0 0 var(--sp-3); padding: .5em .7em;
  background: var(--warn-wash); border: 1px solid var(--warn);
  border-radius: var(--r-sm); color: var(--ink); font-size: var(--fs-sm);
  line-height: var(--lh-body);
}
.preview-bar { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; margin-bottom: var(--sp-3); }
.preview-bar label { font-size: var(--fs-sm); color: var(--ink-soft); display: flex; align-items: center; gap: var(--sp-1); }
.preview-bar input[type=checkbox] { width: auto; }

/* ------------------------------- editor ---------------------------------- */
/* The one interaction that matters most: typing `answer_he` while watching the
   preview. Two columns, answer field first, preview sticky beside it — the old
   stack (preview, then metadata, then the answer field) made it impossible to
   see both at once. */
.editor-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(17rem, 22rem);
  gap: var(--sp-4);
  align-items: start;
}
.editor-side { position: sticky; top: calc(var(--topbar-h) + var(--sp-3)); }
.editor-side .card { margin-bottom: 0; }
.editor-side .wa { max-width: 100%; }

.grid2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); gap: 0 var(--sp-4); }

.rows { display: grid; gap: var(--sp-2); margin: 0; padding: 0; list-style: none; }
.row { display: flex; gap: var(--sp-2); align-items: flex-start; }
.row-n {
  flex: 0 0 auto; min-width: 1.4em; text-align: center;
  color: var(--muted); font-size: var(--fs-xs); font-family: var(--mono);
  padding-top: .6em;
}
.row-body { flex: 1; min-width: 0; }
.row-tools { display: flex; gap: var(--sp-1); align-items: flex-start; }
.row input, .row textarea { width: 100%; }
.rows-foot { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; margin-top: var(--sp-3); }

.counter { font-size: var(--fs-2xs); color: var(--muted); text-align: end; }
.counter.is-over { color: var(--danger); font-weight: 700; }
.field-error { color: var(--danger); font-size: var(--fs-sm); margin: var(--sp-1) 0 0; }

.errbox {
  background: var(--danger-wash); border: 1px solid var(--danger); color: var(--danger);
  border-radius: var(--r-sm); padding: .6em .8em; margin-bottom: var(--sp-4); font-size: var(--fs-md);
}
.errbox ul { margin: var(--sp-1) 0 0; padding-inline-start: 1.2em; }

.editor-foot {
  position: sticky; bottom: 0; background: var(--surface);
  border-top: 1px solid var(--line); padding: var(--sp-3) 0 var(--sp-1);
  display: flex; gap: var(--sp-2); align-items: center; flex-wrap: wrap;
  z-index: 6;
}
.editor-foot .spacer { flex: 1; }

/* The byte budget for the whole request. It lives beside the save button
   because it is what gates it: the network filter drops any body at or over
   8192 bytes, and Hebrew spends two bytes a character. */
.budget { min-width: 13rem; display: grid; gap: 3px; }
.budget-label { font-size: var(--fs-xs); color: var(--ink-soft); }
.budget-label strong { color: var(--danger); }
.budget-track { height: 4px; background: var(--sunken); border-radius: 999px; overflow: hidden; }
.budget-track > i { display: block; height: 100%; width: 0; background: var(--ok); transition: width .15s; }
.budget.is-near .budget-track > i { background: var(--warn); }
.budget.is-over .budget-track > i { background: var(--danger); }
.budget.is-over .budget-label { color: var(--danger); }
/* The save button still works — pressing it is how you get the explanation —
   but it stops looking like the happy path. */
.btn--warned { background: var(--warn); border-color: var(--warn); color: var(--paper); }

/* ------------------------------- images ---------------------------------- */
.dropzone {
  border: 2px dashed var(--line-firm); border-radius: var(--r-md);
  padding: var(--sp-5); text-align: center; color: var(--muted);
  background: var(--surface-2); cursor: pointer;
}
.dropzone.is-hot { border-color: var(--accent); background: var(--accent-wash); color: var(--accent-hi); }
.thumbs { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin-top: var(--sp-3); }
.thumb {
  width: 11rem; border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--surface); overflow: hidden;
}
.thumb-img {
  height: 6.5rem; background: var(--sunken); display: grid; place-items: center;
  overflow: hidden; color: var(--muted); font-size: var(--fs-2xs); text-align: center;
  padding: var(--sp-1); gap: 2px;
}
.thumb-img img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* An attachment whose presigned URL never arrived says so, in words. A broken
   image icon reads as a bug in the console. */
.thumb-img.is-failed { background: var(--danger-wash); color: var(--danger); }
.thumb-fail-mark { font-size: 1.1rem; line-height: 1; }
.thumb-fail { line-height: 1.35; }
.thumb-wait { color: var(--muted); }
.thumb-body { padding: var(--sp-2); display: grid; gap: var(--sp-1); }
.thumb-cap { font-size: var(--fs-sm); }
.thumb-key { font-family: var(--mono); font-size: var(--fs-2xs); color: var(--muted); }
/* A media key is 60+ characters in an 11rem card: it has to be allowed to break
   anywhere, unlike the command tokens above. */
.thumb-key, .thumb-key .mono { overflow-wrap: anywhere; word-break: break-all; }
.upload-line { width: 11rem; }
.progress { height: 4px; background: var(--sunken); border-radius: 999px; overflow: hidden; }
.progress > i { display: block; height: 100%; background: var(--accent); width: 0; transition: width .15s; }

/* ------------------------------- audit ----------------------------------- */
.audit { display: grid; gap: var(--sp-2); }
.audit-row { border: 1px solid var(--line); border-radius: var(--r-md); background: var(--surface-2); }
.audit-row > summary { cursor: pointer; padding: var(--sp-2) var(--sp-3); display: flex; gap: var(--sp-2); align-items: center; flex-wrap: wrap; font-size: var(--fs-md); }
.audit-row > summary::marker { color: var(--muted); }
.audit-act { font-weight: 700; }
.audit-act--create { color: var(--accent-hi); }
.audit-act--update { color: var(--ink-soft); }
.audit-act--publish { color: var(--ok); }
.audit-act--unpublish, .audit-act--delete { color: var(--danger); }
.audit-ts { color: var(--muted); font-family: var(--mono); font-size: var(--fs-xs); }

/* "Who changed what" was a JSON.stringify dump in a left-to-right <pre>:
   escaped Hebrew, no field names, every value on the wrong edge. It is a real
   per-field before/after list now. */
.diff { border-top: 1px solid var(--line); padding: var(--sp-3); display: grid; gap: var(--sp-3); }
.diff-field { border: 1px solid var(--line); border-radius: var(--r-md); background: var(--surface); padding: var(--sp-2) var(--sp-3); }
.diff-name { margin: 0 0 var(--sp-2); font-size: var(--fs-sm); font-weight: 700; color: var(--ink); }
.diff-name .mono { color: var(--muted); font-weight: 400; }
.diff-sides { display: grid; grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); gap: var(--sp-2); }
.diff-side { border-radius: var(--r-sm); padding: var(--sp-2); background: var(--sunken); border: 1px solid var(--line); min-width: 0; }
.diff-side--was { background: var(--danger-wash); border-color: color-mix(in srgb, var(--danger) 25%, transparent); }
.diff-side--now { background: var(--ok-wash); border-color: color-mix(in srgb, var(--ok) 30%, transparent); }
.diff-side-label { font-size: var(--fs-2xs); font-weight: 700; letter-spacing: .04em; color: var(--ink-soft); margin-bottom: var(--sp-1); text-transform: uppercase; }
.diff-body {
  unicode-bidi: isolate;
  white-space: pre-wrap; overflow-wrap: anywhere;
  font-size: var(--fs-md); line-height: var(--lh-body); color: var(--ink);
}
.diff-body.is-latin { font-family: var(--mono); font-size: var(--fs-sm); }
.diff-body.is-clamped { max-height: 6.2em; overflow: hidden; mask-image: linear-gradient(to bottom, #000 70%, transparent); }
.diff-list { margin: 0; padding-inline-start: 1.1em; display: grid; gap: 2px; }
.diff-list li { overflow-wrap: anywhere; font-size: var(--fs-md); }
.diff-list .mono { font-size: var(--fs-sm); }
.diff-nil { color: var(--muted); font-size: var(--fs-sm); }
.diff-tally { margin: var(--sp-2) 0 0; font-size: var(--fs-2xs); }
.diff-empty { padding: var(--sp-3); margin: 0; border-top: 1px solid var(--line); }
.audit-raw {
  margin: 0; padding: .6em .8em; background: var(--code-bg); color: var(--code-ink);
  font-family: var(--mono); font-size: var(--fs-xs); overflow-x: auto;
  direction: ltr; text-align: left; border-top: 1px solid var(--line);
}

/* ------------------------------- toasts ---------------------------------- */
.toasts {
  position: fixed; inset-block-end: var(--sp-4); inset-inline-start: var(--sp-4);
  display: grid; gap: var(--sp-2); z-index: 60; max-width: 26rem;
}
.toast {
  background: var(--surface); border: 1px solid var(--line-firm);
  border-inline-start: 3px solid var(--accent);
  border-radius: var(--r-md); padding: .6em .8em; box-shadow: var(--shadow-md);
  font-size: var(--fs-md);
}
.toast--bad { border-inline-start-color: var(--danger); }
.toast--ok { border-inline-start-color: var(--ok); }

/* ------------------------------- responsive ------------------------------ */
/* The date field is typed, not picked: the contract stores YYYY-MM-DD and a
   native date widget shows a locale format (07/09/2026) that is ambiguous to a
   reviewer. */
.date-row { display: flex; gap: var(--sp-1); align-items: center; }
.date-row input { flex: 1; }

/* One column below this width, and the preview pins itself to the top of the
   scroll instead of sitting beside the form — so the answer field and the
   preview are still on screen together. */
/* ----------------------- active filter chip bar --------------------------
   A filter that hides rows has to be visible next to the rows it is hiding and
   undoable in one click. The `is-on` state on the filter buttons was not
   enough: with all 34 entries published, one click on "טיוטה" emptied the list,
   and an empty list reads as lost data, not as an active filter. */
.active-filters {
  display: flex; flex-wrap: wrap; gap: var(--sp-1); align-items: center;
  margin-top: var(--sp-2);
}
.active-filters:empty { display: none; }

/* A load failure or a partial load sits WITH the list, not in a toast that
   vanishes after five seconds, and carries its own retry. */
.list-alert { margin-top: var(--sp-2); display: grid; gap: var(--sp-2); justify-items: start; font-size: var(--fs-sm); }
.list-alert:empty { display: none; }
.list-alert.is-bad { color: var(--danger); }
.list-alert.is-warn { color: var(--warn); }
.list-alert p { margin: 0; line-height: var(--lh-body); }
.active-filters-lede {
  font-size: var(--fs-2xs); font-weight: 700; color: var(--warn);
  width: 100%; margin-bottom: 2px;
}
.chip--active-filter {
  background: var(--warn-wash); border-color: var(--warn); color: var(--warn);
  font-weight: 600; max-width: 100%; overflow: hidden;
  display: inline-flex; align-items: center; gap: .35em;
}
.chip--active-filter:hover { background: var(--danger-wash); border-color: var(--danger); color: var(--danger); }
.chip-x { font-size: .9em; opacity: .8; }

.empty-filters { list-style: none; margin: var(--sp-2) 0; padding: 0; display: grid; gap: var(--sp-1); justify-items: center; }
.empty-filters li {
  font-size: var(--fs-sm); background: var(--warn-wash); color: var(--warn);
  border: 1px solid var(--warn); border-radius: var(--r-sm); padding: .15em .6em;
}

/* ------------------------------ field help -------------------------------
   Per-field `i`. A real button with aria-expanded and a sibling paragraph, not
   a `title` tooltip: a tooltip cannot be reached from the keyboard, does not
   exist on touch, and is truncated by the OS at roughly the length where this
   help starts to be worth reading. */
.help-i {
  appearance: none; margin-inline-start: .45em; width: 1.15em; height: 1.15em;
  padding: 0; border: 1px solid var(--line-firm); border-radius: 999px;
  background: var(--surface); color: var(--accent-hi);
  font-family: var(--mono); font-size: var(--fs-2xs); font-weight: 700;
  line-height: 1; cursor: pointer; vertical-align: middle;
}
.help-i:hover { background: var(--accent-wash); border-color: var(--accent); }
.help-i.is-open { background: var(--accent); border-color: var(--accent); color: var(--accent-on); }
.field-help {
  margin: var(--sp-1) 0 var(--sp-2);
  background: var(--accent-wash); border-inline-start: 3px solid var(--accent);
  border-radius: var(--r-sm); padding: .55em .7em;
  font-size: var(--fs-sm); line-height: var(--lh-prose); color: var(--ink-soft);
}
.card > h3 .help-i { vertical-align: baseline; }

/* --------------------------- progressive folds ---------------------------
   The verbosity stays — the owner values it — it just stops arriving all at
   once. Required core open, provenance and the optional English fields shut. */
.fold { padding: 0; overflow: hidden; }
.fold > summary {
  cursor: pointer; padding: var(--sp-3) var(--sp-4);
  display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--sp-2);
  background: var(--surface-2);
}
.fold[open] > summary { border-bottom: 1px solid var(--line); }
.fold > summary:hover { background: var(--accent-wash); }
/* `display: flex` on a <summary> makes Chrome drop the disclosure triangle
   altogether, so a collapsed card looked like a card and not like something you
   can open — which would have hidden the provenance fields rather than
   deferring them. Explicit chevron, and the native marker suppressed so there
   is never a second one in Firefox. It points the RTL way: down when open,
   towards the start of the line when shut. */
.fold > summary { list-style: none; }
.fold > summary::-webkit-details-marker { display: none; }
.fold > summary::marker { content: ''; }
.fold-chev {
  flex: none; color: var(--accent-hi); font-size: .8em;
  transition: transform .12s ease;
}
@media (prefers-reduced-motion: reduce) { .fold-chev { transition: none; } }
.fold[open] > summary .fold-chev { transform: rotate(-90deg); }
.fold-title {
  font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: .06em;
  color: var(--ink-soft); font-weight: 700;
}
.fold-lede { color: var(--muted); font-size: var(--fs-sm); font-weight: 400; }
.fold-body { padding: var(--sp-4); }
.fold-body > .field:last-child, .fold-body > .card:last-child { margin-bottom: 0; }
.kv--ro { margin-top: var(--sp-3); padding-top: var(--sp-3); border-top: 1px solid var(--line); }

/* ------------------------------- steps ----------------------------------- */
.step-h { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.step-n {
  display: grid; place-items: center; flex: none;
  width: 1.55em; height: 1.55em; border-radius: 999px;
  background: var(--accent); color: var(--accent-on);
  font-size: var(--fs-xs); font-weight: 700; font-family: var(--mono);
  text-transform: none; letter-spacing: 0;
}
.step-field { color: var(--muted); font-weight: 400; }

/* --------------------------- new-entry guide ------------------------------
   Replaces the blank 17-field form as the first thing a new case shows: the
   five things that make an entry the bot can use, ticking themselves as they
   are filled, each pointing at the numbered step that fills it. */
.card--guide { border-inline-start: 3px solid var(--accent); background: var(--surface-2); }
.guide { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--sp-1); }
.guide-item {
  display: flex; align-items: baseline; gap: var(--sp-2);
  padding: .3em .55em; border-radius: var(--r-sm);
  background: var(--surface); border: 1px solid var(--line);
  font-size: var(--fs-md);
}
.guide-item.is-done { background: var(--ok-wash); border-color: color-mix(in srgb, var(--ok) 35%, transparent); }
.guide-mark { font-weight: 700; color: var(--muted); flex: none; width: 1em; text-align: center; }
.guide-item.is-done .guide-mark { color: var(--ok); }
.guide-label { flex: 1; min-width: 0; }
.guide-step {
  font-size: var(--fs-2xs); color: var(--muted); font-weight: 700;
  white-space: nowrap;
}
.guide-tally { margin-top: var(--sp-1); font-size: var(--fs-sm); color: var(--ink-soft); font-weight: 600; }

@media (max-width: 1200px) {
  .editor-grid { grid-template-columns: 1fr; }
  .editor-side {
    order: -1; position: sticky; top: var(--topbar-h); z-index: 5;
    max-height: 48vh; overflow: auto;
    background: var(--paper); padding-bottom: var(--sp-2);
  }
}
@media (max-width: 900px) {
  .layout { grid-template-columns: 1fr; }
  .pane--list {
    position: static; max-height: none;
    border-inline-end: 0; border-bottom: 1px solid var(--line);
  }
  .pane--list.is-collapsed { display: none; }
  .entry-list { max-height: 55vh; }
  .whoami-user { display: none; }
  .pane--detail { padding: var(--sp-4) var(--sp-3) var(--sp-6); }
  .editor-side { top: 0; }
}
@media (min-width: 901px) {
  .back-to-list { display: none !important; }
}
