/* ==========================================================================
   Genie Connect — responsive app shell · COMMAND CENTRE
   --------------------------------------------------------------------------
   One shell that reflows from a 390px phone to a 1440px desktop.

   Breakpoints
     mobile   < 640px    bottom tab bar, single column, full-bleed cards
     tablet   640–1023px left icon rail, wider column, grids open up
     desktop  ≥ 1024px   labelled sidebar, multi-pane, hover affordances

   Non-negotiables baked in here:
     · every interactive target clears 44px
     · every text input is 16px (below that, iOS zooms on focus)
     · nothing may cause horizontal scroll at 320px

   ── the design, and its one hard rule ────────────────────────────────────
   This is an instrument face: white panels, thin technical rules, black
   chrome, mono for every label, code and number, and orange used the way a
   machine uses it — to say "here", "active", "you are this far".

   Signal orange #FF5A1F is 2.94:1 on white. It can therefore NEVER carry
   text on a light ground, at any size. So the palette splits the job:

     --signal  #FF5A1F   fills, indicator blocks, progress, markers,
                         and text ON BLACK (6.42:1)
     --accent  #C2410C   every orange WORD on a light ground (4.9:1 on
                         warm paper, 5.2:1 on white)

   If you are about to write colour:var(--signal) on a white surface, you
   want --accent. The reverse — --accent as a large fill — is safe but flat;
   --signal is the one that reads as a live indicator.

   Every token name here predates the redesign and is referenced from the
   three page templates and from messages.js. Retune values freely; do not
   rename or delete, or a page-level style silently loses its colour.
   ========================================================================== */

@import url("https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@500;600;700&family=Inter:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500;600&display=swap");

:root{
  /* --- colour ------------------------------------------------ */
  --ink:#080808;
  --paper:#FFFFFF;
  --paper-2:#FFF9F2;          /* warm paper — alternating surfaces */
  --line:rgba(8,8,8,.10);     /* hairline */
  --line-2:rgba(8,8,8,.17);   /* panel edge */
  --line-w:rgba(255,255,255,.16);  /* hairline on black */
  --mute:#5E5E5E;             /* 6.4:1 on white — the floor for small text */
  --signal:#FF5A1F;           /* indicator orange: fills and type on black */
  --accent:#C2410C;           /* burnt orange: orange type on light grounds */
  --warm:#FF5A1F;             /* was a yellow; the instrument reads orange   */
  --teal:#FF5A1F;             /* installer accent, folded into the theme     */
  --green:#1F6F43;            /* status: nominal   (5.9:1 on white)          */
  --danger:#A3200E;           /* status: fault     (7.2:1 on white)          */

  /* --- type -------------------------------------------------- */
  --f-disp:"Space Grotesk","Arial Narrow",sans-serif;
  --f-body:"Inter",Arial,sans-serif;
  --f-mono:"IBM Plex Mono",ui-monospace,monospace;

  /* --- geometry ---------------------------------------------- */
  --radius:0;
  --phone-w:326px;
  --phone-h:700px;
  --phone-r:44px;
  --screen-r:36px;
  --notch-w:110px;
  --notch-h:24px;
  --win-w:1100px;

  /* --- surfaces ---------------------------------------------- */
  --bg-desk:radial-gradient(120% 120% at 50% 0%,#e9e3d7 0%,#c7bfb0 100%);
  --bg-soft:radial-gradient(120% 120% at 50% 0%,#faf8f4 0%,#eee7db 55%,#e2d9c9 100%);
  /* the coordinate grid, used sparingly behind quiet panels */
  --grid:linear-gradient(rgba(8,8,8,.055) 1px,transparent 1px) 0 0/100% 20px,
         linear-gradient(90deg,rgba(8,8,8,.055) 1px,transparent 1px) 0 0/20px 100%;
}

*{box-sizing:border-box;margin:0;padding:0}

:root{
  --rail:72px;              /* icon-only nav on tablet */
  --side:236px;             /* labelled nav on desktop */
  --bar:56px;               /* top bar height */
  --tabs:70px;              /* bottom tab bar height, phone only */
  --gut:16px;               /* page gutter, phone */
  --col:720px;              /* default reading column cap */
  --tap:44px;               /* minimum tap target */
  --r:2px;                  /* the small technical radius */
}

html{-webkit-text-size-adjust:100%}
body{
  font-family:var(--f-body);
  color:var(--ink);
  background:var(--paper);
  font-size:15px;
  line-height:1.45;
  overflow-x:hidden;
  -webkit-font-smoothing:antialiased;
  letter-spacing:-.004em;
}
img{max-width:100%;display:block}
button,input,select,textarea{font:inherit;color:inherit}
button{cursor:pointer}
a{color:inherit}

/* ── shell ───────────────────────────────────────────────────────────────── */

/* The document itself never scrolls — the scrolling lives inside .main.
   This is not a stylistic preference. Chrome collapses its toolbar as the
   DOCUMENT scrolls and re-expands it on a bottom overscroll, and on Chrome
   for iOS that toolbar ignores theme-color entirely (near-black in dark
   mode) — so with body scroll, a thick dark bar "descends from the top"
   every time a student bounces off the foot of a page, and no colour or
   meta tag on our side can stop it. With the shell fixed and .main the
   scroller, the toolbar never collapses, so it never has anything to
   descend from. Safari never had the behaviour; this makes Chrome match. */
html,body{height:100%;height:100dvh;overflow:hidden;overscroll-behavior:none}
.app{
  display:grid;
  grid-template-rows:auto 1fr auto;
  grid-template-areas:"bar" "main" "nav";
  height:100vh;
  height:100dvh;
}

/* ── top bar — the instrument face plate ─────────────────────────────────── */

.appbar{
  grid-area:bar;
  position:sticky;top:0;z-index:40;
  height:var(--bar);
  display:flex;align-items:center;gap:12px;
  padding:0 var(--gut);
  background:var(--ink);color:#fff;
  border-bottom:2px solid var(--signal);
}
.appbar .brand{display:flex;align-items:center;gap:9px;min-width:0}
.appbar .brand img{height:26px}   /* the mark is already white-on-transparent — do NOT invert it here */
.appbar .who{
  font-family:var(--f-mono);font-size:10px;font-weight:500;letter-spacing:.17em;
  text-transform:uppercase;color:rgba(255,255,255,.72);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.appbar .spacer{flex:1}
.appbar .iconbtn{
  width:var(--tap);height:var(--tap);
  display:grid;place-items:center;
  background:transparent;border:0;color:#fff;font-size:17px;
  margin-right:-8px;transition:color .14s linear;
}
.appbar .iconbtn:hover{color:var(--signal)}
.appbar .iconbtn:last-child{margin-right:-10px}
.appbar .pill{
  font-family:var(--f-mono);font-size:11px;font-weight:600;letter-spacing:.1em;
  padding:6px 10px;border:1px solid rgba(255,255,255,.34);color:#fff;
  border-radius:var(--r);white-space:nowrap;
}
.appbar .pill b{color:var(--signal);font-weight:600}

/* ── navigation — a control panel, not a tab strip ───────────────────────── */
/* phone: bottom console. tablet/desktop: left rail (see media queries).      */

.nav{
  grid-area:nav;
  position:sticky;bottom:0;z-index:40;
  display:flex;
  height:calc(var(--tabs) + env(safe-area-inset-bottom));
  padding-bottom:env(safe-area-inset-bottom);
  background:var(--ink);
  border-top:1px solid var(--signal);
}
.nav .tab{
  flex:1;
  min-width:0;min-height:var(--tap);
  display:flex;flex-direction:column;align-items:center;justify-content:center;gap:6px;
  background:transparent;border:0;
  padding:8px 2px;
  color:rgba(255,255,255,.66);
  position:relative;
  transition:color .14s linear,background .14s linear;
}
/* The glyph stays — five identical indicator blocks would look the part and
   destroy wayfinding on the tablet rail, where the label is 8px. The tab
   carries a separate indicator bar above it instead. */
.nav .tab .ic{font-size:18px;line-height:1;display:block}
.nav .tab .lb{
  font-family:var(--f-mono);font-size:8.5px;font-weight:500;
  letter-spacing:.13em;text-transform:uppercase;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%;
}
.nav .tab:hover{color:#fff}
.nav .tab[aria-selected="true"]{color:var(--ink);background:var(--signal)}
.nav .tab[aria-selected="true"]::before{
  content:"";position:absolute;top:0;left:0;right:0;height:3px;background:var(--ink);
}
/* idle tabs get a thin white marker so the row reads as a bank of controls */
.nav .tab::after{
  content:"";position:absolute;top:0;left:34%;right:34%;height:3px;
  background:rgba(255,255,255,.28);
}
.nav .tab[aria-selected="true"]::after{display:none}
.nav .tab .dot{
  position:absolute;top:9px;left:calc(50% + 14px);
  width:7px;height:7px;background:var(--signal);border-radius:50%;
  box-shadow:0 0 0 2px var(--ink);
}
.nav .tab[aria-selected="true"] .dot{background:var(--ink);box-shadow:0 0 0 2px var(--signal)}
.nav .navhead,.nav .navfoot{display:none}

/* ── main ────────────────────────────────────────────────────────────────── */

/* the app's one scroller. overscroll-behavior:contain is the other half of
   the fix above: a flick past the end of the list must die here, not chain
   to the document and hand Chrome its toolbar-reveal gesture. */
.main{grid-area:main;min-width:0;min-height:0;background:var(--paper);
  overflow-y:auto;-webkit-overflow-scrolling:touch;overscroll-behavior-y:contain}
.view{display:none}
.view.on{display:block}
.wrap{max-width:var(--col);margin:0 auto;padding:var(--gut) var(--gut) 30px}
.wrap.wide{max-width:1180px}

/* ── type helpers ────────────────────────────────────────────────────────── */

.eyebrow{
  font-family:var(--f-mono);font-size:9.5px;font-weight:600;letter-spacing:.2em;
  text-transform:uppercase;color:var(--accent);
  display:inline-flex;align-items:center;gap:8px;
}
/* the leading tick — an alignment mark, not decoration */
.eyebrow::before{content:"";width:10px;height:2px;background:var(--signal);flex:none}
.eyebrow.mute{color:var(--mute)}
.eyebrow.mute::before{background:var(--line-2)}
.card.ink .eyebrow{color:var(--signal)}
h1.disp{font-family:var(--f-disp);font-weight:700;font-size:clamp(25px,6.6vw,35px);
  text-transform:uppercase;line-height:1;letter-spacing:-.028em;margin-top:8px}
h2.disp{font-family:var(--f-disp);font-weight:700;font-size:clamp(15px,3.6vw,20px);
  text-transform:uppercase;line-height:1.06;letter-spacing:-.02em}
h3.disp{font-family:var(--f-disp);font-weight:600;font-size:13px;text-transform:uppercase;
  letter-spacing:.01em}
.sub{font-size:13.5px;color:var(--mute);margin-top:5px}
.mono{font-family:var(--f-mono)}
.num{font-family:var(--f-mono);font-weight:600;font-variant-numeric:tabular-nums;
  letter-spacing:-.02em}
/* section head: title, then a technical rule out to the folio on the right */
.sechead{display:flex;align-items:center;gap:12px;margin:28px 0 11px}
.sechead:first-child{margin-top:0}
.sechead::after{content:"";flex:1;height:1px;background:var(--line-2);order:1}
.sechead > *{order:0}
.sechead .more{order:2;font-family:var(--f-mono);font-size:10px;font-weight:600;
  letter-spacing:.14em;text-transform:uppercase;color:var(--accent);
  background:none;border:0;padding:8px 0;min-height:var(--tap);white-space:nowrap}

/* ── surfaces ────────────────────────────────────────────────────────────── */

.card{border:1px solid var(--line-2);background:var(--paper);padding:15px;
  border-radius:var(--r);position:relative}
.card + .card{margin-top:-1px}
/* the armour panel: one cut corner, and a tick in the opposite one */
.card.ink{
  background:var(--ink);color:#fff;border-color:var(--ink);
  clip-path:polygon(0 0,calc(100% - 18px) 0,100% 18px,100% 100%,0 100%);
}
.card.ink::after{
  content:"";position:absolute;right:0;top:0;width:18px;height:18px;
  background:var(--signal);clip-path:polygon(100% 0,100% 100%,0 0);
}
.card.soft{background:var(--paper-2);background-image:var(--grid)}
.card.flush{padding:0}
.stack{display:flex;flex-direction:column}
.row{display:flex;align-items:center;gap:12px}
.row.between{justify-content:space-between}
.grid{display:grid;gap:12px}
.g2{grid-template-columns:1fr}
.g3{grid-template-columns:1fr}
.g4{grid-template-columns:repeat(2,1fr)}

/* ── buttons ─────────────────────────────────────────────────────────────── */

.btn{
  font-family:var(--f-mono);font-size:11px;font-weight:600;letter-spacing:.14em;
  text-transform:uppercase;
  min-height:var(--tap);padding:12px 18px;
  border:1px solid var(--ink);background:var(--ink);color:#fff;
  border-radius:var(--r);
  display:inline-flex;align-items:center;justify-content:center;gap:8px;
  text-align:center;text-decoration:none;
  transition:background .14s linear,color .14s linear,border-color .14s linear;
}
.btn:hover{background:var(--signal);border-color:var(--signal);color:var(--ink)}
.btn.ghost{background:transparent;color:var(--ink);border-color:var(--line-2)}
.btn.ghost:hover{background:var(--ink);color:var(--signal);border-color:var(--ink)}
.btn.accent{background:var(--accent);border-color:var(--accent);color:#fff}
.btn.accent:hover{background:var(--ink);border-color:var(--ink);color:var(--signal)}
.btn.full{display:flex;width:100%}
.btn[disabled],.btn.off{opacity:.34;pointer-events:none}
.btn.sm{font-size:10px;padding:9px 14px;min-height:var(--tap);letter-spacing:.12em}
.btnrow{display:flex;gap:10px;margin-top:14px}
.btnrow .btn{flex:1}

/* ── chips / tags ────────────────────────────────────────────────────────── */

.tag{
  font-family:var(--f-mono);font-size:9.5px;font-weight:600;letter-spacing:.14em;
  text-transform:uppercase;padding:4px 8px;border:1px solid var(--line-2);
  color:var(--mute);border-radius:var(--r);white-space:nowrap;
}
.tag.ok{color:var(--green);border-color:rgba(31,111,67,.45)}
.tag.warn{color:var(--accent);border-color:rgba(194,65,12,.5);background:rgba(255,90,31,.08)}
.tag.bad{color:var(--danger);border-color:rgba(163,32,14,.45)}
.tag.acc{color:var(--accent);border-color:rgba(194,65,12,.5)}
.tag.solid{background:var(--ink);color:var(--signal);border-color:var(--ink)}

/* scrollable chip row — the only horizontal scroll allowed anywhere */
.chips{display:flex;gap:8px;overflow-x:auto;padding-bottom:4px;-webkit-overflow-scrolling:touch;scrollbar-width:none}
.chips::-webkit-scrollbar{display:none}
.chip{
  font-family:var(--f-mono);font-size:10.5px;font-weight:600;letter-spacing:.1em;
  text-transform:uppercase;padding:10px 13px;min-height:var(--tap);
  border:1px solid var(--line-2);background:transparent;white-space:nowrap;
  border-radius:var(--r);
  display:inline-flex;align-items:center;gap:6px;
  flex:none;            /* never let a flex parent squeeze a chip below its label */
  transition:background .14s linear,color .14s linear,border-color .14s linear;
}
.chip:hover{border-color:var(--accent)}
.chip[aria-pressed="true"]{background:var(--ink);color:var(--signal);border-color:var(--ink)}

/* ── progress ────────────────────────────────────────────────────────────── */

.bar{height:10px;background:var(--paper);border:1px solid var(--ink);overflow:hidden;
  border-radius:var(--r)}
.bar i{display:block;height:100%;background:var(--signal)}
.bar.ink i{background:var(--ink)}
.card.ink .bar{background:transparent;border-color:rgba(255,255,255,.4)}

/* ── list rows ───────────────────────────────────────────────────────────── */

.list{border:1px solid var(--line-2);border-radius:var(--r);background:var(--paper)}
.item{
  display:flex;align-items:center;gap:12px;
  width:100%;min-height:56px;padding:12px 14px;
  background:transparent;border:0;border-bottom:1px solid var(--line);
  text-align:left;
  transition:background .14s linear;
}
.item:last-child{border-bottom:0}
.item:hover{background:var(--paper-2)}
.item .t{display:block;font-weight:600;font-size:14px}
.item .m{display:block;font-family:var(--f-mono);font-size:10.5px;letter-spacing:.05em;
  color:var(--mute);margin-top:3px}
.item .grow{display:block}
.item .grow{flex:1;min-width:0}
.item .val{font-family:var(--f-mono);font-weight:600;font-size:15px;
  font-variant-numeric:tabular-nums;letter-spacing:-.02em;white-space:nowrap}
.item .val.pos{color:var(--green)}
.item .val.neg{color:var(--danger)}
.item[aria-current="true"]{background:var(--paper-2);box-shadow:inset 3px 0 0 var(--signal)}
.avat{
  width:38px;height:38px;flex:none;display:grid;place-items:center;
  background:var(--ink);color:var(--signal);
  font-family:var(--f-disp);font-weight:700;font-size:12px;letter-spacing:.02em;
  border-radius:var(--r);
}
.avat.alt{background:var(--paper-2);color:var(--ink);border:1px solid var(--line-2)}

/* ── forms ───────────────────────────────────────────────────────────────── */

.field{margin-bottom:14px}
.field label{
  display:block;font-family:var(--f-mono);font-size:9.5px;font-weight:600;
  letter-spacing:.17em;text-transform:uppercase;color:var(--mute);margin-bottom:6px;
}
.input,select.input,textarea.input{
  width:100%;font-size:16px;                    /* 16px stops iOS zoom-on-focus */
  min-height:var(--tap);padding:11px 12px;
  border:1px solid var(--line-2);background:var(--paper);border-radius:var(--r);
  -webkit-appearance:none;appearance:none;
  transition:border-color .14s linear;
}
.input:focus{border-color:var(--ink)}
select.input{background-image:linear-gradient(45deg,transparent 50%,var(--ink) 50%),linear-gradient(135deg,var(--ink) 50%,transparent 50%);
  background-position:calc(100% - 17px) 50%,calc(100% - 12px) 50%;
  background-size:5px 5px,5px 5px;background-repeat:no-repeat;padding-right:34px}
.input:focus-visible,.btn:focus-visible,.item:focus-visible,.chip:focus-visible,.tab:focus-visible,.stepbtn:focus-visible{
  outline:2px solid var(--signal);outline-offset:2px}
.hint{font-family:var(--f-mono);font-size:10.5px;line-height:1.6;color:var(--mute);margin-top:6px}

/* stepper — the marking control. Big by design: used mid-lesson, standing up. */
.step{display:flex;align-items:center;gap:0;border:1px solid var(--ink);border-radius:var(--r)}
.stepbtn{
  width:var(--tap);height:var(--tap);flex:none;
  display:grid;place-items:center;font-size:19px;font-weight:600;
  background:var(--paper);border:0;
  transition:background .12s linear,color .12s linear;
}
.stepbtn:hover{background:var(--ink);color:var(--signal)}
.stepbtn[disabled]{opacity:.26;pointer-events:none}
.step .v{
  flex:1;text-align:center;font-family:var(--f-mono);font-weight:600;font-size:16px;
  font-variant-numeric:tabular-nums;border-left:1px solid var(--ink);border-right:1px solid var(--ink);
  min-width:52px;line-height:var(--tap);
}
.step.max .v{color:var(--accent)}

/* toggle */
.sw{position:relative;width:52px;height:30px;flex:none;background:var(--paper);
  border:1px solid var(--ink);border-radius:var(--r);transition:background .15s}
.sw::after{content:"";position:absolute;top:3px;left:3px;width:22px;height:22px;
  background:var(--ink);transition:transform .15s}
.sw[aria-checked="true"]{background:var(--signal)}
.sw[aria-checked="true"]::after{transform:translateX(24px)}
.swrow{display:flex;align-items:center;gap:12px;min-height:var(--tap);padding:10px 0}

/* ── notices ─────────────────────────────────────────────────────────────── */

.note{border:1px solid var(--line-2);border-left:3px solid var(--signal);
  background:var(--paper-2);padding:12px 14px;font-size:13px;border-radius:var(--r)}
.note.warn{border-left-color:var(--accent)}
.note.bad{border-left-color:var(--danger)}
.note.ok{border-left-color:var(--green)}
.note b{font-weight:700}

/* ── sticky action footer (teacher totals, admin bulk bar) ───────────────── */

.sticky{
  position:sticky;bottom:0;z-index:30;
  background:var(--ink);color:#fff;
  padding:12px var(--gut);
  display:flex;align-items:center;gap:14px;
  border-top:2px solid var(--signal);
}
.sticky .big{font-family:var(--f-mono);font-weight:600;font-size:21px;
  font-variant-numeric:tabular-nums;letter-spacing:-.03em;line-height:1;color:var(--signal)}
.sticky .cap{font-family:var(--f-mono);font-size:9.5px;letter-spacing:.16em;
  text-transform:uppercase;color:rgba(255,255,255,.72)}
.sticky .btn{border-color:var(--signal);background:var(--signal);color:var(--ink)}
.sticky .btn:hover{background:#fff;border-color:#fff;color:var(--ink)}
.sticky .btn.ghost{background:transparent;color:#fff;border-color:rgba(255,255,255,.45)}
.sticky .btn.ghost:hover{background:#fff;color:var(--ink)}

/* ── tables (admin) ──────────────────────────────────────────────────────── */

.tbl{width:100%;border-collapse:collapse;font-size:13.5px}
.tbl th{
  font-family:var(--f-mono);font-size:9.5px;font-weight:600;letter-spacing:.16em;
  text-transform:uppercase;color:var(--mute);text-align:left;
  padding:10px 12px;border-bottom:1px solid var(--ink);white-space:nowrap;
}
.tbl td{padding:12px;border-bottom:1px solid var(--line);vertical-align:middle}
.tbl tr:last-child td{border-bottom:0}
.tbl tbody tr:hover{background:var(--paper-2)}
.tbl .r{text-align:right;font-family:var(--f-mono);font-variant-numeric:tabular-nums}
.tblwrap{border:1px solid var(--line-2);border-radius:var(--r)}
.showtbl{display:none}                 /* table view is desktop/tablet only */
.showcards{display:block}              /* card view is the phone fallback   */

/* ── two-pane (admin) ────────────────────────────────────────────────────── */
/* phone = push navigation: the detail pane covers the list.                   */

.panes{display:block}
.pane-list{display:block}
.pane-detail{display:none}
.panes.showing-detail .pane-list{display:none}
.panes.showing-detail .pane-detail{display:block}
.backlink{
  display:inline-flex;align-items:center;gap:8px;min-height:var(--tap);
  font-family:var(--f-mono);font-size:10px;font-weight:600;letter-spacing:.14em;
  text-transform:uppercase;
  background:none;border:0;padding:0;margin-bottom:8px;color:var(--accent);
}

/* ── misc ────────────────────────────────────────────────────────────────── */

.only-mobile{display:block}
.only-tablet{display:none}
.only-desk{display:none}
.hide-mobile{display:none}
.divider{height:1px;background:var(--line-2);margin:22px 0}
.empty{text-align:center;padding:36px 16px;color:var(--mute);
  font-family:var(--f-mono);font-size:11px;letter-spacing:.1em;text-transform:uppercase}
.footnote{font-size:11.5px;color:var(--mute);line-height:1.6;margin-top:20px;
  border-top:1px solid var(--line-2);padding-top:14px}
.footnote b{color:var(--ink)}

/* breakpoint read-out — a build aid, not part of the product.
   It is how you check at a glance which layout you are looking at. */
.bp{
  position:fixed;right:10px;bottom:calc(var(--tabs) + 12px);z-index:60;
  font-family:var(--f-mono);font-size:9px;font-weight:600;letter-spacing:.16em;
  text-transform:uppercase;background:var(--ink);color:var(--signal);
  padding:6px 9px;opacity:.7;border-radius:var(--r);
}
.bp::after{content:"mobile · phone-first"}
.bp[hidden]{display:none}

/* ══ TABLET ══════════════════════════════════════════════════ 640–1023px ══ */
@media (min-width:640px){
  :root{--gut:24px}
  body{font-size:15.5px}

  .app{
    grid-template-columns:var(--rail) 1fr;
    grid-template-rows:auto 1fr;
    grid-template-areas:"nav bar" "nav main";
  }

  /* nav becomes a full-height instrument rail */
  .nav{
    position:sticky;top:0;bottom:auto;
    flex-direction:column;height:100%;
    padding-bottom:0;
    border-top:0;border-right:1px solid var(--signal);
    background:var(--ink);
  }
  .nav .navhead{
    display:flex;align-items:center;justify-content:center;
    height:var(--bar);flex:none;background:var(--ink);
    border-bottom:1px solid var(--signal);
  }
  .nav .navhead img{height:24px}
  .nav .tab{
    flex:none;height:62px;gap:6px;padding:8px 4px;
    border-bottom:1px solid var(--line-w);
  }
  /* the rail already separates tabs with a rule; the idle marker on top of
     that reads as a stray dash */
  .nav .tab::after{display:none}
  .nav .tab[aria-selected="true"]::before{
    top:0;bottom:0;left:0;right:auto;width:3px;height:auto;
  }
  .nav .tab .lb{font-size:8px}
  .nav .navfoot{display:block;margin-top:auto;padding:14px 8px;text-align:center}
  .nav .navfoot .tag{font-size:8.5px;padding:3px 5px;color:rgba(255,255,255,.72);
    border-color:rgba(255,255,255,.3)}
  .nav .navfoot .tag.acc{color:var(--signal);border-color:var(--signal)}

  .appbar{padding:0 var(--gut)}
  .wrap{padding:22px var(--gut) 40px}

  .g2{grid-template-columns:repeat(2,1fr)}
  .g3{grid-template-columns:repeat(2,1fr)}
  .g4{grid-template-columns:repeat(4,1fr)}
  .grid{gap:14px}

  .showtbl{display:table}
  .showcards{display:none}

  .only-mobile{display:none}
  .only-tablet{display:block}
  .hide-mobile{display:block}

  .btnrow .btn{flex:0 1 auto;min-width:150px}
  .sticky{padding:14px var(--gut)}
  .bp{bottom:12px}
  .bp::after{content:"tablet · rail nav"}
}

/* ══ DESKTOP ═════════════════════════════════════════════════ ≥ 1024px ════ */
@media (min-width:1024px){
  :root{--gut:32px;--col:820px}

  .app{grid-template-columns:var(--side) 1fr}

  /* rail expands into a labelled sidebar */
  .nav .tab{
    flex-direction:row;justify-content:flex-start;gap:14px;
    height:52px;padding:0 18px;
  }
  .nav .tab .ic{font-size:16px;width:22px;text-align:center}
  .nav .tab .lb{font-size:10px;letter-spacing:.15em}
  .nav .tab .dot{position:static;margin-left:auto;box-shadow:none}
  .nav .navhead{justify-content:flex-start;padding:0 18px}
  .nav .navhead img{height:26px}
  .nav .navfoot{text-align:left;padding:16px 18px}

  .wrap{padding:28px var(--gut) 56px}
  .g3{grid-template-columns:repeat(3,1fr)}

  .only-tablet{display:none}
  .only-desk{display:block}

  /* two panes side by side — no more push navigation */
  .panes{display:grid;grid-template-columns:minmax(300px,380px) 1fr;gap:0;align-items:start}
  .panes .pane-list,.panes.showing-detail .pane-list{display:block;border-right:1px solid var(--line-2)}
  .panes .pane-detail,.panes.showing-detail .pane-detail{display:block;padding-left:24px}
  .backlink{display:none}

  .item{min-height:52px}
  .bp::after{content:"desktop · sidebar"}
}

@media (min-width:1440px){
  .wrap.wide{max-width:1320px}
}

/* respect the setting; the shell has no motion that carries meaning */
@media (prefers-reduced-motion:reduce){
  *{transition:none !important;animation:none !important}
}

/* print — teachers do print class summaries */
@media print{
  .nav,.appbar,.sticky,.bp,.btnrow{display:none !important}
  .app{display:block}
  .wrap{max-width:none;padding:0}
  .card{break-inside:avoid}
  .card.ink{clip-path:none;background:#fff;color:#000;border:1px solid #000}
  .card.ink::after{display:none}
}

/* ── messages: staff ↔ student ──────────────────────────────────────────────
   Two panes on a phone (list, then conversation); side by side from tablet up.
   Nothing here decides who may write to whom — the database does that, and
   this only draws what it returns. */
.msg .msg-threads .item{align-items:flex-start}
.msg .msg-t{flex:1;min-width:0}
.msg .msg-n{display:block;font-weight:600;font-size:14px}
.msg .msg-n .tag{margin-left:7px;vertical-align:1px}
.msg .msg-p{display:block;font-size:12px;color:var(--mute);margin-top:3px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.msg .msg-when{flex:none;font-family:var(--f-mono);font-size:9.5px;letter-spacing:.08em;
  color:var(--mute);display:flex;align-items:center;gap:7px;padding-top:2px}
.msg .msg-thread.unread .msg-n{font-weight:700}
.msg .msg-thread.unread .msg-p{color:var(--ink)}
.msg .msg-dot{width:8px;height:8px;background:var(--signal);display:block}

.msg .msg-log{border:1px solid var(--line-2);border-radius:var(--r);padding:12px;
  max-height:52vh;overflow-y:auto;background:var(--paper);background-image:var(--grid)}
.msg .msg-b{max-width:82%;margin-bottom:12px}
.msg .msg-b.mine{margin-left:auto}
.msg .msg-meta{display:block;font-family:var(--f-mono);font-size:9px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--mute);margin-bottom:4px}
.msg .msg-b.mine .msg-meta{text-align:right}
.msg .msg-x{display:block;padding:10px 12px;font-size:14px;line-height:1.45;
  background:var(--paper);border:1px solid var(--line-2);border-radius:var(--r)}
.msg .msg-b.mine .msg-x{background:var(--ink);color:#fff;border-color:var(--ink)}
.msg .msg-b.gone .msg-x{font-style:italic;color:var(--mute);background:transparent;
  border-style:dashed}
.msg .msg-b.mine.gone .msg-x{color:var(--mute)}

.msg .msg-form{display:flex;gap:10px;align-items:flex-end;margin-top:12px}
.msg .msg-body{flex:1;min-width:0;resize:vertical;font-family:var(--f-body);font-size:14px}
.msg .msg-send{flex:none}
.msg .msg-foot{margin-top:10px}

/* display:grid beats the `hidden` attribute's UA display:none, so without this
   the picker stays invisible but keeps covering the viewport and eats every
   click on the page. */
.msg .msg-picker[hidden]{display:none}
.msg .msg-picker{position:fixed;inset:0;z-index:70;background:rgba(8,8,8,.62);
  display:grid;place-items:end center;padding:0}
.msg .msg-picker-in{width:100%;max-width:640px;background:var(--paper);
  border-top:2px solid var(--signal);padding:16px 16px 24px;max-height:86vh;overflow:auto}

/* unread count sitting on a nav tab */
.msg-badge{position:absolute;top:7px;right:calc(50% - 24px);min-width:17px;height:17px;
  padding:0 4px;border-radius:9px;background:var(--signal);color:var(--ink);
  font-family:var(--f-mono);font-size:10px;font-weight:600;line-height:17px;text-align:center}
.nav .tab[aria-selected="true"] .msg-badge{background:var(--ink);color:var(--signal)}
.nav .tab{position:relative}

@media (min-width:820px){
  .msg .msg-picker{place-items:center}
  .msg .msg-picker-in{border:1px solid var(--ink);max-height:76vh}
  .msg.panes{display:grid;grid-template-columns:300px 1fr;gap:22px;align-items:start}
  .msg.panes .pane-list,
  .msg.panes.showing-detail .pane-list{display:block;border-right:0}
  .msg.panes .pane-detail,
  .msg.panes.showing-detail .pane-detail{display:block;padding-left:0}
  .msg .msg-back{display:none}
  .msg .msg-log{max-height:56vh}
}

/* ── alerts — the instrument speaking, unprompted ─────────────────────────
   A stack under the face plate. Each one is a black panel with a single
   orange indicator block, a monospace channel label, and a hairline gauge
   that drains as its dismissal timer runs, so the countdown is visible
   rather than a surprise.

   `.note` was already taken — it is the inline callout inside a card — so
   this block is `.alr`. Reusing it would have put a white callout background
   under white text, which is exactly the collision that has bitten twice.

   Nothing bounces. An alert settles in and leaves the same way, because the
   rest of the interface behaves like an instrument and an alert that springs
   reads as a different app. */
.alrs{
  position:fixed;z-index:80;
  top:calc(var(--bar) + 8px);left:var(--gut);right:var(--gut);
  display:flex;flex-direction:column;gap:8px;
  pointer-events:none;                 /* the gaps stay clickable */
}
.alr{
  pointer-events:auto;position:relative;overflow:hidden;
  display:grid;grid-template-columns:6px 1fr auto;align-items:stretch;
  background:var(--ink);color:#fff;border:1px solid var(--signal);
  box-shadow:0 12px 28px rgba(8,8,8,.30);
  animation:alr-in .2s linear both;
}
.alr.alr-out{animation:alr-out .16s linear both}
@keyframes alr-in{from{opacity:0;transform:translateY(-8px)}to{opacity:1;transform:none}}
@keyframes alr-out{from{opacity:1}to{opacity:0;transform:translateY(-6px)}}

.alr-bar{background:var(--signal)}
.alr-in{
  min-width:0;padding:10px 2px 12px 12px;
  background:transparent;border:0;color:inherit;font:inherit;text-align:left;
  cursor:pointer;
}
.alr-in:disabled{cursor:default}
/* On black, signal orange is 6.42:1 — this is the one place it carries type. */
.alr-ch{display:block;font-family:var(--f-mono);font-size:9.5px;font-weight:600;
  letter-spacing:.2em;text-transform:uppercase;color:var(--signal)}
.alr-t{display:block;font-family:var(--f-disp);font-weight:600;font-size:14.5px;
  letter-spacing:-.01em;margin-top:4px;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.alr-m{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;
  overflow:hidden;font-size:12.5px;line-height:1.36;margin-top:3px;
  color:rgba(255,255,255,.78)}
.alr-x{
  width:var(--tap);flex:none;background:transparent;border:0;color:rgba(255,255,255,.62);
  font-size:16px;line-height:1;transition:color .14s linear;
}
.alr-x:hover{color:var(--signal)}
.alr-g{position:absolute;left:0;bottom:0;height:2px;width:100%;background:var(--signal);
  transform-origin:left;animation:alr-drain linear forwards}
@keyframes alr-drain{from{transform:scaleX(1)}to{transform:scaleX(0)}}

/* Reduced motion keeps the alert and loses the movement. The gauge would
   still be honest as a static full bar, but a countdown nobody can see count
   is worse than none, so it goes too. */
@media (prefers-reduced-motion:reduce){
  .alr,.alr.alr-out{animation:none}
  .alr-g{display:none}
}

@media (min-width:640px){
  .alrs{left:calc(var(--rail) + var(--gut));right:auto;width:min(430px,52vw)}
}
