/* LORE console — the course timeline (2026-10-12).
 *
 * The first part is the approved sketch (docs/mockups/course-timeline.html), ported: every class is
 * tl-..., every custom property --tl-..., every animation tl-..., and everything is scoped to the
 * .tl block, so no rule here can reach the rest of the console and no console rule or token is
 * redefined. The three looks (hologram, the default; scholastic; dusk) are .tl[data-look="..."]:
 * colour, type and surface only. Nothing is fetched from another host. Atkinson Hyperlegible is the
 * one the console already serves; the scholastic look's two faces, Source Serif 4 and Courier Prime,
 * are served from console/fonts beside it (added 2026-10-12, each under the SIL Open Font License:
 * SourceSerif4-OFL.txt, CourierPrime-OFL.txt), with the system serif and monospace faces after them.
 */

/* The scholastic look's faces, declared as console.css declares Atkinson and Inter. Source Serif 4 is one
   file for every weight from 400 to 700 (Latin); Courier Prime is a file each for regular and bold. A browser
   fetches a face only when something on the page is set in it, so the hologram and dusk looks fetch neither. */
@font-face {
  font-family: "Source Serif 4";
  font-style: normal; font-weight: 400 700; font-display: swap;
  src: url("../fonts/source-serif-4-var.woff2?v=1") format("woff2");
}
@font-face {
  font-family: "Courier Prime";
  font-style: normal; font-weight: 400; font-display: swap;
  src: url("../fonts/courier-prime-400.woff2?v=1") format("woff2");
}
@font-face {
  font-family: "Courier Prime";
  font-style: normal; font-weight: 700; font-display: swap;
  src: url("../fonts/courier-prime-700.woff2?v=1") format("woff2");
}

/* The console's page-wide rules stop at the timeline's edge. The sketch was drawn on a bare page: content-box
   sizing and the browser's own headings, and every size in it assumes that. console.css sets border-box on
   everything and restyles h1 to h3. These two rules come FIRST, so every rule below can still say otherwise.
   (Hiding with the `hidden` attribute works here because console.css has [hidden] { display: none !important }.) */
.tl, .tl *, .tl *::before, .tl *::after { box-sizing: content-box; }
.tl h1, .tl h2, .tl h3 { font-weight: 700; letter-spacing: normal; line-height: inherit; }
/* A button is the one element a bare page does NOT size content-box: every browser's own stylesheet gives it
   border-box. The sketch's cards, plates and rows are buttons, so a card's 208 by 138 is its OUTER size and its
   margins centre exactly that; content-box would make it 232 by 157 and push it off its place on the rail.
   :where() keeps this at the weight of the first rule, so it only puts back what that rule took away. */
.tl :where(button) { box-sizing: border-box; }

/* Layout: one dark room. A lit time rail runs through it; at every hour of teaching a deck of
   glass cards stands on the rail, one card per lesson, receding into the hour. Pick a deck and the
   view flies in and the deck fans out along its sixty minutes; pick a card and it comes to hand
   with its text and a player beside it. One world, three distances; nothing is ever on a different page. */
.tl { color-scheme: dark;
  --tl-bg: #04070D; --tl-bg2: #0A1422; --tl-ink: #EBF6FF; --tl-ink2: #A8C2D6; --tl-muted: #7390AA;
  --tl-holo: #6BD2FF; --tl-holo-line: rgba(107, 210, 255, .38); --tl-holo-soft: rgba(107, 210, 255, .10);
  --tl-glass: rgba(12, 26, 42, .78); --tl-on-holo: #03202E;
  --tl-warn: #FFB454; --tl-warn-soft: rgba(255, 180, 84, .16); --tl-ok: #5BD49A;
  --tl-hit: #7CF3D0; --tl-struggle: #B8A2FF; --tl-struggle-soft: rgba(184, 162, 255, .18); --tl-ghost: rgba(168, 194, 214, .5);
  --tl-sans: "Atkinson Hyperlegible", "Segoe UI", system-ui, sans-serif;
  --tl-mono: ui-monospace, Menlo, Consolas, monospace; --tl-field-line: rgba(107, 210, 255, .5); }
:where(.tl) button, :where(.tl) input { font: inherit; color: inherit; }
:where(.tl) button { cursor: pointer; }
:where(.tl) :focus-visible { outline: 2px solid var(--tl-holo); outline-offset: 3px; }
.tl-mono { font-family: var(--tl-mono); font-variant-numeric: tabular-nums; }
/* (The room's ground, its cards' glow and lit edge, and each look's, are the looks' one definition: console/css/looks.css,
   from which the console's own pages are drawn too. The colours stay here.) */
.tl { height: 100%; display: grid; grid-template-columns: minmax(0, 1fr); grid-template-rows: auto minmax(0, 1fr) auto; background: var(--look-ground), var(--tl-bg); }
/* ---- bar ---- */
.tl-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 18px; padding: 12px 20px; border-bottom: 1px solid var(--tl-holo-soft); position: relative; z-index: 3; }
.tl-bar h1 { font-size: 19px; margin: 0; letter-spacing: .01em; }
.tl-term { color: var(--tl-ink2); font-size: 13px; }
.tl-term b { color: var(--tl-holo); font-weight: 700; }
.tl-grow { flex: 1 1 40px; }
.tl-tools { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.tl-chip { border: 1px solid var(--tl-holo-line); background: rgba(107, 210, 255, .04); border-radius: 3px; padding: 6px 11px; font-size: 13px; color: var(--tl-ink2); display: inline-flex; gap: 8px; align-items: center; }
.tl-chip:where(:not([aria-disabled="true"])):hover { color: var(--tl-ink); background: var(--tl-holo-soft); }
.tl-chip[aria-pressed="true"] { background: var(--tl-holo); border-color: var(--tl-holo); color: var(--tl-on-holo); font-weight: 700; }
.tl-chip .tl-sw { width: 9px; height: 9px; border: 1.5px dashed var(--tl-ghost); }
.tl-chip.tl-struggle .tl-sw { border: 0; background: var(--tl-struggle); }
.tl-chip[aria-pressed="true"] .tl-sw { border-color: var(--tl-on-holo); }
.tl-chip.tl-todo { border-color: var(--tl-warn); color: var(--tl-warn); font-weight: 700; }
.tl-chip.tl-todo.tl-clear { border-color: var(--tl-holo-line); color: var(--tl-ok); }
.tl-zoom { display: inline-flex; border: 1px solid var(--tl-holo-line); border-radius: 3px; overflow: hidden; }
.tl-zoom button { border: 0; background: transparent; padding: 6px 11px; font-size: 13px; color: var(--tl-muted); border-left: 1px solid var(--tl-holo-soft); }
.tl-zoom button:first-child { border-left: 0; }
.tl-zoom button[aria-current="true"] { background: var(--tl-holo-soft); color: var(--tl-holo); font-weight: 700; }
.tl-zoom button:disabled { opacity: .35; cursor: default; }
/* ---- the room ---- */
.tl-stage { position: relative; min-height: 0; overflow: hidden; }
.tl-space { position: absolute; inset: 0; overflow: hidden; perspective: 1250px; perspective-origin: 50% 34%; touch-action: none; }
.tl-space::after { content: ""; position: absolute; inset: 0; pointer-events: none; z-index: 1;
  background: repeating-linear-gradient(0deg, rgba(107, 210, 255, .028) 0 1px, transparent 1px 3px), radial-gradient(ellipse at 50% 46%, transparent 52%, rgba(2, 4, 8, .30) 100%); }
.tl-drift { position: absolute; inset: 0; transform-style: preserve-3d; pointer-events: none; animation: tl-drift 13s ease-in-out infinite alternate; }
.tl-card, .tl-plate, .tl-slot { pointer-events: auto; }
@keyframes tl-drift { from { transform: rotateY(-1.3deg) translateY(4px); } to { transform: rotateY(1.3deg) translateY(-4px); } }
.tl-world { position: absolute; left: var(--tl-wl, 50%); top: var(--tl-wt, 50%); width: 0; height: 0; transform-style: preserve-3d;
  transform: scale(calc(var(--tl-ws, 1) * var(--tl-pz, 1))) rotateX(calc(var(--tl-rx, 8deg) + var(--tl-py, 0deg))) rotateY(calc(var(--tl-ry, 20deg) + var(--tl-px, 0deg)));
  transition: transform .9s cubic-bezier(.2, .8, .2, 1), left .9s cubic-bezier(.2, .8, .2, 1), top .9s cubic-bezier(.2, .8, .2, 1); }
.tl-keep3d { transform-style: preserve-3d; }
.tl-at { position: absolute; left: 0; top: 0; transform: translate3d(var(--tl-x, 0px), var(--tl-y, 0px), var(--tl-z, 0px)) rotateY(var(--tl-r, 0deg)) scale(var(--tl-s, 1));
  transition: transform .9s cubic-bezier(.2, .8, .2, 1), opacity .6s ease; }
.tl-floor { width: 3600px; height: 2200px; margin: -1100px 0 0 -1800px; transform: translate3d(0, 216px, -260px) rotateX(90deg);
  background: repeating-linear-gradient(90deg, rgba(107, 210, 255, .13) 0 1px, transparent 1px 90px), repeating-linear-gradient(0deg, rgba(107, 210, 255, .09) 0 1px, transparent 1px 90px);
  -webkit-mask-image: radial-gradient(closest-side, #000 20%, transparent 78%); mask-image: radial-gradient(closest-side, #000 20%, transparent 78%); pointer-events: none; }
.tl-card { width: 208px; height: 138px; margin: -69px 0 0 -104px; padding: 9px 11px 8px; text-align: left; color: var(--tl-ink);
  border: 1px solid var(--tl-holo-line); border-radius: 4px; overflow: hidden; display: flex; flex-direction: column; gap: 3px;
  background: linear-gradient(112deg, transparent 38%, rgba(255, 255, 255, .055) 50%, transparent 62%), linear-gradient(158deg, rgba(38, 86, 118, .93), rgba(13, 32, 50, .92) 44%, rgba(5, 12, 22, .94));
  box-shadow: var(--look-card-shadow); }
.tl-card.tl-back > * { visibility: hidden; }
.tl-card::after { content: ""; position: absolute; left: 0; right: 0; top: 0; height: 1px; background: var(--look-lit-edge); opacity: .8; }
.tl-card.tl-deck:hover, .tl-card.tl-mini:hover { border-color: var(--tl-holo); }
.tl-card.tl-sel { border-color: var(--tl-holo); box-shadow: 0 0 54px rgba(107, 210, 255, .30), inset 0 0 28px rgba(107, 210, 255, .09); }
.tl-card.tl-pop, .tl-card.tl-held { border-color: var(--tl-holo); box-shadow: 0 0 64px rgba(107, 210, 255, .34), inset 0 0 30px rgba(107, 210, 255, .10); }
.tl-card.tl-pop::before, .tl-card.tl-held::before { content: ""; position: absolute; inset: 4px; pointer-events: none; opacity: .9; background:
  linear-gradient(var(--tl-holo), var(--tl-holo)) left top / 12px 1px no-repeat, linear-gradient(var(--tl-holo), var(--tl-holo)) left top / 1px 12px no-repeat,
  linear-gradient(var(--tl-holo), var(--tl-holo)) right top / 12px 1px no-repeat, linear-gradient(var(--tl-holo), var(--tl-holo)) right top / 1px 12px no-repeat,
  linear-gradient(var(--tl-holo), var(--tl-holo)) left bottom / 12px 1px no-repeat, linear-gradient(var(--tl-holo), var(--tl-holo)) left bottom / 1px 12px no-repeat,
  linear-gradient(var(--tl-holo), var(--tl-holo)) right bottom / 12px 1px no-repeat, linear-gradient(var(--tl-holo), var(--tl-holo)) right bottom / 1px 12px no-repeat; }
.tl-card.tl-todo { border-color: var(--tl-warn); }
.tl-card.tl-miss { border-color: var(--tl-struggle); box-shadow: 0 0 34px rgba(184, 162, 255, .34), inset 0 0 28px rgba(184, 162, 255, .10); background: linear-gradient(158deg, rgba(84, 70, 140, .94), rgba(28, 26, 58, .93) 44%, rgba(8, 10, 24, .95)); }
.tl-card .tl-tc { font: 600 11px var(--tl-mono); letter-spacing: .06em; color: var(--tl-holo); display: flex; justify-content: space-between; }
.tl-card .tl-sl { flex: 1; display: flex; align-items: center; font-size: 13.5px; line-height: 1.2; min-height: 0; overflow: hidden; }
.tl-card .tl-tt { font-size: 12px; font-weight: 700; color: var(--tl-ink2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tl-card .tl-cs { display: flex; gap: 4px; flex-wrap: nowrap; overflow: hidden; min-height: 17px; }
.tl-tag { border-radius: 2px; padding: 0 5px; font-size: 10.5px; line-height: 17px; letter-spacing: .03em; background: var(--tl-holo-soft); color: var(--tl-holo); white-space: nowrap; }
.tl-tag.tl-warn { background: var(--tl-warn-soft); color: var(--tl-warn); font-weight: 700; }
.tl-tag.tl-miss { background: var(--tl-struggle-soft); color: var(--tl-struggle); font-weight: 700; }
.tl-shade { width: 208px; height: 138px; margin: -69px 0 0 -104px; border: 1px dashed var(--tl-ghost); border-radius: 4px; padding: 9px 11px; font-size: 12px; line-height: 1.35; color: var(--tl-ink2); pointer-events: none; overflow: hidden; background: rgba(10, 18, 28, .84); }
.tl-shade b { display: block; font: 600 10.5px var(--tl-mono); letter-spacing: .08em; color: var(--tl-muted); margin-bottom: 4px; }
.tl-plate { width: 230px; margin: 0 0 0 -115px; text-align: left; background: none; border: 0; border-top: 1px solid var(--tl-holo); padding: 8px 2px 0; color: var(--tl-ink); }
.tl-plate .tl-h { font: 600 12px var(--tl-mono); letter-spacing: .12em; color: var(--tl-holo); display: block; }
.tl-plate .tl-n { font-size: 15px; font-weight: 700; display: block; margin: 2px 0; }
.tl-plate .tl-d { font-size: 12.5px; color: var(--tl-ink2); display: block; }
.tl-plate .tl-cs { display: flex; gap: 5px; margin-top: 5px; flex-wrap: wrap; }
.tl-plate:hover .tl-n, .tl-plate.tl-sel .tl-n { color: var(--tl-holo); }
.tl-rail { height: 2px; margin-top: -1px; background: linear-gradient(90deg, transparent, var(--tl-holo) 6%, var(--tl-holo) 94%, transparent); box-shadow: 0 0 18px var(--tl-holo); pointer-events: none; }
.tl-tick { width: 1px; height: 12px; background: var(--tl-holo); pointer-events: none; }
.tl-tick.tl-big { height: 22px; width: 2px; }
.tl-lbl { font: 600 11.5px var(--tl-mono); letter-spacing: .08em; color: var(--tl-holo); white-space: nowrap; transform: translate3d(var(--tl-x, 0px), var(--tl-y, 0px), var(--tl-z, 0px)) translateX(-50%); pointer-events: none; }
.tl-lbl.tl-lesson { font: 700 13px var(--tl-sans); letter-spacing: 0; color: var(--tl-ink2); }
.tl-span { height: 5px; width: var(--tl-w, 60px); margin: -2px 0 0 calc(var(--tl-w, 60px) / -2); border-radius: 3px; background: var(--tl-holo); box-shadow: 0 0 16px var(--tl-holo); pointer-events: none; }
.tl-beam { width: 1px; height: 186px; background: linear-gradient(to top, var(--tl-holo), transparent); pointer-events: none; }
.tl-num { font: 600 112px/1 var(--tl-mono); letter-spacing: -.03em; color: transparent; -webkit-text-stroke: 1px var(--tl-holo-line); white-space: nowrap; pointer-events: none;
  transform: translate3d(var(--tl-x, 0px), var(--tl-y, 0px), var(--tl-z, 0px)) translateX(-50%); }
.tl-pool { width: 380px; height: 380px; margin: -190px 0 0 -190px; pointer-events: none; background: radial-gradient(closest-side, rgba(107, 210, 255, .30), rgba(107, 210, 255, .07) 48%, transparent 72%);
  transform: translate3d(var(--tl-x, 0px), 215px, var(--tl-z, -150px)) rotateX(90deg) scale(var(--tl-s, 1), 1); }
.tl-slot { width: var(--tl-w, 60px); height: 440px; margin: -320px 0 0 calc(var(--tl-w, 60px) / -2); cursor: pointer; }
/* ---- video: each lesson is also a film on the rail, and the card in hand is its screen ---- */
.tl-playhead { width: 2px; height: 78px; margin: -64px 0 0 -1px; background: linear-gradient(to bottom, transparent, #EBF6FF 35%, var(--tl-holo)); box-shadow: 0 0 14px var(--tl-holo); pointer-events: none; transition: opacity .3s ease; }
.tl-cap { font-size: 11.5px; line-height: 1.3; color: var(--tl-muted); min-height: 30px; }
.tl-cap b { color: var(--tl-ink); font-weight: 400; }
.tl-prog { position: absolute; left: 0; bottom: 0; height: 3px; width: 0; background: var(--tl-holo); box-shadow: 0 0 10px var(--tl-holo); }
.tl-card.tl-held { cursor: pointer; }
.tl-card.tl-held .tl-sl { padding-right: 36px; }
.tl-glyph { position: absolute; right: 10px; top: 50%; margin-top: -14px; width: 28px; height: 28px; display: grid; place-items: center; font-size: 11px; color: var(--tl-holo); border: 1px solid var(--tl-holo); border-radius: 50%; background: rgba(4, 10, 18, .66); }
.tl-note { margin: 8px 0 0; font-size: 13px; color: var(--tl-muted); }
.tl-reader { touch-action: pan-y; }
/* ---- search: typed or spoken; what it finds lights up where it sits in the course ---- */
.tl-find { flex: 1 1 220px; max-width: 430px; margin: 0 auto; position: relative; display: flex; align-items: center; gap: 4px; height: 38px; padding: 0 5px 0 11px;
  border: 1px solid var(--tl-holo-line); border-radius: 4px; background: rgba(4, 10, 18, .6); color: var(--tl-muted); }
.tl-find:focus-within { border-color: var(--tl-holo); box-shadow: 0 0 26px rgba(107, 210, 255, .22); color: var(--tl-holo); }
.tl-find svg { flex: none; }
.tl-find input { flex: 1; min-width: 0; height: 100%; border: 0; background: none; outline: none; color: var(--tl-ink); font-size: 14.5px; padding: 0 6px; }
.tl-find input::placeholder { color: var(--tl-muted); }
.tl-find input::-webkit-search-cancel-button { display: none; }
.tl-fbtn { flex: none; width: 28px; height: 28px; display: grid; place-items: center; border: 0; border-radius: 50%; background: none; color: var(--tl-ink2); font-size: 17px; line-height: 1; }
.tl-fbtn:hover { color: var(--tl-holo); background: var(--tl-holo-soft); }
.tl-fbtn.tl-mic[aria-pressed="true"] { color: var(--tl-on-holo); background: var(--tl-holo); animation: tl-listen 1.3s ease-out infinite; }
@keyframes tl-listen { from { box-shadow: 0 0 0 0 rgba(107, 210, 255, .6); } to { box-shadow: 0 0 0 14px rgba(107, 210, 255, 0); } }
.tl-results { position: absolute; left: -1px; right: -1px; min-width: min(470px, calc(100vw - 40px)); top: calc(100% + 6px); z-index: 6; max-height: min(62vh, 460px); overflow-y: auto; display: grid; gap: 2px; padding: 6px;
  background: rgba(8, 18, 30, .97); border: 1px solid var(--tl-holo-line); border-radius: 5px; box-shadow: 0 20px 60px rgba(0, 0, 0, .6), 0 0 40px rgba(107, 210, 255, .14); scrollbar-width: thin; scrollbar-color: var(--tl-holo-line) transparent; }
/* The options are the listbox and only they are: the count under them belongs to the panel. */
.tl .tl-opts { display: grid; gap: 2px; }
.tl-results button { display: grid; grid-template-columns: 44px minmax(0, 1fr); gap: 1px 10px; text-align: left; border: 0; border-radius: 3px; background: none; padding: 8px 10px; }
.tl-results button:hover, .tl-results button[aria-selected="true"] { background: var(--tl-holo-soft); }
.tl-results .tl-rt { grid-row: span 2; padding-top: 2px; font: 600 12px var(--tl-mono); color: var(--tl-holo); }
.tl-results .tl-rn { font-size: 14px; font-weight: 700; color: var(--tl-ink); }
.tl-results .tl-rs { font-size: 12.5px; color: var(--tl-ink2); }
.tl-results .tl-rw { margin-right: 7px; font: 600 10px var(--tl-mono); letter-spacing: .08em; text-transform: uppercase; color: var(--tl-muted); }
.tl-results mark { background: none; color: var(--tl-hit); font-weight: 700; }
.tl-results .tl-foot { margin: 0; padding: 6px 10px 4px; font-size: 12px; color: var(--tl-muted); }
.tl-card.tl-hit { border-color: var(--tl-hit); box-shadow: 0 0 34px rgba(124, 243, 208, .45), inset 0 0 26px rgba(124, 243, 208, .12); }
.tl-card.tl-back.tl-hit > * { visibility: visible; }
.tl-tag.tl-hit { background: rgba(124, 243, 208, .16); color: var(--tl-hit); font-weight: 700; }
.tl-strip button i .tl-hm { position: absolute; top: -2px; width: 3px; height: 8px; margin-left: -1px; background: var(--tl-hit); box-shadow: 0 0 6px var(--tl-hit); }
@media (prefers-reduced-motion: reduce) {
  .tl-fbtn.tl-mic[aria-pressed="true"] { animation: none; }
}
.tl-hud { position: absolute; left: 20px; top: 14px; right: 20px; display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 12px; z-index: 2; font-size: 13px; color: var(--tl-ink2); pointer-events: none; }
.tl-hud > * { pointer-events: auto; }
.tl-hud h2 { font-size: 17px; margin: 0; color: var(--tl-ink); }
.tl-hud .tl-up { border: 0; background: none; padding: 0; color: var(--tl-holo); text-decoration: underline; text-underline-offset: 3px; }
.tl-hud .tl-nav { border: 1px solid var(--tl-holo-line); background: rgba(4, 10, 18, .6); border-radius: 3px; padding: 3px 11px; color: var(--tl-holo); }
.tl-hud .tl-nav:disabled { opacity: .3; cursor: default; }
.tl-hint { position: absolute; left: 20px; right: 20px; bottom: 12px; margin: 0; text-align: center; color: var(--tl-muted); font-size: 12.5px; z-index: 2; pointer-events: none; white-space: pre-wrap; }
.tl-hint.tl-read { color: var(--tl-ink2); font-size: 14.5px; }
.tl-hint.tl-side { right: 48%; }
.tl-reader, .tl-drawer { scrollbar-width: thin; scrollbar-color: var(--tl-holo-line) transparent; }
.tl-hint.tl-read b { color: var(--tl-holo); font-weight: 600; }
/* ---- the lesson in hand: its panel, to read and to play (nothing in it edits) ----
   NOT AS THE SKETCH HAD IT (2026-10-12): the sketch centred this panel on the room's height (top: 50%, shifted up by
   48% of itself, at most 86% tall), and on a wide screen it covered the Earlier and Later arrows at the end of the
   room's heading. It now starts under the heading and stops above the line at the room's foot. timeline-room.js
   works out both (layout(): panelTop, panelMax) and sets them on the panel; the two figures here are what it has
   until the first paint. */
.tl-reader { position: absolute; right: 3%; top: 70px; width: min(500px, 43%); max-height: calc(100% - 122px); overflow-y: auto; z-index: 2;
  background: var(--tl-glass); -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px); border: 1px solid var(--tl-holo-line); border-radius: 6px; padding: 16px 18px; box-shadow: 0 0 60px rgba(107, 210, 255, .12); }
.tl-reader.tl-in { animation: tl-arrive .5s cubic-bezier(.2, .8, .2, 1); }
@keyframes tl-arrive { from { opacity: 0; transform: translateX(40px); } }
.tl-reader h3 { font: 600 11px var(--tl-mono); letter-spacing: .12em; text-transform: uppercase; color: var(--tl-holo); margin: 0 0 8px; }
.tl-reader .tl-block + .tl-block { margin-top: 18px; }
.tl-statusline { display: flex; flex-wrap: wrap; gap: 8px 12px; align-items: center; margin-top: 10px; font-size: 13.5px; color: var(--tl-ink2); }
.tl-statusline .tl-warn { color: var(--tl-warn); font-weight: 700; }
.tl-btn { border: 1px solid var(--tl-holo); background: var(--tl-holo); color: var(--tl-on-holo); border-radius: 3px; padding: 7px 13px; font-size: 13.5px; font-weight: 700; }
.tl-btn.tl-quiet { background: transparent; color: var(--tl-holo); }
.tl-link { border: 0; background: none; padding: 0; color: var(--tl-holo); text-decoration: underline; text-underline-offset: 3px; font-size: 13.5px; }
.tl-qa p { margin: 0 0 6px; font-weight: 700; }
.tl-qa ul { margin: 0; padding: 0; list-style: none; display: grid; gap: 3px; font-size: 14px; color: var(--tl-ink2); }
.tl-qa li.tl-right { color: var(--tl-ink); font-weight: 700; }
.tl-qa li span:first-child { font: 600 12px var(--tl-mono); color: var(--tl-muted); margin-right: 8px; }
.tl-evidence { margin-top: 10px; padding: 9px 12px; background: var(--tl-struggle-soft); border-left: 2px solid var(--tl-struggle); font-size: 13.5px; }
.tl-evidence b { color: var(--tl-struggle); }
/* ---- strip: the whole course, always underfoot ---- */
.tl-strip { border-top: 1px solid var(--tl-holo-soft); padding: 8px 20px 10px; display: flex; gap: 6px; align-items: flex-end; overflow-x: auto; position: relative; z-index: 3; }
.tl-strip button { flex: 1 1 60px; min-width: 60px; border: 0; background: none; padding: 0; text-align: left; }
.tl-strip button span { display: block; font: 600 10.5px var(--tl-mono); letter-spacing: .1em; color: var(--tl-muted); }
.tl-strip button i { display: block; height: 4px; margin-top: 4px; background: var(--tl-holo-soft); position: relative; }
.tl-strip button[aria-current="true"] span { color: var(--tl-holo); }
.tl-strip button[aria-current="true"] i { background: var(--tl-holo); box-shadow: 0 0 10px var(--tl-holo); }
.tl-strip button.tl-todo i::after { content: ""; position: absolute; right: 0; top: -3px; width: 10px; height: 10px; border-radius: 50%; background: var(--tl-warn); }
.tl-strip .tl-note { flex: none; align-self: center; font-size: 12px; color: var(--tl-muted); padding-left: 14px; }
/* ---- the out-of-date list: a drawer at the side of the window, to read (it changes nothing) ---- */
.tl-drawer { position: fixed; top: 0; right: 0; bottom: 0; box-sizing: border-box; width: min(431px, 100%); background: #08121E; border-left: 1px solid var(--tl-holo-line); box-shadow: -30px 0 60px rgba(0, 0, 0, .6); padding: 18px 20px calc(24px + env(safe-area-inset-bottom, 0px)); overflow-y: auto; z-index: 5; display: flex; flex-direction: column; gap: 24px; }
.tl-drawer header { display: flex; justify-content: space-between; align-items: baseline; }
.tl-drawer h2 { font-size: 17px; margin: 0; }
.tl-drawer h3 { font: 600 11px var(--tl-mono); letter-spacing: .12em; text-transform: uppercase; color: var(--tl-holo); margin: 0 0 8px; }
.tl-drawer p { margin: 0 0 8px; color: var(--tl-ink2); font-size: 13.5px; }
.tl-todo-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; }
.tl-todo-list li { border: 1px solid var(--tl-holo-line); border-radius: 4px; padding: 10px 12px; display: grid; gap: 6px; }
.tl-todo-list li span { font-size: 13px; color: var(--tl-ink2); }
.tl-acts { display: flex; gap: 12px; flex-wrap: wrap; align-items: center; }
.tl-done { color: var(--tl-ok); font-size: 13.5px; }
/* ---- narrow screens: the same course as a list ----
   NOT AS THE SKETCH HAD IT. Under 980px the sketch kept the bar's controls on one row that scrolled sideways with
   its scrollbar HIDDEN, and the row cut every focus ring: two thirds of the bar (Details, both highlights, the
   out-of-date list, Zoom, Look) was off the screen with nothing to say so. Round C (2026-10-13) let the controls
   wrap, each 44px under a finger, and on a phone 375px wide that made the bar six rows and 472px tall: more than
   half the screen before the room began.
   ROUND D (2026-10-13): the bar is three rows there. The course's name; the search field; and ALL the tools on ONE
   row that scrolls sideways INSIDE ITSELF (the page never does). What round C found wrong with one row is put
   right in it: the scrollbar is not hidden (a thin one, where the system shows scrollbars at all); the row keeps
   6px above and below and 8px at each end for the focus ring, which stands 5px outside a control (8px outside a
   look's swatch), and takes the same back with a negative margin, so that room costs the bar no height; and
   scroll-padding keeps a control that the keyboard reaches, and its ring, clear of the row's ends. No control
   shrinks or wraps (.tl-tools > *), and each keeps its 44px. The line under the course's name wraps (it was
   cut, and its end was nowhere on the page). ---- */
/* ---- sharp text. A card that is scaled up in 3D is drawn by stretching a small picture of it, so its
   text goes soft. The card being read is therefore laid out --k times larger and drawn 1/k as large:
   the same size on screen, from more pixels. Every length of a card is a multiple of --u for that. ---- */
.tl-card { --tl-u: calc(1px * var(--tl-k, 1)); width: calc(208 * var(--tl-u)); height: calc(138 * var(--tl-u)); margin: calc(-69 * var(--tl-u)) 0 0 calc(-104 * var(--tl-u));
  padding: calc(9 * var(--tl-u)) calc(11 * var(--tl-u)) calc(8 * var(--tl-u)); border-width: var(--tl-u); border-radius: calc(4 * var(--tl-u)); gap: calc(3 * var(--tl-u));
  box-shadow: 0 0 calc(22 * var(--tl-u)) rgba(107, 210, 255, .12), inset 0 0 calc(28 * var(--tl-u)) rgba(107, 210, 255, .07); }
.tl-card::after { height: var(--tl-u); }
.tl-card.tl-sel { box-shadow: 0 0 calc(54 * var(--tl-u)) rgba(107, 210, 255, .30), inset 0 0 calc(28 * var(--tl-u)) rgba(107, 210, 255, .09); }
.tl-card.tl-pop, .tl-card.tl-held { box-shadow: 0 0 calc(64 * var(--tl-u)) rgba(107, 210, 255, .34), inset 0 0 calc(30 * var(--tl-u)) rgba(107, 210, 255, .10); }
.tl-card.tl-pop::before, .tl-card.tl-held::before { inset: calc(4 * var(--tl-u)); background-size:
  calc(12 * var(--tl-u)) var(--tl-u), var(--tl-u) calc(12 * var(--tl-u)), calc(12 * var(--tl-u)) var(--tl-u), var(--tl-u) calc(12 * var(--tl-u)),
  calc(12 * var(--tl-u)) var(--tl-u), var(--tl-u) calc(12 * var(--tl-u)), calc(12 * var(--tl-u)) var(--tl-u), var(--tl-u) calc(12 * var(--tl-u)); }
.tl-card.tl-miss { box-shadow: 0 0 calc(34 * var(--tl-u)) rgba(184, 162, 255, .34), inset 0 0 calc(28 * var(--tl-u)) rgba(184, 162, 255, .10); }
.tl-card.tl-hit { box-shadow: 0 0 calc(34 * var(--tl-u)) rgba(124, 243, 208, .45), inset 0 0 calc(26 * var(--tl-u)) rgba(124, 243, 208, .12); }
.tl-card .tl-tc { font-size: calc(11 * var(--tl-u)); }
.tl-card .tl-sl { font-size: calc(13.5 * var(--tl-u)); }
.tl-card .tl-tt { font-size: calc(12 * var(--tl-u)); }
.tl-card .tl-cs { gap: calc(4 * var(--tl-u)); min-height: calc(17 * var(--tl-u)); }
.tl-card .tl-tag { border-radius: calc(2 * var(--tl-u)); padding: 0 calc(5 * var(--tl-u)); font-size: calc(10.5 * var(--tl-u)); line-height: calc(17 * var(--tl-u)); }
.tl-card .tl-cap { font-size: calc(11.5 * var(--tl-u)); min-height: calc(30 * var(--tl-u)); }
.tl-card .tl-prog { height: calc(3 * var(--tl-u)); box-shadow: 0 0 calc(10 * var(--tl-u)) var(--tl-holo); }
.tl-card.tl-held .tl-sl { padding-right: calc(36 * var(--tl-u)); }
.tl-card .tl-glyph { right: calc(10 * var(--tl-u)); margin-top: calc(-14 * var(--tl-u)); width: calc(28 * var(--tl-u)); height: calc(28 * var(--tl-u)); font-size: calc(11 * var(--tl-u)); border-width: var(--tl-u); }
/* ---- the room on a phone: one thing in front, the rest of time to either side ---- */
.tl-space.tl-tall .tl-hint { left: 12px; right: 12px; bottom: 8px; }
.tl-space.tl-tall .tl-hint.tl-read { font-size: 13px; }
.tl-space.tl-tall .tl-hud { left: 12px; right: 12px; top: 10px; gap: 3px 10px; align-items: center; }
.tl-space.tl-tall .tl-hud .tl-up { order: 1; }
.tl-space.tl-tall .tl-hud .tl-grow { order: 2; }
.tl-space.tl-tall .tl-hud .tl-nav { order: 3; }
.tl-space.tl-tall .tl-hud h2 { order: 4; flex-basis: 100%; font-size: 16px; }
.tl-space.tl-tall .tl-hud > span:not(.tl-grow) { order: 5; flex-basis: 100%; font-size: 12px; }
.tl-space.tl-tall .tl-reader { left: 10px; right: 10px; bottom: 8px; width: auto; max-height: none; transform: none; padding: 14px; }
.tl-space.tl-tall .tl-reader.tl-in { animation-name: tl-rise; }
@keyframes tl-rise { from { opacity: 0; transform: translateY(28px); } }
.tl-space.tl-tall .tl-num { font-size: 96px; }
@media (max-width: 979px) {
  .tl-bar { padding: 8px 12px; gap: 8px 10px; }
  .tl-bar h1 { font-size: 17px; }
  .tl-term { font-size: 12px; white-space: normal; max-width: calc(100vw - 24px); }
  .tl-find { order: 2; flex: 1 1 100%; max-width: none; }
  .tl-bar > * { min-width: 0; }
  .tl-tools { order: 3; flex: 1 1 100%; max-width: 100%; flex-wrap: nowrap; overflow-x: auto; overflow-y: hidden;
    padding: 6px 8px; margin: -6px -8px; scroll-padding: 0 8px;
    scrollbar-width: thin; scrollbar-color: var(--tl-holo-line) transparent; }
  .tl-tools > * { flex: none; }
  .tl-strip { padding: 6px 12px 8px; }
}
.tl-flow { position: absolute; inset: 0; padding: 14px 16px 24px; overflow-y: auto; }
.tl-flow .tl-hud { position: static; padding: 0 0 12px; }
.tl-flow .tl-list { display: grid; gap: 10px; }
.tl-flow .tl-flowrow { text-align: left; border: 1px solid var(--tl-holo-line); border-radius: 5px; padding: 11px 13px; background: linear-gradient(158deg, rgba(107, 210, 255, .14), rgba(6, 14, 24, .6)); display: grid; gap: 3px; box-shadow: 4px 4px 0 -1px rgba(107, 210, 255, .10), 8px 8px 0 -2px rgba(107, 210, 255, .06); }
.tl-flow .tl-lessonrow { box-shadow: none; }
.tl-flow .tl-flowrow .tl-tc { font: 600 11px var(--tl-mono); letter-spacing: .08em; color: var(--tl-holo); }
.tl-flow .tl-flowrow .tl-n { font-weight: 700; }
.tl-flow .tl-flowrow .tl-d { font-size: 13px; color: var(--tl-ink2); }
.tl-flow .tl-flowrow .tl-cs { display: flex; gap: 5px; flex-wrap: wrap; margin-top: 3px; }
.tl-flow .tl-reader { position: static; transform: none; width: auto; max-height: none; animation: none; }
@media (prefers-reduced-motion: reduce) {
  .tl-world, .tl-at { transition: none; }
  .tl-reader.tl-in, .tl-drift { animation: none; }
}
/* ---- the scholastic look: the same room and the same behaviour, dressed as paper. Index cards with a red
   rule and blue lines, ink for light, a shadow on the desk where the hologram glowed. Only colour, type and
   surface change here; nothing about where things are or what they do. ---- */
.tl[data-look="scholastic"] { color-scheme: light;
  --tl-bg: #F1E9D8; --tl-bg2: #E6DCC6; --tl-ink: #22252B; --tl-ink2: #474B55; --tl-muted: #655F52;
  --tl-holo: #1F3A5F; --tl-holo-line: rgba(31, 58, 95, .36); --tl-holo-soft: rgba(31, 58, 95, .09);
  --tl-glass: rgba(255, 253, 246, .97); --tl-on-holo: #FBF6E9;
  --tl-warn: #963F09; --tl-warn-soft: rgba(168, 72, 12, .13); --tl-ok: #2C6A4B;
  --tl-hit: #7A5A00; --tl-struggle: #6A3C9C; --tl-struggle-soft: rgba(106, 60, 156, .12); --tl-ghost: rgba(71, 75, 85, .7);
  --tl-sans: "Source Serif 4", Georgia, "Iowan Old Style", "Palatino Linotype", "Times New Roman", serif;
  --tl-mono: "Courier Prime", "Courier New", ui-monospace, monospace; --tl-field-line: rgba(31, 58, 95, .65); }
.tl[data-look="scholastic"] { background: var(--look-ground), var(--tl-bg); }
.tl[data-look="scholastic"] .tl-bar h1 { font-size: 21px; letter-spacing: 0; }
.tl[data-look="scholastic"] .tl-chip { background: rgba(255, 253, 246, .75); }
.tl[data-look="scholastic"] .tl-space::after { background: var(--look-vignette); }
.tl[data-look="scholastic"] .tl-floor { background: repeating-linear-gradient(90deg, rgba(31, 58, 95, .11) 0 1px, transparent 1px 90px), repeating-linear-gradient(0deg, rgba(31, 58, 95, .08) 0 1px, transparent 1px 90px); }
.tl[data-look="scholastic"] .tl-card { --tl-rule: var(--look-margin) 0 calc(25 * var(--tl-u)) / 100% var(--tl-u) no-repeat,
  var(--look-ruled) 0 calc(26 * var(--tl-u)) / 100% 100% no-repeat;
  background: var(--tl-rule), #FFFDF6; border-color: var(--look-card-edge); box-shadow: var(--look-card-shadow); }
.tl[data-look="scholastic"] .tl-card::after { display: none; }
.tl[data-look="scholastic"] .tl-card.tl-sel { border-color: var(--tl-holo); box-shadow: 0 calc(10 * var(--tl-u)) calc(22 * var(--tl-u)) rgba(60, 42, 20, .30); }
.tl[data-look="scholastic"] .tl-card.tl-pop, .tl[data-look="scholastic"] .tl-card.tl-held { border-color: var(--tl-holo); box-shadow: 0 calc(14 * var(--tl-u)) calc(30 * var(--tl-u)) rgba(60, 42, 20, .34); }
.tl[data-look="scholastic"] .tl-card.tl-todo { border-color: var(--tl-warn); }
.tl[data-look="scholastic"] .tl-card.tl-miss { border-color: var(--tl-struggle); background: var(--tl-rule), #F5EDFB; box-shadow: 0 calc(6 * var(--tl-u)) calc(14 * var(--tl-u)) rgba(106, 60, 156, .26); }
.tl[data-look="scholastic"] .tl-card.tl-hit { border-color: #8F6B00; background: var(--tl-rule), #FFF5BF; box-shadow: 0 calc(6 * var(--tl-u)) calc(16 * var(--tl-u)) rgba(150, 110, 0, .30); }
.tl[data-look="scholastic"] .tl-shade { background: rgba(250, 246, 236, .94); }
.tl[data-look="scholastic"] .tl-pool { background: radial-gradient(closest-side, rgba(60, 42, 20, .24), rgba(60, 42, 20, .06) 48%, transparent 72%); }
.tl[data-look="scholastic"] .tl-rail, .tl[data-look="scholastic"] .tl-span, .tl[data-look="scholastic"] .tl-prog { box-shadow: none; }
.tl[data-look="scholastic"] .tl-num { -webkit-text-stroke: 0; color: rgba(31, 58, 95, .15); font-family: var(--tl-sans); font-weight: 700; letter-spacing: 0; }
.tl[data-look="scholastic"] .tl-playhead { background: linear-gradient(to bottom, transparent, #B3261E 35%, #B3261E); box-shadow: none; }
.tl[data-look="scholastic"] .tl-glyph, .tl[data-look="scholastic"] .tl-find, .tl[data-look="scholastic"] .tl-hud .tl-nav { background: #FFFDF6; }
.tl[data-look="scholastic"] .tl-find:focus-within { box-shadow: 0 0 0 3px rgba(31, 58, 95, .16); }
.tl[data-look="scholastic"] .tl-fbtn.tl-mic[aria-pressed="true"] { animation-name: tl-listen-ink; }
@keyframes tl-listen-ink { from { box-shadow: 0 0 0 0 rgba(31, 58, 95, .5); } to { box-shadow: 0 0 0 14px rgba(31, 58, 95, 0); } }
.tl[data-look="scholastic"] .tl-results { background: #FFFDF6; box-shadow: 0 18px 40px rgba(60, 42, 20, .28); }
.tl[data-look="scholastic"] .tl-results mark { color: var(--tl-ink); background: #FFE680; }
.tl[data-look="scholastic"] .tl-tag.tl-hit { background: #FFE680; color: #453500; }
.tl[data-look="scholastic"] .tl-strip button[aria-current="true"] i { box-shadow: none; }
.tl[data-look="scholastic"] .tl-strip button i .tl-hm { background: #8F6B00; box-shadow: none; }
.tl[data-look="scholastic"] .tl-reader { box-shadow: 0 16px 40px rgba(60, 42, 20, .26); -webkit-backdrop-filter: none; backdrop-filter: none; }
.tl[data-look="scholastic"] .tl-drawer { background: #F7F0E1; box-shadow: -24px 0 50px rgba(60, 42, 20, .30); }
.tl[data-look="scholastic"] .tl-flow .tl-flowrow { background: #FFFDF6; box-shadow: 4px 4px 0 -1px rgba(60, 42, 20, .10), 8px 8px 0 -2px rgba(60, 42, 20, .06); }
/* ---- the dusk look: a dark that is easy on the eyes. Warm charcoal, off-white text, one quiet sage accent,
   matte cards with soft shadows. Nothing glows, there are no scan lines, and the room holds still. ---- */
.tl[data-look="dusk"] { color-scheme: dark;
  --tl-bg: #1B1D21; --tl-bg2: #24272C; --tl-ink: #E4E1D9; --tl-ink2: #BCB9B0; --tl-muted: #A5A299;
  --tl-holo: #9CC2A9; --tl-holo-line: rgba(156, 194, 169, .30); --tl-holo-soft: rgba(156, 194, 169, .09);
  --tl-glass: rgba(36, 39, 44, .98); --tl-on-holo: #1B1D21;
  --tl-warn: #E2B36B; --tl-warn-soft: rgba(226, 179, 107, .13); --tl-ok: #A9CBB7;
  --tl-hit: #F0DE9A; --tl-struggle: #CDB2E1; --tl-struggle-soft: rgba(205, 178, 225, .13); --tl-ghost: rgba(188, 185, 176, .55);
  --tl-field-line: rgba(156, 194, 169, .55); }
.tl[data-look="dusk"] { background: var(--look-ground), var(--tl-bg); }
.tl[data-look="dusk"] .tl-chip { background: rgba(255, 255, 255, .03); }
.tl[data-look="dusk"] .tl-space::after { background: var(--look-vignette); }
.tl[data-look="dusk"] .tl-drift { animation: none; }
.tl[data-look="dusk"] .tl-floor { background: repeating-linear-gradient(90deg, rgba(255, 255, 255, .045) 0 1px, transparent 1px 90px), repeating-linear-gradient(0deg, rgba(255, 255, 255, .03) 0 1px, transparent 1px 90px); }
.tl[data-look="dusk"] .tl-card { background: #2A2D33; border-color: var(--look-card-edge); box-shadow: var(--look-card-shadow); }
.tl[data-look="dusk"] .tl-card::after { display: none; }
.tl[data-look="dusk"] .tl-card.tl-sel { border-color: var(--tl-holo); box-shadow: 0 calc(10 * var(--tl-u)) calc(24 * var(--tl-u)) rgba(0, 0, 0, .45); }
.tl[data-look="dusk"] .tl-card.tl-pop, .tl[data-look="dusk"] .tl-card.tl-held { border-color: var(--tl-holo); background: #30343B; box-shadow: 0 calc(14 * var(--tl-u)) calc(32 * var(--tl-u)) rgba(0, 0, 0, .5); }
.tl[data-look="dusk"] .tl-card.tl-todo { border-color: var(--tl-warn); }
.tl[data-look="dusk"] .tl-card.tl-miss { border-color: var(--tl-struggle); background: #322E3B; box-shadow: 0 calc(6 * var(--tl-u)) calc(14 * var(--tl-u)) rgba(0, 0, 0, .4); }
.tl[data-look="dusk"] .tl-card.tl-hit { border-color: var(--tl-hit); background: #37352A; box-shadow: 0 calc(6 * var(--tl-u)) calc(16 * var(--tl-u)) rgba(0, 0, 0, .4); }
.tl[data-look="dusk"] .tl-shade { background: rgba(36, 39, 44, .95); }
.tl[data-look="dusk"] .tl-pool { background: radial-gradient(closest-side, rgba(0, 0, 0, .40), rgba(0, 0, 0, .12) 48%, transparent 72%); }
.tl[data-look="dusk"] .tl-rail, .tl[data-look="dusk"] .tl-span, .tl[data-look="dusk"] .tl-prog { box-shadow: none; }
.tl[data-look="dusk"] .tl-num { -webkit-text-stroke: 0; color: rgba(255, 255, 255, .06); }
.tl[data-look="dusk"] .tl-playhead { background: linear-gradient(to bottom, transparent, var(--tl-warn) 35%, var(--tl-warn)); box-shadow: none; }
.tl[data-look="dusk"] .tl-glyph, .tl[data-look="dusk"] .tl-find, .tl[data-look="dusk"] .tl-hud .tl-nav { background: #24272C; }
.tl[data-look="dusk"] .tl-find:focus-within { box-shadow: 0 0 0 3px rgba(156, 194, 169, .16); }
.tl[data-look="dusk"] .tl-fbtn.tl-mic[aria-pressed="true"] { animation-name: tl-listen-dusk; }
@keyframes tl-listen-dusk { from { box-shadow: 0 0 0 0 rgba(156, 194, 169, .5); } to { box-shadow: 0 0 0 14px rgba(156, 194, 169, 0); } }
.tl[data-look="dusk"] .tl-results { background: #24272C; box-shadow: 0 18px 40px rgba(0, 0, 0, .5); }
.tl[data-look="dusk"] .tl-tag.tl-hit { background: rgba(240, 222, 154, .15); }
.tl[data-look="dusk"] .tl-strip button[aria-current="true"] i, .tl[data-look="dusk"] .tl-strip button i .tl-hm { box-shadow: none; }
.tl[data-look="dusk"] .tl-reader { box-shadow: 0 16px 40px rgba(0, 0, 0, .45); -webkit-backdrop-filter: none; backdrop-filter: none; }
.tl[data-look="dusk"] .tl-drawer { background: #212428; box-shadow: -24px 0 50px rgba(0, 0, 0, .5); }
.tl[data-look="dusk"] .tl-flow .tl-flowrow { background: #2A2D33; box-shadow: 4px 4px 0 -1px rgba(0, 0, 0, .28), 8px 8px 0 -2px rgba(0, 0, 0, .18); }
/* ---- the look switch: three swatches, each half ground and half ink of its look ---- */
.tl-looks { display: inline-flex; align-items: center; gap: 7px; font-size: 12px; color: var(--tl-muted); }
.tl-looks button { width: 24px; height: 24px; padding: 0; border-radius: 50%; border: 2px solid var(--tl-holo-line); }
.tl-looks button[aria-current="true"] { border-color: var(--tl-ink); box-shadow: 0 0 0 2px var(--tl-bg), 0 0 0 4px var(--tl-holo); }
.tl-looks button[data-look="hologram"] { background: linear-gradient(135deg, #04070D 50%, #6BD2FF 50%); }
.tl-looks button[data-look="scholastic"] { background: linear-gradient(135deg, #F1E9D8 50%, #1F3A5F 50%); }
.tl-looks button[data-look="dusk"] { background: linear-gradient(135deg, #1B1D21 50%, #9CC2A9 50%); }

/* ==== In the console (2026-10-12). Everything from the first rule of .tl down to here is the sketch, ported
   (one thing in it is not as the sketch had it, and says so where it stands: where the lesson's panel is placed).
   Everything below is what the product needs that the sketch did not have. ==== */

/* The timeline is one block in the console's panel, as tall as the window below the console's tab bar, less 8px
   above it and below it; never less than 560px. --tl-top is where the tab bar ends: its height where it sticks to
   the top of the window, 0 where it scrolls away with the page (a phone). timeline-page.js measures it and, when
   the timeline is shown, scrolls the page so the block's top stands 8px under the bar: the whole block is then in
   view. 49px is the console's own figure for the bar (--tabs-h in console.css), until the page has measured.
   The height is said twice. On a phone 100vh is the window with the browser's own bars hidden, so the block's foot
   stood under the address bar; 100dvh is the window as it is now. A browser that does not know dvh drops the
   second line and keeps the first. */
.tl { position: relative; height: max(560px, calc(100vh - var(--tl-top, 49px) - 16px)); height: max(560px, calc(100dvh - var(--tl-top, 49px) - 16px)); border-radius: 10px; overflow: hidden;
  color: var(--tl-ink); font: 15px/1.45 var(--tl-sans); text-align: left; }
/* The console's Easy reading theme exists for readers who need Atkinson Hyperlegible. Under it the timeline's
   text stays in that face in every look: the scholastic look's serif and typewriter faces too, and the figures
   the other looks set in a system monospace. Three parts strong, so it outweighs each look's own choice. */
[data-theme="reading"] .tl, [data-theme="reading"] .tl[data-look] {
  --tl-sans: "Atkinson Hyperlegible", "Segoe UI", system-ui, sans-serif;
  --tl-mono: "Atkinson Hyperlegible", ui-monospace, Menlo, Consolas, monospace; }
/* Above the tab bar (20) and the docked player (40), under a dialog (50). */
.tl-drawer { z-index: 45; }
/* A finger moving up or down over the room scrolls the page. In the sketch the room was the whole page and took
   every touch (touch-action: none, above). A sideways swipe and two fingers pinching are still the room's own:
   timeline-room.js reads those itself, and lets go of a touch the browser takes (pointercancel). */
.tl-space { touch-action: pan-y; }

/* The bar: the way back, the course, Timeline | Details. */
.tl-id { display: grid; gap: 2px; min-width: 0; }
.tl-id h1 { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: min(46vw, 520px); }
.tl-bar .tl-up { justify-self: start; border: 0; background: none; padding: 0; font-size: 12.5px; color: var(--tl-holo);
  text-decoration: underline; text-underline-offset: 3px; }
.tl-faces { display: inline-flex; border: 1px solid var(--tl-holo-line); border-radius: 3px; overflow: hidden; }
.tl-faces .tl-chip { border: 0; border-radius: 0; }
/* A pressed chip keeps its filled ground and its own words in every look. Each look gives .tl-chip a ground of its
   own (paper in scholastic, a faint wash in dusk) with a selector three parts strong; the sketch's rule for a
   pressed chip is two parts strong and lost to it: the Timeline button and both highlights, when on, showed light
   words on a light ground in scholastic and dark on dark in dusk. This one is four parts strong, for whatever look
   the timeline is in. */
.tl[data-look] .tl-chip[aria-pressed="true"] { background: var(--tl-holo); border-color: var(--tl-holo); color: var(--tl-on-holo); }
.tl-chip.tl-todo[aria-expanded="true"] { background: var(--tl-warn-soft); }
/* A highlight that has nothing it could show yet (nobody has answered; the edit history could not be read) is
   drawn, and says why in its tooltip and its description. It is not `disabled`, so the keyboard reaches it. It is
   quiet by its colour and a dashed edge, not by fading: its words are there to be read, and at 60% they were
   3 to 1 against the bar. */
.tl-chip[aria-disabled="true"], .tl-chip[aria-disabled="true"]:hover { color: var(--tl-muted); border-style: dashed; cursor: default; }
/* The search field shows focus on its frame (.tl-find:focus-within), not with the console's ring on the input. */
.tl-find input:focus, .tl-find input:focus-visible { outline: none; box-shadow: none; }

/* A long lesson title is clipped by the stylesheet, never by the script: the whole title is in the page. */
.tl-card .tl-sl { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 4; align-items: flex-start; font-weight: 700; }
.tl-hud h2 { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; min-width: 0; max-width: 100%; }
.tl-results .tl-rn { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* A result's first column is where it is on the course, written with its unit ("1 h 07 min"): wider than the
   sketch's column, which held digits and a colon. */
.tl-results button { grid-template-columns: 78px minmax(0, 1fr); }
/* The bar's count of estimated lengths says what an estimate is in its tooltip, and shows that it has one. */
.tl-term span[title] { text-decoration: underline dotted; text-underline-offset: 3px; cursor: help; }
/* The first-visit line: one note across the bar, after its controls (and after them on a narrow screen, where
   the bar's parts are ordered), at the Course zoom until it is put away. */
.tl-first { order: 4; flex: 1 1 100%; display: flex; gap: 8px 16px; align-items: flex-start; justify-content: space-between;
  padding: 9px 12px; border: 1px solid var(--tl-holo-line); border-radius: 4px; background: var(--tl-holo-soft); font-size: 13.5px; color: var(--tl-ink); }
.tl-first p { margin: 0; max-width: 96ch; }
.tl-first .tl-btn { flex: none; padding: 5px 11px; font-size: 13px; }
/* A course that is not published: the marker in the bar, under the course's name, with the way to where a
   course is published. */
.tl-status { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 10px; font-size: 13px; font-weight: 700; color: var(--tl-warn); }
.tl-status .tl-link { font-size: 13px; font-weight: 700; }
/* The heading of a part of the lesson's panel with a way out beside it: "Edit this lesson" beside what plays,
   "Edit questions" beside the questions. */
.tl-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 6px 12px; margin: 0 0 8px; }
.tl-reader .tl-head h3 { margin: 0; }
.tl-head .tl-btn { flex: none; padding: 5px 11px; font-size: 13px; }
.tl-evidence .tl-link { font-weight: 700; }
/* Where a search found it, in the lesson's panel: the paragraph, or the questions, a picked result was in. It is
   marked in words too (the tag "search match"), not by the colour of an edge alone. */
.tl-para.tl-found { border-left-color: var(--tl-hit); }
.tl-para .tl-fm { grid-column: 2; justify-self: start; }
.tl-qa.tl-found { outline: 1px dashed var(--tl-hit); outline-offset: 6px; }
.tl-qa .tl-fm { display: inline-block; margin: 0 0 8px; }
/* The line under the room. In the Easy reading theme console.css narrows every paragraph to a reading column
   ([data-theme="reading"] p { max-width: 70ch }), which would pull this centred line to the left. */
.tl .tl-hint { max-width: none; }
/* At the deck distance that line is the time and the lesson's title, cut with an ellipsis when the title is long
   (the whole title is in the lesson's heading and in the card's name), and then what to do, which is never cut. */
.tl-hint.tl-read { display: flex; justify-content: center; white-space: normal; }
.tl-hint .tl-ht { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: pre; }
.tl-hint .tl-hr { flex: none; white-space: pre; }
/* On a phone: the title on one line, what to do on the next. */
.tl-space.tl-tall .tl-hint.tl-read { display: block; }
.tl-space.tl-tall .tl-hint .tl-ht { display: block; }
.tl-space.tl-tall .tl-hint .tl-hr { display: block; white-space: normal; }

/* The focus ring of a card is drawn in the card's own enlarged layout (see "sharp text" above), so it has to
   grow with the card, or on the card in hand it is a third as thick. */
.tl-card:focus-visible { outline-width: calc(2 * var(--tl-u)); outline-offset: calc(3 * var(--tl-u)); }

/* Changed since the original: a dashed edge, while that highlight is on. The edge is two of the card's own
   pixels wide (one, times the room's scale, was under a pixel on the screen), and its colour stays the card's own
   where the card has one to say something with (chosen, out of date, found by a search, where the class
   struggles). A card that is changed and nothing else had the look's plain edge, which hardly shows against the
   room (1.5 to 1 in the scholastic look, 1.7 in dusk): it takes the colour of the dashed tag, which passes 3 to 1. */
.tl-card.tl-changed { border-style: dashed; border-width: calc(2 * var(--tl-u)); }
.tl-card.tl-changed:not(.tl-sel):not(.tl-pop):not(.tl-held):not(.tl-todo):not(.tl-miss):not(.tl-hit):not(:hover) { border-color: var(--tl-ghost); }
.tl-tag.tl-changed { background: none; border: 1px dashed var(--tl-ghost); color: var(--tl-ink2); line-height: 15px; }
/* On a card every length is a multiple of --tl-u: the tag's edge and its line height with the rest. */
.tl-card .tl-tag.tl-changed { border-width: var(--tl-u); line-height: calc(15 * var(--tl-u)); }

/* The lesson in hand: a player, then what is said. Each paragraph is plain text to read; the second it starts
   stands in front of it and is the button that plays from there. (The headings of its parts are set where the
   panel is: .tl-reader h3, above.) */
.tl-video { display: block; box-sizing: border-box; width: 100%; aspect-ratio: 16 / 9; background: #000; border: 1px solid var(--tl-holo-line); border-radius: 4px; }
.tl-audio { display: block; width: 100%; }
.tl-what { margin: 8px 0 0; font-size: 13.5px; color: var(--tl-ink2); }
.tl-reader .tl-warn { margin: 6px 0 0; font-size: 13.5px; font-weight: 700; color: var(--tl-warn); }
.tl-paras { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; }
.tl-para { display: grid; grid-template-columns: 44px minmax(0, 1fr); gap: 10px; padding: 8px 10px; border-left: 2px solid transparent;
  border-radius: 3px; font-size: 16px; line-height: 1.5; }
.tl-para.tl-plays { cursor: pointer; }
.tl-para.tl-plays:hover { background: var(--tl-holo-soft); }
.tl-para .tl-pt { padding-top: 3px; font-size: 12px; font-weight: 600; color: var(--tl-holo); }
.tl-para button.tl-pt { justify-self: stretch; align-self: start; min-height: 24px; border: 0; background: none; padding: 3px 0 0; text-align: left; }
.tl-para button.tl-pt:hover, .tl-para button.tl-pt:focus-visible { text-decoration: underline; text-underline-offset: 3px; }
.tl-para .tl-px { grid-column: 2; }
.tl-para.is-speaking { background: var(--tl-holo-soft); border-left-color: var(--tl-holo); }
.tl-q + .tl-q { margin-top: 12px; }
.tl-card.tl-held .tl-cap { margin-top: auto; }
/* The play mark is an icon here, not a character as in the sketch, so it does not grow with the type: it has
   to be told to (see "sharp text" above: the card in hand is laid out --tl-k times larger). */
.tl-card .tl-glyph svg { width: calc(12 * var(--tl-u)); height: calc(12 * var(--tl-u)); }

/* With a lesson in hand she is reading or listening, and nothing in the room needs to move. The room's slow drift
   is paused there: paused, not taken off, so it holds the angle it had and goes on from it when she steps back.
   And the lesson's panel is not a pane of blurred glass: a browser works a backdrop blur out again for every
   frame of whatever moves behind it, for as long as she listens. (The panel is on the page only while a lesson
   is in hand, so that is all the time it is there.) In the hologram look, the one look that had the blur, the
   panel's ground is made nearly solid instead, so the room does not show through its words. */
.tl[data-level="lesson"] .tl-drift { animation-play-state: paused; }
.tl[data-level="lesson"] .tl-reader { -webkit-backdrop-filter: none; backdrop-filter: none; }
.tl[data-look="hologram"][data-level="lesson"] .tl-reader { background: rgba(12, 26, 42, .93); }

/* A course with no lessons: one sentence in the middle of the stage. The stage is not a grid (it holds the room,
   which is placed absolutely), so the sentence fills the stage as the room does and centres what it holds. */
.tl-none { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center;
  padding: 24px; text-align: center; color: var(--tl-ink2); }
.tl-none h2 { margin: 0 0 8px; max-width: 460px; font-size: 19px; color: var(--tl-ink); }
.tl-none p { margin: 0; max-width: 460px; }

/* Details: the same switch, on today's course page, in the console's own buttons. */
.face-switch { display: inline-flex; gap: 4px; }

/* ==== "Your outline": the course's stacks and lessons in a column beside whichever view is showing (step 1c of
   the faculty workspace, 2026-10-13; timeline-page.js, outlineColumn()). It is the page's own, not a view's.
   PROVISIONAL: the professor has not said whether the integrated page keeps it. TO TAKE IT OUT, delete this block
   down to "end of Your outline", and the rules marked "Your outline" in the three blocks below it (a narrow
   screen, a finger, forced colours). Where there is no column the block has no tl-with-col class and no node
   carries a tl-col class: none of these rules then applies, and the layout is the one above, untouched.
   IT STANDS HERE, before the narrow screen's block, because that block's rules for the column weigh what these
   do and must come later to win.
   ROOM FOR IT. On a wide screen the block gains a first column, 200 to 250px wide (the study's own 210 and 250),
   between the bar and the strip, which both still run the block's whole width. The column is placed there by
   the grid itself, being the block's first child after the bar; the stage, or the view's root, takes the second.
   ITS HEADING STAYS. The column itself does not scroll: it is its heading and, under it, its list, and the LIST
   is the box that scrolls (a long course scrolls inside it, not the page). So "Your outline" is still at the top
   when a later lesson has been brought into view, and nothing passes behind it: it stands on the block's own
   ground in each look. The list's padding is room for the focus ring, which stands 5px outside a button: a box
   that scrolls cuts what is outside it. ==== */
.tl.tl-with-col { grid-template-columns: clamp(200px, 18vw, 250px) minmax(0, 1fr); }
.tl.tl-with-col > .tl-bar { grid-column: 1 / -1; }
.tl.tl-with-col > .tl-strip { grid-column: 1 / -1; }
.tl .tl-col { display: flex; flex-direction: column; min-width: 0; min-height: 0; border-right: 1px solid var(--tl-holo-line); }
.tl .tl-col-head { flex: none; margin: 0; padding: 16px 16px 8px 18px; border-bottom: 1px solid var(--tl-holo-soft); font-size: 15px; color: var(--tl-ink); }
/* The lesson selector is the column's form on a narrow screen (below): on a wide one the list is the column.
   Its edge is the search field's, the stronger one: an edge is what shows that it is a control. Its type is 16px:
   a phone's browser enlarges the whole page when a field with smaller type takes the keyboard. It never grows past
   its row, whatever its longest title (the control shows one line of it; its list of options shows it whole). */
.tl .tl-col-choose { display: none; }
.tl .tl-col-choose label { flex: none; font-size: 13px; font-weight: 700; color: var(--tl-ink2); }
.tl .tl-col-choose select { flex: 1 1 auto; min-width: 0; max-width: 100%; box-sizing: border-box; border: 1px solid var(--tl-field-line); border-radius: 4px;
  padding: 6px 8px; font: 16px/1.3 var(--tl-sans); color: var(--tl-ink); background: var(--tl-bg); }
.tl .tl-col-list { flex: 1 1 auto; min-height: 0; overflow-y: auto; list-style: none; margin: 0; padding: 8px 10px 20px 12px;
  scrollbar-width: thin; scrollbar-color: var(--tl-holo-line) transparent; }
.tl .tl-col-lessons { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.tl .tl-col-stack + .tl-col-stack { margin-top: 8px; }
/* A stack's button opens and closes its lessons (its mark turns; nothing is animated). */
.tl .tl-col-toggle { display: flex; align-items: baseline; gap: 6px; width: 100%; border: 0; border-radius: 3px; background: none;
  padding: 6px 8px 6px 8px; text-align: left; font-size: 13px; color: var(--tl-ink2); }
.tl .tl-col-toggle:hover { background: var(--tl-holo-soft); }
.tl .tl-col-mark { flex: none; width: 12px; text-align: center; color: var(--tl-holo); }
.tl .tl-col-toggle[aria-expanded="true"] .tl-col-mark { transform: rotate(90deg); }
.tl .tl-col-name { min-width: 0; font-weight: 700; overflow-wrap: anywhere; }
/* A lesson: its number, then its title and its length in a box that takes what is left of the row, so a long
   title wraps inside the column, under itself, and is never cut. */
.tl .tl-col-pick { display: flex; align-items: baseline; gap: 8px; width: 100%; border: 0; border-radius: 3px; background: none;
  padding: 7px 8px 7px 11px; text-align: left; color: var(--tl-ink); }
.tl .tl-col-pick:hover { background: var(--tl-holo-soft); }
.tl .tl-col-num { flex: none; min-width: 18px; font: 600 12px var(--tl-mono); color: var(--tl-holo); }
.tl .tl-col-what { flex: 1 1 0; min-width: 0; display: grid; gap: 1px; }
.tl .tl-col-title { font-size: 14px; line-height: 1.3; overflow-wrap: anywhere; }
.tl .tl-col-len { font-size: 12px; color: var(--tl-ink2); }
/* THE SELECTED LESSON is shown by shapes, never by a colour alone: a bar down its left edge (taken from its
   padding, so nothing moves), a ground, its title heavier and underlined. A stack she has closed over the selected
   lesson keeps the same bar on its own button, so the selection is never without a sign in the column. */
.tl .tl-col-on .tl-col-pick { border-left: 3px solid var(--tl-holo); padding-left: 8px; background: var(--tl-holo-soft); }
.tl .tl-col-on .tl-col-title { font-weight: 700; text-decoration: underline; text-underline-offset: 3px; }
.tl .tl-col-toggle.tl-col-holds[aria-expanded="false"] { border-left: 3px solid var(--tl-holo); padding-left: 5px; }
/* ==== end of Your outline ==== */

/* ==== The paper the Outline holds (workspace-views.js; docs/faculty-workspace-contract.md, 4.2.1): the selected
   lesson, written out by another file, in a region of its own. Only where a paper is registered: all the Outline
   draws then stands in one block, .tl-outline-papered. With none, no node carries any of these classes and the
   Outline is laid out by its own rules, further down, as it always was.
   ON A WIDE SCREEN that block is as tall as the view, so the view has nothing to scroll: under the heading and
   the first line it is two columns, the tree and the paper's region, and each scrolls inside itself. The tree
   keeps a readable least width and the paper takes the larger share of the rest. (The view's root is a row of
   the timeline's grid, which gives it a height: that is what 100% is taken of. Where a browser would not take
   it, the block is as tall as what it holds and the view scrolls with both in it: nothing is lost.)
   THESE RULES STAND HERE, before the narrow screen's block, and not with the Outline's other rules: that block's
   rules for the paper weigh what these do, and must come later to win.
   None of them lays a ground or colours a text. What the paper draws is its author's; what the shell writes
   there (the sentence that the paper could not be drawn) is a .tl-face-fail, measured with every view's. ==== */
.tl .tl-face[data-face="outline"] .tl-outline-papered { height: 100%; min-height: 0; display: flex; flex-direction: column; }
.tl .tl-face[data-face="outline"] .tl-outline-papered > h2, .tl .tl-face[data-face="outline"] .tl-outline-papered > p { flex: none; }
.tl .tl-face[data-face="outline"] .tl-outline-split { flex: 1 1 auto; min-height: 0; display: grid; grid-template-columns: minmax(340px, 2fr) minmax(0, 3fr); gap: 0 18px; }
/* The tree's column. Its padding is room for the focus ring, which stands 5px outside a button (a box that
   scrolls cuts what is outside it); the same is taken back with a negative margin, so the tree stands where it
   stood. */
.tl .tl-face[data-face="outline"] .tl-outline-side { min-width: 0; min-height: 0; overflow-y: auto; padding: 6px; margin: -6px;
  scrollbar-width: thin; scrollbar-color: var(--tl-holo-line) transparent; }
/* The paper's region: a rule down its left edge sets it apart from the tree. "Go to the lesson" sends the
   keyboard to it, so that it can be scrolled without a pointer. Its focus ring is the page's own, 5px outside its
   edge: the view's padding and the gap between the two columns are the room for it. What it holds keeps 6px from
   its own edges, for the rings of the paper's controls. */
.tl .tl-face[data-face="outline"] .tl-outline-paper { min-width: 0; min-height: 0; overflow-y: auto; border-left: 1px solid var(--tl-holo-line);
  padding: 6px 6px 6px 18px; scrollbar-width: thin; scrollbar-color: var(--tl-holo-line) transparent; }
/* "Go to the lesson", after "Open" on the selected lesson: the same size as Open, in the middle of the row's height. */
.tl .tl-face[data-face="outline"] .tl-outline-to-paper { flex: none; align-self: center; padding: 5px 11px; font-size: 13px; }
/* The two stand in ONE group after the lesson, and the row may wrap. The lesson keeps at least 240px (never more
   than the row less the button before it, at its size under a finger, and the gap), and where that leaves the
   group no room it moves as one under the lesson's title, to the row's right edge. Beside the title in a tree
   column some 320px wide (a window 980 to 1100px wide), or on a phone, the two left it a column one word wide. */
.tl .tl-face[data-face="outline"] .tl-outline-papered .tl-outline-row { flex-wrap: wrap; }
.tl .tl-face[data-face="outline"] .tl-outline-papered .tl-outline-pick { flex-basis: min(240px, calc(100% - 48px)); }
.tl .tl-face[data-face="outline"] .tl-outline-acts { flex: none; align-self: center; display: flex; align-items: center; gap: 4px; margin-left: auto; }
/* ==== end of the paper the Outline holds ==== */

@media (max-width: 979px) {
  /* On a narrow screen the block is AT LEAST as tall as the window, and the room is never under 460px: the block
     grows past the window instead, and the page scrolls (a finger moving up or down over the room scrolls the
     page). Round C, 2026-10-13: with the bar's controls wrapped onto six rows, on a phone 375 by 812 the bar took
     472 of the block's 796px and left the room 265. A stack at its smallest scale needs some 370 (the room's
     layout: a heading, then 530 at half size), so its plate ran down into the line written at the room's foot.
     (It was a fixed height.) Round D made the bar three rows there (some 213px: see "narrow screens", above),
     so on that phone the room has its 460 without the block growing; on a shorter screen, with a long course
     name, a draft marker or the first-visit line showing, the block still grows as it did. */
  .tl { height: auto; min-height: max(520px, calc(100vh - var(--tl-top, 49px) - 16px)); min-height: max(520px, calc(100dvh - var(--tl-top, 49px) - 16px));
    grid-template-rows: auto minmax(460px, 1fr) auto; }
  /* With a lesson open the room holds the lesson's card and, under it, the panel she reads in: at 460 that panel
     was 204px tall on the same phone. At 600 it is some 330, about what it had before the bar grew. */
  .tl[data-level="lesson"] { grid-template-rows: auto minmax(600px, 1fr) auto; }
  /* The course's name takes two lines on a narrow screen, as the heading over the room does. */
  .tl-id h1 { max-width: calc(100vw - 24px); white-space: normal; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; }
  /* "Your outline" on a narrow screen (see its block, just above this one): ONE LESSON SELECTOR in a row of its
     own between the bar and the view. The block is one column again; the list and its heading are not drawn and
     the selector is. The view keeps the 460px a room is never under. (These rules weigh what the wide screen's
     do, and win by standing after them: the column's block must stay above this one. And the first stands after
     the rule for an open lesson, so it wins only where the column is drawn: never at the carousel's Lesson zoom,
     where the column steps aside and the room has its 600.) */
  .tl.tl-with-col { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto auto minmax(460px, 1fr) auto; }
  .tl .tl-col { padding: 8px 12px; border-right: 0; border-bottom: 1px solid var(--tl-holo-soft); }
  .tl .tl-col-head, .tl .tl-col-list { display: none; }
  .tl .tl-col-choose { display: flex; align-items: center; gap: 10px; }
  /* The paper the Outline holds, on a narrow screen (see its block, above this one): ONE COLUMN, the paper UNDER
     the tree with a rule over it. Nothing scrolls inside itself: the view grows and the page scrolls, as for every
     view here. Pressing a lesson brings the paper's top into view (workspace-views.js); it stops clear of the
     console's tab bar, which sticks to the top of the window. */
  .tl .tl-face[data-face="outline"] .tl-outline-papered { height: auto; display: block; }
  .tl .tl-face[data-face="outline"] .tl-outline-split { display: block; }
  .tl .tl-face[data-face="outline"] .tl-outline-side { overflow-y: visible; padding: 0; margin: 0; }
  .tl .tl-face[data-face="outline"] .tl-outline-paper { overflow-y: visible; border-left: 0; border-top: 1px solid var(--tl-holo-line); margin-top: 18px; padding: 16px 0 0;
    scroll-margin-top: calc(var(--tl-top, 49px) + 12px); }
}

/* ==== Every teacher can read it (round C, 2026-10-13). A review measured every text and every edge in the three
   looks (keyboard, screen reader, low vision, colour blindness, a phone, reduced motion). What follows, and the
   colours changed in the looks above, are what it found. The suite works each ratio out again from this file
   (its section 4c): text holds 4.5 to 1, an edge or a mark that is the only sign of a state 3 to 1. ==== */

/* The search field is known by its edge and its icon, so its edge is stronger than the bar's other edges (chips
   and the zoom buttons are named by their words). Its edge with the cursor in it (.tl-find:focus-within) still
   outweighs this. */
.tl-find { border-color: var(--tl-field-line); }
/* The time at the top of a card stands on the lightest part of the hologram card's gradient, in 11px type, and
   on the outermost cards under the room's vignette. A lighter blue, in that look only. */
.tl[data-look="hologram"] .tl-card .tl-tc { color: #B5E6FF; }
/* The selected search result: a bar down its left edge, a shape and not a tint alone. The cursor stays in the
   field while the arrow keys move through the results, so the row has no focus ring to show which it is. */
.tl-results button[aria-selected="true"] { box-shadow: inset 3px 0 0 var(--tl-holo); }
/* A stack's tags stand on a ground of their own: their tint, over the room's own colour, solid. The plate has
   none, and the pool of light on the floor under the selected stack (a shadow, in the scholastic look) is drawn
   right behind the plate's tag rows: taken through the room's transforms and its perspective, the pool's centre
   lands inside them at every size of room tried (1352 by 690 with 3 and with 10 stacks, 952 by 430, 1832 by 870).
   On that glow "out of date" was 3.5 to 1 in the hologram look and 3.2 in the scholastic one, the struggle tag
   2.8 and 3.5. (--tl-tint is the tag's tint. A look that gives a kind of tag a ground of its own, with a heavier
   rule, keeps it: the scholastic look's solid yellow for "N matches", and dusk's tint for it, which lies over a
   pool that is a shadow and so only gains.)
   THIS RULE WAS TAKEN OUT ONCE AND PUT BACK (2026-10-13). A measurement in a browser seemed to show the pool
   75px below the plate. It was taken in a tab that was not on the screen, where a browser holds every transition
   at its start: the plate and the pool were being measured where they stand before the room is first laid out. */
.tl-plate .tl-tag { background: linear-gradient(var(--tl-tint, var(--tl-holo-soft)), var(--tl-tint, var(--tl-holo-soft))), var(--tl-bg); }
.tl-plate .tl-tag.tl-warn { --tl-tint: var(--tl-warn-soft); }
.tl-plate .tl-tag.tl-miss { --tl-tint: var(--tl-struggle-soft); }
.tl-plate .tl-tag.tl-hit { --tl-tint: rgba(124, 243, 208, .16); }
.tl-plate .tl-tag.tl-changed { --tl-tint: transparent; }
/* The selected stack. Its plate showed it by the colour of its name alone (1.3 to 1 against an unselected one in
   the scholastic look, 1.5 in dusk): the rule over the plate is three pixels thick and the name is underlined,
   which are shapes. (The plate keeps its height: what the rule gains, the space under it gives up.) The room
   marks it for a screen reader, aria-current. */
.tl-plate.tl-sel { border-top-width: 3px; padding-top: 6px; }
.tl-plate.tl-sel .tl-n { text-decoration: underline; text-underline-offset: 3px; }
/* Two fingers on the lesson's text enlarge it: that is how a reader with low vision reads 16px type on a phone.
   The sketch gave the panel, and the room it stands in, touch-action: pan-y, which takes the browser's own zoom
   away; and a browser counts the room's rule too, whatever the panel's says (a pinch is looked up through every
   ancestor, a scroll only as far as what scrolls). So the panel allows it, and so does the room for as long as a
   lesson's panel is open in it. Over the room itself, with a lesson open, two fingers are then the browser's as
   well in most browsers: the Zoom buttons and Esc zoom out. The room does not count a touch that begins in the
   panel toward its own pinch or swipe (timeline-room.js). */
.tl-reader { touch-action: pan-y pinch-zoom; }
.tl[data-level="lesson"] .tl-space { touch-action: pan-y pinch-zoom; }

/* The focus ring. Timeline | Details and the zoom buttons stand in frames that cut what is outside them
   (overflow: hidden, for their rounded corners), and the ring is drawn 3px outside a button: all that showed of
   it was one upright stroke. On those it is drawn inside the button. The search field's frame showed the cursor
   by one pixel of colour; it takes the same ring as everything else. And a look's swatch has its ring outside
   the ring that marks the look in use, which reaches 4px, so the two can be told apart. */
.tl-zoom button:focus-visible, .tl-faces .tl-chip:focus-visible { outline-offset: -3px; }
.tl-find:focus-within { outline: 2px solid var(--tl-holo); outline-offset: 2px; }
.tl-looks button:focus-visible { outline-offset: 6px; }
/* A ring drawn INSIDE a control stands on that control's own ground. The pressed one of Timeline | Details is
   filled with the look's ink, which is the ring's colour: 1 to 1, a ring nobody could see, on a chip that is
   always pressed and is a tab stop. There the ring is the colour the chip's words are (round D). */
.tl-faces .tl-chip[aria-pressed="true"]:focus-visible { outline-color: var(--tl-on-holo); }

/* What the review of round C found (round D, 2026-10-13).
   THE ROOM'S VIGNETTE is drawn over the cards and the plates, words and grounds alike, and takes a little from
   every ratio where it is strongest: at the outermost stacks, and most of all in a wide, short room (a 1366 by
   768 laptop), where the plates hang near the corner. It ends at .30 in the hologram look (it was .45) and at
   .07 in the scholastic one (it was .17: .10 holds "N narrations out of date" at 4.5 to 1 in a room 1352 by
   690, and not in one 1352 by 460). Dusk keeps its vignette and takes a lighter struggle colour (#CDB2E1 for
   #C6A8DC): its struggle tag on a lesson a search did not find was 4.3 there whatever the vignette. The suite
   lays each look's vignette, as strong as the room's own layout lets it stand over a tag, over every kind of
   tag on plates and cards, and over the ground of the line under the room.
   A MATCH'S MARK ON THE STRIP, on the track of the selected stack, stood on the look's ink in the colour of a
   match (1.3 to 1 in the hologram look, 2.3 and 1.5 in the others). There it takes an edge in the colour that
   words on that ink are. */
.tl-strip button[aria-current="true"] i .tl-hm { outline: 1px solid var(--tl-on-holo); }

/* ==== The faculty workspace (2026-10-13): one course, several views of it. Drawn only while the install's
   faculty_workspace switch is on as well as course_timeline: timeline-page.js then puts a row of views in the
   bar and, where the stage stands, the root of the view that is showing (.tl-face, with data-face="its name").
   No node carries any of these classes otherwise.
   A VIEW'S OWN RULES all begin .tl .tl-face[data-face="its name"], and every class it adds is tl-<its name>-...:
   that is what keeps two teams' views out of each other's way (docs/faculty-workspace-contract.md). A view reads
   its colours from the --tl-... properties, so the three looks dress it without a rule per look. ==== */

/* The row of views: across the bar, under its controls and over the first-visit line. Six buttons do not fit a
   phone, so at every width it is ONE row that scrolls sideways inside itself (the page never does), as the tools
   are on a narrow screen and with what was learned there: the scrollbar is not hidden; the row keeps 6px above
   and below and 8px at each end for the focus ring, which stands 5px outside a button, and takes the same back
   with a negative margin, so that room costs the bar nothing; and a button the keyboard reaches is brought clear
   of the row's ends. Its buttons are chips: the one that is pressed is filled, as the pressed one of
   Timeline | Details is, in every look. */
.tl .tl-views { order: 4; flex: 1 1 100%; max-width: 100%; display: flex; gap: 6px; overflow-x: auto; overflow-y: hidden;
  padding: 6px 8px; margin: -6px -8px; scroll-padding: 0 8px; scrollbar-width: thin; scrollbar-color: var(--tl-holo-line) transparent; }
.tl .tl-views > * { flex: none; }
.tl .tl-view { white-space: nowrap; }

/* The view that is showing stands in the block's middle row, where the stage stands on the carousel (the stage
   is hidden then, not taken apart). On a wide screen the block is as tall as the window, so a long view scrolls
   inside itself; on a narrow one the block grows and the page scrolls. Its ground is the block's own. What
   follows is the plain type every view starts from; a view's own rules outweigh it. */
.tl .tl-face { min-height: 0; overflow-y: auto; padding: 18px 20px 28px; scrollbar-width: thin; scrollbar-color: var(--tl-holo-line) transparent; }
.tl .tl-face h2 { margin: 0 0 6px; font-size: 19px; color: var(--tl-ink); }
.tl .tl-face p { margin: 0 0 14px; max-width: 72ch; color: var(--tl-ink2); }
/* A view that could not be drawn says so, in the colour of a warning and in heavier type. */
.tl .tl-face .tl-face-fail { color: var(--tl-warn); font-weight: 700; }
/* A tag in a view stands on a ground of its own, as on a stack's plate: its tint over the block's own solid
   colour, so the wash behind the view takes nothing from its words. And it is larger than on a card, where
   every tag shares one short line. */
.tl .tl-face .tl-tag { font-size: 12px; line-height: 20px; background: linear-gradient(var(--tl-tint, var(--tl-holo-soft)), var(--tl-tint, var(--tl-holo-soft))), var(--tl-bg); }
.tl .tl-face .tl-tag.tl-warn { --tl-tint: var(--tl-warn-soft); }
.tl .tl-face .tl-tag.tl-miss { --tl-tint: var(--tl-struggle-soft); }
.tl .tl-face .tl-tag.tl-changed { --tl-tint: transparent; line-height: 18px; }
/* A picture a view shows through ctx.image (workspace.js makes the node and gives it this class, the only node in the
   console that has it). It has no size of its own, so the shell gives it one: never wider than the box it stands in,
   as tall as that width makes it, on a line of its own. A view sizes a picture by putting it inside an element of its
   own that its stylesheet sizes, and sets nothing on the node. (The span that stands in for one that failed is
   .tl-picture-alt, a different class: this rule does not reach it.) */
.tl .tl-face .tl-picture { max-width: 100%; height: auto; display: block; }

/* The Outline (workspace-views.js): the course's stacks, each stack's lessons, each lesson's parts. A tree
   to read, made of plain buttons: one opens and closes what is under it (its mark turns; nothing is animated),
   one selects a lesson. THE SELECTED LESSON is shown by shapes, never by a colour alone: a bar down its left
   edge (taken from its padding, so nothing moves), its title heavier and underlined, and its "Open" button. */
.tl .tl-face[data-face="outline"] .tl-outline-stacks { list-style: none; margin: 0; padding: 0; display: grid; gap: 4px; max-width: 980px; }
.tl .tl-face[data-face="outline"] .tl-outline-stack h3 { margin: 0; font-size: 15px; }
.tl .tl-face[data-face="outline"] .tl-outline-toggle { display: inline-flex; flex-wrap: wrap; align-items: center; align-content: center; gap: 2px 12px;
  border: 0; border-radius: 3px; background: none; padding: 6px 10px 6px 4px; text-align: left; color: var(--tl-ink); }
.tl .tl-face[data-face="outline"] .tl-outline-toggle:hover, .tl .tl-face[data-face="outline"] .tl-outline-pick:hover { background: var(--tl-holo-soft); }
.tl .tl-face[data-face="outline"] .tl-outline-mark { flex: none; width: 14px; text-align: center; color: var(--tl-holo); }
.tl .tl-face[data-face="outline"] .tl-outline-toggle[aria-expanded="true"] .tl-outline-mark { transform: rotate(90deg); }
.tl .tl-face[data-face="outline"] .tl-outline-name { font-weight: 700; }
.tl .tl-face[data-face="outline"] .tl-outline-meta { font-size: 13px; font-weight: 400; color: var(--tl-ink2); }
.tl .tl-face[data-face="outline"] .tl-outline-lessons { list-style: none; margin: 2px 0 8px 18px; padding: 0; display: grid; gap: 2px; }
.tl .tl-face[data-face="outline"] .tl-outline-row { display: flex; align-items: flex-start; gap: 4px; }
.tl .tl-face[data-face="outline"] .tl-outline-row .tl-outline-toggle { flex: none; justify-content: center; width: 26px; padding: 6px 0; }
.tl .tl-face[data-face="outline"] .tl-outline-none { flex: none; width: 26px; }
.tl .tl-face[data-face="outline"] .tl-outline-pick { flex: 1 1 auto; min-width: 0; display: flex; flex-wrap: wrap; align-items: baseline; align-content: center; gap: 2px 10px;
  border: 0; border-radius: 3px; background: none; padding: 6px 10px; text-align: left; color: var(--tl-ink); }
.tl .tl-face[data-face="outline"] .tl-outline-num { flex: none; min-width: 22px; font: 600 12px var(--tl-mono); color: var(--tl-holo); }
/* A lesson's title, where it is on the course, how long it runs and its marks stand in a box beside its number.
   The box starts from no width and takes what is left of the row, so it never drops under the number; a long
   title wraps inside it. */
.tl .tl-face[data-face="outline"] .tl-outline-what { flex: 1 1 0; min-width: 0; display: flex; flex-wrap: wrap; align-items: baseline; gap: 2px 10px; }
.tl .tl-face[data-face="outline"] .tl-outline-title { font-size: 15px; }
.tl .tl-face[data-face="outline"] .tl-outline-on .tl-outline-pick { border-left: 3px solid var(--tl-holo); padding-left: 7px; background: var(--tl-holo-soft); }
.tl .tl-face[data-face="outline"] .tl-outline-on .tl-outline-title { font-weight: 700; text-decoration: underline; text-underline-offset: 3px; }
.tl .tl-face[data-face="outline"] .tl-outline-open { flex: none; align-self: center; padding: 5px 11px; font-size: 13px; }
.tl .tl-face[data-face="outline"] .tl-outline-parts { list-style: none; margin: 0 0 6px 30px; padding: 2px 0 2px 12px; border-left: 1px solid var(--tl-holo-line);
  display: grid; gap: 4px; font-size: 13.5px; color: var(--tl-ink2); }
.tl .tl-face[data-face="outline"] .tl-outline-parts li { display: grid; grid-template-columns: 44px minmax(0, 1fr); gap: 10px; }
.tl .tl-face[data-face="outline"] .tl-outline-parts .tl-stamp { padding-top: 1px; font-size: 12px; font-weight: 600; color: var(--tl-holo); }
.tl .tl-face[data-face="outline"] .tl-outline-words { grid-column: 2; }
/* What a highlight adds to a row (the Outline draws the two highlights): tags in words, among the row's own.
   Their holder is not a box of its own: the tags in it are laid out as the row's own, and an empty holder
   takes no room and makes no gap. */
.tl .tl-face[data-face="outline"] .tl-outline-marks { display: contents; }
/* The sentence over the tree that the group's figures could not be read: in the block's own ink and heavier
   type, with a bar in the colour of a warning down its edge (a shape beside the words, not a colour alone). */
.tl .tl-face[data-face="outline"] .tl-outline-note { margin: 0 0 10px; border-left: 3px solid var(--tl-warn); padding: 4px 10px; font-weight: 600; color: var(--tl-ink); }

/* A finger. Where the pointer is a finger, or the layout is a phone's, every control is at least 44 by 44 CSS
   pixels (they were 23 to 33 high). Not on a wide screen with a mouse: nothing outside this block is enlarged.
   The round ones (a look's swatch, the search field's clear and microphone buttons) keep their size and take a
   larger area to press (44px for a swatch, 48 for the others), and stand far enough apart that those areas do
   not overlap. A link's words stand in the middle of its height (and the arrow of "All courses" keeps its
   distance from them: as a flex item its trailing space is not drawn). */
@media (pointer: coarse), (max-width: 979px) {
  .tl-chip, .tl-zoom button, .tl-btn, .tl-strip button, .tl-para button.tl-pt { min-height: 44px; }
  .tl-zoom button { min-width: 44px; }
  .tl-find { height: 42px; }                                 /* with its 1px edge above and below: 44 (it was 40) */
  .tl-strip button { padding: 11px 0 10px; }
  .tl-up, .tl-link { min-height: 44px; min-width: 44px; display: inline-flex; align-items: center; gap: .35em; }
  .tl-hud .tl-nav { min-width: 44px; min-height: 44px; }
  .tl-looks { gap: 20px; }
  .tl-looks button, .tl-fbtn { position: relative; }
  .tl-looks button::after, .tl-fbtn::after { content: ""; position: absolute; inset: -10px; }
  /* The area is placed from INSIDE the button's edge. A swatch is 24px with a 2px edge (a button is sized by its
     outer edge here), so 20px inside it: 10px out each way was 40, not 44. Twelve is 44. (The search field's
     round buttons have no edge: 28 and ten each way.) */
  .tl-looks button::after { inset: -12px; }
  .tl-find .tl-fbtn + .tl-fbtn { margin-left: 16px; }
  /* "Play from 1:52" is 44px tall here, and a button stands its words in the middle of its height: 10px below
     the first line of the paragraph they belong to. Its words start at its top, as they do on a wide screen
     (its 3px of padding puts their baseline on the first line's); the 44px to press stay. */
  .tl-para button.tl-pt { display: flex; align-items: flex-start; }
  /* The workspace. The row of views is made of chips, which are 44px here already. The Outline's buttons: the one
     that opens a stack and the one that selects a lesson are as tall, the small one that opens a lesson's
     paragraphs as wide too (and the gap that stands for it on a lesson with none, so the titles stay in line). */
  .tl .tl-face[data-face="outline"] .tl-outline-toggle, .tl .tl-face[data-face="outline"] .tl-outline-pick { min-height: 44px; }
  .tl .tl-face[data-face="outline"] .tl-outline-row .tl-outline-toggle, .tl .tl-face[data-face="outline"] .tl-outline-none { min-width: 44px; }
  /* "Your outline": a stack's button, a lesson's, and the lesson selector are as tall under a finger. */
  .tl .tl-col-toggle, .tl .tl-col-pick, .tl .tl-col-choose select { min-height: 44px; }
}

/* Windows high contrast (forced colours). The system takes away grounds, shadows and the looks' colours, and
   four states were shown by a ground or a shadow alone: a pressed chip, the look in use, the selected search
   result, the selected stack. Each keeps an edge, in the system's own colours. (An edge that is transparent
   elsewhere is drawn in full there: every paragraph of a lesson would get the bar of the one being spoken.) */
@media (forced-colors: active) {
  .tl[data-look] .tl-chip[aria-pressed="true"] { border: 2px solid Highlight; }
  .tl-looks button[aria-current="true"] { border: 4px solid Highlight; }
  .tl-results button[aria-selected="true"] { outline: 2px solid Highlight; outline-offset: -2px; }
  .tl-plate.tl-sel { border-top-color: Highlight; }
  .tl-para { border-left-color: Canvas; }
  .tl-para.is-speaking { border-left-color: Highlight; }
  .tl .tl-face[data-face="outline"] .tl-outline-on .tl-outline-pick { border-left-color: Highlight; }
  .tl .tl-col-on .tl-col-pick { border-left-color: Highlight; }      /* "Your outline": the selected lesson's bar */
}
