/* jarchi look: the tokens, the base and the shared components every page builds on (pages.css, classes.css,
   prejoin.css, feedback.css… sit on top), then the class room. Plain CSS; light and dark come from the same
   tokens (prefers-color-scheme, or the person's choice: html[data-theme="light" | "dark"]).

   The design system (DESIGN-SYS.md; the A1 proposal and palette.json in the design research): calm by default,
   loud only on purpose, never colour alone.
   - Every colour of the product is a token in the block below, and only here (tools/check-tokens.mjs fails the
     build on a colour written anywhere else in the CSS, and checks every pair below by APCA and WCAG 2.2, and the
     status colours and the board's pens under colour-blind vision).
   - Grounds are warm near-neutral, never #fff or #000; the board is paper on a mid-dark stage (its glare cut).
   - Four hues carry meaning, each at its own lightness (so they stay apart for colour-blind eyes too):
       --accent  turquoise «فیروزه»: the brand, selected, the one main action      L .52, white text
       --speak   green: a voice on the air («آماده‌ام», my mic open, who speaks)    L .55, white text
       --hand    amber: attention (a raised hand, a weak line, a lock that is on)  L .86, dark text
       --danger  red: end, remove, cut, recording                                  L .46, white text
     "Fine" gets no colour (--icon). Each hue has a solid, an -ink (its colour as text or glyph), a -soft (a quiet
     state ground) and a -line (an edge); --on-<hue> is the text on its solid.
   - Every state also has a shape (a slash, a level ring, a number, bars, a badge): colour only confirms it.
   - Type is in rem (the phone's text size reaches the page through <meta name="text-scale">); nothing a student
     reads is under 16 px (html[data-who="student"] lifts the small steps), a teacher's under 13 px.
   Older names stay as aliases for one release (the lanes in flight). Note the one that changed meaning:
   --accent-ink is now the turquoise as text; the text on a turquoise solid is --on-accent. */

/* Vazirmatn, one family in two files: the everyday one (Persian and Arabic, basic Latin, digits, punctuation; the
   weights the pages use, 400–800: 60 KB) loads with the page; the full font (111 KB) only when a text has a
   character outside it. Both swap in: the text shows at once in the device's font. */
@font-face {
  font-family: "Vazirmatn";
  src: url("/fonts/vazirmatn-fa-wght.woff2") format("woff2");
  font-weight: 400 800;
  font-display: swap;
  unicode-range: U+0020-007E, U+00A0-00FF, U+0600-06FF, U+0750-077F, U+200C-200F, U+2010-2027, U+2030-205E,
    U+2066-2069, U+2122, U+2190-2193, U+2212, U+2215, U+FB50-FDFF, U+FE70-FEFF;
}
@font-face {
  font-family: "Vazirmatn";
  src: url("/fonts/vazirmatn-wght.woff2") format("woff2");
  font-weight: 100 900;
  font-display: swap;
  unicode-range: U+0100-05FF, U+0700-074F, U+0780-200B, U+2028-202F, U+205F-2065, U+206A-2121, U+2123-218F,
    U+2194-2211, U+2213-2214, U+2216-FB4F, U+FE00-FE6F, U+FF00-FFFF;
}

/* ===== tokens: start (every colour lives here; check-tokens.mjs reads this block) ===== */
:root {
  /* grounds and lines (sand: OKLCH h 80, C .006) */
  --bg: #f4f1ed;
  --bg-sunken: #edebe7;
  --surface: #fefbf7;
  --surface-raised: #ffffff;
  --line: #dddad6;
  --line-strong: #82807c;
  --scrim: rgba(24, 22, 19, .45);
  --hover: rgba(29, 34, 39, .06);
  --press: rgba(29, 34, 39, .11);

  /* text and icons (slate: h 255, C .016) */
  --ink: #1a2027;
  --ink-2: #383e46;
  --muted: #4d535b;
  --faint: #868d96;
  --icon: #2d333b;
  --icon-quiet: #525961;

  /* the brand: turquoise «فیروزه» */
  --accent: #1a7777;
  --accent-hover: #156464;
  --accent-ink: #135e5e;
  --accent-soft: #d7f6f5;
  --accent-line: #7ed6d5;
  --on-accent: #ffffff;
  --focus: #1a7777;

  /* the status family: one hue each, at its own lightness */
  --speak: #1d8742;
  --speak-hover: #13702f;
  --speak-ink: #115c2b;
  --speak-soft: #e0f5e3;
  --speak-line: #8bd99c;
  --hand: #f7c97f;
  --hand-ink: #6c4c0f;
  --hand-soft: #feecd1;
  --hand-line: #f0ba60;
  --on-hand: #2b1c03;
  --danger: #a21820;
  --danger-hover: #87131a;
  --danger-ink: #99161e;
  --danger-soft: #ffe9e6;
  --danger-line: #fbada6;
  --on-solid: #ffffff;
  /* recording: the danger family while it records, a calm amber while it waits (paused) */
  --rec: var(--danger);
  --rec-ink: var(--danger-ink);
  --rec-soft: var(--danger-soft);
  --rec-line: var(--danger-line);
  --on-rec: var(--on-solid);
  --rec-paused: var(--hand);
  --rec-paused-ink: var(--hand-ink);
  --rec-paused-soft: var(--hand-soft);
  --rec-paused-line: var(--hand-line);
  --on-rec-paused: var(--on-hand);
  /* a rating's five faces (the after-class form): red → amber → green, each a soft ground and its ink */
  --rate-1: var(--danger-soft); --rate-1-ink: var(--danger-ink);
  --rate-2: #fde3cf; --rate-2-ink: #7a3b06;
  --rate-3: var(--hand-soft); --rate-3-ink: var(--hand-ink);
  --rate-4: var(--speak-soft); --rate-4-ink: var(--speak-ink);
  --rate-5: var(--accent-soft); --rate-5-ink: var(--accent-ink);
  /* the reactions' bubbles (white words on each, in both schemes): «فهمیدم» green, «نفهمیدم» amber (the teacher
     should notice), «تکرار کنید» turquoise, «آفرین» violet, ❤ rose; each also has its own glyph */
  --rx-got: var(--speak);
  --rx-lost: #7a5613;
  --rx-again: var(--accent);
  --rx-bravo: #6d3a9c;
  --rx-heart: #c23a55;

  /* the tooltip: the inverse of the page */
  --tip-bg: #1a2027;
  --tip-ink: #f7f5f1;

  /* the stage around the lesson (always dark-ish: it sets the glare budget), and what sits on it */
  --stage: #494744;
  --stage-raised: #5a5854;
  --stage-av: #75726c;
  --stage-ink: #f7f5f1;
  --stage-muted: #e7e4e0;
  --stage-chip: rgba(20, 18, 15, .62);
  --stage-chip-strong: rgba(18, 17, 15, .84);
  --stage-hover: rgba(255, 255, 255, .14);
  --stage-live: #8bd99c;
  --stage-live-ring: rgba(139, 217, 156, .5);
  --stage-focus: #5ac5c4;
  --stage-hand: #f7c97f;
  --stage-rec: #f97770;
  --stage-ov-teacher: rgba(15, 82, 82, .95);
  --stage-tag-ink: #0f5252;
  --ov-msg: rgba(24, 23, 21, .7);
  --ov-msg-group: rgba(24, 23, 21, .56);
  --ov-who: #b9e3e1;
  --stage-ov-q: #f7c97f;
  --on-stage-ov-q: #2b1c03;
  --video-ground: #000000;
  --knob: #ffffff;

  /* the board and the page: paper (a little dimmer in dark), chalk boards, the printed lines */
  --paper: #fbfaf8;
  --paper-ink: #1a2027;   /* text on paper: the same in both schemes (paper is always light) */
  --paper-muted: #454b52;
  --board-green: #1e4635;
  --board-black: #23272a;
  --print-grid: rgba(48, 92, 140, .3);
  --print-margin: rgba(200, 60, 60, .5);
  --print-mm: rgba(214, 112, 52, .45);
  --print-mm-fine: rgba(214, 112, 52, .18);
  --print-dot: rgba(48, 72, 100, .5);
  --print-axis: #2a2f35;
  --ink-select: #1a7777;
  --ink-select-ground: rgba(255, 255, 255, .55);
  --ink-select-dark: #96e1e0;
  --ink-select-dark-ground: rgba(0, 0, 0, .2);
  --cursor-eraser: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='28'%3E%3Ccircle cx='14' cy='14' r='10' fill='white' fill-opacity='.6' stroke='%23555' stroke-width='1.5'/%3E%3C/svg%3E") 14 14, cell;
  --swatch-edge: rgba(0, 0, 0, .18);

  /* staff pages (بازرس): good / so-so / bad */
  --good: var(--speak-ink); --good-soft: var(--speak-soft);
  --mid: var(--hand-ink); --mid-soft: var(--hand-soft);
  --bad: var(--danger-ink); --bad-soft: var(--danger-soft);
  --spark: var(--muted);

  /* small drawings a CSS background needs (the glyph's colour is part of the token) */
  --badge-lock: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232b1c03' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='4' y='10' width='16' height='11' rx='3'/%3E%3Cpath d='M8 10V7a4 4 0 0 1 8 0v3M12 14.5v2'/%3E%3C/svg%3E");
  --ic-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%234d535b' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='10.5' cy='10.5' r='6.5'/%3E%3Cpath d='M15.5 15.5 20 20'/%3E%3C/svg%3E");
  /* marks: a glyph on a small disc (the disc is the element's background; the glyph's colour is the one on it) */
  --mark-ok: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fefbf7' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4.5 12 9.5 17 19.5 7'/%3E%3C/svg%3E");
  --mark-attn: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232b1c03' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 6v7.5'/%3E%3Ccircle cx='12' cy='18' r='1.875' fill='%232b1c03' stroke='none'/%3E%3C/svg%3E");
  --mark-cut: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 6v7.5'/%3E%3Ccircle cx='12' cy='18' r='1.875' fill='%23fff' stroke='none'/%3E%3C/svg%3E");
  --mark-skip: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%23fff' stroke='%23fff' stroke-width='2' stroke-linejoin='round'%3E%3Cpath d='M12 6v12l8.5-6Z'/%3E%3Cpath d='M3.5 6v12L12 12Z'/%3E%3C/svg%3E");
  --ic-chat: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 3.5h12a3 3 0 0 1 3 3v8a3 3 0 0 1-3 3h-7l-4 3.5v-3.5H6a3 3 0 0 1-3-3v-8a3 3 0 0 1 3-3Z'/%3E%3Cpath d='M7.5 8.5h9M7.5 12.5h5'/%3E%3C/svg%3E");
  /* the connection's bars as masks (alpha only; the colour is the element's): 4 lit, 2 lit, 1 lit, cut */
  --ic-signal-4: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4.5 20v-3.5M9.5 20v-7.5M14.5 20V8.5M19.5 20V4.5'/%3E%3C/svg%3E");
  --ic-signal-2: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4.5 20v-3.5M9.5 20v-7.5'/%3E%3Cpath d='M14.5 20V8.5M19.5 20V4.5' stroke-opacity='.28'/%3E%3C/svg%3E");
  --ic-signal-1: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4.5 20v-3.5'/%3E%3Cpath d='M9.5 20v-7.5M14.5 20V8.5M19.5 20V4.5' stroke-opacity='.28'/%3E%3C/svg%3E");
  --ic-signal-x: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d=''/%3E%3Cpath d='M4.5 20v-3.5M9.5 20v-7.5M14.5 20V8.5M19.5 20V4.5' stroke-opacity='.28'/%3E%3Cpath d='m3.5 3.5 4.5 4.5M8 3.5 3.5 8'/%3E%3C/svg%3E");
  /* the wordmark's three voice bars (on the turquoise square) */
  --mark-bars: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='3 3 18 18' fill='none' stroke='%23fff' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M8 10.5v3M12 7v10M16 9v6'/%3E%3C/svg%3E");

  /* ---- type: Vazirmatn, Persian first (its letters sit ~0.7× the size of Latin at the same px) ---- */
  --fs-display: 1.875rem;   /* 30: the one big moment, «نوبت توئه!» */
  --fs-title: 1.5rem;       /* 24: page titles */
  --fs-heading: 1.25rem;    /* 20: sheet and panel titles */
  --fs-lead: 1.125rem;      /* 18: the one line a student must read */
  --fs-body-phone: 1.0625rem; /* 17: chat and messages on phones */
  --fs-body: 1rem;          /* 16: body text, every input (iPhone never zooms) */
  --fs-label: 1rem;         /* 16: buttons, names */
  --fs-meta: .875rem;       /* 14: time, counts, captions (teacher side) */
  --fs-micro: .8125rem;     /* 13: a laptop teacher's timestamps */
  --fs-badge: .75rem;       /* 12: a badge's digits only (800) */
  /* older names */
  --fs-xs: var(--fs-micro);
  --fs-s: var(--fs-meta);
  --fs-sm: var(--fs-meta);
  --fs: var(--fs-body);
  --fs-md: var(--fs-lead);
  --fs-lg: var(--fs-title);
  --fs-xl: var(--fs-display);
  --fw: 400;
  --fw-m: 600;
  --fw-b: 700;
  --fw-x: 800;

  /* ---- the UI kit (POLISH.md): radii by role, a 4/8 grid, depth by role, motion ---- */
  --r-sm: 8px;
  --r: 12px;
  --r-lg: 16px;
  --r-xl: 20px;
  --r-pill: 999px;
  --r-ctl: 12px;
  --r-card: 16px;
  --r-pop: 14px;
  --r-sheet: 20px;
  --s1: 4px;
  --s2: 8px;
  --s3: 12px;
  --s4: 16px;
  --s5: 20px;
  --s6: 24px;
  --s8: 32px;
  --tap: 44px;
  --tap-lg: 56px;
  --shadow-1: 0 1px 2px rgba(40, 33, 24, .05), 0 1px 1px rgba(40, 33, 24, .03);
  --shadow-2: 0 8px 24px rgba(40, 33, 24, .12), 0 1px 4px rgba(40, 33, 24, .06);
  --shadow-3: 0 24px 64px rgba(40, 33, 24, .22), 0 4px 12px rgba(40, 33, 24, .08);
  --shadow-stage: 0 6px 24px rgba(0, 0, 0, .35);
  /* The room's ground around the lesson on a phone (round 1 #1): the page's warm ground in light (no dark hole under
     the lesson), the stage's calm dark in dark; the paper keeps a thin edge on the light ground. */
  --room-ground: var(--bg);
  --room-ink: var(--ink);
  --room-muted: var(--muted);
  --room-paper-edge: 0 0 0 1px var(--line), var(--shadow-1);
  /* ---- motion (A3 §7): what moves explains cause and continuity, then stops; only transform and opacity ---- */
  --dur-tap: 80ms;       /* press feedback */
  --dur-fast: 120ms;     /* colour, icon or label swap, toggles */
  --dur-med: 200ms;      /* small things in (toast, menu, badge, chip); every exit */
  --dur-slow: 280ms;     /* big things in: a sheet, a banner, the floor's card */
  --dur-fade: 400ms;     /* things leaving by themselves: a chat line, a solved banner, the end of the class */
  --dur-ping: 600ms;     /* the one ring that points at the cause */
  --dur-breathe: 1600ms; /* a waiting pulse: three at most unless it is a real wait (a spinner) */
  --ease-std: cubic-bezier(.2, 0, 0, 1);
  --ease-enter: cubic-bezier(.05, .7, .1, 1);
  --ease-exit: cubic-bezier(.3, 0, .8, .15);
  --ease-pop: cubic-bezier(.34, 1.4, .64, 1); /* badges and counters only */
  --move: 1;             /* every travel distance × this: 0 with reduced motion (fades stay, nothing travels) */
  --t-fast: var(--dur-fast);
  --t-med: var(--dur-med);
  --ease: var(--ease-enter);

  /* ---- older names (aliases, one release) ---- */
  --card: var(--surface);
  --card-raised: var(--surface-raised);
  --chrome: var(--surface);
  --accent-strong: var(--accent-ink);
  --hand-solid: var(--hand);
  --warn: var(--hand-ink);
  --warn-solid: var(--hand-ink);
  --warn-soft: var(--hand-soft);
  --warn-line: var(--hand-line);
  --live: var(--hand-ink);
  --live-soft: var(--hand-soft);
  --ok: var(--icon);
  --ok-ink: var(--ink-2);
  --ok-soft: var(--bg-sunken);
  --ring: var(--speak);
  --paper-dim: 1; /* a document page's image: dimmed with the paper in dark */
  color-scheme: light;
}
/* Dark: by the device (prefers-color-scheme) unless the person chose (html[data-theme], «تنظیمات من» › نمایش);
   the two blocks are the same tokens (check-tokens.mjs holds them equal). */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --paper-dim: .92;
    --room-ground: var(--stage);
    --room-ink: var(--stage-ink);
    --room-muted: var(--stage-muted);
    --room-paper-edge: var(--shadow-stage);
    --bg: #171613;
    --bg-sunken: #13110f;
    --surface: #1e1d1a;
    --surface-raised: #262421;
    --line: #44423f;
    --line-strong: #82807c;
    --scrim: rgba(0, 0, 0, .6);
    --hover: rgba(255, 255, 255, .07);
    --press: rgba(255, 255, 255, .12);

    /* dark mode's hierarchy comes from size and weight, not from greyer text (APCA: Lc 75 on L .23 needs L ≥ .85) */
    --ink: #edebe7;
    --ink-2: #dddad6;
    --muted: #d3d1cd;
    --faint: #a09e9a;
    --icon: #e0deda;
    --icon-quiet: #c6c4c0;

    /* the solids stay the same as in light (no glowing pastels); their inks get light */
    --accent-ink: #96e1e0;
    --accent-soft: #043030;
    --accent-line: #135e5e;
    --focus: #5ac5c4;
    --speak-ink: #a1e4ae;
    --speak-soft: #172f1d;
    --speak-line: #13632f;
    --hand-ink: #fad08f;
    --hand-soft: #35260c;
    --hand-line: #7a5613;
    --danger-ink: #fcc9c4;
    --danger-soft: #3c201d;
    --danger-line: #99161e;
    --rate-2: #3b2414; --rate-2-ink: #ffc49a;

    --tip-bg: #f1eeea;
    --tip-ink: #1a2027;

    --stage: #282623;
    --stage-raised: #34322e;
    --stage-av: #4b4842;
    --stage-ink: #edebe7;
    --stage-muted: #d3d1cd;
    --stage-chip: rgba(0, 0, 0, .62);
    --stage-rec: #f86a65;
    --paper: #eae9e6;

    --shadow-1: 0 1px 2px rgba(0, 0, 0, .3);
    --shadow-2: 0 10px 28px rgba(0, 0, 0, .45), 0 1px 4px rgba(0, 0, 0, .3);
    --shadow-3: 0 28px 72px rgba(0, 0, 0, .6), 0 4px 12px rgba(0, 0, 0, .35);
    --swatch-edge: rgba(255, 255, 255, .34);
    --mark-ok: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%231e1d1a' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4.5 12 9.5 17 19.5 7'/%3E%3C/svg%3E");
    --ic-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23d3d1cd' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='10.5' cy='10.5' r='6.5'/%3E%3Cpath d='M15.5 15.5 20 20'/%3E%3C/svg%3E");
    color-scheme: dark;
  }
}
:root[data-theme="dark"] {
  --paper-dim: .92;
  --room-ground: var(--stage);
  --room-ink: var(--stage-ink);
  --room-muted: var(--stage-muted);
  --room-paper-edge: var(--shadow-stage);
  --bg: #171613;
  --bg-sunken: #13110f;
  --surface: #1e1d1a;
  --surface-raised: #262421;
  --line: #44423f;
  --line-strong: #82807c;
  --scrim: rgba(0, 0, 0, .6);
  --hover: rgba(255, 255, 255, .07);
  --press: rgba(255, 255, 255, .12);

  /* dark mode's hierarchy comes from size and weight, not from greyer text (APCA: Lc 75 on L .23 needs L ≥ .85) */
  --ink: #edebe7;
  --ink-2: #dddad6;
  --muted: #d3d1cd;
  --faint: #a09e9a;
  --icon: #e0deda;
  --icon-quiet: #c6c4c0;

  /* the solids stay the same as in light (no glowing pastels); their inks get light */
  --accent-ink: #96e1e0;
  --accent-soft: #043030;
  --accent-line: #135e5e;
  --focus: #5ac5c4;
  --speak-ink: #a1e4ae;
  --speak-soft: #172f1d;
  --speak-line: #13632f;
  --hand-ink: #fad08f;
  --hand-soft: #35260c;
  --hand-line: #7a5613;
  --danger-ink: #fcc9c4;
  --danger-soft: #3c201d;
  --danger-line: #99161e;
  --rate-2: #3b2414; --rate-2-ink: #ffc49a;

  --tip-bg: #f1eeea;
  --tip-ink: #1a2027;

  --stage: #282623;
  --stage-raised: #34322e;
  --stage-av: #4b4842;
  --stage-ink: #edebe7;
  --stage-muted: #d3d1cd;
  --stage-chip: rgba(0, 0, 0, .62);
  --stage-rec: #f86a65;
  --paper: #eae9e6;

  --shadow-1: 0 1px 2px rgba(0, 0, 0, .3);
  --shadow-2: 0 10px 28px rgba(0, 0, 0, .45), 0 1px 4px rgba(0, 0, 0, .3);
  --shadow-3: 0 28px 72px rgba(0, 0, 0, .6), 0 4px 12px rgba(0, 0, 0, .35);
  --swatch-edge: rgba(255, 255, 255, .34);
  --mark-ok: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%231e1d1a' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4.5 12 9.5 17 19.5 7'/%3E%3C/svg%3E");
  --ic-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23d3d1cd' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='10.5' cy='10.5' r='6.5'/%3E%3Cpath d='M15.5 15.5 20 20'/%3E%3C/svg%3E");
  color-scheme: dark;
}
/* A student reads nothing under 16 px (A1: Persian at 16 px is the smallest a 10-year-old reads at speed on a
   phone); the small steps lift. app.js sets data-who from the link or the join. */
html[data-who="student"] {
  --fs-meta: 1rem;
  --fs-micro: 1rem;
  --fs-xs: 1rem;
  --fs-s: 1rem;
  --fs-sm: 1rem;
}
/* Reduced motion (the device's, or the person's choice html[data-motion="reduce"]): no travel, short fades, no pings,
   no breathing; feedback stays (A3 §7, WCAG 2.3.3). */
@media (prefers-reduced-motion: reduce) {
  :root:not([data-motion="full"]) { --move: 0; --dur-slow: 160ms; --dur-fade: 200ms; --dur-ping: 0ms; --dur-breathe: 0ms; }
}
:root[data-motion="reduce"] { --move: 0; --dur-slow: 160ms; --dur-fade: 200ms; --dur-ping: 0ms; --dur-breathe: 0ms; }
/* ===== tokens: end ===== */

/* ---------- base ---------- */
* { box-sizing: border-box; }
[hidden] { display: none !important; }
html, body { margin: 0; }
body {
  background: var(--bg);
  color: var(--ink);
  font-family: "Vazirmatn", Tahoma, "Segoe UI", system-ui, sans-serif;
  font-size: var(--fs);
  line-height: 1.7;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
  min-height: 100dvh;
  font-feature-settings: "ss01" 0;
  -webkit-font-smoothing: antialiased;
}
button, input, select, textarea { font: inherit; color: inherit; }
a { color: var(--accent-ink); text-underline-offset: 3px; }
h1, h2, h3 { line-height: 1.45; }
:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
::selection { background: var(--accent-soft); }
kbd {
  display: inline-grid; place-items: center;
  min-width: 20px; height: 20px; padding: 0 5px;
  border-radius: 6px; border: 1px solid var(--line-strong); border-bottom-width: 2px;
  background: var(--surface); color: var(--muted);
  font-family: ui-monospace, "SFMono-Regular", Menlo, monospace; font-size: var(--fs-badge); font-weight: var(--fw-b); line-height: 1;
  direction: ltr;
}
/* Keyboard hints only where there is a keyboard (round 7 #5): a phone or a tablet (a touch first screen) shows no
   «R» or «Shift+T», in «بیشتر», in a tooltip or anywhere else; a laptop keeps them. */
@media (hover: none), (pointer: coarse) { kbd { display: none !important; } }

/* ---------- icons (icons.js): one family. Beside a word: 20 px, stroke 1.75. Where the icon is the control's only
   label (the bars, the tool strips, icon buttons): 24 px, stroke 2, in --icon (A1: «icons are text»). ---------- */
.ic {
  width: 20px; height: 20px; flex: none;
  fill: none; stroke: currentColor; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round;
}
.ic-24, .cb-ic .ic, .tl .ic, .btn.icon .ic { width: 24px; height: 24px; stroke-width: 2; }
[dir="rtl"] .ic.flip { transform: scaleX(-1); }

.wrap {
  max-width: 460px;
  margin: 0 auto;
  padding: max(20px, env(safe-area-inset-top)) max(16px, env(safe-area-inset-right)) max(24px, env(safe-area-inset-bottom)) max(16px, env(safe-area-inset-left));
}

/* The wordmark: a small turquoise mark (three voice bars) before «جارچی». */
.brand { display: flex; align-items: center; flex-wrap: wrap; gap: 4px 10px; margin: 8px 0 20px; }
.brand h1 { display: flex; align-items: center; gap: 10px; font-size: var(--fs-lg); font-weight: var(--fw-x); margin: 0; letter-spacing: 0; }
.brand h1::before, .mark {
  content: "";
  flex: none;
  width: 32px; height: 32px;
  border-radius: 10px;
  background: var(--accent) var(--mark-bars) center / 100% no-repeat;
}
.brand span { color: var(--muted); font-size: var(--fs-sm); }

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  padding: var(--s5);
  margin-bottom: var(--s4);
  box-shadow: var(--shadow-1);
}
.card h2 { font-size: var(--fs-md); margin: 0 0 4px; font-weight: var(--fw-x); }
.hint { color: var(--muted); font-size: var(--fs-sm); margin: 0 0 12px; }

/* ---------- buttons (the kit) ----------
   .btn            primary: the one main action (turquoise, full width by default)
   .btn.ghost      secondary: outlined
   .btn.quiet      ghost: text only
   .btn.danger     end / remove (red); .btn.ghost.danger / .btn.danger-line: outlined red
   .btn.icon       a square icon-only button (aria-label + data-tip)
   .btn.small      auto width, 44 px; .btn.tiny compact (still a 44 px target)
   Every button: a hover tint (mouse only), a press, a focus ring, a quiet disabled look. The room's bar buttons
   (.cb) and the board's tool strip (.tl) follow the same states. */
.btn {
  appearance: none;
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border: 1px solid transparent;
  border-radius: var(--r-ctl);
  padding: 10px 18px;
  min-height: 48px;
  font-weight: var(--fw-b);
  line-height: 1.4;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  background: var(--accent);
  color: var(--on-accent);
  width: 100%;
  touch-action: manipulation;
  transition: background-color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease),
    box-shadow var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
}
.btn .ic { width: 20px; height: 20px; }
.btn:disabled, .btn[aria-disabled="true"] { opacity: .45; cursor: default; }
.btn:not(:disabled):active { transform: scale(.98); }
.btn.ghost { background: var(--surface); color: var(--accent-ink); border-color: var(--line-strong); }
.btn.quiet { background: transparent; color: var(--muted); border-color: transparent; }
.btn.danger { background: var(--danger); color: var(--on-solid); }
.btn.ghost.danger, .btn.danger-line { background: var(--surface); color: var(--danger-ink); border-color: var(--danger-line); }
.btn.small { width: auto; min-height: var(--tap); padding: 8px 16px; font-size: var(--fs-sm); }
.btn.tiny { width: auto; min-height: var(--tap); min-width: var(--tap); padding: 4px 12px; font-size: var(--fs-s); border-radius: 10px; white-space: nowrap; }
.btn.icon { width: var(--tap); min-width: var(--tap); min-height: var(--tap); padding: 0; background: transparent; color: var(--muted); border-radius: var(--r-ctl); }
.btn:focus-visible, input:focus-visible, select:focus-visible, textarea:focus-visible { outline: 2px solid var(--focus); outline-offset: 2px; }
a.btn { text-decoration: none; }
/* Hover only where there is a mouse (a tap must not leave a button looking pressed). */
@media (hover: hover) {
  .btn:where(:not(:disabled)):hover { background: var(--accent-hover); }
  .btn.ghost:where(:not(:disabled)):hover { background: var(--accent-soft); border-color: var(--accent-line); }
  .btn.quiet:where(:not(:disabled)):hover, .btn.icon:where(:not(:disabled)):hover { background: var(--hover); color: var(--ink); }
  .btn.danger:where(:not(:disabled)):hover { background: var(--danger-hover); }
  .btn.ghost.danger:where(:not(:disabled)):hover, .btn.danger-line:where(:not(:disabled)):hover { background: var(--danger-soft); }
}
.btn.quiet:where(:not(:disabled)):active, .btn.icon:where(:not(:disabled)):active { background: var(--press); }

/* ---------- motion: things that come and go fade and rise a little (--t-fast / --t-med; none for reduced motion) ---------- */
@keyframes kit-pop { from { opacity: 0; transform: translateY(calc(6px * var(--move))) scale(calc(1 - .02 * var(--move))); } }
@keyframes kit-fade { from { opacity: 0; } }
@keyframes kit-rise { from { transform: translateY(calc(24px * var(--move))); opacity: .4; } }
.kit-pop { animation: kit-pop var(--t-med) var(--ease); }
.kit-fade { animation: kit-fade var(--t-med) var(--ease); }

/* ---------- the tooltip (ui.js): one at a time, on a mouse's rest or a keyboard's focus, with the shortcut ---------- */
.tip {
  position: fixed; z-index: 60; top: 0; left: 0;
  display: inline-flex; align-items: center; gap: 8px;
  max-width: min(280px, calc(100vw - 16px));
  padding: 5px 10px;
  border-radius: var(--r-sm);
  background: var(--tip-bg); color: var(--tip-ink);
  font-size: var(--fs-s); font-weight: var(--fw-m); line-height: 1.5;
  box-shadow: 0 6px 18px rgba(0, 0, 0, .22);
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--t-fast) var(--ease);
}
.tip[data-on="1"] { opacity: 1; }
.tip kbd { background: transparent; border-color: currentColor; color: inherit; }

/* ---------- loading: a skeleton line or block that breathes ---------- */
.skel {
  display: block; border-radius: var(--r-sm);
  background: linear-gradient(90deg, var(--bg-sunken) 0%, var(--line) 50%, var(--bg-sunken) 100%) 0 0 / 200% 100%;
  animation: skel 1.4s ease-in-out infinite;
}
.skel-line { height: 14px; margin: 8px 0; }
.skel-row { height: 44px; margin: 6px 0; border-radius: var(--r); }
@keyframes skel { from { background-position: 100% 0; } to { background-position: -100% 0; } }
@media (prefers-reduced-motion: reduce) { .skel { animation: none; } }

.sr-only {
  position: absolute !important; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* ---------- an empty list's one helpful line ---------- */
.empty-state {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  padding: 20px 12px; text-align: center; color: var(--muted);
}
.empty-state .ic { width: 24px; height: 24px; color: var(--faint); margin-bottom: 4px; }
.empty-state b { color: var(--ink-2); font-size: var(--fs-sm); font-weight: var(--fw-b); }
.empty-state span { font-size: var(--fs-s); line-height: 1.6; }

.linkrow { display: flex; gap: 8px; align-items: center; }
.linkbox {
  flex: 1;
  min-width: 0;
  direction: ltr;
  text-align: left;
  font-family: ui-monospace, "SFMono-Regular", Menlo, monospace;
  font-size: var(--fs-micro);
  background: var(--bg-sunken);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 10px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ---------- forms ---------- */
label { display: block; font-weight: var(--fw-b); font-size: var(--fs-sm); margin-bottom: 6px; }
input[type=text], input[type=search], textarea {
  width: 100%;
  min-height: 48px;
  padding: 10px 14px;
  border: 1px solid var(--line-strong);
  border-radius: var(--r-ctl);
  background: var(--surface);
  margin-bottom: 12px;
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease), background-color var(--t-fast) var(--ease);
}
input[type=text]::placeholder, input[type=search]::placeholder, textarea::placeholder { color: var(--faint); }
@media (hover: hover) { input[type=text]:hover, input[type=search]:hover, textarea:hover { border-color: var(--faint); } }
input[type=text]:focus, input[type=search]:focus, textarea:focus {
  border-color: var(--accent); outline: none;
  box-shadow: 0 0 0 3px var(--accent-soft);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 32%, transparent);
}
input[type=text]:focus-visible, input[type=search]:focus-visible, textarea:focus-visible { outline: none; }
.err { color: var(--danger-ink); font-size: var(--fs-sm); margin: 8px 0 0; min-height: 1em; }
.err.quiet { margin: 0 0 12px; }
.err.quiet:empty { display: none; }

/* ---------- small things ---------- */
.top { display: flex; justify-content: space-between; align-items: center; margin: 4px 0 16px; gap: 8px; }
.top h1 { font-size: var(--fs-heading); margin: 0; font-weight: 800; }

/* A status pill (not a button): turquoise by default, .bad for trouble, .ok / .warn / .hand by meaning. */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: var(--fs-meta);
  font-weight: 700;
  line-height: 1.5;
  padding: 3px 10px;
  border-radius: var(--r-pill);
  background: var(--accent-soft);
  color: var(--accent-ink);
  white-space: nowrap;
}
.chip.ok { background: var(--bg-sunken); color: var(--ink-2); }
.chip.warn { background: var(--hand-soft); color: var(--hand-ink); }
.chip.hand { background: var(--hand-soft); color: var(--hand-ink); }
.chip.bad { background: var(--danger-soft); color: var(--danger-ink); }

/* A quiet label next to a name («معلم»، «خودت»). */
.tag {
  display: inline-block;
  font-size: var(--fs-xs);
  font-weight: 500;
  line-height: 1.6;
  color: var(--muted);
  background: var(--bg-sunken);
  border-radius: var(--r-pill);
  padding: 0 8px;
  white-space: nowrap;
}

/* A one-line message in a soft box: .notice (attention), .notice.ok, .notice.bad. */
.notice {
  background: var(--hand-soft); color: var(--hand-ink);
  border-radius: var(--r); padding: 10px 14px; margin: 0 0 12px; font-weight: 700; font-size: var(--fs-body);
}
.notice.ok { background: var(--bg-sunken); color: var(--ink-2); }
.notice.bad { background: var(--danger-soft); color: var(--danger-ink); }

.avatar {
  flex: none;
  width: 40px; height: 40px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--accent-soft); color: var(--accent-ink);
  font-weight: 800;
  line-height: 1;
}

.foot { display: flex; justify-content: center; gap: 8px; flex-wrap: wrap; }

/* ---------- tables (attendance) ---------- */
.tablewrap { overflow-x: auto; margin: 6px 0 14px; }
table.att { width: 100%; border-collapse: collapse; font-size: var(--fs-sm); }
table.att th { text-align: start; color: var(--muted); font-weight: 700; padding: 6px 8px; font-size: var(--fs-meta); border-bottom: 1px solid var(--line); }
table.att td { padding: 10px 8px; border-top: 1px solid var(--line); }
table.att tbody tr:first-child td { border-top: 0; }
table.att td .tag { margin-inline-start: 6px; }
.st { font-weight: 700; }
.st-present { color: var(--ink-2); }
.st-late, .st-left_early { color: var(--hand-ink); }
.st-absent { color: var(--muted); }

/* ====================================================================================================
   The class room (app.js Session): a webinar around the stage
   A thin top bar (the mark, the class's name, the time, recording, the connection dot); the stage (stage.js)
   filling the middle on a calm dark ground; one bottom bar of icon buttons with a word under each; one side panel
   (participants with the hands first, and the chat) that opens from the bar: beside the stage on a wide screen, a
   sheet over it on a phone. The page itself never scrolls. Everything here is built from the kit above: the
   type scale, the 4/8 spacing, radii and depth by role, 120/200 ms motion.
   ==================================================================================================== */

.wrap.room-wrap { max-width: none; padding: 0; }
body.in-room .ver { display: none; }
body.in-room { overflow: hidden; }

.room {
  --rbar-h: 56px;
  --cbar-h: 64px;
  --side-w: 340px;
  --gut: 16px;
  height: 100dvh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--bg);
}

@keyframes room-blink { 50% { opacity: .3; } }

/* ---------- the top bar ---------- */
.rbar {
  flex: none;
  position: relative; z-index: 10;
  display: flex; align-items: center; gap: 8px 12px;
  min-height: var(--rbar-h);
  padding: max(4px, env(safe-area-inset-top)) max(var(--gut), env(safe-area-inset-right)) 4px max(var(--gut), env(safe-area-inset-left));
  background: var(--surface);
  border-bottom: 1px solid var(--line);
}
.rbar-title { flex: 1 1 0; min-width: 0; display: flex; align-items: center; gap: 12px; }
.rbar-mark { width: 28px; height: 28px; border-radius: 8px; }
.rbar-names { min-width: 0; display: flex; align-items: baseline; gap: 2px 12px; }
.rbar h1 {
  margin: 0; min-width: 0; font-size: var(--fs); font-weight: var(--fw-x); line-height: 1.5;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.rbar-sub {
  display: flex; align-items: center; flex: none; min-width: 0;
  margin: 0; color: var(--muted); font-size: var(--fs-s); font-weight: var(--fw-m); line-height: 1.5; white-space: nowrap;
}
.rbar-sub > :not([hidden]):not(:empty) ~ :not([hidden]):not(:empty)::before { content: "·"; margin-inline: 8px; color: var(--faint); }
.rbar-sub > :empty { display: none; }
.rbar-who { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.rbar-clock { font-variant-numeric: tabular-nums; }
.rbar-rec { display: contents; }

/* The connection: signal bars, tap for the details (A1: a shape for every state, colour only confirms). Four bars
   in the icon's colour when it is fine (no colour for "fine"), two lit in amber when weak, × over empty bars in red
   when cut, one while connecting. The words (conn.js) are the button's text, kept for screen readers and the
   tooltip, not drawn (font-size 0). The bars are a CSS mask, so they take the button's colour. */
#conn {
  appearance: none; flex: none; position: relative;
  display: inline-grid; place-items: center;
  width: 48px; min-width: 48px; height: 48px; min-height: 48px; padding: 0;
  border: 0; border-radius: var(--r-pill);
  background: transparent; color: var(--icon);
  font-size: 0; line-height: 0; overflow: hidden;
  cursor: pointer; touch-action: manipulation;
  transition: background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
#conn::before {
  content: ""; width: 24px; height: 24px;
  background: currentColor;
  -webkit-mask: var(--ic-signal-4) center / 24px no-repeat; mask: var(--ic-signal-4) center / 24px no-repeat;
}
#conn[data-q="weak"] { color: var(--hand-ink); }
#conn[data-q="weak"]::before { -webkit-mask-image: var(--ic-signal-2); mask-image: var(--ic-signal-2); }
#conn[data-q="wait"] { color: var(--muted); }
#conn[data-q="wait"]::before { -webkit-mask-image: var(--ic-signal-1); mask-image: var(--ic-signal-1); animation: room-blink 1.2s ease-in-out infinite; }
#conn[data-q="down"] { background: var(--danger-soft); color: var(--danger-ink); }
#conn[data-q="down"]::before { -webkit-mask-image: var(--ic-signal-x); mask-image: var(--ic-signal-x); }
@media (hover: hover) { #conn:hover { background: var(--hover); } #conn[data-q="down"]:hover { background: var(--danger-soft); } }
#conn:active { background: var(--press); }

/* Banners rejoin.js and prejoin.js put under the bar. */
.room > .rejoin, .room > .pj-unlock, .room > .pj-note { flex: none; width: auto; margin: 8px var(--gut) 0; animation: kit-pop var(--t-med) var(--ease); }
.room .pj-unlock { position: relative; top: auto; min-height: 64px; margin-bottom: 0; }

/* ---------- the body: the stage, and the side panel ---------- */
.room-body { flex: 1 1 auto; min-height: 0; display: flex; }
.room-main {
  position: relative;
  flex: 1 1 auto; min-width: 0; min-height: 0;
  display: flex; flex-direction: column; gap: 12px;
  padding: var(--gut);
  background: var(--stage);
  color: var(--stage-ink);
}
.room-main > .stg { flex: 1 1 auto; min-height: 0; }
.stage-notes { flex: none; display: flex; flex-direction: column; align-items: center; gap: 8px; }
.stage-notes:not(:has(> :not([hidden]):not(:empty))) { display: none; }
.stage-notes > * { max-width: min(560px, 100%); }
/* The toasts' column spans the stage's foot: only the toasts themselves take a tap, the pen writes beside them. */
.room-toasts { display: flex; flex-direction: column; align-items: center; gap: 8px; width: 100%; pointer-events: none !important; }
.room-toasts > * { pointer-events: auto; }
.room-toasts:empty { display: none; }
.room-toasts > :not([hidden]) { animation: kit-pop var(--t-med) var(--ease); }
.room .err.quiet {
  margin: 0; padding: 8px 16px; border-radius: var(--r-pop);
  background: var(--surface-raised); color: var(--danger-ink); font-weight: var(--fw-b); font-size: var(--fs-sm);
  box-shadow: var(--shadow-2), inset 0 0 0 1px var(--danger-line);
}
.room .pj-guide { margin: 0; color: var(--ink); }
.cam-note-slot:empty { display: none; }
/* On a wide screen (and a teacher's every screen) the notes and toasts float over the stage's foot, above the
   page's controls, so the page never jumps when one comes or goes. */
@media (min-width: 960px) {
  .stage-notes {
    position: absolute; z-index: 7;
    /* --notes-b: above the stage's foot (app.js notesAt: the page bar, a dock, the floating undo/redo) */
    inset-inline: var(--gut); bottom: var(--notes-b, calc(var(--gut) + var(--tap) + 20px));
    pointer-events: none;
  }
  .stage-notes > * { pointer-events: auto; }
}
.room[data-role="teacher"] .stage-notes {
  position: absolute; z-index: 7;
  inset-inline: var(--gut); bottom: var(--notes-b, calc(var(--gut) + var(--tap) + 20px));
  pointer-events: none;
}
.room[data-role="teacher"] .stage-notes > * { pointer-events: auto; }

/* Who is speaking: one light chip on the stage's (on an upright phone, the lesson's) top corner, for every state
   (round 4 #3; app.js paintSpeaking): the teacher speaking is her initial and the level only, and steps away after
   2 s without her voice (tickLevels); a classmate speaking adds the first name; a classmate's turn («نوبت …») and
   the teacher's mic off (edge.css) are words without the level. */
.spk {
  position: absolute; z-index: 6; top: calc(var(--gut) + 8px); inset-inline-end: calc(var(--gut) + 8px);
  display: inline-flex; align-items: center; gap: 4px;
  max-width: calc(100% - 2 * var(--gut) - 16px);
  min-height: 32px; padding: 4px; padding-inline-end: 10px; border-radius: var(--r-pill);
  background: var(--surface); color: var(--ink);
  box-shadow: inset 0 0 0 1px var(--line), var(--shadow-1);
  font-size: var(--fs-s); font-weight: var(--fw-b); line-height: 1.5;
  pointer-events: none;
  animation: kit-fade var(--t-med) var(--ease);
  transition: opacity var(--t-med) var(--ease);
}
.spk.is-quiet { opacity: 0; }
.spk-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding-inline-start: 2px; }
.spk[data-kind="teacher"] .spk-text { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.spk-ini {
  display: grid; place-items: center; flex: none; width: 24px; height: 24px; border-radius: 50%;
  background: var(--speak-soft); color: var(--speak-ink); font-size: var(--fs-xs); font-weight: var(--fw-x); line-height: 1;
}
.spk .lvl { height: 14px; gap: 2px; }
.spk .lvl i { width: 3px; background: var(--speak); }
.spk .lvl i:is(:nth-child(1), :nth-child(5)) { display: none; }
.spk:is([data-kind="turn"], [data-kind="off"]) .lvl { display: none; }

/* ---------- voice levels ---------- */
.lvl { --l: 0; display: inline-flex; align-items: center; gap: 3px; height: 20px; flex: none; }
.lvl i {
  display: block; width: 3px; height: 100%; border-radius: 2px;
  background: var(--speak);
  transform: scaleY(.2);
  transition: transform .12s ease-out;
}
.lvl i:nth-child(1), .lvl i:nth-child(5) { transform: scaleY(max(.2, min(.6, calc(var(--l) * .7)))); }
.lvl i:nth-child(2), .lvl i:nth-child(4) { transform: scaleY(max(.2, min(.85, calc(var(--l) * 1)))); }
.lvl i:nth-child(3) { transform: scaleY(max(.2, min(1, calc(var(--l) * 1.3)))); }

/* ---------- a student's floor, in words above the bar ---------- */
.floor {
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  padding: 10px 18px; border-radius: var(--r-pop);
  background: var(--surface-raised); color: var(--ink);
  text-align: center; box-shadow: var(--shadow-2);
  animation: kit-pop var(--t-med) var(--ease);
}
.floor[hidden] { display: none; }
.floor .lead { display: inline-flex; align-items: center; gap: 8px; margin: 0; font-size: var(--fs-sm); font-weight: var(--fw-b); line-height: 1.6; }
.floor .lead.live { color: var(--speak-ink); }
.floor .hint { margin: 0; font-size: var(--fs-s); }
.floor .notice { margin: 0; padding: 0; background: none; font-size: var(--fs-sm); }
.floor .lvl { height: 18px; }
.floor-sub { margin: 0; color: var(--muted); font-size: var(--fs-s); line-height: 1.5; }
.room[data-floor="hand"] .floor { box-shadow: var(--shadow-2), inset 0 0 0 1px var(--hand-line); }
.room[data-floor="hand"] .floor .lead { color: var(--hand-ink); }
/* «نوبت توئه!» (round 1 design #2): a plain card with one big line; the only saturated green is the button and its ring. */
.room[data-floor="offered"] .floor { background: var(--surface); box-shadow: var(--shadow-2); }
.room[data-floor="offered"] .floor .lead { color: var(--speak-ink); font-size: var(--fs); font-weight: var(--fw-x); }
.room[data-floor="muted"] .floor { box-shadow: var(--shadow-2), inset 0 0 0 1px var(--hand-line); }
.room[data-floor="muted"] .floor .notice { color: var(--hand-ink); }

/* The hands chip, for the teacher (A2 T2): the oldest hand, «+۲» for the rest, «اجازه» in one tap; it stays while
   hands wait and the hands list is out of sight. The amber disc and the hand glyph carry it, the name says who. */
.hand-toast {
  display: flex; align-items: center; gap: 6px;
  max-width: min(420px, 100%);
  padding: 4px; border-radius: var(--r-pill);
  background: var(--surface-raised); color: var(--ink); box-shadow: var(--shadow-2), inset 0 0 0 1.5px var(--hand-line);
  font-size: var(--fs-sm);
}
.hand-toast[hidden] { display: none; }
.ht-who {
  appearance: none; flex: 1 1 auto; min-width: 0;
  display: inline-flex; align-items: center; gap: 8px;
  min-height: 44px; padding: 0 10px 0 2px; border: 0; border-radius: var(--r-pill);
  background: transparent; color: inherit; font: inherit; cursor: pointer; touch-action: manipulation;
}
@media (hover: hover) { .ht-who:hover { background: var(--hover); } }
.ht-ic { flex: none; display: grid; place-items: center; width: 40px; height: 40px; border-radius: 50%; background: var(--hand); color: var(--on-hand); }
.ht-ic .ic { width: 22px; height: 22px; stroke-width: 2; }
.ht-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ht-text b { font-weight: var(--fw-x); }
.ht-more { flex: none; color: var(--muted); font-weight: var(--fw-b); font-variant-numeric: tabular-nums; }
.hand-toast .btn.tiny { flex: none; min-width: 76px; min-height: 44px; border-radius: var(--r-pill); }

/* ---------- the bottom bar ---------- */
.cbar {
  flex: none;
  position: relative; z-index: 12;
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 8px;
  min-height: var(--cbar-h);
  padding: 6px max(var(--gut), env(safe-area-inset-right)) max(6px, env(safe-area-inset-bottom)) max(var(--gut), env(safe-area-inset-left));
  background: var(--surface);
  border-top: 1px solid var(--line);
}
.cbar-group { display: flex; align-items: center; gap: 6px; min-width: 0; }
.cbar-me { justify-self: start; }
.cbar-stage { justify-self: center; }
.cbar-room { justify-self: end; grid-column: 3; }
.room[data-role="student"] .cbar { grid-template-columns: 1fr auto 1fr; }
.room[data-role="student"] .cbar-me { grid-column: 2; justify-self: center; }
.cb-slot { display: contents; }
.cb-slot[hidden] { display: none; }
.stg-switch { display: flex; align-items: center; gap: 4px; }
/* Groups by spacing only: mic and camera · the stage · hands, people, chat · «بیشتر» · the end. */
.cbar-sep { width: 14px; height: 1px; }
.cbar-room > .cb-more { margin-inline-start: 14px; }

/* One bar button: an icon alone (the owner: as minimal as it can be, the lesson keeps the eye). Its name stays the
   button's accessible name (.cb-label, out of sight) and shows as the kit's tooltip (ui.js: a mouse resting, the
   keyboard's focus, a long press on a touch screen). Every bar button has the same 48px shape and states: hover
   tint, press, focus ring; "open" or "chosen" (the panel it opens, what is on the stage) in turquoise; "on the air"
   (my mic, my camera, my screen) in green; "off and it matters" (my mic) in red. */
.cb {
  appearance: none; position: relative;
  display: inline-flex; flex-direction: column; align-items: center; justify-content: center;
  min-width: 48px; min-height: 48px; padding: 2px;
  border: 0; border-radius: var(--r-pill);
  background: transparent; color: var(--muted);
  font-size: var(--fs-xs); font-weight: var(--fw-m); line-height: 1.35;
  cursor: pointer; touch-action: manipulation;
  -webkit-touch-callout: none; -webkit-user-select: none; user-select: none;
}
.cb:focus-visible { outline-offset: 0; }
.cb-ic {
  position: relative;
  display: grid; place-items: center;
  width: 44px; height: 44px; border-radius: var(--r-pill);
  color: var(--ink);
  transition: background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease), box-shadow var(--t-fast) ease-out, transform var(--t-fast) var(--ease);
}
.cb-ic .ic { width: 24px; height: 24px; }
.cb-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); opacity: 0; white-space: nowrap; pointer-events: none; }
.cb:disabled { opacity: .45; cursor: default; }
@media (hover: hover) { .cb:not(:disabled):hover .cb-ic { background: var(--hover); } }
.cb:not(:disabled):active .cb-ic { background: var(--press); transform: scale(.94); }
.cb[aria-pressed="true"] .cb-ic, .cb[aria-expanded="true"] .cb-ic { background: var(--accent-soft); color: var(--accent-ink); }
.cb[aria-pressed="true"] .cb-label, .cb[aria-expanded="true"] .cb-label { color: var(--accent-ink); }
/* The mic: crossed and red while off; green with a ring that follows the voice while on. */
.cb-mic[data-state="off"] .cb-ic, .cb-mic:not([data-state]) .cb-ic { background: var(--danger-soft); color: var(--danger-ink); }
.cb-mic[data-state="off"] .cb-label { color: var(--danger-ink); }
.cb-mic[data-state="on"] .cb-ic { --l: 0; background: var(--speak-soft); color: var(--speak-ink); box-shadow: 0 0 0 calc(var(--l) * 5px) var(--speak-line); }
.cb-mic[data-state="on"] .cb-label { color: var(--speak-ink); }
.cb-mic[data-state="wait"] .cb-ic { background: var(--bg-sunken); color: var(--muted); }
@media (hover: hover) {
  .cb-mic[data-state="off"]:not(:disabled):hover .cb-ic { background: var(--danger-line); }
  .cb-mic[data-state="on"]:not(:disabled):hover .cb-ic { background: var(--speak-line); }
}
/* The camera and the share read like a voice on the air while on. */
.cam-tile[data-state="on"] .cb-ic, .stg-share[aria-pressed="true"] .cb-ic { background: var(--speak-soft); color: var(--speak-ink); }
.cam-tile[data-state="on"] .cb-label, .stg-share[aria-pressed="true"] .cb-label { color: var(--speak-ink); }
.cam-tile:is([data-state="lost"], [data-state="fail"], [data-state="denied"], [data-state="nodevice"]) .cb-ic,
.stg-share:is([data-state="lost"], [data-state="fail"]) .cb-ic { background: var(--hand-soft); color: var(--hand-ink); }
.cam-tile .cam-prev, .cam-tile .cam-txt { display: none !important; }
/* The hands: amber while someone waits; a lock badge while the floor is locked. */
.cb-hands[data-on="1"] .cb-ic { background: var(--hand-soft); color: var(--hand-ink); }
.cb-hands[data-on="1"] .cb-label { color: var(--hand-ink); }
.cb-hands[data-locked="1"] .cb-ic::after, .cb-thumb.locked .cb-ic::after {
  content: ""; position: absolute; bottom: -2px; inset-inline-start: 4px;
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--hand) var(--badge-lock) center / 10px no-repeat;
  box-shadow: 0 0 0 2px var(--surface);
}
.nbadge {
  position: absolute; top: 0; inset-inline-end: 0; /* inside the button's own box: never over a neighbour */
  min-width: 18px; height: 18px; padding: 0 5px;
  display: grid; place-items: center;
  border-radius: var(--r-pill);
  background: var(--ink-2); color: var(--surface);
  font-size: var(--fs-badge); font-weight: var(--fw-x); line-height: 1;
  box-shadow: 0 0 0 2px var(--surface);
  animation: kit-pop var(--t-med) var(--ease);
}
.nbadge:empty { display: none; }
.hand-n { background: var(--hand); color: var(--on-hand); }
.chat-nbadge { background: var(--accent); color: var(--on-accent); }
.cb-leave .cb-ic { color: var(--muted); }

/* «پایان کلاس»: set apart by space, a red icon (its «کلاس برای همه تموم بشه؟» asks before anything happens). */
.cb-end { flex-direction: row; gap: 6px; min-height: 44px; padding: 0 16px 0 14px; border-radius: var(--r-pill); background: var(--danger); color: var(--on-solid); }
.cb-end .cb-ic { width: auto; height: auto; background: none !important; color: inherit; transform: none !important; }
.cb-end .cb-ic .ic { width: 20px; height: 20px; stroke-width: 2.25; }
.cb-end .cb-label { position: static; width: auto; height: auto; overflow: visible; clip-path: none; opacity: 1; color: inherit !important; font-size: var(--fs-label); font-weight: var(--fw-x); }
.cb-end:not(:disabled):active { transform: scale(.97); }
@media (hover: hover) { .cb-end:not(:disabled):hover { background: var(--danger-hover); } }

/* A student's one button: big, in the thumb zone. */
.cb-thumb {
  flex-direction: row; gap: 10px;
  min-width: 184px; min-height: 52px; padding: 0 24px 0 20px;
  border-radius: var(--r-pill);
  background: var(--accent); color: var(--on-accent);
  font-size: var(--fs); font-weight: var(--fw-x);
  box-shadow: 0 2px 8px rgba(25, 124, 124, .22);
  transition: background-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease), transform var(--t-fast) var(--ease);
}
.cb-thumb .cb-ic { width: auto; height: auto; background: none !important; color: inherit; transform: none !important; }
.cb-thumb .cb-ic .ic { width: 24px; height: 24px; }
.cb-thumb .cb-label { position: static; width: auto; height: auto; overflow: visible; clip-path: none; opacity: 1; color: inherit !important; }
.cb-thumb:not(:disabled):active { transform: scale(.97); }
@media (hover: hover) { .cb-thumb:not(:disabled):hover { background: var(--accent-hover); } }
.cb-thumb.hand-up { background: var(--hand-soft); color: var(--hand-ink); box-shadow: inset 0 0 0 1.5px var(--hand-line); }
.cb-thumb.ready {
  background: var(--speak); color: var(--on-solid);
  box-shadow: 0 0 0 0 var(--speak-line);
  animation: room-offer 1.6s ease-in-out infinite;
}
.cb-thumb.ready:disabled { animation: none; }
/* The offer's time left: a thin line along the button's foot that drains from the start side to nothing; the seconds
   show as a small ringed number in the mic icon's place only in the last 10 s, so the button keeps its width. */
.cb-thumb.ready { position: relative; }
.ready-drain {
  position: absolute; inset-inline: 22px; bottom: 6px; height: 3px; border-radius: 2px;
  background: var(--speak-line); transform-origin: right center; pointer-events: none;
  animation: ready-drain linear forwards;
}
@keyframes ready-drain { from { transform: scaleX(1); } to { transform: scaleX(0); } }
.ready-left[hidden] { display: none; }
.cb-thumb.ready:has(.ready-left:not([hidden])) .cb-ic { display: none; }
.ready-left {
  order: -1; display: inline-grid; place-items: center; min-width: 26px; height: 26px; padding: 0 3px; border-radius: var(--r-pill);
  box-shadow: inset 0 0 0 1.5px currentColor; font-size: var(--fs-s); font-weight: var(--fw-b); font-variant-numeric: tabular-nums;
}
/* On air (round 1 #5): solid green with an open mic and «تموم شد», a steady ring saying "your voice is out". */
.cb-thumb.giveback { background: var(--speak); color: var(--on-solid); box-shadow: 0 0 0 3px var(--speak-line); }
.room[data-floor="muted"] .cb-thumb.giveback { background: var(--hand-soft); color: var(--hand-ink); box-shadow: inset 0 0 0 1.5px var(--hand-line); }
.cb-thumb.locked { background: var(--bg-sunken); color: var(--muted); box-shadow: none; opacity: 1; }
@keyframes room-offer { 50% { box-shadow: 0 0 0 7px var(--speak-line); } }
@media (hover: hover) {
  .cb-thumb.hand-up:not(:disabled):hover { background: var(--hand-line); }
  .cb-thumb.ready:not(:disabled):hover { background: var(--speak-hover); }
  .room:not([data-floor="muted"]) .cb-thumb.giveback:not(:disabled):hover { background: var(--speak-hover); }
}

/* ---------- «بیشتر» ---------- */
.more-menu {
  position: fixed; z-index: 25;
  bottom: calc(var(--cbar-h) + env(safe-area-inset-bottom) + 8px);
  inset-inline-end: max(12px, env(safe-area-inset-left));
  width: min(360px, 100vw - 24px);
  max-height: calc(100dvh - var(--cbar-h) - var(--rbar-h) - 24px);
  overflow-y: auto; overscroll-behavior: contain;
  display: flex; flex-direction: column; gap: 2px;
  padding: 6px;
  background: var(--surface-raised); color: var(--ink);
  border: 1px solid var(--line); border-radius: var(--r-pop);
  box-shadow: var(--shadow-2);
  transform-origin: bottom left;
  animation: kit-pop var(--t-med) var(--ease);
}
@media (max-width: 959px) { .room[data-role="student"] .more-menu { inset-inline: 0; margin-inline: auto; transform-origin: bottom center; } }
.more-list, .more-extra { display: flex; flex-direction: column; gap: 2px; }
.more-extra:empty { display: none; }
.more-extra:not(:empty) + * { border-top: 1px solid var(--line); padding-top: 4px; margin-top: 2px; }
.more-foot { display: flex; flex-direction: column; gap: 2px; border-top: 1px solid var(--line); padding-top: 4px; margin-top: 2px; }
.more-foot:empty { display: none; }
.more-row, .room .fb-open {
  appearance: none; position: static;
  display: flex; align-items: center; gap: 12px;
  width: 100%; min-height: 48px; padding: 6px 12px;
  border: 0; border-radius: 10px;
  background: transparent; color: var(--ink);
  font-size: var(--fs-sm); font-weight: var(--fw-m); text-align: start;
  cursor: pointer; box-shadow: none;
  transition: background-color var(--t-fast) var(--ease);
}
.more-row .ic, .room .fb-open svg { width: 20px; height: 20px; color: var(--muted); }
.more-row > span { flex: 1 1 auto; min-width: 0; }
.more-row kbd { flex: none; }
@media (hover: hover) { .more-row:hover, .room .fb-open:hover { background: var(--hover); color: var(--ink); border-color: transparent; } }
.more-row:active, .room .fb-open:active { background: var(--press); }
.room .fb-spacer { height: auto; }
.phone-only { display: none; }
/* The teacher's keyboard shortcuts, at the foot of «بیشتر» (only where there is a keyboard). */
.more-keys { display: none; }
@media (hover: hover) and (pointer: fine) {
  .more-keys {
    display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px;
    margin-top: 2px; padding: 10px 12px 6px; border-top: 1px solid var(--line);
    color: var(--muted); font-size: var(--fs-xs); font-weight: var(--fw-m);
  }
  .more-keys > b { flex: 1 1 100%; color: var(--muted); font-weight: var(--fw-b); }
  .more-keys > span { display: inline-flex; align-items: center; gap: 4px; }
}
/* Class tools as rows: an icon, the name and its state, a switch or a button. */
.tool {
  display: flex; align-items: center; gap: 12px;
  min-height: 56px; padding: 6px 6px 6px 12px;
  border: 0; border-radius: 10px;
  background: transparent; min-width: 0;
  transition: background-color var(--t-fast) var(--ease);
}
.tool[hidden] { display: none; }
.tool-ic {
  flex: none; display: grid; place-items: center;
  width: 36px; height: 36px; border-radius: 10px;
  background: var(--bg-sunken); color: var(--muted);
  transition: background-color var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.tool-txt { flex: 1; min-width: 0; display: flex; flex-direction: column; line-height: 1.45; }
.tool-txt b { font-size: var(--fs-sm); font-weight: var(--fw-b); }
.tool-txt small { color: var(--muted); font-size: var(--fs-xs); }
.tool[data-on="1"] .tool-ic { background: var(--hand-soft); color: var(--hand-ink); }
.tool[data-on="1"] small { color: var(--hand-ink); }

/* An on/off switch (a button with aria-pressed; the row's title names it). */
.switch {
  appearance: none; position: relative; flex: none;
  width: 56px; height: var(--tap);
  border: 0; padding: 0; margin: 0;
  background: transparent; cursor: pointer;
  border-radius: var(--r-pill);
  touch-action: manipulation;
}
.switch::before {
  content: ""; position: absolute; inset-inline: 6px; top: 11px; height: 22px;
  border-radius: var(--r-pill); background: var(--line-strong);
  transition: background-color var(--t-med) var(--ease);
}
.switch::after {
  content: ""; position: absolute; top: 14px; inset-inline-start: 9px;
  width: 16px; height: 16px; border-radius: 50%;
  background: var(--knob); box-shadow: 0 1px 3px rgba(0, 0, 0, .3);
  transition: transform var(--t-med) var(--ease);
}
.switch[aria-pressed="true"]::before { background: var(--accent); }
.switch[aria-pressed="true"]::after { transform: translateX(-20px); }
[dir="ltr"] .switch[aria-pressed="true"]::after { transform: translateX(20px); }
.switch:disabled { opacity: .5; cursor: progress; }
.switch:focus-visible { outline-offset: -2px; }

/* ---------- the side panel ---------- */
.room-side {
  flex: none;
  width: var(--side-w);
  display: flex; flex-direction: column; min-height: 0;
  background: var(--surface);
  border-inline-start: 1px solid var(--line);
  animation: kit-fade var(--t-med) var(--ease);
}
.room[data-panel=""] .room-side, .room:not([data-panel]) .room-side { display: none; }
.side-head { flex: none; display: flex; align-items: flex-end; gap: 4px; min-height: 56px; padding: 0 8px 0 12px; border-bottom: 1px solid var(--line); }
.side-head > .side-x { align-self: center; }
.side-tabs { flex: 1 1 auto; min-width: 0; display: flex; align-self: stretch; }
.side-tabs:empty { display: none; }
.side-title { flex: 1 1 auto; align-self: center; display: flex; align-items: center; gap: 8px; margin: 0; font-size: var(--fs); font-weight: var(--fw-x); }
.side-tabs:not(:empty) + .side-title { display: none; }
.side-x { color: var(--muted); }
.side-x .ic { width: 20px; height: 20px; }
.side-pane { flex: 1 1 auto; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 8px 8px 16px; }
.room-side[data-tab="chat"] > .side-pane { display: none; }
.room-side > .chat { padding: 8px 12px 12px; }
.count {
  display: inline-grid; place-items: center;
  min-width: 22px; height: 20px; padding: 0 6px;
  border-radius: var(--r-pill);
  background: var(--bg-sunken); color: var(--muted);
  font-size: var(--fs-xs); font-weight: var(--fw-b); line-height: 1;
}
.count:empty { display: none; }

/* The people search (a class of 12 or more). */
.people-search {
  margin: 4px 4px 8px; width: calc(100% - 8px); min-height: var(--tap);
  padding-inline-start: 40px; border-radius: var(--r-pill);
  background: var(--bg-sunken) var(--ic-search) no-repeat right 14px center / 18px;
  border-color: transparent;
}
[dir="ltr"] .people-search { background-position: left 14px center; }
.people-search:focus { background-color: var(--surface); border-color: var(--accent); }
.people-none { margin: 8px 12px 0; }

/* The participants: the hands first, in the order they came up, with «اجازه» at hand; then everyone else. Each
   person is in one place only. */
.people { display: flex; flex-direction: column; }
.people-list { list-style: none; padding: 0; margin: 0; }
.people-label { margin: 8px 8px 2px; color: var(--muted); font-size: var(--fs-xs); font-weight: var(--fw-b); }
.people-label[hidden] { display: none; }
.prow {
  display: flex; align-items: center; flex-wrap: wrap; gap: 4px 12px;
  min-height: 52px; padding: 6px 8px;
  border-radius: 10px;
  transition: background-color var(--t-fast) var(--ease);
}
.prow[hidden] { display: none; }
@media (hover: hover) { .prow:hover { background: var(--hover); } }
.avatar { position: relative; }
.prow .avatar { width: 36px; height: 36px; font-size: var(--fs-sm); }
.prow[data-role="student"] .avatar { background: var(--bg-sunken); color: var(--ink-2); }
.spk-dot { display: none; }
.prow.speaking .avatar { box-shadow: 0 0 0 2px var(--surface), 0 0 0 4px var(--speak); }
.who { flex: 1 1 96px; min-width: 96px; display: flex; flex-direction: column; gap: 0; line-height: 1.45; }
.pname-row { display: flex; align-items: baseline; gap: 6px; min-width: 0; }
.pname { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: var(--fw-m); font-size: var(--fs-sm); }
.pme { flex: none; color: var(--muted); font-size: var(--fs-xs); font-weight: var(--fw); }
.psub { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--muted); font-size: var(--fs-xs); }
.psub:empty { display: none; }
.psub.live { color: var(--speak-ink); font-weight: var(--fw-b); }
.psub.warn { color: var(--hand-ink); font-weight: var(--fw-b); }
.psub.offer { color: var(--accent-ink); font-weight: var(--fw-b); }
.prow .lvl { height: 16px; gap: 2px; }
.prow .lvl i { width: 3px; }
.prow .acts { display: flex; gap: 4px; flex: none; margin-inline-start: auto; }
.prow .acts .btn.tiny { min-width: var(--tap); padding-inline: 12px; }
.prow .acts .mod-more { width: var(--tap); padding: 0; color: var(--muted); }
/* With a mouse, a row's quiet actions show on hover or focus (the floor's live actions always show). */
@media (hover: hover) and (pointer: fine) {
  .prow .acts > .quiet-act { opacity: 0; transition: opacity var(--t-fast) var(--ease); }
  .prow:hover .acts > .quiet-act, .prow:focus-within .acts > .quiet-act { opacity: 1; }
  /* A row with only quiet actions: they take no room at rest, so the name gets the whole row (round 5 critic #2);
     on hover or focus they come over the row's far end on the panel's ground. */
  .prow { position: relative; }
  .prow .acts:not(:has(> :not(.quiet-act))) {
    position: absolute; inset-inline-end: 8px; top: 50%; transform: translateY(-50%);
    padding-inline-start: 8px; border-radius: 10px;
  }
  .prow:is(:hover, :focus-within) .acts:not(:has(> :not(.quiet-act))) { background: linear-gradient(var(--hover), var(--hover)), var(--surface); }
}

/* The hands: a soft amber group at the top. */
.hands { margin: 0 0 8px; padding: 4px; border-radius: var(--r-pop); background: var(--hand-soft); animation: kit-pop var(--t-med) var(--ease); }
.hands[hidden] { display: none; }
.hands-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-height: var(--tap); padding-inline: 8px 0; }
.hands-head h3 { display: flex; align-items: center; gap: 6px; margin: 0; font-size: var(--fs-s); font-weight: var(--fw-x); color: var(--hand-ink); }
.hands-head h3 .ic { width: 18px; height: 18px; }
.hands .count { background: var(--surface); color: var(--hand-ink); }
.hands .btn.quiet { color: var(--hand-ink); }
@media (hover: hover) { .hands .btn.quiet:hover { background: var(--hand-line); color: var(--hand-ink); } }
.hand-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
.hand-list .prow { background: var(--surface); box-shadow: var(--shadow-1); padding-inline-start: 6px; }
@media (hover: hover) { .hand-list .prow:hover { background: var(--surface); } }
.qn {
  flex: none; display: grid; place-items: center;
  width: 24px; height: 24px; border-radius: 50%;
  background: var(--hand-soft); color: var(--hand-ink); font-weight: var(--fw-x); font-size: var(--fs-xs);
}
.hand-list .prow:first-child .qn { background: var(--hand); color: var(--on-hand); }
.since { color: var(--hand-ink); font-size: var(--fs-xs); line-height: 1.4; }
.since:empty { display: none; }
.hand-list .btn.tiny:not(.mod-more) { min-width: 72px; }
.dropped-box:empty, .dropped-box > [hidden] { display: none; }
.dropped-box .notice { font-size: var(--fs-s); margin: 0 0 8px; }
.people-empty { margin: 8px 0 0; }
.mod-locked { margin: 0 0 8px; }

/* ---------- sheets: the connection details, «پایان کلاس؟» ---------- */
.sheet {
  position: fixed; inset: 0; z-index: 30;
  display: flex; align-items: flex-end; justify-content: center;
  background: var(--scrim);
  animation: kit-fade var(--t-med) var(--ease);
}
.sheet-card {
  width: 100%; max-width: 440px;
  max-height: 90dvh; overflow-y: auto;
  background: var(--surface-raised); color: var(--ink);
  border-radius: var(--r-sheet) var(--r-sheet) 0 0;
  padding: 24px 20px max(20px, env(safe-area-inset-bottom));
  box-shadow: var(--shadow-3);
  animation: kit-rise var(--t-med) var(--ease);
}
.sheet-card h2 { margin: 0 0 8px; font-size: var(--fs-md); font-weight: var(--fw-x); }
.sheet-card .hint { margin-bottom: 16px; }
.sheet-row { display: flex; gap: 8px; flex-wrap: wrap; }
.sheet-row > .btn { flex: 1 1 140px; }
@media (min-width: 600px) {
  .sheet { align-items: center; }
  .sheet-card { border-radius: var(--r-sheet); animation-name: kit-pop; }
}
.conn-state { display: flex; align-items: center; gap: 10px; margin: 0 0 2px; font-size: var(--fs-md); }
.conn-dot { flex: none; width: 12px; height: 12px; border-radius: 50%; background: var(--faint); }
.conn-sheet[data-q="ok"] .conn-dot { background: var(--icon); box-shadow: 0 0 0 4px var(--bg-sunken); }
.conn-sheet[data-q="weak"] .conn-dot { background: var(--hand-ink); box-shadow: 0 0 0 4px var(--hand-soft); }
.conn-sheet[data-q="down"] .conn-dot { background: var(--danger); box-shadow: 0 0 0 4px var(--danger-soft); }
.conn-sheet[data-q="weak"] .conn-head { color: var(--hand-ink); }
.conn-sheet[data-q="down"] .conn-head { color: var(--danger-ink); }
.conn-tip { margin: 0 0 12px; }
.conn-tech { margin: 0 0 16px; padding: 8px 12px; border-radius: var(--r-sm); background: var(--bg-sunken); color: var(--muted); font-size: var(--fs-xs); line-height: 1.7; }
.conn-tech .net { color: var(--ink-2); }

/* ---------- narrow screens (phones, an upright tablet) ---------- */
@media (max-width: 959px) {
  .room { --rbar-h: 56px; --cbar-h: 64px; --gut: 12px; }
  .rbar { gap: 8px; }
  .rbar-title { gap: 10px; }
  .rbar-mark { width: 24px; height: 24px; border-radius: 7px; }
  .rbar-names { flex-direction: column; align-items: flex-start; gap: 0; }
  .rbar h1 { font-size: var(--fs-sm); line-height: 1.45; max-width: 100%; }
  .rbar-sub { font-size: var(--fs-xs); max-width: 100%; }
  .rbar-count { display: none; }
  .room .rec-badge { min-height: 28px; padding: 2px 10px; font-size: var(--fs-xs); }
  .room-main { padding: 0; gap: 0; background: var(--room-ground); color: var(--room-ink); }
  /* On the light ground (round 1 #1): the paper's thin edge, the words that sit on the ground in ink, the floor's
     line a light chip like the pin card. Fullscreen keeps the stage's dark. */
  .room-main .stg-page { box-shadow: var(--room-paper-edge); }
  .room-main :is(.stg-empty, .stg-empty .ic) { color: var(--room-muted); }
  .room-main .stg-pagetag { color: var(--room-ink); }
  .stg.is-max .stg-page { box-shadow: var(--shadow-stage); }
  .stg.is-max :is(.stg-empty, .stg-empty .ic) { color: var(--stage-muted); }
  .stg.is-max .stg-pagetag { color: var(--stage-ink); }
  .stg-frame:fullscreen .stg-page { box-shadow: var(--shadow-stage); }
  .stg-frame:fullscreen :is(.stg-empty, .stg-empty .ic) { color: var(--stage-muted); }
  .stg-frame:fullscreen .stg-pagetag { color: var(--stage-ink); }
  .floor { background: var(--surface); box-shadow: inset 0 0 0 1px var(--line); }
  .room-main > .stg { padding: 0; }
  .stage-notes { padding: 8px var(--gut); }
  .room[data-role="teacher"] .stage-notes { padding: 0; bottom: var(--notes-b, calc(var(--tap) + 20px)); inset-inline: var(--gut); }
  .spk { top: 10px; inset-inline-end: 10px; font-size: var(--fs-xs); }
  .cbar { display: flex; justify-content: space-around; gap: 0; padding-inline: 4px; }
  .cbar-group { display: contents; }
  .cbar-sep { display: none; }
  .cbar-room > .cb-more { margin-inline-start: 0; }
  .cb { min-width: 48px; }
  .room[data-role="teacher"] .cam-slot, .room[data-role="teacher"] .stage-slot { display: none; }
  .phone-only { display: flex; }
  .room[data-role="student"] .cbar { justify-content: space-between; padding-inline: 12px; }
  /* «خروج» lives in «بیشتر» on a phone (and the phone's back asks first): never a mis-tap in the bar's corner. */
  .room[data-role="student"] .cb-leave { display: none; }
  /* A teacher's «پایان» sits at the top bar's far end on a phone (app.js moves it). */
  .rbar > .cb-end { min-height: 44px; padding-inline: 14px 12px; }
  .cb-thumb { min-width: 0; flex: 1 1 auto; max-width: 260px; margin-inline-end: 8px; }
  /* The participants: a sheet over the stage, above the bar. */
  .room-side {
    position: fixed; z-index: 20;
    inset-inline: 0; bottom: calc(var(--cbar-h) + env(safe-area-inset-bottom));
    width: auto; height: min(72dvh, calc(100dvh - var(--cbar-h) - 40px));
    border: 0; border-radius: var(--r-sheet) var(--r-sheet) 0 0;
    box-shadow: 0 -12px 32px rgba(0, 0, 0, .22);
    animation: kit-fade var(--t-med) var(--ease);
  }
  .room-side::before {
    content: ""; position: absolute; top: 6px; left: 50%; width: 36px; height: 4px; margin-left: -18px;
    border-radius: 2px; background: var(--line-strong);
  }
  .room[data-panel="chat"] .room-side { display: none; }
  .room[data-chat-wide="0"] .side-tabs { display: none; }
  .room[data-chat-wide="0"] .side-title { display: flex; }
  .more-menu { bottom: calc(var(--cbar-h) + env(safe-area-inset-bottom) + 6px); }
}


/* A student's one button (A2 S1–S4): an icon in the bar's middle at rest, with hand up (amber, my place in the queue
   on it) and while talking (the same button ends the turn); it grows into «آماده‌ام» when the floor is offered. The
   word stays the button's name and its long-press label. */
.cb-thumb:not(.ready, .giveback) { min-width: 76px; max-width: 76px; flex: none; padding: 0; justify-content: center; }
.cb-thumb:not(.ready, .giveback) .cb-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); opacity: 0; white-space: nowrap; }
.cb-thumb .hand-pos { top: 2px; inset-inline-end: 4px; min-width: 22px; height: 22px; background: var(--hand); color: var(--on-hand); box-shadow: 0 0 0 2px var(--surface); }
.room[data-floor="offered"] .floor .lead.turn-lead { font-size: var(--fs-display); font-weight: var(--fw-x); line-height: 1.35; color: var(--speak-ink); }
@media (max-width: 959px) {
  /* The bar, right to left: chat · reactions · the hand (the middle) · bigger · more (A2 S1). */
  .room[data-role="student"] .cbar { justify-content: space-around; padding-inline: 8px; }
  .room[data-role="student"] .cbar #chat-open { order: 1; }
  .room[data-role="student"] .cbar #react-open { order: 2; }
  .room[data-role="student"] .cbar .cb-thumb { order: 3; margin: 0; }
  .room[data-role="student"] .cbar .cb-thumb.ready { flex: 1 1 auto; max-width: 240px; min-width: 150px; }
  .room[data-role="student"] .cbar .cb-thumb.giveback { flex: 0 1 auto; min-width: 124px; max-width: 200px; padding-inline: 18px 16px; }
  .room[data-role="student"] .cbar .cb-big { order: 4; }
  .room[data-role="student"] .cbar .cb-more { order: 5; }
}
/* A narrow phone (320–400 px: the SE, small Androids): every button stays on screen with ≥8 px to the edges (and the
   safe areas). The side icons keep the 44 px tap minimum; the turn's button («آماده‌ام» / «تموم شد») gives up its
   minimum width and some padding, and its word never pushes a neighbour off. */
@media (max-width: 400px) {
  .room[data-role="student"] .cbar {
    justify-content: space-between; gap: 2px;
    padding-inline: max(8px, env(safe-area-inset-right)) max(8px, env(safe-area-inset-left));
  }
  .room[data-role="student"] .cbar .cb:not(.cb-thumb) { min-width: var(--tap); width: var(--tap); flex: none; }
  .room[data-role="student"] .cbar .cb-thumb:is(.ready, .giveback) { min-width: 0; flex: 1 1 auto; gap: 8px; padding-inline: 14px 12px; }
  .room[data-role="student"] .cbar .cb-thumb:is(.ready, .giveback) .cb-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}
/* A teacher's phone bar, right to left: the people (the hands waiting as its badge) · the mic (the middle) · the chat ·
   «بیشتر» (A2 T1); «دست‌ها» is the floating chip, «پایان» the top bar's. */
@media (max-width: 959px) {
  .room[data-role="teacher"] .cbar #hands-open { display: none; }
  .room[data-role="teacher"] .cbar #people-open { order: 1; }
  .room[data-role="teacher"] .cbar #speak { order: 2; }
  .room[data-role="teacher"] .cbar #chat-open { order: 3; }
  .room[data-role="teacher"] .cbar .cb-more { order: 4; }
  .room[data-role="teacher"] .cbar #speak .cb-ic { width: 64px; }
}
@media (min-width: 960px) { .people-hands { display: none !important; } }
/* A teacher's laptop (round 1, design 5): one centred cluster [mic · camera · the stage · hands · people · chat · ⋯]
   with «پایان» alone at the far end (left). From 1024px the top bar steps down into the bar's start (right) as one
   quiet line (the title, the clock, the rec chip, the signal bars), and the lesson gets its 56px. */
@media (min-width: 960px) {
  .room[data-role="teacher"] .cbar { display: flex; justify-content: center; gap: 16px; }
  .room[data-role="teacher"] .cbar-room > .cb-more { margin-inline-start: 0; }
  /* «تنظیمات کلاس» stays in «⋯» (and on S); the bar keeps the class's own tools. */
  .room[data-role="teacher"] .cbar #set-open { display: none; }
  .room[data-role="teacher"] .more-menu { inset-inline-end: auto; left: clamp(12px, var(--more-l, 12px), calc(100vw - 372px)); }
  .room[data-role="teacher"] .cbar-end {
    position: absolute; top: 0; bottom: max(6px, env(safe-area-inset-bottom)); padding-top: 6px;
    inset-inline-end: max(var(--gut), env(safe-area-inset-left));
  }
  /* «پایان» quiet at rest, like the phone (round 4): the power glyph alone in the danger ink with a thin danger ring;
     its name is the tip; it fills only under the mouse or the keyboard's focus, and it still asks first. */
  .room[data-role="teacher"] .cbar-end > .cb-end {
    width: 48px; min-width: 48px; min-height: 48px; padding: 0;
    background: transparent; color: var(--danger-ink); box-shadow: inset 0 0 0 1.5px var(--danger-line);
  }
  .room[data-role="teacher"] .cbar-end > .cb-end .cb-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); opacity: 0; }
  .room[data-role="teacher"] .cbar-end > .cb-end .cb-ic .ic { width: 22px; height: 22px; }
  .room[data-role="teacher"] .cbar-end > .cb-end:focus-visible { background: var(--danger); color: var(--on-solid); box-shadow: none; }
  @media (hover: hover) { .room[data-role="teacher"] .cbar-end > .cb-end:not(:disabled):hover { background: var(--danger); color: var(--on-solid); box-shadow: none; } }
}
@media (min-width: 1024px) {
  .room[data-role="teacher"] { --rbar-h: 0px; position: relative; }
  .room[data-role="teacher"] > .rbar {
    position: absolute; z-index: 13; bottom: 0; inset-inline-start: 0;
    max-width: calc(50% - 300px); min-height: var(--cbar-h); gap: 8px;
    padding: 6px max(var(--gut), env(safe-area-inset-right)) max(6px, env(safe-area-inset-bottom)) 0;
    background: none; border: 0; pointer-events: none;
  }
  .room[data-role="teacher"] > .rbar > * { pointer-events: auto; }
  .room[data-role="teacher"] > .rbar .rbar-mark { display: none; }
  .room[data-role="teacher"] > .rbar h1 { font-size: var(--fs-s); font-weight: var(--fw-b); color: var(--muted); }
  .room[data-role="teacher"] > .rbar .rbar-count { display: none; }
}
@media (min-width: 1024px) and (max-width: 1279px) { .room[data-role="teacher"] > .rbar .rbar-names > h1 { display: none; } }
@media (max-width: 959px) and (orientation: portrait) {
  .room[data-role="student"] #stage-big, .room[data-role="student"] .stg-turn { display: none !important; }
}
@media (max-width: 959px) and (orientation: landscape) { .cb-big { display: none !important; } }

/* An upright phone (A2 §3): the lesson is anchored under the top bar, full width, and never moves; the dark band
   under it holds the class (who speaks, the floor's words, the last lines, the sheets at half). */
@media (max-width: 959px) and (orientation: portrait) {
  .room .stg-view { align-items: flex-start; }
  /* The speaking chip sits on the lesson's top corner (stage.js --lesson-t), not in the band. */
  .room-main > #speaking.is-chip { top: calc(var(--lesson-t, 0px) + 8px); }
  /* A student's sits at the head of the class strip under the lesson instead (round 4, r1 #25; overlay.css). */
  .room[data-role="student"] .room-main > #speaking.is-chip[data-kind] { top: calc(var(--lesson-b, 0px) + 12px); inset-inline: 10px auto; }
  /* The notes (the hands chip, the floor's words, the toasts) take the band's foot: the page stays where it is. */
  .room[data-role="teacher"] .stage-notes { position: static; padding: 8px var(--gut); pointer-events: auto; }
}

/* A phone on its side: the stage takes the screen; the bars are slim. */
@media (max-width: 959px) and (max-height: 540px) and (orientation: landscape) {
  .room { --rbar-h: 44px; --cbar-h: 56px; }
  .rbar { min-height: var(--rbar-h); padding-block: 0; }
  .rbar-names { flex-direction: row; align-items: baseline; gap: 10px; }
  .rbar h1 { font-size: var(--fs-s); }
  .cb-thumb { min-height: var(--tap); max-width: 220px; }
  .room-side { height: calc(100dvh - var(--cbar-h) - 8px); }
  .room-side::before { display: none; }
  /* The floor's words and the messages float over the stage's foot instead of taking a row. */
  .room[data-role="student"] .stage-notes { position: absolute; z-index: 6; inset-inline: 8px; bottom: 6px; padding: 0; pointer-events: none; }
  .room[data-role="student"] .stage-notes > * { pointer-events: auto; }
  .floor { padding: 4px 14px; }
  .floor .lead { font-size: var(--fs-s); }
  .room[data-floor="offered"] .floor .lead { font-size: var(--fs-sm); }
  /* A student's lesson takes the whole screen (A2 S12): the top bar floats over it and steps away after a few quiet
     seconds (a tap brings it back); the hand, the chat and the rest float as one small pill in the holding thumb's
     corner, the hand and the chat always there. Nothing moves the lesson. */
  .room[data-role="student"] .rbar { position: absolute; top: 0; inset-inline: 0; z-index: 16; box-shadow: var(--shadow-2); }
  .room[data-role="student"] .cbar {
    position: absolute; z-index: 16;
    bottom: max(8px, env(safe-area-inset-bottom)); inset-inline-start: max(8px, env(safe-area-inset-right)); inset-inline-end: auto;
    width: auto; min-height: 0; padding: 4px; gap: 2px;
    border: 0; border-radius: var(--r-pill);
    background: var(--surface); box-shadow: var(--shadow-2);
  }
  .room[data-role="student"] .cbar .cb-thumb { flex: none; min-width: 64px; max-width: 200px; margin: 0; }
  .room[data-chrome="off"] .rbar, .room[data-chrome="off"] .stg-bar,
  .room[data-role="student"][data-chrome="off"] .cbar :is(.react-slot, .cb-more) { display: none; }
  .room[data-chrome="off"] .spk { top: 8px; }
  .room[data-role="student"] .stage-notes { bottom: calc(max(8px, env(safe-area-inset-bottom)) + 64px); }
  /* A teacher's class rail on the inline start (A2 T8: the mic, the people, the chat, «بیشتر»); the lesson beside it. */
  .room[data-role="teacher"] .cbar {
    position: absolute; z-index: 12;
    top: var(--rbar-h); bottom: 0; inset-inline-start: 0; inset-inline-end: auto;
    width: calc(64px + env(safe-area-inset-right)); min-height: 0;
    flex-direction: column; justify-content: center; gap: 4px;
    padding: 4px 0; padding-inline-start: env(safe-area-inset-right);
    border-top: 0; border-inline-end: 1px solid var(--line);
  }
  .room[data-role="teacher"] .room-body { margin-inline-start: calc(64px + env(safe-area-inset-right)); }
  .room[data-role="teacher"] .cbar #speak .cb-ic { width: 44px; } /* the rail is 64 px wide */
  /* The stage's «بزرگ‌تر» and the banners keep clear of the pill and the floating top bar. */
  .room[data-role="student"] .stg-bar { inset-inline-start: auto; inset-inline-end: 6px; }
  .room[data-role="student"] > :is(.conn-banner, .rejoin, .pj-unlock, .pj-note, .catchup) {
    position: absolute; z-index: 15; top: calc(var(--rbar-h) + 6px); inset-inline: var(--gut); margin: 0;
  }
  /* A sheet is a side sheet at the inline end; the lesson keeps the rest (sheet.js data-side). */
  .room[data-sheet]:not([data-sheet=""]) .room-body { margin-inline-end: min(38vw, 340px); }
}

/* Reduced motion keeps feedback (short fades through the tokens, motion.css); only the loops stop here. */
@media (prefers-reduced-motion: reduce) {
  #conn[data-q="wait"]::before { animation: none; }
  .lvl i, .switch::after { transition: none; }
}
:root[data-motion="reduce"] #conn[data-q="wait"]::before { animation: none; }
.prow[data-hand]:not([data-hand="0"]) .avatar { background: var(--hand-soft); color: var(--hand-ink); }
.hand-list .prow .avatar { display: none; }
@media (max-width: 959px) { .more-keys { display: none !important; } }
