aboutsummaryrefslogtreecommitdiff
path: root/docs/prototypes/panel-widget-gallery.html
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-07-11 23:07:32 -0500
committerCraig Jennings <c@cjennings.net>2026-07-11 23:07:32 -0500
commit18d4b33e9338fac2a316f51a479574db07d7cedc (patch)
treebc7054b1937de9f557a2d2d3d025da80568a2ea0 /docs/prototypes/panel-widget-gallery.html
parent5fdded5daccc5df5d56af080cbe79b294aac436f (diff)
downloadarchsetup-18d4b33e9338fac2a316f51a479574db07d7cedc.tar.gz
archsetup-18d4b33e9338fac2a316f51a479574db07d7cedc.zip
fix(gallery): repair broken widgets, standardize pulses, retune to amber
I wrapped the status-lamp and jewel-pilot indicators in an inline-flex row so they render. Their sub-elements were bare inline spans, so the fixed width/height were ignored and the widgets collapsed to empty stages. The other multi-element widgets already use this pattern. The transport cluster looked dead because the reel spokes were near-black on a near-black reel, so the rotation was invisible. Steel spokes plus one amber index spoke make the spin legible. The button logic was already correct. All pulses now run at 1s ease-in-out. The busy lamp was 0.7s, fast enough to read as a flash rather than a pulse. I marked 1s as the standard cadence so new widgets inherit it. I shifted the gold accent to a warm amber across the tokens, glow colors, and lit gradients together, so nothing stays yellow next to amber. I removed the magic-eye tube, dropped from the instrument-panel design that draws from this gallery. I renamed the file to panel-widget-gallery.html (the living catalogue now, not a dated prototype) and updated the two inbound links.
Diffstat (limited to 'docs/prototypes/panel-widget-gallery.html')
-rw-r--r--docs/prototypes/panel-widget-gallery.html1111
1 files changed, 1111 insertions, 0 deletions
diff --git a/docs/prototypes/panel-widget-gallery.html b/docs/prototypes/panel-widget-gallery.html
new file mode 100644
index 0000000..5f1dcf3
--- /dev/null
+++ b/docs/prototypes/panel-widget-gallery.html
@@ -0,0 +1,1111 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<title>Panel widget gallery — dupre instrument console (interactive)</title>
+<style>
+:root{
+ --ground:#151311; --panel:#100f0f; --well:#0a0c0d; --raise:#1a1917;
+ --gold:#e2a038; --gold-hi:#ffbe54; --silver:#bfc4d0; --cream:#f3e7c5;
+ --steel:#969385; --dim:#7c838a; --slate:#424f5e; --slate-hi:#54677d;
+ --wash:#2c2f32; --pass:#74932f; --fail:#cb6b4d;
+ --mono:"BerkeleyMono Nerd Font","Berkeley Mono",monospace;
+ --phos:#7fe0a0; --phos-dim:#1c3626; --vfd:#63e6c8; --sevgrn:#57d357; --sevred:#e2543f;
+ --sevoff:#1a1613; --jewel-r:#ff5b45; --jewel-a:#ffb43a; --jewel-g:#6fce33;
+}
+*{box-sizing:border-box;margin:0;padding:0}
+html{background:var(--ground)}
+body{font-family:var(--mono);color:var(--silver);padding:2.4rem 2rem 5rem;line-height:1.45;
+ background:radial-gradient(1200px 600px at 70% -10%,#1c1915 0%,transparent 60%),var(--ground)}
+.wrap{max-width:1320px;margin:0 auto}
+.eyebrow{color:var(--steel);font-size:.72rem;letter-spacing:.28em;text-transform:uppercase}
+h1{color:var(--gold);font-size:1.5rem;margin:.35rem 0 .4rem}
+.masthead p{color:var(--dim);font-size:.86rem;max-width:86ch}
+.masthead p b{color:var(--silver)}
+h2{color:var(--steel);font-size:.74rem;letter-spacing:.24em;text-transform:uppercase;
+ margin:2.2rem 0 .2rem;display:flex;align-items:center;gap:12px}
+h2::after{content:"";height:1px;background:var(--wash);flex:1}
+
+.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(232px,1fr));gap:14px;margin-top:1rem}
+.card{background:linear-gradient(180deg,var(--raise),var(--panel));border:1px solid #262320;border-radius:12px;
+ padding:13px 14px 12px;display:flex;flex-direction:column;gap:9px;
+ box-shadow:inset 0 1px 0 rgba(255,255,255,.04),0 6px 14px rgba(0,0,0,.4)}
+.wname{color:var(--cream);font-size:.82rem;font-weight:700;display:flex;align-items:center;gap:8px}
+.wname .no{color:var(--panel);background:var(--gold);border-radius:4px;font-size:.6rem;padding:0 5px;font-weight:400}
+.stagew{background:var(--well);border:1px solid #201d17;border-radius:9px;padding:14px 12px;
+ min-height:78px;display:flex;align-items:center;justify-content:center;gap:12px;flex-wrap:wrap}
+.wrd{color:var(--gold-hi);font-size:.68rem;letter-spacing:.06em;font-variant-numeric:tabular-nums;
+ min-height:.95rem;display:flex;align-items:center;gap:6px}
+.wrd::before{content:"▸";color:var(--steel);font-size:.6rem}
+.wnote{color:var(--dim);font-size:.72rem;line-height:1.4}
+.wnote b{color:var(--steel);font-weight:400}
+
+/* ---- shared primitives ---- */
+.lamp{width:9px;height:9px;border-radius:50%;background:var(--pass);box-shadow:0 0 6px 1px rgba(116,147,47,.55)}
+.lamp.gold{background:var(--gold);box-shadow:0 0 6px 1px rgba(226,160,56,.6)}
+.lamp.red{background:var(--fail);box-shadow:0 0 6px 1px rgba(203,107,77,.55)}
+.lamp.off{background:var(--wash);box-shadow:none}
+.lamp.busy{background:var(--gold);animation:pulse 1s ease-in-out infinite}
+/* standard pulse: 1s ease-in-out — the norm for every pulsing / flashing element */
+@keyframes pulse{50%{opacity:.25}}
+
+.switch{width:40px;height:21px;border-radius:11px;background:var(--wash);border:1px solid var(--slate);
+ position:relative;cursor:pointer}
+.switch::after{content:"";position:absolute;top:2px;left:2px;width:15px;height:15px;border-radius:50%;
+ background:var(--dim);transition:left .15s}
+.switch.on{background:var(--slate);border-color:var(--gold)}
+.switch.on::after{left:21px;background:var(--gold)}
+.switch.red{background:rgba(203,107,77,.2);border-color:var(--fail)}
+.switch.red::after{background:var(--fail);left:2px}
+
+.key{font:inherit;font-size:11.5px;letter-spacing:.06em;color:var(--silver);cursor:pointer;
+ background:linear-gradient(180deg,#23211e,#191715);border:1px solid #33302b;border-bottom-color:#0c0b0a;
+ border-radius:8px;padding:8px 12px;box-shadow:inset 0 1px 0 rgba(255,255,255,.04),0 2px 3px rgba(0,0,0,.4)}
+.key:hover{color:var(--gold);border-color:var(--gold)}
+.key:active{transform:translateY(1px)}
+.key.on{color:var(--panel);background:linear-gradient(180deg,#f2c76a,var(--gold));border-color:var(--gold-hi);font-weight:700}
+.key.red{color:var(--cream);background:linear-gradient(180deg,#d98a6f,var(--fail));border-color:var(--fail)}
+.key.off{opacity:.4}
+
+.chip{color:var(--dim);cursor:pointer;border-bottom:1px dotted var(--wash);font-size:12px}
+.chip.on{color:var(--gold);border-color:var(--gold)}
+
+.badge{font-size:.62rem;letter-spacing:.18em;color:var(--panel);background:var(--gold);border-radius:4px;padding:1px 6px}
+.badge.red{background:var(--fail);color:var(--cream)}
+.badge.ghost{background:transparent;border:1px solid var(--slate);color:var(--silver)}
+
+/* fader */
+.fader{width:150px;height:16px;position:relative;cursor:pointer;touch-action:none}
+.fader .slot{position:absolute;top:6px;left:0;right:0;height:4px;border-radius:2px;background:#0d0f10;border:1px solid #231f18;overflow:hidden}
+.fader .fill{position:absolute;top:0;left:0;bottom:0;background:linear-gradient(90deg,#8f671f,var(--gold))}
+.fader .cap{position:absolute;top:1px;width:7px;height:14px;border-radius:2px;margin-left:-3.5px;
+ background:linear-gradient(180deg,#f2c76a,#d29638);border:1px solid #7d5c16;box-shadow:0 1px 2px rgba(0,0,0,.5)}
+/* vertical fader */
+.vfader{width:16px;height:64px;position:relative;cursor:pointer;touch-action:none}
+.vfader .slot{position:absolute;left:6px;top:0;bottom:0;width:4px;border-radius:2px;background:#0d0f10;border:1px solid #231f18;overflow:hidden}
+.vfader .fill{position:absolute;left:0;right:0;bottom:0;background:linear-gradient(0deg,#8f671f,var(--gold))}
+.vfader .cap{position:absolute;left:1px;height:7px;width:14px;border-radius:2px;margin-top:-3.5px;
+ background:linear-gradient(90deg,#d29638,#f2c76a);border:1px solid #7d5c16}
+
+/* rotary knob */
+.knob{width:52px;height:52px;border-radius:50%;position:relative;cursor:ns-resize;touch-action:none;
+ background:radial-gradient(circle at 40% 35%,#2a2622,#141210);border:1px solid #3a352c;
+ box-shadow:inset 0 2px 3px rgba(255,255,255,.05),0 3px 6px rgba(0,0,0,.5)}
+.knob .ind{position:absolute;left:50%;top:5px;width:2px;height:16px;background:var(--gold-hi);
+ margin-left:-1px;transform-origin:50% 21px;border-radius:1px;box-shadow:0 0 5px rgba(255,190,84,.6)}
+
+/* needle gauge */
+.gauge{width:96px;cursor:ns-resize;touch-action:none}
+.gauge .dial{position:relative;height:48px;overflow:hidden}
+.gauge .arc{position:absolute;inset:0 0 -48px 0;border:2px solid var(--wash);border-radius:50%}
+.gauge .tk{position:absolute;left:50%;bottom:0;width:1.5px;height:8px;background:var(--steel);transform-origin:50% 48px}
+.gauge .ndl{position:absolute;left:50%;bottom:0;width:2px;height:40px;background:var(--gold-hi);
+ transform-origin:50% 100%;transform:rotate(0deg);border-radius:2px;box-shadow:0 0 6px rgba(255,190,84,.5);
+ transition:transform .12s cubic-bezier(.3,1.3,.5,1)}
+.gauge .hub{position:absolute;left:50%;bottom:-4px;width:8px;height:8px;margin-left:-4px;border-radius:50%;background:var(--gold)}
+.gauge .gv{color:var(--cream);text-align:center;font-size:12px;font-weight:700;margin-top:5px;font-variant-numeric:tabular-nums}
+
+/* segmented VU / LED bar */
+.vu{width:170px;display:flex;flex-direction:column;gap:5px}
+.vurow{display:flex;align-items:center;gap:7px}
+.vurow .ch{color:var(--steel);font-size:.6rem;width:8px}
+.vubar{flex:1;display:flex;gap:2px;height:9px}
+.vubar i{flex:1;background:var(--wash);border-radius:1px;opacity:.3}
+.vubar i.on{opacity:1;background:var(--pass)}.vubar i.hot{opacity:1;background:var(--gold)}
+.vubar i.clip{opacity:1;background:var(--fail)}.vubar i.peak{outline:1px solid var(--gold-hi);outline-offset:-1px}
+
+/* mini 4-bar signal */
+.sig{display:flex;align-items:flex-end;gap:2px;height:18px}
+.sig i{width:4px;background:var(--wash);border-radius:1px}
+.sig i:nth-child(1){height:5px}.sig i:nth-child(2){height:9px}.sig i:nth-child(3){height:13px}.sig i:nth-child(4){height:17px}
+.sig i.on{background:var(--pass)}.sig i.hot{background:var(--gold)}.sig i.clip{background:var(--fail)}
+
+/* signal ladder (wifi bars) */
+.ladder{display:inline-flex;gap:3px;align-items:flex-end;height:18px;cursor:pointer}
+.ladder i{width:5px;background:var(--wash);border-radius:1px}
+.ladder i:nth-child(1){height:6px}.ladder i:nth-child(2){height:10px}
+.ladder i:nth-child(3){height:14px}.ladder i:nth-child(4){height:18px}
+
+/* linear progress / fuel bar */
+.bar{width:160px;height:12px;background:#0d0f10;border:1px solid #231f18;border-radius:6px;overflow:hidden;position:relative;cursor:pointer;touch-action:none}
+.bar>span{position:absolute;left:0;top:0;bottom:0;background:linear-gradient(90deg,#8f671f,var(--gold));border-radius:6px}
+.bar.warn>span{background:linear-gradient(90deg,#a35a3f,var(--fail))}
+
+/* radial ring */
+.ring{width:60px;height:60px;border-radius:50%;cursor:ns-resize;touch-action:none;
+ background:conic-gradient(var(--gold) calc(var(--p)*1%),var(--wash) 0);
+ display:grid;place-items:center;position:relative}
+.ring::before{content:"";position:absolute;inset:6px;border-radius:50%;background:var(--well)}
+.ring b{position:relative;color:var(--cream);font-size:12px;font-weight:700;font-variant-numeric:tabular-nums}
+
+/* tabular readout */
+.readout{color:var(--cream);font-size:24px;font-weight:700;font-variant-numeric:tabular-nums;letter-spacing:.04em;cursor:pointer}
+.readout small{color:var(--dim);font-size:12px;font-weight:400}
+.readout .u{color:var(--steel);font-size:.6rem;letter-spacing:.2em;display:block;text-align:center;margin-top:2px}
+
+/* sparkline */
+.spark{width:170px;height:44px}
+.spark svg{display:block;width:100%;height:100%}
+
+/* lamp row (list item) */
+.lrow{width:190px;display:flex;align-items:center;gap:9px;padding:6px 8px;border-radius:7px;background:#141210;cursor:pointer;font-size:12.5px}
+.lrow:hover{background:var(--wash)}
+.lrow .who{color:var(--silver)}.lrow .who b{color:var(--cream)}
+.lrow .what{margin-left:auto;color:var(--dim);font-size:11px}
+
+/* arm-to-fire */
+.arm{font:inherit;font-size:11.5px;color:var(--silver);cursor:pointer;background:#191715;border:1px solid #33302b;
+ border-radius:8px;padding:7px 12px}
+.arm.armed{background:rgba(203,107,77,.12);border-color:var(--fail);color:var(--fail)}
+
+/* stepper / segmented selector */
+.seg{display:flex;border:1px solid #33302b;border-radius:8px;overflow:hidden}
+.seg button{font:inherit;font-size:11px;color:var(--silver);background:#191715;border:0;border-right:1px solid #33302b;padding:7px 11px;cursor:pointer}
+.seg button:last-child{border-right:0}
+.seg button.on{background:linear-gradient(180deg,#f2c76a,var(--gold));color:var(--panel);font-weight:700}
+
+/* engraved section label */
+.engrave{width:180px;color:var(--steel);font-size:.62rem;letter-spacing:.3em;text-transform:uppercase;cursor:pointer;
+ display:flex;align-items:center;gap:9px}
+.engrave::before,.engrave::after{content:"";height:1px;background:var(--wash);flex:1}
+.engrave::before{max-width:10px}
+.engrave .cnt{color:var(--dim);letter-spacing:.1em;text-transform:none}
+
+/* waveform strip */
+.wave{width:170px;height:38px}
+.wave svg{width:100%;height:100%;display:block}
+
+/* toast */
+.toastw{font-size:11px;color:var(--cream);background:var(--slate);border-radius:7px;padding:5px 10px;cursor:pointer}
+
+/* output well (log step) */
+.owell{width:200px;background:var(--well);border:1px solid var(--wash);border-radius:8px;padding:7px 9px;font-size:11px;cursor:pointer}
+.ostep{display:flex;gap:7px;align-items:flex-start;padding:2px 0}
+.ostep .lamp{margin-top:3px;width:7px;height:7px}
+.ostep b{color:var(--cream);font-weight:700}.ostep .ev{color:var(--steel);display:block;font-size:10.5px}
+
+/* rotary selector */
+.rotsel{position:relative;width:118px;height:74px}
+.rotsel>.knob{position:absolute;left:50%;top:20px;margin-left:-26px;cursor:pointer}
+.rotsel .pos{position:absolute;font-size:9px;color:var(--dim);transform:translate(-50%,-50%);letter-spacing:.02em}
+.rotsel .pos.on{color:var(--gold-hi);text-shadow:0 0 6px rgba(255,190,84,.55)}
+
+/* slide-rule tuner dial */
+.tuner{width:180px;height:46px;position:relative;border-radius:6px;overflow:hidden;cursor:pointer;
+ background:linear-gradient(180deg,#191510,#0b0908);border:1px solid #2a251c;
+ box-shadow:inset 0 0 20px rgba(226,160,56,.12),inset 0 1px 0 rgba(255,255,255,.03)}
+.tuner .tick{position:absolute;top:6px;width:1px;height:11px;background:var(--steel);transform:translateX(-50%)}
+.tuner .mk{position:absolute;bottom:8px;transform:translateX(-50%);color:var(--steel);font-size:10px}
+.tuner .mk.on{color:var(--gold-hi);text-shadow:0 0 6px rgba(255,190,84,.6)}
+.tuner:focus-visible{outline:2px solid var(--gold);outline-offset:2px}
+.tuner .ndl{position:absolute;top:3px;bottom:3px;width:2px;margin-left:-1px;border-radius:1px;
+ background:var(--fail);box-shadow:0 0 7px rgba(203,107,77,.85);transition:left .25s}
+
+/* nixie tube */
+.nixie{display:inline-flex;gap:5px;cursor:pointer}
+.nixie .tube{width:30px;height:44px;border-radius:5px;position:relative;overflow:hidden;
+ background:radial-gradient(circle at 50% 38%,#241a12,#0b0807);border:1px solid #2c261d;
+ display:grid;place-items:center;box-shadow:inset 0 0 12px rgba(0,0,0,.6)}
+.nixie .tube b{font-size:26px;font-weight:400;color:#ff9a3c;
+ text-shadow:0 0 6px rgba(255,140,50,.85),0 0 15px rgba(255,120,40,.45)}
+.nixie .tube.off b{color:#3a2a1c;text-shadow:none}
+.nixie .tube::after{content:"";position:absolute;inset:0;pointer-events:none;
+ background:linear-gradient(180deg,rgba(255,255,255,.06),transparent 32%)}
+
+/* ===== candidate-unique CSS ===== */
+/* rocker */
+.rocker{width:66px;height:40px;border-radius:7px;cursor:pointer;position:relative;
+ background:linear-gradient(180deg,#25211c,#141210);border:1px solid #34302a;
+ box-shadow:inset 0 1px 0 rgba(255,255,255,.05),0 3px 6px rgba(0,0,0,.5);overflow:hidden}
+.rocker .half{position:absolute;left:0;right:0;height:50%;display:flex;align-items:center;justify-content:center;
+ font-size:12px;letter-spacing:.06em;color:var(--dim)}
+.rocker .top{top:0;border-bottom:1px solid #0c0b0a;background:linear-gradient(180deg,#211d19,#181513)}
+.rocker .bot{bottom:0;background:linear-gradient(180deg,#141210,#100e0c);box-shadow:inset 0 3px 5px rgba(0,0,0,.55)}
+.rocker.on .top{background:linear-gradient(180deg,#f2c76a,var(--gold));color:var(--panel);font-weight:700;box-shadow:0 0 10px rgba(255,190,84,.35)}
+.rocker.on .bot{color:var(--steel)}
+.rocker:not(.on) .top{color:var(--steel)}
+.rocker:not(.on) .bot{background:linear-gradient(180deg,#2a1512,#1c0f0d);color:var(--fail);box-shadow:inset 0 3px 5px rgba(0,0,0,.55),0 0 8px rgba(203,107,77,.25)}
+
+/* transport */
+.reels{display:flex;gap:16px;align-items:center;justify-content:center;margin-bottom:2px}
+.reel{width:26px;height:26px;border-radius:50%;border:2px solid #34302a;position:relative;
+ background:radial-gradient(circle at 45% 40%,#211d18,#0d0b09)}
+.reel::before{content:"";position:absolute;inset:9px;border-radius:50%;border:1px solid #4a443a;background:#161310}
+.reel i{position:absolute;left:50%;top:50%;width:2px;height:11px;background:var(--steel);margin:-5.5px 0 0 -1px;transform-origin:50% 5.5px}
+.reel i:nth-child(1){background:var(--gold-hi);box-shadow:0 0 4px rgba(255,190,84,.55)}
+.reel i:nth-child(2){transform:rotate(120deg)}.reel i:nth-child(3){transform:rotate(240deg)}
+.transport{display:flex;gap:5px}
+.tbtn{font:inherit;font-size:12px;color:var(--silver);cursor:pointer;width:30px;height:26px;display:grid;place-items:center;
+ background:linear-gradient(180deg,#23211e,#191715);border:1px solid #33302b;border-bottom-color:#0c0b0a;border-radius:6px}
+.tbtn:hover{color:var(--gold);border-color:var(--gold)}
+.tbtn.on{color:var(--panel);background:linear-gradient(180deg,#f2c76a,var(--gold));border-color:var(--gold-hi)}
+.tbtn.rec.on{color:var(--cream);background:linear-gradient(180deg,#d98a6f,var(--fail));border-color:var(--fail)}
+
+/* radio bank */
+.radiobank{display:flex;gap:0;border:1px solid #0c0b0a;border-radius:7px;overflow:hidden;
+ background:#0c0b0a;padding:3px;box-shadow:inset 0 2px 4px rgba(0,0,0,.5)}
+.preset{font:inherit;font-size:11px;color:var(--dim);cursor:pointer;padding:8px 9px;border:0;border-radius:4px;
+ background:linear-gradient(180deg,#211d19,#161310);box-shadow:inset 0 1px 0 rgba(255,255,255,.04)}
+.preset+.preset{margin-left:3px}
+.preset:hover{color:var(--silver)}
+.preset.on{color:var(--panel);background:linear-gradient(180deg,#f2c76a,var(--gold));font-weight:700;
+ box-shadow:inset 0 2px 4px rgba(0,0,0,.4)}
+
+/* concentric dual knob */
+.dualknob{width:64px;height:64px;position:relative}
+.dualknob .outer{width:64px;height:64px;border-radius:50%;position:absolute;inset:0;cursor:ns-resize;touch-action:none;
+ background:radial-gradient(circle at 40% 35%,#2a2622,#100e0c);border:1px solid #3a352c;
+ box-shadow:inset 0 2px 3px rgba(255,255,255,.05),0 3px 6px rgba(0,0,0,.5)}
+.dualknob .outer .tick{position:absolute;left:50%;top:3px;width:2px;height:9px;background:var(--steel);margin-left:-1px;transform-origin:50% 29px}
+.dualknob .inner{width:34px;height:34px;border-radius:50%;position:absolute;left:15px;top:15px;cursor:ns-resize;touch-action:none;
+ background:radial-gradient(circle at 40% 35%,#37322a,#1a1713);border:1px solid #4a443a;box-shadow:0 2px 4px rgba(0,0,0,.5)}
+.dualknob .inner .ind{position:absolute;left:50%;top:3px;width:2px;height:11px;background:var(--gold-hi);margin-left:-1px;
+ transform-origin:50% 14px;border-radius:1px;box-shadow:0 0 5px rgba(255,190,84,.6)}
+
+/* rotary encoder + LED ring */
+.encoder{position:relative;width:66px;height:66px;display:grid;place-items:center;cursor:ns-resize;touch-action:none}
+.encoder .led{position:absolute;width:5px;height:5px;border-radius:50%;background:var(--wash);
+ left:50%;top:50%;margin:-2.5px}
+.encoder .led.on{background:var(--gold);box-shadow:0 0 5px 1px rgba(226,160,56,.7)}
+.encoder .knob{width:40px;height:40px;cursor:ns-resize}
+.encoder .knob .ind{transform-origin:50% 15px;top:4px;height:12px}
+
+/* keyed mode switch */
+.keylock{position:relative;width:110px;height:70px}
+.keylock .body{position:absolute;left:50%;top:30px;margin-left:-21px;width:42px;height:42px;border-radius:50%;
+ background:radial-gradient(circle at 42% 36%,#2a2622,#0f0d0b);border:1px solid #3a352c;cursor:pointer;
+ box-shadow:inset 0 2px 3px rgba(255,255,255,.05),0 3px 6px rgba(0,0,0,.5)}
+.keylock .barrel{position:absolute;left:50%;top:50%;width:5px;height:5px;margin:-2.5px;border-radius:1px;background:#0a0908;
+ box-shadow:0 0 2px rgba(0,0,0,.8)}
+.keylock .bit{position:absolute;left:50%;top:50%;width:3px;height:15px;margin:-15px 0 0 -1.5px;background:var(--gold-hi);
+ border-radius:1px;transform-origin:50% 100%;box-shadow:0 0 5px rgba(255,190,84,.55);transition:transform .2s}
+.keylock .kpos{position:absolute;font-size:9px;color:var(--dim);letter-spacing:.05em;transform:translate(-50%,-50%)}
+.keylock .kpos.on{color:var(--gold-hi);text-shadow:0 0 6px rgba(255,190,84,.55)}
+
+/* crossfader */
+.xfader{width:160px;height:22px;position:relative;cursor:pointer;touch-action:none}
+.xfader .slot{position:absolute;top:9px;left:0;right:0;height:4px;border-radius:2px;background:#0d0f10;border:1px solid #231f18}
+.xfader .detent{position:absolute;top:2px;left:50%;width:1px;height:18px;background:var(--steel);margin-left:-.5px;opacity:.7}
+.xfader .end{position:absolute;top:11px;font-size:9px;color:var(--steel);transform:translateY(-50%)}
+.xfader .cap{position:absolute;top:3px;width:9px;height:16px;border-radius:2px;margin-left:-4.5px;transition:left .05s;
+ background:linear-gradient(180deg,#f2c76a,#d29638);border:1px solid #7d5c16;box-shadow:0 1px 2px rgba(0,0,0,.5)}
+
+/* thumbwheel */
+.thumbw{display:flex;align-items:center;gap:10px}
+.thumbwheel{width:34px;height:52px;border-radius:6px;cursor:ns-resize;touch-action:none;position:relative;overflow:hidden;
+ border:1px solid #34302a;box-shadow:inset 0 0 8px rgba(0,0,0,.6);
+ background:repeating-linear-gradient(0deg,#0e0c0a 0 2px,#221e19 2px 3px,#2f2a23 3px 5px,#221e19 5px 6px)}
+.thumbwheel::after{content:"";position:absolute;inset:0;background:linear-gradient(90deg,rgba(0,0,0,.55),transparent 30%,transparent 70%,rgba(0,0,0,.55))}
+.thumbw .win{color:var(--cream);font-size:15px;font-weight:700;font-variant-numeric:tabular-nums;
+ background:var(--well);border:1px solid #231f18;border-radius:4px;padding:3px 8px}
+
+/* DIP bank */
+.dip{display:flex;gap:3px;padding:6px 7px;background:#0f1a2a;border:1px solid #24344a;border-radius:5px;
+ box-shadow:inset 0 1px 3px rgba(0,0,0,.5)}
+.dipsw{width:12px;height:26px;background:#0a1220;border-radius:2px;position:relative;cursor:pointer;border:1px solid #1c2c42}
+.dipsw i{position:absolute;left:1px;right:1px;height:11px;border-radius:1px;background:linear-gradient(180deg,#eae4d2,#b4ad98);
+ bottom:1px;transition:bottom .12s,top .12s}
+.dipsw.on i{bottom:auto;top:1px;background:linear-gradient(180deg,#f2c76a,var(--gold))}
+
+/* jog / shuttle */
+.jog{position:relative;width:74px;height:74px;cursor:ns-resize;touch-action:none}
+.jog .shuttle{position:absolute;inset:0;border-radius:50%;border:6px solid #1a1713;
+ background:conic-gradient(from -90deg,#3a352c 0 var(--sh,40deg),#141210 0 360deg);
+ box-shadow:inset 0 0 8px rgba(0,0,0,.6)}
+.jog .inner{position:absolute;inset:12px;border-radius:50%;transition:transform .05s linear;
+ background:radial-gradient(circle at 42% 36%,#2c2822,#100e0c);border:1px solid #3a352c;box-shadow:0 2px 5px rgba(0,0,0,.6)}
+.jog .dimple{position:absolute;left:50%;top:7px;width:8px;height:8px;margin-left:-4px;border-radius:50%;
+ background:radial-gradient(circle at 40% 35%,#151210,#000);box-shadow:inset 0 1px 2px rgba(0,0,0,.9)}
+
+/* oscilloscope */
+.scope{width:176px;height:78px;border-radius:6px;position:relative;overflow:hidden;
+ background:radial-gradient(circle at 50% 45%,#04140a,#020a05);border:1px solid #123018;
+ box-shadow:inset 0 0 16px rgba(0,0,0,.7)}
+.scope .grat{position:absolute;inset:0;opacity:.5;
+ background-image:linear-gradient(rgba(111,206,51,.18) 1px,transparent 1px),linear-gradient(90deg,rgba(111,206,51,.18) 1px,transparent 1px);
+ background-size:22px 19.5px}
+.scope .grat::after{content:"";position:absolute;left:0;right:0;top:50%;height:1px;background:rgba(111,206,51,.35)}
+.scope svg{position:absolute;inset:0;width:100%;height:100%}
+.scope polyline{fill:none;stroke:var(--phos);stroke-width:1.6;filter:drop-shadow(0 0 3px rgba(127,224,160,.8))}
+
+/* spectrum / EQ */
+.eq{display:flex;align-items:flex-end;gap:3px;height:60px}
+.eq .band{width:9px;display:flex;flex-direction:column-reverse;gap:2px;height:100%}
+.eq .band i{height:5px;border-radius:1px;background:var(--wash);opacity:.3}
+.eq .band i.on{opacity:1;background:var(--pass)}
+.eq .band i.hot{opacity:1;background:var(--gold)}
+.eq .band i.clip{opacity:1;background:var(--fail)}
+
+/* crossed-needle */
+.crossm{width:120px}
+.crossm .face{position:relative;height:56px;overflow:hidden;cursor:ns-resize;touch-action:none}
+.crossm .arc{position:absolute;inset:2px 4px -56px;border:2px solid var(--wash);border-radius:50%}
+.crossm .nA{position:absolute;left:14px;bottom:2px;width:2px;height:52px;background:var(--gold-hi);transform-origin:50% 100%;
+ border-radius:2px;box-shadow:0 0 5px rgba(255,190,84,.5);transition:transform .12s cubic-bezier(.3,1.2,.5,1)}
+.crossm .nB{position:absolute;right:14px;bottom:2px;width:2px;height:52px;background:var(--fail);transform-origin:50% 100%;
+ border-radius:2px;box-shadow:0 0 5px rgba(203,107,77,.5);transition:transform .12s cubic-bezier(.3,1.2,.5,1)}
+.crossm .lbl{display:flex;justify-content:space-between;color:var(--steel);font-size:9px;margin-top:2px}
+
+/* thermometer */
+.thermo{display:flex;align-items:flex-end;gap:6px;height:74px;cursor:ns-resize;touch-action:none}
+.thermo .tube{width:12px;height:64px;border-radius:6px 6px 0 0;position:relative;background:#0d0f10;border:1px solid #231f18;overflow:hidden}
+.thermo .fill{position:absolute;left:0;right:0;bottom:0;background:linear-gradient(0deg,#a35a3f,var(--fail))}
+.thermo .bulb{width:20px;height:20px;border-radius:50%;background:var(--fail);position:absolute;left:-4px;bottom:-9px;
+ box-shadow:0 0 6px rgba(203,107,77,.5)}
+.thermo .scale{display:flex;flex-direction:column;justify-content:space-between;height:64px;font-size:9px;color:var(--steel)}
+.thermo .wrapcol{position:relative;padding-bottom:9px}
+
+/* bourdon */
+.bourdon{width:82px;height:82px;border-radius:50%;position:relative;cursor:ns-resize;touch-action:none;
+ background:radial-gradient(circle at 48% 42%,#1d1a16,#0c0b09);border:2px solid #2c261d;
+ box-shadow:inset 0 2px 5px rgba(0,0,0,.6)}
+.bourdon svg{position:absolute;inset:0}
+.bourdon .ndl{position:absolute;left:50%;top:50%;width:2px;height:32px;margin:-32px 0 0 -1px;background:var(--gold-hi);
+ transform-origin:50% 100%;border-radius:2px;box-shadow:0 0 5px rgba(255,190,84,.55);transition:transform .12s cubic-bezier(.3,1.2,.5,1)}
+.bourdon .hub{position:absolute;left:50%;top:50%;width:8px;height:8px;margin:-4px;border-radius:50%;background:var(--gold)}
+.bourdon .cap{position:absolute;left:0;right:0;bottom:12px;text-align:center;font-size:8px;letter-spacing:.16em;color:var(--steel)}
+
+/* strip-chart */
+.strip{width:176px;height:62px;border-radius:5px;position:relative;overflow:hidden;
+ background:#0c0e0f;border:1px solid #231f18}
+.strip .rule{position:absolute;inset:0;opacity:.4;
+ background-image:linear-gradient(90deg,rgba(150,147,133,.14) 1px,transparent 1px);background-size:16px 100%}
+.strip svg{position:absolute;inset:0;width:100%;height:100%}
+.strip polyline{fill:none;stroke:var(--gold);stroke-width:1.4}
+.strip .pen{position:absolute;right:2px;width:6px;height:6px;margin:-3px;border-radius:50%;background:var(--gold-hi);
+ box-shadow:0 0 6px rgba(255,190,84,.8);transition:top .08s linear}
+
+/* correlation */
+.corr{width:150px;cursor:pointer;touch-action:none}
+.corr .face{position:relative;height:44px;overflow:hidden}
+.corr .arc{position:absolute;inset:0 0 -44px;border:2px solid var(--wash);border-radius:50%}
+.corr .zero{position:absolute;left:50%;top:2px;width:1px;height:10px;background:var(--gold);margin-left:-.5px}
+.corr .ndl{position:absolute;left:50%;bottom:0;width:2px;height:38px;background:var(--gold-hi);transform-origin:50% 100%;
+ border-radius:2px;box-shadow:0 0 5px rgba(255,190,84,.5);transition:transform .1s ease-out}
+.corr .lbl{display:flex;justify-content:space-between;color:var(--steel);font-size:9px;margin-top:2px}
+
+/* battery */
+.batt{display:flex;align-items:center;cursor:pointer;touch-action:none}
+.batt .cells{display:flex;gap:2px;padding:3px;border:1px solid #34302a;border-radius:4px;background:#0d0f10}
+.batt .cell{width:12px;height:26px;border-radius:1px;background:var(--wash);opacity:.35}
+.batt .cell.on{opacity:1;background:linear-gradient(180deg,var(--pass),#5c7526)}
+.batt .cell.warn.on{background:linear-gradient(180deg,var(--fail),#a04a34)}
+.batt .nub{width:4px;height:12px;background:#34302a;border-radius:0 2px 2px 0}
+
+/* split-flap */
+.flap{display:inline-flex;gap:4px;cursor:pointer}
+.flapd{width:30px;height:42px;border-radius:5px;position:relative;overflow:hidden;
+ background:linear-gradient(180deg,#211d18,#141210);border:1px solid #34302a;box-shadow:0 2px 4px rgba(0,0,0,.5)}
+.flapd b{position:absolute;inset:0;display:grid;place-items:center;font-size:24px;color:var(--cream);
+ text-shadow:0 1px 2px rgba(0,0,0,.7)}
+.flapd::after{content:"";position:absolute;left:0;right:0;top:50%;height:1px;background:rgba(0,0,0,.65);box-shadow:0 1px 0 rgba(255,255,255,.03)}
+.flapd.flip b{animation:flipdrop .3s ease-in}
+@keyframes flipdrop{0%{transform:translateY(-42%) scaleY(.4);opacity:.3}100%{transform:none;opacity:1}}
+
+/* seven-segment */
+.seven{display:inline-flex;gap:6px;padding:6px 9px;border-radius:6px;background:#0a0806;border:1px solid #231f18;cursor:pointer;
+ box-shadow:inset 0 0 10px rgba(0,0,0,.6)}
+.seg7{width:22px;height:40px;filter:drop-shadow(0 0 3px rgba(87,211,87,.55))}
+.seg7.red{filter:drop-shadow(0 0 3px rgba(226,84,63,.55))}
+.seven .colon{align-self:center;display:flex;flex-direction:column;gap:9px}
+.seven .colon i{width:4px;height:4px;border-radius:50%;background:var(--sevgrn);box-shadow:0 0 4px rgba(87,211,87,.7)}
+
+/* VFD marquee */
+.vfdm{width:176px;height:34px;border-radius:5px;overflow:hidden;position:relative;cursor:pointer;
+ background:linear-gradient(180deg,#04100e,#020807);border:1px solid #123028;box-shadow:inset 0 0 12px rgba(0,0,0,.6)}
+.vfdm .txt{position:absolute;top:50%;transform:translateY(-50%);white-space:nowrap;font-size:15px;letter-spacing:.22em;
+ color:var(--vfd);text-shadow:0 0 6px rgba(99,230,200,.65)}
+.vfdm .mesh{position:absolute;inset:0;pointer-events:none;opacity:.35;
+ background-image:radial-gradient(rgba(0,0,0,.6) 40%,transparent 41%);background-size:3px 3px}
+
+/* annunciator */
+.annun{display:grid;grid-template-columns:repeat(3,1fr);gap:3px}
+.acell{font-size:8.5px;letter-spacing:.08em;text-align:center;color:var(--dim);padding:6px 4px;border-radius:3px;cursor:pointer;
+ background:#141210;border:1px solid #262320;line-height:1.2}
+.acell.warn{color:var(--panel);background:linear-gradient(180deg,#f0b552,var(--gold));font-weight:700;box-shadow:0 0 8px rgba(226,160,56,.4)}
+.acell.fault{color:var(--cream);background:linear-gradient(180deg,#d98a6f,var(--fail));font-weight:700;box-shadow:0 0 8px rgba(203,107,77,.4);animation:pulse 1s ease-in-out infinite}
+
+/* jewel */
+.jewel{width:24px;height:24px;border-radius:50%;position:relative;cursor:pointer;
+ background:radial-gradient(circle at 36% 30%,rgba(255,255,255,.75),var(--jc) 42%,#3a0d08 100%);
+ box-shadow:0 0 10px 1px var(--jc),inset 0 -2px 3px rgba(0,0,0,.5)}
+.jewel::after{content:"";position:absolute;inset:0;border-radius:50%;
+ background:conic-gradient(from 0deg,rgba(255,255,255,.12) 0 22deg,transparent 22deg 45deg,rgba(0,0,0,.18) 45deg 67deg,transparent 67deg 90deg);
+ background-repeat:repeat}
+.jewel.dim{background:radial-gradient(circle at 36% 30%,rgba(120,120,120,.3),#241f1b 55%,#0e0c0a);box-shadow:inset 0 -2px 3px rgba(0,0,0,.5)}
+
+/* tape counter */
+.counter{display:inline-flex;gap:2px;padding:4px;background:#0c0b0a;border:1px solid #2c261d;border-radius:4px;
+ box-shadow:inset 0 1px 3px rgba(0,0,0,.6)}
+.cwheel{width:18px;height:34px;border-radius:2px;position:relative;overflow:hidden;
+ background:linear-gradient(180deg,#efe9d6,#c7c0ac);box-shadow:inset 0 0 3px rgba(0,0,0,.3)}
+.cwheel .col{position:absolute;left:0;right:0;text-align:center;color:#1a1613;font-size:18px;font-weight:700;line-height:34px;
+ transition:top .35s cubic-bezier(.4,1.4,.5,1)}
+.cwheel .col span{display:block;height:34px}
+.cwheel::before,.cwheel::after{content:"";position:absolute;left:0;right:0;height:9px;z-index:2;pointer-events:none}
+.cwheel::before{top:0;background:linear-gradient(180deg,rgba(0,0,0,.4),transparent)}
+.cwheel::after{bottom:0;background:linear-gradient(0deg,rgba(0,0,0,.4),transparent)}
+.counter .redw{background:linear-gradient(180deg,#e7b46a,#cf9440)}
+
+/* analog clock */
+.clock{width:78px;height:78px;border-radius:50%;position:relative;
+ background:radial-gradient(circle at 46% 40%,#1c1915,#0c0b09);border:2px solid #2c261d;box-shadow:inset 0 2px 5px rgba(0,0,0,.6)}
+.clock .tk{position:absolute;left:50%;top:4px;width:1.5px;height:6px;background:var(--steel);margin-left:-.75px;transform-origin:50% 35px}
+.clock .hh{position:absolute;left:50%;top:50%;width:3px;height:20px;margin:-20px 0 0 -1.5px;background:var(--cream);
+ transform-origin:50% 100%;border-radius:2px}
+.clock .mh{position:absolute;left:50%;top:50%;width:2px;height:28px;margin:-28px 0 0 -1px;background:var(--silver);
+ transform-origin:50% 100%;border-radius:2px}
+.clock .sh{position:absolute;left:50%;top:50%;width:1px;height:30px;margin:-30px 0 0 -.5px;background:var(--gold-hi);
+ transform-origin:50% 100%;box-shadow:0 0 4px rgba(255,190,84,.5)}
+.clock .pin{position:absolute;left:50%;top:50%;width:6px;height:6px;margin:-3px;border-radius:50%;background:var(--gold)}
+
+/* frequency-dial scale */
+.freqscale{width:184px;height:44px;position:relative;border-radius:5px;overflow:hidden;cursor:pointer;touch-action:none;
+ background:linear-gradient(180deg,#191510,#0b0908);border:1px solid #2a251c;
+ box-shadow:inset 0 0 16px rgba(226,160,56,.1)}
+.freqscale .tick{position:absolute;top:5px;width:1px;background:var(--steel);transform:translateX(-50%)}
+.freqscale .mk{position:absolute;bottom:6px;transform:translateX(-50%);color:var(--steel);font-size:9px}
+.freqscale .band{position:absolute;bottom:2px;left:6px;color:var(--gold);font-size:8px;letter-spacing:.18em}
+.freqscale .fptr{position:absolute;top:3px;bottom:14px;width:2px;margin-left:-1px;border-radius:1px;
+ background:var(--fail);box-shadow:0 0 7px rgba(203,107,77,.85)}
+
+/* patch-bay */
+.patch{padding:7px 9px;background:#141210;border:1px solid #2c261d;border-radius:5px;position:relative}
+.patch .row{display:flex;gap:9px}
+.patch .row+.row{margin-top:9px}
+.patch .jack{width:13px;height:13px;border-radius:50%;cursor:pointer;background:radial-gradient(circle at 40% 35%,#3a352c,#0a0908 70%);
+ border:1px solid #4a443a;box-shadow:inset 0 1px 2px rgba(0,0,0,.8)}
+.patch .jack.hot{background:radial-gradient(circle at 40% 35%,#7d5c16,#1a1408 70%)}
+.patch .jack.sel{border-color:var(--gold-hi);box-shadow:0 0 6px 1px rgba(255,190,84,.7)}
+.patch svg{position:absolute;inset:0;pointer-events:none;width:100%;height:100%}
+.patch svg path{fill:none;stroke:var(--gold);stroke-width:2.4;opacity:.85;stroke-linecap:round}
+
+@media (prefers-reduced-motion:reduce){*{animation:none!important;transition:none!important}}
+</style>
+</head>
+<body>
+<div class="wrap">
+<header class="masthead">
+ <div class="eyebrow">archsetup · dupre panel family · live kit</div>
+ <h1>Widget gallery — the instrument-console kit, fully driveable</h1>
+ <p>Every control + display idiom in the dupre faceplate language, merged into one live console — the base kit
+ plus the candidate batch, ~55 widgets rendering from the same tokens the net / bt / sound panels use.
+ <b>Controls</b> take input; <b>meters &amp; gauges</b> show a live analog value; <b>indicators &amp;
+ readouts</b> show state or a number. Every widget is operable: drag the faders, knobs and gauges; click the
+ switches, keys and lamps. Each card carries a live readout that tracks what you do. The trace displays run
+ a live signal; the pointer types drive from your drag.</p>
+</header>
+
+<h2>Controls — take input</h2>
+<div class="grid" id="controls"></div>
+
+<h2>Meters &amp; gauges — live analog value</h2>
+<div class="grid" id="meters"></div>
+
+<h2>Indicators &amp; readouts — state or number</h2>
+<div class="grid" id="indicators"></div>
+
+</div>
+<script>
+const $ = id => document.getElementById(id);
+const reduced = matchMedia('(prefers-reduced-motion: reduce)').matches;
+function card(host, no, name, html, note){
+ const c=document.createElement('div'); c.className='card';
+ c.innerHTML=`<div class="wname"><span class="no">${no}</span>${name}</div>`+
+ `<div class="stagew">${html}</div><div class="wrd" id="rd-${no}">—</div><div class="wnote">${note}</div>`;
+ host.appendChild(c); return c;
+}
+function setRd(no,txt){const e=$('rd-'+no);if(e)e.textContent=txt;}
+function buildBars(el,n){el.innerHTML='';for(let k=0;k<n;k++)el.appendChild(document.createElement('i'));}
+
+/* ---- pointer-drag helpers ---- */
+function dragX(el,onPct){ el.style.touchAction='none';
+ const at=e=>{const r=el.getBoundingClientRect();onPct(Math.max(0,Math.min(100,(e.clientX-r.left)/r.width*100)));};
+ el.addEventListener('pointerdown',e=>{el.setPointerCapture(e.pointerId);at(e);
+ const mv=ev=>at(ev),up=()=>{el.removeEventListener('pointermove',mv);el.removeEventListener('pointerup',up);el.removeEventListener('pointercancel',up);};
+ el.addEventListener('pointermove',mv);el.addEventListener('pointerup',up);el.addEventListener('pointercancel',up);e.preventDefault();});
+}
+function dragY(el,onPct){ el.style.touchAction='none';
+ const at=e=>{const r=el.getBoundingClientRect();onPct(Math.max(0,Math.min(100,(r.bottom-e.clientY)/r.height*100)));};
+ el.addEventListener('pointerdown',e=>{el.setPointerCapture(e.pointerId);at(e);
+ const mv=ev=>at(ev),up=()=>{el.removeEventListener('pointermove',mv);el.removeEventListener('pointerup',up);el.removeEventListener('pointercancel',up);};
+ el.addEventListener('pointermove',mv);el.addEventListener('pointerup',up);el.addEventListener('pointercancel',up);e.preventDefault();});
+}
+function dragDelta(el,get,set,opts){ opts=opts||{}; el.style.touchAction='none';
+ const min=opts.min==null?0:opts.min, max=opts.max==null?100:opts.max, sens=opts.sens||((max-min)/160);
+ el.addEventListener('pointerdown',e=>{if(opts.stop)e.stopPropagation();el.setPointerCapture(e.pointerId);
+ const y0=e.clientY, v0=get();
+ const mv=ev=>{let v=v0+(y0-ev.clientY)*sens;set(Math.max(min,Math.min(max,v)));};
+ const up=()=>{el.removeEventListener('pointermove',mv);el.removeEventListener('pointerup',up);el.removeEventListener('pointercancel',up);};
+ el.addEventListener('pointermove',mv);el.addEventListener('pointerup',up);el.addEventListener('pointercancel',up);e.preventDefault();});
+}
+
+/* ---- seven-segment digit builder ---- */
+const SEG={'0':'abcdef','1':'bc','2':'abged','3':'abgcd','4':'fbgc','5':'afgcd','6':'afgedc','7':'abc','8':'abcdefg','9':'abcdfg','-':'g',' ':''};
+function hseg(cy){return `5,${cy} 7,${cy-2} 17,${cy-2} 19,${cy} 17,${cy+2} 7,${cy+2}`;}
+function vseg(cx,ty,by){return `${cx},${ty} ${cx-2},${ty+2} ${cx-2},${by-2} ${cx},${by} ${cx+2},${by-2} ${cx+2},${ty+2}`;}
+const SEGPTS={a:hseg(3),g:hseg(22),d:hseg(41),f:vseg(5,4,21),b:vseg(19,4,21),e:vseg(5,23,40),c:vseg(19,23,40)};
+function seg7(ch,cls){
+ const lit=SEG[ch]||''; let s=`<svg class="seg7 ${cls||''}" viewBox="0 0 24 44">`;
+ for(const k of 'abcdefg'){const on=lit.includes(k);
+ const col=on?(cls==='red'?'var(--sevred)':'var(--sevgrn)'):'var(--sevoff)';
+ s+=`<polygon points="${SEGPTS[k]}" fill="${col}"/>`;}
+ return s+'</svg>';
+}
+
+/* ============ CONTROLS ============ */
+const C=$('controls');
+card(C,'01','Toggle switch',
+ `<span id="toggle01"><span class="switch on"></span></span>`,
+ '<b>on / off.</b> The faceplate master control — power, mute, enable. Click to flip; readout shows the state.');
+card(C,'02','Console key',
+ `<span id="keys02"><button class="key on">LIVE</button><button class="key">SCAN</button><button class="key red">MUTED</button></span>`,
+ '<b>physical push button.</b> Mutually exclusive — click one to engage. Gold = live, terracotta = muted.');
+card(C,'03','Horizontal fader',
+ `<div class="fader" id="f1"><div class="slot"><div class="fill" style="width:68%"></div></div><div class="cap" style="left:68%"></div></div>`,
+ '<b>continuous 0-100.</b> Per-device volume, brightness. Drag the gold cap; readout tracks.');
+card(C,'04','Vertical fader',
+ `<div class="vfader" id="v1"><div class="slot"><div class="fill" style="height:60%"></div></div><div class="cap" style="bottom:60%"></div></div>
+ <div class="vfader" id="v2"><div class="slot"><div class="fill" style="height:35%"></div></div><div class="cap" style="bottom:35%"></div></div>`,
+ '<b>channel-strip style.</b> A mixer column per device. Drag each fader up or down.');
+card(C,'05','Rotary knob',
+ `<span class="knob" id="knob"><span class="ind" id="kind"></span></span>`,
+ '<b>dial in a value.</b> Volume/gain the analog way. Drag up/down to turn; readout shows the level.');
+card(C,'06','Segmented selector',
+ `<div class="seg" id="seg06"><button class="on">TIMER</button><button>ALARM</button><button>POMO</button></div>`,
+ '<b>pick one of a few.</b> Timer type, layout mode. Click a segment; readout names the choice.');
+card(C,'07','Chip toggle',
+ `<span class="chip on" id="chip07">discoverable on</span>`,
+ '<b>inline binary.</b> A soft toggle inside a line of text. Click to flip; gold when on.');
+card(C,'08','Arm-to-fire',
+ `<button class="arm" id="arm">forget</button>`,
+ '<b>two-stage confirm.</b> Destructive actions. First click arms (red), second fires. Readout shows the stage.');
+card(C,'09','Lamp row',
+ `<div class="lrow" id="lrow9"><span class="lamp gold"></span><span class="who"><b>WH-1000XM4</b></span><span class="what">tap to connect</span></div>`,
+ '<b>actionable list item.</b> Lamp + name + status. Click to cycle idle → connecting → connected.');
+card(C,'24','Rotary selector',
+ `<span class="rotsel" id="rotsel24">
+ <span class="pos" style="left:14%;top:53%">4</span><span class="pos" style="left:28%;top:18%">6</span><span class="pos on" style="left:50%;top:7%">8</span><span class="pos" style="left:72%;top:18%">10</span><span class="pos" style="left:86%;top:53%">12</span>
+ <span class="knob"><span class="ind"></span></span>
+ </span>`,
+ '<b>pick one of N by position.</b> Printed detents, the pointer names the value. Click to turn; readout shows it.');
+card(C,'25','Slide-rule dial',
+ `<span class="tuner" id="tuner" tabindex="0" role="slider" aria-label="slide-rule value">
+ <span class="tick" style="left:12px"></span><span class="tick" style="left:51px"></span><span class="tick" style="left:90px"></span><span class="tick" style="left:129px"></span><span class="tick" style="left:168px"></span>
+ <span class="mk" style="left:12px">4</span><span class="mk" style="left:51px">6</span><span class="mk on" style="left:90px">8</span><span class="mk" style="left:129px">10</span><span class="mk" style="left:168px">12</span>
+ <span class="ndl" id="tundl" style="left:90px"></span>
+ </span>`,
+ '<b>value on a printed scale.</b> A lit pointer glides a warm-backlit strip. Click a mark to jump, or focus it and press ←/→ (↑/↓); readout shows it.');
+card(C,'N01','Rocker power switch',
+ `<span class="rocker on" id="rocker"><span class="half top">ON</span><span class="half bot">OFF</span></span>`,
+ '<b>hard on / off, lit legend.</b> A master power paddle — the pressed half glows. Click to rock.');
+card(C,'N02','Transport cluster',
+ `<div style="display:flex;flex-direction:column;gap:6px;align-items:center">
+ <div class="reels"><span class="reel spin"><i></i><i></i><i></i></span><span class="reel spin"><i></i><i></i><i></i></span></div>
+ <div class="transport" id="tport">
+ <button class="tbtn" data-t="rew" onclick="transport(this)">⏮</button>
+ <button class="tbtn on" data-t="play" onclick="transport(this)">▶</button>
+ <button class="tbtn" data-t="stop" onclick="transport(this)">⏹</button>
+ <button class="tbtn rec" data-t="rec" onclick="transport(this)">⏺</button>
+ </div></div>`,
+ '<b>run / pause / capture.</b> One mode lit at a time, reels turn while it plays. Click a button.');
+card(C,'N03','Radio preset bank',
+ `<div class="radiobank" id="rbank">
+ <button class="preset on" onclick="preset(this)">WIFI</button>
+ <button class="preset" onclick="preset(this)">ETH</button>
+ <button class="preset" onclick="preset(this)">CELL</button>
+ <button class="preset" onclick="preset(this)">OFF</button>
+ </div>`,
+ '<b>pick one, the rest release.</b> The car-radio preset row — mechanically exclusive. Click one.');
+card(C,'N04','Concentric dual knob',
+ `<span class="dualknob">
+ <span class="outer" id="dko"><span class="tick" style="transform:rotate(-120deg)"></span><span class="tick" style="transform:rotate(120deg)"></span></span>
+ <span class="inner" id="dki"><span class="ind"></span></span>
+ </span>`,
+ '<b>two values on one spindle.</b> Bass / treble, coarse / fine. Drag the outer ring or inner cap — each is independent.');
+card(C,'N05','Rotary encoder + LED ring',
+ `<span class="encoder" id="enc"></span>`,
+ '<b>endless dial, lit position.</b> A detentless encoder; the LED arc lights to the level and the value keeps accumulating. Drag to turn.');
+card(C,'N06','Keyed mode switch',
+ `<span class="keylock" id="keylock6">
+ <span class="kpos" style="left:16%;top:64%">OFF</span><span class="kpos on" style="left:50%;top:12%">ON</span><span class="kpos" style="left:84%;top:64%">RUN</span>
+ <span class="body" onclick="keyTurn()"><span class="bit" id="kbit"></span><span class="barrel"></span></span>
+ </span>`,
+ '<b>guarded three-position mode.</b> Off · on · run. The key-bit points at the live position. Click to turn.');
+card(C,'N07','Center-detented crossfader',
+ `<div class="xfader" id="xf">
+ <div class="slot"></div><div class="detent"></div>
+ <span class="end" style="left:0">A</span><span class="end" style="right:0">B</span>
+ <div class="cap" id="xfcap" style="left:50%"></div>
+ </div>`,
+ '<b>throw to either side of zero.</b> A fader notched at center — balance, L/R mix. Drag; readout shows the signed value.');
+card(C,'N08','Thumbwheel',
+ `<div class="thumbw"><span class="thumbwheel" id="thumbwheel"></span><span class="win" id="thval">42</span></div>`,
+ '<b>ribbed edge-wheel, one value.</b> A knurled wheel with a windowed number. Drag up/down to roll.');
+card(C,'N09','DIP-switch bank',
+ `<span class="dip" id="dips">
+ <span class="dipsw on" onclick="dip(this)"><i></i></span><span class="dipsw" onclick="dip(this)"><i></i></span>
+ <span class="dipsw on" onclick="dip(this)"><i></i></span><span class="dipsw on" onclick="dip(this)"><i></i></span>
+ <span class="dipsw" onclick="dip(this)"><i></i></span><span class="dipsw" onclick="dip(this)"><i></i></span>
+ </span>`,
+ '<b>a bank of hard flags.</b> Hardware slide switches — up is on. Click each to flip; readout is the binary word.');
+card(C,'N10','Jog / shuttle wheel',
+ `<span class="jog" id="jog10"><span class="shuttle" style="--sh:40deg"></span><span class="inner" id="jogi"><span class="dimple"></span></span></span>`,
+ '<b>scrub fine, shuttle fast.</b> The edit-deck wheel. Drag to jog the inner wheel; readout shows the position.');
+
+/* ============ METERS & GAUGES ============ */
+const M=$('meters');
+card(M,'10','Needle gauge',
+ `<div class="gauge" id="gauge10"><div class="dial"><div class="arc"></div>
+ <div class="tk" style="transform:rotate(-60deg)"></div><div class="tk" style="transform:rotate(0)"></div><div class="tk" style="transform:rotate(60deg)"></div>
+ <div class="ndl" id="g1"></div><div class="hub"></div></div><div class="gv"><span id="g1v">0</span>%</div></div>`,
+ '<b>analog dial.</b> Throughput, battery, volume. Drag up/down to sweep the needle; readout tracks. <b>Smooth sweep wants a Cairo/GTK area.</b>');
+card(M,'11','Stereo VU (LED bar)',
+ `<div class="vu"><div class="vurow"><span class="ch">L</span><span class="vubar" id="vuL"></span></div>
+ <div class="vurow"><span class="ch">R</span><span class="vubar" id="vuR"></span></div></div>`,
+ '<b>live signal level.</b> The sound panel meter row, peak-hold outline. Runs a live signal; readout shows L/R.');
+card(M,'12','Mini signal (4-bar)',
+ `<span class="sig" id="mini"></span>`,
+ '<b>compact activity.</b> Per-row "is this device playing". Live signal; readout shows activity %.');
+card(M,'13','Signal ladder',
+ `<span class="ladder" id="ladder"><i></i><i></i><i></i><i></i></span>`,
+ '<b>discrete strength.</b> Wifi bars, bt RSSI — a stepped 0-4. Click to cycle strength; readout shows bars.');
+card(M,'14','Linear fuel bar',
+ `<div class="bar" id="bar14"><span style="width:72%"></span></div><div class="bar" id="bar14b"><span style="width:40%"></span></div>`,
+ '<b>a single 0-100.</b> Battery, disk, download. Drag either bar; warn tint under threshold; readout tracks.');
+card(M,'15','Radial ring',
+ `<span class="ring" id="ring15" style="--p:68"><b>68</b></span>`,
+ '<b>percentage as a donut.</b> CPU, battery. Drag up/down to set; conic-gradient tracks the readout.');
+card(M,'16','Sparkline',
+ `<span class="spark" id="spark"><svg viewBox="0 0 170 44" preserveAspectRatio="none"><polyline id="sparkp" fill="none" stroke="var(--gold-hi)" stroke-width="1.5"/></svg></span>`,
+ '<b>recent history.</b> Throughput/CPU over the last minute. Live trace; readout shows the current value.');
+card(M,'17','Waveform strip',
+ `<span class="wave" id="wave"><svg viewBox="0 0 170 38" preserveAspectRatio="none"><path id="wavep" fill="none" stroke="var(--gold)" stroke-width="1.2"/></svg></span>`,
+ '<b>audio waveform / scope.</b> A richer signal view. Live trace; readout shows amplitude. <b>Needs a drawing surface.</b>');
+card(M,'N11','Oscilloscope',
+ `<span class="scope"><span class="grat"></span><svg viewBox="0 0 176 78" preserveAspectRatio="none"><polyline id="scopep"/></svg></span>`,
+ '<b>a live phosphor trace.</b> A waveform swept over a graticule. Live; readout shows Vpp. <b>Needs a Cairo/GTK area for a smooth trace.</b>');
+card(M,'N12','Spectrum / EQ bars',
+ `<span class="eq" id="eq"></span>`,
+ '<b>level across bands.</b> A live multi-band bar graph — spectrum, per-core CPU. Live; readout shows the peak band.');
+card(M,'N13','Crossed-needle meter',
+ `<div class="crossm"><div class="face" id="crossm13"><div class="arc"></div><div class="nA" id="cnA"></div><div class="nB" id="cnB"></div></div>
+ <div class="lbl"><span>FWD</span><span>RFL</span></div></div>`,
+ '<b>two readings, one face.</b> Forward + reflected needles cross. Drag up/down to drive power; readout shows both. <b>Round build wants a drawing surface.</b>');
+card(M,'N14','Thermometer column',
+ `<div class="thermo" id="thermo14"><div class="scale"><span>90</span><span>60</span><span>30</span></div>
+ <div class="wrapcol"><div class="tube"><div class="fill" id="thermf" style="height:58%"></div></div><div class="bulb"></div></div></div>`,
+ '<b>a rising column.</b> The classic mercury tube — temperature, a climbing load. Drag up/down; readout shows the value.');
+card(M,'N15','Bourdon pressure gauge',
+ `<div class="bourdon" id="bourdon15">
+ <svg viewBox="0 0 82 82"><path d="M14 62 A34 34 0 0 1 68 62" fill="none" stroke="#2c2f32" stroke-width="3"/>
+ <path d="M52 22 A34 34 0 0 1 68 62" fill="none" stroke="#cb6b4d" stroke-width="3"/></svg>
+ <div class="ndl" id="bourd" style="transform:rotate(30deg)"></div><div class="hub"></div><div class="cap">PSI</div></div>`,
+ '<b>a round dial with a red zone.</b> Needle over a printed arc, redline in terracotta. Drag to set PSI; readout tracks. <b>Round sweep is a drawing-area job.</b>');
+card(M,'N16','Strip-chart recorder',
+ `<span class="strip"><span class="rule"></span><svg viewBox="0 0 176 62" preserveAspectRatio="none"><polyline id="stripp"/></svg><span class="pen" id="strippen" style="top:31px"></span></span>`,
+ '<b>a scrolling pen trace.</b> History scrolls left, the pen writes at the right edge. Live; readout shows the current value. <b>Real trace wants a drawing surface.</b>');
+card(M,'N17','Correlation meter (±)',
+ `<div class="corr" id="corr17"><div class="face"><div class="arc"></div><div class="zero"></div><div class="ndl" id="corrn" style="transform:rotate(8deg)"></div></div>
+ <div class="lbl"><span>−1</span><span>0</span><span>+1</span></div></div>`,
+ '<b>deviation from center.</b> The needle rests at 0 and swings ±. Drag left/right; readout shows the signed value.');
+card(M,'N18','Battery-cell gauge',
+ `<div class="batt" id="batt18"><div class="cells" id="battc"></div><span class="nub"></span></div>`,
+ '<b>charge as discrete cells.</b> Filled cells count up, the last warn in terracotta. Drag left/right to set; readout shows %.');
+
+/* ============ INDICATORS & READOUTS ============ */
+const I=$('indicators');
+card(I,'18','Status lamp',
+ `<span id="lamp18" style="display:inline-flex;gap:9px;align-items:center"><span class="lamp"></span><span class="lamp gold"></span><span class="lamp red"></span><span class="lamp off"></span><span class="lamp busy"></span></span>`,
+ '<b>one-glance health.</b> Green ok · gold engaged · red fail · dim off · pulsing busy. Click any lamp to cycle its state.');
+card(I,'19','Badge / tag',
+ `<span id="badge19"><span class="badge">TUNNEL</span> <span class="badge red">LOW BATT</span> <span class="badge ghost">2.4G</span></span>`,
+ '<b>a labelled flag.</b> MUTED, AIRPLANE, a band tag. Click a badge to cycle its variant.');
+card(I,'20','Tabular readout',
+ `<div style="text-align:center"><div class="readout" id="treadout">24:10</div><span class="u">timer</span></div>`,
+ '<b>a precise number.</b> Clock, countdown, volume %. Runs a live countdown; click to pause/resume.');
+card(I,'21','Engraved label',
+ `<span class="engrave" id="engrave">outputs<span class="cnt" id="engc">· 3</span></span>`,
+ '<b>section divider.</b> The hairline-flanked caps label with a count. Click to bump the count.');
+card(I,'22','Output well',
+ `<div class="owell" id="owell"><div class="ostep"><span class="lamp"></span><span><b>Link</b><span class="ev">wlp170s0 · @Hyatt</span></span></div>
+ <div class="ostep"><span class="lamp gold"></span><span><b>DNS</b><span class="ev">resolving…</span></span></div></div>`,
+ '<b>streaming step log.</b> Lamp-per-step with evidence. Click to stream the next step.');
+card(I,'23','Toast / status line',
+ `<span class="toastw" id="toast">joined @Hyatt_WiFi — saved</span>`,
+ '<b>transient confirmation.</b> The one-line result after an action. Click to fire the next toast.');
+card(I,'26','Nixie tube',
+ `<span class="nixie" id="nixie"><span class="tube off"><b>0</b></span><span class="tube"><b>8</b></span></span>`,
+ '<b>a single warm-glowing numeral.</b> One lit digit per tube, leading zeros dark. Click to increment the count.');
+card(I,'N20','Split-flap display',
+ `<span class="flap" id="flap"><span class="flapd"><b>D</b></span><span class="flapd"><b>N</b></span><span class="flapd"><b>S</b></span></span>`,
+ '<b>flips to the new value.</b> Each card drops to the next glyph with the mechanical clack. Auto-flips; click to flip now.');
+card(I,'N21','Seven-segment display',
+ `<span class="seven" id="seven"></span>`,
+ '<b>a lit-segment number.</b> Green segments, distinct from the nixie glow. Live countdown; click to add a minute.');
+card(I,'N22','VFD marquee',
+ `<span class="vfdm" id="vfdm"><span class="txt" id="vfdt">ARCHSETUP · NET OK · BT 2 · SND 62%</span><span class="mesh"></span></span>`,
+ '<b>scrolling status line.</b> Teal glow, dot-matrix mesh, text tracks across. Scrolls live; click to change the message.');
+card(I,'N23','Annunciator panel',
+ `<div class="annun" id="annun">
+ <span class="acell">SYNC</span><span class="acell warn">LOW BATT</span><span class="acell">LINK</span>
+ <span class="acell fault">NO DNS</span><span class="acell">VPN</span><span class="acell">DISK</span>
+ </div>`,
+ '<b>a grid of named alarms.</b> Cells light amber to warn, red to fault (faults pulse). Click a cell to cycle its state.');
+card(I,'N24','Jewel pilot lamps',
+ `<span id="jewels" style="display:inline-flex;gap:10px;align-items:center"><span class="jewel" style="--jc:var(--jewel-r)"></span><span class="jewel" style="--jc:var(--jewel-a)"></span>
+ <span class="jewel" style="--jc:var(--jewel-g)"></span><span class="jewel dim"></span></span>`,
+ '<b>a faceted glass indicator.</b> The chunky bezel pilot lamp with a real bloom. Click a jewel to cycle red · amber · green · dark.');
+card(I,'N25','Tape counter',
+ `<span class="counter" id="counter"></span>`,
+ '<b>rolling odometer digits.</b> Numbered wheels roll to the next figure. Rolls live; readout shows the total.');
+card(I,'N26','Analog clock',
+ `<span class="clock" id="clock"><span class="hh" id="clkh"></span><span class="mh" id="clkm"></span><span class="sh" id="clks"></span><span class="pin"></span></span>`,
+ '<b>time on a real face.</b> Engraved ticks, three hands, live seconds sweep. Runs live; readout shows the time.');
+card(I,'N27','Frequency-dial scale',
+ `<span class="freqscale" id="fscale"><span class="band">MHz</span></span>`,
+ '<b>a printed log scale.</b> Marks crowd low, spread high — a real logarithmic axis. Drag the pointer; readout shows the frequency.');
+card(I,'N28','Patch-bay jack field',
+ `<div class="patch" id="patch"></div>`,
+ '<b>routing shown as patches.</b> A grid of jacks with cables between connected pairs. Click one jack then another to add/remove a cable.');
+
+/* ============ CONTROL WIRING ============ */
+/* 01 toggle */
+(function(){const sw=$('toggle01').querySelector('.switch');
+ function upd(){setRd('01',sw.classList.contains('on')?'ON':'OFF');}
+ sw.onclick=()=>{sw.classList.toggle('on');upd();};upd();})();
+/* 02 console key */
+$('keys02').querySelectorAll('.key').forEach(k=>k.onclick=()=>{
+ $('keys02').querySelectorAll('.key').forEach(x=>x.classList.remove('on','red'));
+ k.classList.add(k.textContent==='MUTED'?'red':'on');setRd('02',k.textContent);});
+setRd('02','LIVE');
+/* 03 horizontal fader */
+function setF1(p){const f=$('f1');f.querySelector('.fill').style.width=p+'%';f.querySelector('.cap').style.left=p+'%';setRd('03','level '+Math.round(p));}
+dragX($('f1'),setF1);setF1(68);
+/* 04 vertical faders */
+let vfA=60,vfB=35;
+function vfUpd(){setRd('04','A '+Math.round(vfA)+' · B '+Math.round(vfB));}
+function setVf(el,p){el.querySelector('.fill').style.height=p+'%';el.querySelector('.cap').style.bottom=p+'%';}
+dragY($('v1'),p=>{vfA=p;setVf($('v1'),p);vfUpd();});
+dragY($('v2'),p=>{vfB=p;setVf($('v2'),p);vfUpd();});
+setVf($('v1'),60);setVf($('v2'),35);vfUpd();
+/* 05 knob */
+let knobV=53;
+function setKnob(v){knobV=v;$('kind').style.transform=`rotate(${-150+v/100*300}deg)`;setRd('05','gain '+Math.round(v));}
+dragDelta($('knob'),()=>knobV,setKnob,{min:0,max:100});setKnob(53);
+/* 06 segmented */
+$('seg06').querySelectorAll('button').forEach(b=>b.onclick=()=>{
+ $('seg06').querySelectorAll('button').forEach(x=>x.classList.remove('on'));b.classList.add('on');setRd('06',b.textContent);});
+setRd('06','TIMER');
+/* 07 chip */
+$('chip07').onclick=()=>{$('chip07').classList.toggle('on');setRd('07',$('chip07').classList.contains('on')?'ON':'OFF');};
+setRd('07','ON');
+/* 08 arm */
+let armed=false;
+$('arm').onclick=()=>{const a=$('arm');if(!armed){armed=true;a.classList.add('armed');a.textContent='forget? again';setRd('08','ARMED');}
+ else{armed=false;a.classList.remove('armed');a.textContent='forget';setRd('08','FIRED · reset');}};
+setRd('08','SAFE');
+/* 09 lamp row */
+const lrStates=[['gold','tap to connect'],['busy','connecting…'],['','connected']];let lrI=0;
+$('lrow9').onclick=()=>{lrI=(lrI+1)%3;const s=lrStates[lrI];$('lrow9').querySelector('.lamp').className='lamp '+s[0];
+ $('lrow9').querySelector('.what').textContent=s[1];setRd('09',s[1]);};
+setRd('09','tap to connect');
+/* 24 rotary selector */
+const rotVals=[4,6,8,10,12];let rotIdx=2;const rotAng=[-70,-35,0,35,70];
+$('rotsel24').querySelector('.knob').onclick=()=>{rotIdx=(rotIdx+1)%5;
+ $('rotsel24').querySelector('.ind').style.transform=`rotate(${rotAng[rotIdx]}deg)`;
+ $('rotsel24').querySelectorAll('.pos').forEach((p,i)=>p.classList.toggle('on',i===rotIdx));setRd('24','size '+rotVals[rotIdx]);};
+setRd('24','size 8');
+/* 25 slide-rule */
+const tunVals=[4,6,8,10,12];let tunIdx=2;const tunX=[12,51,90,129,168];
+function setTun(i){tunIdx=Math.max(0,Math.min(tunVals.length-1,i));$('tundl').style.left=tunX[tunIdx]+'px';
+ $('tuner').querySelectorAll('.mk').forEach((m,j)=>m.classList.toggle('on',j===tunIdx));setRd('25','pos '+tunVals[tunIdx]);}
+$('tuner').onclick=(e)=>{const r=$('tuner').getBoundingClientRect(),x=e.clientX-r.left;
+ let best=0,bd=1e9;tunX.forEach((tx,j)=>{const d=Math.abs(tx-x);if(d<bd){bd=d;best=j;}});setTun(best);$('tuner').focus();};
+$('tuner').onkeydown=(e)=>{if(e.key==='ArrowLeft'||e.key==='ArrowDown'){e.preventDefault();setTun(tunIdx-1);}
+ else if(e.key==='ArrowRight'||e.key==='ArrowUp'){e.preventDefault();setTun(tunIdx+1);}};
+setRd('25','pos 8');
+/* N01 rocker */
+$('rocker').onclick=()=>{$('rocker').classList.toggle('on');setRd('N01',$('rocker').classList.contains('on')?'ON':'OFF');};
+setRd('N01','ON');
+/* N02 transport */
+function transport(b){b.parentElement.querySelectorAll('.tbtn').forEach(x=>x.classList.remove('on'));b.classList.add('on');
+ const playing=b.dataset.t==='play';document.querySelectorAll('.reel.spin').forEach(r=>r.style.animationPlayState=playing&&!reduced?'running':'paused');
+ setRd('N02',{rew:'REW',play:'PLAY',stop:'STOP',rec:'REC'}[b.dataset.t]);}
+setRd('N02','PLAY');
+/* N03 radio preset */
+function preset(b){b.parentElement.querySelectorAll('.preset').forEach(x=>x.classList.remove('on'));b.classList.add('on');setRd('N03',b.textContent);}
+setRd('N03','WIFI');
+/* N04 concentric dual knob */
+let dkoV=50,dkiV=50;
+function setDual(){$('dko').style.transform=`rotate(${-150+dkoV/100*300}deg)`;$('dki').style.transform=`rotate(${-150+dkiV/100*300}deg)`;
+ setRd('N04','bass '+Math.round(dkoV)+' · treble '+Math.round(dkiV));}
+dragDelta($('dko'),()=>dkoV,v=>{dkoV=v;setDual();},{min:0,max:100});
+dragDelta($('dki'),()=>dkiV,v=>{dkiV=v;setDual();},{min:0,max:100,stop:true});
+setDual();
+/* N05 encoder */
+let encV=7;
+function paintEnc(){const leds=$('enc').querySelectorAll('.led');const lit=((Math.floor(encV)%12)+12)%12;
+ leds.forEach((l,i)=>l.classList.toggle('on',i<=lit));}
+function setEnc(v){encV=v;paintEnc();const ind=$('enc').querySelector('.knob .ind');if(ind)ind.parentElement.style.transform=`rotate(${encV*30}deg)`;
+ setRd('N05','pos '+Math.round(encV));}
+(function(){const enc=$('enc');const R=27,cx=33,cy=33;
+ for(let i=0;i<12;i++){const a=(i*30-90)*Math.PI/180;const d=document.createElement('span');d.className='led';
+ d.style.left=(cx+R*Math.cos(a))+'px';d.style.top=(cy+R*Math.sin(a))+'px';enc.appendChild(d);}
+ const k=document.createElement('span');k.className='knob';k.innerHTML='<span class="ind"></span>';enc.appendChild(k);})();
+dragDelta($('enc'),()=>encV,setEnc,{min:0,max:100000,sens:0.25});setEnc(7);
+/* N06 keylock */
+let keyIdx=1;const keyAng=[-70,0,70];const keyNm=['OFF','ON','RUN'];
+function keyTurn(){keyIdx=(keyIdx+1)%3;$('kbit').style.transform=`rotate(${keyAng[keyIdx]}deg)`;
+ $('keylock6').querySelectorAll('.kpos').forEach((p,i)=>p.classList.toggle('on',i===keyIdx));setRd('N06',keyNm[keyIdx]);}
+setRd('N06','ON');
+/* N07 crossfader */
+function setXf(p){$('xfcap').style.left=p+'%';const v=Math.round(p-50);setRd('N07',(v>0?'+':'')+v);}
+dragX($('xf'),setXf);setXf(50);
+/* N08 thumbwheel */
+let thumbV=42;
+function setThumb(v){thumbV=Math.round(v);const s=(((thumbV%100)+100)%100);$('thval').textContent=String(s).padStart(2,'0');setRd('N08','value '+s);}
+dragDelta($('thumbwheel'),()=>thumbV,setThumb,{min:0,max:99,sens:0.2});setThumb(42);
+/* N09 DIP */
+function dipUpd(){const bits=[...$('dips').querySelectorAll('.dipsw')].map(x=>x.classList.contains('on')?'1':'0').join('');setRd('N09',bits);}
+function dip(s){s.classList.toggle('on');dipUpd();}
+dipUpd();
+/* N10 jog */
+let jogV=0;
+function setJog(v){jogV=v;$('jogi').style.transform=`rotate(${jogV*4}deg)`;setRd('N10','pos '+Math.round(jogV));}
+dragDelta($('jog10'),()=>jogV,setJog,{min:-100000,max:100000,sens:0.5});setJog(0);
+
+/* ============ METER WIRING (drag-driven) ============ */
+/* 10 needle gauge */
+let gV=50;
+function setGauge(v){gV=v;$('g1').style.transform=`rotate(${-60+v/100*120}deg)`;$('g1v').textContent=Math.round(v);setRd('10','value '+Math.round(v)+'%');}
+dragDelta($('gauge10'),()=>gV,setGauge,{min:0,max:100});setGauge(50);
+/* 13 signal ladder */
+let ladV=3;
+function setLadder(v){ladV=v;const bars=$('ladder').children;
+ for(let i=0;i<bars.length;i++)bars[i].style.background=i<v?'var(--gold)':'var(--wash)';setRd('13',v+'/4');}
+$('ladder').onclick=()=>setLadder((ladV+1)%5);setLadder(3);
+/* 14 fuel bars */
+function setBar(id,no,p){const b=$(id);b.querySelector('span').style.width=p+'%';b.classList.toggle('warn',p<20);setRd(no,Math.round(p)+'%');}
+dragX($('bar14'),p=>setBar('bar14','14',p));dragX($('bar14b'),p=>setBar('bar14b','14',p));
+setBar('bar14','14',72);
+/* 15 radial ring */
+let ringV=68;
+function setRing(v){ringV=v;const r=$('ring15');r.style.setProperty('--p',v);r.querySelector('b').textContent=Math.round(v);setRd('15',Math.round(v)+'%');}
+dragDelta($('ring15'),()=>ringV,setRing,{min:0,max:100});setRing(68);
+/* N13 crossed-needle */
+let cnPow=55;
+function setCross(v){cnPow=v;const fwd=v,rfl=v*0.68;$('cnA').style.transform=`rotate(${-42+fwd/100*84}deg)`;
+ $('cnB').style.transform=`rotate(${42-rfl/100*84}deg)`;setRd('N13','FWD '+Math.round(fwd)+' · RFL '+Math.round(rfl));}
+dragDelta($('crossm13'),()=>cnPow,setCross,{min:0,max:100});setCross(55);
+/* N14 thermometer */
+let thV=58;
+function setThermo(v){thV=v;$('thermf').style.height=v+'%';setRd('N14',Math.round(30+v/100*60)+'°');}
+dragDelta($('thermo14'),()=>thV,setThermo,{min:0,max:100});setThermo(58);
+/* N15 bourdon */
+let bV=45;
+function setBour(v){bV=v;$('bourd').style.transform=`rotate(${-60+v/100*120}deg)`;setRd('N15',Math.round(v/100*160)+' PSI');}
+dragDelta($('bourdon15'),()=>bV,setBour,{min:0,max:100});setBour(45);
+/* N17 correlation */
+function setCorr(p){const v=(p-50)/50;$('corrn').style.transform=`rotate(${v*38}deg)`;setRd('N17',(v>=0?'+':'')+v.toFixed(2));}
+dragX($('corr17'),setCorr);setCorr(58);
+/* N18 battery */
+(function(){const bc=$('battc');for(let i=0;i<8;i++){const c=document.createElement('span');c.className='cell';bc.appendChild(c);}})();
+function setBatt(p){const cells=$('battc').children,lit=Math.round(p/100*cells.length);
+ for(let i=0;i<cells.length;i++)cells[i].className='cell'+(i<lit?' on':'')+((p<=25&&i<lit)?' warn':'');setRd('N18',Math.round(p)+'%');}
+dragX($('batt18'),setBatt);setBatt(62);
+
+/* ============ INDICATOR WIRING ============ */
+/* 18 status lamp */
+(function(){const lst=['lamp','lamp gold','lamp red','lamp off','lamp busy'];const nm=['ok','engaged','fault','off','busy'];
+ $('lamp18').querySelectorAll('.lamp').forEach(l=>{l.style.cursor='pointer';l.onclick=()=>{
+ let i=lst.indexOf(l.className);if(i<0)i=0;i=(i+1)%lst.length;l.className=lst[i];setRd('18',nm[i]);};});})();
+setRd('18','five states');
+/* 19 badge */
+(function(){const bv=['badge','badge red','badge ghost'];
+ $('badge19').querySelectorAll('.badge').forEach(b=>{b.style.cursor='pointer';b.onclick=()=>{
+ let i=bv.indexOf(b.className);if(i<0)i=0;i=(i+1)%bv.length;b.className=bv[i];setRd('19',b.textContent);};});})();
+setRd('19','three variants');
+/* 21 engraved */
+let engN=3;$('engrave').onclick=()=>{engN=engN%9+1;$('engc').textContent='· '+engN;setRd('21','count '+engN);};
+setRd('21','count 3');
+/* 22 output well */
+const owSteps=[['gold','Probe','8.8.8.8 …'],['','Gateway','10.0.0.1 ok'],['','DNS','1.1.1.1 ok'],['red','Retry','timeout']];let owI=0;
+$('owell').onclick=()=>{owI=(owI+1)%owSteps.length;const s=owSteps[owI];const d=document.createElement('div');d.className='ostep';
+ d.innerHTML=`<span class="lamp ${s[0]}"></span><span><b>${s[1]}</b><span class="ev">${s[2]}</span></span>`;
+ $('owell').appendChild(d);while($('owell').children.length>5)$('owell').removeChild($('owell').firstChild);setRd('22','+ '+s[1]);};
+setRd('22','click to stream');
+/* 23 toast */
+const toastMsgs=['link up · 300 Mbps','bt paired — WH-1000XM4','profile switched','joined @Hyatt_WiFi — saved'];let toastN=0;
+$('toast').onclick=()=>{toastN++;$('toast').textContent=toastMsgs[toastN%toastMsgs.length];
+ $('toast').style.opacity='0';requestAnimationFrame(()=>{$('toast').style.transition='opacity .3s';$('toast').style.opacity='1';});setRd('23','fired '+toastN);};
+setRd('23','click to fire');
+/* 26 nixie */
+let nixV=8;
+function setNix(v){nixV=v;const t=$('nixie').children,s=String(v).padStart(2,'0');
+ t[0].classList.toggle('off',v<10);t[0].querySelector('b').textContent=s[0];t[1].querySelector('b').textContent=s[1];setRd('26',s);}
+$('nixie').onclick=()=>setNix((nixV+1)%100);setNix(8);
+/* N23 annunciator */
+(function(){const st=['acell','acell warn','acell fault'];const nm=['ok','warn','fault'];
+ $('annun').querySelectorAll('.acell').forEach(cell=>{const label=cell.textContent;cell.onclick=()=>{
+ let cur=cell.className.trim();let i=st.indexOf(cur);if(i<0)i=0;i=(i+1)%st.length;cell.className=st[i];setRd('N23',label+' → '+nm[i]);};});})();
+setRd('N23','click a cell');
+/* N24 jewel */
+(function(){const cols=['var(--jewel-r)','var(--jewel-a)','var(--jewel-g)'];const nm=['red','amber','green'];
+ $('jewels').querySelectorAll('.jewel').forEach(j=>{j.onclick=()=>{
+ if(j.classList.contains('dim')){j.classList.remove('dim');j.style.setProperty('--jc',cols[0]);setRd('N24','red');return;}
+ let cur=j.style.getPropertyValue('--jc').trim();let i=cols.indexOf(cur);
+ if(i>=cols.length-1||i<0){j.classList.add('dim');setRd('N24','dark');}else{j.style.setProperty('--jc',cols[i+1]);setRd('N24',nm[i+1]);}};});})();
+setRd('N24','click to cycle');
+/* N27 frequency-dial + pointer */
+(function(){const fs=$('fscale');const W=184;const marks=[0.5,1,2,3,5,7,10,14,20];const lo=Math.log10(0.5),hi=Math.log10(20);
+ marks.forEach(m=>{const x=6+((Math.log10(m)-lo)/(hi-lo))*(W-12);
+ const tk=document.createElement('span');tk.className='tick';tk.style.left=x+'px';tk.style.height='11px';fs.appendChild(tk);
+ const mk=document.createElement('span');mk.className='mk';mk.style.left=x+'px';mk.textContent=m;fs.appendChild(mk);});
+ for(let m=0.5;m<=20;m+=(m<2?0.25:m<10?1:2)){const x=6+((Math.log10(m)-lo)/(hi-lo))*(W-12);
+ const tk=document.createElement('span');tk.className='tick';tk.style.left=x+'px';tk.style.height='6px';tk.style.opacity='.5';fs.appendChild(tk);}
+ const ptr=document.createElement('span');ptr.className='fptr';fs.appendChild(ptr);
+ function freqAt(p){return Math.pow(10,lo+(p/100)*(hi-lo));}
+ window.setFreq=function(p){ptr.style.left=(6+p/100*(W-12))+'px';const f=freqAt(p);setRd('N27',(f<10?f.toFixed(1):Math.round(f))+' MHz');};
+ dragX(fs,window.setFreq);window.setFreq(45);})();
+/* N28 patch-bay */
+(function(){const patch=$('patch');const rows=2,cols=4;const jacks=[];
+ for(let r=0;r<rows;r++){const rowEl=document.createElement('div');rowEl.className='row';
+ for(let c=0;c<cols;c++){const j=document.createElement('span');j.className='jack';j.dataset.id=(r*cols+c);rowEl.appendChild(j);jacks.push(j);}
+ patch.appendChild(rowEl);}
+ const svg=document.createElementNS('http://www.w3.org/2000/svg','svg');patch.appendChild(svg);
+ let conns=[];let pending=null;
+ function key(a,b){return Math.min(a,b)+'-'+Math.max(a,b);}
+ function draw(){while(svg.firstChild)svg.removeChild(svg.firstChild);
+ const pr=patch.getBoundingClientRect();
+ jacks.forEach(j=>j.classList.remove('hot'));
+ conns.forEach(pair=>{const[a,b]=pair.split('-').map(Number);
+ const ra=jacks[a].getBoundingClientRect(),rb=jacks[b].getBoundingClientRect();
+ const x1=ra.left-pr.left+ra.width/2,y1=ra.top-pr.top+ra.height/2;
+ const x2=rb.left-pr.left+rb.width/2,y2=rb.top-pr.top+rb.height/2;
+ const p=document.createElementNS('http://www.w3.org/2000/svg','path');
+ const my=Math.max(y1,y2)+16;p.setAttribute('d',`M${x1} ${y1} C${x1} ${my} ${x2} ${my} ${x2} ${y2}`);svg.appendChild(p);
+ jacks[a].classList.add('hot');jacks[b].classList.add('hot');});
+ setRd('N28',conns.length?conns.map(c=>{const[a,b]=c.split('-');return a+'↔'+b;}).join(' '):'no cables');}
+ jacks.forEach(j=>{j.onclick=()=>{const id=+j.dataset.id;
+ if(pending==null){pending=id;j.classList.add('sel');return;}
+ if(pending===id){pending=null;j.classList.remove('sel');return;}
+ const k=key(pending,id);const i=conns.indexOf(k);if(i>=0)conns.splice(i,1);else conns.push(k);
+ jacks[pending].classList.remove('sel');pending=null;draw();};});
+ conns=['0-5','2-7'];draw();window.addEventListener('resize',draw);})();
+
+/* ============ LIVE SIGNAL LOOPS ============ */
+buildBars($('vuL'),16);buildBars($('vuR'),16);$('mini').innerHTML='<i></i><i></i><i></i><i></i>';
+(function(){const eq=$('eq');for(let b=0;b<11;b++){const band=document.createElement('span');band.className='band';
+ for(let s=0;s<9;s++)band.appendChild(document.createElement('i'));eq.appendChild(band);}})();
+(function(){const cl=$('clock');for(let i=0;i<12;i++){const t=document.createElement('span');t.className='tk';
+ t.style.transform=`rotate(${i*30}deg)`;cl.insertBefore(t,cl.firstChild);}})();
+const counterDigits=[4,7,1,3,0,0];
+(function(){const ct=$('counter');counterDigits.forEach((d,idx)=>{const w=document.createElement('span');
+ w.className='cwheel'+(idx>=4?' redw':'');const col=document.createElement('span');col.className='col';
+ for(let n=-1;n<=10;n++){const s=document.createElement('span');s.textContent=((n+10)%10);col.appendChild(s);}
+ w.appendChild(col);ct.appendChild(w);setWheel(w,d);});})();
+function setWheel(w,d){w.querySelector('.col').style.top=(-(d+1)*34)+'px';}
+
+let ph=0;
+const hist=Array.from({length:40},()=>0.5);
+const eqBands=Array.from({length:11},(_,i)=>({v:0.4,ph:i*0.6}));
+const stripHist=Array.from({length:60},()=>31);
+const pkL={v:0},pkR={v:0};
+function paintVU(el,l,pk){const b=el.children,n=b.length,lit=Math.round(l*n);
+ pk.v=Math.max(lit,(pk.v||0)-0.4);const p=Math.round(pk.v);
+ for(let k=0;k<n;k++){let c=k<lit?(k>=n-2?'clip':k>=n-4?'hot':'on'):'';if(p>0&&k===p-1)c=(c?c+' ':'')+'peak';b[k].className=c;}}
+function paintMini(el,l){const b=el.children,lit=Math.round(l*4);for(let k=0;k<4;k++)b[k].className=k<lit?(k>=3?'clip':k>=2?'hot':'on'):'';}
+function paintEq(){const bands=$('eq').children;let peak=0;
+ for(let b=0;b<bands.length;b++){const cells=bands[b].children,n=cells.length,val=eqBands[b].v;const lit=Math.round(val*n);peak=Math.max(peak,val);
+ for(let k=0;k<n;k++){let c='';if(k<lit)c=(k>=n-1?'clip':k>=n-3?'hot':'on');cells[k].className=c?c:'';}}return peak;}
+function lvl(){return Math.max(0,Math.min(1,0.5+0.4*Math.sin(ph*1.3)+(Math.random()<0.15?Math.random()*0.4:0)-Math.random()*0.08));}
+function fastTick(){
+ ph+=0.09;
+ const a=lvl(),b=lvl();
+ paintVU($('vuL'),a,pkL);paintVU($('vuR'),b,pkR);paintMini($('mini'),a);
+ setRd('11','L '+Math.round(a*100)+' · R '+Math.round(b*100));
+ setRd('12',Math.round(a*100)+'%');
+ hist.push(0.5+0.42*Math.sin(ph*0.9)+(Math.random()-0.5)*0.25);hist.shift();
+ $('sparkp').setAttribute('points',hist.map((v,i)=>`${i/(hist.length-1)*170},${44-Math.max(0,Math.min(1,v))*40-2}`).join(' '));
+ setRd('16',Math.round(Math.max(0,Math.min(1,hist[hist.length-1]))*100));
+ let d='M0 19';const env=Math.min(1,0.6+0.3*Math.sin(ph*0.4));
+ for(let x=0;x<=170;x+=3){const y=19+Math.sin(x*0.18+ph*3)*Math.sin(x*0.05)*14;d+=` L${x} ${y.toFixed(1)}`;}
+ $('wavep').setAttribute('d',d);setRd('17','amp '+Math.round(env*100)+'%');
+ let sp='';for(let x=0;x<=176;x+=3){const y=39+Math.sin(x*0.16+ph*3.2)*Math.min(1,0.6+0.3*Math.sin(ph*0.4))*22;sp+=`${x},${y.toFixed(1)} `;}
+ $('scopep').setAttribute('points',sp.trim());setRd('N11','Vpp '+Math.round((0.6+0.3*Math.sin(ph*0.4))*100));
+ eqBands.forEach(bd=>{bd.ph+=0.16;bd.v=Math.max(0.05,Math.min(1,0.5+0.42*Math.sin(bd.ph)+(Math.random()<0.2?Math.random()*0.3:0)-Math.random()*0.06));});
+ const peak=paintEq();setRd('N12','peak '+Math.round(peak*100)+'%');
+ stripHist.push(31-24*Math.sin(ph*0.7)*(0.6+0.4*Math.sin(ph*0.13))+(Math.random()-0.5)*4);stripHist.shift();
+ const last=Math.max(3,Math.min(59,stripHist[stripHist.length-1]));
+ $('stripp').setAttribute('points',stripHist.map((v,i)=>`${i/(stripHist.length-1)*176},${Math.max(3,Math.min(59,v)).toFixed(1)}`).join(' '));
+ $('strippen').style.top=last+'px';setRd('N16',Math.round((59-last)/56*100));
+}
+/* clock */
+function tickClock(){const d=new Date();const s=d.getSeconds(),m=d.getMinutes(),h=d.getHours()%12;
+ $('clks').style.transform=`rotate(${s*6}deg)`;$('clkm').style.transform=`rotate(${m*6+s*0.1}deg)`;$('clkh').style.transform=`rotate(${h*30+m*0.5}deg)`;
+ setRd('N26',String(d.getHours()).padStart(2,'0')+':'+String(m).padStart(2,'0')+':'+String(s).padStart(2,'0'));}
+/* split-flap */
+const flapWords=['DNS ','LINK','SYNC','WIFI','SCAN'];let flapI=0;
+function tickFlap(){flapI=(flapI+1)%flapWords.length;const w=flapWords[flapI].padEnd(4,' ');
+ $('flap').querySelectorAll('.flapd').forEach((dd,i)=>{const ch=w[i]||' ';const bel=dd.querySelector('b');
+ if(bel.textContent!==ch){bel.textContent=ch;if(!reduced){dd.classList.remove('flip');void dd.offsetWidth;dd.classList.add('flip');}}});
+ setRd('N20',flapWords[flapI].trim());}
+$('flap').onclick=tickFlap;
+/* seven-segment countdown */
+let sevenSecs=24*60+10;
+function renderSeven(){const mm=String(Math.floor(sevenSecs/60)).padStart(2,'0'),ss=String(sevenSecs%60).padStart(2,'0');
+ $('seven').innerHTML=seg7(mm[0])+seg7(mm[1])+'<span class="colon"><i></i><i></i></span>'+seg7(ss[0])+seg7(ss[1]);setRd('N21',mm+':'+ss);}
+function tickSeven(){sevenSecs=(sevenSecs-1+3600)%3600;renderSeven();}
+$('seven').onclick=()=>{sevenSecs=(sevenSecs+60)%3600;renderSeven();};
+renderSeven();
+/* tabular timer */
+let tSecs=24*60+10,tRun=true;
+function renderT(){$('treadout').textContent=String(Math.floor(tSecs/60)).padStart(2,'0')+':'+String(tSecs%60).padStart(2,'0');
+ setRd('20',tRun?'running':'paused');}
+function tickT(){if(tRun){tSecs=(tSecs-1+3600)%3600;renderT();}}
+$('treadout').onclick=()=>{tRun=!tRun;renderT();};renderT();
+/* VFD marquee */
+const vfdMsgs=['ARCHSETUP · NET OK · BT 2 · SND 62%','WIFI @Hyatt · 300 Mbps · VPN UP','BATTERY 84% · DISK 61% · TEMP 47C'];let vfdMi=0,vfdX=176;
+function tickVfd(){const t=$('vfdt');vfdX-=1.1;if(vfdX< -t.offsetWidth)vfdX=176;t.style.left=vfdX+'px';}
+$('vfdm').onclick=()=>{vfdMi=(vfdMi+1)%vfdMsgs.length;$('vfdt').textContent=vfdMsgs[vfdMi];vfdX=176;setRd('N22','msg '+(vfdMi+1)+'/'+vfdMsgs.length);};
+setRd('N22','scrolling');
+/* tape counter */
+let ctrVal=471300;
+function tickCounter(){ctrVal+=137;const s=String(ctrVal).padStart(6,'0');
+ $('counter').querySelectorAll('.cwheel').forEach((w,i)=>setWheel(w,+s[i]));setRd('N25',s);}
+setRd('N25',String(ctrVal).padStart(6,'0'));
+
+/* reels spin keyframe */
+(function(){const st=document.createElement('style');st.textContent='@keyframes reelspin{to{transform:rotate(360deg)}}';document.head.appendChild(st);})();
+document.querySelectorAll('.reel.spin').forEach(r=>{r.style.animation='reelspin 2.6s linear infinite';});
+
+/* static paint for reduced motion */
+function paintStatic(){
+ paintVU($('vuL'),0.55,pkL);paintVU($('vuR'),0.5,pkR);paintMini($('mini'),0.55);
+ setRd('11','L 55 · R 50');setRd('12','55%');
+ $('sparkp').setAttribute('points',hist.map((v,i)=>`${i/(hist.length-1)*170},${44-0.5*40-2}`).join(' '));setRd('16','50');
+ $('wavep').setAttribute('d','M0 19 L170 19');setRd('17','amp 60%');
+ eqBands.forEach((bd,i)=>bd.v=0.3+0.5*Math.abs(Math.sin(i*0.9)));setRd('N12','peak '+Math.round(paintEq()*100)+'%');
+ $('scopep').setAttribute('points',Array.from({length:60},(_,i)=>`${i*3},${39+Math.sin(i*0.5)*18}`).join(' '));setRd('N11','Vpp 74');
+ $('stripp').setAttribute('points',stripHist.map((v,i)=>`${i/(stripHist.length-1)*176},${31-Math.sin(i*0.3)*16}`).join(' '));setRd('N16','50');
+ tickClock();renderSeven();setRd('N20','DNS');setRd('N22','scrolling');setRd('N25',String(ctrVal).padStart(6,'0'));
+}
+
+if(!reduced){
+ setInterval(fastTick,80);
+ setInterval(tickClock,1000);tickClock();
+ setInterval(tickFlap,1500);
+ setInterval(tickVfd,32);
+ setInterval(tickCounter,1600);
+ setInterval(tickSeven,1000);
+ setInterval(tickT,1000);
+ document.querySelectorAll('.reel.spin').forEach(r=>r.style.animationPlayState='running');
+}else{
+ paintStatic();
+ document.querySelectorAll('.reel.spin').forEach(r=>r.style.animationPlayState='paused');
+}
+</script>
+</body>
+</html>