/* =============================================================
   TONE — REFRESH LAYER (v92.70.57 · 2 Sep 2026)
   -------------------------------------------------------------
   Visual-only pass from the September design review. Loaded LAST
   (after tone-foundation.css) so its rules win; every declaration
   here is presentation — nothing changes what a screen does.

   What it does, in order:
     1. Type scale — Instrument Serif for headings, Inter for body,
        JetBrains Mono kept for labels / codes / chips / buttons.
        Body 15px (16px on phones). No text below 12px anywhere
        (the 9–11px declarations in styles.css / tone-foundation.css
        were raised to 12px in the same release).
     2. Hero headings capped at 44px so the work sits above the fold.
     3. Contrast — the muted caption tint reads at ≥ 4.5:1.
     4. Sidebar / buttons / chips — 44px targets, one label size.
     5. Phone tab bar (rendered by js/shell.js) — an extra way in;
        the drawer and its Menu button are untouched.
     6. Shell hygiene — 100dvh, safe-area padding, focus handling.
   Brand pairings from js/branding.js are injected AFTER this file
   and still win, so a school's own fonts / radius are respected.
   ============================================================= */

/* ---------- 0 · tokens ---------- */
:root {
  --rf-display: 'Instrument Serif', 'Fraunces', 'Times New Roman', serif;
  --rf-body:    'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
  --rf-mono:    'JetBrains Mono', 'IBM Plex Mono', ui-monospace, monospace;

  --rf-label:   12px;
  --rf-body-sz: 15px;
  --rf-h1:      clamp(28px, 3.2vw, 44px);
  --rf-h2:      clamp(22px, 2.4vw, 30px);
  --rf-h3:      clamp(18px, 1.8vw, 22px);

  --rf-target:  44px;
  --rf-tabbar:  56px;

  /* Contrast: the foundation layer's 42%-ink caption tint measured
     2.3:1 on bone. 62% clears 4.5:1 on every Tone surface. */
  --tc-ink-3: rgba(20, 17, 16, 0.62) !important;
  /* Unbranded Tone: --ink-3 (paper-cool-5) measured 3.0:1. Same
     hue, darker. Branded registers derive their own in branding.js. */
  --ink-3: #5F6964 !important;
  --paper-cool-5: #5F6964 !important;
}

/* ---------- 1 · type ---------- */
html, body,
p, li, dd, dt, blockquote, figcaption, td, th,
.body, .body-sm, .body-lg, .body-serif,
.desc-details-content, .field-block, .field label,
.tile, .tile-title, .tile-foot,
.lesson-list, .lesson-title, .lesson-status {
  font-family: var(--rf-body) !important;
}
body {
  font-size: var(--rf-body-sz) !important;
  line-height: 1.55 !important;
  letter-spacing: 0 !important;
}
p, .body, .body-sm, .body-serif { letter-spacing: 0 !important; line-height: 1.6 !important; }
.body-lg { font-size: 17px !important; letter-spacing: 0 !important; }
p { text-wrap: pretty; }

input, textarea, select {
  font-family: var(--rf-body) !important;
  font-size: var(--rf-body-sz) !important;
  letter-spacing: 0 !important;
}
@media (max-width: 760px) {
  body { font-size: 16px !important; }
  input, textarea, select { font-size: 16px !important; } /* iOS: no zoom on focus */
}

/* Headings: serif, regular weight, tight but not crushed. `em`
   inside a heading stays italic — that is the "Finlee." register. */
h1, h2, h3, h4,
.display, .display-xxl, .display-xl, .display-l, .display-m, .tc-head {
  font-family: var(--rf-display) !important;
  font-weight: 400 !important;
  font-style: normal !important;
  letter-spacing: -0.01em !important;
  line-height: 1.08 !important;
  text-wrap: balance;
}
h1 em, h2 em, .display em, .display-xl em, .display-l em, .display.italic, em.display {
  font-style: italic !important;
  font-weight: 400 !important;
  color: inherit;
}
.display-xxl { font-size: clamp(30px, 3.6vw, 48px) !important; }
.display-xl,
.main h1     { font-size: var(--rf-h1) !important; }
.display-l,
.main h2     { font-size: var(--rf-h2) !important; }
.display-m,
.main h3     { font-size: var(--rf-h3) !important; }
h4           { font-size: 17px !important; }
.main h1     { max-width: 40ch; }

/* The shell header: tighter rhythm now that the title is a title
   rather than a poster. (.mb-55 was 55px below the h1.) */
.main > header.mb-55 { margin-bottom: 34px !important; row-gap: 13px; }
.main > header .section-code { margin-bottom: 8px !important; }

/* Labels, codes, chips, buttons stay mono — one size, one tracking. */
.meta, .eyebrow, .code, .caption, .section-code, .section-code > .num,
.btn, .sig-pill, .pill, .tag, .chip, .pulse-chip,
.lesson-type, .tile-type, .cs-line-label, .desc-details > summary,
.side-link, .profile-role, .topbar-menu, .nav-toggle {
  font-family: var(--rf-mono) !important;
  letter-spacing: 0.08em !important;
}
.meta, .eyebrow, .caption, .section-code, .cs-line-label, .profile-role {
  font-size: var(--rf-label) !important;
}
.section-code > .num { letter-spacing: 0.04em !important; }

/* Numbers that sit in columns line up. */
.ov2-stat-val, .ov2-bignum, .stat-val, .tone-stat-num, .roster-stat-num, td {
  font-variant-numeric: tabular-nums;
}
.ov2-stat-val, .stat-val, .tone-stat-num { font-family: var(--rf-display) !important; }

/* ---------- 2 · sidebar ---------- */
.side-link {
  font-size: var(--rf-label) !important;
  min-height: var(--rf-target);
  padding: 12px 13px !important;
  line-height: 1.2;
  border-radius: 4px;
}
.side-nav-group-head { min-height: 40px; font-size: 11px !important; }
.side-nav-group-label { font-size: 11px !important; letter-spacing: 0.1em; }
.profile-chip { min-height: var(--rf-target); }
.profile-name { font-family: var(--rf-body) !important; font-size: 14px !important; }
.sidebar-foot .btn { min-height: var(--rf-target) !important; }
.notif-badge, .side-link .count { font-size: 11px !important; letter-spacing: 0 !important; }

/* ---------- 3 · buttons, chips, inputs ---------- */
.btn {
  min-height: 40px;
  font-size: var(--rf-label) !important;
}
.btn-sm { min-height: 36px; }
.chip, .pill, .sig-pill, .tag, .pulse-chip { font-size: 11px !important; }
input[type="text"], input[type="email"], input[type="password"], input[type="number"],
input[type="url"], input[type="search"], input[type="date"], select {
  min-height: var(--rf-target);
}
@media (pointer: coarse) {
  .btn, .btn-sm, .chip, .pill, .sig-pill, .tag, .pulse-chip,
  .side-link, .ov2-ghostbtn, .ov2-upbadge,
  button:not(.tabbar-link) { min-height: var(--rf-target); }
  .ov2-gicon, .ov2-gicon-adder, .icon-btn, .imp-return { min-width: var(--rf-target); min-height: var(--rf-target); }
}

/* Focus: keep the ring for keyboards, hide it on the programmatic
   heading focus the router performs after each navigation. */
h1[tabindex="-1"]:focus, h1[tabindex="-1"]:focus-visible, .main h1:focus { outline: none !important; box-shadow: none !important; }
:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

/* ---------- 4 · shell hygiene ---------- */
.app-shell { min-height: 100dvh; }

/* ---------- 5 · one navigation, everywhere ---------- */
/* The floating pill IS the navigation at every width: bottom of the
   screen on phones, top of the screen on tablets and laptops. The
   docked sidebar is retired; the full list lives in the drawer that
   "More" (or the brand) opens, on every device. Old strips (topbar,
   hamburger pill) are hidden. The active tab is an ink capsule lit in
   acid — the same ink-on-acid signal the app has always used. */
:root { --rf-tabbar: 66px; }

.nav-toggle { display: none !important; }
/* Phones keep a quiet top strip with just the wordmark — no Menu
   button (More in the bar opens the drawer). Larger screens carry
   the wordmark in the top pill instead, so the strip goes. */
@media (max-width: 767px) {
  .topbar {
    display: flex !important;
    position: fixed !important;        /* a later rule made it static → the gap under it */
    top: 0 !important; left: 0 !important; right: 0 !important;
    z-index: 190 !important;
    align-items: center !important;
    justify-content: flex-start !important;
    height: calc(52px + env(safe-area-inset-top, 0px)) !important;
    padding: env(safe-area-inset-top, 0px) 20px 0 20px !important;
    background: var(--bone) !important;
    border-bottom: 1px solid var(--line-soft) !important;
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
  }
  .topbar-menu { display: none !important; }
  .topbar-brand { font-size: 22px !important; letter-spacing: -0.01em; }
  html.nav-open .topbar { z-index: 190 !important; }
  /* Hero cards no longer need their own notch padding — the strip
     above already clears it (tone-foundation added max(…, safe-area)). */
  .main .tone-hero, .main .hero, .main .hero-strip, .main .dashboard-hero, .main .apprentice-hero,
  .main .card-ink, .main .ov2-hero,
  .main section[style*="background: #141110"], .main section[style*="background:#141110"] {
    padding-top: var(--tsp-hero-y, 24px) !important;
  }
  .main > section[style*="background: var(--ink)"] { padding: 26px 22px !important; }
  /* Tighter page header on phones: hairline, eyebrow, title, hairline. */
  .app-shell .main > header { padding: 14px 0 18px !important; margin-bottom: 20px !important; }
}
@media (min-width: 768px) { .topbar { display: none !important; } }

/* The drawer is an overlay at EVERY width (undoes the ≥1024px docking
   from tone-foundation.css, which carried !important). */
@media (min-width: 1024px) {
  .app-shell > aside.sidebar,
  .app-shell > .sidebar {
    transform: translateX(-100%) !important;
    transition: transform 240ms ease !important;
    box-shadow: 0 0 28px rgba(0,0,0,0.18) !important;
    width: min(82vw, 300px) !important;
    z-index: 220 !important;
  }
  html.nav-open .app-shell > aside.sidebar,
  html.nav-open .app-shell > .sidebar { transform: translateX(0) !important; }
  .app-shell > main.main,
  .app-shell > .main { margin-left: 0 !important; }
  .nav-scrim { display: block !important; }
  html.nav-open .nav-scrim { opacity: 1 !important; pointer-events: auto !important; }
  .sidebar .nav-collapse { display: inline-flex !important; }
}

/* Content clears the bar: below it on phones, under it on larger screens. */
@media (max-width: 767px) {
  .app-shell > .main,
  .app-shell > main.main {
    padding-top: calc(env(safe-area-inset-top, 0px) + 52px + 20px) !important;
    padding-bottom: calc(var(--rf-tabbar) + 44px + env(safe-area-inset-bottom, 0px)) !important;
  }
  .pwa-install { bottom: calc(var(--rf-tabbar) + 28px + env(safe-area-inset-bottom, 0px)); }
}
@media (min-width: 768px) {
  .app-shell > .main,
  .app-shell > main.main {
    padding-top: calc(env(safe-area-inset-top, 0px) + var(--rf-tabbar) + 40px) !important;
  }
  .main > * { max-width: 1280px; margin-left: auto; margin-right: auto; }
}

.tabbar {
  position: fixed;
  z-index: 200;
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 2px;
  padding: 6px;
  border-radius: 24px;
  background: var(--cream);
  border: 1px solid color-mix(in srgb, var(--ink) 10%, transparent);
  box-shadow:
    0 18px 40px -18px rgba(20, 17, 16, 0.40),
    0 1px 0 rgba(255, 255, 255, 0.45) inset;
  -webkit-tap-highlight-color: transparent;
  user-select: none;
  -webkit-user-select: none;
  touch-action: manipulation;
  transform: translateZ(0);          /* own layer: never repaints with the page */
  transition: opacity var(--fast, 180ms) ease, transform var(--fast, 180ms) ease;
}
/* phone: bottom */
@media (max-width: 767px) {
  .tabbar { left: 12px; right: 12px; bottom: calc(10px + env(safe-area-inset-bottom, 0px)); }
  .tabbar-brand { display: none !important; }
}
/* tablet + laptop: top, centred, labels beside icons, brand at the left */
@media (min-width: 768px) {
  .tabbar {
    top: calc(12px + env(safe-area-inset-top, 0px));
    left: 50%; right: auto; bottom: auto;
    transform: translateX(-50%) translateZ(0);
    width: min(860px, calc(100% - 32px));
    grid-template-columns: auto repeat(5, minmax(0, 1fr));
    align-items: center;
  }
  html.nav-open .tabbar { transform: translateX(-50%) translateY(-8px) translateZ(0); }
  .tabbar-link { flex-direction: row; gap: 8px; min-height: 48px; padding: 0 14px; border-radius: 18px; }
  .tabbar-link .tabbar-ico { width: 34px; height: 28px; }
  .tabbar-lbl { font-size: 11px; }
  .tabbar-brand {
    display: inline-flex; align-items: center;
    min-height: 48px; padding: 0 18px 0 16px;
    margin-right: 4px;
    border-right: 1px solid color-mix(in srgb, var(--ink) 10%, transparent);
    font-family: var(--serif) !important;
    font-size: 20px; letter-spacing: -0.01em;
    color: var(--ink); text-decoration: none; white-space: nowrap;
  }
}
.tabbar-link {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 4px;
  min-height: 54px;
  padding: 4px 0;
  border: 0; background: transparent;
  border-radius: 18px;
  font-family: var(--rf-mono) !important;
  font-size: 10px !important;
  letter-spacing: 0.06em !important;
  text-transform: uppercase;
  color: var(--ink-2);
  text-decoration: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: color var(--fast, 180ms) ease;
}
.tabbar-ico {
  display: grid; place-items: center;
  width: 44px; height: 28px;
  border-radius: 14px;
  color: inherit;
  transition: background 200ms ease, color 120ms ease, transform 120ms ease;
}
.tabbar-link svg { width: 22px; height: 22px; stroke: currentColor; fill: none; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }
.tabbar-lbl { line-height: 1; }
.tabbar-link:active .tabbar-ico { transform: scale(0.88); }
.tabbar-link:hover { color: var(--ink); }
.tabbar-link[aria-current="page"] { color: var(--ink); }
.tabbar-link[aria-current="page"] .tabbar-ico { background: var(--ink); color: var(--acid); }
.tabbar-link[aria-current="page"] .tabbar-lbl { font-weight: 600; }
.tabbar-link:focus-visible { outline: 2px solid var(--ink); outline-offset: -2px; }
html.nav-open .tabbar { opacity: 0; pointer-events: none; }
@media (max-width: 767px) { html.nav-open .tabbar { transform: translateY(8px) translateZ(0); } }
@media (prefers-reduced-motion: reduce) {
  .tabbar, .tabbar-ico { transition: none; }
  .tabbar-link:active .tabbar-ico { transform: none; }
}
@media print { .tabbar { display: none !important; } }

/* ---------- 6 · finish: quiet depth, calm surfaces ---------- */
/* Same colours, more restraint. Hairline lines, one soft shadow
   recipe, real hover/press states, thin scrollbars, a brand-coloured
   text selection. Brand CSS (radius, card fills) still lands after
   this file and keeps the last word. */
:root {
  --rf-shadow-1: 0 1px 2px rgba(20, 17, 16, 0.04), 0 10px 30px -20px rgba(20, 17, 16, 0.22);
  --rf-shadow-2: 0 2px 4px rgba(20, 17, 16, 0.05), 0 18px 40px -22px rgba(20, 17, 16, 0.30);
  --rf-ring: 0 0 0 3px color-mix(in srgb, var(--oxblood) 14%, transparent);
}
::selection { background: var(--acid); color: var(--ink); }
* { scrollbar-width: thin; scrollbar-color: var(--line) transparent; }
hr, .divider, .divider-soft { border-color: var(--line-soft); }

/* Cards and tiles: hairline + soft depth; lift only when they are links. */
.card, .card-paper, .tile, .stat, .ov2-card, .ov2-gcard, .tone-card,
.roster-card, .tk-card, .mb-tile {
  box-shadow: var(--rf-shadow-1);
  transition: box-shadow var(--med, 320ms) var(--ease, ease), transform var(--med, 320ms) var(--ease, ease), border-color var(--fast, 180ms);
}
a.card:hover, a.card-paper:hover, a.tile:hover, a.ov2-gcard:hover, a.tone-card:hover, a.mb-tile:hover,
.card[href]:hover, .tile[href]:hover, .card-link:hover {
  box-shadow: var(--rf-shadow-2);
  transform: translateY(-1px);
}

/* Buttons: hairline ghost, honest press. (Primary fill is the brand's call.) */
.btn { transition: background var(--fast, 180ms) ease, color var(--fast, 180ms) ease, border-color var(--fast, 180ms) ease, box-shadow var(--fast, 180ms) ease, transform 80ms ease; }
.btn-ghost { border-color: var(--line); }
.btn-ghost:hover { border-color: var(--ink); background: var(--cream); }
.btn:active { transform: translateY(1px); }
.btn:focus-visible { box-shadow: var(--rf-ring); }

/* Inputs: calm field, clear focus. */
input[type="text"], input[type="email"], input[type="password"], input[type="number"],
input[type="url"], input[type="search"], input[type="date"], textarea, select {
  border-color: var(--line-soft);
  transition: border-color var(--fast, 180ms) ease, box-shadow var(--fast, 180ms) ease;
}
input:focus, textarea:focus, select:focus { border-color: var(--ink) !important; box-shadow: var(--rf-ring); outline: none; }
::placeholder { color: var(--ink-3); opacity: 1; }

/* Lists: rows breathe, and answer the pointer. */
.ov2-row:hover, .tk-row:hover, .roster-row:hover, tbody tr:hover > td { background: var(--cream); }

/* Sidebar: quieter chrome around the acid active state. */
.sidebar { border-right-color: var(--line-soft); }
.side-nav-group-head { color: var(--ink-3); }
.side-link { transition: background var(--fast, 180ms) ease, color var(--fast, 180ms) ease; }
.side-link:not(.active):hover { background: color-mix(in srgb, var(--ink) 5%, transparent); }
.profile-chip { border-radius: 4px; transition: background var(--fast, 180ms) ease; }
.profile-chip:hover { background: var(--cream); }

/* Modals and toasts: one elevation recipe. */
.modal, .modal-card, .toast { box-shadow: var(--rf-shadow-2); }

@media (prefers-reduced-motion: reduce) {
  .card, .card-paper, .tile, .stat, .btn, .side-link, .profile-chip { transition: none !important; }
  a.card:hover, a.card-paper:hover, a.tile:hover, .card[href]:hover, .tile[href]:hover { transform: none; }
}

/* ---------- 7 · instant navigation ---------- */
/* The router paints the destination's chrome plus this skeleton the
   moment a tab is tapped (js/shell.js shellPlaceholder), so nothing
   ever feels stuck. Shorter page fade so the hand-off reads as one
   motion, not two. */
.main.fade-in { animation-duration: 160ms !important; }
.skel-page { display: flex; flex-direction: column; gap: 16px; }
.skel-row  { display: flex; flex-direction: column; gap: 10px; }
.skel-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; }
@media (max-width: 760px) { .skel-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.skel {
  border-radius: 4px;
  background: linear-gradient(90deg,
    color-mix(in srgb, var(--ink) 6%, var(--bone)) 0%,
    color-mix(in srgb, var(--ink) 3%, var(--bone)) 40%,
    color-mix(in srgb, var(--ink) 6%, var(--bone)) 80%);
  background-size: 200% 100%;
  animation: skel-shimmer 1.1s ease-in-out infinite;
}
@keyframes skel-shimmer { from { background-position: 100% 0; } to { background-position: -100% 0; } }
@media (prefers-reduced-motion: reduce) { .skel { animation: none; } }

/* ---------- 8 · speed ---------- */
/* The jank on phones and iPads came from paint cost, not from the
   navigation: a full-screen blur(80px) wash layer (body::before) that
   repaints on every scroll, a fixed-attachment body gradient, and a
   few blur(36–48px) hero pseudo-elements. Those are the decorative
   melt effects from V75; the colours stay, the expensive blur goes. */
body { background-attachment: scroll !important; }
body::before { display: none !important; }
.hero-melt::before, .shell-header::before,
.melt-warm::before, .melt-cool::before, .melt-spectrum::before { filter: none !important; opacity: 0.6; }
.main.fade-in { animation-duration: 140ms !important; }
.skel { animation-duration: 1.4s; }
@media (max-width: 1023px) {
  /* no transition-all storms while a page mounts */
  .side-link, .btn, .card, .card-paper, .tile { transition-duration: 120ms; }
}

/* ---------- 9 · fit and cohesion (Apple-grade layout rules) ---------- */
/* One measure, one rhythm, one header pattern everywhere.
   – Page header is a stack: eyebrow → title → actions (never a title
     squeezed beside seven buttons; never a word broken mid-line).
   – Title size wins over the old poster rules (they carried a
     higher-specificity !important).
   – Content sits on an 8pt rhythm inside a readable measure. */
.app-shell .main > header,
.app-shell .main > header.mb-55 {
  display: flex !important;
  flex-direction: column !important;
  align-items: stretch !important;
  gap: 16px !important;
  padding: 20px 0 24px !important;
  margin-bottom: 32px !important;
}
.app-shell .main > header > div:first-child { width: 100%; min-width: 0; flex: none !important; }
.app-shell .main > header > div:first-child > h1,
.app-shell .main > header > div:first-child > .display-xl,
.app-shell .main > header .display-xl,
.app-shell .main > header h1 {
  font-size: var(--rf-h1) !important;
  line-height: 1.08 !important;
  letter-spacing: -0.01em !important;
  max-width: 28ch;
  word-break: normal !important;
  overflow-wrap: break-word !important;   /* only when a word truly can't fit… */
  -webkit-hyphens: auto !important; hyphens: auto !important;  /* …and then with a hyphen, never "worksho|p" */
  text-wrap: balance;
}
/* Same rule for every display headline (sign-in, marketing, hero panels). */
h1, h2, .display-xxl, .display-xl, .display-l {
  word-break: normal !important;
  overflow-wrap: break-word !important;
  -webkit-hyphens: auto; hyphens: auto;
}
/* actions: left-aligned row that wraps, primary first */
.app-shell .main > header > div:last-child:not(:first-child) {
  display: flex !important; flex-wrap: wrap !important; gap: 8px !important;
  justify-content: flex-start !important; width: 100%;
}
.app-shell .main > header .btn { min-height: 40px; padding-left: 16px; padding-right: 16px; }
@media (max-width: 767px) {
  .app-shell .main > header { padding: 14px 0 18px !important; margin-bottom: 20px !important; gap: 12px !important; }
  .app-shell .main > header .btn { flex: 1 1 calc(50% - 4px); }
}

/* measure + gutters */
@media (min-width: 768px) {
  .app-shell > .main, .app-shell > main.main { padding-left: clamp(24px, 4vw, 56px) !important; padding-right: clamp(24px, 4vw, 56px) !important; }
  .main > * { max-width: 1120px; }
}

/* the top pill's wordmark / logo never dominates the bar */
.tabbar-brand img { height: 24px !important; max-width: 110px !important; width: auto !important; object-fit: contain; display: block; }

/* hero panels: calmer scale, same colours */
.main > section[style*="background: var(--ink)"] h1 { font-size: clamp(28px, 3.4vw, 44px) !important; line-height: 1.08 !important; }
.main > section[style*="background: var(--ink)"] p  { font-size: 17px !important; line-height: 1.5 !important; }
@media (min-width: 768px) { .main > section[style*="background: var(--ink)"] { padding: 36px 40px !important; } }

/* Section eyebrows and numerals share one voice */
.section-code { display: inline-flex; align-items: center; gap: 10px; }
.section-code > .num { padding: 3px 7px; border-radius: 3px; }
