/* Cool Kids Activities -- the product shell.
 *
 * Used by every surface that is NOT the room: the landing page, sign-in, the
 * entity account page and the platform console. The room-facing screens (the
 * launcher and the game) keep shared/base.css and a bingo skin on purpose --
 * big, themed and readable from the back row is the product. The mistake this
 * file corrects is having FOUR looks across four steps rather than the two that
 * actually mean something.
 *
 * It is a
 * deliberate sibling of shared/base.css, not a layer on top of it: base.css is
 * built for the in-room app (height:100vh, overflow:hidden, a root font size
 * scaled to the viewport so a TV fills edge to edge) and a scrolling account
 * page would have to override nearly all of it.
 *
 * It also does NOT call applyTheme(). The consoles used to inherit whichever
 * bingo skin was last picked, so a director opening their account page could
 * find it dressed as Spooky Night. Colors here are the fixed brand palette,
 * light and dark only.
 */

@font-face { font-family: 'Baloo 2'; font-style: normal; font-weight: 700; font-display: swap; src: url('../fonts/Baloo2-700.ttf') format('truetype'); }
@font-face { font-family: 'Baloo 2'; font-style: normal; font-weight: 800; font-display: swap; src: url('../fonts/Baloo2-800.ttf') format('truetype'); }
@font-face { font-family: 'Nunito'; font-style: normal; font-weight: 400; font-display: swap; src: url('../fonts/Nunito-400.ttf') format('truetype'); }
@font-face { font-family: 'Nunito'; font-style: normal; font-weight: 600; font-display: swap; src: url('../fonts/Nunito-600.ttf') format('truetype'); }
@font-face { font-family: 'Nunito'; font-style: normal; font-weight: 700; font-display: swap; src: url('../fonts/Nunito-700.ttf') format('truetype'); }
@font-face { font-family: 'Nunito'; font-style: normal; font-weight: 800; font-display: swap; src: url('../fonts/Nunito-800.ttf') format('truetype'); }

:root {
  --indigo: #2b2250;
  --indigo-700: #1e173a;
  --indigo-500: #3e2f70;
  --indigo-300: #6b5cc8;
  --coral: #ff686b;
  /* The brand coral is a fill color. As TEXT on a light surface it measures
     2.82:1 -- the wordmark beside the logo was failing AA on every console
     page. Darkened here for text only; --coral itself is untouched, so the
     hero button and the landing page keep the brand tone. The dark scheme
     keeps the bright coral, which already measures 5.72:1 there. */
  --coral-ink: #cc3a3e;
  --yellow: #ffc93c;
  --teal: #4ecdc4;
  --cream: #fff9f0;

  --bg: #f6f4ef;
  --surface: #ffffff;
  --surface-2: #f1eee8;
  --ink: #2b2250;
  --ink-soft: #5b5570;
  --line: #e2ddd4;
  --accent: #3e2f70;
  --accent-ink: #ffffff;
  --ok: #1f7a52;
  --warn: #8a5a00;
  --danger: #c0343a;
  --ok-bg: #e4f4ec;
  --warn-bg: #fdf1d8;
  --danger-bg: #fbe6e7;

  --font-display: 'Baloo 2', 'Segoe UI', system-ui, -apple-system, sans-serif;
  --font-body: 'Nunito', 'Segoe UI', system-ui, -apple-system, sans-serif;
  --radius: 0.9rem;
  --shadow: 0 0.5rem 1.5rem rgba(43, 34, 80, 0.08);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --coral-ink: #ff686b;
    --bg: #161227;
    --surface: #221c3d;
    --surface-2: #2b2450;
    --ink: #f4f1ea;
    --ink-soft: #b3accb;
    --line: #38315c;
    --accent: #8f7fe8;
    --accent-ink: #14102a;
    --ok: #62d29e;
    --warn: #f0c060;
    --danger: #ff8a8d;
    --ok-bg: #14372a;
    --warn-bg: #3a2e14;
    --danger-bg: #3d1e21;
  }
}
:root[data-theme="dark"] {
  --coral-ink: #ff686b;
  --bg: #161227;
  --surface: #221c3d;
  --surface-2: #2b2450;
  --ink: #f4f1ea;
  --ink-soft: #b3accb;
  --line: #38315c;
  --accent: #8f7fe8;
  --accent-ink: #14102a;
  --ok: #62d29e;
  --warn: #f0c060;
  --danger: #ff8a8d;
  --ok-bg: #14372a;
  --warn-bg: #3a2e14;
  --danger-bg: #3d1e21;
}

/* The consoles read at 125%.

   Everything in this file is in rem, so one number at the root scales type,
   padding, borders and radii together -- which is exactly what browser zoom
   does, and what people were doing by hand to make these pages comfortable.
   Scaling a font-size alone would have grown the text inside boxes that
   stayed put.

   Opt-in per page rather than global because the landing page is not a
   console: its hero is tuned with clamp() against the viewport, and 25% more
   of it would overflow the fold on a laptop. Add the attribute to a page when
   that page is a working surface. */
html[data-scale="console"] { font-size: 125%; }

* { box-sizing: border-box; }
.hidden { display: none !important; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}
h1, h2, h3 { font-family: var(--font-display); font-weight: 800; line-height: 1.15; margin: 0; }
p { margin: 0; }
a { color: var(--accent); }

.wrap { width: min(64rem, 100% - 2rem); margin-inline: auto; }
.wrap-wide { width: min(84rem, 100% - 2rem); margin-inline: auto; }

/* ---------- header ---------- */
.topbar {
  background: var(--surface);
  border-bottom: 0.0625rem solid var(--line);
  position: sticky; top: 0; z-index: 30;
}
.topbar-in { display: flex; align-items: center; gap: 0.75rem; padding: 0.7rem 0; }
.brand { display: flex; align-items: center; gap: 0.55rem; text-decoration: none; color: inherit; }
.brand svg { width: 2.2rem; height: 2.2rem; flex: none; }
.brand-words { display: flex; flex-direction: column; line-height: 1.05; }
.brand-1 { font-family: var(--font-display); font-weight: 800; font-size: 1.05rem; }
.brand-2 { font-family: var(--font-display); font-weight: 700; font-size: 0.82rem; color: var(--coral-ink); }
.topbar-actions { margin-left: auto; display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; }

/* ---------- buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.4rem;
  font-family: var(--font-body); font-weight: 700; font-size: 0.92rem;
  padding: 0.5rem 0.95rem; border-radius: 62rem; cursor: pointer;
  background: var(--surface); color: var(--ink);
  border: 0.0625rem solid var(--line);
  text-decoration: none; white-space: nowrap;
  transition: background 0.12s ease, border-color 0.12s ease;
}
.btn:hover:not(:disabled) { border-color: var(--accent); }
.btn:disabled { opacity: 0.45; cursor: not-allowed; }
.btn-primary { background: var(--accent); color: var(--accent-ink); border-color: transparent; }
.btn-primary:hover:not(:disabled) { filter: brightness(1.08); }
.btn-danger { background: var(--danger); color: #fff; border-color: transparent; }
.btn-danger:hover:not(:disabled) { filter: brightness(1.08); }
.btn-sm { font-size: 0.82rem; padding: 0.32rem 0.7rem; }
.btn:focus-visible, a:focus-visible, input:focus-visible,
select:focus-visible, textarea:focus-visible {
  outline: 0.18rem solid var(--yellow); outline-offset: 0.12rem;
}

/* ---------- page furniture ---------- */
main { padding: 1.75rem 0 4rem; }
.page-head { margin-bottom: 1.5rem; }
.page-head h1 { font-size: clamp(1.6rem, 3.2vw, 2.1rem); }
.page-head .sub { color: var(--ink-soft); margin-top: 0.35rem; }

.card {
  background: var(--surface); border: 0.0625rem solid var(--line);
  border-radius: var(--radius); padding: 1.35rem; margin-bottom: 1.15rem;
  box-shadow: var(--shadow);
}
.card > h2 { font-size: 1.2rem; margin-bottom: 0.25rem; }
.card > .card-sub { color: var(--ink-soft); font-size: 0.9rem; margin-bottom: 1rem; }
.card-actions { display: flex; gap: 0.6rem; flex-wrap: wrap; align-items: center; margin-top: 1.1rem; }

.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); gap: 0.9rem 1.1rem; }
.row { display: flex; gap: 0.6rem; align-items: center; flex-wrap: wrap; }
.muted { color: var(--ink-soft); font-size: 0.88rem; }
.err { color: var(--danger); }
/* `.card > .card-sub` is more specific than `.err`, so an error message inside
   a card rendered in the muted ink and looked like ordinary help text. */
.card > .card-sub.err { color: var(--danger); }
.empty { color: var(--ink-soft); font-style: italic; padding: 0.9rem 0; }

/* ---------- status pills ---------- */
.pill {
  display: inline-flex; align-items: center; gap: 0.3rem;
  border-radius: 62rem; padding: 0.15rem 0.65rem;
  font-size: 0.76rem; font-weight: 800; letter-spacing: 0.02em;
}
.pill-ok     { background: var(--ok-bg);     color: var(--ok); }
.pill-warn   { background: var(--warn-bg);   color: var(--warn); }
.pill-danger { background: var(--danger-bg); color: var(--danger); }
.pill-plain  { background: var(--surface-2); color: var(--ink-soft); }

/* ---------- forms ---------- */
.field { display: flex; flex-direction: column; gap: 0.3rem; }
.field label { font-size: 0.82rem; font-weight: 800; color: var(--ink-soft); letter-spacing: 0.02em; }
.field input, .field select, .field textarea {
  background: var(--bg); color: var(--ink);
  border: 0.0625rem solid var(--line); border-radius: 0.55rem;
  padding: 0.55rem 0.65rem; font-family: inherit; font-size: 0.95rem;
  width: 100%; min-width: 0;
}
.field textarea { resize: vertical; }
.field input:disabled, .field select:disabled, .field textarea:disabled {
  background: var(--surface-2); color: var(--ink-soft); cursor: not-allowed;
}
.field-hint { font-size: 0.78rem; color: var(--ink-soft); }
.field-err { font-size: 0.78rem; color: var(--danger); font-weight: 700; }

/* ---------- tables ---------- */
.table-wrap { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; font-size: 0.92rem; }
th, td { text-align: left; padding: 0.6rem 0.7rem; border-bottom: 0.0625rem solid var(--line); }
th {
  color: var(--ink-soft); font-size: 0.72rem; text-transform: uppercase;
  letter-spacing: 0.07em; font-weight: 800;
}
tbody tr:last-child td { border-bottom: 0; }
td .row { justify-content: flex-end; }

/* A sortable column header (platform/index.html's runsTable). A <button>
 * filling the <th> rather than a click handler on the <th> itself, so it is
 * reachable and activatable from the keyboard for free -- <th> has neither.
 * `font: inherit` etc. because buttons are one of the few elements that do
 * NOT inherit text styling from their parent by default; without it this
 * would render in the browser's UI font, not the table's. */
.th-sort {
  display: flex; align-items: center; gap: 0.3rem; width: 100%;
  background: none; border: 0; padding: 0; cursor: pointer;
  font: inherit; color: inherit; text-transform: inherit; letter-spacing: inherit;
}
.th-sort:hover { color: var(--ink); }
.th-sort.is-on { color: var(--ink); }
.sort-arrow { font-size: 0.62rem; }

/* The mini pattern icon plus its name, packed into one small pill -- used
 * where a pattern is one fact among several in a row (the runs table)
 * rather than the main subject of a legend row (the pie chart). */
.chip {
  display: inline-flex; align-items: center; gap: 0.35rem;
  background: var(--surface-2); border-radius: 999px;
  padding: 0.2rem 0.55rem 0.2rem 0.35rem; font-size: 0.85rem; white-space: nowrap;
}

/* ---------- tabs ---------- */
.tabbar {
  display: flex; gap: 0.25rem; flex-wrap: wrap;
  border-bottom: 0.0625rem solid var(--line); margin-bottom: 1.35rem;
}
.tabbar button {
  font-family: var(--font-body); font-weight: 800; font-size: 0.94rem;
  background: none; border: 0; color: var(--ink-soft); cursor: pointer;
  padding: 0.6rem 0.9rem; border-bottom: 0.18rem solid transparent;
  margin-bottom: -0.0625rem;
}
.tabbar button:hover { color: var(--ink); }
.tabbar button.is-on { color: var(--ink); border-bottom-color: var(--accent); }

/* ---------- dialog ---------- */
.scrim {
  position: fixed; inset: 0; background: rgba(20, 16, 42, 0.55);
  display: grid; place-items: center; z-index: 80; padding: 1rem;
}
.dialog {
  background: var(--surface); border: 0.0625rem solid var(--line);
  border-radius: var(--radius); padding: 1.5rem; max-width: 26rem; width: 100%;
  box-shadow: 0 1.5rem 3rem rgba(0, 0, 0, 0.3);
  display: flex; flex-direction: column; gap: 0.7rem;
}
.dialog h2 { font-size: 1.15rem; }
.dialog p { color: var(--ink-soft); }
.dialog-actions { display: flex; gap: 0.6rem; justify-content: flex-end; margin-top: 0.4rem; }

/* ---------- feedback ---------- */
.dialog-wide { max-width: 32rem; }
/* Words, not the game's emoji faces. The same five ratings reach the same
   inbox; this side of the product just does not speak in emoji. */
.fb-scale { display: flex; gap: 0.4rem; flex-wrap: wrap; }
.fb-scale .btn { flex: 1 1 auto; justify-content: center; }
/* Honeypot: off-screen rather than display:none, which some bots skip. */
.fb-hp {
  position: absolute; left: -9999px; width: 0.0625rem; height: 0.0625rem;
  opacity: 0; pointer-events: none;
}

/* ---------- toast ---------- */
#toast {
  position: fixed; left: 50%; bottom: 1.5rem; transform: translate(-50%, 1.5rem);
  background: var(--indigo); color: var(--cream);
  padding: 0.7rem 1.15rem; border-radius: 62rem; font-weight: 700; font-size: 0.92rem;
  opacity: 0; pointer-events: none; transition: opacity 0.18s ease, transform 0.18s ease;
  z-index: 90; max-width: min(30rem, calc(100% - 2rem)); text-align: center;
}
#toast.show { opacity: 1; transform: translate(-50%, 0); }
#toast.toast-err { background: var(--danger); color: #fff; }

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; }
}

/* ---------- shared product header ----------
   The same lockup, account chip and actions in the same place on the landing
   page, sign-in and both consoles. The launcher deliberately keeps its own
   chunky header: that is the boundary between the office and the room, and it
   should be visible when you cross it. */
.topbar-actions .btn-primary { border-color: transparent; }

/* The way into an activity from an admin page. Not a back-link -- running
   activities is the director's actual job, so it carries primary weight. */
.btn-start { font-weight: 800; }
.btn-start::before { content: '\25B6'; font-size: 0.8em; }

.acct-chip {
  display: inline-flex; align-items: center; gap: 0.4rem;
  font-size: 0.85rem; color: var(--ink-soft); padding: 0 0.3rem;
  max-width: 14rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
@media (max-width: 40rem) { .acct-chip { display: none; } }

/* ---- A year of days ------------------------------------------------------
 *
 * Beside the component in shared/ui.js rather than inline in one console: it
 * is drawn on the account page and on the platform Usage tab, and a stylesheet
 * that only one of them loads is how the second one renders a grid of
 * invisible squares. These colours have already been wrong twice.
 */
/* A year of days. Fixed 0.72rem squares rather than anything responsive: a
   grid that reflows loses the week columns, and the columns are what make it
   readable at a glance. It scrolls instead, from the right. */
.heat-wrap { overflow-x: auto; padding-bottom: 0.3rem; direction: rtl; }
.heat, .heat-months { direction: ltr; }
.heat { display: flex; gap: 0.18rem; width: max-content; }
.heat-col { display: flex; flex-direction: column; gap: 0.18rem; }
.heat-day, .heat-pad { width: 0.72rem; height: 0.72rem; border-radius: 0.15rem; }
.heat-pad { background: transparent; }
.heat-months {
  display: flex; gap: 0.18rem; width: max-content;
  margin-bottom: 0.25rem; font-size: 0.66rem; color: var(--ink-soft);
}
.heat-month { width: 0.72rem; white-space: nowrap; }
/* Five steps of one hue. Colour-blind safe by construction: the only thing
   that varies is lightness, so it reads the same to everybody. */
/* An empty day still has to be a square. The first attempt used --panel-2,
   which is all but identical to the card behind it, so five of the seven rows
   vanished and a year of Tuesdays and Thursdays looked like two stripes. The
   second used --text, which this stylesheet does not define -- color-mix with
   an unknown colour yields transparent, so they vanished again, silently.
   --ink is the one that exists here, and it flips with the theme. */
.heat-0 { background: color-mix(in srgb, var(--ink) 14%, transparent); }
.heat-1 { background: color-mix(in srgb, var(--accent) 28%, transparent); }
.heat-2 { background: color-mix(in srgb, var(--accent) 50%, transparent); }
.heat-3 { background: color-mix(in srgb, var(--accent) 74%, transparent); }
.heat-4 { background: var(--accent); }
.heat-outer { position: relative; }
.heat-tip {
  position: absolute; transform: translate(-50%, -125%);
  z-index: 5; pointer-events: none; white-space: nowrap;
  padding: 0.3rem 0.55rem; border-radius: 0.4rem;
  background: var(--ink); color: var(--surface);
  font-size: 0.75rem; font-weight: 600;
}
.heat-tip[hidden] { display: none; }
.heat-day:focus-visible { outline: 0.15rem solid var(--accent); outline-offset: 0.1rem; }
.heat-key {
  display: flex; align-items: center; gap: 0.25rem;
  margin-top: 0.5rem; font-size: 0.72rem;
}

/* ---- A pie of named counts ------------------------------------------------
 *
 * Beside pieChart() in shared/ui.js for the same reason the heatmap's CSS
 * lives here rather than in one console: it is drawn on an account's own
 * Usage panel and on the platform-wide Usage tab (issue #17).
 */
.pie-wrap { display: flex; gap: 1.3rem; flex-wrap: wrap; align-items: center; }
.pie-chart { width: 8.5rem; height: 8.5rem; flex: 0 0 auto; }
.pie-legend { display: grid; gap: 0.4rem; flex: 1 1 14rem; min-width: 12rem; }
.pie-legend li { display: flex; align-items: center; gap: 0.5rem; font-size: 0.86rem; }
.pie-swatch {
  width: 0.75rem; height: 0.75rem; border-radius: 0.2rem; flex: 0 0 auto;
}
.pie-label {
  flex: 1 1 auto; display: flex; align-items: center; gap: 0.4rem;
  min-width: 0;
}
.pie-value { color: var(--ink-soft); white-space: nowrap; }

/* The mini bingo card next to a pattern's name in the game-type pie legend
 * (platform/index.html's patternIcon()) -- sized like the emoji beside a
 * theme or voice name, not like the full-size preview on the game page.
 */
.pattern-mini-wrap { display: flex; flex: 0 0 auto; }
.pattern-mini { width: 1.15rem; height: 1.36rem; display: block; }
/* A locked account, on its own page. Loud, because everything else on the
   page is about an account that can be used. */
.locked-note {
  background: var(--danger-bg); border: 0.125rem solid var(--danger);
  border-radius: var(--radius); padding: 1.2rem 1.35rem; margin-bottom: 1.15rem;
}
.locked-note h2 { color: var(--danger); font-size: 1.25rem; margin-bottom: 0.35rem; }
.locked-note p { color: var(--ink); }
.locked-why { margin-top: 0.8rem; }
.locked-why summary {
  cursor: pointer; font-weight: 800; color: var(--danger);
  font-size: 0.9rem; width: fit-content;
}
.locked-why p { margin-top: 0.5rem; color: var(--ink-soft); }
.locked-do { margin-top: 0.8rem !important; font-size: 0.92rem; }

/* One question under another, and narrow: a password box as wide as the
   card invites the eye to look for a second column that is not there. */
.pw-stack { display: grid; gap: 0.9rem; max-width: 22rem; }
.pw-who { background: var(--surface-2); color: var(--ink-soft); }
.pw-eye { justify-self: start; font-size: 0.88rem; }

