/* OCSI SAP — extracted verbatim from docs/prototype/ocsi_sap_prototype_v05.html <style>.
   Production additions (login card, header user chip) are appended at the bottom. */
:root{
  --maroon:#8C1D2F; --maroon-soft:#F4E6E8; --ink:#20242C; --paper:#FBFAF7;
  --slate:#6A7280; --line:#E5E1D8; --teal:#1F7A8C; --gold:#C99532; --usa:#9AA0AB;
  --flag:#C0392B; --ok:#2E7D5B;
  --display:'Sora',system-ui,sans-serif; --body:'Inter',system-ui,sans-serif; --mono:'IBM Plex Mono',monospace;
}
*{box-sizing:border-box;margin:0;padding:0}
body{background:var(--paper);color:var(--ink);font-family:var(--body);font-size:15px;line-height:1.5}
header{border-bottom:3px solid var(--maroon);padding:28px 32px 0;background:#fff}
.brand{display:flex;align-items:baseline;gap:14px;flex-wrap:wrap}
.brand h1{font-family:var(--display);font-weight:700;font-size:22px;letter-spacing:-.01em}
.brand h1 span{color:var(--maroon)}
.brand .tag{font-family:var(--mono);font-size:12px;color:var(--slate);text-transform:uppercase;letter-spacing:.08em}
nav{display:flex;gap:2px;margin-top:20px;overflow-x:auto}
nav button{font-family:var(--display);font-size:13px;font-weight:600;background:none;border:none;border-bottom:3px solid transparent;padding:10px 16px;cursor:pointer;color:var(--slate);white-space:nowrap;margin-bottom:-3px}
nav button:hover{color:var(--ink)}
nav button.active{color:var(--maroon);border-bottom-color:var(--maroon)}
nav button:focus-visible{outline:2px solid var(--maroon);outline-offset:-2px}
main{max-width:1080px;margin:0 auto;padding:32px 24px 80px}
section{display:none}section.active{display:block}
h2{font-family:var(--display);font-size:26px;font-weight:700;letter-spacing:-.015em;margin-bottom:6px}
.sub{color:var(--slate);margin-bottom:28px}
.grid{display:grid;gap:20px}
@media(min-width:820px){.grid.two{grid-template-columns:1fr 1fr}}
.card{background:#fff;border:1px solid var(--line);border-radius:10px;padding:22px;position:relative}
.card h3{font-family:var(--display);font-size:15px;font-weight:600;margin-bottom:4px;padding-right:70px}
.card .note{font-size:12.5px;color:var(--slate);margin-bottom:16px}
.chartbox{position:relative;height:300px}
.chartbox.tall{height:340px}
.tools{position:absolute;top:16px;right:16px;display:flex;gap:6px}
.tools button{font-family:var(--mono);font-size:11px;border:1px solid var(--line);background:#fff;color:var(--slate);border-radius:6px;padding:4px 8px;cursor:pointer}
.tools button:hover{color:var(--maroon);border-color:var(--maroon)}
.stats{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:14px;margin-bottom:22px}
.stat{background:#fff;border:1px solid var(--line);border-radius:10px;padding:16px 18px}
.stat .v{font-family:var(--mono);font-size:25px;font-weight:500;color:var(--maroon)}
.stat .v small{font-size:13px;color:var(--slate);font-weight:400}
.stat .l{font-size:12px;color:var(--slate);text-transform:uppercase;letter-spacing:.06em;margin-top:2px}
.stat .d{font-family:var(--mono);font-size:11.5px;margin-top:4px}
.d.up{color:var(--ok)}.d.dn{color:var(--flag)}.d.flat{color:var(--slate)}
.controls{display:flex;gap:10px;flex-wrap:wrap;margin-bottom:18px}
select{font-family:var(--body);font-size:13.5px;padding:7px 10px;border:1px solid var(--line);border-radius:7px;background:#fff;color:var(--ink)}
table{width:100%;border-collapse:collapse;font-size:13.5px}
th{font-family:var(--display);font-size:11.5px;text-transform:uppercase;letter-spacing:.06em;color:var(--slate);text-align:left;padding:8px 10px;border-bottom:2px solid var(--line)}
td{padding:9px 10px;border-bottom:1px solid var(--line)}
td.mono{font-family:var(--mono)}
tbody tr:hover td{background:var(--maroon-soft)}
.pill{display:inline-block;font-family:var(--mono);font-size:12px;padding:2px 8px;border-radius:20px}
.pill.flag{background:#FBE9E7;color:var(--flag)}
.pill.ok{background:#E6F2EC;color:var(--ok)}
.pill.na{background:#F0EEE8;color:var(--slate)}
.legend{display:flex;gap:18px;flex-wrap:wrap;font-size:12.5px;color:var(--slate);margin-top:14px}
.legend span{display:flex;align-items:center;gap:6px}
.covgrid td:first-child{font-weight:500}
.yrbar{display:inline-flex;gap:3px}
.yr{font-family:var(--mono);font-size:11px;padding:1px 6px;border-radius:4px;background:var(--maroon-soft);color:var(--maroon)}
.yr.empty{background:#F0EEE8;color:#B4AFA3}
.banner{background:var(--maroon-soft);border:1px solid #E8CDD1;border-radius:10px;padding:12px 16px;font-size:13px;color:#6E2430;margin-bottom:24px}
.hint{font-size:12px;color:var(--slate);font-style:italic;margin-top:10px}
footer{text-align:center;font-family:var(--mono);font-size:11.5px;color:var(--slate);padding:20px}
/* comments */
.tools button.hasc{color:var(--maroon);border-color:var(--maroon)}
.cmt{border:1px solid var(--line);border-radius:8px;padding:10px 12px;margin-bottom:10px}
.cmt .who{font-family:var(--mono);font-size:11.5px;color:var(--slate);margin-bottom:3px}
.cmt .txt{font-size:14px}
.cform{display:grid;gap:8px;margin-top:14px}
.cform input,.cform textarea{font-family:var(--body);font-size:14px;padding:8px 10px;border:1px solid var(--line);border-radius:7px;background:#fff}
.cform textarea{min-height:70px;resize:vertical}
.cform .row{display:flex;gap:8px;justify-content:space-between;align-items:center}
.cform button{font-family:var(--display);font-size:13px;font-weight:600;background:var(--maroon);color:#fff;border:none;border-radius:7px;padding:8px 16px;cursor:pointer}
.cform button.ghost{background:none;color:var(--slate);border:1px solid var(--line)}
.cform input:disabled{background:#F0EEE8;color:var(--slate)}
.cempty{font-size:13px;color:var(--slate);font-style:italic}
/* modal */
#modal{display:none;position:fixed;inset:0;background:rgba(32,36,44,.55);z-index:50;padding:4vh 4vw;align-items:center;justify-content:center}
#modal.open{display:flex}
#modalCard{background:#fff;border-radius:12px;padding:26px;width:100%;max-width:1000px;max-height:92vh;overflow:auto;position:relative}
#modalCard h3{font-family:var(--display);font-size:18px;margin-bottom:14px;padding-right:40px}
#modalClose{position:absolute;top:14px;right:14px;font-size:18px;border:none;background:none;cursor:pointer;color:var(--slate)}
#modalClose:hover{color:var(--maroon)}
#modalBody .chartbox{height:60vh}
.ddgrid{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:12px;margin-bottom:18px}
.ddstat{border:1px solid var(--line);border-radius:8px;padding:12px 14px}
.ddstat .v{font-family:var(--mono);font-size:20px;color:var(--maroon)}
.ddstat .l{font-size:11px;color:var(--slate);text-transform:uppercase;letter-spacing:.05em}
@media(prefers-reduced-motion:no-preference){section.active{animation:fade .25s ease}}
@keyframes fade{from{opacity:0;transform:translateY(4px)}to{opacity:1}}

/* ---- production additions (not in prototype): auth UI in the same design system ---- */
.brand .user{margin-left:auto;display:flex;align-items:center;gap:10px;font-family:var(--mono);font-size:12px;color:var(--slate)}
.brand .user button{font-family:var(--mono);font-size:11px;border:1px solid var(--line);background:#fff;color:var(--slate);border-radius:6px;padding:4px 10px;cursor:pointer}
.brand .user button:hover{color:var(--maroon);border-color:var(--maroon)}
.login-wrap{max-width:420px;margin:8vh auto 0}
.login-wrap .card{padding:30px}
.login-wrap .card h3{font-size:18px;padding-right:0;margin-bottom:8px}
.login-err{background:#FBE9E7;color:var(--flag);border-radius:8px;padding:10px 12px;font-size:13px;margin-bottom:14px}
.btn-primary{font-family:var(--display);font-size:14px;font-weight:600;background:var(--maroon);color:#fff;border:none;border-radius:7px;padding:10px 18px;cursor:pointer;width:100%}
.btn-primary:hover{background:#7A1929}
.btn-primary:focus-visible{outline:2px solid var(--ink);outline-offset:2px}

/* ---- production additions: admin tab + local sign-in (appended; existing classes reused where possible) ---- */
.login-alt{display:block;margin:12px auto 0;background:none;border:none;color:var(--slate);font-family:var(--body);font-size:13px;cursor:pointer;text-decoration:underline}
.login-alt:hover{color:var(--maroon)}
.local-form{display:grid;gap:8px;margin-top:14px}
.local-form input{font-family:var(--body);font-size:14px;padding:8px 10px;border:1px solid var(--line);border-radius:7px;background:#fff}
.btn-admin{font-family:var(--display);font-size:13px;font-weight:600;background:var(--maroon);color:#fff;border:none;border-radius:7px;padding:8px 14px;cursor:pointer;white-space:nowrap}
.btn-admin:hover{background:#7A1929}
.btn-admin:disabled{opacity:.55;cursor:default}
.btn-admin.ghost{background:none;color:var(--slate);border:1px solid var(--line)}
.btn-admin.ghost:hover{color:var(--maroon);border-color:var(--maroon)}
.admin-row{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin-bottom:16px}
.admin-row input[type="text"]{font-family:var(--body);font-size:13.5px;padding:7px 10px;border:1px solid var(--line);border-radius:7px;background:#fff}
.admin-subhead{font-family:var(--display);font-size:14px;font-weight:600;margin:22px 0 8px}
.admin-msg{font-size:12.5px;color:var(--slate)}
.admin-msg.ok{color:var(--ok)}
.admin-msg.err{color:var(--flag)}
.admin-dim{font-size:12.5px;color:var(--slate)}
.admin-mtime{font-family:var(--mono);font-size:11.5px;color:var(--slate)}
.admin-file{font-size:12px;color:var(--slate);max-width:220px}
.admin-errs{display:inline-block;margin-left:8px;font-size:12px}
.admin-errs summary{cursor:pointer;color:var(--flag)}
.admin-errdetail{font-family:var(--mono);font-size:11.5px;white-space:pre-wrap;background:var(--paper);border:1px solid var(--line);border-radius:6px;padding:8px 10px;margin:6px 0 0;max-width:520px;overflow-x:auto}
.admin-form{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:8px;align-items:end;margin-top:10px}
.admin-form input,.admin-form select{font-family:var(--body);font-size:13.5px;padding:7px 10px;border:1px solid var(--line);border-radius:7px;background:#fff;width:100%}
.admin-th{display:flex;flex-direction:column;gap:4px;font-size:11px;color:var(--slate);text-transform:uppercase;letter-spacing:.05em}
#adUserMsg{display:block;margin-top:10px}

/* ==== responsive pass (appended; overrides only — original rules above are untouched) ====
   Fixes the visible nav scrollbar and adds tablet/phone support. Acceptance bar:
   the page body never scrolls horizontally at 375px; wide content (tables) scrolls
   inside its own card instead. */

/* -- nav: allow horizontal scroll at any width, but hide the scrollbar chrome.
      A subtle right-edge fade hints that more tabs are off-screen. -- */
nav{
  overflow-x:auto;
  -webkit-overflow-scrolling:touch;
  scrollbar-width:none;            /* Firefox */
  -ms-overflow-style:none;         /* legacy Edge/IE */
  white-space:nowrap;
}
nav::-webkit-scrollbar{display:none} /* WebKit/Blink */

/* -- grid children may shrink below their content's intrinsic width; without this
      a Chart.js canvas (or wide table) props the column open and pushes the card
      past the viewport on narrow screens -- */
.grid>*{min-width:0}
@media(max-width:1100px){
  /* fade only where the nav can actually overflow, so the last tab isn't dimmed
     on wide screens */
  nav{
    -webkit-mask-image:linear-gradient(to right,#000 calc(100% - 32px),transparent);
    mask-image:linear-gradient(to right,#000 calc(100% - 32px),transparent);
  }
}

/* -- tablet (<=820px): .grid.two already collapses to one column here (the two-column
      rule is min-width:820px); tighten spacing and let the header wrap gracefully -- */
@media(max-width:820px){
  header{padding:18px 18px 0}
  .brand{gap:6px 12px}
  nav{margin-top:14px}
  main{padding:24px 16px 64px}
  h2{font-size:22px}
  .sub{margin-bottom:20px}
  .stats{grid-template-columns:repeat(auto-fit,minmax(140px,1fr))}
}

/* -- phone (<=560px) -- */
@media(max-width:560px){
  body{font-size:14px}
  .card{padding:14px}
  .chartbox{height:240px}
  .chartbox.tall{height:280px}
  /* wide tables scroll inside their card, never the page (works with or without
     an overflow wrapper div in the markup) */
  table{display:block;overflow-x:auto;-webkit-overflow-scrolling:touch;font-size:13px}
  th,td{padding:7px 8px}
  /* stat tiles: 2 per row */
  .stats{grid-template-columns:repeat(2,1fr);gap:10px}
  .stat{padding:12px 14px}
  .stat .v{font-size:21px}
  /* selects and control strips wrap instead of overflowing */
  select{max-width:100%}
  .controls,.admin-row,.admin-form{max-width:100%}
  /* chart tools strip: comfortable tap targets; keep the title clear of them */
  .tools button{min-width:40px;min-height:40px;padding:6px 8px}
  .card h3{padding-right:150px}
  .login-wrap .card h3,#modalCard h3{padding-right:40px}
  /* modal: near-full-screen with internal scroll */
  #modal{padding:0}
  #modalCard{width:94vw;max-width:94vw;max-height:88vh;padding:18px 16px}
  #modalBody .chartbox{height:50vh}
  /* login card: full width with 16px side margins */
  .login-wrap{max-width:none;margin:24px 16px 0}
  .login-wrap .card{padding:22px 18px}
  .admin-errdetail{max-width:100%}
}

/* -- very narrow (<=400px): drop the header tag line so the brand row fits -- */
@media(max-width:400px){
  .brand .tag{display:none}
}

/* ==== personalization pass (appended; overrides only — original rules above are
   untouched). Stars/hiding on every card, the view filter bar under the header
   nav, mini-tab strips inside flagship cards, and the collapsed restore row for
   hidden charts. ==== */

/* -- favorite star in the tools strip (filled + gold when on) -- */
.tools button[data-act="fav"]{font-size:13px;line-height:1}
.tools button[data-act="fav"].on{color:var(--gold);border-color:var(--gold)}

/* -- stat strips take an injected tools strip of their own (position context) -- */
.stats{position:relative}
.stats>.tools{top:4px;right:4px;opacity:.85}

/* -- view filter bar (under the header, above main) -- */
.viewbar{display:flex;gap:8px;align-items:center;flex-wrap:wrap;background:#fff;border-bottom:1px solid var(--line);padding:10px 32px}
.viewbar-l{font-family:var(--mono);font-size:11px;text-transform:uppercase;letter-spacing:.08em;color:var(--slate);margin-right:2px}
.vchip{font-family:var(--display);font-size:12px;font-weight:600;padding:5px 14px;border-radius:20px;border:1px solid var(--line);background:#fff;color:var(--slate);cursor:pointer}
.vchip:hover{color:var(--maroon);border-color:var(--maroon)}
.vchip.active{background:var(--maroon);border-color:var(--maroon);color:#fff}
.vchip:focus-visible,.minitabs button:focus-visible,.pref-show:focus-visible{outline:2px solid var(--maroon);outline-offset:1px}
.viewbar select{font-size:12.5px;padding:5px 10px;border-radius:20px}
.viewbar select.active{border-color:var(--maroon);color:var(--maroon)}

/* -- mini-tab strip inside a card header (maroon-soft ramp, chBehCat palette) -- */
.minitabs{display:flex;gap:4px;margin:6px 0 10px;flex-wrap:wrap}
.minitabs button{font-family:var(--display);font-size:12px;font-weight:600;padding:4px 12px;border:1px solid var(--line);border-radius:16px;background:#fff;color:var(--slate);cursor:pointer}
.minitabs button:hover{color:var(--maroon);border-color:#CB8391}
.minitabs button.active{background:var(--maroon-soft);border-color:#CB8391;color:var(--maroon)}

/* -- hidden charts: the container collapses to a single quiet restore row -- */
.pref-off{display:none!important}
.pref-hidden>:not(.pref-restore){display:none!important}
.card.pref-hidden{padding:10px 16px}
.stats.pref-hidden{display:block;background:#fff;border:1px solid var(--line);border-radius:10px;padding:10px 16px}
.chartbox.pref-hidden{height:auto!important;border:1px dashed var(--line);border-radius:8px;padding:10px 16px}
.pref-restore{display:flex;align-items:center;justify-content:space-between;gap:10px}
.pref-restore-t{font-family:var(--display);font-size:13px;color:var(--slate)}
.pref-show{font-family:var(--mono);font-size:11px;border:1px solid var(--line);background:#fff;color:var(--slate);border-radius:20px;padding:3px 12px;cursor:pointer}
.pref-show:hover{color:var(--maroon);border-color:var(--maroon)}

/* -- empty tab under a filter -- */
.view-empty{font-size:13px;color:var(--slate);font-style:italic;border:1px dashed var(--line);border-radius:10px;padding:14px 16px;margin-top:6px}

/* -- quiet hide control inside the expand modal -- */
.fs-hide-row{margin-top:8px;text-align:right}
.fs-hide{font-family:var(--mono);font-size:11px;border:none;background:none;color:var(--slate);cursor:pointer;text-decoration:underline}
.fs-hide:hover{color:var(--maroon)}

@media(max-width:820px){.viewbar{padding:8px 16px}}
@media(max-width:560px){
  .vchip,.minitabs button{min-height:32px}
  /* the tools strip gained a 4th button (star); reserve room so card titles
     wrap clear of it (extends the responsive pass's 150px rule) */
  .card h3{padding-right:200px}
  .login-wrap .card h3,#modalCard h3{padding-right:40px}
}

/* ==== admin: Veracross scope checklist + school data templates (appended;
   additions only — original rules above are untouched). ==== */

/* -- scope checklist under the Veracross buttons -- */
.vc-scopes{margin-top:8px}
.vc-sum{font-family:var(--mono);font-size:12px;margin:2px 0 6px}
.vc-sum.ok{color:var(--ok)}
.vc-sum.err{color:var(--flag)}
.vc-scope-row{display:flex;align-items:center;gap:8px;padding:2px 0;font-size:12.5px}
.vc-scope-row .mono{font-family:var(--mono);font-size:12px;color:var(--ink)}
.vc-scope-row .admin-dim{font-size:11.5px}

/* -- school data templates block under the Datasets table -- */
.admin-tmpl{display:flex;flex-direction:column;gap:2px}
.admin-tmpl-row{display:flex;align-items:baseline;gap:12px;padding:4px 0;border-bottom:1px solid var(--line);flex-wrap:wrap}
.admin-tmpl-row:last-child{border-bottom:none}
.admin-tmpl-row .mono{font-family:var(--mono);font-size:12.5px;min-width:120px}
.admin-tmpl-row .admin-dim{flex:1;min-width:180px}
.admin-tmpl-dl{font-family:var(--mono);font-size:11.5px;color:var(--teal);white-space:nowrap}
.admin-tmpl-dl:hover{color:var(--maroon)}

/* ---- annual report pack (Phase 3; appended) ---- */
.rp-btn{margin-left:auto;font-family:var(--display);font-size:12px;font-weight:600;padding:5px 14px;border-radius:20px;border:1px solid var(--maroon);background:#fff;color:var(--maroon);cursor:pointer;white-space:nowrap}
.rp-btn:hover{background:var(--maroon);color:#fff}
.rp-scope{display:grid;gap:8px}
.rp-scope label{display:flex;align-items:center;gap:8px;font-size:14px;cursor:pointer}
.rp-scope select{margin-left:4px;font-size:13px;padding:4px 8px;border-radius:6px;border:1px solid var(--line)}
#rpBuild{font-family:var(--display);font-size:13px;font-weight:600;background:var(--maroon);color:#fff;border:none;border-radius:8px;padding:9px 18px;cursor:pointer}
#rpBuild:hover{filter:brightness(1.1)}
#rpBuild:disabled{opacity:.6;cursor:default}
#rpProg{font-family:var(--mono);font-size:12px;min-height:16px}
/* During a pack build, view-filtered cards must lay out so charts can size. */
body.packshot .pref-off{display:block!important}
body.packshot .stats.pref-off{display:grid!important}

/* ==== head-of-school polish pass (appended; additions and overrides only —
   original rules above are untouched). ==== */

/* -- accreditation-framework chips under card titles (core.js makeChart).
      Reference-only frameworks (IB/CIS) render lighter with a dashed outline
      and carry the 'reference only' tooltip. -- */
.fwchips{display:flex;gap:4px;flex-wrap:wrap;margin:2px 0 10px}
.fwchip{font-family:var(--mono);font-size:10px;letter-spacing:.02em;padding:1px 8px;border-radius:10px;background:#F0EEE8;color:var(--slate);white-space:nowrap}
.fwchip.ref{background:none;border:1px dashed var(--line);color:#B4AFA3;cursor:help}

/* -- framework filter (view bar select): hidden cards use the same
      display:none collapse as the prefs template filter, and compose with it
      (a card shows only when neither filter hides it). -- */
.fw-off{display:none!important}
body.packshot .fw-off{display:block!important}
body.packshot .stats.fw-off{display:grid!important}

/* -- report pack as a quiet ghost button (admin + leadership only) -- */
.rp-btn.ghost{border-color:var(--line);color:var(--slate);background:#fff}
.rp-btn.ghost:hover{background:#fff;border-color:var(--maroon);color:var(--maroon)}

/* -- stat tiles: 3-year mini-trend row under the big number -- */
.stat .t3{font-family:var(--mono);font-size:10.5px;color:var(--slate);margin-top:4px;line-height:1.6;overflow-wrap:anywhere}

/* -- MAP tab note width fix. The Bands/Growth mini-tab notes were reported
      cut to ~60% width: the phone-width tools reservation (.card h3
      {padding-right:200px} at <=560px, ~60% of a ~500px card) squeezes the
      whole card header column, and notes/mini-tab strips must never inherit
      any such reservation. Fix properly: (1) pin .note and .minitabs to the
      card's full content width, immune to header reservations; (2) at phone
      widths, give tool-strip cards a real top band for the buttons (via
      :has) and release the h3 squeeze entirely — titles, mini-tabs, and
      notes all get the full card width. -- */
.card>.note,.card>.minitabs{width:100%;max-width:100%;padding-right:0}
@media(max-width:560px){
  .card:has(>.tools){padding-top:56px}
  .card:has(>.tools) h3{padding-right:0}
  .card:not(:has(>.tools)) h3{padding-right:0}
  .card>.tools{top:8px;right:10px}
}

/* -- Surveys section (admin + leadership): audience pill strip, per-question
      100%-stacked HTML bars (divs, not canvas — cheap, responsive, printable),
      grouping headers, alias-review card. Appended per the append-only rule. -- */
#surveyTabs.minitabs{margin:0 0 18px}
.sv-head{display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin-bottom:12px}
.sv-mini{position:relative;width:170px;height:44px;flex:0 0 auto}
.sv-legend{display:flex;gap:14px;flex-wrap:wrap;font-size:11.5px;color:var(--slate);margin:0 0 14px}
.sv-legend span{display:flex;align-items:center}
.sv-legend i{display:inline-block;width:10px;height:10px;border-radius:2px;margin-right:5px;flex:0 0 auto}
.sv-group{font-family:var(--display);font-size:13px;font-weight:600;color:var(--ink);margin:20px 0 2px}
.svq{padding:9px 0;border-bottom:1px solid var(--line)}
.svq:last-child{border-bottom:none}
.svq-top{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap;margin-bottom:5px}
.svq-text{font-size:12.5px;line-height:1.45;min-width:0}
.sv-chip{font-family:var(--mono);font-size:10.5px;color:var(--slate);background:#F0EEE8;border-radius:10px;padding:1px 7px;white-space:nowrap}
.svq-row{display:flex;align-items:center;gap:12px}
.svq-bar{flex:1 1 auto;display:flex;height:22px;border-radius:4px;overflow:hidden;min-width:0}
.svq-seg{display:flex;align-items:center;justify-content:center;font-family:var(--mono);font-size:10.5px;overflow:hidden;white-space:nowrap;min-width:0}
.svq-meta{flex:0 0 auto;width:150px;font-family:var(--mono);font-size:11.5px;color:var(--slate);text-align:right;line-height:1.5}
.svq-meta .pos{color:var(--maroon);font-weight:500}
.svq-meta .d{font-size:10.5px;margin-top:0}
.sv-suppressed{font-size:12px;color:var(--slate);font-style:italic}
.sv-alias-row{display:flex;align-items:center;gap:14px;padding:10px 0;border-bottom:1px solid var(--line);flex-wrap:wrap}
.sv-alias-row:last-child{border-bottom:none}
.sv-alias-q{flex:1 1 260px;min-width:0;font-size:12.5px;line-height:1.45}
.sv-alias-arrow{font-size:11px;color:var(--slate);font-style:italic;margin:2px 0}
.sv-alias-btns{display:flex;gap:8px;flex:0 0 auto}
.sv-alias-btns button[disabled]{opacity:.5;cursor:not-allowed}
@media(max-width:560px){
  .svq-row{flex-wrap:wrap;gap:6px}
  .svq-meta{width:100%;text-align:left}
  .sv-mini{width:130px;height:38px}
  .sv-alias-btns{width:100%}
}

/* ==== Surveys v2 (head-of-school review pass) — appended block owned by the
   surveys builder. Additions only; nothing above this comment is modified.
   Covers: clickable question rows (real <button>s), SY tags, the per-audience
   overview panel, the compare-last-3-years rows, the question detail modal and
   the collapsed Data sources card. ==== */

/* -- clickable question rows. The row is a real <button> so it is keyboard
      reachable and announced as a control; the reset below removes the UA
      chrome and restores the .svq layout the div rows had. -- */
button.svq{display:block;width:100%;max-width:100%;text-align:left;font:inherit;color:inherit;background:none;border:none;border-bottom:1px solid var(--line);border-radius:0;padding:9px 4px 9px 0;margin:0;cursor:pointer}
button.svq:last-child{border-bottom:none}
button.svq:hover{background:var(--maroon-soft)}
button.svq:focus-visible{outline:2px solid var(--maroon);outline-offset:-2px}
.svq .sv-suppressed{display:block;margin-top:2px}
.svq-meta .d{display:block}
.svq-more{margin-left:auto;flex:0 0 auto;font-family:var(--mono);font-size:10px;color:#B4AFA3;opacity:.6;white-space:nowrap}
button.svq:hover .svq-more,button.svq:focus-visible .svq-more{opacity:1;color:var(--maroon)}

/* -- SY tags: which school years asked this question (Nick's parent-survey ask) -- */
.sv-yrs{display:inline-flex;gap:3px;flex-wrap:wrap}
.sv-yr{font-family:var(--mono);font-size:9.5px;letter-spacing:.02em;color:#8A857A;background:#F5F3EE;border-radius:8px;padding:1px 5px;white-space:nowrap}

/* -- per-audience overview panel: caution pill + strongest / weakest / movers -- */
.pill.warn{background:#FBF0DA;color:#8A6100}
.sv-caution{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin:-6px 0 20px}
.sv-caution-t{font-size:12.5px;color:var(--slate)}
.sv-lists{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:18px}
.sv-list h4{font-family:var(--display);font-size:11.5px;font-weight:600;text-transform:uppercase;letter-spacing:.06em;color:var(--slate);margin:0 0 8px}
.sv-list ul{list-style:none;margin:0;padding:0}
.sv-list li{display:flex;align-items:baseline;gap:10px;padding:5px 0;border-bottom:1px solid var(--line);font-size:12.5px;line-height:1.4}
.sv-list li:last-child{border-bottom:none}
.sv-li-t{flex:1 1 auto;min-width:0;overflow-wrap:anywhere}
.sv-li-r{flex:0 0 auto;text-align:right;white-space:nowrap}
.sv-li-v{font-family:var(--mono);font-size:11.5px;color:var(--maroon);font-weight:500}
.sv-li-n{display:block;font-family:var(--mono);font-size:9.5px;color:#B4AFA3}
.sv-li-r .d{font-family:var(--mono);font-size:11.5px;margin:0}

/* -- compare last 3 years: three positive-% mini bars per question row -- */
.sv-cmp-cap{font-size:11.5px;color:var(--slate);font-style:italic;margin:0 0 12px}
.svc-row{display:flex;align-items:center;gap:14px;flex-wrap:wrap}
.svc-cell{display:flex;align-items:center;gap:6px;flex:1 1 160px;min-width:0}
.svc-y{font-family:var(--mono);font-size:10px;color:#8A857A;flex:0 0 52px}
.svc-bar{display:block;flex:1 1 auto;min-width:0;height:9px;border-radius:5px;background:#F0EEE8;overflow:hidden}
.svc-bar i{display:block;height:100%;background:var(--teal);border-radius:5px}
.svc-p{font-family:var(--mono);font-size:11px;color:var(--ink);flex:0 0 44px;text-align:right}
.svc-d{flex:0 0 auto;font-family:var(--mono);font-size:11px}

/* -- question detail modal -- */
.svm-q{font-size:14.5px;line-height:1.5;color:var(--ink);margin-bottom:4px}
.svm-sub{font-size:12px;color:var(--slate);margin-bottom:8px}
.svm-years{margin-bottom:6px}
.svm-h{font-family:var(--display);font-size:13px;font-weight:600;color:var(--ink);margin:18px 0 8px}
.svm-cmp{margin-bottom:4px}
.svm-adm{padding:10px 0;border-bottom:1px solid var(--line)}
.svm-adm:last-of-type{border-bottom:none}
.svm-adm-h{font-family:var(--mono);font-size:11.5px;color:var(--slate);margin-bottom:6px}
.svm-adm-h .pos{color:var(--maroon)}
.svm-opts{list-style:none;margin:8px 0 0;padding:0}
.svm-opts li{display:flex;align-items:center;gap:8px;font-size:12px;padding:2px 0}
.svm-opts i{display:inline-block;width:9px;height:9px;border-radius:2px;flex:0 0 auto}
.svm-ol{flex:1 1 auto;min-width:0;overflow-wrap:anywhere}
.svm-ov,.svm-op{font-family:var(--mono);font-size:11.5px;color:var(--slate);flex:0 0 auto;text-align:right}
.svm-ov{width:46px}
.svm-op{width:54px}
.svm-cap{font-size:11px;color:var(--slate);font-style:italic;margin-top:6px}
.svm-seg{padding:8px 0}
.svm-seg-h{font-family:var(--mono);font-size:11.5px;color:var(--slate);margin-bottom:5px}

/* -- collapsed "Data sources" card on the Surveys overview -- */
details.sv-sources{margin-top:20px}
details.sv-sources>summary{font-family:var(--display);font-size:15px;font-weight:600;color:var(--ink);cursor:pointer;list-style:none}
details.sv-sources>summary::-webkit-details-marker{display:none}
details.sv-sources>summary::before{content:'\25B8  ';color:var(--slate);font-size:11px}
details.sv-sources[open]>summary::before{content:'\25BE  '}
details.sv-sources>summary:focus-visible{outline:2px solid var(--maroon);outline-offset:2px}
.sv-src-tbl{margin-top:8px}
.sv-src-f{overflow-wrap:anywhere}
.sv-sha{font-family:var(--mono);font-size:10px;color:#B4AFA3}

@media(max-width:560px){
  .sv-lists{grid-template-columns:1fr}
  .svc-cell{flex:1 1 100%}
  .svc-row{gap:8px}
  .svq-more{margin-left:0}
  .sv-caution{margin-top:0}
  .svm-opts li{font-size:11.5px}
  .svm-ov{width:38px}
  .svm-op{width:46px}
}

/* ==== reviewed-feedback wave (appended; additions and overrides only —
   every rule above is untouched). Chart-wide 3-year compare, accreditation
   chip cleanup, role gating, gap placeholders. ==== */

/* -- accreditation chips: the reference tooltip and its explanatory note are
      gone (head of school), so the help cursor goes with them. IB/CIS chips
      stay visually lighter — a label, nothing more. -- */
.fwchip.ref{cursor:default}

/* -- year picker: 'Compare last 3 years' first, then individual years. Slightly
      wider than a plain select so the compare label never truncates. -- */
.yearsel{min-width:190px}
@media(max-width:560px){.yearsel{min-width:0;width:100%}}

/* -- role gating: Data Map (and any other leadership-only section) is hidden by
      attribute for roles that may not see it, and `hidden` must beat the
      section.active display rule. -- */
section[hidden],nav button[hidden]{display:none!important}

/* -- gap placeholders: quiet, muted cards naming a chart that has no source yet
      and what would light it up. Never compete with real data; they drop out of
      the ★ Favorites view entirely. -- */
.gap-card{background:#FCFBF8;border-style:dashed;box-shadow:none}
.gap-card h3{color:var(--slate);font-weight:600}
.gap-card h3 .pill{vertical-align:2px;margin-left:6px}
.gap-card .note{margin-bottom:12px}
.gap-l{font-family:var(--mono);font-size:10.5px;text-transform:uppercase;letter-spacing:.08em;color:#B4AFA3;margin-top:10px}
.gap-t{font-size:12.5px;color:var(--slate);line-height:1.55;margin-top:3px}
section>.gap-card{margin-top:20px}
body.view-fav .gap-card{display:none!important}

/* -- settings-driven target line on a stat tile (map_participation.targets;
      colouring only — the numbers themselves are never changed by a target) -- */
.stat .goal{font-family:var(--mono);font-size:10.5px;margin-top:3px}
.stat .goal.met{color:var(--ok)}
.stat .goal.under{color:var(--flag)}

/* ==== audit follow-up wave (appended; comments and overrides only — every
   rule above is untouched). ==== */

/* -- Correction to the comment above the .fwchip rules (the 'head-of-school
      polish pass' block): it still says reference-only chips 'carry the
      "reference only" tooltip' and its .fwchip.ref rule still sets
      cursor:help. Both are stale. The tooltip and its explanatory note were
      removed at the head of school's request, and the later 'reviewed-feedback
      wave' block already overrides the cursor with .fwchip.ref{cursor:default}
      — that override wins, so the help cursor never renders. The chips are
      labels only: no hover text, no help cursor, just a lighter dashed style.
      The stale lines are left in place because this stylesheet is append-only;
      read them as superseded by this note and by the cursor:default rule. -- */

/* ==== admin wave: report pack moved into Admin, user edit/remove (appended;
   additions and overrides only — every rule above is untouched). ==== */

/* -- The Report pack no longer renders in the view bar. Head of school,
      Aug 2026: "I worry it is too accessible ... Review and hide in the Admin
      settings I think is best." The .rp-btn / .rp-btn.ghost rules above are
      therefore dead (nothing carries that class any more); they are left in
      place because this stylesheet is append-only. .rp-scope and body.packshot
      are still live: the scope radios moved with the feature into the Admin
      "Data & sync" card, and packshot is what lets view-filtered cards lay out
      while the pack is being rendered. -- */
.admin-rp .rp-scope{margin-top:14px}
.admin-rp .rp-scope label{font-size:13.5px}
.admin-rp .hint{margin-top:12px}

/* -- Users pane: inline-editable name/email cells and the Remove control.
      The cell shows its value with a quiet text-button affordance; editing
      swaps in an input plus Save/Cancel, so the row height barely moves.
      Nick could not find the controls before ("I only see adding"), so Edit
      stays visible at rest — quiet, but never hover-only. -- */
.u-cell{display:inline-flex;align-items:center;gap:6px;flex-wrap:wrap;max-width:100%}
.u-val{overflow-wrap:anywhere}
.u-cell .u-edit{font-family:var(--display);font-size:11px;font-weight:600;color:var(--slate);background:none;border:none;border-bottom:1px dotted var(--line);padding:0 1px;cursor:pointer;opacity:.7;transition:opacity .12s,color .12s}
.u-cell .u-edit:hover,.u-cell .u-edit:focus-visible{opacity:1;color:var(--maroon);border-bottom-color:var(--maroon)}
.u-input{font-family:var(--body);font-size:13px;padding:5px 8px;border:1px solid var(--line);border-radius:6px;background:#fff;min-width:150px;max-width:230px}
.u-cell .btn-admin{font-size:11.5px;padding:5px 9px}
.u-msg{display:block;margin-top:5px;max-width:230px}

/* ==== School Life climate strips (appended; additions only — every rule above
   is untouched). public/js/tabs/climate.js renders two cards driven by the
   survey question bank, in the slots the Chapel and climate gap placeholders
   used to hold. .clim-q is the quiet "how many questions matched" counter that
   keeps the cards honest about what they are measuring; .clim-sub is the
   per-theme line under the mini-tab strip; .clim-foot is the shared suppression
   footnote that sits under both cards rather than being repeated in each. ==== */
.clim-wrap .card .note{margin-bottom:10px}
.clim-q{color:var(--slate);font-variant-numeric:tabular-nums;white-space:normal}
.clim-sub{margin-top:2px}
.clim-tail{display:inline-block;margin-top:2px}
.clim-foot{font-size:12px;color:var(--slate);margin-top:10px;max-width:900px}

/* ==== student lookup wave (head of school, Aug 2026: "How can I lookup S-8D3B
   to see who they are? ... with permissions or a log of the lookup?" and "Why
   under 'Literacy' page, there is a Chronic absence watch section?").
   Appended; additions only — every rule above is untouched. ==== */

/* -- The S-XXXX label as an affordance. It has to read as clickable without
      shouting: the anonymous label is still the primary text, with a dotted
      underline saying "there is more behind this". Rendered ONLY for admin and
      leadership (tabs/literacy.js studentCellHtml); every other role gets the
      same label as plain text, so the two states line up in the same column. -- */
button.slookup{font-family:var(--mono);font-size:inherit;color:var(--ink);background:none;border:none;border-bottom:1px dotted var(--slate);padding:0 1px;cursor:pointer;transition:color .12s,border-color .12s}
button.slookup:hover,button.slookup:focus-visible{color:var(--maroon);border-bottom-color:var(--maroon)}
.lookup-hint{font-size:12px;color:var(--slate);font-style:italic;margin:6px 0 2px}

/* -- The lookup modal. The name is the answer, so it leads; the audit note is
      not a footnote — it sits in a bordered block that is always present, on
      the same screen, in plain words. -- */
.lookup-head{font-family:var(--mono);font-size:13px;color:var(--slate);letter-spacing:.06em;margin-bottom:12px}
.lookup-wait{font-size:13px;color:var(--slate);font-style:italic}
.lookup-hit{border-left:3px solid var(--maroon);padding:8px 0 8px 12px;margin-bottom:12px}
.lookup-name{font-family:var(--display);font-size:20px;font-weight:600;color:var(--ink);overflow-wrap:anywhere}
.lookup-grade{font-size:13px;color:var(--slate);margin-top:2px}
.lookup-multi{font-size:13px;color:var(--flag);margin-bottom:12px}
.lookup-err{font-size:14px;color:var(--ink);margin-bottom:14px}
.lookup-audit{border:1px solid var(--line);border-left:3px solid var(--slate);background:var(--paper);border-radius:0 6px 6px 0;padding:10px 12px;font-size:12.5px;line-height:1.55;color:var(--slate)}

/* ==== cohort view redesign (appended; additions only — every rule above is
   untouched). Head of school, Aug 2026: "'Cohort trends by measure' is hard to
   read, I would prefer year by year ... Cohort information can be very helpful
   if clear." The eleven-line chart lost its Chart.js legend: the classes are
   now named by a chip strip under the chart that doubles as the focus control,
   and the "Year by year" view prints the grade x school-year grid as a table
   beneath the chart. Both live inside the #chDra card. ==== */
.coh-chips{display:flex;gap:6px;flex-wrap:wrap;margin:12px 0 0}
.coh-chip{display:inline-flex;align-items:center;gap:6px;font-family:var(--display);font-size:11.5px;font-weight:600;padding:3px 10px;border:1px solid var(--line);border-radius:14px;background:#fff;color:var(--slate);cursor:pointer;white-space:nowrap}
.coh-chip:hover{color:var(--maroon);border-color:#CB8391}
.coh-chip:focus-visible{outline:2px solid var(--maroon);outline-offset:1px}
.coh-chip.on{background:var(--maroon-soft);border-color:#CB8391;color:var(--maroon)}
.coh-chip .coh-sw{width:9px;height:9px;border-radius:2px;background:var(--coh,var(--slate));flex:none}
.coh-chip.coh-all .coh-sw{display:none}
/* graduated classes: quieter, and the swatch goes hollow to match the dashed line */
.coh-chip.gone{opacity:.7}
.coh-chip.gone .coh-sw{background:none;border:1px dashed var(--coh,var(--slate))}
.coh-tablewrap{margin-top:16px;overflow-x:auto}
.coh-grid{font-size:12.5px}
.coh-grid th,.coh-grid td{padding:6px 10px;vertical-align:top}
.coh-grid tbody th{font-family:var(--mono);font-size:12px;text-transform:none;letter-spacing:0;color:var(--ink);border-bottom:1px solid var(--line);white-space:nowrap}
.coh-grid td.mono{font-size:12.5px}
.coh-sub{display:block;font-family:var(--body);font-size:10.5px;color:var(--slate);letter-spacing:0;text-transform:none;margin-top:1px}
.coh-d.up{color:var(--ok)}
.coh-d.dn{color:var(--flag)}
.coh-d.flat{color:var(--slate)}
@media(max-width:700px){.coh-chips{gap:5px}.coh-chip{min-height:32px}}

/* ==== login-flash fix + Admin access log (appended; additions only — every rule
   above is untouched).

   1) PRE-AUTH PAINT. Nick, Aug 2026: "When I load https://sap.ocsi.jp/ there is
      a short second that I can see everything (the dashboard) just before the
      log screen appears. It is likely just page load order but looks bad as if
      security is weak." It was exactly page-load order — index.html shipped the
      whole shell and main.js hid it only after /api/auth/status came back.
      The app container now ships hidden BY DEFAULT, in CSS, and public/js/main.js
      removes .app-locked in one place, after the auth answer. No stylesheet, no
      script, no slow network and no JS error can make the dashboard paint before
      the server has said who is asking; the boot card below is all that shows.
      Belt and braces on the display:none — a later rule cannot un-hide it. ==== */
#app.app-locked{display:none!important}
.boot-screen{max-width:420px;margin:8vh auto 0;padding:0 24px}
.boot-card{background:#fff;border:1px solid var(--line);border-radius:10px;padding:30px;text-align:center}
.boot-brand{font-family:var(--display);font-weight:700;font-size:22px;letter-spacing:-.01em}
.boot-brand span{color:var(--maroon)}
.boot-note{font-size:12.5px;color:var(--slate);margin-top:10px}
@media(max-width:560px){.boot-screen{margin:24px 0 0;padding:0 16px}.boot-card{padding:22px 18px}}

/* 2) ACCESS LOG (Admin -> Access log). Nick: "Student lookup worked, where is
      that log? If possible have the Admin area have an access log dashboard
      there." Table of audit_log rows: time, actor, action, detail. The detail
      column is JSON written by the server, rendered as key:value chips.
      Student-lookup rows are the reason this page exists — a lookup is the one
      action in the system that turns S-XXXX back into a child — so those rows
      carry a maroon rail and a tinted background instead of being one grey line
      among hundreds. Denied attempts get the red pill: someone without the role
      trying is more interesting than someone with it succeeding. */
.al-filters{display:flex;gap:10px;align-items:flex-end;flex-wrap:wrap;margin-bottom:16px}
.al-f{display:flex;flex-direction:column;gap:4px}
.al-f label{font-family:var(--display);font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.06em;color:var(--slate)}
.al-f input,.al-f select{font-family:var(--body);font-size:13px;padding:6px 9px;border:1px solid var(--line);border-radius:7px;background:#fff;color:var(--ink);min-width:150px}
.al-table{table-layout:auto}
.al-table td{vertical-align:top}
.al-when{font-family:var(--mono);font-size:12px;color:var(--slate);white-space:nowrap}
.al-actor{font-size:12.5px;overflow-wrap:anywhere}
.al-actor .al-sys{color:var(--slate);font-style:italic}
.al-action{font-family:var(--mono);font-size:12px}
.al-chips{display:flex;gap:5px;flex-wrap:wrap}
.al-chip{display:inline-flex;align-items:baseline;gap:4px;font-family:var(--mono);font-size:11px;background:#F0EEE8;color:var(--slate);border-radius:5px;padding:2px 7px;max-width:100%;overflow-wrap:anywhere}
.al-chip b{font-weight:500;color:var(--ink)}
.al-none{color:var(--slate);font-style:italic;font-size:12px}
/* the rows the log exists for */
.al-table tr.al-look td{background:var(--maroon-soft)}
.al-table tr.al-look td:first-child{box-shadow:inset 3px 0 0 var(--maroon)}
.al-table tr.al-look:hover td{background:#EFD9DD}
.al-table tr.al-look .al-action{color:var(--maroon);font-weight:500}
.al-page{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin-top:14px}
.al-count{font-size:12.5px;color:var(--slate)}
@media(max-width:560px){.al-f input,.al-f select{min-width:0;width:100%}.al-f{flex:1 1 140px}}

/* ==== survey detail fixes (head of school, Aug 2026: "clicking any question in
   Event Feedback brings the same popup" + "staff exit popup and main chart seem
   to have a data issue") — appended block owned by the surveys builder;
   additions only, every rule above is left untouched. Two new pieces of the
   question modal: the per-EVENT comparison rows (the event audience is not a
   time series — one school year, twelve events, one shared question set) and
   the all-years pooled block plus its plain-language "why not year by year"
   note for audiences whose yearly cells are all under the floor. ==== */
.svm-ev{padding:9px 0;border-bottom:1px solid var(--line)}
.svm-ev:last-of-type{border-bottom:none}
.svm-ev-h{display:flex;align-items:baseline;gap:10px;margin-bottom:5px}
.svm-ev-n{font-size:12.5px;font-weight:600;color:var(--ink);flex:1 1 auto;min-width:0;overflow-wrap:anywhere}
.svm-ev-m{font-family:var(--mono);font-size:11.5px;color:var(--slate);flex:0 0 auto;white-space:nowrap}
.svm-ev-m .pos{color:var(--maroon)}
.svm-ev.held .svm-ev-n{font-weight:400;color:var(--slate)}
.svm-held{margin-top:14px;padding-top:10px;border-top:1px dashed var(--line)}
.svm-held .svm-ev{padding:3px 0;border-bottom:none}
.svm-why{font-size:12.5px;line-height:1.55;color:var(--ink);background:var(--maroon-soft);border-left:3px solid var(--maroon);border-radius:0 7px 7px 0;padding:9px 12px;margin:14px 0 4px}
.svm-yns{display:flex;flex-wrap:wrap;gap:6px 8px}
.svm-yn{font-family:var(--mono);font-size:11.5px;color:var(--slate);background:#F0EEE8;border-radius:5px;padding:2px 8px}
.svm-yn b{font-weight:500;color:var(--ink)}
@media(max-width:560px){.svm-ev-h{flex-wrap:wrap;gap:2px 10px}.svm-ev-m{white-space:normal}}

/* ==== homeroom lens + cohort coverage panel (appended; additions only — every rule
   above is untouched).

   Head of school, Aug 2026, two complaints answered here.

   1) "Homeroom snapshot section is currently meaningless ... I only want 3 year
      patterns and if a cohort plays a role in that aspect. There is also an issue
      visually with the columns exceeding the space box." The card used to put a
      six-column table (two of them MAP) into one half of a .grid.two, which at the
      1080px main width left the columns running past the card edge. MAP is gone and
      the table is now full width inside .hr-wrap, which is the ONLY thing allowed to
      scroll sideways: overflow-x on the wrapper, nowrap on the cells so the columns
      keep their shape, and max-width:100% so the card is never pushed wider than the
      page. The card itself never scrolls.

   2) "A lot of the 'Cohort trends by measure' charts are blank, but I believe there
      should be data to generate such." An empty chart box is replaced by .coh-cov —
      the years and grades that DO hold data — so "blank" always comes with a reason. */
.coh-cov{margin:14px 0 0;overflow-x:auto}
.coh-cov-t{font-size:12.5px;width:auto;min-width:100%}
.coh-cov-t th,.coh-cov-t td{padding:6px 10px;white-space:nowrap}
.coh-cov-t tbody th{font-family:var(--mono);font-size:12px;text-transform:none;letter-spacing:0;color:var(--ink);border-bottom:1px solid var(--line)}

/* the wide table: it scrolls, the card does not */
.hr-wrap{margin-top:16px;overflow-x:auto;max-width:100%}
.hr-table{font-size:12.5px;width:auto;min-width:100%}
.hr-table th,.hr-table td{padding:6px 10px;vertical-align:top;white-space:nowrap}
.hr-table tbody th{font-family:var(--mono);font-size:12px;text-transform:none;letter-spacing:0;color:var(--ink);border-bottom:1px solid var(--line);text-align:left}
.hr-table td.mono{font-size:12.5px}
.hr-table tbody th .coh-sub{font-family:var(--body)}
#hrVerdict{margin-top:12px}
@media(max-width:700px){.hr-table th,.hr-table td{padding:5px 8px}}

/* ==== School climate "What is being measured" (appended; additions only —
   climate.js's question-detail modal and cross-links, Aug 2026). .clim-measure
   opens the modal listing each theme's ACTUAL matched questions; .clim-qrow is
   one question (wording left, its own latest positive share right), weakest
   first; .clim-qna is the withheld dash; .clim-chg the changed-question-set
   note under a trend; .clim-def the one-sentence pooled-share definition;
   .clim-govsurveys the 'Surveys tab' jump every card tail carries. */
.clim-measure,.clim-govsurveys{background:none;border:none;padding:0;font:inherit;font-size:inherit;color:var(--teal);cursor:pointer;text-decoration:underline;text-underline-offset:2px}
.clim-measure:hover,.clim-govsurveys:hover{color:var(--maroon)}
.clim-measure{white-space:nowrap}
.clim-chg{margin-top:4px;color:var(--slate);font-size:12px}
.clim-def{margin-bottom:12px;font-weight:600}
.clim-qgrp{margin-bottom:16px}
.clim-qhead{font-weight:600;margin-bottom:2px}
.clim-qrow{display:flex;width:100%;gap:10px;align-items:baseline;text-align:left;background:none;border:none;border-top:1px solid var(--line);padding:6px 2px;font:inherit;color:inherit;cursor:pointer}
.clim-qrow:hover{background:var(--maroon-soft)}
.clim-qtext{flex:1 1 auto}
.clim-qval{font-variant-numeric:tabular-nums;font-weight:600;white-space:nowrap}
.clim-qna{color:var(--slate);font-weight:400}
.clim-qmeta{color:var(--slate);font-size:12px;white-space:nowrap;font-variant-numeric:tabular-nums}
.clim-mnote{margin-top:6px}

/* ==== KPI viewability + menu/responsive polish wave (Nick, Aug 2026; appended;
   additions and overrides only — every rule above is untouched).

   Three requests answered here.
   1) "I like these KPI chart views... increase the size but also allow
      expanding." The per-KPI mini tiles (tabs/kpis.js) move their inline
      styling into the .kpi-mini* classes below: taller chart box (150px, was
      96px), wider minimum tile so the grid drops columns before it squeezes
      charts, and a quiet expand button in each tile's corner. The inline
      minmax(230px,1fr) grid in kpis.js is the pinned baseline
      (test/kpis_v2.test.js); the .kpi-minigrid overrides below are what
      actually lay it out, hence the !important.
   2) "the system and menu mobile or responsive screen size if and where
      possible." Polish over the existing responsive pass: the nav strip stays
      one momentum-scrolling row (never wraps), nav/sub-tab touch targets reach
      40px+, stat tiles finish the 4 -> 2 -> 1 ladder, chart cards keep a sane
      minimum height, and the modal goes full-bleed on phones.
   3) The nav reorder itself lives in index.html/main.js; no CSS needed. ==== */

/* -- KPI mini tiles (tabs/kpis.js chart view) -- */
.kpi-mini{position:relative;border:1px solid var(--line);border-radius:8px;padding:10px 12px}
.kpi-mini-name{font-size:11.5px;line-height:1.35;min-height:46px;color:var(--ink);padding-right:34px}
.kpi-mini-val{font-family:var(--mono);font-size:15px;color:var(--maroon);margin:2px 0 4px}
.kpi-minibox{height:150px;position:relative}
.kpi-minibox-empty{display:flex;align-items:center;justify-content:center;color:var(--slate);font-size:12px}
.kpi-expand{position:absolute;top:8px;right:8px;font-family:var(--mono);font-size:12px;line-height:1;border:1px solid var(--line);background:#fff;color:var(--slate);border-radius:6px;padding:5px 7px;cursor:pointer}
.kpi-expand:hover,.kpi-expand:focus-visible{color:var(--maroon);border-color:var(--maroon)}
/* wider tile minimum than the pinned inline 230px, so charts stay wide and the
   auto-fill grid sheds columns sooner; one column on phones */
.kpi-minigrid{grid-template-columns:repeat(auto-fill,minmax(300px,1fr))!important;gap:12px!important}
@media(max-width:560px){
  .kpi-minigrid{grid-template-columns:1fr!important}
  .kpi-expand{min-width:40px;min-height:40px}
}

/* -- chart cards keep a sane minimum even where a future rule shrinks them
      (:not so the collapsed hidden-chart restore row above stays collapsed) -- */
.chartbox:not(.pref-hidden){min-height:200px}

/* -- nav strip: one row with momentum scrolling at every width (the base rules
      above already set overflow-x:auto + -webkit-overflow-scrolling:touch);
      comfortable touch targets on touch-sized screens -- */
nav{flex-wrap:nowrap}
@media(max-width:820px){
  nav button{min-height:44px;padding:10px 14px}
  .minitabs button{min-height:40px}   /* supersedes the earlier 32px at <=560px */
  .vchip{min-height:40px}
}

/* -- stat tiles: finish the 4 -> 2 -> 1 ladder (2-up at <=560px is above) -- */
@media(max-width:400px){
  .stats{grid-template-columns:1fr}
}

/* -- view bar wraps gracefully; the freshness chip takes its own line instead
      of forcing a squeeze (its inline margin-left:auto needs the !important) -- */
@media(max-width:560px){
  .viewbar{row-gap:8px}
  #dataFresh{margin-left:0!important;flex-basis:100%}
}

/* -- modal: full-bleed on phones (was 94vw); the card scrolls internally -- */
@media(max-width:560px){
  #modal{padding:0}
  #modalCard{width:100%;max-width:none;height:100%;max-height:none;border-radius:0;padding:18px 14px 24px}
}

/* ---------------------------------------------------------------------------
   SCHOOL LIFE: attendance/behavior context (Nick, Aug 2026). APPEND-ONLY block.
   - .prestart: the "school year starts Aug 24 — attendance begins then" state
     for cards whose per-day data is entirely pre-entered future rows.
   - .chronic-single: one completed year of chronic-absence history rendered as
     a value statement instead of a lone dot on an empty 3-year axis.
   - .stats.mini: the smaller referral-context tiles above the behavior charts.
--------------------------------------------------------------------------- */
.prestart{background:var(--paper,#faf8f5);border:1px dashed var(--line);border-radius:8px;
  padding:22px 18px;margin-top:12px;text-align:center;font-size:14px;color:var(--slate)}
.chronic-single{padding:14px 4px 4px;text-align:center}
.chronic-single .v{font-family:var(--mono);font-size:44px;font-weight:500;color:var(--flag)}
.chronic-single .v small{font-size:18px;color:var(--slate);font-weight:400}
.chronic-single .t{font-size:13px;color:var(--ink);margin-top:4px}
.chronic-single .hint{margin-top:8px}
.stats.mini{margin:0 0 14px;grid-template-columns:repeat(auto-fit,minmax(150px,1fr))}
.stats.mini .stat{padding:10px 14px}
.stats.mini .stat .v{font-size:20px}

/* ---------------------------------------------------------------------------
   TEACHER CLASS SCOPING — 'My classes' tab + admin toggle card (Veracross
   build 5). APPEND-ONLY block; every rule above is untouched.
   The feature SHIPS DARK (settings row teacher_scoping_enabled = '0'): while
   dark, nothing below is ever reached — #navMyClasses and #myclasses ship
   hidden and EMPTY in index.html, so no rule here can paint anything for any
   role until an admin turns the flag on. tabs/myclasses.js owns the markup.
   - .mc-cards: responsive grid of per-class cards
   - .mc-map: the small MAP subject-means table inside a class card
   - .mc-suppressed / .mc-foot: the under-floor note and the '—' footnote
--------------------------------------------------------------------------- */
.mc-cards{display:grid;gap:16px;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));margin-top:16px}
.mc-card{margin:0}
.mc-card .mc-stats{margin:0 0 12px}
.mc-map{font-size:12.5px;width:100%;margin-top:4px}
.mc-map th,.mc-map td{padding:5px 8px}
.mc-map td.mono{font-variant-numeric:tabular-nums}
.mc-year{margin:-6px 0 0}
.mc-suppressed{margin-top:8px}
.mc-foot{margin-top:14px;color:var(--slate)}
@media(max-width:560px){.mc-cards{grid-template-columns:1fr}}

/* ---------------------------------------------------------------------------
   NOTES YEAR-END DIGEST — the card in Admin → Data & sync (roadmap: "fold the
   notes year-end digest in wherever cheap"). APPEND-ONLY block; every rule
   above is untouched. tabs/admin.js owns the markup (#notesDigestCard).
   The @media print rules are the whole export story: the card's Print button
   sets body.print-digest (removed on afterprint) and calls window.print(), and
   with that class present everything on the page hides except the digest —
   Nick's year-end review artifact is a paper copy, no new download machinery.
--------------------------------------------------------------------------- */
.nd-controls{margin-top:12px}
.nd-controls select{padding:6px 8px;border:1px solid var(--line);border-radius:6px;
  font:inherit;font-size:13px;color:var(--ink);background:#fff}
.nd-section{margin-top:18px;border-top:1px solid var(--line);padding-top:12px}
.nd-sec-t{font-family:var(--display);font-size:15px;font-weight:600;color:var(--ink)}
.nd-chart{margin-top:10px;padding-left:12px;border-left:2px solid var(--line)}
.nd-chart-t{font-size:13px;font-weight:600;color:var(--ink)}
.nd-note{margin-top:6px;font-size:13px;color:var(--ink)}
.nd-note .nd-who{display:block;font-size:12px;color:var(--slate)}
.nd-note .nd-txt{white-space:pre-wrap}
.nd-empty{margin-top:12px}
@media print{
  body.print-digest header,
  body.print-digest footer,
  body.print-digest #modal,
  body.print-digest .viewbar,
  body.print-digest main section{display:none!important}
  body.print-digest #admin{display:block!important}
  body.print-digest #admin>h2,
  body.print-digest #admin>div:not(#adminData){display:none!important}
  body.print-digest #adminData{display:block!important}
  body.print-digest #adminData>.card:not(#notesDigestCard){display:none!important}
  body.print-digest #notesDigestCard{border:none;box-shadow:none;padding:0}
  body.print-digest #notesDigestCard .nd-controls select,
  body.print-digest #notesDigestCard .nd-controls .btn-admin{display:none!important}
  body.print-digest .nd-section{break-inside:avoid-page}
}

/* ---------------------------------------------------------------------------
   MOBILE NAVIGATION DRAWER (Nick, Aug 2026: "I still do not see ... my mobile
   menu, responsive design"). APPEND-ONLY block owned by the mobile-nav
   builder; every rule above is untouched.

   The earlier passes made the nav a momentum-scrolling strip; what a phone
   user expects is a hamburger and a drawer. Under 700px the header collapses
   to one brand row (h1 + compact user box + hamburger) and #nav — the SAME
   element, same buttons, never cloned — becomes a fixed full-height drawer
   that slides in from the right when main.js sets body.nav-open. Because the
   drawer IS the desktop nav re-laid-out, every role reveal (navSurveys,
   navKpis, navAdmin, navMyClasses) and the active-section highlight work in
   the drawer with zero duplicated logic, and nav button[hidden]
   {display:none!important} (defined above) keeps gated tabs out of it.
   Above 700px nothing here applies except two display:none defaults that
   hide the new hamburger/backdrop elements — the desktop nav is untouched.
   main.js owns open/close (CSP: script-src 'self', nothing inline).
--------------------------------------------------------------------------- */

/* hamburger + backdrop exist in the markup at every width, but PAINT only
   under the breakpoint: these defaults hide them everywhere, and only the
   max-width:700px block below ever shows them */
#navToggle{display:none}
#navBackdrop{display:none}

@media(max-width:700px){
  /* -- brand row: one line. The tag line drops (it already drops at <=400px
        above); the name in the user box truncates instead of wrapping. -- */
  header{padding:12px 16px 12px}
  .brand{flex-wrap:nowrap;align-items:center;gap:10px}
  .brand .tag{display:none}
  .brand h1{font-size:19px;flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .brand .user{margin-left:0;flex:0 1 auto;min-width:0;gap:6px}
  .brand .user .uname{max-width:110px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

  /* -- the hamburger: 44px touch target, three CSS bars, no glyph font -- */
  #navToggle{display:flex;flex-direction:column;justify-content:center;align-items:center;gap:4px;flex:0 0 auto;width:44px;height:44px;min-width:44px;min-height:44px;border:1px solid var(--line);border-radius:8px;background:#fff;cursor:pointer;padding:0}
  #navToggle .nt-bar{display:block;width:18px;height:2px;border-radius:1px;background:var(--ink)}
  #navToggle[aria-expanded="true"]{border-color:var(--maroon)}
  #navToggle[aria-expanded="true"] .nt-bar{background:var(--maroon)}
  #navToggle:focus-visible{outline:2px solid var(--maroon);outline-offset:2px}

  /* -- #nav becomes the drawer: fixed, full-height, slides in from the right.
        visibility:hidden while closed keeps its buttons out of the tab order;
        the transition delay flips visibility only after the slide-out ends.
        mask-image:none undoes the right-edge scroll fade the strip uses. -- */
  #nav{position:fixed;top:0;right:0;bottom:0;z-index:70;width:min(320px,85vw);height:100dvh;margin:0;padding:16px 0 24px;background:#fff;border-left:1px solid var(--line);box-shadow:-12px 0 30px rgba(32,36,44,.18);display:flex;flex-direction:column;align-items:stretch;gap:0;overflow-y:auto;overflow-x:hidden;-webkit-mask-image:none;mask-image:none;transform:translateX(105%);visibility:hidden;transition:transform .22s ease,visibility 0s .22s}
  body.nav-open #nav{transform:translateX(0);visibility:visible;transition:transform .22s ease}
  #nav::before{content:'Menu';display:block;font-family:var(--mono);font-size:11px;text-transform:uppercase;letter-spacing:.08em;color:var(--slate);padding:6px 22px 10px;border-bottom:1px solid var(--line)}

  /* -- drawer items: large touch targets (>=48px), left-rail active marker
        instead of the strip's bottom border -- */
  #nav button{display:block;width:100%;text-align:left;font-size:15px;min-height:48px;padding:13px 22px;margin:0;border:none;border-left:3px solid transparent;border-radius:0;color:var(--ink);white-space:normal}
  #nav button:hover{color:var(--maroon)}
  #nav button.active{color:var(--maroon);background:var(--maroon-soft);border-left-color:var(--maroon)}
  #nav button:focus-visible{outline-offset:-2px}

  /* -- backdrop: dims the page while the drawer is open; main.js closes on tap.
        The page behind must not scroll while the drawer does. -- */
  body.nav-open #navBackdrop{display:block;position:fixed;inset:0;z-index:60;background:rgba(32,36,44,.45)}
  body.nav-open{overflow:hidden}

  /* -- view bar: tighter at phone widths; the freshness chip's own-line rule
        at <=560px above keeps the "Data as of" stamp visible and honest -- */
  .viewbar{padding:8px 16px;gap:6px 8px}

  /* -- Admin users table: without this, width:100% + overflow-wrap:anywhere
        squeezed the email column into letter-per-line soup at 375px. Cells
        keep their shape and the table scrolls inside the card instead (the
        base phone rule above already makes tables display:block scroll). -- */
  #adminUsers td,#adminUsers th{white-space:nowrap}
  #adminUsers .u-val{overflow-wrap:normal}

  /* -- sub-tab strips that can outgrow a phone (Admin's pane switcher, the
        Surveys audience strip): one row, finger-scrollable, no wrap -- */
  #adminTabs,#surveyTabs{flex-wrap:nowrap;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none;padding-bottom:4px}
  #adminTabs::-webkit-scrollbar,#surveyTabs::-webkit-scrollbar{display:none}
  #adminTabs button,#surveyTabs button{flex:0 0 auto;white-space:nowrap}
}

/* drawer slide honors reduced-motion */
@media(max-width:700px) and (prefers-reduced-motion:reduce){
  #nav,body.nav-open #nav{transition:none}
}

/* ---------------------------------------------------------------------------
   ==== Reading (DRA) page (Aug 2026) ====================================
   Nick: "a by student and by class snapshot ... a whole DRA tab or page."
   Owned by public/js/tabs/dra.js. Append-only block, nothing above is edited.

   Bucket chips mirror the class sheet legend, mapped onto the app palette:
   above = teal (#1F7A8C), at = green (#2E7D5B), one below = gold (#C99532),
   two below = amber (#B2701F — the palette has no amber; it sits between
   gold and flag on the same warm ramp), three-four+ below = flag (#C0392B).
   The chips reuse .pill's shape; only the colors are new.

   The Students table is ~15 columns wide (two windows × six measures), so it
   lives inside .dra-tablewrap: the TABLE scrolls sideways inside its card and
   the page body never grows a horizontal scrollbar — the 375px rule the
   responsive pass enforces everywhere else.
--------------------------------------------------------------------------- */
.pill.dra-b{color:#fff}
.pill.dra-b-above{background:#1F7A8C}
.pill.dra-b-at{background:#2E7D5B}
.pill.dra-b-one_below{background:#C99532}
.pill.dra-b-two_below{background:#B2701F}
.pill.dra-b-three_plus_below{background:#C0392B}

.dra-tablewrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
.dra-tablewrap table{min-width:640px}
.dra-tablewrap th,.dra-tablewrap td{white-space:nowrap}
.dra-winhead{text-align:center;border-left:1px solid var(--line)}

/* three selects (year / grade / window) wrap as a row of controls on phones */
#dra .controls{display:flex;flex-wrap:wrap;gap:8px}

/* ============================================================================
   ES GRADES REDESIGN: two systems, students not marks (tabs/literacy.js,
   Nick Aug 2026 — "divide the 1,2,3,4 and the E,N,S data"). APPEND-ONLY
   block; every rule above is untouched.
   .esheat  — the big-picture grade x subject table. Cell backgrounds are
              inline rgba() written by literacy.js (share of students at the
              top band); these rules cover layout and the system divider only.
   .esbands — the per-card headline row: top-band / bottom-band pills plus a
              small n caption, between the controls and the chart. */
.esheat{overflow-x:auto;-webkit-overflow-scrolling:touch}
.esheat table{border-collapse:collapse;width:100%;font-size:12.5px}
.esheat th,.esheat td{padding:5px 8px;text-align:center;border-bottom:1px solid var(--line);white-space:nowrap}
.esheat thead th{font-weight:600;color:var(--slate)}
.esheat th.esh-sys{font-family:var(--mono);font-size:11px;text-transform:uppercase;letter-spacing:.06em;border-bottom:none;padding-bottom:0}
.esheat th.esh-sub{font-size:12px}
.esheat th.esh-g,.esheat td.esh-g{text-align:left;font-family:var(--mono)}
.esheat td.esh{font-family:var(--mono)}
.esheat td.esh-na{color:var(--line)}
.esheat .esh-div{border-left:2px solid var(--line)}
.esbands{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin:-6px 0 10px}
.esbands .esbands-n{font-size:12px;color:var(--slate)}

/* ============================================================================
   ==== INFORMATION ARCHITECTURE: grouped nav + level badges (Nick, Aug 2026:
   "I am also a little lost about where I should look to find something ...
   consider or reconsider the best organization of what is elementary, what is
   middle or high school, and what is used by both"). APPEND-ONLY block owned
   by the IA builder; every rule above is untouched.

   .nav-group — the small non-clickable school-level labels inside #nav
   (Whole school / Elementary (K-5) / Secondary (6-12) / All grades /
   Leadership). Desktop keeps the strip lean: each span paints as a hairline
   separator plus ONLY its tiny data-short overline ("K-5", "6-12" — the split
   Nick asked to tell apart; the other groups carry an empty short so the bar
   does not bloat). The FULL label text lives inside the span — font-size:0
   parks it at desktop widths while screen readers still announce it — and
   under 700px, where #nav is the slide-in drawer (block above), the full
   labels return as group headings with room to breathe. main.js
   updateNavGroups() sets [hidden] on a label whose whole group is role-hidden;
   the !important rule mirrors nav button[hidden] so no later display rule can
   resurrect one.

   .lvl-chip — the small scope badge on every section header ('Elementary',
   'Secondary', 'All grades', 'Whole school'): one class, static markup in
   index.html, so anyone landing anywhere knows which school level they are
   reading. Same quiet mono-overline voice as the drawer headings.
============================================================================ */
.nav-group{flex:0 0 auto;align-self:stretch;display:inline-flex;align-items:center;font-size:0;padding:0 2px 0 10px;margin-left:8px;border-left:1px solid var(--line);user-select:none}
.nav-group::after{content:attr(data-short);font-family:var(--mono);font-size:9px;font-weight:500;text-transform:uppercase;letter-spacing:.08em;color:var(--slate);white-space:nowrap}
#nav .nav-group:first-child{border-left:none;margin-left:0;padding-left:0}
#nav .nav-group[hidden]{display:none!important}

.lvl-chip{display:inline-block;vertical-align:2px;margin-left:10px;font-family:var(--mono);font-size:10px;font-weight:500;text-transform:uppercase;letter-spacing:.07em;color:var(--slate);border:1px solid var(--line);border-radius:999px;padding:2px 9px;white-space:nowrap}

@media(max-width:700px){
  /* the drawer has room: full group labels as headings above their buttons.
     The :first-child override matches the base rule's specificity so the
     later (this) rule wins and restores the drawer padding. */
  #nav .nav-group{display:block;align-self:auto;font-size:11px;font-family:var(--mono);text-transform:uppercase;letter-spacing:.08em;color:var(--slate);padding:14px 22px 4px;margin:6px 0 0;border-left:none;border-top:1px solid var(--line)}
  #nav .nav-group::after{content:none}
  #nav .nav-group:first-child{border-top:none;margin-top:0;padding:6px 22px 4px}
  #nav .nav-group[hidden]{display:none!important}
}

/* ============================================================================
   ==== Elementary Grades page (Nick, Aug 2026: "an elementary grades page ...
   tabs or subpages for each subject ... this is more about teacher coverage
   than individual students"). APPEND-ONLY block owned by tabs/esgrades.js;
   every rule above is untouched.

   The pill strip reuses .minitabs (esgrades.js adds the class to #esgTabs,
   the Surveys pattern), and the Overview meeting-or-exceeding tables reuse
   the .esheat layout rules that block already appended — only the pieces new
   to this page live here:
   .esg-search    — the instant client-side criteria filter input.
   .esg-tablewrap — sideways scroll INSIDE the card for the criteria and
                    weak-points tables (the 375px rule: the page body never
                    grows a horizontal scrollbar). Criterion-name cells are
                    the one column allowed to wrap, so a long "I can ..."
                    rubric sentence costs height, not width.
   .esg-whead     — the grade · subject group rows inside the weak-points
                    table.
   .pill.esg-un   — the 'not assessed' coverage badge: GOLD, deliberately
                    distinct from both n<5 suppression (grey .na) and a real
                    below-share (red .flag).
============================================================================ */
.esg-search{font:inherit;font-size:13px;padding:5px 10px;border:1px solid var(--line);border-radius:16px;min-width:220px;background:#fff;color:var(--ink)}
.esg-search:focus-visible{outline:2px solid var(--maroon);outline-offset:1px}
.esg-tablewrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
.esg-tablewrap th,.esg-tablewrap td{white-space:nowrap}
.esg-tablewrap td.esg-critname,.esg-tablewrap td.esg-crits{white-space:normal;min-width:260px;max-width:440px}
.esg-whead td{font-family:var(--mono);font-size:11.5px;text-transform:uppercase;letter-spacing:.05em;color:var(--slate);background:var(--paper);padding-top:12px}
.esg-more{color:var(--slate);font-size:11.5px;white-space:nowrap}
.pill.esg-un{background:#C99532;color:#fff}

/* phone: the sub-tab strip can outgrow the screen (Overview + every subject +
   Weak points + Reading (DRA)) — one row, finger-scrollable, no wrap, same
   treatment as #adminTabs/#surveyTabs in the earlier block */
@media(max-width:700px){
  #esgTabs{flex-wrap:nowrap;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none;padding-bottom:4px}
  #esgTabs::-webkit-scrollbar{display:none}
  #esgTabs button{flex:0 0 auto;white-space:nowrap}
}

/* ============================================================================
   ==== COLLAPSIBLE VIEW BAR (Nick, Aug 2026: "make this 'View' task bar
   something collapsable or slight less obvious as it is not used so much,
   almost a setting for the user"). APPEND-ONLY block; every rule above is
   untouched.

   main.js wraps the filter controls (View chips, role template, Framework)
   in .viewbar-body and prepends a quiet #viewBarToggle button. Two things sit
   OUTSIDE the wrapper so collapsing never hides them: the toggle itself and
   the "Data as of" freshness stamp (#dataFresh) — the staleness signal must
   survive the collapse. Default state is collapsed; the choice persists via
   prefs.js getViewbarCollapsed/setViewbarCollapsed (localStorage, the same
   store as the ★ Favorites view mode), and an ACTIVE filter auto-expands on
   load with its summary painted on the toggle line (.vb-sum, '★ Favorites ·
   WASC') so a filtered view is never mysterious.
============================================================================ */
#viewBarToggle{display:flex;align-items:center;gap:6px;min-height:32px;padding:4px 10px;margin-left:-10px;border:none;border-radius:16px;background:none;font-family:var(--mono);font-size:11px;text-transform:uppercase;letter-spacing:.08em;color:var(--slate);cursor:pointer}
#viewBarToggle:hover{color:var(--maroon)}
#viewBarToggle:focus-visible{outline:2px solid var(--maroon);outline-offset:1px}
.vb-chev{display:inline-block;font-size:9px;line-height:1;transition:transform .15s ease}
#viewBar:not(.vb-collapsed) .vb-chev{transform:rotate(90deg)}

/* the active-filter summary rides on the toggle line, visible in BOTH states */
.vb-sum{font-family:var(--display);font-size:12px;font-weight:600;text-transform:none;letter-spacing:0;color:var(--maroon);margin-left:2px}
.vb-sum:empty{display:none}

/* display:contents keeps every control a direct flex item of .viewbar, so all
   the earlier wrap / row-gap / phone-padding rules keep applying unchanged */
.viewbar-body{display:contents}
#viewBar.vb-collapsed .viewbar-body{display:none}

/* collapsed = one slim quiet line (frees vertical space, phones most of all) */
#viewBar.vb-collapsed{padding-top:4px;padding-bottom:4px}

/* real touch target on touch-sized screens (same 44px bar as nav buttons; the
   drawer/hamburger rules above are untouched by this block) */
@media(max-width:820px){
  #viewBarToggle{min-height:44px;min-width:44px}
}
@media(prefers-reduced-motion:reduce){
  .vb-chev{transition:none}
}

/* ============================================================================
   ==== Secondary Grades page (Nick, Aug 2026: "Under the 6-12 secondary
   section, I want a secondary grades division by subjects and trends like
   elementary has but using the grading methods and styles"). APPEND-ONLY
   block owned by tabs/secgrades.js; every rule above is untouched.

   The page deliberately reuses the Elementary Grades vocabulary — the pill
   strip is .minitabs (secgrades.js adds the class to #sgTabs), the Overview
   mean-grade table reuses .esheat, and the weak-points / honors tables reuse
   .esg-tablewrap and .esg-whead — so only the phone-width strip rule is new:
   the sub-tab strip (Overview + every subject + Weak points) can outgrow the
   screen, so it gets the same one-row finger-scroll treatment as #esgTabs.
============================================================================ */
@media(max-width:700px){
  #sgTabs{flex-wrap:nowrap;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none;padding-bottom:4px}
  #sgTabs::-webkit-scrollbar{display:none}
  #sgTabs button{flex:0 0 auto;white-space:nowrap}
}

/* ============================================================================
   ==== Enrollment sub-pages (Nick, Aug 2026: "likely sub pages for this
   deeper dive into admissions and enrollment"). APPEND-ONLY block owned by
   tabs/enroll.js; every rule above is untouched.

   The pill strip reuses .minitabs (enroll.js adds the class to #enTabs, the
   esgrades pattern). New here:
   .en-tablewrap — sideways scroll INSIDE the card for the projection by-grade
                   table (the 375px rule: the page body never grows a
                   horizontal scrollbar).
   .en-switch    — the 'Show projections' opt-in row on the Projections pane:
                   a plain labeled checkbox, deliberately quiet.
   .en-projdis   — the projection disclaimer banner: the shared .banner look
                   with the weight turned up, because the disclaimer must read
                   BEFORE the numbers do.
============================================================================ */
#enTabs{margin-bottom:16px}
#enTabs:empty{display:none}
.en-tablewrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
.en-tablewrap th,.en-tablewrap td{white-space:nowrap}
.en-switch{display:inline-flex;align-items:center;gap:8px;margin-top:10px;font-family:var(--display);font-size:13px;font-weight:600;color:var(--maroon);cursor:pointer}
.en-switch input{accent-color:var(--maroon);width:16px;height:16px;cursor:pointer}
.banner.en-projdis{font-weight:600;border-width:2px;margin-bottom:20px}

/* phone: the sub-tab strip gets the same one-row finger-scroll treatment as
   #esgTabs/#sgTabs */
@media(max-width:700px){
  #enTabs{flex-wrap:nowrap;overflow-x:auto;-webkit-overflow-scrolling:touch;scrollbar-width:none;padding-bottom:4px}
  #enTabs::-webkit-scrollbar{display:none}
  #enTabs button{flex:0 0 auto;white-space:nowrap}
}

/* ============================================================================
   ==== Projections pane v2 (Nick, Aug 2026: the switch becomes an agreement
   to the disclaimer, and the pane splits into three labeled layers —
   CONDITIONS WE WATCH / THE PROJECTION / LEVERS THE SCHOOL CAN PULL — so the
   known-book vs market separation and the school's own agency are visible in
   the layout itself). APPEND-ONLY block owned by tabs/enroll.js; every rule
   above is untouched.
============================================================================ */
/* layer headings: quiet mono captions with a rule line, not shouting */
.en-layerhead{margin:26px 0 12px;font-family:var(--mono);font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.14em;color:var(--slate);display:flex;align-items:center;gap:10px}
.en-layerhead::after{content:'';flex:1;border-top:1px solid var(--line)}
#projBody>.en-layerhead:first-child{margin-top:4px}

/* climate card: one quiet headline read + per-signal rows */
.en-climread{font-family:var(--display);font-size:22px;font-weight:700;margin:2px 0 6px;text-transform:capitalize}
.en-climread.up{color:var(--ok)}
.en-climread.down{color:var(--maroon)}
.en-climread.mixed{color:var(--gold)}
.en-climread.flat{color:var(--slate)}
.en-signal{padding:10px 0;border-top:1px solid var(--line)}
.en-signal .hint{margin-top:4px}
.en-sigtop{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}
.en-sigdir{margin-left:auto;margin-top:0}
.en-arrow{font-size:12px}
.en-arrow.up{color:var(--ok)}
.en-arrow.down{color:var(--maroon)}
.en-arrow.flat{color:var(--slate)}
.en-arrow.mixed{color:var(--gold)}
.en-sigvals{font-size:12px;margin:4px 0 0}

/* component rows: known book / market / combined, each with its own range */
.en-comp{display:flex;gap:14px;align-items:flex-start;padding:9px 0;border-top:1px solid var(--line)}
.en-comp .hint{margin-top:2px}
.en-comp.en-combined{border-top-width:2px}
.en-compv{font-size:22px;font-weight:600;min-width:52px;text-align:right;line-height:1.2}
.en-range{color:var(--slate);font-size:12px;margin-left:8px}

/* scenario strip: three pickable cards; active = the table's current lens */
.en-scens{display:flex;gap:12px;flex-wrap:wrap;margin:4px 0 14px}
.en-scen{flex:1 1 160px;min-width:150px;text-align:left;padding:10px 12px;border:1px solid var(--line);border-radius:10px;background:none;cursor:pointer;font-family:var(--body);color:var(--ink)}
.en-scen:hover{border-color:var(--maroon)}
.en-scen:focus-visible{outline:2px solid var(--maroon);outline-offset:1px}
.en-scen.active{border-color:var(--maroon);box-shadow:inset 0 0 0 1px var(--maroon);background:var(--maroon-soft)}
.en-scent{display:block;font-family:var(--mono);font-size:11px;text-transform:uppercase;letter-spacing:.08em;color:var(--slate)}
.en-scenv{display:block;font-size:20px;font-weight:600;margin:2px 0}
.en-scen .hint{display:block;margin-top:2px;font-size:11px}

/* thin-sample honesty note inside a table row (principle 1: visible, not
   hover-only) */
.en-thin{color:var(--maroon);font-style:italic}

/* levers: school-entered input rows with their badge */
.en-inputs{margin-top:6px}
.en-input{padding:8px 0;border-top:1px solid var(--line)}
.en-input .hint{margin-top:2px}
.pill.en-badge{background:#E4EEF0;color:var(--teal)}

/* phone: scenario cards stack; tables already finger-scroll via .en-tablewrap */
@media(max-width:700px){
  .en-scens{flex-direction:column}
  .en-scen{min-width:0}
  .en-sigdir{margin-left:0}
}

/* ==================== Clever sync (Admin sub-tab) ====================
   The live log pane the roster-CSV generate/push jobs write into. Monospace,
   scrollable, capped at ~16em; admin.js APPENDS lines (never re-renders) and
   auto-scrolls only while the admin is at the bottom, so scrolling up to read
   an earlier line pauses the follow. Everything else in the pane reuses the
   existing .card / .admin-* / .btn-admin vocabulary. */
.cl-log{font-family:var(--mono);font-size:11.5px;line-height:1.5;background:var(--paper);border:1px solid var(--line);border-radius:6px;padding:8px 10px;margin:6px 0 12px;max-height:16em;overflow-y:auto}
.cl-line{white-space:pre-wrap;word-break:break-word}
.cl-t{color:var(--slate);margin-right:8px}
.cl-files{display:flex;flex-direction:column;gap:2px}
.cl-file-row{display:flex;align-items:center;gap:12px;padding:4px 0;border-bottom:1px solid var(--line);flex-wrap:wrap}
.cl-file-row:last-of-type{border-bottom:none}
.cl-file-row .mono{font-family:var(--mono);font-size:12.5px;min-width:120px}
.cl-file-row .btn-admin{font-size:11.5px;padding:5px 9px}
/* compact preview table: scrolls both ways inside its own box (student PII —
   rendered on demand, cleared again when the preview is hidden) */
.cl-prev{border:1px solid var(--line);border-radius:6px;margin:4px 0 10px;max-height:20em;overflow:auto}
.cl-prev table{font-size:11.5px;white-space:nowrap;margin:6px 8px 8px}
.cl-prev th,.cl-prev td{padding:3px 8px}
/* sync settings: Auto/Paused radios with the cron input inline, and the
   resolved-term line (red when out of window or unresolvable) */
.cl-mode{display:flex;align-items:center;gap:6px;font-size:13.5px}
.cl-cron{font-family:var(--mono);font-size:12.5px;padding:6px 9px;border:1px solid var(--line);border-radius:7px;background:#fff;width:130px}
.cl-resolved.err{color:var(--flag)}
/* schools table: 13 directory columns is wide — it scrolls sideways inside its
   own box; the per-cell inputs stay compact so a row reads as one line */
.cl-schools{overflow-x:auto;border:1px solid var(--line);border-radius:6px;margin:6px 0 10px}
.cl-schools table{font-size:11.5px;white-space:nowrap;margin:6px 8px 8px}
.cl-schools th,.cl-schools td{padding:3px 4px;text-align:left}
.cl-schools th{font-size:10.5px;color:var(--slate);text-transform:uppercase;letter-spacing:.04em}
.cl-schools input{font-family:var(--body);font-size:12px;padding:4px 6px;border:1px solid var(--line);border-radius:5px;background:#fff;width:110px}
.cl-schools .btn-admin{font-size:11px;padding:4px 8px}

/* ---- Admin: connection test rows (v1.0.14) ---- */
.conn-row{margin:8px 0 0;line-height:1.5;font-size:13px}
.conn-row .pill{margin-right:4px}

/* ---- Report cards: numbered file rows + optional SFTP block (v1.0.23) ---- */
.rc-file-title{display:inline-flex;gap:6px;align-items:baseline;flex-wrap:wrap}
.rc-file-title a{font-size:12px}
.rc-sftp{margin:8px 0 4px}
.rc-sftp summary{cursor:pointer;font-size:12.5px}
.rc-file-title .rc-kind{font-size:11.5px}
/* Report cards: posting progress bar (v1.0.25) */
.rc-bar{height:8px;background:var(--line,#E5E1D8);border-radius:4px;overflow:hidden;margin-top:8px}
.rc-bar>span{display:block;height:100%;background:#8C1D2F;transition:width .4s ease}
/* Report cards: year-end comment preview (v1.0.26) */
td.rc-cmt{white-space:pre-line;max-width:520px;font-size:12px;line-height:1.45}

/* ---- Attendance & Tardies (School Life sub page + Overview tile + admin) ---- */
.att-sum{margin:0 0 20px}
.att-sum-grid{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:14px;margin:10px 0 12px}
.att-sum-div{border:1px solid var(--line);border-radius:10px;padding:12px 14px;background:#fff}
.att-sum-name{font-family:var(--display);font-weight:600;font-size:13px;color:var(--ink);margin-bottom:6px}
.att-sum-v{font-family:var(--mono);font-size:21px;color:var(--maroon);margin-top:4px}
.att-sum-l{font-size:11px;color:var(--slate);text-transform:uppercase;letter-spacing:.05em}
.att-open{font-family:var(--display);font-size:13px;font-weight:600;background:none;border:none;color:var(--maroon);cursor:pointer;padding:0}
.att-open:hover{text-decoration:underline}
.att-controls{display:flex;gap:14px;flex-wrap:wrap;align-items:center;margin-top:10px}
.att-controls .minitabs{margin:0}
.att-ctl{font-size:12.5px;color:var(--slate);display:flex;gap:6px;align-items:center}
.att-annual td,.att-annual th{white-space:nowrap}
.att-annual tr.att-group td{font-family:var(--display);font-weight:600;font-size:12.5px;color:var(--ink);background:var(--paper,#faf8f5);padding-top:10px}
.att-annual td.att-manual{color:var(--slate);font-style:italic}
.att-annual td.att-partial{color:var(--slate)}
.att-annual sup{font-size:9px;margin-left:1px}
.att-defs{font-style:normal}
.att-csv{margin-left:8px;padding:3px 10px;font-size:12px}
.att-terms input[type=date]{display:block;margin:2px 0;font-size:12px;padding:3px 5px;border:1px solid var(--line);border-radius:5px}
.att-cfg input,.att-cfg select{max-width:220px}
input.att-leg{width:70px;font-family:var(--mono);font-size:12px;padding:3px 5px;border:1px solid var(--line);border-radius:5px}
.admin-msg.warn{color:#8A6100}
@media (max-width:700px){
  .att-sum-grid{grid-template-columns:1fr}
  .att-controls{flex-direction:column;align-items:flex-start}
}
.att-cfg{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:12px 18px;margin:8px 0}
.att-cfg .admin-th{display:flex;flex-direction:column;gap:4px}
.att-cfg input{font-family:var(--mono);font-size:13px;padding:6px 8px;border:1px solid var(--line);border-radius:6px}

/* Data & sync: refused rows + reasons (2026-10-01) */
.admin-rejects{margin-top:6px;font-size:12.5px}
.admin-why{padding:2px 9px;font-size:11.5px;margin-left:6px}
.admin-why-out table{margin-top:8px;font-size:12.5px}
.admin-why-out td{vertical-align:top}
.admin-msg.warn{color:#8A6100}
