@import url("https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;700&family=Press+Start+2P&display=swap");
/* =========================================================================
   PIXEL UI: PIXELATO's shared design tokens and components (v9.1.0).
   Retro-pixel, but calm: sharp 2 px borders, hard offset shadows (never
   blurred glows), motion on transform/opacity only, reduced motion honoured.

   HOW TO USE
     <link rel="stylesheet" href="pixel-ui.css?v=9.1.0">
     Add class="px-page" to <body> on pages built on this file (base type,
     colours, selection). Pages that only need the shared modals/toasts can
     load the file without it: nothing here styles bare elements except the
     focus ring, the reduced-motion kill switch and view transitions.

   SPECIFICITY
     Every token sits on :where(:root), which has ZERO specificity, so a page's
     own :root block (for example gold.html's --bg, racing.html's --accent)
     always wins no matter which file loads first. PixelTheme writes inline
     styles on <html>, which beat both.

   ── TOKENS ────────────────────────────────────────────────────────────────
   Colour     --px-bg #16161a (page)        --px-panel #1f1f24 (cards, bars)
              --px-raised #26262d           --px-field #2c2c34 (inputs)
              --px-line #34343d (1 px)      --px-line-strong #46464f (2 px)
              --px-text #ececec             --px-text-2 #9a9aa4  --px-text-3 #6b6b75
              --px-accent #39ff7a           --px-accent-hover #4dffa0
              --px-accent-dim #1f8c47       --px-on-accent #0c1f10 (text on accent)
              --px-accent-soft (accent at 8 %)  --px-accent-2 #3df2ff (cyan)
              --px-gold #ffd23d  --px-on-gold #1c1606  --px-amber #ffb454
              --px-danger #ff5c5c  --px-on-danger #1f0707  --px-info #3df2ff
              --px-accent-rgb / --px-panel-rgb / --px-bg-rgb: "r, g, b" triplets
                for rgba(var(--px-accent-rgb), .2) style mixes
              --px-backdrop (modal scrim)
   Type       --px-font-arcade "Press Start 2P" (only at 8/10/12/16/24 px)
              --px-font-mono "JetBrains Mono" (labels, buttons, code)
              --px-font-body "Inter" (running text)
              --fs-8 --fs-10 --fs-12 --fs-14 --fs-16 --fs-20 --fs-24 --fs-32
              --lh-tight 1.2  --lh 1.5  --lh-loose 1.7
   Space      --sp-1 4px  --sp-2 8px  --sp-3 12px  --sp-4 16px  --sp-5 24px
              --sp-6 32px --sp-7 40px --sp-8 48px   --gutter 16px (page edge)
   Radius     --r-0 0  --r-1 2px (default, sharp)  --r-2 4px
   Border     --bw-1 1px  --bw-2 2px
   Shadow     --px-shadow-sm 2px 2px 0 #000  --px-shadow 4px 4px 0 #000
              --px-shadow-lg 6px 6px 0 #000   (hard pixel offsets, no blur)
   Z-index    --z-header 100  --z-nav 850     --z-drawer 9000  --z-anim 9700
              --z-paywall 9800  --z-save 9850  --z-toast 9900   --z-auth 9999
              (<dialog> modals use the browser top layer and need none)
   Motion     --dur-1 120ms  --dur-2 200ms  --dur-3 320ms
              --ease cubic-bezier(.2,.8,.2,1)  (all 0ms under reduced motion)
   Controls   --ctl-h 36px (44px on touch screens)  --ctl-h-sm 28px  --ctl-h-lg 44px
   Layout     --container-sm 640px  --container 960px  --container-lg 1200px
   Workspace  --grid-alpha .15  --grid-color #000000  --grid-width 1px
              --grid-rgba  --mask-color  --mask-opacity .55  (PixelTheme sets these)

   Legacy aliases (same values, so un-migrated CSS keeps working):
     style.css / hub pages: --bg-canvas --bg-panel --bg-panel-raised --bg-raised
       --bg-field --border-subtle --border-strong --text-primary --text-secondary
       --text-tertiary --accent --accent-dim --accent-text-on --accent-on --amber
       --danger --gold --cyan --font-display --font-body --font-arcade
       --radius-sm 4px --radius-md 8px --radius-lg 14px
     tool pages: --bg --panel --raised --field --line --line2 --strong --txt
       --txt2 --txt3 --text --muted --dim --fm --fb --fa --mono --body --arcade

   ── COMPONENTS ────────────────────────────────────────────────────────────
   .px-page                  body base: background, text colour, Inter, selection
   .px-container(--narrow|--wide)  centred column with 16 px gutters
   .px-grid                  auto-fill grid; set --grid-min (default 220px)
   .px-stack                 vertical flex; set --stack-gap (default 12px)
   .px-row  .px-spacer       wrapping horizontal flex, flexible gap filler
   .px-header (__brand __nav __link) sticky top bar; one per page (it carries
                             the view-transition name)
   .px-nav                   the "PIXELATO ▾" dropdown mounted by pixel-nav.js
                             into a page's own top bar (see pixel-nav.js)
   .px-btn                   2 px bordered button/link; hover lifts by transform
     --primary --secondary (default) --ghost --danger --gold
     --sm --lg --block --icon (square, icon only)   [disabled], [aria-disabled]
   .px-card (--raised --link) __title __meta         flat panel, 2 px border
   .px-chip (--accent --gold --danger) [aria-pressed=true]  small pill-less tag
   .px-field .px-label .px-hint .px-input (--error)   inputs, selects, textareas
   .px-tabs > .px-tab[aria-selected=true]            underline tabs (scaleX)
   .px-modal                 on <dialog>: __head __title __close __body __foot
                             (.is-fallback + .px-overlay when <dialog> is missing)
   .px-drawer (--left)       side sheet on <dialog>; .px-drawer--clear keeps the
                             page visible behind it (live previews)
   .px-toasts > .px-toast (--success --warn --error --gold)  status messages
   .px-icon (--2x --3x)      16 px pixel icon from pixel-icons.svg
   .px-progress > .px-progress__bar   set --value 0..1 (animates scaleX)
   .px-banner (--info --warn --gold --success) __text __actions  inline notice
   .px-table-wrap > .px-table  scrollable data table
   .px-prose                 long-form text (headings, lists, links, code)
   .px-arcade .px-mono .px-muted .px-kbd .px-divider .px-sr-only .px-skip
   ========================================================================= */

:where(:root) {
  color-scheme: dark;

  /* colour */
  --px-bg: #16161a;
  --px-panel: #1f1f24;
  --px-raised: #26262d;
  --px-field: #2c2c34;
  --px-line: #34343d;
  --px-line-strong: #46464f;
  --px-text: #ececec;
  --px-text-2: #9a9aa4;
  --px-text-3: #6b6b75;
  --px-accent: #39ff7a;
  --px-accent-rgb: 57, 255, 122;
  --px-accent-hover: #4dffa0;
  --px-accent-dim: #1f8c47;
  --px-accent-soft: rgba(var(--px-accent-rgb), .08);
  --px-on-accent: #0c1f10;
  --px-accent-2: #3df2ff;
  --px-gold: #ffd23d;
  --px-on-gold: #1c1606;
  --px-amber: #ffb454;
  --px-danger: #ff5c5c;
  --px-on-danger: #1f0707;
  --px-info: #3df2ff;
  --px-panel-rgb: 31, 31, 36;
  --px-bg-rgb: 22, 22, 26;
  --px-backdrop: rgba(8, 8, 10, .74);

  /* type */
  --px-font-arcade: "Press Start 2P", "JetBrains Mono", monospace;
  --px-font-mono: "JetBrains Mono", "SF Mono", ui-monospace, monospace;
  --px-font-body: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
  --fs-8: 8px; --fs-10: 10px; --fs-12: 12px; --fs-14: 14px;
  --fs-16: 16px; --fs-20: 20px; --fs-24: 24px; --fs-32: 32px;
  --lh-tight: 1.2; --lh: 1.5; --lh-loose: 1.7;

  /* space, radius, borders, shadows */
  --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px;
  --sp-5: 24px; --sp-6: 32px; --sp-7: 40px; --sp-8: 48px;
  --gutter: 16px;
  --r-0: 0; --r-1: 2px; --r-2: 4px;
  --bw-1: 1px; --bw-2: 2px;
  --px-shadow-sm: 2px 2px 0 #000;
  --px-shadow: 4px 4px 0 #000;
  --px-shadow-lg: 6px 6px 0 #000;

  /* z-index scale (BUILD_SPEC §5) */
  --z-header: 100; --z-nav: 850; --z-drawer: 9000; --z-anim: 9700; --z-paywall: 9800;
  --z-save: 9850; --z-toast: 9900; --z-auth: 9999;

  /* motion */
  --dur-1: 120ms; --dur-2: 200ms; --dur-3: 320ms;
  --ease: cubic-bezier(.2, .8, .2, 1);

  /* controls and layout */
  --ctl-h: 36px; --ctl-h-sm: 28px; --ctl-h-lg: 44px;
  --container-sm: 640px; --container: 960px; --container-lg: 1200px;

  /* workspace (PixelTheme overrides these) */
  --grid-alpha: .15; --grid-color: #000000; --grid-width: 1px;
  --grid-rgba: rgba(0, 0, 0, .15);
  --mask-color: var(--px-accent); --mask-opacity: .55;

  /* legacy aliases: style.css and hub pages */
  --bg-canvas: var(--px-bg);
  --bg-panel: var(--px-panel);
  --bg-panel-raised: var(--px-raised);
  --bg-raised: var(--px-raised);
  --bg-field: var(--px-field);
  --border-subtle: var(--px-line);
  --border-strong: var(--px-line-strong);
  --text-primary: var(--px-text);
  --text-secondary: var(--px-text-2);
  --text-tertiary: var(--px-text-3);
  --accent: var(--px-accent);
  --accent-dim: var(--px-accent-dim);
  --accent-text-on: var(--px-on-accent);
  --accent-on: var(--px-on-accent);
  --amber: var(--px-amber);
  --danger: var(--px-danger);
  --gold: var(--px-gold);
  --cyan: var(--px-accent-2);
  --font-display: var(--px-font-mono);
  --font-body: var(--px-font-body);
  --font-arcade: var(--px-font-arcade);
  --radius-sm: 4px; --radius-md: 8px; --radius-lg: 14px;

  /* legacy aliases: tool pages (mathify, ascii, photo, draw ...) */
  --bg: var(--px-bg); --panel: var(--px-panel); --raised: var(--px-raised);
  --field: var(--px-field); --line: var(--px-line); --line2: var(--px-line-strong);
  --strong: var(--px-line-strong); --txt: var(--px-text); --txt2: var(--px-text-2);
  --txt3: var(--px-text-3); --text: var(--px-text); --muted: var(--px-text-2);
  --dim: var(--px-text-3);
  --fm: var(--px-font-mono); --fb: var(--px-font-body); --fa: var(--px-font-arcade);
  --mono: var(--px-font-mono); --body: var(--px-font-body); --arcade: var(--px-font-arcade);
}

@media (pointer: coarse) {
  :where(:root) { --ctl-h: 44px; --ctl-h-sm: 36px; }
}
/* PixelTheme density presets */
:where(html[data-density="compact"]) { --ctl-h: 30px; --ctl-h-sm: 24px; }
:where(html[data-density="comfy"]) { --ctl-h: 42px; --ctl-h-sm: 32px; }

/* ── global (the only bare-element rules) ─────────────────────────────── */
:where(:focus-visible) {
  outline: 2px solid var(--px-accent);
  outline-offset: 2px;
}

@media (prefers-reduced-motion: no-preference) {
  @view-transition { navigation: auto; }
  ::view-transition-old(root) { animation: px-vt-out 160ms cubic-bezier(.2, .8, .2, 1) both; }
  ::view-transition-new(root) { animation: px-vt-in 200ms cubic-bezier(.2, .8, .2, 1) both; }
}
@keyframes px-vt-out { to { opacity: 0; transform: translateY(-8px); } }
@keyframes px-vt-in { from { opacity: 0; transform: translateY(8px); } }

@media (prefers-reduced-motion: reduce) {
  :root { --dur-1: 0ms; --dur-2: 0ms; --dur-3: 0ms; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ── page base (opt in with body.px-page) ─────────────────────────────── */
.px-page {
  margin: 0;
  min-height: 100vh;
  min-height: 100dvh;
  background: var(--px-bg);
  color: var(--px-text);
  font-family: var(--px-font-body);
  font-size: var(--fs-16);
  line-height: var(--lh);
  -webkit-font-smoothing: antialiased;
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scrollbar-color: var(--px-line-strong) var(--px-bg);
}
.px-page *, .px-page *::before, .px-page *::after { box-sizing: border-box; }
.px-page ::selection { background: var(--px-accent); color: var(--px-on-accent); }
.px-page img, .px-page svg, .px-page canvas { max-width: 100%; }

/* ── layout ───────────────────────────────────────────────────────────── */
.px-container {
  width: 100%;
  max-width: calc(var(--container) + 2 * var(--gutter));
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.px-container--narrow { max-width: calc(720px + 2 * var(--gutter)); }
.px-container--wide { max-width: calc(var(--container-lg) + 2 * var(--gutter)); }
.px-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(var(--grid-min, 220px), 100%), 1fr));
  gap: var(--grid-gap, var(--sp-4));
}
.px-stack { display: flex; flex-direction: column; gap: var(--stack-gap, var(--sp-3)); }
.px-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--row-gap, var(--sp-2)); }
.px-spacer { flex: 1 1 auto; }

/* ── header ───────────────────────────────────────────────────────────── */
.px-header {
  position: sticky;
  top: 0;
  z-index: var(--z-header);
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  min-height: 56px;
  padding: var(--sp-2) var(--gutter);
  background: var(--px-panel);
  border-bottom: 2px solid var(--px-line);
}
@media (prefers-reduced-motion: no-preference) {
  .px-header { view-transition-name: px-header; }
}
.px-header__brand {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  color: var(--px-text);
  text-decoration: none;
  font-family: var(--px-font-arcade);
  font-size: var(--fs-12);
  letter-spacing: .04em;
  white-space: nowrap;
}
.px-header__nav { display: flex; align-items: center; gap: var(--sp-1); margin-left: auto; flex-wrap: wrap; justify-content: flex-end; }
.px-header__link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: var(--ctl-h-sm);
  padding: 0 var(--sp-2);
  color: var(--px-text-2);
  font: 500 var(--fs-12)/1 var(--px-font-mono);
  text-decoration: none;
  border: 2px solid transparent;
  border-radius: var(--r-1);
}
.px-header__link:hover { color: var(--px-text); border-color: var(--px-line); }
.px-header__link[aria-current="page"] { color: var(--px-accent); }

/* ── buttons ──────────────────────────────────────────────────────────────
   Only transform animates. The hard shadow steps with the lift so its
   bottom-right edge stays put (translate -1px + shadow +1px). */
.px-btn {
  --btn-bg: var(--px-raised);
  --btn-fg: var(--px-text);
  --btn-bd: var(--px-line-strong);
  --btn-hover-bg: var(--btn-bg);
  --btn-shadow: #000;
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  min-height: var(--ctl-h);
  padding: 0 var(--sp-4);
  margin: 0;
  font: 700 var(--fs-12)/1.1 var(--px-font-mono);
  letter-spacing: .06em;
  text-transform: uppercase;
  text-decoration: none;
  text-align: center;
  white-space: nowrap;
  color: var(--btn-fg);
  background: var(--btn-bg);
  border: 2px solid var(--btn-bd);
  border-radius: var(--r-1);
  box-shadow: 2px 2px 0 var(--btn-shadow);
  cursor: pointer;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  transition: transform var(--dur-1) var(--ease);
}
.px-btn:hover {
  background: var(--btn-hover-bg);
  transform: translate(-1px, -1px);
  box-shadow: 3px 3px 0 var(--btn-shadow);
}
.px-btn:active {
  transform: translate(2px, 2px);
  box-shadow: 0 0 0 var(--btn-shadow);
}
.px-btn--primary {
  --btn-bg: var(--px-accent);
  --btn-fg: var(--px-on-accent);
  --btn-bd: var(--px-accent);
  --btn-hover-bg: var(--px-accent-hover);
}
.px-btn--secondary { --btn-bg: var(--px-raised); --btn-bd: var(--px-line-strong); --btn-hover-bg: var(--px-field); }
.px-btn--ghost {
  --btn-bg: transparent;
  --btn-bd: transparent;
  --btn-hover-bg: rgba(255, 255, 255, .04);
  box-shadow: none;
}
.px-btn--ghost:hover { box-shadow: none; border-color: var(--px-line); }
.px-btn--ghost:active { box-shadow: none; }
.px-btn--danger { --btn-bg: var(--px-danger); --btn-fg: var(--px-on-danger); --btn-bd: var(--px-danger); }
.px-btn--gold { --btn-bg: var(--px-gold); --btn-fg: var(--px-on-gold); --btn-bd: var(--px-gold); }
.px-btn--sm { min-height: var(--ctl-h-sm); padding: 0 var(--sp-3); font-size: var(--fs-10); gap: 6px; }
.px-btn--lg { min-height: var(--ctl-h-lg); padding: 0 var(--sp-5); font-size: var(--fs-14); }
.px-btn--block { display: flex; width: 100%; }
.px-btn--icon { padding: 0; width: var(--ctl-h); }
.px-btn--icon.px-btn--sm { width: var(--ctl-h-sm); }
.px-btn[disabled], .px-btn[aria-disabled="true"], .px-btn.is-busy {
  opacity: .5;
  cursor: not-allowed;
  transform: none;
  box-shadow: 2px 2px 0 var(--btn-shadow);
}
.px-btn--ghost[disabled], .px-btn--ghost[aria-disabled="true"] { box-shadow: none; }
.px-btn.is-busy { cursor: progress; }

/* ── cards ────────────────────────────────────────────────────────────── */
.px-card {
  display: block;
  padding: var(--sp-4);
  color: var(--px-text);
  background: var(--px-panel);
  border: 2px solid var(--px-line);
  border-radius: var(--r-1);
}
.px-card--raised { box-shadow: var(--px-shadow); border-color: var(--px-line-strong); }
.px-card--link { text-decoration: none; transition: transform var(--dur-1) var(--ease); }
.px-card--link:hover { transform: translate(-2px, -2px); box-shadow: 4px 4px 0 #000; border-color: var(--px-line-strong); }
.px-card--link:active { transform: translate(0, 0); box-shadow: 0 0 0 #000; }
.px-card__title {
  margin: 0 0 var(--sp-2);
  font: 700 var(--fs-14)/var(--lh-tight) var(--px-font-mono);
  letter-spacing: .02em;
  color: var(--px-text);
  display: flex;
  align-items: center;
  gap: var(--sp-2);
}
.px-card__meta { margin: 0; color: var(--px-text-2); font-size: var(--fs-14); }

/* ── chips ────────────────────────────────────────────────────────────── */
.px-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 24px;
  padding: 0 var(--sp-2);
  font: 500 var(--fs-12)/1 var(--px-font-mono);
  color: var(--px-text-2);
  background: var(--px-field);
  border: 1px solid var(--px-line-strong);
  border-radius: var(--r-1);
  white-space: nowrap;
}
button.px-chip { cursor: pointer; transition: transform var(--dur-1) var(--ease); }
button.px-chip:hover { color: var(--px-text); transform: translateY(-1px); }
.px-chip--accent, .px-chip[aria-pressed="true"] {
  color: var(--px-on-accent);
  background: var(--px-accent);
  border-color: var(--px-accent);
}
.px-chip--gold { color: var(--px-on-gold); background: var(--px-gold); border-color: var(--px-gold); }
.px-chip--danger { color: var(--px-danger); border-color: var(--px-danger); background: transparent; }

/* ── form fields ──────────────────────────────────────────────────────── */
.px-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }
.px-label {
  font: 500 var(--fs-12)/1.2 var(--px-font-mono);
  color: var(--px-text-2);
  letter-spacing: .02em;
}
.px-hint { font-size: var(--fs-12); color: var(--px-text-3); margin: 0; }
.px-input {
  width: 100%;
  min-height: var(--ctl-h);
  padding: 0 var(--sp-3);
  font: 400 var(--fs-14)/1.3 var(--px-font-body);
  color: var(--px-text);
  background: var(--px-field);
  border: 2px solid var(--px-line);
  border-radius: var(--r-1);
  outline: none;
  appearance: none;
  -webkit-appearance: none;
}
@media (pointer: coarse) { .px-input { font-size: var(--fs-16); } } /* no iOS zoom on focus */
.px-input::placeholder { color: var(--px-text-3); }
.px-input:hover { border-color: var(--px-line-strong); }
.px-input:focus { border-color: var(--px-accent); }
.px-input:focus-visible { outline: 2px solid var(--px-accent); outline-offset: 2px; }
.px-input--error, .px-input[aria-invalid="true"] { border-color: var(--px-danger); }
textarea.px-input { min-height: 96px; padding: var(--sp-2) var(--sp-3); resize: vertical; line-height: var(--lh); }
select.px-input {
  padding-right: 32px;
  background-image: linear-gradient(45deg, transparent 50%, var(--px-text-2) 50%), linear-gradient(135deg, var(--px-text-2) 50%, transparent 50%);
  background-position: calc(100% - 16px) 50%, calc(100% - 11px) 50%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}
input[type="color"].px-input { padding: 2px; width: var(--ctl-h); min-width: var(--ctl-h); cursor: pointer; }
input[type="range"].px-range { width: 100%; accent-color: var(--px-accent); min-height: var(--ctl-h-sm); }
input[type="checkbox"].px-check, input[type="radio"].px-check { accent-color: var(--px-accent); width: 16px; height: 16px; }

/* ── tabs ─────────────────────────────────────────────────────────────── */
.px-tabs {
  display: flex;
  gap: var(--sp-1);
  border-bottom: 2px solid var(--px-line);
  overflow-x: auto;
  scrollbar-width: none;
}
.px-tabs::-webkit-scrollbar { display: none; }
.px-tab {
  position: relative;
  flex: none;
  min-height: var(--ctl-h);
  padding: 0 var(--sp-3);
  font: 700 var(--fs-12)/1 var(--px-font-mono);
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--px-text-2);
  background: none;
  border: 0;
  cursor: pointer;
}
.px-tab::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -2px;
  height: 2px;
  background: var(--px-accent);
  transform: scaleX(0);
  transition: transform var(--dur-2) var(--ease);
}
.px-tab:hover { color: var(--px-text); }
.px-tab[aria-selected="true"] { color: var(--px-text); }
.px-tab[aria-selected="true"]::after { transform: scaleX(1); }

/* ── modal (<dialog>) ─────────────────────────────────────────────────── */
.px-modal {
  width: min(520px, calc(100vw - 2 * var(--gutter)));
  max-width: none;
  max-height: calc(100vh - 2 * var(--gutter));
  max-height: calc(100dvh - 2 * var(--gutter));
  padding: 0;
  margin: auto;
  color: var(--px-text);
  background: var(--px-panel);
  border: 2px solid var(--px-line-strong);
  border-radius: var(--r-1);
  box-shadow: var(--px-shadow-lg);
  font-family: var(--px-font-body);
  font-size: var(--fs-14);
  line-height: var(--lh);
  overflow: hidden;
  flex-direction: column;
}
.px-modal[open], .px-modal.is-fallback { display: flex; }
.px-modal--lg { width: min(760px, calc(100vw - 2 * var(--gutter))); }
.px-modal--sm { width: min(400px, calc(100vw - 2 * var(--gutter))); }
.px-modal::backdrop { background: var(--px-backdrop); }
.px-modal[open], .px-modal.is-fallback { animation: px-pop-in var(--dur-2) var(--ease); }
.px-modal[open]::backdrop { animation: px-fade-in var(--dur-2) var(--ease); }
.px-modal.is-closing { animation: px-pop-out var(--dur-1) var(--ease) forwards; }
.px-modal.is-closing::backdrop { animation: px-fade-out var(--dur-1) var(--ease) forwards; }
.px-modal__head {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: 44px;
  padding: var(--sp-2) var(--sp-2) var(--sp-2) var(--sp-4);
  background: var(--px-raised);
  border-bottom: 2px solid var(--px-line);
  flex: none;
}
.px-modal__title {
  flex: 1 1 auto;
  margin: 0;
  font: 400 var(--fs-10)/1.6 var(--px-font-arcade);
  letter-spacing: .04em;
  color: var(--px-text);
  min-width: 0;
}
.px-modal__close { margin-left: auto; flex: none; }
.px-modal__body {
  padding: var(--sp-4);
  overflow: auto;
  overscroll-behavior: contain;
  flex: 1 1 auto;
  min-height: 0;
}
.px-modal__body > :first-child { margin-top: 0; }
.px-modal__body > :last-child { margin-bottom: 0; }
.px-modal__body p { margin: 0 0 var(--sp-3); color: var(--px-text-2); }
.px-modal__foot {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4);
  border-top: 2px solid var(--px-line);
  background: var(--px-panel);
  flex: none;
}
@media (max-width: 480px) {
  .px-modal__foot .px-btn { flex: 1 1 auto; }
}
/* fallback when HTMLDialogElement.showModal is unavailable */
.px-overlay {
  position: fixed;
  inset: 0;
  z-index: var(--z-auth);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--gutter);
  background: var(--px-backdrop);
  animation: px-fade-in var(--dur-2) var(--ease);
}
.px-overlay.is-closing { animation: px-fade-out var(--dur-1) var(--ease) forwards; }
.px-overlay > .px-drawer { position: absolute; top: 0; bottom: 0; right: 0; }
.px-overlay > .px-drawer--left { right: auto; left: 0; }

/* ── drawer (<dialog>) ────────────────────────────────────────────────── */
.px-drawer {
  position: fixed;
  inset: 0 0 0 auto;
  width: min(400px, 100vw);
  max-width: 100vw;
  height: 100vh;
  height: 100dvh;
  max-height: none;
  margin: 0;
  padding: 0;
  color: var(--px-text);
  background: var(--px-panel);
  border: 0;
  border-left: 2px solid var(--px-line-strong);
  border-radius: 0;
  box-shadow: -4px 0 0 #000;
  font-family: var(--px-font-body);
  font-size: var(--fs-14);
  line-height: var(--lh);
  flex-direction: column;
  overflow: hidden;
}
.px-drawer[open], .px-drawer.is-fallback { display: flex; animation: px-slide-in-r var(--dur-3) var(--ease); }
.px-drawer--left { inset: 0 auto 0 0; border-left: 0; border-right: 2px solid var(--px-line-strong); box-shadow: 4px 0 0 #000; }
.px-drawer--left[open], .px-drawer--left.is-fallback { animation-name: px-slide-in-l; }
.px-drawer.is-closing { animation: px-slide-out-r var(--dur-2) var(--ease) forwards; }
.px-drawer--left.is-closing { animation-name: px-slide-out-l; }
.px-drawer::backdrop { background: var(--px-backdrop); }
.px-drawer[open]::backdrop { animation: px-fade-in var(--dur-2) var(--ease); }
.px-drawer.is-closing::backdrop { animation: px-fade-out var(--dur-2) var(--ease) forwards; }
.px-drawer--clear::backdrop { background: transparent; }
.px-overlay.is-clear { background: transparent; }
.px-drawer .px-modal__head { padding-left: var(--sp-4); }
.px-drawer .px-modal__body { flex: 1 1 auto; }

@keyframes px-pop-in { from { opacity: 0; transform: translateY(8px); } }
@keyframes px-pop-out { to { opacity: 0; transform: translateY(8px); } }
@keyframes px-fade-in { from { opacity: 0; } }
@keyframes px-fade-out { to { opacity: 0; } }
@keyframes px-slide-in-r { from { transform: translateX(100%); } }
@keyframes px-slide-out-r { to { transform: translateX(100%); } }
@keyframes px-slide-in-l { from { transform: translateX(-100%); } }
@keyframes px-slide-out-l { to { transform: translateX(-100%); } }

/* ── toasts ───────────────────────────────────────────────────────────── */
.px-toasts {
  position: fixed;
  z-index: var(--z-toast);
  inset: auto var(--gutter) calc(var(--gutter) + env(safe-area-inset-bottom, 0px)) auto;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: var(--sp-2);
  width: min(380px, calc(100vw - 2 * var(--gutter)));
  pointer-events: none;
}
.px-toasts[popover] {           /* reset the UA popover box */
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  color: inherit;
  overflow: visible;
  height: auto;
}
@media (max-width: 560px) {
  .px-toasts { inset: auto var(--gutter) calc(var(--gutter) + env(safe-area-inset-bottom, 0px)) var(--gutter); width: auto; align-items: stretch; }
}
.px-toast {
  --toast-accent: var(--px-accent-2);
  display: flex;
  align-items: flex-start;
  gap: var(--sp-2);
  width: 100%;
  padding: var(--sp-3);
  color: var(--px-text);
  background: var(--px-raised);
  border: 2px solid var(--px-line-strong);
  border-left: 6px solid var(--toast-accent);
  border-radius: var(--r-1);
  box-shadow: var(--px-shadow);
  font: 400 var(--fs-14)/1.4 var(--px-font-body);
  pointer-events: auto;
  animation: px-pop-in var(--dur-2) var(--ease);
}
.px-toast.is-closing { animation: px-toast-out var(--dur-2) var(--ease) forwards; }
.px-toast > .px-icon { color: var(--toast-accent); margin-top: 1px; }
.px-toast__msg { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
.px-toast__action { margin: -4px 0; }
.px-toast__close { margin: -6px -6px -6px 0; }
.px-toast--success { --toast-accent: var(--px-accent); }
.px-toast--warn { --toast-accent: var(--px-amber); }
.px-toast--error { --toast-accent: var(--px-danger); }
.px-toast--gold { --toast-accent: var(--px-gold); }
@keyframes px-toast-out { to { opacity: 0; transform: translateX(16px); } }

/* ── icons ────────────────────────────────────────────────────────────── */
.px-icon {
  display: inline-block;
  flex: none;
  width: 16px;
  height: 16px;
  fill: currentColor;
  shape-rendering: crispEdges;
  vertical-align: -3px;
  overflow: visible;
}
.px-icon--2x { width: 32px; height: 32px; vertical-align: middle; }
.px-icon--3x { width: 48px; height: 48px; vertical-align: middle; }

/* ── progress ─────────────────────────────────────────────────────────── */
.px-progress {
  position: relative;
  height: 12px;
  background: var(--px-field);
  border: 2px solid var(--px-line-strong);
  border-radius: var(--r-1);
  overflow: hidden;
}
.px-progress__bar {
  position: absolute;
  inset: 0;
  background:
    repeating-linear-gradient(90deg, transparent 0 6px, rgba(0, 0, 0, .28) 6px 8px),
    var(--progress-color, var(--px-accent));
  transform: scaleX(var(--value, 0));
  transform-origin: left center;
  transition: transform var(--dur-2) var(--ease);
}
.px-progress--gold { --progress-color: var(--px-gold); }
.px-progress--sm { height: 8px; }

/* ── banner ───────────────────────────────────────────────────────────── */
.px-banner {
  --banner-accent: var(--px-accent-2);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sp-2) var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  color: var(--px-text);
  background: var(--px-raised);
  border: 2px solid var(--px-line-strong);
  border-left: 6px solid var(--banner-accent);
  border-radius: var(--r-1);
  font-size: var(--fs-14);
  line-height: 1.4;
}
.px-banner > .px-icon { color: var(--banner-accent); }
.px-banner__text { flex: 1 1 200px; min-width: 0; margin: 0; }
.px-banner__actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); }
.px-banner--warn { --banner-accent: var(--px-amber); }
.px-banner--gold { --banner-accent: var(--px-gold); }
.px-banner--success { --banner-accent: var(--px-accent); }
.px-banner--info { --banner-accent: var(--px-accent-2); }

/* ── table ────────────────────────────────────────────────────────────── */
.px-table-wrap {
  width: 100%;
  overflow-x: auto;
  border: 2px solid var(--px-line);
  border-radius: var(--r-1);
  -webkit-overflow-scrolling: touch;
}
.px-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-14);
  line-height: 1.4;
}
.px-table th, .px-table td {
  padding: var(--sp-2) var(--sp-3);
  text-align: left;
  vertical-align: top;
  border-bottom: 1px solid var(--px-line);
}
.px-table th {
  font: 700 var(--fs-12)/1.3 var(--px-font-mono);
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--px-text-2);
  background: var(--px-raised);
  white-space: nowrap;
}
.px-table tr:last-child td { border-bottom: 0; }
.px-table td { color: var(--px-text); }

/* ── long-form text ───────────────────────────────────────────────────── */
.px-prose { color: var(--px-text); font-size: var(--fs-16); line-height: var(--lh-loose); }
.px-prose > * + * { margin-top: var(--sp-4); }
.px-prose p, .px-prose ul, .px-prose ol, .px-prose dl { margin: 0; }
.px-prose * + p, .px-prose * + ul, .px-prose * + ol { margin-top: var(--sp-3); }
.px-prose h1 {
  margin: 0;
  font: 400 var(--fs-24)/1.4 var(--px-font-arcade);
  letter-spacing: .02em;
}
.px-prose h2 {
  margin: var(--sp-7) 0 0;
  font: 700 var(--fs-24)/var(--lh-tight) var(--px-font-body);
  letter-spacing: -.01em;
  scroll-margin-top: 80px;
}
.px-prose h3 {
  margin: var(--sp-5) 0 0;
  font: 700 var(--fs-16)/1.3 var(--px-font-mono);
  color: var(--px-text);
  scroll-margin-top: 80px;
}
.px-prose h2 + *, .px-prose h3 + * { margin-top: var(--sp-2); }
.px-prose ul, .px-prose ol { padding-left: 1.3em; }
.px-prose li + li { margin-top: var(--sp-1); }
.px-prose li::marker { color: var(--px-accent-dim); }
.px-prose a, .px-link { color: var(--px-accent); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 3px; }
.px-prose a:hover, .px-link:hover { color: var(--px-accent-hover); text-decoration-thickness: 2px; }
.px-prose strong { color: var(--px-text); font-weight: 600; }
.px-prose code, .px-kbd {
  font: 500 .88em/1 var(--px-font-mono);
  padding: 2px 5px;
  background: var(--px-field);
  border: 1px solid var(--px-line-strong);
  border-radius: var(--r-1);
}
.px-kbd { box-shadow: 0 2px 0 var(--px-line-strong); }
.px-prose .px-lead { font-size: var(--fs-20); line-height: var(--lh); color: var(--px-text-2); }
.px-prose hr, .px-divider { border: 0; border-top: 2px solid var(--px-line); margin: var(--sp-6) 0; }

/* ── utilities ────────────────────────────────────────────────────────── */
.px-arcade { font-family: var(--px-font-arcade); letter-spacing: .02em; }
.px-mono { font-family: var(--px-font-mono); }
.px-muted { color: var(--px-text-2); }
.px-sr-only {
  position: absolute !important;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
.px-skip {
  position: absolute;
  left: var(--gutter);
  top: -100px;
  z-index: calc(var(--z-header) + 1);
  padding: var(--sp-2) var(--sp-3);
  color: var(--px-on-accent);
  background: var(--px-accent);
  font: 700 var(--fs-12)/1 var(--px-font-mono);
  text-decoration: none;
}
.px-skip:focus { top: var(--sp-2); }

/* ── nav (pixel-nav.js: the "PIXELATO ▾" top-ribbon dropdown) ───────────
   .px-nav sits inline wherever pixel-nav.js mounts it (usually right after
   a page's own .brand). The panel is `position: absolute` off .px-nav, so
   it needs no help from the host's own layout; on mobile it detaches into
   a fixed full-width sheet instead (media query below). Only opacity/
   transform (+ a zero-duration visibility swap) animate; the site-wide
   reduced-motion rule above already collapses --dur-* to ~0. */
.px-nav {
  pointer-events: auto; /* hosts like intro.html set pointer-events:none on their overlay */
  position: relative;
  display: inline-flex;
  align-items: center;
}
.px-nav-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: var(--ctl-h-sm);
  padding: 0 var(--sp-2);
  color: var(--px-text);
  background: var(--px-raised);
  border: var(--bw-2) solid var(--px-line-strong);
  border-radius: var(--r-1);
  font: 700 var(--fs-12)/1 var(--px-font-mono);
  letter-spacing: .02em;
  cursor: pointer;
  transition: transform var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease);
}
.px-nav-btn:hover { border-color: var(--px-accent); }
.px-nav-btn:active { transform: translateY(1px); }
.px-nav.is-open .px-nav-btn { border-color: var(--px-accent); color: var(--px-accent); }
.px-nav-icon { color: inherit; }
.px-nav-caret {
  display: inline-block;
  font-size: var(--fs-10);
  transition: transform var(--dur-1) var(--ease);
}
.px-nav.is-open .px-nav-caret { transform: rotate(180deg); }
.px-nav-chip {
  display: inline-flex;
  align-items: center;
  min-height: 16px;
  padding: 0 5px;
  margin-left: 2px;
  font: 700 9px/1 var(--px-font-mono);
  letter-spacing: .03em;
  color: var(--px-on-gold);
  background: var(--px-gold);
  border-radius: var(--r-1);
}
.px-nav-chip[hidden], .px-nav-btn-icon[hidden] { display: none; }

.px-nav-panel {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  width: max-content;
  min-width: 240px;
  max-width: min(320px, calc(100vw - 2 * var(--gutter)));
  max-height: min(70vh, 560px);
  overflow-y: auto;
  background: var(--px-panel);
  border: var(--bw-2) solid var(--px-line-strong);
  border-radius: var(--r-2);
  box-shadow: var(--px-shadow-lg);
  z-index: var(--z-nav);
  visibility: hidden;
  opacity: 0;
  transform: translateY(-6px) scale(.98);
  transform-origin: top left;
  transition: opacity var(--dur-2) var(--ease), transform var(--dur-2) var(--ease), visibility 0s linear var(--dur-2);
}
.px-nav-panel.is-open {
  visibility: visible;
  opacity: 1;
  transform: translateY(0) scale(1);
  transition: opacity var(--dur-2) var(--ease), transform var(--dur-2) var(--ease), visibility 0s linear 0s;
}
.px-nav-scroll { padding: var(--sp-2); padding-bottom: calc(var(--sp-2) + env(safe-area-inset-bottom, 0px)); }
.px-nav-group + .px-nav-group { margin-top: var(--sp-2); padding-top: var(--sp-2); border-top: 1px solid var(--px-line); }
.px-nav-group-title {
  padding: var(--sp-1) var(--sp-2);
  font: 700 var(--fs-10)/1 var(--px-font-mono);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--px-text-3);
}
.px-nav-item {
  display: block;
  padding: var(--sp-2);
  color: var(--px-text-2);
  text-decoration: none;
  font: 500 var(--fs-14)/1.2 var(--px-font-body);
  border-radius: var(--r-1);
  border: 2px solid transparent;
}
.px-nav-item:hover, .px-nav-item:focus-visible {
  color: var(--px-text);
  background: var(--px-field);
}
.px-nav-item:focus-visible { outline: none; border-color: var(--px-accent); }
.px-nav-item.is-current {
  color: var(--px-accent);
  background: var(--px-accent-soft);
}
.px-nav-item--gold { color: var(--px-gold); }
.px-nav-item--gold.is-current, .px-nav-item--gold:hover, .px-nav-item--gold:focus-visible { color: var(--px-gold); }

.px-nav-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  background: var(--px-backdrop);
  z-index: calc(var(--z-nav) - 1);
}

/* fallback slim bar (no .topbar/header/nav found on the page) */
.px-nav-fixedbar {
  position: fixed;
  top: 0; left: 0; right: 0;
  height: 44px;
  display: flex;
  align-items: center;
  padding: 0 var(--sp-3);
  background: var(--px-panel);
  border-bottom: var(--bw-2) solid var(--px-line-strong);
  z-index: var(--z-header);
}
body.px-nav-has-fixedbar { padding-top: 44px; }

@media (max-width: 640px) {
  .px-nav-btn-label { display: none; }
  .px-nav-backdrop[hidden] { display: none; }
  .px-nav.is-open .px-nav-backdrop { display: block; }
  .px-nav-panel {
    position: fixed;
    top: auto;
    bottom: 0; left: 0; right: 0;
    width: auto;
    max-width: none;
    max-height: 80vh;
    border-radius: var(--r-2) var(--r-2) 0 0;
    border-width: var(--bw-2) 0 0 0;
    transform: translateY(16px);
    transform-origin: bottom;
  }
  .px-nav-panel.is-open { transform: translateY(0); }
}

/* ==========================================================================
   TOOL TOP BAR (hub-design v9.1)
   The editor / draw / photo / signify / mathify / studio bars already hold
   page-specific controls. PixelNav mounts next to the brand and carries every
   cross-page link, so those duplicate links step aside as the bar gets tight.
   Selectors are written `header.topbar ...` so they win over each page's own
   .topbar rules regardless of stylesheet order. No hub page (.hubbar) is hit.
   ========================================================================== */
header.topbar:not(.hubbar) .brand { min-width: 0; }
header.topbar:not(.hubbar) .topbar-actions { min-width: 0; justify-content: flex-end; }

@media (max-width: 1500px) {
  header.topbar:has(.px-nav) .topbar-actions > a.btn[href$=".html"] { display: none; }
}

@media (max-width: 1250px) {
  header.topbar:not(.hubbar) .brand-tag { display: none; }
  /* secondary editor actions go icon-only (their title= tooltips stay) */
  header.topbar .topbar-actions > .btn:not(.btn-accent):not(#undo-btn):not(#redo-btn) {
    font-size: 0; gap: 0; padding-left: 10px; padding-right: 10px;
  }
  header.topbar .topbar-actions > .btn > i { font-size: 16px; }
}

@media (max-width: 720px) {
  /* editor: row 1 = brand, menu, account, credits; row 2 = the tool buttons */
  header.topbar:has(.topbar-actions) {
    height: auto; min-height: var(--topbar-h, 56px);
    flex-wrap: wrap; justify-content: flex-start; align-items: center;
    padding: 6px 12px; row-gap: 6px; column-gap: 8px;
  }
  header.topbar:has(.topbar-actions)::after { content: ""; order: 2; flex: 0 0 100%; height: 0; }
  header.topbar:has(.topbar-actions) .topbar-actions { display: contents; }
  header.topbar .topbar-actions > .divider-v { display: none; }
  header.topbar .topbar-actions > span[id$="-mount"] { order: 1; }
  header.topbar .topbar-actions > #account-mount { margin-left: auto; }
  header.topbar .topbar-actions > .btn { order: 3; min-height: 40px; min-width: 40px; justify-content: center; }
  header.topbar .topbar-actions > #export-toggle-btn { font-size: 0; gap: 0; }
  header.topbar .topbar-actions > #export-toggle-btn > i { font-size: 16px; }
}

@media (max-width: 480px) {
  header.topbar:has(.topbar-actions) .brand-name { display: none; }
}

@media (max-width: 640px) {
  /* photo / signify / draw / studio: keep the second row for account + credits only */
  header.topbar:has(.px-nav) .top-nav > a.btn[href$=".html"] { display: none; }
  /* ...which lets the bar fit on ONE row instead of wrapping under the brand */
  header.topbar:not(.px-header):has(.px-nav):has(.top-nav) { flex-wrap: nowrap; gap: 8px; }
  header.topbar:not(.px-header):has(.px-nav):has(.top-nav) > .brand { display: block; flex: 0 1 auto; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; font-size: 10px; }
  header.topbar:not(.px-header):has(.px-nav) .px-nav { flex: 0 0 auto; }
  header.px-header.topbar > .px-header__brand { flex: 0 0 auto; white-space: nowrap; }
  header.px-header.topbar > .px-nav { flex: 0 0 auto; }
  header.px-header.topbar > .px-header__nav { flex: 1 1 0; min-width: 0; justify-content: flex-end; }
  header.topbar:not(.px-header):has(.px-nav) .top-nav { flex: 1 1 auto; flex-wrap: nowrap; justify-content: flex-end; min-width: 0; margin-left: auto; }
}

/* ==========================================================================
   CROWDED TOP BARS (pixel-nav.js fitBar adds .px-fit-1..4 to the bar)
   Steps down one level at a time until nothing overlaps the menu button.
   ========================================================================== */
header.topbar > .px-nav { margin-left: 12px; margin-right: 12px; flex-shrink: 0; }
.px-fit-1 .brand-tag { display: none !important; }
.px-fit-2 .px-nav-btn-label { display: none; }
.px-fit-3 .pxa-name {
  display: inline-block; max-width: 9ch; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; vertical-align: middle;
}
.px-fit-4 .topbar-actions > .btn:not(.btn-accent):has(> i) {
  font-size: 0; gap: 0; padding-left: 10px; padding-right: 10px;
}
.px-fit-4 .topbar-actions > .btn:has(> i) > i { font-size: 16px; }/* level 5: still crowded -> the same two-row layout phones use (see the
   max-width:720px block above): brand, menu, account and saves on row 1,
   the tool buttons on row 2. */
header.topbar.px-fit-5:has(.topbar-actions) {
  height: auto; min-height: var(--topbar-h, 56px);
  flex-wrap: wrap; justify-content: flex-start; align-items: center;
  padding: 6px 12px; row-gap: 6px; column-gap: 8px;
}
header.topbar.px-fit-5:has(.topbar-actions)::after { content: ""; order: 2; flex: 0 0 100%; height: 0; }
header.topbar.px-fit-5:has(.topbar-actions) .topbar-actions { display: contents; }
header.topbar.px-fit-5 .topbar-actions > .divider-v { display: none; }
header.topbar.px-fit-5 .topbar-actions > span[id$="-mount"] { order: 1; }
header.topbar.px-fit-5 .topbar-actions > #account-mount { margin-left: auto; }
header.topbar.px-fit-5 .topbar-actions > .btn { order: 3; min-height: 40px; min-width: 40px; justify-content: center; }