/* ══════════════════════════════════════════════════════════════════════════
   takhte — the Plume look on takhte's anatomy (docs/adr/0026, docs/08).

   ONE palette, light: Taher's green, with its inks stepped a little darker
   than Plume's so that every one of them keeps 4.5:1 on the patterned
   ground's deepest point (docs/08 §ink). No theme switch, no dark cut.

   The ground is patterned — pools of sunlight and moss under a fine grid, on
   one fixed layer behind the page — and what a person reads and uses sits on
   the SURFACE: cards at a 10px radius, controls at 7px, dialogs at 14px, pills
   for chips. ONE soft shadow, and only on what floats above the page: the
   palette, a modal, a popover, a toast, the drawer. The audit measures both
   rules (e2e/src/audit.ts: shapeFacts) and measures text that reaches the
   ground against its deepest point (--ground-deep).

   Built for the people who use it most: a teacher at a desktop who is not
   young, and a student on a small phone. So the type ladder starts at 12px and
   body text is 15px; every control is 44px on every shell (the teacher
   density layer is retired); quiet text is quiet by token, never by opacity;
   a row's verb is visible, never hover-only; a task that interrupts the page
   opens in a modal that has one clear way out.

   Kept from dv4 and Taher: RTL-first logical properties, hairlines rather than
   boxes inside a card, one primary ink (green) and one highlight
   (gold-brown), amber means "waiting on you", weight at most 600, drawn dots,
   Persian digits in copy, and IRANSansWeb(FaNum) as the one face.

   Tap floors stay in px: they are physical, not typographic, and must not
   move with the type scale.
   ══════════════════════════════════════════════════════════════════════════ */

/* IRANSansWeb(FaNum) — the exact face dv4 ships (dv4 myfont.scss), converted
   woff→woff2. ONE regular cut: anything ≥600 is browser-synthesized bold and
   500 renders as the regular glyph, which is precisely why dv4 never shouts.
   FaNum: ASCII digits render with Persian shapes. Proprietary (FontIran),
   licensed alongside dv4 — not OFL like the Vazirmatn it replaced.
   The URL is rewritten to a content-addressed one at startup (src/assets.rs);
   `/static/ec4f7d2095721e4264ba40573dfc1d61.woff2` never reaches a browser. */
@font-face {
  font-family: "IRANSans";
  src: url("/static/ec4f7d2095721e4264ba40573dfc1d61.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;          /* fallback text for 200ms beats no text */
}

/* ── Identifiers. FaNum draws every ASCII digit with a Persian shape, so a
   login such as `student7` read as «student۷» wherever it appeared — and a
   new student reading the printed slip tried to type ۷. Logins take the
   sheet's Latin monospace, in text and in the fields a person types one into
   (docs/05: identifiers are not copy). ─────────────────────────────────── */
/* `.input` sets the `font` shorthand, which resets the family, so the field
   rules need the extra class to win. */
.login, .input.login, .input[name="login"], .c-login { font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: .95em; }
.login { direction: ltr; unicode-bidi: isolate; }
/* The hint inside an empty login field is Persian copy, not an identifier:
   it keeps the page's face and direction. */
.input.login::placeholder, .input[name="login"]::placeholder { font-family: "IRANSans", Tahoma, system-ui, sans-serif; direction: rtl; }

/* ── Matching pairs: the author's rows and the candidate's controls. ─────── */
.matching-editor-rows, .matching-question { display: grid; gap: .5rem; }
.matching-editor-rows { margin-bottom: .35rem; }
.matching-editor-row { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto; gap: .5rem; align-items: center; }
/* Row removal is a red text link like an attachment's «حذف»; adding a row is
   a quiet link — a bordered box on every row and a full-width grey bar read
   as one disabled control after another. */
.matching-editor-row .danger-button { border-color: transparent; background: none; box-shadow: none; padding: 0 .45rem; }
.matching-editor-row .danger-button:hover { background: var(--red-tint); }
.matching-editor-add { display: inline-flex; align-items: center; min-block-size: var(--tap); padding: 0 .2rem; border: none; background: none; color: var(--blue); font-size: var(--t-small); font-weight: 600; cursor: pointer; }
.matching-editor-add:hover { text-decoration: underline; }
.matching-question label { display: grid; grid-template-columns: minmax(7.5rem, 1fr) minmax(10rem, 1fr); gap: .75rem; align-items: center; }
.quiz-hint { margin-top: .3rem; color: var(--faint); font-size: var(--t-meta); }

/* ── The one-time credential sheet: hairline cards, no radius, the slip's
   password face; two columns when printed. ─────────────────────────────── */
.credential-sheet { display: grid; grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr)); gap: .75rem; margin-top: 1rem; }
.credential-card { border: 1px solid var(--line-2); border-radius: var(--r); padding: .9rem 1rem; background: var(--surface); }
.credential-card > strong { display: block; font-weight: 600; margin-bottom: .35rem; }
.credential-card dl { margin: 0; }
.credential-card dl div { display: flex; justify-content: space-between; align-items: baseline; gap: .75rem; padding: .35rem 0; border-top: 1px solid var(--line); }
.credential-card dt { color: var(--muted); font-size: var(--t-meta); }
.credential-card dd { margin: 0; }
.credential-foot { margin-top: 1.2rem; }
@media (max-width: 43rem) { .matching-editor-row, .matching-question label { grid-template-columns: 1fr; } }
@media print { .side, .top, .mobile-nav, .page-hd-actions, .crumb, .notice, .credential-foot { display: none !important; } .wrap, .body { display: block !important; margin: 0 !important; padding: 0 !important; } .credential-sheet { grid-template-columns: repeat(2, 1fr); } }

/* ══════════════════════════════════════════════════════════════════════════
   TOKENS. The palette first, then the names the components use, each named
   for its job (Plume's names), then the shape scale, the type ladder and the
   ground. Every component reads these; none writes a colour of its own.
   ══════════════════════════════════════════════════════════════════════════ */
:root {
  color-scheme: light;

  /* The palette — docs/08 §palette records each ink's ratio on every ground
     it can sit on. */
  --bg0: #e9f4ee;              /* the ground, under its pattern */
  --bg1: #dcece3;              /* a hairline between things on the surface */
  --bg2: #cfe2d6;              /* a control's edge; a hovered card's edge */
  --bg3: #b8d0c1;              /* a quiet mark: an idle dot, a spent rail */
  --content: #f3faf6;          /* the surface */
  --fg0: #1b2420;              /* emphasis */
  --fg1: #2b3a32;              /* body and titles */
  --fg2: #3a4a41;              /* a label a step under the body */
  --fg3: #56655c;              /* muted, on any ground */
  --fg4: #5b6a61;              /* faint — 4.6:1 even on --bg1, so legal everywhere */
  --blue: #1f7231;             /* the PRIMARY: links, buttons, focus, the current page */
  --accent: #886000;           /* the HIGHLIGHT: counts, chips, bars, progress */
  --amber: #8f4f00;            /* waiting on you */
  --aqua: #0a6878;             /* affirmative */
  --red: #b52424;              /* negative */
  --mark: #b07d00;             /* the logo's gold (docs/logo): the brand tile, never on green */

  --accent-rgb: 232, 163, 26;
  --neutral-rgb: 200, 212, 204;
  --accent-tint: rgba(232, 163, 26, .12);
  --accent-tint-hover: rgba(232, 163, 26, .18);
  --accent-edge: rgba(232, 163, 26, .28);
  --accent-edge-hover: rgba(232, 163, 26, .42);
  --bar-bg: #2b3a32;
  --bar-fg: #eef5f0;

  /* Names by job. A hover and a chip are laid ON the surface rather than over
     whatever is under them, so each is one opaque colour on a card and on the
     patterned ground alike, and grey text on it keeps 4.5:1. */
  --ground: var(--bg0);
  --surface: var(--content);
  --raised: var(--content);
  --line: var(--bg1);
  --line-2: var(--bg2);
  --ink: var(--fg0);
  --ink-2: var(--fg1);
  --muted: var(--fg3);
  --faint: var(--fg4);
  --sunk: color-mix(in srgb, var(--bg0) 55%, var(--content));
  --hover: color-mix(in srgb, rgb(var(--neutral-rgb)) 30%, var(--content));
  --chip: color-mix(in srgb, rgb(var(--neutral-rgb)) 17%, var(--content));
  --row-hover: var(--hover);
  --primary-tint: color-mix(in srgb, var(--blue) 8%, var(--content));
  --primary-edge: color-mix(in srgb, var(--blue) 35%, var(--content));
  /* The highlight as text on its own tint: a step deeper, so it keeps 4.5:1. */
  --accent-ink: color-mix(in srgb, var(--accent) 82%, var(--fg0));
  --amber-tint: color-mix(in srgb, var(--amber) 9%, var(--content));
  --aqua-tint: color-mix(in srgb, var(--aqua) 8%, var(--content));
  --red-tint: color-mix(in srgb, var(--red) 7%, var(--content));
  --on-accent: #ffffff;
  --scrim: rgba(16, 30, 22, .42);
  --shadow-pop: 0 16px 40px -10px rgba(16, 36, 26, .24), 0 2px 6px rgba(16, 36, 26, .07);
  --ring: 0 0 0 3px color-mix(in srgb, var(--blue) 22%, transparent);
  --ease: cubic-bezier(.23, 1, .32, 1);

  /* The shape scale (ADR-0026). The audit refuses anything else above 3.5px. */
  --r-sm: 7px;                 /* controls: buttons, fields, menu items */
  --r: 10px;                   /* cards, tiles, notices, empty states */
  --r-pop: 11px;               /* popovers and menus */
  --r-lg: 14px;                /* dialogs: the palette, a modal, sign-in */
  --pill: 999px;               /* chips, badges, counts */

  /* The type ladder: nine steps, nothing under 12px. The IRANSans x-height
     reads small against a Latin face at the same size, and the people who
     read these pages most are not young — so the floor holds, in pixels.
     The steps are relative to the root, and the root is 87.5% (below): the
     sizes on the right are what they come to at a browser's default 16px. */
  --t-micro: max(12px, .75rem);    /* 12 — micro-labels, counts inside badges */
  --t-meta: max(12px, .8125rem);   /* 12 — bylines, meta lines, small print */
  --t-small: .875rem;          /* 12.25 — tabs, chips, secondary text */
  --t-body: .9375rem;          /* 13.1 — body, row titles, buttons */
  --t-lead: 1rem;              /* 14 — fields, card titles, a row that leads */
  --t-read: 1.0625rem;         /* 14.9 — reading text: a lesson, a post, feedback */
  --t-section: 1.125rem;       /* 15.75 — section titles */
  --t-sub: 1.25rem;            /* 17.5 — a big number, a sub-page title */
  --t-title: 1.625rem;         /* 22.75 — the page title */

  --tap: 44px;                 /* floor, not a preference — docs/08 */

  /* Controls (docs/08 §controls): a button and a field share one height and
     one face. 44px wherever a finger may drive — a narrow layout, a coarse
     pointer — and 36px where a mouse drives a wide one: Taher's law 7, drawn
     as Plume draws it (its 34px, plus room for the dots under IRANSans's
     line). Rows, links and the shell keep --tap. */
  --h: 44px;
  --control: #ffffff;          /* the face: white, one step up from the card it sits on */
  --control-edge: color-mix(in srgb, var(--fg3) 28%, var(--content));
  --control-edge-hover: color-mix(in srgb, var(--fg3) 50%, var(--content));
  --control-lift: 0 1px 2px rgba(16, 36, 26, .07);  /* the face's own lower edge: 2px of blur is an edge, not elevation (the shape gate) */
  --primary-fill: #237a36;     /* Plume's green, as a fill under white text (5.4:1); text on the ground keeps --blue */
  --primary-fill-hover: color-mix(in srgb, var(--primary-fill) 86%, var(--fg0));
  --nav-w: 16rem;

  /* The ground's pattern. Pools are coloured more than they are dark: the
     sunlight's core (--sun) is their deepest point, and every ink that sits
     on the ground keeps 4.5:1 there. The grid is lighter than the ground, so
     it costs no ink any contrast. A change to a pool changes --ground-deep. */
  --sun: #fbefc9;
  --moss: #e2f7cc;
  --rule: rgba(255, 255, 255, .45);  /* the grid's ink; the SVG below repeats it — a data URI cannot read a custom property */
  --ground-deep: var(--sun);
}
/* The compact controls: a wide layout under a precise pointer. The audit asks
   the page the same question (e2e/src/audit.ts `tapFloorFor`). */
@media (min-width: 62rem) and (pointer: fine) {
  /* Rows and links too, not only controls: a list of 44px rows under 13px type
     was most of what still read as big. 36px is above the audit's 32px floor
     for a precise pointer; a finger keeps 44. */
  :root { --h: 36px; --tap: 36px; }
}

@media print { .sheet-page { background: #fff !important; } }

/* ── The settings page follows the class page's anatomy: `.manage-section`
   cards with a 34rem form, an aside with the page's own table of contents.
   There is no appearance section: the product has one look (ADR-0026). ──── */
.settings .manage-section:first-child { padding-top: 0; }
.settings .form { max-width: 34rem; }
.settings-notice { max-width: 48rem; margin-bottom: .6rem; }
.settings .form-row--two { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.notification-preferences fieldset { border: 0; padding: 0; }
.notification-preferences legend { margin-bottom: .55rem; font-size: var(--t-small); font-weight: 600; }
.preference-row { display: grid; grid-template-columns: minmax(9rem, 1fr) repeat(3, auto); align-items: center; gap: .35rem 1rem; min-height: var(--tap); padding-block: .45rem; border-bottom: 1px solid var(--bg2); font-size: var(--t-small); }
.preference-row label { display: inline-flex; align-items: center; gap: .3rem; min-height: var(--tap); white-space: nowrap; }
@media (max-width: 40rem) { .preference-row { grid-template-columns: 1fr; gap: 0; } }

*, *::before, *::after { box-sizing: border-box; }

/* The whole page two steps down (2026-09-28, the product owner: "everything is
   too big", and then of smaller type alone, "I don't feel it"): the root, not the
   ladder, because nearly every padding, gap and margin here is in rem, and a page
   whose type shrank inside the same boxes still reads as big. A percentage of the
   reader's own size, so one who raised the browser's size keeps it. Media queries
   do not see this — their rem is the browser's — so no breakpoint moves. */
html {
  font-size: 87.5%;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--ground);
  color: var(--fg1);
  font-family: "IRANSans", Tahoma, system-ui, sans-serif;
  font-size: var(--t-body);
  line-height: 1.65;           /* Persian's dots and descenders want room */
  -webkit-font-smoothing: antialiased;
}

/* THE GROUND — a forest floor, mirrored for RTL: sunlight from the top-left
   (the side away from the sidebar), moss down the sidebar's edge and at the
   bottom-left, a white light over the sidebar's head, and over them a grid —
   a line every 90px that stops short of each crossing, with a dot on it.
   ONE fixed layer behind everything: the compositor scrolls it without a
   repaint. Never `background-attachment: fixed`, which Chromium repaints on
   the main thread for every scrolled frame. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='90' height='90'%3E%3Cpath d='M0 45.5h35m20 0h35M45.5 0v35m0 20v35' stroke='%23fff' stroke-opacity='.45'/%3E%3Ccircle cx='45.5' cy='45.5' r='1.5' fill='%23fff' fill-opacity='.45'/%3E%3C/svg%3E") 0 0 / 90px 90px,
    radial-gradient(46vmax 32vmax at 20% 0%, var(--sun), color-mix(in srgb, var(--sun) 84%, transparent) 25%, color-mix(in srgb, var(--sun) 50%, transparent) 50%, color-mix(in srgb, var(--sun) 16%, transparent) 75%, transparent),
    radial-gradient(34vmax 34vmax at 98% 70%, var(--moss), color-mix(in srgb, var(--moss) 84%, transparent) 25%, color-mix(in srgb, var(--moss) 50%, transparent) 50%, color-mix(in srgb, var(--moss) 16%, transparent) 75%, transparent),
    radial-gradient(32vmax 22vmax at 0% 90%, color-mix(in srgb, var(--moss) 84%, transparent), color-mix(in srgb, var(--moss) 50%, transparent) 30%, color-mix(in srgb, var(--moss) 16%, transparent) 65%, transparent),
    radial-gradient(30vmax 18vmax at 76% 4%, rgba(255, 255, 255, .55), transparent);
}
@media (forced-colors: active) { body::before { display: none; } }
@media print { body::before { display: none; } body { background: #fff; } }

/* The browser's 700 default for headings and <strong> is the loudest voice in
   the file; titles are 600, and weight above 600 exists nowhere. */
h1, h2, h3 { font-weight: 600; }

h1, h2, p, ul, ol, figure { margin: 0; }
ul, ol { padding: 0; list-style: none; }
a { color: inherit; text-decoration: none; }
svg { display: block; flex-shrink: 0; }
button { font: inherit; color: inherit; }

a:focus-visible,
button:focus-visible,
summary:focus-visible,
input:focus-visible {
  outline: 2px solid var(--blue);
  outline-offset: 2px;
}

/* ══════════════════════════════════════════════════════════════════════════
   SHELL — Plume's shell with takhte's parts. The sidebar is chrome on the
   patterned ground: the brand tile, the workspace switcher, the places and
   each class, the current one lifted onto the surface. The page's top row
   carries the search, the notices, who is signed in and the way out — the
   SAME controls at every width, so nothing a person needs hides in a drawer
   (docs/08 §shell; the journeys press logout on a phone). On a phone the
   sidebar becomes a drawer from the right — the inline START in RTL — and the
   bottom bar carries the five places.
   ══════════════════════════════════════════════════════════════════════════ */
.app { display: flex; min-height: 100vh; }

.side {
  flex: 0 0 var(--nav-w);
  /* Without this the sidebar is as wide as its longest class title: a flex
     item's automatic minimum size is its min-content, and `white-space:
     nowrap` on a truncating link makes that the whole untruncated string. */
  min-width: 0;
  position: sticky;
  top: 0;
  align-self: flex-start;
  height: 100vh;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: .1rem;
  padding: .85rem .7rem 1.25rem;
  border-inline-end: 1px solid var(--line-2);
  scrollbar-width: thin;
}

/* The brand: the mark in white on its gold tile, as the app icon draws it
   (docs/logo), then the name. */
.side-brand {
  display: flex;
  align-items: center;
  gap: .65rem;
  min-height: var(--tap);
  padding: .1rem .45rem .55rem;
  color: var(--ink);
  font-size: var(--t-section);
  font-weight: 600;
}
.side-brand svg {
  box-sizing: content-box;
  padding: 6px;
  border-radius: 7px;
  background: var(--mark);
  color: var(--on-accent);
}

/* A group's name above its places. */
.side-label {
  padding: 1rem .6rem .3rem;
  font-size: var(--t-micro);
  font-weight: 600;
  color: var(--muted);
}

/* A place. The current one sits on the surface with a hairline — the same
   lift a card has — and its icon takes the primary. Places and classes are
   as tall as a control (--h): 36px under a mouse on a wide layout, as
   Plume's are, and 44px under a finger — the drawer on a phone. */
.side-btn {
  display: flex;
  align-items: center;
  gap: .6rem;
  width: 100%;
  min-height: var(--h);
  padding: .3rem .6rem;
  border: none;
  border-radius: var(--r-sm);
  background: none;
  color: var(--fg1);
  font-size: var(--t-body);
  font-weight: 500;
  line-height: 1.4;
  text-align: start;
  cursor: pointer;
  transition: background-color .12s, color .12s;
}
.side-btn:hover { background: var(--hover); color: var(--ink); }
.side-btn.is-active { background: var(--surface); box-shadow: inset 0 0 0 1px var(--line-2); color: var(--ink); font-weight: 600; }
.side-btn .ico { display: flex; color: var(--muted); }
.side-btn.is-active .ico { color: var(--blue); }
.side-btn .label { flex: 1 1 auto; min-width: 0; }
.side-btn .chev { color: var(--muted); display: flex; transition: transform .12s; }

/* A class under "my classes": indented behind a small dot that turns green
   for the one open now. */
.side-sub-link {
  position: relative;
  display: flex;
  align-items: center;
  min-height: var(--h);
  padding: .3rem .6rem;
  padding-inline-start: 2.15rem;
  border-radius: var(--r-sm);
  color: var(--fg2);
  font-size: var(--t-small);
  transition: background-color .12s, color .12s;
}
.side-sub-link::before {
  content: "";
  position: absolute;
  inset-inline-start: 1.05rem;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--line-2);
}
.side-sub-link:hover:not(.is-active) { background: var(--hover); color: var(--ink); }
.side-sub-link.is-active { background: var(--surface); box-shadow: inset 0 0 0 1px var(--line-2); color: var(--ink); font-weight: 600; }
.side-sub-link.is-active::before { background: var(--blue); }
/* `min-width: 0` is what makes the ellipsis work (docs/08). */
.side-sub-name {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The page: no plane of its own — it stands on the ground, and its cards are
   the surface. */
.wrap { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }

/* The top row: the search as a wide field-like button at the start, and at
   the far end the notices, the person and the way out. */
.top {
  display: flex;
  align-items: center;
  gap: .4rem;
  min-height: 60px;
  padding: .55rem 2rem 0;
}
.qa-trigger {
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  inline-size: min(25rem, 100%);
  min-height: var(--h);
  padding: 0 .85rem;
  border: 1px solid var(--control-edge);
  border-radius: var(--r-sm);
  background: var(--control);
  color: var(--muted);
  font-size: var(--t-body);
  text-align: start;
  cursor: pointer;
  transition: border-color .12s, color .12s, transform .12s var(--ease);
}
.qa-trigger > span { flex: 1 1 auto; }
.qa-trigger:hover { border-color: var(--control-edge-hover); color: var(--ink); }
.qa-trigger:active { transform: scale(.99); }
.qa kbd, .qa-trigger kbd {
  padding: .1rem .4rem;
  border: 1px solid var(--line-2);
  border-radius: 5px;
  background: var(--surface);
  color: var(--muted);
  font-family: ui-monospace, monospace;
  font-size: var(--t-micro);
  line-height: 1.5;
}
.top .who {
  margin-inline-start: auto;
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  min-width: 0;
  padding: .2rem .35rem;
  font-size: var(--t-body);
  color: var(--fg2);
}
.top .who-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 600; color: var(--ink); }
.who-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  inline-size: 2rem;
  block-size: 2rem;
  border-radius: 50%;
  background: var(--accent-tint);
  color: var(--accent-ink);
}
.top a, .top .linkish {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: var(--tap);
  min-inline-size: var(--tap);
  padding: 0 .7rem;
  border-radius: var(--r-sm);
  color: var(--fg2);
  font-size: var(--t-body);
  transition: background-color .12s, color .12s;
}
.top a:hover, .top .linkish:hover { background: var(--hover); color: var(--ink); }
.top .top-notification { position: relative; padding: 0; }
.top-notification-count {
  position: absolute;
  inset-block-start: .2rem;
  inset-inline-end: .1rem;
  min-width: 1.2rem;
  padding: 0 .3rem;
  border: 2px solid var(--ground);
  border-radius: var(--pill);
  background: var(--amber);
  color: var(--on-accent);
  font-size: var(--t-micro);
  font-weight: 600;
  line-height: 1.35;
  text-align: center;
}
.inline-form { display: inline-flex; }
.linkish { background: none; border: none; cursor: pointer; }
/* Author styles beat the UA's [hidden]; without this reset an .icon-btn
   stays visible even while hidden. */
[hidden] { display: none !important; }
.top .nav-toggle { display: none; }
.nav-backdrop { display: none; }

/* The page's column. */
.body { min-width: 0; flex: 1 1 auto; padding: .6rem 2rem 3rem; }

/* sidebar ‹ main ‹ aside — dv4's show pages. Main is written first and laid
   out first, so in RTL it stands beside the nav sidebar and the info aside
   lands on the far left. A grid, so it stacks on a phone with no breakpoint
   to keep in sync (docs/08). */
.cols {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 17.5rem;
  gap: 1.5rem;
  align-items: start;
}
.col-main { min-width: 0; }
/* A workbench whose own outline is its navigation (the content builder)
   has no aside to repeat the strip in: the width goes to the work. */
.cols--solo { grid-template-columns: minmax(0, 1fr); }
/* The aside column stretches to the row so `.aside-inner` has room to stick:
   under `align-items: start` the column was only as tall as its own content,
   and "sticky" had nowhere to go (found by measuring, 2026-09-04). */
.col-aside { align-self: stretch; min-width: 0; }
.aside-inner { position: sticky; top: 1rem; }
/* dv4's edit sidebar holds the uploads; at the aside's width the file rows
   drop their icon and let the actions share the name's line. */
.aside-inner .attachment-list > div { display: flex; flex-wrap: wrap; align-items: center; }
.aside-inner .attachment-list > div > span { flex: 1 1 100%; min-width: 0; }
.aside-inner .attachment-list .file-mark { display: none; }
.aside-inner .attachment-upload { flex-direction: column; align-items: stretch; }

@media (max-width: 62rem) {
  .cols { grid-template-columns: minmax(0, 1fr); gap: 1rem; }
  .aside-inner { position: static; }
  .side { display: none; }
  .top { min-height: 56px; padding: .45rem .75rem 0; gap: .2rem; }
  .body { padding: .5rem .75rem 2rem; }
  /* The search keeps its name for assistive technology and shows only its
     glass; the name in the row gives way first. */
  .qa-trigger { inline-size: auto; padding: 0; justify-content: center; min-inline-size: var(--tap); }
  .qa-trigger > span, .qa-trigger kbd { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  .top .who { font-size: var(--t-small); }
  .who-mark { display: none; }
  /* The bottom nav carries the five primary destinations; everything else in
     the sidebar — the class links, the workspace switcher, settings — opens
     as a drawer from the toggle. An overlay, so it takes the one shadow. */
  .top .nav-toggle { display: inline-flex; }
  body.nav-open .side {
    display: flex;
    position: fixed;
    inset-block: 0;
    inset-inline-start: 0;    /* the sidebar's own edge: the right, in RTL */
    z-index: 70;
    width: min(19rem, 85vw);
    height: auto;
    border-inline-end: 0;
    border-start-end-radius: 16px;
    border-end-end-radius: 16px;
    background: var(--surface);
    box-shadow: var(--shadow-pop);
    animation: drawer-in .24s var(--ease);
  }
  body.nav-open .nav-backdrop {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 60;
    border: none;
    background: var(--scrim);
    cursor: pointer;
    animation: fade .16s ease;
  }
  body.nav-open { overflow: hidden; }
}
/* RTL: the drawer comes in from the right. */
@keyframes drawer-in { from { transform: translateX(100%); } }
@keyframes fade { from { opacity: 0; } }


/* Class discussion: one calm reading surface. Topics scan like a directory
   in a card; replies remain a chronological document rather than pretending
   to be chat. */
.discussion-page .col-main { min-inline-size: 0; }
/* Starting a topic is a button at the end of the bar under the strip
   (proposal 09) — the staff's page's one fill, a student's quiet face — and
   its <details> opens as the dialog (`.create-panel`, app.js). Without
   script the form unfolds under the bar, full width. */
.discussion-create[open]:not([data-modal-ready]) > form { margin-top: .6rem; }
.discussion-row-icon, .discussion-author-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  inline-size: 2.35rem;
  block-size: 2.35rem;
  border-radius: 9px;
  background: var(--accent-tint);
  color: var(--accent-ink);
}
.create-hint { color: var(--muted); font-size: var(--t-meta); line-height: 1.75; }
.form-stack { display: grid; gap: .75rem; }
.form-stack label { display: grid; gap: .35rem; color: var(--fg2); font-size: var(--t-meta); font-weight: 600; }
.form-stack input, .form-stack textarea { inline-size: 100%; padding: .5rem .75rem; border: 1px solid var(--control-edge); border-radius: var(--r-sm); background: var(--control); color: var(--ink); font: inherit; font-size: var(--t-lead); line-height: 1.75; resize: vertical; transition: border-color .12s, box-shadow .12s; }
.form-stack input { min-block-size: var(--h); padding-block: .3rem; line-height: 1.5; resize: none; }
.form-stack input:hover, .form-stack textarea:hover { border-color: var(--control-edge-hover); }
.form-stack input:focus, .form-stack textarea:focus { border-color: var(--blue); outline: none; box-shadow: var(--ring); }
.form-compact { gap: .45rem; margin-top: .45rem; }
.form-compact .quiet-button { justify-content: center; }
.quiet-button.is-danger { color: var(--red); }
.discussion-board { margin-block-start: 0; }
.discussion-filters { display: flex; gap: .25rem; margin-block: 0 .6rem; overflow-x: auto; scrollbar-width: none; }
/* A student's board has no reading switch: its filters take the bar's
   start, the create button its end — one row on a desktop. */
.board-bar { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: .6rem 1rem; margin: 0 0 .9rem; }
.board-bar > .discussion-filters { flex: 1 1 auto; min-inline-size: 0; margin: 0; }
.board-bar:has(.create-actions > details[open]:not([data-modal-ready])) .create-actions { flex-basis: 100%; }
.discussion-filters::-webkit-scrollbar { display: none; }
.discussion-filters a { display: inline-flex; flex: 0 0 auto; align-items: center; min-block-size: var(--h); padding-inline: .9rem; border: 1px solid transparent; border-radius: var(--pill); color: var(--muted); font-size: var(--t-small); }
.discussion-filters a:hover { color: var(--ink); background: var(--hover); }
.discussion-filters a:active { transform: scale(.97); }
.discussion-filters a.is-active { border-color: var(--primary-edge); background: var(--primary-tint); color: var(--blue); font-weight: 600; }
.discussion-list { padding: 0; overflow: hidden; }
.discussion-group-label {
  display: flex;
  align-items: center;
  min-block-size: 2.2rem;
  padding-inline: .8rem;
  border-block-end: 1px solid var(--line);
  background: var(--sunk);
  color: var(--muted);
  font-size: var(--t-micro);
  font-weight: 600;
}
.discussion-group-label--recent { background: var(--sunk); }
.discussion-row {
  display: grid;
  grid-template-columns: 2.1rem minmax(0, 1fr) auto auto;
  align-items: center;
  gap: .7rem;
  min-block-size: 3.6rem;
  padding: .5rem .8rem;
  border-block-end: 1px solid var(--line);
  border-inline-start: 3px solid transparent;
  color: var(--fg1);
  transition: background-color .12s ease, border-color .12s ease;
}
.discussion-row:last-child { border-block-end: 0; }
.discussion-row:hover { background: var(--hover); }
.discussion-row:active { transform: scale(.995); }
.discussion-row.is-fresh { border-inline-start-color: var(--blue); }
.discussion-row-icon { inline-size: 2.1rem; block-size: 2.1rem; background: var(--chip); color: var(--fg2); }
/* The icon is the row's state (proposal 09), told apart by its shape as
   well as its tint: pinned on the gold, closed muted, unanswered a question
   — on the amber where it waits on the staff reading it. */
.discussion-row.is-pinned .discussion-row-icon { background: var(--accent-tint); color: var(--accent-ink); }
.discussion-row.is-locked .discussion-row-icon { color: var(--muted); }
.discussion-row.is-waiting .discussion-row-icon { background: var(--amber-tint); color: var(--amber); }
.discussion-row .row-chev { display: flex; color: var(--faint); }
.discussion-main { display: flex; flex-direction: column; min-inline-size: 0; }
.discussion-title { display: flex; align-items: center; flex-wrap: wrap; gap: .35rem; min-inline-size: 0; }
.discussion-title > strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--fg1); font-size: var(--t-body); font-weight: 500; }
.discussion-row:hover .discussion-title > strong { color: var(--blue); }
.discussion-by { display: flex; align-items: center; gap: .35rem; margin-block-start: .2rem; color: var(--muted); font-size: var(--t-micro); }
.discussion-by .byline-dot { margin-inline: .05rem; }
.discussion-new { background: var(--primary-tint); color: var(--blue); }
.discussion-meta { display: flex; align-items: center; justify-content: flex-end; gap: .8rem; color: var(--muted); font-size: var(--t-micro); }
.discussion-reply-total { display: grid; grid-template-columns: auto auto; align-items: baseline; gap: .22rem; min-inline-size: 3.5rem; }
.discussion-reply-total strong { color: var(--fg1); font-size: var(--t-body); font-weight: 600; }
.discussion-reply-total small { color: var(--muted); font-size: var(--t-micro); }
.discussion-waiting { display: inline-flex; align-items: center; gap: .35rem; min-inline-size: 3.5rem; color: var(--muted); font-size: var(--t-small); white-space: nowrap; }
.discussion-row.is-waiting .discussion-waiting { color: var(--amber); font-weight: 600; }
.discussion-row.is-waiting .discussion-waiting::before { content: ""; flex: none; inline-size: .45rem; block-size: .45rem; border-radius: 50%; background: currentColor; }
/* «استاد» beside the teacher's name, on the board and in a thread: her words
   read as hers for everyone. */
.author-tag { display: inline-flex; align-items: center; padding: 0 .45rem; border-radius: var(--pill); background: var(--primary-tint); color: var(--blue); font-size: var(--t-micro); font-weight: 600; line-height: 1.8; white-space: nowrap; }
.discussion-by .author-tag { margin-inline-start: .1rem; }
/* The card's head ends in what needs the staff, as phrases with their
   numbers (the class home's `.glance-fact` rule): new activity in the primary, the
   unanswered in amber — the door to that filter — or the calm line. */
.discussion-board > .sect-hd { flex-wrap: wrap; row-gap: 0; }
.board-facts { display: flex; flex-wrap: wrap; align-items: center; gap: 0 1rem; margin: 0; font-size: var(--t-small); }
.board-fact { display: inline-flex; align-items: center; gap: .4rem; min-block-size: var(--tap); color: var(--muted); white-space: nowrap; }
.board-fact::before { content: ""; flex: none; inline-size: .45rem; block-size: .45rem; border-radius: 50%; background: currentColor; }
.board-fact.is-new { color: var(--blue); }
.board-fact.is-waiting { color: var(--amber); font-weight: 600; }
.board-fact.is-clear { color: var(--aqua); }
.board-fact.is-clear::before { content: none; }
a.board-fact:hover { text-decoration: underline; text-underline-offset: 4px; }
.discussion-pagination { margin-block: .65rem 1rem; }
.discussion-pagination--inside { display: flex; justify-content: center; margin: 0; padding: .45rem; border-block-end: 1px solid var(--line); }
.discussion-aside-note p, .aside-note p { color: var(--muted); font-size: var(--t-meta); line-height: 1.75; }
.discussion-aside-note p + p, .aside-note p + p { margin-top: .4rem; }
.discussion-aside-note .quiet-link { display: inline-flex; align-items: center; gap: .35rem; min-block-size: var(--tap); }
.discussion-lead {
  margin-block: 1rem;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--surface);
}
.discussion-lead-head { display: grid; grid-template-columns: 2.35rem minmax(0, 1fr) auto; align-items: center; gap: .7rem; padding: .8rem 1rem; border-block-end: 1px solid var(--line); }
/* The author's mark says who: a student's plain, the teacher's mortarboard
   on the primary's tint. */
.discussion-lead-head .discussion-author-mark { background: var(--chip); color: var(--fg2); }
.discussion-author-mark.is-teacher, .discussion-lead-head .discussion-author-mark.is-teacher { background: var(--primary-tint); color: var(--blue); }
.discussion-author { display: flex; flex-wrap: wrap; align-items: baseline; gap: .35rem .7rem; color: var(--muted); font-size: var(--t-meta); }
.discussion-author strong, .discussion-post > .discussion-post-main > header strong { color: var(--fg1); font-size: var(--t-body); font-weight: 600; }
.discussion-state-list { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: .3rem; }
.discussion-state-list .state-chip, .discussion-post-main > header .state-chip { gap: .25rem; }
.discussion-state-list .state-chip svg, .discussion-post-main > header .state-chip svg { inline-size: 12px; block-size: 12px; }
/* A report no moderator has resolved yet, for the class's teacher: the word
   in ink, the flag red. */
.state-chip.is-flagged svg { color: var(--red); }
.discussion-lead-body { max-inline-size: 52rem; margin: 0; padding: 1rem 1.05rem 1.2rem; font-size: var(--t-lead); }
.discussion-lead-actions { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .25rem .65rem; padding: .15rem .6rem; border-block-start: 1px solid var(--line); }
/* The topic's tools sit where they act (proposal 09): pin, close, delete —
   quiet, the delete red — each at the tap floor. */
.topic-tools { display: flex; flex-wrap: wrap; align-items: center; gap: .1rem; margin: 0; }
.tool-btn { display: inline-flex; align-items: center; gap: .35rem; min-block-size: var(--tap); min-inline-size: var(--tap); padding: 0 .6rem; border: 0; border-radius: var(--r-sm); background: none; color: var(--fg2); font: inherit; font-size: var(--t-small); cursor: pointer; transition: background-color .12s, color .12s; }
.tool-btn svg { color: var(--muted); }
.tool-btn:hover { background: var(--hover); color: var(--ink); }
.tool-btn.is-danger { color: var(--red); }
.tool-btn.is-danger svg { color: currentColor; }
.tool-btn.is-danger:hover { background: var(--red-tint); color: var(--red); }
.discussion-lead-actions > .quiet-link { display: inline-flex; align-items: center; gap: .35rem; min-block-size: var(--tap); padding-inline: .6rem; font-size: var(--t-small); }
.discussion-body { overflow-wrap: anywhere; margin-block-start: .55rem; color: var(--fg1); font-size: var(--t-body); line-height: 1.9; }
.discussion-body--plain { white-space: pre-wrap; }
.discussion-body p + p { margin-top: .75rem; }
.discussion-thread { margin-block-start: 0; }
.discussion-thread > .sect-hd .sect-title { display: flex; align-items: center; gap: .4rem; }
.discussion-thread > .sect-hd .quiet-link { display: inline-flex; align-items: center; min-block-size: var(--tap); margin-inline-start: auto; }
.discussion-post { display: grid; grid-template-columns: 1.9rem minmax(0, 1fr); gap: .55rem; padding: .65rem .75rem 0; scroll-margin-block-start: 1rem; }
.discussion-post-rail { position: relative; display: flex; flex-direction: column; align-items: center; align-self: stretch; }
.discussion-post-rail::before { content: ""; position: absolute; inset-block: -.65rem 0; inset-inline-start: 50%; inline-size: 1px; background: var(--line-2); }
.discussion-posts > .discussion-post:first-of-type .discussion-post-rail::before { inset-block-start: .875rem; }
.discussion-posts > .discussion-post:last-of-type .discussion-post-rail::before { inset-block-end: calc(100% - .875rem); }
.discussion-post-rail .discussion-author-mark { position: relative; z-index: 1; inline-size: 1.85rem; block-size: 1.85rem; border-radius: 50%; background: var(--surface); box-shadow: inset 0 0 0 1px var(--line-2); }
.discussion-post.is-teacher .discussion-post-rail .discussion-author-mark { background: var(--primary-tint); color: var(--blue); box-shadow: inset 0 0 0 1px var(--primary-edge); }
.discussion-post-rail .discussion-author-mark svg { inline-size: 14px; block-size: 14px; }
.discussion-post-main { min-inline-size: 0; padding-block-end: .3rem; }
.discussion-post-main > header { display: flex; flex-wrap: wrap; align-items: baseline; gap: .35rem .7rem; color: var(--muted); font-size: var(--t-meta); }
.discussion-post .discussion-body { margin-block-start: .3rem; line-height: 1.75; }
.discussion-files { margin: .35rem .85rem .65rem; }
.discussion-post .discussion-files { margin-inline: 0; }
.discussion-files > a { padding-block: .45rem; }
.discussion-post footer { display: flex; flex-wrap: wrap; align-items: flex-start; gap: .25rem .65rem; margin-block-start: .15rem; }
.discussion-reply-ref { margin-block-start: .2rem; color: var(--faint); font-size: var(--t-meta); }
/* Who a reply answers, in words: the name and the first of their words, the
   door to that post. */
.reply-quote { display: grid; align-content: center; gap: .05rem; max-inline-size: 40rem; min-block-size: var(--tap); margin-block-start: .35rem; padding: .3rem .7rem; border-inline-start: 2px solid var(--line-2); border-radius: var(--r-sm); background: var(--sunk); color: var(--muted); font-size: var(--t-meta); line-height: 1.7; }
.reply-quote-who { color: var(--fg2); font-weight: 600; }
.reply-quote-text { min-inline-size: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
a.reply-quote:hover { border-inline-start-color: var(--blue); }
a.reply-quote:hover .reply-quote-who { color: var(--blue); }
/* What came after the reader's own last reply. */
.post-seam { display: flex; align-items: center; gap: .6rem; margin: .7rem .75rem .1rem; color: var(--blue); font-size: var(--t-micro); font-weight: 600; }
.post-seam::before, .post-seam::after { content: ""; flex: 1 1 auto; block-size: 1px; background: var(--primary-edge); }
.discussion-edit { margin: .75rem 1rem; padding: .9rem; border: 1px solid var(--primary-edge); border-radius: var(--r); background: var(--surface); }
.discussion-edit--post { margin-inline: 0; }
.discussion-edit-files { display: grid; gap: .25rem; margin: 0; padding: .6rem .75rem; border: 1px solid var(--line-2); border-radius: var(--r-sm); }
.discussion-edit-files legend { padding-inline: .3rem; color: var(--muted); font-size: var(--t-meta); }
.discussion-edit-files label { display: flex; align-items: center; gap: .55rem; min-block-size: 2.4rem; cursor: pointer; }
.discussion-edit-files label > span { display: flex; min-inline-size: 0; align-items: baseline; gap: .5rem; overflow-wrap: anywhere; }
.discussion-edit-files small { color: var(--muted); white-space: nowrap; }
.inline-disclosure { position: relative; color: var(--muted); font-size: var(--t-micro); }
.inline-disclosure > summary { display: inline-flex; align-items: center; justify-content: center; gap: .3rem; min-block-size: var(--tap); min-inline-size: var(--tap); cursor: pointer; list-style: none; }
.inline-disclosure > summary svg { inline-size: 14px; block-size: 14px; }
.inline-disclosure > summary::-webkit-details-marker { display: none; }
.inline-disclosure[open] { inline-size: min(28rem, 100%); }
.inline-disclosure > form { inline-size: 100%; margin-block: 0 .7rem; padding: .75rem; border: 1px solid var(--line-2); border-radius: var(--r); background: var(--surface); }
.discussion-reply-box { scroll-margin-block-start: 1rem; }
.discussion-reply-box textarea { min-block-size: 8rem; }
.discussion-reply-context { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .5rem; min-block-size: var(--tap); padding: .35rem .8rem; border-radius: var(--r-sm); background: var(--primary-tint); color: var(--fg1); font-size: var(--t-small); }
.reply-context-text { display: grid; flex: 1 1 0; min-inline-size: 0; }
.reply-context-text small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--muted); font-size: var(--t-meta); }
.discussion-reply-context .quiet-link { display: inline-flex; align-items: center; min-block-size: var(--tap); }
/* The thread's aside: the topic in two sentences. */
.topic-state p { display: flex; align-items: flex-start; gap: .45rem; color: var(--fg2); font-size: var(--t-small); line-height: 1.75; }
.topic-state p + p { margin-top: .35rem; }
.topic-state svg { flex: none; margin-top: .3rem; color: var(--muted); inline-size: 14px; block-size: 14px; }
.discussion-closed { margin-block-start: 1rem; }
.notice-ok { border-color: color-mix(in srgb, var(--aqua) 25%, var(--content)); background: var(--aqua-tint); }


@media (max-width: 40rem) {
  .board-bar > .discussion-filters { flex-basis: 100%; }
  .discussion-row { grid-template-columns: 2rem minmax(0, 1fr); align-items: start; gap: .6rem; padding: .6rem .55rem; }
  .discussion-meta { grid-column: 2; justify-content: flex-start; }
  .discussion-row .row-chev { display: none; }
  .discussion-title > strong { display: -webkit-box; white-space: normal; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
  .discussion-lead-actions { justify-content: flex-start; }
  .discussion-lead-head { grid-template-columns: 2.1rem minmax(0, 1fr); }
  .discussion-state-list { grid-column: 2; justify-content: flex-start; }
  .discussion-lead-body { padding-inline: .8rem; }
  .discussion-post { grid-template-columns: 1.9rem minmax(0, 1fr); gap: .55rem; padding-inline: .65rem; }
  .discussion-thread > .sect-hd { flex-wrap: wrap; }
}

/* ══════════════════════════════════════════════════════════════════════════
   BREADCRUMB — small and muted above the title: every ancestor a link, the
   current page plain. The separator is `‹`, which the bidi algorithm mirrors
   in an RTL run — typing `›` would render backwards.
   ══════════════════════════════════════════════════════════════════════════ */
.crumb {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0;
  margin: 0 0 .25rem;
  font-size: var(--t-small);
  color: var(--muted);
}
.crumb li { display: inline-flex; align-items: center; min-width: 0; }
/* The one compact chrome left (ADR-0026): 32px under a precise pointer at
   desktop width, 44px wherever a finger or a narrow screen is (below). */
.crumb a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 32px;
  min-inline-size: 32px;
  padding-inline: .2rem;
  color: var(--muted);
  transition: color .12s;
}
.crumb a:hover { color: var(--ink); text-decoration: underline; text-underline-offset: 4px; }
/* The separator ends the step before it, not the step after: a long title
   that wraps to a line of its own then starts clean, and the `‹` stays at the
   end of the line of ancestors it belongs to. */
.crumb li:not(:last-child)::after { content: "‹"; margin-inline: .3rem; color: var(--faint); }

/* ── THE WORKSPACE HEADER — the root pages. The markup is the old dashboard
   band's (`header.crumb-bar > ol.crumb > li > h1`), so every anchor the
   journeys hold still holds; the look is Plume's page header: the title with
   room around it, the date under it, the page's one action at the far end. */
.crumb-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .15rem 1rem;
  margin: 0 0 1.1rem;
}
.crumb-bar .crumb { flex: 1 1 auto; margin: 0; }
.crumb h1 {
  font-size: var(--t-title);
  font-weight: 600;
  line-height: 1.35;
  color: var(--ink);
}
.crumb-note { order: 3; flex-basis: 100%; color: var(--muted); font-size: var(--t-small); }
.crumb-bar .go { margin-top: 0; }
.crumb-bar .icon-btn { color: var(--muted); }

/* ══════════════════════════════════════════════════════════════════════════
   PAGE HEADER — content pages: the crumb above, then the title with its
   byline under it on the start side and the actions at the far end (the
   top-left corner in RTL). The page's one call to action is the first child
   of the cluster and is filled; the rest are quiet.
   ══════════════════════════════════════════════════════════════════════════ */
.page-hd {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: .6rem 1rem;
  margin-bottom: 1.1rem;
}
.page-hd-main { flex: 1 1 16rem; min-width: 0; }
.page-hd h1 { font-size: var(--t-title); line-height: 1.35; color: var(--ink); }
.page-hd .byline { margin-top: .4rem; }
.byline-author { font-weight: 600; color: var(--fg1); }
.page-hd-actions {
  flex-shrink: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .4rem;
}
/* The header's own buttons-in-forms; not a form inside a dialog that
   happens to live in the header (the term planner's dates). */
.page-hd-actions > form { display: inline-flex; }
.page-hd-actions .go { margin-top: 0; }
/* One line under the title that says what the page is for — the first thing
   a teacher who has not been here before needs, and short enough to pass. */
.page-note { max-width: 46rem; margin: -.5rem 0 1.1rem; color: var(--muted); font-size: var(--t-body); line-height: 1.75; }

/* A ghost square for a secondary tool: an icon with a name for assistive
   technology and a title for the pointer. It carries the tap floor. */
.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--h);
  min-height: var(--h);
  border: none;
  border-radius: var(--r-sm);
  background: none;
  color: var(--muted);
  cursor: pointer;
  transition: background-color .12s, color .12s, transform .12s var(--ease);
}
.icon-btn:hover { background: var(--hover); color: var(--ink); }
.icon-btn:active { transform: scale(.95); }
/* Destructive, but at rest it is just another row tool: a red trash on every
   row makes deletion the loudest thing on the page. It reddens when reached. */
.icon-btn.is-danger { color: var(--muted); }
.icon-btn.is-danger:hover { background: var(--red-tint); color: var(--red); }

/* ══════════════════════════════════════════════════════════════════════════
   TABS — a line of places under the header. The current one is ink with the
   primary green under it; the rest are muted until pointed at.
   ══════════════════════════════════════════════════════════════════════════ */
.tabs {
  display: flex;
  align-items: stretch;
  gap: .1rem;
  overflow-x: auto;
  margin-bottom: 1rem;
  /* The line is drawn inside the box, and a tab's underline overlaps it
     inside the box too. As a border, that 1px overlap was vertical overflow,
     and this is a scroll container: a desktop with a mouse drew a scrollbar
     beside the tabs (the builder's, 2026-09). Same height, same look. */
  padding-bottom: 1px;
  box-shadow: inset 0 -1px 0 var(--line-2);
}
/* A tab is as tall as a control (--h). Its line box is set, not inherited,
   so the padding and the 2px underline fit inside those 36px. */
.tab {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  min-height: var(--h);
  padding: .25rem .75rem;
  line-height: 1.4;
  border: none;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  background: none;
  color: var(--muted);
  font-size: var(--t-body);
  font-weight: 500;
  white-space: nowrap;
  cursor: pointer;
  transition: color .12s, border-color .12s;
}
.tab:hover { color: var(--ink); border-bottom-color: var(--line-2); }
.tab.is-active { color: var(--ink); border-bottom-color: var(--blue); font-weight: 600; }
.tab.is-placeholder { color: var(--faint); cursor: not-allowed; }
.tab svg { inline-size: 17px; block-size: 17px; color: var(--muted); }
.tab.is-active svg { color: var(--blue); }
/* On a phone a strip holds its places with less air between them, so the
   teacher's tabs fit a 412px screen even when «ارزیابی‌ها» carries the papers
   waiting on the home page: a strip that overflows on one sibling and not the next grows
   a «بیشتر» on one only, and the tabs move under the reader's thumb (the
   continuity gate, e2e/evaluations/other-workspaces.spec.ts). */
@media (max-width: 40rem) {
  /* …and never narrower than a finger: at the ladder's 13px, «نمایه» alone
     was 41px wide. A set minimum replaces flex's own (the label's width), so
     the tab must not shrink either: a strip of shrinking tabs changes its own
     overflow, which shows and hides «بیشتر», which resizes the strip — a loop
     that never let the exam editor's tabs hold still for a click. */
  .tab { gap: .35rem; padding-inline: .5rem; min-inline-size: var(--tap); flex-shrink: 0; justify-content: center; }
}

/* The quieter nested strip, for a picker inside a page (the attendance
   session switcher), one step down from the page's tabs. */
.tabs--sub { margin-bottom: .8rem; }
.tabs--sub .tab { font-size: var(--t-small); }

/* ══════════════════════════════════════════════════════════════════════════
   BADGES — pills. A count is the highlight on its tint; a zero is dimmed,
   never hidden; a count that waits on the reader is amber.
   ══════════════════════════════════════════════════════════════════════════ */
.badge-total, .badge-count, .badge-zero, .badge-warn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  min-inline-size: 1.6rem;
  padding: .05rem .5rem .1rem;
  border-radius: var(--pill);
  font-size: var(--t-micro);
  font-weight: 600;
  line-height: 1.6;
  font-variant-numeric: tabular-nums;
  text-align: center;
  vertical-align: middle;
}
.badge-total, .badge-count { background: var(--accent-tint); color: var(--accent-ink); }
.badge-zero { background: var(--chip); color: var(--muted); font-weight: 500; }
/* dv4's dashboards find the actionable rows by colour, not by reading. */
.badge-warn { background: var(--amber-tint); color: var(--amber); }

/* ══════════════════════════════════════════════════════════════════════════
   CARDS — `.sect` is the card: the surface, one hairline, a 10px radius. Its
   header is the card's title as text (no strip, no tint, no bar); its body
   holds the rows, inset so a hover never meets the rounded edge. A card has
   no shadow: nothing that sits on the page does.
   ══════════════════════════════════════════════════════════════════════════ */
.sect, .card {
  margin-bottom: .8rem;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--surface);
}
.sect:last-child, .card:last-child { margin-bottom: 0; }

.sect-hd {
  display: flex;
  align-items: center;
  gap: .5rem;
  min-height: 2.9rem;
  padding: .6rem 1rem .2rem;
  list-style: none;
  user-select: none;
}
.sect-hd::-webkit-details-marker { display: none; }
a.sect-hd, summary.sect-hd { cursor: pointer; min-height: var(--tap); }
a.sect-hd:hover .sect-title, summary.sect-hd:hover .sect-title { color: var(--blue); }
.sect-hd:hover .grip { color: var(--muted); }
/* A card that folds shows its header alone when closed, with even padding. */
details.sect:not([open]) > .sect-hd { padding-block: .6rem; }

.grip { color: var(--line-2); display: flex; transition: color .12s; }
.sect-icon { color: var(--muted); display: flex; }
.sect-title {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--t-lead);
  font-weight: 600;
  color: var(--ink);
  transition: color .12s;
}
.task-more { border-top: 1px solid var(--line); }
.task-more .quiet-link { display: flex; justify-content: flex-start; padding-inline: .6rem; font-size: var(--t-small); }

/* The fold is a real <details>: keyboard-operable for free, no JavaScript
   (ADR-0001). Closed points along the reading direction — left, in RTL. */
.sect-hd .chev { color: var(--muted); display: flex; transition: transform .15s var(--ease); transform: rotate(90deg); }
.sect[open] > .sect-hd .chev { transform: rotate(0deg); }

.sect-bd { padding: .3rem 1rem .9rem; }
/* A body that is a list of rows: the rows bring their own padding; the body
   keeps a small inset so the hover fill stays inside the card's corners. */
.sect-bd--flush { padding: .1rem .45rem .45rem; }
/* The far-end link of a card header: "همهٔ …" hangs off the title instead of
   spending a button on it. */
.sect-hd .quiet-link { font-size: var(--t-small); }

/* Compact crumbs must not make touch navigation harder. Narrow layouts and
   devices that report a coarse primary pointer take the full floor. */
@media (max-width: 62rem), (pointer: coarse) {
  .crumb a { min-height: 44px; min-inline-size: 44px; }
}

/* A list of rows is itself a card when it stands on the page, and plain rows
   when a card already holds it — one surface, never two nested. */
:where(.task-list, .teacher-list, .roster-list, .marking-list, .poll-list, .notification-feed, .grade-list,
       .report-list, .announcement-list, .session-list, .lesson-edit-list,
       .class-hub, .discussion-list, .check-list, .material-files, .attachment-list, .builder,
       .conversation-list, .staff-list) {
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--surface);
  padding: .1rem .45rem;
}
:where(.sect, .card, .manage-section, .modal, .side-sec, .acc-row, .message-workspace, .builder-editor,
       .builder-tree, .report-row, .reading-layout, .import-panel)
  :where(.task-list, .teacher-list, .roster-list, .marking-list, .poll-list, .notification-feed, .grade-list,
         .report-list, .announcement-list, .session-list, .lesson-edit-list,
         .class-hub, .discussion-list, .check-list, .material-files, .attachment-list, .builder,
         .conversation-list, .staff-list) {
  border: 0;
  border-radius: 0;
  background: none;
  padding: 0;
}

/* ══════════════════════════════════════════════════════════════════════════
   DIRECTORY ROWS — a lesson list inside a class card. Rows are divided by a
   hairline; the one the student comes back for reads a step heavier.
   ══════════════════════════════════════════════════════════════════════════ */
.dir { padding: 0 .45rem .45rem; }
.dir-item + .dir-item { border-top: 1px solid var(--line); }
.dir-link {
  display: flex;
  align-items: center;
  gap: .6rem;
  min-height: var(--tap);
  padding: .5rem .7rem;
  padding-inline: 1.4rem .7rem;
  border-radius: var(--r-sm);
  color: var(--fg1);
  transition: background-color .1s, color .1s;
}
.dir-link:hover { background: var(--hover); color: var(--ink); }
.dir-name {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--t-body);
  font-weight: 500;
}
/* The dot fills only when there is something behind the row. An empty lesson
   gets a hollow ring and an em-dash, never a zero — a zero is a measurement. */
.state-icon { color: var(--accent); display: flex; }
.dir-link[data-primary] .dir-name { font-weight: 600; color: var(--ink); }
.dir-link--empty { color: var(--muted); }
.dir-link--empty .state-icon { color: var(--line-2); }
.state-zero { color: var(--faint); font-size: var(--t-body); flex-shrink: 0; }

/* ══════════════════════════════════════════════════════════════════════════
   BUTTONS. Four buttons and no more (docs/08 §controls), drawn
   as Plume draws them. Colour is kept for meaning, so a page has one green
   thing to press and the rest are quiet:
     .btn-primary  — the page's one call to action: Plume's green, filled.
     .go           — go somewhere or do the next thing: the white face, ink.
     .quiet-button — a secondary action: the white face, the second ink.
     .danger-button— a destructive one: the white face, red ink; it asks first.
   One height (--h), 7px round, and each says what it does in words.
   ══════════════════════════════════════════════════════════════════════════ */
.btn-primary, .go, .quiet-button, .danger-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .4rem;
  min-height: var(--h);
  /* «حذف» alone is narrower than a finger at this type size. */
  min-inline-size: var(--h);
  padding: 0 .9rem;
  border: 1px solid var(--control-edge);
  border-radius: var(--r-sm);
  background: var(--control);
  box-shadow: var(--control-lift);
  color: var(--ink);
  font-size: var(--t-body);
  font-weight: 500;
  line-height: 1.4;
  cursor: pointer;
  transition: background-color .12s, border-color .12s, color .12s, transform .12s var(--ease);
}
.go { margin-top: .5rem; }
.quiet-button { color: var(--fg1); }
.go:hover, .quiet-button:hover { border-color: var(--control-edge-hover); background: var(--sunk); color: var(--ink); }
.danger-button { color: var(--red); }
.danger-button:hover { border-color: color-mix(in srgb, var(--red) 40%, var(--control)); background: var(--red-tint); }
/* The fill: the page's one call to action — a form's own button, or the
   header's create button (`.go.is-primary`). */
.btn-primary, .go.is-primary {
  padding-inline: 1rem;
  border-color: var(--primary-fill);
  background: var(--primary-fill);
  color: var(--on-accent);
  font-weight: 600;
}
.btn-primary:hover, .go.is-primary:hover { border-color: var(--primary-fill-hover); background: var(--primary-fill-hover); color: var(--on-accent); }
.btn-primary:disabled { cursor: not-allowed; opacity: .55; }
.btn-primary:active, .go:active, .quiet-button:active, .danger-button:active { transform: scale(.97); }


/* ══════════════════════════════════════════════════════════════════════════
   THE INFO COLUMN — the aside keeps its place (sidebar ‹ main ‹ aside, dv4's
   order) and becomes a stack of small cards on the ground: each `.side-sec`
   is one card, a label and then stats, chips, quick links or files. It
   sticks beside the page on a desktop and follows the page on a phone. It
   reads one rung down the ladder — glance material, not reading material —
   but its controls keep the 44px floor.
   ══════════════════════════════════════════════════════════════════════════ */
.side-sec {
  padding: .75rem .9rem .8rem;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--surface);
}
.side-sec + .side-sec { margin-top: .65rem; }
.aside-inner { font-size: var(--t-small); }
.aside-inner .side-sec-label { margin-bottom: .45rem; }
.aside-inner .byline { font-size: var(--t-small); }
.aside-inner .stat-num { font-size: var(--t-lead); }
.aside-inner .stat-lbl { font-size: var(--t-meta); }
.aside-inner .chip { font-size: var(--t-meta); }
.aside-inner .meta-row { margin-bottom: .55rem; }
.aside-inner .meta-label { margin-bottom: .2rem; }
.aside-inner .quiet-link, .aside-inner .summary-count { font-size: var(--t-small); }
.aside-inner .feed-link, .aside-inner .act-text, .aside-inner .feed-empty { font-size: var(--t-small); }
.aside-inner .section-help { font-size: var(--t-meta); }
.aside-inner .attachment-list > div { padding: .45rem 0; }
.aside-inner .attachment-list small { font-size: var(--t-micro); }
.aside-inner .upload-field { padding: .55rem .65rem; gap: .4rem; }
.aside-inner .upload-btn, .aside-inner .upload-names { font-size: var(--t-meta); }
.aside-inner .btn-primary, .aside-inner .quiet-button, .aside-inner .danger-button { font-size: var(--t-small); padding: 0 .75rem; }
/* The upload button hugs its label like every other form button — a
   full-column bar read as a banner, not an action. */
.aside-inner .attachment-upload .btn-primary,
.aside-inner .attachment-upload .quiet-button { align-self: flex-start; }
/* In a file row the two actions speak the same language: دریافت is a quiet
   link, so حذف is a red one. The element stays a <button> in a POST form. */
.attachment-list .danger-button { border-color: transparent; background: none; box-shadow: none; padding: 0 .5rem; }
.attachment-list .danger-button:hover { background: var(--red-tint); }
.aside-inner .work-facts dt { font-size: var(--t-meta); }
.aside-inner .work-facts dd { font-size: var(--t-body); }
.aside-inner .work-facts dl div { padding: .45rem 0; }

.side-sec-label {
  display: flex;
  align-items: center;
  gap: .35rem;
  margin-bottom: .45rem;
  font-size: var(--t-micro);
  font-weight: 600;
  color: var(--muted);
}
.side-sec-label svg { color: var(--faint); }

.byline {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .35rem 0;
  font-size: var(--t-small);
  line-height: 1.45;
  color: var(--muted);
}
.byline-item { display: inline-flex; align-items: baseline; gap: .25rem; white-space: nowrap; }
/* The drawn mid-dot for inline text runs. Beside a Persian digit a typed "·"
   is indistinguishable from ۰ — "۲۴ · پاسخ" reads as ۲۴۰ (docs/05). */
.dot-sep {
  display: inline-block;
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: var(--faint);
  margin: 0 .35rem;
  vertical-align: .2em;
}
/* The mid-dot between flex items: drawn, never typed. */
.byline-dot {
  display: inline-block;
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: var(--line-2);
  margin: 0 .55rem;
  flex-shrink: 0;
}
.stat-num {
  font-size: var(--t-lead);
  font-weight: 600;
  color: var(--fg1);
  margin-inline-end: .15rem;
  font-variant-numeric: tabular-nums;
}
.stat-lbl { font-size: var(--t-meta); color: var(--muted); }

.feed-empty { font-size: var(--t-small); color: var(--muted); padding: .2rem 0; }
/* Quick links in an aside stack, one per line, start-aligned. The width
   floor stays — zeroing it once squeezed a دریافت link to 42px. */
.side-sec .quiet-link { display: flex; justify-content: flex-start; }

/* A placeholder: a dashed edge marks the unfinished (Plume's one meaning for
   it) — visible enough not to look done, never mistakable for data. */
.placeholder {
  padding: .6rem .75rem;
  border: 1.5px dashed var(--line-2);
  border-radius: var(--r);
  text-align: center;
  color: var(--muted);
}

/* .show-activity-feed */
.feed { display: flex; flex-direction: column; }
.act-row {
  display: flex;
  gap: .5rem;
  align-items: flex-start;
  padding: .45rem 0;
  border-bottom: 1px solid var(--line);
}
.act-row:last-child { border-bottom: none; }
.act-icon {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  margin-top: 1px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.act-fwd { background: var(--aqua-tint); color: var(--aqua); }
.act-bck { background: var(--red-tint); color: var(--red); }
.act-body { flex: 1 1 auto; min-width: 0; }
/* The shortcut to the most urgent piece of work. It shipped at 23px — barely
   half the 44px floor — on the one surface a student opens first. */
.feed-link {
  display: flex;
  align-items: center;
  min-block-size: 44px;
  font-size: var(--t-small);
  font-weight: 500;
  color: var(--fg1);
  line-height: 1.4;
}
.feed-link:hover { color: var(--blue); text-decoration: underline; text-underline-offset: 4px; }
.act-states { display: block; font-size: var(--t-meta); color: var(--muted); }
.age-late { color: var(--amber); }   /* whisper-quiet amber, never a red field */

/* Metadata as quiet chips: a label over a row of pills. `.chip` is the
   highlight on its tint (a class, a term); `--dim` is a fact (a date, a
   state); `--warn`, `--ok` and `--bad` carry amber, aqua and red. */
.meta-row { margin-bottom: .55rem; }
.meta-row:last-child { margin-bottom: 0; }
.meta-label {
  display: block;
  margin-bottom: .2rem;
  color: var(--muted);
  font-size: var(--t-micro);
  font-weight: 600;
}
.chips { display: flex; flex-wrap: wrap; gap: .3rem; }
.chip {
  display: inline-block;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  padding: .08rem .6rem .16rem;
  border-radius: var(--pill);
  background: var(--accent-tint);
  color: var(--accent-ink);
  font-size: var(--t-meta);
  line-height: 1.8;
  vertical-align: middle;
}
.chip--dim { background: var(--chip); color: var(--fg2); }
/* An assistant's role (T1 §3.1), where the primary teacher's doors stand in a
   header: a fact on the chip ground, never a control — no border, no hover.
   The class home's facts close on the two lines of who does what, and name
   the reader among the staff. */
.role-chip { display: inline-flex; align-items: center; gap: .35rem; padding-inline: .65rem .75rem; font-size: var(--t-small); }
.role-chip > svg { flex: none; inline-size: 14px; block-size: 14px; color: var(--muted); }
.side-sec .role-rights { margin-top: .8rem; }
.staff-you { color: var(--muted); font-size: var(--t-meta); }

/* ══════════════════════════════════════════════════════════════════════════
   EMPTY STATE — what is missing and the next useful step, in a dashed frame
   that says "nothing here yet"; inside a card the frame steps away and the
   card's own edge does the job.
   ══════════════════════════════════════════════════════════════════════════ */
.empty {
  display: grid;
  justify-items: center;
  gap: .35rem;
  padding: 2.25rem 1.25rem;
  border: 1.5px dashed var(--line-2);
  border-radius: var(--r);
  text-align: center;
  color: var(--muted);
}
:where(.sect, .card, .manage-section, .side-sec, .modal) .empty { border: 0; padding: 1.5rem 1rem; }
.empty svg { margin: 0 auto .5rem; color: var(--faint); }
.empty p { font-size: var(--t-lead); font-weight: 600; color: var(--ink); }
.empty p + p { margin-top: 0; font-size: var(--t-body); font-weight: 400; color: var(--muted); }

/* Notifications are one flat chronological feed.  Hairlines and whitespace
   carry grouping; unread is blue, while amber is reserved for rows that need
   an action rather than merely being new. */
.notification-page { max-width: 58rem; }
.notification-feed { padding-block: 0; }
/* Each row is its own door (proposal S1): its verb's target is stretched
   over the row, so an unread row still holds exactly one <button> in its
   POST form, which marks it read on the way. */
.notification-row {
  position: relative;
  display: grid;
  grid-template-columns: .65rem minmax(0, 1fr) auto;
  align-items: center;
  gap: .75rem;
  min-height: 4.5rem;
  padding: .8rem .45rem;
  border-bottom: 1px solid var(--line);
  transition: background-color .12s;
}
.notification-row:last-child { border-bottom: 0; }
.notification-row.is-unread { background: var(--primary-tint); }
.notification-dot { inline-size: .42rem; block-size: .42rem; border-radius: 50%; background: var(--bg3); }
.notification-row.is-unread .notification-dot { background: var(--blue); }
.notification-row.is-actionable .notification-dot { background: var(--amber); }
.notification-copy { min-width: 0; }
.notification-row:hover { background: var(--hover); }
.notification-row.is-unread:hover { background: color-mix(in srgb, var(--blue) 12%, var(--content)); }
.notification-copy h2 { margin: 0 0 .15rem; font-size: var(--t-lead); line-height: 1.55; }
.notification-meta { margin: 0; color: var(--muted); font-size: var(--t-meta); line-height: 1.8; }
.notification-open { justify-self: end; white-space: nowrap; }
.notification-verb { min-block-size: var(--tap); border: 0; background: none; font: inherit; font-size: var(--t-small); font-weight: 600; cursor: pointer; }
.notification-verb::after { content: ""; position: absolute; inset: 0; }
.notification-row:hover .task-action { background: var(--primary-tint); }
.notification-more { margin-block-start: 1rem; text-align: center; }
.notification-empty svg { inline-size: 40px; block-size: 40px; }
@media (max-width: 38rem) {
  .notification-row { grid-template-columns: .5rem minmax(0, 1fr) auto; gap: .6rem; }
}

/* A notice that arrives while a page is open shows itself in the bottom
   corner at the inline end — the left, in Persian — above the phone's bar
   (reported 2026-10-14: the bell's number rose and nothing else said so).
   ADR-0026 keeps toasts away from the outcome of a person's own action, which
   belongs where the eye already is; this is news from elsewhere, and script
   adds it, so without script nothing is left covering the page. A toast is a
   feed row in small: one door, its verb stretched over it, the close button
   above that. Three at most; the newest nearest the corner. */
.toasts {
  position: fixed;
  inset-inline-end: 1rem;
  inset-block-end: 1rem;
  z-index: 55;
  display: flex;
  flex-direction: column;
  gap: .5rem;
  inline-size: min(23rem, calc(100vw - 2rem));
  pointer-events: none;
}
.toasts:empty { display: none; }
.toast {
  position: relative;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: start;
  gap: .7rem;
  padding-block: .8rem .6rem;
  padding-inline: .85rem .35rem;
  border: 1px solid var(--line-2);
  border-radius: var(--r-pop);
  background: var(--raised);
  box-shadow: var(--shadow-pop);
  pointer-events: auto;
  animation: toast-in .22s var(--ease) both;
  transition: background-color .12s;
}
.toast:hover { background: color-mix(in srgb, var(--blue) 5%, var(--raised)); }
.toast.is-leaving { animation: toast-out .18s var(--ease) both; }
.toast-icon { display: grid; place-items: center; inline-size: 2.1rem; block-size: 2.1rem; margin-block-start: .1rem; border-radius: 50%; background: var(--primary-tint); color: var(--blue); }
.toast.is-actionable .toast-icon { background: var(--amber-tint); color: var(--amber); }
.toast-copy { min-width: 0; }
.toast-title { display: -webkit-box; margin: 0; overflow: hidden; color: var(--ink); font-size: var(--t-body); font-weight: 600; line-height: 1.55; overflow-wrap: anywhere; -webkit-box-orient: vertical; -webkit-line-clamp: 2; }
.toast-meta { margin: .1rem 0 0; color: var(--muted); font-size: var(--t-meta); line-height: 1.7; }
.toast-open { margin-block-start: .15rem; }
.toast-open .notification-verb { min-block-size: var(--tap); margin-inline-start: -.6rem; }
.toast:hover .task-action { background: var(--primary-tint); }
.toast-close { position: relative; z-index: 1; margin-block-start: -.3rem; color: var(--muted); }
.toast-more { display: flex; align-items: center; justify-content: center; gap: .25rem; min-block-size: var(--tap); padding: .5rem 1rem; color: var(--blue); font-size: var(--t-small); font-weight: 600; }
@keyframes toast-in { from { opacity: 0; transform: translateY(.6rem); } }
@keyframes toast-out { to { opacity: 0; transform: translateY(.3rem); } }
@media (prefers-reduced-motion: reduce) { .toast, .toast.is-leaving { animation: none; } }
@media (max-width: 62rem) {
  .toasts { inset-inline: 1rem; inset-block-end: calc(4.4rem + env(safe-area-inset-bottom, 0px) + .5rem); inline-size: auto; }
}
/* A phone has room for one: three would cover the page they arrive on. The
   newest shows; the others are on the bell and in the feed. */
@media (max-width: 38rem) {
  article.toast:not(:last-of-type) { display: none; }
}

/* ══════════════════════════════════════════════════════════════════════════
   ERROR PAGE — the empty state, with a reason.
   Same centred column as sign-in, same 40px mark at .3 as `.empty`, no border
   and no shadow. An error is not a special visual mode; it is a page with
   nothing on it and one sentence explaining why.
   ══════════════════════════════════════════════════════════════════════════ */
.notice-page { max-width: 28rem; margin: 3.5rem auto; padding: 1.75rem 1.5rem 1.5rem; border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--surface); text-align: center; }
.notice-mark { margin: 1.5rem 0 .75rem; color: var(--line-2); }
.notice-mark svg { margin: 0 auto; }
.notice-title { font-size: var(--t-title); font-weight: 600; color: var(--fg0); }
.notice-detail { margin-top: .6rem; color: var(--muted); line-height: 1.8; }
.notice-actions {
  display: flex;
  justify-content: center;
  gap: .6rem;
  margin-top: 1.6rem;
}
/* `.btn-primary` is styled for a column form, where stretching reads as one
   full-width control. Here it sits inline, so it takes its own width and the
   controls' height rather than the column's. */
.notice-actions .btn-primary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-block-size: var(--h);
  min-inline-size: var(--h);
  padding-inline: 1.1rem;
  text-decoration: none;
}
.notice-code { margin-top: 1.75rem; color: var(--muted); font-size: var(--t-small); }

/* ══════════════════════════════════════════════════════════════════════════
   SIGN-IN, FORMS AND FIELDS. The sign-in pages (sign-in, the first-login
   password) are one column in the middle of the window: the kit's stacked
   lockup on the ground, one card holding only what is typed, and the way to
   get help under it. A field is the controls' white face with their grey
   edge, 7px round, as tall as a button (--h), at 15px under a mouse and 16px
   under a finger — the size a phone does not zoom into — and on focus a green
   edge with a soft ring (a ring is spread, not blurred: it is a line, not a
   shadow).
   ══════════════════════════════════════════════════════════════════════════ */
/* `.body` already fills the window's height, so centring is all it takes;
   the column still grows past a short window (a phone on its side, a
   keyboard up) and scrolls rather than clipping the button. */
.signin-page {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.5rem;
  padding: 2.5rem 16px 3.5rem;
}
.signin-lockup svg { block-size: 6.25rem; inline-size: auto; }
.signin {
  inline-size: 100%;
  max-inline-size: 28rem;
  padding: 1.9rem 1.9rem 2rem;
  border: 1px solid var(--line-2);
  border-radius: var(--r-lg);
  background: var(--surface);
}
/* The one form a person meets before anything else, typed from a slip: under
   a mouse its field and button stay a step above the compact 36px. A finger's
   layout already has 44. */
@media (min-width: 62rem) and (pointer: fine) {
  .signin { --h: 40px; }
}
.signin-foot {
  max-inline-size: 28rem;
  text-align: center;
  text-wrap: balance;
  font-size: var(--t-small);
  color: var(--muted);
}
/* The guide, under the help line it continues: a link, not a second button
   competing with «ورود». The negative margin pulls it into the foot's group. */
.signin-help {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  min-block-size: var(--tap);
  margin-block-start: -1rem;
  padding: 0 .5rem;
  border-radius: var(--r-sm);
  font-size: var(--t-small);
  font-weight: 600;
  color: var(--blue);
  text-decoration: none;
}
.signin-help:hover { background: var(--hover); }
.signin-help svg { flex: none; }
.signin-brand {
  display: flex;
  align-items: center;
  gap: .6rem;
  margin-bottom: 1.4rem;
  color: var(--ink);
  font-size: var(--t-section);
  font-weight: 600;
}
.signin-brand svg { box-sizing: content-box; padding: 6px; border-radius: 7px; background: var(--mark); color: var(--on-accent); }
.signin-brand span { color: var(--ink); }
.signin-title { font-size: var(--t-title); font-weight: 600; color: var(--ink); text-align: center; }
.signin-lead { margin-top: .5rem; text-align: center; text-wrap: balance; color: var(--muted); line-height: 1.8; }
.signin .alert { margin-top: 1.25rem; }
.signin .form { margin-top: 1.5rem; }
.form { display: flex; flex-direction: column; gap: 1.1rem; margin-top: 1.1rem; }
/* In a column form a button stretches to the full column and reads as a
   disabled input, not an action. Buttons hug their label; the sign-in page,
   where one big target is the point, opts back in. */
.form > .btn-primary, .form > .quiet-button { align-self: flex-start; }
.signin .form > .btn-primary { align-self: stretch; }
.field { display: flex; flex-direction: column; gap: .35rem; }
.field-label { font-size: var(--t-small); font-weight: 600; color: var(--fg2); }
.input {
  min-height: var(--h);
  padding: .3rem .75rem;
  font: inherit;
  font-size: var(--t-lead);
  line-height: 1.5;
  color: var(--ink);
  background: var(--control);
  border: 1px solid var(--control-edge);
  border-radius: var(--r-sm);
  transition: border-color .12s, box-shadow .12s;
}
.input:hover { border-color: var(--control-edge-hover); }
.input:focus { border-color: var(--blue); outline: none; box-shadow: var(--ring); }
.input:disabled { background-color: var(--sunk); color: var(--muted); }
/* What a person may read but not change sits a step down, so it does not
   invite a click that does nothing. */
.input[readonly] { background-color: var(--sunk); }
.input[readonly]:hover { border-color: var(--control-edge); }
/* A box or a dot to tick: the platform's own, in the palette's green and a
   size an older hand can see. Zero specificity, so a list that sizes its own
   (the poll's options, the import's parts) still does. */
:where(input[type="checkbox"], input[type="radio"]) { inline-size: 1rem; block-size: 1rem; accent-color: var(--blue); }
textarea.input { padding-block: .5rem; line-height: 1.75; }

/* The browser's own arrow, in the page's line and on the inline end (the left
   in RTL); the list it opens stays the platform's. */
select.input {
  appearance: none;
  padding-inline-end: 2.2rem;
  background: var(--control) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2356655c' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E") no-repeat left .7rem center / 1rem;
}
/* Under a mouse on a wide layout the text steps down with the box. A finger's
   layout keeps 16px — the size a phone does not zoom into: a field under it
   zooms the whole page the moment it takes focus, and the page stays zoomed.
   The ladder's field size is under 16px now, so the floor is said outright
   (`:root` so the palette's own field rule, later in the file, does not win). */
@media (min-width: 62rem) and (pointer: fine) {
  .input, .form-stack input, .form-stack textarea { font-size: var(--t-body); }
}
@media (pointer: coarse) {
  :root .input, :root .form-stack input, :root .form-stack textarea, :root .qa-input-wrap input { font-size: 16px; }
}
/* Four Persian words need room; a narrow box makes the reader lose their place. */
.input--words { font-size: var(--t-section); letter-spacing: .01em; }
/* A typed Jalali date (src/dates.rs). The field is LTR because a date and a
   clock are two number runs, and in an RTL box the bidi algorithm would lay
   «۱۴۰۵/۰۶/۱۵ ۰۸:۳۰» out as «۰۸:۳۰ ۱۴۰۵/۰۶/۱۵». It keeps the page's right
   alignment so it still sits in the form like every other control. */
.input--date { direction: ltr; text-align: right; font-variant-numeric: tabular-nums; }
.input--date::placeholder { color: var(--muted); }
.alert {
  padding: .7rem .9rem;
  border: 1px solid color-mix(in srgb, var(--red) 25%, var(--content));
  border-radius: var(--r);
  background: var(--red-tint);
  color: var(--ink);
  font-size: var(--t-body);
}

/* ══════════════════════════════════════════════════════════════════════════
   STUDENT CORE — action lists, reader, work, grades and conversation, in the
   card language: rows divided by hairlines inside a card, pills for states,
   the reader on a sheet of its own. Hierarchy comes from size and spacing,
   never from a second accent or a shadow.
   ══════════════════════════════════════════════════════════════════════════ */
.skip-link {
  position: fixed;
  inset-block-start: .5rem;
  inset-inline-start: .5rem;
  z-index: 100;
  /* docs/09 floors every interactive element at 44px. Padding alone left this
     at 43.2 — close enough to look right and to be wrong. It is the first
     thing a keyboard user meets on every authenticated page. */
  display: inline-flex;
  align-items: center;
  min-block-size: 44px;
  padding-inline: .9rem;
  border-radius: var(--r-sm);
  background: var(--bar-bg);
  color: var(--bar-fg);
  transform: translateY(-150%);
}
.skip-link:focus { transform: translateY(0); }
.mobile-nav { display: none; }

.panel-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: .6rem 1rem;
  margin-bottom: .9rem;
}
.panel-head h1 { font-size: var(--t-title); line-height: 1.35; color: var(--ink); }
.panel-head h2 { font-size: var(--t-section); color: var(--ink); }
.eyebrow { margin-bottom: .15rem; color: var(--muted); font-size: var(--t-meta); font-weight: 600; }
.summary-count, .quiet-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .25rem;
  min-height: var(--tap);
  /* "دریافت" on an attachment row measured 41.2px wide — under the floor by
     less than 3px, which is exactly the size of miss no one finds by eye. */
  min-inline-size: var(--tap);
  color: var(--muted);
  font-size: var(--t-small);
}
.quiet-link { color: var(--blue); font-weight: 500; }
/* A <button> in a POST form that reads as a link: no UA face. */
button.quiet-link { padding: 0 .5rem; border: 0; border-radius: var(--r-sm); background: none; font: inherit; font-size: var(--t-small); font-weight: 500; cursor: pointer; }
button.quiet-link:hover { background: var(--primary-tint); text-decoration: none; }
.quiet-link:hover { text-decoration: underline; text-underline-offset: 4px; }
.section-heading { margin: 1.7rem 0 .65rem; }
.section-heading h2 { font-size: var(--t-section); font-weight: 600; color: var(--ink); }

/* A micro-label above a group of cards — the aside's label idiom, allowed
   into the main column so a group heading never competes with the page. */
.list-label {
  display: flex;
  align-items: center;
  gap: .35rem;
  margin: 1.4rem 0 .5rem;
  font-size: var(--t-micro);
  font-weight: 600;
  color: var(--muted);
}

/* "All done" is a calm line in the affirmative ink, never a celebration. */
.calm-state, .complete-note {
  display: flex;
  align-items: center;
  gap: .5rem;
  min-height: var(--tap);
  padding: .6rem .85rem;
  border-radius: var(--r-sm);
  background: var(--aqua-tint);
  color: var(--aqua);
}
/* Row titles are 500 at body size — enough to lead the row — so real bold is
   left for what is really important: stat numbers, counts, states. */
.task-row strong, .task-copy strong, .teacher-list strong, .class-hub-row strong,
.conversation-main strong, .marking-row strong, .attachment-list strong,
.material-files strong, .roster-list strong,
.builder-section > summary strong, .lesson-edit > summary strong,
.report-row strong, .poll-row strong { font-weight: 500; font-size: var(--t-body); }

.class-hub-row { display: grid; grid-template-columns: 2.4rem minmax(0, 1fr) auto; gap: .75rem; align-items: center; min-height: 3.6rem; padding: .5rem .65rem; border-bottom: 1px solid var(--line); transition: background-color .12s, transform .12s var(--ease); }
.class-hub-row:last-child { border-bottom: 0; }
.class-hub-row:hover { background: var(--hover); }
.class-hub-row:active { transform: scale(.995); }
.class-hub-row > span:nth-child(2) { display: flex; flex-direction: column; min-width: 0; }
.class-hub-row strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.class-hub-row small { color: var(--faint); font-size: var(--t-meta); }
.class-hub-icon { display: flex; align-items: center; justify-content: center; color: var(--blue); }
.task-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(8rem, auto) auto;
  align-items: center;
  gap: .75rem;
  /* The row carries a second context line and the tap floor. */
  min-height: 3.4rem;
  padding: .5rem .65rem;
  border-bottom: 1px solid var(--line);
  border-inline-start: 3px solid transparent;
  color: var(--fg1);
  transition: background-color .12s, border-color .12s, transform .12s var(--ease);
}
.task-list > li:last-child > .task-row, .task-list > li:last-child { border-bottom: 0; }
.task-row:hover { background: var(--hover); }
.task-row:active { transform: scale(.995); }
.task-row.is-urgent { border-inline-start-color: var(--amber); }
.task-main, .task-copy, .conversation-main { display: flex; flex-direction: column; min-width: 0; }
.task-main strong, .task-copy strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.task-class, .task-copy small { color: var(--faint); font-size: var(--t-meta); }
.state-chip { display: inline-flex; align-items: center; padding: .04rem .6rem .12rem; border-radius: var(--pill); background: var(--chip); color: var(--fg2); font-size: var(--t-micro); line-height: 1.7; }
.copy-preview { display: flex; flex-wrap: wrap; gap: .35rem; margin: -.15rem 0 .35rem; }
.task-time { color: var(--faint); font-size: var(--t-meta); white-space: nowrap; }
.task-time.age-late { color: var(--amber); }
/* The row's verb says what the row does, in the primary ink, at rest — an
   older reader should not have to hover to find out a row is a door. The row
   is the target; its hover fills the verb. */
.task-action { display: inline-flex; align-items: center; gap: .25rem; padding: .25rem .6rem; margin-inline-end: -.4rem; border-radius: var(--r-sm); color: var(--blue); font-size: var(--t-small); font-weight: 600; white-space: nowrap; transition: background-color .12s, color .12s; }
.task-row:hover .task-action, .marking-row:hover .task-action, .material-files > a:hover .task-action { background: var(--primary-tint); }
/* The title darkens with the row. */
.task-row:hover .task-copy strong, .task-row:hover .task-main strong, .marking-row:hover strong { color: var(--ink); }

/* The reader: a sheet of its own on the ground, at a reading measure. */
.reading-layout {
  max-width: 50rem;
  margin: 0 auto;
  padding: 1.25rem 1.75rem 1rem;
  border: 1px solid var(--line);
  border-radius: var(--r);
  background: var(--surface);
}
.lesson-head { padding-bottom: 1rem; border-bottom: 1px solid var(--line); }
.lesson-meta { margin-top: .4rem; color: var(--faint); font-size: var(--t-small); }
.lesson-body, .prose { padding: 1.4rem 0; font-size: var(--t-read); line-height: 2; }
.lesson-body p + p, .prose p + p { margin-top: 1rem; }
.lesson-complete { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem 1rem; padding: 1rem 0; border-top: 1px solid var(--line); }
.lesson-complete .section-help { margin: 0; }
/* The pager names where it leads (proposal S2 §E); on a phone it stacks. */
.lesson-nav { display: flex; align-items: center; justify-content: space-between; gap: .5rem; min-height: 4rem; padding-block: .6rem; border-top: 1px solid var(--line); }
.lesson-nav > a { min-inline-size: 0; max-inline-size: 49%; }
.lesson-nav .go { margin-top: 0; }
.lesson-nav bdi { min-inline-size: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 40rem) {
  .lesson-nav { flex-direction: column; align-items: stretch; }
  .lesson-nav > a { max-inline-size: none; justify-content: center; }
  .lesson-nav > span:empty { display: none; }
  .lesson-complete > form, .lesson-complete .btn-primary { inline-size: 100%; justify-content: center; }
}

.work-main { min-width: 0; }
.work-facts dl div { padding: .55rem 0; border-bottom: 1px solid var(--line); }
.work-facts dl div:last-child { border-bottom: none; }
.work-facts dt { color: var(--muted); font-size: var(--t-meta); }
.work-facts dd { margin: .12rem 0 0; font-weight: 600; }
.submission-form { padding: 1rem 0; border-top: 1px solid var(--line); }
.textarea { width: 100%; min-height: 12rem; margin-top: .35rem; resize: vertical; line-height: 1.8; }
.form-actions { display: flex; flex-wrap: wrap; align-items: center; gap: .7rem; margin-top: .75rem; color: var(--muted); font-size: var(--t-meta); }

/* A score where it is a fact read once — a work page's result, an exam's
   receipt, a finished activity: a pill. On «نمره‌ها» the score is a column
   of the teacher's `.mark-row` instead (the block «نمره‌ها», below). */
.grade-score { display: inline-flex; align-items: baseline; gap: .25rem; padding: .02rem .65rem .1rem; border-radius: var(--pill); background: var(--accent-tint); color: var(--accent-ink); font-size: var(--t-read); font-weight: 600; font-variant-numeric: tabular-nums; line-height: 1.6; }
.grade-score small { color: var(--accent-ink); font-size: var(--t-micro); font-weight: 500; }

.conversation-main strong { color: var(--fg1); }
.conversation-main small, .conversation-main > span, .conversation-row time { overflow: hidden; color: var(--muted); font-size: var(--t-micro); text-overflow: ellipsis; white-space: nowrap; }
.announcement { padding: .8rem 0; border-bottom: 1px solid var(--line); }
.announcement h3 { margin: .2rem 0; font-size: var(--t-lead); }
.announcement p { color: var(--fg2); font-size: var(--t-body); line-height: 1.75; }
.conversation-head { display: flex; align-items: center; gap: .7rem; padding-bottom: .75rem; border-bottom: 1px solid var(--line); }
.conversation-head h1 { font-size: var(--t-section); }
.conversation-head p { color: var(--muted); font-size: var(--t-meta); }
.thread { display: flex; flex-direction: column; gap: .55rem; max-width: 42rem; min-height: 18rem; padding: 1rem 0; }
/* Two voices, told apart by side and fill. A bubble stops at two-thirds of
   the thread so the empty side says who spoke; the reader's own carry the
   primary's tint. The corner nearest the speaker is the small one. */
.bubble { align-self: flex-start; max-width: min(30rem, 72%); padding: .6rem .85rem .45rem; border: 1px solid var(--line); border-radius: 14px 14px 14px 4px; background: var(--surface); }
.bubble.mine { align-self: flex-end; border-color: var(--primary-edge); border-radius: 14px 14px 4px 14px; background: var(--primary-tint); }
.bubble p { white-space: pre-wrap; overflow-wrap: anywhere; line-height: 1.75; }
.bubble time { display: block; margin-top: .2rem; color: var(--muted); font-size: var(--t-micro); }
/* Reporting is for what the other party wrote: a quiet line under the bubble,
   present on every one so it is never hunted for, never louder than the
   message. It keeps the tap floor. */
.message-report { margin-top: .1rem; }
.message-report > summary { display: inline-flex; align-items: center; min-block-size: var(--tap); list-style: none; color: var(--faint); font-size: var(--t-meta); cursor: pointer; }
.message-report > summary::-webkit-details-marker { display: none; }
.message-report > summary:hover { color: var(--red); }
.message-report form { display: grid; gap: .4rem; padding-bottom: .3rem; }
.composer { max-width: 42rem; padding-top: .75rem; border-top: 1px solid var(--line); }
.composer > div { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: .5rem; align-items: stretch; }
.composer textarea { width: 100%; resize: vertical; }
/* The composer's file picker: one quiet row under the field, not the dashed
   box a form's upload is — a chat is mostly words, and the box would double
   the composer's height for the one message in ten that carries a file. */
.composer .composer-files { margin-top: .5rem; padding: 0; border: 0; background: none; gap: 0; }
/* Its caption stays the input's name for a screen reader, out of sight. */
.composer .composer-files > span:not(.upload-row) { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
.composer .composer-files .upload-row { min-height: var(--tap); }
/* A message's files, under its text, as the class's other files are listed. */
.bubble .message-files { margin-top: .4rem; }
.bubble .message-files > a { padding: .4rem .3rem; }

@media (max-width: 62rem) {
  /* Room for the fixed bottom bar, plus the phone's own home indicator
     underneath it: without the inset the last control on a page — a
     receipt, the save button on the marking sheet — sits under the bar. */
  body { padding-bottom: calc(4.4rem + env(safe-area-inset-bottom, 0px)); }
  .mobile-nav {
    position: fixed;
    inset-inline: 0;
    inset-block-end: 0;
    z-index: 50;
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    min-height: 3.9rem;
    padding-bottom: env(safe-area-inset-bottom, 0px);
    border-top: 1px solid var(--line-2);
    background: var(--surface);
  }
  .mobile-nav a { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: .15rem; min-height: var(--tap); color: var(--muted); font-size: var(--t-micro); font-weight: 500; }
  .mobile-nav a.is-active { color: var(--blue); font-weight: 600; }
  .reading-layout { padding: 1rem 1rem .75rem; }
}

@media (max-width: 38rem) {
  .task-row { grid-template-columns: minmax(0, 1fr) auto; }
  .task-meta { grid-column: 1; }
  /* A task row's verb spans its two lines at the end. Scoped: unscoped, it
     moved every other row's verb — «کلاس‌ها», a material file — into the
     text column on a phone. */
  .task-row .task-action { grid-column: 2; grid-row: 1 / span 2; }
  .page-hd-main { flex-basis: 100%; }
}

/* ══════════════════════════════════════════════════════════════════════════
   TEACHER WORKSPACE — the same cards, fields and buttons as everywhere.
   The density hand-back that used to live here (a 32px floor and smaller
   controls at desktop width) is retired (ADR-0026): the people who use this
   workspace most are the ones for whom a small target is hardest to hit.
   Operational screens avoid decorative entrance motion: teachers revisit
   these controls dozens of times a day. Press feedback remains immediate.
   ══════════════════════════════════════════════════════════════════════════ */
.teacher-brand-tag { padding: .05rem .5rem .12rem; border-radius: var(--pill); background: var(--primary-tint); color: var(--blue); font-size: var(--t-micro); font-weight: 600; }
.teacher-body { max-width: 76rem; width: 100%; margin-inline: auto; }
.teacher-columns { display: grid; grid-template-columns: repeat(2,minmax(0,1fr)); gap: 1.5rem; }
.teacher-columns h2,.manage-section h2 { font-size: var(--t-section); }
.teacher-list > a, .teacher-list > div { display: flex; align-items: center; justify-content: space-between; gap: 1rem; min-height: 3.4rem; padding: .5rem .65rem; border-bottom: 1px solid var(--line); transition: background-color .12s, transform .12s var(--ease); }
.teacher-list > :last-child { border-bottom: 0; }
.teacher-list > a:hover { background: var(--hover); }
.teacher-list > a:active { transform: scale(.995); }
.teacher-list > a > span:first-child, .teacher-list > div > span:first-child { display: flex; flex-direction: column; min-width: 0; }
.teacher-list strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.teacher-list small { color: var(--faint); font-size: var(--t-meta); }
.teacher-list--large { margin-top: 1.2rem; }
.quick-create { padding: .9rem 1rem; border: 1px solid var(--line); border-radius: var(--r); background: var(--surface); }
.quick-create > label { display: block; margin-bottom: .4rem; color: var(--fg2); font-size: var(--t-small); font-weight: 600; }
.quick-create > div,.inline-editor > div,.add-row { display: grid; grid-template-columns: minmax(0,1fr) auto; gap: .5rem; }
/* The create panel is a <details> (de-facto API) whose summary doubles the
   header's create button for the no-JS path. With script it opens as a modal
   (app.js `enhanceModals`, docs/08 §modals) and never unfolds in the page;
   without, it unfolds into a card below its button. */
.create-panel > summary {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  min-height: var(--h);
  padding: 0 .9rem;
  border: 1px solid var(--control-edge);
  border-radius: var(--r-sm);
  background: var(--control);
  box-shadow: var(--control-lift);
  color: var(--ink);
  font-size: var(--t-body);
  font-weight: 500;
  cursor: pointer;
  list-style: none;
  transition: background-color .12s, border-color .12s;
}
.create-panel > summary::-webkit-details-marker { display: none; }
.create-panel > summary:hover { background: var(--sunk); border-color: var(--control-edge-hover); }
.create-panel[open]:not([data-modal-ready]) { padding: .9rem 1rem 1rem; border: 1px solid var(--line); border-radius: var(--r); background: var(--surface); }
.create-panel .form { max-width: 38rem; padding-top: .6rem; }
/* A create panel with no summary (the class form: it carries a rich editor,
   so it unfolds in the page rather than as a dialog). The header's button
   (`data-open`) is the one way in and its «انصراف» (`data-close`) the way
   out, so nothing but the submit reads «ایجاد کلاس». Without script the
   header link targets it and `:target` shows it; with script app.js toggles
   `is-open`, and `is-closed` outlasts a fragment still in the address. */
.create-panel--target { display: none; padding: .9rem 1rem 1rem; border: 1px solid var(--line); border-radius: var(--r); background: var(--surface); }
.create-panel--target:target, .create-panel--target.is-open { display: block; }
.create-panel--target.is-closed:not(.is-open) { display: none; }
/* One line under a list of one or two: what this list is for, so a young
   workspace reads as young rather than broken. */
.list-hint { max-width: 42rem; margin-top: .8rem; color: var(--muted); font-size: var(--t-small); line-height: 1.8; }
.inline-editor { max-width: 42rem; padding: 1rem 0; }
.builder-section { border-bottom: 1px solid var(--line); }
.builder-section:last-child { border-bottom: 0; }
.builder-section > summary { display: grid; grid-template-columns: 2.1rem minmax(0,1fr) auto auto; gap: .6rem; align-items: center; min-height: 3.4rem; padding: .5rem; cursor: pointer; list-style: none; }
.builder-section > summary::-webkit-details-marker,.lesson-edit > summary::-webkit-details-marker { display:none; }
.builder-section > summary small { color: var(--muted); font-size: var(--t-micro); }
.builder-section > summary > svg { transition: transform .15s var(--ease); }
.builder-section[open] > summary > svg { transform: rotate(180deg); }
.builder-order { display: flex; align-items: center; justify-content: center; width: 1.8rem; height: 1.8rem; border-radius: var(--r-sm); background: var(--chip); color: var(--fg2); font-variant-numeric: tabular-nums; }
.builder-body { padding: .9rem; border-top: 1px solid var(--line); background: var(--sunk); }
.compact-form { display: grid; grid-template-columns: minmax(10rem,1fr) 6rem auto auto; gap: .6rem; align-items: end; padding-bottom: .8rem; }
.compact-form label,.form-row label,.lesson-edit form > label { display: flex; flex-direction: column; gap: .3rem; color: var(--fg2); font-size: var(--t-small); font-weight: 500; }
.check-label { display: inline-flex!important; flex-direction: row!important; align-items: center; gap: .45rem!important; min-height: var(--tap); color: var(--fg1); font-size: var(--t-body); }
/* A floor as well as a cap: in a narrow grid cell a number input shrank to
   36px (F19), which is under the tap floor and too narrow to read a value. */
.input--short, .input[type="number"] { min-inline-size: 4.5rem; }
.input--short { max-width: 6.5rem; }
.lesson-edit { border-bottom: 1px solid var(--line); }
.lesson-edit:last-child { border-bottom: 0; }
.lesson-edit > summary { display: grid; grid-template-columns: 1.5rem minmax(0,1fr) auto; gap: .5rem; align-items: center; min-height: var(--tap); padding: .45rem; cursor: pointer; }
.lesson-edit > summary small { color: var(--muted); font-size: var(--t-micro); }
.lesson-edit form { padding: .8rem; border-top: 1px solid var(--line); }
/* The two side columns hold a typed date and clock — «۱۴۰۵/۰۶/۱۰ ۲۰:۰۰» —
   and a clipped deadline is a wrong one. */
.form-row { display: grid; grid-template-columns: minmax(10rem,1fr) 11rem 11rem; gap: .7rem; }
.textarea--editor { min-height: 10rem; }
/* Marked for removal: faint and struck, never faded — faded text is text
   nobody can read, and the row's own "keep" control must stay legible. */
.is-deleted { color: var(--faint); }
.is-deleted strong { text-decoration: line-through; }
.add-row { margin-top: .75rem; }
.add-section { max-width: 42rem; padding-top: 1rem; }
/* A notice: amber means "waiting on you" — a card on its tint, never a field
   of warning colour. */
.notice { max-width: 46rem; margin-top: 1rem; padding: .8rem 1rem; border: 1px solid color-mix(in srgb, var(--amber) 22%, var(--content)); border-radius: var(--r); background: var(--amber-tint); color: var(--fg1); }
/* The one destructive act of a page lives in its own quiet box at the end,
   with a sentence that says what it does. */
.archive-card { display: flex; align-items: center; justify-content: space-between; gap: 1rem; max-width: 46rem; margin-top: 2rem; padding: .9rem 1rem; border: 1px solid color-mix(in srgb, var(--red) 20%, var(--content)); border-radius: var(--r); background: var(--surface); }
.archive-card p { color: var(--fg2); font-size: var(--t-small); }
.preview-banner { display: flex; align-items: center; justify-content: space-between; gap: .7rem; padding: .3rem .4rem .3rem 1rem; margin-bottom: 1rem; border: 1px solid color-mix(in srgb, var(--amber) 22%, var(--content)); border-radius: var(--r); background: var(--amber-tint); color: var(--fg1); font-size: var(--t-small); }
/* The only control on the preview, and the way back: it holds the tap floor
   like every other control (F15 — it was 17.8px tall). */
.preview-banner a { display: inline-flex; align-items: center; min-height: var(--tap); min-inline-size: var(--tap); padding: 0 .6rem; border-radius: var(--r-sm); color: var(--blue); font-weight: 600; }
.preview-section { padding: 1rem 0; border-bottom: 1px solid var(--line); }
.preview-section h2 { font-size: var(--t-section); }
.preview-section article { padding: .8rem 0; }
.preview-section h3 { font-size: var(--t-lead); margin-bottom: .35rem; }
.preview-section p { line-height: 1.9; }
.preview-section p + p { margin-top: .7rem; }
/* A management section is a card: its title, one line on what it is for,
   then its form or its list. */
.manage-section { max-width: 50rem; margin-bottom: 1rem; padding: 1rem 1.25rem 1.2rem; border: 1px solid var(--line); border-radius: var(--r); background: var(--surface); scroll-margin-top: 1rem; }
.manage-section > .form { max-width: 34rem; }
.section-help { margin: .25rem 0 .8rem; color: var(--muted); font-size: var(--t-small); line-height: 1.8; }
/* A door named inside the sentence: the session edit page's word about
   where its online class is set. */
.section-help a { color: var(--blue); font-weight: 500; }
.section-help a:hover { text-decoration: underline; }
.readonly-facts { display: grid; grid-template-columns: repeat(3,minmax(0,1fr)); max-width: 36rem; border-top: 1px solid var(--line); }
.readonly-facts > div { padding: .7rem; border-bottom: 1px solid var(--line); }
.readonly-facts dt { color: var(--muted); font-size: var(--t-meta); }
.readonly-facts dd { margin: .15rem 0 0; }
.check-list { display: flex; flex-direction: column; margin-bottom: .75rem; }
.check-list label { display: flex; align-items: center; gap: .55rem; min-height: var(--tap); padding: .35rem .45rem; border-bottom: 1px solid var(--line); }
.check-list label:last-child { border-bottom: 0; }
.teacher-mobile { grid-template-columns:repeat(5,1fr); }
@media(max-width:62rem){.teacher-columns{grid-template-columns:minmax(0,1fr)}.compact-form{grid-template-columns:minmax(0,1fr) 5rem}.compact-form .check-label{grid-column:1}.form-row{grid-template-columns:minmax(0,1fr) 10rem 10rem}.manage-section{padding:.9rem .9rem 1rem}}
@media(max-width:38rem){.quick-create>div,.inline-editor>div,.add-row{grid-template-columns:minmax(0,1fr)}.form-row{grid-template-columns:minmax(0,1fr)}.compact-form{grid-template-columns:minmax(0,1fr)}.compact-form .input--short{max-width:none}.archive-card{align-items:stretch;flex-direction:column}.archive-card .danger-button{width:100%}}

/* Teacher operations: stable surfaces with no decorative entrance motion. */
.assessment-settings { max-width: 50rem; padding: 1.1rem 0; }
.marking-row { display: grid; grid-template-columns: minmax(14rem,1fr) 6.5rem 11rem 6rem; gap: .75rem; align-items: center; min-height: 3.6rem; padding: .5rem .65rem; border-bottom: 1px solid var(--line); color: var(--fg1); transition: background-color .12s, transform .12s var(--ease); }
.marking-list > :last-child, .marking-list > li:last-child > .marking-row { border-bottom: 0; }
.marking-row:hover { background: var(--hover); }
.marking-row:active { transform: scale(.995); }
.marking-row > span:first-child { display: flex; flex-direction: column; min-width: 0; }
.marking-row small,.marking-row time,.marking-row > span:nth-child(2) { color: var(--faint); font-size: var(--t-meta); }
.queue-next { margin-top: 1rem; }
.roster-pager { display: flex; flex-wrap: wrap; gap: .4rem 1rem; align-items: baseline; margin-top: .8rem; color: var(--muted); font-size: var(--t-small); line-height: 1.8; }
.mark-layout { display: grid; grid-template-columns: minmax(0,1fr) 21rem; gap: 1.5rem; align-items: start; }
/* The work under the marker's eye: a sheet of its own, at reading size. */
.submission-paper { min-height: 28rem; padding: 1.25rem 1.4rem; border: 1px solid var(--line); border-radius: var(--r); background: var(--surface); font-size: var(--t-read); line-height: 1.95; }
.submission-paper p { white-space: pre-wrap; overflow-wrap: anywhere; }
.mark-panel { position: sticky; top: 1rem; padding: 1rem; border: 1px solid var(--line); border-radius: var(--r); background: var(--surface); }
.mark-panel form > .field + .field { margin-top: .85rem; }
.mark-panel .textarea { min-height: 10rem; }
/* «ثبت و برگهٔ بعدی», the page's one fill, and under it a quiet «فقط ثبت». */
.mark-panel .btn-primary { width: 100%; margin-top: .9rem; }
.mark-panel .quiet-button { width: 100%; margin-top: .5rem; }
/* One short field for a number of two digits, and its scale beside it. */
.score-field { display: flex; align-items: center; gap: .6rem; }
.score-field .input { max-inline-size: 6.5rem; text-align: center; font-weight: 600; font-variant-numeric: tabular-nums; }
.score-field > span { color: var(--muted); font-size: var(--t-body); font-variant-numeric: tabular-nums; white-space: nowrap; }
/* The two boxes, under the question they answer. */
.mark-audience { margin: .9rem 0 0; padding: .35rem .8rem .25rem; border: 1px solid var(--line); border-radius: var(--r-sm); }
.mark-audience legend { padding: 0 .3rem; color: var(--fg2); font-size: var(--t-small); font-weight: 600; }
.mark-audience .check-label { display: flex !important; }
/* An exam paper read as its student answered it (T1 B11): each question's
   prompt over the answer; and where the panel offers less than the boxes —
   an assistant on an exam, a paper the save refuses — one line on why. */
.paper-q + .paper-q { margin-top: 1.3rem; padding-top: 1.1rem; border-top: 1px solid var(--line); }
.paper-prompt { margin: 0 0 .45rem; color: var(--muted); font-size: var(--t-small); line-height: 1.8; }
.paper-prompt strong { color: var(--fg2); font-weight: 600; }
.paper-prompt > p { margin: 0; }
.paper-missing { margin: 0; color: var(--faint); font-size: var(--t-small); }
.mark-panel .staff-rights { margin-top: .9rem; }
.mark-closed { display: flex; align-items: flex-start; gap: .5rem; margin: 0; color: var(--fg2); font-size: var(--t-small); line-height: 1.8; }
.mark-closed svg { flex: none; inline-size: 14px; block-size: 14px; margin-top: .3rem; color: var(--muted); }
/* Where a waiting paper sits among its assessment's, and its neighbours. */
.pile-bar { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem .6rem; margin: 0 0 1rem; }
.pile-pos { padding-inline: .35rem; color: var(--fg2); font-size: var(--t-small); font-variant-numeric: tabular-nums; }
.pile-bar .quiet-button { display: inline-flex; align-items: center; gap: .3rem; }
.mark-saved { margin: 0 0 1rem; }
/* A paper's facts in its byline: its state as a word on a wash, how late it
   came in amber. The assessment and the class are links, inline. */
.page-hd .byline .st, .page-hd .byline .late { vertical-align: .05em; }
.byline a { color: inherit; text-decoration: none; }
.byline a:hover { color: var(--blue); text-decoration: underline; }
/* What was asked, folded over the answer; and a rewrite's earlier attempts
   under it, each folded, its feedback on the sunk wash. */
.submission-paper > .paper-brief { margin: -.35rem 0 .9rem; }
.submission-paper > .paper-brief > summary { padding-top: 0; }
.submission-paper .acc-body .material-files { margin-top: .5rem; }
.paper-sect-label { margin: 0 0 .35rem; color: var(--muted); font-size: var(--t-meta); font-weight: 600; line-height: 1.6; }
.submission-paper > .attempt { margin-top: 1.2rem; border-top: 1px solid var(--line); border-bottom: 0; }
.attempt-feedback { margin: .1rem 0 .55rem; padding: .6rem .8rem; border-radius: var(--r-sm); background: var(--sunk); color: var(--fg1); font-size: var(--t-small); line-height: 1.9; }
.attempt-feedback cite { display: block; margin-bottom: .15rem; color: var(--muted); font-size: var(--t-meta); font-style: normal; }
.answer-text { white-space: pre-wrap; overflow-wrap: anywhere; }
/* A quiz paper read against its key: the exam review's own items. */
.submission-paper > .quiz-item:first-of-type { padding-top: 0; }
.quiz-item h3 .pts { flex-shrink: 0; color: var(--muted); font-size: var(--t-meta); font-weight: 500; white-space: nowrap; }
.quiz-item.is-removed h3 { color: var(--muted); font-weight: 500; }
.review-answers dd.is-right { color: var(--aqua); font-weight: 600; }
.review-answers dd.is-wrong { color: var(--red); }
.pair-grid { display: grid; grid-template-columns: repeat(4, max-content); justify-content: start; align-items: baseline; gap: .2rem .55rem; margin: .45rem 0 0; font-size: var(--t-body); }
.pair-grid .arrow { color: var(--faint); }
.pair-grid .ok { color: var(--aqua); font-weight: 600; }
.pair-grid .bad { color: var(--red); }
.pair-grid small { color: var(--muted); font-size: var(--t-meta); }
/* A quiz's score is a result, read first; changing it is folded under it. */
.auto-score { display: grid; gap: .2rem; padding-bottom: .85rem; border-bottom: 1px solid var(--line); }
.auto-label { color: var(--muted); font-size: var(--t-meta); }
.auto-score strong { color: var(--ink); font-size: var(--t-sub); font-weight: 600; line-height: 1.4; font-variant-numeric: tabular-nums; }
.auto-score strong small { color: var(--muted); font-size: var(--t-body); font-weight: 400; }
.auto-score p { margin: 0; color: var(--fg2); font-size: var(--t-small); }
.auto-score .released { display: inline-flex; align-items: center; gap: .3rem; color: var(--aqua); font-weight: 600; }
.auto-score .released svg { inline-size: 14px; block-size: 14px; }
.mark-panel .acc-body form > .field + .field { margin-top: .7rem; }
.mark-panel .acc-body .textarea { min-height: 6rem; }
.override-note { margin: 0 0 .6rem; color: var(--muted); font-size: var(--t-meta); line-height: 1.8; }
@media (max-width: 40rem) { .pair-grid { grid-template-columns: max-content auto max-content; } .pair-grid small { grid-column: 1 / -1; margin-bottom: .3rem; } }

/* ── One exercise or quiz as a place: «برگه‌ها» ─────────────────────────────
   The class against the assessment in one band — who handed in, the marks so
   far, the deadline — then its filters and what can be done to many papers
   at once, then one line per student. Every colour is a token. */
.papers-done { margin: 0 0 .9rem; }
.papers-summary { display: grid; grid-template-columns: minmax(0, 1.3fr) minmax(0, 1fr) minmax(0, 1fr); margin: 0 0 1rem; border: 1px solid var(--line); border-radius: var(--r); background: var(--surface); }
.ps-block { display: flex; flex-direction: column; gap: .35rem; min-width: 0; padding: .9rem 1.1rem; }
.ps-block + .ps-block { border-inline-start: 1px solid var(--line); }
.ps-label { color: var(--muted); font-size: var(--t-meta); }
.ps-big { color: var(--ink); font-size: var(--t-sub); font-weight: 600; line-height: 1.4; font-variant-numeric: tabular-nums; }
.ps-big small { color: var(--muted); font-size: var(--t-small); font-weight: 400; }
.ps-block .stack-bar { inline-size: 100%; block-size: 8px; }
.ps-block .chart-key { margin: .1rem 0 0; gap: .2rem .9rem; }
.ps-line { margin: 0; color: var(--fg2); font-size: var(--t-small); line-height: 1.7; }
.ps-line.is-warn { color: var(--amber); }
.ps-block .hist-fig { margin-top: .2rem; }
.papers-bar { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .6rem 1rem; margin: 0 0 .6rem; }
.papers-bar > .tabs--sub { margin: 0; }
/* The filters take the bar's free width: app.js measures their row to decide
   whether «بیشتر» is needed, and a row only as wide as its tabs clipped them
   on a phone with the reveal still hidden. */
.papers-bar > nav.tabs, .papers-bar > .section-navigation { flex: 1 1 auto; min-width: 0; }
.papers-bar > .section-navigation > nav.tabs { margin: 0; }
.filter-count { display: inline-flex; }
.papers-actions { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; }
.papers-actions > form { display: inline-flex; }
.papers-actions .quiet-button { display: inline-flex; align-items: center; gap: .35rem; }
.paper-table { border: 1px solid var(--line); border-radius: var(--r); background: var(--surface); overflow: hidden; }
.paper-row { display: grid; grid-template-columns: minmax(8rem, 1.3fr) minmax(9rem, 1.2fr) minmax(10rem, 1.4fr) 3.5rem 5.5rem 6rem; align-items: center; gap: .75rem; min-block-size: var(--tap); padding: .35rem 1rem; border-top: 1px solid var(--line); color: var(--ink-2); font-size: var(--t-body); text-decoration: none; }
.paper-row:first-child { border-top: 0; }
a.paper-row:hover { background: var(--row-hover); }
a.paper-row:hover .who { color: var(--blue); }
.paper-row.is-head { min-block-size: 2.4rem; background: var(--sunk); color: var(--muted); font-size: var(--t-micro); font-weight: 600; }
.paper-row > span { min-width: 0; }
.paper-row .who { color: var(--ink); font-weight: 600; overflow-wrap: anywhere; }
.paper-row.is-none .who { color: var(--fg2); font-weight: 500; }
.paper-row .when { display: flex; flex-wrap: wrap; align-items: center; gap: .2rem .45rem; color: var(--fg2); font-size: var(--t-small); }
.paper-row .num, .paper-row.is-none .when, .paper-row.is-none .score { color: var(--muted); font-size: var(--t-small); font-variant-numeric: tabular-nums; }
.paper-row .score strong { color: var(--ink); font-weight: 600; font-variant-numeric: tabular-nums; }
.paper-row .score small { color: var(--muted); font-size: var(--t-meta); }
.paper-row .act { justify-self: end; color: var(--muted); font-size: var(--t-small); }
.paper-row .act-open { display: inline-flex; align-items: center; gap: .25rem; }
.paper-row .act-go { color: var(--blue); font-weight: 600; }
.paper-empty { margin: 0; padding: 1rem; }
.paper-foot { margin: .6rem .2rem 0; color: var(--muted); font-size: var(--t-meta); line-height: 1.8; }
/* A paper's state, a word on a wash; the colour repeats the word. */
.st { display: inline-flex; align-items: center; gap: .3rem; padding: .04rem .55rem .1rem; border-radius: var(--pill); background: var(--chip); color: var(--fg2); font-size: var(--t-micro); font-weight: 600; line-height: 1.7; white-space: nowrap; }
.st svg { inline-size: 12px; block-size: 12px; flex-shrink: 0; }
.st--wait { background: var(--amber-tint); color: var(--amber); }
.st--done { background: var(--aqua-tint); color: var(--aqua); }
.st--held { background: var(--accent-tint); color: var(--accent-ink); }
.st--back { background: var(--primary-tint); color: var(--blue); }
.st--none { padding-inline: 0; background: none; color: var(--muted); font-weight: 500; }
.late { display: inline-flex; align-items: center; padding: 0 .45rem; border-radius: var(--pill); background: var(--amber-tint); color: var(--amber); font-size: var(--t-micro); font-weight: 600; line-height: 1.8; white-space: nowrap; }
/* The assessment read, beside every view but the form's. */
.brief-text { margin: 0 0 .5rem; color: var(--fg1); font-size: var(--t-small); line-height: 1.85; }
.aside-chips { display: flex; flex-wrap: wrap; gap: .35rem; }
.side-link { display: inline-flex; align-items: center; gap: .3rem; min-block-size: var(--tap); color: var(--blue); font-size: var(--t-small); font-weight: 600; text-decoration: none; }
.side-link:hover { text-decoration: underline; }
/* «پرسش‌ها» once published: each question with the answer it takes. */
.q-intro { display: flex; flex-wrap: wrap; align-items: center; gap: .3rem .5rem; margin: 0 0 .8rem; color: var(--fg2); font-size: var(--t-small); }
.q-intro > svg { color: var(--blue); }
.q-publish-hint { margin: 1rem 0 0; }
.q-card { padding: .95rem 1.1rem 1rem; border: 1px solid var(--line); border-radius: var(--r); background: var(--content); }
.q-card + .q-card { margin-top: .6rem; }
.q-card h3 { display: flex; align-items: flex-start; gap: .45rem; margin: 0; color: var(--ink); font-size: var(--t-lead); font-weight: 600; line-height: 1.75; }
.q-text { flex: 1 1 auto; min-width: 0; }
.q-meta { display: flex; flex-wrap: wrap; gap: .3rem .5rem; margin: .1rem 0 .55rem; padding-inline-start: 2rem; color: var(--muted); font-size: var(--t-meta); }
.q-choices { display: grid; gap: .25rem; margin: 0; padding: 0; padding-inline-start: 2rem; list-style: none; }
.q-choices li { display: flex; align-items: center; gap: .5rem; padding: .3rem .6rem; border-radius: var(--r-sm); color: var(--fg2); font-size: var(--t-body); }
.q-choices li::before { content: ""; flex-shrink: 0; inline-size: .7rem; block-size: .7rem; border: 1.5px solid var(--control-edge-hover); border-radius: var(--pill); }
.q-choices li.is-key { background: var(--aqua-tint); color: var(--aqua); font-weight: 600; }
.q-choices li.is-key::before { border-color: var(--aqua); background: var(--aqua); }
.q-key { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: .25rem .8rem; margin: 0; padding-inline-start: 2rem; font-size: var(--t-body); }
.q-key dt { color: var(--muted); }
.q-key dd { margin: 0; color: var(--aqua); font-weight: 600; }
.q-key small { color: var(--muted); font-weight: 400; }
.q-pairs { display: grid; grid-template-columns: repeat(3, max-content); justify-content: start; align-items: baseline; gap: .25rem .6rem; padding-inline-start: 2rem; font-size: var(--t-body); }
.q-pairs .arrow { color: var(--faint); }
.q-pairs .right { color: var(--aqua); font-weight: 600; }
/* «تنظیمات»: what being published means, and the two acts that take it from
   students, together and last. */
.settings-note { display: flex; align-items: center; gap: .5rem; max-width: 50rem; margin: 0 0 1rem; padding: .6rem .85rem; border-radius: var(--r); background: var(--primary-tint); color: var(--fg1); font-size: var(--t-small); }
.settings-note > svg { flex-shrink: 0; color: var(--blue); }
.danger-zone { max-width: 46rem; margin-top: 2rem; }
.danger-zone > h2 { margin: 0; font-size: var(--t-section); font-weight: 600; }
.danger-zone > .archive-card { margin-top: .75rem; }
@media (max-width: 62rem) {
  .papers-summary { grid-template-columns: minmax(0, 1fr); }
  .ps-block + .ps-block { border-inline-start: 0; border-top: 1px solid var(--line); }
}
@media (max-width: 48rem) {
  .paper-row { grid-template-columns: minmax(0, 1fr) auto; gap: .15rem .75rem; padding-block: .55rem; }
  .paper-row.is-head { display: none; }
  .paper-row .who { grid-column: 1; grid-row: 1; }
  .paper-row .state { grid-column: 2; grid-row: 1; justify-self: end; }
  .paper-row .when { grid-column: 1; grid-row: 2; }
  .paper-row .score { grid-column: 2; grid-row: 2; justify-self: end; }
  .paper-row .num, .paper-row .act { display: none; }
  .q-meta, .q-choices, .q-key, .q-pairs { padding-inline-start: 0; }
}
/* The table hugs its columns: a class with two assessments is a small table,
   not a wide one with an empty half. The scroll box is inline so its edge
   ends where the columns end, and it scrolls only when the columns outgrow
   the page. */
.gradebook-scroll { display: inline-block; overflow: auto; max-width: 100%; border: 1px solid var(--line); border-radius: var(--r); background: var(--surface); }
/* Its own scroll box, as tall as the window allows: the head row and the name
   column stick inside it, a spreadsheet's behaviour. With no height of its
   own the box grew with the page and the head scrolled away with it. */
.gradebook-scroll { max-block-size: min(46rem, calc(100dvh - 7rem)); }
.gradebook { width: max-content; border-collapse: collapse; font-size: var(--t-body); }
.gradebook th,.gradebook td { min-width: 6.5rem; padding: .6rem .7rem; border-bottom: 1px solid var(--line); border-inline-end: 1px solid var(--line); text-align: center; }
.gradebook th:first-child { position: sticky; inset-inline-start: 0; z-index: 1; inline-size: 13rem; min-width: 13rem; max-inline-size: 13rem; background: var(--surface); text-align: start; }
/* The average sticks beside the name, so with twenty columns it is still
   beside whose it is (the register's count, `.register-total`, does the same). */
.gradebook thead th:nth-child(2), .gradebook td.gb-avg { position: sticky; inset-inline-start: 13rem; z-index: 1; background: var(--surface); box-shadow: inset 1px 0 0 var(--line-2); }
.gradebook tbody tr:hover > th, .gradebook tbody tr:hover > td { background-color: var(--row-hover); }
/* The header row is sunk a step, opaque: it sticks over the rows it names. */
.gradebook thead th { position: sticky; top: 0; z-index: 2; background: var(--sunk); color: var(--fg1); font-size: var(--t-small); }
.gradebook tbody tr:last-child th, .gradebook tbody tr:last-child td { border-bottom: none; }
.gradebook tr > :last-child { border-inline-end: none; }
.gradebook thead th:first-child, .gradebook thead th:nth-child(2) { z-index: 3; }
.gradebook thead th:nth-child(2) { background: var(--sunk); }
.gradebook th small { display: block; color: var(--muted); font-weight: 400; }
/* A mark in ink, tabular — not a column of aqua 600 down a 630-row table; a
   waiting paper is «● نمره‌دهی» in amber, the verb of the door it is; a paper
   back with its student keeps its mark behind a red dot; nothing handed in is
   a faint «—» and no door. */
.gradebook td.is-marked, .gradebook td.is-returned { color: var(--fg1); font-weight: 500; font-variant-numeric: tabular-nums; }
.gradebook td.is-pending { color: var(--amber); }
.gradebook td.is-empty { color: var(--faint); }
.gradebook td.is-pending .gb-cell { font-size: var(--t-small); font-weight: 600; }
.gradebook td.is-pending .gb-cell::before, .gradebook td.is-returned .gb-cell::before { content: ""; flex: none; inline-size: .42rem; block-size: .42rem; border-radius: 50%; background: currentColor; }
.gradebook td.is-returned .gb-cell::before { background: var(--red); }
/* A cell with a paper behind it opens that paper where papers are marked
   (ADR-0028): the whole cell is the link, so the target is the cell. */
.gradebook .gb-cell { display: flex; align-items: center; justify-content: center; gap: .35rem; margin: -.6rem -.7rem; padding: .6rem .7rem; color: inherit; font-weight: inherit; }
.gradebook .gb-cell:hover { background: var(--hover); }
.gradebook .gb-cell:focus-visible { outline: 2px solid var(--blue); outline-offset: -2px; }
/* A finger's floor: the cell's own height came from its line, and a 13px
   line is under it. */
@media (max-width: 62rem), (pointer: coarse) {
  .gradebook .gb-cell { min-block-size: var(--tap); }
}
.quiz-sheet { display: flex; flex-direction: column; gap: 1rem; }
.quiz-question { padding: 1rem 1.1rem; border: 1px solid var(--line); border-radius: var(--r); background: var(--surface); }
.quiz-question legend { padding: 0 .35rem; font-weight: 600; line-height: 1.6; }
/* Only the number wears the square. The rule once matched every span, so an
   exam prompt wrapped in `.rich-inline` was squeezed into the same 1.6rem box
   and rendered one word per line. */
.quiz-question legend > span:first-child, .q-num { display: inline-flex; align-items: center; justify-content: center; min-width: 1.6rem; height: 1.6rem; margin-inline-end: .4rem; padding: 0 .35rem; border-radius: var(--r-sm); background: var(--chip); font-size: var(--t-small); vertical-align: middle; }
.quiz-question legend small { color: var(--fg3); font-size: var(--t-micro); font-weight: 400; }
.rich-inline { display: inline; }
.rich-inline > p { display: inline; margin: 0; }
.rich-inline > p + p::before { content: " "; }
.quiz-question > label { display: flex; align-items: center; gap: .55rem; min-height: var(--tap); padding: .3rem .45rem; border-bottom: 1px solid var(--line); }
.quiz-question > label:last-of-type { border-bottom: 0; }
@media(max-width:62rem){.mark-layout{grid-template-columns:minmax(0,1fr)}.mark-panel{position:static}.marking-row{grid-template-columns:minmax(0,1fr) auto}.marking-row time{grid-column:1}.marking-row .task-action{grid-column:2;grid-row:1/span 2}}

/* Rich authoring and private class materials, on the system's tokens. */
.rich-create-form, .intro-form { max-width: 52rem; }
.intro-form { margin-block: 1rem 1.5rem; }
.rich-editor { min-height: 13rem; }
/* The editor is a control, so it wears the control's edge and radius and
   nothing of TinyMCE's own design system, and the focus ring is the same
   green edge and ring every .input takes. */
.tox.tox-tinymce { border: 1px solid var(--line-2); border-radius: var(--r-sm); box-shadow: none; transition: border-color .12s, box-shadow .12s; }
.tox.tox-tinymce.tox-edit-focus { border-color: var(--blue); box-shadow: var(--ring); }
.tox .tox-edit-area::before { display: none; }
/* The toolbar joins the page: surface fill, a hairline below, flat buttons at
   the page's 13px, the page's ink on every glyph. */
.tox .tox-toolbar-overlord, .tox:not(.tox-tinymce-inline) .tox-editor-header { background: var(--content) !important; box-shadow: none !important; border-bottom: 1px solid var(--bg2) !important; padding: 0 !important; }
.tox .tox-toolbar__primary { background: var(--content) !important; padding: 0 .2rem !important; }
.tox .tox-toolbar__group { padding: 0 .25rem !important; }
.tox .tox-tbtn { background: transparent; border-radius: 5px; cursor: pointer; height: 30px; margin: 2px 0; color: var(--fg1); font-family: inherit; }
.tox .tox-tbtn:hover { background: var(--row-hover) !important; }
.tox .tox-tbtn--enabled, .tox .tox-tbtn--enabled:hover { background: var(--accent-tint) !important; color: var(--blue) !important; }
.tox .tox-tbtn svg { fill: var(--fg1) !important; }
.tox .tox-tbtn--enabled svg { fill: var(--blue) !important; }
.tox .tox-tbtn--select { width: auto; }
.tox .tox-tbtn__select-label { font-family: inherit; font-size: var(--t-small); }
/* The block picker is a dropdown of the page's own words, so it takes the
   page's face. */
.tox .tox-tbtn__select-label, .tox .tox-collection__item-label, .tox .tox-menu { font-family: "IRANSans", Tahoma, system-ui, sans-serif !important; }
.tox .tox-menu { border: 1px solid var(--line-2) !important; border-radius: 11px !important; background: var(--raised) !important; box-shadow: var(--shadow-pop) !important; }
.tox .tox-collection--list .tox-collection__item--active { background: var(--accent-tint) !important; color: var(--blue) !important; }
.tox .tox-dialog { border-radius: 14px !important; border: 1px solid var(--line) !important; font-family: "IRANSans", Tahoma, system-ui, sans-serif !important; }
.upload-field { display: grid; grid-template-columns: minmax(0, 1fr); gap: .55rem; padding: .9rem 1rem; border: 1.5px dashed var(--line-2); border-radius: var(--r); background: var(--surface); cursor: pointer; transition: border-color .12s; }
.upload-field:hover { border-color: var(--primary-edge); }
.upload-field > span { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 0 1rem; font-weight: 600; }
.upload-field small { font-weight: 400; color: var(--muted); }
/* The audit measures the file input itself (only checkbox/radio defer to
   their label), so the input carries the 44px floor directly. */
.upload-field input[type=file] { max-width: 100%; min-height: var(--h); font: inherit; color: var(--fg3); }

/* With JS the native control — which speaks the browser's language and takes
   no styling — becomes an invisible layer over the whole dashed field, and a
   drawn Persian button + status line stand in for it. Without JS none of this
   applies and the native input stays visible. */
.upload-field--js { position: relative; }
.upload-field--js input[type=file] {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  cursor: pointer;
}
.upload-row { display: flex; align-items: center; gap: .6rem; min-height: var(--tap); }
.upload-btn {
  display: inline-flex;
  flex: none;
  align-items: center;
  min-height: 2rem;
  padding: 0 .8rem;
  border: 1px solid var(--control-edge);
  border-radius: var(--r-sm);
  background: var(--control);
  box-shadow: var(--control-lift);
  color: var(--ink);
  font-size: var(--t-small);
  font-weight: 500;
  white-space: nowrap;
}
.upload-field--js:hover .upload-btn { background: var(--sunk); border-color: var(--control-edge-hover); }
.upload-names { color: var(--muted); font-size: var(--t-small); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.upload-field input[type=file]::file-selector-button { margin-inline-end: .75rem; border: 1px solid var(--control-edge); border-radius: var(--r-sm); padding: .3rem .8rem; background: var(--control); color: var(--ink); font: inherit; cursor: pointer; transition: border-color .12s, background-color .12s; }
.upload-field input[type=file]::file-selector-button:hover { border-color: var(--control-edge-hover); background: var(--sunk); }

/* Moodle restore is deliberately a calm three-step page, not a wizard modal.
   The archive can take minutes to upload and the manifest deserves a stable
   URL-sized surface where Back, refresh and assistive navigation stay normal. */
.import-head { margin-bottom: 0; }
.import-steps {
  display: grid; grid-template-columns: repeat(3,minmax(0,1fr));
  max-width: 36rem; margin: 1rem 0 1.25rem; padding: 0; list-style: none;
  border: 1px solid var(--line); border-radius: var(--r); background: var(--surface); overflow: hidden;
}
.import-steps li {
  display: flex; align-items: center; gap: .45rem; min-height: var(--tap);
  padding: .45rem .65rem; color: var(--fg3); font-size: var(--t-meta);
  border-inline-start: 3px solid transparent;
}
.import-steps li span {
  display: inline-flex; align-items: center; justify-content: center;
  inline-size: 1.5rem; block-size: 1.5rem; flex: 0 0 1.5rem;
  border: 1px solid var(--line-2); border-radius: 50%; color: var(--muted); font-size: var(--t-micro);
}
.import-steps li span svg { inline-size: .75rem; block-size: .75rem; }
.import-steps .is-current { border-inline-start-color: var(--blue); background: var(--primary-tint); color: var(--ink); font-weight: 600; }
.import-steps .is-current span { border-color: var(--blue); color: var(--blue); }
.import-steps .is-done { color: var(--aqua); }
.import-steps .is-done span { border-color: color-mix(in srgb,var(--aqua) 45%,var(--bg2)); color: var(--aqua); }
.import-cols { align-items: start; }
.import-panel { margin-top: 0; max-width: 52rem; }
.import-upload-form { max-width: 42rem; }
.import-drop { padding-block: 1rem; }
.import-summary {
  display: grid; grid-template-columns: repeat(6,minmax(0,1fr));
  max-width: 58rem; margin-bottom: 1.25rem;
  border: 1px solid var(--line); border-radius: var(--r); background: var(--surface); overflow: hidden;
}
.import-summary > div { min-width: 0; padding: .7rem .6rem; border-bottom: 1px solid var(--bg1); }
.import-summary strong { display: block; overflow: hidden; color: var(--fg0); font-size: var(--t-section); font-variant-numeric: tabular-nums; text-overflow: ellipsis; white-space: nowrap; }
.import-summary span { display: block; margin-top: .15rem; color: var(--muted); font-size: var(--t-meta); }
.import-parts { display: grid; grid-template-columns: repeat(2,minmax(0,1fr)); gap: 0; padding: 0; border: 1px solid var(--line); border-radius: var(--r); background: var(--surface); overflow: hidden; }
.import-parts label {
  display: flex; align-items: center; gap: .7rem; min-height: var(--tap);
  padding: .65rem .75rem; border-bottom: 1px solid var(--bg1); cursor: pointer;
  transition: background .12s, border-color .12s;
}
.import-parts label:nth-child(odd) { border-inline-end: 1px solid var(--bg1); }
.import-parts label:nth-last-child(-n+2) { border-bottom: 0; }
.import-parts input { inline-size: 1rem; block-size: 1rem; flex: 0 0 auto; accent-color: var(--blue); }
.import-parts span { display: flex; min-width: 0; flex-direction: column; }
.import-parts strong { color: var(--fg1); font-size: var(--t-small); font-weight: 600; }
.import-parts small { margin-top: .12rem; color: var(--muted); font-size: var(--t-meta); }
.import-parts .is-disabled { cursor: not-allowed; color: var(--faint); }
.import-parts .is-disabled strong { color: var(--faint); }
@media(hover:hover) and (pointer:fine) { .import-parts label:not(.is-disabled):hover { background: var(--hover); } }
.import-accounts { border: 1px solid color-mix(in srgb, var(--amber) 22%, var(--content)); border-radius: var(--r); background: var(--amber-tint); }
.import-accounts summary { display: flex; align-items: center; gap: .5rem; min-height: var(--tap); padding: .45rem .7rem; cursor: pointer; color: var(--fg1); font-size: var(--t-small); }
.import-accounts summary::marker { content: ""; }
.import-accounts[open] summary .chev { transform: rotate(0); }
.import-accounts summary .chev { display: inline-flex; transform: rotate(90deg); transition: transform .12s; }
.import-accounts > div { padding: 0 .8rem .7rem; }
.import-accounts ul { display: grid; margin: .5rem 0 0; padding: 0; list-style: none; border-top: 1px solid var(--bg2); }
.import-accounts li { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: .45rem 0; border-bottom: 1px solid var(--bg1); }
.import-accounts li span { display: flex; align-items: baseline; gap: .4rem; min-width: 0; }
.import-accounts li small { color: var(--fg3); font-size: var(--t-micro); }
.import-accounts code { color: var(--fg3); font: var(--t-meta) ui-monospace,SFMono-Regular,Menlo,monospace; }
.import-safety { margin: 0; }
.import-apply-form .form-actions { margin-top: 0; }
.import-cancel { margin-top: .75rem; }
.import-manifest { max-width: 54rem; padding: 0 .45rem; border: 1px solid var(--line); border-radius: var(--r); background: var(--surface); scroll-margin-top: 1rem; }
.manifest-group + .manifest-group { border-top: 1px solid var(--line); }
.manifest-group summary { display: flex; align-items: center; gap: .55rem; min-height: var(--tap); padding: .45rem .6rem; cursor: pointer; }
.manifest-group summary::marker { content: ""; }
.manifest-group summary strong { flex: 1; font-size: var(--t-small); font-weight: 600; }
.manifest-group summary .chev { display: inline-flex; transform: rotate(90deg); transition: transform .12s; }
.manifest-group[open] summary .chev { transform: rotate(0); }
.manifest-mark { inline-size: 1rem; flex: 0 0 1rem; color: var(--fg3); text-align: center; font-family: ui-monospace,SFMono-Regular,Menlo,monospace; }
.manifest-mark svg { inline-size: .8rem; block-size: .8rem; }
.manifest-adjusted .manifest-mark { color: var(--amber); }
.manifest-refused .manifest-mark { color: var(--red); }
.manifest-mapped .manifest-mark { color: var(--aqua); }
.manifest-group > div { padding-inline: 2.15rem .6rem; }
.manifest-group > div > p { display: grid; grid-template-columns: minmax(10rem,.8fr) minmax(12rem,1.2fr); gap: 1rem; margin: 0; padding: .5rem 0; border-top: 1px solid var(--bg1); }
.manifest-group p strong { min-width: 0; color: var(--fg1); font-size: var(--t-meta); font-weight: 500; overflow-wrap: anywhere; }
.manifest-group p small { color: var(--fg3); font-size: var(--t-micro); line-height: 1.7; }
.manifest-group .feed-empty { display: block; color: var(--fg3); }
.import-complete { max-width: 42rem; margin: 2.5rem auto; text-align: center; }
.import-complete .notice-mark { color: var(--aqua); opacity: 1; }
.import-complete .notice-mark svg { inline-size: 2.5rem; block-size: 2.5rem; }
.import-complete h2 { font-size: var(--t-sub); }
.import-complete > p { margin-top: .45rem; color: var(--fg3); }
.import-complete .import-summary { grid-template-columns: repeat(3,minmax(0,1fr)); margin: 1.5rem auto; text-align: start; }
.import-complete .notice-actions .quiet-button { display: inline-flex; align-items: center; }
@media(max-width:52rem) { .import-summary { grid-template-columns: repeat(3,minmax(0,1fr)); } }
@media(max-width:40rem) {
  .import-steps { max-width: none; }
  .import-steps li { align-items: flex-start; flex-direction: column; gap: .25rem; }
  .import-parts { grid-template-columns: minmax(0,1fr); }
  .import-parts label:nth-child(odd) { border-inline-end: 0; }
  .import-parts label:nth-last-child(2) { border-bottom: 1px solid var(--bg1); }
  .manifest-group > div { padding-inline: .65rem; }
  .manifest-group > div > p { grid-template-columns: minmax(0,1fr); gap: .2rem; }
}
.attachment-upload { display: flex; align-items: end; gap: .75rem; margin-top: 1rem; }
.attachment-upload .upload-field { flex: 1; }
.attachment-list { display: grid; }
.attachment-list > div { display: grid; grid-template-columns: auto minmax(0, 1fr) auto auto; align-items: center; gap: .75rem; padding: .6rem .2rem; border-bottom: 1px solid var(--line); }
.attachment-list > div:last-child { border-bottom: 0; }
.attachment-list strong, .material-files strong { display: block; overflow-wrap: anywhere; }
.attachment-list small, .material-files small { display: block; color: var(--muted); margin-top: .15rem; }
.file-mark { display: grid; place-items: center; width: 2.25rem; height: 2.25rem; border-radius: 9px; background: var(--accent-tint); color: var(--accent-ink); }
.material-files { display: grid; margin-top: 1rem; }
.material-files > a { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: .75rem; padding: .55rem .45rem; border-bottom: 1px solid var(--line); color: inherit; transition: background-color .12s; }
.material-files > a:last-child { border-bottom: 0; }
.material-files > a:hover { background: var(--hover); }
.class-materials { margin-block: 1rem 1.5rem; }
.class-materials h2 { margin: 0; }
/* Files in the aside (docs/09 §distance: facts wanted on repeat sit beside
   the page, not above it). One rung down the ladder like everything in the
   aside, but the row keeps the 44px floor — it is a download. */
.aside-files { display: grid; margin-top: .35rem; }
.aside-files > a { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: .5rem; min-height: var(--tap); padding: .35rem 0; border-top: 1px solid var(--line); color: inherit; }
.aside-files > a:hover .task-action { background: var(--primary-tint); }
.aside-files strong { display: block; font-size: var(--t-small); font-weight: 500; color: var(--fg1); overflow-wrap: anywhere; }
.aside-files small { font-size: var(--t-micro); color: var(--muted); }
.aside-files .task-action { font-size: var(--t-meta); margin-inline-end: 0; }
.rich-content { color: var(--fg1); line-height: 1.95; overflow-wrap: anywhere; }
.rich-content > :first-child { margin-top: 0; }
.rich-content > :last-child { margin-bottom: 0; }
.rich-content h2, .rich-content h3, .rich-content h4 { line-height: 1.45; margin-block: 1.25em .5em; }
.rich-content ul, .rich-content ol { padding-inline-start: 1.5rem; }
.rich-content ul { list-style: disc; }
.rich-content ol { list-style: decimal; }
.rich-content blockquote { margin-inline: 0; padding: .7rem 1rem; border-inline-start: 3px solid var(--blue); border-start-end-radius: var(--r-sm); border-end-end-radius: var(--r-sm); background: var(--sunk); }
.rich-content table { display: block; max-width: 100%; overflow-x: auto; border-collapse: collapse; }
.rich-content td, .rich-content th { border: 1px solid var(--line-2); padding: .5rem .7rem; }
.rich-content a { color: var(--blue); }
.preview-description { margin-block: 1rem 1.5rem; }
@media(max-width:40rem){.attachment-upload{align-items:stretch;flex-direction:column}.attachment-list>div{grid-template-columns:auto minmax(0,1fr) auto}.attachment-list>div form{grid-column:2/4}.upload-field>span{align-items:flex-start;flex-direction:column;gap:.25rem}}

/* Scheduled class sessions — rows in a card. The state is a pill; the
   cancelled state is a red word on its pill, never a red field. */
.class-sessions { margin-block: 1rem 1.5rem; }
.class-sessions h2, .session-card h3 { margin: 0; }
.session-list { display: grid; }
.sect > .session-list { border-top: 0; }
.sect > .session-list .session-card:last-child { border-bottom: 0; }
.sect.class-sessions, .sect.class-polls { margin-block: 0 1.4rem; }
.sect > .sect-bd > .poll-list { border-top: 0; }
.sect > .sect-bd > .poll-list .poll-row:last-child { border-bottom: 0; }
.session-create { margin-bottom: 1rem; }
.session-create > summary, .session-edit > summary { width: max-content; cursor: pointer; list-style: none; }
.session-create > summary::-webkit-details-marker, .session-edit > summary::-webkit-details-marker { display: none; }
.session-form { margin-top: 1rem; max-width: 52rem; }
.session-card { padding: .9rem .75rem; border-bottom: 1px solid var(--line); }
.session-list > .session-card:last-child { border-bottom: 0; }
.session-card.is-cancelled h3 { color: var(--faint); text-decoration: line-through; }
.session-state { display: inline-flex; align-items: center; padding: .08rem .6rem .14rem; border-radius: var(--pill); background: var(--accent-tint); color: var(--accent-ink); font-size: var(--t-micro); font-weight: 600; }
.session-state-1 { background: var(--chip); color: var(--fg2); }
.session-state-2 { background: var(--red-tint); color: var(--red); }
/* ── Live classes (docs/18) ───────────────────────────────────────────────
   "Live" is carried by ink, weight and one slow pulse on its dot (cut to
   nothing under reduced motion). */
.session-state-live { background: var(--accent-tint); color: var(--accent-ink); }
.live-dot { display: inline-block; inline-size: .45rem; block-size: .45rem; border-radius: 50%;
            background: currentColor; margin-inline-end: .35rem; }
.session-note { margin-top: .5rem; font-size: var(--t-small); color: var(--fg4); }
.session-live-bar { display: flex; align-items: center; justify-content: space-between; gap: 1rem;
                    flex-wrap: wrap; margin-top: .75rem; padding: .55rem .75rem;
                    border-radius: var(--r-sm); background: var(--accent-tint); }
.session-live-bar span { font-size: var(--t-small); color: var(--fg1); }
.quiet-form { display: contents; }
.live-row { display: flex; align-items: center; justify-content: space-between; gap: 1rem;
            padding: .75rem .65rem; flex-wrap: wrap; }
.live-copy { display: flex; flex-direction: column; gap: .2rem; min-width: 0; }
.live-copy strong { font-size: var(--t-body); font-weight: 500; color: var(--fg1); }
.live-copy small { font-size: var(--t-meta); color: var(--faint); }
/* An endpoint is an identifier: Latin, isolated, never in Persian digits. */
.ident-line { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
              font-size: var(--t-meta); color: var(--fg3); unicode-bidi: isolate; overflow-wrap: anywhere; }
@media (max-width: 40rem) { .live-row { flex-direction: column; align-items: stretch; } }

.session-description { margin-top: .7rem; padding-top: .6rem; border-top: 1px solid var(--line); }
.session-edit { margin-top: .8rem; padding-top: .65rem; border-top: 1px solid var(--line); }

/* ── The date tile ────────────────────────────────────────────────────────
   The whole date used to be prose inside the card's muted .78rem line, which
   is where the eye goes last on a list of fourteen. Day and month move to a
   tile at the card's reading edge and the line keeps only the weekday and the
   time: a 44px tile on the shape scale's small rung. */
.session-card-main { flex: 1 1 auto; min-width: 0; }
.session-when { flex-shrink: 0; display: flex; flex-direction: column; align-items: center; justify-content: center;
                inline-size: 44px; block-size: 44px; border-radius: 8px;
                background: var(--chip); line-height: 1.15; }
.session-when-day { font-size: var(--t-section); font-weight: 600; color: var(--fg0); font-variant-numeric: tabular-nums; }
.session-when-month { font-size: var(--t-micro); color: var(--muted); }
/* What has not happened yet carries the accent; what has, stays neutral. */
.session-when--next { background: var(--accent-tint); }
.session-when--next .session-when-day { color: var(--accent-ink); }
.session-past-more { display: flex; align-items: center; justify-content: space-between; gap: 1rem;
                     padding: .6rem .65rem; font-size: var(--t-small); color: var(--fg4); }
.lesson-files { margin: .75rem 0; padding: .7rem; border-radius: var(--r-sm); background: var(--sunk); }
@media(max-width:40rem){.session-form .form-row{grid-template-columns:1fr}}
@media(max-width:38rem){.marking-row>span:nth-child(2){display:none}}

/* Configurable assignments, roster moderation, and class polls. */
.config-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:.8rem;margin:1rem 0;padding:1rem 1.1rem;border:1px solid var(--line);border-radius:var(--r);background:var(--surface)}.config-grid legend{padding:0 .4rem;font-weight:600}.config-grid>label:not(.check-label){display:flex;flex-direction:column;gap:.3rem;color:var(--fg2);font-size:var(--t-small);font-weight:500}.config-grid>.field{grid-column:1/-1}.assessment-resources{max-width:50rem;margin:1rem 0;padding-top:1rem;border-top:1px solid var(--line)}.submission-form>.upload-field{margin-block:1rem}.poll-list{display:grid}.poll-row{display:flex;align-items:center;justify-content:space-between;gap:1rem;min-height:3.8rem;padding:.6rem;border-bottom:1px solid var(--line);color:inherit}.poll-list>.poll-row:last-child{border-bottom:0}.poll-row>span:first-child{display:flex;min-width:0;flex-direction:column}.poll-row small{color:var(--muted);font-size:var(--t-meta)}.poll-page{max-width:46rem}.poll-page>header{margin-bottom:1.2rem}.poll-options{display:grid;gap:.6rem;margin:1.25rem 0;padding:1rem 1.1rem;border:1px solid var(--line);border-radius:var(--r);background:var(--surface)}.poll-options legend{padding:0 .4rem;font-weight:600}.poll-options label{display:flex;align-items:center;gap:.7rem;min-height:var(--tap);padding:.5rem .75rem;border:1px solid var(--line-2);border-radius:var(--r-sm);background:var(--surface);cursor:pointer;transition:border-color .12s,background-color .12s}.poll-options label:has(input:checked){border-color:var(--blue);background:var(--primary-tint)}.poll-options input{inline-size:1.15rem;block-size:1.15rem;accent-color:var(--blue)}
@media(hover:hover) and (pointer:fine){.poll-row:hover{background:var(--hover)}.poll-options label:hover{border-color:var(--primary-edge)}}
@media(max-width:46rem){.config-grid{grid-template-columns:minmax(0,1fr)}.config-grid>.field{grid-column:auto}}

/* ══════════════════════════════════════════════════════════════════════════
   SETTINGS AS AN ACCORDION — dv4's unified-edit idiom in the card language:
   the secondary settings of a page sit in one card of rows, each a real
   <details> (keyboard-operable, no JavaScript) whose summary names the group
   and previews its values as chips, closed by default.
   ══════════════════════════════════════════════════════════════════════════ */
.acc { margin: 1rem 0; border: 1px solid var(--line); border-radius: var(--r); background: var(--surface); }
/* In the card a row runs edge to edge — each is a full-column surface
   (e2e/src/surface-contracts.ts, `#class-files`) — and its contents keep the
   inset. A row on its own, in a form, keeps its own. */
.acc > .acc-row > summary, .acc > .acc-row > .acc-body { padding-inline: 1rem; }
.acc-row { border-bottom: 1px solid var(--line); }
.acc-row:last-child { border-bottom: 0; }
.acc-row > summary {
  display: flex;
  align-items: center;
  gap: .5rem;
  /* A rem height is a size, not a floor: under the 87.5% root 3.1rem is 43px. */
  min-height: max(var(--tap), 3.1rem);
  padding: .35rem .1rem;
  cursor: pointer;
  list-style: none;
  user-select: none;
}
.acc-row > summary::-webkit-details-marker { display: none; }
.acc-row > summary .chev {
  flex-shrink: 0;
  display: flex;
  color: var(--muted);
  transition: transform .15s var(--ease);
  transform: rotate(90deg);        /* closed points along the reading direction */
}
.acc-row[open] > summary .chev { transform: rotate(0); }
.acc-title { flex-shrink: 0; font-size: var(--t-body); font-weight: 600; color: var(--fg1); }
.acc-row > summary:hover .acc-title { color: var(--blue); }
.acc-row > summary .chips { flex: 1 1 auto; min-width: 0; overflow: hidden; }
.acc-body { padding: .2rem .1rem 1.1rem; }
.acc-body > .form { max-width: 34rem; }
.chip-none { font-size: var(--t-meta); color: var(--muted); font-style: italic; }


/* ══════════════════════════════════════════════════════════════════════════
   QUICK ACCESS — dv4's command bar (command_bar.scss), on a native <dialog>.
   An overlay, so it shares the bulk bar's licence for depth: this radius and
   shadow are the palette's, and stop at its edge.
   ══════════════════════════════════════════════════════════════════════════ */
.qa {
  width: min(34rem, calc(100vw - 2rem));
  margin: 12vh auto 0;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--raised);
  color: var(--ink);
  box-shadow: var(--shadow-pop);
  overflow: hidden;
}
.qa::backdrop { background: var(--scrim); }
.qa-input-wrap {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: 0 1rem;
  border-bottom: 1px solid var(--line);
  color: var(--muted);
}
.qa-input-wrap input {
  flex: 1 1 auto;
  min-width: 0;
  padding: .8rem 0;
  border: none;
  background: none;
  color: var(--fg0);
  font: inherit;
  font-size: var(--t-lead);
}
.qa-input-wrap input:focus { outline: none; }
.qa-input-wrap input::placeholder { color: var(--muted); }
.qa-results { max-height: 19rem; overflow-y: auto; }
.qa-results:empty { display: none; }
#qa-defaults[hidden] { display: none; }
.qa-group {
  padding: .6rem 1rem .2rem;
  font-size: var(--t-micro);
  font-weight: 600;
  color: var(--muted);
}
.qa-row {
  display: flex;
  align-items: baseline;
  gap: .5rem;
  min-height: var(--tap);
  margin: 0 .4rem;
  padding: .45rem .6rem;
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: background-color .1s;
}
.qa-row:hover, .qa-row.is-active { background: var(--hover); }
.qa-row-title {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--fg0);
  font-size: var(--t-body);
  font-weight: 500;
}
.qa-row.is-active .qa-row-title { color: var(--blue); }
.qa-row-sub {
  margin-inline-start: auto;
  flex-shrink: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--muted);
  font-size: var(--t-meta);
}
.qa-empty { padding: 1.2rem 1rem; text-align: center; color: var(--muted); font-size: var(--t-body); }
.qa-footer {
  display: flex;
  flex-wrap: wrap;
  gap: .3rem 1rem;
  margin-top: .4rem;
  padding: .55rem 1rem;
  border-top: 1px solid var(--line);
  background: var(--sunk);
  color: var(--muted);
  font-size: var(--t-micro);
}

/* ══════════════════════════════════════════════════════════════════════════
   MODALS — a short task that interrupts the page opens in a native <dialog>
   on the top layer (docs/08 §modals; app.js `enhanceModals`, `confirmFirst`):
   a title that says what is being done, the form or the question, and one
   clear way out — the close button, Esc, a click outside, or «انصراف». The
   dialog lives INSIDE the <details> it enhances, so the page's anchors (and
   the journeys' locators) still find its form. Without script there is no
   modal: the form unfolds in the page, as it always has.
   ══════════════════════════════════════════════════════════════════════════ */
.modal {
  width: min(36rem, calc(100vw - 2rem));
  max-height: calc(100dvh - 2rem);
  margin: auto;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--raised);
  color: var(--ink);
  box-shadow: var(--shadow-pop);
  overflow: auto;
  overscroll-behavior: contain;
}
.modal[open] { animation: modal-in .2s var(--ease); }
.modal::backdrop { background: var(--scrim); animation: fade .16s ease; }
@keyframes modal-in { from { opacity: 0; transform: translateY(8px) scale(.98); } }
.modal-hd { display: flex; align-items: center; gap: .75rem; padding: 1rem 1.25rem .35rem; }
.modal-hd h2 { flex: 1 1 auto; min-width: 0; margin: 0; font-size: var(--t-section); font-weight: 600; line-height: 1.5; }
.modal-hd .icon-btn { margin-inline-end: -.45rem; }
.modal-body { padding: .35rem 1.25rem 1.25rem; }
.modal-body > .form, .modal-body > form { margin-top: .35rem; max-width: none; }
.modal-body > p { color: var(--fg2); font-size: var(--t-body); line-height: 1.85; }
.modal-ft { display: flex; flex-wrap: wrap; gap: .5rem; padding: .85rem 1.25rem 1.1rem; border-top: 1px solid var(--line); background: var(--sunk); }
/* The form's own button and «انصراف» share one row at the foot. */
.modal-actions { margin-top: .4rem; }
.modal-actions > .btn-primary, .modal-actions > .go { align-self: auto; }
/* A popover's form, moved into a modal, drops its popover frame and stacks
   its fields, one to a row. */
.modal .message-actions form { position: static; width: auto; padding: 0; border: 0; border-radius: 0; background: none; box-shadow: none; }
/* The enhanced <details> keeps only its summary in the page. */
details[data-modal-ready] > :not(summary):not(dialog) { display: none; }

/* The confirm: what will happen in one sentence, then two buttons — the act
   named as a verb, filled red, and the way back, which has the focus. */
.modal--confirm { width: min(31rem, calc(100vw - 2rem)); }
/* A task with a list in it — the term planner's dates. */
.modal--wide { width: min(50rem, calc(100vw - 2rem)); }
.modal--confirm .modal-hd { padding-block-start: 1.2rem; }
.modal-mark { display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; inline-size: 2.5rem; block-size: 2.5rem; border-radius: 50%; background: var(--red-tint); color: var(--red); }
.btn-danger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .4rem;
  min-height: var(--h);
  padding: 0 1rem;
  border: 1px solid var(--red);
  border-radius: var(--r-sm);
  background: var(--red);
  color: var(--on-accent);
  font-size: var(--t-body);
  font-weight: 600;
  cursor: pointer;
  transition: background-color .12s, transform .12s var(--ease);
}
.btn-danger:hover { border-color: color-mix(in srgb, var(--red) 86%, var(--ink)); background: color-mix(in srgb, var(--red) 86%, var(--ink)); }
.btn-danger:active { transform: scale(.97); }

/* On a phone the modal rises from the bottom as a sheet, the thumb's side. */
@media (max-width: 40rem) {
  .modal { width: 100%; max-width: none; max-height: 92dvh; margin: auto 0 0; border-radius: 16px 16px 0 0; }
  .modal[open] { animation: sheet-in .24s var(--ease); }
  .modal-ft { padding-bottom: calc(1.1rem + env(safe-area-inset-bottom, 0px)); }
  .modal-ft > *, .modal-actions > * { flex: 1 1 0; }
}
@keyframes sheet-in { from { transform: translateY(100%); } }

/* ══════════════════════════════════════════════════════════════════════════
   THE PRINTED SHEET — ADR-0015. This page IS a credential in physical form.
   ══════════════════════════════════════════════════════════════════════════ */
.sheet-page { background: #fff; }
.sheet { max-width: 44rem; margin: 0 auto; padding: 1.5rem; }
.sheet-warn {
  display: flex;
  gap: .5rem;
  align-items: flex-start;
  border-inline-start: 3px solid var(--red);
  background: color-mix(in srgb, var(--red) 6%, transparent);
  padding: .6rem .8rem;
  margin-bottom: 1.2rem;
  font-size: var(--t-body);
  font-weight: 700;
}
.sheet-warn svg { color: var(--red); margin-top: .15rem; }
.sheet-title { font-size: var(--t-sub); font-weight: 700; }
.sheet-meta { font-size: var(--t-small); color: var(--fg3); margin-bottom: 1rem; }
.sheet-table { width: 100%; border-collapse: collapse; }
.sheet-table th {
  text-align: start;
  font-size: var(--t-micro);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--fg3);
  padding: .4rem .5rem;
  border-bottom: 1px solid var(--fg3);
}
.sheet-table td { padding: .5rem; border-bottom: 1px solid var(--bg2); }
.c-login { font-family: ui-monospace, monospace; font-size: var(--t-body); }
/* The password is the thing a person reads aloud and types. Give it room. */
.c-pass { font-size: var(--t-section); font-weight: 700; letter-spacing: .01em; }
.sheet-foot { margin-top: 1rem; font-size: var(--t-small); color: var(--fg3); }

@media print {
  html { font-size: 100%; }
  .sheet { padding: 0; }
  .sheet-warn { background: none; }
  a[href]::after { content: none; }
}

/* Motion is cut to nothing, not slowed, for a reader who asked for less —
   the e2e suites ask for it too, so no journey waits on a transition. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; scroll-behavior: auto !important; }
}

/* ══════════════════════════════════════════════════════════════════════════
   OPERATIONS — the moderator/admin workspaces, in the same card language.
   Nothing here invents a mode: chips are .chip, rows are hairlines in a card,
   and the one overlay (the workspace menu) takes the one shadow.
   ══════════════════════════════════════════════════════════════════════════ */

/* Context switcher: navigation only. Authority is always checked again on
   the destination route. */
.workspace-switcher { position: relative; margin: .2rem 0 .5rem; }
.workspace-switcher summary {
  list-style: none; cursor: pointer; display: flex; align-items: center;
  justify-content: space-between; gap: .5rem; min-height: var(--h); padding: .2rem .75rem;
  border: 1px solid var(--control-edge); border-radius: var(--r-sm); background: var(--control);
  box-shadow: var(--control-lift); color: var(--fg1); font-size: var(--t-small); font-weight: 600;
  transition: border-color .12s;
}
.workspace-switcher summary:hover { border-color: var(--control-edge-hover); }
.workspace-switcher summary::-webkit-details-marker { display: none; }
.workspace-switcher summary small { color: var(--muted); font-size: var(--t-micro); font-weight: 500; }
/* An overlay, like the palette — the shadow stops at its edge. */
.workspace-menu {
  position: absolute; z-index: 30; inset-inline: 0; top: calc(100% + .3rem);
  display: grid; padding: .35rem; border: 1px solid var(--line-2); border-radius: var(--r-pop);
  background: var(--raised); box-shadow: var(--shadow-pop);
}
.workspace-menu a { min-height: var(--h); display: flex; align-items: center; padding: 0 .65rem; border-radius: var(--r-sm); color: var(--fg1); font-size: var(--t-body); }
.workspace-menu a:hover { background: var(--hover); }
.workspace-menu a.is-current { background: var(--primary-tint); color: var(--blue); font-weight: 600; }

/* The administration top bar's one job (A1): finding a person. The palette
   trigger's box, holding a real GET search on the people page; on a phone
   only its glass shows, a link to that page, whose field is the search. */
.people-finder { inline-size: min(25rem, 100%); margin: 0; }
.people-finder-field {
  display: flex; align-items: center; gap: .55rem; min-height: var(--h); padding: 0 .85rem;
  border: 1px solid var(--control-edge); border-radius: var(--r-sm); background: var(--control); color: var(--muted);
  transition: border-color .12s, box-shadow .12s;
}
.people-finder-field:hover { border-color: var(--control-edge-hover); }
.people-finder-field:focus-within { border-color: var(--blue); box-shadow: var(--ring); color: var(--ink); }
.people-finder-field input {
  flex: 1 1 auto; min-inline-size: 0; min-height: calc(var(--h) - 2px); padding: 0; border: 0; background: none;
  color: var(--ink); font: inherit; font-size: var(--t-body); outline: none;
}
.people-finder-field input::placeholder { color: var(--muted); }
.top .people-finder-glass { display: none; }
@media (max-width: 62rem) {
  .people-finder { display: none; }
  .top .people-finder-glass { display: inline-flex; padding: 0; border: 1px solid var(--control-edge); background: var(--control); color: var(--muted); }
}

/* The read-only support view announces itself the way overdue does — amber,
   quiet, a band across the top, never a warning field. */
.support-banner {
  display: flex; align-items: center; gap: .8rem; padding: .35rem 1rem;
  background: var(--amber-tint); border-bottom: 1px solid color-mix(in srgb, var(--amber) 25%, var(--content));
  color: var(--fg1); font-size: var(--t-small);
}
.support-banner strong { color: var(--amber); font-weight: 600; }
.support-banner > .support-who { flex: 1; }
.support-banner form { margin: 0; }
.support-banner button {
  min-height: var(--h); padding: 0 .9rem; border: 1px solid var(--control-edge); border-radius: var(--r-sm);
  background: var(--control); box-shadow: var(--control-lift); color: var(--ink); font-size: var(--t-small); font-weight: 500; cursor: pointer;
  transition: background-color .1s, border-color .1s;
}
.support-banner button:hover { background: var(--sunk); border-color: var(--control-edge-hover); }
/* The phone bar holds the strip's places (A1): administration's five,
   moderation's two. */
.ops-mobile { grid-template-columns: repeat(5,1fr); }
.ops-mobile--moderator { grid-template-columns: repeat(2,1fr); }

/* «نمای کلی» of administration (A1 §3.2): the class home's column of cards —
   what waits, what changed, the glance — none inside another. The glance's
   term strip spans the band above the cards it shares it with. */
.ops-home { display: grid; gap: .8rem; }
.ops-home > .sect, .ops-home > .glance-band { margin: 0; }
.glance-band > .term-strip { margin: 0 0 .8rem; }
.sect-bd--flush > .chart-empty { margin: 0; padding: .55rem .9rem .75rem; }
/* The accounts in parts, a share per line over its own meter; the services
   one line each, under their glyph. */
.share-rows { display: grid; gap: .7rem; margin-top: .9rem; }
.share-rows .meter-line { margin: 0 0 .3rem; font-size: var(--t-small); }
.svc-line + .svc-line { margin-top: .9rem; padding-top: .8rem; border-top: 1px solid var(--line); }
.svc-line h4 { display: flex; align-items: center; gap: .4rem; margin: 0 0 .35rem; color: var(--ink); font-size: var(--t-body); font-weight: 600; }
.svc-line h4 svg { inline-size: 16px; block-size: 16px; color: var(--accent); }

/* «تغییرات» (A1 §3.3): sentence rows under their days. A row whose subject
   the reader may not open is a fact — the home row's grid with no verb and
   nothing to press. The reason is the person's own words, in quotes. */
.task-row.is-fact:hover { background: none; }
.task-row.is-fact:active { transform: none; }
.audit-reason { display: block; margin-top: .1rem; color: var(--fg2); font-size: var(--t-small); line-height: 1.6; overflow-wrap: anywhere; }
.audit-reason::before { content: "«"; }
.audit-reason::after { content: "»"; }
.audit-code { font-family: ui-monospace, "SF Mono", Menlo, monospace; font-size: .92em; }
.sect-bd--flush > .list-label { margin: .85rem .9rem .15rem; }
.sect-bd--flush > .list-label:first-child { margin-top: .55rem; }
.audit-log { margin: 0; }
.audit-log + .queue-next { margin-top: .8rem; }

/* ══════════════════════════════════════════════════════════════════════════
   FORMAL EXAMS — the same paper-and-hairline language; only the clock is
   allowed to stay put. During an attempt the page is the exam: no search in
   the bar, no bottom tabs, and the aside (clock + flagged questions) is
   sticky beside the paper on a desktop and rides the top on a phone.
   ══════════════════════════════════════════════════════════════════════════ */
.visually-hidden { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.mobile-nav--off { display: none !important; }
.exam-description { max-width: 52rem; margin-bottom: 1rem; }

/* Pre-flight: the exam's «before» phase card (proposal S3 §3.3) — the
   numbers first, what they count beneath, unframed inside the card (a card
   never nests a card); the warning as a sentence with its clock; the code
   and the one green «آغاز امتحان», or the sentence that says why not. */
.exam-preflight { max-width: 52rem; }
.exam-facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr)); margin: 0 0 .75rem; border-bottom: 1px solid var(--line); }
.exam-facts > div { padding: .35rem 0 .7rem; }
.exam-facts dd { margin: 0; color: var(--fg1); font-size: var(--t-lead); }
.exam-facts dd .stat-num { font-size: var(--t-sub); }
.exam-facts dt { margin-top: .1rem; color: var(--fg4); font-size: var(--t-meta); }
.exam-warning { display: flex; align-items: flex-start; gap: .5rem; margin: 0 0 .75rem; color: var(--fg2); font-size: var(--t-small); line-height: 1.8; }
.exam-warning > svg { flex: none; inline-size: 15px; block-size: 15px; margin-top: .3rem; color: var(--muted); }
.exam-warning.exam-shut { margin: 0; color: var(--fg1); font-size: var(--t-body); }
.exam-start.form { flex-direction: row; flex-wrap: wrap; align-items: flex-end; gap: .6rem .75rem; margin: 0; }
.exam-start .field { flex: 1 1 14rem; margin: 0; }
.exam-start > .btn-primary { align-self: flex-end; margin-top: 0; }

.exam-cols { align-items: start; }
.exam-timer { padding: .6rem .85rem; border: 1px solid var(--accent-edge-hover); border-radius: var(--r); background: var(--surface); transition: background-color .2s, border-color .2s; }
.exam-timer small { display: block; color: var(--muted); font-size: var(--t-meta); }
.exam-timer strong { display: block; margin-top: .12rem; font-size: var(--t-title); line-height: 1.2; font-variant-numeric: tabular-nums; color: var(--fg0); }
.exam-timer.is-urgent { border-color: var(--amber); background: var(--amber-tint); }
.exam-timer.is-urgent strong { color: var(--amber); }
.exam-flags { display: flex; flex-wrap: wrap; gap: .3rem; }
.exam-flags .chip { display: inline-flex; align-items: center; justify-content: center; min-inline-size: var(--tap); min-block-size: var(--tap); font-size: var(--t-body); font-variant-numeric: tabular-nums; background: var(--amber-tint); color: var(--amber); }
.exam-form { max-width: 52rem; }
.exam-form .quiz-sheet { display: grid; gap: 1rem; }
.exam-form .quiz-question { scroll-margin-top: 4.5rem; }
.exam-form .quiz-question[hidden] { display: none; }
.save-state { min-height: 1.4rem; color: var(--muted); font-size: var(--t-meta); }
/* In-place forms (app.js `data-swap`/`data-quiet`): the state line turns red
   when the write did not land; a field the browser refused is edged red. */
.is-failed .save-state { color: var(--red); }
form[aria-busy="true"] { cursor: progress; }
.upload-field.is-invalid { border-color: var(--red); }
.upload-field.is-invalid .upload-names { color: var(--red); }
.question-flag { color: var(--muted); font-size: var(--t-meta); }
/* A flagged question waits on the candidate: it and its chip turn amber, the
   flag a ruled foot row at the tap floor. CSS only — exam.js keeps its hooks. */
.exam-form .question-flag { display: flex; align-items: center; gap: .55rem; min-height: var(--tap); margin-top: .3rem; padding: .3rem .45rem 0; border-top: 1px solid var(--line); }
.exam-form .quiz-question:has([data-exam-flag]:checked) { border-color: color-mix(in srgb, var(--amber) 45%, var(--content)); }
.exam-form .quiz-question:has([data-exam-flag]:checked) .question-flag { color: var(--amber); font-weight: 600; }
/* The bar is sticky at the foot of the viewport; the sheet leaves room under
   its last question so nothing is ever hidden behind it. */
/* It floats at the foot of the viewport over the paper, so it takes the one
   shadow (docs/08 §shape: what floats). */
.exam-actions, .exam-page-nav { position: sticky; bottom: .75rem; z-index: 5; display: flex; align-items: center; justify-content: space-between; gap: .7rem; margin-top: .75rem; padding: .6rem .8rem; border: 1px solid var(--line-2); border-radius: var(--r); background: var(--raised); box-shadow: var(--shadow-pop); }
.exam-form .quiz-sheet { padding-bottom: .5rem; }
.exam-page-nav[hidden] { display: none; }
.exam-files { display: grid; gap: .35rem; margin-bottom: .5rem; }
.exam-files .file-row { display: flex; align-items: center; gap: .55rem; padding: .4rem 0; border-bottom: 1px solid var(--line); }

/* The receipt is the exam's «after» phase card: handed in and when, then
   the score as the grades page's chip. The review is one card of rows: each
   verdict in the one mark language (✓ aqua, ✕ in red ink, the word beside
   it — never a coloured edge), the two answers as a pair, the feedback on
   the sunk tint. */
.exam-receipt { max-width: 52rem; }
.exam-handed { display: flex; align-items: flex-start; gap: .4rem; margin: 0; color: var(--fg1); }
.exam-handed > svg { flex: none; inline-size: 16px; block-size: 16px; margin-top: .3rem; color: var(--aqua); }
.exam-receipt-score { margin: .6rem 0 0; }
.exam-receipt-score .grade-score { font-size: var(--t-sub); }
.exam-receipt-wait { margin: .45rem 0 0; color: var(--muted); font-size: var(--t-small); line-height: 1.8; }
.exam-review { max-width: 52rem; }
.review-item { padding: .8rem 0 .85rem; border-bottom: 1px solid var(--line); }
.review-item:last-child { border-bottom: 0; padding-bottom: .2rem; }
.review-item h3 { display: flex; align-items: flex-start; gap: .45rem; margin: 0; font-size: var(--t-body); font-weight: 600; line-height: 1.7; color: var(--ink); }
.review-item h3 .rich-inline { flex: 1 1 auto; min-width: 0; }
.review-item h3 .mark-chip { flex-shrink: 0; margin-inline-start: auto; }
.review-answers { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: .2rem .8rem; margin: .45rem 0 0; font-size: var(--t-body); }
.review-answers dt { color: var(--muted); }
.review-answers dd { margin: 0; color: var(--fg1); }
.review-item > .rich-content { margin-top: .5rem; padding: .5rem .75rem; border-radius: var(--r-sm); background: var(--sunk); font-size: var(--t-small); }

/* The teacher's page. Equal columns for rows whose fields are peers; the
   default .form-row (one wide, two narrow) is for a name beside two dates. */
.form-row--two { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.form-row--three { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.check-list--plain { margin: .4rem 0 0; border: 0; background: none; padding: 0; }
.check-list--plain label { border-bottom: none; padding-inline: 0; min-height: var(--tap); font-size: var(--t-body); }
.readonly-facts--wide { max-width: 48rem; grid-template-columns: repeat(3, minmax(0, 1fr)); }
.readonly-facts--wide > div:nth-child(n+7) { grid-column: 1 / -1; }
.readonly-facts dd .chips { margin-top: .2rem; }
.exam-question-row > summary { grid-template-columns: 1.5rem minmax(0, 1fr); }
.exam-question-name { display: flex; flex-direction: column; min-width: 0; }
.exam-question-name strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500; font-size: var(--t-body); }
.exam-question-name small { color: var(--fg4); font-size: var(--t-micro); }
.exam-question-body { padding: .5rem .7rem .8rem; }
/* The monitor: a candidate on the start side, the proctor's three moves as
   three one-line forms on the end side — minutes, reason, verb. */
.exam-monitor-row { display: grid; grid-template-columns: minmax(11rem, 1fr) minmax(0, 30rem); gap: .8rem; align-items: start; padding: .75rem .3rem; border-bottom: 1px solid var(--line); }
.exam-monitor-row small { display: block; color: var(--muted); }
/* The monitor's rows live in a .teacher-list, whose `> div` is a flex row;
   the monitor needs its grid, so it names itself one step more exactly. */
.teacher-list > .exam-monitor-row { display: grid; }
.exam-proctor { display: grid; gap: .35rem; }
.exam-proctor form, .exam-proctor-line { display: grid; grid-template-columns: 7rem minmax(0, 1fr) auto; align-items: center; gap: .35rem; }
.exam-proctor form:not(:has(.input--short)), .exam-proctor-line:not(:has(.input--short)) { grid-template-columns: minmax(0, 1fr) auto; }
.exam-proctor .input--short, .exam-proctor-line .input--short { max-width: none; }
.exam-proctor .quiet-button, .exam-proctor .danger-button, .exam-proctor-line .quiet-button { white-space: nowrap; }

/* Scoped workspaces: navigation changes the job while the object header stays
   put. The cards are summaries and links, never miniature management forms. */
.workspace-cards { display: grid; grid-template-columns: repeat(auto-fit,minmax(10rem,1fr)); gap: .65rem; margin-top: 1rem; }
.workspace-cards > a { display: flex; flex-direction: column; gap: .2rem; min-height: 4.5rem; padding: .85rem 1rem; border: 1px solid var(--line); border-radius: var(--r); background: var(--surface); transition: border-color .12s, transform .12s var(--ease); }
.workspace-cards > a:hover { border-color: var(--primary-edge); }
.workspace-cards > a:active { transform: scale(.99); }
.workspace-cards > a strong { color: var(--fg1); font-size: var(--t-body); }
.workspace-cards > a span { color: var(--faint); font-size: var(--t-meta); }
.exam-overview,.settings-panel { max-width: 54rem; }

/* A class's content has one navigable structure and one editor. Selecting an item is
   URL-backed, so Back and refresh restore the exact editing context. */
.builder-workspace { display: grid; grid-template-columns: minmax(16rem,21rem) minmax(0,1fr); gap: 1.25rem; align-items: start; }
/* The outline stays in view while a long lesson is edited beside it. */
.builder-tree { position: sticky; top: 1rem; max-height: calc(100vh - 2rem); overflow-y: auto; padding-bottom: .35rem; border: 1px solid var(--line); border-radius: var(--r); background: var(--surface); }
.builder-tree-head { display: flex; justify-content: space-between; align-items: center; min-height: var(--tap); padding: .5rem .75rem; border-bottom: 1px solid var(--line); }
.builder-tree-head h2 { margin: 0; font-size: var(--t-body); font-weight: 600; color: var(--ink); }
/* The content's two places that are not a section: its introduction first,
   its files last, each a row of the outline with a mark where a section has
   its number. */
.builder-tree-place svg { justify-self: center; inline-size: 16px; block-size: 16px; color: var(--muted); }
.builder-tree-place.is-selected svg { color: var(--blue); }
.builder-tree-place strong { font-weight: inherit; }
.builder-tree-place + .builder-tree-section { border-top: 1px solid var(--line); }
.builder-tree-section { border-bottom: 1px solid var(--line); }
.builder-tree-section:last-of-type { border-bottom: 0; }
.builder-tree-row { display: grid; grid-template-columns: 1.7rem minmax(0,1fr) auto; gap: .45rem; align-items: center; min-height: var(--tap); margin: .15rem .35rem; padding: .35rem .5rem; border-radius: var(--r-sm); color: var(--fg2); }
.builder-tree-row:hover { background: var(--hover); }
.builder-tree-row.is-selected { background: var(--primary-tint); color: var(--blue); font-weight: 600; }
.builder-tree-row small { color: var(--faint); font-size: var(--t-micro); }
.builder-tree-lessons { padding-inline-start: .8rem; }
.builder-tree-lesson { grid-template-columns: 1.4rem minmax(0,1fr) auto; font-size: var(--t-small); }
.builder-tree .add-section { display: grid; grid-template-columns: minmax(0,1fr); max-width: none; padding: .65rem; margin: 0; border-bottom: 1px solid var(--line); }
.builder-editor { min-width: 0; padding: 1rem 1.2rem; border: 1px solid var(--line); border-radius: var(--r); background: var(--surface); }
.builder-editor-head { display: flex; justify-content: space-between; align-items: center; gap: 1rem; margin-bottom: 1rem; padding-bottom: .7rem; border-bottom: 1px solid var(--line); }
.builder-editor-head h2 { margin: .1rem 0 0; font-size: var(--t-section); }
/* A section's content is added where it is listed: under its items in the
   outline, as a section is added under the sections. */
.builder-tree .add-lesson { display: grid; grid-template-columns: minmax(0,1fr); gap: .35rem; max-width: none; margin: .2rem .35rem .45rem; padding: 0; }

/* Messages are a workspace, not two unrelated feeds. The list is the stable
   place map; the selected thread changes without making the reader rebuild
   that map. Operational state is carried by words first and tint second. */
.unread-count { display: inline-flex; align-items: center; justify-content: center; min-width: 1.25rem; height: 1.25rem; padding: 0 .3rem; border-radius: 999px; background: var(--blue); color: white; font-size: var(--t-micro); font-weight: 600; font-variant-numeric: tabular-nums; }
.message-workspace { display: grid; grid-template-columns: minmax(17rem, 21rem) minmax(0, 1fr); height: min(70vh, 44rem); min-height: 34rem; border: 1px solid var(--line); border-radius: var(--r); background: var(--surface); overflow: hidden; }
.message-rail { min-width: 0; overflow-y: auto; border-inline-end: 1px solid var(--line); background: var(--sunk); }
.conversation-list { border-top: 0; }
.conversation-row, .teacher-list > a.conversation-row { display: grid; grid-template-columns: 2rem minmax(0, 1fr) auto; align-items: center; gap: .6rem; min-height: 5rem; padding: .55rem .7rem; border: 0; border-bottom: 1px solid var(--line); border-inline-start: 3px solid transparent; color: inherit; transition: none; }
.conversation-row:hover, .teacher-list > a.conversation-row:hover { background: var(--hover); }
.conversation-row.is-active, .teacher-list > a.conversation-row.is-active { border-inline-start-color: var(--blue); background: var(--primary-tint); }
.conversation-avatar { display: flex; align-items: center; justify-content: center; width: 2.1rem; height: 2.1rem; border-radius: 50%; background: var(--accent-tint); color: var(--accent-ink); }
.conversation-main, .teacher-list > a.conversation-row > .conversation-main { display: flex; flex-direction: column; min-width: 0; }
.conversation-title { display: flex; align-items: baseline; justify-content: space-between; gap: .45rem; min-width: 0; }
.conversation-title strong { overflow: hidden; color: var(--fg1); font-size: var(--t-small); text-overflow: ellipsis; white-space: nowrap; }
.conversation-main small { overflow: hidden; margin-top: .05rem; color: var(--faint); font-size: var(--t-micro); text-overflow: ellipsis; white-space: nowrap; }
.conversation-preview { overflow: hidden; margin-top: .2rem; color: var(--muted); font-size: var(--t-meta); text-overflow: ellipsis; white-space: nowrap; }
.conversation-preview em { color: var(--fg2); font-style: normal; }
.conversation-meta { align-self: stretch; display: flex; flex-direction: column; align-items: end; justify-content: space-between; padding-block: .1rem; }
.conversation-meta time { color: var(--faint); font-size: var(--t-micro); white-space: nowrap; }
.message-detail { min-width: 0; min-height: 0; display: flex; flex-direction: column; background: var(--content); }
.message-detail.is-empty { align-items: center; justify-content: center; padding: 2rem; }
.message-empty { max-width: 25rem; margin: auto; padding: 2rem 1rem; text-align: center; color: var(--muted); }
.message-empty h2, .message-empty h3 { margin-top: .5rem; color: var(--fg2); font-size: var(--t-lead); }
.message-empty p { margin-top: .3rem; font-size: var(--t-meta); }
.message-empty-icon { display: inline-flex; align-items: center; justify-content: center; width: 3rem; height: 3rem; border-radius: 50%; background: var(--accent-tint); color: var(--accent-ink); }
.message-detail .conversation-head { flex: 0 0 auto; min-height: 4rem; padding: .55rem .85rem; }
.message-detail .conversation-head h1, .message-detail .conversation-head h2 { font-size: var(--t-lead); }
.message-back { display: none; align-items: center; justify-content: center; min-inline-size: var(--tap); min-block-size: var(--tap); padding-inline: .35rem; color: var(--blue); font-size: var(--t-meta); }
.message-detail .thread { flex: 1 1 auto; max-width: none; min-height: 0; overflow-y: auto; padding: .8rem clamp(.75rem, 3vw, 2.25rem) 1rem; }
.message-detail .thread > * { flex-shrink: 0; }
.thread-pagination { display: flex; justify-content: center; gap: .5rem; min-height: .25rem; padding-bottom: .5rem; }
.day-separator, .unread-separator { align-self: stretch; display: flex; align-items: center; gap: .6rem; color: var(--faint); font-size: var(--t-micro); text-align: center; }
.day-separator::before, .day-separator::after, .unread-separator::before, .unread-separator::after { content: ""; flex: 1; height: 1px; background: var(--line-2); }
.unread-separator { color: var(--blue); }
.unread-separator::before, .unread-separator::after { background: var(--accent-edge); }
.bubble.is-joined { margin-top: -.35rem; }
.bubble footer { display: flex; align-items: center; justify-content: flex-end; gap: .45rem; min-height: 1rem; }
.bubble time { margin: 0; }
.message-actions { position: relative; margin: 0; }
.message-actions > summary { display: inline-flex; align-items: center; justify-content: center; min-inline-size: var(--tap); min-block-size: var(--tap); padding: 0; }
.message-actions form { position: absolute; inset-inline-start: 0; z-index: 4; width: min(18rem, 70vw); padding: .75rem; border: 1px solid var(--line-2); border-radius: var(--r-pop); background: var(--raised); box-shadow: var(--shadow-pop); }
.message-detail .composer { position: sticky; inset-block-end: 0; flex: 0 0 auto; max-width: none; padding: .7rem .9rem; border-top: 1px solid var(--line); background: var(--surface); }
.message-detail .composer textarea { min-height: var(--tap); max-height: 9rem; }
.announcement-list { padding-inline: .9rem; }
.announcement-content { min-width: 0; }

@media (max-width: 62rem) {
  .message-workspace { display: block; height: auto; min-height: 30rem; }
  .message-rail { max-height: none; border-inline-end: 0; }
  .message-workspace:not(.has-selection) .message-detail { display: none; }
  .message-workspace.has-selection .message-rail { display: none; }
  .message-workspace.has-selection .message-detail { display: flex; min-height: min(70vh, 40rem); }
  .message-back { display: inline-flex; flex: 0 0 100%; }
  .message-detail .conversation-head { flex-wrap: wrap; }
}

@media (max-width: 40rem) { .form-row--two, .form-row--three, .readonly-facts--wide { grid-template-columns: minmax(0, 1fr); } .exam-monitor-row, .teacher-list > .exam-monitor-row { grid-template-columns: minmax(0, 1fr); } .exam-proctor form, .exam-proctor-line { grid-template-columns: minmax(0, 1fr); } }
@media (max-width: 62rem) {
  /* The aside comes first and stays at the top: the clock is never off
     screen on a phone. */
  .exam-cols .exam-aside { order: -1; position: sticky; top: 0; z-index: 6; margin: 0 -.75rem .75rem; padding: 0 .75rem; border-top: none; border-bottom: 1px solid var(--bg2); background: var(--content); }
  .exam-aside .aside-inner { display: flex; align-items: center; gap: .5rem; }
  .exam-aside .side-sec { border-bottom: none; padding: .35rem 0; }
  .exam-aside .side-sec:first-child { flex: 0 0 auto; }
  .exam-aside .side-sec:last-child { flex: 1 1 auto; min-width: 0; }
  .exam-aside .side-sec-label { margin-bottom: .15rem; }
  .exam-timer { display: flex; align-items: baseline; gap: .5rem; padding: .3rem .6rem; }
  .exam-timer strong { margin-top: 0; font-size: var(--t-sub); }
  .exam-form .quiz-question { scroll-margin-top: 5rem; }
  .builder-workspace { grid-template-columns: minmax(0,1fr); }
  .builder-tree { position: static; max-height: 22rem; overflow-y: auto; }
}

/* Workspace tabs keep their height when the current tab gains a count. */
.tab .badge-total, .tab .badge-warn { line-height: 1; }
/* Section descriptions and action rows must fit the shared frame on phones. */
.panel-head > div { min-inline-size: 0; }
.panel-head .byline-item { white-space: normal; }
.panel-head .page-hd-actions { flex-wrap: wrap; }

/* Section links remain fully available without script. The disclosure sits
   at the logical tail of the strip, outside its scrolling viewport. */
nav.tabs { flex-wrap: wrap; }
.section-navigation { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: start; }
nav.sections-enhanced { min-inline-size: 0; flex-wrap: nowrap; overflow-x: auto; }
nav.sections-expanded { flex-wrap: wrap; overflow-x: visible; }
nav.sections-expanded a { white-space: normal; overflow-wrap: anywhere; max-inline-size: 100%; }
.section-reveal {
  justify-content: center;
  color: var(--blue);
  border-bottom-color: var(--bg2);
  border-inline-start: 1px solid var(--bg2);
  margin: 0;
}
.section-reveal::after { content: '⌄'; }
.section-reveal[aria-expanded="true"]::after { content: '⌃'; }

/* Management lists use the assigned column; individual fields retain their scale. */
#sessions.manage-section { max-width: none; }
#sessions .session-form { max-width: none; }
.session-result, .session-list [id] { scroll-margin-block-start: 1rem; }
.session-result p { margin-block: 0 .5rem; }

/* Lists use their assigned content column, retaining the workspace gutters. */
#roster, #polls, #staff, .report-list,
#servers, #flag-queue { max-width: none; }
.notice.action-result { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .5rem 1rem; max-width: none; border-color: color-mix(in srgb, var(--aqua) 25%, var(--content)); background: var(--aqua-tint); }
.action-result p { margin: 0; font-weight: 500; }
[id^="created-"], .action-result { scroll-margin-block-start: 1rem; }
@media (max-width: 62rem) {
  html { scroll-padding-block-end: calc(5rem + env(safe-area-inset-bottom, 0px)); }
  main button, main input, main select, main textarea { scroll-margin-block-end: calc(5rem + env(safe-area-inset-bottom, 0px)); }
}

/* --- Teacher class pages: revamp prototype (tabs, overview, roster) ------ */

/* The class strip (ADR-0029): five places, each with its icon, in one row on
   every screen and the same on every sibling. On a desktop, icon and name on
   one line at the body size: about 435px, which a column holds from the
   width where the sidebar and the aside come in (446px at 62rem) — so the
   first 2rem above that take the phone's form too, for the margin. On a
   phone, five equal cells, the icon over its name: nothing scrolls, folds or
   wraps, and a 360px phone holds all five (67px a cell; «دانشجویان» is 52). */
.tab-strip { display: flex; align-items: stretch; border-bottom: 1px solid var(--line-2); margin-bottom: 1.25rem; }
.tab-strip .tabs { flex: 1 1 auto; min-width: 0; gap: .15rem; margin-bottom: 0; padding-bottom: 0; box-shadow: none; flex-wrap: wrap; overflow-x: visible; }
.tab-strip .tab { gap: .4rem; padding: .4rem .7rem; font-size: var(--t-body); }
.tab-strip .tab > svg { inline-size: 16px; block-size: 16px; margin: 0; }
@media (max-width: 40rem), (min-width: 62rem) and (max-width: 64rem) {
  .tab-strip .tabs { flex-wrap: nowrap; gap: 0; }
  .tab-strip .tab { flex: 1 1 0; min-inline-size: 0; flex-direction: column; justify-content: center; gap: .25rem; min-height: 52px; padding: .45rem .1rem .4rem; font-size: var(--t-micro); line-height: 1.3; }
  .tab-strip .tab > svg { inline-size: 18px; block-size: 18px; }
}

/* Strip tabs elsewhere get the same optical centering for their glyphs
   beside Persian labels. */
.tab { gap: .45rem; }
.tab > svg { flex-shrink: 0; margin-block-start: 1px; }

/* Overview cards (the exam overview's facts): icon, the number, the name. */
.workspace-cards > a { gap: .25rem; min-height: 6.6rem; padding: .85rem; }

/* ── The class home (proposal 01) ─────────────────────────────────────────
   One column of cards, most volatile first and none inside another: the
   session in hand — the schedule's own card, «امروز» on the primary's
   hairline (`.today-card`) when it is today's — what waits on the teacher, a
   new class's first steps, and the class at a glance. */
.class-today { display: grid; gap: .8rem; }
.class-today > .sect { margin: 0; }
.now-none { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem; padding-top: .45rem; }
.now-none > .calm-state { flex: 1 1 16rem; }
.now-none > .go { margin-top: 0; }

/* A row of «در انتظار شما» or «برای شروع» (`ui::home_row`): the teacher
   home's row, an icon before its sentence and the verb at its end. What
   waits on the teacher is amber with a dot — the colour is never the only
   sign — so the eye finds it first; a first step is neutral ink with its
   one line of help under it. The whole row is the door. */
.task-row.home-row { grid-template-columns: auto minmax(0, 1fr) auto; }
.home-row-ico { display: inline-flex; color: var(--class-accent, var(--accent)); }
.home-row-ico svg { inline-size: 16px; block-size: 16px; }
.home-row .task-copy strong { white-space: normal; }
/* «دستیار» on a class row, on a home that holds both kinds (T1 §3.3). */
.home-row .task-copy strong .chip { margin-inline-start: .45rem; font-size: var(--t-micro); font-weight: 500; }
.glance-fact { font-variant-numeric: tabular-nums; }
.glance-fact.is-waiting { display: inline-flex; align-items: center; gap: .4rem; color: var(--amber); font-weight: 600; }
.glance-fact.is-waiting::before { content: ""; flex: none; inline-size: .45rem; block-size: .45rem; border-radius: 50%; background: currentColor; }
@media (max-width: 38rem) {
  .home-row .task-action { grid-column: 3; grid-row: 1; }
  /* A step is a sentence to read: its verb goes under it. */
  .class-start .task-row.home-row { grid-template-columns: auto minmax(0, 1fr); }
  .class-start .home-row .task-action { grid-column: 2; grid-row: 2; justify-self: start; margin-inline: -.6rem 0; }
}

/* ── The student's «امروز» (proposal S1) ──────────────────────────────────
   The teacher's pieces, read by a student: today's sessions in the
   schedule's own card, each naming its class first and holding the one thing
   due now; «در انتظار شما» in `home_row`s; each class as one row with the
   shared meter, gold — a quantity — its figure in words beside it, and the
   way on. */
.session-card-class { color: var(--fg2); font-weight: 500; }
.session-card-link .session-note { margin: .1rem 0 0; color: var(--muted); }
.session-card-state { display: inline-flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: .3rem; }
.now-bar .checkin-form { flex: 1 1 auto; }
.now-bar .checkin-form .field { color: var(--fg2); font-size: var(--t-small); }
.now-bar .checkin-form .btn-primary, .now-bar .checkin-form .go { margin: 0; }
.class-progress { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; grid-template-areas: "ico hd hd" ". fig next"; align-items: center; column-gap: .75rem; padding: .45rem .65rem .55rem; border-bottom: 1px solid var(--line); }
.class-progress:last-child { border-bottom: 0; }
.class-progress > .home-row-ico { grid-area: ico; }
.class-progress-hd { grid-area: hd; display: flex; flex-wrap: wrap; align-items: center; gap: 0 .6rem; min-width: 0; }
.class-progress-name { display: inline-flex; align-items: center; min-block-size: var(--tap); min-width: 0; max-width: 100%; color: var(--ink); font-size: var(--t-body); font-weight: 600; }
.class-progress-name bdi { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.class-progress-name:hover { color: var(--blue); }
.class-progress-talk { display: inline-flex; align-items: center; gap: .35rem; min-block-size: var(--tap); color: var(--blue); font-size: var(--t-small); font-weight: 500; }
.class-progress-talk > svg { inline-size: 15px; block-size: 15px; }
.class-progress-fig { grid-area: fig; display: flex; align-items: center; gap: .7rem; min-width: 0; }
.class-progress-fig .meter { flex: 1 1 auto; max-inline-size: 18rem; }
.meter-figure { flex-shrink: 0; color: var(--muted); font-size: var(--t-small); white-space: nowrap; }
.meter-figure .stat-num { color: var(--ink); font-weight: 600; }
.class-progress-note { grid-area: fig; margin: 0; color: var(--muted); font-size: var(--t-small); }
.class-progress-next { grid-area: next; display: inline-flex; align-items: center; gap: .3rem; min-block-size: var(--tap); min-width: 0; max-inline-size: 21rem; padding-inline: .6rem; margin-inline-end: -.4rem; border-radius: var(--r-sm); color: var(--blue); font-size: var(--t-small); font-weight: 600; }
.class-progress-next:hover { background: var(--primary-tint); }
.class-progress-next bdi { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.next-verb { color: var(--muted); font-weight: 500; }
@media (max-width: 38rem) {
  .class-progress { grid-template-columns: auto minmax(0, 1fr); grid-template-areas: "ico hd" ". fig" ". next"; }
  .class-progress-fig .meter { max-inline-size: none; }
  .class-progress-next { justify-self: start; max-inline-size: 100%; margin-inline: -.6rem 0; }
}

/* «کلاس‌ها»: the directory. Its icon wears the class's hue; a paused class
   says so beside its name. */
.class-hub-row[class*='ca-'] .class-hub-icon { color: var(--class-accent); }
.class-hub-title { display: flex; align-items: center; gap: .5rem; min-width: 0; }
.class-hub-title strong { min-width: 0; }

/* The class at a glance: small charts under a micro-label, one series each,
   drawn by the shared figures (`ui::hist`, `ui::meter`). The term's
   absences take the column; grading and progress share the row under it
   while the column holds two cards with their doors (38rem) — on a phone,
   and in the narrow column beside both rails, they stack. Each card's head
   ends in the place its numbers come from. */
.glance-band { container-type: inline-size; }
.glance-band > .list-label { margin: .35rem 0 .5rem; }
.glance-charts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: .8rem; }
.glance-charts > .sect { margin: 0; }
.glance-charts > .chart--wide { grid-column: 1 / -1; }
@container (max-width: 38rem) { .glance-charts { grid-template-columns: minmax(0, 1fr); } }
.chart-card .sect-bd { padding: .15rem 1rem .85rem; }
.chart-help { margin: 0 0 .55rem; color: var(--muted); font-size: var(--t-small); line-height: 1.7; }
.chart-foot { margin: .6rem 0 0; color: var(--muted); font-size: var(--t-meta); line-height: 1.7; }
.chart-foot + .chart-foot { margin-top: .05rem; }
.chart-empty { margin: .15rem 0 0; color: var(--muted); font-size: var(--t-small); line-height: 1.7; }
.meter-line { margin: .1rem 0 .55rem; color: var(--fg2); font-size: var(--t-body); }
.meter-line .stat-num { margin-inline-end: .1rem; }


/* --- Teacher class pages: revamp prototype, round two ---------------------
   Button rule for these pages: one primary (`btn-primary`/`go`) per region,
   `quiet-button` for secondary actions, `icon-btn` for tools, `danger-button`
   only where the act is destructive. */

/* Gradebook: a bar per student beside their average. */
.chip--warn { background: var(--amber-tint); color: var(--amber); }
.gb-avg { min-width: 8.5rem; }
.gb-bar { display: block; max-width: 7rem; height: .35rem; margin-top: .35rem; border-radius: 999px; background: var(--line); overflow: hidden; }
.gb-bar > span { display: block; height: 100%; border-radius: 999px; background: var(--accent); }

/* The draft/publish boundary, legible at a glance: anything students cannot
   see yet wears the amber of "waiting", and the publish button says so. */
.builder-tree-row.is-draft { background: var(--amber-tint); }
.builder-tree-row.is-draft:hover { background: color-mix(in srgb, var(--amber) 15%, var(--content)); }
.builder-tree-row.is-draft.is-selected { background: var(--primary-tint); }
.attachment-list > .is-draft { background: var(--amber-tint); }
.builder-editor-head .chip { vertical-align: middle; margin-inline-start: .4rem; }

/* Card tools stay quiet next to the card's one primary action. */
/* --- Teacher pages: clarity and legibility round -------------------------- */

/* Persian in chips: the script's descenders (ی ج چ پ گ) need a little more
   room below the baseline than Latin metrics assume, or text rides high and
   clips. A taller line and asymmetric padding center it honestly. */
.state-chip { line-height: 1.7; padding: .14rem .4rem .2rem; }
.chip--ok { background: var(--aqua-tint); color: var(--aqua); }
.chip--bad { background: var(--red-tint); color: var(--red); }

/* A running session is the one thing on the page that cannot wait to be seen. */
@keyframes live-pulse { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: .45; transform: scale(.78); } }
.live-dot { animation: live-pulse 1.6s ease-in-out infinite; }
.session-card:has(.session-state-live) { border-inline-start: 3px solid var(--accent); }
@media (prefers-reduced-motion: reduce) { .live-dot { animation: none; } }

/* Each class wears one of six hues so a teacher with several classes
   navigates by colour before reading a word. They ride on --class-accent so
   components opt in one property at a time. Each is a text colour held to
   4.5:1 on the surface, on --bg1 and on the ground's deepest point
   (docs/08 §ink): four of Gruvbox's six were stepped one shade darker for the
   green ground in ADR-0026. */
.cols { --class-accent: var(--accent); --class-accent-rgb: var(--accent-rgb); }
.ca-1 { --class-accent: #076678; --class-accent-rgb: 7, 102, 120; }
.ca-2 { --class-accent: #35704a; --class-accent-rgb: 53, 112, 74; }
.ca-3 { --class-accent: #80530d; --class-accent-rgb: 128, 83, 13; }
.ca-4 { --class-accent: #8f3f71; --class-accent-rgb: 143, 63, 113; }
.ca-5 { --class-accent: #5f6109; --class-accent-rgb: 95, 97, 9; }
.ca-6 { --class-accent: #9a3403; --class-accent-rgb: 154, 52, 3; }
.tab-strip .tab.is-active { color: var(--class-accent); box-shadow: inset 0 -2px 0 var(--class-accent); }
.tab-strip .tab.is-active > svg { color: var(--class-accent); }
/* The learning workspace's root strip (proposal S1) is a workspace's, not a
   class's: its current place keeps the primary's ink and underline, as the
   other roots' strips do, whatever hue a page around it wears. */
.tab-strip--root .tab.is-active { color: var(--ink); box-shadow: inset 0 -2px 0 var(--blue); }
.tab-strip--root .tab.is-active > svg { color: var(--blue); }

/* While previewing what students see, the banner stays in view so there is
   never a doubt about which side of the publish line you are on. */
.preview-banner { position: sticky; top: 0; z-index: 20; }

/* The meeting-mode select says what each choice implies. */
.mode-help { display: block; margin-top: .3rem; color: var(--fg4); font-size: var(--t-micro); min-height: 1.1em; }

/* Icon-only destructive buttons arm in place before they act. */
.icon-btn.is-armed { inline-size: auto; padding: 0 .7rem; background: var(--red-tint); color: var(--red); font-size: var(--t-small); font-weight: 600; white-space: nowrap; }


/* The Jalali date picker: a plain month grid under the input. */
.date-pick { position: absolute; z-index: 60; display: grid; gap: .45rem; padding: .7rem; border: 1px solid var(--line-2); border-radius: var(--r-pop); background: var(--raised); box-shadow: var(--shadow-pop); }
.date-pick-head { display: flex; align-items: center; justify-content: space-between; gap: .4rem; }
.date-pick-title { font-size: var(--t-body); font-weight: 600; }
.date-pick-nav { display: inline-flex; gap: .15rem; }
.date-pick-nav .icon-btn, .date-pick-today { min-inline-size: 2.2rem; }
.date-pick-today { display: inline-flex; align-items: center; padding: 0 .7rem; min-height: max(2.75rem, var(--tap)); border: 1px solid var(--line-2); border-radius: var(--r-sm); background: var(--surface); color: var(--fg2); font-size: var(--t-small); cursor: pointer; }
.date-pick-grid { display: grid; grid-template-columns: repeat(7, 2.75rem); }
.date-pick-grid > span { display: flex; align-items: center; justify-content: center; color: var(--faint); font-size: var(--t-micro); }
.date-pick-grid > button { display: flex; align-items: center; justify-content: center; min-block-size: max(2.75rem, var(--tap)); border: 0; border-radius: 8px; background: none; color: var(--fg1); font-size: var(--t-body); font-variant-numeric: tabular-nums; cursor: pointer; }
.date-pick-grid > button:hover { background: var(--hover); }
.date-pick-grid > button.is-selected { background: var(--blue); color: var(--on-accent); font-weight: 600; }
.date-pick-grid > button.is-blank { visibility: hidden; }

/* --- Student pages: state you can scan ------------------------------------ */

/* The student class strip and class tiles wear the class hue, the same one
   the teaching side of the same class wears. */
.tabs[class*='ca-'] .tab.is-active { color: var(--class-accent, var(--accent)); box-shadow: inset 0 -2px 0 var(--class-accent, var(--accent)); }

/* The resume lesson is where the student continues, so it leads with the
   class accent on its leading edge. Only "next" is marked: the product
   records the last lesson visited, not which lessons were read, so a
   "done" mark would be a claim the data cannot back. The border takes its
   width out of the row's own padding so the text does not shift. */
.dir-link.is-next { border-inline-start: 3px solid var(--class-accent, var(--accent)); padding-inline-start: calc(1.6rem - 3px); }
.dir-link.is-next .state-icon { color: var(--class-accent, var(--accent)); }

/* The submit action keeps its distance from the column edge. */
.submission-form .form-actions { padding-inline-end: .5rem; }

/* ══════════════════════════════════════════════════════════════════════════
   SESSIONS AS THE SPINE (ADR-0027). A class is read session by session: the
   week view, a session's own page, its roll call, the register, the term
   planner and the room's check-in code. Everything is drawn in the card
   language above — no new colour, no shadow on anything that sits on the
   page — and every control keeps the tap floor.
   ══════════════════════════════════════════════════════════════════════════ */

/* The two ways to read a class: a segmented control, one of two links. */
.view-switch { display: inline-flex; gap: .2rem; margin: 0 0 .9rem; padding: .2rem; border: 1px solid var(--line-2); border-radius: var(--r-pop); background: var(--sunk); }
/* One bar under the strip for a tab read two ways: the switch at the start,
   in the same spot in both readings, and that reading's own actions and state
   at the end, so neither reading needs a header row of its own. */
.reading-bar { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: .6rem 1.25rem; margin: 0 0 1rem; }
.reading-bar .view-switch { margin: 0; }
.reading-bar-end { display: flex; align-items: center; flex-wrap: wrap; gap: .5rem .75rem; min-inline-size: 0; }
.reading-bar-end .byline { margin: 0; }
.reading-bar-end > form { display: inline-flex; }
.view-switch a { display: inline-flex; align-items: center; gap: .4rem; min-height: var(--h); padding: 0 1rem; border-radius: var(--r-sm); color: var(--fg2); font-size: var(--t-body); font-weight: 500; }
.view-switch a:hover { color: var(--ink); background: var(--hover); }
.view-switch a[aria-current="true"] { background: var(--surface); color: var(--blue); font-weight: 600; box-shadow: 0 0 0 1px var(--line-2); }
/* A place read three or four ways («جلسه‌ها», «ارتباطات», ADR-0029): on a
   phone its switch keeps one row by its words alone. The icons are how the
   strip's places are told apart; a second row of them under the strip would
   read as a second strip. (With icons, four readings need about 440px.) */
@media (max-width: 30rem) {
  .view-switch:has(> a:nth-of-type(3)) a { gap: 0; padding: 0 .55rem; font-size: var(--t-small); }
  .view-switch:has(> a:nth-of-type(3)) a > svg { display: none; }
}
/* On a phone a bar's switch takes the row, its readings in equal cells, as
   the student's does; the bar's actions and figures wrap under it. */
@media (max-width: 40rem) { .reading-bar > .view-switch { flex: 1 1 100%; } }

/* The class's settings: a labelled door in its header (ADR-0029), marked
   while its page is open the way a switch marks its reading. */
.page-hd-actions [aria-current="page"] { border-color: var(--primary-edge); background: var(--primary-tint); color: var(--blue); }

/* A session's state pills beyond the three the schedule had: today, and a
   make-up session. */
.session-state-today { background: var(--primary-tint); color: var(--blue); }
.session-state-makeup { background: var(--aqua-tint); color: var(--aqua); }
.session-card h3 a { display: inline-flex; align-items: center; min-block-size: var(--h); color: inherit; }
.session-card h3 a:hover { color: var(--blue); }
.session-card.is-live { background: var(--primary-tint); border-radius: var(--r-sm); }
.roll-door.is-attention { border-color: color-mix(in srgb, var(--amber) 45%, var(--control)); color: var(--amber); }
.page-hd-sub { display: block; margin-top: .2rem; font-size: var(--t-lead); font-weight: 500; color: var(--fg2); }

/* A roll-call mark as a pill: the mark's own shape (ADR-0029), then its word,
   in the mark's ink on the quiet chip — red is the cross and the word, never
   a field behind them. Present is the norm and keeps the chip's ink. */
.mark-chip { display: inline-flex; align-items: center; gap: .25rem; padding: .04rem .55rem .12rem; border-radius: var(--pill); font-size: var(--t-micro); font-weight: 600; line-height: 1.7; background: var(--chip); color: var(--fg2); }
.mark-chip > svg { inline-size: 12px; block-size: 12px; flex-shrink: 0; }
.mark-chip--0 > svg { color: var(--aqua); }
.mark-chip--1 { color: var(--red); }
.mark-chip--1 > svg { stroke-width: 2.6; }
.mark-chip--2 { color: var(--amber); }
.mark-chip--3 { color: var(--blue); }

/* ── The student's class, week by week (proposal S2) ────────────────────
   The teacher's pieces read by a student: «امروز», the session cards and the
   week groups (below, with the schedule's), the term strip in the aside. A
   session's material hangs under its title, past the date tile, at the
   inline start; a week's deadlines close its group, amber — they wait on
   the student. An absence is never a red field or edge (ADR-0027). */
.week-range { margin-inline-start: .35rem; font-size: var(--t-small); font-weight: 400; color: var(--muted); }
.week-title { display: flex; align-items: baseline; gap: .2rem; margin: .8rem .5rem .3rem; font-size: var(--t-body); font-weight: 600; color: var(--fg1); }
.week-items { margin: 0; padding: 0 .45rem .15rem; list-style: none; }
.session-card > .week-items { margin: .3rem 0 0; padding: 0; padding-inline-start: calc(44px + .15rem); }
.week-item { display: flex; align-items: center; gap: .55rem; min-height: var(--tap); padding: .3rem .6rem; border-radius: var(--r-sm); color: var(--fg1); }
.week-item:hover { background: var(--hover); color: var(--ink); }
.week-due { display: flex; flex-wrap: wrap; align-items: center; gap: .2rem .5rem; margin: .3rem .45rem .5rem; padding: .35rem .6rem; border-radius: var(--r-sm); background: var(--amber-tint); }
.week-due-label { display: inline-flex; align-items: center; gap: .35rem; color: var(--amber); font-size: var(--t-small); font-weight: 600; }
.week-due .week-item { flex: 1 1 14rem; }
.week-group > .week-due { margin-top: .15rem; }
.other-section + .other-section { margin-top: .6rem; }
.other-section .week-title { margin-inline: .2rem; }
.taught-in { flex-shrink: 0; }

/* The class page's reading bar: the switch at its start, «ادامه» at its end
   (the teacher's bar, ADR-0028 §3). On a phone the door takes its own row,
   full width, its title cut rather than wrapped. */
.continue-end .go { max-inline-size: 100%; }
.continue-end .go bdi { min-inline-size: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
@media (max-width: 40rem) {
  .reading-bar-end.continue-end { inline-size: 100%; }
  .continue-end .go { flex: 1 1 100%; justify-content: center; }
}

/* The term at a glance in the student's aside: the teacher's figure
   (`ui::term_strip`) at the aside's scale — its title a micro-label. */
.aside-inner .term-strip { margin: 0 0 .65rem; padding: .75rem .9rem .8rem; }
.aside-inner .term-hd h2 { font-size: var(--t-micro); color: var(--muted); }
.aside-inner .term-legend { gap: .2rem .8rem; font-size: var(--t-meta); }

/* «وضعیت شما»: the student's own progress over the shared meter, then their
   row of the register (`.session-strip`), as the teacher reads it on their
   page — the count in plain ink, the marks in their shapes. */
.aside-inner .attendance-line { margin: 0 0 .5rem; font-size: var(--t-small); line-height: 1.75; }
.aside-inner .meter { margin: .1rem 0 .75rem; }
.aside-inner .session-strip { gap: .25rem; margin-bottom: .6rem; }
.aside-inner .mark-legend { gap: .2rem .75rem; font-size: var(--t-meta); }

/* Polls on the class page: the teacher's row (`.polls-board`), the reader's
   own state at its end — amber only while it waits on them. */
.poll-mine { font-size: var(--t-small); white-space: nowrap; }
.poll-mine.is-done { display: inline-flex; align-items: center; gap: .3rem; color: var(--fg2); }
.poll-mine.is-done svg { inline-size: 14px; block-size: 14px; color: var(--aqua); }
@media (max-width: 40rem) {
  .polls-board .poll-mine { grid-column: 1; grid-row: 2; justify-self: start; }
}

/* The student's check-in: one field, one button, big enough for a thumb. */
.checkin-form { display: flex; flex-wrap: wrap; align-items: flex-end; gap: .6rem; }
.checkin-input { inline-size: 9rem; font-size: var(--t-section); letter-spacing: .3em; text-align: center; font-variant-numeric: tabular-nums; }

/* ── A teacher's session page ────────────────────────────────────────── */
.roll-prompt { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .6rem 1rem; margin: 0 0 .9rem; padding: .7rem .9rem; border: 1px solid color-mix(in srgb, var(--amber) 30%, var(--content)); border-radius: var(--r); background: var(--amber-tint); }
.roll-prompt-copy { display: flex; flex-direction: column; min-width: 0; }
.roll-prompt-copy strong { color: var(--ink); font-size: var(--t-body); font-weight: 600; }
.roll-prompt-copy small { color: var(--fg3); font-size: var(--t-meta); }
.roll-prompt .go { margin-top: 0; }
.roll-summary { display: flex; flex-wrap: wrap; align-items: center; gap: .35rem .5rem; }
.roll-summary .stat-num { margin-inline-end: .6rem; }
.roll-names { display: flex; flex-wrap: wrap; gap: .35rem; margin: .7rem 0 0; }
/* Who was not there, each with the mark's shape: the chip stays quiet. */
.roll-name { display: inline-flex; align-items: center; gap: .3rem; padding: .2rem .6rem; border-radius: var(--pill); background: var(--chip); font-size: var(--t-small); }
.roll-name small { color: var(--fg3); }

/* The phase card (proposal 02): the session's three moments as a quiet rail,
   the current one its title; a sentence on where things stand; that moment's
   buttons, one fill at most; and the roll's state closing the card. */
.phase-card { border-color: var(--primary-edge); }
.phase-card.is-cancelled { border-color: var(--line); }
.phase-card > .sect-hd { flex-wrap: wrap; row-gap: .2rem; }
.phase-rail { display: flex; flex-wrap: wrap; align-items: center; gap: .3rem .5rem; margin: 0; padding: 0; list-style: none; font-size: var(--t-small); color: var(--faint); }
.phase-rail li { display: inline-flex; align-items: center; gap: .5rem; }
.phase-rail li + li::before { content: ""; inline-size: 1.1rem; block-size: 1px; background: var(--line-2); }
.phase-rail li[aria-current="step"] { color: var(--ink); }
.phase-rail h2 { margin: 0; font-size: var(--t-lead); font-weight: 600; color: var(--ink); }
.phase-note { margin: 0 0 .75rem; color: var(--fg2); font-size: var(--t-body); line-height: 1.8; }
.phase-note + .section-help { margin-top: -.4rem; }
.phase-actions { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; }
.phase-actions:not(:has(> *)) { display: none; }
.phase-actions .go, .phase-actions > form { margin-top: 0; }
.phase-actions .now-end, .now-bar .now-end { display: inline-flex; margin-inline-start: auto; }
.phase-status { display: flex; flex-wrap: wrap; align-items: center; gap: .3rem .6rem; margin: .8rem 0 0; padding-top: .65rem; border-top: 1px solid var(--line); font-size: var(--t-small); color: var(--muted); }
.phase-status strong { font-weight: 600; color: var(--ink); }
.phase-status--taken { display: block; }
.phase-foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .3rem 1rem; margin: .6rem 0 0; }
/* The phase card read by a student (proposal S2 §D): the check-in ruled off
   like the teacher's status lines; the reader's own mark closes the card, in
   words beside the shared chip — never a red field — and, for a student who
   was away, the line that says they reviewed it. */
.phase-checkin { margin: .8rem 0 0; padding-top: .7rem; border-top: 1px solid var(--line); }
.phase-checkin .checkin-form .field { font-size: var(--t-small); color: var(--fg2); }
.phase-checkin .checkin-form .go, .phase-checkin .checkin-form .btn-primary { margin-top: 0; }
.phase-checkin .section-help { margin: .45rem 0 0; }
.phase-checkin .notice { margin: 0 0 .6rem; }
.phase-status .mark-chip { margin-inline-start: .3rem; }
.phase-status > form { margin-inline-start: auto; }
.phase-status .now-note { flex: 1 1 14rem; line-height: 1.7; }
.phase-status .calm-mark { display: inline-flex; align-items: center; gap: .3rem; color: var(--fg2); }
.phase-status .calm-mark svg { inline-size: 14px; block-size: 14px; color: var(--aqua); }
@media (max-width: 40rem) {
  .phase-status > form { flex: 1 1 100%; margin-inline-start: 0; }
  .phase-status > form > button { inline-size: 100%; justify-content: center; }
  .phase-checkin .checkin-form { align-items: stretch; }
  .phase-checkin .checkin-form .field, .phase-checkin .checkin-form .checkin-input { inline-size: 100%; }
  .phase-checkin .checkin-form > button { flex: 1 1 100%; justify-content: center; }
}
/* The session's online class, one ruled line: its icon, what it is — a link
   in Latin monospace, left to right, cut in the middle by the server — and
   the one door that changes it at the line's end. */
.online-icon { display: inline-flex; color: var(--fg3); }
.online-copy { flex: 1 1 14rem; min-inline-size: 0; }
.online-url { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: var(--t-meta); color: var(--fg2); overflow-wrap: anywhere; }
.online-status > .create-panel { margin-inline-start: auto; }
.online-status > details[open]:not([data-modal-ready]) { flex-basis: 100%; }

/* Adding to a session's one list: two small dialogs under it, never a box
   inside it. */
.material-add-row { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; margin-top: .75rem; padding-top: .75rem; border-top: 1px solid var(--line); }
.material-add-row .add-lead { flex: 1 1 100%; margin: 0 0 .1rem; font-size: var(--t-small); color: var(--muted); }
.material-add-row > details[open]:not([data-modal-ready]) { flex-basis: 100%; }
.pick-section { margin: 0 0 .7rem; padding: 0; border: 0; }
.pick-section legend { margin-bottom: .3rem; font-weight: 600; color: var(--fg1); }
.pick-section .check-label { display: flex; align-items: center; gap: .5rem; min-height: var(--tap); }
.manage-row { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; }
.manage-row > details[open]:not([data-modal-ready]) { flex-basis: 100%; }
.side-facts { display: flex; flex-direction: column; gap: .45rem; }
.side-facts .meta-row { flex-direction: column; align-items: flex-start; gap: .1rem; }
/* The session among its neighbours: where it stands in the term, and the
   doors to the one before and after. */
.side-pos { margin: 0 0 .35rem; font-size: var(--t-small); color: var(--muted); }
.side-pos strong { font-weight: 600; color: var(--ink); }
.session-nav { display: flex; flex-direction: column; }
.session-nav a { display: flex; flex-direction: column; justify-content: center; gap: .1rem; min-block-size: var(--tap); padding: .45rem 0; border-top: 1px solid var(--line); color: var(--fg1); }
.session-nav a:first-of-type { border-top: 0; }
.session-nav a:hover strong { color: var(--blue); }
.session-nav .nav-dir { display: inline-flex; align-items: center; gap: .25rem; font-size: var(--t-micro); color: var(--muted); }
.session-nav strong { font-size: var(--t-small); font-weight: 600; color: var(--ink); }
.session-nav small { font-size: var(--t-meta); color: var(--muted); }

/* ── The roll call (proposal 06) ────────────────────────────────────────
   One line a student: the name, the four marks as one segmented control in
   the register's shapes, then what the room saw of them. A mark that is not
   «حاضر» shows its note under the choices and a thin bar of its colour at
   the row's start; «حاضر», where everyone starts, stays quiet. */
.roll-tools { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .5rem 1rem; max-inline-size: 60rem; margin-bottom: .7rem; }
.roll-tools .roll-intro { flex: 1 1 18rem; margin: 0; color: var(--fg2); font-size: var(--t-small); }
.roll-filter { position: relative; display: flex; align-items: center; flex: 1 1 16rem; max-width: 22rem; }
.roll-filter svg { position: absolute; inset-inline-start: .7rem; color: var(--muted); pointer-events: none; }
.roll-filter .input { inline-size: 100%; padding-inline-start: 2.2rem; }
.roll-sheet { max-inline-size: 60rem; }
.roll-list { overflow: clip; border: 1px solid var(--line); border-radius: var(--r); background: var(--surface); }
.roll-row { display: grid; grid-template-columns: minmax(9rem, 13rem) auto minmax(0, 1fr); grid-template-areas: "who choices ev" ". note note"; align-items: center; gap: .35rem 1rem; margin: 0; padding: .4rem .9rem; border: 0; border-bottom: 1px solid var(--line); min-inline-size: 0; }
.roll-row:last-child { border-bottom: 0; }
.roll-row[data-state="1"] { box-shadow: inset -3px 0 0 var(--red); }
.roll-row[data-state="2"] { box-shadow: inset -3px 0 0 var(--amber); }
.roll-row[data-state="3"] { box-shadow: inset -3px 0 0 var(--blue); }
/* Marked by the suggestion, not yet confirmed: waiting on the teacher. */
.roll-row.is-suggested { background: var(--amber-tint); }
.roll-who { grid-area: who; display: flex; flex-wrap: wrap; align-items: baseline; gap: .05rem .45rem; min-inline-size: 0; font-size: var(--t-body); }
.roll-who strong { font-weight: 600; color: var(--ink); }
.roll-who small { color: var(--faint); font-size: var(--t-meta); }
/* The four choices as one control, like the reading switch: a sunk track, the
   chosen one lifted onto the white face in its mark's ink and edge. */
.roll-choices { grid-area: choices; display: inline-grid; grid-auto-flow: column; grid-auto-columns: minmax(5.4rem, 1fr); gap: 2px; padding: 2px; border: 1px solid var(--line-2); border-radius: var(--r-pop); background: var(--sunk); }
.roll-choice { position: relative; display: flex; }
.roll-choice input { position: absolute; inline-size: 1px; block-size: 1px; opacity: 0; }
.roll-choice span { display: inline-flex; align-items: center; justify-content: center; gap: .35rem; inline-size: 100%; min-height: var(--tap); padding: 0 .75rem; border-radius: var(--r-sm); color: var(--fg2); font-size: var(--t-body); font-weight: 500; cursor: pointer; transition: background-color .12s, color .12s, box-shadow .12s; }
.roll-choice span > svg { inline-size: 15px; block-size: 15px; color: var(--muted); }
.roll-choice span:hover { background: var(--hover); color: var(--ink); }
.roll-choice input:checked + span { background: var(--control); color: var(--ink); font-weight: 600; box-shadow: 0 0 0 1px var(--line-2), var(--control-lift); }
.roll-choice input:focus-visible + span { box-shadow: var(--ring); }
.roll-choice--0 input:checked + span > svg { color: var(--aqua); }
.roll-choice--1 input:checked + span { color: var(--red); box-shadow: 0 0 0 1.5px color-mix(in srgb, var(--red) 55%, var(--control)); }
.roll-choice--1 input:checked + span > svg { color: var(--red); stroke-width: 2.6; }
.roll-choice--2 input:checked + span { color: var(--amber); box-shadow: 0 0 0 1.5px color-mix(in srgb, var(--amber) 55%, var(--control)); }
.roll-choice--2 input:checked + span > svg { color: var(--amber); }
.roll-choice--3 input:checked + span { color: var(--blue); box-shadow: 0 0 0 1.5px var(--primary-edge); }
.roll-choice--3 input:checked + span > svg { color: var(--blue); }
.roll-ev { grid-area: ev; display: flex; flex-wrap: wrap; gap: .3rem; justify-self: start; }
.roll-ev .chip { display: inline-flex; align-items: center; gap: .25rem; }
.roll-ev .chip > svg { inline-size: 13px; block-size: 13px; }
.roll-note { grid-area: note; max-inline-size: 30rem; }
.js .roll-row:not(.is-marked) .roll-note { display: none; }
/* What the room saw, and the one thing to do about it. */
.roll-evidence { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: .5rem .9rem; max-inline-size: 60rem; margin: 0 0 .9rem; padding: .75rem .9rem; border: 1px solid var(--line); border-radius: var(--r); background: var(--surface); }
.roll-evidence-ico { display: grid; place-items: center; inline-size: 2.3rem; block-size: 2.3rem; border-radius: var(--r-sm); background: var(--aqua-tint); color: var(--aqua); }
.roll-evidence p { margin: 0; }
.roll-evidence-lead { color: var(--ink); font-size: var(--t-body); line-height: 1.8; }
.roll-evidence-lead strong { font-weight: 600; }
.roll-unseen { margin-top: .15rem; color: var(--fg2); font-size: var(--t-small); line-height: 1.8; }
.roll-evidence-act { display: flex; flex-wrap: wrap; align-items: center; justify-content: flex-end; gap: .35rem .8rem; }
.roll-evidence-act .quiet-button { white-space: nowrap; }
.roll-suggested { max-inline-size: 22rem; color: var(--amber); font-size: var(--t-small); font-weight: 600; line-height: 1.8; }
.roll-bar, .plan-bar { position: sticky; inset-block-end: 0; z-index: 5; display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .5rem 1rem; margin-top: .8rem; padding: .7rem .9rem; border: 1px solid var(--line-2); border-radius: var(--r); background: var(--surface); }
.roll-counts { display: flex; flex-wrap: wrap; gap: .3rem .9rem; font-size: var(--t-small); color: var(--fg2); }
.roll-count { display: inline-flex; align-items: center; gap: .3rem; }
.roll-count > svg { inline-size: 14px; block-size: 14px; }
.roll-count strong { font-size: var(--t-lead); font-variant-numeric: tabular-nums; }
.roll-count--0 > svg, .roll-count--0 strong { color: var(--aqua); }
.roll-count--1 > svg, .roll-count--1 strong { color: var(--red); }
.roll-count--1 > svg { stroke-width: 2.6; }
.roll-count--2 > svg, .roll-count--2 strong { color: var(--amber); }
.roll-count--3 > svg, .roll-count--3 strong { color: var(--blue); }
.roll-bar .save-state { margin-inline-start: auto; }

/* ── The register (proposal 06) ──────────────────────────────────────────
   The sessions read student by student. A workbench: it fills its column
   like every list surface (the task-surface gate), and a term wider than
   that scrolls inside it — opening at the newest session: the scroller runs
   left to right and the table inside it right to left, so the names, the
   counts and the latest columns show first, older ones a scroll away. The
   name and the absence count stay put while the sessions scroll under them.
   The scroller is also the positioning context that clips the cells'
   visually-hidden words instead of widening the page. */
.register-scroll { position: relative; display: block; direction: ltr; }
.register { min-inline-size: 100%; direction: rtl; }
.register th, .register td { min-width: 2.9rem; padding: .45rem .3rem; }
.register thead th:first-child, .register tbody th[scope="row"] { inline-size: 12rem; min-inline-size: 12rem; max-inline-size: 12rem; }
.register tbody th[scope="row"] { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500; color: var(--ink); }
/* The count: plain ink, a faint zero — a count, never a verdict (ADR-0027). */
.register .register-total { position: sticky; inset-inline-start: 12rem; z-index: 1; inline-size: 3.6rem; min-inline-size: 3.6rem; background: var(--surface); box-shadow: inset 1px 0 0 var(--line-2); color: var(--fg1); font-weight: 600; font-variant-numeric: tabular-nums; }
.register thead .register-total { z-index: 3; background: var(--sunk); vertical-align: bottom; font-size: var(--t-small); }
.register tbody .register-total.is-zero { color: var(--faint); font-weight: 400; }
.register tbody tr:hover > th, .register tbody tr:hover > td { background-color: var(--row-hover); }
.register thead th.register-corner { vertical-align: bottom; }
.register-corner-in { display: flex; flex-direction: column; justify-content: space-between; gap: .4rem; min-block-size: 5.6rem; white-space: normal; }
.register-axis { color: var(--muted); font-size: var(--t-micro); font-weight: 400; line-height: 1.5; }
/* Each session's header is its door — the number in link ink, at rest — and
   its column of the chart (`ui::vbar`): who came, of everyone on the roll. */
.register thead th.register-col { padding: .35rem .2rem .3rem; vertical-align: bottom; }
.register-col a { display: flex; flex-direction: column; align-items: center; gap: .12rem; min-block-size: var(--tap); min-inline-size: var(--tap); color: var(--blue); font-weight: 600; text-decoration: none; }
.register-col a:hover .register-num { text-decoration: underline; text-underline-offset: 3px; }
.register-col a:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; border-radius: var(--r-sm); }
.register-pct { color: var(--fg3); font-size: var(--t-micro); font-weight: 400; font-variant-numeric: tabular-nums; line-height: 1.5; white-space: nowrap; }
.register-col.is-pending .register-pct { color: var(--amber); font-weight: 600; }
.register-num { font-size: var(--t-body); line-height: 1.4; }
.register-col small { color: var(--muted); font-size: var(--t-micro); font-weight: 400; white-space: nowrap; }
.register-col.is-today small { color: var(--blue); font-weight: 600; }
.register-head { align-items: flex-end; margin-top: .2rem; }
.register-head .byline { margin-top: .3rem; }
.register-stats .chip strong { font-weight: 600; }

/* ── The term planner and its syllabus table ─────────────────────────── */
.plan-days { margin: 0 0 .9rem; padding: 0; border: 0; }
.plan-days legend { margin-bottom: .4rem; font-weight: 600; color: var(--fg1); }
.day-choices { display: flex; flex-wrap: wrap; gap: .35rem; }
.day-choice { position: relative; display: inline-flex; }
.day-choice input { position: absolute; inline-size: 1px; block-size: 1px; opacity: 0; }
.day-choice span { display: inline-flex; align-items: center; min-height: var(--tap); padding: 0 .95rem; border: 1px solid var(--control-edge); border-radius: var(--pill); background: var(--control); color: var(--fg1); cursor: pointer; }
.day-choice input:checked + span { border-color: var(--primary-edge); background: var(--primary-tint); color: var(--blue); font-weight: 600; }
.day-choice input:focus-visible + span { box-shadow: var(--ring); }
.plan-list { margin-top: 1.2rem; }
.plan-slot { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem .8rem; min-height: var(--tap); padding: .4rem .7rem; border-bottom: 1px solid var(--line); }
.plan-slot:last-child { border-bottom: 0; }
/* The date and its tick are one target; the topic beside it is the
   session's own «موضوع (اختیاری)», typed like a syllabus row. */
.plan-slot-pick { display: flex; flex: 1 1 18rem; flex-wrap: wrap; align-items: center; gap: .4rem .8rem; min-height: var(--tap); cursor: pointer; }
.plan-slot-pick input { inline-size: 1.1rem; block-size: 1.1rem; accent-color: var(--blue); }
.plan-slot-topic { flex: 1 1 14rem; min-inline-size: 0; }
.plan-slot-date { flex: 1 1 10rem; font-weight: 500; color: var(--ink); }
.plan-slot-time { color: var(--fg3); font-size: var(--t-small); font-variant-numeric: tabular-nums; }
.plan-slot.is-holiday .plan-slot-date, .plan-slot.is-existing .plan-slot-date { color: var(--fg3); }
.plan-slot.is-existing .plan-slot-pick { cursor: default; }

/* ── The room's check-in code, for a projector (proposal 06) ────────────
   One card, the stage: the students' one instruction, the digits in four
   tiles, how many of the class have typed them. The teacher's own note stays
   outside it, so the room never sees it. `:target` makes the stage fill the
   window with nothing else on it, and app.js asks for the browser's full
   screen as well (`is-projecting`). Projection sizes are in vh — the one
   place the type ladder does not reach, like the live room's stage. */
.checkin-stage { display: flex; flex-direction: column; align-items: center; gap: .9rem; padding: 1.6rem 1rem 1.8rem; border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--surface); text-align: center; }
.checkin-step { margin: 0; color: var(--fg1); font-size: var(--t-lead); }
.checkin-screen { display: flex; flex-direction: column; align-items: center; gap: .8rem; inline-size: 100%; }
/* Tiles, inline: the code reads back as one word, «۴۸۲۷», never four lines. */
.checkin-digits { margin: 0; font-size: clamp(3rem, 11vw, 6.5rem); font-weight: 600; line-height: 1; color: var(--ink); }
.checkin-digits > span { display: inline-block; min-inline-size: 1.25em; margin-inline: .07em; padding: .14em .12em .1em; border: 1px solid var(--line-2); border-radius: var(--r-lg); background: var(--control); font-variant-numeric: tabular-nums; }
.checkin-seen { margin: 0; color: var(--fg2); font-size: var(--t-lead); }
.checkin-seen strong { color: var(--ink); font-weight: 600; }
.checkin-stage .meter { inline-size: min(22rem, 80%); block-size: .4rem; }
.checkin-foot, .checkin-close { display: none; }
.checkin-note { max-inline-size: 44rem; margin: .8rem auto 0; text-align: center; }
.checkin-stage:target, .checkin-stage.is-projecting { position: fixed; inset: 0; z-index: 80; justify-content: center; gap: 4vh; margin: 0; padding: 6vh 5vw; border: 0; border-radius: 0; }
:is(.checkin-stage:target, .checkin-stage.is-projecting) .checkin-step { font-size: clamp(1.1rem, 3.6vh, 2.4rem); }
:is(.checkin-stage:target, .checkin-stage.is-projecting) .checkin-screen { gap: 4vh; }
:is(.checkin-stage:target, .checkin-stage.is-projecting) .checkin-digits { font-size: min(24vh, 14vw); }
:is(.checkin-stage:target, .checkin-stage.is-projecting) .checkin-seen { font-size: clamp(1rem, 3vh, 2rem); }
:is(.checkin-stage:target, .checkin-stage.is-projecting) .meter { inline-size: min(40rem, 60vw); block-size: .7rem; }
:is(.checkin-stage:target, .checkin-stage.is-projecting) .checkin-foot { display: block; position: absolute; inset-block-end: 3vh; inset-inline: 0; margin: 0; color: var(--muted); font-size: clamp(.9rem, 2.2vh, 1.4rem); line-height: 1.6; }
.checkin-foot > bdi { display: block; }
:is(.checkin-stage:target, .checkin-stage.is-projecting) .checkin-close { display: inline-flex; position: absolute; inset-block-start: 2.5vh; inset-inline-end: 2.5vw; }

@media (max-width: 62rem) {
  /* Sticky bars ride above the fixed bottom navigation, not under it. */
  .roll-bar, .plan-bar { inset-block-end: calc(4rem + env(safe-area-inset-bottom, 0px)); }
}
@media (max-width: 40rem) {
  /* A roll row: the name and what the room saw share a line, the four
     choices take the next one in equal cells, the note the one after. */
  .roll-row { grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "who ev" "choices choices" "note note"; padding: .6rem .75rem; }
  .roll-ev { justify-self: end; }
  .roll-choices { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); grid-auto-flow: row; }
  .roll-choice span { gap: .25rem; padding: 0 .3rem; }
  .roll-note { max-inline-size: none; }
  .roll-evidence { grid-template-columns: auto minmax(0, 1fr); }
  .roll-evidence-act { grid-column: 1 / -1; justify-content: stretch; }
  .roll-evidence-act > * { flex: 1 1 100%; justify-content: center; }
  .roll-prompt .go { flex: 1 1 100%; }
  /* The register on a phone: a narrower name, the count beside it, and
     about four sessions in view — the newest. */
  .register thead th:first-child, .register tbody th[scope="row"] { inline-size: 8.5rem; min-inline-size: 8.5rem; max-inline-size: 8.5rem; }
  .register .register-total { inset-inline-start: 8.5rem; inline-size: 2.9rem; min-inline-size: 2.9rem; }
  .week-items { padding-inline-start: .45rem; }
  .view-switch { display: flex; }
  .view-switch a { flex: 1 1 0; justify-content: center; }
}

/* ── The schedule, as one list of doors (ADR-0027) ─────────────────────────
   A session's card is one link to its page — the date tile, «جلسهٔ ۲ —
   topic», one line of facts, the clock's word — with at most one action
   beside it, the one due now. */
.session-card-row { display: flex; align-items: center; gap: .75rem; }
.session-card-link { display: grid; flex: 1 1 auto; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; column-gap: .75rem; min-width: 0; min-block-size: var(--tap); color: inherit; text-decoration: none; }
.session-card-link:hover h3, .session-card-link:focus-visible h3 { color: var(--blue); }
.session-card-link .session-card-main { display: flex; flex-direction: column; gap: .2rem; }
.session-card-meta { color: var(--muted); font-size: var(--t-small); line-height: 1.7; }
.session-card-note { color: var(--amber); font-size: var(--t-small); }
.session-card-state { flex-shrink: 0; }
.session-card-row > .go, .session-card-row > .quiet-button, .session-card-row > .quiet-form, .session-card-row > .quiet-link { flex-shrink: 0; white-space: nowrap; }
/* A fact that waits on the teacher, inside a line of facts: amber, a dot. */
.meta-waiting { display: inline-flex; align-items: center; gap: .3rem; color: var(--amber); font-weight: 600; }
.meta-waiting::before { content: ""; inline-size: .4rem; block-size: .4rem; border-radius: 50%; background: currentColor; }

/* The schedule has no card around its cards (proposal 02): #sessions is a
   plain column, and its groups — today, a roll still owed, the term, what is
   to come, what has been held — are the cards. */
#sessions.sessions-board { max-width: none; margin: 0; padding: 0; border: 0; background: none; scroll-margin-top: 1rem; }
.sessions-board > .sect, .sessions-board > .roll-prompt, .sessions-board > .notice, .sessions-board > .empty { margin: 0 0 .8rem; }
/* «امروز»: the one card about now, in the primary's hairline. Its session
   carries what the clock says is due in a bar under it. */
.today-card { border-color: var(--primary-edge); }
.now-bar { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; margin-top: .7rem; padding-top: .7rem; border-top: 1px solid var(--line); }
.now-bar:not(:has(> *)) { display: none; }
.now-bar .go, .now-bar > form { margin-top: 0; }
/* «هفته‌به‌هفته» reads by week: each list's sessions under their week's
   name and range. */
.week-group + .week-group { margin-top: .2rem; border-top: 1px solid var(--line); }
.week-label { display: flex; align-items: baseline; gap: .45rem; margin: .65rem .6rem .1rem; font-size: var(--t-small); color: var(--fg2); }
.week-label strong { font-weight: 600; color: var(--ink); }
.week-label .week-range { margin: 0; }
.week-group > .session-card:last-child { border-bottom: 0; }
/* With nothing planned, the planner is the page's one fill. */
.create-panel > summary.is-primary { border-color: var(--primary-fill); background: var(--primary-fill); color: var(--on-accent); font-weight: 600; }
.create-panel > summary.is-primary:hover { border-color: var(--primary-fill-hover); background: var(--primary-fill-hover); }
@media (max-width: 40rem) {
  /* The title keeps the width; the clock's word goes under it. */
  .session-card-link { grid-template-columns: auto minmax(0, 1fr); row-gap: .35rem; }
  .session-card-state { grid-column: 2; justify-self: start; }
  .session-card-row { flex-wrap: wrap; }
  .session-card-row > .go, .session-card-row > .quiet-button, .session-card-row > .quiet-form { flex: 1 1 100%; }
  .session-card-row > .quiet-form > button { inline-size: 100%; }
  /* Today's verbs stack full width, the fill first, «پایان» last. */
  .now-bar > a, .now-bar > form, .now-bar > form > button, .phase-actions > a, .phase-actions > form, .phase-actions > form > button { flex: 1 1 100%; justify-content: center; }
  .now-bar .now-end, .phase-actions .now-end { margin-inline-start: 0; }
  .reading-bar-end.create-actions { inline-size: 100%; }
  .reading-bar-end.create-actions > details:not([open]) { flex: 1 1 0; }
  .reading-bar-end.create-actions > details > summary { display: flex; justify-content: center; }
}

/* Planning a term and adding one session sit together over the schedule;
   without script the one opened unfolds below them, full width. */
/* Create dialogs opened from a bar (the schedule's planner and add-one, a
   class's new assessment): without script each unfolds in place, full width. */
.create-actions { gap: .5rem; }
.create-actions > details[open]:not([data-modal-ready]) { flex-basis: 100%; order: 2; }
.reading-bar:has(.create-actions > details[open]:not([data-modal-ready])) .create-actions,
.panel-head:has(.create-actions > details[open]:not([data-modal-ready])) .create-actions { flex-basis: 100%; }
.plan-dates { margin-top: .2rem; }
.plan-dates:focus { outline: none; }
.plan-slots { border: 1px solid var(--line); border-radius: var(--r); background: var(--surface); }
.modal .plan-bar { inset-block-end: 0; background: var(--raised); }
/* Two numbered parts (proposal 02): a disc, never «۱.» — a period beside a
   Persian digit reads as a zero. Before the dates load their place says what
   will come, dashed (not yet); once they load, part one folds to the one line
   that says what was asked. */
.plan-part { display: flex; align-items: center; gap: .55rem; margin: .3rem 0 .8rem; font-size: var(--t-lead); font-weight: 600; color: var(--ink); }
.step-num { display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; inline-size: 1.6rem; block-size: 1.6rem; border-radius: 50%; background: var(--primary-tint); color: var(--blue); font-size: var(--t-small); font-weight: 600; }
.plan-note { margin: -.35rem 0 .7rem; font-size: var(--t-meta); color: var(--muted); }
.plan-form .plan-preview { align-self: stretch; }
.plan-divider { margin: 1.1rem 0 .9rem; border: 0; border-top: 1px solid var(--line); }
.plan-dates-empty { margin: 0; padding: .85rem 1rem; border: 1px dashed var(--line-2); border-radius: var(--r); color: var(--muted); font-size: var(--t-small); line-height: 1.8; }
.plan-pattern { margin: 0 0 .9rem; border: 1px solid var(--line); border-radius: var(--r); background: var(--surface); }
.plan-pattern > summary { display: flex; flex-wrap: wrap; align-items: center; gap: .3rem .6rem; min-block-size: var(--tap); padding: .45rem .8rem; list-style: none; cursor: pointer; font-size: var(--t-small); color: var(--fg2); }
.plan-pattern > summary::-webkit-details-marker { display: none; }
.plan-pattern > summary .step-num { inline-size: 1.4rem; block-size: 1.4rem; }
.plan-pattern > summary strong { font-weight: 600; color: var(--ink); }
.plan-pattern > summary .plan-change { margin-inline-start: auto; }
.plan-pattern[open] > summary { border-bottom: 1px solid var(--line); }
.plan-pattern > .plan-form { margin: 0; padding: .8rem .9rem .9rem; }
/* The list says its arithmetic, and a long term breaks by month. */
.plan-summary { display: flex; flex-wrap: wrap; align-items: center; gap: .25rem .5rem; margin: 0 0 .3rem; font-size: var(--t-small); color: var(--fg2); }
.plan-summary strong { font-weight: 600; color: var(--ink); }
.plan-month { padding: .45rem .7rem .25rem; border-bottom: 1px solid var(--line); background: var(--sunk); font-size: var(--t-micro); font-weight: 600; color: var(--muted); }
.plan-slots > .plan-month:first-child { border-start-start-radius: 9px; border-start-end-radius: 9px; }
/* A field only one way of meeting needs appears with it: the link for a
   session held on another service, the recording for an online one. A
   browser without :has() shows them all, as before. */
@supports selector(:has(*)) {
  form:has(select[name="meeting_mode"]) .if-link { display: none; }
  form:has(select[name="meeting_mode"] option[value="1"]:checked) .if-link { display: flex; }
  form:has(select[name="meeting_mode"]) .if-online { display: none !important; }
  form:has(select[name="meeting_mode"] option:is([value="2"], [value="3"]):checked) .if-online { display: inline-flex !important; }
  /* The same with the choices as radio cards: the online class's dialog. */
  form:has(input[type="radio"][name="meeting_mode"]) .if-link { display: none; }
  form:has(input[type="radio"][name="meeting_mode"][value="1"]:checked) .if-link { display: flex; }
  form:has(input[type="radio"][name="meeting_mode"]) .if-online { display: none !important; }
  form:has(input[type="radio"][name="meeting_mode"]:is([value="2"], [value="3"]):checked) .if-online { display: inline-flex !important; }
  /* The classroom's rules: only while Takhte's classroom is chosen. */
  form:has(input[type="radio"][name="meeting_mode"]) .if-classroom { display: none; }
  form:has(input[type="radio"][name="meeting_mode"][value="3"]:checked) .if-classroom { display: grid; }
}
/* The classroom's rules in the online class's dialog (ADR-0032): what the
   class allows, and a switch for each thing this session may turn off. */
fieldset.room-rules { gap: .55rem; min-inline-size: 0; margin: 0; padding: .7rem .9rem .85rem; border: 1px solid var(--line); border-radius: var(--r); background: var(--sunk); }
fieldset.room-rules > legend { padding: 0 .35rem; font-size: var(--t-small); font-weight: 600; color: var(--fg2); }
.room-rules-name { display: flex; flex-wrap: wrap; align-items: center; gap: .3rem; margin: 0; }
.room-rules-switches { display: flex; flex-wrap: wrap; gap: .25rem 1.1rem; }
/* «قواعد کلاس آنلاین» (ADR-0032): a rule set as a card — its name, what
   uses it, its rules in chips and its doors — then the classes as rows, each
   with its select, and the clashes ahead. */
.rule-set { display: grid; gap: .45rem; padding: .85rem 0; border-bottom: 1px solid var(--line); }
.rule-set:last-of-type { border-bottom: 0; }
.rule-set-hd { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; }
.rule-set-hd h3 { margin: 0; font-size: var(--t-body); font-weight: 600; color: var(--ink); }
.rule-set-use { margin-inline-start: auto; font-size: var(--t-meta); color: var(--faint); }
.rule-set-note { margin: 0; font-size: var(--t-small); color: var(--muted); }
.rule-set .chips { margin: 0; }
.rule-set-actions { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; }
.rule-set-actions form { margin: 0; }
.rules-switches { display: flex; flex-wrap: wrap; gap: .1rem 1.1rem; margin: 0; padding: 0; border: 0; }
.rules-term { display: flex; flex-wrap: wrap; align-items: end; gap: .5rem; margin: 0 0 .6rem; }
.rule-classes { display: grid; margin: 0; padding: 0; list-style: none; }
.rule-class { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem .9rem; min-block-size: var(--tap); padding: .45rem 0; border-bottom: 1px solid var(--line); }
.rule-class:last-child { border-bottom: 0; }
.rule-class .task-copy { flex: 1 1 14rem; }
.rule-class-form { display: flex; align-items: center; gap: .4rem; margin: 0; }
.rule-class-form .input { min-inline-size: 11rem; }
.rule-clash { font-size: var(--t-small); font-weight: 600; color: var(--amber); }
/* A session's own form: three groups a teacher recognises, on the surface. */
.session-edit-form { max-width: 46rem; }
fieldset.form-group { display: flex; flex-direction: column; gap: .9rem; min-inline-size: 0; margin: 0; padding: .85rem 1rem 1rem; border: 1px solid var(--line); border-radius: var(--r); background: var(--surface); }
fieldset.form-group > legend { padding: 0 .35rem; font-size: var(--t-small); font-weight: 600; color: var(--fg2); }
/* The builder's bar: where publishing stands in words — changes the students
   cannot see yet in amber — beside a white publish button. */
.publish-state { display: inline-flex; align-items: center; gap: .4rem; font-size: var(--t-small); color: var(--muted); }
.publish-state.is-waiting { color: var(--amber); font-weight: 600; }
.publish-state.is-waiting::before { content: ""; inline-size: .45rem; block-size: .45rem; border-radius: 50%; background: currentColor; }

/* A session's material, one list: its content, its files, its recording. */
.material-list { display: grid; margin: 0; padding: 0; list-style: none; }
.material-row { display: flex; align-items: center; gap: .6rem; min-block-size: var(--tap); padding: .35rem 0; border-bottom: 1px solid var(--line); }
.material-row:last-child { border-bottom: 0; }
.material-copy { display: flex; flex: 1 1 auto; flex-direction: column; min-width: 0; color: var(--fg1); }
.material-copy small { color: var(--muted); font-size: var(--t-small); }

/* ── «دانشجویان»: the roster, the report, one student's page (proposals 03,
   07). The roster is light — names, logins, a state only where it is not the
   ordinary one — and every row is the door to the student's page, where the
   record and the rare tools are. The report measures each student against
   the class and says why in words; absences stay a count in plain ink. ── */

/* An enrolment's state: the word stays in ink, the colour is only its dot.
   The roster draws one only for a student who is not ordinary. */
.state-chip[class*="state-chip--"] { gap: .3rem; }
.state-chip[class*="state-chip--"]::before { content: ""; flex: none; inline-size: .45rem; block-size: .45rem; border-radius: 50%; background: var(--dot, var(--faint)); }
.state-chip--active { --dot: var(--aqua); }
.state-chip--suspended { --dot: var(--amber); }
.state-chip--banned { --dot: var(--red); }
.state-chip.state-chip--pending::before { background: none; box-shadow: inset 0 0 0 1.5px var(--faint); }

/* The reading's two actions; on a phone they share the row under the switch. */
.roster-actions > form { display: inline-flex; }
@media (max-width: 40rem) {
  .roster-actions > form { flex: 1 1 0; }
  .roster-actions > form > button { inline-size: 100%; justify-content: center; }
}

/* A dialog's parts: a lead sentence, a help line under a field, radio cards
   that say what each choice does, and a note on what happens next. */
.dialog-lead { margin: 0 0 .9rem; color: var(--fg2); font-size: var(--t-body); line-height: 1.85; }
.field-help { margin: -.2rem 0 .8rem; color: var(--muted); font-size: var(--t-meta); line-height: 1.75; }
/* A column of logins, pasted: typed and read left to right in the sheet's
   face, the example in the field included. */
.roster-paste textarea { min-block-size: 8.5rem; }
.roster-paste .input.login::placeholder { font-family: ui-monospace, "SF Mono", Menlo, monospace; direction: ltr; }
.choice-list { display: grid; gap: .4rem; min-width: 0; margin: 0 0 .9rem; padding: 0; border: 0; }
.choice-list legend { margin-bottom: .45rem; padding: 0; color: var(--fg1); font-size: var(--t-small); font-weight: 600; }
.choice { display: grid; grid-template-columns: auto minmax(0, 1fr); column-gap: .6rem; align-items: start; min-height: var(--tap); padding: .5rem .75rem; border: 1px solid var(--line-2); border-radius: var(--r-sm); background: var(--control); cursor: pointer; transition: border-color .12s, background-color .12s; }
.choice:hover { border-color: var(--control-edge-hover); }
.choice:has(input:checked) { border-color: var(--blue); background: var(--primary-tint); }
.choice input { margin-top: .35rem; accent-color: var(--blue); }
.choice strong { color: var(--ink); font-size: var(--t-body); font-weight: 600; }
.choice small { grid-column: 2; color: var(--fg3); font-size: var(--t-meta); line-height: 1.7; }
.dialog-note { margin: 1rem 0 0; padding-top: .8rem; border-top: 1px solid var(--line); color: var(--fg3); font-size: var(--t-meta); line-height: 1.8; }

/* What the last add or close did, in the list it changed. */
.roster-result { display: flex; align-items: flex-start; gap: .6rem; max-width: none; margin: 0 0 .9rem; }
.roster-result > svg { flex: none; margin-top: .3rem; color: var(--amber); }
.roster-result.notice-ok > svg { color: var(--aqua); }
.roster-result p { margin: 0; line-height: 1.85; }
.roster-result small { display: block; color: var(--fg3); font-size: var(--t-meta); }
#roster.roster { scroll-margin-block-start: 1rem; }

/* Search, then the states with their counts: one row above the list. */
.roster-tools { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem .75rem; margin-bottom: .3rem; }
.roster-search { display: flex; align-items: center; gap: .4rem; flex: 1 1 14rem; max-width: 22rem; min-width: 0; margin: 0; }
.roster-search .input { flex: 1 1 auto; min-width: 0; }
.roster-filters { display: flex; flex-wrap: wrap; gap: .2rem; min-width: 0; }
.roster-filters a { display: inline-flex; flex: none; align-items: center; gap: .35rem; min-height: var(--h); padding: 0 .75rem; border-radius: var(--pill); color: var(--muted); font-size: var(--t-small); white-space: nowrap; }
.roster-filters a:hover { background: var(--hover); color: var(--ink); }
.roster-filters a[aria-current] { background: var(--primary-tint); color: var(--blue); font-weight: 600; }
.filter-count { font-variant-numeric: tabular-nums; font-weight: 600; }

/* One row a student; the whole row is the door to their page. */
.roster-list { margin-top: .5rem; }
.roster-row { display: flex; align-items: center; gap: .75rem; min-height: 3.4rem; padding: .45rem .55rem; border-bottom: 1px solid var(--line); color: var(--fg1); transition: background-color .12s; }
.roster-row:last-child { border-bottom: 0; }
.roster-row:hover { background: var(--hover); }
.roster-row:focus-visible { outline: 2px solid var(--blue); outline-offset: -2px; }
.roster-id { display: flex; flex: 1 1 auto; flex-direction: column; min-width: 0; }
.roster-name { display: flex; flex-wrap: wrap; align-items: center; gap: .15rem .5rem; min-width: 0; }
.roster-name strong { color: var(--ink); }
.roster-id small { color: var(--muted); font-size: var(--t-meta); }
.roster-row.is-off .roster-name strong { color: var(--muted); }
.roster-chev { display: flex; flex: none; color: var(--faint); }
.roster-list > .calm-state { flex-wrap: wrap; margin: .4rem 0; }
.roster-list > .calm-state .go { margin: 0 auto 0 0; }

/* The pager and the one rare tool share the list's foot. */
.roster-foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .2rem 1rem; margin-top: .5rem; }
.roster-foot .roster-pager { margin: 0; }
.roster-close > summary { display: inline-flex; align-items: center; gap: .4rem; min-height: var(--tap); padding-inline: .5rem; margin-inline-end: -.5rem; border-radius: var(--r-sm); color: var(--fg3); font-size: var(--t-small); cursor: pointer; list-style: none; }
.roster-close > summary::-webkit-details-marker { display: none; }
.roster-close > summary:hover { background: var(--hover); color: var(--ink); }
.roster-close[open]:not([data-modal-ready]) { flex-basis: 100%; }

/* The aside's help: how to read the list, in a few plain lines. */
.side-help p { color: var(--fg2); font-size: var(--t-meta); line-height: 1.8; }
.side-help p + p { margin-top: .35rem; }

/* The report's filter: everyone, or who needs attention. */
.filter-pills { display: flex; flex-wrap: wrap; align-items: center; gap: .3rem; margin: 0 0 .7rem; }
.filter-pills a { display: inline-flex; align-items: center; gap: .45rem; min-block-size: var(--h); padding-inline: .9rem; border: 1px solid transparent; border-radius: var(--pill); color: var(--muted); font-size: var(--t-small); transition: background-color .12s, color .12s; }
.filter-pills a:hover { background: var(--hover); color: var(--ink); }
.filter-pills a.is-active { border-color: var(--primary-edge); background: var(--primary-tint); color: var(--blue); font-weight: 600; }
.report-flag-help { margin-top: -.2rem; }

/* The report: one line a student, a second only for a student who needs
   attention, and it says why. */
.report-head, .report-row { display: grid; grid-template-columns: minmax(9rem, 1fr) 7.25rem 7.25rem 3.75rem 7.5rem; gap: .75rem; align-items: center; padding: .3rem .6rem; border-bottom: 1px solid var(--line); }
.report-head { min-height: 2.4rem; color: var(--fg3); font-size: var(--t-micro); font-weight: 600; }
.report-row { min-height: var(--tap); }
.report-row:last-child { border-bottom: 0; }
/* The flag's edge is an inset line, so a flagged row's columns do not move. */
.report-row.is-risk { box-shadow: inset -3px 0 0 var(--amber); }
.report-who { display: flex; flex-direction: column; min-width: 0; }
.report-who strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.report-why { display: flex; flex-wrap: wrap; align-items: center; gap: 0 .7rem; color: var(--muted); font-size: var(--t-meta); line-height: 1.7; }
.report-why .why { display: inline-flex; align-items: center; gap: .35rem; color: var(--amber); font-weight: 600; }
.report-why .why::before { content: ""; flex: none; inline-size: .42rem; block-size: .42rem; border-radius: 50%; background: currentColor; }
.report-num { display: flex; align-items: center; gap: .5rem; min-width: 0; color: var(--fg1); font-size: var(--t-body); font-variant-numeric: tabular-nums; }
.report-num > b { min-inline-size: 2.4rem; font-weight: 500; }
.report-num .meter { flex: 1 1 auto; max-inline-size: 3.75rem; }
/* A zero, or no grade yet, is quiet and never hidden. Absences have no other
   state: no colour, no weight, no part in the flag (ADR-0027). */
.report-num.is-quiet { color: var(--muted); }
/* A number's name: the head row says it on a wide screen, the cell on a phone. */
.cell-lbl { position: absolute; inline-size: 1px; block-size: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
/* The row's verb, visible at rest: its notes, on the student's page. */
.report-notes { display: inline-flex; align-items: center; justify-self: start; gap: .4rem; min-block-size: var(--tap); min-inline-size: var(--tap); padding-inline: .55rem; margin-inline-start: -.55rem; border-radius: var(--r-sm); color: var(--blue); font-size: var(--t-small); font-weight: 500; white-space: nowrap; transition: background-color .12s; }
.report-notes:hover { background: var(--primary-tint); }
.report-list > .calm-state { margin: .45rem 0; }

/* The class at a glance: two small histograms on one axis (`ui::hist`),
   each with its mean in words and one line of what it leaves out. */
.class-shape .dist { margin: 0; }
.class-shape .dist + .dist { margin-top: .8rem; padding-top: .7rem; border-top: 1px solid var(--line); }
.dist-hd { display: flex; align-items: baseline; justify-content: space-between; gap: .5rem; margin-bottom: .2rem; }
.dist-title { color: var(--fg1); font-size: var(--t-small); font-weight: 600; }
.dist-mean { display: inline-flex; align-items: center; gap: .35rem; color: var(--muted); font-size: var(--t-meta); }
.dist-mean::before { content: ""; inline-size: 1px; block-size: .8rem; background: var(--fg2); }
.dist-mean strong { color: var(--fg1); font-weight: 600; }
.dist-note { margin-top: .3rem; color: var(--muted); font-size: var(--t-meta); line-height: 1.6; }
.report-legend p { color: var(--fg2); font-size: var(--t-meta); line-height: 1.75; }
.report-legend p + p { margin-top: .3rem; }
.report-legend strong { color: var(--fg1); font-weight: 600; }

/* One student's page: their standing in three facts. */
.standing { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); border-top: 1px solid var(--line); border-radius: 0 0 var(--r) var(--r); overflow: hidden; }
.standing-fact { display: flex; flex-direction: column; gap: .2rem; min-width: 0; padding: .75rem 1rem .85rem; border-inline-start: 1px solid var(--line); color: var(--fg1); }
.standing-fact:first-child { border-inline-start: 0; }
a.standing-fact { transition: background-color .12s; }
a.standing-fact:hover { background: var(--hover); }
.standing-label { color: var(--muted); font-size: var(--t-meta); font-weight: 600; }
.standing-fact strong { color: var(--ink); font-size: var(--t-sub); font-weight: 600; line-height: 1.5; font-variant-numeric: tabular-nums; }
.standing-fact .meter { max-inline-size: 9rem; margin: .1rem 0 .2rem; }
.standing-fact small { color: var(--muted); font-size: var(--t-meta); line-height: 1.65; }

/* The follow-up notes: the form, then the history, newest first. */
.note-form { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: end; gap: .5rem; }
.note-form textarea { min-block-size: 4.4rem; resize: vertical; }
.note-list { margin: .9rem 0 0; padding: 0; list-style: none; border-top: 1px solid var(--line); }
.note-list li { padding: .7rem .15rem .75rem; border-bottom: 1px solid var(--line); }
.note-list li:last-child { border-bottom: 0; padding-bottom: .2rem; }
.note-meta { display: flex; align-items: center; margin: 0; color: var(--muted); font-size: var(--t-meta); }
.note-body { margin: .2rem 0 0; color: var(--fg1); font-size: var(--t-read); line-height: 1.9; white-space: pre-line; overflow-wrap: anywhere; }
#notes .feed-empty { margin-top: .7rem; }

/* Each assessment and the student's latest attempt at it. */
.mark-list { display: grid; }
.mark-row { display: grid; grid-template-columns: minmax(0, 1fr) 5.5rem 4.5rem 10.5rem; align-items: center; gap: .4rem .9rem; min-height: var(--tap); padding: .45rem .55rem; border-bottom: 1px solid var(--line); color: var(--fg1); }
.mark-row:last-child { border-bottom: 0; }
a.mark-row { transition: background-color .12s; }
a.mark-row:hover { background: var(--hover); }
.mark-title { display: flex; flex-direction: column; min-width: 0; }
.mark-title small { color: var(--muted); font-size: var(--t-meta); }
.mark-score { font-variant-numeric: tabular-nums; white-space: nowrap; }
.mark-score b { font-weight: 600; }
.mark-state { color: var(--muted); font-size: var(--t-small); }
.mark-state.is-waiting { color: var(--amber); font-weight: 600; }
.mark-foot { margin: .55rem .55rem .15rem; color: var(--muted); font-size: var(--t-meta); line-height: 1.75; }
#marks .feed-empty { padding: .5rem .55rem; }

/* The student's row of the register, read across: a session's number over
   the mark, each cell the door to that roll call. */
.attendance-line { margin: 0 0 .7rem; color: var(--fg2); font-size: var(--t-body); }
.attendance-line strong { color: var(--ink); font-weight: 600; font-variant-numeric: tabular-nums; }
.session-strip { display: flex; flex-wrap: wrap; gap: .3rem; margin: 0 0 .75rem; padding: 0; list-style: none; }
.strip-cell { display: grid; justify-items: center; align-content: center; gap: .1rem; min-inline-size: var(--tap); min-block-size: calc(var(--tap) + .6rem); padding: .15rem .35rem; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--control); color: var(--fg1); transition: border-color .12s; }
.strip-cell:hover { border-color: var(--control-edge-hover); }
.strip-cell small { color: var(--muted); font-size: var(--t-micro); line-height: 1.4; font-variant-numeric: tabular-nums; }

/* Their access, beside the record. */
.access-block { display: grid; gap: .45rem; }
.access-block + .access-block { margin-top: .8rem; padding-top: .75rem; border-top: 1px solid var(--line); }
.access-line { display: flex; flex-wrap: wrap; align-items: center; gap: .3rem .45rem; margin: 0; color: var(--fg2); font-size: var(--t-small); line-height: 1.75; }
.access-note { margin: 0; color: var(--muted); font-size: var(--t-meta); line-height: 1.7; }
.access-change > summary { justify-self: start; font-size: var(--t-small); }
.access-change[open]:not([data-modal-ready]) { padding: .75rem; }

/* A phone (and a narrow window): each report row is the name and its verb,
   then the three numbers each saying what it is; a student's facts stack. */
@media (max-width: 44rem) {
  .report-head { display: none; }
  .report-row { grid-template-columns: repeat(3, minmax(0, 1fr)) auto; grid-template-areas: "who who who note" "prog grade abs note"; row-gap: .3rem; padding-block: .55rem; }
  .report-who { grid-area: who; }
  .report-prog { grid-area: prog; }
  .report-grade { grid-area: grade; }
  .report-abs { grid-area: abs; }
  .report-notes { grid-area: note; align-self: start; }
  .report-num { flex-wrap: wrap; gap: 0 .4rem; }
  .report-num > b { min-inline-size: 0; }
  .report-num .cell-lbl { position: static; flex-basis: 100%; inline-size: auto; block-size: auto; margin: 0; overflow: visible; clip: auto; color: var(--muted); font-size: var(--t-micro); }
  .report-num .meter { max-inline-size: 2.75rem; }
  .standing { grid-template-columns: minmax(0, 1fr); }
  .standing-fact { border-inline-start: 0; border-top: 1px solid var(--line); }
  .standing-fact:first-child { border-top: 0; }
  .mark-row { grid-template-columns: minmax(0, 1fr) auto; }
  .mark-bar { display: none; }
  .mark-state { grid-column: 1 / -1; }
  .note-form { grid-template-columns: minmax(0, 1fr); }
  .note-form .btn-primary { justify-self: start; }
  .roster-search { flex-basis: 100%; max-width: none; }
}

/* ══════════════════════════════════════════════════════════════════════════
   ASSESSMENTS (proposal 04, ADR-0028). «ارزیابی‌ها» read assessment by
   assessment — a row each: its kind, its state (the shared pill), its day
   and its class's progress (the shared stacked bar), and while papers wait a
   door to them beside the row's link — and student by student, the gradebook
   under one card for the class. The doors to marking are one control in two
   sizes: the class's, the page's fill at the reading bar's end, and a row's,
   white. The marking panel's own rules sit with the marking page above.
   ══════════════════════════════════════════════════════════════════════════ */

/* The reading bar's end: the one create control, and the class's door. */
.reading-bar-end .go { margin-top: 0; }
/* A class with nothing yet: creating is the only thing to do, so it is the
   page's fill (`.btn-primary`'s face on the dialog's summary). */
.create-panel.is-primary > summary { border-color: var(--primary-fill); background: var(--primary-fill); box-shadow: none; color: var(--on-accent); font-weight: 600; }
.create-panel.is-primary > summary:hover { border-color: var(--primary-fill-hover); background: var(--primary-fill-hover); color: var(--on-accent); }
.marking-door { gap: .45rem; }
/* The Teaching home's door ends «در انتظار شما»'s head (T1 §3.3); white
   while another is the fill, its count then in the ink of the words. */
.sect-hd > .marking-door { flex: none; margin-top: 0; margin-inline-start: auto; }
.go:not(.is-primary) > .marking-door-count { background: var(--chip); color: var(--fg); }
.marking-door-count { display: inline-flex; align-items: center; justify-content: center; min-inline-size: 1.5rem; padding: .02rem .45rem .08rem; border-radius: var(--pill); background: var(--on-accent); color: var(--primary-fill); font-size: var(--t-micro); font-weight: 600; line-height: 1.6; font-variant-numeric: tabular-nums; }

/* Every class's list: which class, then the kinds. The button keeps its own
   height beside the select instead of stretching to the label's. */
.work-filter { align-items: end; margin: 0 0 .9rem; }
/* The kinds as sub-tabs, each with its icon; the count a pill. */
.work-kinds .tab svg { inline-size: 16px; block-size: 16px; }

/* A row: the link is the assessment and the door sits beside it, in one
   `.work-item` — the link's own attributes are the tests' hooks (J30). The
   door's column is kept on every row, door or not, so the bars line up down
   the list. */
.teacher-list > .work-item { display: grid; grid-template-columns: minmax(0, 1fr) 7.75rem; align-items: center; gap: .5rem; min-height: 0; padding: 0; border-bottom: 1px solid var(--line); transition: none; }
.teacher-list > .work-item:last-child { border-bottom: 0; }
.work-row { display: grid; grid-template-columns: 2rem minmax(0, 1fr) 11.5rem; align-items: center; column-gap: .8rem; min-height: 3.75rem; padding: .5rem .55rem; border-radius: var(--r-sm); color: var(--fg1); transition: background-color .12s; }
.work-row:hover { background: var(--hover); }
.work-row:focus-visible { outline: 2px solid var(--blue); outline-offset: -2px; }
/* The row the last paper came from, when the marker lands back on the list. */
.work-item:target .work-row { background: var(--aqua-tint); }
.work-kind { display: inline-grid; place-items: center; inline-size: 2rem; block-size: 2rem; border-radius: var(--r-sm); background: var(--chip); color: var(--fg2); }
.work-kind svg { inline-size: 16px; block-size: 16px; }
.work-copy { display: flex; flex-direction: column; gap: .15rem; min-width: 0; }
.work-title { display: flex; align-items: center; gap: .5rem; min-width: 0; }
.work-title strong { min-width: 0; color: var(--ink); }
.work-title .state-pill { flex-shrink: 0; }
.work-copy small { color: var(--muted); }
.work-progress { display: flex; flex-direction: column; gap: .35rem; min-width: 0; }
.work-progress small { color: var(--muted); font-size: var(--t-meta); font-variant-numeric: tabular-nums; white-space: nowrap; }
.work-progress small strong { overflow: visible; color: var(--fg1); font-weight: 600; }
.work-progress .work-note { line-height: 1.6; white-space: normal; }
.go.work-door { justify-self: end; margin: 0; margin-inline-end: .55rem; padding-inline: .75rem; }
.work-done { margin: 0 0 .75rem; }
.teacher-list > .empty { display: grid; justify-items: center; gap: .35rem; padding: 2.25rem 1.25rem; border: 0; }
.teacher-list > .empty p + p { max-inline-size: 34rem; }

/* The aside: facts, not places — the nearest deadline and the key. */
.work-due { display: flex; flex-wrap: wrap; align-items: baseline; gap: .15rem .45rem; margin: 0; color: var(--fg1); font-size: var(--t-small); }
.work-due small { color: var(--muted); font-size: var(--t-meta); }
.aside-inner .work-due + .calm-state { margin-top: .6rem; font-size: var(--t-small); }
.work-key .chart-key { display: grid; gap: .4rem; margin: 0; font-size: var(--t-meta); }

/* The create dialog: the kind as three explained choices (a radio each, its
   card the label), the title, and what happens next in one line. */
.kind-choices { display: grid; gap: .5rem; min-inline-size: 0; margin: 0; padding: 0; border: 0; }
.kind-choices legend { margin-bottom: .5rem; padding: 0; color: var(--fg2); font-size: var(--t-small); font-weight: 600; }
.kind-choice { display: grid; grid-template-columns: auto 2.25rem minmax(0, 1fr); align-items: center; gap: .75rem; min-height: var(--tap); padding: .6rem .8rem; border: 1px solid var(--line-2); border-radius: var(--r-sm); background: var(--control); cursor: pointer; transition: border-color .12s, background-color .12s; }
.kind-choice:hover { border-color: var(--control-edge-hover); }
.kind-choice:has(input:checked) { border-color: var(--blue); background: var(--primary-tint); }
.kind-choice:has(input:focus-visible) { box-shadow: var(--ring); }
.kind-choice input { inline-size: 1.1rem; block-size: 1.1rem; margin: 0; }
.kind-choice .work-kind { inline-size: 2.25rem; block-size: 2.25rem; }
.kind-choice:has(input:checked) .work-kind { background: var(--surface); color: var(--blue); }
.kind-choice strong { display: block; color: var(--ink); font-size: var(--t-body); font-weight: 600; }
.kind-choice small { display: block; color: var(--muted); font-size: var(--t-meta); line-height: 1.7; }
.create-note { display: flex; align-items: flex-start; gap: .5rem; margin: 0; padding: .6rem .75rem; border-radius: var(--r-sm); background: var(--sunk); color: var(--fg2); font-size: var(--t-meta); line-height: 1.8; }
.create-note svg { flex: none; margin-top: .25rem; color: var(--muted); }

/* The gradebook's summary: the class in one card — its average (a figure,
   not a hero), its shape (`ui::hist`, ten bins read by their shape, the mean
   across them) and two lines of facts, all about the class. */
.gb-summary { display: grid; grid-template-columns: auto minmax(10rem, 15.5rem) minmax(0, 1fr); align-items: center; gap: .75rem 2rem; margin: 0 0 .55rem; padding: .8rem 1.1rem; border: 1px solid var(--line); border-radius: var(--r); background: var(--surface); }
.gb-figure { display: flex; flex-direction: column; gap: .05rem; }
.gb-label { color: var(--muted); font-size: var(--t-meta); font-weight: 600; }
.gb-figure strong { color: var(--ink); font-size: var(--t-sub); font-weight: 600; line-height: 1.35; font-variant-numeric: tabular-nums; }
.gb-dist { display: grid; gap: .3rem; min-width: 0; margin: 0; }
.gb-dist figcaption { display: flex; align-items: center; gap: .35rem; color: var(--muted); font-size: var(--t-meta); font-weight: 600; }
.gb-dist figcaption svg { inline-size: 14px; block-size: 14px; color: var(--faint); }
.gb-none { color: var(--muted); font-size: var(--t-small); }
.gb-facts { display: grid; gap: .3rem; min-width: 0; color: var(--fg2); font-size: var(--t-small); }
.gb-facts p { display: flex; flex-wrap: wrap; align-items: center; row-gap: .2rem; margin: 0; }
.gb-facts strong { margin-inline-end: .25rem; color: var(--ink); font-weight: 600; font-variant-numeric: tabular-nums; }
/* The key to the cells, and what a click does. */
.gb-legend { display: flex; flex-wrap: wrap; align-items: center; gap: .3rem 1.1rem; margin: 0 0 .6rem; color: var(--muted); font-size: var(--t-meta); }
.gb-key { display: inline-flex; align-items: center; gap: .35rem; }
.gb-key::before { content: ""; inline-size: .45rem; block-size: .45rem; border-radius: 50%; background: currentColor; }
.gb-key.is-pending { color: var(--amber); font-weight: 600; }
.gb-key.is-returned::before { background: var(--red); }
.gb-key.is-empty::before { content: "—"; inline-size: auto; block-size: auto; border-radius: 0; background: none; color: var(--faint); }

/* A narrow list: between 62rem and 69rem the sidebar and the aside both stand
   beside it, so the bar goes under the title. */
@media (max-width: 69rem) {
  .work-row { grid-template-columns: 2rem minmax(0, 1fr); row-gap: .5rem; }
  .work-progress { grid-column: 2; max-inline-size: 24rem; }
}
/* A phone: the filters keep one row by their words; a row is its tile and
   title, its day, then the bar full width, and the door under it at the
   text's start. */
@media (max-width: 40rem) {
  .work-kinds .tab svg { display: none; }
  .teacher-list > .work-item { grid-template-columns: minmax(0, 1fr); gap: 0; padding-bottom: .5rem; }
  .work-title { flex-wrap: wrap; row-gap: .15rem; }
  .teacher-list .work-title strong { white-space: normal; }
  .work-progress { max-inline-size: none; }
  .go.work-door { justify-self: start; margin: 0; margin-inline-start: calc(2rem + .8rem + .55rem); }
  .gb-summary { grid-template-columns: auto minmax(0, 1fr); gap: .6rem 1.2rem; padding: .75rem .85rem; }
  .gb-facts { grid-column: 1 / -1; }
  .gradebook th:first-child { inline-size: 9rem; min-width: 9rem; max-inline-size: 9rem; }
  /* Only the name sticks sideways on a phone; the head row still sticks. */
  .gradebook td.gb-avg { position: static; box-shadow: none; }
  .gradebook thead th:nth-child(2) { position: sticky; inset-inline-start: auto; box-shadow: none; z-index: 2; }
}
@media (forced-colors: active) {
  .marking-door-count { forced-color-adjust: none; background: Canvas; color: CanvasText; }
  .kind-choice:has(input:checked) { outline: 2px solid Highlight; }
}

/* ══════════════════════════════════════════════════════════════════════════
   «ارتباطات» (proposals 08, 09, ADR-0029) and a student's «پیام‌ها»
   (proposal S5). The teacher's messages are an inbox grouped by what each
   student asks of her — waiting on her answer in amber, a bar, a dot and a
   count; the conversations she answered last, ticked sent or seen; the rest
   of the class by name — and a thread that opens at its new messages and
   says who reads the reply. A student's inbox is the same workspace: a
   teacher's unread word is her amber, her own last word is ticked, and her
   thread has the same head and composer. Announcements are a card of what
   was said to everyone; a student's rows are its doors. The board's rows and
   thread live in the discussion block above.
   ══════════════════════════════════════════════════════════════════════════ */
.message-workspace { grid-template-columns: minmax(18rem, 22rem) minmax(0, 1fr); }
/* The search leads the rail and stays with it; Enter submits, and it reads
   every student, whatever group they stand in. */
.message-workspace .message-search { position: sticky; inset-block-start: 0; z-index: 2; display: block; padding: .6rem .6rem .55rem; border-bottom: 1px solid var(--line); background: var(--sunk); }
.message-search-field { position: relative; display: block; }
.message-search-field > svg { position: absolute; inset-block-start: 50%; inset-inline-start: .75rem; transform: translateY(-50%); color: var(--faint); pointer-events: none; }
.message-search-field .input { width: 100%; padding-inline-start: 2.2rem; }
.conversation-group { display: flex; align-items: center; gap: .45rem; margin: 0; padding: .8rem .85rem .3rem; color: var(--muted); font-size: var(--t-micro); font-weight: 600; line-height: 1.6; }
.conversation-group .badge-warn, .conversation-group .badge-total { margin-inline-start: auto; }
.conversation-group.is-waiting { color: var(--amber); }
.conversation-group.is-waiting::before { content: ""; flex: none; inline-size: .45rem; block-size: .45rem; border-radius: 50%; background: currentColor; }
.message-workspace .conversation-row { min-height: 4rem; }
.message-workspace .conversation-row.is-waiting { border-inline-start-color: var(--amber); }
.message-workspace .conversation-row.is-active { border-inline-start-color: var(--blue); background: var(--primary-tint); }
/* A face is the name's first letter on the gold tint, not one icon on every
   row. */
.message-workspace .conversation-avatar { flex-shrink: 0; font-size: var(--t-small); font-weight: 600; line-height: 1; }
.message-workspace .conversation-title time { flex-shrink: 0; color: var(--faint); font-size: var(--t-micro); }
.message-workspace .conversation-preview { display: flex; align-items: center; gap: .3rem; }
.message-workspace .conversation-preview > .preview-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.message-workspace .conversation-row.is-waiting .conversation-preview { color: var(--fg2); }
/* What is new from a student waits on the teacher: amber, not a green disc. */
.message-workspace .unread-count { background: var(--amber-tint); color: var(--amber); }
/* The ticks every messenger draws: sent, then seen. */
.msg-receipt { display: inline-flex; align-items: center; gap: .2rem; flex-shrink: 0; color: var(--faint); font-size: var(--t-micro); }
.msg-receipt svg { inline-size: 14px; block-size: 14px; }
.msg-receipt.is-seen { color: var(--aqua); }
.bubble footer .msg-receipt { margin-inline-start: .1rem; }
.others-hint { margin: 0; padding: .2rem .85rem .9rem; color: var(--muted); font-size: var(--t-meta); line-height: 1.8; }
.others-hint .quiet-link { display: inline-flex; align-items: center; min-block-size: var(--tap); font-size: var(--t-meta); }
.message-workspace .calm-state { margin: .65rem .6rem .15rem; font-size: var(--t-small); }
/* The thread: who, that it is private, and whether the last word was seen. */
.message-workspace .conversation-head p { display: flex; align-items: center; flex-wrap: wrap; gap: .3rem; }
.message-workspace .conversation-head .conversation-avatar { flex-shrink: 0; }
.conversation-private { display: inline-flex; align-items: center; gap: .25rem; }
.conversation-private svg, .composer-note svg { flex: none; inline-size: 12px; block-size: 12px; }
.message-back svg { flex: none; }
/* One row at every width, the button at the field's foot and its own
   height, and under it who reads the message. */
.message-workspace .message-detail .composer > div { grid-template-columns: minmax(0, 1fr) auto; align-items: end; }
.composer-note { display: flex; align-items: center; gap: .35rem; margin-top: .4rem; color: var(--faint); font-size: var(--t-micro); }
.message-empty-icon.is-waiting { background: var(--amber-tint); color: var(--amber); }
.inbox-next p { line-height: 1.85; }
/* What was said to the whole class, newest first. */
.announce-board .announcement-list { padding: 0 .45rem .3rem; }
.announce-board .announcement { display: block; padding: .9rem .6rem; border-bottom: 1px solid var(--line); }
.announce-board .announcement:last-child { border-bottom: 0; }
.announce-top { display: flex; align-items: baseline; justify-content: space-between; gap: 1rem; }
.announce-top h3 { margin: 0; color: var(--ink); font-size: var(--t-lead); font-weight: 600; }
.announce-top time { flex-shrink: 0; color: var(--faint); font-size: var(--t-meta); }
.announce-board .announcement p { margin-top: .25rem; line-height: 1.85; }
.announce-audience { display: flex; align-items: center; gap: .45rem; margin: 0 0 .9rem; padding: .6rem .75rem; border-radius: var(--r-sm); background: var(--sunk); color: var(--fg2); font-size: var(--t-small); }
.announce-audience svg { flex: none; color: var(--muted); }
/* A student's announcements are doors (proposal S5): the whole row is the
   link, as a topic, a poll or a roster row is — the class it came from
   first, «تازه» and the fresh topic's bar while unread, then the title and
   the day, the text, and where it leads in words. */
.announce-board a.announcement { position: relative; border-inline-start: 3px solid transparent; color: var(--fg1); transition: background-color .12s ease; }
.announce-board a.announcement.is-unread { border-inline-start-color: var(--blue); }
.announce-board a.announcement:hover { background: var(--hover); }
.announce-board a.announcement:hover .announce-top h3 { color: var(--blue); }
.announce-class { display: flex; align-items: center; gap: .45rem; margin: 0 0 .2rem; color: var(--faint); font-size: var(--t-meta); }
.announce-class bdi { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.announce-door { display: inline-flex; align-items: center; gap: .3rem; margin-top: .4rem; color: var(--blue); font-size: var(--t-meta); font-weight: 500; }
/* The switch of «پیام‌ها» says what is new in each reading, a count beside
   its name. */
.view-switch a > .badge-warn, .view-switch a > .badge-total { margin-inline-start: .15rem; }
/* On a narrow phone its two cells (about 164px at 360) keep the icon, the
   name and the count on one line by giving up some of their padding — both
   cells alike, so they stay equal. */
@media (max-width: 30rem) {
  .view-switch:has(> a > .badge-warn, > a > .badge-total) a { gap: .3rem; padding-inline: .45rem; }
}
/* A paused class's thread: the composer's place says why nothing can be
   sent. */
.message-detail .composer-paused { position: sticky; inset-block-end: 0; display: flex; align-items: center; gap: .45rem; margin: 0; padding: .8rem .9rem; border-top: 1px solid var(--line); background: var(--sunk); color: var(--muted); font-size: var(--t-small); line-height: 1.7; }
.composer-paused svg { flex: none; inline-size: 14px; block-size: 14px; }
@media (max-width: 40rem) {
  .announce-top { flex-direction: column; gap: .1rem; }
}

/* ══════════════════════════════════════════════════════════════════════════
   «رأی‌گیری» (proposal 10, ADR-0029), the fourth reading of «ارتباطات». A
   row says where its poll stands — the lifecycle pill, one time fact, and
   once it has been open who answered, over a meter; one short dialog makes a
   poll, the question and its options first and the rest folded under words
   that say what it is set to; a poll's page is its result. The pill, the
   meter and the tally's bars are the shared figures below.
   ══════════════════════════════════════════════════════════════════════════ */
/* A row: the question over its state and time, who answered at its end, the
   chevron. The whole row is the door; the meters line up at its end. */
.polls-board .poll-row { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; align-items: center; gap: .45rem 1.1rem; min-height: 4rem; padding: .7rem .6rem; }
.poll-row-main { display: flex; flex-direction: column; gap: .3rem; min-width: 0; }
.polls-board .poll-row-main strong { color: var(--ink); line-height: 1.6; }
.poll-row-meta { display: flex; flex-wrap: wrap; align-items: center; gap: .25rem 0; color: var(--muted); font-size: var(--t-meta); }
.poll-row-meta .state-pill { margin-inline-end: .55rem; }
.poll-turnout { display: grid; justify-items: end; gap: .35rem; color: var(--muted); font-size: var(--t-meta); white-space: nowrap; font-variant-numeric: tabular-nums; }
.poll-turnout strong { color: var(--fg1); font-size: var(--t-small); font-weight: 600; }
.poll-turnout .meter { inline-size: 6.5rem; }
.poll-row-go { grid-column: 3; display: flex; color: var(--faint); }

/* The one poll form (`ui::poll_fields`), in the dialog and on a draft's page.
   Options are rows of one field each once app.js has drawn them: a number,
   the field, a way to remove it while more than two remain. */
.poll-form { gap: 1rem; }
.option-set { display: grid; gap: .45rem; min-width: 0; margin: 0; padding: 0; border: 0; }
.option-set > legend { margin-bottom: .35rem; padding: 0; }
.option-lines { display: grid; gap: .3rem; }
.field-hint { margin: 0; color: var(--muted); font-size: var(--t-meta); line-height: 1.75; }
.option-rows { display: grid; gap: .45rem; margin: 0; padding: 0; list-style: none; }
.option-row { display: grid; grid-template-columns: 1.9rem minmax(0, 1fr) auto; align-items: center; gap: .5rem; }
.option-num { display: inline-flex; align-items: center; justify-content: center; inline-size: 1.9rem; block-size: 1.9rem; border-radius: var(--r-sm); background: var(--chip); color: var(--fg2); font-size: var(--t-small); font-weight: 600; font-variant-numeric: tabular-nums; }
.option-row .icon-btn:disabled { visibility: hidden; }
.option-add { justify-self: start; }
/* «تنظیمات بیشتر»: shut, its summary says what the settings are, in words;
   open, the controls. Shut or open, they are sent — that keeps the defaults. */
.more-settings { border: 1px solid var(--line); border-radius: var(--r); background: var(--sunk); }
.more-settings > summary { display: flex; flex-wrap: wrap; align-items: center; gap: .15rem .5rem; min-height: var(--tap); padding: .5rem .85rem; border-radius: var(--r); color: var(--fg1); font-weight: 500; cursor: pointer; list-style: none; }
.more-settings > summary::-webkit-details-marker { display: none; }
.more-settings > summary .chev { display: flex; color: var(--muted); transform: rotate(90deg); transition: transform .15s var(--ease); }
.more-settings[open] > summary .chev { transform: rotate(0deg); }
.more-settings[open] > summary { border-radius: var(--r) var(--r) 0 0; }
.more-settings-now { display: flex; flex-wrap: wrap; align-items: center; flex-basis: 100%; padding-inline-start: 1.1rem; color: var(--muted); font-size: var(--t-meta); font-weight: 400; }
.more-settings[open] .more-settings-now { display: none; }
.more-settings-body { display: grid; gap: 1.15rem; padding: .9rem .9rem 1rem; border-top: 1px solid var(--line); border-radius: 0 0 var(--r) var(--r); background: var(--surface); }
.setting-group { display: grid; gap: .1rem; min-width: 0; margin: 0; padding: 0; border: 0; }
.setting-group > legend { margin-bottom: .25rem; padding: 0; color: var(--fg2); font-size: var(--t-small); font-weight: 600; }
.setting-group .field-hint { padding-inline-start: 1.6rem; }
/* The ceiling only once more than one choice is allowed (no script needed). */
.multi-max { display: none; align-items: center; gap: .6rem; padding-inline-start: 1.6rem; color: var(--fg2); font-size: var(--t-small); }
.setting-group:has(input[name="multiple"]:checked) .multi-max { display: flex; }
.poll-form-actions { margin-top: 0; }
.poll-form-note { margin: -.35rem 0 0; color: var(--muted); font-size: var(--t-meta); line-height: 1.8; }
@media (hover: hover) and (pointer: fine) { .more-settings > summary:hover { background: var(--hover); } }

/* A poll's page: the turnout over its result, which says while it is open
   that it keeps itself up to date. */
.tally > .sect-hd { flex-wrap: wrap; }
.tally-live { display: inline-flex; align-items: center; margin-inline-start: auto; color: var(--muted); font-size: var(--t-micro); }
.tally-live .live-dot { color: var(--aqua); }
.turnout-line { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: baseline; gap: .5rem 1rem; margin: 0; padding-bottom: .95rem; border-bottom: 1px solid var(--line); color: var(--fg2); }
.turnout-line strong { color: var(--ink); font-weight: 600; }
.turnout-line .meter { grid-column: 1 / -1; }
.turnout-pct { color: var(--ink); font-size: var(--t-lead); font-weight: 600; font-variant-numeric: tabular-nums; }
.turnout-line + .tally-chart { padding-top: 1rem; }
.poll-manage .sect-bd > p { margin: 0 0 .7rem; color: var(--fg2); font-size: var(--t-small); line-height: 1.8; }
.draft-options { display: grid; gap: .35rem; margin: 0; padding-inline-start: 1.2rem; }
.side-sec .rich-content { font-size: var(--t-small); line-height: 1.85; }
/* The student's page (proposal S3 §3.4): the vote as a card — the rule at
   its head, the choices, and at its foot whether it is anonymous beside the
   one fill; a recorded vote the calm line; a closed poll a neutral one. */
.poll-description { margin-bottom: 1rem; }
.poll-vote .poll-options { margin: 0; padding: 0; border: 0; background: none; }
.poll-rule { margin-inline-start: auto; color: var(--muted); font-size: var(--t-meta); white-space: nowrap; }
.poll-vote-foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .6rem 1rem; margin-top: .9rem; }
.poll-anonymous { display: inline-flex; align-items: center; gap: .4rem; margin: 0; color: var(--muted); font-size: var(--t-small); }
.poll-anonymous > svg { flex: none; inline-size: 15px; block-size: 15px; color: var(--faint); }
.poll-vote-foot .btn-primary { margin-top: 0; }
.poll-page > .calm-state { margin: 0 0 .8rem; }
.poll-closed-line { display: flex; align-items: center; gap: .5rem; min-height: var(--tap); margin: 0 0 .8rem; padding: .6rem .85rem; border-radius: var(--r-sm); background: var(--chip); color: var(--fg2); }
.poll-closed-line > svg { flex: none; inline-size: 15px; block-size: 15px; color: var(--muted); }
.poll-wait { margin: 0 0 .8rem; color: var(--muted); font-size: var(--t-small); }
@media (max-width: 40rem) {
  .poll-vote-foot .btn-primary { flex: 1 1 100%; justify-content: center; }
}
.tally-count { margin-inline-start: auto; color: var(--muted); font-size: var(--t-meta); font-variant-numeric: tabular-nums; }
@media (max-width: 40rem) {
  /* The count and its meter drop under the facts; the chevron spans both. */
  .polls-board .poll-row { grid-template-columns: minmax(0, 1fr) auto; }
  .polls-board .poll-turnout { grid-column: 1; grid-row: 2; grid-auto-flow: column; justify-content: start; align-items: center; gap: .6rem; }
  .polls-board .poll-row-go { grid-column: 2; grid-row: 1 / span 2; }
  /* The dialog's sheet: publishing takes the row, the other two share one. */
  .poll-form-actions > .btn-primary { flex: 1 1 100%; justify-content: center; }
  .poll-form-actions > .quiet-button { flex: 1 1 0; justify-content: center; }
}

/* ══════════════════════════════════════════════════════════════════════════
   SHARED: PILLS, METERS, CHARTS, MARKS (ADR-0029). One drawing of each for
   every tab (macros.html: state_pill, meter, stack_bar + stack_key, hist,
   mark + mark_legend); a tab extends them here and never forks a copy.
   Colour keeps one meaning each: gold is a quantity, amber waits on you,
   aqua is done or affirmative, red is a mark's ink and never a field. A
   figure is written out beside its drawing, which is aria-hidden. The
   gallery's `ui-kit` page shows every one in every state.
   ══════════════════════════════════════════════════════════════════════════ */

/* A lifecycle — draft, scheduled, open, closed — for assessments and polls
   alike: one word and one shape, drawn like a session's pill. */
.state-pill { display: inline-flex; align-items: center; gap: .3rem; padding: .06rem .55rem .12rem; border-radius: var(--pill); background: var(--chip); color: var(--fg2); font-size: var(--t-micro); font-weight: 600; line-height: 1.7; white-space: nowrap; vertical-align: middle; }
.state-pill > svg { inline-size: 12px; block-size: 12px; flex-shrink: 0; }
.state-pill--open { background: var(--aqua-tint); color: var(--aqua); }
.state-pill-dot { inline-size: .45rem; block-size: .45rem; border-radius: 50%; background: currentColor; flex-shrink: 0; }

/* A thin meter: one share of its whole, gold on the chip. It takes its
   box's width. */
.meter { display: block; inline-size: 100%; block-size: 6px; border-radius: var(--pill); background: var(--chip); overflow: hidden; }
.meter > i { display: block; block-size: 100%; border-radius: var(--pill); background: var(--accent); }

/* A poll's result (`ui::poll_tally`): one bar an option on the chip's track,
   the label and its figures on the line above — the share in ink, the people
   muted, tabular so they align. The most chosen is the full gold and says so
   in words; the rest a lighter step of the same gold. */
.tally-chart { display: grid; gap: 1.05rem; margin: 0; padding-top: .3rem; }
.tally-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; grid-template-areas: "label value" "bar bar"; align-items: end; gap: .4rem 1rem; }
.tally-label { grid-area: label; display: flex; flex-wrap: wrap; align-items: center; gap: .25rem .5rem; min-width: 0; color: var(--fg1); line-height: 1.65; }
.tally-value { grid-area: value; display: inline-flex; align-items: baseline; gap: .45rem; white-space: nowrap; font-variant-numeric: tabular-nums; }
.tally-value strong { color: var(--ink); font-size: var(--t-lead); font-weight: 600; }
.tally-value span { color: var(--muted); font-size: var(--t-meta); }
.tally-bar { grid-area: bar; display: block; block-size: .6rem; border-radius: var(--pill); background: var(--chip); overflow: hidden; }
.tally-bar > i { display: block; block-size: 100%; border-radius: var(--pill); background: color-mix(in srgb, var(--accent) 50%, var(--content)); }
.tally-row.is-leading .tally-bar > i { background: var(--accent); }
.tally-row.is-leading .tally-label > bdi { color: var(--ink); font-weight: 600; }
.tally-lead { display: inline-flex; align-items: center; padding: 0 .5rem .06rem; border-radius: var(--pill); background: var(--accent-tint); color: var(--accent-ink); font-size: var(--t-micro); font-weight: 600; line-height: 1.8; white-space: nowrap; }
.tally-note { margin: .85rem 0 0; color: var(--muted); font-size: var(--t-meta); line-height: 1.8; }
/* The student's own choices, on their page: the primary's quiet chip. */
.tally-mine { display: inline-flex; align-items: center; padding: 0 .5rem .06rem; border-radius: var(--pill); background: var(--primary-tint); color: var(--blue); font-size: var(--t-micro); font-weight: 600; line-height: 1.8; white-space: nowrap; }

/* One whole in its parts: done, waiting on you, and the rest (the track).
   Segments part by a 2px gap of the surface; each keeps 3px, so a sliver is
   still seen. */
.stack-bar { display: flex; block-size: 6px; border-radius: var(--pill); background: var(--line); overflow: hidden; }
.stack-bar > i { display: block; flex: none; block-size: 100%; min-inline-size: 3px; }
.stack-bar > i + i { border-inline-start: 2px solid var(--surface); }
.stack-bar > .is-done { background: var(--aqua); }
.stack-bar > .is-waiting { background: var(--amber); }

/* A chart's key: a swatch and a word for each mark the chart uses. */
.chart-key { display: flex; flex-wrap: wrap; align-items: center; gap: .25rem 1rem; margin: .6rem 0 0; color: var(--muted); font-size: var(--t-meta); }
.chart-key > span { display: inline-flex; align-items: center; gap: .4rem; }
.chart-key i { display: inline-block; flex: none; inline-size: 1.1rem; block-size: 6px; border-radius: var(--pill); background: var(--line); }
.chart-key .key-done { background: var(--aqua); }
.chart-key .key-waiting { background: var(--amber); }
.chart-key .key-bar { inline-size: 10px; block-size: 10px; border-radius: 2px; background: var(--accent); }
.chart-key .key-owed { inline-size: 12px; block-size: 9px; border: 1px dashed var(--amber); border-bottom: 0; border-radius: 0; background: none; }
.chart-key .key-today { inline-size: 8px; block-size: 8px; border-radius: 50%; background: var(--blue); }
.chart-key .key-ahead { inline-size: 12px; block-size: 2px; border-radius: 0; background: var(--bg3); }

/* Columns on one baseline — a distribution's bins, or a term's sessions:
   one series in gold, its count on the cap, its name under the line. A
   height is a share of the tallest slot (charts::Hist::heights). */
.hist-fig { --hist-h: 4.25rem; --hist-cap: 1.15rem; position: relative; }
.hist { display: flex; align-items: stretch; gap: 2px; margin: 0; padding: 0; list-style: none; }
.hist-slot { display: flex; flex: 1 1 0; flex-direction: column; align-items: center; min-inline-size: 0; }
.hist-plot { display: flex; align-items: flex-end; justify-content: center; inline-size: 100%; block-size: var(--hist-h); padding-top: var(--hist-cap); border-bottom: 1px solid var(--line-2); }
.hist-plot > i { position: relative; display: block; inline-size: min(1.5rem, 64%); block-size: max(2px, var(--v, 0%)); border-radius: 4px 4px 0 0; background: var(--accent); }
.hist-plot > i > b { position: absolute; z-index: 1; inset-block-end: calc(100% + 2px); inset-inline: -.75rem; background: var(--surface); color: var(--fg2); font-size: var(--t-micro); font-style: normal; font-weight: 600; line-height: 1.25; text-align: center; font-variant-numeric: tabular-nums; white-space: nowrap; }
.hist-name { margin-top: .3rem; color: var(--muted); font-size: var(--t-micro); line-height: 1.35; text-align: center; white-space: nowrap; }
.hist-axis { display: flex; justify-content: space-between; margin-top: .2rem; color: var(--muted); font-size: var(--t-micro); font-variant-numeric: tabular-nums; }
/* The mean: one ink hairline across the bars, where it falls on the axis. */
.hist-mean { position: absolute; inset-block-start: var(--hist-cap); inset-inline-start: var(--m); inline-size: 1px; block-size: calc(var(--hist-h) - var(--hist-cap)); background: var(--fg2); }
/* Dense: ten bins edge to edge, read by their shape, no figures on the caps. */
.hist-fig--dense { --hist-h: 2.6rem; --hist-cap: 0rem; }
.hist-fig--dense .hist-plot > i { inline-size: 100%; border-radius: 2px 2px 0 0; }
/* A term's sessions: a roll still owed is unfinished (dashed) and waits on
   you (amber); today is the primary's dot; what is ahead, a faint tick. */
.hist-slot.is-owed .hist-plot > i { block-size: 14px; border: 1px dashed var(--amber); border-bottom: 0; background: none; }
.hist-slot.is-owed :is(b, .hist-name) { color: var(--amber); }
.hist-slot.is-today .hist-plot > i { inline-size: 8px; block-size: 8px; margin-block-end: 3px; border-radius: 50%; background: var(--blue); }
.hist-slot.is-today .hist-name { color: var(--blue); font-weight: 600; }
.hist-slot.is-ahead .hist-plot > i { block-size: 2px; border-radius: 0; background: var(--bg3); }
.hist-slot.is-ahead .hist-name { color: var(--faint); }
/* A slot's second line (`Bin.note`): a session's date while its column has
   room for the widest («۲۸ شهریور», 49px at the 12px floor of --t-micro)
   and some air — twelve columns in a narrow card, or a phone, have not —
   and «امروز», which always stays. The slot is the container, so the rule
   follows the column, not the window; px, since the face is a px floor. */
.hist-slot:has(> .hist-name > small) { container-type: inline-size; }
.hist-name > small { display: block; color: var(--faint); font-size: var(--t-micro); font-weight: 400; }
.hist-slot.is-today .hist-name > small { color: var(--blue); font-weight: 600; }
.hist-slot.is-owed .hist-name > small { color: var(--amber); }
@container (max-width: 56px) { .hist-slot:not(.is-today) .hist-name > small { display: none; } }

/* A column of a chart standing in a table's header (the register's share of
   the class that came): gold on its lighter track from a hairline baseline.
   A roll still owed is a dashed amber slot — unfinished, waiting on you. */
.vbar { position: relative; display: block; inline-size: .875rem; block-size: 2.4rem; margin-block-end: .15rem; overflow: hidden; border-radius: 4px 4px 0 0; background: var(--accent-tint); box-shadow: 0 1px 0 var(--line-2); }
.vbar > i { position: absolute; inset-inline: 0; inset-block-end: 0; display: block; block-size: var(--v, 0%); border-radius: 4px 4px 0 0; background: var(--accent); }
.vbar.is-owed { border: 1px dashed color-mix(in srgb, var(--amber) 55%, var(--content)); border-block-end: 0; background: none; box-shadow: 0 1px 0 color-mix(in srgb, var(--amber) 55%, var(--content)); }

/* A term at a glance: one segment a session in date order (the first on the
   right), its state in shape as well as colour — held filled gold, today the
   primary and taller, a roll owed an amber outline on its tint, cancelled
   struck through in red, ahead an empty slot whose edge keeps 3:1. A word
   sits over a month's first session and over today's; the key under the
   track says every state with its count. */
.term-strip { padding: .75rem 1rem .85rem; }
.term-hd { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: .2rem 1rem; }
.term-hd h2 { margin: 0; font-size: var(--t-lead); font-weight: 600; color: var(--ink); }
.term-pos { font-size: var(--t-small); color: var(--muted); }
.term-pos strong { font-weight: 600; color: var(--ink); }
.term-track { display: flex; align-items: flex-end; gap: 3px; margin: 1.55rem 0 0; }
.term-slot { position: relative; display: flex; flex: 1 1 0; min-inline-size: 4px; max-inline-size: 5.5rem; }
.term-seg, .term-sw { display: block; border-radius: 4px; background: var(--surface); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--fg3) 70%, var(--content)); }
.term-seg { inline-size: 100%; block-size: 10px; }
.term-sw { flex-shrink: 0; inline-size: 16px; block-size: 8px; }
.term-slot.is-held > .term-seg, .term-sw.is-held { background: var(--accent); box-shadow: none; }
.term-slot.is-today > .term-seg, .term-sw.is-today { background: var(--blue); box-shadow: none; }
.term-slot.is-today > .term-seg { block-size: 16px; }
.term-slot.is-owed > .term-seg, .term-sw.is-owed { background: var(--amber-tint); box-shadow: inset 0 0 0 2px var(--amber); }
.term-slot.is-cancelled > .term-seg, .term-sw.is-cancelled { background: linear-gradient(var(--red), var(--red)) center / 100% 2px no-repeat, var(--surface); }
.term-mark { position: absolute; inset-block-end: calc(100% + .3rem); inset-inline-start: 0; font-size: var(--t-micro); line-height: 1.2; white-space: nowrap; color: var(--muted); }
.term-slot.is-today > .term-mark { color: var(--blue); font-weight: 600; }
.term-legend { display: flex; flex-wrap: wrap; gap: .3rem 1.1rem; margin: .8rem 0 0; padding: 0; list-style: none; font-size: var(--t-small); color: var(--fg2); }
.term-legend li { display: inline-flex; align-items: center; gap: .4rem; }
.term-legend strong { font-weight: 600; color: var(--ink); font-variant-numeric: tabular-nums; }
.term-legend li.is-waiting, .term-legend li.is-waiting strong { color: var(--amber); font-weight: 600; }

/* An attendance mark: the shape carries the state and only the exceptions
   take a colour; an absence is the cross's red ink, never a red field. */
.att-mark { display: inline-flex; align-items: center; justify-content: center; min-inline-size: 16px; color: var(--muted); vertical-align: middle; }
.att-mark > svg { inline-size: 15px; block-size: 15px; }
.att-mark--1 { color: var(--red); }
.att-mark--1 > svg { stroke-width: 2.6; }
.att-mark--2 { color: var(--amber); }
.att-mark--3 { color: var(--blue); }
.att-mark--none { color: var(--faint); }
.mark-legend { display: flex; flex-wrap: wrap; align-items: center; gap: .3rem 1rem; margin: 0; padding: 0; list-style: none; color: var(--fg2); font-size: var(--t-small); }
.mark-legend li { display: inline-flex; align-items: center; gap: .3rem; }

/* Forced colours: the bars keep their lengths and their parts. */
@media (forced-colors: active) {
  .meter, .stack-bar, .tally-bar, .hist-plot > i, .chart-key i { forced-color-adjust: none; }
  .meter, .stack-bar, .tally-bar { background: Canvas; outline: 1px solid CanvasText; }
  .meter > i, .tally-bar > i, .stack-bar > .is-done, .hist-plot > i, .chart-key .key-done, .chart-key .key-bar { background: CanvasText; }
  .tally-row.is-leading .tally-bar > i { background: Highlight; }
  .vbar, .term-seg, .term-sw { forced-color-adjust: none; }
  .vbar { background: Canvas; outline: 1px solid CanvasText; }
  .vbar > i, .term-slot.is-held > .term-seg, .term-sw.is-held { background: CanvasText; }
  .term-slot.is-today > .term-seg, .term-sw.is-today { background: Highlight; }
  .term-seg, .term-sw { box-shadow: inset 0 0 0 1px CanvasText; }
  .stack-bar > .is-waiting, .chart-key .key-waiting { background: Highlight; }
  .hist-slot.is-owed .hist-plot > i, .chart-key .key-owed { background: none; border-color: CanvasText; }
}

/* ══════════════════════════════════════════════════════════════════════════
   A CLASS'S SETTINGS (proposal 05, ADR-0029) — a page below the class that
   the header's door opens, like a session's edit form below the session: one
   readable column at the start edge, no strip, no aside. A card each for what
   students can see and do, who teaches the class, its name and dates, the
   note to students and which sections they see; then, apart, the archive
   box. Every card spans the column (`#staff` is the LU `class-staff`).
   ══════════════════════════════════════════════════════════════════════════ */
.set-cols > .col-main { inline-size: 100%; max-inline-size: 52rem; }
/* An assistant's notice spans the column like the cards under it. */
.set-cols .notice { max-width: none; margin: 0 0 1rem; }
.set-card { max-width: none; }
.set-card-hd { display: flex; align-items: flex-start; gap: .7rem; }
.set-card-hd h2 { display: flex; flex-wrap: wrap; align-items: center; gap: .45rem; margin: 0; font-size: var(--t-section); line-height: 1.6; color: var(--ink); }
.set-card-hd .section-help { margin: 0; }
/* A card's tile takes the class's hue, as the class home's glance does. */
.set-ico { display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; inline-size: 2.15rem; block-size: 2.15rem; border-radius: var(--r-sm); background: rgba(var(--class-accent-rgb), .09); color: var(--class-accent); }
.set-ico--quiet { background: var(--chip); color: var(--fg2); }

/* What students can see and do: three rows in lifecycle order, each saying
   it in words — a no is in the text («نمی‌بینند»), the mark only repeats it.
   The class's own state is lifted (a tint and a hairline: a line, not a
   shadow); the others carry the verb that moves the class there. */
.state-rows { margin-top: .75rem; }
.state-row { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: .35rem .85rem; min-height: var(--tap); padding: .7rem .65rem; border-bottom: 1px solid var(--line); }
.state-row:last-child, .state-row:has(+ .state-row.is-current) { border-bottom-color: transparent; }
.state-row.is-current { border-bottom-color: transparent; border-radius: var(--r-sm); background: var(--primary-tint); box-shadow: 0 0 0 1px var(--primary-edge); }
.state-ico { display: inline-flex; align-items: center; justify-content: center; inline-size: 2.15rem; block-size: 2.15rem; border-radius: 50%; background: var(--chip); color: var(--fg2); }
.state-row.is-current .state-ico { background: var(--surface); color: var(--blue); box-shadow: 0 0 0 1px var(--primary-edge); }
.state-main { display: flex; flex-direction: column; gap: .2rem; min-width: 0; }
.state-name { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; font-size: var(--t-lead); font-weight: 600; color: var(--fg0); }
.state-now { display: inline-flex; align-items: center; gap: .25rem; padding: .05rem .55rem .12rem; border-radius: var(--pill); background: var(--surface); color: var(--blue); font-size: var(--t-meta); font-weight: 600; }
.state-now > svg { inline-size: 12px; block-size: 12px; }
.state-facts { display: flex; flex-wrap: wrap; gap: .15rem 1.1rem; color: var(--fg2); font-size: var(--t-small); }
.state-fact { display: inline-flex; align-items: center; gap: .3rem; }
.state-fact > svg { flex-shrink: 0; inline-size: 14px; block-size: 14px; }
.state-fact.is-yes > svg { color: var(--aqua); }
.state-fact.is-no { color: var(--muted); }
.state-fact.is-no > svg { color: var(--faint); }
.state-act { justify-self: end; }
/* A class being prepared: what it has, in the row it is about to become.
   A missing step is amber with a dot — waiting on the teacher — and the door
   to where it is done. */
.state-ready { display: flex; flex-wrap: wrap; align-items: center; gap: .1rem 1rem; margin-top: .4rem; padding-top: .45rem; border-top: 1px solid var(--line); color: var(--fg1); font-size: var(--t-small); }
.state-ready-label { color: var(--muted); font-weight: 600; }
.ready-item { display: inline-flex; align-items: center; gap: .3rem; }
.ready-item > svg { inline-size: 14px; block-size: 14px; color: var(--aqua); }
.ready-item.is-waiting { color: var(--amber); font-weight: 600; }
.ready-item.is-waiting::before { content: ""; inline-size: .45rem; block-size: .45rem; border-radius: 50%; background: currentColor; }
.state-ready .quiet-link { display: inline-flex; align-items: center; min-height: var(--tap); }
/* Archived: the card says so, once, calmly. */
.set-archived { display: flex; align-items: flex-start; gap: .6rem; margin: .75rem 0 0; padding: .7rem .8rem; border-radius: var(--r-sm); background: var(--sunk); color: var(--fg1); font-size: var(--t-small); line-height: 1.8; }
.set-archived > svg { flex-shrink: 0; margin-top: .3rem; color: var(--fg2); }
.set-archived strong { color: var(--fg0); font-weight: 600; }

/* Who teaches the class: a mark, the name with its role and login under it,
   the one act at the end; then the add; then who may do what, in two lines. */
.set-staff { margin-top: .5rem; }
.staff-row { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: .3rem .75rem; min-height: var(--tap); padding: .55rem .4rem; border-bottom: 1px solid var(--line); }
.staff-row:last-child { border-bottom: 0; }
.staff-mark { display: inline-flex; align-items: center; justify-content: center; inline-size: 2.15rem; block-size: 2.15rem; border-radius: 50%; background: var(--accent-tint); color: var(--accent-ink); font-size: var(--t-body); font-weight: 600; }
.staff-who { display: flex; flex-direction: column; gap: .15rem; min-width: 0; }
.staff-who strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--fg0); font-weight: 600; }
.staff-you { color: var(--muted); font-size: var(--t-small); font-weight: 500; }
.staff-meta { display: flex; flex-wrap: wrap; align-items: center; gap: .2rem .6rem; }
.staff-meta .chip { display: inline-flex; align-items: center; gap: .2rem; }
.staff-meta .chip > svg { inline-size: 12px; block-size: 12px; }
.staff-login { color: var(--muted); font-size: var(--t-meta); }
.staff-row > form { display: inline-flex; }
.staff-empty { margin: 0; padding: .7rem .4rem; color: var(--muted); font-size: var(--t-small); }
.staff-add { margin-top: .75rem; padding-top: .8rem; border-top: 1px solid var(--line); }
.staff-add .add-row { margin-top: .4rem; }
.staff-add .section-help { margin: .45rem 0 0; }
.set-failed { display: flex; align-items: flex-start; gap: .4rem; margin: .45rem 0 0; color: var(--red); font-size: var(--t-small); font-weight: 600; line-height: 1.8; }
.set-failed > svg { flex-shrink: 0; margin-top: .3rem; }
.staff-rights { display: grid; gap: .3rem; margin: .9rem 0 0; padding: .65rem .8rem; list-style: none; border-radius: var(--r-sm); background: var(--sunk); color: var(--fg2); font-size: var(--t-small); line-height: 1.8; }
.staff-rights li { display: flex; align-items: flex-start; gap: .5rem; }
.staff-rights svg { flex-shrink: 0; inline-size: 14px; block-size: 14px; margin-top: .3rem; }
.staff-rights .is-yes svg { color: var(--aqua); }
.staff-rights .is-key svg { color: var(--accent-ink); }

/* The name and the dates: facts read far more often than changed; the
   change is a dialog. */
.set-facts { display: grid; grid-template-columns: minmax(0, 2fr) repeat(2, minmax(0, 1fr)); gap: 0 1rem; margin: .7rem 0 0; border-top: 1px solid var(--line); }
.set-facts > div { min-width: 0; padding: .6rem .1rem; border-bottom: 1px solid var(--line); }
.set-facts dt { color: var(--muted); font-size: var(--t-meta); }
.set-facts dd { margin: .1rem 0 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--fg0); font-weight: 500; }
.set-help { margin: .6rem 0 0; }
.set-card > .set-edit { margin-top: .6rem; }
.set-edit > summary { display: inline-flex; list-style: none; cursor: pointer; }
.set-edit > summary::-webkit-details-marker { display: none; }

/* The note to students: the text as it stands, then its editor, unfolding
   in the card — the rich editor cannot sit in a dialog (docs/08). */
.set-note { margin-top: .7rem; padding: .7rem .9rem; border-radius: var(--r-sm); background: var(--sunk); }
.set-card > .staff-empty { padding-inline: 0; }
.set-card-ft { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .4rem 1rem; margin-top: .6rem; }
.set-fold[open] { flex: 1 1 100%; }

/* Which sections students see: a question and its answer on a fold, rarely
   opened — the list, or for whoever may not change it, each section in
   words. */
.set-fold-card > summary { align-items: center; min-height: var(--tap); cursor: pointer; list-style: none; }
.set-fold-card > summary::-webkit-details-marker { display: none; }
.set-fold-title { display: flex; flex: 1 1 auto; flex-wrap: wrap; align-items: center; gap: .3rem .6rem; min-width: 0; }
.set-fold-card > summary:hover h2 { color: var(--blue); }
.set-fold-card > summary .chev { flex-shrink: 0; display: flex; color: var(--muted); transition: transform .15s var(--ease); transform: rotate(90deg); }
.set-fold-card[open] > summary .chev { transform: rotate(0); }
.set-fold-body { margin-top: .75rem; }
.set-fold-body > .section-help { margin-top: 0; }
.set-sections { margin: 0; padding: 0; list-style: none; }
.set-sections li { display: flex; align-items: center; gap: .55rem; min-height: var(--tap); padding: .35rem .45rem; border-bottom: 1px solid var(--line); color: var(--fg1); }
.set-sections li:last-child { border-bottom: 0; }
.set-sections li > svg { flex-shrink: 0; }
.set-sections .is-yes > svg { color: var(--aqua); }
.set-sections .is-no > svg { color: var(--faint); }
.set-section-state { margin-inline-start: auto; color: var(--muted); font-size: var(--t-small); white-space: nowrap; }

/* The one act that cannot be undone, last, in the house's archive box. */
.set-archive { max-width: none; margin-top: 1.25rem; }
.set-archive-copy { display: flex; align-items: flex-start; gap: .7rem; min-width: 0; }
.set-archive-copy strong { display: block; color: var(--fg0); font-weight: 600; }
.set-archive-copy p { margin-top: .15rem; line-height: 1.8; }
.set-archive > .danger-button { flex-shrink: 0; white-space: nowrap; }

@media (max-width: 38rem) {
  .state-row { grid-template-columns: auto minmax(0, 1fr); }
  .state-act { grid-column: 2; justify-self: start; }
  .set-facts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .set-fact--wide { grid-column: 1 / -1; }
}

/* ══════════════════════════════════════════════════════════════════════════
   «فعالیت‌ها» (proposal S3): the student's activity list in the teacher's row
   grammar, grouped by what each row asks of them; a piece of work read by its
   phase. Amber is what waits on the student; a missed deadline or a missed
   session is a fact in ink, never red.
   ══════════════════════════════════════════════════════════════════════════ */
/* One card; the group headings are the teacher inbox's. */
.act-board > .sect-bd { padding: 0 .45rem .45rem; }
.act-board .calm-state { margin: .6rem .15rem .1rem; }
.act-board > .sect-bd > .empty { margin: .45rem 0 0; }
.act-list { display: grid; }
.act-list > .act-row:last-child { border-bottom: 0; }
/* A row: the kind on its tile, the title and its pill over a line of facts,
   the student's own state, and the verb — one door. */
.task-row.act-row { grid-template-columns: 2rem minmax(0, 1fr) minmax(8.5rem, auto) auto; column-gap: .8rem; min-height: 3.75rem; padding: .55rem; }
.act-row .task-main { gap: .2rem; }
.act-row .work-title { gap: .45rem; }
.act-row .work-title strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.act-row .task-class { display: flex; flex-wrap: wrap; align-items: center; row-gap: .1rem; color: var(--muted); }
.act-when { display: inline-flex; align-items: center; white-space: nowrap; }
.act-due.is-near { color: var(--amber); font-weight: 600; }
.act-state { display: flex; flex-wrap: wrap; align-items: center; gap: .3rem .45rem; min-width: 0; }
.act-state .grade-score { padding-block: 0 .06rem; font-size: var(--t-body); }
.work-kind.is-session { background: none; box-shadow: inset 0 0 0 1px var(--line-2); }
/* The student's own state in the roster chip's grammar: hollow for «not yet»,
   aqua once handed in, amber with the word where it waits on them, and a
   quiet dot for what is over. */
.state-chip.state-chip--todo::before { background: none; box-shadow: inset 0 0 0 1.5px var(--faint); }
.state-chip--handed { --dot: var(--aqua); }
.state-chip--waiting { --dot: var(--amber); background: var(--amber-tint); color: var(--amber); font-weight: 600; }
.state-chip--quiet { --dot: var(--bg3); color: var(--muted); }
/* «تمام‌شده» folds (docs/09 guardrail 3), its count kept on the summary. */
.act-fold { margin-top: .3rem; border-top: 1px solid var(--line); }
.act-fold > summary { min-height: var(--tap); cursor: pointer; list-style: none; }
.act-fold > summary::-webkit-details-marker { display: none; }
.act-fold > summary:hover { color: var(--blue); }
.act-fold > summary .badge-total { margin-inline-start: auto; }
.act-fold > summary .chev { display: flex; transform: rotate(90deg); transition: transform .15s var(--ease); }
.act-fold[open] > summary .chev { transform: none; }
/* The aside: the nearest deadline and the student's own figures. */
.act-next { margin: .3rem 0 0; color: var(--fg2); font-size: var(--t-small); }
.act-glance > p { margin: 0 0 .5rem; color: var(--fg2); font-size: var(--t-small); }
.act-glance strong { color: var(--ink); font-weight: 600; font-variant-numeric: tabular-nums; }
.act-glance .chart-key { display: grid; gap: .3rem; }
/* A phone: the tile and the title take the first line across the row; the
   state and the verb share the second, the verb at its end. */
@media (max-width: 38rem) {
  .task-row.act-row { grid-template-columns: 2rem minmax(0, 1fr) auto; row-gap: .45rem; align-items: center; padding: .6rem .45rem; }
  .act-row .work-kind { grid-row: 1; align-self: start; }
  .act-row .task-main { grid-column: 2 / -1; grid-row: 1; }
  .act-row .act-state { grid-column: 2; grid-row: 2; }
  .act-row .task-action { grid-column: 3; grid-row: 2; margin-inline-end: -.3rem; }
  .act-row .work-title { flex-wrap: wrap; row-gap: .15rem; }
  .act-row .work-title strong { white-space: normal; }
  .act-row .act-state:empty { display: none; }
  .act-row:has(.act-state:empty) .task-action { grid-column: 2 / -1; justify-self: end; }
}

/* A piece of work read by its phase (the session's `.phase-card`): the
   sentence, the teacher's words or the mark, and the receipt as the card's
   ruled last line. Then the brief and the answer, each a card; the one fill
   is the answer's submit. */
.work-main > .sect { margin-bottom: .8rem; }
.work-main > .sect:last-child { margin-bottom: 0; }
.work-phase .phase-note { margin-bottom: .55rem; }
.work-phase .phase-note .glance-fact { margin-inline-end: .35rem; }
.work-phase .phase-note:last-child { margin-bottom: 0; }
.teacher-note { margin: .15rem 0 0; padding: .65rem .85rem .75rem; border-radius: var(--r-sm); background: var(--sunk); }
.teacher-note figcaption { color: var(--muted); font-size: var(--t-meta); font-weight: 600; }
.teacher-note blockquote { margin: .2rem 0 0; color: var(--fg1); font-size: var(--t-read); line-height: 1.9; white-space: pre-line; }
.work-score { margin: 0 0 .6rem; }
.work-score .grade-score { font-size: var(--t-sub); }
.work-phase .phase-status { font-size: var(--t-small); }
.work-phase .ok-mark { display: inline-flex; color: var(--aqua); }
.work-phase .ok-mark svg { inline-size: 15px; block-size: 15px; }
.work-phase .phase-status > span { display: inline-flex; align-items: center; gap: .35rem; }
.sect-note { margin-inline-start: auto; color: var(--muted); font-size: var(--t-meta); white-space: nowrap; }
.work-answer .submission-form { padding: 0; border-top: 0; }
.work-answer .textarea { margin-top: 0; }
.work-answer .upload-field { margin-block: .85rem 0; }
.work-answer .form-actions { margin-top: .85rem; padding-inline-end: 0; }
.work-answer .sect-bd > .material-files { margin: 0 0 .75rem; }
.work-handed { margin: 0; color: var(--fg1); font-size: var(--t-read); line-height: 1.9; white-space: pre-wrap; overflow-wrap: anywhere; }
.work-handed + .material-files { margin-top: .6rem; }
.work-brief .material-files { margin-top: .5rem; }
.work-brief .prose, .work-brief .rich-content { padding: 0; }
details.work-brief > summary .chev { margin-inline-start: auto; }
@media (max-width: 40rem) {
  .work-answer .form-actions .btn-primary { flex: 1 1 100%; justify-content: center; }
}

/* A question's number and prompt sit inside its card, as every card's title
   does, not on its border (the practice quiz and the exam alike). */
.quiz-question > legend { float: inline-start; inline-size: 100%; margin: 0 0 .45rem; padding: 0; }
.quiz-question > legend + * { clear: both; }

/* ── «نمره‌ها» (proposal S4) ──────────────────────────────────────────────
   The teacher's page of one student (`teacher_student.html`), read by its
   subject: the standing's three facts, the student's marks session by
   session, and each released mark as the teacher's `.mark-row` — the whole
   row one door. On `/grades`, one card a class inside `#grades`, the one
   surface the task-surface contract measures. */
.grade-classes { display: grid; gap: .8rem; }
.grade-classes > .sect { margin: 0; }
.grade-class .set-ico { inline-size: 1.9rem; block-size: 1.9rem; }
.grade-class > .grade-list { border-top: 1px solid var(--line); }
.grade-class-empty { margin: 0; padding: .6rem 1rem .75rem; border-top: 1px solid var(--line); }
.grade-class > .task-more { padding-block: .1rem; }

/* The standing kept in one row at every width — three short figures read
   across, the way the report's phone row reads — where the teacher's page
   of a student stacks its facts on a phone. */
.standing--row .standing-fact small { overflow-wrap: anywhere; }
@media (max-width: 44rem) {
  .standing.standing--row { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .standing--row .standing-fact { padding: .6rem .7rem .7rem; border-top: 0; border-inline-start: 1px solid var(--line); }
  .standing--row .standing-fact:first-child { border-inline-start: 0; }
  .standing--row .standing-fact strong { font-size: var(--t-section); }
}

/* The student's marks, session by session: the shared shapes on small cells
   (4px, the radius scale's small parts), drawing only — the absences fact
   says the count in words. */
.standing-marks { display: flex; flex-wrap: wrap; align-items: center; gap: .3rem .6rem; padding: .5rem 1rem .6rem; border-top: 1px solid var(--line); }
.standing-marks-label { color: var(--muted); font-size: var(--t-meta); font-weight: 600; }
.mark-run { display: flex; flex-wrap: wrap; gap: 3px; margin: 0; padding: 0; list-style: none; }
.mark-run > li { display: inline-flex; align-items: center; justify-content: center; inline-size: 20px; block-size: 20px; border: 1px solid var(--line); border-radius: 4px; background: var(--control); }
.mark-run .att-mark { min-inline-size: 0; }
.mark-run .att-mark > svg { inline-size: 12px; block-size: 12px; }

/* A released mark: title block, score, meter, state — then, when there are
   any, the teacher's words under the title. The title block is the door
   (44px, so the audit measures a real target) and its ::after covers the
   row. New is amber, waiting on the student — never the primary's green
   fill. */
.grade-row.mark-row { position: relative; grid-template-columns: minmax(0, 1fr) 5.5rem 4.5rem 7.5rem; row-gap: 0; padding-block: .35rem; border-inline-start: 3px solid transparent; }
.grade-row.mark-row:hover { background: var(--hover); }
.grade-row.is-unread { border-inline-start-color: var(--amber); }
.grade-row > .grade-door, .grade-row > .grade-seen { grid-column: 1; grid-row: 1; }
.grade-row > .mark-score, .grade-row > .mark-bar, .grade-row > .mark-state, .grade-row > .task-action { grid-row: 1; }
.grade-seen { min-inline-size: 0; margin: 0; }
.grade-door { justify-content: center; gap: .05rem; min-block-size: var(--tap); color: var(--fg1); text-align: start; }
button.grade-door { inline-size: 100%; padding: 0; border: 0; background: none; font: inherit; cursor: pointer; }
.grade-title { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--ink); font-size: var(--t-body); font-weight: 600; }
.grade-door::after { content: ""; position: absolute; inset: 0; border-radius: var(--r-sm); }
.grade-door:focus-visible { outline: none; }
.grade-door:focus-visible::after { box-shadow: inset 0 0 0 2px var(--ring); }
.grade-row:hover .grade-title { color: var(--blue); }
.mark-row .grade-score { display: inline; padding: 0; border-radius: 0; background: none; color: var(--fg2); font-size: var(--t-body); font-weight: 400; line-height: inherit; }
.mark-row .grade-score b { color: var(--ink); font-size: var(--t-lead); font-weight: 600; }
.grade-row .mark-state, .grade-row .task-action { justify-self: end; }
.grade-row .task-action { margin: 0; }
.grade-row .mark-state.is-waiting { display: inline-flex; align-items: center; gap: .35rem; white-space: nowrap; }
.grade-row .mark-state.is-waiting::before { content: ""; flex: none; inline-size: .45rem; block-size: .45rem; border-radius: 50%; background: currentColor; }
/* The teacher's words: a read mark's first line, the paper one press away;
   a new one's whole, at the reading size, where it arrives (docs/08:
   feedback is reading text). */
.grade-excerpt { grid-column: 1; grid-row: 2; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 1; overflow: hidden; margin: 0 0 .3rem; color: var(--fg2); font-size: var(--t-small); line-height: 1.75; }
.grade-row.is-unread .grade-excerpt { display: block; overflow: visible; color: var(--fg1); font-size: var(--t-read); line-height: 1.9; white-space: pre-line; overflow-wrap: anywhere; }
@media (max-width: 44rem) {
  .grade-row.mark-row { grid-template-columns: minmax(0, 1fr) 5rem; }
  .grade-row > .mark-score { grid-column: 2; justify-self: end; align-self: start; padding-block-start: .55rem; }
  .grade-row .grade-excerpt { grid-column: 1 / -1; }
  .grade-row > .mark-state, .grade-row > .task-action { grid-column: 1; grid-row: 3; justify-self: start; margin-block: .15rem .1rem; }
  .grade-row > .mark-bar { display: block; grid-column: 2; grid-row: 3; align-self: center; }
}

/* The student's own marks over the term, one column a mark. */
.grade-trend .hist-fig { margin-top: .2rem; }
#attendance .mark-foot { margin-inline: 0; }

/* ── «افراد» (A2, W3): the directory, one person, the slip, the support view
   ─────────────────────────────────────────────────────────────────────── */
/* A person's initial: the inbox's face (.conversation-avatar), on each row of
   people and at the head of a person's page. A closed account's face is grey. */
.person-face { flex: none; inline-size: 2.1rem; block-size: 2.1rem; font-size: var(--t-small); font-weight: 600; line-height: 1; }
.person-face--lg { inline-size: 3.25rem; block-size: 3.25rem; font-size: var(--t-section); }
.is-off > .person-face, .person-face.is-off { background: var(--chip); color: var(--muted); }
.roster-row.is-off .roster-name strong { color: var(--muted); }

/* The directory is the teacher's roster card (.roster): search and the
   readings with their counts, the rows, the pager — the column's width. */
#people-list.roster { max-width: none; }
.people-row .chips { flex: none; justify-content: flex-end; max-inline-size: 45%; }
.people-row .roster-id small { line-height: 1.85; }
@media (max-width: 40rem) {
  .people-row { flex-wrap: wrap; row-gap: .3rem; }
  .people-row .roster-chev { order: 2; }
  .people-row .chips { order: 3; flex: 1 1 100%; max-inline-size: none; justify-content: flex-start; padding-inline-start: 2.85rem; }
}
.people-bar { margin-bottom: .8rem; }

/* The aside's facts: one share drawn (who has signed in), and who holds the
   system's two powers, by name. */
.facts-figure { margin: 0 0 .5rem; color: var(--fg2); font-size: var(--t-small); line-height: 1.75; }
.facts-figure .stat-num { color: var(--ink); font-weight: 600; }
.people-facts .chart-key { margin-top: .55rem; }
.meta-row--stack .chips { margin-top: .1rem; }

/* What a save came to, on the card it changed: calm when it landed, red ink
   when it was refused — and inside a dialog sent back open, the reason. */
.save-line { display: flex; align-items: flex-start; gap: .4rem; margin: 0 0 .75rem; color: var(--fg2); font-size: var(--t-small); line-height: 1.8; }
.save-line > svg { flex: none; inline-size: 14px; block-size: 14px; margin-top: .3rem; color: var(--aqua); }
.save-line.is-refused, .save-line.is-refused > svg { color: var(--red); }
.form-error { display: flex; align-items: flex-start; gap: .45rem; margin: 0; padding: .55rem .75rem; border: 1px solid color-mix(in srgb, var(--red) 25%, var(--content)); border-radius: var(--r-sm); background: var(--red-tint); color: var(--red); font-size: var(--t-small); line-height: 1.8; }
.form-error > svg { flex: none; inline-size: 14px; block-size: 14px; margin-top: .3rem; }

/* One person: the face, the name, the login, the state and the system roles. */
.person-hd { align-items: center; }
.person-hd > .person-face { align-self: center; }
.person-hd .byline .chips { display: inline-flex; }

/* «ورود به تخته»: the state in a sentence, then its acts — the fill first,
   the closing one in red ink, each a dialog that says what will happen. */
.access-state { display: flex; flex-wrap: wrap; align-items: center; gap: .3rem .55rem; margin: .1rem 0 .9rem; color: var(--fg1); font-size: var(--t-body); line-height: 1.8; }
.access-reason { flex-basis: 100%; color: var(--fg2); font-size: var(--t-small); }
.access-acts { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem .75rem; }
.access-acts > details[open]:not([data-modal-ready]) { flex-basis: 100%; order: 2; }
.create-panel.is-danger > summary { color: var(--red); }
.create-panel.is-danger > summary:hover { border-color: color-mix(in srgb, var(--red) 40%, var(--control)); background: var(--red-tint); }
.access-note { margin: .85rem 0 0; color: var(--muted); font-size: var(--t-meta); line-height: 1.8; }
.access-note.is-waiting { color: var(--amber); }
@media (max-width: 40rem) {
  .access-acts > details:not([open]) { flex: 1 1 100%; }
  .access-acts > details > summary { display: flex; justify-content: center; }
}

/* System roles: three choices that each say what they allow, then the reason
   and the save. A class role is not set here, and the card says so once. */
.roles-form { margin-top: .2rem; gap: .8rem; }
.roles-form .choice-list { margin: 0; }
.choice:has(input:disabled) { cursor: not-allowed; }
.choice-lock { grid-column: 2; margin-top: .25rem; color: var(--amber); font-size: var(--t-meta); line-height: 1.7; }
.roles-save { display: flex; flex-wrap: wrap; align-items: flex-end; gap: .6rem .75rem; }
.roles-save .field { flex: 1 1 16rem; }
.roles-note { margin: .9rem 0 0; padding-top: .75rem; border-top: 1px solid var(--line); color: var(--muted); font-size: var(--t-meta); line-height: 1.8; }
.roles-held { display: flex; flex-wrap: wrap; gap: .3rem; margin: .1rem 0 0; }

/* Their classes: facts, not doors — administration has no class page. */
.person-classes { margin: 0; padding: 0; list-style: none; }
.person-class { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: .75rem; min-height: 3.4rem; padding: .5rem .55rem; border-bottom: 1px solid var(--line); }
.person-class:last-child { border-bottom: 0; }
.person-class .task-copy small { color: var(--muted); }
.person-classes-none { margin: .2rem .55rem .6rem; color: var(--fg2); font-size: var(--t-small); line-height: 1.8; }
.person-history { margin: 0; }

/* The aside's «مشخصات»: label over value, then the two edit doors. */
.person-facts { margin: 0; }
.person-facts > div { padding: .45rem 0; border-top: 1px solid var(--line); }
.person-facts > div:first-child { padding-top: 0; border-top: 0; }
.person-facts dt { color: var(--muted); font-size: var(--t-micro); font-weight: 600; }
.person-facts dd { margin: .1rem 0 0; color: var(--fg1); font-size: var(--t-small); overflow-wrap: anywhere; }
.person-edit { display: flex; flex-wrap: wrap; gap: .4rem; margin-top: .8rem; }
.aside-inner .create-panel > summary { font-size: var(--t-small); padding-inline: .75rem; }

/* The CSV dialog: the four columns as the sheet will look, one example row. */
.csv-sample-wrap { overflow-x: auto; margin: 0; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--surface); }
.csv-sample { inline-size: 100%; border-collapse: collapse; font-size: var(--t-meta); }
.csv-sample th { padding: .35rem .55rem; border-bottom: 1px solid var(--line-2); color: var(--fg1); font-family: ui-monospace, "SF Mono", Menlo, monospace; font-weight: 600; text-align: start; }
.csv-sample td { padding: .35rem .55rem; border-bottom: 1px solid var(--line); color: var(--fg2); vertical-align: top; line-height: 1.6; }
.csv-sample tr:last-child td { border-bottom: 0; }
.csv-sample .csv-what td { color: var(--muted); }

/* What an import did: three figures and one bar — made (aqua), to fix
   (amber, it waits on you), already had an account (the track) — then the
   rows to fix, each with its row number in the file and why. */
.import-report { margin-top: 1rem; }
.report-figures { display: flex; flex-wrap: wrap; gap: .3rem 1.6rem; margin: 0 0 .65rem; color: var(--fg2); font-size: var(--t-small); }
.report-figures strong { margin-inline-end: .35rem; color: var(--ink); font-size: var(--t-section); font-weight: 600; font-variant-numeric: tabular-nums; }
.report-figures .is-waiting strong { color: var(--amber); }
.import-report .stack-bar { block-size: 8px; }
.report-sub { margin: 1.15rem 0 .4rem; color: var(--ink); font-size: var(--t-body); font-weight: 600; }
.fix-list { margin: 0; padding: 0; list-style: none; border: 1px solid var(--line); border-inline-start: 3px solid var(--amber); border-radius: var(--r-sm); }
.fix-list li { display: grid; grid-template-columns: 4.6rem minmax(6rem, 9rem) minmax(0, 1fr); align-items: baseline; gap: .15rem .9rem; padding: .55rem .75rem; border-bottom: 1px solid var(--line); font-size: var(--t-small); }
.fix-list li:last-child { border-bottom: 0; }
.fix-row-no { color: var(--amber); font-weight: 600; white-space: nowrap; }
.fix-why { color: var(--fg2); line-height: 1.75; }
@media (max-width: 40rem) { .fix-list li { grid-template-columns: auto minmax(0, 1fr); } .fix-why { grid-column: 1 / -1; } }
.report-help { margin: .55rem 0 0; color: var(--muted); font-size: var(--t-meta); line-height: 1.8; }
.report-acts { display: flex; flex-wrap: wrap; gap: .5rem; margin: .75rem 0 0; }
.report-fold { margin-top: 1rem; border-top: 1px solid var(--line); }
.report-fold > summary { display: flex; align-items: center; gap: .5rem; min-height: var(--tap); color: var(--fg1); font-size: var(--t-small); font-weight: 600; cursor: pointer; list-style: none; }
.report-fold > summary::-webkit-details-marker { display: none; }
.report-fold > summary .chev { display: inline-flex; color: var(--muted); transform: rotate(90deg); transition: transform .12s; }
.report-fold[open] > summary .chev { transform: rotate(0); }
.existing-list { margin: .4rem 0 0; padding: 0; list-style: none; }
.existing-list li { display: flex; flex-wrap: wrap; align-items: baseline; gap: .2rem .8rem; padding: .4rem 0; border-top: 1px solid var(--line); font-size: var(--t-small); color: var(--fg2); }
.existing-list .fix-row-no { color: var(--muted); font-weight: 500; }
.slips-hd { display: flex; align-items: baseline; gap: .6rem; margin: 1.4rem 0 0; }
.slips-hd h2 { margin: 0; color: var(--ink); font-size: var(--t-lead); font-weight: 600; }
.slips-hd small { color: var(--muted); font-size: var(--t-meta); }

/* The slip: what is handed over — the name, the login in the sheet's Latin
   face, the password large enough to read aloud, and the one rule for it.
   Printed, each is cut out along its dashes. */
.credential-sheet--one { grid-template-columns: minmax(0, 25rem); }
.credential-card dd.c-pass { font-size: var(--t-section); font-weight: 700; }
.credential-sheet--one .credential-card dd.c-pass { font-size: var(--t-sub); }
.slip-foot { margin: .5rem 0 0; padding-top: .45rem; border-top: 1px solid var(--line); color: var(--muted); font-size: var(--t-micro); line-height: 1.7; }
.handover-note { max-width: 46rem; margin: .9rem 0 0; color: var(--muted); font-size: var(--t-meta); line-height: 1.8; }
@media print {
  .import-report, .handover-note, .slips-hd small { display: none !important; }
  .credential-card { border: 1px dashed var(--fg3); border-radius: 0; break-inside: avoid; background: #fff; }
}

/* The start of a support view: the person, four plain terms, the reason. */
.support-start { max-inline-size: 44rem; }
.support-person { display: flex; align-items: center; gap: .8rem; padding: .95rem 1rem .85rem; border-bottom: 1px solid var(--line); }
.support-person strong { display: block; color: var(--ink); font-size: var(--t-lead); font-weight: 600; }
.support-person small { color: var(--muted); font-size: var(--t-meta); }
.support-terms { margin: 0; padding: .3rem 1rem .1rem; list-style: none; }
.support-terms li { display: grid; grid-template-columns: 1.5rem minmax(0, 1fr); gap: .05rem .6rem; padding: .6rem 0; border-bottom: 1px solid var(--line); }
.support-terms li:last-child { border-bottom: 0; }
.support-terms li > svg { margin-top: .2rem; color: var(--muted); }
.support-terms strong { color: var(--fg1); font-size: var(--t-body); font-weight: 600; }
.support-terms small { grid-column: 2; color: var(--fg2); font-size: var(--t-small); line-height: 1.8; }
.support-terms .meter { grid-column: 2; max-inline-size: 12rem; margin-top: .4rem; }
.support-start > .form { margin: 0; padding: .5rem 1rem 1.15rem; border-top: 1px solid var(--line); }

/* The band while viewing: whose view, how long is left, the way out — held
   at the top while the page scrolls. Amber and quiet, as before. */
.support-banner { position: sticky; top: 0; z-index: 30; flex-wrap: wrap; row-gap: .25rem; padding: .4rem 1rem; }
.support-banner > .support-mark { flex: none; display: inline-flex; color: var(--amber); }
.support-banner > .support-who { flex: 1 1 16rem; min-inline-size: 0; }
.support-banner > .support-time { flex: none; display: inline-flex; align-items: center; gap: .5rem; color: var(--fg2); white-space: nowrap; font-variant-numeric: tabular-nums; }
.support-banner .support-time > span { flex: none; }
.support-banner .support-time .meter { flex: none; inline-size: 4.5rem; }
@media (max-width: 40rem) {
  .support-banner > .support-time { order: 1; margin-inline-start: auto; }
  .support-banner > .support-who { order: 2; flex: 1 1 12rem; font-size: var(--t-meta); line-height: 1.7; }
  .support-banner > form { order: 3; }
}

/* What a support view does not show (plan §0): the row stays, and where its
   words or its figure would be, a quiet sentence says they are withheld. */
.withheld { color: var(--muted); font-size: var(--t-small); font-style: italic; font-weight: 400; }
.mark-score.withheld { justify-self: end; align-self: center; }
.exam-receipt-score.withheld { margin: .4rem 0 0; }

/* The page an administration or teaching address gives during a support
   view: both ways on, the way out first. */
.notice-actions > form { display: inline-flex; margin: 0; }

/* ══════════════════════════════════════════════════════════════════════════
   «نیم‌سال‌ها» AND «سرویس‌ها» (A3, the staff revamp's W4) — the term calendar,
   the live-class servers and email. Every rule extends a shared primitive
   (the term strip, the state rows, the readiness line, the phase status, the
   stack bar, the column chart) or lays out a card made of them. Existing
   tokens only.
   ══════════════════════════════════════════════════════════════════════════ */
/* A notice or a calm line over the cards. */
.terms-bar + .settings-notice, .reading-bar + .settings-notice { margin: 0 0 .8rem; }
.col-main > .calm-state[data-t="terms-calm"], .col-main > .calm-state[data-t="providers-calm"] { margin: 0 0 .8rem; }
.col-main > .roll-prompt { margin: 0 0 .8rem; }

/* ── The year strip: `ui::term_strip`, a week a slot ─────────────────── */
/* A year is many weeks: the slots may thin to 2px with 2px between (1px on
   a phone), so two terms of any length fit the column; the section clips
   rather than ever widening the page. */
.year-strip { padding: .85rem 1rem 1rem; overflow-x: clip; }
.year-strip .term-track { gap: 2px; margin-top: 1.7rem; }
.year-strip .term-slot { min-inline-size: 2px; }
.year-strip .term-bands { gap: 2px; }
@media (max-width: 40rem) { .year-strip .term-track, .year-strip .term-bands { gap: 1px; } }
/* A week between two terms: no box, a dotted baseline. */
.term-slot.is-gap > .term-seg { block-size: 5px; background: none; box-shadow: none; border-block-end: 2px dotted var(--bg3); border-radius: 0; }
.term-sw.is-gap { block-size: 4px; background: none; box-shadow: none; border-block-end: 2px dotted var(--bg3); border-radius: 0; }
/* A week with a holiday in it: a dot under the week, in ink — never a colour
   that means something else. */
.term-slot.is-holiday::after { content: ""; position: absolute; inset-block-start: calc(100% + 4px); inset-inline-start: 50%; inline-size: 4px; block-size: 4px; margin-inline-start: -2px; border-radius: 50%; background: var(--fg2); }
.term-sw.is-holiday { inline-size: 6px; block-size: 6px; border-radius: 50%; background: var(--fg2); box-shadow: none; }
.term-mark--month { color: var(--muted); }
/* The terms named under their weeks. */
.term-bands { display: flex; gap: 3px; margin: .95rem 0 0; padding: 0; list-style: none; font-size: var(--t-meta); color: var(--fg2); }
.term-bands > li { min-inline-size: 0; padding-top: .3rem; border-top: 2px solid var(--line-2); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.term-bands > li.is-now { border-top-color: var(--blue); color: var(--ink); font-weight: 600; }
.term-bands > li.is-waiting { border-top-color: var(--amber); color: var(--amber); font-weight: 600; }
.term-bands > li.is-gap { border-top-color: transparent; }
@media (max-width: 40rem) { .term-mark--month { display: none; } }

/* ── A term: name, facts, what it still needs, its holidays, two doors ── */
.term-list { margin: 0 0 .8rem; }
.term-list > .term-row { display: grid; gap: .55rem; align-items: start; justify-content: stretch; min-height: 0; padding: .85rem .5rem .8rem; border-bottom: 1px solid var(--line); scroll-margin-block-start: 1rem; }
.term-list > .term-row:last-of-type { border-bottom: 0; }
.term-list > .term-row + .acc-row { border-top: 1px solid var(--line); }
.term-row-hd { display: flex; align-items: flex-start; gap: .75rem; min-width: 0; }
.term-row-hd > .work-kind { flex-shrink: 0; }
.term-row.is-now .term-row-hd > .work-kind { background: var(--primary-tint); color: var(--blue); }
.term-row-main { display: flex; flex-direction: column; gap: .15rem; min-width: 0; }
.term-row-title { display: flex; flex-wrap: wrap; align-items: center; gap: .3rem .55rem; }
.term-row-title strong { font-size: var(--t-lead); font-weight: 600; color: var(--ink); }
.term-row-main small { color: var(--muted); font-size: var(--t-small); line-height: 1.75; }
.term-row .state-ready, .term-days, .term-row-actions { margin-inline-start: 2.75rem; }
.term-row .state-ready { margin-top: 0; }
.term-days { display: flex; flex-wrap: wrap; align-items: center; gap: .35rem .45rem; font-size: var(--t-small); color: var(--fg2); }
.term-days-label { color: var(--muted); font-weight: 600; margin-inline-end: .2rem; }
.term-days .chip.chip--dim { color: var(--fg2); }
.term-row-actions { display: flex; flex-wrap: wrap; gap: .5rem; }
.term-list > .acc-row > summary { padding-inline: .5rem; }
.term-list > .acc-row .acc-body { padding: 0 .5rem .6rem; }
.term-past { display: flex; flex-wrap: wrap; justify-content: space-between; gap: .2rem 1rem; margin: 0; padding: .55rem 0; border-top: 1px solid var(--line); color: var(--fg2); font-size: var(--t-small); }
.term-past:first-child { border-top: 0; }
.term-past strong { color: var(--fg1); font-weight: 600; }
@media (max-width: 40rem) {
  .term-row .state-ready, .term-days, .term-row-actions { margin-inline-start: 0; }
  .term-row-actions > details { flex: 1 1 8rem; }
  .term-row-actions > details > summary { inline-size: 100%; justify-content: center; }
}

/* The rollover dialog: what will happen, in words, before the button. */
.rollover-facts { display: grid; gap: .5rem; margin: .1rem 0 1rem; padding: .8rem .9rem; border-radius: var(--r-sm); background: var(--sunk); list-style: none; }
.rollover-facts .state-fact { align-items: flex-start; line-height: 1.75; }
.rollover-facts .state-fact > svg { margin-top: .32rem; }
.rollover-facts .state-fact.is-no { color: var(--fg2); }
.rollover-pair { margin-bottom: .9rem; }
/* A prompt whose door is a dialog: without script the open panel takes the
   prompt's width. */
.roll-prompt > .create-panel { flex-shrink: 0; }
.roll-prompt > details[open]:not([data-modal-ready]) { flex-basis: 100%; }
.roll-prompt > form { display: inline-flex; }

/* A term's holidays in their dialog: the add first, then a row a day, each
   entered one with its one verb at the end, the fixed ones greyed. */
.holiday-rows { margin: 1rem 0 0; padding: 0; list-style: none; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--surface); }
.holiday-rows:empty { display: none; }
.holiday-rows > li { display: flex; align-items: center; gap: .75rem; min-height: var(--tap); padding-block: .2rem; padding-inline: .8rem .25rem; border-bottom: 1px solid var(--line); }
.holiday-rows > li:last-child { border-bottom: 0; }
.holiday-when { flex-shrink: 0; min-inline-size: 5.5rem; font-weight: 600; color: var(--ink); white-space: nowrap; }
.holiday-what { flex: 1 1 auto; min-width: 0; color: var(--fg2); }
.holiday-rows > li.is-fixed .holiday-when, .holiday-rows > li.is-fixed .holiday-what { color: var(--muted); font-weight: 400; }
.holiday-rows > li.is-fixed small { color: var(--muted); font-size: var(--t-meta); padding-inline-end: .55rem; }
.holiday-rows .danger-button { border-color: transparent; background: none; box-shadow: none; padding: 0 .6rem; }
.holiday-add { display: grid; grid-template-columns: 11rem minmax(0, 1fr); gap: .6rem; align-items: end; }
@media (max-width: 40rem) { .holiday-add { grid-template-columns: minmax(0, 1fr); } }

/* ── A service's state: one sentence, at the top of its page ──────────── */
.service-status { display: flex; flex-wrap: wrap; align-items: flex-start; gap: .8rem; padding: .9rem 1rem .85rem; }
.service-status-copy { display: flex; flex-direction: column; gap: .2rem; flex: 1 1 18rem; min-width: 0; }
.service-status-copy strong { color: var(--ink); font-size: var(--t-lead); font-weight: 600; line-height: 1.65; }
.service-status-copy p { margin: 0; color: var(--fg2); font-size: var(--t-small); line-height: 1.85; }
.service-status > form { display: inline-flex; align-self: center; margin-inline-start: auto; }
.health-mark { display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; inline-size: 1.6rem; block-size: 1.6rem; border-radius: 50%; }
.health-mark svg { inline-size: 14px; block-size: 14px; }
.service-status > .health-mark { inline-size: 2.15rem; block-size: 2.15rem; }
.service-status > .health-mark svg { inline-size: 16px; block-size: 16px; }
.health-mark.is-ok { background: var(--aqua-tint); color: var(--aqua); }
.health-mark.is-bad { background: var(--red-tint); color: var(--red); }
.health-mark.is-none { background: var(--amber-tint); color: var(--amber); }
.health-mark.is-off { background: var(--chip); color: var(--fg2); }

/* ── A live-class server: who it is, its load, whether it answered, two
   doors. A failed test is the one place red appears. ─────────────────── */
.servers-now { margin: 0; padding: 0 1rem .2rem; color: var(--fg2); font-size: var(--t-small); }
.provider-card { display: grid; gap: .65rem; padding: 1rem .55rem .9rem; border-bottom: 1px solid var(--line); scroll-margin-block-start: 1rem; }
.provider-card:last-child { border-bottom: 0; }
.provider-card.is-failing { border-inline-start: 3px solid var(--red); padding-inline-start: calc(.55rem - 3px); }
.provider-hd { display: flex; align-items: flex-start; gap: .75rem; min-width: 0; }
.provider-hd > .work-kind { flex-shrink: 0; }
.provider-main { display: flex; flex-direction: column; gap: .2rem; flex: 1 1 auto; min-width: 0; }
.provider-main p { margin: 0; }
.provider-title { display: flex; flex-wrap: wrap; align-items: center; gap: .3rem .55rem; }
.provider-title h3 { margin: 0; font-size: var(--t-read); font-weight: 600; color: var(--ink); }
.provider-kind { color: var(--fg2); font-size: var(--t-small); }
.provider-kind .ident-line { margin-inline-start: .3rem; }
/* An identifier on a line of its own starts where the Persian does. */
.provider-main > .ident-line, .app-row .ident-line { text-align: end; }
/* An address on a line of its own stays one line: cut with «…» at its end,
   the whole value in `title` — never a lone «/» wrapped onto the next line. */
.ident-line.ident-one { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; overflow-wrap: normal; }
/* The state keeps `.session-state` (J22 S22.9); here it is a fact: active
   affirmative, the chosen others quiet chips — never red. */
.provider-card .session-state { background: var(--aqua-tint); color: var(--aqua); }
.provider-card .session-state.is-draining { background: var(--chip); color: var(--fg2); }
.provider-card .session-state.is-disabled { background: var(--chip); color: var(--muted); }
.provider-load { display: grid; grid-template-columns: auto minmax(0, 14rem); align-items: center; gap: .3rem .9rem; margin-inline-start: 2.75rem; }
.provider-load .meter-line { margin: 0; font-size: var(--t-small); color: var(--fg2); }
.provider-health { margin: 0; margin-inline-start: 2.75rem; padding-top: .7rem; }
.provider-health .health-copy { flex: 1 1 15rem; min-width: 0; color: var(--fg2); line-height: 1.8; }
.provider-health .health-copy small { display: block; color: var(--muted); font-size: var(--t-meta); }
.provider-health .health-copy .is-bad { color: var(--red); font-weight: 600; }
.provider-health .health-copy .is-ok { color: var(--aqua); font-weight: 600; }
.provider-health .health-copy .is-none { color: var(--amber); font-weight: 600; }
.provider-note { margin: 0; margin-inline-start: 2.75rem; color: var(--fg2); font-size: var(--t-small); line-height: 1.8; }
.provider-note.is-waiting { color: var(--amber); font-weight: 600; }
.provider-actions { display: flex; flex-wrap: wrap; gap: .5rem; margin-inline-start: 2.75rem; }
/* The Connect login is Connect's alone: hidden by CSS, so the form without
   script is the same form. */
form:has(input[name="kind"][value="0"]:checked) .if-connect { display: none; }
.kind-fixed { margin: 0 0 .8rem; color: var(--fg2); font-size: var(--t-small); line-height: 1.8; }
.kind-fixed strong { color: var(--ink); font-weight: 600; }
@media (max-width: 40rem) {
  .provider-load, .provider-health, .provider-note, .provider-actions { margin-inline-start: 0; }
  .provider-load { grid-template-columns: minmax(0, 1fr); }
  .provider-actions > details { flex: 1 1 8rem; }
  .provider-actions > details > summary { inline-size: 100%; justify-content: center; }
}

/* Takhte's own room and the applications that borrow it: facts. */
.service-facts { margin: 0 0 .5rem; color: var(--fg1); font-size: var(--t-small); }
.sect-hd > .state-pill { flex-shrink: 0; }
.app-rows { margin: 0 0 .4rem; padding: 0; list-style: none; }
.app-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .4rem 1rem; min-height: 3.2rem; padding: .45rem .1rem; border-bottom: 1px solid var(--line); }
.app-row:last-child { border-bottom: 0; }
.app-row .task-copy { display: flex; flex-direction: column; flex: 1 1 14rem; min-width: 0; }
.app-row .task-copy strong { color: var(--fg1); font-weight: 600; }

/* ── Email: the month in its parts, the days, what did not arrive ──────── */
.stack-bar > .is-failed { background: var(--red); }
.chart-key .key-failed { background: var(--red); }
.chart-key strong { color: var(--ink); font-weight: 600; font-variant-numeric: tabular-nums; }
.delivery-month { display: grid; gap: .5rem; padding: .75rem 1rem 1rem; border-top: 1px solid var(--line); }
.delivery-month-hd { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: .2rem 1rem; margin: 0; color: var(--fg2); font-size: var(--t-small); font-weight: 600; }
.delivery-month-hd small { color: var(--muted); font-weight: 400; font-size: var(--t-meta); }
.delivery-month .chart-key { margin: 0; }
.sect-note { flex-shrink: 0; color: var(--muted); font-size: var(--t-meta); }
.hist-slot.is-current .hist-name { color: var(--blue); font-weight: 600; }
.hist-slot.is-low .hist-plot > i { background: color-mix(in srgb, var(--accent) 45%, var(--content)); }
.failure-lead { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .5rem 1rem; margin: .2rem 0 .4rem; padding: .7rem .8rem; border-radius: var(--r-sm); background: var(--amber-tint); }
.failure-lead p { flex: 1 1 18rem; margin: 0; color: var(--fg1); font-size: var(--t-small); line-height: 1.85; }
.failure-lead p strong { color: var(--ink); font-weight: 600; }
.failure-lead > form { display: inline-flex; }
.failure-group { display: flex; flex-wrap: wrap; align-items: center; gap: .2rem .45rem; margin: .85rem .1rem .2rem; color: var(--fg1); font-size: var(--t-small); font-weight: 600; }
.failure-group > svg { inline-size: 14px; block-size: 14px; color: var(--muted); }
.failure-group small { color: var(--muted); font-weight: 400; }
.home-row .ident-line { font-size: var(--t-meta); }
.tech-detail { margin: .8rem 0 0; }
.tech-detail > :not(summary) { margin: 0; padding: .6rem .85rem; }
.tech-detail .ident-line { display: block; line-height: 1.8; }
.action-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .6rem 1rem; padding: .85rem 1rem; }
.action-row .set-archive-copy { display: flex; align-items: flex-start; gap: .7rem; flex: 1 1 18rem; min-width: 0; }
.action-row .set-archive-copy strong { color: var(--ink); font-weight: 600; }
.action-row .set-archive-copy p { margin: .1rem 0 0; color: var(--fg2); font-size: var(--t-small); line-height: 1.8; }
.action-row > form { display: inline-flex; }
/* The aside: an identifier stays Latin and wraps anywhere. */
.side-facts .ident-line { font-size: var(--t-meta); color: var(--fg2); }
@media (max-width: 40rem) {
  .action-row > form, .action-row > form > button,
  .roll-prompt > form, .roll-prompt > form > button,
  .service-status > form, .service-status > form > button,
  .failure-lead > form, .failure-lead > form > button { inline-size: 100%; justify-content: center; }
}
/* «نظارت» (M1): the report queue. A report is a row — what it is and where,
   who wrote it, the words themselves, why it was reported, how long it has
   waited — with one verb that opens the decision. The kind is the door to
   the report read in place: its target is stretched over the row and the
   verb sits above it. `flag-*`, because `.report-*` is the class report's
   (its `.report-who` is a column: the mockup's sender line, a word a line). */
.flag-list { margin: 0; padding: 0; list-style: none; }
.flag-row { position: relative; display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: .25rem .75rem; align-items: start; padding: .8rem .65rem; border-bottom: 1px solid var(--line); transition: background-color .12s; }
.flag-list > .flag-row:last-child { border-bottom: 0; }
.flag-row:hover { background: var(--hover); }
.flag-row > .home-row-ico { padding-top: .3rem; color: var(--fg2); }
.flag-copy { min-width: 0; }
.flag-head { margin: 0; line-height: 1.8; }
.flag-head strong { color: var(--ink); font-size: var(--t-body); font-weight: 600; }
.flag-head small { margin-inline-start: .55rem; color: var(--faint); font-size: var(--t-meta); }
.flag-head .state-chip { margin-inline-start: .45rem; vertical-align: .1em; }
.flag-door { color: inherit; text-decoration: none; }
.flag-door::after { content: ""; position: absolute; inset: 0; }
.flag-door:hover strong { color: var(--blue); }
.flag-door:focus-visible { outline: none; }
.flag-door:focus-visible::after { box-shadow: inset 0 0 0 2px var(--ring); border-radius: var(--r-sm); }
/* One line that wraps as words: «از X به Y», «نوشتهٔ X در «…»». */
.flag-who { margin: .1rem 0 0; color: var(--fg2); font-size: var(--t-small); line-height: 1.8; }
.flag-title { color: var(--fg1); }
.flag-quote { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden; margin: .5rem 0 .4rem; padding: .5rem .8rem; border-inline-start: 3px solid var(--line-2); border-start-end-radius: var(--r-sm); border-end-end-radius: var(--r-sm); background: var(--sunk); color: var(--ink); font-size: var(--t-body); line-height: 1.85; white-space: pre-wrap; overflow-wrap: anywhere; }
.flag-reason { display: flex; align-items: flex-start; gap: .4rem; margin: 0; color: var(--fg2); font-size: var(--t-small); line-height: 1.8; }
.flag-reason > svg { flex: none; inline-size: 14px; block-size: 14px; margin-top: .35rem; color: var(--muted); }
.flag-reason-lbl { color: var(--muted); }
.flag-gone { display: flex; align-items: flex-start; gap: .4rem; margin: .35rem 0 0; color: var(--muted); font-size: var(--t-meta); line-height: 1.75; }
.flag-gone > svg { flex: none; inline-size: 14px; block-size: 14px; margin-top: .25rem; }
.flag-row.is-gone .flag-quote { color: var(--fg2); }
.flag-side { position: relative; z-index: 1; display: flex; flex-direction: column; align-items: flex-end; gap: .5rem; padding-top: .1rem; }
.flag-side .task-time { white-space: nowrap; }
.flag-close > summary { min-inline-size: 6.5rem; justify-content: center; }
/* Without script the dialog unfolds in the row: give it the row. */
.flag-row:has(.flag-close[open]:not([data-modal-ready])) .flag-side { grid-column: 1 / -1; align-items: stretch; }
/* The dialog repeats what is being decided, quieter, so it reads alone. */
.flag-recap { padding: .75rem .9rem; border: 1px solid var(--line); border-radius: var(--r-sm); background: var(--surface); }
.flag-recap .flag-head small { margin-inline-start: .45rem; }
.flag-recap .flag-quote { -webkit-line-clamp: 6; margin-bottom: .35rem; }
.flag-form .field-help { margin: -.6rem 0 0; }
.flag-notice { display: flex; align-items: center; gap: .5rem; margin: .45rem .2rem .2rem; padding: .55rem .85rem; border-radius: var(--r-sm); background: var(--aqua-tint); color: var(--aqua); font-size: var(--t-small); }
.flag-notice > svg { flex: none; inline-size: 14px; block-size: 14px; }
.queue-more { margin: 0; padding: .6rem .65rem .2rem; color: var(--muted); font-size: var(--t-small); }
.moderator-facts p { margin: 0; }
/* The report read in place (M1 §3.6): the report, then the thread around it,
   read-only; the reported one marked with an amber edge. */
.flag-byline .byline-item { white-space: normal; }
.flag-card .sect-hd .state-chip, .flag-context .sect-hd .flag-readonly { margin-inline-start: auto; }
.flag-act { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem 1rem; margin-top: .8rem; }
.flag-act-note { color: var(--muted); font-size: var(--t-small); }
.flag-readonly { display: inline-flex; align-items: center; gap: .3rem; color: var(--muted); font-size: var(--t-meta); white-space: nowrap; }
.flag-readonly > svg { inline-size: 13px; block-size: 13px; }
.flag-thread { padding-block-end: .6rem; }
.flag-item { padding-block-end: .35rem; }
.flag-item.is-reported { margin-block: .25rem; border-inline-start: 3px solid var(--amber); border-start-end-radius: var(--r-sm); border-end-end-radius: var(--r-sm); background: var(--sunk); padding-inline-start: calc(.75rem - 3px); }
.flag-topic-title { margin: .3rem 0 0; color: var(--ink); font-size: var(--t-read); font-weight: 600; line-height: 1.7; }
.flag-seam { display: flex; align-items: center; gap: .6rem; margin: .7rem .75rem .2rem; color: var(--muted); font-size: var(--t-micro); }
.flag-seam::before, .flag-seam::after { content: ""; flex: 1 1 auto; block-size: 1px; background: var(--line-2); }
.flag-facts-note { margin: .6rem 0 0; color: var(--muted); font-size: var(--t-meta); line-height: 1.75; }
@media (max-width: 40rem) {
  .flag-row { grid-template-columns: auto minmax(0, 1fr); padding-inline: .45rem; }
  .flag-side { grid-column: 2; flex-direction: row; align-items: center; justify-content: space-between; flex-wrap: wrap; }
}
@media (forced-colors: active) {
  .stack-bar > .is-failed, .chart-key .key-failed { forced-color-adjust: none; background: Mark; }
  .term-slot.is-holiday::after, .term-sw.is-holiday { forced-color-adjust: none; background: CanvasText; }
}
