/* Thaumaturgy app styles.
 *
 * Lifted out of app.html unchanged. It is registered in three places and all three are
 * required: deploy.py FILES (or production 404s it), build_app_bundle.py ROOT_FILES (or
 * fix() rewrites the href to an absolute https URL and the offline native app ships
 * unstyled, silently), and sw.js PRECACHE (so a cold offline start is styled).
 *
 * Do not move it under fonts/, logo/ or sounds/: those are immutable in _headers and
 * cache-first in the service worker, so edits would never reach anyone.
 */
:root{
  --void:#0b0d12; --panel:#141821; --strip:#0f1219; --line:#232937; --line-2:#2f3647;
  --gold:#d4a72c; --gold-2:#e6b95a; --gold-dim:rgba(212,167,44,.14);
  --bone:#e9e4d6; --ash:#8a8f9c; --ash-2:#5f6572;
  --live:#3fae6b; --stop:#c0392b;
  --display:"Cinzel",Georgia,"Times New Roman",serif;
  --body:"Source Sans 3","Segoe UI",system-ui,Roboto,Helvetica,Arial,sans-serif;
}
*{box-sizing:border-box}
html,body{height:100%}
body{margin:0;background:var(--void);color:var(--bone);font:15px/1.45 var(--body);-webkit-tap-highlight-color:transparent;
  background-image:radial-gradient(1200px 600px at 50% -200px,rgba(212,167,44,.07),transparent 70%)}
::selection{background:var(--gold);color:#1a1405}
button{font-family:inherit}
input[type=range]{accent-color:var(--gold)}
select,.dd{font-family:inherit}

/* ---------- top bar ---------- */
.top{position:sticky;top:0;z-index:20;background:rgba(11,13,18,.88);backdrop-filter:blur(10px);border-bottom:1px solid var(--line)}
.top-in{max-width:1400px;margin:0 auto;padding:10px 20px;display:flex;align-items:center;gap:18px;flex-wrap:wrap}
.brand{display:flex;align-items:center;gap:12px;text-decoration:none;color:inherit}
.brand img{width:40px;height:40px;filter:drop-shadow(0 0 6px rgba(212,167,44,.35))}
.brand h1.word{margin:0;font-weight:inherit}
.brand .word{font:600 22px/1 var(--display);letter-spacing:.06em;color:var(--bone)}
.brand .word b{color:var(--gold);font-weight:600}
.brand .tag{display:block;font:500 10.5px/1 var(--body);letter-spacing:.22em;text-transform:uppercase;color:var(--ash);margin-top:5px}
.top-ctl{display:flex;align-items:center;gap:16px;margin-left:auto;flex-wrap:wrap}
.howto{background:transparent;color:var(--gold);border:1px solid var(--line-2);border-radius:8px;padding:7px 12px;cursor:pointer;font-size:12.5px;letter-spacing:.04em;font-family:inherit;white-space:nowrap}
.howto:hover{border-color:var(--gold)}
.vmodal{align-items:center}
.vbox{width:min(960px,96vw);background:var(--panel);border:1px solid var(--line-2);border-radius:16px;overflow:hidden;box-shadow:0 30px 80px rgba(0,0,0,.6)}
.vhead{display:flex;align-items:center;justify-content:space-between;padding:10px 14px 10px 18px;font:600 13px/1 var(--display);letter-spacing:.14em;text-transform:uppercase;color:var(--gold);border-bottom:1px solid var(--line)}
.vhead button{background:transparent;border:1px solid var(--line-2);color:var(--ash);border-radius:7px;width:30px;height:30px;cursor:pointer}
.vhead button:hover{color:var(--bone);border-color:var(--gold)}
.vbox video{display:block;width:100%;aspect-ratio:16/10;background:#000}
.nudge{position:fixed;left:50%;bottom:22px;transform:translate(-50%,20px);opacity:0;transition:transform .25s,opacity .25s;z-index:8000;background:var(--panel);border:1px solid var(--gold);border-radius:12px;padding:10px 12px 10px 14px;display:flex;gap:10px;align-items:center;max-width:min(560px,calc(100vw - 32px));box-shadow:0 20px 50px rgba(0,0,0,.6);font-size:14px}
.nudge.in{transform:translate(-50%,0);opacity:1}
.nudge b{color:var(--gold)}
.nudge .go{background:var(--gold);color:#1a1405;border:0;border-radius:8px;padding:7px 12px;font-weight:700;cursor:pointer;white-space:nowrap}
.nudge .x{background:transparent;border:0;color:var(--ash);cursor:pointer;font-size:12px;padding:4px}
.nudge.upd{border-color:var(--gold);align-items:flex-start}
.nudge.upd .go:disabled{opacity:.6;cursor:default}
@media (max-width:640px){.nudge{bottom:84px;flex-wrap:wrap}.nudge span{flex-basis:100%}}
.beta{display:block;margin-bottom:8px;color:var(--ash)}
.beta b{color:var(--gold);font-weight:600;letter-spacing:.06em;text-transform:uppercase;font-size:11.5px;margin-right:6px}
.beta a{color:var(--gold)}
@media (max-width:640px){.ed-head{flex-direction:column;align-items:stretch}.ed-head .ed-name{max-width:none}.ed-actions{margin-left:0}.section-head{flex-wrap:wrap;gap:6px 14px}.section-head h2{white-space:nowrap}}
.ctl{display:flex;align-items:center;gap:8px;font-size:12.5px;color:var(--ash);letter-spacing:.02em}
.ctl input[type=range]{width:110px}
.ctl input[type=checkbox]{accent-color:var(--gold)}
.panic{background:transparent;color:var(--stop);border:1.5px solid var(--stop);border-radius:8px;padding:8px 14px;font-weight:600;font-size:12.5px;letter-spacing:.08em;cursor:pointer;transition:background .12s,color .12s}
.panic:hover{background:var(--stop);color:#fff}
.acct{display:flex;align-items:center;gap:8px;padding-left:12px;border-left:1px solid var(--line)}
.acct-who{font-size:12.5px;color:var(--ash);max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.acct-status{font-size:10.5px;letter-spacing:.08em;text-transform:uppercase;color:var(--ash-2);display:flex;align-items:center;gap:5px}
.acct-status::before{content:"";width:6px;height:6px;border-radius:50%;background:var(--ash-2)}
.acct-status[data-s="synced"]{color:var(--live)}.acct-status[data-s="synced"]::before{background:var(--live)}
.acct-status[data-s="offline"]{color:var(--stop)}.acct-status[data-s="offline"]::before{background:var(--stop)}
a.acct-btn{text-decoration:none;display:inline-block;line-height:1}
.acct-btn{background:transparent;color:var(--ash);border:1px solid var(--line-2);border-radius:8px;padding:7px 12px;cursor:pointer;font-size:12.5px;letter-spacing:.04em;font-family:inherit}
.acct-btn:hover{color:var(--bone);border-color:var(--gold)}
.acct-btn.primary{color:var(--gold);border-color:var(--gold)}
@media (max-width:640px){.acct{border-left:0;padding-left:0}}

main{max-width:1400px;margin:0 auto;padding:22px 20px 60px}

/* ---------- environment console ---------- */
.env{position:relative;background:var(--panel);border:1px solid var(--line);border-radius:18px;padding:18px 18px 16px;overflow:hidden;
  box-shadow:0 30px 80px -40px rgba(0,0,0,.9)}
.env::before{content:"";position:absolute;right:-120px;top:-120px;width:520px;height:520px;background:url(logo/thaumaturgy-mark-512.png) center/contain no-repeat;opacity:.05;pointer-events:none;transition:opacity .6s}
.env.on::before{opacity:.09;animation:breathe 6s ease-in-out infinite}
@keyframes breathe{0%,100%{transform:scale(1);opacity:.07}50%{transform:scale(1.03);opacity:.11}}
.env.on{border-color:rgba(63,174,107,.55)}
.env-head{display:flex;align-items:center;gap:14px 22px;flex-wrap:wrap;position:relative}
.env-eyebrow{font:500 10.5px/1 var(--body);letter-spacing:.24em;text-transform:uppercase;color:var(--ash)}
.env-name{font:600 26px/1.1 var(--display);letter-spacing:.02em;color:var(--gold);margin-top:6px;text-wrap:balance}
.env-presets{display:flex;gap:6px;align-items:center;flex-wrap:wrap;margin-left:auto}
.env-presets select,.env-presets .dd{background:var(--strip);color:var(--bone);border:1px solid var(--line-2);border-radius:8px;padding:8px 10px;min-width:210px;font-size:13.5px}
.env-presets button{background:transparent;color:var(--ash);border:1px solid var(--line-2);border-radius:8px;padding:8px 11px;cursor:pointer;font-size:12.5px;letter-spacing:.04em;transition:color .12s,border-color .12s}
.env-presets button:hover{color:var(--bone);border-color:var(--gold)}
.env-play{position:relative;background:linear-gradient(180deg,var(--gold-2),var(--gold));color:#1a1405;border:0;border-radius:12px;padding:14px 30px;font:700 15px/1 var(--display);letter-spacing:.16em;cursor:pointer;
  box-shadow:0 8px 24px -8px rgba(212,167,44,.6);transition:transform .08s,box-shadow .2s}
.env-play:hover{box-shadow:0 10px 30px -8px rgba(212,167,44,.8)}
.env-play:active{transform:scale(.98)}
.env-play.on{background:linear-gradient(180deg,#4cc27c,var(--live));color:#052b13;box-shadow:0 8px 24px -8px rgba(63,174,107,.7)}

/* ---------- layer rack ---------- */
.layers{display:grid;align-items:start;grid-template-columns:repeat(4,minmax(0,1fr));gap:12px;margin-top:18px;position:relative}
.layer{background:var(--strip);border:1px solid var(--line);border-radius:14px;padding:14px 14px 12px;display:flex;flex-direction:column;gap:10px;transition:opacity .2s,border-color .2s;min-width:0}
.layer.off{opacity:.42}
.layer.off:hover{opacity:.6}
.layer-head{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.layer-head .sw{display:flex;align-items:center;gap:9px;cursor:pointer;user-select:none}
.layer-head .sw input{appearance:none;width:34px;height:18px;border-radius:9px;background:var(--line-2);position:relative;cursor:pointer;transition:background .15s;flex:0 0 auto;margin:0}
.layer-head .sw input::after{content:"";position:absolute;top:2px;left:2px;width:14px;height:14px;border-radius:50%;background:var(--ash);transition:transform .15s,background .15s}
.layer-head .sw input:checked{background:var(--gold-dim);border:1px solid var(--gold)}
.layer-head .sw input:checked::after{transform:translateX(16px);background:var(--gold);top:1px;left:1px}
.layer-head .sw b{font:600 15px/1 var(--display);letter-spacing:.08em;color:var(--bone)}
.layer-head .hint{font-size:10.5px;color:var(--ash-2);letter-spacing:.06em;text-transform:uppercase;line-height:1.3;flex-basis:100%;margin-top:-2px}
.layer .pick{display:grid;grid-template-columns:1fr;gap:6px}
.layer .pick-q{width:100%;min-width:0;padding:8px 10px;border-radius:9px;border:1px solid var(--line-2);
  background:var(--ink,#0e1117);color:var(--bone);font:inherit;font-size:13px}
.layer .pick-q::placeholder{color:var(--ash-2)}
.layer .pick-q:focus{outline:none;border-color:var(--gold);box-shadow:0 0 0 2px rgba(212,167,44,.18)}
.vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0 0 0 0);clip-path:inset(50%);white-space:nowrap;border:0}
.layer .pq{position:relative;min-width:0}
.layer .pick-res{position:absolute;z-index:40;left:0;right:0;top:calc(100% + 4px);max-height:260px;overflow-y:auto;
  background:var(--panel);border:1px solid var(--line-2);border-radius:10px;box-shadow:0 10px 30px rgba(0,0,0,.55);padding:4px}
.layer .pick-res[hidden]{display:none}
.layer .pick-hit{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:10px;align-items:baseline;width:100%;
  background:transparent;border:0;border-radius:7px;padding:7px 9px;text-align:left;color:var(--bone);font:inherit;font-size:13px;cursor:pointer}
.layer .pick-hit .ph-l{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.layer .pick-hit .ph-f{color:var(--ash-2);font-size:11px;white-space:nowrap}
.layer .pick-hit:hover,.layer .pick-hit.on{background:var(--line);color:var(--gold-2)}
.layer .pick-hit.cur .ph-l{color:var(--gold);font-weight:600}
.layer .pick-none{padding:8px 9px;font-size:12.5px;color:var(--ash-2)}
.layer select,.layer .dd{background:var(--panel);color:var(--bone);border:1px solid var(--line-2);border-radius:8px;padding:7px 9px;font-size:13px;min-width:0;width:100%}
.layer select[data-k="family"],.layer .dd[data-k="family"]{color:var(--gold);font-weight:600;letter-spacing:.02em}
.layer label{display:grid;grid-template-columns:1fr auto;gap:2px 8px;font-size:11.5px;color:var(--ash);letter-spacing:.04em;text-transform:uppercase}
.layer label .v{color:var(--gold-2);font-weight:600;text-transform:none;letter-spacing:0;font-variant-numeric:tabular-nums;text-align:right}
.layer label input[type=range]{grid-column:1/-1;width:100%;margin:2px 0 0}
.layer .sep{height:1px;background:var(--line);margin:2px 0}

.env-foot{display:flex;gap:18px;align-items:center;margin-top:14px;flex-wrap:wrap}
.env-foot label{flex:1;max-width:340px;display:grid;grid-template-columns:1fr auto;gap:2px 8px;font-size:11.5px;color:var(--ash);letter-spacing:.04em;text-transform:uppercase}
.env-foot label .v{color:var(--gold-2);font-weight:600;text-transform:none;letter-spacing:0;font-variant-numeric:tabular-nums}
.env-foot label input[type=range]{grid-column:1/-1;width:100%}
.env-foot .status{font-size:12.5px;color:var(--ash);font-variant-numeric:tabular-nums;display:flex;align-items:center;gap:8px}
.env-foot .status::before{content:"";width:8px;height:8px;border-radius:50%;background:var(--ash-2)}
.env.on .env-foot .status{color:var(--live)}
.env.on .env-foot .status::before{background:var(--live);box-shadow:0 0 10px var(--live)}


/* ---------- nav ---------- */
.nav{display:flex;gap:4px;background:var(--strip);border:1px solid var(--line);border-radius:10px;padding:3px}
.nav button{background:transparent;color:var(--ash);border:0;border-radius:8px;padding:7px 16px;font:600 13px/1 var(--display);letter-spacing:.1em;cursor:pointer;transition:background .12s,color .12s}
.nav button.on{background:var(--gold);color:#1a1405}
.nav button:not(.on):hover{color:var(--bone)}
.env-summary{display:flex;align-items:center;gap:10px 16px;flex-wrap:wrap;margin-top:14px}
.env-chips{display:flex;flex-wrap:wrap;gap:6px;min-width:0;flex:1}
.env-chip{font-size:12px;max-width:250px;overflow:hidden;text-overflow:ellipsis;background:var(--strip);border:1px solid var(--line);border-radius:6px;padding:4px 9px;color:var(--ash);white-space:nowrap;cursor:pointer;font-family:inherit}
.env-chip:hover{border-color:var(--line-2);color:var(--bone)}
.env-chip.open{border-color:var(--gold);color:var(--bone)}
.env-tweak{margin-top:10px;border:1px solid var(--line-2);border-radius:10px;background:var(--strip);padding:12px 14px}
.env-tweak .lv-note{font-size:12px;color:var(--ash-2);border-left:2px solid var(--gold);padding-left:9px;margin-bottom:11px;line-height:1.45}
.env-tweak .lv-note b{color:var(--gold-2,var(--gold));font-weight:600}
.env-tweak .lv-head{display:flex;align-items:center;gap:10px;margin-bottom:9px}
.env-tweak .lv-head .lv-name{font-family:Cinzel,serif;font-size:14px;color:var(--bone);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:60%}
.env-tweak .lv-head .lv-src{font-size:12px;color:var(--ash-2)}
.env-tweak .lv-head .lv-x{margin-left:auto;background:transparent;border:1px solid var(--line-2);color:var(--ash);border-radius:6px;width:24px;height:24px;cursor:pointer;font-size:11px;padding:0}
.env-tweak .lv-head .lv-x:hover{color:var(--bone);border-color:var(--gold)}
.env-tweak .lv-dials{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:9px 18px}
.env-tweak label{display:block;font-size:11px;letter-spacing:.09em;text-transform:uppercase;color:var(--ash-2)}
.env-tweak label .v{float:right;text-transform:none;letter-spacing:0;color:var(--ash)}
.env-tweak input[type=range]{width:100%;margin:3px 0 0}
.sheet-scrim{display:none}                 /* phone only: the tweak sheet's tap-away target */
/* Six dials are too tall to live inline: on a phone they shoved the boards down the page and could
   open below the fold with nothing to say they had opened. As a sheet the panel rises from the
   bottom, in thumb reach, and can never be off screen.
   This is a console-shell rule, not a phone one. The environment bar is shell chrome now, so an
   inline panel grows the chrome instead of the page: on a Fire HD 10 in landscape (960x600 -- the
   Amazon build's only target) it took the bar to 338px, 56% of the screen, leaving 205px for the
   boards. A transient control must not reflow the app. */
html.console .env-tweak{position:fixed;left:0;right:0;z-index:45;margin:0;border-radius:16px 16px 0 0;
  border:1px solid var(--line-2);border-bottom:0;padding:12px 14px calc(14px + env(safe-area-inset-bottom,0px));
  bottom:calc(56px + env(safe-area-inset-bottom,0px));
  max-height:62vh;overflow-y:auto;-webkit-overflow-scrolling:touch;
  box-shadow:0 -14px 40px rgba(0,0,0,.6);animation:sheetUp .18s ease-out}
html.console .env-tweak .lv-head{position:sticky;top:0;background:var(--strip);padding-bottom:6px;z-index:1}
html.console .env-tweak .lv-x{min-width:44px;min-height:44px}
/* stops short of the tab bar on purpose: covering it killed STOP and the screen switcher once before */
html.console .sheet-scrim{display:block;position:fixed;left:0;right:0;top:0;z-index:44;background:rgba(0,0,0,.45);
  bottom:calc(56px + env(safe-area-inset-bottom,0px))}

@media (max-width:640px){
  /* phone sizing only -- a tablet sheet has room for the dials side by side */
  .env-tweak .lv-dials{grid-template-columns:1fr;gap:6px}
  .env-tweak .lv-note{font-size:11.5px;line-height:1.4;margin-bottom:9px}
  .env-tweak label{font-size:10.5px}
  .env-tweak input[type=range]{margin-top:1px}
}
@keyframes sheetUp{from{transform:translateY(12px);opacity:.6}to{transform:none;opacity:1}}
.env-chip b{color:var(--bone);font-weight:600}
.env-chip.off{opacity:.45;text-decoration:line-through}
.env-chips .none{font-size:12.5px;color:var(--ash-2);font-style:italic}
.env-ed .env-body{margin-top:4px}
.env-ed.on{border-color:rgba(63,174,107,.55)}
.env-ed.on .env-live,.env-ed.on .env-foot .status{color:var(--live)}
.env-ed.on .env-live::before,.env-ed.on .env-foot .status::before{background:var(--live);box-shadow:0 0 10px var(--live)}
.env-play-sm{padding:10px 22px;font-size:14px;border-radius:10px}
.env-ops{margin-top:14px;padding-top:14px;border-top:1px solid var(--line);margin-left:0}
.env-ed .ed-name{max-width:520px}
.brow .ops{display:none;gap:3px;margin-left:auto}
#envList .brow{flex-direction:row;align-items:center;flex-wrap:wrap;gap:2px 6px}
#envList .brow .nm{flex:1 1 auto;min-width:0}
#envList .brow .meta{flex-basis:100%}
.brow:hover .ops,.brow.on .ops{display:flex}
.brow .ops button{background:transparent;border:1px solid var(--line-2);color:var(--ash);border-radius:5px;width:22px;height:22px;cursor:pointer;font-size:9px;padding:0}
.brow .ops button:hover{color:var(--bone);border-color:var(--gold)}

.layer-head .lc{background:transparent;border:0;color:var(--ash);cursor:pointer;font-size:10px;padding:2px 3px;transition:transform .15s}
.layer.collapsed .lc{transform:rotate(-90deg)}
.layer.collapsed .pick,.layer.collapsed .sep,.layer.collapsed > label,.layer.collapsed .hint{display:none}
.layer .lsum{display:none;flex-basis:100%;font-size:12px;color:var(--ash);padding-left:26px;margin-top:-2px}
.layer.collapsed .lsum{display:block}
.layer.collapsed{padding-bottom:10px}
.layer-head .lname{color:var(--bone);font:600 15px/1.25 var(--display);letter-spacing:.06em;padding:4px 6px;flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;cursor:default}

.layer.loop > label.d-cad{display:none}
.layer-head .lrm{background:transparent;border:0;color:var(--ash-2);cursor:pointer;font-size:12px;padding:2px 4px;border-radius:5px}
.layer-head .lrm:hover{color:var(--stop);background:var(--strip)}
.layer.add-layer{display:flex;flex-direction:column;align-items:center;justify-content:center;gap:8px;border-style:dashed;text-align:center;min-height:180px}
.add-layer .add-title{font:600 13px/1 var(--display);letter-spacing:.14em;text-transform:uppercase;color:var(--gold)}
.add-layer .add-note{font-size:12px;color:var(--ash-2);display:none}
.add-layer.many .add-note{display:block}
.add-layer .add-btns{display:flex;gap:8px}
.add-layer .add-btns button{background:transparent;color:var(--bone);border:1px solid var(--line-2);border-radius:9px;padding:9px 14px;cursor:pointer;font-size:13px;font-family:inherit}
.add-layer .add-btns button:hover{border-color:var(--gold);color:var(--gold)}
.add-layer .add-btns button:disabled{opacity:.4;cursor:default}
.add-layer .add-cap{font-size:12px;color:var(--ash)}

/* ---------- chapters ---------- */
.chapters{display:flex;align-items:center;gap:12px 16px;flex-wrap:wrap;margin-bottom:14px;padding:10px 14px;background:var(--strip);border:1px solid var(--line);border-radius:12px}
.ch-chips{display:flex;align-items:center;gap:8px;flex-wrap:wrap;flex:1;min-width:0}
.ch-chip{position:relative;display:inline-flex;align-items:stretch;border:1px solid var(--line-2);border-radius:9px;overflow:visible;background:var(--panel)}
.ch-chip .ch-go{background:transparent;border:0;color:var(--bone);padding:8px 10px 8px 12px;cursor:pointer;font:600 13.5px/1 var(--body);letter-spacing:.01em;white-space:nowrap;max-width:220px;overflow:hidden;text-overflow:ellipsis;border-radius:9px 0 0 9px}
.ch-chip .ch-more{background:transparent;border:0;border-left:1px solid var(--line);color:var(--ash-2);padding:0 8px;cursor:pointer;font-size:14px;border-radius:0 9px 9px 0}
.ch-chip:hover{border-color:#3d4557}
.ch-chip .ch-more:hover{color:var(--bone)}
.ch-chip.on{border-color:var(--gold);background:var(--gold-dim)}
.ch-chip.on .ch-go{color:var(--gold)}
.ch-new,.ch-save{background:transparent;border:1px dashed var(--line-2);color:var(--ash);border-radius:9px;padding:8px 12px;cursor:pointer;font-size:13px;font-family:inherit;white-space:nowrap}
.ch-new:hover{color:var(--bone);border-color:var(--gold)}
.ch-save{border-style:solid;border-color:var(--gold);color:var(--gold);font-weight:600}
.ch-hint{flex-basis:100%;font-size:12.5px;color:var(--ash)}
/* fixed and parented to <html> (see chapters.js): inside the chip it was clipped by .ch-chips, which
   scrolls horizontally. z-index 48 clears the Now Playing bar (47) and the tab bar (46), and stays
   under the modal (50). */
.ch-menu{position:fixed;z-index:48;display:flex;flex-direction:column;min-width:200px;background:var(--panel);border:1px solid var(--line-2);border-radius:10px;padding:4px;box-shadow:0 10px 30px rgba(0,0,0,.5)}
.ch-menu button{background:transparent;border:0;color:var(--bone);text-align:left;padding:8px 10px;border-radius:7px;cursor:pointer;font-size:13px;font-family:inherit}
.ch-menu button:hover{background:var(--strip)}
.ch-menu button.danger{color:var(--stop)}
.ch-menu .ch-tick{display:flex;align-items:center;gap:8px;padding:8px 10px;font-size:13px;color:var(--bone);cursor:pointer;border-bottom:1px solid var(--line);margin-bottom:4px}
.ch-menu .ch-tick input{accent-color:var(--gold)}
.ch-chip .ch-auto{font-size:9px;color:var(--live);margin-left:6px;vertical-align:1px}
@media (max-width:640px){.chapters{padding:10px 12px;flex-direction:column;align-items:stretch;gap:8px}.chapters > .env-eyebrow{order:-1}.ch-chips{justify-content:flex-start}.ch-chip .ch-go{max-width:170px}}

/* ---------- session: boards ---------- */
.boards-area{margin-top:22px}
.boards-bar{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:12px}
.boards-bar select,.boards-bar .dd{background:var(--strip);color:var(--bone);border:1px solid var(--line-2);border-radius:8px;padding:9px 12px;font-size:14px;min-width:240px}
.load-status{font-size:12px;color:var(--ash);font-variant-numeric:tabular-nums;animation:pulse 1.4s ease-in-out infinite}
/* the env bar's "Edit environments" link shares this; it was unstyled there, a white browser button */
.boards-bar .link,.env-summary .link{background:transparent;border:0;color:var(--gold);cursor:pointer;font-size:13px;margin-left:auto;padding:6px 2px;font-family:inherit}
/* Each loaded board stops on its own: the others, and the environment under them, keep playing.
   Dim until that board has something to stop, so a row of red squares is not the resting state. */
.board-head .bstop{color:var(--ash-2);font-size:11px;line-height:1}
.board-head .bstop:hover{color:var(--bone)}
.board-head .bstop.hot{color:var(--stop)}
.board-head .bstop.hot:hover{color:#fff;background:var(--stop)}
.boards-bar .link:hover,.env-summary .link:hover{text-decoration:underline}
/* minmax(0,1fr), not 1fr: a bare 1fr floors the track at the item's min-content, and the board head's
   -14px bleed margins push that past the viewport once a board is loaded -- the page then overflows and
   the phone zooms the whole app out to fit. */
.loaded{display:grid;grid-template-columns:minmax(0,1fr);gap:16px}
@media (min-width:1180px){.loaded{grid-template-columns:repeat(2,minmax(0,1fr))}}
.board.collapsed .bgrid{display:none}
.board.collapsed .bc{transform:rotate(-90deg)}
.board-head .bc{background:transparent;border:0;color:var(--ash);cursor:pointer;font-size:11px;padding:0 4px 0 0;transition:transform .15s}
.board-head .bops{margin-left:auto;display:flex;gap:4px}
.board-head .bops button{background:transparent;border:1px solid var(--line-2);color:var(--ash);border-radius:7px;width:28px;height:28px;cursor:pointer;font-size:11px}
.board-head .bops button:hover{color:var(--bone);border-color:var(--gold)}
.board-head .bops .bx:hover{color:var(--stop);border-color:var(--stop)}
.env-live{font-size:11.5px;letter-spacing:.06em;text-transform:uppercase;color:var(--ash-2);display:flex;align-items:center;gap:7px}
.env-live::before{content:"";width:8px;height:8px;border-radius:50%;background:var(--ash-2)}
.env.on .env-live{color:var(--live)}
.env.on .env-live::before{background:var(--live);box-shadow:0 0 10px var(--live)}
.board{background:var(--panel);border:1px solid var(--line);border-radius:16px;padding:14px 14px 12px}
.board-head{display:flex;align-items:center;gap:12px;margin:-14px -14px 12px;padding:12px 14px 10px;position:sticky;top:62px;background:var(--panel);border-radius:16px 16px 0 0;z-index:2;border-bottom:1px solid var(--line)}
.board-head h2{font:600 17px/1 var(--display);letter-spacing:.06em;color:var(--gold);margin:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
.board-head .cnt{font-size:12px;color:var(--ash);white-space:nowrap}
.bgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(112px,1fr));gap:8px}
.bb{position:relative;background:var(--strip);border:1px solid var(--line-2);border-radius:12px;padding:10px 8px 8px;aspect-ratio:1;text-align:center;color:var(--bone);cursor:pointer;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;min-width:0;
  transition:background .08s,border-color .12s,transform .05s;font-family:inherit;user-select:none;
  touch-action:manipulation}   /* panning stays the browser's (a scroll cancels the tap) and no double-tap zoom delay */
.bb:hover{background:#151a24;border-color:#3d4557}
.bb:active,.bb.playing{background:var(--gold-dim);border-color:var(--gold);transform:scale(.985)}
.bb .ic{font-size:30px;line-height:1;filter:saturate(.8);margin-bottom:2px}
.bb .lb{font-weight:600;font-size:13.5px;letter-spacing:.01em;line-height:1.15;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;max-width:100%}
.bb .nt{font-size:11px;color:var(--ash);line-height:1.25;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;max-width:100%}
.bb .lp{position:absolute;top:6px;right:6px;font-size:9px;letter-spacing:.14em;text-transform:uppercase;color:var(--ash-2);border:1px solid var(--line-2);border-radius:4px;padding:2px 5px}
.bb.loop.on{background:rgba(63,174,107,.12);border-color:var(--live)}
.bb.loop.on .lp{color:var(--live);border-color:var(--live);animation:pulse 1.4s ease-in-out infinite}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.45}}
.bb.missing{opacity:.4;cursor:not-allowed}
.empty-boards{border:1px dashed var(--line-2);border-radius:16px;padding:28px 20px;text-align:center;color:var(--ash);font-size:14px}
.empty-boards .e-title{font:600 15px/1 var(--display);letter-spacing:.06em;color:var(--bone);margin-bottom:8px}
.empty-note{color:var(--ash-2);font-size:13px;padding:10px 4px;grid-column:1/-1}

/* ---------- builder ---------- */
.builder{display:grid;grid-template-columns:280px minmax(0,1fr);gap:16px;align-items:start}
.bl{background:var(--panel);border:1px solid var(--line);border-radius:16px;padding:14px;position:sticky;top:78px}
.bl-top{display:flex;align-items:center;justify-content:space-between;margin-bottom:10px}
.bl-h{font-size:10.5px;letter-spacing:.2em;text-transform:uppercase;color:var(--ash-2);margin:12px 0 6px}
.bl-empty{font-size:12.5px;color:var(--ash-2);padding:6px 2px}
.bl-g{display:flex;align-items:center;gap:8px;width:100%;background:transparent;border:1px solid transparent;border-radius:9px;padding:8px 10px;cursor:pointer;color:var(--bone);font-family:Cinzel,serif;font-size:12.5px;letter-spacing:.06em;text-align:left}
.bl-g:hover{background:var(--strip)}
.bl-g .tri{color:var(--ash-2);font-size:11px;transition:transform .15s;display:inline-block}
.bl-g.open .tri{transform:rotate(90deg);color:var(--gold)}
.bl-g .gn{flex:1}
.bl-g .gc{font-family:"Source Sans 3",sans-serif;font-size:11px;color:var(--ash-2);border:1px solid var(--line-2);border-radius:999px;padding:0 7px}
.bl-box{padding-left:8px;border-left:1px solid var(--line);margin:0 0 4px 12px}
.brow{display:flex;flex-direction:column;gap:2px;padding:9px 10px;border-radius:9px;cursor:pointer;border:1px solid transparent}
.brow:hover{background:var(--strip)}
.brow.on{background:var(--strip);border-color:var(--gold)}
.brow .nm{font-weight:600;font-size:14px}
.brow .meta{font-size:11.5px;color:var(--ash-2)}
.ed{background:var(--panel);border:1px solid var(--line);border-radius:16px;padding:16px;min-height:300px}
.ed-head{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:14px}
.ed-name{background:var(--strip);color:var(--gold);border:1px solid var(--line-2);border-radius:9px;padding:9px 12px;font:600 20px/1.1 var(--display);letter-spacing:.03em;min-width:0;flex:1}
.ed-name:disabled{opacity:.8}
.ed-actions{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-left:auto}
.ed-actions .ro{font-size:12px;color:var(--ash);max-width:260px}
[hidden]{display:none!important}          /* a class that sets display beats the attribute otherwise — silently */
.ed-dirty{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin:0 0 14px;padding:11px 14px;border:1px solid var(--gold);border-radius:10px;background:linear-gradient(180deg,rgba(212,167,44,.12),rgba(212,167,44,.05));font-size:13px;color:var(--bone);line-height:1.45}
.ed-dirty b{color:var(--gold)}
.ed-dirty span{flex:1 1 320px;min-width:0}
.ed-dirty .link{white-space:nowrap}
.ed-dirty-acts{display:flex;align-items:center;gap:12px;margin-left:auto;flex-shrink:0}
@media (max-width:640px){.ed-dirty{font-size:12.5px}.ed-dirty button{flex:1 1 auto}}
.ed-actions button,.bl-top button{background:transparent;color:var(--ash);border:1px solid var(--line-2);border-radius:8px;padding:8px 12px;cursor:pointer;font-size:12.5px;letter-spacing:.03em;font-family:inherit}
.ed-actions button:hover,.bl-top button:hover{color:var(--bone);border-color:var(--gold)}
.ed-actions button.primary,.bl-top button.primary{background:var(--gold);color:#1a1405;border-color:var(--gold);font-weight:700}
.ed-actions button.danger:hover{color:var(--stop);border-color:var(--stop)}
.ed-body{display:grid;grid-template-columns:minmax(0,1.3fr) minmax(0,1fr);gap:16px;align-items:start}
.ed-list{display:flex;flex-direction:column;gap:8px}
.ed-row{display:grid;grid-template-columns:auto minmax(0,1fr) auto auto;gap:10px;align-items:center;background:var(--strip);border:1px solid var(--line);border-radius:12px;padding:10px}
.ed-row .pv,.pk-row .pv{background:var(--panel);border:1px solid var(--line-2);color:var(--gold);border-radius:8px;width:36px;height:36px;cursor:pointer;font-size:12px}
.ed-fields{display:flex;flex-direction:column;gap:5px;min-width:0}
.ed-fields input{background:var(--panel);color:var(--bone);border:1px solid var(--line-2);border-bottom-color:var(--line-2);border-radius:7px;padding:7px 9px;font-size:13.5px;font-family:inherit;min-width:0;width:100%;transition:border-color .12s}
.ed-fields input:hover{border-color:#3d4557}
.ed-fields input:focus{border-color:var(--gold);outline:none}
.ed-fields input::placeholder{color:var(--ash-2);font-style:italic}
.ed-fields .f-label{font-weight:600}
.ed-fields .f-src{font-size:11px;color:var(--ash-2)}
.tk-toggle{background:transparent;border:0;color:var(--gold);cursor:pointer;font:inherit;font-size:11px;padding:0}
.tk-toggle:hover{text-decoration:underline}
.takes[hidden]{display:none}
.takes{display:flex;flex-direction:column;gap:3px;margin-top:6px;padding:6px 8px;background:var(--panel);border:1px solid var(--line);border-radius:8px}
.take{display:grid;grid-template-columns:auto auto minmax(0,1fr) auto;gap:8px;align-items:center;font-size:12.5px;cursor:default}
.take .pv{width:26px;height:26px;font-size:10px}
.take .tn{font-weight:600}
.take .tf{color:var(--ash-2);font-size:11px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.take input{accent-color:var(--gold)}
.take.off .tn,.take.off .tf{opacity:.45;text-decoration:line-through}
.take-ro{font-size:11.5px;color:var(--gold);padding:2px 0 4px}
.take input:disabled{opacity:.35}
.f-loop{font-size:12px;color:var(--ash);display:flex;align-items:center;gap:5px;white-space:nowrap}
.f-loop input{accent-color:var(--live)}
.ed-ops{display:flex;gap:4px}
.ed-ops button{background:transparent;border:1px solid var(--line-2);color:var(--ash);border-radius:6px;width:28px;height:28px;cursor:pointer;font-size:11px}
.ed-ops button:hover{color:var(--bone);border-color:var(--gold)}
.ed-ops .rm:hover{color:var(--stop);border-color:var(--stop)}
.ed-picker{background:var(--strip);border:1px solid var(--line);border-radius:12px;padding:12px;position:sticky;top:78px}
.pk-head{font:600 12px/1 var(--display);letter-spacing:.14em;text-transform:uppercase;color:var(--gold);margin-bottom:10px}
.pk-ctl{display:grid;grid-template-columns:1fr 1fr;gap:6px;margin-bottom:8px}
.pk-ctl select,.pk-ctl .dd,.pk-ctl input{background:var(--panel);color:var(--bone);border:1px solid var(--line-2);border-radius:7px;padding:7px 9px;font-size:13px;font-family:inherit;min-width:0}
.pk-list{max-height:60vh;overflow:auto;display:flex;flex-direction:column;gap:4px}
.pk-row{display:grid;grid-template-columns:auto auto minmax(0,1fr) auto;grid-template-areas:"pv ic nm add" "pv ic fm add";column-gap:8px;row-gap:1px;align-items:center;padding:5px 6px;border-radius:8px}
.pk-row .pv{grid-area:pv}.pk-row .ic{grid-area:ic}.pk-row .nm{grid-area:nm}.pk-row .fm{grid-area:fm}.pk-row .add{grid-area:add}
.pk-row:hover{background:var(--panel)}
.pk-row .ic{font-size:16px}
.pk-row .nm{font-size:13.5px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pk-row .fm{font-size:11px;color:var(--ash-2);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.pk-row .add{background:transparent;color:var(--gold);border:1px solid var(--gold);border-radius:6px;padding:5px 10px;font-weight:700;cursor:pointer;font-size:12px;font-family:inherit}
.pk-row .add:hover{background:var(--gold);color:#1a1405}
@media (max-width:1100px){.bl{position:static}.ed-picker{position:static}}
@media (max-width:1100px){.ed-body{grid-template-columns:1fr}.ed-picker{position:static}}
@media (max-width:900px){.builder{grid-template-columns:1fr}}
/* clear the stacked sticky headers when a just-loaded board is scrolled into view. 130px is the
   desktop stack; in a console shell the pane's own sticky bars are the env bar (measured) plus the
   chapter strip, so it is derived rather than guessed. */
.board{scroll-margin-top:130px}
html.console .board{scroll-margin-top:calc(var(--chapstrip-h,74px) + 12px)}
.board.flash{animation:boardflash 1.6s ease-out}
@keyframes boardflash{0%{box-shadow:0 0 0 2px var(--gold)}100%{box-shadow:0 0 0 0 transparent}}
@media (max-width:640px){
  /* Three across, fixed -- auto-fill gave two on a narrow phone and wasted half the width. The tiles
     are tapped mid-game, so they stay tall enough to hit: squarer, not smaller, and the note drops to
     one line because at this size two lines of it was just noise. */
  .bgrid{grid-template-columns:repeat(3,minmax(0,1fr));gap:6px}
  .bb{padding:8px 5px 7px;border-radius:10px;gap:2px;aspect-ratio:auto;min-height:92px}
  .bb .ic{font-size:22px;margin-bottom:0}
  .bb .lb{font-size:11.5px;line-height:1.12;-webkit-line-clamp:2}
  .bb .nt{font-size:9.5px;line-height:1.2;-webkit-line-clamp:1}.nav button{flex:1;text-align:center}.boards-bar select,.boards-bar .dd{flex:1 1 150px;min-width:150px}.boards-bar .load-status{flex-basis:100%;order:5}.ed-row{grid-template-columns:auto minmax(0,1fr);grid-template-areas:"pv fields" "loop ops"}.ed-row .pv{grid-area:pv}.ed-fields{grid-area:fields}.f-loop{grid-area:loop}.ed-ops{grid-area:ops;justify-content:flex-end}}

/* ---------- sections below ---------- */
.section{margin-top:34px}
.section-head{display:flex;align-items:baseline;gap:14px;margin-bottom:12px;cursor:pointer;user-select:none}
.section-head h2{font:600 16px/1 var(--display);letter-spacing:.12em;color:var(--bone);margin:0;text-transform:uppercase}
.section-head .sub{font-size:12.5px;color:var(--ash)}
.section-head .chev{margin-left:auto;color:var(--ash);transition:transform .2s;font-size:12px}
.section.collapsed .chev{transform:rotate(-90deg)}
.section.collapsed .section-body{display:none}
.amb{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:10px}
.amb .slot{background:var(--strip);border:1px dashed var(--line-2);border-radius:12px;padding:12px;display:flex;flex-direction:column;gap:8px}
.amb .slot.on{border-style:solid;border-color:var(--live)}
.amb label{font-size:11.5px;color:var(--ash);letter-spacing:.04em;text-transform:uppercase}
.amb input[type=file]{position:absolute;width:1px;height:1px;opacity:0;pointer-events:none}
.amb .pick-file{display:flex;align-items:center;gap:8px;min-width:0}
.amb .pick-file button{background:transparent;color:var(--ash);border:1px solid var(--line-2);border-radius:8px;padding:6px 10px;cursor:pointer;font-size:12.5px;white-space:nowrap}
.amb .pick-file button:hover{color:var(--bone);border-color:var(--gold)}
.amb .pick-file .fn{font-size:12px;color:var(--ash);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}
.amb .row{display:flex;gap:8px;align-items:center}
.amb .row button{flex:1;background:var(--panel);color:var(--bone);border:1px solid var(--line-2);border-radius:8px;padding:8px;cursor:pointer;font-weight:600}
.amb .row button.on{background:var(--live);border-color:var(--live);color:#052b13}
.amb input[type=range]{width:100%;accent-color:var(--live)}

h3.cat{font:600 11px/1 var(--body);letter-spacing:.22em;text-transform:uppercase;color:var(--gold);margin:22px 0 10px;display:flex;align-items:center;gap:12px}
h3.cat::after{content:"";flex:1;height:1px;background:var(--line)}
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(148px,1fr));gap:10px}
.pad{background:var(--strip);border:1px solid var(--line);border-radius:12px;padding:14px 8px 11px;cursor:pointer;user-select:none;text-align:center;position:relative;min-height:92px;display:flex;flex-direction:column;justify-content:center;gap:5px;
  transition:background .08s,transform .05s,border-color .12s}
.pad:hover{border-color:var(--line-2);background:#151a24}
.pad:active,.pad.playing{background:var(--gold-dim);border-color:var(--gold);transform:scale(.97)}
.pad .ic{font-size:26px;line-height:1;filter:saturate(.8)}
.pad .lb{font-weight:600;font-size:13px;letter-spacing:.01em}
.pad .key{position:absolute;top:6px;right:8px;font-size:10px;color:var(--ash);background:var(--void);border-radius:4px;padding:1px 5px;font-family:ui-monospace,Consolas,monospace}
.pad .n{position:absolute;top:6px;left:8px;font-size:10px;color:var(--ash-2)}
body.nokeys .pad .key{display:none}

.about{max-width:820px;margin:40px auto 0;padding:0 20px;color:var(--ash)}
.about h2{font:600 15px/1.3 var(--display);letter-spacing:.12em;text-transform:uppercase;color:var(--gold);margin:0 0 12px}
.about p{font-size:14px;line-height:1.6;margin:0 0 12px}
.about strong{color:var(--bone);font-weight:600}
.about a{color:var(--gold)}
footer{color:var(--ash);font-size:11.5px;padding:26px 20px;text-align:center;border-top:1px solid var(--line);line-height:1.6;max-width:900px;margin:0 auto}
footer a{color:var(--ash)}

/* ---------- modal ---------- */
.modal[hidden]{display:none!important}
.modal{position:fixed;inset:0;background:rgba(6,8,12,.7);display:flex;align-items:center;justify-content:center;z-index:50;backdrop-filter:blur(3px)}
.modal-box{background:var(--panel);border:1px solid var(--gold);border-radius:16px;padding:22px 24px;width:min(440px,92vw);box-shadow:0 30px 80px rgba(0,0,0,.7)}
.modal-title{font:600 17px/1.2 var(--display);letter-spacing:.04em;color:var(--gold);margin-bottom:10px}
.modal-body{font-size:14px;color:var(--bone);margin-bottom:14px;line-height:1.5}
.modal-input{width:100%;background:var(--void);color:var(--bone);border:1px solid var(--line-2);border-radius:9px;padding:11px 13px;font-size:15px;margin-bottom:16px;outline:none;font-family:inherit}
.modal-input:focus{border-color:var(--gold)}
.modal-extra{margin-bottom:14px;min-height:1px}
.rp-form{display:flex;flex-direction:column;gap:6px;text-align:left}
.rp-l{font-size:12px;color:var(--ash);letter-spacing:.02em}
.rp-opt{color:var(--ash-2);font-size:11px}
.rp-sel,.rp-note,.rp-mail{width:100%;background:var(--void);color:var(--bone);border:1px solid var(--line-2);border-radius:8px;padding:9px 11px;font:inherit;font-size:14px;outline:none}
.rp-sel:focus,.rp-note:focus,.rp-mail:focus{border-color:var(--gold)}
.rp-note{resize:vertical}
.pk-row .rp{background:transparent;border:0;color:var(--ash-2);cursor:pointer;font-size:15px;line-height:1;padding:6px 8px;border-radius:7px;opacity:.5;transition:opacity .15s,color .15s}
.pk-row:hover .rp,.pk-row .rp:focus-visible{opacity:1}
.pk-row .rp:hover{color:var(--stop);background:rgba(192,57,43,.12)}
@media (pointer:coarse){.pk-row .rp{opacity:.8;min-width:40px;min-height:40px}}
.modal-actions{display:flex;gap:8px;justify-content:flex-end}
.modal-actions button{border:0;border-radius:9px;padding:10px 20px;font-weight:700;cursor:pointer;background:var(--gold);color:#1a1405;letter-spacing:.03em}
.modal-actions button.secondary{background:var(--line-2);color:var(--bone)}
.modal-actions button.danger{background:var(--stop);color:#fff}

:focus-visible{outline:2px solid var(--gold);outline-offset:2px}
@media (prefers-reduced-motion:reduce){.env.on::before{animation:none}*{transition:none!important}}
@media (max-width:1100px){.layers{grid-template-columns:repeat(2,minmax(0,1fr))}}
.panic-float{display:none}
.tabbar{display:none}                      /* console shells only; the header nav does this on a desktop */
.env-more{display:none}

/* ---------- console shell ---------- */
/* Phone, tablet and the installed app get a fixed frame: the chrome never moves, and the screen you
   are on scrolls inside it. A desktop browser keeps the document scroll and is left alone. Which shape
   you get is decided once, by the script in the head, and written onto <html>.

   Built out of flex and nothing else. Nothing in this section may use `transform`: dropdown.js hangs
   its menus off <html> and envs.js hangs the tweak scrim off <body> *precisely* so a transformed
   ancestor cannot displace them, and a transform on the shell would reproduce the bug those two
   comments exist to describe. Same reason the tab bar lost its backdrop-filter, which also creates a
   containing block for fixed descendants -- and with a static bar there is nothing behind it to blur. */
html.console,html.console body{height:100%;overflow:hidden}
html.console body{display:flex;flex-direction:column}
/* The tab bar sits before <main> in the source, so keyboard focus reaches it early; order puts it last
   on screen. */
html.console .top{order:1;flex:0 0 auto;position:static}
html.console main{order:3;flex:1 1 auto;min-height:0;display:flex;flex-direction:column;max-width:none;margin:0;padding:0}
html.console main > div{flex:1 1 auto;min-height:0;overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;padding:16px}
/* No top padding on Session. A sticky element cannot rise above its containing block, which is the
   pane CONTENT box -- so with padding-top the chapter strip stuck 16px down and scrolled board tiles
   showed through the band above it. The strip provides its own spacing instead. */
html.console #viewSession{padding-top:0}
html.console .tabbar{order:4;flex:0 0 auto;display:flex;position:static;z-index:46;
  padding:0 4px calc(env(safe-area-inset-bottom,0px));
  background:rgba(11,13,18,.97);border-top:1px solid var(--line)}
html.console .tabbar button{flex:1;min-width:0;min-height:56px;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
  background:none;border:0;color:var(--ash);font:600 10px/1 "Source Sans 3",sans-serif;letter-spacing:.04em;padding:8px 2px;cursor:pointer}
/* The board editor ends 16px after its last row, which is fine on a desktop where the nav is at the
   top. In a console shell the tab bar is 57px of chrome at the bottom of the same column, so the
   final rows -- in practice the report button on the last sound in the picker -- finish underneath
   it with the view already scrolled as far as it goes. Reserve the bar height. */
html.console .ed{padding-bottom:72px}
/* On a phone the picker had its own scrollbar inside the page's scrollbar, and because its height
   was budgeted from the viewport rather than from where it actually starts, the bottom of the list
   kept landing under the tab bar -- the report button on the last row could not be reached at all.
   Any vh cap overshoots for the same reason, so the nested scroller goes away instead: the editor
   scrolls as one, which is what a phone wants, and .ed's bottom padding guarantees the last row
   clears the bar. The search box above the list is what makes a long list workable this way. */
html.console .pk-list{max-height:none;overflow:visible}
html.console .tabbar button .ti{font-size:17px;line-height:1}
html.console .tabbar button .tl{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
html.console .tabbar button.on{color:var(--gold)}
html.console .tabbar button.on .ti{filter:drop-shadow(0 0 8px rgba(212,167,44,.5))}
html.console .tabbar button:active{background:rgba(255,255,255,.05)}
/* The documentation links on More. Each is a row with a heading and a line of what is behind it,
   because "Docs" on its own tells someone who has never opened them nothing about why they would. */
.more-links{display:flex;flex-direction:column;gap:8px;margin:0 0 14px}
.more-links a{display:block;text-decoration:none;padding:10px 12px;border:1px solid var(--line);border-radius:10px;background:var(--strip)}
.more-links a:active{border-color:var(--gold)}
.more-links b{display:block;color:var(--gold);font:600 14px/1.2 "Source Sans 3",sans-serif}
.more-links span{display:block;color:var(--ash);font-size:12.5px;line-height:1.45;margin-top:3px}
.vfoot{margin:10px 2px 0;font-size:13px;color:var(--ash)}
.vfoot a{color:var(--gold)}
html.console .tabbar .tb-stop{color:var(--ash);flex:0 0 22%;opacity:.55}
html.console .tabbar .tb-stop.live{color:#e7796b;opacity:1}
html.console .tabbar .tb-stop:active{color:#fff;background:var(--stop)}
html.console .nav{display:none}            /* the bottom bar owns screen switching */
html.console .panic-float{display:none}
/* The toast is position:fixed, so it is placed against the VIEWPORT -- the tab bar being a flex child
   rather than fixed changes nothing about the 56px of screen it occupies at the bottom. Dropping this
   to 16px put the toast on top of the bar and swallowed the Environments tab. 56px bar + 16px gap,
   and the bar's own safe-area padding on top of that. */
html.console .nudge{bottom:calc(72px + env(safe-area-inset-bottom,0px))}
/* Credits, docs and privacy move to the More screen. The markup stays in the document, so a crawler
   -- desktop, fine pointer, never console -- still sees it. */
html.console body > footer{display:none}
/* Installed there is no website left to show: no masthead, and no link out of the shell. */
html.app .top{display:none}
/* The seven-minute tour streams 79 MB from the site, so it is dead weight in an app whose premise is
   that it needs no connection -- offline the modal has nothing to play at all. Hidden rather than
   removed, because app.html wires $("#howto") unguarded and would throw on a missing node. Targets
   the id, not .howto: the Feedback button shares that class and stays. */
html.app #howto{display:none}

/* Now Playing. The script at the foot of app.html lifts #env out of the Session view and makes it a
   child of <body>, so what is playing stays on screen while you are editing a board. As shell chrome
   it is a plain flex child -- not sticky, not fixed, not in anyone's scroll area -- which is what
   keeps it out of the stacking-context trap the section header describes. z-index 47 is the one free
   slot above the tab bar (46) and the tweak sheet (45) and below the modal (50). */
/* position stays `relative`: .env::before is the absolutely-positioned watermark, and with the bar
   static it reparented to the viewport and painted a 520px sigil across the whole screen, outside the
   card's overflow:hidden. */
html.console .env{order:2;flex:0 0 auto;position:relative;z-index:47;margin:0;
  padding:10px 12px;border-radius:0;border-width:0 0 1px;box-shadow:none}
/* Installed, this is the topmost thing on the screen, so it owns the notch. */
html.app .env{padding-top:calc(10px + env(safe-area-inset-top,0px))}
/* With the bar lifted out, the chapter strip is the top of the pane and sticks to it directly --
   --envbar-h is no longer its offset (it is still measured, for the non-console path). */
html.console .chapters{position:sticky;top:0;z-index:19;margin:0 -16px 10px;padding:7px 12px;border-radius:0}
/* board titles stack under the strip rather than at the desktop masthead's 62px */
html.console .board-head{top:var(--chapstrip-h,74px)}
/* STOP, relocated out of the screen switcher to sit beside PLAY. */
html.console .env-head .tb-stop{flex:none;display:flex;align-items:center;justify-content:center;
  width:44px;min-height:44px;padding:0;gap:0;background:none;border:1px solid var(--line);
  border-radius:10px;color:var(--ash-2);font-size:13px;cursor:pointer;opacity:.55}
html.console .env-head .tb-stop .tl{display:none}
html.console .env-head .tb-stop.live{color:#e7796b;border-color:#e7796b;opacity:1}
html.console .env-head .tb-stop:active{background:var(--stop);color:#fff;border-color:var(--stop)}
html.console .chapters .env-eyebrow{font-size:9px;margin-bottom:4px}
html.console .chapters .ch-hint{display:none}   /* the explainer is for the desktop first run, not mid-game */
html.console .ch-chips{display:flex;gap:6px;overflow-x:auto;scrollbar-width:none;-webkit-overflow-scrolling:touch;padding-bottom:2px}
html.console .ch-chips::-webkit-scrollbar{display:none}
html.console .ch-chips .ch-chip{flex:0 0 auto;min-height:36px}
html.console .boards-area{margin-top:12px}
html.console #secOwn{margin-top:18px}
/* Collapsed to one line: what is playing, play/stop, and a chevron. The rest appears when you open it. */
html.console .env-head{display:flex;align-items:center;gap:8px;flex-wrap:nowrap}
html.console .env-head > div:first-child{min-width:0;flex:1}
html.console .env-name{font-size:16px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
html.console .env .env-eyebrow{display:none}
/* The PLAY button already reads "STOP" while it is running, so the word beside it is saying the same
   thing twice -- and at 390px it was costing the environment name enough room to truncate it. The
   editor's copy (#envLive2) is untouched; it has the space and no button beside it. */
html.console .env .env-live{display:none}
html.console .env-play{width:auto;flex:none;padding:9px 13px;font-size:12px;min-height:44px}
html.console .env-more{display:flex;align-items:center;justify-content:center;flex:none;width:44px;min-height:44px;
  background:none;border:1px solid var(--line);border-radius:10px;color:var(--ash);font-size:13px;cursor:pointer}
html.console .env-more[aria-expanded="true"]{transform:rotate(180deg);color:var(--gold);border-color:var(--gold)}
html.console .env:not(.open) .env-presets,html.console .env:not(.open) .env-summary{display:none}
html.console .env.open .env-presets{margin:8px 0 0;width:100%;display:grid;grid-template-columns:1fr;gap:6px}
html.console .env.open .env-presets select,html.console .env.open .env-presets .dd{grid-column:1/-1;min-width:0;width:100%}
html.console .env.open .env-summary{display:flex;flex-direction:column;align-items:flex-start;margin-top:8px}
html.console .env.open .env-summary .link{margin-left:0}
html.console .env.open .env-chips{width:100%}
/* ---- More ---- */
/* The controls in here arrived from the masthead and the footer, where they were laid out as a tight
   horizontal strip. Unpick that: full width, stacked, thumb-sized. */
html.console #viewMore{display:flex;flex-direction:column;gap:22px}
html.console .more-sec{display:flex;flex-direction:column;align-items:flex-start;gap:10px;
  background:var(--panel);border:1px solid var(--line);border-radius:14px;padding:14px 16px 16px}
html.console .more-sec h2{margin:0;font:600 11px/1 var(--display);letter-spacing:.14em;
  text-transform:uppercase;color:var(--gold)}
html.console .more-sec .howto{min-height:44px}
html.console .more-sec .fbtn span{display:inline}      /* the header hid the word to save room; there is room here */
html.console .more-sec .ctl{display:flex;align-items:center;gap:12px;width:100%;font-size:14px}
html.console .more-sec .ctl input{flex:1;min-width:0;width:auto}
html.console .more-sec .acct{border:0;padding:0;margin:0}
html.console #moreAbout footer{display:block;max-width:none;margin:0;padding:0;border:0;text-align:left}
/* everything that was in here has moved to More; STOP lives in the Now Playing bar */
html.console .top-ctl{display:none}

/* the environment sits above the chapter strip, then the boards, whatever the DOM order is */
html.console #viewSession{display:flex;flex-direction:column}
/* The pane has a definite height, so flex items would rather shrink than overflow it -- which crushed
   the environment bar to a sliver with its PLAY button sliced off. Nothing in here shrinks; the pane
   scrolls instead. */
html.console #viewSession > *{flex:0 0 auto}
html.console #viewSession > .env{order:1}html.console #viewSession > .chapters{order:2}
html.console #viewSession > .boards-area{order:3}html.console #viewSession > #secOwn{order:4}

/* ---- tablet landscape, in a console shell ---- */
/* The Fire tablet is the Amazon build's only target and a propped-up iPad is how this gets used at a
   table, yet 641-899px had no layout of its own: it fell through to the desktop rules inside a console
   frame. Session splits into a rail and a board field, so the boards -- the thing tapped every thirty
   seconds -- get the whole right-hand side instead of sitting below a fold.
   Gated on html.console, so a desktop browser at this width is untouched. */
@media (min-width:760px){
  /* Three rows, not two: the board column spans all of them, so its height is shared out across the
     rows rather than stretching row 1. With only two rows the boards made row 1 as tall as themselves
     and shoved "your own tracks" ~1300px down the rail, behind a screen of dead space. The trailing
     1fr row soaks up whatever the boards need beyond the two rail items. */
  html.console #viewSession{display:grid;grid-template-columns:minmax(260px,320px) 1fr;
    grid-template-rows:auto auto 1fr;gap:16px;align-content:start}
  /* the rail holds what you set once per scene; it stays put while the boards scroll */
  html.console #viewSession > .chapters{grid-column:1;grid-row:1;position:sticky;top:0;align-self:start;margin:0}
  html.console #viewSession > #secOwn{grid-column:1;grid-row:2;margin-top:0;align-self:start}
  html.console #viewSession > .boards-area{grid-column:2;grid-row:1/-1;margin-top:0;min-width:0}
  /* the editors' own sticky columns were offset for the desktop masthead; in a pane the top is 0 */
  html.console .bl,html.console .ed-picker{top:0}
  /* the rail is ~280px and this header was laid out as a full-width row, so it broke "YOUR OWN
     TRACKS" across three lines */
  html.console #viewSession > #secOwn .section-head{flex-wrap:wrap;gap:4px 8px}
  html.console #viewSession > #secOwn .section-head h2{font-size:12px;letter-spacing:.08em}
  html.console #viewSession > #secOwn .section-head .sub{font-size:11px}
}

@media (max-width:640px){
  .layers{grid-template-columns:1fr}
  /* The layer name's flex-basis is auto and its text does not wrap, so on a narrow screen it claimed the
     whole row and bumped the remove button onto a line of its own, floating under the toggle. Basis 0
     lets it take what is left instead of demanding what it wants. */
  .layer-head .lname{flex:1 1 0}
  .layer-head .lc{flex:0 0 auto;min-width:34px;min-height:34px}
  .layer-head .lrm{flex:0 0 auto;min-width:44px;min-height:44px;display:flex;align-items:center;justify-content:center}
  /* Phone header: two rows -- [brand] then [tour, feedback, master, sign in]. The screen switcher is
     NOT here; it lives in the bottom bar, within thumb reach. These must WRAP: forced onto one nowrap
     row the controls need ~529px, and rather than overflow, Chromium widens the layout viewport to fit
     them and zooms the whole app out on a real phone. Installed, the header is gone and this cannot
     arise -- but the same CSS serves a phone browser, where it still can. */
  .top{position:static}
  .top-in{padding:8px 12px;gap:6px 10px;flex-wrap:wrap}.brand .tag{display:none}.brand .word{font-size:17px}.brand img{width:30px;height:30px}
  .top-ctl{margin-left:0;width:100%;gap:6px;justify-content:space-between;flex-wrap:nowrap;min-width:0}
  .top-ctl .ctl{font-size:12px;gap:5px;min-width:0;flex:0 1 auto}.top-ctl .ctl input{width:64px;min-width:0}
  .acct{flex:none}
  .howto{padding:6px 8px;font-size:12px;flex:none}.fbtn span{display:none}
  .top-ctl .panic{display:none}
  .nav{display:none}
  .panic-float{display:none}
  /* Only reachable with ?mode=off, since a phone is always a console shell. Kept as a sane fallback. */
  main{padding:16px 16px 20px}
  footer{padding:22px 16px calc(84px + env(safe-area-inset-bottom,0px))}
  .grid{grid-template-columns:repeat(auto-fill,minmax(112px,1fr))}.pad .ic{font-size:22px}.pad .lb{font-size:12px}.pad .key{display:none}
}

/* ---- Listen along: the GM's Broadcast button + sheet (broadcast.js) ---- */
.bcast-btn.on{border-color:var(--live);color:var(--bone)}
.bcast-btn .dot{display:inline-block;width:8px;height:8px;border-radius:50%;background:var(--live);box-shadow:0 0 0 3px rgba(63,174,107,.25);vertical-align:1px;animation:bcPulse 1.6s ease-in-out infinite}
@keyframes bcPulse{50%{box-shadow:0 0 0 6px rgba(63,174,107,0)}}
@media (prefers-reduced-motion:reduce){.bcast-btn .dot{animation:none}}
/* 49: over the chapter menu (48), under the modal (50) -- its "Stop broadcasting?" confirm must land on top */
.bcast-sheet{position:fixed;z-index:49;right:16px;top:70px;width:min(380px,calc(100vw - 32px));background:var(--panel);border:1px solid var(--line-2);border-radius:14px;padding:14px 16px 16px;box-shadow:0 24px 60px rgba(0,0,0,.55)}
html.console .bcast-sheet{top:auto;bottom:calc(76px + env(safe-area-inset-bottom));left:16px;right:16px;width:auto}
.bcast-sheet[hidden]{display:none}
.bc-head{display:flex;align-items:center;justify-content:space-between;font:600 13px/1 var(--display);letter-spacing:.14em;text-transform:uppercase;color:var(--gold);margin-bottom:10px}
.bc-x{background:transparent;border:1px solid var(--line-2);color:var(--ash);border-radius:7px;width:44px;height:44px;cursor:pointer;font-size:14px}
.bc-lede{margin:0 0 10px;color:var(--bone)}
.bc-note{margin:10px 0 12px;color:var(--ash);font-size:13px}
.bc-code{font:600 40px/1 var(--display);letter-spacing:.12em;color:var(--gold);text-align:center;padding:10px 0;user-select:all}
.bc-link{display:flex;gap:8px}
.bc-link input{flex:1;min-width:0;background:var(--strip);border:1px solid var(--line-2);color:var(--bone);border-radius:8px;padding:10px;font:inherit;font-size:13px}
.bc-copy,.bc-start,.bc-stop{border-radius:8px;padding:10px 14px;font:600 14px/1 var(--body);cursor:pointer;min-height:44px}
.bc-or{display:flex;align-items:center;gap:10px;margin:16px 0 12px;color:var(--ash-2);font-size:11.5px;letter-spacing:.14em;text-transform:uppercase}
.bc-or::before,.bc-or::after{content:"";flex:1;height:1px;background:var(--line)}
.bc-join{display:flex;gap:8px;margin-top:8px}
.bc-join input{flex:1;min-width:0;background:var(--void);color:var(--bone);border:1px solid var(--line-2);border-radius:9px;padding:10px 13px;font:inherit;font-size:19px;letter-spacing:.3em;text-align:center;outline:none}
.bc-join input:focus{border-color:var(--gold)}
.bc-join button{background:var(--gold);color:#1a1405;border:0;border-radius:8px;padding:10px 20px;font:600 14px/1 var(--body);cursor:pointer;min-height:44px;white-space:nowrap}
.bc-err{color:var(--stop);font-size:12.5px;margin:7px 0 0;min-height:1em}
.bc-copy{background:var(--gold);color:#1a1405;border:0;white-space:nowrap}
.bc-start{width:100%;background:var(--gold);color:#1a1405;border:0}
.bc-stop{width:100%;background:transparent;color:var(--bone);border:1px solid var(--stop)}
.bc-count{margin:10px 0 0;color:var(--live);font-weight:600}
#moreBcast .bcast-btn{width:100%;min-height:44px;font-size:14px}
