/* ============================================================
   THE ANNOTATED NOTEBOOK — page shell (Phase 2).
   Everything OUTSIDE the components: the paper itself, shared topbar and
   footer placement, the reading container, and the JS-state
   classes the reused legacy scripts toggle. Those class names
   (.cn-children/.collapsed, html.note-focus-mode, .nt-top-progress,
   .sidebar-*) are FROZEN contracts owned by note-reading.js and
   noteviewer-sidebar.js — restyle, never rename.

   Discipline (test-enforced by pages/tests_notebook.py):
   · zero raw colors — every color enters as var(--nb-*)
   · every class is nb-prefixed OR on the documented contract
     allowlist in NotebookCssDisciplineTests
   ============================================================ */

/* ---------- 1 · The paper ----------------------------------------
   Same reset + dotted-grid pattern the approved demo page carries.
   The grid texture lives on --nb-paper ONLY; raised sheets (topbar,
   cards) sit plain on top of the gridded page. */
*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  min-height: 100%;
  background-color: var(--nb-paper); /* overscroll shows paper, not UA white */
  /* Programmatic scrolls (flashcards.js scrollIntoView, question-pager
     centerOnOpen) must clear the responsive shared topbar so the breadcrumb /
     eyebrow / H1 / back-link are never sliced under the bar. */
  scroll-padding-top: calc(var(--nb-chrome-h) + var(--nb-s4));
}

body {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  font-family: var(--nb-sans);
  font-size: var(--nb-text-base);
  line-height: 1.5;
  color: var(--nb-ink);
  background-color: var(--nb-paper);
  background-image: radial-gradient(var(--nb-grid-dot) 1px, transparent 1px);
  background-size: var(--nb-grid-size) var(--nb-grid-size);
}

/* Theme flips are INSTANT (site rule): nb_base's toggle handler adds
   this class for the swap frame only, so colors change all at once
   instead of a staggered per-element sweep. */
html.nb-theme-switching *,
html.nb-theme-switching *::before,
html.nb-theme-switching *::after {
  transition: none !important;
}

/* ---------- 2 · Shared chrome contract ----------------------------
   chrome-navbar.css owns the topbar layout; this shell consumes its height
   token for offsets and fades the shared .topbar during focus mode.
   This theme-independent layer also owns shared chrome typography on the
   isolated notebook base. The legacy-base equivalent lives in the late,
   nb_active-only notebook-typography.css bridge. */
html .topbar {
  font-family: var(--nb-sans);
}
html .topbar > a {
  font: var(--nb-type-title);
  font-weight: 700;
  letter-spacing: -0.02em;
}
html .topbar > nav > a,
html .topbar > div > a,
html #account-btn,
html #mobile-nav-drawer a,
html #mobile-nav-drawer button {
  font: var(--nb-type-control);
}
html .topbar > nav > a[data-ui-current="page"],
html #mobile-nav-drawer a[data-ui-current="page"],
html #mobile-nav-drawer .mobile-nav-row--program.is-active {
  font-weight: 700;
}
/* Programme links step one size above the flanking controls — keep in lockstep
   with the legacy-base bridge (notebook-typography.css). Placed after the
   control-role group so the later equal-specificity declaration wins. */
html .topbar > nav > a {
  font-size: var(--nb-text-md);
}
html #account-popup,
html #auth-modal {
  font-family: var(--nb-sans);
}
html #account-popup [class~="account-popup-heading"] {
  font: var(--nb-type-control);
  letter-spacing: normal;
}
/* The signed-in email and the menu's small print are 13px words: at 400
   the stroke is smoothed into the night paper and reads grey even in full
   ink (owner, 2026-09-26: "are these white or what???"), so they take 500,
   the second weight, in both themes (The One-Ink Rule). */
html #account-popup [class~="account-popup-email"],
html #account-popup [class~="account-popup-support"],
html #account-popup [class~="account-popup-footer"] {
  font-family: var(--nb-sans);
  font-size: var(--nb-text-sm);
  font-weight: 500;
  line-height: 1.4;
}
html #account-popup a,
html #account-popup button {
  font: var(--nb-type-control);
}
html #account-popup [class~="account-popup-plan-badge"],
html #account-popup [class~="account-popup-link"] {
  font: var(--nb-type-label);
}
html #account-popup [class~="account-popup-action"],
html #account-popup [class~="account-popup-nav-link"],
html #account-popup [class~="account-popup-theme"],
html #account-popup [class~="account-popup-signout"] {
  font: var(--nb-type-control);
}
html #auth-modal [class~="auth-modal-title"] {
  font: var(--nb-type-headline);
  letter-spacing: -0.015em;
}
html #auth-modal [class~="auth-field"] label,
html #auth-modal [class~="acct-identity-label"],
html #auth-modal [class~="acct-plan-label"] {
  font: var(--nb-type-label);
}
html #auth-modal [class~="auth-field"] input {
  font: var(--nb-type-ui);
}
html #auth-modal [class~="auth-modal-close"],
html #auth-modal [class~="google-btn"],
html #auth-modal [class~="auth-btn"] {
  font: var(--nb-type-control);
}
html #auth-modal [class~="auth-divider"] span,
html #auth-modal [class~="auth-field-hint"] {
  font: var(--nb-type-label);
}
html #auth-modal [class~="auth-modal-footer"],
html #auth-modal [class~="auth-modal-footer-link"],
html #auth-modal [class~="auth-modal-switch-btn"],
html #auth-modal [class~="auth-modal-notice"] {
  font: var(--nb-type-ui);
}
html #auth-modal [class~="acct-name"] {
  font: var(--nb-type-title);
}
html #auth-modal [class~="acct-email"],
html #auth-modal [class~="acct-plan-premium-sub"],
html #auth-modal [class~="acct-plan-desc"] {
  font-family: var(--nb-sans);
  font-size: var(--nb-text-sm);
  font-weight: 400;
  line-height: 1.5;
}
html #auth-modal [class~="acct-plan-premium-title"],
html #auth-modal [class~="acct-plan-name"] {
  font: var(--nb-type-control);
}
html #auth-modal [class~="acct-upgrade-btn"],
html #auth-modal [class~="acct-nav-link"],
html #auth-modal [class~="acct-logout-btn"] {
  font: var(--nb-type-control);
}
/* ---------- 3 · Reading container --------------------------------- */
.nb-page-main {
  flex: 1 0 auto; /* pins the footer to the page bottom */
  width: 100%;
  max-width: 860px; /* the demo's reading measure */
  margin: 0 auto;
  padding: var(--nb-s7) var(--nb-s5) var(--nb-s10);
}

/* ---------- 4 · Top viewport progress ------------------------------
   note-reading.js writes width:% onto #nt-top-progress-fill. The bar
   rides above the shared topbar; ink is the student's pen. */
.nt-top-progress {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 3px;
  z-index: 1100;
  pointer-events: none;
  background: transparent;
}
.nt-top-progress-fill {
  width: 0;
  height: 100%;
  background: var(--nb-blue);
}

/* ---------- 5 · Focus mode (the calm reading room) -----------------
   note-reading.js toggles html.note-focus-mode. The whole desk clears —
   topbar, rail, footer, breadcrumb, toolbar — and a single reading
   column is set alone on the dotted-grid paper, with a wider vertical
   rhythm and only the thin reading line up top and one
   quiet way back. Section 11 carries the reading-room specifics; this
   block owns the layout collapse. All CSS-only (the JS just flips the
   class). See §11. */
/* The rail sits inside the layout grid, so it must leave the flow entirely —
   the grid folds to a single column below and it would otherwise steal a row. */
html.note-focus-mode .nb-rail {
  display: none;
}
/* The topbar and footer are the chrome the reader watches recede: they FADE
   out rather than snapping away. The animation ends at opacity:0 +
   visibility:hidden (fill-mode forwards) so they stop taking clicks and drop
   from the a11y tree once gone. Duration-only reduced-motion guard zeroes
   --nb-dur-2, making the fade instant with no lingering transform. */
html.note-focus-mode .topbar,
html.note-focus-mode .site-footer {
  animation: nb-chrome-out var(--nb-dur-2) var(--nb-ease) forwards;
}
@keyframes nb-chrome-out {
  from { opacity: 1; }
  to   { opacity: 0; visibility: hidden; }
}
/* The layout grid folds to one column and the page-main sheds its wide
   study measure so the reading column can sit centered on the paper. */
html.note-focus-mode .nb-page-layout {
  grid-template-columns: minmax(0, 1fr);
}
html.note-focus-mode .nb-page-main:has(.nb-page-layout) {
  max-width: none;
  padding-top: var(--nb-s9);
}

/* ---------- 6 · Sidebar JS contract ---------------------------------
   noteviewer-sidebar.js expands/collapses chapters by toggling
   .collapsed on the .cn-children container (sidebar_tree.html). */
.cn-children.collapsed {
  display: none;
}

/* ---------- 7 · Notes page layout (Task 3) --------------------------
   Rail + reading column. The rail is the notebook's edge (290px, the
   component layer's .nb-rail width); the reading column keeps the
   demo's calm measure. Below 861px the rail folds into the drawer —
   861 is noteviewer-sidebar.js's own breakpoint (syncDrawerForViewport
   force-closes the drawer above 860), so CSS and JS agree exactly. */
/* The rail stays pinned at the page's left edge (owner directive 2026-07-13);
   the reading column then centres inside the track to its right, so the notes
   read balanced instead of jammed hard-left with a vast empty right margin on
   wide screens. Focus mode (§5) drops the rail and centres the lone column. */
.nb-page-main:has(.nb-page-layout) {
  max-width: none;
  margin: 0;
  padding-inline: clamp(20px, 2.5vw, 48px);
}
.nb-page-layout {
  display: grid;
  grid-template-columns: 290px minmax(0, 1fr);
  gap: var(--nb-s9);
  align-items: start;
}
/* A page with no chapter rail is one column (the tutor's quiz, owner
   2026-10-05: "the mcqs are not centered"): its reading column centres in the
   page instead of sitting in the rail's 290px track. */
.nb-page-layout:has(> .nb-notes-column:first-child) {
  grid-template-columns: minmax(0, 1fr);
}
/* The reading column keeps a comfortable ~800px measure and centres inside its
   track (auto margins), so with the desk block centred the notes sit balanced
   rather than tethered hard to the rail. */
/* ⚑ width: 100%, or the auto margins make this grid item fit-content: a 5
   or 6 column table's min-content (about 730px) then beat the minmax(0, 1fr)
   track, and from 861 to 1080 (the rail band, iPad landscape) and with the
   tutor docked at 1081 to 1280 the right side of the note was clipped or ran
   under the sheet (mobile audit 2026-09-25). Text-only notes already filled
   the track, so they are unchanged. A FULLY paywalled chapter (its body is
   only the paywall card) keeps its fit-content column, as before. */
.nb-notes-column {
  min-width: 0;
  width: 100%;
  max-width: 800px;
  margin-inline: auto;
}
.nb-notes-column:has(> .nb-notes > .nb-paywall-wrap:first-child) { width: auto; }
@media (max-width: 1100px) {
  .nb-page-layout {
    gap: var(--nb-s6);
  }
}
@media (max-width: 860px) {
  .nb-page-layout {
    grid-template-columns: minmax(0, 1fr);
  }
  .nb-notes-column {
    width: 100%;
    max-width: 100%;
    margin-inline: 0;
  }
  .nb-rail {
    display: none;
  }
  .nb-page-main {
    padding: var(--nb-s6) var(--nb-s4) var(--nb-s9);
  }
}

/* ---------- 8 · Chapter rail restyle ---------------------------------
   The demo's section 15 grammar drawn over the FROZEN sidebar contract:
   sidebar_tree.html markup (.sidebar-toggle/.sidebar-link/.cn-*) is
   included unchanged and restyled here — never renamed. Chapters are
   vertical index tabs fused to the page spine; lessons hang off a
   hairline thread; the active lesson fills with the student's pen.
   No mastery ink-lines in Phase 2 — no per-chapter mastery data exists,
   and the notebook never fakes what it cannot measure. */
.nb-rail {
  position: sticky;
  top: calc(var(--nb-chrome-h) + var(--nb-s6));
  max-height: calc(100vh - var(--nb-chrome-h) - var(--nb-s7));
  overflow-y: auto;
  padding-bottom: var(--nb-s6);
}

/* Custom scrollbar for the two chapter scroll containers — the sticky rail
   (desktop) and the drawer body (mobile). Owner pick 2026-07-03 (demo 15b,
   treatment B "student's margin"): HIDDEN AT REST — the rail reads as clean
   paper — and a slim blue thumb appears only while the pointer (or focus) is
   over the rail. Firefox uses the two-value scrollbar-color (thumb track);
   WebKit/Chromium uses the pseudo-elements below. Tokens only. */
.nb-rail,
.nb-rail-drawer-scroll {
  scrollbar-width: thin;
  scrollbar-color: transparent transparent;
  /* scrolling the chapters never scrolls the note behind them, at their ends
     included (owner 2026-09-30, some devices; smooth-scroll.js leaves a wheel
     inside them to the browser) */
  overscroll-behavior: contain;
}
.nb-rail:hover,
.nb-rail:focus-within,
.nb-rail-drawer-scroll:hover,
.nb-rail-drawer-scroll:focus-within {
  scrollbar-color: var(--nb-blue) transparent;
}
.nb-rail::-webkit-scrollbar,
.nb-rail-drawer-scroll::-webkit-scrollbar {
  width: 5px;
}
.nb-rail::-webkit-scrollbar-track,
.nb-rail-drawer-scroll::-webkit-scrollbar-track {
  background: transparent;
}
.nb-rail::-webkit-scrollbar-thumb,
.nb-rail-drawer-scroll::-webkit-scrollbar-thumb {
  background: transparent;
  border-radius: var(--nb-r-pill);
}
.nb-rail:hover::-webkit-scrollbar-thumb,
.nb-rail:focus-within::-webkit-scrollbar-thumb,
.nb-rail-drawer-scroll:hover::-webkit-scrollbar-thumb,
.nb-rail-drawer-scroll:focus-within::-webkit-scrollbar-thumb {
  background: var(--nb-blue);
}
.nb-rail::-webkit-scrollbar-thumb:hover,
.nb-rail-drawer-scroll::-webkit-scrollbar-thumb:hover {
  background: var(--nb-blue-strong);
}
/* ⚑ A TOUCH RAIL SAYS WHEN THERE IS MORE BELOW (audit N-030, 2026-09-25). The
   thumb above appears on hover or focus, which a finger never gives, and iOS
   draws no custom scrollbar at all: on an iPad in landscape "Study this topic"
   sat at the rail's foot with its links and the Unlock card below the fold,
   a heading with nothing under it. On a touch screen that shows the rail
   (861px and up, no hover) the thumb rests in blue, and a soft ink shade lies
   along the rail's foot while more of the rail is below it. The shade is the
   scroll layer; a strip of paper the same height rides at the end of the
   content (the local layer) and slides over it as the end arrives, so the
   shade is gone at the end, and never drawn on a rail with nothing to scroll.
   The strip lies in the rail's 24px foot padding. A desk with a mouse keeps
   the owner's hidden-at-rest rail. */
@media (hover: none) and (min-width: 861px) {
  /* The shade is the page's own dot ink (--nb-grid-dot), already tuned per
     theme: a soft navy by day, a faint haze by night, never a glow. */
  .nb-rail {
    scrollbar-color: var(--nb-blue) transparent;
    background:
      linear-gradient(var(--nb-paper), var(--nb-paper)) bottom / 100% var(--nb-s5) no-repeat local,
      linear-gradient(to top, color-mix(in srgb, var(--nb-grid-dot) 70%, transparent), transparent) bottom / 100% var(--nb-s5) no-repeat scroll;
  }
  .nb-rail::-webkit-scrollbar-thumb {
    background: var(--nb-blue);
  }
  /* Folded to the ribbon (8b), the rail hides its chapters and scrolls no
     more, so it has nothing to point at. */
  html.nb-tutor-open .nb-page-layout:has(.nb-tutor-margin) > .nb-rail {
    background: none;
  }
}

.nb-rail-label {
  margin: 0 0 var(--nb-s3);
  font: var(--nb-type-label);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--nb-ink);
}
/* The chapters belong to the subject above them, so the label sits close
   under the header. "Study this topic" is a separate group and gets its own
   air (§ .nb-rail-siblings below). */
.nb-rail-siblings {
  margin-top: var(--nb-s7);
}

/* The chapters column carries the page spine on its right edge. */
.nb-rail-chapters {
  border-right: 1px solid var(--nb-border);
  padding: var(--nb-s2) 0;
}
.nb-rail-chapters .sidebar-tree {
  display: flex;
  flex-direction: column;
  gap: var(--nb-s2);
}

/* Chapter head = one vertical index tab: rounded left, flat right,
   fused to the spine; eases OUT of the edge on hover (the vertical
   twin of the horizontal tab's -1px lift). */
.nb-rail-chapters .sidebar-toggle {
  display: flex;
  align-items: center;
  gap: var(--nb-s2);
  width: 100%;
  text-align: left;
  font-family: var(--nb-sans);
  cursor: pointer;
}
.nb-rail-chapters .cn-chapter-head {
  padding: var(--nb-s3) var(--nb-s3) var(--nb-s3) var(--nb-s4);
  background: var(--nb-paper-sunken);
  border: 1px solid var(--nb-border);
  border-right: none; /* flat edge fused to the spine */
  border-radius: var(--nb-r-md) 0 0 var(--nb-r-md);
  transition:
    background-color var(--nb-dur-1) var(--nb-ease),
    transform var(--nb-dur-1) var(--nb-ease);
}
.nb-rail-chapters .cn-chapter-head:hover {
  transform: translateX(-1px);
}
.nb-rail-chapters .cn-chapter-head:hover .cn-chapter-title {
  color: var(--nb-ink);
}
.nb-rail-chapters .cn-chapter-head.open {
  background: var(--nb-paper-raised);
}
.nb-rail-chapters .cn-chapter-head.open .cn-chapter-title {
  color: var(--nb-ink);
}
/* The chapter holding the page you are on writes its number in pen. */
.nb-rail-chapters .cn-chapter:has(.sidebar-link.is-active) > .cn-chapter-head .cn-chip--num,
.nb-rail-chapters .cn-chapter:has(.sidebar-link.is-active) > .cn-chapter-head .cn-chapter-num {
  color: var(--nb-blue);
}

/* Chapter numbers: quiet tabular ink. The icon-chip variant is retired
   notebook-wide (no candy icons) — hide it; the number variant stays. */
.nb-rail-chapters .cn-chip {
  display: none;
}
.nb-rail-chapters .cn-chip--num {
  display: inline-block;
  min-width: 1.5em; /* aligns single- and double-digit chapter numbers */
  background: none;
  border: none;
  padding: 0;
  text-align: right;
  font: var(--nb-type-label);
  font-variant-numeric: tabular-nums;
  color: var(--nb-ink-2); /* small text stays on the 4.5:1 ink tier */
}
.nb-rail-chapters .cn-chapter-num {
  min-width: 1.5em;
  text-align: right;
  font: var(--nb-type-label);
  font-variant-numeric: tabular-nums;
  color: var(--nb-ink-2);
}
.nb-rail-chapters .cn-chapter-title {
  flex: 1 1 auto;
  font: var(--nb-type-control);
  color: var(--nb-ink);
  transition: color var(--nb-dur-1) var(--nb-ease);
}

/* Chevron: drawn, quiet, turns when the chapter opens. */
.nb-rail-chapters .cn-chevron {
  display: inline-flex;
  flex-shrink: 0;
  color: var(--nb-ink-3);
  transition: transform var(--nb-dur-1) var(--nb-ease);
}
.nb-rail-chapters .cn-chevron svg {
  width: 14px;
  height: 14px;
}
.nb-rail-chapters .sidebar-toggle.open .cn-chevron {
  transform: rotate(90deg);
}

/* Locked chapter: a bare, quiet padlock (owner pick 2026-07-03, demo 15b mix
   — the gold "Premium" pill read cheap). The markup's stroke padlock SVG
   (.cn-lock) is un-retired as the single per-row marker, in quiet ink; the
   word "Premium" lives once in the free/locked divider below. The gold
   .cn-badge pill is retired on chapter heads. */
.nb-rail-chapters .cn-chapter-head .cn-lock {
  display: inline-block;
  width: 14px;
  height: 14px;
  margin-left: auto;            /* trail to the row's edge, before the chevron */
  flex-shrink: 0;
  color: var(--nb-ink-3);
}
.nb-rail-chapters .cn-chapter-head .cn-badge {
  display: none;
}
/* A sub-group never carries its own lock: is_paid is set on top-level chapter
   nodes only (content_tree.chapter_is_paid), and the section rows the rail now
   builds are display-only, so .cn-subgroup-head .cn-badge can never render. The
   CSS-drawn padlock that used to live here was deleted 2026-08-18 — the chapter
   head owns the lock. */
/* The crown SVG and the legacy timeline dot stay retired. */
.nb-rail-chapters .cn-badge-icon,
.nb-rail-chapters .cn-node {
  display: none;
}
/* ONE quiet boundary where the free chapters end (owner pick: demo B) — a
   centered small-caps PREMIUM rule on the first locked chapter that follows
   an unlocked one. Per-row pills are retired; rows below stay clean. */
.nb-rail-chapters .cn-chapter:not(.cn-chapter--locked) + .cn-chapter--locked::before {
  content: "Premium";
  display: block;
  margin: var(--nb-s3) var(--nb-s2) var(--nb-s2);
  text-align: center;
  font: var(--nb-type-label);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--nb-ink-2);
  background:
    linear-gradient(var(--nb-border-strong), var(--nb-border-strong)) no-repeat left center / calc(50% - 46px) 1px,
    linear-gradient(var(--nb-border-strong), var(--nb-border-strong)) no-repeat right center / calc(50% - 46px) 1px;
}
.nb-rail-chapters .cn-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Lessons hang off a hairline thread inside the open chapter. */
.nb-rail-chapters .cn-timeline {
  display: flex;
  flex-direction: column;
  gap: var(--nb-s1);
  margin: var(--nb-s2) var(--nb-s2) var(--nb-s3) var(--nb-s4);
  padding-left: var(--nb-s3);
  border-left: 1px solid var(--nb-border); /* structural hairline, not an accent */
}
/* Topics hang further off their section than a bare topic hangs off the
   chapter, so the parent-child step is unmistakable at a glance. */
.nb-rail-chapters .cn-timeline--nested {
  margin: var(--nb-s1) 0 var(--nb-s2) var(--nb-s3);
}

/* 3-level nesting: the section row between the chapter tab and the lesson
   rows. It was set in --nb-type-control, which is byte-identical to the lesson
   title beside it (both 15px/600), so a section read as a peer of its own
   topics and as a twin of a bare topic like "1.2 Motion" that is a LINK, not a
   group. It now takes the label voice instead: a step down in size, tracked,
   and quiet — the same "this names things, it is not one of them" treatment
   the CHAPTERS eyebrow uses. Sentence case, not uppercase: the authored names
   run to "Formulae, Equations and Amount of Substance" and shouting those in a
   290px rail costs a third line for no gain. */
.nb-rail-chapters .cn-subgroup-head {
  padding: var(--nb-s2) var(--nb-s3);
  margin: var(--nb-s3) 0 var(--nb-s2);   /* air above brackets each group */
  /* A filled band, not a bordered tab: the chapter head above already owns
     sunken paper plus a border plus the spine-fused radius, so a section must
     differ in KIND or the two read as the same rung. A neutral ink tint sits
     between them — heavier than a plain row, lighter than a chapter card —
     and resolves in both themes without a new token. */
  background: color-mix(in srgb, var(--nb-ink) 7%, transparent);
  border: none;
  border-radius: var(--nb-r-sm);
  transition: background-color var(--nb-dur-1) var(--nb-ease);
}
.nb-rail-chapters .cn-subgroup-title {
  flex: 1 1 auto;
  /* Same size as the chapter and the topics, but the only 700 in the rail, so
     it outweighs the topics under it without outranking the chapter above. */
  font: var(--nb-type-control);
  font-weight: 700;
  color: var(--nb-ink);
}
.nb-rail-chapters .cn-subgroup-head:hover {
  background: color-mix(in srgb, var(--nb-ink) 12%, transparent);
}

/* Lesson rows: quiet ink at rest; hover answers in the pen's wash;
   the ACTIVE lesson fills with the student's pen (contract class). */
.nb-rail-chapters .sidebar-link {
  display: flex;
  align-items: baseline;
  gap: var(--nb-s2);
  padding: var(--nb-s2) var(--nb-s3);
  border-radius: var(--nb-r-sm);
  font: var(--nb-type-control);
  color: var(--nb-ink);
  text-decoration: none;
  transition:
    background-color var(--nb-dur-1) var(--nb-ease),
    color var(--nb-dur-1) var(--nb-ease);
}
.nb-rail-chapters .sidebar-link:hover {
  background: var(--nb-blue-wash);
  color: var(--nb-ink);
}
.nb-rail-chapters .cn-lesson-num {
  font: var(--nb-type-label);
  font-variant-numeric: tabular-nums;
  color: var(--nb-ink-2);
}
.nb-rail-chapters .cn-lesson-title {
  flex: 1 1 auto;
}
.nb-rail-chapters .sidebar-link.is-active {
  background: var(--nb-selection-fill);
  color: var(--nb-selection-ink);
  font-weight: 600;
  box-shadow:
    inset 3px 0 0 var(--nb-selection-marker),
    inset 0 0 0 1px var(--nb-selection-border);
}
.nb-rail-chapters .sidebar-link.is-active .cn-lesson-num {
  color: var(--nb-selection-ink);
}
/* "Practice whole chapter" is the rail's one action, so it reads in the
   student's pen, the colour of every action on the site, words and bolt alike
   (owner 2026-10-04: "make this stand out"). AA in both themes: 7.3:1 on the
   night desk, 5.1:1 by day; at rest and on hover; the selected row keeps its
   fill. The phone drawer's row reset (notebook-thumbbar.css, ID selectors)
   is matched by the second selector. */
.nb-rail-chapters .sidebar-link.cn-practice-all:not(.is-active),
html:has(> body > #nb-tbar) #nv-rail-drawer .nb-rail-chapters .sidebar-link.cn-practice-all:not(.is-active) {
  color: var(--nb-blue);
}
/* Premium lesson: the same bare padlock as chapters (owner pick 2026-07-03),
   sized for the dense list — the markup's own stroke SVG, quiet ink, trailing
   the row. The gold "Premium" chip is retired. */
.nb-rail-chapters .sidebar-link.is-paid .cn-lock {
  display: inline-block;
  width: 12px;
  height: 12px;
  margin-left: auto;
  flex-shrink: 0;
  align-self: center; /* the row aligns to baseline; the glyph centers */
  color: var(--nb-ink-3);
}

/* Free-user conversion card at the rail foot (owner-approved, demo 15b B).
   Rendered by nb_rail_sidebar.html only when the viewer has no subscription;
   the primary button is the one blue CTA in the rail. */
.nb-rail-cta {
  margin-top: var(--nb-s6);
  padding: var(--nb-s4);
  background: var(--nb-paper-raised);
  border: 1px solid var(--nb-border);
  border-radius: var(--nb-r-md);
}
.nb-rail-cta-title {
  margin: 0 0 var(--nb-s1);
  font: var(--nb-type-label);
  color: var(--nb-ink);
}
.nb-rail-cta-sub {
  margin: 0 0 var(--nb-s3);
  font: var(--nb-type-ui);
  color: var(--nb-ink);
}
.nb-rail-cta .nb-btn {
  width: 100%;
  box-sizing: border-box;
  justify-content: center;
}

/* Focus ring for every interactive piece the rail restyles. */
.nb-rail-chapters .sidebar-toggle:focus-visible,
.nb-rail-chapters .sidebar-link:focus-visible,
.nb-rail-sibling:focus-visible,
.nb-rail-trigger:focus-visible,
.nb-rail-drawer-close:focus-visible,
.nb-focus-exit:focus-visible {
  outline: 2px solid var(--nb-blue);
  outline-offset: 2px;
}

/* Study this topic — links to the OTHER core resources; every entry is
   pre-filtered server-side, but if all three fall away (fuzzy siblings)
   the label would float alone, so hide the group when no link is left.
   Keyed on the links, not on :empty: the template loop leaves whitespace
   text inside the ul even with every li filtered out, and :empty is false
   for whitespace, so the old .nb-rail-sibling-list:empty guard never fired. */
.nb-rail-siblings:not(:has(.nb-rail-sibling)) {
  display: none;
}
.nb-rail-sibling-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--nb-s1);
}
.nb-rail-sibling {
  display: block;
  padding: var(--nb-s1) var(--nb-s3);
  border-radius: var(--nb-r-sm);
  font: var(--nb-type-control);
  color: var(--nb-ink);
  text-decoration: none;
  transition:
    background-color var(--nb-dur-1) var(--nb-ease),
    color var(--nb-dur-1) var(--nb-ease);
}
.nb-rail-sibling:hover {
  color: var(--nb-ink);
  background: var(--nb-blue-wash);
}

/* ---------- 9 · Mobile drawer + trigger ------------------------------
   noteviewer-sidebar.js owns the behavior (.is-open, aria, body lock);
   this is only the paper. The scrim is a sheet of tracing paper — the
   page dims toward --nb-paper, never a black glass wash. */
.nb-rail-trigger {
  display: none;
  position: fixed;
  left: var(--nb-s5);
  bottom: var(--nb-s5);
  z-index: 120;
  align-items: center;
  gap: var(--nb-s2);
  padding: 10px var(--nb-s4); /* the documented button padding */
  background: var(--nb-paper-raised);
  border: 1px solid var(--nb-border);
  border-radius: var(--nb-r-pill);
  box-shadow: var(--nb-shadow-2); /* floating chrome rides above the page */
  color: var(--nb-blue);
  font: var(--nb-type-control);
  cursor: pointer;
  transition: opacity var(--nb-dur-2) var(--nb-ease),
              transform var(--nb-dur-2) var(--nb-ease);
}
/* ⚑ PINNED UNDER THE NAVBAR, NOT IN THE FLOW (audit S-014a, 2026-09-25).
   In the flow it existed only at the top of the column: Topic Questions opens
   already panned to the first question (the button 300px above the screen),
   flashcards opens with it under the navbar, and after any scroll the only
   way to the chapter drawer was back up to the top. It sticks 8px under the
   navbar instead (the owner-approved 2a3e8ef8 of 2026-07-18, which never
   reached this branch), stays a grid item, so it leaves with the layout
   before the footer, and align-self keeps it its own height. z-index 800:
   above the column, under the navbar (1000) and under the phone menu
   (.mobile-nav-drawer, 900, a sibling of the navbar), which 2a3e8ef8's 1001
   would have painted over. A note keeps its own floating button (below),
   which resets top. .nb-rail-trigger--away (after the footer rule) hides it
   while the student reads on down. */
@media (max-width: 860px) {
  .nb-rail-trigger {
    display: inline-flex;
    position: sticky;
    top: calc(var(--nb-chrome-h, 64px) + var(--nb-s2));
    z-index: 800;
    align-self: start;
    justify-self: start;
    min-block-size: 44px; /* touch target */
    /* In the page flow it is a resting control, not floating chrome: the
       flat step at rest, the lift on hover (DESIGN.md, Lift Is Feedback;
       audit N-028). The floating trigger on a note keeps --nb-shadow-2. */
    box-shadow: var(--nb-shadow-1);
  }
}
@media (max-width: 860px) and (hover: hover) {
  .nb-rail-trigger:hover {
    box-shadow: var(--nb-shadow-2);
  }
}
/* The historical footer tuck of the fixed trigger. Nothing adds the class
   since audit N-005b (2026-09-25): the only floating trigger left, the one
   on a note, rests above Previous / Next instead and can never reach the
   footer (below). The rules stay, inert, for the source guards. */
.nb-rail-trigger--tucked {
  opacity: 0;
  transform: translateY(140%);
  pointer-events: none;
}
@media (max-width: 860px) {
  /* The compact trigger lives in flow (or rests above the pager on a
     note), so a tucked state must be inert here. */
  .nb-rail-trigger--tucked {
    opacity: 1;
    transform: none;
    pointer-events: auto;
  }
}
/* Out of the way while the student scrolls on down, back on the first scroll
   up (the class is the page script's, audit S-014b): pinned for good it sat
   over the text being read, the Topic Questions answer box among it. It
   slides up under the navbar as it fades, and leaves the Tab order once
   gone; it returns visible at once. Not on a note, whose floating button
   is always there (below). Reduced motion zeroes the durations. */
@media (max-width: 860px) {
  .nb-page-layout:not(:has(> .nb-notes-column > .nb-notes)) > .nb-rail-trigger--away {
    opacity: 0;
    transform: translateY(calc(-100% - var(--nb-s2)));
    visibility: hidden;
    pointer-events: none;
    transition: opacity var(--nb-dur-2) var(--nb-ease),
                transform var(--nb-dur-2) var(--nb-ease),
                visibility 0s linear var(--nb-dur-2);
  }
}
/* ⚑ ON A NOTE THE TRIGGER FLOATS AGAIN (audit N-005a, 2026-09-25). In flow
   it existed only at the top of the page: 4,000px into a note the only ways
   to another topic were scrolling back up or Previous / Next at the foot,
   while the desk's rail stays in view the whole way down. It left the flow
   because the floating labelled pill met the tutor pill at the foot's
   centre; this one is a 48px round button in the bottom-left corner, on the
   tutor pill's baseline, and clears the pill by 8px at 320 (the pill starts
   at x 72) and 43px at 390. Icon only on a phone: "Chapters" stays in the
   markup for a screen reader (and the button's aria-label names it), and
   shows again from 560px, where there is room (below). Under an open tutor
   sheet it is hidden (notebook-tutor.css), and focus mode hides it with the
   rest of the rail (section 11).
   Notes only (the leaf whose column holds the note, .nb-notes): flashcards, MCQ,
   questions and video keep the in-flow trigger above. Judgement call: a
   chapters control that is always reachable beats a labelled one that
   exists only at the top.
   ⚑ IT RESTS ABOVE PREVIOUS / NEXT (audit N-005b, 2026-09-25). Fixed to the
   screen it covered "<- Previous" at the foot, and the footer tuck that
   hid it left a short note (a sealed chapter on a portrait tablet, whose
   footer shows from the first paint) with no way to the chapters at all.
   So it is sticky, not fixed. It shares the note column's grid cell and
   sits at the cell's foot, and its bottom margin (the pager's share of the
   cell, --nb-rail-clear from the script in nb_base.html, plus 8px) parks it
   8px above the pager, in a bay of its own (below). Mid-note it sticks to
   the foot of the screen where the fixed button was; at the end it stops
   above Previous / Next and leaves with them, so it never covers them and
   never reaches the footer, and on a short note it simply rests there. The
   browser moves it, so it keeps up with a fling. The -4px keeps the fixed
   button's 16px inset (the column starts at 20px). */
@media (max-width: 860px) {
  .nb-page-layout:has(> .nb-notes-column > .nb-notes) > .nb-rail-trigger {
    position: sticky;
    box-shadow: var(--nb-shadow-2); /* floating chrome rides above the page */
    top: auto; /* the pinned trigger's top (above) would win over bottom */
    left: auto; /* sticky: the base 20px left would hold it at x 20 */
    bottom: calc(var(--nb-s4) + env(safe-area-inset-bottom, 0px));
    grid-row: 1;
    grid-column: 1;
    align-self: end;
    margin-inline-start: calc(var(--nb-s4) - var(--nb-s5));
    margin-block-end: calc(var(--nb-rail-clear, 184px) + var(--nb-s2));
    /* above the tutor pill (790): with the text enlarged (150% and up at
       320px) the pill grows into this corner, and then this button covers
       the pill's left cap rather than the pill hiding the chapters */
    z-index: 795;
    inline-size: 48px;
    block-size: 48px;
    padding: 0;
    justify-content: center;
  }
  /* The column keeps the cell it now shares: placed by hand, the button
     would otherwise push it down to a second row. */
  .nb-page-layout:has(> .nb-notes-column > .nb-notes) > .nb-notes-column {
    grid-row: 1;
    grid-column: 1;
  }
  /* Its parking bay. Parked in the pager's 32px top margin, the 48px button
     took the bottom of "Practice this topic" (the Flashcards button) or the
     note's last line for good. The margin opens to 64px here, so it rests
     over nothing, 8px from the block above and 8px above the hairline.
     Focus mode draws no button, so it keeps the 32px. */
  html:not(.note-focus-mode) .nb-page-layout:has(> .nb-notes-column > .nb-notes) > .nb-notes-column > .nb-notes > .nb-notes-pagination {
    margin-top: calc(var(--nb-s9) + var(--nb-s4));
  }
  .nb-page-layout:has(> .nb-notes-column > .nb-notes) > .nb-rail-trigger .nb-rail-trigger-lbl {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}
/* ⚑ ITS LEFT EDGE WAS CUT OFF WHEREVER THE TUTOR SHEET EXISTS (found while
   fixing audit N-R1-1, 2026-09-26). notebook-tutor.css clips the layout's x
   axis for the folded sheet's slide on the desk, and the layout starts at the
   page gutter, 20px in. The -4px margin above put the button's left 4px and
   the left of its shadow past that edge, so on every note and summary, in
   both engines, the round button (and the tablet's pill) read flat on the
   left, its shadow ended in a hard line, and a tap on that sliver fell
   through to the page. Here the layout reaches the screen's edges and takes
   the gutter back as padding: the clip edge is the screen's, and no column,
   heading or pager moves. The clamp is .nb-page-main's own gutter (section
   7); a page without the sheet has no clip and is left as it is. */
@media (max-width: 860px) {
  .nb-page-layout:has(.nb-tutor-margin) {
    margin-inline: calc(-1 * clamp(20px, 2.5vw, 48px));
    padding-inline: clamp(20px, 2.5vw, 48px);
  }
}
/* Where the foot has room beside the tutor pill (560px and up: the portrait
   tablets), the button keeps its word: a "Chapters" pill of the same height,
   still clear of the tutor pill by 50px or more. */
@media (min-width: 560px) and (max-width: 860px) {
  .nb-page-layout:has(> .nb-notes-column > .nb-notes) > .nb-rail-trigger {
    inline-size: auto;
    padding: 0 var(--nb-s4);
  }
  .nb-page-layout:has(> .nb-notes-column > .nb-notes) > .nb-rail-trigger .nb-rail-trigger-lbl {
    position: static;
    width: auto;
    height: auto;
    overflow: visible;
    clip-path: none;
  }
}
/* A short screen (a landscape phone): the tutor pill steps down to the
   44px touch floor, 8px off the foot (notebook-tutor.css rule 22, audit
   N-031b), and this button steps with it, so the two stay on one baseline
   and the band they keep over the note is 52px, not 64px. A round button
   stays round.
   ⚑ ROUND ON A SHORT SCREEN UNDER 700PX TOO (audit N-R1-1, 2026-09-26). On
   a phone turned on its side (568 x 320, 667 x 375) the labelled pill ran to
   x 137 and, while a sealed chapter's card passed the foot of the screen,
   lay over the left of "Unlock Premium" (50px of it at 568, so the button
   read "ck Premium"). The round 44px button ends at x 60, short of the
   card's buttons (x 87 and x 137), and "Chapters" stays for a screen reader
   as it does on a portrait phone. 740 x 360 and 844 x 390 keep their word:
   the card is wide enough there that the pill clears it. */
@media (max-width: 860px) and (max-height: 500px) {
  .nb-page-layout:has(> .nb-notes-column > .nb-notes) > .nb-rail-trigger {
    block-size: 44px;
    bottom: calc(var(--nb-s2) + env(safe-area-inset-bottom, 0px));
  }
}
@media (max-width: 699px) and (max-height: 500px) {
  .nb-page-layout:has(> .nb-notes-column > .nb-notes) > .nb-rail-trigger {
    inline-size: 44px;
    padding: 0;
  }
  .nb-page-layout:has(> .nb-notes-column > .nb-notes) > .nb-rail-trigger .nb-rail-trigger-lbl {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

.nb-rail-backdrop {
  position: fixed;
  inset: 0;
  z-index: 1200;
  background: color-mix(in srgb, var(--nb-paper) 65%, transparent);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--nb-dur-2) var(--nb-ease);
}
.nb-rail-backdrop.is-open {
  opacity: 1;
  pointer-events: auto;
}

.nb-rail-drawer {
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  z-index: 1210;
  width: min(330px, 88vw);
  display: flex;
  flex-direction: column;
  background: var(--nb-paper-raised);
  border-right: 1px solid var(--nb-border);
  box-shadow: var(--nb-shadow-3); /* the one lifted sheet while open */
  transform: translateX(-102%);
  transition: transform var(--nb-dur-2) var(--nb-ease);
}
.nb-rail-drawer.is-open {
  transform: translateX(0);
  visibility: visible;
  transition: transform var(--nb-dur-2) var(--nb-ease), visibility 0s;
}
/* ⚑ PARKED, IT IS NOT DRAWN (audit N-009, 2026-09-25). Closed, the drawer
   is only translated off the left edge, and its --nb-shadow-3 still painted
   a grey band about 20px wide down the left of every note at 860 and below.
   It hides once its slide out has finished (the shadow stays for the slide),
   and shows at once when it opens. It is already inert and aria-hidden while
   closed, so nothing a keyboard could reach is lost. */
.nb-rail-drawer:not(.is-open) {
  visibility: hidden;
  transition: transform var(--nb-dur-2) var(--nb-ease), visibility 0s linear var(--nb-dur-2);
}
/* Above 860px the drawer can never open: its trigger is hidden and
   noteviewer-sidebar.js force-closes it there. Parked at translateX(-102%)
   it still painted, and its --nb-shadow-3 bled 26px (day) to 41px (night)
   into the screen's left edge, shading the chapters ribbon (8c). So above
   860px it is not drawn at all. */
@media (min-width: 861px) {
  .nb-rail-drawer { display: none; }
}
.nb-rail-drawer-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--nb-s3);
  padding: var(--nb-s5) var(--nb-s5) var(--nb-s4);
  border-bottom: 1px solid var(--nb-border);
}
.nb-rail-drawer .nb-rail-head {
  padding: 0;
}
.nb-rail-drawer-close {
  display: inline-flex; /* flex centering — grid does not center a <button> */
  align-items: center;
  justify-content: center;
  width: var(--nb-s8);
  height: var(--nb-s8);
  flex-shrink: 0;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--nb-r-sm);
  color: var(--nb-ink-2);
  cursor: pointer;
  transition:
    background-color var(--nb-dur-1) var(--nb-ease),
    color var(--nb-dur-1) var(--nb-ease);
}
.nb-rail-drawer-close:hover {
  color: var(--nb-blue);
  background: var(--nb-blue-wash);
}
.nb-rail-drawer-scroll {
  flex: 1 1 auto;
  overflow-y: auto;
  /* 20px above CHAPTERS: the step the desk rail's head leaves before it
     (notebook-components.css .nb-rail-head), and the drawer's own side
     padding. At 0 the label met the head's hairline (audit N-029). */
  padding: var(--nb-s5) var(--nb-s5) var(--nb-s6);
}
/* "Study this topic" in the drawer: rows, not loose words. The chapters
   above them are tabs, and three bare words under the tabs read as leftover
   text (owner review 2026-09-24). Each link takes the chapter tab's shape at
   a lighter weight: the tab's padding, hairline and radius, on the drawer's
   own paper instead of the tab's sunken fill, so a chapter still outranks
   it, with the tab's quiet chevron trailing and the chapter list's step
   between rows. The desktop rail keeps its quiet text index. */
.nb-rail-drawer .nb-rail-sibling-list {
  gap: var(--nb-s2);
}
.nb-rail-drawer .nb-rail-sibling {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--nb-s2);
  padding: var(--nb-s3) var(--nb-s3) var(--nb-s3) var(--nb-s4);
  border: 1px solid var(--nb-border);
  border-radius: var(--nb-r-md);
}
.nb-rail-drawer .nb-rail-sibling::after {
  content: "";
  flex-shrink: 0;
  inline-size: 6px;
  block-size: 6px;
  margin-inline-end: var(--nb-s1);
  border-top: 1.5px solid var(--nb-ink-3);
  border-right: 1.5px solid var(--nb-ink-3);
  transform: rotate(45deg);
}
.nb-rail-drawer .nb-rail-sibling:hover {
  border-color: var(--nb-border-strong);
}

/* ---------- 10 · Notes header chrome ---------------------------------
   Breadcrumb → chapter eyebrow → sans-700 title → meta/toolbar rule.
   The hairline under the toolbar is the notebook's margin rule; the
   reading rhythm starts beneath it. */
.nb-notes-header {
  margin-bottom: var(--nb-s7);
  /* The masthead centres as one block: breadcrumb, title, controls. The
     crumb's <ol> is a flex row, so it needs its own justify-content below
     (text-align does not reach flex items). */
  text-align: center;
}
.nb-notes-header .nb-breadcrumb {
  margin-bottom: var(--nb-s5);
}
.nb-notes-header .nb-breadcrumb ol {
  justify-content: center;
}
.nb-notes-eyebrow {
  margin-bottom: var(--nb-s2);
  font: var(--nb-type-label);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--nb-blue);
}
.nb-notes-title {
  font: var(--nb-type-headline);
  letter-spacing: -0.015em;
  color: var(--nb-ink);
  text-wrap: balance;
  text-align: center;
  /* A word wider than the column (only with the text enlarged: 45px type at
     150% on a 320px phone, "Characteristics") breaks rather than pushing
     the page sideways and the Topic Questions pager off the screen (audit
     S-G3a). break-word never breaks a word that fits on a line of its own,
     so no title at the default size moves; no hyphens: auto, which would
     re-break ordinary titles. */
  overflow-wrap: break-word;
}
.nb-notes-toolbar {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--nb-s3);
  margin-top: var(--nb-s4);
  padding-bottom: var(--nb-s3);
  border-bottom: 1px solid var(--nb-border);
}
/* Phone guard: 56% of the corpus's 813 leaf titles wrap at 380px and 11%
   reach three lines or more (max 5) - centred, that block stops reading as
   a heading. The narrow column keeps the left edge, and so does the rest of
   the masthead (audit N-026, 2026-09-25): a crumb wrapping to four or five
   centred lines over a left title, then a centred Focus mode, zigzagged
   under the left-aligned Chapters button. Every crumb is kept; only the
   edge moves. After the toolbar's own rule, so this one wins. */
@media (max-width: 480px) {
  .nb-notes-header {
    text-align: left;
  }
  /* the breadcrumb stays centred on a phone, on every study page (owner 2026-09-30) */
  .nb-notes-header .nb-breadcrumb ol {
    justify-content: center;
  }
  .nb-notes-title {
    text-align: left;
  }
  .nb-notes-toolbar {
    justify-content: flex-start;
  }
  /* A quiet button draws no edge at rest, so its glyph is what the eye lines
     up: the button's 16px padding and 1px border step back into the gutter
     and the icon starts on the title's edge. */
  .nb-notes-toolbar .nb-focus-toggle {
    margin-inline-start: calc(-1 * var(--nb-s4) - 1px);
  }
}
/* ---------- 11 · Focus mode — the reading room -----------------------
   With the chrome gone (§5), the notes become the whole room. Everything
   the reader does not read is hidden: the mobile trigger, the footer,
   the breadcrumb, and the toolbar (focus button). What remains is
   the title, the thin reading line up top, the note, and one quiet pill
   back out. The paywall is never reachable here — focus is only offered
   on readable content — so no gate styling is needed. */
html.note-focus-mode .nb-rail-trigger,
html.note-focus-mode .site-footer,
html.note-focus-mode .nb-notes-header .nb-breadcrumb,
html.note-focus-mode .nb-notes-toolbar {
  display: none;
}

/* A single reading column, centered on the paper. The measure opens to a
   relaxed ~880px reading line (wider than the study view — focus is the
   roomy reading room, not a compact strip) and the top rhythm opens up so
   the title has room to breathe. */
html.note-focus-mode .nb-notes-column {
  max-width: min(880px, 100%);
  margin-inline: auto;
}
/* Focus relaxes the reading rather than blowing it up (owner directive
   2026-07-13 — keep the size close, just one gentle notch, and open it up):
   a subtle +6% size with a roomier line-height baked into each role, in the
   wider column above. The type ROLES are re-declared so `font: var(--nb-type-*)`
   consumers (prose, titles, callouts) grow when .nb-notes inherits the role
   whole — a bare scale-token override does not reach them, because the role's
   nested var() resolves against :root. The scale tokens are lifted the same
   +6% for the `font-size: var(--nb-text-*)` consumers (headings, kickers,
   inline & display KaTeX scale with them). Literals only, so nothing
   double-applies; scoped to the column, so normal reading is untouched.
   Custom-property declarations, so the font fingerprint is unmoved. */
html.note-focus-mode .nb-notes-column {
  --nb-type-ui: 400 calc(0.9375rem * 1.06)/1.65 var(--nb-sans);
  --nb-type-prose: 400 calc(1.0625rem * 1.06)/1.85 var(--nb-sans);
  --nb-type-control: 600 calc(0.9375rem * 1.06)/1.25 var(--nb-sans);
  --nb-type-label: 600 calc(0.8125rem * 1.06)/1.25 var(--nb-sans);
  --nb-type-title: 600 calc(1.25rem * 1.06)/1.4 var(--nb-sans);
  --nb-type-headline: 700 calc(1.875rem * 1.06)/1.25 var(--nb-sans);
  --nb-type-examiner: italic 400 calc(1.0625rem * 1.06)/1.7 var(--nb-serif);
  --nb-type-editorial: 600 calc(1.5rem * 1.06)/1.3 var(--nb-serif);
  --nb-text-xs: calc(0.75rem * 1.06);
  --nb-text-sm: calc(0.8125rem * 1.06);
  --nb-text-base: calc(0.9375rem * 1.06);
  --nb-text-md: calc(1.0625rem * 1.06);
  --nb-text-lg: calc(1.25rem * 1.06);
  --nb-text-xl: calc(1.5rem * 1.06);
  --nb-text-2xl: calc(1.875rem * 1.06);
  --nb-text-3xl: calc(2.375rem * 1.06);
}
html.note-focus-mode .nb-notes-header {
  margin-top: var(--nb-s4);
  margin-bottom: var(--nb-s8);
}

/* ---------- 11a · Focus-mode entrance (the room settles) --------------
   Entering focus, the reading column arrives with a calm, premium settle —
   a gentle rise + fade, ~420ms on the canonical spring. The top reading
   line and the Exit pill follow a beat later so the eye lands on the note
   first. Keyframes (not transitions) so the choreography REPLAYS every time
   the class is toggled on. All motion is duration-driven: the reduced-motion
   guard zeroes --nb-dur-3, collapsing the keyframes to an instant, no-op
   settle with no transform left hanging (fill-mode is safe at 0ms). */
html.note-focus-mode .nb-notes-column {
  animation: nb-focus-rise var(--nb-dur-3) var(--nb-ease) both;
}
@keyframes nb-focus-rise {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}
/* The reading line draws in from the top edge, slightly delayed. */
html.note-focus-mode .nt-top-progress {
  animation: nb-focus-fade var(--nb-dur-3) var(--nb-ease) 90ms both;
}
/* The way-back pill is the last thing to appear, so it never pulls focus on
   arrival — a quiet, later fade. */
html.note-focus-mode .nb-focus-exit {
  animation: nb-focus-fade var(--nb-dur-2) var(--nb-ease) 200ms both;
}
@keyframes nb-focus-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}
/* Reduced motion: the token guard already zeroes the DURATIONS, but the staged
   delays above are literal ms — zero them too so the room appears instantly,
   fully opaque, with nothing waiting behind a delay. */
@media (prefers-reduced-motion: reduce) {
  html.note-focus-mode .topbar,
  html.note-focus-mode .site-footer,
  html.note-focus-mode .nb-notes-column,
  html.note-focus-mode .nt-top-progress,
  html.note-focus-mode .nb-focus-exit {
    animation-delay: 0s;
    animation-duration: 0s;
  }
}

/* Focus opens the vertical rhythm; the reading text itself is zoomed one notch
   larger via the scale-token re-scope on the column (above). */
html.note-focus-mode .nb-notes p,
html.note-focus-mode .nb-notes ul,
html.note-focus-mode .nb-notes ol {
  margin-bottom: var(--nb-s6);
}
html.note-focus-mode .nb-notes li {
  margin-bottom: var(--nb-s4);
}

/* The way back: a QUIET text pill (nb-btn--quiet grammar) — no raised
   sheet, no shadow. It rests as calm blue ink on the paper and only
   draws a hairline surface on hover, so it never competes with the note.
   "Exit focus · Esc" — the middot separator + a whisper-quiet key hint. */
.nb-focus-exit {
  display: none;
  position: fixed;
  top: var(--nb-s5);
  right: var(--nb-s5);
  z-index: 240;
  align-items: center;
  gap: var(--nb-s2);
  padding: var(--nb-s2) var(--nb-s3);
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--nb-r-pill);
  color: var(--nb-blue);
  font: var(--nb-type-control);
  cursor: pointer;
  transition:
    background-color var(--nb-dur-1) var(--nb-ease),
    border-color var(--nb-dur-1) var(--nb-ease),
    color var(--nb-dur-1) var(--nb-ease);
}
html.note-focus-mode .nb-focus-exit {
  display: inline-flex;
}
.nb-focus-exit:hover {
  background: var(--nb-paper-raised);
  border-color: var(--nb-border);
  color: var(--nb-blue-strong);
}
/* "· Esc" — a faint key hint, no boxed chip: the middot separates it
   from the label and the key reads as a quiet whisper, not a control. */
.nb-focus-exit-kbd {
  font: var(--nb-type-label);
  color: var(--nb-ink-2); /* small text stays on the 4.5:1 tier */
}
.nb-focus-exit-kbd::before {
  content: "· ";
  color: var(--nb-ink-2);
}
/* ⚑ WHERE THE NOTE CAN RUN UNDER IT, IT HAS GROUND (audit N-006,
   2026-09-25). The pill is bare ink at rest and draws its surface only on
   hover, which touch never has, and the centred focus column (880px) reaches
   under it at every width below about 1232px: headings ran straight through
   "Exit focus". There it rests on the surface :hover already draws. Still
   quiet: no shadow. Wider screens keep the bare pill. */
@media (max-width: 1279px) {
  html.note-focus-mode .nb-focus-exit {
    background: var(--nb-paper-raised);
    border-color: var(--nb-border);
  }
}
/* A touch screen has no Esc key to hint at. */
@media (hover: none) {
  .nb-focus-exit-kbd { display: none; }
}

/* On a phone the column drops below the fixed exit pill so nothing overlaps.
   The study-prose role remains unchanged across focus and viewport states. */
@media (max-width: 720px) {
  html.note-focus-mode .nb-notes-header {
    margin-top: var(--nb-s8);
  }
  .nb-focus-exit {
    top: var(--nb-s4);
    right: var(--nb-s4);
  }
}

/* The compact chapter drawer is modal on touch devices; its icon retains the
   same glyph while the surrounding hit box reaches the 44px target floor. */
@media (pointer: coarse) {
  .nb-rail-drawer-close {
    min-inline-size: 44px;
    min-block-size: 44px;
  }
  /* Exit focus reaches the same floor (audit S-020): it was 36px tall, the
     one control left in the reading room. Its words and place are the same. */
  .nb-focus-exit {
    min-block-size: 44px;
  }
  /* "Study this topic" rows reach the same floor. At rest they are 26px text
     rows with a 4px gap (measured 2026-09-24 at 390 in the phone drawer, and
     the desktop rail a tablet shows is the same list), so a thumb aimed at
     Flashcards could land on Questions. The row grows; the text, its padding
     and the gap between rows do not change (the drawer's rows set their own,
     § 9 above, and already clear 44px). */
  .nb-rail-sibling {
    display: flex;
    align-items: center;
    min-block-size: 44px;
  }
  /* The lesson rows and the section rows reach it too (audit N-017,
     2026-09-25): a one-line lesson was 34px, edge to edge with the next.
     Padding, not align-items: center, so the lesson number stays on the
     title's first baseline; 1lh is the row's own line, and the s3 line
     before it is the fallback where lh is unknown (the 44px floor still
     holds). A two-line row grows by the same 10px. */
  .nb-rail-chapters .sidebar-link {
    min-block-size: 44px;
    padding-block: var(--nb-s3);
    padding-block: calc((44px - 1lh) / 2);
  }
  .nb-rail-chapters .cn-subgroup-head {
    min-block-size: 44px;
  }
  /* Get Premium at the rail's foot: the phone .nb-btn floor stops at 720px,
     so a landscape phone, a tablet and the touch rail had a 40px button. */
  .nb-rail-cta .nb-btn {
    min-height: 44px;
  }
}

/* ---------- 12 · The tutor margin, a third track ----------------------
   The notes tutor is drawn as a sheet of paper lying beside the note, so it is
   a GRID SIBLING of .nb-notes-column and never a child of it. That is not
   tidiness: §11a gives the column `animation: nb-focus-rise ... both`, whose
   `to` keyframe is `transform: none`. fill-mode keeps applying it, so the
   column's COMPUTED transform is an identity matrix rather than the keyword,
   which makes it the containing block for positioned descendants. The sheet's
   binding and margin rule are absolutely positioned; inside the column they
   would resolve against the wrong box. nb_resource_detail.html records the
   468px version of this bug in full.

   ⚑ GATED ON :has(). The aside is absent for an anonymous visitor, a fully
   paywalled chapter, an unmapped subject and whenever ENGINE_SURFACES_LIVE is
   off, which is most of the time. An ungated third track would reserve 400px
   of empty paper on every one of those pages and squeeze the measure for
   nothing. The parent already uses :has() the same way at §7.

   Below 1081px the two-track grid stands and the aside takes the COLUMN track
   explicitly: as the third child of a two-column grid it would otherwise
   auto-place into row 2 column 1, underneath the rail. Below 860px §7 collapses
   to one track and it moves with it.

   The sheet's own paint, padding, sticky and scroll live in notebook-tutor.css.
   This section owns the track and nothing else. */
/* ⚑ 1081px, NOT 1400px, AND THE OLD NUMBER LEFT A HOLE. notebook-tutor.css
   turns the sheet inline and hides the tab at 1080 and below, so the docked
   arrangement has to begin at 1081 or the band between them has a bookmark tab
   with no track reserved for it. Measured at 1100 before this change: the note
   column ran 17px UNDER the tab, and the sheet stacked below the note instead
   of docking beside it. One breakpoint, shared by both files, no gap. */
@media (min-width: 1081px) {
  .nb-page-layout:has(.nb-tutor-margin) {
    grid-template-columns: 290px minmax(0, 1fr) 400px;
  }
  /* ── 8b · THE RAIL FOLDS TO MAKE ROOM FOR THE SHEET ───────────────────
     Source: the recovered "Lumen Notes - Your Tutor" document, whose script
     states the rule outright -- `these two are mutually exclusive`, one
     40px..236px column that is EITHER the chapters OR out of the way. It
     collapses 236px -> 40px on a .55s cubic-bezier(.22,.85,.3,1) while the
     note's right padding grows, so the sheet's arrival costs the reader far
     less than the sheet's full width.

     Ours differs in one deliberate way: their sheet is a panel the student
     opens, so their trigger is an event. Ours is always in the margin when
     the surface allows it, so the trigger is the sheet's PRESENCE. No
     open/closed state had to be invented to hang this on, and the selector
     is the one this file already uses two rules up.

     ⚑ ONLY AT 1081px AND UP. Below it the sheet leaves the three-column grid
     entirely (see the max-width rules below), so there is nothing to make
     room for and folding the rail would take navigation away for free.

     ⚑ TRANSITIONING grid-template-columns, not a transform. The note column
     has to REFLOW to its new measure; sliding it under a moving panel would
     leave the text at the old width for the whole animation. */
  .nb-page-layout:has(.nb-tutor-margin) {
    /* ⚑ THE HOUSE CURVE, NOT THE SOURCE'S. Lumen uses .55s
       cubic-bezier(.22,.85,.3,1); this project has a motion system
       (notebook-tokens.css:406-407) and a duration guard, so the fold takes
       --nb-dur-3 (420ms) on --nb-ease. Slightly quicker than the source and
       on the same curve as every other lift on the site, which matters more
       than matching one document's timing. */
    transition: grid-template-columns var(--nb-dur-3) var(--nb-ease);
  }
  /* ⚑ ONE STATE, TWO PANELS, AND THE SOURCE SAYS SO IN ITS OWN SCRIPT. Its
     comment reads "the swap : tutor and chapters are mutually exclusive" over
     a function setPanel(p) taking 'tutor' or 'chapters'.
     ⚑ THAT SENTENCE IS PARAPHRASED, NOT QUOTED, AND IT HAS TO BE. The source
     is JavaScript and its comment ends in a star-slash; pasted inside a CSS
     comment it closes THIS one early, because CSS comments do not nest. The
     first build did exactly that and the parser ate the rule below during
     error recovery -- the rail silently never folded, while the :not() rule a
     few lines down survived and worked, which made it look like a
     specificity problem. Never paste foreign comment text into a CSS comment.
     The first build here gave the rail its own independent preference key.
     That was wrong: it allowed both panels at full width, which is the one
     arrangement the design exists to prevent, and it left the tutor with no
     way to be put away at all. Now `html.nb-tutor-open` is the whole state.
     Tutor out -> chapters folded to the ribbon (8c). Chapters out -> the
     tutor tucked to its tab and its track removed.
     The folded track is the ribbon's own width, --nb-tutor-tab-w (44px). The
     ribbon is position: fixed at the screen's edge, outside this grid, so the
     track holds nothing: it only keeps the note from sliding under it. */
  html.nb-tutor-open .nb-page-layout:has(.nb-tutor-margin) {
    grid-template-columns: var(--nb-tutor-tab-w) minmax(0, 1fr) 400px;
  }
  /* ⚑ TUCKED: THE 400px TRACK DOES NOT EXIST. It is reserved only while the
     sheet is actually out. Folded, the third track shrinks to the width of the
     bookmark tab and nothing more, so the note gets the whole rest of the page
     at its own 800px measure -- which is what it has always had.

     The earlier build kept a 582px cap on the note here, derived from a real
     line-length measurement but applied at EVERY width. At 2550px that pinned
     a 582px strip of text inside a 1918px track. The measurement was right; making it
     unconditional was not, and the cap is gone. */
  html:not(.nb-tutor-open) .nb-page-layout:has(.nb-tutor-margin) {
    grid-template-columns: 290px minmax(0, 1fr) var(--nb-tutor-tab-w);
  }
  /* (An "option B" that seated the open sheet 48px beside the note and
     centred the pair from 1500px was built and shown on 2026-09-21; the owner
     preferred the sheet at the screen's edge, so nothing of it remains.) */

  /* ── 8b-i · THE NOTE KEEPS ITS OWN MEASURE ───────────────────────────
     ⚑ THERE IS NO max-width OVERRIDE HERE ANY MORE, AND THAT IS THE FIX.
     An earlier build capped .nb-notes-column at 582px whenever the sheet was
     on the page. The number came from a real measurement -- counting
     characters on every full rendered line, 582px = 76 characters against a
     65-75 band -- but it was applied at EVERY width, with the breakpoint
     deliberately removed. At 2550px that pinned a 582px strip of text inside a
     1918px track with 670px of void on each side. The measurement was sound;
     making it unconditional was the error.

     The column now takes HEAD's 800px cap at every width, on every surface,
     with or without a tutor. If the measure is ever narrowed it is a
     site-wide typographic decision taken on its own terms, not a side effect
     of the tutor arriving. */

  /* THE TUCK (2026-09-23). The chapters keep their width while the track
     closes over them, so no line rewraps mid-motion; they slide a little
     left as they fade, which says "put away to the side", and the rail clips
     them. The rail never scrolls sideways on the way back out. */
  .nb-page-layout:has(.nb-tutor-margin) .nb-rail { overflow-x: hidden; }
  .nb-page-layout:has(.nb-tutor-margin) .nb-rail-full { min-width: 270px; }
  /* Folded, the chapters fade and tuck at once. Once they have faded they
     leave the Tab order as well (visibility, one fade later), so Tab from the
     ribbon goes on to the note, never into an invisible list. Coming back,
     visibility returns at once and focus can land on the chapter. */
  html.nb-tutor-open .nb-page-layout:has(.nb-tutor-margin) .nb-rail-full {
    opacity: 0;
    pointer-events: none;
    transform: translateX(-28px);
    visibility: hidden;
    transition: opacity var(--nb-dur-2) var(--nb-ease),
                transform var(--nb-dur-3) var(--nb-ease),
                visibility 0s linear var(--nb-dur-2);
  }
  /* The rail stops scrolling while folded: its chapters are hidden and a
     stray scrollbar would sit in the gutter. It is also lifted one layer:
     z-index 1 makes the sticky rail the ribbon's stacking context, above the
     site footer, so the footer never paints over the ribbon at the page foot
     on a short window. The navbar (z-index 1000) still covers the ribbon's
     tucked top. */
  html.nb-tutor-open .nb-page-layout:has(.nb-tutor-margin) .nb-rail {
    overflow: hidden;
    z-index: 1;
  }
}

/* ── 8c · The ribbon: the folded chapters ──────────────────────────────
   While the tutor is out, the chapters are a bookmark ribbon: one solid
   strip of the student's blue hanging from under the navbar, flush to the
   screen's left edge. It says "your chapters are kept here" the way a ribbon
   in a book says "your place is here". The owner asked for it in two steps
   (2026-09-24): "make the chapter bar longer and tucked into side", then, of
   the rail lab's designs (/_notebook/rail-lab/?v=ribbon), "the deafult
   ribbon is what i want", the flat Ribbon rather than a textured one. This
   section is that design, moved out of the lab unchanged. It keeps the
   site's voice, not the sheet's: the rail is navigation and belongs to the
   site, the tutor sheet is paper and belongs to the notebook.

   THE GEOMETRY. 44px wide (--nb-tutor-tab-w, the width of the tutor's own
   bookmark tab on the right edge), hanging 290px below the navbar's foot. A
   plain rectangle: square at the screen edge and under the navbar,
   --nb-r-sm on the one free corner at the foot. The chevron and the word sit
   in its middle, so it never reads as a label with an empty tail. Its top
   16px sits UNDER the navbar (which paints over the rail at z-index 1000),
   so the ribbon reads as coming out of the bar and can be pulled a few px on
   hover without its top edge ever showing.

   POSITION: FIXED. The rail's own box starts at the page's gutter and clips
   what it holds; a fixed ribbon is placed by the viewport instead, so it
   sits at x 0 at every width and the rail's clip cannot reach it. 8b lifts
   the folded rail one layer so the site footer never covers it.

   INK. --nb-blue fill, --nb-on-blue ink: the site's text-on-blue pair,
   5.68:1 by day and 7.28:1 at night. The word is 15px (--nb-text-base), one
   step over the label role's 13px: on solid colour at the screen's edge it
   is read from the corner of the eye. Sentence case down the spine, like
   the back of a book.

   THE MOTION. Folding, the chapters tuck left (8b) and one beat later the
   ribbon drops out of the navbar on the house curve. Unfolding, it goes back
   up at once and the chapters come out with no empty beat between. Hover
   pulls it down 4px and deepens the blue a shade; a press pulls it 8px. No
   ring, no nudge, no bounce. The arrival uses the `translate` property and
   the pull uses `transform`, so the arrival's delay never makes the hover
   lag. Every duration and delay here is a --nb-dur-* token, which
   notebook-tokens.css zeroes under prefers-reduced-motion, so there the
   ribbon simply appears and goes; a local reduced-motion block would be dead
   code that looks load-bearing.

   AT REST, with no tutor out or below 1081px, the ribbon is up inside the
   navbar, hidden, and out of the Tab order and the accessibility tree. */
.nb-rail-fold {
  --nb-rail-ribbon-tuck: var(--nb-s4);  /* the part kept under the navbar */
  --nb-rail-ribbon-len: 290px;          /* what hangs below the navbar */
  position: fixed;
  top: calc(var(--nb-chrome-h) - var(--nb-rail-ribbon-tuck));
  left: 0;
  width: var(--nb-tutor-tab-w);
  height: calc(var(--nb-rail-ribbon-len) + var(--nb-rail-ribbon-tuck));
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--nb-s3);
  /* Even padding on the visible part, so the pair centres in what shows. */
  padding: calc(var(--nb-rail-ribbon-tuck) + var(--nb-s5)) 0 var(--nb-s5);
  background: var(--nb-blue);
  border: 0;
  border-radius: 0 0 var(--nb-r-sm) 0;
  color: var(--nb-on-blue);
  cursor: pointer;
  /* ⚑ ONE `font` DECLARATION. A <button> does not inherit type and this
     sheet has no global button reset, so the ribbon sets it, as the whole
     --nb-type-label shorthand: the word below inherits the weight and
     changes only its size. */
  font: var(--nb-type-label);
  visibility: hidden;
  pointer-events: none;
  translate: 0 -100%;
  -webkit-tap-highlight-color: transparent;
  /* leaving: straight back up, then out of the accessibility tree */
  transition: translate var(--nb-dur-2) var(--nb-ease),
              visibility 0s linear var(--nb-dur-2),
              transform var(--nb-dur-2) var(--nb-ease),
              background-color var(--nb-dur-1) var(--nb-ease);
}
.nb-rail-fold-ic {
  flex: none;
  display: grid;
  place-items: center;
}
.nb-rail-fold-lbl {
  writing-mode: vertical-rl;
  font-size: var(--nb-text-base);
  letter-spacing: .04em;
  white-space: nowrap;
  user-select: none;
}

/* Coming back, the chapters start at once, so the left edge is never empty
   while the ribbon goes up. Folding, 8b's rule takes over and adds their
   exit from the Tab order. */
.nb-rail-full {
  transition: opacity var(--nb-dur-2) var(--nb-ease), transform var(--nb-dur-3) var(--nb-ease);
}

@media (min-width: 1081px) {
  /* Folded: the ribbon drops out of the navbar one beat after the chapters
     start to tuck. */
  html.nb-tutor-open .nb-page-layout:has(.nb-tutor-margin) .nb-rail-fold {
    visibility: visible;
    pointer-events: auto;
    translate: 0 0;
    transition: translate var(--nb-dur-3) var(--nb-ease) var(--nb-dur-1),
                visibility 0s linear var(--nb-dur-1),
                transform var(--nb-dur-2) var(--nb-ease),
                background-color var(--nb-dur-1) var(--nb-ease);
  }
  /* Hover: pulled a little, a shade deeper. Press: pulled further. */
  html.nb-tutor-open .nb-page-layout:has(.nb-tutor-margin) .nb-rail-fold:hover {
    transform: translateY(var(--nb-s1));
    background: color-mix(in srgb, var(--nb-blue) 55%, var(--nb-blue-strong));
  }
  html.nb-tutor-open .nb-page-layout:has(.nb-tutor-margin) .nb-rail-fold:active {
    transform: translateY(var(--nb-s2));
    transition-duration: var(--nb-dur-2), 0s, var(--nb-dur-1), var(--nb-dur-1);
  }
  /* Keyboard: the site's 2px blue outline, 2px out. On a plain rectangle it
     follows the shape: it shows along the page side and under the foot; the
     rest is the screen edge and the navbar. */
  html.nb-tutor-open .nb-page-layout:has(.nb-tutor-margin) .nb-rail-fold:focus-visible {
    outline: 2px solid var(--nb-blue);
    outline-offset: 2px;
  }
}

/* Windows high contrast drops the painted fill; keep an edge. */
@media (forced-colors: active) {
  .nb-rail-fold { border: 1px solid currentColor; }
}

/* Below the dock, the sheet is not a third column: it stacks in the note's own
   column. 1080 is the same edge notebook-tutor.css uses to turn it inline and
   hide the tab, so the two files change state together. */
@media (max-width: 1080px) {
  .nb-tutor-margin { grid-column: 2; }
}
@media (max-width: 860px) {
  .nb-tutor-margin { grid-column: 1; }
}

/* ---------- 13 · The sealed page at the desk (Thumb Bar v2, Stage 2) -----
   A fully paywalled chapter now renders the padlocked tutor sheet, folded,
   with its bookmark tab (the paywall ruling, Option B: the tab floats in the
   right gutter and nothing on the page moves). The owner's pick as the Stage 0
   spike corrected it (guard/spike/report.json, "final"), placed before the
   focus-mode tie line below.
   S = html.nb-tutor-js:not(.nb-tutor-open):not(.note-focus-mode)
       .nb-page-layout:has(> .nb-tutor-margin):has(> .nb-notes-column >
       .nb-notes > .nb-paywall-wrap:first-child), specificity (0,9,1), over
   the (0,3,1) folded grid of section 12:
   - from 1081px the page keeps its own two tracks (the folded aside draws
     nothing there, notebook-tutor.css section 17), so the card and the pager
     stay where they have always been;
   - from 1081 to 1279px it keeps the theme lane on its right, which
     interaction-feedback.css gives every study layout WITHOUT an aside and so
     withdraws the moment the aside renders: the same token and the same
     expression, restored for S alone. With the lane the column's right edge
     is at least 36px clear of the 44px tab, so no clamp is needed.
   Without script (no html.nb-tutor-js) the noscript dock in the template
   stands; opened, S stops matching and section 12 applies. */
@media (min-width: 1081px) {
  html.nb-tutor-js:not(.nb-tutor-open):not(.note-focus-mode) .nb-page-layout:has(> .nb-tutor-margin):has(> .nb-notes-column > .nb-notes > .nb-paywall-wrap:first-child) {
    grid-template-columns: 290px minmax(0, 1fr);
  }
}
@media (min-width: 1081px) and (max-width: 1279px) {
  html.nb-tutor-js:not(.nb-tutor-open):not(.note-focus-mode) .nb-page-layout:has(> .nb-tutor-margin):has(> .nb-notes-column > .nb-notes > .nb-paywall-wrap:first-child) {
    padding-right: calc(var(--ft-theme-lane) - clamp(20px, 2.5vw, 48px));
  }
}
/* The same two rules from the FIRST PAINT (review G2-2). tutor-sheet.js sets
   html.nb-tutor-js only once it wires, at DOMContentLoaded, and a sealed page
   painted before that took the folded three tracks, then its card jumped
   right (46px at 1280, 7.5px at 1081) when the class arrived. The scripting
   media feature is true from the first frame when script runs and false
   without it, where the noscript dock still stands. Same declarations; the
   selector drops the class, (0,8,1), still over the (0,3,1) folded grid. The
   class-gated pair above stays for a browser without the feature (Safari
   before 17), which keeps the switch at DOMContentLoaded. */
@media (min-width: 1081px) and (scripting: enabled) {
  html:not(.nb-tutor-open):not(.note-focus-mode) .nb-page-layout:has(> .nb-tutor-margin):has(> .nb-notes-column > .nb-notes > .nb-paywall-wrap:first-child) {
    grid-template-columns: 290px minmax(0, 1fr);
  }
}
@media (min-width: 1081px) and (max-width: 1279px) and (scripting: enabled) {
  html:not(.nb-tutor-open):not(.note-focus-mode) .nb-page-layout:has(> .nb-tutor-margin):has(> .nb-notes-column > .nb-notes > .nb-paywall-wrap:first-child) {
    padding-right: calc(var(--ft-theme-lane) - clamp(20px, 2.5vw, 48px));
  }
}

/* Focus mode with the tutor on the page (2026-09-23): the note alone, in one
   column. html.nb-tutor-open .nb-page-layout:has(.nb-tutor-margin) and its
   :not() twin are (0,3,1) and beat focus mode's own (0,2,1) grid, which
   crammed the note into the rail's 290px track (and into the folded 44px
   track with the sheet open). This ties them at (0,3,1) and wins by coming
   later. */
html.note-focus-mode .nb-page-layout:has(.nb-tutor-margin) { grid-template-columns: minmax(0, 1fr); }

