/* oldskool-web-framework — text-mode / demoscene stylesheet.
   Font family comes from fonts.css via the --zine-font custom property,
   which is switched by html[data-font="..."]. Themes via html[data-theme]. */

:root {
  --cols: 76;
  --maxw: 78ch;
  /* default theme (paper) — overridden by [data-theme] below */
  --bg: #f4f1e8;
  --fg: #1a1a1a;
  --dim: #6b6b6b;
  --link: #7a0000;
  --link-hover: #c00000;
  --accent: #7a0000;
  --rule: #b9b2a0;
  --selbg: #1a1a1a;
  --selfg: #f4f1e8;
}

/* ---- Themes (screen modes) ---- */
html[data-theme="paper"] { --bg:#f4f1e8; --fg:#1a1a1a; --dim:#6b6b6b; --link:#7a0000; --link-hover:#c00000; --accent:#7a0000; --rule:#b9b2a0; --selbg:#1a1a1a; --selfg:#f4f1e8; }
html[data-theme="ansi"]  { --bg:#0a0a12; --fg:#c8c8d8; --dim:#6a6a82; --link:#5fd7ff; --link-hover:#ffffff; --accent:#ff5fd7; --rule:#33334d; --selbg:#5fd7ff; --selfg:#0a0a12; }
html[data-theme="amber"] { --bg:#160d00; --fg:#ffb000; --dim:#a06b00; --link:#ffd24a; --link-hover:#fff2c0; --accent:#ffd24a; --rule:#5a3d00; --selbg:#ffb000; --selfg:#160d00; }
html[data-theme="green"] { --bg:#001100; --fg:#33ff66; --dim:#1a8a3a; --link:#90ffb0; --link-hover:#ffffff; --accent:#90ffb0; --rule:#0a4a1a; --selbg:#33ff66; --selfg:#001100; }

* { box-sizing: border-box; }

html { background: var(--bg); }

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--zine-font, "Courier New", monospace);
  font-size: 16px;
  line-height: 1.35;
  -webkit-font-smoothing: none;
  font-smooth: never;
  image-rendering: pixelated;
}

::selection { background: var(--selbg); color: var(--selfg); }

a { color: var(--link); text-decoration: none; }
a:hover { color: var(--link-hover); text-decoration: underline; }

/* ---- Top bar ---- */
.topbar {
  display: flex; justify-content: space-between; align-items: center;
  gap: 1ch; flex-wrap: wrap;
  padding: 4px 10px;
  border-bottom: 1px solid var(--rule);
}
.topbar .brand a { color: var(--accent); font-weight: bold; }
.switchers { display: flex; align-items: center; gap: 1ch; font-size: .95em; }
.switchers select.switcher-font {
  background: var(--bg); color: var(--fg); border: 1px solid var(--rule);
  font-family: inherit; font-size: 1em; padding: .1em .3em;
}
.switchers button.switcher-theme {
  background: transparent; color: var(--link);
  border: 0; padding: 0 .2ch; margin: 0;
  font-family: inherit; font-size: 1em; cursor: pointer;
}
.switchers button.switcher-theme:hover { color: var(--link-hover); text-decoration: underline; }

/* ---- Background cube (all pages using the base shell; not the intro) ---- */
/* body must be transparent so the fixed #cube-bg (z-index:-1) shows through;
   the dark comes from html's background. */
body.doc { background: transparent; }
body.doc #cube-bg {
  position: fixed; left: 50%; top: 42%; transform: translate(-50%, -50%);
  z-index: -1; opacity: .14; pointer-events: none;
}

/* ---- Layout ---- */
.wrap { max-width: var(--maxw); margin: 0 auto; padding: 1.2em 1ch 3em; }

.mainnav {
  text-align: center; word-spacing: .2ch;
  font-family: "P0T-NOoDLE", "Courier New", monospace;
}
.mainnav .nav { white-space: nowrap; }
.mainnav .nav.on { color: var(--accent); font-weight: bold; }

/* Single-key nav (assets/js/hotkeys.js): highlighted hotkey letter + the
   "?" help overlay. */
.hk { color: var(--accent); }
.hk-help {
  position: fixed; inset: 0; z-index: 90;
  background: rgba(0, 0, 0, .65);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
}
.hk-help pre {
  background: var(--bg); color: var(--fg);
  border: 4px double var(--fg);
  padding: 1rem 2rem; margin: 0;
}

/* Jukebox (and any) pagination: bracketed prev / page-numbers / next. */
.pager { text-align: center; margin: 1.4em 0 .2em; word-spacing: .3ch; }
.pager a, .pager span { white-space: nowrap; }
.pager .cur { color: var(--accent); font-weight: bold; }

hr.rule {
  border: 0; border-top: 1px solid var(--rule);
  margin: 1em 0; height: 0;
}

/* Classic Amiga copper/raster bar -- an alternative to hr.rule for the
   nav/content divider: a cycling rainbow gradient strip instead of a plain
   line. Colors are fixed rather than theme-driven, same as the demo effects
   that use this look (copper-bars.html, megascreen.html). */
.raster-bar {
  height: 4px; margin: 1em 0; border-radius: 2px;
  background: linear-gradient(90deg, #ff5fd7, #5fd7ff, #ffe75f, #ff5fd7);
  background-size: 200% 100%;
  animation: raster-scroll 6s linear infinite;
}
@media (prefers-reduced-motion: reduce) {
  .raster-bar { animation: none; }
}
@keyframes raster-scroll {
  0% { background-position: 0% 0; }
  100% { background-position: 200% 0; }
}

/* ---- Banners / pre blocks ---- */
pre {
  font-family: inherit;
  white-space: pre;
  overflow-x: auto;
  margin: .6em 0;
}
pre.banner { color: var(--accent); line-height: 1.0; font-size: 14px; }
pre.banner.small { font-size: 12px; }
/* Half-block ANSI logo: force a monospace with full block-element coverage and
   tighten the grid so ▀/▄ rows meet cleanly. */
pre.logo {
  font-family: "Courier New", "DejaVu Sans Mono", monospace;
  line-height: 1.0; letter-spacing: 0; font-size: 11px;
}
@media (max-width: 760px) { pre.logo { font-size: 6px; } }
/* Logo container: measured in inline-size so the P0T-NOoDLE index banner can
   scale its font down to fit the content column (see cqw font-size in index.js). */
.logobox { container-type: inline-size; }
/* Copper-bar logo: the <pre> is the layout + glow; a canvas overlay paints the
   copper bars into the letter shapes, so the text fill itself is hidden. */
.logo-wrap { position: relative; display: inline-block; }
/* The <pre> is only a layout/measurement box — hide its text and glow entirely
   so the copper canvas (with its own drop-shadow glow) is all that shows. */
.logo-wrap .logo { color: transparent; text-shadow: none; }
.logo-copper {
  position: absolute; inset: 0; width: 100%; height: 100%;
  pointer-events: none;
}
pre.glow { text-shadow: 0 0 8px var(--accent); }
pre.tagline { color: var(--dim); }
pre.tagline.center { text-align: center; }
pre.meta { color: var(--dim); }
pre.editorial, pre.prose, pre.bio, pre.abstract {
  white-space: pre-wrap; word-wrap: break-word;
}

/* ---- Headings ---- */
h1.ph, h2.sec {
  font-weight: bold; font-size: 1em; margin: 1.2em 0 .4em;
  color: var(--accent);
}
h1.ph { text-align: center; }

/* Post + section headers (and in-article markdown headings) in the Amiga
   P0T-NOoDLE logo font, matching the nav. */
.mainnav, .philenav .secjump,
h1.ph, h2.sec, .seccard h3.sec,
.philebody h1, .philebody h2, .philebody h3, .philebody h4 {
  font-family: "P0T-NOoDLE", "Courier New", monospace;
}

/* ---- Tables of contents ---- */
table.toc { width: 100%; border-collapse: collapse; }
table.toc td { padding: .1em .8ch; vertical-align: top; }
table.toc td.n { color: var(--dim); white-space: nowrap; width: 6ch; }
table.toc td.a { color: var(--dim); white-space: nowrap; text-align: right; }
table.toc td.fmt { color: var(--dim); white-space: nowrap; width: 9ch; }
table.toc td.d { color: var(--dim); white-space: nowrap; width: 11ch; }
/* Listing rows get a little breathing room between entries. */
table.toc.list td { padding: .5em .8ch; border-top: 1px solid var(--rule); }
table.toc.list tr:first-child td { border-top: 0; }

/* ---- Section grid (home) + section cards ---- */
.secgrid {
  display: grid; gap: 1em 2ch; margin-top: 2em;
  grid-template-columns: repeat(auto-fit, minmax(24ch, 1fr));
}
.seccard h3.sec { margin: 0 0 .2em; }
.seccard h3.sec a { color: var(--accent); }
.reclist { list-style: none; margin: .3em 0 0; padding: 0; }
.reclist li { padding: .1em 0; }

/* ---- Tags ---- */
.tags { margin: .3em 0; }
.tag { color: var(--dim); white-space: nowrap; margin-right: .6ch; }

/* ---- Entry media (video player / effect + video embeds) ---- */
.embed { position: relative; width: 100%; aspect-ratio: 16 / 9; margin: 1em 0; }
.embed .entry-media { position: absolute; inset: 0; width: 100%; height: 100%; }
video.entry-media { width: 100%; height: auto; margin: 1em 0; background: #000; }
.entry-media { border: 1px solid var(--rule); }
.demo-stage { aspect-ratio: 4 / 3; max-width: 900px; margin: 1em auto; border: 1px solid var(--accent); }
.demo-controls { text-align: right; max-width: 900px; margin: -0.4em auto 1em; }
.demo-controls button {
  background: transparent; color: var(--link);
  border: 0; padding: 0 .4ch; margin: 0;
  font-family: inherit; font-size: 1em; cursor: pointer;
}
.demo-controls button:hover { color: var(--link-hover); text-decoration: underline; }

/* ---- Jukebox ---- */
table.jukebox td.fmt { white-space: nowrap; width: 16ch; }
table.jukebox td.ctrl { white-space: nowrap; width: 14ch; text-align: right; }
table.jukebox tr.playing td.t { color: var(--accent); font-weight: bold; }
table.jukebox tr.playing td.t::before { content: "» "; color: var(--accent); }
.jukebox button {
  background: transparent; color: var(--link);
  border: 0; padding: 0 .4ch; margin: 0;
  font-family: inherit; font-size: 1em; cursor: pointer;
}
.jukebox button:hover { color: var(--link-hover); text-decoration: underline; }
.jukebox tr.playing .jb-play { color: var(--accent); font-weight: bold; }
#jb-status { margin: .4em 0 1em; }

.issuebar { word-spacing: .1ch; }
.issuebar .cur { color: var(--accent); font-weight: bold; }
.dl { text-align: center; margin-top: 1.5em; }

/* ---- Phile body ---- */
.philenav { color: var(--dim); }
.philebody {
  white-space: normal;
  overflow-wrap: break-word;
  word-wrap: break-word;
}
/* Prose paragraphs: wrap at the column edge (scene philes, not pre). */
.philebody p {
  margin: .55em 0;
  max-width: 100%;
  line-height: 1.45;
}
/* Fenced / indented code: keep monospaced left bar, but wrap long lines so
   imported tutorial dumps don't blow out the column or look like solid bars. */
.philebody pre {
  border-left: 2px solid var(--rule);
  padding: .35em 0 .35em 1ch;
  color: var(--fg);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  word-break: break-word;
  overflow-x: auto;
  max-width: 100%;
}
/* Block code inherits pre; only INLINE code gets the muted chip background. */
.philebody code {
  font-family: inherit;
}
.philebody :not(pre) > code {
  background: rgba(127, 127, 127, .15);
  padding: 0 .3ch;
}
.philebody pre code {
  background: transparent;
  padding: 0;
  display: block;
  white-space: inherit;
}
.philebody h1, .philebody h2, .philebody h3 {
  color: var(--accent); font-size: 1em; margin: 1.2em 0 .3em;
}
.philebody h1::before { content: ".:: "; }
.philebody h1::after { content: " ::."; }
.philebody a { text-decoration: underline; }
/* Tutorial / phile screenshots: sit in the column, centered, no overflow. */
.philebody img {
  display: block;
  max-width: 100%;
  height: auto;
  margin: .9em auto;
  border: 1px solid var(--rule);
  background: #000;
}
.philebody p > img { margin: .9em auto; }
.philebody blockquote {
  margin: .6em 0; padding-left: 1ch; border-left: 2px solid var(--accent);
  color: var(--dim);
}
.dim { color: var(--dim); }

/* ---- Footer ---- */
footer { color: var(--dim); text-align: center; }
footer .socials a { margin: 0 .4ch; }
footer .copy { margin-top: .5em; font-size: .9em; }

/* ---- Search ---- */
.searchbox {
  width: 100%; background: var(--bg); color: var(--fg);
  border: 1px solid var(--rule); font-family: inherit; font-size: 1em;
  padding: .3em .6ch;
}
.results .hit { margin: .6em 0; }
.results .hit .meta { color: var(--dim); font-size: .9em; }

/* ============ Intro / landing ============ */
body.intro {
  overflow: hidden; height: 100vh;
  background: #000; color: var(--fg);
}
#fx-back, #fx-front {
  position: fixed; inset: 0; width: 100%; height: 100%;
  display: block; pointer-events: none;
}
#fx-back { z-index: 0; }
#fx-front { z-index: 2; }
/* Decrunch-bar intro phase: covers everything else while it plays, then
   fades out once (see templates/intro.js) to reveal the cube/logo/scroller
   already running underneath. */
#decrunch-overlay {
  position: fixed; inset: 0; width: 100%; height: 100%;
  display: block; z-index: 3; pointer-events: none;
  image-rendering: pixelated;
}
.intro-overlay {
  position: relative; z-index: 1;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  height: 100vh; gap: 1.2em; text-align: center;
  pointer-events: none;
}
.intro-overlay a, .intro-overlay button, .intro-overlay select { pointer-events: auto; }
.intro-overlay .banner { font-size: 16px; }
.intro-overlay .logo { font-size: 10px; }
@media (max-width: 760px) { .intro-overlay .logo { font-size: 5px; } }
.scroller { color: var(--accent); }
/* Old-terminal typed tagline: stacked lines + blinking modem-style cursor. */
.term-line { line-height: 1.3; }
.type-cursor { color: var(--accent); animation: type-blink 1.06s steps(1, end) infinite; }
@keyframes type-blink { 50% { opacity: 0; } }
.intro-controls { display: flex; gap: 1.5ch; flex-wrap: wrap; justify-content: center; }
.btn {
  background: rgba(0,0,0,.4); color: var(--link);
  border: 1px solid var(--rule); padding: .3em 1ch;
  font-family: inherit; font-size: 1em; cursor: pointer;
}
.btn:hover { color: var(--link-hover); border-color: var(--accent); }
.music-select {
  background: rgba(0,0,0,.5); color: var(--fg);
  border: 1px solid var(--rule); font-family: inherit; font-size: 1em;
  padding: .3em 1ch; cursor: pointer;
}
.music-select:hover { border-color: var(--accent); }

/* ---- Oneliner wall ---- */
.ol-wall {
  white-space: pre-wrap;
  line-height: 1.4;
  min-height: 8em;
}
.ol-row { margin: 0.15em 0; }
.ol-handle { color: var(--accent); margin-right: 1ch; }
.ol-date { margin-right: 1ch; }
.ol-prompt { color: var(--dim); }
.ol-cursor {
  color: var(--accent);
  animation: type-blink 1.06s steps(1, end) infinite;
}
.ol-form { display: flex; flex-wrap: wrap; gap: 1ch; align-items: center; margin: 0.8em 0; }
.ol-form input { font-family: inherit; background: var(--bg); color: var(--fg); border: 1px solid var(--rule); padding: 0.2em 0.5ch; }
.ol-form .ol-input { min-width: 40ch; flex: 1; }
.ol-form button { font-family: inherit; background: transparent; color: var(--link); border: 1px solid var(--rule); cursor: pointer; padding: 0.2em 1ch; }
.ol-form button:hover { color: var(--link-hover); border-color: var(--accent); }

/* ---- Keygen window ---- */
body.keygen-page .wrap main { max-width: 72ch; }
.keygen-window {
  border: 2px solid var(--accent);
  background: rgba(0, 0, 0, 0.55);
  padding: 0 0 1em;
  box-shadow: 0 0 0 1px var(--rule), 4px 4px 0 rgba(0, 0, 0, 0.5);
}
.keygen-titlebar {
  background: var(--accent);
  color: var(--bg);
  padding: 0.25em 1ch;
  font-weight: bold;
  text-align: center;
}
.keygen-logo { text-align: center; margin: 1em 0 0.5em; position: relative; }
.keygen-logo .logo { font-size: 8px; display: inline-block; }
.keygen-scroll {
  display: block;
  width: 100%;
  height: 28px;
  background: #000;
  image-rendering: pixelated;
}
.keygen-body { padding: 1em 1.5ch; text-align: center; }
.keygen-meta { text-align: left; display: inline-block; margin: 0.5em auto; }
.keygen-serial code { color: var(--accent); letter-spacing: 0.1ch; }
.keygen-foot { text-align: center; margin-top: 0.5em; }
.keygen-body .btn {
  background: rgba(0, 0, 0, 0.4);
  color: var(--link);
  border: 1px solid var(--rule);
  padding: 0.3em 1ch;
  font-family: inherit;
  font-size: 1em;
  cursor: pointer;
  margin: 0.2em;
}
.keygen-body .btn:hover { color: var(--link-hover); border-color: var(--accent); }

/* ---- Dial-up pre-intro ---- */
body.dialup-wait #decrunch-overlay,
body.dialup-wait #fx-back,
body.dialup-wait #fx-front,
body.dialup-wait .intro-overlay { visibility: hidden; }
.dialup-stage {
  position: fixed;
  inset: 0;
  z-index: 20;
  background: #000;
  color: #33ff66;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.2em;
  padding: 2em 1ch;
}
.dialup-term {
  width: min(72ch, 100%);
  min-height: 14em;
  max-height: 50vh;
  overflow: auto;
  background: #001100;
  border: 1px solid #1a8a3a;
  padding: 1em 1.5ch;
  text-align: left;
  white-space: pre-wrap;
  color: #33ff66;
  font-family: var(--zine-font, "Courier New", monospace);
}
.dialup-stage .btn {
  background: #001100;
  color: #33ff66;
  border: 1px solid #1a8a3a;
}
.dialup-stage .btn:hover { color: #90ffb0; border-color: #33ff66; }

/* ---- ProTracker pattern view ---- */
.ptview-wrap { margin: 1em 0; text-align: center; }
.ptview {
  display: inline-block;
  image-rendering: pixelated;
  border: 1px solid var(--rule);
  background: #0a0a18;
  max-width: 100%;
}

/* ---- Diskmag reader ---- */
body.mag-page .wrap { max-width: 100%; }
.mag-layout {
  display: grid;
  grid-template-columns: minmax(18ch, 28ch) 1fr;
  gap: 1.5ch;
  align-items: start;
}
@media (max-width: 720px) {
  .mag-layout { grid-template-columns: 1fr; }
}
.mag-index {
  border-right: 1px solid var(--rule);
  padding-right: 1ch;
  max-height: 80vh;
  overflow: auto;
}
.mag-list { list-style: none; padding: 0; margin: 0 0 1em; }
.mag-list li { margin: 0.2em 0; }
.mag-list a.on { color: var(--accent); font-weight: bold; }
.mag-sec { font-size: 1em; margin: 0.8em 0 0.3em; }
.mag-panel { min-height: 60vh; }
.mag-body { margin: 0.8em 0; }
.mag-nav { display: flex; gap: 1ch; flex-wrap: wrap; margin-top: 1em; }
.mag-nav .btn {
  background: transparent;
  color: var(--link);
  border: 1px solid var(--rule);
  font-family: inherit;
  cursor: pointer;
  padding: 0.2em 1ch;
}
.mag-nav .btn:hover { color: var(--link-hover); border-color: var(--accent); }
.ansi-controls { margin: 0.4em 0; }
.ansi-controls .btn {
  background: transparent;
  color: var(--link);
  border: 1px solid var(--rule);
  font-family: inherit;
  cursor: pointer;
  padding: 0.2em 1ch;
}

/* ---- ANSI art canvas (embeddable) ---- */
canvas.ansi { image-rendering: pixelated; max-width: 100%; }

/* ---- Module info + VU ---- */
.modinfo-wrap { margin: 1em 0; text-align: left; }
.modinfo-meta {
  white-space: pre-wrap;
  border: 1px solid var(--rule);
  padding: 0.6em 1ch;
  background: rgba(0,0,0,0.35);
  max-height: 14em;
  overflow: auto;
}
.modinfo-vu {
  display: block;
  margin-top: 0.5em;
  image-rendering: pixelated;
  border: 1px solid var(--rule);
  max-width: 100%;
}

/* ---- Charts ---- */
.charts-table {
  white-space: pre;
  overflow-x: auto;
  line-height: 1.35;
  border: 1px solid var(--rule);
  padding: 0.6em 1ch;
  background: rgba(0,0,0,0.25);
}

/* ---- Page FX ---- */
#pagefx-decrunch {
  position: fixed; inset: 0; width: 100%; height: 100%;
  z-index: 9998; pointer-events: none;
  image-rendering: pixelated;
  transition: opacity 0.2s ease;
}
html.pagefx-phosphor body.doc,
html.pagefx-fade body.doc,
html.pagefx-scan body.doc,
html.pagefx-glitch body.doc,
html.pagefx-decrunch body.doc {
  transition: opacity 0.22s ease, filter 0.22s ease, transform 0.22s ease;
}
html.pagefx-phosphor:not(.pagefx-ready) body.doc,
html.pagefx-fade:not(.pagefx-ready) body.doc { opacity: 0; }
html.pagefx-phosphor.pagefx-leaving body.doc,
html.pagefx-fade.pagefx-leaving body.doc { opacity: 0; }
html.pagefx-scan:not(.pagefx-ready) body.doc {
  clip-path: inset(0 0 100% 0);
}
html.pagefx-scan.pagefx-ready body.doc { clip-path: inset(0 0 0 0); transition: clip-path 0.28s steps(12); }
html.pagefx-scan.pagefx-leaving body.doc { clip-path: inset(100% 0 0 0); }
html.pagefx-glitch:not(.pagefx-ready) body.doc {
  opacity: 0.2; filter: hue-rotate(90deg); transform: translateX(4px);
}
html.pagefx-glitch.pagefx-leaving body.doc {
  opacity: 0; filter: hue-rotate(-40deg); transform: translateX(-6px);
}
html.pagefx-decrunch:not(.pagefx-ready) body.doc { opacity: 0.3; }

#pagefx-effect-frame {
  position: fixed; inset: 0; width: 100%; height: 100%;
  z-index: 9999; /* above #pagefx-decrunch -- only one plays at a time anyway */
  border: 0; background: #000;
  pointer-events: none; /* decorative during the leave delay, not interactive */
  opacity: 0; transition: opacity 0.3s ease;
}
#pagefx-effect-frame.show { opacity: 1; }

/* ---- Trainer menu ---- */
.trainer-overlay {
  position: fixed; inset: 0; z-index: 10000;
  background: rgba(0,0,0,0.72);
  display: flex; align-items: center; justify-content: center;
  padding: 1em;
}
.trainer-panel {
  background: #000;
  color: #ffb000;
  border: 2px solid #ff0000;
  padding: 1em 1.5ch;
  max-width: 48ch;
  box-shadow: 0 0 0 1px #880000, 4px 4px 0 #000;
  white-space: pre;
  font-family: var(--zine-font, monospace);
}
.trainer-guru {
  position: fixed; inset: 0; z-index: 10001;
  background: #000; color: #ff0000;
  display: flex; align-items: center; justify-content: center;
  border: 6px double #ff0000;
  animation: trainer-guru-blink 1s steps(1) infinite;
  cursor: pointer;
  font-family: "Topaz A500", var(--zine-font, monospace);
}
@keyframes trainer-guru-blink {
  50% { border-color: #000; }
}
@media (prefers-reduced-motion: reduce) {
  .trainer-guru { animation: none; }
}
body.trainer-scanlines::after {
  content: "";
  pointer-events: none;
  position: fixed; inset: 0; z-index: 9990;
  background: repeating-linear-gradient(
    to bottom,
    transparent 0, transparent 2px,
    rgba(0,0,0,0.18) 2px, rgba(0,0,0,0.18) 3px
  );
}
body.trainer-copper .raster-bar {
  height: 8px;
  background: linear-gradient(90deg, #f0f, #0ff, #ff0, #f0f);
  background-size: 200% 100%;
  animation: trainer-copper 2s linear infinite;
}
@keyframes trainer-copper {
  to { background-position: 200% 0; }
}
body.trainer-cursor,
body.trainer-cursor * {
  cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16'%3E%3Cpath d='M1 1h4v10H3v4H1z' fill='%23fff' stroke='%23000'/%3E%3Cpath d='M5 11l6 4-2-6 4-2z' fill='%23f00' stroke='%23000'/%3E%3C/svg%3E") 1 1, auto !important;
}
body.trainer-bloom .wrap,
body.trainer-bloom .topbar {
  text-shadow: 0 0 4px currentColor, 0 0 12px rgba(255,95,215,0.35);
}

/* ---- fxtext: embeddable text-driven effect box ---- */
.fxtext { margin: 1em 0; }
.fxtext-canvas {
  display: block; width: 100%;
  background: #000; border: 1px solid var(--rule);
  image-rendering: pixelated;
}
.fxtext-controls {
  display: flex; gap: 1ch; align-items: stretch; margin-top: 6px;
}
.fxtext-input {
  flex: 1 1 auto; resize: vertical;
  background: var(--bg); color: var(--fg);
  border: 1px solid var(--rule); font-family: inherit; font-size: 1em;
  padding: .3em .6ch;
}
.fxtext-pick { display: flex; align-items: center; gap: .4ch; white-space: nowrap; }
.fxtext-pick label { color: var(--dim); }
.fxtext-select {
  background: var(--bg); color: var(--fg);
  border: 1px solid var(--rule); font-family: inherit; font-size: 1em; padding: 0 .3ch;
}

@media (max-width: 640px) {
  body { font-size: 14px; }
  pre.banner { font-size: 10px; }
}
