/* platform.ui v1 — shared UI primitives
   All classes prefixed pui- to avoid module collisions.
   Uses shell CSS vars (--bg, --bg2, --primary, etc). */

/* ── THE layer scale (Damon 2026-10-17: "menus always open on top of everything"). Every page-level z-index on the
   site is one of these names (a part may add +1/+2 to keep its own pieces in order). Lowest → highest:
   page < chrome (top bar, game bar) < panel (docks, chips, framed panels) < popup (every pop-up, overlay, lightbox;
   a pop-up opened later sits on the earlier one) < menu (every menu, dropdown, picker, tooltip) < toast < top
   (the recording frame and admin bar only). Change a number here and the whole site follows. */
/* THE side gap on a phone: every page's content sits this far from the screen (or pop-up) edge, left = right (Damon 2026-10-20) */
:root { --pui-side: 8px; }
:root { --z-page: 1; --z-chrome: 100; --z-panel: 500; --z-popup: 1000; --z-menu: 2000; --z-toast: 3000; --z-top: 2147483000; }
/* a menu that opens inside the top bar takes the whole bar up to the menu layer, so it is never under a pop-up */
.pub-header:has(.open), .pub-header:has(.pui-held) { z-index: var(--z-menu) !important; }

/* ── THE scrollbar (Damon 2026-10-17: one style for the whole site) ───────────
   Every scrollbar, horizontal and vertical, in every page and frame is drawn by
   THIS rule and nowhere else. Change a token here and every scrollbar changes.
   (A list that hides its bar on purpose says scrollbar-width:none — that hides,
   it does not style.) The fast-scroll grab bar (.pui-fs-th) uses the same tokens. */
:root { --pui-sb: 8px; --pui-sb-thumb: #9a9ab0; --pui-sb-track: transparent; }
::-webkit-scrollbar { width: var(--pui-sb); height: var(--pui-sb); }
::-webkit-scrollbar-track, ::-webkit-scrollbar-corner { background: var(--pui-sb-track); }
::-webkit-scrollbar-thumb { background: var(--pui-sb-thumb); border-radius: var(--pui-sb); }
@supports not selector(::-webkit-scrollbar) { * { scrollbar-color: var(--pui-sb-thumb) var(--pui-sb-track); } }

/* EVERY PAGE IS A DARK PAGE (Damon 2026-10-18: on his PC, Chrome's Auto Dark Mode turned the yellow buttons brown): a page
   that says it is dark is left alone by a browser's forced dark mode, so the brand colours show as made */
:root { color-scheme: dark; }
/* ── Modal ───────────────────────────────────────── */
/* THE ONE POP-UP GAP (Damon 2026-10-17: halve the gaps above and below every pop-up): the space between a pop-up and
   the screen's edges (the page pop-up: the top bar and the bottom). One value for every pop-up frame. */
:root { --pui-pop-gap: 10px; }
@media (max-width: 760px) { :root { --pui-pop-gap: 4px; } }
/* ONE POP-UP LOOK, phone + PC (Damon 2026-10-18): every pop-up's outline is --pui-pop-line, and THE X's ring AND glyph
   are --pui-x-ring (not full white; a touch brighter than the outline). Change these two and every pop-up changes. */
:root { --pui-pop-line: rgba(255,255,255,.42); --pui-x-ring: rgba(255,255,255,.64); }
/* THE POP-UP BACKDROP (Damon 2026-10-18: one blur for every pop-up — the game pop-up's): the page behind every pop-up
   (ui.modal, ui.confirm, the shell's page pop-up) is darkened and blurred with these two tokens, phone and PC */
:root { --pui-backdrop: rgba(5,5,12,.55); --pui-backdrop-blur: blur(7px); }
.pui-modal-overlay, .pui-confirm-overlay { background: var(--pui-backdrop) !important; -webkit-backdrop-filter: var(--pui-backdrop-blur); backdrop-filter: var(--pui-backdrop-blur); }
.pui-modal, .pui-confirm, #pubPop .pub-pop-panel, .mfiles-overlay .mfiles-root, .sup-card, .gfb-card { border: 1px solid var(--pui-pop-line) !important; }
/* THE SAFE AREA (Damon 2026-10-20): ONE token for the phone's status bar / home bar in the home-screen app — every fixed or
   full-screen layer and every control placed at the top uses it, so nothing sits under the clock or the battery */
:root { --pui-safe-top: env(safe-area-inset-top, 0px); --pui-safe-bottom: env(safe-area-inset-bottom, 0px); }
.pui-modal-overlay {   /* EVERY POP-UP APPEARS COMPLETE IN ONE FRAME — no fade or slide in (Damon 2026-10-18: the Jump In cards were half
     see-through over the welcome page while they faded; his 10-16 ruling: pages just appear) */
  position: fixed;
  inset: 0;
  z-index: var(--z-popup, 1000);
  display: flex;
  align-items: center;
  justify-content: center;
  box-sizing: border-box; padding-top: var(--pui-safe-top); padding-bottom: var(--pui-safe-bottom);   /* never under the status / home bar */
}
.pui-modal-overlay.pui-modal-top { align-items: flex-start; }   /* ui.modal({ align: 'top' }) — tabbed pop-ups */
/* THE SAFE AREA CAN'T BE TAKEN OFF (Damon 2026-10-20: the phone's full-screen Leaderboards ran under the status bar and its
   X took no taps): a module's own 'padding:0 !important' on a pop-up's overlay keeps its sides, never the status / home bar
   room. (html:root wins over any module's .pui-modal-overlay:has(...) rule.) */
html:root .pui-modal-overlay, html:root .pui-confirm-overlay { padding-top: var(--pui-safe-top) !important; padding-bottom: var(--pui-safe-bottom) !important; }
.pui-modal-top > .pui-modal { margin-top: calc(max(0px, var(--pui-top, 0px) - var(--pui-safe-top)) + var(--pui-pop-gap));
  max-height: calc(100% - max(0px, var(--pui-top, 0px) - var(--pui-safe-top)) - 2 * var(--pui-pop-gap)); }
.pui-modal {
  background: var(--bg2);
  border: 1px solid var(--pui-pop-line, var(--border2));
  border-radius: 12px;
  box-shadow: 0 8px 32px rgba(0,0,0,0.4);
  min-width: 320px;
  max-width: 90vw;
  max-height: calc(100% - 2 * var(--pui-pop-gap));   /* of the overlay (it may start under a top bar): corners always in view */
  display: flex;
  flex-direction: column;
}
/* the bot check's box (ui.botToken): empty and invisible unless Cloudflare asks for its single tick — then it sits at the
   bottom centre, over any pop-up */
.pui-bot { position: fixed; left: 50%; bottom: 12px; transform: translateX(-50%); z-index: calc(var(--z-popup, 1000) + 50); }
/* NEVER SHOWN UNTIL FINAL (ui.revealWhenFinal): hidden, not faded, until everything sits in its final place */
.pui-pre { visibility: hidden !important; }
.pui-notrans, .pui-notrans * { transition: none !important; }   /* the reveal frame: every part shows at once */
/* a tab being built: laid out in place (same width, its pictures load), unseen, over nothing, until it is final */
.pui-building { visibility: hidden !important; position: absolute !important; left: 0; right: 0; top: 0; pointer-events: none !important; }
/* the tapped item lights at once while the next pop-up is being built (ui.v1 watchHold) */
/* THE PRESS GLOW (Damon GO 2026-10-22): every button and icon, pressed, glows brighter for 180ms (ui.v1.js adds
   .pui-glow) — never darker: no grey tap flash anywhere, no :active darkening or shrinking */
html, html * { -webkit-tap-highlight-color: transparent; }
.pui-glow { filter: brightness(1.4) drop-shadow(0 0 6px rgba(255,255,255,.35)) !important; }
/* a held press is a tap, never iOS's text selection or link preview (Damon 2026-10-22: Support / Settings stuck orange) */
.pub-user-menu .pub-user-item, .pui-modal button, .pui-modal a, .pui-confirm button { -webkit-touch-callout: none; -webkit-user-select: none; user-select: none; }
.pui-modal { position: relative; }
/* NO EMPTY X ROW, PC AND PHONE (Damon 2026-10-18 — replaces the 10-17 strip): the X floats in the top-right corner (it
   never scrolls) and the content starts at the very top. A title shares its row with the X; with no title only the FIRST
   line/box gets room on its right (and is at least as tall as the X) so nothing sits under it. The pop-up's one
   scrollbar (THE bar, ui.fastScroll) starts below the X, so it never runs under it. Sizes per device below. */
.pui-modal { box-sizing: border-box; }
.pui-modal:not(:has(> .pui-modal-header)) > .pui-modal-content > :first-child { margin-right: 28px; min-height: 32px; box-sizing: border-box; }
/* a pop-up's own padding stays (16px); a TITLE that opens the content sits on the X's row, centred with the X */
.pui-modal:not(:has(> .pui-modal-header)) > .pui-modal-content:has(> :is(h1,h2,h3):first-child) { padding-top: 8px; }
.pui-modal:not(:has(> .pui-modal-header)) > .pui-modal-content > :is(h1,h2,h3):first-child { display: flex; align-items: center; margin-top: 0; }
html.gmob .pui-modal:not(:has(> .pui-modal-header)) > .pui-modal-content:has(> :is(h1,h2,h3):first-child) { padding-top: 6px; }
.pui-modal > .pui-modal-header { min-height: 56px; box-sizing: border-box; display: flex; align-items: center;
  padding-top: 0 !important; padding-bottom: 0 !important; flex: none; }
.pui-modal-x { position: absolute; top: 8px; right: 8px; width: 32px; height: 32px; border: 0; border-radius: 8px; background: transparent;
  color: var(--text-dim, #9a9ab4); font: 400 26px/1 'DM Sans', system-ui, sans-serif; cursor: pointer; display: flex; align-items: center; justify-content: center; z-index: 2; }
@media (hover:hover){.pui-modal-x:hover{ background: var(--bg3, #1c1c2c); color: var(--text, #e4e4f0); }}
.pui-modal-header {
  padding: 16px 52px 0 20px;
  font-family: var(--font-head);
  font-size: 13px;
  letter-spacing: 0.08em;
  color: var(--primary);
  text-transform: uppercase;
}
.pui-modal-content {
  padding: 16px 20px;
  overflow-y: auto;
  flex: 1;
}
.pui-modal-actions {
  display: flex;
  gap: 8px;
  justify-content: flex-end;
  padding: 12px 20px 16px;
  border-top: 1px solid var(--border);
}

/* ── Toast ───────────────────────────────────────── */
.pui-toast-container {
  position: fixed;
  bottom: 24px;
  left: 50%;
  transform: translateX(-50%);
  /* above every pop-up: a toast fired from inside one (e.g. the report thanks over the rating
     pop-up at z 9999) was hidden behind it (2026-10-16) */
  z-index: var(--z-toast, 3000);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  pointer-events: none;
}
.pui-toast-tap { pointer-events: auto; cursor: pointer; }   /* a toast a tap acts on ('Posted ✓' opens the post) */
.pui-toast {
  /* fallbacks: a page without the shell's colour variables (a bare frame) drew raw text with no pill (fix 5) */
  background: var(--bg3, #1a1a2e);
  color: var(--text, #e8e8f0);
  border: 1px solid var(--border2, #2a2a3e);
  border-radius: 14px;
  padding: 16px 30px; font-family: 'DM Sans', system-ui, sans-serif;
  font-size: 26px;   /* twice the old 13px (Damon 2026-10-16: "tiny little writing") */
  font-weight: 600;
  /* a long message stays a wide box, never a 195px column of single words (masterPhone 2026-10-16) */
  width: max-content; max-width: min(92vw, 640px); box-sizing: border-box; text-align: center; line-height: 1.25;
  box-shadow: 0 4px 16px rgba(0,0,0,0.3);
  /* it GLOWS as it appears (Damon 2026-10-21: lost at the bottom) — a soft orange glow for about a second, then it settles */
  animation: puiFadeIn 0.15s ease-out, puiToastGlow 1.1s ease-out;
  pointer-events: auto;
}
@keyframes puiToastGlow {
  0%   { box-shadow: 0 4px 16px rgba(0,0,0,0.3), 0 0 0 0 rgba(245,137,31,0); }
  25%  { box-shadow: 0 4px 16px rgba(0,0,0,0.3), 0 0 26px 6px rgba(245,137,31,.6); border-color: rgba(245,137,31,.85); }
  100% { box-shadow: 0 4px 16px rgba(0,0,0,0.3), 0 0 0 0 rgba(245,137,31,0); }
}
/* PC: half the size (Damon 2026-10-22: 'huge, almost the width of the screen') — the phone keeps the 26px box above */
@media (min-width: 761px) {
  .pui-toast { padding: 10px 18px; font-size: 16px; border-radius: 10px; max-width: min(92vw, 340px); }
}
.pui-toast.pui-toast-ok { color: #39ff7f; border-color: rgba(57,255,127,.55); }   /* a green 'done' ('Posted ✓') */
/* ui.toast opts.choices: a row of picks under the words */
.pui-toast.pui-toast-pick { width: min(92vw, 460px); padding: 16px 14px 14px; }
.pui-toast-choices { display: flex; gap: 8px; justify-content: center; margin-top: 12px; }
.pui-toast-choice { flex: 1 1 0; min-width: 0; display: flex; flex-direction: column; align-items: center; gap: 2px; padding: 8px 4px; border: 0; border-radius: 10px;
  background: var(--bg2, #2a2a3e); color: #10101a; cursor: pointer; font-family: inherit; }
.pui-toast-choice b { font-size: 22px; line-height: 1; font-weight: 800; }
.pui-toast-choice small { font-size: 16px; line-height: 1.1; font-weight: 700; }
.pui-toast.pui-toast-out {
  animation: puiFadeOut 0.2s ease-in forwards;
}

/* ── Confirm ─────────────────────────────────────── */
.pui-confirm-overlay {
  position: fixed;
  inset: 0;
  /* A confirm must never lose a stacking fight — it sat at 1050 and opened
     BEHIND the shell's modal-mod overlay (z 9000), so Delete looked dead
     (Damon, sheet review). One below ui.menu's 2147483646 max-tier. */
  z-index: calc(var(--z-popup, 1000) + 2);
  box-sizing: border-box; padding-top: var(--pui-safe-top); padding-bottom: var(--pui-safe-bottom);
  display: flex;
  align-items: center;
  justify-content: center;
}
.pui-confirm {
  background: var(--bg2);
  border: 1px solid var(--border2);
  border-radius: 10px;
  box-shadow: 0 8px 32px rgba(0,0,0,0.4);
  padding: 20px 24px;
  min-width: min(280px, calc(100vw - 32px));
  max-width: min(400px, calc(100vw - 32px));   /* side margins on a phone (2026-10-16) */
  box-sizing: border-box;
}
.pui-confirm-msg {
  font-size: 17px;
  color: var(--text);
  margin-bottom: 18px;
  line-height: 1.4;
}
/* a phone reads it without squinting (Damon 2026-10-21: 'eagle-eye mini writing') */
@media (max-width: 760px) { .pui-confirm-msg { font-size: 19px; } }
html.gmob .pui-confirm-msg { font-size: 19px; }
.pui-confirm-actions {
  display: flex;
  gap: 10px;
  justify-content: flex-end;
}
/* BOTH buttons one Bungee button, the same size (Damon 2026-10-21: Cancel was DM Sans beside a Bungee action):
   Cancel the plain one, the action the brand one */
html .pui-confirm .pui-confirm-actions > .pui-btn { font-family: 'Bungee', var(--font-head, system-ui), sans-serif; font-weight: 400; letter-spacing: .03em;
  font-size: var(--pui-pri-fs, 16px); line-height: 1; min-height: 44px; padding: 10px 18px; border-radius: 10px; }
html .pui-confirm .pui-confirm-actions > .pui-btn:not(.pui-btn-primary) { background: transparent; border: 1.5px solid var(--pui-sec-line, var(--border2)); color: var(--text, #e4e4f0); }
html .pui-confirm .pui-confirm-actions > .pui-btn-primary { border-width: 1.5px; }

/* ── Dropzone ────────────────────────────────────── */
.pui-dropzone {
  border: 2px dashed var(--border2);
  border-radius: 10px;
  padding: 24px;
  text-align: center;
  color: var(--text-dim);
  font-size: 13px;
  transition: border-color 0.15s, background 0.15s;
  cursor: pointer;
  width: 100%;
  box-sizing: border-box;
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
}
.pui-dropzone.active {
  border-color: var(--primary);
  background: color-mix(in srgb, var(--accent), transparent 95%);
  color: var(--primary);
}
.pui-dz-hint {
  margin-top: 8px;
  font-size: 12px;
  color: var(--text-dim);
  text-align: center;
}

/* ── Video Player ───────────────────────────────── */
.pui-video-player {
  width: 100%;
  background: var(--bg);
  border-radius: 8px;
  overflow: hidden;
  border: 1px solid var(--border2);
}
.pui-video-player video {
  display: block;
  width: 100%;
  max-height: 360px;
  object-fit: contain;
  background: #000;
}

/* ── File Preview ────────────────────────────────── */
.pui-file-preview {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--bg3);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 8px 12px;
  font-size: 12px;
  color: var(--text-mid);
}
.pui-file-preview-thumb {
  width: 36px;
  height: 36px;
  border-radius: 4px;
  object-fit: cover;
  background: var(--bg);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 16px;
  color: var(--text-dim);
  flex-shrink: 0;
}
.pui-file-preview-name {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.pui-file-preview-remove {
  background: none;
  border: none;
  color: var(--text-dim);
  font-size: 14px;
  cursor: pointer;
  padding: 2px 6px;
  border-radius: 4px;
  line-height: 1;
}
@media (hover:hover){.pui-file-preview-remove:hover{
  color: var(--red);
  background: rgba(255,57,151,0.1);
}}

/* ── List ────────────────────────────────────────── */
.pui-list {
  list-style: none;
  padding: 0;
  margin: 0;
}
.pui-list-item {
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
  transition: background 0.1s;
  cursor: pointer;
}
.pui-list-item:last-child { border-bottom: none; }
@media (hover:hover){.pui-list-item:hover{ background: var(--bg3); }}

/* ── Buttons ─────────────────────────────────────── */
.pui-btn {
  background: var(--bg3);
  border: 1px solid var(--border2);
  color: var(--text);
  font-size: 13px;
  padding: 8px 16px;
  border-radius: 6px;
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s;
  font-family: inherit;
}
@media (hover:hover){.pui-btn:hover{
  background: var(--border);
  border-color: var(--border2);
}}
.pui-btn-primary {
  background: var(--primary);
  border: 1px solid var(--primary);
  color: var(--bg);
  font-weight: 600;
}
/* hover BRIGHTENS the primary action (was opacity:.85, which dimmed it) */
@media (hover:hover){.pui-btn-primary:hover{ filter: brightness(1.15); box-shadow: 0 0 0 2px color-mix(in srgb, var(--primary) 35%, transparent); }}
.pui-btn-danger {
  background: transparent;
  border: 1px solid var(--red);
  color: var(--red);
}
@media (hover:hover){.pui-btn-danger:hover{
  background: rgba(255,57,151,0.1);
}}

/* ── THE BUTTON MAKER (Damon 2026-10-18) — ui.button(text, type, opts) → class "pui-b pui-b-<type> pui-c-<colour>".
   NINE TYPES (the look): cta · filled · outline · pill · chip · tile · icon-round · icon-square · link.
   COLOUR is separate: orange · yellow · blue · dark · danger. Each type's size is fixed by tokens (phone + PC): the text
   is ~48% of the button height, the side padding 1x the text, and the left padding adds the letter-spacing so caps
   fonts (Bungee) sit dead centre. Defaults always; opts.overrides changes one only when Damon asks. */
:root {
  --pb-cta-h: 50px; --pb-cta-fs: 24px; --pb-std-h: 40px; --pb-std-fs: 19px; --pb-sm-h: 32px; --pb-sm-fs: 15px;
  --pb-icon: 40px; --pb-tile-h: 64px; --pb-tile-fs: 16px; --pb-link-fs: 16px; --pb-line: #3f4858;
}
@media (max-width: 760px) { :root {
  --pb-cta-h: 54px; --pb-cta-fs: 26px; --pb-std-h: 44px; --pb-std-fs: 21px; --pb-sm-h: 36px; --pb-sm-fs: 17px;
  --pb-icon: 44px; --pb-tile-h: 72px; --pb-tile-fs: 18px; --pb-link-fs: 18px;
} }
.pui-b { --ls: 0em; display: inline-flex; align-items: center; justify-content: center; gap: .4em; box-sizing: border-box;
  margin: 0; line-height: 1; white-space: nowrap; cursor: pointer; text-decoration: none; font-family: inherit; font-weight: 700;
  letter-spacing: var(--ls); border: 1.5px solid transparent; transition: filter .12s, background .12s; }
.pui-b:disabled { opacity: .5; cursor: default; filter: none; }
.pui-b svg { width: 1em; height: 1em; flex: none; }
/* sizes, per type */
.pui-b-cta { --ls: .06em; height: var(--pb-cta-h); font-size: var(--pb-cta-fs); border-radius: 12px;
  padding: 0 var(--pb-cta-fs) 0 calc(var(--pb-cta-fs) + var(--ls)); font-family: 'Bungee', var(--font-head, system-ui), sans-serif; font-weight: 400; text-transform: uppercase; }
.pui-b-filled, .pui-b-outline, .pui-b-pill { height: var(--pb-std-h); font-size: var(--pb-std-fs); border-radius: 10px;
  padding: 0 var(--pb-std-fs) 0 calc(var(--pb-std-fs) + var(--ls)); }
.pui-b-pill { border-radius: 999px; }
.pui-b-chip { height: var(--pb-sm-h); font-size: var(--pb-sm-fs); border-radius: 8px; padding: 0 var(--pb-sm-fs) 0 calc(var(--pb-sm-fs) + var(--ls)); font-weight: 600; }
.pui-b-tile { flex-direction: column; gap: 6px; min-height: var(--pb-tile-h); font-size: var(--pb-tile-fs); border-radius: 10px; padding: 8px 6px; white-space: normal; }
.pui-b-tile svg, .pui-b-tile .pui-b-ic { width: 1.25em; height: 1.25em; font-size: 1.25em; }
.pui-b-icon-round, .pui-b-icon-square { width: var(--pb-icon); height: var(--pb-icon); padding: 0; font-size: calc(var(--pb-icon) * .48); }
.pui-b-icon-round { border-radius: 50%; }
.pui-b-icon-square { border-radius: 10px; }
.pui-b-link { height: auto; padding: 0; border: 0; background: none; font-size: var(--pb-link-fs); font-weight: 500; text-decoration: underline; text-underline-offset: 3px; }
/* colours: --c is the colour, --on the text on a solid --c */
.pui-c-orange { --c: #f5891f; --on: #0b0b14; }
.pui-c-yellow { --c: #ffe03d; --on: #0b0b14; }
.pui-c-blue { --c: #3dc8ff; --on: #0b0b14; }
.pui-c-danger { --c: #ff4d6d; --on: #fff; }
.pui-c-dark { --c: var(--pb-line); --on: var(--text, #e4e4f0); --c-text: var(--text, #e4e4f0); }
/* solid looks */
.pui-b-cta, .pui-b-filled, .pui-b-pill { background: var(--c); border-color: var(--c); color: var(--on); }
@media (hover:hover){.pui-b-cta:hover, .pui-b-filled:hover, .pui-b-pill:hover{ filter: brightness(1.1); }}
/* line looks */
.pui-b-outline, .pui-b-chip { background: transparent; border-color: var(--c); color: var(--c-text, var(--c)); }
.pui-b-chip.on{ background: color-mix(in srgb, var(--c) 14%, transparent); }
@media (hover:hover){.pui-b-outline:hover, .pui-b-chip:hover{ background: color-mix(in srgb, var(--c) 14%, transparent); }}
.pui-b-tile, .pui-b-icon-round, .pui-b-icon-square { background: var(--bg, #0b0b14); border-color: var(--c); color: var(--c-text, var(--c)); }
@media (hover:hover){.pui-b-tile:hover, .pui-b-icon-round:hover, .pui-b-icon-square:hover{ background: color-mix(in srgb, var(--c) 14%, var(--bg, #0b0b14)); }}
.pui-b-link { color: var(--c-text, var(--c)); }
.pui-c-dark.pui-b-link { --c-text: var(--text-mid, #a0aab0); }

/* ── THE TWO BUTTON STYLES (Damon 2026-10-20: Play / Live didn't look like buttons) — every clickable that should read
   as a button is ONE of two: PRIMARY (the brand orange, filled, black text) or SECONDARY (a clearly visible outline — the
   card/field line — round readable text). A page sets only its size and shape; fill, line and text colour come from here.
   On gamoid (config.ui.cardLine) every shared button line — the maker's dark outline, the sign-in providers, the
   pop-ups' plain buttons — is that same card/field line; hashoid keeps its own.
   A page that is shared with hashoid and changes on gamoid only (Settings) maps its own classes onto the same tokens. */
:root { --pui-pri-bg: var(--primary, #f5891f); --pui-pri-fg: var(--pub-on-brand, #000); --pui-sec-line: var(--pui-card-line, #454c66); --pui-sec-fg: var(--text, #e4e4f0); }
.pui-primary { background: var(--pui-pri-bg) !important; border: 1.5px solid var(--pui-pri-bg) !important; color: var(--pui-pri-fg) !important; }
.pui-secondary { background: transparent !important; border: 1.5px solid var(--pui-sec-line) !important; color: var(--pui-sec-fg) !important; }
@media (hover:hover){ .pui-primary:hover { filter: brightness(1.1); } .pui-secondary:hover { border-color: var(--pui-pri-bg) !important; } }
/* THEIR LABELS (Damon 2026-10-20: '+ New Game' was tiny, the buttons inconsistent), on gamoid (config.ui.phoneTextLaw):
   PRIMARY in Bungee — a full-width one (pui-wide) 21px on a phone / 18px on a PC, any other 18px / 16px; SECONDARY in
   DM Sans 18px / 16px. The size is zero-weight: a page sets none of its own, except a button Damon sized bigger (Play). */
:root { --pui-pri-fs: 16px; --pui-pri-fs-wide: 18px; --pui-sec-fs: 16px; }
@media (max-width: 760px) { :root { --pui-pri-fs: 18px; --pui-pri-fs-wide: 21px; --pui-sec-fs: 18px; } }
html.gmob { --pui-pri-fs: 18px; --pui-pri-fs-wide: 21px; --pui-sec-fs: 18px; }
html[data-tl] .pui-primary, html[data-tl] .pui-btn-primary { font-family: 'Bungee', var(--font-head, system-ui), sans-serif !important; font-weight: 400 !important; letter-spacing: .03em; }
html[data-tl] .pui-secondary { font-family: 'DM Sans', system-ui, sans-serif !important; font-weight: 600; }
:where(html[data-tl]) :where(.pui-primary) { font-size: var(--pui-pri-fs); }
:where(html[data-tl]) :where(.pui-primary.pui-wide) { font-size: var(--pui-pri-fs-wide); }
:where(html[data-tl]) :where(.pui-secondary) { font-size: var(--pui-sec-fs); }
html[data-tl] .pui-btn.pui-btn-primary { font-size: var(--pui-pri-fs); }   /* over .pui-btn's own 13px / 16px */
html[data-tl] .pui-btn.pui-btn-primary.pui-wide { font-size: var(--pui-pri-fs-wide); }
html[data-tl] .pui-btn.pui-secondary { font-size: var(--pui-sec-fs); }   /* a pop-up's Cancel (Report): over .pui-btn's 13px too */
html[data-cl] { --pb-line: var(--pui-card-line); --pui-btn-line: var(--pui-card-line); }
html[data-cl] .pui-btn:not(.pui-btn-primary):not(.pui-btn-danger) { border-color: var(--pui-card-line); color: var(--text, #e4e4f0); }
html[data-cl] .pui-btn-primary { color: var(--pub-on-brand, #000); }

/* ── Switch ──────────────────────────────────────── */
/* THE ON/OFF SWITCH (Damon 2026-10-22): one switch everywhere — Settings' toggles (Enable 2FA…) and the studio
   dashboard's Public analytics. ON = green. Markup: <div class="pui-switch [on]" role="switch">, optional
   <span class="pui-switch-label"> right after it; ui.switch() builds a wired one. */
.pui-switch-wrap { display: flex; align-items: center; gap: calc(10 * var(--u, 1px)); }
.pui-switch {
  width: calc(42 * var(--u, 1px)); height: calc(22 * var(--u, 1px)); background: var(--bg); border: calc(1 * var(--u, 1px)) solid var(--border);
  border-radius: calc(11 * var(--u, 1px)); cursor: pointer; position: relative; transition: all 0.3s; flex-shrink: 0; touch-action: manipulation;
}
.pui-switch.on { background: rgba(57,255,127,0.12); border-color: #39ff7f; }
.pui-switch::after {
  content: ''; width: calc(16 * var(--u, 1px)); height: calc(16 * var(--u, 1px)); background: var(--text-dim);
  border-radius: 50%; position: absolute; top: calc(2 * var(--u, 1px)); left: calc(2 * var(--u, 1px)); transition: all 0.3s;
}
.pui-switch.on::after { left: calc(22 * var(--u, 1px)); background: #39ff7f; box-shadow: 0 0 calc(8 * var(--u, 1px)) rgba(57,255,127,0.3); }
.pui-switch[aria-disabled="true"] { opacity: 0.5; pointer-events: none; }
.pui-switch-label { font-size: calc(14 * var(--u, 1px)); font-family: var(--font-mono, ui-monospace, monospace); color: var(--text-dim); min-width: calc(28 * var(--u, 1px)); }
.pui-switch.on + .pui-switch-label { color: #39ff7f; }

/* ── Code entry ──────────────────────────────────── */
/* THE CODE ENTRY (Damon 2026-10-22, ui.codeEntry): the 6-digit boxes (.pui-code) and, under them, PASTE and — for an
   emailed code — DIDN'T GET IT? RESEND (counting down its 30s wait). No mic in a code box. */
.pui-code-bar { display: flex; flex-wrap: wrap; justify-content: center; gap: calc(8 * var(--u, 1px)); margin: calc(10 * var(--u, 1px)) 0; }
.pui-code-bar .pui-btn { min-width: calc(110 * var(--u, 1px)); }
.pui-code-bar .pui-code-resend:disabled { opacity: .6; cursor: default; }

/* THE PROMPT (ui.prompt): the words, then the fields stacked full width, each with its label over it. */
.pui-prompt-text { margin: 0 0 calc(14 * var(--u, 1px)); font-size: calc(18 * var(--u, 1px)); line-height: 1.4; color: var(--text, #e4e4f0); }
.pui-prompt-form { display: flex; flex-direction: column; gap: calc(12 * var(--u, 1px)); }
.pui-prompt-field { display: flex; flex-direction: column; gap: calc(6 * var(--u, 1px)); font-size: calc(16 * var(--u, 1px)); color: var(--text-dim, #a0a0bc); }
.pui-prompt-form .pui-input { width: 100%; box-sizing: border-box; font-size: calc(18 * var(--u, 1px)); }
.pui-prompt-form .pui-code { display: flex; justify-content: center; gap: calc(6 * var(--u, 1px)); }
.pui-prompt-form .pui-code-digit { width: calc(44 * var(--u, 1px)); height: calc(54 * var(--u, 1px)); text-align: center; font-size: calc(24 * var(--u, 1px)); box-sizing: border-box; padding: 0; }

/* ── Input ───────────────────────────────────────── */
/* THE TEXT FIELD (Damon 2026-10-18): EVERY text-entry box on every page and frame — text/email/password/number/search/
   date inputs, textareas, selects — always shows a clearly defined outline (--pui-field-line, stronger than the button
   line) and turns the brand orange when focused. One rule; pages don't set their own field borders. A field drawn
   INSIDE a framed wrapper (a search pill, a composer) opts out with class pui-bare — the wrapper is its box. */
:root { --pui-field-line: rgba(255,255,255,.38); }
/* THE CARD OUTLINE (Damon 2026-10-19: on a phone you couldn't see the cards' edges): ONE value for every card, tile
   and panel — on gamoid the approved text-field outline (hashoid keeps its own line) — and ONE class that draws it. A card with a deliberate coloured outline
   (Studio AI yellow, Jump In blue) keeps its own. */
:root { --pui-card-line: var(--border, #454c66); }   /* a site's own card line … */
html[data-cl] { --pui-card-line: var(--pui-field-line); }   /* … or, where config.ui.cardLine is on (gamoid), the bright field line */
.pui-card { border: 1px solid var(--pui-card-line); }
input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=color]):not([type=file]):not([type=hidden]):not([type=button]):not([type=submit]):not([type=reset]):not([type=image]):not(.pui-bare),
textarea:not(.pui-bare), select:not(.pui-bare), .pui-input, .pui-textarea {
  border: 1px solid var(--pui-field-line) !important; }
/* THE TYPED TEXT (Damon 2026-10-20: what you type was tiny on his iPhone): every text box's text is the shared field
   size on a site with the phone text law (gamoid) — 18px on a phone (never under 16, or iOS zooms in), 16px on a PC.
   Zero-weight (:where), so a box drawn bigger keeps its size; a mod sets no smaller size of its own. */
:root { --pui-field-fs: 16px; }
@media (max-width: 760px) { :root { --pui-field-fs: 18px; } }
html.gmob { --pui-field-fs: 18px; }
:where(html[data-tl]) :where(input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=color]):not([type=file]):not([type=hidden]):not([type=button]):not([type=submit]):not([type=reset]):not([type=image]), textarea, select) { font-size: var(--pui-field-fs); }
input:not([type=checkbox]):not([type=radio]):not([type=range]):not([type=color]):not([type=file]):not([type=hidden]):not([type=button]):not([type=submit]):not([type=reset]):not([type=image]):not(.pui-bare):focus,
textarea:not(.pui-bare):focus, select:not(.pui-bare):focus, .pui-input:focus, .pui-textarea:focus {
  border-color: var(--primary, #f5891f) !important; outline: none; }
.pui-input {
  background: var(--bg);
  border-radius: 8px;
  padding: 9px 14px;
  color: var(--text);
  font-size: 13px;
  font-family: inherit;
  outline: none;
  transition: border-color 0.15s;
  width: 100%;
}

/* ── Avatar ──────────────────────────────────────── */
.pui-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--bg3);
  border: 1px solid var(--border2);
  font-weight: 700;
  color: var(--primary);
  flex-shrink: 0;
  line-height: 1;
}
.pui-avatar-sm { width: 24px; height: 24px; font-size: 10px; }
.pui-avatar-md { width: 32px; height: 32px; font-size: 14px; }
.pui-avatar-lg { width: 48px; height: 48px; font-size: 20px; }
.pui-avatar-xl { width: 72px; height: 72px; font-size: 32px; }

/* ── Badge ───────────────────────────────────────── */
.pui-badge {
  display: inline-block;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 2px 8px;
  border-radius: 4px;
  line-height: 1.4;
}
.pui-badge-default { background: var(--bg3); color: var(--text-mid); border: 1px solid var(--border2); }
.pui-badge-primary { background: color-mix(in srgb, var(--accent), transparent 88%); color: var(--primary); border: 1px solid color-mix(in srgb, var(--accent), transparent 70%); }
.pui-badge-green { background: rgba(57,255,127,0.1); color: #39ff7f; border: 1px solid rgba(57,255,127,0.3); }
.pui-badge-red { background: rgba(255,57,151,0.1); color: var(--red); border: 1px solid rgba(255,57,151,0.3); }
.pui-badge-yellow { background: rgba(255,215,0,0.1); color: var(--yellow); border: 1px solid rgba(255,215,0,0.3); }
.pui-badge-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--text-dim);
}
.pui-badge-dot.green { background: #39ff7f; box-shadow: 0 0 6px rgba(57,255,127,0.5); }
.pui-badge-dot.yellow { background: var(--yellow); box-shadow: 0 0 6px rgba(255,215,0,0.5); }
.pui-badge-dot.red { background: var(--red); box-shadow: 0 0 6px rgba(255,57,151,0.5); }
/* THE COUNT BADGE (Damon 2026-10-19): a small round number on a menu item — ui.countBadge(el, n). Studio AI yellow,
   dark number; the same on phone and PC. */
.pui-count { display: inline-flex; align-items: center; justify-content: center; min-width: 20px; height: 20px; padding: 0 6px;
  box-sizing: border-box; margin-left: 8px; border-radius: 10px; background: #ffe03d; color: #14141f;
  font: 700 12px/1 'DM Sans', system-ui, sans-serif; vertical-align: middle; }

/* ── Tabs ────────────────────────────────────────── */
.pui-tabs {
  display: flex;
  gap: 0;
  border-bottom: 1px solid var(--border);
  overflow-x: auto;
}
.pui-tab {
  padding: 10px 18px;
  font-family: var(--font-head);
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-dim);
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  cursor: pointer;
  white-space: nowrap;
  transition: color 0.12s, border-color 0.12s;
  font-family: inherit;
}
@media (hover:hover){.pui-tab:hover{ color: var(--text-mid); }}
.pui-tab.active {
  color: var(--primary);
  border-bottom-color: var(--primary);
}

/* ── Form Group ──────────────────────────────────── */
.pui-form-group {
  margin-bottom: 14px;
}
.pui-label {
  display: block;
  font-size: 11px;
  color: var(--text-mid);
  margin-bottom: 4px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 600;
}
.pui-textarea {
  background: var(--bg);
  border-radius: 8px;
  padding: 9px 14px;
  color: var(--text);
  font-size: 13px;
  font-family: inherit;
  outline: none;
  transition: border-color 0.15s;
  width: 100%;
  min-height: 80px;
  resize: vertical;
}
.pui-select {
  background: var(--bg);
  border-radius: 8px;
  padding: 9px 14px;
  color: var(--text);
  font-size: 13px;
  font-family: inherit;
  outline: none;
  transition: border-color 0.15s;
  width: 100%;
  cursor: pointer;
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%235a6a70' d='M3 5l3 3 3-3'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  padding-right: 32px;
}
.pui-form-error {
  font-size: 12px;
  color: var(--red);
  margin-top: 4px;
  display: none;
}
.pui-form-hint {
  font-size: 11px;
  color: var(--text-dim);
  margin-top: 4px;
}

/* ── Star Rating ─────────────────────────────────── */
.pui-stars {
  display: inline-flex;
  gap: 2px;
}
.pui-star {
  font-size: 18px;
  cursor: pointer;
  color: var(--border2);
  transition: color 0.1s;
  user-select: none;
}
.pui-star.lit { color: #f0c040; }
.pui-star.hover { color: #f0c040; opacity: 0.7; }
.pui-stars-display .pui-star { cursor: default; }
.pui-stars-val {
  font-size: 13px;
  color: #f0c040;
  font-weight: 600;
  margin-left: 6px;
}

/* ── Empty State ─────────────────────────────────── */
.pui-empty {
  text-align: center;
  padding: 40px 20px;
  color: var(--text-dim);
}
.pui-empty-icon {
  font-size: 32px;
  opacity: 0.3;
  margin-bottom: 8px;
}
.pui-empty-msg {
  font-size: 14px;
}
@media (max-width: 760px) { .pui-empty-msg { font-size: 17px; } }   /* Phone text law: every empty list reads at a glance */

/* ── Button disabled ─────────────────────────────── */
.pui-btn:disabled, .pui-btn.disabled {
  opacity: 0.5;
  cursor: not-allowed;
  pointer-events: none;
}
.pui-btn-sm {
  font-size: 11px;
  padding: 5px 10px;
}

/* ── Animations ──────────────────────────────────── */
@keyframes puiFadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}
@keyframes puiFadeOut {
  from { opacity: 1; }
  to { opacity: 0; }
}

/* Universal-search highlight pulse — applied for ~1.5s by ui.highlightFromUrl()
   when arriving at a mod page with ?_highlight=<id>. */
.pui-search-flash {
  animation: pui-search-flash 1.5s ease;
  outline: 2px solid var(--primary, #00e6d2);
  outline-offset: 2px;
  border-radius: inherit;
}
@keyframes pui-search-flash {
  0%, 100% { box-shadow: none; }
  20%, 60% { box-shadow: 0 0 0 4px var(--primary, #00e6d2); }
}

/* ── platform.ui.heart — 4-state shared heart ────────────────────────
   States set via data-state attribute by ui.heart():
     none         → grey filled (not following)
     follows-you  → orange outline (they → you only)
     following    → red outline   (you → them only)
     mates        → solid red     (mutual)
     self         → display:none  (don't render heart on your own profile)
*/
/* THE ONE HEART RULE (Damon 2026-10-20): the follow heart svg (ui.heartSvg) and the heart button (ui.heart, its size
   inline) — no nudges; a heart is centred by its ROW (the heart + count row is align-items:center) and the count beside
   it (.pui-hcount) has its box trimmed to its digits (cap height → baseline), so 'centre' is the digits' centre */
.pui-hcount { text-box: trim-both cap alphabetic; }
.pui-heart {
  width: 1em; height: 1em; flex: none; vertical-align: middle;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  border: none;
  padding: 0;
  cursor: pointer;
  transition: transform 0.12s;
  color: currentColor;
}
@media (hover:hover){.pui-heart:hover{ transform: scale(1.08); }}
.pui-heart svg path {
  fill: transparent;
  stroke: currentColor;
  stroke-width: 1.6;
  vector-effect: non-scaling-stroke;
}
.pui-heart[data-state="none"]         { color: #7a7d85; }
.pui-heart[data-state="none"]         svg path { fill: #7a7d85; stroke: #7a7d85; }
.pui-heart[data-state="follows-you"]  { color: #ff9d2a; }
.pui-heart[data-state="follows-you"]  svg path { fill: transparent; stroke: #ff9d2a; }
.pui-heart[data-state="following"]    { color: #ff3366; }
.pui-heart[data-state="following"]    svg path { fill: transparent; stroke: #ff3366; }
.pui-heart[data-state="mates"]        { color: #ff1a4c; }
.pui-heart[data-state="mates"]        svg path { fill: #ff1a4c; stroke: #ff1a4c; }
.pui-heart[data-busy="1"]             { opacity: 0.5; pointer-events: none; }

/* ── Shared banter composer (ui.banterBar) — tourney + Multi lobbies use the
   SAME widget so the composer never drifts (Damon 2026-07-07). ── */
.uib { flex: 1 1 auto; display: flex; flex-direction: column; min-height: 0; border-top: 1px solid var(--border, #2a2a3a); }
/* head + bar never shrink: on a narrow portrait panel a shrinkable bar measured
   0-height mid-settle (master2, tourney) — pin both so the composer is stable in
   every consumer, not per-consumer overrides. */
.uib-head { flex: 0 0 auto; display: flex; align-items: center; gap: 10px; padding: 8px 12px; font-family: var(--font-head, 'Bungee', sans-serif); font-size: 13px; text-transform: uppercase; letter-spacing: .05em; color: var(--text-mid, #9a9aae); }
.uib-title { flex: 0 0 auto; }
.uib-head.uib-drag { cursor: ns-resize; touch-action: none; user-select: none; }
.uib-head.uib-drag::after { content: '↕'; opacity: .35; font-size: 12px; margin-left: auto; flex: 0 0 auto; }
/* action pill (Nudge/Invite mates) sits to the RIGHT of the title; when the
   head is also a drag handle it sits just left of the ↕ glyph. */
.uib-action { margin-left: auto; display: inline-flex; align-items: center; gap: 5px; padding: 5px 11px; border-radius: 999px; cursor: pointer; font-family: inherit; font-size: 11px; text-transform: uppercase; letter-spacing: .04em; background: color-mix(in srgb, var(--accent), transparent 86%); border: 1px solid var(--primary, #00e6d2); color: var(--primary, #00e6d2); transition: background .12s, color .12s; }
.uib-action svg { width: 15px; height: 15px; display: block; }
@media (hover:hover){.uib-action:hover{ background: var(--primary, #00e6d2); color: var(--bg, #0e0e16); }}
.uib-body { flex: 1; overflow-y: auto; padding: 0 12px; display: flex; flex-direction: column; gap: 1px; min-height: 0; }
.uib-msg { display: flex; align-items: center; gap: 8px; padding: 1px 0; font-size: 15px; color: var(--text, #e8e8f0); line-height: 1.3; }
.uib-msg .pui-avatar, .uib-msg .ui-ava, .uib-msg img { width: 22px; height: 22px; flex: 0 0 22px; border-radius: 50%; }
.uib-msg-body b { color: var(--primary, #00e6d2); margin-right: 5px; }
.uib-msg-empty { color: var(--text-mid, #9a9aae); font-size: 12px; padding: 8px 0; }
.uib-bar { flex: 0 0 auto; display: flex; align-items: center; gap: 6px; padding: 8px 12px; border-top: 1px solid var(--border, #2a2a3a); }
.uib-input { flex: 1 1 auto; min-width: 0; background: var(--bg, #0e0e16); border: 1px solid var(--border, #2a2a3a); border-radius: 8px; color: var(--text, #e8e8f0); padding: 7px 10px; font-size: 13px; }
.uib-send { flex: 0 0 auto; width: 34px; height: 34px; border-radius: 8px; display: inline-flex; align-items: center; justify-content: center; background: var(--primary, #00e6d2); border: 1px solid var(--primary, #00e6d2); color: var(--bg, #0e0e16); cursor: pointer; line-height: 1; transition: filter .12s; }
.uib-send svg { width: 18px; height: 18px; display: block; }
@media (hover:hover){.uib-send:hover{ filter: brightness(1.1); }}
.uib-voice { display: inline-flex; gap: 6px; flex: 0 0 auto; }

/* ── platform.report — report pop-up, the report button, the admin queue (2026-10-16) ── */
/* opened from inside other pop-ups (rating 9999, files 9000) — must never open behind them, like ui.confirm */
.pui-modal-overlay.pui-report-ov { z-index: calc(var(--z-popup, 1000) + 1); }
.pui-report-reasons { display: flex; flex-direction: column; gap: 6px; }
.pui-report-reason { text-align: left; padding: 10px 12px; border-radius: 8px; border: 1px solid var(--border, #333);
  background: transparent; color: inherit; font: inherit; font-size: 17px; cursor: pointer; }
.pui-report-reason.on { border-color: var(--primary, #f5891f); background: color-mix(in srgb, var(--primary, #f5891f) 14%, transparent); }
.pui-report-note { width: 100%; box-sizing: border-box; margin-top: 10px; padding: 8px 10px; border-radius: 8px;
  border: 1px solid var(--border, #333); background: transparent; color: inherit; font: inherit; font-size: 17px; resize: vertical; }
.pui-report-btn { display: inline-flex; align-items: center; justify-content: center; gap: 4px; min-width: 32px; min-height: 32px;
  padding: 4px; border: 0; border-radius: 6px; background: transparent; color: var(--text-dim, #999); cursor: pointer; font: inherit; }
@media (hover:hover){.pui-report-btn:hover{ color: var(--danger, #e5484d); }}
.pui-report-queue { font-size: 17px; }
.pui-rq-item { padding: 10px 0; border-bottom: 1px solid var(--border, #333); }
.pui-rq-head { font-size: 16px; text-transform: uppercase; letter-spacing: .04em; color: var(--text-dim, #999); }
.pui-rq-title { margin: 4px 0; font-weight: 600; overflow-wrap: anywhere; }
.pui-rq-why { font-size: 16px; color: var(--text-dim, #999); overflow-wrap: anywhere; }
@media (max-width: 760px) { .pui-report-queue { font-size: 18px; } }
.pui-rq-acts { display: flex; gap: 8px; margin-top: 8px; flex-wrap: wrap; }

.pui-block-btn { padding: 6px 12px; border-radius: 8px; border: 1px solid var(--border, #333); background: transparent; color: inherit; font: inherit; cursor: pointer; }

/* ── ui.quickPost — write, drop in a picture or clip, Post (gamoid social launch 2026-10-16) ── */
.pui-qp { background: var(--bg-card, #12121f); border: 1px solid var(--border, #2a2a3e); border-radius: 14px; padding: 12px 14px; display: flex; flex-direction: column; gap: 10px; box-sizing: border-box; }
.pui-qp.drag { border-color: var(--accent, #f5891f); }
.pui-qp-text { width: 100%; box-sizing: border-box; resize: none; background: transparent; border: 0; border-radius: 10px; padding: 8px 12px; outline: none; color: var(--text, #e8e8f0); font: inherit; font-size: 16px; line-height: 1.45; min-height: 64px; }   /* rounded like everything else (its field line is THE field line's) */
/* THE MIC (ui.mic.seat, Damon 2026-10-20): seated INSIDE its box, bottom right (pui-mic-top: top right); the box leaves room */
.pui-mic-wrap { position: relative; display: block; width: 100%; }
.pui-mic-wrap > textarea { display: block; width: 100%; box-sizing: border-box; padding-right: 58px !important; }
.pui-mic { position: absolute; right: 8px; bottom: 8px; width: 44px; height: 44px; border-radius: 50%; padding: 0; display: flex; align-items: center; justify-content: center;
  background: #1c1c2c; border: 1px solid #2a2a40; color: #bfc6d4; cursor: pointer; z-index: 1; }
.pui-mic-top > .pui-mic { top: 8px; bottom: auto; }
.pui-mic.pui-mic-auto { bottom: auto; right: auto; }   /* the automatic one: placed over its field by ui.v1 (left/top/size) */
.pui-mic.pui-mic-line svg { width: 60%; height: 60%; }
.pui-mic svg { width: 22px; height: 22px; }
.pui-mic.on { background: #e5484d; border-color: #e5484d; color: #fff; animation: puiMicOn 1.2s ease-in-out infinite; }
@keyframes puiMicOn { 50% { box-shadow: 0 0 0 6px rgba(229,72,77,.25); } }
@media (hover:hover) { .pui-mic:not(.on):hover { border-color: var(--accent, #f5891f); color: var(--accent, #f5891f); } }
@media (max-width: 760px) { .pui-mic { width: 52px; height: 52px; } .pui-mic svg { width: 26px; height: 26px; } .pui-mic-wrap > textarea { padding-right: 66px !important; } }
.pui-qp-media { position: relative; border-radius: 10px; overflow: hidden; background: #000; align-self: flex-start; max-width: 100%;
  border: 1.5px solid var(--primary, #f5891f); box-sizing: border-box; }   /* a thin brand-orange outline, as the guide's pictures — so it never just sits there (Damon 2026-10-20) */
.pui-qp-media img, .pui-qp-media video { display: block; max-width: 100%; max-height: 320px; }
.pui-qp-rm { position: absolute; top: 6px; right: 6px; width: 30px; height: 30px; border-radius: 50%; border: 0; background: rgba(0,0,0,.65); color: #fff; font-size: 20px; line-height: 1; cursor: pointer; z-index: 1; }
.pui-qp-bar { display: flex; align-items: center; gap: 10px; }
.pui-qp-add { display: inline-flex; align-items: center; gap: 7px; color: var(--text-mid, #a0a0b8); cursor: pointer; font-size: 14px; padding: 6px 10px; border-radius: 8px; border: 1px solid var(--border, #2a2a3e); }
.pui-qp-add[hidden], .pui-qp-rm[hidden] { display: none; }   /* editing a post: its picture or clip stays as it is */
@media (hover:hover){.pui-qp-add:hover{ color: var(--accent, #f5891f); border-color: var(--accent, #f5891f); }}
.pui-qp-go { margin-left: auto; min-width: 84px; }
.pui-qp-add, .pui-qp-go { height: 38px; box-sizing: border-box; font-size: 14px; }
.pui-qp-note { font-size: 15px; color: var(--text-dim, #7a7a92); }
.pui-qp-modal { width: min(560px, calc(100vw - 32px)); box-sizing: border-box; }
.pui-qp-modal .pui-qp { border: 0; padding: 0; background: transparent; }
.pui-qp-modal .pui-modal-actions { display: none; }   /* the post pop-up has its own Post button: no empty footer under it */
@media (max-width: 760px) { .pui-qp-add, .pui-qp-go { height: 46px; font-size: 17px; } .pui-qp-note { font-size: 16px; } }   /* Phone text law: nothing under 16px */
/* gamoid (config.ui.phoneTextLaw / cardLine; Damon 2026-10-20 — the composer's text was tiny on his iPhone): the typed
   text is the shared field size (below), the bar's buttons the shared button sizes — Photo / video SECONDARY, Post
   PRIMARY — and the note reads at normal contrast */
html[data-tl] .pui-qp-text { font-size: var(--pui-field-fs); }
html[data-tl] .pui-qp-bar .pui-qp-add, html[data-tl] .pui-qp-bar .pui-qp-go { height: var(--pb-std-h); }
html[data-tl] .pui-qp-bar .pui-qp-add { font-size: var(--pui-sec-fs); font-weight: 600; }   /* Photo / video: the secondary label; Post: the primary label */
html[data-cl] .pui-qp-add { border: 1.5px solid var(--pui-sec-line); color: var(--pui-sec-fg); }
html[data-tl] .pui-qp-note { color: var(--text, #e8e8f0); }

/* ── INFO pop-up from the top-right menu (shell pubOpenInfo: Notifications | FAQ | Roadmap; gamoid 2026-10-19, was the FAQ pop-up) ── */
.pub-info-modal{width:min(720px,calc(100vw - 32px));max-width:none;min-width:0;height:min(680px,86vh);box-sizing:border-box}   /* one size for every tab: switching tabs never resizes it; centred with the blur behind, 16px gutters on a phone (Damon's pop-up rule) */
.pub-info-modal .pui-modal-actions{display:none}
.pub-info-modal .pui-tabs{margin:0 0 16px}
/* Info's section titles (Notifications, FAQ, Roadmap) in Bungee at the normal text colour, 18px on a PC (the phone's gmob.css sets its tabs to 16px: all three fit at 390) (Damon 2026-10-21) */
.pub-info-modal .pui-tab{font-family:'Bungee',var(--font-head,system-ui),sans-serif;font-weight:400;font-size:18px;letter-spacing:.03em;color:var(--text,#e8e8f0)}
.pub-info-modal .pui-tab.active{color:var(--primary)}
@media (max-width:760px){.pub-info-modal .pui-tabs{justify-content:space-between}.pub-info-modal .pui-tab{font-size:20px !important;letter-spacing:0;padding:10px 4px;white-space:nowrap}}
.pub-info-q{font-weight:700;-webkit-text-stroke:.5px currentColor;font-size:18px;color:var(--text,#e8e8f0);margin:18px 0 6px}
/* THE TITLES (FAQ questions, a post's title, a Roadmap item's 'Title:') 2px bigger and bolder than they were (Damon 2026-10-20);
   DM Sans is loaded up to 700, so the extra weight is a hairline stroke */
.pub-info-t{font-weight:700;-webkit-text-stroke:.5px currentColor;font-size:calc(1em + 2px);color:var(--text,#e8e8f0)}
.pub-info-q:first-child{margin-top:0}
@media (max-width:760px){.pub-info-q,.pub-info-t{font-size:22px}}   /* phone text law: titles 22px, words 18px */
.pub-info-date{font-size:16px;color:var(--text-dim,#8a8aa0);margin:0 0 6px}   /* a Notifications post's date, under its title */
.pub-info-a{font-size:18px;line-height:1.55;color:var(--text-mid,#b8b8cc);margin:0;white-space:pre-wrap;overflow-wrap:anywhere}
/* the tab being built (ui.swapWhenFinal) lies hidden over the shown one: clipped here, so it never stretches the pop-up's scroll
   before the swap — the tab changes in ONE step (Damon 2026-10-20: it settled 16px a frame later) */
.pub-info-bodies{position:relative;overflow:hidden}
.pub-info-list{margin:0;padding:0 0 0 20px;font-size:18px;line-height:1.55;color:var(--text-mid,#b8b8cc)}
.pub-info-list li{margin:0 0 12px;overflow-wrap:anywhere}
@media (max-width:760px){.pub-info-modal{height:min(600px,calc(100% - max(0px, var(--pui-top, 0px) - var(--pui-safe-top)) - 2 * var(--pui-pop-gap)))}}

/* ── THE ADMIN PAGE (shell pubAdmin, Damon 2026-10-22): the avatar menu's top item, admins only — tabs are the shared
   buttons (the open one primary), the page as big as a page pop-up; phone text law (18 / 22) ── */
.pub-user-admin{display:block;width:calc(100% - 16px);margin:4px 8px 8px;min-height:46px;border-radius:12px}
.pub-admin-modal{width:min(1100px,calc(100vw - 32px));max-width:none;min-width:0;height:min(880px,90vh);box-sizing:border-box}
.pub-admin-modal .pui-modal-actions{display:none}
.pad-tabs{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 16px}
.pad-tabs .pui-btn{min-height:40px;padding:6px 14px;border-radius:10px}
.pad-body{font-size:16px;position:relative}
.pad-msg,.pad-note{font-size:17px;color:var(--text-mid,#b8b8cc);padding:6px 0 10px}
.pad-row{font-size:16px;padding:8px 0;border-bottom:1px solid rgba(255,255,255,.08);overflow-wrap:anywhere}
.pad-dim{color:var(--text-mid,#a0aab0)}
.pad-gate{display:flex;flex-direction:column;align-items:center;gap:16px;padding:40px 8px;text-align:center}
.pad-gate-t{font-size:22px;font-weight:700;color:var(--text,#e8e8f0)}
.pad-gate-b{min-height:48px;padding:10px 24px;border-radius:12px}
.pad-code{width:220px;height:54px;box-sizing:border-box;border-radius:12px;border:1.5px solid var(--pui-sec-line,#454c66);background:var(--bg,#0b0b14);color:var(--text,#e8e8f0);font:600 24px/1 system-ui,sans-serif;letter-spacing:.2em;text-align:center}
.pad-err{font-size:18px;color:#ff6b6b}
@media (max-width:760px){
  .pub-admin-modal{height:calc(100% - max(0px, var(--pui-top, 0px) - var(--pui-safe-top)) - 2 * var(--pui-pop-gap))}
  .pad-body,.pad-row,.pad-msg,.pad-note,.pad-err{font-size:18px}
  .pad-gate-t{font-size:24px}
}

/* the auth pages' shared top bar (/signup, /signup-player, /login) — the brand-coloured bits (.gs-nav itself,
   .gs-nav-logo-text, .gs-nav-right a, the CTA) stay with each page; these were pasted identically in all three */
.gs-nav-icon { display: inline-flex; }
.gs-nav-icon img { width: 40px; height: 40px; border-radius: 6px; object-fit: cover; display: block; }
.gs-nav-logo { display: flex; align-items: center; justify-content: center; }
.gs-nav-logo img { max-height: 53px; max-width: 280px; object-fit: contain; display: block; }
.gs-nav-right { display: flex; justify-content: flex-end; align-items: center; gap: 14px; }

/* the auth pages' top bar on a phone (2026-10-16, masterPhone): logo + Sign In + Sign Up must fit 390px with no
   sideways scroll — the logo column shrinks, the links don't wrap. html body beats mod-signup's later 17px rule. */
.gs-nav-logo { min-width: 0; }
/* scoped to the auth pages' own bar (.gs-nav-auth, okdunio server.js) so these caps never reach another page's
   top bar — the gamoid landing shrank under them (Damon 2026-10-18) */
@media (max-width: 480px) {
  html body .gs-nav-auth { grid-template-columns: auto minmax(0, 1fr) auto; padding: 0 10px; gap: 8px; }
  html body .gs-nav-auth .gs-nav-logo img { max-height: 34px; max-width: 100%; }
  html body .gs-nav-auth .gs-nav-right { gap: 8px; }
  html body .gs-nav-auth .gs-nav-right a { font-size: 14px; white-space: nowrap; }
  html body .gs-nav-auth .gs-nav-right .gs-nav-cta { padding: 7px 12px; font-size: 12px; }
}

/* ── Every pop-up on a PHONE (Damon 2026-10-16: "the X is too small on mobile, should be twice as big"; "the words
   are all just tiny"): a thumb-size ×, a readable title, body text at 17px, buttons a finger can hit. html.gmob is
   the shell's phone class; the 760px query covers pages without it. */
html.gmob .pui-modal-x { width: 56px; height: 56px; top: 6px; right: 6px; font-size: 44px; border-radius: 12px; }
html.gmob .pui-modal-header { padding: 0 70px 0 18px; font-size: 18px; }
html.gmob .pui-modal > .pui-modal-header { min-height: 66px; }
html.gmob .pui-modal:not(:has(> .pui-modal-header)) > .pui-modal-content > :first-child { margin-right: 46px; min-height: 46px; }
html.gmob .pui-modal-content { font-size: 17px; line-height: 1.5; }
html.gmob .pui-modal-actions .pui-btn { font-size: 17px; padding: 12px 20px; }
html.gmob .pub-info-modal .pub-info-q { font-size: 23px; }
html.gmob .pub-info-modal .pub-info-a, html.gmob .pub-info-modal .pub-info-list { font-size: 19px; }
html[data-tl] .pui-modal-content { font-size: 16px; }   /* a PC pop-up's body text on gamoid (18px on a phone, below) */
@media (max-width: 760px) {
  .pui-modal-x { width: 56px; height: 56px; font-size: 44px; }
  .pui-modal-header { padding-right: 70px; font-size: 18px; }
  .pui-modal > .pui-modal-header { min-height: 66px; }
  .pui-modal:not(:has(> .pui-modal-header)) > .pui-modal-content > :first-child { margin-right: 46px; min-height: 46px; }
  .pui-modal:not(:has(> .pui-modal-header)) > .pui-modal-content:has(> :is(h1,h2,h3):first-child) { padding-top: 6px; }
  .pui-modal-content { font-size: 17px; line-height: 1.5; }
  .pui-modal-actions .pui-btn { font-size: 17px; padding: 12px 20px; }
  /* THE PHONE TEXT LAW at the source (Damon 2026-10-19: nothing read under 16px, titles 20px+), on a site that turns it
     on (config.ui.phoneTextLaw → html[data-tl]; gamoid — hashoid keeps its sizes): a pop-up's title, ui.tabs and buttons
     (and the small ones) are phone-size by default */
  html[data-tl] .pui-modal-header { font-size: 20px; }
  /* POP-UP BODY TEXT (Damon 2026-10-20: he kept hitting tiny text): 18px on a phone, and a mod's pop-up sets NO size of
     its own for its body — it inherits this; only titles, big numbers and buttons size themselves */
  html[data-tl] .pui-modal-content { font-size: 18px; }
  html[data-tl] .pui-tab, html[data-tl] .pui-btn, html[data-tl] .pui-btn-sm { font-size: 16px; }
  .pub-info-modal .pub-info-q { font-size: 21px; }
  .pub-info-modal .pub-info-a, .pub-info-modal .pub-info-list { font-size: 17px; }
}


/* ── THE X — ONE close button for every pop-up and every game-mode X (Damon 2026-10-16 "uniform per device";
   2026-10-17 game-mode fix 1). New code uses ui.closeX() / class "pui-x"; the older ids/classes listed here are the
   same component. The glyph is a drawn X (not the font's ×, which sat 1-4px low), centred by construction: a 12px
   glyph in a 32px circle on a PC, 14px in a 42px circle on a phone. The circle is 80% of the old 40/52px one; the
   4px/5px margin keeps the X exactly where it was (same centre). Always TOP RIGHT (GAMOID.md). */
.pui-x, .pui-modal-x, .sup-close, .tp-lightbox-x, .gfb-x, .pub-user-x, .sl-x, .gs-modal .gs-close, .pub-page-close, #gbAskX, #cpX, .news-lightbox-close, .pcap-menu-x, .news-menu-x, #gameBarX, #gpChip .x {
  box-sizing: border-box !important; width: 32px !important; height: 32px !important; min-width: 0 !important; margin: 4px !important;
  border-radius: 50% !important; padding: 0 !important; border: 2px solid var(--pui-x-ring) !important; color: transparent !important;
  background: rgba(14,14,24,.88) !important;
  font: 0/0 a !important; text-indent: 0 !important; display: flex !important; align-items: center !important; justify-content: center !important; flex: none; box-shadow: 0 3px 12px rgba(0,0,0,.45); cursor: pointer; }
.pui-x > *, .pui-modal-x > *, .sup-close > *, .tp-lightbox-x > *, .gfb-x > *, .pub-user-x > *, .sl-x > *, .gs-modal .gs-close > *, .pub-page-close > *, #gbAskX > *, #cpX > *, .news-lightbox-close > *, .pcap-menu-x > *, .news-menu-x > *, #gameBarX > *, #gpChip .x > * { display: none !important; }
@media (hover:hover){.pui-x:hover, .pui-modal-x:hover, .sup-close:hover, .tp-lightbox-x:hover, .gfb-x:hover, .pub-user-x:hover, .sl-x:hover, .gs-modal .gs-close:hover, .pub-page-close:hover, #gbAskX:hover, #cpX:hover, .news-lightbox-close:hover, .pcap-menu-x:hover, .news-menu-x:hover, #gameBarX:hover, #gpChip .x:hover{ background: #f5891f !important; border-color: #f5891f !important; }}
@media (max-width: 760px) {
  .pui-x, .pui-modal-x, .sup-close, .tp-lightbox-x, .gfb-x, .pub-user-x, .sl-x, .gs-modal .gs-close, .pub-page-close, #gbAskX, #cpX, .news-lightbox-close, .pcap-menu-x, .news-menu-x, #gameBarX, #gpChip .x { width: 42px !important; height: 42px !important; margin: 5px !important; }
  @media (hover:hover){.pui-x:hover, .pui-modal-x:hover, .sup-close:hover, .tp-lightbox-x:hover, .gfb-x:hover, .pub-user-x:hover, .sl-x:hover, .gs-modal .gs-close:hover, .pub-page-close:hover, #gbAskX:hover, #cpX:hover, .news-lightbox-close:hover, .pcap-menu-x:hover, .news-menu-x:hover, #gameBarX:hover, #gpChip .x:hover{ }}
  /* Info +2px (Damon 2026-10-16, the FAQ's sizes; the questions +2px more 2026-10-20) */
  .pub-info-modal .pub-info-q { font-size: 23px; }
  .pub-info-modal .pub-info-a, .pub-info-modal .pub-info-list { font-size: 19px; }
}
/* THE X's glyph: drawn in --pui-x-ring (dark on the orange hover), 12px on a PC, 14px on a phone */
.pui-x::before, .pui-modal-x::before, .sup-close::before, .tp-lightbox-x::before, .gfb-x::before, .pub-user-x::before, .sl-x::before, .gs-modal .gs-close::before, .pub-page-close::before, #gbAskX::before, #cpX::before, .news-lightbox-close::before, .pcap-menu-x::before, .news-menu-x::before, #gameBarX::before, #gpChip .x::before { content: '' !important; display: block !important; flex: none; width: 12px; height: 12px; background: var(--pui-x-ring); -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M1.5 1.5L10.5 10.5M10.5 1.5L1.5 10.5' stroke='%23fff' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E") center / contain no-repeat; mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'%3E%3Cpath d='M1.5 1.5L10.5 10.5M10.5 1.5L1.5 10.5' stroke='%23fff' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E") center / contain no-repeat; }
@media (hover:hover){.pui-x:hover::before, .pui-modal-x:hover::before, .sup-close:hover::before, .tp-lightbox-x:hover::before, .gfb-x:hover::before, .pub-user-x:hover::before, .sl-x:hover::before, .gs-modal .gs-close:hover::before, .pub-page-close:hover::before, #gbAskX:hover::before, #cpX:hover::before, .news-lightbox-close:hover::before, .pcap-menu-x:hover::before, .news-menu-x:hover::before, #gameBarX:hover::before, #gpChip .x:hover::before{ background: #0b0b14; }}
@media (max-width: 760px) { .pui-x::before, .pui-modal-x::before, .sup-close::before, .tp-lightbox-x::before, .gfb-x::before, .pub-user-x::before, .sl-x::before, .gs-modal .gs-close::before, .pub-page-close::before, #gbAskX::before, #cpX::before, .news-lightbox-close::before, .pcap-menu-x::before, .news-menu-x::before, #gameBarX::before, #gpChip .x::before { width: 14px; height: 14px; } }
/* ── ONE RULE: while ANY pop-up is open (here or in a frame inside this page), the page behind it does not scroll and
   only the TOP pop-up takes the wheel / a drag (Damon 2026-10-16/17: "one piece of code, not millions"). ui.v1.js
   (popLock) finds the pop-ups, sets html.pui-lock, marks each pop-up .pui-pop and routes the wheel and touch. */
/* NO overflow:hidden on the page (Damon 2026-10-18, PC: "tapping Jump In makes the background grow" — hiding the page's
   overflow took its scrollbar away and the page widened); the wheel/touch routing above already keeps it still */
html.pui-lock, html.pui-lock body, html.pui-lock #list-app { overscroll-behavior: none; }
.pui-pop, .pui-pop * { overscroll-behavior: contain; }

/* the grab-and-drag scrollbar (ui.fastScroll): a SLIM grey bar in the gap right of the cards (never over them), with a
   44px-wide grab strip around it while it shows (Damon 2026-10-16) */
.pui-fs { position: fixed; width: 44px; z-index: var(--z-toast, 3000); display: none; pointer-events: none; opacity: 0; transition: opacity .25s; touch-action: none; }
.pui-fs.on { opacity: 1; pointer-events: auto; }
html.gpop .pui-fs { display: none !important; }   /* never a scroll bar while a game is up (the game layer: html.gpop) */
.pui-fs-th { position: absolute; right: 2px; width: var(--pui-sb); border-radius: var(--pui-sb); background: var(--pui-sb-thumb); pointer-events: none; }
.pui-fs.drag .pui-fs-th { background: var(--primary, #f5891f); }
/* a list with the grab-and-drag bar shows only that one — no second, slowly fading system bar (Damon 2026-10-16) */
.pui-fs.pui-fs-x .pui-fs-th { right: auto; top: auto; bottom: 2px; height: var(--pui-sb); }   /* the same bar, along a sideways strip */
/* EVERY POP-UP (Damon 2026-10-18): it never scrolls sideways, and its ONE scrollbar is THE bar (ui.fastScroll) — no
   other scrollbar shows at any layer inside it (a page shown in a pop-up = html.pui-framed). Sideways scrolling exists
   only inside a strip, with the same bar along it. */
html.pui-framed, html.pui-framed body, .pui-modal-content { overflow-x: hidden !important; }
html.pui-framed, .pui-modal, #pubPop { overscroll-behavior-x: none; }
html.pui-framed *, .pui-modal * { scrollbar-width: none; }
html.pui-framed *::-webkit-scrollbar, .pui-modal *::-webkit-scrollbar { display: none; width: 0; height: 0; }
/* a date field shows its box on an iPhone like every other field (iOS ignores the border on the native date input) */
input[type="date"] { -webkit-appearance: none; appearance: none; min-height: 44px; box-sizing: border-box; }
.pui-fs-host { scrollbar-width: none; }
.pui-fs-host::-webkit-scrollbar { display: none; width: 0; height: 0; }
/* the boxes THE bar takes over have no native bar from their FIRST paint (Damon 2026-10-20: nothing resizes after it
   shows) — ui.fastScroll marks them 300ms after they render, and until then the native bar took 8px and the Play list's
   cards widened when it went */
#pubPop .pub-pop-scroll, [data-fastscroll] { scrollbar-width: none; }
#pubPop .pub-pop-scroll::-webkit-scrollbar, [data-fastscroll]::-webkit-scrollbar { display: none; width: 0; height: 0; }
/* on a PHONE every page's own scroller (the box right under the page pane: the Play list, Latest's feed, a studio page)
   has THE overlay bar and no native bar — the native one took 8px on the right, so the right gap was bigger than the
   left (Damon 2026-10-20: equal, small side gaps; the bar never steals width on a phone) */
@media (max-width: 760px) { #pub-mod-active > * { scrollbar-width: none; } #pub-mod-active > *::-webkit-scrollbar { display: none; width: 0; height: 0; } }
/* THE TOP NAV NEVER MOVES (Damon 2026-10-20, iPhone app: on Latest the WHOLE screen scrolled, nav included, and the feed
   would not reach its end): on an app page the document itself never takes a scroll — iOS drags it despite
   overflow:hidden once a swipe runs past a list's end — and each page's own scroller keeps its scroll to itself */
html:has(#pub-mod-active), html:has(#pub-mod-active) body { overscroll-behavior: none; }
#pub-mod-active > * { overscroll-behavior-y: contain; }
/* ── ONE BUSY INDICATOR (Damon 2026-10-18: a static '…' after Sign In looked crashed): a button that waits shows three
   dots that keep cycling . .. ... — ui.busy(btn, true) puts them in, ui.busy(btn, false) gives the label back. The
   dots hold their width, so the button never jumps. */
.pui-busy { pointer-events: none; }
.pui-dots { display: inline-block; letter-spacing: .12em; }
.pui-dots i { font-style: normal; }
.pui-dots i:nth-child(2) { animation: pui-dot2 1.2s linear infinite; }
.pui-dots i:nth-child(3) { animation: pui-dot3 1.2s linear infinite; }
@keyframes pui-dot2 { 0%, 33% { opacity: 0; } 33.5%, 100% { opacity: 1; } }
@keyframes pui-dot3 { 0%, 66% { opacity: 0; } 66.5%, 100% { opacity: 1; } }
/* THE settings Save while nothing has changed (ui.saveWatch, Damon 2026-10-18): dimmed, not clickable */
.pui-save-off{ opacity: .45 !important; cursor: default !important; filter: none !important; }
@media (hover:hover){.pui-save-off:hover{ opacity: .45 !important; cursor: default !important; filter: none !important; }}
/* THE page loader (Damon 2026-10-18): the one 'Loading…' a page or pop-up shows while it's still loading — one size
   token; 50% bigger on a phone. Every loader uses this class, so changing it changes them all. */
:root { --pui-loader-size: 16px; }
@media (max-width: 760px) { :root { --pui-loader-size: 24px; } }
.pui-loader { font: 600 var(--pui-loader-size)/1.2 system-ui, -apple-system, 'Segoe UI', sans-serif !important; color: #9a9ab0; }

/* ── A PAGE IN A POP-UP (ui.modal({ frame })): the pop-up is as tall as its page (ui.fitFrame sizes the frame), centred,
   up to the screen less the gap — only a taller page fills the height and scrolls inside (Damon 2026-10-18) */
.pui-modal.pui-modal-framed .pui-modal-content { flex: 0 1 auto; min-height: 0; display: block; padding: 0; position: relative; overflow-y: auto; }
/* a pop-up holding a page keeps its ROUNDED CORNERS (Damon 2026-10-18: the plans pop-up's top corners were chopped — the
   page inside painted square over them): the panel clips everything to its own corners, its scroller and the frame
   take the same rounding, the frame itself paints nothing */
.pui-modal.pui-modal-framed { overflow: hidden; }
.pui-modal.pui-modal-framed > .pui-modal-content, .pui-modal.pui-modal-framed .pui-frame { border-radius: inherit; background: transparent; }
.pui-modal.pui-modal-framed .pui-frame { display: block; width: 100%; height: 100%; }
/* the page inside a pop-up never scrolls itself (ui.fitFrame sizes the frame to it); while the page has its own pop-up
   open (pui-fit-off) it scrolls itself for that moment so the overlay sits in view */
html.pui-framed:not(.pui-fit-off), html.pui-framed:not(.pui-fit-off) body { overflow-y: hidden !important; }
/* …and nothing in it is sized from the frame's own height (100% / 100vh minimums would only let it grow): the page is
   as tall as its content */
html.pui-framed:not(.pui-fit-off), html.pui-framed:not(.pui-fit-off) body, html.pui-framed:not(.pui-fit-off) #mod-root { min-height: 0 !important; height: auto !important; }
.pui-frame { flex: 1; width: 100%; min-height: 0; border: 0; background: transparent; }
/* ── THE BUTTON OUTLINE (Damon 2026-10-18: the sign-in buttons barely showed as boxes): one token, as distinct as a plan
   card's border; every sign-in provider button uses it (the plans pop-up's Jump In box, the welcome page's sign-in, the
   sign-in modal); hover keeps its own colour */
:root { --pui-btn-line: #3f4858; }
.gs-modal .gs-soc-btn:not(:hover) { border-color: var(--pui-btn-line) !important; }

/* a pop-up holding a PAGE (ui.modal({ frame })): the X's room is given by the page inside to its own first box — the
   frame itself is never narrowed (the plans pop-up lost 46px of width to it) */
.pui-modal.pui-modal-framed > .pui-modal-content > :first-child { margin-right: 0 !important; min-height: 0 !important; }

/* ── THE PROVIDER ROW (ui.providerRow): Google / Discord / Steam / Nostr four across, outlined boxes (--pui-btn-line),
   the same in the sign-in pop-up and the Jump In box (Damon 2026-10-18) */
.pui-prov { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; }
.pui-prov-btn { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 5px; min-height: 64px; padding: 8px 2px;
  border: 1px solid var(--pui-btn-line, #3f4858); border-radius: 10px; background: #0b0b14; color: #e8e8f0; font: 600 16px 'DM Sans', system-ui, sans-serif; cursor: pointer; }
@media (hover:hover){.pui-prov-btn:hover{ border-color: var(--primary, #f5891f); }}
.pui-prov-ic { font-size: 24px; line-height: 1; }
.pui-prov-ic svg { width: 22px; height: 22px; }
.pui-prov-lbl { white-space: nowrap; }
/* the row's one message line, under the buttons (Nostr's 'No Nostr signer found. Get Alby →', a provider error) */
.pui-prov-msg { margin-top: 8px; font-size: 15px; line-height: 1.35; color: #c4c4d4; text-align: center; }
.pui-prov-msg:empty { display: none; }
.pui-prov-msg a { color: var(--primary, #f5891f); font-weight: 600; text-decoration: underline; }
@media (max-width: 760px) { .pui-prov-msg { font-size: 17px; } }

/* ── THE AVATAR PICKER (ui.avatarPicker, Damon 2026-10-19: one picker, drawn in place — no page in a frame). The sizes
   are the approved ones the framed picker had: sign-up form (phone 96 picture / 48 arrows / Change 18px / 18px dots;
   PC 76 / 36 / 14px / 16px), Settings → Account (84 / 48 / 18px / 18px + SAVE), the plain page (110 / 48 / 14px / 26px). */
.pap { font-family: 'DM Sans', sans-serif; color: var(--pap-text); text-align: left; }
.pap *, .pap *::before, .pap *::after { box-sizing: border-box; }
.pap-card { display: flex; flex-direction: column; align-items: center; gap: 12px; padding: 18px 16px; }
.pap-wrap { display: flex; flex-direction: column; align-items: center; gap: 8px; width: 100%; }
.pap-thm { display: none; }
.pap-pic { width: 84px; height: 84px; border-radius: 50%; border: 2px solid var(--pap-border); background: var(--pap-circle); display: flex; align-items: center; justify-content: center; overflow: hidden; position: relative; flex: none; }
.pap-btns { display: flex; gap: 8px; align-items: center; }
.pap-nav, .pap-change { background: var(--pap-input); border: 1px solid #3dc8ff; color: var(--pap-text); font: 600 18px 'DM Sans', sans-serif; cursor: pointer; transition: all .15s; }
.pap-nav { width: 48px; height: 48px; padding: 0; border-radius: 50%; color: #fff; line-height: 1; display: inline-flex; align-items: center; justify-content: center; }
.pap-nav svg { width: 28px; height: 28px; }
.pap-nav:disabled { opacity: .55; cursor: default; }
.pap-change { padding: 8px 18px; border-radius: 8px; }
@media (hover:hover) { .pap-change:hover, .pap-nav:hover:not(:disabled) { color: #3dc8ff; } }
.pap-cols { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 6px; }
.pap-sw { width: 18px; height: 18px; border-radius: 50%; border: 2px solid transparent; cursor: pointer; transition: all .15s; flex-shrink: 0; }
@media (hover:hover) { .pap-sw:hover { transform: scale(1.15); } }
.pap-sw.pap-on { border-color: #fff; box-shadow: 0 0 8px rgba(255,255,255,.4); }
.pap-glow { position: absolute; pointer-events: none; opacity: 0; }
.pap-glow-on { animation: pap-glow .6s ease-out forwards; }
@keyframes pap-glow { 0% { opacity: 0; } 30% { opacity: .8; } 100% { opacity: 0; } }
.pap-photo { width: 100%; height: 100%; border-radius: 50%; object-fit: cover; display: block; transform-origin: center center; transition: transform .1s linear; }
.pap-save { display: block; order: 99; align-self: center; width: 80%; max-width: 220px; margin: 6px 0 0; padding: 9px 14px; border: none; border-radius: 6px; background: #3dc8ff; color: #0b0b14; font: 13px 'Bungee', cursive; cursor: pointer; }
.pap-save:disabled { opacity: .4; cursor: default; }
/* gamoid (config.ui.cardLine): SAVE is the primary button; Change and the arrows keep their approved blue outline
   (Damon 2026-10-20) */
html[data-cl] .pap-save { background: var(--pui-pri-bg); color: var(--pui-pri-fg); }
html[data-cl][data-tl] .pap-save { font-size: var(--pui-pri-fs); }   /* the primary label size (Bungee already) */
.pap-err { order: 100; align-self: center; margin-top: 6px; color: #ff3997; font-size: 13px; text-align: center; }
.pap-err:empty { display: none; }
@media (max-width: 760px) { html[data-tl] .pap-save, html[data-tl] .pap-err { font-size: 16px; } }   /* the phone text law (Damon 2026-10-19) */
/* the sign-up form: its own outlined box; the picture left, the two arrows with Change under them beside it, the colours
   on their own centred row (Damon 2026-10-18, one screen per form) */
.pap-signup { border: 1px solid var(--border); border-radius: 8px; background: var(--bg2); padding-bottom: 10px; }
.pap-signup .pap-card { padding-bottom: 4px; }
.pap-signup .pap-wrap { display: grid; grid-template-columns: auto auto; grid-template-areas: "thm thm" "pic btns" "cols cols"; column-gap: 16px; row-gap: 10px; align-items: center; justify-content: center; }
.pap-signup .pap-pic { grid-area: pic; width: 96px; height: 96px; }
.pap-signup .pap-stage { grid-area: pic; }
.pap-signup .pap-btns { grid-area: btns; display: grid; grid-template-columns: 48px 48px; gap: 6px; justify-content: start; }
.pap-signup .pap-change { grid-column: 1 / -1; justify-self: center; }
.pap-signup .pap-cols { grid-area: cols; justify-self: center; }
.pap-signup .pap-src { grid-column: 1 / -1; }
.pap-pc .pap-card { padding: 12px 16px; }
.pap-pc .pap-pic { width: 76px; height: 76px; }
.pap-pc .pap-btns { grid-template-columns: 36px 36px; }
.pap-pc .pap-nav, .pap-pc .pap-change { font-size: 14px; }
.pap-pc .pap-change { padding: 5px 14px; }
.pap-pc .pap-nav { width: 36px; height: 36px; }
.pap-pc .pap-nav svg { width: 20px; height: 20px; }
.pap-pc .pap-sw { width: 16px; height: 16px; }
/* the plain player page (/signup-player) */
.pap-page .pap-card { padding: 0; }
.pap-page .pap-wrap { gap: 12px; margin-bottom: 10px; }
.pap-page .pap-pic { width: 110px; height: 110px; border-color: var(--border); background: var(--bg-surface); }
.pap-page .pap-change { padding: 10px 24px; font-size: 14px; border-color: var(--border); background: var(--bg-surface); }
.pap-page .pap-sw { width: 26px; height: 26px; }
/* Custom Photo (sites without a fixed avatar set): Photo / Local / Assets under the colours, the crop buttons round the picture */
.pap-src { display: flex; gap: 6px; justify-content: center; flex-wrap: wrap; margin-top: 8px; width: 100%; }
.pap-cb { padding: 6px 10px; background: var(--pap-input); border: 1px solid var(--pap-border); color: var(--pap-text); font: 13px 'DM Sans', sans-serif; border-radius: 5px; cursor: pointer; transition: border-color .15s, color .15s; }
@media (hover:hover) { .pap-cb:hover { border-color: #3dc8ff; color: #3dc8ff; } }
.pap-src .pap-cb { display: inline-flex; align-items: center; gap: 6px; }
.pap-ic { display: inline-flex; font-size: 16px; line-height: 0; }
.pap-stage { position: relative; width: 124px; height: 124px; display: flex; align-items: center; justify-content: center; margin: 0 auto; }
.pap-signup .pap-stage { width: 200px; height: 200px; }
.pap-halo { position: absolute; width: 24px; height: 24px; padding: 0; display: flex; align-items: center; justify-content: center; font-size: 12px; line-height: 1; border-radius: 50%; background: rgba(0,0,0,.55); }
.pap-signup .pap-halo { width: 34px; height: 34px; font-size: 17px; }
.pap-h-up { top: 0; left: 50%; transform: translateX(-50%); } .pap-h-down { bottom: 0; left: 50%; transform: translateX(-50%); }
.pap-h-left { left: 0; top: 50%; transform: translateY(-50%); } .pap-h-right { right: 0; top: 50%; transform: translateY(-50%); }
.pap-h-zout { top: 0; left: 0; } .pap-h-zin { top: 0; right: 0; } .pap-h-reset { bottom: 0; right: 0; }
.pap-signup .pap-h-up { top: -6px; } .pap-signup .pap-h-down { bottom: -6px; } .pap-signup .pap-h-left { left: -6px; } .pap-signup .pap-h-right { right: -6px; }
.pap-signup .pap-h-zout { top: -2px; left: -2px; } .pap-signup .pap-h-zin { top: -2px; right: -2px; } .pap-signup .pap-h-reset { bottom: -2px; right: -2px; }
.pap-crop-off .pap-halo { pointer-events: none; opacity: .4; }
.pap-video { width: 320px; max-width: 100%; height: 240px; background: #000; border-radius: 6px; object-fit: cover; display: block; }


/* THE TOOLTIP (Damon 2026-10-19): class pui-tip + data-tip="words" — a soft rounded label under the element (data-tip-at=
   "above": over it; "right" / "above-right": starting at its left edge, for things at a screen edge) on a hover (PC); on a phone a tap shows it for an info-only element (pui-tip-tap, ui.v1.js). One look
   everywhere: the Play bar's icons, Latest's bar, a studio card's flag and owner. */
.pui-tip[data-tip] { position: relative; }
.pui-tip[data-tip].pui-tip-on::after { content: attr(data-tip); }
@media (hover: hover) { .pui-tip[data-tip]:hover::after { content: attr(data-tip); } }
.pui-tip[data-tip]::after { position: absolute; top: calc(100% + 8px); left: 50%; transform: translateX(-50%); white-space: nowrap;
  padding: 6px 12px; border-radius: 10px; background: #1c1c2c; border: 1px solid rgba(255,255,255,.16); color: #e8e8f0;
  font: 600 16px/1.2 'DM Sans', system-ui, sans-serif; box-shadow: 0 6px 18px rgba(0,0,0,.5); z-index: var(--z-menu, 2000); pointer-events: none; }
.pui-tip[data-tip][data-tip-at="above"]::after { top: auto; bottom: calc(100% + 8px); }
.pui-tip[data-tip][data-tip-at="right"]::after { left: 0; transform: none; }
.pui-tip[data-tip][data-tip-at="above-right"]::after { top: auto; bottom: calc(100% + 8px); left: 0; transform: none; }
.pui-tip[data-tip][data-tip-at="auto"]::after { transform: translateX(calc(-50% + var(--tip-dx, 0px))); }   /* centred, slid just enough to stay on the screen (ui.v1.js) */

/* THE EDIT PEN (ui.editPen) — a card's own pen, top-right */
.pui-pen-host { position: relative; }
.pui-pen { position: absolute; top: 8px; right: 8px; z-index: 4; width: 43px; height: 43px; padding: 0; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center; cursor: pointer;
  background: rgba(11,11,20,.75); border: 1.5px solid var(--pui-card-line, #454c66); color: #c8c8dc; box-sizing: border-box; }   /* the circle's outline: the shared bright card line (Damon 2026-10-20) */
.pui-pen svg { width: 30px !important; height: 30px !important; vertical-align: middle !important; stroke-width: 1.6; }   /* the pen drawing 20% smaller (37 → 30px), the circle unchanged */
@media (hover: hover) { .pui-pen:hover { border-color: var(--primary, #f5891f); color: var(--primary, #f5891f); } }

/* THE SUB-MENU ROW (Damon 2026-10-20) — ONE definition the Play bar and Latest's bar both read, so they can't drift apart:
   its buttons (w x h), their icons, and its words (the feed's name, POST, All / Following).
   PC 48x44 / icons 26 / words 18; a narrow window 44x40 / 24 / 12; a phone (gmob) 53x48 / 29 / 18. */
:root { --pui-sub-w: 48px; --pui-sub-h: 44px; --pui-sub-ic: 26px; --pui-sub-fs: 18px; }
@media (max-width: 760px) { :root { --pui-sub-w: 44px; --pui-sub-h: 40px; --pui-sub-ic: 24px; --pui-sub-fs: 12px; } }
html.gmob { --pui-sub-w: 53px; --pui-sub-h: 48px; --pui-sub-ic: 29px; --pui-sub-fs: 18px; }

/* THE upload modal (ui.uploadModal, Damon GO 2026-10-21): a drop zone with 'Choose your .zip', its line, progress */
.pui-up-zone { border: 2px dashed var(--pui-card-line, #3a3a52); border-radius: 12px; padding: 26px 16px; display: flex; flex-direction: column; align-items: center; gap: 10px; text-align: center; }
.pui-up-zone.drag { border-color: var(--primary); }
.pui-up-pick { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pui-up-sub { font-size: 18px; color: var(--text-dim, #8a8aa0); }
.pui-up-msg { font-size: 18px; color: var(--text-mid, #b8b8cc); margin-top: 10px; min-height: 1.4em; text-align: center; }
/* its title is BLUE — it opens from the blue UPLOAD buttons (Damon 2026-10-21); 'Choose your .zip' +2px */
.pui-up .pui-modal-header { color: #3dc8ff; font-size: 15px; }
html[data-tl] .pui-up .pui-modal-actions .pui-btn { font-size: 18px; }
html[data-tl] .pui-up .pui-up-pick { font-size: 18px; }
.pui-up-msg.bad { color: var(--danger, #ff5a5a); }
.pui-up-prog { display: none; height: 8px; margin-top: 8px; border-radius: 6px; background: rgba(255,255,255,.08); overflow: hidden; }
.pui-up-prog.on { display: block; }
.pui-up-bar { height: 100%; width: 0; border-radius: 6px; background: var(--primary); transition: width .2s; }
.pui-up-prog.indet .pui-up-bar { width: 40% !important; transition: none; animation: pui-up-slide 1.1s ease-in-out infinite; }
@keyframes pui-up-slide { 0% { margin-left: -40%; } 100% { margin-left: 100%; } }
@media (max-width: 760px) { .pui-up-sub, .pui-up-msg { font-size: 20px; } html[data-tl] .pui-up .pui-up-pick { font-size: 20px; } html[data-tl] .pui-up .pui-modal-header { font-size: 22px; } html[data-tl] .pui-up .pui-modal-actions .pui-btn { font-size: 20px; } }
