/* Small, global invariants only. Component and page selectors deliberately
   stay out of this file so a feature cannot accidentally acquire new layout
   merely because it shares an HTML element with another screen. */
* { box-sizing: border-box; }
html, body { height: 100%; }

/* Scrollbars are a useful affordance, not a separate white panel. Keep the
   track transparent so it works on paper, raised cards and every theme. The
   thumb resolves --muted HERE, not in :root (body owns the chosen palette).
   No overflow changes, hidden scrollbars or JavaScript scroll imitation. */
* { scrollbar-color: color-mix(in srgb, var(--muted) 82%, transparent) transparent; }
/* Chromium now supports the standard color property too; a non-auto value
   overrides its WebKit styling. Prefer the latter where available so rounded
   thumbs can sit away from a card's rounded ends. Firefox keeps native shape
   and width. Existing deliberately hidden tab/menu rails still win. */
@supports selector(::-webkit-scrollbar) {
  * { scrollbar-color: auto; }
  *::-webkit-scrollbar { width: 12px; height: 12px; background: transparent; }
  *::-webkit-scrollbar-track { background: transparent; margin: 12px; }
  *::-webkit-scrollbar-thumb {
    background: color-mix(in srgb, var(--muted) 82%, transparent);
    background-clip: padding-box;
    border: 3px solid transparent;
    border-radius: 999px;
  }
  *::-webkit-scrollbar-thumb:hover, *::-webkit-scrollbar-thumb:active { background-color: var(--ink); }
  *::-webkit-scrollbar-corner { background: transparent; }
}
/* Preserve the user's accessibility palette and larger native hit areas. */
@media (forced-colors: active), (prefers-contrast: more) {
  * { scrollbar-color: auto; }
  *::-webkit-scrollbar, *::-webkit-scrollbar-track,
  *::-webkit-scrollbar-thumb, *::-webkit-scrollbar-corner { all: revert; }
}

/* The hidden attribute must ALWAYS win. Without this, any rule that sets
   display (e.g. .register{display:grid}) silently overrides [hidden] — which
   is exactly how the master-key section leaked onto the public login page. */
[hidden] { display: none !important; }
.ac-defs { position: absolute; }

body {
  margin: 0;
  background-color: var(--paper);
  /* Subtle texture: a faint hairline grid, low-contrast so content stays king. */
  background-image:
    linear-gradient(var(--grid) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid) 1px, transparent 1px);
  background-size: 30px 30px;
  color: var(--ink);
  font-family: var(--font);
  font-weight: 400; /* variable font defaults to 200; keep body readable */
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

/* Reduced motion: zeroing the shared duration tokens collapses every
   token-driven transition and entrance app-wide in one place. Features
   that still hard-code a duration keep their own local guards. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --motion-fast: 0ms;
    --motion-med: 0ms;
  }
}

/* Session display names (docs/STUDENT-NAMES.md). One renderer draws every
   student label — teacher rail, student header, games — so the rules live in
   the foundation rather than being restated per surface.

   The number is always present and always visually subordinate: it is the
   durable identity, the name is the courtesy. `rt` carries the furigana a
   student confirmed, never a reading we guessed. */
.member-label { display: inline-flex; align-items: baseline; gap: 0.35em; min-width: 0; }
.member-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.member-name ruby { ruby-position: over; }
.member-name rt {
  font-size: 0.52em; font-weight: 600; letter-spacing: 0.02em;
  opacity: 0.78; /* furigana supports the name; it must not compete with it */
}
/* Browsers without <ruby> fall back to the <rp> brackets, which should read as
   quietly as the furigana would. */
.member-name rp { font-size: 0.6em; opacity: 0.7; }
.member-number { flex: none; font-size: 0.78em; font-weight: 700; opacity: 0.72; font-variant-numeric: tabular-nums; }

/* The Atelier press (docs/GAME-FEEL.md §1, web/static/core/press.js).
   Foundation rather than component: a committing control behaves the same way
   in every game, and the rule is about the student's hand rather than about any
   one screen — which is the same argument .member-label makes above.

   .press-target guarantees the 44x44px Apple has published as the minimum
   since the first iPhone, WITHOUT forcing the label to grow. A confirm on a
   crowded board may be small type; it may not be a small target. */
.press-target {
  min-height: 44px;
  min-width: 44px;
  /* Touch-action stops iPadOS treating a quick second tap on the control as a
     double-tap-to-zoom gesture, which delays the click by ~300ms and is the
     other half of why fast taps feel unreliable on these screens. */
  touch-action: manipulation;
}

/* A control inside an arming window is inert (press.js swallows the input);
   this makes that legible instead of mysterious. The buttons visibly settle
   for exactly as long as they are refusing, so a student who taps too fast
   sees an arrival rather than a dead button.

   Kept to the buttons rather than the container: several of these overlays
   already run their own entrance animation, and two transforms on one element
   compound into a wobble. */
.is-arming button,
.is-arming .btn {
  animation: press-settle 350ms var(--ease-out) both;
}
@keyframes press-settle {
  from { opacity: 0.5; transform: translateY(3px); }
  to   { opacity: 1; transform: none; }
}
/* A literal duration cannot be collapsed by zeroing the motion tokens, so this
   one needs its own guard. The window itself is unaffected — the protection is
   in the event handler, never in the animation. */
@media (prefers-reduced-motion: reduce) {
  .is-arming button,
  .is-arming .btn { animation: none; }
}

/* ---- themed dialogs (core/dialog.js) -----------------------------------
   HERE, not in style.css, because core/dialog.js is imported by the STUDENT
   bundle too and style.css is the teacher app's alone. It lived there until
   2026-09-12, when the owner photographed a confirm on a real iPad rendering
   as a bare unstyled div at the top of the page, pushing the lesson down: the
   markup was fine and there was simply no rule for it on that page. base.css
   is loaded by every surface, which is the property this needs.

   See also .popconfirm in css/pages/live.css — the anchored Yes/No that
   replaced the modal wherever a student confirms something on a board. */
.dlg-host {
  position: fixed;
  inset: 0;
  z-index: 6000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  background: rgba(20, 14, 8, 0.38);
  backdrop-filter: blur(2px);
  animation: dlg-fade var(--motion-fast) var(--ease-out);
}
.dlg {
  width: 100%;
  max-width: 26rem;
  background: var(--raised);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: var(--radius-window);
  box-shadow: var(--shadow-window);
  padding: 1.1rem 1.2rem 1rem;
  animation: dlg-rise var(--motion-med) var(--ease-out);
}
.dlg-title { margin: 0 0 0.4rem; font-size: 1.05rem; font-weight: 700; }
.dlg-msg { margin: 0 0 0.9rem; color: var(--muted); line-height: 1.45; overflow-wrap: anywhere; }
.dlg-input { width: 100%; margin-bottom: 0.9rem; }
.dlg-row { display: flex; justify-content: flex-end; gap: 0.5rem; }
.dlg-btn { min-width: 5.5rem; }
/* Scoped to .dlg: the plain .btn rule in style.css loads after this file at
   the same specificity and was quietly painting every dialog's primary
   button as an ordinary one (found 2026-10-12). */
.dlg .dlg-ok, .dlg .dlg-ok:hover { background: var(--accent-fill); border-color: var(--accent-fill); color: var(--on-accent); }
.dlg-danger .dlg-ok, .dlg-danger .dlg-ok:hover { background: var(--bad-fill); border-color: var(--bad-fill); }
/* Several outcomes stack full width, each a full touch target, so a long
   label never squeezes the others. A destructive one that is not the primary
   still reads as destructive (red text, not a second red fill). */
.dlg-row-choices { flex-direction: column; align-items: stretch; }
.dlg-row-choices .dlg-btn { min-height: 44px; }
.dlg-choice-danger:not(.dlg-ok) { color: var(--bad-text); }
@keyframes dlg-fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes dlg-rise {
  from { opacity: 0; transform: translateY(8px) scale(0.98); }
  to { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .dlg-host, .dlg { animation: none; }
}
