/* TopGoal ESL — teacher console
   ─────────────────────────────────────────────────────────────────────────────
   Visual language adapted from creative-card-portfolio-project-2.vercel.app:
   Geist, a near-black / pure-white ground, dashed hairline column rules as the
   structural signature, one jade accent, and content sitting directly on the
   ground instead of inside cards.

   Light is the default on purpose. The scene is a teacher standing in a sunlit
   Saudi classroom at 07:45, phone in hand, marking 34 boys before the bell —
   glare beats mood, so dark ink on white wins. The OS preference and the manual
   toggle both still switch it.

   The reference's dashed rule is reused semantically here, not decoratively:
   dashed = not yet recorded, solid = recorded.                                */

/* ──────────────────────────────────────────────────────────────── tokens */

:root {
  /* ground + ink */
  --bg:        oklch(1 0 0);
  --bg-2:      oklch(0.978 0.001 250);        /* toolbars, panels, table heads */
  --ink:       oklch(0.185 0.004 250);
  --ink-2:     oklch(0.42 0.008 250);
  --ink-3:     oklch(0.52 0.008 250);          /* 5.6:1 on white — passes body */
  --rule:      oklch(0.185 0.004 250 / 0.13);
  --rule-firm: oklch(0.185 0.004 250 / 0.24);

  /* accent — jade, from the reference (#1F9D74), darkened from L 0.60 to 0.545
     so that white pill text clears 4.5:1 instead of the reference's 3.75:1 */
  --accent:    oklch(0.545 0.12 165);
  --accent-ink: oklch(0.44 0.10 165);          /* accent text on light ground */
  --accent-wash: oklch(0.545 0.12 165 / 0.11);
  --on-accent: oklch(1 0 0);

  /* attendance — present is deliberately uncoloured; only exceptions carry hue */
  --absent:    oklch(0.55 0.19 25);
  --absent-wash:  oklch(0.55 0.19 25 / 0.09);
  --late:      oklch(0.66 0.15 65);
  --late-wash:    oklch(0.66 0.15 65 / 0.12);
  --excused:   oklch(0.55 0.12 250);
  --excused-wash: oklch(0.55 0.12 250 / 0.10);

  /* type */
  --font:      "Geist", "IBM Plex Sans Arabic", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-ar:   "IBM Plex Sans Arabic", "Geist", system-ui, "Segoe UI", sans-serif;
  --font-mono: "Geist Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  --t-display: 3.25rem;   /* view title */
  --t-h1:      2rem;
  --t-h2:      1.375rem;
  --t-h3:      1.0625rem;
  --t-body:    0.9375rem;
  --t-small:   0.8125rem;
  --t-micro:   0.6875rem;

  /* space — 4px base, varied on purpose */
  --s1: 4px; --s2: 8px; --s3: 12px; --s4: 16px; --s5: 24px; --s6: 32px; --s7: 48px; --s8: 72px;

  --radius:    10px;
  --radius-sm: 7px;
  --pill:      999px;

  /* motion */
  --out:      cubic-bezier(0.22, 1, 0.36, 1);   /* ease-out-quint */
  --fast:     140ms;
  --mid:      200ms;

  /* semantic z scale — never arbitrary */
  --z-rules: 0; --z-sticky: 20; --z-scrim: 40; --z-drawer: 50; --z-toast: 60;
}

:root[data-theme="dark"],
html:not([data-theme="light"]) {
  color-scheme: light;
}

@media (prefers-color-scheme: dark) {
  html:not([data-theme="light"]) {
    --bg:        oklch(0.145 0.005 255);
    --bg-2:      oklch(0.185 0.006 255);
    --ink:       oklch(0.965 0.002 100);
    --ink-2:     oklch(0.78 0.005 255);
    --ink-3:     oklch(0.66 0.006 255);
    --rule:      oklch(1 0 0 / 0.13);
    --rule-firm: oklch(1 0 0 / 0.24);
    --accent:    oklch(0.70 0.13 165);
    --accent-ink: oklch(0.80 0.13 165);
    --accent-wash: oklch(0.70 0.13 165 / 0.14);
    --on-accent: oklch(0.16 0.02 165);
    --absent:    oklch(0.66 0.17 25);
    --absent-wash:  oklch(0.66 0.17 25 / 0.14);
    --late:      oklch(0.76 0.14 70);
    --late-wash:    oklch(0.76 0.14 70 / 0.14);
    --excused:   oklch(0.70 0.11 250);
    --excused-wash: oklch(0.70 0.11 250 / 0.14);
    color-scheme: dark;
  }
}

html[data-theme="dark"] {
  --bg:        oklch(0.145 0.005 255);
  --bg-2:      oklch(0.185 0.006 255);
  --ink:       oklch(0.965 0.002 100);
  --ink-2:     oklch(0.78 0.005 255);
  --ink-3:     oklch(0.66 0.006 255);
  --rule:      oklch(1 0 0 / 0.13);
  --rule-firm: oklch(1 0 0 / 0.24);
  --accent:    oklch(0.70 0.13 165);
  --accent-ink: oklch(0.80 0.13 165);
  --accent-wash: oklch(0.70 0.13 165 / 0.14);
  --on-accent: oklch(0.16 0.02 165);
  --absent:    oklch(0.66 0.17 25);
  --absent-wash:  oklch(0.66 0.17 25 / 0.14);
  --late:      oklch(0.76 0.14 70);
  --late-wash:    oklch(0.76 0.14 70 / 0.14);
  --excused:   oklch(0.70 0.11 250);
  --excused-wash: oklch(0.70 0.11 250 / 0.14);
  color-scheme: dark;
}

/* ───────────────────────────────────────────────────────────────── base */

* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0; min-height: 100dvh;
  background: var(--bg); color: var(--ink);
  font-family: var(--font); font-size: var(--t-body); line-height: 1.55;
  font-feature-settings: "cv11", "ss01";
  -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility;
}
body[dir="rtl"] { font-family: var(--font-ar); }

h1, h2, h3, h4 { margin: 0; font-weight: 650; line-height: 1.15; letter-spacing: -0.022em; }
h1 { font-size: var(--t-h1); }
h2 { font-size: var(--t-h2); }
h3 { font-size: var(--t-h3); letter-spacing: -0.012em; }
p  { margin: 0; }
button, input, select, textarea { font: inherit; color: inherit; }
a { color: var(--accent-ink); text-underline-offset: 2px; }

:where(button, a, input, select, textarea, [tabindex]):focus-visible {
  outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 3px;
}

.mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; letter-spacing: -0.01em; }
.muted { color: var(--ink-3); }
.small { font-size: var(--t-small); }
.micro { font-size: var(--t-micro); }
.row { display: flex; align-items: center; gap: var(--s3); flex-wrap: wrap; }
.spread { display: flex; align-items: center; justify-content: space-between; gap: var(--s4); flex-wrap: wrap; }
.prose { max-width: 68ch; text-wrap: pretty; }

/* ──────────────────────────────────────────────── the dashed column rules */

/* The signature. Full-height dashed hairlines at the quarter columns, sitting
   behind everything, clipped to the content width so they never touch the
   viewport edge on wide screens. */
.rules {
  position: fixed; inset: 0; z-index: var(--z-rules); pointer-events: none;
  max-width: 1280px; margin: 0 auto;
}
.rules i {
  position: absolute; top: 0; bottom: 0; width: 0;
  border-left: 1px dashed var(--rule);
}
.rules i:nth-child(1) { left: 0; }
.rules i:nth-child(2) { left: 25%; }
.rules i:nth-child(3) { left: 50%; }
.rules i:nth-child(4) { left: 75%; }
.rules i:nth-child(5) { left: calc(100% - 1px); }
@media (max-width: 700px) { .rules i:nth-child(2), .rules i:nth-child(4) { display: none; } }

/* ──────────────────────────────────────────────────────────────── chrome */

.topbar {
  position: sticky; top: 0; z-index: var(--z-sticky);
  display: flex; align-items: center; gap: var(--s4);
  padding: var(--s3) var(--s5);
  background: color-mix(in oklab, var(--bg) 88%, transparent);
  backdrop-filter: saturate(140%) blur(12px);
  border-bottom: 1px dashed var(--rule);
}
.mark { display: flex; align-items: baseline; gap: var(--s2); min-width: 0; flex: 0 1 auto; }
.mark h1 { font-size: 0.9375rem; font-weight: 600; letter-spacing: -0.02em; white-space: nowrap; }
.mark .sub {
  font-size: var(--t-small); color: var(--ink-3); min-width: 0; max-width: 32ch;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
@media (max-width: 1024px) { .mark .sub { display: none; } }

/* Right-aligned with an auto margin rather than justify-content: flex-end, so
   that when the list is wider than its box the overflow scrolls from its natural
   start instead of spilling over the wordmark. */
.nav {
  display: flex; gap: var(--s4); flex: 0 1 auto; min-width: 0;
  margin-inline-start: auto; padding-inline-start: var(--s4);
  overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.nav::-webkit-scrollbar { display: none; }
.nav button {
  background: none; border: 0; padding: 2px 0; cursor: pointer; white-space: nowrap;
  font-size: var(--t-small); color: var(--ink-2);
  transition: color var(--fast) var(--out);
}
@media (min-width: 1181px) { .nav button { font-size: var(--t-body); } }

/* On a phone the nav gets its own scrollable row; nothing overlaps and the
   theme / sign-out controls stay reachable with a thumb. */
@media (max-width: 760px) {
  .topbar { flex-wrap: wrap; row-gap: var(--s2); padding-inline: var(--s4); }
  .chrome-actions { order: 2; margin-inline-start: auto; }
  .nav {
    order: 3; flex: 1 0 100%; margin-inline-start: 0; padding-inline-start: 0;
    padding-top: var(--s2); border-top: 1px dashed var(--rule);
  }
  main { padding: var(--s6) var(--s4) var(--s8); }
  .section { margin-top: var(--s7); }
}
.nav button:hover { color: var(--ink); }
/* Active state borrowed from the reference: the current page is struck through. */
.nav button[aria-current="page"] {
  color: var(--ink-3); text-decoration: line-through; text-decoration-thickness: 1.5px;
}

.chrome-actions { display: flex; align-items: center; gap: var(--s2); flex: none; }
.icon-btn {
  width: 32px; height: 32px; display: grid; place-items: center; cursor: pointer;
  background: none; border: 1px solid var(--rule); border-radius: var(--pill);
  color: var(--ink-2); transition: border-color var(--fast) var(--out), color var(--fast) var(--out);
}
.icon-btn:hover { border-color: var(--rule-firm); color: var(--ink); }
.lang-btn {
  background: none; border: 0; cursor: pointer; padding: 2px 4px;
  font-size: var(--t-small); color: var(--ink-3); letter-spacing: .02em;
}
.lang-btn:hover { color: var(--ink); }

.pill {
  display: inline-flex; align-items: center; gap: var(--s2); cursor: pointer;
  background: var(--accent); color: var(--on-accent); border: 0;
  border-radius: var(--pill); padding: 9px 18px;
  font-size: var(--t-body); font-weight: 550; white-space: nowrap;
  transition: filter var(--fast) var(--out), transform var(--fast) var(--out);
}
.pill:hover { filter: brightness(1.07); }
.pill:active { transform: translateY(1px); }
.pill[disabled] { opacity: .5; cursor: progress; }

.ghost {
  background: none; border: 1px solid var(--rule); border-radius: var(--pill);
  padding: 8px 15px; cursor: pointer; font-size: var(--t-small); color: var(--ink-2);
  transition: border-color var(--fast) var(--out), color var(--fast) var(--out);
}
.ghost:hover { border-color: var(--rule-firm); color: var(--ink); }

main {
  position: relative; z-index: 1;
  max-width: 1280px; margin: 0 auto;
  padding: var(--s7) var(--s5) var(--s8);
}

/* Section: a firm rule and a title, no box. */
.section { margin-top: var(--s8); }
.section > header {
  display: flex; align-items: baseline; gap: var(--s4); flex-wrap: wrap;
  padding-bottom: var(--s3); margin-bottom: var(--s5);
  border-bottom: 1px solid var(--rule-firm);
}
.section > header h2 { font-size: var(--t-h2); }

.block { padding: var(--s5) 0; border-top: 1px dashed var(--rule); }
.block:first-of-type { border-top: 0; }

.tag {
  display: inline-block; padding: 3px 9px; border-radius: var(--pill);
  font-size: var(--t-micro); font-weight: 600; letter-spacing: .01em;
  background: var(--accent-wash); color: var(--accent-ink);
}
.tag.flat { background: none; border: 1px solid var(--rule-firm); color: var(--ink-3); }
.tag.warn { background: var(--late-wash); color: var(--late); }

/* ───────────────────────────────────────────────────────────────── login */

.login-wrap { display: grid; place-items: center; min-height: 62vh; }
.login { width: min(420px, 100%); }
.login h2 { font-size: var(--t-h1); margin-bottom: var(--s3); }
.login .field-line {
  display: flex; align-items: center; gap: var(--s3);
  margin-top: var(--s6); padding-bottom: var(--s3);
  border-bottom: 1px solid var(--rule-firm);
}
.login input {
  flex: 1; min-width: 0; background: none; border: 0; padding: 4px 0;
  font-size: 1.125rem; color: var(--ink);
}
.login input:focus { outline: 0; }
.login .field-line:focus-within { border-bottom-color: var(--accent); }
.err { color: var(--absent); font-size: var(--t-small); margin-top: var(--s3); }

/* ───────────────────────────────────────────────────────────────── today */

.hero { padding-bottom: var(--s6); border-bottom: 1px solid var(--rule-firm); }
.hero .live {
  display: inline-flex; align-items: center; gap: var(--s2);
  font-size: var(--t-small); color: var(--ink-3); letter-spacing: .01em;
}
.hero .live .dot {
  width: 7px; height: 7px; border-radius: var(--pill); background: var(--accent);
}
@media (prefers-reduced-motion: no-preference) {
  .hero .live.on .dot { animation: pulse 2.4s var(--out) infinite; }
}
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }

.hero .headline {
  font-size: clamp(2.25rem, 7vw, var(--t-display));
  font-weight: 700; letter-spacing: -0.035em; line-height: 0.95;
  margin: var(--s3) 0 var(--s4); text-wrap: balance;
}
.hero .headline .dim { color: var(--ink-3); }
.hero .meta { font-size: var(--t-body); color: var(--ink-2); }

/* The day, as a row of rule-separated columns — not cards. */
.daystrip {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(132px, 1fr));
  border-top: 1px solid var(--rule-firm);
}
.slot {
  display: flex; flex-direction: column; gap: 2px; align-items: flex-start;
  padding: var(--s4) var(--s3) var(--s5);
  background: none; border: 0; border-inline-end: 1px dashed var(--rule);
  cursor: pointer; text-align: start;
  transition: background var(--fast) var(--out);
}
.slot:last-child { border-inline-end: 0; }
.slot:hover { background: var(--bg-2); }
.slot .p { font-size: var(--t-micro); color: var(--ink-3); letter-spacing: .04em; white-space: nowrap; }
.slot .c { font-size: 1.25rem; font-weight: 650; letter-spacing: -0.02em; }
.slot .t { font-size: var(--t-small); color: var(--ink-3); }
.slot.free { cursor: default; }
.slot.free .c { color: var(--ink-3); font-weight: 400; }
.slot.free:hover { background: none; }
.slot.now { background: var(--accent-wash); }
.slot.now .c { color: var(--accent-ink); }

/* A duty period is not a free one — he is on the corridor, not at his desk. */
.slot.duty { cursor: default; background: var(--late-wash); }
.slot.duty:hover { background: var(--late-wash); }
.slot.duty .c { color: var(--late); font-weight: 550; }

/* The break is drawn between the periods it separates, not as one of them. */
.slot.brk {
  cursor: default; flex: 0 0 auto; min-width: 92px; background: var(--bg-2);
  border-inline-end: 1px dashed var(--rule);
}
.slot.brk:hover { background: var(--bg-2); }
.slot.brk .c { font-family: var(--font-mono); font-size: 1rem; color: var(--ink-3); font-weight: 400; }

/* ─────────────────────────────────────────────────────────────── classes */

/* Two columns on wide screens, the way the reference stacks its link lists —
   a single full-width row leaves a lake of dead space between name and count. */
.class-list {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
  column-gap: var(--s7); border-top: 1px solid var(--rule-firm);
}
.class-row {
  display: grid; grid-template-columns: 4.5rem 1fr auto auto;
  align-items: center; gap: var(--s4);
  width: 100%; padding: var(--s4) var(--s2);
  background: none; border: 0; border-bottom: 1px dashed var(--rule);
  cursor: pointer; text-align: start;
  transition: background var(--fast) var(--out), padding-inline-start var(--mid) var(--out);
}
.class-row:hover { background: var(--bg-2); padding-inline-start: var(--s4); }
.class-row .id { font-size: 1.5rem; font-weight: 700; letter-spacing: -0.03em; }
.class-row .ar { font-size: var(--t-body); color: var(--ink-2); }
.class-row .n { font-size: var(--t-small); color: var(--ink-3); }
.class-row .arrow { color: var(--ink-3); transition: transform var(--mid) var(--out); }
.class-row:hover .arrow { transform: translate(3px, -3px); }
body[dir="rtl"] .class-row .arrow { transform: scaleX(-1); }
body[dir="rtl"] .class-row:hover .arrow { transform: scaleX(-1) translate(3px, -3px); }
@media (max-width: 600px) {
  .class-row { grid-template-columns: 3.5rem 1fr auto; }
  .class-row .arrow { display: none; }
}

/* ────────────────────────────────────────────────────────── seating plan */

.board {
  display: flex; align-items: center; gap: var(--s3);
  font-size: var(--t-micro); color: var(--ink-3);
  letter-spacing: .22em; text-transform: uppercase;
  margin-bottom: var(--s5);
}
.board::before, .board::after {
  content: ""; flex: 1; height: 0; border-top: 1px solid var(--rule-firm);
}

/* The room's real shape: --cols is how many desks across the class actually is.
   Below tablet width it falls back to whatever fits. */
.seats {
  display: grid; gap: var(--s2);
  grid-template-columns: repeat(var(--cols, 6), minmax(0, 1fr));
}
@media (max-width: 900px) {
  .seats { grid-template-columns: repeat(auto-fill, minmax(112px, 1fr)); }
}
.seats.editing .seat { cursor: pointer; }
.seats.editing .seat:hover { border-color: var(--accent); }

.seat-tools { margin-bottom: var(--s4); }
.ghost.on { border-color: var(--accent); color: var(--accent-ink); background: var(--accent-wash); }

.seat.picked {
  outline: 2px solid var(--accent); outline-offset: 1px;
  background: var(--accent-wash);
}

/* Seating groups — a tinted edge and a matching chip, six hues that stay legible
   in both themes and never collide with the attendance colours. */
.group-chips { display: flex; flex-wrap: wrap; gap: var(--s2); margin-top: var(--s3); }
.gchip {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 6px 3px 10px; border-radius: var(--pill);
  font-size: var(--t-micro); font-weight: 600;
  border: 1px solid currentColor; background: none;
}
.gchip button {
  background: none; border: 0; cursor: pointer; color: inherit;
  font-size: var(--t-small); line-height: 1; padding: 0 3px; opacity: .65;
}
.gchip button:hover { opacity: 1; }

.g-a { color: oklch(0.55 0.13 300); } .seat.g-a { box-shadow: inset 3px 0 0 oklch(0.55 0.13 300); }
.g-b { color: oklch(0.55 0.12 200); } .seat.g-b { box-shadow: inset 3px 0 0 oklch(0.55 0.12 200); }
.g-c { color: oklch(0.52 0.13 340); } .seat.g-c { box-shadow: inset 3px 0 0 oklch(0.52 0.13 340); }
.g-d { color: oklch(0.50 0.11 140); } .seat.g-d { box-shadow: inset 3px 0 0 oklch(0.50 0.11 140); }
.g-e { color: oklch(0.52 0.12 40);  } .seat.g-e { box-shadow: inset 3px 0 0 oklch(0.52 0.12 40); }
.g-f { color: oklch(0.48 0.09 260); } .seat.g-f { box-shadow: inset 3px 0 0 oklch(0.48 0.09 260); }
@media (prefers-color-scheme: dark) {
  html:not([data-theme="light"]) {
    .g-a { color: oklch(0.75 0.13 300); } .g-b { color: oklch(0.75 0.11 200); }
    .g-c { color: oklch(0.74 0.13 340); } .g-d { color: oklch(0.74 0.11 140); }
    .g-e { color: oklch(0.76 0.12 40);  } .g-f { color: oklch(0.72 0.09 260); }
  }
}
html[data-theme="dark"] {
  .g-a { color: oklch(0.75 0.13 300); } .g-b { color: oklch(0.75 0.11 200); }
  .g-c { color: oklch(0.74 0.13 340); } .g-d { color: oklch(0.74 0.11 140); }
  .g-e { color: oklch(0.76 0.12 40);  } .g-f { color: oklch(0.72 0.09 260); }
}

/* Dashed = not recorded yet. Solid = recorded. The reference's own idiom,
   carrying meaning instead of decoration. */
.seat {
  position: relative; display: flex; flex-direction: column; gap: var(--s1);
  justify-content: space-between; min-height: 66px;
  padding: var(--s2) var(--s3);
  background: none; color: inherit; cursor: pointer; text-align: start;
  border: 1px dashed var(--rule-firm); border-radius: var(--radius-sm);
  transition: background var(--fast) var(--out), border-color var(--fast) var(--out),
              transform var(--fast) var(--out);
}
.seat:hover { border-color: var(--ink-3); }
.seat:active { transform: scale(0.985); }
.seat .n { font-size: var(--t-small); font-weight: 550; line-height: 1.3; unicode-bidi: isolate; }
.seat .foot { display: flex; align-items: center; justify-content: space-between; gap: var(--s2); }
.seat .no { font-size: var(--t-micro); color: var(--ink-3); font-family: var(--font-mono); }
.seat .state { width: 8px; height: 8px; border-radius: var(--pill); background: transparent; flex: none; }

.seat[data-status] { border-style: solid; }
.seat[data-status="present"] { border-color: var(--rule-firm); }
.seat[data-status="present"] .state { background: var(--accent); }
.seat[data-status="absent"]  { background: var(--absent-wash);  border-color: var(--absent); }
.seat[data-status="absent"]  .state { background: var(--absent); }
.seat[data-status="late"]    { background: var(--late-wash);    border-color: var(--late); }
.seat[data-status="late"]    .state { background: var(--late); }
.seat[data-status="excused"] { background: var(--excused-wash); border-color: var(--excused); }
.seat[data-status="excused"] .state { background: var(--excused); }
.seat .flag { position: absolute; inset-block-start: 5px; inset-inline-end: 7px; font-size: var(--t-micro); color: var(--late); }

.legend { display: flex; gap: var(--s4); flex-wrap: wrap; font-size: var(--t-small); color: var(--ink-3); }
.legend span { display: inline-flex; align-items: center; gap: 6px; }
.legend i { width: 8px; height: 8px; border-radius: var(--pill); }
.legend i.dashed { border: 1px dashed var(--ink-3); border-radius: 2px; }

.inline-select {
  background: none; border: 0; border-bottom: 1px solid var(--rule-firm);
  padding: 2px 2px 3px; font-size: var(--t-small); color: var(--ink); cursor: pointer;
}
.inline-select:hover { border-bottom-color: var(--ink-3); }

/* -------------------------------------------------------- teach: the board

   A projector board, not a page.

   The room decides the type size, not the laptop. `--u` is one hundredth of the
   smaller of the projector's two dimensions once a 16:9 frame is fitted inside
   it, so the same board fills a widescreen hall projector and a 4:3 classroom
   one at the same optical size, and the back row reads it either way.

   The stage is three rows: the lesson's goal, the live step, the period rail.
   The step itself is two columns — what we are doing, and what YOUR task is.
   Every one of those regions is its own grid track with `min-height: 0` and its
   own overflow, which is the whole point of the rebuild: the instruction can no
   longer grow down the slide and print itself across the task lanes.          */

/* Nothing of the console belongs on a classroom wall. */
body.teaching .topbar, body.teaching .rules { display: none; }
body.teaching { overflow: hidden; }

/* The stage keeps the interface's own direction: goal, step, lanes and rail all
   have to read the way the teacher and the class read. */
.tg-stage {
  /* `vh` on iPad Safari is the viewport with the toolbar gone, which the fixed
     stage never gets; `dvh` is the height actually on screen. */
  --vh: 1vh;
  --u: min(1vw, calc(var(--vh) * 1.78));
  --pad: calc(var(--u) * 2.6);
  position: fixed; inset: 0; z-index: var(--z-toast);
  display: grid; grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto minmax(0, 1fr) auto;
  background: var(--bg); overflow: hidden;
  /* the sides of a phone held sideways; the top and bottom insets belong to the
     goal bar and the HUD, whose grounds run under them */
  padding-left: env(safe-area-inset-left, 0px); padding-right: env(safe-area-inset-right, 0px);
  /* A wall, not a document. A tap must not zoom it, select a word of it or
     raise the save-image sheet over the page; nothing on it scrolls the body. */
  touch-action: manipulation; overscroll-behavior: none;
  -webkit-user-select: none; user-select: none;
  -webkit-touch-callout: none; -webkit-tap-highlight-color: transparent;
}
@supports (height: 1dvh) { .tg-stage { --vh: 1dvh; } }
.tg-drawer { -webkit-user-select: text; user-select: text; overscroll-behavior: contain; }

/* ------------------------------------------------------------- the lesson view

   "Teach this" frames the lesson's animated chapter: a slim bar (the way out,
   what is on screen, the games, full screen) over the chapter, which fills the
   rest. The chapter scales and centres itself in whatever box it gets, so the
   frame only has to fill its track. An iframe is a replaced element: without
   an explicit size it sits at 300×150 in the corner of its grid cell.        */
.tg-stage:has(> .tg-frame) { grid-template-rows: auto minmax(0, 1fr); background: #0f1613; }
.tg-bar {
  display: flex; align-items: center; gap: 12px; min-width: 0;
  padding: 8px 16px; padding-top: calc(8px + env(safe-area-inset-top, 0px));
  border-bottom: 1px solid var(--rule-firm); background: var(--bg-2);
}
.tg-bar > .tg-btn, .tg-bar > .tg-chip { flex: none; }
.tg-bar > .tg-chip { align-items: center; font-size: var(--t-small); padding: 8px 14px; border-radius: var(--pill); }
.tg-what { flex: 1 1 auto; min-width: 0; display: grid; gap: 2px; }
.tg-what b, .tg-what span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tg-what b { font-size: 16px; font-weight: 600; color: var(--ink); }
.tg-what span { font-size: 13px; color: var(--ink-2); }
.tg-frame {
  display: block; width: 100%; height: 100%; min-height: 0;
  justify-self: stretch; align-self: stretch; border: 0; background: #0f1613;
}

/* ------------------------------------------------------------- the goal bar

   One sentence, in both languages, that does not change for the whole period,
   plus the page the book is open at. It is the answer to "why are we doing
   this" and it is the first thing on the wall, so nobody has to remember it. */

.tg-top {
  display: flex; align-items: center; gap: calc(var(--u) * 2.4);
  padding: calc(var(--u) * 1.5) var(--pad);
  padding-top: calc(var(--u) * 1.5 + env(safe-area-inset-top, 0px));
  border-bottom: 1px solid var(--rule-firm); background: var(--bg-2);
}
.tg-goal { min-width: 0; display: grid; gap: calc(var(--u) * 0.3); text-align: left; }
[dir="rtl"] .tg-goal { text-align: right; }
.tg-goal b, .tg-goal i { text-align: inherit; }
.tg-goal-k {
  font-family: var(--font-mono); font-size: calc(var(--u) * 1.1);
  letter-spacing: .12em; text-transform: uppercase; color: var(--accent-ink);
}
.tg-goal b {
  font-size: calc(var(--u) * 1.75); font-weight: 600; line-height: 1.28;
  letter-spacing: -0.015em; color: var(--ink); text-wrap: pretty;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.tg-goal i {
  font-style: normal; font-family: var(--font-ar);
  font-size: calc(var(--u) * 1.45); line-height: 1.45; color: var(--ink-2);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.tg-where { margin-inline-start: auto; display: flex; align-items: center; gap: calc(var(--u) * 1); flex: none; }
.tg-chip {
  font: inherit; color: var(--ink-2); text-align: start;
  display: flex; align-items: baseline; gap: calc(var(--u) * 0.7);
  padding: calc(var(--u) * 0.7) calc(var(--u) * 1.3);
  border-radius: calc(var(--u) * 1.1); border: 1px solid var(--rule-firm);
  background: var(--bg); font-size: calc(var(--u) * 1.35); color: var(--ink-2);
  white-space: nowrap;
}
/* The page number is the one thing on this bar a boy acts on, so it is the one
   thing that carries the accent. */
button.tg-chip, a.tg-chip { cursor: pointer; transition: border-color var(--fast) var(--out), background var(--fast) var(--out); }
a.tg-chip { text-decoration: none; }
/* Board hovers only where there is a hover. On a touch screen `:hover` sticks to
   whatever was tapped last, and on the wall that reads as a selected button. */
@media (hover: hover) {
  button.tg-chip:hover, a.tg-chip:hover { border-color: var(--accent); background: color-mix(in oklab, var(--accent) 16%, transparent); }
}
.tg-chip.page { background: var(--accent-wash); border-color: color-mix(in oklab, var(--accent) 38%, transparent); }
.tg-chip.page i { font-style: normal; font-size: calc(var(--u) * 1.15); color: var(--accent-ink); }
.tg-chip.page b { font-size: calc(var(--u) * 2.1); font-weight: 700; letter-spacing: -0.03em; color: var(--accent-ink); }

/* ----------------------------------------------------------------- the deck

   Every step stays in the DOM so the rail, the drawer and the tests can address
   it, but only the live one is laid out. Stacking them and fading between would
   put two instructions on the wall at once, half-faded, mid-lesson.           */

.tg-deck { position: relative; min-height: 0; min-width: 0; }
.tg-slide { display: none; }
.tg-slide.is-now {
  display: grid; grid-template-columns: minmax(0, 1.22fr) minmax(0, 1fr);
  gap: calc(var(--u) * 2.6); height: 100%; min-height: 0;
  padding: calc(var(--u) * 2.2) var(--pad);
}

/* ------------------------------------------------------------ the left column */

.tg-step {
  min-width: 0; min-height: 0;
  display: grid; grid-template-rows: auto auto auto minmax(0, 1fr);
  gap: calc(var(--u) * 1.2);
}

.tg-slide-head { display: flex; align-items: center; gap: calc(var(--u) * 1.6); }
.tg-badge {
  flex: none; display: grid; place-items: center;
  width: calc(var(--u) * 4.8); height: calc(var(--u) * 4.8);
  border-radius: calc(var(--u) * 1.2); background: var(--accent-wash); color: var(--accent-ink);
}
.tg-ico { width: calc(var(--u) * 2.8); height: calc(var(--u) * 2.8); }
.tg-slide-t { min-width: 0; }
.tg-kicker {
  display: block; font-family: var(--font-mono); font-size: calc(var(--u) * 1.15);
  letter-spacing: .10em; text-transform: uppercase; color: var(--ink-3);
}
.tg-slide-t h3 {
  font-size: calc(var(--u) * 3.1); line-height: 1.14; letter-spacing: -0.025em;
  margin-top: calc(var(--u) * 0.3); text-wrap: balance;
}
.tg-mins {
  margin-inline-start: auto; flex: none; text-align: center; color: var(--ink-2);
  display: flex; flex-direction: column; align-items: center; line-height: 1;
}
.tg-mins b { font-size: calc(var(--u) * 3.2); line-height: 1.16; font-family: var(--font-mono); letter-spacing: -0.04em; color: var(--ink); }
.tg-mins span { font-size: calc(var(--u) * 1.2); color: var(--ink-3); }

/* The pictogram row: grouping, materials, mode. Big enough to be the first
   thing read from the back wall, quiet enough not to outrank the title. */
.tg-signals { display: flex; flex-wrap: wrap; gap: calc(var(--u) * 0.9); }
.tg-sig {
  display: flex; align-items: center; gap: calc(var(--u) * 0.8);
  padding: calc(var(--u) * 0.7) calc(var(--u) * 1.3) calc(var(--u) * 0.7) calc(var(--u) * 0.9);
  border-radius: calc(var(--u) * 1.1);
  background: var(--bg-2); border: 1px solid var(--rule-firm); color: var(--ink);
}
.tg-sig svg { width: calc(var(--u) * 2.2); height: calc(var(--u) * 2.2); flex: none; color: var(--ink-2); }
.tg-sig i { font-style: normal; font-size: calc(var(--u) * 1.35); font-weight: 550; letter-spacing: -0.01em; }
/* namespaced: `.board` is already the seating plan's whiteboard */
.tg-sig.s-audio { background: var(--accent-wash); border-color: color-mix(in oklab, var(--accent) 34%, transparent); }
.tg-sig.s-audio svg, .tg-sig.s-audio i { color: var(--accent-ink); }
.tg-sig.s-closed svg, .tg-sig.s-open svg { color: var(--late); }

/* The instruction. One sentence or two, written to the class, capped in the
   markup by crisp() and capped again here so a long one cannot push the
   payload out of its own track. */
.tg-body {
  font-size: calc(var(--u) * 2.2); line-height: 1.36; letter-spacing: -0.01em;
  text-wrap: pretty; color: var(--ink); max-width: 44ch;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}

.tg-slide.bare .tg-step { grid-template-rows: auto auto minmax(0, 1fr); }
.tg-slide.bare .tg-payload { display: none; }
.tg-slide.bare .tg-body {
  font-size: calc(var(--u) * 2.8); line-height: 1.28; max-width: 26ch;
  -webkit-line-clamp: 5; align-self: center;
}

/* On the warm-up the game IS the task, so the instruction above it is a caption
   rather than the main event and hands its height to the board. */
.tg-slide:has(.tg-game) .tg-body {
  font-size: calc(var(--u) * 1.7); -webkit-line-clamp: 2;
}

/* ------------------------------------------------------------ the payload

   Whatever this step actually needs on the wall: the audio it plays, the words
   it teaches, the pattern it drills, the page the homework is on, or the game.
   It takes the rest of the column and scrolls inside itself rather than pushing
   anything. */

.tg-payload { min-height: 0; min-width: 0; overflow: hidden; display: flex; align-items: stretch; }
.tg-media > * { flex: none; }
.tg-media {
  display: flex; flex-direction: column; gap: calc(var(--u) * 0.9); align-items: flex-start;
  max-height: 100%; min-width: 0;
  padding: calc(var(--u) * 1.4) calc(var(--u) * 1.7); border-radius: calc(var(--u) * 1.1);
  background: var(--bg-2); border: 1px solid var(--rule);
}
.tg-media-k {
  font-family: var(--font-mono); font-size: calc(var(--u) * 1.05); letter-spacing: .08em;
  text-transform: uppercase; color: var(--ink-3);
}
.tg-media.audio b { font-size: calc(var(--u) * 2.2); color: var(--accent-ink); }
.tg-media audio { height: calc(var(--u) * 3.2); width: min(100%, calc(var(--u) * 34)); }
.tg-miss { font-size: calc(var(--u) * 1.3); color: var(--ink-3); }
.tg-media.home b { font-size: calc(var(--u) * 2.4); color: var(--accent-ink); }
.tg-home-t {
  font-size: calc(var(--u) * 1.6); line-height: 1.4; color: var(--ink); max-width: 40ch;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}

.tg-words { list-style: none; display: flex; flex-wrap: wrap; gap: calc(var(--u) * 0.7); margin: 0; padding: 0; overflow: hidden; }
.tg-words li {
  font-size: calc(var(--u) * 1.9); padding: calc(var(--u) * 0.4) calc(var(--u) * 1.1);
  border-radius: var(--pill); background: var(--bg); border: 1px solid var(--rule-firm);
}
.tg-samples { margin: 0; padding-inline-start: 1.1em; overflow: hidden; }
.tg-samples li { font-size: calc(var(--u) * 1.95); line-height: 1.45; }

/* When the page is the step's only resource it takes a column of its own beside
   the instruction, floor to ceiling, rather than a thumbnail underneath it — at
   a quarter of the column's height a page is decoration, and the class cannot
   read it. Pressing it (or `B`, or the chip) puts it on the whole wall. */
.tg-slide.has-page .tg-step {
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.8fr);
  grid-template-rows: auto auto minmax(0, 1fr);
  grid-template-areas: "head page" "sig  page" "body page";
  column-gap: calc(var(--u) * 1.6);
}
.tg-slide.has-page .tg-slide-head { grid-area: head; }
.tg-slide.has-page .tg-signals    { grid-area: sig; }
/* Half the width means more lines for the same instruction. */
.tg-slide.has-page .tg-body       { grid-area: body; align-self: start; -webkit-line-clamp: 5; }
.tg-slide.has-page .tg-payload    { grid-area: page; }


/* The page brings its own white ground and its own frame, so the panel around it
   is one frame too many: the label, then the page. */
.tg-media.page {
  font: inherit; cursor: pointer; text-align: start; overflow: hidden;
  align-items: stretch; padding: 0; gap: calc(var(--u) * 0.6);
  background: none; border: 0;
}
.tg-media.page img { box-shadow: 0 calc(var(--u) * 1) calc(var(--u) * 2.4) -1px oklch(0.185 0.004 250 / 0.22); }
@media (hover: hover) { .tg-media.page:hover img { outline: 2px solid var(--accent); outline-offset: 2px; } }
/* The preview is bounded by the column's height, not the page's aspect: left to
   itself an A4 page 970px wide is 1286px tall inside a 255px track. */
.tg-media.page img {
  flex: 1 1 auto; min-height: 0; width: 100%; height: 100%;
  object-fit: contain; object-position: center;
  border-radius: calc(var(--u) * 0.4);
}
.tg-media.page .tg-media-k { display: flex; align-items: baseline; gap: calc(var(--u) * 0.5); }
.tg-media.page .tg-media-k b { font-size: calc(var(--u) * 1.5); color: var(--accent-ink); letter-spacing: -0.02em; }

/* --------------------------------------------------------- the page on the wall

   Over everything, because for as long as it is up it IS the lesson: the class is
   looking at the same page they have open on the desk. */
.tg-page {
  position: absolute; inset: 0; z-index: 4;
  display: grid; place-items: center; padding: calc(var(--u) * 1.6);
  background: color-mix(in oklab, var(--ink) 82%, transparent);
  -webkit-backdrop-filter: blur(3px); backdrop-filter: blur(3px);
}
/* `display: grid` above outranks the browser's own `[hidden] { display: none }`,
   so without this the closed overlay is invisible and still covering the board,
   swallowing every click meant for it. */
.tg-page[hidden] { display: none; }
.tg-page-f {
  margin: 0; min-height: 0; max-height: 100%;
  display: flex; flex-direction: column; align-items: center; gap: calc(var(--u) * 1);
}
.tg-page-f img {
  min-height: 0; max-height: 100%; width: auto; max-width: 100%;
  object-fit: contain; border-radius: calc(var(--u) * 0.6);
  background: var(--bg); box-shadow: 0 24px 80px -30px oklch(0 0 0 / 0.7);
}
.tg-page-f figcaption {
  flex: none; display: flex; align-items: center; gap: calc(var(--u) * 0.8);
  padding: calc(var(--u) * 0.5) calc(var(--u) * 1);
  border-radius: var(--pill); background: var(--bg);
}
.tg-page-f figcaption b { font-size: calc(var(--u) * 1.6); letter-spacing: -0.02em; }

/* ---------------------------------------------- the differentiated lanes

   Three lanes, always in the same order, the same colour and the same column,
   so a boy learns in week one which stripe is his and reads it without being
   told again. They are a sibling track of the instruction, never under it.   */

.tg-lanes {
  min-width: 0; min-height: 0; overflow: hidden;
  /* One dimension, so flex rather than grid: `flex: 1 1 0` on the lanes divides
     whatever height is left after the label into three equal boxes. */
  display: flex; flex-direction: column; gap: calc(var(--u) * 1.1);
  padding-inline-start: calc(var(--u) * 2.4);
  border-inline-start: 1px dashed var(--rule-firm);
}
.tg-lanes-k {
  flex: none;
  font-family: var(--font-mono); font-size: calc(var(--u) * 1.1);
  letter-spacing: .10em; text-transform: uppercase; color: var(--ink-3);
}
.tg-lane {
  flex: 1 1 0; min-height: 0; min-width: 0; overflow: hidden;
  /* The lanes are equal boxes so the eye can compare them, and the task sits in
     the optical middle of its own box rather than hanging off the label with a
     pool of empty space beneath it. */
  display: flex; flex-direction: column; justify-content: center; gap: calc(var(--u) * 0.25);
  padding: calc(var(--u) * 0.8) calc(var(--u) * 1.2);
  border-radius: calc(var(--u) * 1.1); border: 1px solid var(--rule);
}
.tg-lane > * { flex: none; }
.tg-lane b {
  display: flex; align-items: center; gap: calc(var(--u) * 0.6); min-width: 0;
  font-size: calc(var(--u) * 1.2); letter-spacing: .04em; text-transform: uppercase;
  padding-bottom: calc(var(--u) * 0.45);
  border-bottom: 1px solid color-mix(in oklab, var(--ink) 12%, transparent);
}
.tg-lane-k { flex: none; }
.tg-lane .n {
  margin-inline-start: auto; flex: none;
  font-family: var(--font-mono); font-size: calc(var(--u) * 1.1); letter-spacing: 0;
  padding: 0 calc(var(--u) * 0.7); border-radius: var(--pill); background: var(--bg);
  border: 1px solid var(--rule-firm); color: var(--ink-2);
}
.tg-lane .en {
  font-size: calc(var(--u) * 1.45); line-height: 1.32; color: var(--ink);
  margin-top: calc(var(--u) * 0.35);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.tg-lane .ar {
  font-family: var(--font-ar); font-size: calc(var(--u) * 1.25); line-height: 1.5;
  color: var(--ink-2);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

.tg-lane.support { background: var(--late-wash);    border-color: color-mix(in oklab, var(--late) 34%, transparent); }
.tg-lane.support b { color: var(--late); }
.tg-lane.core    { background: var(--accent-wash);  border-color: color-mix(in oklab, var(--accent) 34%, transparent); }
.tg-lane.core b { color: var(--accent-ink); }
.tg-lane.stretch { background: var(--excused-wash); border-color: color-mix(in oklab, var(--excused) 34%, transparent); }
.tg-lane.stretch b { color: var(--excused); }

/* --------------------------------------------------------- the lane hero

   The character sits between the tier label and the task: emblem, name, line.
   It has to read from the back of a classroom on a projector, so the name is
   the loud part and the catchphrase sits under it in the lane's own colour.
   The emblem inherits `currentColor`, which the tier rules below already set,
   so a hero picks up the colour of whichever lane it lands in that lesson.   */

.tg-hero-em { width: calc(var(--u) * 2.2); height: calc(var(--u) * 2.2); flex: none; stroke-width: 1.7; }
.tg-hero-n {
  font-style: normal; font-weight: 700; font-size: calc(var(--u) * 1.2); line-height: 1.3;
  letter-spacing: 0; text-transform: none; color: var(--ink);
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* The emblem takes the lane's own colour; the name stays full-contrast ink so
   the reference is legible before the colour is even read. */
.tg-lane.support .tg-hero-em { color: var(--late); }
.tg-lane.core    .tg-hero-em { color: var(--accent-ink); }
.tg-lane.stretch .tg-hero-em { color: var(--excused); }

/* ------------------------------------------------------------------- HUD */

.tg-hud {
  z-index: 2; min-width: 0;
  display: grid; grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center; gap: calc(var(--u) * 2);
  padding: calc(var(--u) * 1.2) var(--pad);
  /* clear of the iPad's home indicator, where a swipe leaves the app */
  padding-bottom: calc(var(--u) * 1.2 + env(safe-area-inset-bottom, 0px));
  background: var(--bg-2); border-top: 1px solid var(--rule-firm);
}
.tg-hud-l { display: flex; align-items: center; gap: var(--s4); }

.tg-clockring { position: relative; width: calc(var(--u) * 5.2); height: calc(var(--u) * 5.2); flex: none; display: grid; place-items: center; }
.tg-clockring svg { position: absolute; inset: 0; width: 100%; height: 100%; transform: rotate(-90deg); }
.tg-clockring circle { fill: none; stroke-width: 5; }
.tg-clockring .trk { stroke: var(--rule); }
.tg-clockring .run { stroke: var(--accent); stroke-linecap: round; transition: stroke-dashoffset 1s linear; }
.tg-clockring .run.over { stroke: var(--absent); }
.tg-clockring b { font-size: calc(var(--u) * 1.35); font-weight: 700; letter-spacing: -0.03em; z-index: 1; }
.tg-clockring b.over { color: var(--absent); }

.tg-hud-t { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.tg-hud-t #tgNow { font-size: calc(var(--u) * 1.5); font-weight: 600; }
.tg-hud-t #periodClock { font-size: calc(var(--u) * 1.15); }

/* ------------------------------------------------------------- the rail

   The signature of this board: the period drawn to scale. Each step is as wide
   as its own minutes, the live one opens to show its name, and the fill inside
   it is the countdown. The class can see the shape of the lesson and how much
   of it is left without the teacher narrating either.                        */

.tg-rail { display: flex; align-items: stretch; gap: calc(var(--u) * 0.35); min-width: 0; height: calc(var(--u) * 3.2); }
.tg-dot {
  position: relative; flex: 1 1 0; min-width: calc(var(--u) * 1.1);
  padding: 0; border: 0; cursor: pointer; overflow: hidden;
  border-radius: calc(var(--u) * 0.5);
  background: color-mix(in oklab, var(--ink) 8%, transparent); color: var(--ink-2);
  transition: background var(--fast) var(--out), color var(--fast) var(--out);
}
@media (hover: hover) { .tg-dot:hover { background: var(--rule-firm); } }
.tg-dot .tg-dot-fill {
  position: absolute; inset: 0; transform-origin: left center; transform: scaleX(0);
  background: color-mix(in oklab, var(--accent) 32%, transparent);
  transition: transform 1s linear;
}
[dir="rtl"] .tg-dot .tg-dot-fill { transform-origin: right center; }
.tg-dot .tg-dot-fill.over { background: color-mix(in oklab, var(--absent) 38%, transparent); }
.tg-dot i {
  position: relative; display: block; padding: 0 calc(var(--u) * 0.6);
  font-style: normal; font-size: calc(var(--u) * 1.15); line-height: calc(var(--u) * 3.2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; opacity: 0;
  transition: opacity var(--fast) var(--out);
}
.tg-dot.done { background: color-mix(in oklab, var(--accent) 18%, transparent); }
.tg-dot.now {
  flex-grow: 0; flex-basis: auto; min-width: calc(var(--u) * 14);
  background: var(--bg); box-shadow: inset 0 0 0 2px var(--accent); color: var(--ink);
}
.tg-dot.now i { opacity: 1; font-weight: 600; }

.tg-actions { display: flex; align-items: center; gap: var(--s2); flex-wrap: wrap; justify-content: flex-end; }
.tg-btn {
  font: inherit; font-size: var(--t-small); font-weight: 500;
  padding: 9px 15px; border-radius: var(--pill); cursor: pointer;
  border: 1px solid var(--rule-firm); background: var(--bg); color: var(--ink);
  transition: background var(--fast) var(--out), border-color var(--fast) var(--out);
}
.tg-btn:disabled { opacity: 0.35; cursor: default; }
.tg-btn.primary { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
@media (hover: hover) {
  .tg-btn:hover:not(:disabled) { background: var(--bg-2); border-color: var(--ink-3); }
  .tg-btn.primary:hover { background: var(--accent-ink); border-color: var(--accent-ink); }
}
.tg-btn.icon { padding: 9px 12px; }

/* A finger is not a cursor: every control on the board is at least the 44pt
   Apple asks for, and the rail's segments grow to match. */
@media (pointer: coarse) {
  .tg-btn { min-height: 44px; min-width: 44px; }
  .tg-rail { height: max(calc(var(--u) * 3.2), 44px); }
  .tg-dot i { line-height: max(calc(var(--u) * 3.2), 44px); }
}
.tg-btn[aria-pressed="true"] { background: var(--accent-wash); border-color: var(--accent); color: var(--accent-ink); }

/* The drawer covers the trailing edge of the stage, which is exactly where the
   task lanes are. The board gives way to it rather than letting it sit on top of
   the one part of the wall the class reads. */
.tg-stage:has(> .tg-drawer:not([hidden])) .tg-top,
.tg-stage:has(> .tg-drawer:not([hidden])) .tg-deck,
.tg-stage:has(> .tg-drawer:not([hidden])) .tg-hud {
  padding-inline-end: min(400px, 92vw);
  transition: padding-inline-end var(--mid) var(--out);
}
/* The board loses a quarter of its width to the drawer but none of its height,
   so the type steps down with it. Without this the task lanes wrap to more
   lines than their track has room for and the Arabic half of the lowest lane is
   the first thing to go. */
.tg-stage:has(> .tg-drawer:not([hidden])) { --u: min(0.78vw, calc(var(--vh) * 1.39)); }
.tg-stage:has(> .tg-drawer:not([hidden])) .tg-goal b { -webkit-line-clamp: 3; }
/* Beside the drawer there is no room for the page to hold a column of its own —
   the step's own title starts wrapping. It stacks back under the instruction,
   and the chip and `B` still put it on the whole wall. */
.tg-stage:has(> .tg-drawer:not([hidden])) .tg-slide.has-page .tg-step {
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto auto auto minmax(0, 1fr);
  grid-template-areas: "head" "sig" "body" "page";
}
.tg-stage:has(> .tg-drawer:not([hidden])) .tg-slide.has-page .tg-body { -webkit-line-clamp: 3; }
/* An iPad or a 4:3 board beside the drawer has about 600px left for the HUD, and
   the clock and the transport take all of it: the rail was squeezed to a sliver
   its own segments overflowed. It takes a row of its own under them instead. */
@media (max-width: 1280px) {
  .tg-stage:has(> .tg-drawer:not([hidden])) .tg-hud { grid-template-columns: auto minmax(0, 1fr); row-gap: calc(var(--u) * 1); }
  .tg-stage:has(> .tg-drawer:not([hidden])) .tg-actions { grid-column: 2; grid-row: 1; }
  .tg-stage:has(> .tg-drawer:not([hidden])) .tg-rail { grid-column: 1 / -1; grid-row: 2; }
}

/* ----------------------------------------------------- the teacher's drawer

   Everything the class must not see: the run sheet, the step in the guide's own
   words, the lesson's differentiation paragraphs, and the names in each tier.  */

.tg-drawer {
  position: absolute; inset-block: 0; inset-inline-end: 0; z-index: 3;
  width: min(400px, 92vw); overflow-y: auto;
  padding: var(--s5) var(--s5) 190px;
  background: var(--bg); border-inline-start: 1px solid var(--rule-firm);
  box-shadow: -24px 0 60px -40px oklch(0.185 0.004 250 / 0.5);
}
.tg-drawer header { margin-bottom: var(--s5); }
.tg-drawer h4 { font-size: var(--t-h3); }
.tg-d-pages { margin-top: var(--s2); color: var(--accent-ink); letter-spacing: .02em; }
.tg-d-block { padding: var(--s4) 0; border-top: 1px dashed var(--rule); }
.tg-d-block > b {
  display: block; font-size: var(--t-micro); letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-3); margin-bottom: var(--s3);
}
.tg-runsheet { list-style: none; margin: 0; padding: 0; }
.tg-runsheet button {
  display: grid; grid-template-columns: 3rem 1fr auto; gap: var(--s3); align-items: center;
  width: 100%; padding: 7px 4px; background: none; border: 0; cursor: pointer;
  text-align: start; font: inherit; font-size: var(--t-small); color: var(--ink-2);
  border-radius: var(--radius-sm);
}
.tg-runsheet button:hover { background: var(--bg-2); color: var(--ink); }
.tg-runsheet .mono { font-family: var(--font-mono); font-size: var(--t-micro); color: var(--ink-3); }
.tg-runsheet li.now button { background: var(--accent-wash); color: var(--ink); font-weight: 600; }
.tg-runsheet li.done button { color: var(--ink-3); text-decoration: line-through; }

.tg-d-tier { padding: var(--s3) 0 var(--s3) var(--s3); border-inline-start: 3px solid var(--rule-firm); margin-bottom: var(--s3); }
.tg-d-tier > span { font-size: var(--t-micro); letter-spacing: .06em; text-transform: uppercase; }
.tg-d-tier.support { border-inline-start-color: var(--late); }
.tg-d-tier.support > span { color: var(--late); }
.tg-d-tier.core { border-inline-start-color: var(--accent); }
.tg-d-tier.core > span { color: var(--accent-ink); }
.tg-d-tier.stretch { border-inline-start-color: var(--excused); }
.tg-d-tier.stretch > span { color: var(--excused); }
.tg-d-hero { margin-top: 2px; color: var(--ink-2); }
.tg-d-hero q { quotes: '"' '"'; color: var(--ink-3); }
.tg-names { display: flex; flex-wrap: wrap; gap: 5px; margin-top: var(--s2); }
.tg-names button {
  font: inherit; font-size: var(--t-micro); padding: 3px 9px; cursor: pointer;
  border-radius: var(--pill); border: 1px solid var(--rule); background: var(--bg-2); color: var(--ink-2);
}
.tg-names button:hover { border-color: var(--ink-3); color: var(--ink); }

/* A phone is not a projector. The board becomes a reference the teacher reads
   in his hand, and a hand can scroll: the two columns stack, the step is laid
   out at its natural height, and the whole slide scrolls under a fixed goal bar
   and a fixed rail. Clipping text is right on a wall, where there is no second
   look; it is wrong in a pocket, where there is. */
@media (max-width: 860px) {
  .tg-stage { --u: min(2.4vw, calc(var(--vh) * 1.1)); }
  .tg-top { flex-wrap: wrap; gap: calc(var(--u) * 1); }
  .tg-goal { flex: 1 1 100%; }
  .tg-goal b { -webkit-line-clamp: 4; }
  .tg-goal i { display: none; }
  .tg-where { margin-inline-start: 0; flex: 0 1 auto; flex-wrap: wrap; }

  .tg-deck { overflow-y: auto; }
  .tg-slide.is-now {
    grid-template-columns: minmax(0, 1fr); grid-template-rows: auto auto;
    height: auto; min-height: 100%;
  }
  .tg-step { grid-template-rows: auto auto auto auto; }
  /* In the hand the page stacks under the instruction like everything else;
     side by side it leaves the step's title about 90px to live in. */
  .tg-slide.has-page .tg-step {
    grid-template-columns: minmax(0, 1fr); grid-template-rows: auto auto auto auto;
    grid-template-areas: "head" "sig" "body" "page";
  }
  .tg-slide.has-page .tg-payload { min-height: 46vh; }
  .tg-body, .tg-slide:has(.tg-game) .tg-body { -webkit-line-clamp: 6; }
  .tg-payload { overflow: visible; }
  .tg-lanes {
    padding-inline-start: 0; border-inline-start: 0;
    border-top: 1px dashed var(--rule-firm); padding-top: calc(var(--u) * 1.2);
  }
  .tg-lane { flex: none; overflow: visible; }
  .tg-lane .en, .tg-lane .ar { -webkit-line-clamp: 4; }

  /* Three rows in the hand, not one ragged one: the clock and the step, then
     the transport spread across the width, then the rail. */
  .tg-hud {
    grid-template-columns: minmax(0, 1fr); gap: var(--s3); padding: var(--s3) var(--s4);
    padding-bottom: calc(var(--s3) + env(safe-area-inset-bottom, 0px));
  }
  .tg-deck { overscroll-behavior: contain; }
  .tg-actions { grid-column: 1 / -1; flex-wrap: nowrap; justify-content: space-between; }
  .tg-rail { grid-column: 1 / -1; order: 3; }
}

/* --------------------------------------------------- teacher assistant / roll */

/* The stage is read from across the room while the class answers, so the name is
   the largest thing on the page. */
.roll-stage {
  /* Centred on purpose: mixing an Arabic name with Latin counters leaves the two
     stranded at opposite edges when the stage is start-aligned. */
  text-align: center;
  padding: var(--s6) var(--s4) var(--s5);
  border-top: 1px solid var(--rule-firm);
  border-bottom: 1px dashed var(--rule);
}
.roll-stage.live { background: var(--accent-wash); border-radius: var(--radius); }
.roll-pos { font-size: var(--t-micro); color: var(--ink-3); letter-spacing: .06em; }
.roll-name {
  font-size: clamp(1.75rem, 5.5vw, 3rem); font-weight: 700;
  letter-spacing: -0.03em; line-height: 1.1; margin: var(--s2) 0 var(--s2);
  unicode-bidi: isolate; text-wrap: balance;
}
.roll-seat { margin-bottom: var(--s3); }
.roll-heard { font-size: var(--t-small); min-height: 1.4em; }

.roll-keys { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--s2); margin-top: var(--s5); }
@media (max-width: 560px) { .roll-keys { grid-template-columns: repeat(2, 1fr); } }
.rk {
  display: flex; align-items: center; justify-content: center; gap: var(--s2);
  padding: 16px 8px; cursor: pointer; font-size: var(--t-body); font-weight: 600;
  background: none; border: 1px solid var(--rule-firm); border-radius: var(--radius-sm);
  transition: background var(--fast) var(--out), border-color var(--fast) var(--out), color var(--fast) var(--out);
}
.rk .k {
  font-family: var(--font-mono); font-size: var(--t-micro); font-weight: 400;
  color: var(--ink-3); border: 1px solid var(--rule); border-radius: 4px; padding: 0 5px;
}
.rk:hover { border-color: currentColor; }
.rk-present:hover { color: var(--accent-ink); background: var(--accent-wash); }
.rk-absent:hover  { color: var(--absent);  background: var(--absent-wash); }
.rk-late:hover    { color: var(--late);    background: var(--late-wash); }
.rk-excused:hover { color: var(--excused); background: var(--excused-wash); }

.seat[aria-current="true"] { outline: 2px solid var(--accent); outline-offset: 1px; }

/* ─────────────────────────────────────────────────────────────── drawer */

.scrim {
  position: fixed; inset: 0; z-index: var(--z-scrim);
  background: color-mix(in oklab, var(--ink) 55%, transparent);
  display: grid; place-items: end center;
  animation: fade var(--mid) var(--out);
}
@keyframes fade { from { opacity: 0; } }
.drawer {
  position: relative; z-index: var(--z-drawer);
  width: min(580px, 100%); max-height: 92dvh; overflow: auto;
  background: var(--bg); color: var(--ink);
  border: 1px solid var(--rule-firm); border-bottom: 0;
  border-radius: var(--radius) var(--radius) 0 0;
  padding: var(--s5) var(--s5) var(--s7);
  animation: rise 280ms var(--out);
}
@keyframes rise { from { transform: translateY(14px); opacity: 0; } }
@media (min-width: 720px) {
  .scrim { place-items: center; }
  .drawer { border-bottom: 1px solid var(--rule-firm); border-radius: var(--radius); max-height: 88dvh; }
}
@media (prefers-reduced-motion: reduce) {
  .scrim, .drawer { animation: none; }
  * { transition-duration: 1ms !important; }
}
.drawer > header { display: flex; align-items: flex-start; gap: var(--s4); }
.drawer > header h2 { flex: 1; font-size: var(--t-h1); }
.drawer .close {
  flex: none; width: 30px; height: 30px; display: grid; place-items: center;
  background: none; border: 1px solid var(--rule); border-radius: var(--pill);
  color: var(--ink-3); cursor: pointer; font-size: 1rem; line-height: 1;
}
.drawer .close:hover { color: var(--ink); border-color: var(--rule-firm); }

.drawer .part { margin-top: var(--s6); padding-top: var(--s4); border-top: 1px dashed var(--rule); }
.drawer .part > h3 { margin-bottom: var(--s3); }
.drawer .part > .lede { font-size: var(--t-small); color: var(--ink-3); margin-bottom: var(--s3); }

.field { display: grid; gap: 5px; }
.field + .field, .grid2 + .field { margin-top: var(--s3); }
.field label { font-size: var(--t-micro); color: var(--ink-3); letter-spacing: .04em; text-transform: uppercase; }
.field input, .field select, .field textarea {
  background: none; border: 0; border-bottom: 1px solid var(--rule-firm);
  padding: 6px 2px; color: var(--ink); border-radius: 0;
}
.field textarea { border: 1px solid var(--rule-firm); border-radius: var(--radius-sm); padding: var(--s3); resize: vertical; }
.field input:focus, .field select:focus, .field textarea:focus { outline: 0; border-color: var(--accent); }
.grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s4); }

.status-pick { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--s2); }
.status-pick button {
  padding: 11px 4px; cursor: pointer; font-size: var(--t-small); font-weight: 550;
  background: none; color: var(--ink-2);
  border: 1px dashed var(--rule-firm); border-radius: var(--radius-sm);
  transition: all var(--fast) var(--out);
}
.status-pick button:hover { border-style: solid; color: var(--ink); }
.status-pick button[aria-pressed="true"] { border-style: solid; color: var(--on-accent); }
.status-pick button[data-s="present"][aria-pressed="true"] { background: var(--accent);  border-color: var(--accent); }
.status-pick button[data-s="absent"][aria-pressed="true"]  { background: var(--absent);  border-color: var(--absent);  color: #fff; }
.status-pick button[data-s="late"][aria-pressed="true"]    { background: var(--late);    border-color: var(--late);    color: oklch(0.2 0.04 65); }
.status-pick button[data-s="excused"][aria-pressed="true"] { background: var(--excused); border-color: var(--excused); color: #fff; }

/* ---------------------------------------------------- what he brought

   Three squares, the same three every lesson, in the same order, so a teacher
   going down a row of desks ticks by position rather than by reading. Dashed is
   the console's grammar for "not recorded", so an untouched square is dashed and
   a ticked one is solid jade — the same rule the register follows.            */

.brought { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s2); }
.tick {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 10px 4px; cursor: pointer; font: inherit;
  background: none; color: var(--ink-2);
  border: 1px dashed var(--rule-firm); border-radius: var(--radius-sm);
  transition: color var(--fast) var(--out), border-color var(--fast) var(--out);
}
.tick:hover { border-style: solid; color: var(--ink); }
.tick .box {
  position: relative; display: grid; place-items: center;
  width: 34px; height: 34px; border-radius: var(--radius-sm);
  border: 1px solid var(--rule-firm); background: var(--bg-2);
  transition: background var(--fast) var(--out), border-color var(--fast) var(--out);
}
.tick .box svg { width: 20px; height: 20px; }
.tick .lbl { font-size: var(--t-micro); font-weight: 550; }
.tick[aria-pressed="true"] { border-style: solid; border-color: var(--accent); color: var(--accent-ink); }
.tick[aria-pressed="true"] .box { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
/* The tick itself, drawn over the corner of the square rather than replacing the
   icon: the teacher still needs to see which of the three he is looking at. */
.tick[aria-pressed="true"] .box::after {
  content: "✓"; position: absolute; inset-block-end: -6px; inset-inline-end: -6px;
  width: 16px; height: 16px; display: grid; place-items: center;
  font-size: 10px; font-weight: 700; border-radius: var(--pill);
  background: var(--bg); color: var(--accent-ink); border: 1px solid var(--accent);
}

/* On the seat: three dots, one per thing, filled left to right. It answers "has
   this row got their books out" without opening anybody. */
.seat-kit { display: flex; gap: 3px; flex: none; }
.seat-kit i { width: 5px; height: 5px; border-radius: var(--pill); background: var(--rule-firm); }
.seat-kit[data-kit="1"] i:nth-child(-n + 1),
.seat-kit[data-kit="2"] i:nth-child(-n + 2),
.seat-kit[data-kit="3"] i { background: var(--accent); }

.wa { text-decoration: none; margin-top: var(--s4); }
.wa.disabled { background: none; border: 1px dashed var(--rule-firm); color: var(--ink-3); pointer-events: none; }
.check { display: inline-flex; align-items: center; gap: 7px; font-size: var(--t-small); color: var(--ink-3); margin-top: var(--s3); cursor: pointer; }

.hist { list-style: none; margin: 0; padding: 0; font-size: var(--t-small); }
.hist li { display: flex; gap: var(--s3); padding: 5px 0; border-top: 1px dashed var(--rule); }
.hist li:first-child { border-top: 0; }
.hist .d { color: var(--ink-3); font-family: var(--font-mono); font-size: var(--t-micro); flex: none; }

/* ────────────────────────────────────────────────────────── lesson plans */

.book-switch { display: flex; gap: var(--s5); }
.book-switch button {
  background: none; border: 0; padding: 0 0 var(--s2); cursor: pointer;
  font-size: var(--t-h3); font-weight: 600; color: var(--ink-3);
  border-bottom: 2px solid transparent;
  transition: color var(--fast) var(--out), border-color var(--fast) var(--out);
}
.book-switch button:hover { color: var(--ink); }
.book-switch button[aria-pressed="true"] { color: var(--ink); border-bottom-color: var(--accent); }

.week-nav { display: flex; gap: 3px; flex-wrap: wrap; }
.week-nav button {
  min-width: 34px; padding: 6px 5px; cursor: pointer;
  background: none; color: var(--ink-3);
  border: 1px dashed var(--rule-firm); border-radius: var(--radius-sm);
  font-family: var(--font-mono); font-size: var(--t-small);
  transition: all var(--fast) var(--out);
}
.week-nav button:hover { border-style: solid; color: var(--ink); }
.week-nav button[aria-current="true"] {
  background: var(--accent); border-color: var(--accent); border-style: solid; color: var(--on-accent);
}
.week-nav button.exam { border-color: var(--late); color: var(--late); }
.week-nav button.exam[aria-current="true"] { color: var(--on-accent); }

.lesson { padding: var(--s6) 0; border-top: 1px solid var(--rule-firm); }
.lesson > header { display: flex; align-items: baseline; gap: var(--s3); flex-wrap: wrap; margin-bottom: var(--s3); }
.lesson > header a.ghost { text-decoration: none; }
.lesson > header .num {
  font-family: var(--font-mono); font-size: var(--t-small); color: var(--ink-3);
}
.lesson .obj { font-size: var(--t-h3); font-weight: 450; max-width: 62ch; text-wrap: pretty; margin-bottom: var(--s5); }

.phases { display: grid; gap: 0; }
.phase { display: grid; grid-template-columns: 8.5rem 1fr; gap: var(--s4); padding: var(--s3) 0; border-top: 1px dashed var(--rule); }
.phase .ph b { display: block; font-size: var(--t-small); font-weight: 550; }
.phase .ph span { font-family: var(--font-mono); font-size: var(--t-micro); color: var(--ink-3); }
.phase .do { max-width: 68ch; text-wrap: pretty; }
@media (max-width: 620px) { .phase { grid-template-columns: 1fr; gap: 2px; } }

.tiers { display: grid; gap: 0; margin-top: var(--s5); }
.tier { display: grid; grid-template-columns: 6rem 1fr; gap: var(--s4); padding: var(--s3) 0; border-top: 1px dashed var(--rule); }
.tier b { font-size: var(--t-micro); letter-spacing: .05em; text-transform: uppercase; color: var(--ink-3); }
.tier b .count {
  font-family: var(--font-mono); letter-spacing: 0; color: var(--accent-ink);
  background: var(--accent-wash); border-radius: var(--pill); padding: 1px 6px; margin-inline-start: 4px;
}
.who { list-style: none; display: flex; flex-wrap: wrap; gap: 4px 6px; margin: var(--s2) 0 0; padding: 0; }
.who-name {
  background: none; border: 1px dashed var(--rule-firm); border-radius: var(--pill);
  padding: 2px 9px; font-size: var(--t-micro); color: var(--ink-2); cursor: pointer;
  transition: border-color var(--fast) var(--out), color var(--fast) var(--out);
}
.who-name:hover { border-style: solid; border-color: var(--accent); color: var(--accent-ink); }
.tier p { font-size: var(--t-small); max-width: 66ch; }
@media (max-width: 620px) { .tier { grid-template-columns: 1fr; gap: 2px; } }

.notes { margin-top: var(--s5); display: grid; gap: var(--s3); }
.notes p { font-size: var(--t-small); max-width: 70ch; text-wrap: pretty; }
.notes b { font-weight: 600; }

/* ------------------------------------------------ teacher's guide procedure */

.guide { margin-top: var(--s5); padding-top: var(--s4); border-top: 1px solid var(--rule-firm); }
.g-head { display: flex; align-items: baseline; gap: var(--s3); margin-bottom: var(--s3); }
.g-head b { font-size: var(--t-small); }
.g-part { display: grid; grid-template-columns: 9.5rem 1fr; gap: var(--s4); padding: var(--s3) 0; border-top: 1px dashed var(--rule); }
.g-part:first-of-type { border-top: 0; }
.g-part > b {
  font-size: var(--t-micro); letter-spacing: .05em; text-transform: uppercase;
  color: var(--ink-3); font-weight: 600;
}
.g-body { max-width: 70ch; }
.g-body p { font-size: var(--t-small); text-wrap: pretty; }
.g-body p + p { margin-top: var(--s2); }
.g-list { margin: var(--s2) 0 0; padding-inline-start: 1.1em; font-size: var(--t-small); }
.g-list li { padding: 2px 0; text-wrap: pretty; }
.g-list + p, p + .g-list { margin-top: var(--s2); }
.g-ex { margin: 0; padding: 0; list-style: none; counter-reset: gex; font-size: var(--t-small); }
.g-ex li {
  position: relative; padding: var(--s2) 0 var(--s2) 0; padding-inline-start: 1.9em;
  border-top: 1px dashed var(--rule); text-wrap: pretty;
}
.g-ex li:first-child { border-top: 0; }
.g-ex li::before {
  counter-increment: gex; content: counter(gex);
  position: absolute; inset-inline-start: 0; top: var(--s2);
  font-family: var(--font-mono); font-size: var(--t-micro); color: var(--ink-3);
}
@media (max-width: 620px) { .g-part { grid-template-columns: 1fr; gap: 2px; } }

/* Answers stay folded — nobody wants them on the projector by accident. */
.g-answers { margin-top: var(--s3); }
.g-answers summary {
  cursor: pointer; font-size: var(--t-small); color: var(--ink-3);
  padding: var(--s2) 0; list-style-position: inside;
}
.g-answers summary:hover { color: var(--ink); }
.g-answers ul { margin: var(--s2) 0 0; padding-inline-start: 1.2em; font-size: var(--t-small); }
.g-answers li { padding: 2px 0; }

.unit-brief { margin-bottom: var(--s6); padding-bottom: var(--s4); border-bottom: 1px solid var(--rule-firm); }
.unit-brief > summary {
  cursor: pointer; display: flex; align-items: baseline; gap: var(--s3);
  padding: var(--s3) 0; list-style-position: inside;
}
.unit-brief > summary:hover b { color: var(--accent-ink); }

.tracks { margin-top: var(--s5); }
.track { display: flex; align-items: center; gap: var(--s3); padding: var(--s3) 0; border-top: 1px dashed var(--rule); font-size: var(--t-small); }
.track .id {
  flex: none; font-family: var(--font-mono); font-size: var(--t-micro); font-weight: 500;
  padding: 3px 8px; border-radius: var(--radius-sm);
  background: var(--accent-wash); color: var(--accent-ink);
}
.track .desc { flex: 1; min-width: 0; }
.track audio { height: 30px; max-width: 210px; }
.track .missing { color: var(--ink-3); font-size: var(--t-micro); font-style: italic; }

/* ──────────────────────────────────────────────────────────── timetable */

.scroll-x { overflow-x: auto; }
.timetable { width: 100%; border-collapse: collapse; font-size: var(--t-small); }
.timetable th, .timetable td { padding: var(--s3) var(--s2); text-align: center; border-bottom: 1px dashed var(--rule); }
.timetable thead th {
  border-bottom: 1px solid var(--rule-firm); color: var(--ink-3);
  font-size: var(--t-micro); font-weight: 550; letter-spacing: .03em; white-space: nowrap;
}
.timetable thead th .t { display: block; font-family: var(--font-mono); color: var(--ink-3); }
.timetable tbody th { text-align: start; font-weight: 600; white-space: nowrap; }
.timetable td.free { color: var(--ink-3); }
.timetable td.has { cursor: pointer; font-weight: 550; transition: background var(--fast) var(--out); }
.timetable td.has:hover { background: var(--bg-2); }
.timetable tr.today th, .timetable tr.today td { background: var(--accent-wash); }
.timetable tr.today th { color: var(--accent-ink); }
.timetable td.duty { color: var(--late); font-weight: 550; background: var(--late-wash); }
/* Period 7 does not exist Monday to Thursday: no dash, because there is no
   lesson there to be free of. */
.timetable td.off { background: repeating-linear-gradient(135deg, transparent 0 5px, var(--rule) 5px 6px); }
.timetable .brk-col { width: 44px; padding: var(--s3) 2px; background: var(--bg-2); color: var(--ink-3); }
.timetable .brk-col span, .timetable thead .brk-col .t {
  display: block; font-size: var(--t-micro); font-family: var(--font-mono);
  writing-mode: vertical-rl; margin-inline: auto; white-space: nowrap;
}
.timetable tr.today .brk-col { background: var(--bg-2); }

/* ────────────────────────────────────────────────────────────── reports */

.rtable { width: 100%; border-collapse: collapse; font-size: var(--t-small); }
.rtable th, .rtable td { padding: var(--s3) var(--s3); text-align: start; border-bottom: 1px dashed var(--rule); }
.rtable thead th {
  border-bottom: 1px solid var(--rule-firm); color: var(--ink-3);
  font-size: var(--t-micro); font-weight: 550; letter-spacing: .04em; text-transform: uppercase;
}
.rtable td.num { text-align: end; font-family: var(--font-mono); }
.rtable tbody tr:hover { background: var(--bg-2); }
.meter { display: flex; align-items: center; gap: var(--s2); }
.meter .track-bg { flex: 1; min-width: 56px; height: 3px; background: var(--rule); border-radius: 2px; overflow: hidden; }
.meter .track-bg span { display: block; height: 100%; background: var(--accent); }
.meter .pct { font-family: var(--font-mono); font-size: var(--t-micro); color: var(--ink-3); white-space: nowrap; }

/* The card's skill table is only three columns — left full width it strands a
   lake of space between the label and the bar. */
.rtable.skills { max-width: 640px; }
.rtable.skills th:nth-child(1), .rtable.skills td:nth-child(1) { width: 40%; }
.rtable.skills th:nth-child(2), .rtable.skills td:nth-child(2) { width: 18%; }

/* performance card — what needs work */
.need { padding: var(--s4) 0; border-top: 1px dashed var(--rule); }
.need:first-of-type { border-top: 0; }
.need b { display: block; font-size: var(--t-micro); letter-spacing: .05em; text-transform: uppercase; color: var(--ink-3); margin-bottom: 4px; }
.need p { max-width: 72ch; text-wrap: pretty; }
.hist li b { font-family: var(--font-mono); }

/* ────────────────────────────────────────────────────────────── toolkit */

.tk-tiers { display: grid; gap: 0; border-top: 1px solid var(--rule-firm); }
.tk-tier { display: grid; grid-template-columns: minmax(9rem, 14rem) 1fr; gap: var(--s5); padding: var(--s5) 0; border-bottom: 1px dashed var(--rule); }
.tk-tier h3 { font-size: var(--t-h3); }
.tk-tier .desc { font-size: var(--t-small); color: var(--ink-2); max-width: 60ch; }
.tk-tier ul { margin: var(--s2) 0 0; padding-inline-start: 1.1em; font-size: var(--t-small); color: var(--ink-2); }
@media (max-width: 700px) { .tk-tier { grid-template-columns: 1fr; gap: var(--s2); } }

.tk-item { padding: var(--s4) 0; border-top: 1px dashed var(--rule); }
.tk-item h4 { font-size: var(--t-body); font-weight: 600; }
.tk-item p { font-size: var(--t-small); max-width: 72ch; text-wrap: pretty; }
.tk-item .script { margin-top: var(--s2); font-size: var(--t-small); color: var(--ink-3); font-style: italic; }

/* ──────────────────────────────────────────── weekly parent form (slips) */

/* Each slip is a document a guardian reads, so it is always Arabic and always
   right-to-left, whichever language the teacher has the console set to. */
.slips { margin-top: var(--s6); }
.slip {
  direction: rtl; text-align: start;
  padding: var(--s5) 0; border-top: 1px solid var(--rule-firm);
}
.slip-head { display: flex; justify-content: space-between; align-items: baseline; gap: var(--s4); flex-wrap: wrap; }
.slip-head b { font-size: var(--t-body); font-weight: 600; }
.slip-name { font-size: var(--t-h2); margin: var(--s4) 0 var(--s3); }

.slip-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s5); }
@media (max-width: 620px) { .slip-grid { grid-template-columns: 1fr; gap: var(--s4); } }
.slip h4 {
  font-size: var(--t-micro); letter-spacing: .05em; text-transform: uppercase;
  color: var(--ink-3); margin-bottom: var(--s2);
}
.slip-list { list-style: none; margin: 0; padding: 0; font-size: var(--t-small); }
.slip-list li {
  display: flex; justify-content: space-between; gap: var(--s3);
  padding: 5px 0; border-top: 1px dashed var(--rule);
}
.slip-list li:first-child { border-top: 0; }
.st-absent  { color: var(--absent); }
.st-late    { color: var(--late); }
.st-excused { color: var(--excused); }
.st-none    { color: var(--ink-3); font-weight: 400; }

.slip-cover { margin-top: var(--s4); padding-top: var(--s3); border-top: 1px dashed var(--rule); }
.slip-cover .vocab { font-family: var(--font-mono); font-size: var(--t-micro); unicode-bidi: isolate; }

.slip-sign { margin-top: var(--s4); }
.slip-sign .rule-line { height: 0; border-top: 1px dashed var(--rule-firm); margin: var(--s5) 0 var(--s2); }
.slip-sign-row { display: flex; justify-content: space-between; gap: var(--s4); flex-wrap: wrap; }
.slip-actions { margin-top: var(--s4); }

/* ───────────────────────────────────────────────────────── skeleton / toast */

.skeleton { display: grid; gap: var(--s2); grid-template-columns: repeat(auto-fill, minmax(116px, 1fr)); }
.skeleton i {
  height: 66px; border-radius: var(--radius-sm);
  border: 1px dashed var(--rule); background: var(--bg-2);
}
@media (prefers-reduced-motion: no-preference) {
  .skeleton i { animation: shimmer 1.4s var(--out) infinite; }
  .skeleton i:nth-child(2n) { animation-delay: .12s; }
  .skeleton i:nth-child(3n) { animation-delay: .24s; }
}
@keyframes shimmer { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }

.empty { padding: var(--s7) 0; border-top: 1px dashed var(--rule); }
.empty h3 { margin-bottom: var(--s2); }
.empty p { font-size: var(--t-small); color: var(--ink-3); max-width: 52ch; }

.toast {
  position: fixed; inset-block-end: var(--s5); inset-inline: 0; z-index: var(--z-toast);
  margin-inline: auto; width: fit-content;
  background: var(--ink); color: var(--bg);
  padding: 9px 18px; border-radius: var(--pill); font-size: var(--t-small);
  animation: rise 220ms var(--out);
}

/* ──────────────────────────────────────────────────────────────── print */

@page { size: A4; margin: 14mm; }

@media print {
  .topbar, .nav, .ghost, .pill, .week-nav, .rules, .icon-btn, .lang-btn,
  .no-print, .hero, .book-switch, .inline-select { display: none !important; }
  body { background: #fff; color: #000; }
  /* @page supplies the paper margin; the small inline padding keeps glyphs off
     the edge in browsers that print with a zero margin box. */
  main { padding: 0 4mm; max-width: none; }
  .seat { break-inside: avoid; }

  /* One parent slip per sheet. */
  .slips { margin: 0; }
  .slip {
    break-after: page; break-inside: avoid;
    border-top: 0; padding: 0 0 var(--s6);
    min-height: 0;
  }
  .slip:last-child { break-after: auto; }
  .slip-list li, .slip-cover, .slip-sign .rule-line { border-color: #999; }
  /* printing a lesson should print the guide procedure with it */
  .guide, .g-part { break-inside: avoid; }
  .unit-brief[open] > summary { list-style: none; }
  .slip h4, .slip .muted { color: #444; }
}

/* ------------------------------------------------------- the class timeline

   The book in order, per class: what was taught, what is next, and the page each
   lesson is worked from. It is a checklist, not a chart — the teacher's question
   is "where are 6C" and the answer is a row he can point at.

   `done` fades but does not disappear: a term is also a record of what happened,
   and the printed copy is the evidence. `next` is the only row with the accent,
   because at any moment exactly one lesson is the one to teach.               */

.tl-bar {
  margin-top: var(--s4); height: 6px; border-radius: var(--pill);
  background: var(--rule); overflow: hidden; max-width: 520px;
}
.tl-bar span { display: block; height: 100%; background: var(--accent); }

.timeline { list-style: none; margin: 0; padding: 0; }
.timeline li {
  display: grid; grid-template-columns: 4.5rem 1fr auto auto;
  align-items: center; gap: var(--s4);
  padding: var(--s3) 0; border-top: 1px dashed var(--rule);
}
.timeline li:first-child { border-top: 0; }
.timeline li.done { color: var(--ink-3); }
/* In a list of fifty-seven rows, the one to teach next has to be findable from
   the top of the page rather than read for. */
.timeline li.next {
  background: var(--accent-wash);
  box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--accent) 26%, transparent);
  border-radius: var(--radius-sm); border-top-color: transparent;
  padding-inline: var(--s3); margin-inline: calc(var(--s3) * -1);
}

.tl-when { font-size: var(--t-micro); color: var(--ink-3); letter-spacing: .04em; }
.tl-when i { font-style: normal; opacity: 0.6; }
.timeline li.next .tl-when { color: var(--accent-ink); font-weight: 600; }

.tl-what { min-width: 0; display: flex; flex-direction: column; gap: 1px; }
/* Book strand titles run long ("A story about making a new friend (comparing and
   contrasting information)"), and on a phone the column is narrow enough that one
   of them has nowhere to break. */
.tl-what b { font-size: var(--t-body); font-weight: 550; unicode-bidi: isolate; overflow-wrap: anywhere; }
.timeline li.done .tl-what b { font-weight: 400; }
.tl-what i { font-style: normal; font-size: var(--t-micro); color: var(--ink-3); }

.tl-page {
  flex: none; font-size: var(--t-micro); padding: 2px 9px; border-radius: var(--pill);
  background: var(--accent-wash); color: var(--accent-ink);
  border: 1px solid color-mix(in oklab, var(--accent) 28%, transparent);
}
.tl-page.none { background: none; border-color: transparent; color: var(--ink-3); }

.tl-tick {
  display: flex; align-items: center; gap: 7px; min-width: 8.5rem; justify-content: flex-end;
  font: inherit; font-size: var(--t-micro); cursor: pointer; color: var(--ink-3);
  padding: 6px 11px; border-radius: var(--pill);
  background: none; border: 1px dashed var(--rule-firm);
  transition: all var(--fast) var(--out);
}
.tl-tick:hover { border-style: solid; color: var(--ink); }
.tl-tick em { font-style: normal; font-family: var(--font-mono); }
.tl-tick[aria-pressed="true"] {
  border-style: solid; border-color: color-mix(in oklab, var(--accent) 40%, transparent);
  background: var(--accent-wash); color: var(--accent-ink);
}

@media (max-width: 620px) {
  .timeline li { grid-template-columns: 3.2rem 1fr auto; row-gap: var(--s2); }
  .tl-tick { grid-column: 2 / -1; justify-content: flex-start; min-width: 0; }
}

@media print {
  .tl-tick { border: 0; padding: 0; }
}
