:root{
  --k-bg:#f5f6fb;
  --k-panel:#ffffff;
  --k-panel-alt:#fcfcff;
  --k-line:#e7e9f2;
  --k-text:#1f2430;
  --k-muted:#69707d;
  --k-primary:#42108d;
  --k-primary-2:#5a41cb;
  --k-primary-3:#6b57d8;
  --k-accent:#ece5ff;
  --k-good:#dff5e8;
  --k-warn:#fff4d6;
  --k-danger:#ffe2e2;
  --k-shadow:0 18px 40px rgba(31,36,48,.10);
  --k-radius-xl:28px;
  --k-radius-lg:22px;
  --k-radius-md:18px;
  --k-radius-sm:14px;
  --k-sidebar-w:224px;
  --k-sidebar-collapsed:78px;
  --k-topbar-h:76px;
}
*{box-sizing:border-box}
html,body{
  margin:0;
  min-height:100%;
  font-family:Arial,sans-serif;
  background:var(--k-bg);
  color:var(--k-text);
}
body.k-shell-lock{overflow:hidden}
.k-app-shell{
  display:grid;
  grid-template-columns:var(--k-sidebar-w) 1fr;
  min-height:100vh;
}
body.sidebar-collapsed .k-app-shell{
  grid-template-columns:var(--k-sidebar-collapsed) 1fr;
}
.k-sidebar{
  background:
    radial-gradient(circle at 18% 14%, rgba(255,255,255,.08), transparent 22%),
    radial-gradient(circle at 82% 82%, rgba(255,255,255,.07), transparent 24%),
    linear-gradient(180deg,var(--k-primary) 0%, var(--k-primary-2) 100%);
  color:#fff;
  padding:18px 14px;
  display:flex;
  flex-direction:column;
  min-height:100vh;
  border-radius:0 24px 24px 0;
  box-shadow:inset -1px 0 0 rgba(255,255,255,.04);
}
.k-brand{
  display:flex;
  align-items:center;
  gap:12px;
  color:#fff;
  text-decoration:none;
  margin-bottom:18px;
}
.k-brand-logo{
  width:42px;
  height:42px;
  border-radius:14px;
  object-fit:cover;
  display:block;
  background:rgba(255,255,255,.10);
  padding:2px;
  box-shadow:0 10px 24px rgba(0,0,0,.18);
}
.k-brand-copy{
  display:flex;
  flex-direction:column;
  line-height:1.05;
}
.k-brand-title{
  font-size:18px;
  font-weight:800;
  letter-spacing:.08em;
}
.k-brand-subtitle{
  margin-top:4px;
  font-size:10px;
  font-weight:700;
  letter-spacing:.14em;
  text-transform:uppercase;
  opacity:.82;
}
.k-portal-chip{
  display:inline-flex;
  align-items:center;
  width:fit-content;
  padding:8px 12px;
  border-radius:999px;
  background:rgba(255,255,255,.10);
  border:1px solid rgba(255,255,255,.14);
  font-size:12px;
  font-weight:800;
  margin-bottom:16px;
}
.k-nav{flex:1 1 auto}
.k-nav a{
  position:relative;
  display:flex;
  align-items:center;
  gap:10px;
  padding:11px 12px;
  margin-bottom:6px;
  border-radius:14px;
  color:#fff;
  text-decoration:none;
  font-size:14px;
  font-weight:600;
  opacity:.96;
  transition:background .16s ease, transform .16s ease, opacity .16s ease;
}
.k-nav a:hover{background:rgba(255,255,255,.10)}
.k-nav a.active{
  background:rgba(255,255,255,.16);
  border:1px solid rgba(255,255,255,.10);
  font-weight:800;
}
.k-nav-icon{
  width:18px;
  display:inline-flex;
  justify-content:center;
  flex-shrink:0;
  font-size:15px;
}
.k-nav-label{white-space:nowrap}
.k-sidebar-footer{
  margin-top:18px;
  padding-top:14px;
  border-top:1px solid rgba(255,255,255,.14);
  display:flex;
  justify-content:space-between;
  align-items:center;
  gap:10px;
}
.k-sidebar-mark{
  display:flex;
  align-items:center;
  justify-content:center;
}
.k-sidebar-mark img{
  width:28px;
  height:auto;
  display:block;
  opacity:.95;
}
.k-sidebar-toggle{
  width:32px;
  height:32px;
  border-radius:10px;
  border:1px solid rgba(96,198,255,.42);
  background:rgba(77,182,255,.18);
  color:#dff5ff;
  cursor:pointer;
  display:flex;
  align-items:center;
  justify-content:center;
  font-size:17px;
  font-weight:800;
  text-shadow:0 0 12px rgba(77,182,255,.65);
}
body.sidebar-collapsed .k-brand-copy,
body.sidebar-collapsed .k-brand-title,
body.sidebar-collapsed .k-brand-subtitle,
body.sidebar-collapsed .k-nav-label,
body.sidebar-collapsed .k-portal-chip{
  display:none !important;
}
body.sidebar-collapsed .k-brand{justify-content:center}
body.sidebar-collapsed .k-nav a{
  justify-content:center;
  padding-left:10px;
  padding-right:10px;
}
body.sidebar-collapsed .k-sidebar-footer{
  flex-direction:column;
  justify-content:center;
}
.k-main{
  min-width:0;
  display:grid;
  grid-template-rows:var(--k-topbar-h) 1fr;
  min-height:100vh;
}
.k-topbar{
  background:rgba(255,255,255,.86);
  backdrop-filter:blur(12px);
  border-bottom:1px solid var(--k-line);
  display:flex;
  justify-content:space-between;
  align-items:center;
  gap:16px;
  padding:12px 18px;
}
.k-topbar-left,.k-topbar-right{
  display:flex;
  align-items:center;
  gap:12px;
}
.k-school-badge,.k-user-avatar{
  width:40px;
  height:40px;
  border-radius:999px;
  overflow:hidden;
  background:var(--k-accent);
  flex-shrink:0;
}
.k-school-badge img,.k-user-avatar img{
  width:100%;
  height:100%;
  object-fit:cover;
  display:block;
}
.k-meta-title{
  font-weight:700;
  font-size:15px;
  color:var(--k-text);
  line-height:1.1;
}
.k-meta-sub{
  font-size:11px;
  color:var(--k-muted);
  line-height:1.1;
}
.k-user-box{
  display:flex;
  align-items:center;
  gap:8px;
  background:#fafafe;
  border:1px solid var(--k-line);
  border-radius:14px;
  padding:6px 8px;
}
.k-page{
  overflow:auto;
  min-height:0;
  padding:20px;
}
.k-panel{
  padding:18px;
  background:#fff;
  border:1px solid var(--k-line);
  border-radius:22px;
  box-shadow:var(--k-shadow);
}
.k-home-hero{
  position:relative;
  overflow:hidden;
  border-radius:28px;
  padding:28px;
  margin-bottom:18px;
  color:#fff;
  background:
    radial-gradient(circle at 18% 20%, rgba(255,255,255,.10), transparent 26%),
    radial-gradient(circle at 82% 78%, rgba(255,255,255,.08), transparent 28%),
    linear-gradient(135deg,#2f1688 0%, #4b2aad 52%, #5a41cb 100%);
  box-shadow:0 24px 48px rgba(21,8,63,.18);
}
.k-home-hero-grid{
  display:grid;
  grid-template-columns:1.2fr .8fr;
  gap:18px;
  align-items:stretch;
}
.k-home-hero-copy .k-eyebrow{
  font-size:12px;
  font-weight:800;
  letter-spacing:.18em;
  text-transform:uppercase;
  color:rgba(255,255,255,.72);
  margin-bottom:10px;
}
.k-home-hero-copy h1{
  margin:0 0 12px 0;
  font-family:Georgia,"Times New Roman",serif;
  font-size:42px;
  line-height:1.02;
}
.k-home-hero-copy p{
  margin:0;
  max-width:760px;
  color:rgba(255,255,255,.84);
  font-size:15px;
  line-height:1.65;
}
.k-home-hero-actions{
  display:flex;
  gap:10px;
  flex-wrap:wrap;
  margin-top:18px;
}
.k-home-btn{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  gap:8px;
  min-height:42px;
  padding:11px 14px;
  border-radius:14px;
  text-decoration:none;
  font-size:13px;
  font-weight:800;
  transition:transform .15s ease, background .15s ease;
}
.k-home-btn:hover{transform:translateY(-1px)}
.k-home-btn.primary{
  background:#fff;
  color:#4b2aad;
  border:1px solid #fff;
}
.k-home-btn.ghost{
  background:rgba(255,255,255,.10);
  color:#fff;
  border:1px solid rgba(255,255,255,.16);
}
.k-home-hero-side{
  display:grid;
  gap:12px;
}
.k-home-focus-card,.k-home-stat-grid{
  background:rgba(255,255,255,.10);
  border:1px solid rgba(255,255,255,.14);
  border-radius:20px;
}
.k-home-focus-card{padding:16px}
.k-home-focus-card h3{
  margin:0 0 8px 0;
  font-size:18px;
}
.k-home-focus-card p{
  margin:0;
  color:rgba(255,255,255,.84);
  font-size:14px;
  line-height:1.55;
}
.k-home-stat-grid{
  padding:14px;
  display:grid;
  grid-template-columns:repeat(2,1fr);
  gap:12px;
}
.k-home-stat{
  padding:12px 12px;
  border-radius:16px;
  background:rgba(255,255,255,.08);
  border:1px solid rgba(255,255,255,.10);
}
.k-home-stat .label{
  font-size:12px;
  opacity:.85;
  margin-bottom:6px;
}
.k-home-stat .value{
  font-size:20px;
  font-weight:800;
}
.k-home-grid{
  display:grid;
  grid-template-columns:1.15fr .85fr;
  gap:18px;
}
.k-item{
  border:1px solid var(--k-line);
  border-radius:18px;
  background:#fcfcff;
  padding:14px;
  margin-bottom:12px;
}
.k-item:last-child{margin-bottom:0}
.k-item-top{
  display:flex;
  justify-content:space-between;
  gap:12px;
  align-items:flex-start;
  margin-bottom:8px;
}
.k-item h3{
  margin:0;
  font-size:16px;
}
.k-item p{
  margin:0;
  color:var(--k-muted);
  line-height:1.45;
  font-size:14px;
}
.k-actions{
  display:flex;
  gap:10px;
  flex-wrap:wrap;
  margin-top:12px;
}
.k-btn-soft{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  min-height:40px;
  padding:10px 14px;
  border-radius:12px;
  border:1px solid var(--k-line);
  background:#fff;
  color:var(--k-primary);
  text-decoration:none;
  font-size:13px;
  font-weight:800;
}
@media (max-width:980px){
  body.k-shell-lock{overflow:auto}
  .k-app-shell{
    grid-template-columns:1fr;
    min-height:auto;
  }
  .k-sidebar{
    min-height:auto;
    border-radius:0 0 24px 24px;
  }
  .k-main{
    grid-template-rows:auto 1fr;
    min-height:auto;
  }
  .k-page{
    overflow:visible;
  }
  .k-home-hero-grid,
  .k-home-grid{
    grid-template-columns:1fr;
  }
  .k-home-hero-copy h1{
    font-size:34px;
  }
}



body.k-shell-lock{
  overflow:hidden;
}

.k-app-shell{
  display:grid;
  grid-template-columns: var(--k-sidebar-w) 1fr;
  min-height:100vh;
  height:100vh;
}

.k-sidebar{
  position:sticky;
  top:0;
  height:100vh;
  max-height:100vh;
  overflow:hidden;
  display:flex;
  flex-direction:column;
}

.k-sidebar-nav{
  flex:1 1 auto;
  min-height:0;
  overflow:auto;
}

.k-sidebar-bottom{
  margin-top:auto;
  flex:0 0 auto;
}

.k-topbar{
  position:sticky;
  top:0;
  z-index:60;
}

.k-page{
  position:relative;
  z-index:1;
}

/* ===== Global tooltip override ===== */
.k-sidebar a[data-tooltip]::before,
.k-sidebar a[data-tooltip]::after{
  content:none !important;
  display:none !important;
}

#kGlobalTooltip{
  position:fixed;
  left:0;
  top:0;
  transform:translate3d(0,0,0);
  z-index:2147483647 !important;
  pointer-events:none;
  opacity:0;
  visibility:hidden;
  transition:opacity .14s ease, visibility .14s ease;
  padding:10px 14px;
  border-radius:14px;
  white-space:nowrap;
  color:#fff;
  font-size:12px;
  font-weight:700;
  letter-spacing:.02em;
  background:rgba(75,42,173,.72);
  border:1px solid rgba(255,255,255,.22);
  box-shadow:0 14px 40px rgba(20,10,60,.30);
  backdrop-filter:blur(14px);
  -webkit-backdrop-filter:blur(14px);
}

#kGlobalTooltip.is-visible{
  opacity:1;
  visibility:visible;
}

#kGlobalTooltipArrow{
  position:fixed;
  left:0;
  top:0;
  width:10px;
  height:10px;
  transform:translate3d(0,0,0) rotate(45deg);
  z-index:2147483646 !important;
  pointer-events:none;
  opacity:0;
  visibility:hidden;
  background:rgba(75,42,173,.72);
  border-left:1px solid rgba(255,255,255,.18);
  border-top:1px solid rgba(255,255,255,.18);
  backdrop-filter:blur(14px);
  -webkit-backdrop-filter:blur(14px);
}

#kGlobalTooltipArrow.is-visible{
  opacity:1;
  visibility:visible;
}


/* === LEGACY TETRA SIDEBAR COMPAT === */
:root{
  --k-sidebar-w:224px;
  --k-sidebar-collapsed:78px;
}

body.sidebar-collapsed .app-shell{
  grid-template-columns:var(--k-sidebar-collapsed) 1fr !important;
}

.sidebar{
  position:sticky;
  top:0;
  align-self:start;
  width:100%;
  height:100vh;
  overflow:hidden;
  background:linear-gradient(180deg,#24115f 0%, #3b1f8f 48%, #5b43c4 100%);
  color:#fff;
  padding:18px 14px;
  border-radius:0 28px 28px 0;
  box-shadow:0 24px 80px rgba(55,30,130,.20);
  display:flex;
  flex-direction:column;
}

.brand-wrap{
  display:flex;
  align-items:center;
  gap:10px;
  margin-bottom:22px;
  text-decoration:none;
  color:#fff;
}

.brand-logo{
  width:40px;
  height:40px;
  border-radius:12px;
  object-fit:cover;
  display:block;
  background:rgba(255,255,255,.10);
  padding:2px;
}

.brand-copy{
  display:flex;
  flex-direction:column;
  line-height:1.05;
}

.brand-text{
  font-size:18px;
  font-weight:800;
  letter-spacing:.08em;
}

.brand-subtitle{
  font-size:10px;
  font-weight:700;
  letter-spacing:.12em;
  opacity:.82;
  text-transform:uppercase;
  margin-top:4px;
}

.portal-chip{
  display:inline-flex;
  align-items:center;
  min-height:32px;
  width:fit-content;
  padding:6px 10px;
  margin-bottom:14px;
  border-radius:999px;
  font-size:11px;
  font-weight:800;
  letter-spacing:.04em;
  text-transform:uppercase;
  background:rgba(255,255,255,.12);
  color:#fff;
  border:1px solid rgba(255,255,255,.14);
}

.nav{
  flex:1 1 auto;
  min-height:0;
  overflow:auto;
  padding-right:2px;
}

.nav a{
  display:flex;
  align-items:center;
  gap:10px;
  color:#fff;
  text-decoration:none;
  padding:11px 12px;
  border-radius:14px;
  margin-bottom:6px;
  opacity:.96;
  font-size:14px;
  font-weight:700;
  position:relative;
  transition:background .18s ease, transform .18s ease, opacity .18s ease;
}

.nav a:hover{
  background:rgba(255,255,255,.10);
}

.nav a.active{
  background:rgba(255,255,255,.16);
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.08);
}

.nav-icon{
  width:18px;
  display:inline-flex;
  justify-content:center;
  flex-shrink:0;
  font-size:15px;
}

.sidebar-footer,
.sidebar-footer-row{
  margin-top:18px;
  padding-top:14px;
  border-top:1px solid rgba(255,255,255,.14);
  display:flex;
  justify-content:space-between;
  align-items:center;
  gap:10px;
}

.sidebar-brand-footer,
.k-sidebar-mark{
  display:inline-flex;
  align-items:center;
  justify-content:center;
  width:36px;
  height:36px;
  border-radius:12px;
  background:rgba(255,255,255,.10);
  border:1px solid rgba(255,255,255,.12);
}

.sidebar-brand-mark,
.k-sidebar-mark img{
  width:22px;
  height:22px;
  object-fit:contain;
  display:block;
}

.sidebar-toggle{
  width:32px;
  height:32px;
  border-radius:10px;
  border:1px solid rgba(255,255,255,.18);
  background:rgba(255,255,255,.10);
  color:#fff;
  cursor:pointer;
  display:flex;
  align-items:center;
  justify-content:center;
  font-size:13px;
}

body.sidebar-collapsed .brand-copy,
body.sidebar-collapsed .brand-text,
body.sidebar-collapsed .brand-subtitle,
body.sidebar-collapsed .nav-label,
body.sidebar-collapsed .portal-chip{
  display:none !important;
}

body.sidebar-collapsed .brand-wrap{
  justify-content:center;
}

body.sidebar-collapsed .sidebar-footer,
body.sidebar-collapsed .sidebar-footer-row{
  justify-content:center;
}

body.sidebar-collapsed .nav a{
  justify-content:center;
  padding-left:10px;
  padding-right:10px;
}

body.sidebar-collapsed .nav-icon{
  margin:0;
}


/* ===== LAYOUT CLASS ALIASES ===== */
/* Mirror of .k-app-shell / .k-main / .k-page for pages using pre-k-* class names.
   Keeps topbar-shell.js's .topbar-left / .topbar-right / .school-logo / .user-box
   working without page-local redefinition.                                          */

.app-shell{
  display:grid;
  grid-template-columns:var(--k-sidebar-w) 1fr;
  min-height:100vh;
  height:100vh;
}
body.sidebar-collapsed .app-shell{
  grid-template-columns:var(--k-sidebar-collapsed) 1fr;
}
.right-column{
  min-width:0;
  display:grid;
  grid-template-rows:var(--k-topbar-h) 1fr;
  min-height:100vh;
}
.page-content{
  overflow:auto;
  min-height:0;
  padding:22px;
}
@media (max-width:900px){
  /* Tablet ergonomics only. The app-shell grid is intentionally NOT collapsed
     to a single column here: the sidebar runs as a compact icon rail across the
     whole 721–1280 range (tetra-shell-v2.js `tabletSidebarQuery`), so it must
     keep its rail COLUMN down to 721px. Collapsing the grid at ≤900 (as this
     block used to) zeroed the sidebar between 721–900 — no column here, and the
     mobile bottom-bar treatment only starts ≤720 — leaving a dead zone with no
     navigation at all. Single-column collapse now lives in the ≤720 block below,
     aligned with the bottom bar. */
  .right-column{grid-template-rows:auto 1fr}
  .page-content{padding:16px}
}

/* ============================================================================
 * TM.2 — Canonical mobile shell collapse (shared, ≤720px). Presentation only.
 * WHY THIS EXISTS / WHY !important: several teacher pages re-declare their grid
 * as `.app-shell{grid-template-columns:224px 1fr}` in their OWN inline <style>,
 * which loads AFTER this stylesheet and therefore overrides the shell's earlier
 * @media collapse — leaving a 224px desktop sidebar squeezing content into
 * ~166px on a 390px phone (e.g. /tetrahedron/students/). This end-of-file rule,
 * gated to mobile, authoritatively forces single-column for BOTH grid class
 * names so the collapse is consistent across every route that loads the shell.
 * It only reflows the OUTER shell frame; no inner content/table/form classes,
 * no JS, no data, no teacher business logic are touched. A proper hamburger
 * drawer (hiding the stacked nav behind a toggle) is deferred to TM.2.1 — for
 * now the sidebar stacks as a full-width nav block (functional, no JS).
 * ========================================================================== */
@media (max-width:720px){
  .app-shell, .k-app-shell{
    grid-template-columns:1fr !important;
    height:auto !important;
    min-height:auto !important;
  }
  /* TM.2.1 — the deferred drawer, delivered as a bottom bar.
   *
   * This rule used to include .k-sidebar and force `position:static !important`,
   * stacking the whole rail as a full-width block above the content (the comment
   * above called that a stopgap and deferred the real fix). On a 390px phone it
   * ran ~1960px tall, so the page opened on a wall of navigation.
   *
   * .k-sidebar is now handled by the SHELL.A1 bottom-bar block at the end of this
   * file. It is dropped from this selector rather than overridden there, because
   * `!important` here would win on specificity no matter what that block says —
   * fighting it with more !important is how stylesheets rot.
   *
   * .sidebar (legacy routes that never adopted .k-sidebar) keeps the old
   * stacking behaviour; it has no icon markup to build a bar from.
   */
  .sidebar{
    position:static !important;
    height:auto !important;
    max-height:none !important;
    overflow:visible !important;
    border-radius:0 0 20px 20px;
  }
  .k-sidebar-nav{ overflow:visible !important; }
  .k-main, .right-column{ height:auto !important; min-height:auto !important; }
  .k-page, .page-content{ overflow:visible; }
  /* compact teacher-operations topbar */
  .k-topbar, .topbar{ padding:10px 14px; }
  /* shell controls reachable */
  .k-sidebar-toggle{ min-height:44px; min-width:44px; }
}

/* ============================================================================
 * TM.3B — Tetrahedron operations theme tokens (additive; light defaults + OS
 * dark mode). PRINCIPLE: shared Kairos brand, teacher-OPERATIONS theme — clean
 * and calm, purple as ACCENT only (never a full background). Dark mode uses an
 * operational charcoal/navy canvas, intentionally DISTINCT from Cube's immersive
 * #0c1020 student gradient (no cm- token reuse). Nothing in this shared shell
 * consumes --tet-* yet, so this block is a ZERO-visual-change token API across
 * all 114 routes; pages opt in by using the tokens (home is first, TM.3B).
 * Rollout path: a route adopts --tet-* surfaces → it gains OS dark mode for free.
 * ========================================================================== */
:root {
  --tet-bg:#f5f6fb; --tet-surface:#ffffff; --tet-card:#ffffff;
  --tet-text:#1f2430; --tet-muted:#69707d; --tet-border:#e7e9f2;
  --tet-accent:#4b2aad; --tet-accent-soft:#ece5ff;
  --tet-danger:#c0392b; --tet-warning:#9a6700; --tet-success:#18794e;
}
@media (prefers-color-scheme: dark) {
  :root {
    --tet-bg:#161a22; --tet-surface:#1e232e; --tet-card:#222834;
    --tet-text:#eef1f6; --tet-muted:#a3acbd; --tet-border:#333b48;
    --tet-accent:#a99aff; --tet-accent-soft:#2a2740;
    --tet-danger:#ff8d8d; --tet-warning:#ffc56b; --tet-success:#74d39e;
  }
}
/* Explicit override hooks (no toggle JS exists yet — harmless future hook;
   higher specificity than the @media :root so an explicit choice beats the OS). */
:root[data-theme="dark"] {
  --tet-bg:#161a22; --tet-surface:#1e232e; --tet-card:#222834;
  --tet-text:#eef1f6; --tet-muted:#a3acbd; --tet-border:#333b48;
  --tet-accent:#a99aff; --tet-accent-soft:#2a2740;
  --tet-danger:#ff8d8d; --tet-warning:#ffc56b; --tet-success:#74d39e;
}
:root[data-theme="light"] {
  --tet-bg:#f5f6fb; --tet-surface:#ffffff; --tet-card:#ffffff;
  --tet-text:#1f2430; --tet-muted:#69707d; --tet-border:#e7e9f2;
  --tet-accent:#4b2aad; --tet-accent-soft:#ece5ff;
  --tet-danger:#c0392b; --tet-warning:#9a6700; --tet-success:#18794e;
}

/* ============================================================================
 * TM.8 — Tetrahedron mobile UX system cleanup (shared, tetrahedron-only).
 * PRESENTATION/NAVIGATION ONLY — no JS, no data, no new reads/writes. This file
 * is loaded by tetrahedron routes ONLY (never Cube/Octa/Dodeca/Icosa/Superadmin),
 * and it loads AFTER topbar-shell.css, so these rules tune the SHARED topbar
 * dropdowns + the canonical teacher bottom-nav consistently across every
 * Tetrahedron module WITHOUT editing any cross-portal stylesheet. Every rule is
 * gated ≤720px → desktop renders byte-equivalent.
 *
 * Resolves four cross-module inconsistencies left after TM.2–TM.7:
 *   1. Compact mobile topbar — collapse the user box to its avatar, truncate the
 *      school name, so the bar no longer feels like a desktop bar squeezed small.
 *   2. Mobile-fit notification/user panels — topbar-shell.css anchors these as
 *      right-aligned 390/240px desktop dropdowns (right:-10px) that overflow a
 *      390px phone; re-anchor as viewport-fit sheets (no oversized floating card,
 *      no horizontal overflow).
 *   3. A clear active "bubble" on the selected bottom-nav module (Material-style
 *      pill behind the active icon) — pages only set the active COLOR today.
 *   4. The More-sheet current-module chip — home's TM.3 nav copy lacked the
 *      aria-current highlight that TM.7 routes already had; unify it here so the
 *      current module reads as an active chip on every route.
 * ========================================================================== */
@media (max-width:720px){
  /* ── 1 · Compact mobile topbar ─────────────────────────────────────────── */
  /* A long school name must not push the topbar wide; truncate gracefully. */
  .topbar-left .school-name, .k-topbar-left .k-meta-title{
    max-width:46vw; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  }
  /* Collapse the user box to just the avatar (drop the name/role text + caret).
     The avatar stays a one-tap target; the full menu (Profile / Preferences /
     Help / Log out) is still in the dropdown, so settings remain available. */
  .kairos-user-box{ padding:5px; gap:0; }
  .kairos-user-box > div:not(.user-avatar){ display:none; }

  /* ── 2 · Mobile-fit notification + user panels ─────────────────────────── */
  .kairos-notif-dropdown{
    position:fixed; top:64px; left:10px; right:10px;
    width:auto; max-width:none; max-height:72vh; border-radius:18px;
  }
  .kairos-notif-list{ max-height:none; }
  .kairos-user-dropdown{
    position:fixed; top:64px; right:10px; left:auto;
    width:min(86vw,260px); max-width:none;
  }

  /* ── 3 · Bottom-nav active "bubble" (pill behind the icon) ─────────────── */
  /* Additive: pages set .tm-ico font-size/line-height + the active COLOR; this
     adds the pill container on every icon and the filled fill on the active /
     current item only, so the selected module reads as a clear chip. */
  .tm-bottom-nav .tm-ico{
    display:inline-flex; align-items:center; justify-content:center;
    min-width:46px; height:26px; border-radius:999px; transition:background .15s ease;
  }
  .tm-tab.active .tm-ico, .tm-tab[aria-current="page"] .tm-ico,
  .tm-more.tm-current > summary .tm-ico, .tm-more[open] > summary .tm-ico{
    background:#ece5ff;
  }

  /* ── 4 · More-sheet current-module chip (unify home with TM.7 routes) ───── */
  .tm-more-sheet a[aria-current="page"]{
    background:#f3eefc; color:#4b2aad; font-weight:800;
  }
}

/* ── AI nav item: the tutor's own face, with the shared ring ────────────────
 *
 * The assistant is a person, not a feature, so its nav entry carries the same
 * animated guide rig (ring + breath + blink) used by the FAB, onboarding and the
 * student runtime — rather than a generic sparkle glyph that could be anything.
 *
 * Progressive: the static SVG shipped in the markup stays until
 * kairos-active-guide-v1 resolves, so a failed import degrades to the old icon
 * instead of an empty box. tetra-shell-v2.js adds .has-guide once it has a face.
 *
 * Keyframes are namespaced kng- so this sheet stays standalone (socrates-fab.css
 * owns the sf- copies and is NOT loaded on every page).
 */
/* The face is drawn larger than the line glyphs so it reads as a portrait, but
   the negative side margins keep its LAYOUT width at the shared 18px — so this
   item's label stays aligned with every other one in the nav. Vertical negative
   margin likewise stops the taller disc from growing the row. */
.k-nav-icon.has-guide{
  position:relative;
  width:26px;
  height:26px;
  margin:-4px;
  flex:0 0 auto;
}
.k-nav-icon.has-guide::before{
  content:'';
  position:absolute;
  inset:-2px;
  border-radius:50%;
  background:conic-gradient(from 0deg,
    var(--kng-accent,#7b6cf6), transparent 30%,
    transparent 70%, var(--kng-accent,#7b6cf6));
  animation:kng-ring 7s linear infinite;
}
.k-nav-icon.has-guide .guide-avatar{
  position:relative;
  display:block;
  width:100%;
  height:100%;
  border-radius:50%;
}
.k-nav-icon.has-guide .gf-disc{
  position:absolute;
  inset:1px;
  border-radius:50%;
  overflow:hidden;
  display:block;
  background:#3a3170;
}
.k-nav-icon.has-guide .gf-disc svg{width:100%;height:100%;display:block;}
.k-nav-icon.has-guide .gf-bg{fill:#3a3170;}
.k-nav-icon.has-guide .gf-breath{
  transform-box:fill-box;
  transform-origin:50% 100%;
  animation:kng-breath 4.4s ease-in-out infinite;
}
.k-nav-icon.has-guide .gf-eye{
  transform-box:fill-box;
  transform-origin:center;
  animation:kng-blink 5.6s infinite;
}
/* The mouth only opens when something is actually speaking; idle stays shut. */
.k-nav-icon.has-guide .gf-mouth{opacity:0;}

/* The active tutor gets a fuller ring, so the current section still reads. */
.k-nav a.active .k-nav-icon.has-guide::before{
  inset:-3px;
  animation-duration:5s;
}

@keyframes kng-ring{to{transform:rotate(360deg)}}
@keyframes kng-breath{
  0%,100%{transform:translateY(0) scale(1)}
  50%{transform:translateY(-1px) scale(1.015)}
}
@keyframes kng-blink{
  0%,92%,100%{transform:scaleY(1)}
  95%{transform:scaleY(.08)}
}

@media (prefers-reduced-motion: reduce){
  .k-nav-icon.has-guide::before,
  .k-nav-icon.has-guide .gf-breath,
  .k-nav-icon.has-guide .gf-eye{animation:none;}
}

/* ════════════════════════════════════════════════════════════════════════════
 * SHELL.A1 — the shell layout Tetrahedron never had, and its mobile form.
 *
 * WHY THIS EXISTS
 * Octahedron ships octa-shell.css, which defines .app-shell / .right-column /
 * .page-content for every one of its pages. Tetrahedron had no such file: only
 * 16 of its 118 pages defined that layout in their own <style> block, and the
 * other 102 defined nothing at all. So on most of the portal the whole document
 * scrolled and the sidebar scrolled away with it, while a handful of pages
 * (requests-certifications among them) correctly pinned the rail and scrolled
 * only the content. Same portal, two behaviours, depending on which page you
 * happened to open.
 *
 * These rules give every page the pinned-rail behaviour. The 16 pages that
 * already declare it keep winning — their <style> block comes after this
 * stylesheet — so this changes the other 102 and leaves the working ones alone.
 *
 * body:has(.app-shell) scopes the viewport lock to pages that actually use the
 * shell. A blanket overflow:hidden on body would have broken every standalone
 * page (login, onboarding, print views) that legitimately scrolls.
 * ════════════════════════════════════════════════════════════════════════════ */

body:has(.app-shell){
  height:100vh;
  overflow:hidden;
}

.app-shell{
  display:grid;
  grid-template-columns:var(--k-sidebar-w) 1fr;
  height:100vh;
}
body.sidebar-collapsed .app-shell{
  grid-template-columns:var(--k-sidebar-collapsed) 1fr;
}

/* The rail owns its own scroll: a long nav must not drag the page with it. */
.app-shell > .k-sidebar{
  height:100vh;
  overflow-y:auto;
  overflow-x:hidden;
}

.right-column{
  display:grid;
  grid-template-rows:var(--k-topbar-h) 1fr;
  height:100vh;
  min-width:0;
}

/* min-height:0 is load-bearing: without it a grid child refuses to shrink below
   its content and the overflow never engages, so nothing scrolls. */
.page-content{
  overflow:auto;
  min-height:0;
}

/* ── Tablet band (721–1024px): release the viewport lock ───────────────────
 *
 * The lock above (body:has(.app-shell){height:100vh;overflow:hidden}) only
 * released at <=720px, but several shell pages switch to natural page scroll at
 * <=900px via their own media queries (html/body -> auto, .page-content ->
 * overflow:visible). In the 721–900 band the shell stayed locked to 100vh while
 * .page-content was visible and overflowing, so content past the fold was
 * clipped and unreachable ("can't scroll down on tablet"). This releases the
 * lock across the tablet band while KEEPING the desktop two-column layout: the
 * page scrolls naturally and the rail stays pinned. Below 720px the mobile
 * bottom-bar block takes over. */
@media (min-width:721px) and (max-width:1024px){
  html, body{height:auto !important; min-height:100% !important; overflow-y:auto !important;}
  body:has(.app-shell){height:auto !important; overflow:visible !important;}
  .app-shell{height:auto !important; min-height:100vh !important;}
  .right-column{height:auto !important; min-height:calc(100vh - var(--k-topbar-h)) !important;}
  .page-content{overflow-y:visible !important; height:auto !important; max-height:none !important;}
  .app-shell > .k-sidebar{position:sticky; top:0; height:100vh; align-self:start;}
}

/* ── Mobile: the rail becomes a bottom bar built from the same SVGs ─────────
 *
 * At 390px the desktop rail was still rendering as a real column — ~180px of a
 * 390px screen, with the nav running 1960px down the page. Content got the
 * remaining sliver.
 *
 * Rather than invent a second navigation, the existing sidebar is re-laid-out as
 * a bottom bar: the same links, the same SVG icons, the same active state, the
 * same guide face on the AI item. Nothing new to keep in sync, and it reaches
 * all 118 pages at once.
 *
 * The 37 pages that already ship their own .tm-bottom-nav set
 * .k-sidebar{display:none !important}, which still wins here — so they keep
 * their bar and never get two.
 */
@media (max-width:720px){
  html, body{
    height:auto !important;
    min-height:100% !important;
    overflow-y:auto !important;
  }
  .right-column, .page-content, .k-page{
    height:auto !important;
    max-height:none !important;
  }
  .page-content, .k-page{overflow-y:visible !important;}

  body.tetra-mobile-nav-canonical .tm-bottom-nav{display:none !important;}
  body.tetra-mobile-nav-canonical .app-shell > .k-sidebar{display:flex !important;}
  body.tetra-mobile-nav-canonical .app-shell,
  body.sidebar-collapsed.tetra-mobile-nav-canonical .app-shell{
    grid-template-columns:minmax(0,1fr) !important;
    width:100% !important;
  }
  body.tetra-mobile-nav-canonical .right-column{
    grid-column:1 !important;
    width:100% !important;
    min-width:0 !important;
  }
  body.tetra-mobile-nav-canonical .k-nav-grouped{display:none !important;}
  body.tetra-mobile-nav-canonical .k-nav-mobile-flat{display:flex !important;}

  body:has(.app-shell){
    height:auto;
    overflow:auto;
  }

  .app-shell,
  body.sidebar-collapsed .app-shell{
    grid-template-columns:1fr;
    height:auto;
  }

  .right-column{
    height:auto;
    grid-template-rows:auto 1fr;
    /* Clear the fixed bar, plus the home-indicator inset on notched phones. */
    padding-bottom:calc(68px + env(safe-area-inset-bottom, 0px));
  }

  .page-content{overflow:visible;}

  .app-shell > .k-sidebar{
    position:fixed;
    left:0; right:0; bottom:0;
    top:auto;
    z-index:9995;                     /* under the assistant FAB (9996) */
    height:auto;
    min-height:0;
    overflow:visible;
    flex-direction:row;
    padding:6px 4px calc(6px + env(safe-area-inset-bottom, 0px));
    border-radius:18px 18px 0 0;
    border-right:none;
    border-top:1px solid rgba(255,255,255,.12);
    box-shadow:0 -8px 26px rgba(0,0,0,.42);
  }

  /* Identity and chrome belong to the topbar on a phone, not to the tab bar. */
  .app-shell > .k-sidebar .k-brand,
  .app-shell > .k-sidebar .k-portal-chip,
  .app-shell > .k-sidebar .k-sidebar-footer{display:none;}

  .app-shell > .k-sidebar .k-nav{
    flex:1 1 auto;
    display:flex;
    gap:2px;
    overflow-x:auto;
    overflow-y:hidden;
    scrollbar-width:none;
    -webkit-overflow-scrolling:touch;
  }
  .app-shell > .k-sidebar .k-nav::-webkit-scrollbar{display:none;}

  .app-shell > .k-sidebar .k-nav a{
    flex:0 0 auto;
    flex-direction:column;
    align-items:center;
    justify-content:center;
    gap:3px;
    min-width:60px;
    margin:0;
    padding:6px 4px;
    border-radius:12px;
    font-size:9.5px;
    font-weight:600;
    text-align:center;
  }
  .app-shell > .k-sidebar .k-nav a:hover{transform:none;}

  /* The label is kept, not dropped: an icon-only bar makes a teacher guess. It
     is small and clipped rather than absent. */
  .app-shell > .k-sidebar .k-nav-label{
    display:block !important;
    max-width:56px;
    overflow:hidden;
    text-overflow:ellipsis;
    white-space:nowrap;
    line-height:1.1;
  }

  .app-shell > .k-sidebar .k-nav-icon{
    width:22px;
    height:22px;
  }
  .app-shell > .k-sidebar .k-nav-icon svg{width:20px;height:20px;}

  /* The tutor's face survives the move to the bar. */
  .app-shell > .k-sidebar .k-nav-icon.has-guide{
    width:24px;
    height:24px;
    margin:0;
  }

  /* The collapsed-rail rules are desktop-only; on a bar they would blank the
     labels and re-center the items as if the rail were still vertical. */
  body.sidebar-collapsed .app-shell > .k-sidebar .k-nav-label{display:block !important;}
  body.sidebar-collapsed .app-shell > .k-sidebar .k-nav a{justify-content:center;}
}

/* ── Mobile nav: 4 primary + More ──────────────────────────────────────────
 *
 * Ten targets across 390px is ~39px each — under the comfortable tap size, with
 * labels truncated to noise ("Tasks & A…"). The bar now carries four, and the
 * rest live in a sheet behind More. tetra-shell-v2.js marks the overflow items
 * and injects the button; these rules are inert without it, so a page that
 * somehow loads the CSS alone still shows a working (if crowded) bar.
 */
@media (max-width:720px){
  .app-shell > .k-sidebar .k-nav a[data-nav-overflow]{display:none;}

  /* The bar stops scrolling horizontally once it holds a fixed five. */
  .app-shell > .k-sidebar .k-nav{
    overflow-x:visible;
    justify-content:space-around;
  }

  .k-nav-more{
    appearance:none;
    flex:0 0 auto;
    display:flex;
    flex-direction:column;
    align-items:center;
    justify-content:center;
    gap:3px;
    min-width:60px;
    padding:6px 4px;
    border:1px solid rgba(77,182,255,.35);
    border-radius:12px;
    background:rgba(77,182,255,.12);
    color:#61c5ff;
    font:inherit;
    font-size:9.5px;
    font-weight:600;
    cursor:pointer;
    order:99;                       /* always the last slot */
  }
  .k-nav-more .k-nav-icon{width:22px;height:22px;}
  .k-nav-more .k-nav-icon svg{width:20px;height:20px;}
  .k-nav-more.is-open{
    border-color:#61c5ff;
    background:rgba(77,182,255,.22);
    color:#dff5ff;
    box-shadow:0 0 0 2px rgba(77,182,255,.12);
  }

  /* The sheet rises from behind the bar. Positioned off the bar's own height so
     the two never overlap on a notched phone. */
  .k-nav-sheet{
    position:fixed;
    left:8px; right:8px;
    bottom:calc(68px + env(safe-area-inset-bottom, 0px));
    z-index:9997;                   /* above the bar (9995) and the FAB (9996) */
    display:grid;
    grid-template-columns:1fr 1fr;
    gap:6px;
    padding:10px;
    border-radius:18px;
    background:#241d4d;
    border:1px solid rgba(255,255,255,.14);
    box-shadow:0 18px 44px rgba(0,0,0,.55);
    max-height:52vh;
    overflow-y:auto;
  }
  .k-nav-sheet[hidden]{display:none;}

  .k-nav-sheet a{
    display:flex;
    align-items:center;
    gap:9px;
    padding:11px 10px;
    border-radius:12px;
    color:rgba(255,255,255,.88);
    text-decoration:none;
    font-size:12.5px;
    font-weight:600;
  }
  .k-nav-sheet a:hover,
  .k-nav-sheet a.active{background:rgba(255,255,255,.10);color:#fff;}
  .k-nav-sheet .k-nav-icon{width:20px;height:20px;flex:0 0 auto;}
  .k-nav-sheet .k-nav-icon svg{width:18px;height:18px;}
  .k-nav-sheet .k-nav-icon.has-guide{width:22px;height:22px;margin:0;}
  .k-nav-sheet .k-nav-label{
    display:block;
    overflow:hidden;
    text-overflow:ellipsis;
    white-space:nowrap;
  }
}

/* The sheet is a mobile affordance only; it must never appear on the rail. */
@media (min-width:721px){
  .k-nav-sheet, .k-nav-more, .k-nav-mobile-flat{display:none !important;}
}

/* ── SHELL.A2 — reclaim the canonical sidebar above the mobile breakpoint ─────
 * Many teacher pages ship a legacy page-local mobile shell (TM.9) that hides
 * `.k-sidebar{display:none !important}` and swaps in their own `.tm-bottom-nav`,
 * gated at ≤900px. The canonical shell now REMOVES those bars (tetra-shell-v2.js
 * strips every `.tm-bottom-nav`) and owns mobile navigation itself: a bottom bar
 * ≤720 and a compact icon rail 721–1280. But because the page-local <style>
 * loads after this file, its `.k-sidebar{display:none}` still fired between
 * 721–900 — and with the page's own bar deleted, that range was left with NO
 * navigation at all (the reported tablet↔laptop dead zone).
 *
 * Force the canonical sidebar visible above the mobile breakpoint. The selector
 * `.app-shell > .k-sidebar` (specificity 0,2,0) beats the page-local `.k-sidebar`
 * (0,1,0) regardless of load order, so no per-page edit is needed. It is
 * deliberately NOT scoped to the JS-added `body.tetra-mobile-nav-canonical`
 * class: that class lands only after tetra-shell-v2.js runs, so scoping to it
 * left the sidebar hidden for the first paint (page rule winning) and then
 * popping in — a flicker on every navigation. A class-free selector applies at
 * first paint. At ≤720 the mobile block above still turns the same element into
 * the bottom bar. Combined with the ≤900 grid fix (the sidebar keeps its rail
 * column down to 721px), the rail renders correctly 721–1280. */
@media (min-width:721px){
  .app-shell > .k-sidebar{ display:flex !important; }
}

/* ── SHELL.A3 — kill the obsolete page-local bottom-bar flash ─────────────────
 * Every course-detail page (and ~37 others) ships a page-local `.tm-bottom-nav`
 * element + a `@media(≤900){.tm-bottom-nav{display:flex}}` rule. The canonical
 * shell REMOVES that element on DOMContentLoaded (tetra-shell-v2.js) and owns
 * mobile navigation itself — but between first paint and that removal the stale
 * bar painted at the bottom, then vanished: a menu-button flicker on every page
 * change at tablet/laptop widths. This head-loaded !important hide beats the
 * page rule at first paint so the bar never shows; the JS still strips the node.
 * The canonical mobile bar is `.k-sidebar` (a different element), so ≤720 is
 * unaffected. */
.tm-bottom-nav{ display:none !important; }
