/* ============================================================================
   board.css — the sizing foundation every tool inherits.
   Link this FIRST, before a tool's own styles.

   Written for the browser that is actually in classrooms: Promethean ActivPanel
   and SMART Board panels are all 3840x2160, running a Chromium frozen inside
   firmware somewhere between 88 and ~120. Target is Chromium 90.

   ---------------------------------------------------------------------------
   THE ONE IDEA
   ---------------------------------------------------------------------------
   A panel's glass is a fixed physical size, so `1vw` is a fixed number of
   millimetres on that panel — 16.5mm on a 75" — no matter whether the browser
   reports a 1920 or 3840 CSS viewport. `px` and `rem` have no such property,
   and CSS `mm` is a lie on screens (the spec pins 1in to 96px).

   So: derive the ROOT FONT SIZE from viewport units once, then author
   everything in `rem`. rem now means "a fraction of this board", and
   devicePixelRatio stops mattering. That is not a workaround for the 4K
   sizing trap — it removes the whole bug class.

   ---------------------------------------------------------------------------
   THE RULE THAT IS EASIEST TO BREAK
   ---------------------------------------------------------------------------
   Never put a px or rem CEILING on a size.

       font-size: clamp(2.1rem, 4.6vw, 4.2rem);   /* WRONG */

   The 4.6vw is the correct board-proportional term; the 4.2rem ceiling throws
   it away. On a panel reporting 3840 that headline renders at 29mm instead of
   58mm — half its intended physical size. A rem ceiling is a promise that the
   screen is a laptop.

   Floors in px are fine. Ceilings must be in vw, or absent.
   ============================================================================ */

/* --------------------------------------------------------------- the fonts
   Self-hosted, never a CDN. School networks filter aggressively and
   fonts.googleapis.com is a routine casualty — a blocked font request in front
   of nineteen five-year-olds is a board that looks broken. Both files are
   variable, so one download covers every weight we use. 76KB for the pair. */

@font-face {
  font-family: 'Baloo 2';
  src: url('/platform/fonts/baloo2.woff2') format('woff2');
  font-weight: 400 800;
  font-display: swap;
}

@font-face {
  font-family: 'Nunito';
  src: url('/platform/fonts/nunito.woff2') format('woff2');
  font-weight: 400 800;
  font-display: swap;
}

/* ---------------------------------------------------------------- the knob */

:root {
  /* Teacher's size preference, persisted per device. See ToolKit.setScale(). */
  --scale: 1;

  /* The line that makes rem board-relative.
     vw + vh together so that browser chrome eating vertical space barely moves
     it, and so a non-16:9 window still behaves. The 16px floor keeps this same
     stylesheet sane on a laptop or a phone. */
  font-size: calc(var(--scale) * max(16px, 0.55vw + 0.55vh));

  /* Measured by ToolKit, because `dvh` needs Chromium 108 and these panels may
     be on 88. Falls back to 100vh before the script runs. */
  --app-h: 100vh;

  /* Type scale, by who has to read it and from how far away.
     Derived from ISO 9241 legibility guidance at classroom distances. */
  --t-meta: 0.8rem;  /* admin labels — read up close only */
  --t-body: 1rem;    /* controls and buttons — 12-16mm tall */
  --t-name: 2rem;    /* child names, counts — readable from ~3m */
  --t-title: 3.5rem; /* whole-room headline — readable from ~6m */

  /* Touch. 2.6rem is 32mm on a 65" and 42mm on an 86" — comfortably past the
     20mm that research on under-9s asks for, at any DPR.
     Three-year-olds miss by ~4.5mm on average, so the GAP matters as much as
     the size: with no spacing a near-miss becomes the wrong action. */
  --hit: 2.6rem;
  --hit-big: 4rem;
  --hit-gap: 0.75rem;

  /* ----------------------------------------------------------- theme tokens
     Fourteen, and a theme may override ONLY these. Everything above is
     platform-owned, which is the whole point: a re-skin can change how a tool
     looks but cannot make it unusable on a panel. Defaults below mean a theme
     that forgets a token still looks right. */

  /* colour */
  --bg: linear-gradient(180deg, #eef5fc, #dbe9f8);
  --surface: rgba(255, 255, 255, 0.9);
  --ink: #1f3352;
  --ink-soft: #5a7196;
  --accent: #ff2f92;
  --good: #12a150;
  --warn: #d4585b;

  /* type and shape — radius and shadow in rem so they scale with the board */
  --font: 'Nunito', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-display: 'Baloo 2', 'Nunito', system-ui, sans-serif;
  --radius: 1rem;
  --shadow: 0 0.5rem 1.5rem rgba(31, 51, 82, 0.16);

  /* art: one image per avatar variant */
  --art-pink: url('/platform/img/gb-pink.png');
  --art-blue: url('/platform/img/gb-blue.png');
  --art-plain: url('/platform/img/gb-pink.png');
}

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

/* Class-based display rules outrank the UA sheet's [hidden]; restate it. */
[hidden] {
  display: none !important;
}

html,
body {
  margin: 0;
  padding: 0;
}

body {
  font-family: var(--font);
  font-size: var(--t-body);
  color: var(--ink);
  background: var(--bg);
  -webkit-tap-highlight-color: transparent;
  -webkit-text-size-adjust: 100%;
}

/* ------------------------------------------------------------ layout modes */

/* Board mode: fills the panel exactly and NEVER scrolls. If the class does not
   fit, the cards shrink — a scrollbar means a child scrolls half the class off
   screen with no cue that they did. */
body.board {
  height: var(--app-h);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

/* Page mode: ordinary scrolling document. Admin screens, lists, settings. */
body.page {
  min-height: var(--app-h);
  overflow-x: hidden;
}

/* ---------------------------------------------------------------- touching */

.hit {
  min-width: var(--hit);
  min-height: var(--hit);
  padding: 0.5rem 0.9rem;
  touch-action: manipulation; /* kill double-tap zoom precisely, not globally */
}

.hit--big {
  min-width: var(--hit-big);
  min-height: var(--hit-big);
}

.hit-row {
  display: flex;
  gap: var(--hit-gap);
  align-items: center;
}

/* A child-facing card is a poster, not a button. */
.card-child {
  min-height: 8rem;
  touch-action: manipulation;
  user-select: none;
  -webkit-user-select: none;
}

/* Interactive content belongs low: a 5-year-old can reach roughly the bottom
   two-thirds of a wall-mounted panel. Titles and counts go up top, where only
   the teacher can reach anyway. */
.reach-zone {
  margin-top: auto;
}

/* --------------------------------------------------------------- the scale */

.scaler {
  display: inline-flex;
  gap: 0.35rem;
}

.scaler button {
  min-width: var(--hit);
  min-height: var(--hit);
  font: inherit;
  font-weight: 800;
  border-radius: 0.6rem;
  border: 2px solid rgba(0, 0, 0, 0.14);
  background: #fff;
  cursor: pointer;
  touch-action: manipulation;
}

/* ----------------------------------------------------------- performance --
   backdrop-filter works on these panels (Chromium 76) but is banned by policy.
   An ActivPanel 9 drives 8.3 million pixels with a Mali-G52 — a 2019 midrange
   phone GPU behind a cinema screen. A blur samples a large kernel per pixel.
   Use a solid or slightly translucent fill instead; nobody will miss it. */

.panel {
  background: var(--surface);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

/* --------------------------------------------------------------- offline -- */

body.tk-offline::after {
  content: 'Offline — saved on this device, will sync when you reconnect';
  position: fixed;
  left: 50%;
  bottom: 0.5rem;
  transform: translateX(-50%);
  z-index: 60;
  font-size: var(--t-body);
  font-weight: 800;
  color: #8a5a00;
  background: #fff4d6;
  border: 2px solid #ffdf8f;
  padding: 0.4rem 1rem;
  border-radius: 999px;
  pointer-events: none;
  max-width: 92vw;
  text-align: center;
}

/* -------------------------------------------------------------- motion --- */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}

/* No hover on a panel — never hide anything behind it. */
@media (hover: none) {
  .hover-only {
    display: none;
  }
}

/* ------------------------------------------------------------------- tap --
   Added by ToolKit.tap(). Without touch-callout:none a long press pops a
   text-selection loupe instead of marking a child away. */

.tap {
  touch-action: manipulation;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
  cursor: pointer;
}

.tap.is-holding {
  filter: brightness(0.94);
}

/* Board-mode scaffold from the contract's required skeleton. */

.board-app {
  height: var(--app-h);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.board-app__chrome {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: var(--hit-gap);
  /* nowrap on purpose: a wrapped second row overflows this box and the play
     area then renders on top of the teacher's own controls. Let the flexible
     child shrink instead. */
  flex-wrap: nowrap;
  overflow: hidden;
  padding: 0.5rem 0.8rem;
}

/* Everything a child touches lives here — anchored low, because a five-year-old
   can only reach roughly the bottom two-thirds of a wall-mounted panel. */
.board-app__play {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: 0 1rem 1rem;
}
