/* BayRen Office (the admin panel; folder: BayRen Control Center) — admin theme. Self-hosted. */
/* ── The hidden attribute always wins ──────────────────────────────────────
 * A rule that sets `display:` silently BEATS `hidden`, so an element the code
 * has hidden stays on screen. It is not theoretical: it once froze the Speaking
 * test (a button hidden during "Get ready" was still clickable — see the inline
 * guard at the top of templates/exam/speaking.html), and it left "Audio is
 * Playing" on screen through the sound check, which says nothing is running.
 * Guarding one class at a time only works until the next one, so guard the
 * attribute itself. */
[hidden] { display: none !important; }

/* Self-hosted Inter — the admin named Inter but shipped no font file, so it was
   silently rendering in the OS system font. These @font-face rules (the same
   woff2 the practice apps use) make the panel actually render in the brand type. */
@font-face{font-family:'Inter';font-style:normal;font-weight:300;font-display:swap;src:url('../fonts/inter-v20-latin-300.woff2') format('woff2')}
@font-face{font-family:'Inter';font-style:normal;font-weight:400;font-display:swap;src:url('../fonts/inter-v20-latin-regular.woff2') format('woff2')}
@font-face{font-family:'Inter';font-style:normal;font-weight:500;font-display:swap;src:url('../fonts/inter-v20-latin-500.woff2') format('woff2')}
@font-face{font-family:'Inter';font-style:normal;font-weight:600;font-display:swap;src:url('../fonts/inter-v20-latin-600.woff2') format('woff2')}
@font-face{font-family:'Inter';font-style:normal;font-weight:700;font-display:swap;src:url('../fonts/inter-v20-latin-700.woff2') format('woff2')}
:root{
  --navy:#0B2A49; --navy-800:#08203a; --navy-900:#061626;
  --gold:#D8B04C; --gold-600:#c6a03c; --gold-50:#faf4e1;
  --ink:#1c2733; --body:#41505f; --muted:#6b7888; --line:#e7ebf1;
  --bg:#f4f7fb; --card:#ffffff; --white:#fff;
  --ok:#1f9d55; --ok-bg:#e8f6ee; --warn:#b7791f; --warn-bg:#fbf3e2;
  --danger:#c0392b; --danger-bg:#fdecea; --info-bg:#eaf1fb;
  --radius:14px; --radius-sm:9px; --shadow:0 10px 30px rgba(11,42,73,.08);
  --shadow-sm:0 2px 8px rgba(11,42,73,.06);
  --sans:'Inter',system-ui,-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;
  /* One spacing scale. Before this, spacing was typed into style="" attributes
     as 10px/12px/14px/16px/18px — and the CSP (style-src 'self') threw every
     one of them away, so none of it ever reached the screen. Classes now, and
     five steps instead of five arbitrary numbers. */
  --sp-1:6px; --sp-2:10px; --sp-3:14px; --sp-4:18px; --sp-5:24px;
  /* The frame, in ONE place (17 Sep 2026). The bar's height was written as 62
     in eight rules and in admin.js; change one and the sidebar, the sticky
     column names and the bulk bar gap or overlap. Everything reads these. */
  --topbar-h:52px; --sidenav-w:184px;
}
*,*::before,*::after{box-sizing:border-box}*{margin:0}
body{font-family:var(--sans);background:var(--bg);color:var(--body);line-height:1.45;font-size:14px;-webkit-font-smoothing:antialiased}
/* The desktop got denser on 17 Sep 2026 (14px type, 8px fields and buttons).
   A touch screen keeps what it had — the 15px reading size here, and fields and
   buttons a thumb can hit right after their own rules below. Each restore sits
   straight after the rule it restores, so a later, more particular rule
   (.filters select, .stage-form .btn…) still wins on a phone as it did.
   820px, not 700: that is where the hamburger layout starts, and an iPad held
   upright (768/810) got the touch menu with the desktop's small controls. */
@media (max-width:820px){body{font-size:15px;line-height:1.55}}
a{color:inherit;text-decoration:none}
.wrap{width:100%;max-width:1240px;margin-inline:auto;padding-inline:24px}
/* The sign-in screens stay narrow — a login form 1240px wide is absurd. The
   work pages inside the shell take more (.shell main.wrap, below): a CRM list
   has eight columns, and on a laptop every pixel of width is a column that
   does not wrap. */

/* ---- Top bar (brand, menu switch and search — navigation lives in the sidebar) ---- */
.topbar{background:linear-gradient(90deg,var(--navy),var(--navy-800));color:#fff;box-shadow:var(--shadow-sm);position:sticky;top:0;z-index:30}
.topbar .bar{display:flex;align-items:center;gap:8px;height:var(--topbar-h);padding-inline:10px 20px}
/* The switch and the name take the sidebar's width, so the search box starts
   where the page does. */
.bar-start{display:flex;align-items:center;gap:6px;flex:0 0 calc(var(--sidenav-w) - 10px);min-width:0}
.brand{display:flex;align-items:baseline;gap:10px}
.brand-mark{font-size:1.25rem;font-weight:800;letter-spacing:.01em;color:#fff}
.brand-mark b{color:var(--gold);font-weight:800}
.brand-sub{font-size:.7rem;text-transform:uppercase;letter-spacing:.18em;color:var(--gold-50);opacity:.8}
.nav-toggle{display:none;background:none;border:none;color:#fff;padding:8px;cursor:pointer;border-radius:8px;margin-left:auto}
.nav-toggle:hover{background:rgba(255,255,255,.1)}
.nav-toggle .icon{width:24px;height:24px;display:block}
/* Hide menu (desktop): the sidebar folds away entirely and the page takes its
   room. The choice is a cookie base.html reads, so the page arrives already
   folded — nothing jumps after it paints. */
.nav-hide{display:inline-flex;align-items:center;justify-content:center;flex:none;width:34px;height:34px;
  background:none;border:none;color:inherit;border-radius:8px;cursor:pointer;padding:0}
.nav-hide:hover{background:rgba(255,255,255,.1)}
.nav-hide .icon{width:20px;height:20px;display:block}
/* With the menu hidden its badges are hidden too, so the owed total rides on
   the Show menu button (its label says what the number is). */
.nav-hide{position:relative}
.nav-hide-count{display:none;position:absolute;top:-2px;right:-4px;min-width:17px;height:17px;padding:0 4px;
  border-radius:999px;background:var(--amber-solid,#8a660f);color:#fff;font-size:.68rem;font-weight:700;
  align-items:center;justify-content:center;line-height:1;font-variant-numeric:tabular-nums}
body.nav-hidden .nav-hide-count{display:inline-flex}

/* ---- The shell: grouped sidebar + the page ---- */
.shell{display:flex;align-items:stretch;min-height:calc(100vh - var(--topbar-h))}
.sidenav{flex:0 0 var(--sidenav-w);width:var(--sidenav-w);background:linear-gradient(180deg,var(--navy),var(--navy-900));
  color:#cdd8e6;padding:10px 8px 12px;display:flex;flex-direction:column;gap:1px;
  position:sticky;top:var(--topbar-h);height:calc(100vh - var(--topbar-h));overflow-y:auto}
.sn-group{font-size:.66rem;text-transform:uppercase;letter-spacing:.14em;
  color:#8ea2b8;font-weight:700;margin:16px 10px 6px}
/* Groups without a heading are told apart by a hairline, not a caption. */
.sn-sep{height:1px;background:rgba(255,255,255,.08);margin:7px 8px}
.sn-link{display:flex;align-items:center;gap:9px;padding:7px 10px;border-radius:10px;
  font-weight:600;font-size:.9rem;color:#cdd8e6;transition:background .2s,color .2s}
.sn-link>span:first-of-type{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sn-link .icon{width:18px;height:18px;flex:none;opacity:.85}
.sn-link:hover{background:rgba(255,255,255,.08);color:#fff}
.sn-link.on{background:var(--gold);color:var(--navy)}
.sn-link.on .icon{opacity:1}
.sn-foot{margin-top:auto;padding-top:14px;border-top:1px solid rgba(255,255,255,.08)}
.sn-foot .sn-link{color:#9fb0c4}
.backdrop{display:none}
main.wrap{padding-top:26px;padding-bottom:60px}
.shell main.wrap{flex:1;min-width:0;max-width:1480px;padding-inline:20px;padding-top:16px}
/* "More": the business pages, folded. Open when you are on one of them. */
details.sn-more>summary{list-style:none;cursor:pointer;user-select:none}
details.sn-more>summary::-webkit-details-marker{display:none}
details.sn-more .sn-chev{width:14px;height:14px;margin-left:auto;opacity:.7;transition:transform .15s}
details.sn-more[open] .sn-chev{transform:rotate(180deg)}
.sn-more-list{display:flex;flex-direction:column;gap:1px;padding-left:8px}
@media (min-width:821px){
  body.nav-hidden .sidenav{display:none}
}
/* A short laptop screen (1366x620 once the browser's own bars are drawn):
   with More open the menu was 633px in a 568px column, so Activity sat on the
   cut and Sign out was off screen. Shorter rows there, mouse-sized — a touch
   screen (820px and under) keeps its 40px rows. */
@media (min-width:821px) and (max-height:700px){
  .sn-link{padding:5px 10px}
  .sn-sep{margin:4px 8px}
  .sn-foot{padding-top:6px}
}

/* ---- Flash ---- */
.flashes{display:flex;flex-direction:column;gap:10px;margin-bottom:20px}
.flash{padding:12px 16px;border-radius:var(--radius-sm);font-weight:600;font-size:.92rem;border:1px solid transparent}
.flash--ok{background:var(--ok-bg);color:var(--ok);border-color:#bfe6cf}
.flash--error,.flash--err{background:var(--danger-bg);color:var(--danger);border-color:#f5c6c0}
/* `err` is what 28 of the panel's flash() calls say; only `error` was styled,
   so those failures showed as a plain grey box (17 Sep 2026). */

/* ---- Auth screens ---- */
body.auth{display:grid;place-items:center;min-height:100vh;background:radial-gradient(1200px 600px at 50% -10%,rgba(216,176,76,.10),transparent 60%),var(--bg)}
body.auth main.wrap{max-width:430px;padding-top:0}
.auth-card{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);box-shadow:var(--shadow);padding:34px 30px}
.auth-logo{text-align:center;margin-bottom:6px}
.auth-logo .brand-mark{color:var(--navy);font-size:1.6rem;font-weight:800}
.auth-logo .brand-mark b{color:var(--gold-600)}
.auth-sub{text-align:center;color:var(--muted);font-size:.82rem;text-transform:uppercase;letter-spacing:.16em;margin-bottom:24px}
.auth-card h1{font-size:1.3rem;color:var(--ink);margin-bottom:6px;text-align:center}
.auth-card .lead{color:var(--muted);font-size:.92rem;text-align:center;margin-bottom:22px}
/* The sign-in pages keep the size they had before the desktop got denser
   (17 Sep 2026). Asaf put their look back on 4 Sep; the tighter type, fields
   and buttons are for the pages inside the menu frame, and on a laptop they
   had shrunk these too (fields 47px -> 38px). Scoped by body.auth, so they win
   over the plain rules below whatever the order. */
body.auth{font-size:15px;line-height:1.55}
body.auth input[type=text],body.auth input[type=email],body.auth input[type=password],body.auth textarea,body.auth select{padding:11px 13px}
body.auth .btn{padding:11px 20px}
body.auth .btn--sm{padding:7px 14px}

/* ---- Forms ---- */
label.field{display:block;margin-bottom:16px}
label.field .lab{display:block;font-weight:600;color:var(--ink);font-size:.86rem;margin-bottom:6px}
input[type=text],input[type=email],input[type=password],input[type=search],textarea,select{
  width:100%;padding:8px 11px;border:1px solid var(--line);border-radius:var(--radius-sm);
  font:inherit;color:var(--ink);background:#fff;transition:border-color .2s,box-shadow .2s}
@media (max-width:820px){
  input[type=text],input[type=email],input[type=password],input[type=search],textarea,select{padding:11px 13px}
}
/* A number box (a payment amount, a credit count) dresses like the boxes
   beside it — it was the browser's bare 21px box next to 38px capsules. */
input[type=number]{
  width:100%;padding:8px 11px;border:1px solid var(--line);border-radius:var(--radius-sm);
  font:inherit;color:var(--ink);background:#fff;transition:border-color .2s,box-shadow .2s}
@media (max-width:820px){
  input[type=number]{padding:11px 13px}
}
input:focus,textarea:focus,select:focus{outline:none;border-color:var(--gold);box-shadow:0 0 0 3px rgba(216,176,76,.2)}
.code-input{letter-spacing:.5em;text-align:center;font-size:1.5rem;font-weight:700;font-variant-numeric:tabular-nums}
.hint{color:var(--muted);font-size:.82rem;margin-top:6px}

/* ---- Buttons ---- */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;padding:8px 16px;border-radius:999px;font-weight:700;font-size:.92rem;cursor:pointer;border:1px solid transparent;transition:transform .15s,box-shadow .2s,background .2s,color .2s}
.btn:hover{transform:translateY(-1px)}
.btn--primary{background:var(--gold);color:var(--navy);box-shadow:var(--shadow-sm)}
.btn--primary:hover{background:var(--gold-600)}
.btn--navy{background:var(--navy);color:#fff}
.btn--navy:hover{background:var(--navy-800)}
.btn--block{width:100%}
.btn--sm{padding:5px 11px;font-size:.84rem}
/* A control that sits inside a table row: 28px high, so a row with a Stage
   dropdown or a small button is no taller than a row of plain text. */
.ctl-sm,select.ctl-sm,.btn.ctl-sm{height:28px;min-height:28px;padding:0 9px;font-size:.82rem;
  line-height:1;width:auto;border-radius:8px}
select.ctl-sm{padding-right:24px}
@media (max-width:820px){
  .btn{padding:11px 20px}
  .btn--sm{padding:7px 14px}
  .ctl-sm,select.ctl-sm,.btn.ctl-sm{height:auto;min-height:40px}
}
.btn--ok{background:var(--ok);color:#fff}
.btn--warn{background:var(--warn);color:#fff}
.btn--danger{background:var(--danger);color:#fff}
.btn--ghost{background:#fff;border-color:var(--line);color:var(--ink)}
.btn--ghost:hover{border-color:var(--gold);color:var(--gold-600)}
.btn[disabled]{opacity:.5;cursor:not-allowed;transform:none}

/* ---- Cards / layout ---- */
.page-head{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:14px;flex-wrap:wrap}
.page-head h1{font-size:1.3rem;color:var(--ink)}
.card{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);
  box-shadow:var(--shadow-sm);padding:16px 18px;margin-bottom:14px;
  /* min-width:0 lets a wide table SCROLL INSIDE its .table-scroll instead of
     stretching the card — and with it the whole page — off the screen. */
  min-width:0}
.card h2{font-size:1rem;color:var(--navy);margin-bottom:10px}

/* ---- Stat tiles ----
   These were a fixed six-column GRID, and almost no page has six numbers: two
   tiles sat marooned in a third of the row, four left two columns empty, and
   eight wrapped 6+2. Flex instead, so a row of tiles always fills its width
   whatever the page has to say. --4 and --5 pin the count where a page wants
   an exact shape (eight tiles as 4+4 rather than 6+2). */
.stats{display:flex;flex-wrap:wrap;gap:12px;margin-bottom:22px}
/* max-width stops the leftovers of a wrapped row from ballooning: nine tiles
   is six then three, not six then three half-page slabs. */
.stat{flex:1 1 150px;max-width:264px}
.stats--4>.stat{flex:1 1 calc(25% - 9px);max-width:none}
.stats--5>.stat{flex:1 1 calc(20% - 10px);max-width:none}
.stat{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);
  padding:12px;text-align:center;box-shadow:var(--shadow-sm)}
.stat b{display:block;font-size:1.4rem;font-weight:800;color:var(--navy);line-height:1}
.stat span{font-size:.74rem;text-transform:uppercase;letter-spacing:.08em;color:var(--muted);margin-top:6px;display:block}
.stat.is-pending b{color:var(--warn)}
.stat.is-blocked b{color:var(--danger)}
.stat a{display:block}

/* ---- Tables ---- */
.tbl{width:100%;border-collapse:collapse;font-size:.92rem}
.tbl th{text-align:left;font-size:.72rem;text-transform:uppercase;letter-spacing:.08em;
  color:var(--muted);padding:7px 10px;border-bottom:2px solid var(--line);white-space:nowrap}
.tbl td{padding:8px 10px;border-bottom:1px solid var(--line);vertical-align:middle}
.tbl tr:hover td{background:#fbfcfe}
.tbl .name{font-weight:600;color:var(--ink)}
.tbl .email{color:var(--muted);font-size:.85rem}
.table-scroll{overflow-x:auto;max-width:100%}

/* ── The column names stay on screen (12 Sep 2026) ────────────────────────
   Asaf: "as I scroll down make the name of the columns row stay on the
   screen." position:sticky pins to the nearest SCROLLING ancestor, and
   .table-scroll is one (overflow-x:auto makes an element a scroller on both
   axes) even when its table fits — so a sticky <th> inside it pinned to a box
   that never scrolls, i.e. to nothing. admin.js measures every table:
     · fits the card   → `data-fits`: the wrapper stops being a scroller and
                          the names pin to the page, under the top bar (and
                          under the bulk bar on People);
     · wider than it   → `data-tall`: the wrapper keeps its sideways scroll
                          and becomes a box as tall as the screen that scrolls
                          the rows itself, with the names pinned to its top.
   Either way the names stay put. A phone stacks rows into cards and hides the
   header (below), so there is nothing to pin there. */
.table-scroll[data-fits]{overflow:visible}
.table-scroll[data-tall]{max-height:calc(100vh - var(--stick-top,var(--topbar-h)) - 24px);overflow:auto}
.table-scroll .tbl thead th{position:sticky;top:var(--stick-top,var(--topbar-h));z-index:5;
  background:var(--card);box-shadow:0 2px 0 var(--line)}
.table-scroll[data-tall] .tbl thead th{top:0}
@media (max-width:700px){.table-scroll .tbl thead th{position:static;box-shadow:none}}

/* ── Tables become rows on a phone (7 Sep 2026) ────────────────────────────
   Asaf runs this business from his phone and said the panel "feels clumsy".
   Measured: 48 tables across 26 pages, every one scrolling sideways inside
   .table-scroll — so a person's NAME and their STATUS were never on screen at
   the same time. You scrolled right to read the status and lost whose it was.

   Under 700px each row becomes a card: the first cell is its title, and every
   other value sits beside its column's name. No template changed: admin.js
   copies each <th> into the cells under it and marks the table `data-rows`.
   Every rule below is gated on that attribute, so with JavaScript off — or on
   a table admin.js declined to label — the table is exactly what it is today.

   The desktop layout is untouched; this whole block is inside a media query. */
@media (max-width:700px){
  /* The scroller has nothing left to scroll, and while it is still a scroller
     it clips the card shadows and steals the horizontal drag from the page. */
  .table-scroll:has(> .tbl[data-rows]){overflow-x:visible}

  .tbl[data-rows]{display:block;font-size:.95rem}
  /* display:none, not the screen-reader-only trick. Clipped-but-positioned
     header cells keep their geometry, so every one of them was still measured
     hanging off the right edge of the phone — 19 of them across five pages.
     The column name is on each value now (data-label), so nothing is lost. */
  .tbl[data-rows] thead{display:none}
  .tbl[data-rows] tbody,.tbl[data-rows] tr{display:block}

  .tbl[data-rows] tbody tr{
    border:1px solid var(--line);border-radius:var(--radius-sm);
    background:var(--card);padding:12px 14px;margin:0 0 10px}
  .tbl[data-rows] tbody tr:hover td{background:transparent}
  .tbl[data-rows] tbody tr:last-child{margin-bottom:0}

  /* flex-wrap, and it is not decoration: a cell can hold more than one value
     — People's "What they are" is two badges separated by a <br>, and a <br>
     does nothing inside a flex row. At 360px the label plus both badges was
     6px too wide and put the whole card back into a sideways scroll. They wrap
     onto a second line now. overflow-wrap for the long email addresses. */
  .tbl[data-rows] td{display:flex;flex-wrap:wrap;align-items:baseline;gap:6px 12px;
    padding:5px 0;border:0;text-align:left;overflow-wrap:anywhere;min-width:0}
  .tbl[data-rows] td > *{max-width:100%}
  .tbl[data-rows] td::before{
    content:attr(data-label);flex:0 0 34%;min-width:0;
    font-size:.7rem;text-transform:uppercase;letter-spacing:.07em;
    font-weight:700;color:var(--muted);line-height:1.5;overflow-wrap:anywhere}
  .tbl[data-rows] td:not([data-label])::before{display:none}

  /* The name line: no label, bigger, and a rule under it — this is the card's
     heading, and it is the thing that was never visible beside the status. */
  .tbl[data-rows] td[data-first]{
    display:block;font-weight:700;font-size:1.02rem;color:var(--ink);
    padding:0 0 8px;margin-bottom:6px;border-bottom:1px solid var(--line)}
  .tbl[data-rows] td[data-first]::before{display:none}
  .tbl[data-rows] td[data-first] a{color:var(--navy)}

  /* An empty cell would otherwise be a labelled blank line on every card. */
  .tbl[data-rows] td:empty{display:none}

  /* An empty-state row ("Nobody yet") is a sentence, not a value. */
  .tbl[data-rows] td[data-span]{display:block;color:var(--muted);text-align:center;padding:6px 0}
  .tbl[data-rows] tbody tr:has(> td[data-span]){background:transparent;border-style:dashed}

  /* Actions get the full width and sit at the bottom, where a thumb is. */
  .tbl[data-rows] td.right,.tbl[data-rows] td.wa-cell,
  .tbl[data-rows] td:has(> .btn),.tbl[data-rows] td:has(> form){
    display:flex;flex-wrap:wrap;gap:8px;padding-top:10px;margin-top:4px;
    border-top:1px solid var(--line)}
  .tbl[data-rows] td.right::before,.tbl[data-rows] td.wa-cell::before,
  .tbl[data-rows] td:has(> .btn)::before,.tbl[data-rows] td:has(> form)::before{
    flex-basis:100%;margin-bottom:-4px}
  .tbl[data-rows] td .btn{min-height:40px;display:inline-flex;align-items:center}

  /* A checkbox column is a control, not a value: keep it on the name line. */
  .tbl[data-rows] td:has(> input[type=checkbox]){padding:0 0 6px}

  /* The card's title is the main tap target on the row, and it was 20px tall.
     Padding rather than a min-height so the line does not grow visibly. */
  .tbl[data-rows] td[data-first] a{display:inline-block;padding:9px 0;margin:-9px 0 -7px}

  /* ── Nothing under 12px on a phone ──────────────────────────────────────
     188 pieces of text measured under the floor across 21 pages, all of them
     labels: the sidebar's section headings at 10.6px, the label under every
     stat tile at 11.8px, the board counts and the section labels at 11.5px.
     Raised HERE, inside the phone query, so the desktop panel does not move a
     pixel — its type scale is Asaf's and was not what he complained about.
     All five classes are this panel's own (admin.css); no shared sheet moves
     for another app. */
}

/* :has() is everywhere that matters (Safari 15.4+, Chrome 105+, Firefox 121+),
   but a browser without it must not be left with a table that is half stacked.
   Everything above that :has() controls is decoration — the padding, the action
   row, the scroller — so an old browser gets plain stacked rows, which is still
   far better than sideways. */


/* ---- Status badges ---- */
.badge{display:inline-block;padding:3px 11px;border-radius:999px;font-size:.75rem;font-weight:700;text-transform:capitalize}
.badge--approved{background:var(--ok-bg);color:var(--ok)}
.badge--pending{background:var(--warn-bg);color:var(--warn)}
.badge--rejected{background:#eef1f4;color:var(--muted)}
.badge--blocked{background:var(--danger-bg);color:var(--danger)}
.badge--banned{background:#2b2b2b;color:#fff}

/* ---- View tabs ----
   The three ways of reading one list (List / Board / Due), after People,
   Pipeline and Follow-ups stopped being three sidebar entries. An underline,
   not a pill, so they never read as the filter chips sitting right below them. */
.viewtabs,.subtabs{display:flex;gap:4px;flex-wrap:wrap;align-items:flex-end;
  border-bottom:1px solid var(--line);margin:0 0 18px}
/* One menu entry, two pages (Mock tests: Sittings | Packages & credits). */
.subtabs{margin-bottom:14px}
.viewtab-count{font-size:.72rem;font-weight:700;padding:1px 7px;border-radius:999px;
  background:var(--tone-tint,#e6f3f5);color:var(--tone,#26737f)}
.viewtab-count--warn{background:var(--amber-tint,#fbf3e2);color:var(--amber-solid,#8a660f)}
.viewtab{padding:9px 16px;font-weight:600;font-size:.92rem;color:var(--muted);
  text-decoration:none;border-bottom:2px solid transparent;margin-bottom:-1px;
  display:inline-flex;align-items:center;gap:7px;border-radius:6px 6px 0 0}
.viewtab:hover{color:var(--navy);background:var(--wash,#f6f7f9)}
.viewtab.on{color:var(--navy);border-bottom-color:var(--navy)}
.viewtab:focus-visible{outline:2px solid var(--navy);outline-offset:-2px}

/* ---- Filters ---- */
.filters{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-bottom:18px}
.filters .chip{padding:7px 14px;border-radius:999px;border:1px solid var(--line);background:#fff;font-weight:600;font-size:.84rem;color:var(--body)}
.filters .chip.on{background:var(--navy);color:#fff;border-color:var(--navy)}
.filters form.search{margin-left:auto;display:flex;gap:8px;flex-wrap:wrap}
.filters form.search input{width:220px}

/* ---- Student detail ---- */
.detail-grid{display:grid;grid-template-columns:1.3fr 1fr;gap:20px;align-items:start}
.kv{display:grid;grid-template-columns:130px 1fr;gap:8px 14px;font-size:.92rem}
.kv dt{color:var(--muted);font-weight:600}
.kv dd{color:var(--ink);overflow-wrap:anywhere}
.action-row{display:flex;gap:8px;flex-wrap:wrap;margin-top:8px}
.reason-in{margin:12px 0}
.app-access{display:flex;flex-direction:column;gap:10px}
.app-row{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px;border:1px solid var(--line);border-radius:var(--radius-sm)}
.app-row .an{font-weight:600;color:var(--ink)}
.app-row .meta{font-size:.78rem;color:var(--muted)}
.seg{display:inline-flex;border:1px solid var(--line);border-radius:999px;overflow:hidden;background:#fff}
.seg button{padding:6px 13px;font-size:.82rem;font-weight:600;color:var(--body);background:#fff;border:none;cursor:pointer}
.seg button.on{background:var(--navy);color:#fff}
.seg button.on.grant{background:var(--ok)}
.seg button.on.deny{background:var(--danger)}
.pill-on{color:var(--ok);font-weight:700}.pill-off{color:var(--danger);font-weight:700}

.reset-pw{background:var(--gold-50);border:1px dashed var(--gold);border-radius:var(--radius-sm);padding:14px;text-align:center;margin-bottom:16px}
.reset-pw code{font-size:1.15rem;font-weight:800;color:var(--navy);letter-spacing:.02em}

/* ---- Setup key box ---- */
.keybox{background:var(--navy);color:#fff;border-radius:var(--radius-sm);padding:16px;text-align:center;margin:14px 0}
.keybox .k{font-size:1.15rem;font-weight:800;letter-spacing:.14em;color:var(--gold);word-break:break-all}
.steps{counter-reset:s;list-style:none;margin:16px 0;display:flex;flex-direction:column;gap:10px}
.steps li{position:relative;padding-left:34px;font-size:.9rem}
.steps li::before{counter-increment:s;content:counter(s);position:absolute;left:0;top:-2px;width:24px;height:24px;border-radius:50%;background:var(--gold);color:var(--navy);font-weight:800;display:grid;place-items:center;font-size:.8rem}

.audit-list{font-size:.88rem}
.audit-list td{font-variant-numeric:tabular-nums}
.mono{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.8rem;color:var(--muted);
  /* A database path or a long address has no spaces to break at, and on a phone
     one of them dragged the whole page sideways. */
  overflow-wrap:anywhere}
.tbl .email{overflow-wrap:anywhere}
.empty{text-align:center;color:var(--muted);padding:40px 20px}

.error-page{text-align:center;padding:80px 20px}
.error-page .code{font-size:4rem;font-weight:800;color:var(--navy)}

/* ---- Spacing utilities ----
   The page sends a strict Content-Security-Policy with no 'unsafe-inline', so a
   style="" attribute is DISCARDED by the browser. Classes, not inline styles. */
.hint--below{margin-bottom:14px}
.hint--above{margin-top:14px}
.hint--spaced{margin-top:12px}
.btn--inlined{margin-left:8px}
.right{text-align:right}
.sec-label{font-size:.72rem;text-transform:uppercase;letter-spacing:.08em;
  color:var(--muted);font-weight:700;margin:18px 0 8px}

/* ---- Dashboard: five headline tiles + folded detail ---- */
.stats--5{grid-template-columns:repeat(5,1fr)}
.queue-more{margin:14px 0 0}
details.fold{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);
  box-shadow:var(--shadow-sm);padding:0 24px;margin-bottom:20px}
details.fold summary{cursor:pointer;padding:16px 0;font-weight:700;color:var(--navy);
  font-size:.95rem;list-style:none}
details.fold summary::-webkit-details-marker{display:none}
details.fold summary::before{content:"▸";display:inline-block;margin-right:8px;
  color:var(--gold-600);transition:transform .15s}
details.fold[open] summary::before{transform:rotate(90deg)}
details.fold[open]{padding-bottom:18px}

/* ---- Tags (the CRM's categories) ---- */
.tag-chips{display:flex;gap:6px;flex-wrap:wrap;margin-bottom:12px}
.tag-chip-form{display:inline}
.tag-chip{display:inline-flex;align-items:center;gap:6px;padding:4px 6px 4px 11px;
  border-radius:999px;background:var(--info-bg);color:#2c5b9c;font-size:.8rem;font-weight:700}
.tag-x{background:none;border:none;color:inherit;cursor:pointer;font-size:1rem;
  line-height:1;padding:0 4px;border-radius:50%;opacity:.6}
.tag-x:hover{opacity:1;background:rgba(44,91,156,.15)}
.tag-minis{display:inline-flex;gap:4px;flex-wrap:wrap;margin-left:6px;vertical-align:middle}
.tag-mini{display:inline-block;padding:1px 8px;border-radius:999px;background:var(--info-bg);
  color:#2c5b9c;font-size:.7rem;font-weight:700}
.tag-mini:hover{background:#d7e5f7}
.chip-clear{font-weight:800;margin-left:4px}

/* ---- Mock credits ---- */
/* Classes, never style="" — the CSP (style-src 'self') discards inline styles. */
.qty{max-width:110px;flex:0 0 110px}
.inline-form{display:inline}
.credits-now{font-size:1.02rem;color:var(--ink);margin-bottom:10px}
.credits-now b{font-size:1.5rem;color:var(--navy);font-weight:800}

/* ---- Students list extras ---- */
.wa-cell{white-space:nowrap}
.wa-cell .btn + .btn{margin-left:6px}
.pager{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding-top:14px;flex-wrap:wrap}
.filters select{width:auto;padding:8px 10px;font-size:.86rem}

/* ---- Per-app pills on the students list ---- */
.pills{display:inline-flex;gap:4px;flex-wrap:wrap}
.pill{display:inline-grid;place-items:center;width:26px;height:22px;border-radius:6px;
      background:#eef1f4;color:var(--muted);font-size:.68rem;font-weight:800;
      text-transform:uppercase;letter-spacing:.02em}
.pill--on{background:var(--ok-bg);color:var(--ok)}

/* ---- Apps page ---- */
.app-row-actions{display:flex;align-items:center;gap:10px;flex-wrap:wrap;justify-content:flex-end}
.row--idle td{opacity:.62}

/* ---- Set-a-password / single-field forms ---- */
.pw-form{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-bottom:10px}
/* A form whose field is a box of several lines (the AI keys). */
.pw-form--stack{align-items:flex-start;flex-wrap:wrap}
.pw-form--stack textarea{flex:1 1 100%;min-width:0;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.85rem;line-height:1.5}

.pw-form input{flex:1 1 260px}
form.is-busy{opacity:.55;pointer-events:none}

/* ---- Toasts: confirmation without reloading the page ---- */
.toasts{position:fixed;right:20px;bottom:20px;display:flex;flex-direction:column;
        gap:8px;z-index:60;pointer-events:none}
.toast{background:var(--navy);color:#fff;padding:11px 18px;border-radius:999px;
       font-weight:600;font-size:.88rem;box-shadow:var(--shadow);
       transition:opacity .35s,transform .35s}
.toast--error{background:var(--danger)}
.toast--warn{background:var(--warn)}
.toast--out{opacity:0;transform:translateY(6px)}
@media (prefers-reduced-motion:reduce){.toast{transition:none}}

@media (max-width:820px){
  .stats--4>.stat,.stats--5>.stat{flex:1 1 140px}
  .detail-grid{grid-template-columns:1fr}
  .brand-sub{display:none}
  /* The sidebar slides in over the page; the hamburger in the top bar opens it. */
  .nav-toggle{display:block}
  .nav-hide{display:none}
  .bar-start{flex:0 1 auto}
  /* The desktop's tighter menu rows are too short for a thumb. */
  .sn-link{padding:10px 12px}
  .sidenav{position:fixed;left:0;top:var(--topbar-h);bottom:0;height:auto;width:246px;z-index:40;
    transform:translateX(-100%);transition:transform .2s ease;box-shadow:var(--shadow)}
  body.nav-open .sidenav{transform:translateX(0)}
  body.nav-open .backdrop{display:block;position:fixed;inset:var(--topbar-h) 0 0 0;
    background:rgba(6,22,38,.45);z-index:35}
}
@media (prefers-reduced-motion:reduce){.sidenav{transition:none}}
@media (max-width:520px){
  .stat,.stats--4>.stat,.stats--5>.stat{flex:1 1 132px}
  .filters form.search{margin-left:0;width:100%}
  .filters form.search input{width:100%}
  .filters form.search select{flex:1 1 128px;width:auto}
  .filters form.search .btn{flex:1 1 100%}
}

/* ── Writing submissions view (read-only essays + feedback) ──────────────── */
.head-actions{display:flex;gap:8px;align-items:center;flex-wrap:wrap}

/* Status + error-type badges (reuse .badge base) */
.badge--graded{background:var(--info-bg);color:#2c5b9c}
.badge--published{background:var(--ok-bg);color:var(--ok)}
.badge--revision{background:#fff1e6;color:#b5651d}
.badge--grammar{background:#fde8e8;color:#c0392b}
.badge--spelling{background:#fff6d6;color:#b7791f}
.badge--vocabulary{background:#e2eefb;color:#2c5b9c}
.badge--other{background:#efe6fb;color:#6b3fa0}

.sub-meta{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:10px 24px}
.sub-meta .k{display:block;font-size:.7rem;text-transform:uppercase;letter-spacing:.07em;color:var(--muted);margin-bottom:2px}
.note-card{background:#fff1e6;border-left:4px solid #b5651d;color:#7a4410}

.score-row{display:flex;gap:24px;align-items:center;flex-wrap:wrap}
.score-big{font-size:2.6rem;font-weight:800;color:var(--ink);line-height:1;display:flex;flex-direction:column;align-items:center}
.score-big span{font-size:.68rem;font-weight:600;text-transform:uppercase;letter-spacing:.07em;color:var(--muted);margin-top:4px}
.score-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:10px;flex:1}
.score-grid div{background:var(--bg);border:1px solid var(--line);border-radius:10px;padding:10px 12px}
.score-grid b{font-size:1.3rem;color:var(--ink)}
.score-grid span{display:block;font-size:.75rem;color:var(--muted)}

.wr-feedback{white-space:pre-wrap;line-height:1.6}
.wr-task-img{max-width:100%;max-height:60vh;border:1px solid var(--line);border-radius:10px;background:#fff}

.wr-essay{white-space:pre-wrap;line-height:1.8;font-size:.98rem;color:var(--body)}
.wr-err{border-radius:3px;padding:0 2px;cursor:help}
.wr-err-grammar{background:#fde8e8;border-bottom:2px solid #d45555}
.wr-err-spelling{background:#fff6d6;border-bottom:2px solid #c8960a}
.wr-err-vocabulary{background:#ddeeff;border-bottom:2px solid #3d82c4}
.wr-err-other{background:#ecdeff;border-bottom:2px solid #7a44c4}

.wr-anns{margin:0;padding-left:1.2rem;display:flex;flex-direction:column;gap:12px}
.wr-anns li{line-height:1.5}
.wr-anns s{color:var(--danger)}
.wr-corrected{white-space:pre-wrap;line-height:1.8;background:var(--bg);border:1px solid var(--line);border-radius:10px;padding:14px 16px}

/* ---- Switch: a checkbox with its label beside it, not stretched ---- */
.switch{display:flex;align-items:center;gap:10px;margin:0 0 12px;cursor:pointer;
  font-size:.92rem;color:var(--ink)}
.switch input[type=checkbox]{width:18px;height:18px;flex:none;margin:0;accent-color:var(--navy);cursor:pointer}
.switch span{font-weight:600}
label.field .hint{margin-top:6px;display:block}

/* Add-a-lead form on the Leads screen. Collapsed by default so the list stays
   the point of the page; opened, it is a plain two-column grid. */
.add-lead>summary{cursor:pointer;font-size:.95rem;color:var(--ink);list-style:none}
.add-lead>summary::-webkit-details-marker{display:none}
.add-lead>summary::before{content:"+ ";font-weight:700;color:var(--gold-600)}
.add-lead[open]>summary::before{content:"– "}
.add-lead[open]>summary{margin-bottom:10px}
/* Arriving at #add (the top search's "Add … as a new person"): land below the
   sticky bulk bar, not under it. */
.add-lead{scroll-margin-top:calc(var(--topbar-h) + 76px)}
.form-grid{display:grid;grid-template-columns:1fr 1fr;gap:14px 18px;margin-top:14px}
.form-grid label{display:block;font-weight:600;color:var(--ink);font-size:.86rem}
.form-grid label .hint{font-weight:400}
.form-grid input,.form-grid select,.form-grid textarea{width:100%;margin-top:5px;font-weight:400}
.form-grid .wide{grid-column:1 / -1}
@media (max-width:720px){.form-grid{grid-template-columns:1fr}}

/* ═══ The mock marking desk ═══════════════════════════════════════════════
   Classes, never style="" — the CSP (style-src 'self') discards inline
   styles, so anything written that way simply never reaches the page. */

/* A band a student is waiting for, on the sittings list. */
.band-cell{font-size:1.05rem;color:var(--navy)}
.band-owed{color:var(--warn);font-weight:700}

/* The result as it stands: one big overall band, four sections beside it. */
.band-board{display:grid;grid-template-columns:158px 1fr;gap:20px 28px;align-items:start}
.band-overall{text-align:center;background:var(--navy);color:#fff;border-radius:var(--radius);
  padding:18px 16px}
.band-overall b{display:block;font-size:2.8rem;font-weight:800;line-height:1;color:var(--gold)}
.band-overall span{font-size:.68rem;text-transform:uppercase;letter-spacing:.1em;
  color:var(--gold-50);opacity:.85;margin-top:6px;display:block}
.band-sections{display:grid;grid-template-columns:repeat(4,1fr);gap:10px}
.band-tile{background:var(--bg);border:1px solid var(--line);border-radius:var(--radius-sm);
  padding:12px;text-align:center}
.band-tile b{display:block;font-size:1.5rem;font-weight:800;color:var(--ink);line-height:1}
.band-tile span{display:block;font-size:.78rem;font-weight:600;color:var(--body);margin-top:5px}
.band-tile em{display:block;font-style:normal;font-size:.72rem;color:var(--muted);
  margin-top:3px;line-height:1.35}
.band-tile--owed{border-color:#e6cf95;background:var(--warn-bg)}
.band-tile--owed b{color:var(--warn)}
.band-meta{grid-column:1 / -1;grid-template-columns:120px 1fr 120px 1fr}
/* Notes under the board span it; without this they are trapped in the narrow
   first column beside the overall band and read as a column of two words. */
.band-note{grid-column:1 / -1;margin-top:4px}

/* One task or one skill being marked. */
.mark-block{border:1px solid var(--line);border-radius:var(--radius);padding:18px 20px;
  margin-bottom:16px;background:#fdfefe}
.mark-block:last-of-type{margin-bottom:0}
.mark-head{display:flex;align-items:flex-start;justify-content:space-between;gap:18px;
  margin-bottom:14px;flex-wrap:wrap}
.mark-head h3{font-size:1rem;color:var(--navy)}
.mark-head .hint{margin-top:0}
.mark-lead{flex:1 1 320px}
.mark-band{text-align:center;flex:none}
.mark-band b{display:block;font-size:1.9rem;font-weight:800;color:var(--navy);line-height:1}
.mark-band span{display:block;font-size:.7rem;text-transform:uppercase;letter-spacing:.06em;
  color:var(--muted);margin-top:4px}

/* The four criteria: a grid for Writing, a row-per-criterion for Speaking
   (which carries a note the student reads beside each score). */
.crit-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));
  gap:12px 16px;margin-bottom:14px;
  /* Bottom-aligned, so "Grammatical range & accuracy" wrapping to two lines
     does not drop its dropdown below the row it belongs to. */
  align-items:end}
.crit-grid label,.crit-row label{display:block;font-weight:600;color:var(--ink);font-size:.86rem}
.crit-grid select,.crit-row select,.crit-row input{margin-top:5px;font-weight:400}
.crit-grid .hint{font-weight:400}
.crit-row{display:grid;grid-template-columns:minmax(210px,1fr) 2fr;gap:12px 16px;
  margin-bottom:12px;align-items:start}
.crit-row .crit-score select{width:100%}

/* The AI's draft — visible, and never applied on its own. */
.ai-draft{background:var(--info-bg);border-left:3px solid #2c5b9c;color:#2c5b9c;
  border-radius:var(--radius-sm);padding:10px 14px;font-size:.86rem;margin-bottom:16px}
.ai-draft b{margin-right:6px}
.ai-draft .hint{display:block;margin-top:2px}

/* A fold nested inside a card (the essay text), so it doesn't look like a card. */
details.fold--inline{border:none;box-shadow:none;background:transparent;padding:0;
  margin:14px 0 0;border-top:1px solid var(--line)}
details.fold--inline summary{padding:12px 0 8px;font-size:.88rem}
details.fold--inline[open]{padding-bottom:0}

@media (max-width:820px){
  .band-board{grid-template-columns:1fr}
  .band-sections{grid-template-columns:repeat(2,1fr)}
  .band-meta{grid-template-columns:104px 1fr}
  .crit-row{grid-template-columns:1fr}
}

/* ═══ CRM ═════════════════════════════════════════════════════════════════ */

/* People: the "what they are" column, and the inline stage mover. */
.who-cell .badge + .badge{margin-left:4px}
.stage-form{display:inline-flex;gap:5px;align-items:center;flex-wrap:nowrap}
.stage-form select{width:auto;min-width:104px;padding:6px 7px;font-size:.82rem}
.stage-form .btn{padding:6px 10px;font-size:.78rem}
/* Lost needs a reason: the picker sits on its own line under a row's stage
   and Move (never widening the column), and beside the bulk bar's stage. It
   shows only while Lost is picked; a browser without :has() always shows it —
   a reason it cannot hide still saves. */
.stage-form--why{display:inline-grid;grid-template-columns:auto auto;justify-content:start}
.stage-form--why select.lost-why{grid-row:2;grid-column:1 / -1;width:0;min-width:100%}
@supports selector(:has(*)){
  .stage-form .lost-why,.bulkbar .lost-why{display:none}
  .stage-form:has(select[name=stage] option[value=Lost]:checked) .lost-why,
  .bulkbar:has(select[name=new_stage] option[value=Lost]:checked) .lost-why{display:block}
}
/* The source a person came from: a fact, not a status. As a .badge it was
   title-cased into "Added By Hand", which reads like a label somebody chose. */
.src{font-size:.82rem;color:var(--body)}
.who-facts{white-space:nowrap}
/* Dates and short facts that must not be broken across three lines. */
.nowrap{white-space:nowrap}

/* Pipeline: the six stages side by side. Scrolls horizontally rather than
   squeezing six unreadable columns onto a phone. */
.board{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(184px,1fr);
  gap:12px;overflow-x:auto;padding-bottom:8px;margin-bottom:20px;align-items:start}
.board-col{background:var(--bg);border:1px solid var(--line);border-radius:var(--radius);
  padding:12px;min-height:120px}
.board-head{display:flex;align-items:center;justify-content:space-between;gap:8px;
  margin-bottom:10px}
.board-head h2{font-size:.82rem;text-transform:uppercase;letter-spacing:.08em;
  color:var(--muted);margin:0}
.board-count{background:var(--navy);color:#fff;border-radius:999px;font-size:.72rem;
  font-weight:800;padding:2px 9px;min-width:24px;text-align:center}
.board-col--lost .board-count{background:var(--muted)}
.board-col--paying .board-count{background:var(--ok)}
.board-card{background:var(--card);border:1px solid var(--line);border-radius:var(--radius-sm);
  padding:11px 12px;margin-bottom:8px;box-shadow:var(--shadow-sm)}
.board-card:last-child{margin-bottom:0}
.board-name{font-weight:700;color:var(--ink);font-size:.92rem}
.board-meta{font-size:.78rem;color:var(--muted);margin-top:2px}
.board-late{color:var(--danger);font-weight:700}
.board-due{color:var(--warn);font-weight:700}
.board-action{font-size:.82rem;color:var(--body);margin-top:6px}
.board-foot{display:flex;gap:6px;flex-wrap:wrap;align-items:center;margin-top:9px}
.board-foot .stage-form select{font-size:.78rem;padding:5px 7px}
/* A Board column is 184px and leaves a card 132px, but a 104px picker beside
   Move needs 163px: once everyone could be moved (17 Sep 2026) Move hung off
   every card. On a card the form fills the foot, Move drops under the picker
   when the pair does not fit, and "Why lost?" takes a line of its own. */
.board-foot .stage-form{display:flex;flex-wrap:wrap;width:100%}
.board-foot .stage-form select{flex:1 1 104px;min-width:0}
.board-foot .stage-form select.lost-why{flex-basis:100%;width:auto}
.board-empty{color:var(--muted);font-size:.82rem;text-align:center;padding:14px 0}


/* ═══ Spacing + small layout utilities ════════════════════════════════════
   These exist because a style="" attribute is DISCARDED by this panel's
   Content-Security-Policy (style-src 'self'). Anything laid out inline was
   silently not laid out at all. Never reach for style="" here. */
.mt-1{margin-top:var(--sp-1)}.mt-2{margin-top:var(--sp-2)}.mt-3{margin-top:var(--sp-3)}
.mt-4{margin-top:var(--sp-4)}.mt-5{margin-top:var(--sp-5)}
.mb-1{margin-bottom:var(--sp-1)}.mb-2{margin-bottom:var(--sp-2)}.mb-3{margin-bottom:var(--sp-3)}
.mb-4{margin-bottom:var(--sp-4)}.mb-5{margin-bottom:var(--sp-5)}
.center{text-align:center}
.row-wrap{display:flex;flex-wrap:wrap;gap:8px;align-items:center}
.w-sm{max-width:8rem}
.w-md{max-width:220px}
.eyebrow{font-size:.72rem;text-transform:uppercase;letter-spacing:.12em;opacity:.7;
  margin-bottom:var(--sp-1)}

/* ═══ Tabs (the student page) ═════════════════════════════════════════════
   Real links, one URL each, server-rendered. No JavaScript, so they work with
   scripting off and the strict CSP has nothing to object to. */
.tabs{display:flex;gap:2px;flex-wrap:wrap;margin-bottom:20px;
  border-bottom:1px solid var(--line)}
.tab{padding:10px 16px;font-weight:600;font-size:.92rem;color:var(--muted);
  border-bottom:2px solid transparent;margin-bottom:-1px;border-radius:8px 8px 0 0;
  transition:color .15s,border-color .15s,background .15s}
.tab:hover{color:var(--ink);background:rgba(11,42,73,.04)}
.tab.on{color:var(--navy);border-bottom-color:var(--gold);background:var(--card)}
@media (max-width:520px){.tab{padding:9px 12px;font-size:.86rem}}

/* ═══ The person timeline (lead page + student Overview) ══════════════════
   One list, newest first: enquiry, stage moves, notes, messages, payments.
   The note form posts inline (data-inline) and the whole card is the swapped
   fragment, so everything here must style by class — never style="". */
.tl-form{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:14px}
.tl-form input[type=text]{flex:1;min-width:180px}
.timeline{list-style:none;margin:0;padding:0}
.tl-item{display:flex;gap:12px;padding:7px 0;border-bottom:1px solid var(--line);
  font-size:.9rem;align-items:baseline}
.tl-item:last-child{border-bottom:0}
.tl-when{color:var(--muted);font-size:.78rem;white-space:nowrap}
.tl-words{flex:1;min-width:0;overflow-wrap:anywhere}
.tl--note .tl-words{color:var(--ink)}
.tl--stage .tl-words,.tl--enquiry .tl-words,.tl--student .tl-words{color:var(--muted)}
.tl--payment .tl-words{color:var(--navy);font-weight:600}

/* ═══ Bulk actions bar (the People list) ══════════════════════════════════
   Sticks just under the topbar (--topbar-h) so the buttons stay in reach while
   scrolling a long list. Checkboxes live in the table and point here via
   form="bulk-form". */
.bulkbar{position:sticky;top:var(--topbar-h);z-index:20;display:flex;align-items:center;
  gap:10px;flex-wrap:wrap;background:var(--card);border:1px solid var(--line);
  border-radius:10px;padding:10px 14px;margin-bottom:14px;box-shadow:var(--shadow-sm)}
.bulk-count{font-weight:600;font-size:.88rem;color:var(--navy)}
.bulk-all{display:flex;align-items:center;gap:6px;font-size:.85rem;
  color:var(--muted);white-space:nowrap}
.bulkbar select,.bulkbar input[type=text]{font-size:.85rem;padding:6px 8px;
  width:auto;max-width:200px}
.tbl td.sel,.tbl th.sel{width:28px;padding-right:0}
.tbl .sel input{width:16px;height:16px;accent-color:var(--navy)}
@media (max-width:700px){.bulkbar{position:static}}

/* ═══ Saved views (segments) on the People list ═══════════════════════════ */
.segbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:14px}
.seg-chip{display:inline-flex;align-items:center;gap:2px}
.seg-chip form{display:inline-flex}
.seg-x{border:0;background:none;color:var(--muted);font-size:1rem;line-height:1;
  cursor:pointer;padding:2px 4px;border-radius:4px}
.seg-x:hover{color:var(--danger,#B3352C);background:rgba(179,53,44,.08)}
.seg-save{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-left:auto}
.seg-save input[type=text]{font-size:.85rem;padding:6px 8px}

/* ═══ Campaigns ═══════════════════════════════════════════════════════════ */
.camp-progress{width:100%;height:10px;accent-color:var(--navy);margin:6px 0 10px}
.camp-mini{display:inline-flex;gap:6px;margin-left:6px}
.tg-mark{display:inline-block;font-size:.72rem;font-weight:700;color:#1d7fc4;
  letter-spacing:.02em}

/* ═══ Topbar search + sidebar counts ══════════════════════════════════════ */
.topsearch{display:flex;align-items:center;flex:1;max-width:520px;margin:0 16px 0 12px;position:relative}
.topsearch input{flex:1;min-width:0;background:rgba(255,255,255,.12);border:1px solid
  rgba(255,255,255,.25);border-radius:8px 0 0 8px;color:#fff;padding:7px 10px;
  font-size:.88rem}
.topsearch input::placeholder{color:rgba(255,255,255,.55)}
.topsearch input:focus{outline:2px solid var(--gold,#C9A227);background:rgba(255,255,255,.18)}
.topsearch-go{border:1px solid rgba(255,255,255,.25);border-left:0;background:rgba(255,255,255,.12);
  color:#fff;border-radius:0 8px 8px 0;padding:6px 10px;cursor:pointer;display:flex;align-items:center}
.topsearch-go svg{width:16px;height:16px}
@media (max-width:640px){.topsearch{max-width:none;margin:0 8px}}
.sn-count{margin-left:auto;background:var(--navy,#16406B);color:#fff;font-size:.72rem;
  font-weight:700;border-radius:999px;min-width:20px;height:20px;display:inline-flex;
  align-items:center;justify-content:center;padding:0 6px;
  font-variant-numeric:tabular-nums}
/* Two badges on one entry (Mock tests: to mark · waiting to buy). The first
   takes the push to the right; the second sits beside it. */
.sn-count + .sn-count{margin-left:3px}

/* ── Matches while you type (17 Sep 2026) ──────────────────────────────────
   The same /search URL answers a background call with just this list. */
.topsearch-pop{position:absolute;left:0;right:0;top:calc(100% + 6px);z-index:70;
  background:var(--card,#fff);border:1px solid var(--line);border-radius:12px;padding:6px;
  box-shadow:var(--d-shadow,0 10px 30px rgba(11,42,73,.14));color:var(--ink);
  max-height:min(440px,calc(100vh - var(--topbar-h) - 24px));overflow-y:auto}
.topsearch-list{display:flex;flex-direction:column;gap:1px}
.ta-item{display:flex;align-items:center;gap:10px;padding:6px 8px;border-radius:9px;color:var(--ink);
  text-decoration:none;cursor:pointer}
.ta-item:hover,.ta-item[aria-selected="true"]{background:var(--tone-tint,#e6f3f5)}
.ta-disc{flex:none;width:28px;height:28px;border-radius:50%;display:grid;place-items:center;
  font-weight:800;font-size:.8rem;background:var(--tone-tint,#e6f3f5);color:var(--tone,#26737f);
  border:1px solid var(--tone-edge,transparent)}
.ta-words{min-width:0;flex:1;display:flex;flex-direction:column;line-height:1.3}
.ta-name{font-weight:600;font-size:.9rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ta-meta{font-size:.78rem;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* The disc takes the row's colour (br-cycle); the kind keeps a fixed one, so
   Student and Lead read the same on every row. */
.ta-kind{flex:none;font-size:.72rem;font-weight:700;padding:2px 8px;border-radius:999px}
.ta-kind--student{background:var(--teal-tint,#e6f3f5);color:var(--teal-solid,#26737f)}
.ta-kind--lead{background:var(--amber-tint,#fbf3e2);color:var(--amber-solid,#8a660f)}
/* An account that is not simply approved says so in colour: waiting approval
   orange, blocked / banned / rejected rose. */
.ta-kind--wait{background:var(--orange-tint,#fdf1e8);color:var(--orange-solid,#a8551f)}
.ta-kind--stop{background:var(--rose-tint,#fdeef2);color:var(--rose-solid,#bf4156)}
.ta-empty{padding:10px;color:var(--muted);font-size:.86rem}
.ta-all{display:block;margin-top:4px;padding:8px 10px;border-top:1px solid var(--line);
  font-size:.84rem;font-weight:600;color:var(--tone,#26737f)}
.ta-all:hover{text-decoration:underline}
/* A phone's search box is narrow; its list takes the width of the screen. */
@media (max-width:640px){
  .topsearch-pop{position:fixed;left:8px;right:8px;top:calc(var(--topbar-h) + 4px);
    max-height:calc(100vh - var(--topbar-h) - 16px)}
  /* Thumb-sized: every row and link 40px or more (the chips keep the 12px
     floor below). The phone pass measures pages with this list closed, so
     test_office_search measures it open. */
  .ta-item{padding:9px 8px}
  .ta-all{padding:11px 10px;min-height:40px}
}


/* ============================================================================
   THE CAPSULE-AND-TABLET SKIN  (4 September 2026)

   Asaf: capsules and tablets, a white page, soft colour, and no more leading
   with gold and navy. See BayRen Platform/docs/design-system.md.

   The panel keeps its own stylesheet and all of its class names. This block
   re-points admin.css's token names at the design system, so the 46 rules that
   ask for var(--navy) or var(--gold) follow without being rewritten, and then
   names the eleven that carry a literal.

   THE CACHE, checked rather than assumed. The rollout notes said this site had
   no cache busting, so a restyle would sit invisible behind the browser cache.
   That is out of date: `@app.url_defaults` in app.py already stamps every
   static URL with the file's mtime, and the live pages serve
   `admin.css?v=1788512992`. Adding a second mechanism produced a URL with two
   query strings, so it was taken back out.
   ============================================================================ */

body.br-skin {
  /* ── Ground and ink ────────────────────────────────────────────────────── */
  --bg: var(--d-ground);   --card: var(--d-ground);
  --ink: var(--d-ink);     --body: var(--d-muted);   --muted: var(--d-muted);
  --line: var(--d-line);

  /* ── Brand: gold retired, navy kept as the ink ─────────────────────────── */
  --navy: var(--d-ink);    --navy-800: #0f1f30;      --navy-900: #0a1622;
  --gold: var(--tone);     --gold-600: var(--tone);  --gold-50: var(--tone-tint);

  /* ── Signals. From the --d- names: this sheet declares --ok, --warn and
     --danger itself, and `--ok: var(--ok)` is a cycle the browser drops. ──── */
  --ok: var(--d-correct);      --ok-bg: var(--d-correct-bg);
  --warn: var(--d-warn);       --warn-bg: var(--d-warn-bg);
  --danger: var(--d-wrong);    --danger-bg: var(--d-wrong-bg);
  --info-bg: var(--d-info-bg);

  /* ── Shape and depth: ONE shadow ───────────────────────────────────────── */
  --radius: var(--d-r-tablet);  --radius-sm: var(--d-r-input);
  --shadow: var(--d-shadow);
  --shadow-sm: none;

  background: var(--d-ground);
}

/* ── The top bar: white with a hairline, like every other app ─────────────── */
body.br-skin .topbar {
  background: var(--d-ground);
  color: var(--d-ink);
  border-bottom: 1px solid var(--d-line);
  box-shadow: none;
}
body.br-skin .brand-mark { color: var(--d-ink); }
/* The wordmark's second half stays amber everywhere. The logo does not change. */
body.br-skin .brand-mark b { color: var(--amber-solid); }
body.br-skin .brand-sub { color: var(--d-muted); opacity: 1; }
body.br-skin .nav-toggle,
body.br-skin .nav-hide { color: var(--d-ink); }
body.br-skin .nav-toggle:hover,
body.br-skin .nav-hide:hover { background: var(--d-sunken); }
/* The search box was drawn for the old navy bar — white text on a 12% white
   fill — and on the white bar it was invisible (17 Sep 2026). */
body.br-skin .topsearch input { background: var(--d-sunken); border-color: var(--d-line); color: var(--d-ink); }
body.br-skin .topsearch input::placeholder { color: var(--d-muted); }
body.br-skin .topsearch-go { background: var(--d-sunken); border-color: var(--d-line); color: var(--d-muted); }
body.br-skin .topsearch-go:hover { color: var(--d-ink); }

/* ── The sidebar: a sunken panel, not a navy column ────────────────────────
   Kept visibly separate from the page — an admin sidebar that blends into the
   content is worse than one that is too dark — but in the system's own sunken
   grey rather than a black slab, with ink type and a hairline. */
body.br-skin .sidenav {
  background: var(--d-sunken);
  color: var(--d-muted);
  border-right: 1px solid var(--d-line);
}
body.br-skin .sn-link { color: var(--d-muted); }
body.br-skin .sn-link:hover { background: var(--d-ground); color: var(--d-ink); }
body.br-skin .sn-link.on { background: var(--tone-tint); color: var(--tone); }
/* `.sn-group`, not `.sn-group-label` — the class I guessed at did not exist,
   so the group headings stayed pale-on-pale at 2.44:1. --d-muted, not
   --d-faint: these are small uppercase labels, and faint is documented for
   large text only. */
body.br-skin .sn-group { color: var(--d-muted); }
body.br-skin .sn-count { background: var(--tone); color: #fff; }
body.br-skin .sn-count--credit_requests { background: var(--amber-solid); }
body.br-skin .sn-sep { background: var(--d-line); }

/* ── Buttons become capsules ──────────────────────────────────────────────── */
body.br-skin .btn--primary { background: var(--tone); color: #fff; border-color: var(--tone); box-shadow: none; }
body.br-skin .btn--primary:hover { background: var(--tone); filter: brightness(1.08); color: #fff; }
body.br-skin .btn--navy { background: transparent; color: var(--tone); border-color: var(--tone); }
body.br-skin .btn--navy:hover { background: var(--tone-tint); color: var(--tone); }
body.br-skin .btn--ghost:hover { background: var(--d-sunken); color: var(--d-ink); }

/* ── Tabs, chips and segments follow the page ─────────────────────────────── */
body.br-skin .viewtab.on,
body.br-skin .filters .chip.on,
body.br-skin .seg button.on { background: var(--tone); color: #fff; border-color: var(--tone); }
body.br-skin .viewtab:hover { background: var(--tone-tint); color: var(--tone); }
body.br-skin .tab:hover { background: var(--d-sunken); }

/* ── Focus: a ring in the page's colour, never gold, never absent ─────────── */
body.br-skin input:focus,
body.br-skin select:focus,
body.br-skin textarea:focus,
body.br-skin .topsearch input:focus {
  border-color: var(--tone);
  box-shadow: 0 0 0 3px var(--tone-tint);
  outline: none;
}

/* ── The sign-in screen's gold wash ───────────────────────────────────────── */
body.br-skin.auth { background: var(--tone-tint); }

/* ── Leftovers ────────────────────────────────────────────────────────────── */
body.br-skin .band-tile--owed { border-color: var(--d-warn); background: var(--d-warn-bg); }
body.br-skin .card h2 { color: var(--d-ink); }
body.br-skin .stat b { color: var(--d-ink); }

/* NOT touched, on purpose: `.badge--spelling` and `.wr-err-spelling` are two of
   the four error-code colours a marked essay is read by — the same code the
   Writing app and the mock use, and a code that changes with the page is not a
   code. */

/* ═══ The People list (BayRen Office, step 4 — 17 Sep 2026) ═══════════════
   The page Asaf uses most. The budget that makes ten people fit a laptop
   screen (1366x620 once the browser's bars are drawn): the page starts 12px
   under the top bar, the header is ONE 40px row, the column names 32px, and
   every row 40px — a 28px control inside 6px of padding, one line of text
   that ends in "…" rather than wrapping. test_people_page measures it.
   Colour carries meaning, softly ("we need color, we need life"): each stage,
   each kind of badge and each follow-up state has its own tint. */
body.page-people .shell main.wrap{padding-top:12px}
.people{min-width:0}

/* ── The header: one row, stuck under the top bar ─────────────────────── */
.phead{position:sticky;top:var(--topbar-h);z-index:25;height:40px;margin:0 0 8px;
  background:var(--card);display:flex;align-items:center}
.ph-main{display:flex;align-items:center;gap:8px;width:100%;min-width:0;height:40px}
.ph-title{flex:none;display:flex;align-items:center;gap:7px;margin:0;font-size:1.15rem;
  color:var(--ink);white-space:nowrap}
.ph-count{font-size:.76rem;font-weight:800;color:var(--tone,#26737f);background:var(--tone-tint,#e6f3f5);
  border-radius:999px;padding:2px 8px;font-variant-numeric:tabular-nums}
.ph-views{flex:1 1 auto;min-width:0;display:flex;gap:4px;overflow-x:auto;scrollbar-width:none;padding:2px 0}
/* More chips than room: the strip scrolls sideways, and its edge fades to say
   so (admin.js marks it; a mask needs no inline style). */
.ph-views.has-more{-webkit-mask-image:linear-gradient(to right,#000 calc(100% - 36px),transparent);
  mask-image:linear-gradient(to right,#000 calc(100% - 36px),transparent)}
.ph-views::-webkit-scrollbar{display:none}
.pchip{flex:none;display:inline-flex;align-items:center;gap:4px;height:28px;padding:0 9px;
  border-radius:999px;border:1px solid var(--line);background:var(--card);color:var(--body);
  font-weight:600;font-size:.78rem;white-space:nowrap;transition:background .15s,color .15s,border-color .15s}
.pchip:hover{border-color:var(--tone,#26737f);color:var(--tone,#26737f)}
.pchip.on{background:var(--tone,#26737f);border-color:var(--tone,#26737f);color:#fff}
.pchip-n{min-width:18px;height:18px;padding:0 5px;border-radius:999px;display:inline-flex;align-items:center;
  justify-content:center;font-size:.75rem;font-weight:800;background:var(--amber-tint,#fbf4e0);color:var(--amber-solid,#8a660f)}
.pchip--due .pchip-n{background:var(--rose-tint,#fdeef2);color:var(--rose-solid,#bf4156)}
.pchip--flagged .pchip-n{background:var(--orange-tint,#fdf1e8);color:var(--orange-solid,#a8551f)}
.pchip.on .pchip-n{background:rgba(255,255,255,.28);color:#fff}
/* "More": the chips with no room, as a menu (admin.js folds them in). */
.ph-views-more{flex:none}
details.menu.ph-views-more>summary{min-width:0;height:28px;padding:0 6px 0 9px;gap:2px;border-radius:999px;
  font-weight:600;font-size:.78rem;color:var(--body)}
.ph-views-more .menu-list{min-width:190px}
.ph-views-more .menu-list .pchip{height:auto;border:0;border-radius:8px;padding:8px 10px;font-size:.88rem;
  color:var(--ink);background:none;justify-content:flex-start}
.ph-views-more .menu-list .pchip:hover{background:var(--d-sunken,#f5f7fa)}
.ph-views-more .menu-list .pchip-n{margin-left:auto}
/* The search box stays small until it is used, and gives the chips the room. */
.ph-search{position:relative;flex:0 0 150px;min-width:0;transition:flex-basis .15s}
.ph-search:focus-within,.ph-search:has(input[type=search]:not(:placeholder-shown)){flex-basis:220px}
.ph-search input[type=search]{height:32px;padding:0 10px 0 30px;border-radius:999px;font-size:.86rem;
  background:var(--d-sunken,#f5f7fa)}
.ph-search-icon{position:absolute;left:10px;top:50%;width:15px;height:15px;transform:translateY(-50%);
  color:var(--muted);pointer-events:none}
.ph-filter,.ph-more{flex:none}
details.menu.ph-filter>summary{height:32px;padding:0 10px 0 13px;gap:6px;border-radius:999px;font-size:.86rem;font-weight:600}
.ph-filter-n:not(:empty){min-width:18px;height:18px;padding:0 5px;border-radius:999px;display:inline-flex;
  align-items:center;justify-content:center;background:var(--tone,#26737f);color:#fff;font-size:.7rem;font-weight:800}
.ph-chev{width:14px;height:14px;opacity:.7}
.ph-add{flex:none;height:32px;white-space:nowrap}
details.menu.ph-more>summary{width:32px;height:32px;padding:0;border-radius:999px}
.ph-more summary .icon{width:18px;height:18px}

/* The Filter menu: every choice the registry offers, applied together. */
.menu-panel{position:absolute;right:0;top:calc(100% + 4px);z-index:70;width:min(470px,calc(100vw - 16px));
  max-height:calc(100vh - var(--topbar-h) - 70px);overflow:auto;background:var(--card);
  border:1px solid var(--line);border-radius:14px;padding:14px;
  box-shadow:var(--d-shadow,0 10px 30px rgba(11,42,73,.14))}
.filter-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px 12px}
.ff{display:flex;flex-direction:column;gap:3px;min-width:0}
.ff-lab{font-size:.7rem;font-weight:700;text-transform:uppercase;letter-spacing:.06em;color:var(--muted)}
.ff select{height:32px;padding:0 8px;font-size:.85rem}
.filter-foot{display:flex;justify-content:flex-end;gap:8px;margin-top:14px}
.menu-list .icon{width:16px;height:16px;flex:none;color:var(--muted)}
.menu-cap{font-size:.68rem;text-transform:uppercase;letter-spacing:.08em;color:var(--muted);font-weight:700;
  padding:8px 10px 2px}
.menu-view{display:flex;align-items:center;gap:2px}
.menu-list .menu-view a{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis}
.menu-list .menu-view form{display:block}
.menu-list .menu-view-x{width:auto;flex:none;padding:6px 10px;color:var(--muted);font-size:1rem}
.menu-list .menu-view-x:hover{color:var(--danger)}

/* The bulk bar lies over the header in the same box: nothing moves. */
.phead.is-bulk .ph-main{visibility:hidden}
.ph-bulk{position:absolute;inset:0;display:flex;align-items:center;gap:8px;padding:0 6px 0 12px;
  background:var(--tone-tint,#e6f3f5);border:1px solid var(--tone-edge,#c8e5ea);border-radius:12px;
  min-width:0;overflow-x:auto;scrollbar-width:none}
.ph-bulk .enter-guard{position:absolute}
.bulk-n{font-weight:800;color:var(--tone,#26737f);white-space:nowrap;margin-right:4px}
.ph-bulk .btn{height:30px;white-space:nowrap;flex:none}
.ph-bulk .btn .icon{width:15px;height:15px}
.ph-bulk .bulk-all{display:flex;align-items:center;gap:6px;font-size:.84rem;color:var(--body);white-space:nowrap;
  margin-left:4px;flex:none}
.ph-bulk .bulk-all input{width:16px;height:16px;accent-color:var(--tone,#26737f)}
.ph-bulk .bulk-clear{margin-left:auto}

/* Filters in force that no chip says, each taken off with one click. */
.ph-active{display:flex;flex-wrap:wrap;gap:6px;align-items:center;margin:0 0 8px}
.achip{display:inline-flex;align-items:center;gap:4px;height:26px;padding:0 5px 0 11px;border-radius:999px;
  background:var(--indigo-tint,#eceefb);color:var(--indigo-solid,#4a5bb5);font-size:.8rem;font-weight:600}
.achip:hover{background:var(--indigo-edge,#d8dcf5)}
.achip-x{font-weight:800;padding:0 5px;opacity:.75}
.achip-clear{font-size:.8rem;color:var(--muted);text-decoration:underline;margin-left:4px}

/* ── The table ─────────────────────────────────────────────────────────── */
.card.card--table{padding:0;margin-bottom:12px}
.ptbl{table-layout:fixed;font-size:.88rem}
.ptbl th{height:32px;padding:0 10px;vertical-align:middle}
.ptbl td{height:40px;padding:6px 10px;line-height:1.35;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ptbl th.pc-phone{width:148px}
.ptbl th.pc-where{width:21%}
.ptbl th.pc-stage{width:126px}
.ptbl th.pc-next{width:22%}
.ptbl th.pc-last{width:104px}
.ptbl th.pc-menu{width:46px}
.ptbl th.pc-name input,.ptbl td.pc-name input{width:15px;height:15px;margin:0 9px 0 0;vertical-align:-2px;
  accent-color:var(--tone,#26737f)}
.rowpick{display:inline;cursor:pointer}
.pname{font-weight:600;color:var(--ink)}
a.pname:hover{color:var(--tone,#26737f);text-decoration:underline}
.pfacts{margin-left:7px;color:var(--muted);font-size:.78rem}
.pflag{margin-left:6px;padding:1px 7px;border-radius:999px;font-size:.68rem;font-weight:700;
  background:var(--orange-tint,#fdf1e8);color:var(--orange-solid,#a8551f)}
.pphone{font-variant-numeric:tabular-nums;color:var(--body);font-size:.84rem}
.wa-link{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;margin-left:6px;
  border-radius:999px;background:var(--green-tint,#e9f5f1);color:var(--green-solid,#2d7b63);vertical-align:middle}
.wa-link:hover{background:var(--green-edge,#cfe8df)}
.wa-link .icon{width:14px;height:14px}
.pbadge,.ptag{display:inline-block;margin-right:4px;padding:2px 8px;border-radius:999px;font-size:.72rem;
  font-weight:700;vertical-align:middle;line-height:1.35}
/* The badges share the cell: each gives way ("Student · Batch 1…") before
   the "+N" that says there is more. */
.pwhere{display:flex;align-items:center;gap:4px;min-width:0;overflow:hidden}
.pwhere .pbadge,.pwhere .ptag{flex:0 1 auto;min-width:0;margin-right:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pwhere .pbadge--more,.pwhere .pbadge--archived{flex:none}
.pbadge--student{background:var(--green-tint,#e9f5f1);color:var(--green-solid,#2d7b63)}
.pbadge--immigration{background:var(--purple-tint,#f5edf6);color:var(--purple-solid,#7a4a7d)}
.pbadge--signup{background:var(--blue-tint,#ebf2fb);color:var(--blue-solid,#2f6fb0)}
.pbadge--enquiry{background:var(--orange-tint,#fdf1e8);color:var(--orange-solid,#a8551f)}
.pbadge--mock{background:var(--teal-tint,#e6f3f5);color:var(--teal-solid,#26737f)}
.pbadge--more,.pbadge--archived{background:var(--d-sunken,#f5f7fa);color:var(--muted)}
.ptag{background:var(--indigo-tint,#eceefb);color:var(--indigo-solid,#4a5bb5);font-weight:600}

/* The Stage dropdown wears its stage. */
.stage-auto{display:block;margin:0}
.ptbl .stage-sel{width:100%}
.stage-sel{font-weight:700;border-color:var(--line)}
.stage-sel--new{background-color:var(--blue-tint,#ebf2fb);color:var(--blue-solid,#2f6fb0);border-color:var(--blue-edge,#d3e3f6)}
.stage-sel--contacted{background-color:var(--teal-tint,#e6f3f5);color:var(--teal-solid,#26737f);border-color:var(--teal-edge,#c8e5ea)}
.stage-sel--qualified{background-color:var(--indigo-tint,#eceefb);color:var(--indigo-solid,#4a5bb5);border-color:var(--indigo-edge,#d8dcf5)}
.stage-sel--enrolled{background-color:var(--green-tint,#e9f5f1);color:var(--green-solid,#2d7b63);border-color:var(--green-edge,#cfe8df)}
.stage-sel--paying{background-color:var(--amber-tint,#fbf4e0);color:var(--amber-solid,#8a660f);border-color:var(--amber-edge,#f0e3bd)}
.stage-sel--lost{background-color:var(--rose-tint,#fdeef2);color:var(--rose-solid,#bf4156);border-color:var(--rose-edge,#f6d9e0)}
.stage-sel option{background:#fff;color:var(--ink)}

/* Next step: a button that opens its dialog — who, what, when. */
.ns,.bcard-next{display:flex;align-items:center;gap:6px;width:100%;height:28px;padding:0 6px;margin:0;
  border:1px dashed transparent;border-radius:8px;background:none;font:inherit;font-size:.86rem;
  color:var(--ink);text-align:left;cursor:pointer;min-width:0}
.ns:hover,.bcard-next:hover{border-color:var(--line);background:var(--d-sunken,#f5f7fa)}
.ns-text{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ns.is-empty .ns-text,.bcard-next.is-empty .ns-text{color:var(--muted);font-weight:400}
.owner-chip{flex:none;display:inline-flex;align-items:center;justify-content:center;min-width:22px;height:22px;
  padding:0 4px;border-radius:999px;font-size:.66rem;font-weight:800;letter-spacing:.02em}
.owner-chip--blue{background:var(--blue-tint,#ebf2fb);color:var(--blue-solid,#2f6fb0)}
.owner-chip--teal{background:var(--teal-tint,#e6f3f5);color:var(--teal-solid,#26737f)}
.owner-chip--green{background:var(--green-tint,#e9f5f1);color:var(--green-solid,#2d7b63)}
.owner-chip--amber{background:var(--amber-tint,#fbf4e0);color:var(--amber-solid,#8a660f)}
.owner-chip--orange{background:var(--orange-tint,#fdf1e8);color:var(--orange-solid,#a8551f)}
.owner-chip--rose{background:var(--rose-tint,#fdeef2);color:var(--rose-solid,#bf4156)}
.owner-chip--purple{background:var(--purple-tint,#f5edf6);color:var(--purple-solid,#7a4a7d)}
.owner-chip--indigo{background:var(--indigo-tint,#eceefb);color:var(--indigo-solid,#4a5bb5)}
.due{flex:none;padding:1px 7px;border-radius:999px;font-size:.7rem;font-weight:800;white-space:nowrap}
.due--overdue{background:var(--rose-tint,#fdeef2);color:var(--rose-solid,#bf4156)}
.due--today{background:var(--amber-tint,#fbf4e0);color:var(--amber-solid,#8a660f)}
.due--soon{background:var(--blue-tint,#ebf2fb);color:var(--blue-solid,#2f6fb0)}
.due--later{background:var(--d-sunken,#f5f7fa);color:var(--muted)}
.pc-last{color:var(--muted);font-size:.82rem}
.ptbl td.pc-menu{overflow:visible;text-align:right;padding-right:8px}
details.menu.row-menu>summary{min-width:28px;width:28px;height:28px;padding:0;border-color:transparent;background:none}
.prow:hover details.menu.row-menu>summary,details.menu.row-menu[open]>summary{border-color:var(--line);background:var(--card)}
.row-menu summary .icon{width:16px;height:16px}
.prow.is-new td{background:var(--green-tint,#e9f5f1)}
.prow.is-archived td{color:var(--muted)}
.prow--gone td{background:var(--d-sunken,#f5f7fa);color:var(--muted);height:40px}
.gone-undo{display:inline-block;margin-left:10px}
.pempty td{height:auto;padding:28px 16px;text-align:center;color:var(--muted);white-space:normal}
.pempty a{color:var(--tone,#26737f);text-decoration:underline}
.pfoot{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:8px 12px;
  border-top:1px solid var(--line);font-size:.84rem;color:var(--muted)}
.pager-mini{display:flex;align-items:center;gap:8px}
.pager-where{white-space:nowrap}
@media (max-width:1279px){.ptbl .pc-last{display:none}}

/* ── The Board: the same people by stage; each column scrolls itself ───── */
.pboard{display:grid;grid-template-columns:repeat(6,minmax(176px,1fr));gap:10px;overflow-x:auto;padding-bottom:6px}
.bcol{display:flex;flex-direction:column;min-width:0;max-height:calc(100vh - var(--topbar-h) - 76px);
  background:var(--d-sunken,#f5f7fa);border:1px solid var(--line);border-radius:14px;padding:8px}
.bcol-head{display:flex;align-items:center;justify-content:space-between;gap:6px;padding:2px 4px 8px}
.bcol-head h2{margin:0;font-size:.76rem;text-transform:uppercase;letter-spacing:.08em;color:var(--ink)}
.bcol-n{min-width:24px;padding:1px 8px;border-radius:999px;text-align:center;font-size:.74rem;font-weight:800;
  background:var(--card);color:var(--ink);border:1px solid var(--line)}
.bcol--new .bcol-n{background:var(--blue-tint,#ebf2fb);color:var(--blue-solid,#2f6fb0);border-color:var(--blue-edge,#d3e3f6)}
.bcol--contacted .bcol-n{background:var(--teal-tint,#e6f3f5);color:var(--teal-solid,#26737f);border-color:var(--teal-edge,#c8e5ea)}
.bcol--qualified .bcol-n{background:var(--indigo-tint,#eceefb);color:var(--indigo-solid,#4a5bb5);border-color:var(--indigo-edge,#d8dcf5)}
.bcol--enrolled .bcol-n{background:var(--green-tint,#e9f5f1);color:var(--green-solid,#2d7b63);border-color:var(--green-edge,#cfe8df)}
.bcol--paying .bcol-n{background:var(--amber-tint,#fbf4e0);color:var(--amber-solid,#8a660f);border-color:var(--amber-edge,#f0e3bd)}
.bcol--lost .bcol-n{background:var(--rose-tint,#fdeef2);color:var(--rose-solid,#bf4156);border-color:var(--rose-edge,#f6d9e0)}
.bcol-list{flex:1 1 auto;min-height:48px;overflow-y:auto;display:flex;flex-direction:column;gap:6px;padding:1px}
.bcard{display:flex;flex-direction:column;gap:5px;padding:8px 9px;background:var(--card);border:1px solid var(--line);
  border-left:3px solid var(--blue-solid,#2f6fb0);border-radius:10px}
.bcard--contacted{border-left-color:var(--teal-solid,#26737f)}
.bcard--qualified{border-left-color:var(--indigo-solid,#4a5bb5)}
.bcard--enrolled{border-left-color:var(--green-solid,#2d7b63)}
.bcard--paying{border-left-color:var(--amber-solid,#8a660f)}
.bcard--lost{border-left-color:var(--rose-solid,#bf4156)}
.bcard-top{display:flex;align-items:center;gap:4px;min-width:0}
.bcard-name{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:700;
  font-size:.88rem;color:var(--ink)}
.bcard .wa-link{margin-left:0;width:22px;height:22px}
.bcard-next{height:auto;min-height:26px;flex-wrap:wrap;row-gap:3px;font-size:.8rem;padding:3px 4px}
.bcard-next .ns-text{order:-1;flex-basis:100%;white-space:normal;display:-webkit-box;-webkit-line-clamp:2;
  -webkit-box-orient:vertical}
.bcard-next.is-empty .ns-text{flex-basis:auto}
.bcard .stage-sel{width:100%}
.bcol-empty{margin:0;padding:12px 0;text-align:center;color:var(--muted);font-size:.8rem}
.bcol-more{padding:6px 4px 0;font-size:.78rem;font-weight:600;color:var(--tone,#26737f)}
.lost-card{margin-top:4px;max-width:560px}

/* ── The dialogs ───────────────────────────────────────────────────────── */
dialog.office-dialog.office-dialog--wide{width:min(640px,calc(100vw - 24px))}
/* The page's reset (*{margin:0}) had taken the browser's margin:auto off every
   dialog, so they opened in the top-left corner instead of the middle. */
dialog.office-dialog{margin:auto}
label.field .lab .hint{display:inline;margin:0 0 0 4px;font-weight:400}
.dlg-x{border:0;background:none;font-size:1.4rem;line-height:1;color:var(--muted);cursor:pointer;padding:2px 8px;border-radius:8px}
.dlg-x:hover{background:var(--d-sunken,#f5f7fa);color:var(--ink)}
.office-dialog input[type=date],.office-dialog input[type=tel]{width:100%;padding:8px 11px;border:1px solid var(--line);
  border-radius:var(--radius-sm);font:inherit;color:var(--ink);background:#fff}
.field-pair,.add-grid{display:grid;grid-template-columns:1fr 1fr;gap:0 12px}
.add-wide{grid-column:1 / -1}
.due-picks{display:flex;flex-wrap:wrap;gap:6px;margin:-4px 0 6px}
.pick{border:1px solid var(--line);background:var(--card);border-radius:999px;padding:4px 11px;font:inherit;
  font-size:.8rem;font-weight:600;color:var(--body);cursor:pointer}
.pick:hover{border-color:var(--tone,#26737f);color:var(--tone,#26737f)}
.pick--none{color:var(--muted)}
.add-check{border:1px solid var(--amber-edge,#f0e3bd);background:var(--amber-tint,#fbf4e0);border-radius:12px;
  padding:10px 12px;margin-bottom:12px;color:var(--ink)}
.add-check-who{list-style:none;padding:0;display:flex;flex-direction:column;gap:6px;margin:8px 0}
.add-check-who li{display:flex;flex-wrap:wrap;align-items:center;gap:6px}
.add-check-who .hint{margin:0}
.add-check .hint{margin:0 0 8px}
.lost-why-field{display:none}
.office-dialog:has(select[name=new_stage] option[value=Lost]:checked) .lost-why-field{display:block}

/* ── A phone: the header stacks, the bulk bar sits at the bottom, rows are cards ── */
@media (max-width:820px){
  .phead{position:static;height:auto}
  .ph-main{flex-wrap:wrap;height:auto;row-gap:8px}
  /* Three lines: the name and the two buttons, then search and Filter, then
     the chips. */
  .ph-title{order:1;flex:1 1 auto}
  .ph-add{order:2}
  .ph-more{order:3}
  .ph-search,.ph-search:focus-within,.ph-search:has(input[type=search]:not(:placeholder-shown)){order:4;flex:1 1 160px;min-width:0}
  .ph-filter{order:5}
  .ph-views{order:6;flex:1 1 100%}
  /* relative (for the Filter panel), and top:auto — the desktop's sticky
     top would push the whole header 52px down over the list. */
  .phead{position:relative;top:auto}
  details.menu.ph-filter{position:static}
  .ph-filter .menu-panel{left:0;right:0;width:auto;top:100%}
  .ph-search input[type=search]{height:42px}
  details.menu.ph-filter>summary,.ph-add,details.menu.ph-more>summary{height:40px;min-height:40px}
  details.menu.ph-more>summary{width:40px}
  .pchip,details.menu.ph-views-more>summary{height:40px}
  .people .menu-list a,.people .menu-list button{min-height:44px}
  .phead.is-bulk .ph-main{visibility:visible}
  .ph-bulk{position:fixed;inset:auto 8px 8px 8px;z-index:40;flex-wrap:wrap;padding:8px;height:auto;
    box-shadow:var(--d-shadow,0 10px 30px rgba(11,42,73,.16))}
  .ph-bulk .btn{height:40px}
  .ph-bulk .bulk-clear{margin-left:0}
  /* …and the page keeps the bar's height free below the list (admin.js). */
  body.page-people.has-bulk-bar main.wrap{padding-bottom:calc(var(--bulk-h,200px) + 16px)}
  .field-pair,.add-grid{grid-template-columns:1fr}
  .filter-grid{grid-template-columns:1fr}
  .ff select{height:42px}
  .pboard{grid-template-columns:repeat(6,minmax(240px,82vw))}
}
@media (max-width:700px){
  /* The 12px floor (see the block below): People's small labels on a phone. */
  .pchip-n,.ff-lab,.pflag,.pbadge,.ptag,.owner-chip,.due,.bcol-n,.menu-cap{font-size:.76rem}
  .ptbl[data-rows] tbody tr{position:relative}
  .ptbl[data-rows] td{height:auto;white-space:normal;overflow:visible}
  /* :has() in the table's own phone rule makes it the stronger selector. */
  .ptbl[data-rows] td.pc-name[data-first]{padding-right:52px}
  .ptbl[data-rows] td.pc-last{display:flex}
  .ptbl[data-rows] td.pc-stage{border-top:0;margin-top:0;padding-top:5px}
  .ptbl[data-rows] td.pc-stage::before{flex-basis:34%;margin-bottom:0}
  .ptbl[data-rows] .stage-sel{width:auto;min-width:170px}
  .ptbl[data-rows] td.pc-next .ns{flex:1 1 180px;height:auto;min-height:40px;border-color:var(--line)}
  .ptbl[data-rows] td.pc-menu{position:absolute;top:6px;right:8px;padding:0;border:0;margin:0}
  .ptbl[data-rows] details.menu.row-menu>summary{width:40px;height:40px;border-color:var(--line)}
  .ptbl[data-rows] .wa-link{width:40px;height:40px}
  /* The tick box gets a thumb-sized target around it. */
  .ptbl[data-rows] .rowpick{display:inline-flex;align-items:center;justify-content:center;width:40px;height:40px;
    margin:-8px 2px -8px -10px;vertical-align:middle}
  .ptbl[data-rows] td.pc-name input{width:20px;height:20px;margin:0}
  .pfoot{flex-wrap:wrap}
  .pempty td{padding:16px 0}
}

/* ═══ One page per person (BayRen Office, step 5 — 17 Sep 2026) ═══════════
   The budget: 22px for "‹ Back to list · Next person ›", a header of 56px at
   most (the name and badges on one line, age · district · phone · email on
   the next, Stage / Next step / ⋯ on the right), then the tabs with their
   facts — so what a tab holds starts about 150px under the top of the page
   on a 1366x620 laptop (test_person_page measures it). Colour carries
   meaning: every tab's fact has its own tint, as every stage does. */
body.page-person .shell main.wrap{padding-top:10px}
.person{min-width:0}
.pnav{display:flex;align-items:center;justify-content:space-between;gap:12px;height:22px;margin:0 0 2px;
  font-size:.82rem;font-weight:600}
.pnav a{color:var(--muted);border-radius:999px;padding:1px 8px;margin:0 -8px}
.pnav a:hover{color:var(--tone,#26737f);background:var(--d-sunken,#f5f7fa)}
.pbanner{display:flex;align-items:center;justify-content:space-between;gap:8px 12px;flex-wrap:wrap;
  padding:7px 12px;margin:0 0 6px;border-radius:12px;font-size:.87rem;border:1px solid var(--line);
  background:var(--d-sunken,#f5f7fa);color:var(--ink)}
.pbanner--flag{background:var(--orange-tint,#fdf1e8);border-color:var(--orange-edge,#f6ddcb)}
.pbanner--flag a{color:var(--orange-solid,#a8551f);text-decoration:underline}
.pbanner--ok{background:var(--green-tint,#e9f5f1);border-color:var(--green-edge,#cfe8df)}
.pbanner-act{display:flex;align-items:center;gap:6px;flex-wrap:wrap}
.pbanner-act form,.pbanner form{display:inline-flex;margin:0}
.pflags:empty{display:none}

/* ── The header ───────────────────────────────────────────────────────── */
.phd{display:flex;align-items:center;gap:14px;min-height:50px;max-height:56px;margin:0 0 4px}
.phd-id{flex:1 1 auto;min-width:0}
.phd-line{display:flex;align-items:center;gap:6px;min-width:0;white-space:nowrap;overflow:hidden}
.phd-name{flex:0 1 auto;min-width:0;margin:0 4px 0 0;font-size:1.28rem;line-height:1.25;color:var(--ink);
  overflow:hidden;text-overflow:ellipsis}
.phd-line .pbadge{flex:0 0 auto;margin-right:0}
.phd-facts{gap:14px;margin-top:1px;font-size:.84rem;color:var(--muted)}
.phd-fact{display:inline-flex;align-items:center;min-width:0;overflow:hidden;text-overflow:ellipsis}
.phd-phone{color:var(--body);font-variant-numeric:tabular-nums}
.phd-act{flex:none;display:flex;align-items:center;gap:8px}
.phd-work{display:flex;align-items:center;gap:8px}
.phd-work form{margin:0}
.phd-work .stage-sel{width:128px}
.phd .ns.phd-next{width:250px;height:28px;border:1px solid var(--line);background:var(--card)}
details.menu.phd-menu>summary{width:32px;height:32px;padding:0;border-radius:999px}
.phd-menu summary .icon{width:18px;height:18px}

/* ── The tabs and what they hold ──────────────────────────────────────── */
.ptabs{display:flex;align-items:flex-end;gap:2px;margin:0 0 12px;border-bottom:1px solid var(--line);
  overflow-x:auto;scrollbar-width:none}
.ptabs::-webkit-scrollbar{display:none}
.ptab{flex:none;display:inline-flex;align-items:center;gap:6px;height:38px;padding:0 12px;margin-bottom:-1px;
  border-bottom:2px solid transparent;font-weight:600;font-size:.9rem;color:var(--muted);white-space:nowrap;
  border-radius:10px 10px 0 0}
.ptab:hover{color:var(--ink);background:var(--d-sunken,#f5f7fa)}
.ptab.on{color:var(--navy);border-bottom-color:var(--tone,#26737f);background:var(--card)}
.ptab:focus-visible{outline:2px solid var(--tone,#26737f);outline-offset:-2px}
.ptab-fact{padding:1px 8px;border-radius:999px;font-size:.72rem;font-weight:700;
  background:var(--d-sunken,#f5f7fa);color:var(--muted)}
.ptab-fact--course{background:var(--green-tint,#e9f5f1);color:var(--green-solid,#2d7b63)}
.ptab-fact--mock{background:var(--teal-tint,#e6f3f5);color:var(--teal-solid,#26737f)}
.ptab-fact--immigration{background:var(--purple-tint,#f5edf6);color:var(--purple-solid,#7a4a7d)}
.ptab-fact--account{background:var(--amber-tint,#fbf4e0);color:var(--amber-solid,#8a660f)}
.ppanel{min-width:0}
.ppanel:focus{outline:none}
.ppanel-wait{padding:30px 0;color:var(--muted);text-align:center}
.pgrid{display:grid;grid-template-columns:minmax(0,1.35fr) minmax(0,1fr);gap:14px;align-items:start}
.pgrid--even{grid-template-columns:repeat(2,minmax(0,1fr))}
.pgrid-main,.pgrid-side{min-width:0}
.card.pcard{margin-bottom:14px;padding:16px 18px}
.pcard h2{display:flex;align-items:center;gap:8px;font-size:.98rem}
.kv.kv--tight{grid-template-columns:118px minmax(0,1fr);gap:5px 12px;font-size:.88rem}
.pscore{display:inline-block;padding:1px 9px;border-radius:999px;font-size:.78rem;font-weight:700;
  background:var(--d-sunken,#f5f7fa);color:var(--muted)}
.pscore--hot{background:var(--rose-tint,#fdeef2);color:var(--rose-solid,#bf4156)}
.pscore--warm{background:var(--amber-tint,#fbf4e0);color:var(--amber-solid,#8a660f)}
.pscore--interested{background:var(--blue-tint,#ebf2fb);color:var(--blue-solid,#2f6fb0)}
.pneeds{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}
.pneeds p{margin:0}
.pick-account{display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin:0 0 10px}
.pick-account .pchip{height:28px}
/* An app's Default/Allow/Block drops under its name when the card is too
   narrow for both (a phone), instead of running out of the card. */
.pcard .app-row{flex-wrap:wrap}

/* ── Merge and Split ──────────────────────────────────────────────────── */
.merge-find{display:flex;gap:8px;margin-bottom:10px}
.merge-find input[type=search]{flex:1;min-width:0}
.merge-pick{min-height:40px}
.merge-hits,.split-list{list-style:none;margin:0;padding:0}
.merge-hits li,.split-list li{display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:8px 0;border-bottom:1px solid var(--line)}
.merge-hits li:last-child,.split-list li:last-child{border-bottom:0}
.merge-hit-words,.split-words{min-width:0;overflow:hidden;text-overflow:ellipsis}
.split-list form{margin:0;flex:none}
.merge-compare{font-size:.86rem;margin-bottom:10px}
.merge-compare th{width:24%}
.merge-no{padding:8px 12px;border-radius:10px;background:var(--rose-tint,#fdeef2);color:var(--rose-solid,#bf4156);
  font-weight:600;margin:0 0 8px}
.merge-go{margin:0 0 8px}
.merge-go .hint{margin:0 0 8px}
.merge-back{font-size:.84rem;color:var(--muted);text-decoration:underline}

@media (max-width:1100px){
  .pgrid,.pgrid--even{grid-template-columns:minmax(0,1fr)}
}
@media (max-width:820px){
  body.page-person .shell main.wrap{padding-top:8px}
  .phd{flex-wrap:wrap;align-items:flex-start;max-height:none;gap:8px}
  .phd-id{flex:1 1 100%}
  .phd-line,.phd-facts{white-space:normal;flex-wrap:wrap;row-gap:2px}
  /* Stage, Next step and ⋯ on one row: the ⋯ stays at the right edge, so
     its menu opens on the screen. */
  .phd-act{flex:1 1 100%;min-width:0;flex-wrap:nowrap;align-items:flex-start}
  .phd-work{flex:1 1 auto;min-width:0;flex-wrap:wrap}
  .phd-work .stage-sel{width:auto;min-width:130px}
  .phd .ns.phd-next{flex:1 1 150px;width:auto;min-width:0;height:auto;min-height:40px}
  details.menu.phd-menu>summary{width:40px;height:40px}
  .person .menu-list a,.person .menu-list button{min-height:44px}
  .phd .wa-link{width:40px;height:40px}
  .ptab{height:44px}
  .pnav{height:40px}
  .pnav a{display:inline-flex;align-items:center;min-height:40px;padding:0 8px}
  .merge-find input[type=search]{height:42px}
}

/* ── The 12px floor, on a phone only (7 Sep 2026) ──────────────────────────
   The phone pass measured 188 pieces of text under 12px across 21 pages, all
   of them labels: the sidebar's section headings at 10.6px, the label under
   every stat tile at 11.8px, the board counts and section labels at 11.5px.

   Raised INSIDE the phone query, so the desktop panel does not move a pixel —
   its type scale is Asaf's and is not what he called clumsy. All of these are
   this panel's own classes (admin.css); no shared sheet moves for another app.

   This block sits at the END of the file on purpose. The same rules written
   halfway up lost to `.sec-label` and `.board-count`, which are defined below
   that point: same specificity, later wins. */
@media (max-width:700px){
  .sn-group{font-size:.76rem}          /* 10.6 -> 12.2 */
  .stat span{font-size:.76rem}         /* 11.8 -> 12.2 */
  .sec-label{font-size:.76rem}         /* 11.5 -> 12.2 */
  .board-count{font-size:.76rem}       /* 11.5 -> 12.2 */
  .viewtab-count{font-size:.76rem}     /* 11.5 -> 12.2 (Mock tests tabs, 17 Sep 2026) */
  .ta-kind{font-size:.76rem}           /* 11.5 -> 12.2 (the top search's Student / Lead chips) */
  .ptab-fact,.pscore{font-size:.76rem} /* 11.5 -> 12.2 (the person page's tab facts, lead score) */
  .tbl th{font-size:.76rem}            /* only ever seen on a table that did not stack */

  /* Tap targets. The top bar's search was a 37x30 button beside a 38px field,
     and a Today-queue chip missed 40px by three. */
  .topsearch input{min-height:42px}
  .topsearch-go{min-width:42px;min-height:42px}
  .chip{min-height:40px;display:inline-flex;align-items:center}
}

/* LEFT ALONE, and Asaf's call: the brand link in the top bar is 75x31. It is
   the panel's own chrome and shrinking or padding it changes the header for
   everyone; Grammar's pass left the same class of thing for the same reason. */


/* ═══ Saving without reloading (17 Sep 2026) ══════════════════════════════
   The pieces admin.js send() uses. Classes only — the CSP discards style="". */

/* The banner: signed out, page out of date, a save we cannot confirm. */
.office-banner{position:fixed;left:50%;top:10px;transform:translateX(-50%);z-index:80;
  display:flex;align-items:center;gap:10px;flex-wrap:wrap;max-width:min(760px,calc(100vw - 24px));
  padding:10px 12px 10px 16px;border-radius:14px;background:var(--card);
  border:1px solid var(--line);box-shadow:var(--d-shadow,0 10px 30px rgba(11,42,73,.12));
  font-weight:600;font-size:.9rem;color:var(--ink)}
.office-banner--warn{border-color:var(--warn);background:var(--warn-bg)}
.office-banner--error{border-color:var(--danger);background:var(--danger-bg)}
.office-banner--info{border-color:var(--tone,#26737f);background:var(--tone-tint,#e6f3f5)}
.office-banner-words{flex:1 1 260px}
.office-banner-x{border:0;background:none;font-size:1.3rem;line-height:1;cursor:pointer;
  color:var(--muted);padding:2px 6px;border-radius:6px}
.office-banner-x:hover{background:rgba(0,0,0,.06)}

/* A control whose save could not be confirmed. */
.is-unsure{outline:2px dashed var(--warn);outline-offset:2px}
/* A list being refetched stays readable but says it is working. */
.is-loading{opacity:.6;transition:opacity .15s}

/* Pressing Enter presses a form's FIRST submit button; this disabled one is
   first, so Enter in a text box submits nothing (the status card approved a
   student that way). Visually hidden, still in the tree. */
.enter-guard{position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);border:0}

/* ── Menus: <details class="menu"> ─────────────────────────────────────── */
details.menu{position:relative;display:inline-block}
details.menu>summary{list-style:none;cursor:pointer;display:inline-flex;align-items:center;
  justify-content:center;min-width:30px;height:30px;padding:0 8px;border-radius:8px;
  border:1px solid var(--line);background:var(--card);color:var(--ink);font-weight:700;
  user-select:none}
details.menu>summary::-webkit-details-marker{display:none}
details.menu>summary:hover,details.menu[open]>summary{background:var(--d-sunken,#f5f7fa)}
.menu-list{position:absolute;right:0;top:calc(100% + 4px);z-index:70;min-width:200px;
  background:var(--card);border:1px solid var(--line);border-radius:12px;padding:6px;
  box-shadow:var(--d-shadow,0 10px 30px rgba(11,42,73,.14));display:flex;flex-direction:column}
.menu-list a,.menu-list button{display:flex;align-items:center;gap:8px;width:100%;text-align:left;
  padding:8px 10px;border-radius:8px;border:0;background:none;font:inherit;font-size:.88rem;
  color:var(--ink);cursor:pointer;white-space:nowrap}
.menu-list a:hover,.menu-list button:hover{background:var(--d-sunken,#f5f7fa)}
.menu-list .menu-sep{height:1px;background:var(--line);margin:4px 2px}
.menu-list .menu-danger{color:var(--danger)}
.menu-list form{display:contents}

/* ── Dialogs: <dialog class="office-dialog"> ──────────────────────────── */
dialog.office-dialog{border:1px solid var(--line);border-radius:18px;padding:0;
  width:min(520px,calc(100vw - 24px));max-height:calc(100vh - 40px);color:var(--body);
  background:var(--card);box-shadow:var(--d-shadow,0 20px 60px rgba(11,42,73,.2))}
dialog.office-dialog::backdrop{background:rgba(10,22,34,.42)}
.office-dialog .dlg-head{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:16px 20px 0}
.office-dialog .dlg-head h2{font-size:1.05rem;color:var(--ink);margin:0}
.office-dialog .dlg-body{padding:12px 20px 4px}
.office-dialog .dlg-foot{display:flex;justify-content:flex-end;gap:8px;padding:12px 20px 18px}
.office-dialog label.field{margin-bottom:12px}
