:root {
  --ink:   #ece6ff;
  --dim:   #a99cd0;
  --glass: rgba(14, 8, 28, 0.72);
  --line:  rgba(180, 150, 255, 0.18);
  --hot:   #7df0ff;
  --warm:  #ff86c8;
  --pad:   14px;
}

* { box-sizing: border-box; }

html, body {
  margin: 0; padding: 0; height: 100%; overflow: hidden;
  background: #05030a; color: var(--ink);
  font: 14px/1.45 ui-sans-serif, system-ui, "Segoe UI", sans-serif;
  -webkit-font-smoothing: antialiased;
}

body.idle { cursor: none; }

#gl {
  position: fixed; inset: 0; width: 100%; height: 100%; display: block;
  /* none, not manipulation: `manipulation` suppresses double-tap zoom but still
     hands two-finger pinches to the browser as page zoom, which would fight the
     pinch-to-scale gesture. The page itself never scrolls, so nothing is lost. */
  touch-action: none;
  -webkit-tap-highlight-color: transparent;
  user-select: none; -webkit-user-select: none;
}

/* ── panel ─────────────────────────────────────────────────────────────────── */

#panel {
  position: fixed; top: 0; left: 0; bottom: 0; z-index: 10;
  touch-action: pan-y;
  width: 820px; max-width: 94vw;
  /* No top padding: the sticky header below carries it instead. With the
     padding here, sticky cannot rise above the panel's content box and parks
     18px down, leaving a strip for the sliders to slide up into. */
  padding: 0 var(--pad) 28px;
  overflow-y: auto; overscroll-behavior: contain;
  background: var(--glass);
  backdrop-filter: blur(18px) saturate(1.3);
  -webkit-backdrop-filter: blur(18px) saturate(1.3);
  border-right: 1px solid var(--line);
  transition: transform .32s cubic-bezier(.4,0,.2,1), opacity .32s;
}
/* top/bottom sizes the panel to the LAYOUT viewport, which on iOS is the height
   with the browser toolbars retracted — so the bottom of the panel, and the
   sticky action bar with it, sits underneath iOS Chrome's toolbar and cannot be
   reached. dvh tracks the viewport actually on screen. Left as a @supports so
   anything without dvh keeps the old behaviour rather than losing its height. */
@supports (height: 100dvh) {
  #panel { bottom: auto; height: 100dvh; }
}

body.bare #panel { transform: translateX(-104%); opacity: 0; pointer-events: none; }
body.bare #hud   { opacity: 0; }

#panel::-webkit-scrollbar { width: 8px; }
#panel::-webkit-scrollbar-thumb { background: rgba(180,150,255,.22); border-radius: 4px; }

/* ⚠️ Sticky, and that is load-bearing rather than decorative.
   On a phone this panel is around 2500px of controls in an 800px window, it
   covers the canvas completely, and the only two buttons that dismiss it live
   in this header. When the header scrolled away with everything else, the only
   route back to the picture was to scroll all the way to the top again —
   through fifty-odd sliders, about half of which take a vertical drag and
   change themselves rather than scrolling. Reported from iOS Chrome as
   "I can't scroll up to the top", which is precisely what it was.
   Same trick as .actions at the other end. */
.head {
  position: sticky; top: 0; z-index: 3;
  display: flex; align-items: center; justify-content: space-between;
  margin: 0 calc(var(--pad) * -1) 16px;
  padding: 18px var(--pad) 12px;
  background: linear-gradient(to bottom, var(--glass) 72%, transparent);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
}
.head-btns { display: flex; gap: 8px; }
.done { padding: 8px 14px; font-size: 12.5px; font-weight: 600; }

/* Touch and pointer builds swap a few affordances. Explicit display values
   rather than `revert`, so the rule works the same on every element it lands on. */
p.touch-only, button.touch-only, span.touch-only { display: none; }
@media (hover: none), (pointer: coarse) {
  .pointer-only { display: none; }
  p.touch-only      { display: block; }
  button.touch-only { display: block; }
  span.touch-only   { display: inline; }
}
.head h1 {
  margin: 0; font-size: 21px; font-weight: 650; letter-spacing: .10em;
  text-transform: lowercase;
  background: linear-gradient(92deg, var(--hot), var(--warm));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}

/* Packed by flow rather than a grid, so the tall sections balance themselves
   instead of leaving ragged holes beside the short ones. */
.cols {
  column-count: 3;
  column-gap: 20px;
  column-rule: 1px solid var(--line);
}

section {
  margin-bottom: 14px;
  break-inside: avoid;
  -webkit-column-break-inside: avoid;
}
section h2 {
  margin: 0 0 7px; font-size: 10.5px; font-weight: 700;
  letter-spacing: .16em; text-transform: uppercase; color: var(--dim);
}

.blurb, .note, .keys {
  margin: 7px 0 0; font-size: 11.5px; line-height: 1.5; color: var(--dim);
}
.blurb { min-height: 2.6em; }
.keys { margin-top: 20px; padding-top: 14px; border-top: 1px solid var(--line); font-size: 11px; }

/* ── buttons ───────────────────────────────────────────────────────────────── */

button {
  font: inherit; color: var(--ink); cursor: pointer;
  background: rgba(255,255,255,.07);
  border: 1px solid transparent; border-radius: 9px;
  padding: 9px 11px;
  transition: background .14s, border-color .14s, transform .07s, color .14s;
}
button:hover  { background: rgba(255,255,255,.15); }
button:active { transform: translateY(1px); }
button.on {
  background: rgba(125,240,255,.16);
  border-color: rgba(125,240,255,.55);
  color: #fff;
}

.perform {
  padding: 8px 14px; font-size: 12.5px; font-weight: 600;
  background: linear-gradient(96deg, rgba(125,240,255,.22), rgba(255,134,200,.22));
  border-color: rgba(190,150,255,.4);
}

button.wide { display: block; width: 100%; text-align: left; }
button.big  { font-size: 15px; font-weight: 650; padding: 13px; }

.row { display: flex; gap: 8px; }
.row button { flex: 1; }

.actions {
  position: sticky; bottom: -28px; z-index: 2;
  display: flex; gap: 8px; margin: 6px -14px -28px; padding: 12px 14px 18px;
  background: linear-gradient(to top, var(--glass) 62%, transparent);
  backdrop-filter: blur(10px);
}
.actions .big { flex: 2; }
.actions button:last-child { flex: 1; }

/* ── pattern grid ──────────────────────────────────────────────────────────── */

.patterns { display: grid; grid-template-columns: repeat(2, 1fr); gap: 7px; }
.pat {
  display: flex; align-items: center; gap: 8px;
  padding: 9px 10px; text-align: left; font-size: 13.5px;
}
.pat .num {
  flex: none; width: 19px; height: 19px; border-radius: 5px;
  display: grid; place-items: center;
  font-size: 10.5px; font-weight: 700; color: var(--dim);
  background: rgba(255,255,255,.09);
}
.pat.on .num { background: rgba(125,240,255,.3); color: #fff; }

/* ── sliders ───────────────────────────────────────────────────────────────── */

.row-slider { margin-bottom: 7px; transition: opacity .2s; }
.row-slider.dim { opacity: .35; }
.lab { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 3px; }
.lab .nm  { font-size: 12.5px; }
.lab .val { font-size: 11.5px; color: var(--hot); font-variant-numeric: tabular-nums; }

input[type=range] {
  /* Vertical drags belong to the panel's scroller, horizontal ones to the
     slider. Without this a drag that starts on a slider — and half the panel's
     height is sliders — moves the slider instead of scrolling, which is most of
     why getting back up the panel was so hard. */
  touch-action: pan-y;
  -webkit-appearance: none; appearance: none;
  width: 100%; height: 22px; background: transparent; cursor: pointer; margin: 0;
}
input[type=range]::-webkit-slider-runnable-track {
  height: 5px; border-radius: 3px;
  background: linear-gradient(90deg, rgba(125,240,255,.5), rgba(255,134,200,.42));
}
input[type=range]::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 19px; height: 19px; margin-top: -7px; border-radius: 50%;
  background: #fff; border: 0; box-shadow: 0 1px 6px rgba(0,0,0,.55);
}
input[type=range]::-moz-range-track {
  height: 5px; border-radius: 3px;
  background: linear-gradient(90deg, rgba(125,240,255,.5), rgba(255,134,200,.42));
}
input[type=range]::-moz-range-thumb {
  width: 19px; height: 19px; border-radius: 50%; border: 0; background: #fff;
}

/* ── palettes ──────────────────────────────────────────────────────────────── */

.palettes { display: grid; grid-template-columns: repeat(6, 1fr); gap: 6px; margin-bottom: 12px; }
.pal {
  height: 26px; padding: 0; border-radius: 7px;
  border: 1px solid rgba(255,255,255,.14);
}
.pal.on { border-color: #fff; box-shadow: 0 0 0 2px rgba(125,240,255,.55); }

/* ── chips ─────────────────────────────────────────────────────────────────── */

.row-choice { margin-bottom: 10px; }
.row-choice .nm { display: block; font-size: 12.5px; margin-bottom: 6px; }
.chips { display: flex; flex-wrap: wrap; gap: 6px; }
.chip { padding: 6px 10px; font-size: 12px; border-radius: 7px; }

/* ── presets ───────────────────────────────────────────────────────────────── */

.presets { margin-top: 9px; display: flex; flex-direction: column; gap: 5px; }
.preset-row { display: flex; gap: 5px; }
.preset { flex: 1; display: flex; align-items: center; gap: 9px; text-align: left; font-size: 12.5px; padding: 8px 10px; }
.preset .sw { width: 26px; height: 13px; border-radius: 3px; flex: none; }
.preset .x, .x { flex: none; width: 32px; padding: 0; color: var(--dim); }

/* ── overlays ──────────────────────────────────────────────────────────────── */

#hud {
  position: fixed; right: 12px; bottom: 10px; z-index: 9;
  font: 11px/1.4 ui-monospace, Consolas, monospace;
  color: var(--dim); opacity: .5; pointer-events: none;
  text-shadow: 0 0 8px #000; transition: opacity .3s;
}

#toast {
  position: fixed; left: 50%; top: 26px; transform: translateX(-50%); z-index: 20;
  padding: 10px 18px; border-radius: 10px; pointer-events: none;
  background: var(--glass); backdrop-filter: blur(12px);
  border: 1px solid var(--line);
  font-size: 13px; opacity: 0; transition: opacity .3s;
}
#toast.on { opacity: 1; }

#err {
  position: fixed; inset: 0; z-index: 40; display: none; overflow: auto;
  margin: 0; padding: 28px; white-space: pre-wrap;
  background: rgba(8,2,16,.96); color: #ff9ecb;
  font: 12px/1.55 ui-monospace, Consolas, monospace;
}

#hint {
  position: fixed; left: 50%; bottom: 22px; transform: translateX(-50%); z-index: 9;
  padding: 9px 16px; border-radius: 9px;
  background: var(--glass); border: 1px solid var(--line);
  font-size: 12.5px; color: var(--dim);
  opacity: 0; transition: opacity .4s; pointer-events: none;
}
body.bare #hint { opacity: .8; }
body.bare.idle #hint { opacity: 0; }

/* Scrolling was the thing worth getting rid of, so hold on to three columns as
   the window narrows by tightening them rather than dropping one. Only below
   about 1200px does the panel start eating too much of the picture to justify it. */
@media (max-width: 1500px) {
  #panel { width: 744px; }
}

@media (max-width: 1200px) {
  #panel { width: 620px; }
  .cols { column-count: 2; }
}

@media (max-width: 1040px) {
  #panel { width: 360px; }
  .cols { column-count: 1; column-rule: none; }
  .blurb { min-height: 0; }
}

@media (max-width: 640px) {
  #panel { width: 100%; max-width: 100%; }
}

/* Fingers are not mouse pointers. The panel grows taller for this, which costs
   nothing — on a phone it scrolls regardless. */
@media (hover: none), (pointer: coarse) {
  button { padding: 11px 12px; }
  .pat   { padding: 13px 10px; font-size: 14px; }
  .chip  { padding: 9px 13px; font-size: 12.5px; }
  .pal   { height: 40px; }
  .row-slider { margin-bottom: 12px; }

  input[type=range] { height: 36px; }
  input[type=range]::-webkit-slider-thumb {
    width: 26px; height: 26px; margin-top: -10.5px;
  }
  input[type=range]::-moz-range-thumb { width: 26px; height: 26px; }

  /* Clear of the home indicator on a phone, given viewport-fit=cover. */
  #panel   { padding-bottom: calc(28px + env(safe-area-inset-bottom)); }
  .actions { padding-bottom: calc(18px + env(safe-area-inset-bottom)); }
  #hint    { bottom: calc(22px + env(safe-area-inset-bottom)); font-size: 13.5px; }
  #toast   { font-size: 15px; padding: 12px 22px; }
}

/* on a touch screen the toy opens without its panel, which would cover the
   whole picture, and this says for a few seconds how to bring it up */
body.bare.intro #hint, body.bare.intro.idle #hint { opacity: .85; }

/* ── the way round (the same in each toy with this panel) ──────────────────── */
/* while the panel is away: the controls, home, and the next toy */
#way {
  position: fixed; z-index: 11; display: flex; gap: 6px; align-items: center;
  top: calc(10px + env(safe-area-inset-top)); left: calc(10px + env(safe-area-inset-left));
  transition: opacity .35s;
}
#way a, #way button {
  display: inline-flex; align-items: center; gap: 6px; min-height: 36px; padding: 8px 13px;
  font: 600 13px/1 ui-sans-serif, system-ui, "Segoe UI", sans-serif; color: var(--ink); text-decoration: none;
  background: rgba(14, 14, 22, .62); border: 1px solid rgba(255, 255, 255, .16); border-radius: 999px;
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); cursor: pointer;
}
#way a:hover, #way button:hover { background: rgba(40, 36, 56, .8); }
#way a:focus-visible, #way button:focus-visible, .onward a:focus-visible, .head h1 a:focus-visible,
#panel button:focus-visible, #panel summary:focus-visible { outline: 2px solid var(--warm); outline-offset: 2px; }
body:not(.bare) #way { opacity: 0; pointer-events: none; }
body.bare.idle:not(.intro) #way { opacity: 0; pointer-events: none; }
@media (hover: none), (pointer: coarse) { #way a, #way button { min-height: 44px; padding: 11px 15px; font-size: 14px; } }
/* the title leads home */
.head h1 a { color: inherit; text-decoration: none; }
.head h1 a:hover { text-decoration: underline; text-decoration-color: var(--warm); text-underline-offset: 4px; }
/* and the foot of the panel, home and onward */
.onward { display: flex; justify-content: space-between; gap: 10px; margin: 14px 0 0; font-size: 13px; }
.onward a { color: var(--ink); text-decoration: none; padding: 8px 0; }
.onward a:hover { text-decoration: underline; }
/* section headings above the labels they head, not below them */
section h2 { font-size: 12px; color: var(--ink); opacity: .82; }
/* the fine-tuning, folded */
details.more { margin: 4px 0 12px; border-top: 1px solid var(--line); padding-top: 10px; }
details.more > summary {
  cursor: pointer; list-style: none; font-size: 12px; font-weight: 700; letter-spacing: .16em; text-transform: uppercase;
  color: var(--dim); padding: 6px 0;
}
details.more > summary::-webkit-details-marker { display: none; }
details.more > summary::before { content: '+ '; }
details.more[open] > summary::before { content: '– '; }
details.more > section { margin-top: 10px; }
/* the frames and counts are for the workshop: D shows them */
#hud { display: none; }
body.hud #hud { display: block; }
/* when it cannot start: what happened, in words, and the way back */
#oops {
  display: none; position: fixed; inset: 0; z-index: 40; padding: 28px; place-content: center;
  background: rgba(8, 6, 12, .95); color: var(--ink); text-align: left;
}
#oops:has(#err:not(:empty)) { display: grid; }
#oops > div { max-width: 520px; }
#oops h2 { margin: 0 0 10px; font-size: 22px; }
#oops p { margin: 0 0 14px; line-height: 1.5; color: var(--dim); }
#oops #err {
  position: static; inset: auto; display: block !important; z-index: auto; margin: 0 0 18px; padding: 10px 12px;
  max-height: 30vh; overflow: auto; font-size: 12px; white-space: pre-wrap; background: rgba(255, 255, 255, .06); border-radius: 8px;
}
#oops a { color: var(--ink); font-weight: 600; }

/* the drawn icons: one stroke for all of them */
svg.i { width: 16px; height: 16px; flex: none; fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; vertical-align: -3px; }
.onward a, #oops a { display: inline-flex; align-items: center; gap: 6px; }
details.more > summary { display: flex; align-items: center; gap: 6px; }
details.more > summary::before { content: none !important; }
details.more > summary svg.i { width: 13px; height: 13px; transition: transform .2s; }
details.more[open] > summary svg.i { transform: rotate(90deg); }

/* notes and keys at a size that can be read without leaning in */
.note, .keys, .blurb { font-size: 12.5px; }
.keys { font-size: 12px; }
