aboutsummaryrefslogtreecommitdiff
path: root/docs/prototypes/panel-widget-gallery.html
diff options
context:
space:
mode:
Diffstat (limited to 'docs/prototypes/panel-widget-gallery.html')
-rw-r--r--docs/prototypes/panel-widget-gallery.html2182
1 files changed, 2182 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..9dab675
--- /dev/null
+++ b/docs/prototypes/panel-widget-gallery.html
@@ -0,0 +1,2182 @@
+<!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{
+/* @tokens:start */
+ /* generated from tokens.json by gen_tokens.py — edit tokens.json, then run: python3 gen_tokens.py */
+ --ground:#151311;
+ --panel:#100f0f;
+ --well:#0a0c0d;
+ --raise:#1a1917;
+ --silver:#bfc4d0;
+ --cream:#f3e7c5;
+ --steel:#969385;
+ --dim:#7c838a;
+ --slate:#424f5e;
+ --slate-hi:#54677d;
+ --wash:#2c2f32;
+ --pass:#74932f;
+ --fail:#cb6b4d;
+ --phos:#7fe0a0;
+ --phos-dim:#1c3626;
+ --vfd:#63e6c8;
+ --sevgrn:#57d357;
+ --sevred:#e2543f;
+ --sevoff:#1a1613;
+ --jewel-r:#ff5b45;
+ --jewel-a:#ffb43a;
+ --jewel-g:#6fce33;
+ --gold:#e2a038;
+ --gold-hi:#ffbe54;
+ --amber-grad-top:#f2c76a;
+ --amber-grad-mid:#d29638;
+ --amber-grad-bot:#8f671f;
+ --amber-edge:#7d5c16;
+ --amber-warn:#f0b552;
+ --glow-hi:255,190,84;
+ --glow-lo:226,160,56;
+ --mono:"BerkeleyMono Nerd Font","Berkeley Mono",monospace;
+ --pulse-rate:1s;
+/* @tokens:end */
+}
+*{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(var(--glow-lo),.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 var(--pulse-rate) 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,var(--amber-grad-top),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,var(--amber-grad-bot),var(--gold))}
+.fader .cap{position:absolute;top:1px;width:7px;height:14px;border-radius:2px;margin-left:-3.5px;
+ background:linear-gradient(180deg,var(--amber-grad-top),var(--amber-grad-mid));border:1px solid var(--amber-edge);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,var(--amber-grad-bot),var(--gold))}
+.vfader .cap{position:absolute;left:1px;height:7px;width:14px;border-radius:2px;margin-top:-3.5px;
+ background:linear-gradient(90deg,var(--amber-grad-mid),var(--amber-grad-top));border:1px solid var(--amber-edge)}
+
+/* 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(var(--glow-hi),.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%;top:1px;width:1.5px;height:8px;margin-left:-.75px;background:var(--steel);transform-origin:50% 47px}
+.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(var(--glow-hi),.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,var(--amber-grad-bot),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,var(--amber-grad-top),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(var(--glow-hi),.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(var(--glow-lo),.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(var(--glow-hi),.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,var(--amber-grad-top),var(--gold));color:var(--panel);font-weight:700;box-shadow:0 0 10px rgba(var(--glow-hi),.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(var(--glow-hi),.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,var(--amber-grad-top),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,var(--amber-grad-top),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(var(--glow-hi),.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(var(--glow-lo),.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(var(--glow-hi),.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(var(--glow-hi),.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,var(--amber-grad-top),var(--amber-grad-mid));border:1px solid var(--amber-edge);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,var(--amber-grad-top),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(var(--glow-hi),.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(var(--glow-hi),.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(var(--glow-hi),.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(var(--glow-hi),.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,var(--amber-warn),var(--gold));font-weight:700;box-shadow:0 0 8px rgba(var(--glow-lo),.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 var(--pulse-rate) 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(var(--glow-hi),.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(var(--glow-lo),.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%,var(--amber-edge),#1a1408 70%)}
+.patch .jack.sel{border-color:var(--gold-hi);box-shadow:0 0 6px 1px rgba(var(--glow-hi),.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}
+
+/* ===== reference-batch (R) widgets — SVG-first, after period hardware ===== */
+.rsvg{display:block}
+.rsvg.drag{cursor:ns-resize;touch-action:none}
+.rsvg.press{cursor:pointer}
+
+@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,
+ the candidate batch, and the growing reference batch (R: modeled on period hardware), all 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.');
+card(C,'R02','Calibrated vernier dial',
+ `<svg id="vern" class="rsvg drag" viewBox="0 0 150 150" width="150" height="150"></svg>`,
+ '<b>precision on a rotating disc.</b> The big lab dial — the calibrated disc turns under a fixed hairline. Drag up/down; readout reads to a tenth. After a 1950s lab-oscillator vernier.');
+card(C,'R03','Bat-handle toggle',
+ `<svg id="batsw" class="rsvg press" viewBox="0 0 70 90" width="70" height="90"></svg>`,
+ '<b>the period power switch.</b> Chrome bat lever on a hex bushing, snaps up ON / down OFF. Click to throw it. After a lab-instrument panel toggle.');
+card(C,'R04','Bakelite fluted knob',
+ `<svg id="bakek" class="rsvg drag" viewBox="0 0 110 110" width="110" height="110"></svg>`,
+ '<b>the skirted console knob.</b> Scalloped bakelite skirt, glossy dome, amber index over a printed 0-10 scale. Drag up/down to turn. After a vintage console mixer knob.');
+card(C,'R05','Filter slider bank',
+ `<svg id="fbank" class="rsvg" viewBox="0 0 190 96" width="190" height="96"></svg>`,
+ '<b>a wall of band faders.</b> One slider per band, arrow-head caps on black tracks, dB rail at the side. Drag any cap; readout names band and level. After a variable multi-band filter.');
+card(C,'R06','Chicken-head selector',
+ `<svg id="chick" class="rsvg press" viewBox="0 0 110 96" width="110" height="96"></svg>`,
+ '<b>the pointer-lever switch.</b> The tapered bakelite lever IS the indicator — it aims at the engraved position. Click to step through. After a modulator mode switch.');
+card(C,'R12','Chrome slot fader',
+ `<svg id="slotf" class="rsvg drag" viewBox="0 0 90 150" width="90" height="150"></svg>`,
+ '<b>the console gain slide.</b> A chrome T-handle rides a recessed slot, the dB scale engraved on the plate — gain above zero, cut below. Drag; readout shows signed dB. After a vintage channel-strip output fader.');
+card(C,'R14','Spade-pointer tuning knob',
+ `<svg id="spade" class="rsvg drag" viewBox="0 0 140 124" width="140" height="124"></svg>`,
+ '<b>the pointer rides the knob.</b> A knurled bakelite knob carries a bright spade pointer over a scale engraved into the panel itself. Drag up/down to tune. After a 1920s radio receiver dial.');
+card(C,'R15','Multi-band dial',
+ `<svg id="mband" class="rsvg" viewBox="0 0 190 110" width="190" height="110"></svg>`,
+ '<b>four scales, one needle.</b> Nested band arcs on a cream face; the active ring reads bold. Drag the left dial to tune; click the bandspread dial to switch bands. After a shortwave receiver dial pair.');
+card(C,'R16','Entry keypad',
+ `<svg id="keypad" class="rsvg" viewBox="0 0 150 190" width="150" height="190"></svg>`,
+ '<b>a composed entry instrument.</b> Worn keycaps feed the amber display; the lamp watches the buffer; the amber keys confirm and clear. Click the keys. After an industrial keypad prop.');
+card(C,'R18','Thumb-slide attenuator pair',
+ `<svg id="thumbsl" class="rsvg" viewBox="0 0 130 150" width="130" height="150"></svg>`,
+ '<b>a lit column of numbers, a thumb tab.</b> The scale glows inside the rail; the cream tab rides beside it and the nearest figure lights. Drag either channel. After a compressor blend/mix pair.');
+card(C,'R19','Waveform region editor',
+ `<svg id="wregion" class="rsvg" viewBox="0 0 190 100" width="190" height="100"></svg>`,
+ '<b>pick a region on the wave.</b> The monochrome LCD shows the sample; drag near either flag to move START or END, and the selection draws bright. After a sampler edit screen.');
+card(C,'R20','Drum roller selector',
+ `<svg id="drumr" class="rsvg" viewBox="0 0 130 140" width="130" height="140"></svg>`,
+ '<b>roll to the number.</b> The numbered drum shows through a tall window and the center value sits on an inverted chip. Drag either drum. After an equalizer tone selector.');
+card(C,'R21','LED program row',
+ `<svg id="ledrow" class="rsvg" viewBox="0 0 190 58" width="190" height="58"></svg>`,
+ '<b>identical keys, one lit dot.</b> The LED above the button carries the selection, not the key itself — the classic program-select row. Click a key; readout names the program. After a digital reverb’s program bank.');
+card(C,'R22','Three-position slide',
+ `<svg id="varslide" class="rsvg press" viewBox="0 0 110 64" width="110" height="64"></svg>`,
+ '<b>a detented pill, three stops.</b> The chrome pill parks at A, AB, or B, and the LED pair below tells the truth — both light on AB. Click a position. After a drum machine variation switch.');
+card(C,'R23','Spun-aluminum knob',
+ `<svg id="spunk" class="rsvg drag" viewBox="0 0 110 110" width="110" height="110"></svg>`,
+ '<b>bright metal, machined rings.</b> A spun face with concentric tooling marks in a knurled grip ring, red index over dot ticks. Drag up/down. After a boutique pedal knob, confirmed by an avionics cluster.');
+card(C,'R24','Stomp switch + jewel',
+ `<svg id="stomp" class="rsvg press" viewBox="0 0 110 110" width="110" height="110"></svg>`,
+ '<b>the engage pair.</b> A chrome dome stomp and the faceted jewel that reports it — press to engage, the jewel lights; press again to bypass. Click it. After a tremolo pedal footswitch.');
+card(C,'R27','Winged gain selector',
+ `<svg id="wingk" class="rsvg drag" viewBox="0 0 110 110" width="110" height="110"></svg>`,
+ '<b>the red T-bar, stepped.</b> A bar-grip handle over a dot ring, snapping between labeled gain detents. Drag up/down to step it. After a classic mic-preamp gain switch.');
+card(C,'R28','Rotary disc switch',
+ `<svg id="discsw" class="rsvg press" viewBox="0 0 110 116" width="110" height="116"></svg>`,
+ '<b>the master power disc.</b> The whole red disc turns, grip bar molded in — a heavy three-position selector for OFF, ON, and COMBINE. Click to step. After a marine battery switch.');
+card(C,'R29','Guarded toggle',
+ `<svg id="guardsw" class="rsvg press" viewBox="0 0 90 100" width="90" height="100"></svg>`,
+ '<b>friction sized to consequence.</b> Guard posts flank the lever and a red collar marks it critical — the avionics way to prevent an accidental throw. Click to throw it deliberately. After a flight-deck switch panel.');
+
+/* ============ 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 %.');
+card(M,'R01','Moving-coil VU meter',
+ `<svg id="mcvu" class="rsvg" viewBox="0 0 150 96" width="150" height="96"></svg>`,
+ '<b>the classic cream-faced VU.</b> Printed dB arc, red zone past 0, ballistic needle. Runs the live signal; readout shows VU. After a vintage console meter pair.');
+card(M,'R07','Round panel meter',
+ `<svg id="rndm" class="rsvg drag" viewBox="0 0 110 104" width="110" height="104"></svg>`,
+ '<b>the porthole lab meter.</b> Cream dial in a round black bezel, printed dB arc, black needle. Drag up/down to drive it; readout shows dB. After a modulator front meter.');
+card(M,'R08','Chrome MIN/MAX indicator',
+ `<svg id="chrmm" class="rsvg drag" viewBox="0 0 110 104" width="110" height="104"></svg>`,
+ '<b>the hi-fi trim window.</b> Polished chrome ring, brushed dome, a dark pointer sweeping MIN to MAX over the metal. Drag up/down; readout shows the position. After a hi-fi amplifier level window.');
+card(M,'R09','Black-face aviation gauge',
+ `<svg id="avgauge" class="rsvg drag" viewBox="0 0 110 104" width="110" height="104"></svg>`,
+ '<b>amber on black, zone-marked.</b> The cockpit round: amber ticks and numerals on a black face, painted caution and limit sectors, amber needle. Drag up/down; readout tracks. After a flight-instrument cluster.');
+card(M,'R13','Edgewise strip meter',
+ `<svg id="edgem" class="rsvg drag" viewBox="0 0 70 130" width="70" height="130"></svg>`,
+ '<b>a needle on a vertical scale.</b> The parchment strip reads attenuation down a compressed log scale; the bar rides its edge. Drag up/down; readout shows dB. After a channel-strip gain-reduction meter.');
+card(M,'R17','Round CRT scope',
+ `<svg id="rcrt" class="rsvg" viewBox="0 0 110 104" width="110" height="104"></svg>`,
+ '<b>the round-tube scope.</b> Pale phosphor face in a screwed porthole bezel, dark graticule, a bright live trace. Runs live; readout shows Vpp. After a 1950s bench oscilloscope.');
+
+/* ============ 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.');
+card(I,'R10','Data matrix readout',
+ `<svg id="dmx" class="rsvg press" viewBox="0 0 190 74" width="190" height="74"></svg>`,
+ '<b>a page of amber fields.</b> The console data block — several labeled values on one lit matrix. Click to cycle pages; readout names the page. After a cockpit data readout.');
+card(I,'R11','Warning flag window',
+ `<svg id="wflag" class="rsvg press" viewBox="0 0 120 64" width="120" height="64"></svg>`,
+ '<b>the mechanical alarm flag.</b> A striped barber-pole slides into a window when the condition trips — not a lamp, a flag. Click to trip and clear it. After the VIB flag on an altimeter.');
+card(I,'R25','Fourteen-segment display',
+ `<svg id="seg14" class="rsvg press" viewBox="0 0 130 54" width="130" height="54"></svg>`,
+ '<b>segments that spell.</b> The starburst alphanumeric — diagonals and split bars let it write words, not just digits. Click to cycle the word. After a pedal preset display.');
+card(I,'R26','Response graph',
+ `<svg id="rgraph" class="rsvg" viewBox="0 0 190 110" width="190" height="110"></svg>`,
+ '<b>a curve on labeled axes.</b> Log frequency across, dB up the side, and the amber peak is yours to place — drag it anywhere on the plot. After the response display of a mastering processor.');
+
+/* ============ 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);})();
+
+/* ============ REFERENCE-BATCH (R) WIDGETS — SVG builders ============ */
+const SVGNS='http://www.w3.org/2000/svg';
+function svgEl(parent,tag,attrs){const e=document.createElementNS(SVGNS,tag);
+ for(const k in attrs)e.setAttribute(k,attrs[k]);parent.appendChild(e);return e;}
+function polar(cx,cy,r,deg){const a=deg*Math.PI/180;return [cx+r*Math.sin(a),cy-r*Math.cos(a)];}
+
+/* R01 moving-coil VU: pivot below the face, authentic nonlinear dB scale */
+const VUDB=[[-20,0],[-10,.20],[-7,.31],[-5,.40],[-3,.50],[-2,.58],[-1,.66],[0,.75],[1,.84],[2,.91],[3,1]];
+const mcvu={t:.35,needle:null};
+(function(){const s=$('mcvu'),cx=75,cy=112,sweep=t=>-43+t*86;
+ const defs=svgEl(s,'defs',{});
+ const g1=svgEl(defs,'linearGradient',{id:'vuGlass',x1:0,y1:0,x2:0,y2:1});
+ svgEl(g1,'stop',{offset:'0','stop-color':'rgba(255,255,255,.13)'});
+ svgEl(g1,'stop',{offset:'.35','stop-color':'rgba(255,255,255,0)'});
+ const clip=svgEl(defs,'clipPath',{id:'vuFace'});
+ svgEl(clip,'rect',{x:8,y:8,width:134,height:74,rx:3});
+ svgEl(s,'rect',{x:.5,y:.5,width:149,height:95,rx:7,fill:'#16130f',stroke:'#060505'});
+ svgEl(s,'rect',{x:8,y:8,width:134,height:74,rx:3,fill:'var(--cream)'});
+ const face=svgEl(s,'g',{'clip-path':'url(#vuFace)'});
+ const arcPt=t=>polar(cx,cy,58,sweep(t));
+ const [ax1,ay1]=arcPt(0),[ax2,ay2]=arcPt(1);
+ svgEl(face,'path',{d:`M ${ax1} ${ay1} A 58 58 0 0 1 ${ax2} ${ay2}`,fill:'none',stroke:'#3a3128','stroke-width':1.2});
+ const [rx1,ry1]=arcPt(.75);
+ svgEl(face,'path',{d:`M ${rx1} ${ry1} A 58 58 0 0 1 ${ax2} ${ay2}`,fill:'none',stroke:'var(--fail)','stroke-width':3.5});
+ for(const [db,t] of VUDB){const a=sweep(t),[x1,y1]=polar(cx,cy,55,a),[x2,y2]=polar(cx,cy,63,a);
+ svgEl(face,'line',{x1,y1,x2,y2,stroke:db>0?'var(--fail)':'#3a3128','stroke-width':1.1});}
+ for(const [db,t] of VUDB){if(![-20,-10,-5,-3,0,1,2,3].includes(db))continue;
+ const [x,y]=polar(cx,cy,69,sweep(t));
+ svgEl(face,'text',{x,y:y+2,'text-anchor':'middle','font-size':5.8,'font-family':'var(--mono)',
+ fill:db>0?'var(--fail)':'#3a3128'}).textContent=Math.abs(db);}
+ svgEl(face,'text',{x:75,y:78,'text-anchor':'middle','font-size':11,'font-weight':700,
+ 'font-family':'var(--mono)',fill:'#3a3128'}).textContent='VU';
+ mcvu.needle=svgEl(face,'line',{x1:cx,y1:cy,x2:cx,y2:cy-62,stroke:'#1a1613','stroke-width':1.6,
+ transform:`rotate(${sweep(.35)},${cx},${cy})`});
+ svgEl(face,'circle',{cx,cy:88,r:9,fill:'#16130f'});
+ svgEl(s,'rect',{x:8,y:8,width:134,height:74,rx:3,fill:'url(#vuGlass)'});
+ mcvu.sweep=sweep;})();
+function setMcVu(t){t=Math.max(0,Math.min(1.02,t));mcvu.t=t;
+ mcvu.needle.setAttribute('transform',`rotate(${mcvu.sweep(Math.min(1,t))},75,112)`);
+ const db=vuDb(Math.min(1,t));
+ setRd('R01',(db>0?'+':'')+db.toFixed(1)+' VU');}
+function tickMcVu(){const a=lvl();const target=Math.min(1.02,a*1.12);
+ setMcVu(mcvu.t+(target-mcvu.t)*(target>mcvu.t?0.32:0.10));}
+
+/* R02 calibrated vernier dial: the disc turns under a fixed hairline */
+let vernV=42.0,vernDisc=null;
+(function(){const s=$('vern'),cx=75,cy=75;
+ const defs=svgEl(s,'defs',{});
+ const fg=svgEl(defs,'radialGradient',{id:'vernFace',cx:'50%',cy:'45%',r:'60%'});
+ svgEl(fg,'stop',{offset:'0','stop-color':'#f7f2da'});
+ svgEl(fg,'stop',{offset:'1','stop-color':'#e4dfc2'});
+ const bk=svgEl(defs,'radialGradient',{id:'bakeKnob',cx:'42%',cy:'36%',r:'75%'});
+ svgEl(bk,'stop',{offset:'0','stop-color':'#37332c'});
+ svgEl(bk,'stop',{offset:'1','stop-color':'#060505'});
+ svgEl(s,'circle',{cx,cy,r:72,fill:'#0c0b0a',stroke:'#262320'});
+ vernDisc=svgEl(s,'g',{});
+ svgEl(vernDisc,'circle',{cx,cy,r:66,fill:'url(#vernFace)',stroke:'#b7b29a','stroke-width':1});
+ for(let u=0;u<=100;u++){const a=u*3,major=u%10===0,half=u%5===0;
+ const len=major?10:half?7:4.5,[x1,y1]=polar(cx,cy,63,a),[x2,y2]=polar(cx,cy,63-len,a);
+ svgEl(vernDisc,'line',{x1,y1,x2,y2,stroke:'#3a3128','stroke-width':major?1.3:half?1:.7});
+ if(major){const g=svgEl(vernDisc,'g',{transform:`rotate(${a},${cx},${cy})`});
+ svgEl(g,'text',{x:cx,y:cy-44,'text-anchor':'middle','font-size':7.5,'font-family':'var(--mono)',
+ fill:'#3a3128'}).textContent=u;}}
+ for(let k=0;k<12;k++){const [x,y]=polar(cx,cy,24,k*30);
+ svgEl(s,'circle',{cx:x,cy:y,r:4.8,fill:'url(#bakeKnob)'});}
+ svgEl(s,'circle',{cx,cy,r:24,fill:'url(#bakeKnob)',stroke:'#000','stroke-width':.6});
+ svgEl(s,'circle',{cx,cy,r:16,fill:'url(#bakeKnob)'});
+ svgEl(s,'ellipse',{cx:69,cy:66,rx:7,ry:4,fill:'rgba(255,255,255,.10)',transform:'rotate(-32,69,66)'});
+ svgEl(s,'line',{x1:cx,y1:6,x2:cx,y2:22,stroke:'var(--fail)','stroke-width':2.2,'stroke-linecap':'round'});})();
+function setVern(v){vernV=v;vernDisc.setAttribute('transform',`rotate(${-v*3},75,75)`);setRd('R02',v.toFixed(1));}
+dragDelta($('vern'),()=>vernV,setVern,{min:0,max:100,sens:0.15});setVern(42.0);
+
+/* R03 bat-handle toggle */
+let batOn=true,batLever=null,batLblOn=null,batLblOff=null;
+(function(){const s=$('batsw'),cx=35,cy=44;
+ const defs=svgEl(s,'defs',{});
+ const ng=svgEl(defs,'linearGradient',{id:'nutG',x1:0,y1:0,x2:0,y2:1});
+ svgEl(ng,'stop',{offset:'0','stop-color':'#8a8578'});
+ svgEl(ng,'stop',{offset:'1','stop-color':'#4e4a42'});
+ const cg=svgEl(defs,'linearGradient',{id:'chromeG',x1:0,y1:0,x2:1,y2:0});
+ svgEl(cg,'stop',{offset:'0','stop-color':'#7e7a70'});
+ svgEl(cg,'stop',{offset:'.45','stop-color':'#e8e5db'});
+ svgEl(cg,'stop',{offset:'1','stop-color':'#8a867c'});
+ const tg=svgEl(defs,'radialGradient',{id:'tipG',cx:'40%',cy:'32%',r:'75%'});
+ svgEl(tg,'stop',{offset:'0','stop-color':'#f2efe8'});
+ svgEl(tg,'stop',{offset:'1','stop-color':'#7e7a70'});
+ batLblOn=svgEl(s,'text',{x:cx,y:9,'text-anchor':'middle','font-size':7,'letter-spacing':'.1em',
+ 'font-family':'var(--mono)',fill:'var(--gold-hi)'});batLblOn.textContent='ON';
+ batLblOff=svgEl(s,'text',{x:cx,y:87,'text-anchor':'middle','font-size':7,'letter-spacing':'.1em',
+ 'font-family':'var(--mono)',fill:'var(--dim)'});batLblOff.textContent='OFF';
+ const pts=[];for(let k=0;k<6;k++){const a=(k*60+30)*Math.PI/180;pts.push((cx+17*Math.cos(a))+','+(cy+17*Math.sin(a)));}
+ svgEl(s,'polygon',{points:pts.join(' '),fill:'url(#nutG)',stroke:'#2b2822'});
+ svgEl(s,'circle',{cx,cy,r:9,fill:'#14110e',stroke:'#000'});
+ batLever=svgEl(s,'g',{});
+ svgEl(batLever,'path',{d:`M ${cx-3.2} ${cy} L ${cx-1.8} 21 L ${cx+1.8} 21 L ${cx+3.2} ${cy} Z`,fill:'url(#chromeG)',stroke:'#4e4a42','stroke-width':.5});
+ svgEl(batLever,'ellipse',{cx,cy:17,rx:6.5,ry:8,fill:'url(#tipG)',stroke:'#5e5a52','stroke-width':.6});
+ batLever.style.transformOrigin=`${cx}px ${cy}px`;batLever.style.transition='transform .12s';
+ $('batsw').onclick=()=>setBat(!batOn);})();
+function setBat(on){batOn=on;batLever.style.transform=on?'rotate(0deg)':'rotate(180deg)';
+ batLblOn.setAttribute('fill',on?'var(--gold-hi)':'var(--dim)');
+ batLblOff.setAttribute('fill',on?'var(--dim)':'var(--gold-hi)');setRd('R03',on?'ON':'OFF');}
+setBat(true);
+
+/* R04 bakelite fluted knob over a printed 0-10 scale */
+let bakeV=63,bakeIdx=null;
+(function(){const s=$('bakek'),cx=55,cy=54;
+ const defs=svgEl(s,'defs',{});
+ const sk=svgEl(defs,'radialGradient',{id:'bakeSk',cx:'42%',cy:'36%',r:'80%'});
+ svgEl(sk,'stop',{offset:'0','stop-color':'#312d27'});
+ svgEl(sk,'stop',{offset:'1','stop-color':'#050404'});
+ const dm=svgEl(defs,'radialGradient',{id:'bakeDome',cx:'40%',cy:'32%',r:'80%'});
+ svgEl(dm,'stop',{offset:'0','stop-color':'#3a362f'});
+ svgEl(dm,'stop',{offset:'1','stop-color':'#0a0908'});
+ for(let i=0;i<=10;i++){const a=-135+i*27,major=i%5===0;
+ const [x1,y1]=polar(cx,cy,38,a),[x2,y2]=polar(cx,cy,major?45:43.5,a);
+ svgEl(s,'line',{x1,y1,x2,y2,stroke:'var(--steel)','stroke-width':major?1.5:1});
+ if(major){const [x,y]=polar(cx,cy,50.5,a);
+ svgEl(s,'text',{x,y:y+2.6,'text-anchor':'middle','font-size':8,'font-family':'var(--mono)',
+ fill:'var(--steel)'}).textContent=i;}}
+ for(let k=0;k<18;k++){const [x,y]=polar(cx,cy,31,k*20);
+ svgEl(s,'circle',{cx:x,cy:y,r:3.4,fill:'url(#bakeSk)'});}
+ svgEl(s,'circle',{cx,cy,r:31,fill:'url(#bakeSk)',stroke:'#000','stroke-width':.6});
+ bakeIdx=svgEl(s,'line',{x1:cx,y1:cy-30,x2:cx,y2:cy-21,stroke:'var(--gold-hi)','stroke-width':2.4,
+ 'stroke-linecap':'round'});
+ svgEl(s,'circle',{cx,cy,r:19,fill:'url(#bakeDome)'});
+ svgEl(s,'ellipse',{cx:49,cy:46,rx:6,ry:3.5,fill:'rgba(255,255,255,.14)',transform:'rotate(-28,49,46)'});})();
+function setBake(v){bakeV=v;bakeIdx.setAttribute('transform',`rotate(${v*2.7-135},55,54)`);
+ setRd('R04',(v/10).toFixed(1)+' / 10');}
+dragDelta($('bakek'),()=>bakeV,setBake,{min:0,max:100,sens:0.25});setBake(63);
+
+/* shared: interpolate a dB reading from a 0..1 sweep position (VU law) */
+function vuDb(t){let i=0;while(i<VUDB.length-2&&VUDB[i+1][1]<t)i++;
+ const [d1,t1]=VUDB[i],[d2,t2]=VUDB[i+1];
+ return d1+(d2-d1)*Math.max(0,Math.min(1,(t-t1)/(t2-t1)));}
+
+/* R05 filter slider bank: one fader per band, arrow caps on black tracks */
+const FB_FREQ=[78,136,235,406,701,1210,2090,3620];
+const fbank={vals:[18,30,42,25,35,55,20,48],caps:[]};
+(function(){const s=$('fbank'),y0=14,y1=84,x0=30,dx=19.5;
+ const yOf=v=>y0+v/60*(y1-y0);
+ for(const [lbl,y] of [['0',y0],['20',y0+(y1-y0)/3],['40',y0+2*(y1-y0)/3],['60',y1]]){
+ svgEl(s,'text',{x:14,y:y+2,'text-anchor':'end','font-size':6,'font-family':'var(--mono)',
+ fill:'var(--steel)'}).textContent=lbl;}
+ svgEl(s,'text',{x:14,y:94,'text-anchor':'end','font-size':5.5,'font-family':'var(--mono)',
+ fill:'var(--dim)'}).textContent='dB';
+ FB_FREQ.forEach((f,i)=>{const x=x0+i*dx;
+ svgEl(s,'text',{x,y:8,'text-anchor':'middle','font-size':5.2,'font-family':'var(--mono)',
+ fill:'var(--steel)'}).textContent=f<1000?f:(f/1000)+'k';
+ svgEl(s,'line',{x1:x,y1:y0,x2:x,y2:y1,stroke:'#0a0908','stroke-width':3.4,'stroke-linecap':'round'});
+ svgEl(s,'line',{x1:x-.7,y1:y0,x2:x-.7,y2:y1,stroke:'rgba(255,255,255,.05)','stroke-width':.7});
+ const cap=svgEl(s,'g',{});
+ svgEl(cap,'polygon',{points:`${x-8.5},${-4.5} ${x-2.5},0 ${x-8.5},${4.5}`,fill:'var(--vfd)',stroke:'#123028','stroke-width':.6});
+ svgEl(cap,'polygon',{points:`${x+8.5},${-4.5} ${x+2.5},0 ${x+8.5},${4.5}`,fill:'var(--vfd)',stroke:'#123028','stroke-width':.6});
+ svgEl(cap,'circle',{cx:x,cy:0,r:1.5,fill:'#123028'});
+ fbank.caps.push(cap);
+ const hit=svgEl(s,'rect',{x:x-9.5,y:y0-6,width:19,height:y1-y0+12,fill:'transparent'});
+ hit.style.cursor='ns-resize';
+ dragY(hit,pct=>setFbank(i,(100-pct)/100*60));});
+ })();
+function setFbank(i,db){db=Math.max(0,Math.min(60,db));fbank.vals[i]=db;
+ fbank.caps[i].setAttribute('transform',`translate(0,${14+db/60*70})`);
+ setRd('R05',`${FB_FREQ[i]<1000?FB_FREQ[i]:(FB_FREQ[i]/1000)+'k'} Hz · −${Math.round(db)} dB`);}
+fbank.vals.forEach((v,i)=>setFbank(i,v));setRd('R05','drag a band');
+
+/* R06 chicken-head selector: the tapered lever aims at the position */
+const CHICK_POS=[['OFF',-60],['LO',-20],['MID',20],['HI',60]];
+let chickI=2,chickLever=null,chickLbls=[];
+(function(){const s=$('chick'),cx=55,cy=58;
+ const defs=svgEl(s,'defs',{});
+ const bg=svgEl(defs,'radialGradient',{id:'chickG',cx:'42%',cy:'34%',r:'80%'});
+ svgEl(bg,'stop',{offset:'0','stop-color':'#35312b'});
+ svgEl(bg,'stop',{offset:'1','stop-color':'#070606'});
+ CHICK_POS.forEach(([lbl,a],i)=>{const [tx,ty]=polar(cx,cy,42,a);
+ const t=svgEl(s,'text',{x:tx,y:ty+2.5,'text-anchor':'middle','font-size':6.5,'letter-spacing':'.06em',
+ 'font-family':'var(--mono)',fill:'var(--dim)'});t.textContent=lbl;chickLbls.push(t);
+ const [mx1,my1]=polar(cx,cy,33,a),[mx2,my2]=polar(cx,cy,29,a);
+ svgEl(s,'line',{x1:mx1,y1:my1,x2:mx2,y2:my2,stroke:'var(--steel)','stroke-width':1.2});});
+ svgEl(s,'circle',{cx,cy,r:12,fill:'#0c0b0a'});
+ chickLever=svgEl(s,'g',{});
+ svgEl(chickLever,'path',{d:`M ${cx} ${cy-29} L ${cx+8.5} ${cy-4} Q ${cx+9} ${cy+8} ${cx+5} ${cy+11} A 7 7 0 0 1 ${cx-5} ${cy+11} Q ${cx-9} ${cy+8} ${cx-8.5} ${cy-4} Z`,
+ fill:'url(#chickG)',stroke:'#000','stroke-width':.7});
+ svgEl(chickLever,'line',{x1:cx,y1:cy-26,x2:cx,y2:cy+6,stroke:'#4a463e','stroke-width':1.4,'stroke-linecap':'round'});
+ chickLever.style.transformOrigin=`${cx}px ${cy}px`;chickLever.style.transition='transform .12s';
+ $('chick').onclick=()=>setChick((chickI+1)%CHICK_POS.length);})();
+function setChick(i){chickI=i;chickLever.style.transform=`rotate(${CHICK_POS[i][1]}deg)`;
+ chickLbls.forEach((t,k)=>t.setAttribute('fill',k===i?'var(--gold-hi)':'var(--dim)'));
+ setRd('R06',CHICK_POS[i][0]);}
+setChick(2);
+
+/* R07 round panel meter: porthole bezel, same VU law as R01 */
+let rndT=.5,rndNeedle=null;
+(function(){const s=$('rndm'),cx=55,fy=54,py=74,sweep=t=>-40+t*80;
+ const defs=svgEl(s,'defs',{});
+ const clip=svgEl(defs,'clipPath',{id:'rndFace'});
+ svgEl(clip,'circle',{cx,cy:fy,r:40});
+ svgEl(s,'circle',{cx,cy:fy,r:48,fill:'#141110',stroke:'#060505','stroke-width':2});
+ svgEl(s,'circle',{cx,cy:fy,r:40,fill:'var(--cream)'});
+ const g=svgEl(s,'g',{'clip-path':'url(#rndFace)'});
+ const pt=(r,t)=>polar(cx,py,r,sweep(t));
+ const [ax1,ay1]=pt(44,0),[ax2,ay2]=pt(44,1);
+ svgEl(g,'path',{d:`M ${ax1} ${ay1} A 44 44 0 0 1 ${ax2} ${ay2}`,fill:'none',stroke:'#3a3128','stroke-width':1.1});
+ const [rzx,rzy]=pt(44,.75);
+ svgEl(g,'path',{d:`M ${rzx} ${rzy} A 44 44 0 0 1 ${ax2} ${ay2}`,fill:'none',stroke:'var(--fail)','stroke-width':3});
+ for(const [db,t] of VUDB){const [x1,y1]=pt(41.5,t),[x2,y2]=pt(47,t);
+ svgEl(g,'line',{x1,y1,x2,y2,stroke:db>0?'var(--fail)':'#3a3128','stroke-width':1});}
+ for(const [db,t] of VUDB){if(![-20,-10,-5,-3,0,3].includes(db))continue;
+ const [x,y]=pt(52,t);
+ svgEl(g,'text',{x,y:y+2,'text-anchor':'middle','font-size':5.5,'font-family':'var(--mono)',
+ fill:db>0?'var(--fail)':'#3a3128'}).textContent=Math.abs(db);}
+ svgEl(g,'text',{x:cx,y:fy+14,'text-anchor':'middle','font-size':8,'font-weight':700,
+ 'font-family':'var(--mono)',fill:'#3a3128'}).textContent='dB';
+ rndNeedle=svgEl(g,'line',{x1:cx,y1:py,x2:cx,y2:py-46,stroke:'#1a1613','stroke-width':1.5,
+ transform:`rotate(0,${cx},${py})`});
+ svgEl(g,'circle',{cx,cy:py,r:5,fill:'#141110'});
+ svgEl(s,'ellipse',{cx:cx-8,cy:fy-22,rx:20,ry:9,fill:'rgba(255,255,255,.07)',transform:`rotate(-18,${cx-8},${fy-22})`});})();
+function setRnd(v){const t=Math.max(0,Math.min(1,v/100));rndT=t;
+ rndNeedle.setAttribute('transform',`rotate(${-40+t*80},55,74)`);
+ const db=vuDb(t);setRd('R07',(db>0?'+':'')+db.toFixed(1)+' dB');}
+dragDelta($('rndm'),()=>rndT*100,setRnd,{min:0,max:100});setRnd(50);
+
+/* R08 chrome MIN/MAX indicator */
+let chrV=50,chrPtr=null;
+(function(){const s=$('chrmm'),cx=55,cy=58;
+ const defs=svgEl(s,'defs',{});
+ const ring=svgEl(defs,'linearGradient',{id:'chrRing',x1:0,y1:0,x2:0,y2:1});
+ svgEl(ring,'stop',{offset:'0','stop-color':'#eceef0'});
+ svgEl(ring,'stop',{offset:'.5','stop-color':'#9aa0a8'});
+ svgEl(ring,'stop',{offset:'1','stop-color':'#54585e'});
+ const dome=svgEl(defs,'radialGradient',{id:'chrDome',cx:'48%',cy:'20%',r:'85%'});
+ svgEl(dome,'stop',{offset:'0','stop-color':'#e6e8ec'});
+ svgEl(dome,'stop',{offset:'1','stop-color':'#82878f'});
+ svgEl(s,'circle',{cx,cy:54,r:47,fill:'url(#chrRing)'});
+ svgEl(s,'circle',{cx,cy:54,r:40,fill:'#101214',stroke:'#2c2f33','stroke-width':1});
+ svgEl(s,'path',{d:`M 21 60 A 34 34 0 0 1 89 60 Z`,fill:'url(#chrDome)',stroke:'#55595f','stroke-width':.5});
+ for(const r of [14,22,30])
+ svgEl(s,'path',{d:`M ${cx-r} 60 A ${r} ${r} 0 0 1 ${cx+r} 60`,fill:'none',stroke:'rgba(255,255,255,.13)','stroke-width':.7});
+ chrPtr=svgEl(s,'line',{x1:cx,y1:cy-10,x2:cx,y2:cy-31,stroke:'#17191b','stroke-width':2.2,'stroke-linecap':'round'});
+ svgEl(s,'circle',{cx,cy,r:6,fill:'#23262a'});
+ for(let k=0;k<8;k++){const [x,y]=polar(cx,cy,6,k*45);
+ svgEl(s,'circle',{cx:x,cy:y,r:1.3,fill:'#23262a'});}
+ svgEl(s,'circle',{cx,cy,r:1.6,fill:'#0c0d0e'});
+ svgEl(s,'text',{x:24,y:66,'text-anchor':'middle','font-size':6,'letter-spacing':'.05em',
+ 'font-family':'var(--mono)',fill:'#d7dade'}).textContent='MIN';
+ svgEl(s,'text',{x:86,y:66,'text-anchor':'middle','font-size':6,'letter-spacing':'.05em',
+ 'font-family':'var(--mono)',fill:'#d7dade'}).textContent='MAX';
+ svgEl(s,'text',{x:cx,y:84,'text-anchor':'middle','font-size':7,'font-style':'italic',
+ 'font-family':'var(--mono)',fill:'#787c82'}).textContent='dupre.';
+ svgEl(s,'ellipse',{cx:47,cy:34,rx:22,ry:9,fill:'rgba(255,255,255,.10)',transform:'rotate(-16,47,34)'});})();
+function setChr(v){chrV=Math.max(0,Math.min(100,v));
+ chrPtr.setAttribute('transform',`rotate(${-55+chrV/100*110},55,58)`);
+ setRd('R08',chrV<=2?'MIN':chrV>=98?'MAX':Math.round(chrV)+'%');}
+dragDelta($('chrmm'),()=>chrV,setChr,{min:0,max:100});setChr(50);
+
+/* R09 black-face aviation gauge: zone arcs per the airspeed-indicator scheme */
+let avV=52,avNeedle=null;
+(function(){const s=$('avgauge'),cx=55,cy=52,sweep=t=>-135+t*270;
+ const defs=svgEl(s,'defs',{});
+ const fl=svgEl(defs,'filter',{id:'avGlow',x:'-60%',y:'-60%',width:'220%',height:'220%'});
+ svgEl(fl,'feGaussianBlur',{in:'SourceGraphic',stdDeviation:1.4});
+ svgEl(s,'circle',{cx,cy,r:47,fill:'#1b1917',stroke:'#060505','stroke-width':2});
+ svgEl(s,'circle',{cx,cy,r:41,fill:'#0a0908',stroke:'#3a352c','stroke-width':1});
+ const zone=(t1,t2,color)=>{const [x1,y1]=polar(cx,cy,37,sweep(t1)),[x2,y2]=polar(cx,cy,37,sweep(t2));
+ svgEl(s,'path',{d:`M ${x1} ${y1} A 37 37 0 ${(t2-t1)>.5?1:0} 1 ${x2} ${y2}`,fill:'none',stroke:color,'stroke-width':3,opacity:.85});};
+ zone(.15,.6,'var(--pass)');zone(.6,.85,'var(--gold)');zone(.85,1,'var(--fail)');
+ for(let i=0;i<=40;i++){const t=i/40,major=i%5===0,a=sweep(t);
+ const [x1,y1]=polar(cx,cy,40,a),[x2,y2]=polar(cx,cy,major?32:36,a);
+ svgEl(s,'line',{x1,y1,x2,y2,stroke:'var(--gold)','stroke-width':major?1.6:.8,opacity:major?1:.7});
+ if(major){const [nx,ny]=polar(cx,cy,25,a);
+ svgEl(s,'text',{x:nx,y:ny+2.4,'text-anchor':'middle','font-size':6.5,'font-family':'var(--mono)',
+ fill:'var(--gold-hi)'}).textContent=i/5;}}
+ svgEl(s,'text',{x:cx,y:cy+16,'text-anchor':'middle','font-size':5.5,'letter-spacing':'.14em',
+ 'font-family':'var(--mono)',fill:'var(--gold)',opacity:.8}).textContent='×100 RPM';
+ avNeedle=svgEl(s,'g',{});
+ svgEl(avNeedle,'line',{x1:cx,y1:cy+8,x2:cx,y2:cy-30,stroke:'var(--gold-hi)','stroke-width':4,
+ 'stroke-linecap':'round',opacity:.5,filter:'url(#avGlow)'});
+ svgEl(avNeedle,'line',{x1:cx,y1:cy+8,x2:cx,y2:cy-30,stroke:'var(--gold-hi)','stroke-width':2.2,
+ 'stroke-linecap':'round'});
+ svgEl(s,'circle',{cx,cy,r:5,fill:'#1b1917',stroke:'#3a352c'});
+ svgEl(s,'ellipse',{cx:cx-10,cy:cy-24,rx:18,ry:8,fill:'rgba(255,255,255,.05)',transform:`rotate(-18,${cx-10},${cy-24})`});})();
+function setAv(v){avV=Math.max(0,Math.min(100,v));
+ avNeedle.setAttribute('transform',`rotate(${-135+avV/100*270},55,52)`);
+ setRd('R09',(avV/100*8).toFixed(1)+' ×100 rpm');}
+dragDelta($('avgauge'),()=>avV,setAv,{min:0,max:100});setAv(52);
+
+/* R10 data matrix readout */
+const DMX_PAGES=[
+ ['SYS',()=>['CPU 42 MEM 61','DSK 58 TMP 47C','ARCH 6.18 LTS']],
+ ['NET',()=>['WIFI @HYATT 300M','VPN UP DNS OK','BT 2 PAIRED']],
+ ['TIME',()=>{const d=new Date(),p=n=>String(n).padStart(2,'0');
+ return [`${d.getFullYear()}-${p(d.getMonth()+1)}-${p(d.getDate())}`,
+ `${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`,
+ 'UP 14D 06:12'];}]];
+let dmxI=0,dmxLines=[];
+(function(){const s=$('dmx');
+ const defs=svgEl(s,'defs',{});
+ const fl=svgEl(defs,'filter',{id:'dmxGlow',x:'-30%',y:'-30%',width:'160%',height:'160%'});
+ svgEl(fl,'feGaussianBlur',{in:'SourceGraphic',stdDeviation:1.1});
+ const bg=svgEl(defs,'linearGradient',{id:'dmxBg',x1:0,y1:0,x2:0,y2:1});
+ svgEl(bg,'stop',{offset:'0','stop-color':'#140d06'});
+ svgEl(bg,'stop',{offset:'1','stop-color':'#0a0705'});
+ svgEl(s,'rect',{x:1,y:1,width:188,height:72,rx:5,fill:'url(#dmxBg)',stroke:'#2c261d'});
+ for(let r=0;r<3;r++){
+ const glow=svgEl(s,'text',{x:12,y:24+r*18,'font-size':9,'letter-spacing':'.15em',
+ 'font-family':'var(--mono)',fill:'var(--gold-hi)',opacity:.6,filter:'url(#dmxGlow)'});
+ const crisp=svgEl(s,'text',{x:12,y:24+r*18,'font-size':9,'letter-spacing':'.15em',
+ 'font-family':'var(--mono)',fill:'var(--gold-hi)'});
+ dmxLines.push([glow,crisp]);}
+ $('dmx').onclick=()=>setDmx((dmxI+1)%DMX_PAGES.length);})();
+function setDmx(i){dmxI=i;const [name,rowsFn]=DMX_PAGES[i];
+ rowsFn().forEach((txt,r)=>{dmxLines[r][0].textContent=txt;dmxLines[r][1].textContent=txt;});
+ setRd('R10','page '+name);}
+setDmx(0);
+if(!matchMedia('(prefers-reduced-motion: reduce)').matches)
+ setInterval(()=>{if(DMX_PAGES[dmxI][0]==='TIME')setDmx(dmxI);},1000);
+
+/* R11 warning flag window */
+let flagOn=false,flagStripes=null;
+(function(){const s=$('wflag');
+ const defs=svgEl(s,'defs',{});
+ const pat=svgEl(defs,'pattern',{id:'barber',width:10,height:10,patternUnits:'userSpaceOnUse',
+ patternTransform:'rotate(45)'});
+ svgEl(pat,'rect',{x:0,y:0,width:10,height:10,fill:'#17130c'});
+ svgEl(pat,'rect',{x:0,y:0,width:5,height:10,fill:'var(--gold)'});
+ const clip=svgEl(defs,'clipPath',{id:'flagWin'});
+ svgEl(clip,'rect',{x:14,y:20,width:56,height:24});
+ svgEl(s,'rect',{x:11,y:17,width:62,height:30,rx:3,fill:'#0a0908',stroke:'#2c261d','stroke-width':2});
+ const g=svgEl(s,'g',{'clip-path':'url(#flagWin)'});
+ flagStripes=svgEl(g,'rect',{x:14,y:20,width:56,height:24,fill:'url(#barber)'});
+ flagStripes.style.transition='transform .18s';flagStripes.style.transform='translateX(-58px)';
+ svgEl(s,'text',{x:92,y:35,'text-anchor':'middle','font-size':7,'letter-spacing':'.14em',
+ 'font-family':'var(--mono)',fill:'var(--steel)'}).textContent='VIB';
+ $('wflag').onclick=()=>setFlag(!flagOn);})();
+function setFlag(on){flagOn=on;flagStripes.style.transform=on?'translateX(0)':'translateX(-58px)';
+ setRd('R11',on?'FLAG':'clear');}
+setFlag(false);
+
+/* R12 chrome slot fader: engraved dB scale, chrome T-handle */
+let slotDb=-4,slotHandle=null;
+(function(){const s=$('slotf'),cx=45,yTop=30,yBot=120;
+ const yOf=db=>yTop+(12-db)/36*(yBot-yTop);
+ const defs=svgEl(s,'defs',{});
+ const pl=svgEl(defs,'linearGradient',{id:'sfPlate',x1:0,y1:0,x2:1,y2:1});
+ svgEl(pl,'stop',{offset:'0','stop-color':'#242019'});
+ svgEl(pl,'stop',{offset:'1','stop-color':'#131110'});
+ const ch=svgEl(defs,'linearGradient',{id:'sfChrome',x1:0,y1:0,x2:0,y2:1});
+ svgEl(ch,'stop',{offset:'0','stop-color':'#f0efec'});
+ svgEl(ch,'stop',{offset:'.45','stop-color':'#c4c1b9'});
+ svgEl(ch,'stop',{offset:'1','stop-color':'#75726a'});
+ const sc=svgEl(defs,'radialGradient',{id:'sfScrew',cx:'40%',cy:'35%',r:'75%'});
+ svgEl(sc,'stop',{offset:'0','stop-color':'#9b968a'});
+ svgEl(sc,'stop',{offset:'1','stop-color':'#4a463e'});
+ svgEl(s,'rect',{x:14,y:8,width:62,height:134,rx:6,fill:'url(#sfPlate)',stroke:'#0a0908','stroke-width':1.5});
+ svgEl(s,'rect',{x:15.5,y:9.5,width:59,height:131,rx:5,fill:'none',stroke:'rgba(255,255,255,.05)','stroke-width':1});
+ for(const sy of [16,134]){
+ svgEl(s,'circle',{cx,cy:sy,r:3.2,fill:'url(#sfScrew)',stroke:'#14110e','stroke-width':.6});
+ const [x1,y1]=polar(cx,sy,3,112),[x2,y2]=polar(cx,sy,3,292);
+ svgEl(s,'line',{x1,y1,x2,y2,stroke:'#221f1a','stroke-width':1});}
+ svgEl(s,'rect',{x:40.5,y:yTop-4,width:9,height:yBot-yTop+8,rx:4,fill:'#0b0a09',stroke:'#050404'});
+ for(const db of [12,8,4,0,-4,-8,-12,-16,-20,-24]){const y=yOf(db);
+ svgEl(s,'line',{x1:26,y1:y,x2:39,y2:y,stroke:'var(--steel)','stroke-width':db===0?1.3:.8,opacity:db===0?1:.75});
+ svgEl(s,'line',{x1:51,y1:y,x2:64,y2:y,stroke:'var(--steel)','stroke-width':db===0?1.3:.8,opacity:db===0?1:.75});
+ svgEl(s,'text',{x:23,y:y+2.2,'text-anchor':'end','font-size':6,'font-family':'var(--mono)',
+ fill:db===0?'var(--cream)':'var(--steel)'}).textContent=Math.abs(db);}
+ slotHandle=svgEl(s,'g',{});
+ svgEl(slotHandle,'polygon',{points:'45,0 58,-5 58,5',fill:'#b9b6ae',stroke:'#5e5a52','stroke-width':.5});
+ svgEl(slotHandle,'rect',{x:58,y:-7,width:22,height:14,rx:3.5,fill:'url(#sfChrome)',stroke:'#4e4a42','stroke-width':.6});
+ svgEl(slotHandle,'rect',{x:60,y:-5.2,width:18,height:2.2,rx:1,fill:'rgba(255,255,255,.4)'});
+ dragY(s,pct=>setSlot(-24+pct/100*36));})();
+function setSlot(db){slotDb=Math.max(-24,Math.min(12,db));
+ slotHandle.setAttribute('transform',`translate(0,${30+(12-slotDb)/36*90})`);
+ setRd('R12',(slotDb>0?'+':slotDb<0?'−':'')+Math.abs(slotDb).toFixed(1)+' dB');}
+setSlot(-4);
+
+/* R13 edgewise strip meter: compressed log scale, bar rides the edge */
+const EDGE_SCALE=[[0,.08],[3,.26],[6,.44],[12,.62],[20,.78],[40,.94]];
+let edgeFrac=.62,edgeBar=null;
+(function(){const s=$('edgem'),wy0=12,wy1=118;
+ const defs=svgEl(s,'defs',{});
+ const pg=svgEl(defs,'linearGradient',{id:'edgeFace',x1:0,y1:0,x2:1,y2:0});
+ svgEl(pg,'stop',{offset:'0','stop-color':'#efe6ca'});
+ svgEl(pg,'stop',{offset:'1','stop-color':'#d9cfae'});
+ svgEl(s,'rect',{x:8,y:6,width:54,height:118,rx:8,fill:'#171412',stroke:'#060505','stroke-width':1.5});
+ svgEl(s,'rect',{x:14,y:wy0,width:42,height:wy1-wy0,fill:'url(#edgeFace)',stroke:'#0a0908'});
+ const yOf=f=>wy0+f*(wy1-wy0);
+ for(const [db,f] of EDGE_SCALE){const y=yOf(f);
+ svgEl(s,'line',{x1:19,y1:y,x2:40,y2:y,stroke:'#3a3128','stroke-width':1});
+ svgEl(s,'text',{x:52,y:y+2.4,'text-anchor':'end','font-size':7,'font-family':'var(--mono)',
+ fill:'#3a3128'}).textContent=db;}
+ for(let i=0;i<EDGE_SCALE.length-1;i++){const y=yOf((EDGE_SCALE[i][1]+EDGE_SCALE[i+1][1])/2);
+ svgEl(s,'line',{x1:19,y1:y,x2:32,y2:y,stroke:'#3a3128','stroke-width':.6,opacity:.7});}
+ edgeBar=svgEl(s,'polygon',{points:'56,0 24,-1.4 24,1.4',fill:'#1a1613'});
+ svgEl(s,'rect',{x:14,y:wy0,width:42,height:24,fill:'rgba(255,255,255,.08)'});
+ dragY(s,pct=>setEdge(.08+(100-pct)/100*.86));})();
+function setEdge(f){edgeFrac=Math.max(.08,Math.min(.94,f));
+ edgeBar.setAttribute('transform',`translate(0,${12+edgeFrac*106})`);
+ let i=0;while(i<EDGE_SCALE.length-2&&EDGE_SCALE[i+1][1]<edgeFrac)i++;
+ const [d1,f1]=EDGE_SCALE[i],[d2,f2]=EDGE_SCALE[i+1];
+ const db=d1+(d2-d1)*Math.max(0,Math.min(1,(edgeFrac-f1)/(f2-f1)));
+ setRd('R13','−'+db.toFixed(1)+' dB');}
+setEdge(.62);
+
+/* R14 spade-pointer tuning knob: engraved panel arc, pointer rides the knob */
+let spadeV=8.3,spadeGrp=null;
+(function(){const s=$('spade'),cx=70,cy=82,sweep=v=>-80+v/10*160;
+ const defs=svgEl(s,'defs',{});
+ const bk=svgEl(defs,'radialGradient',{id:'spadeKnob',cx:'42%',cy:'34%',r:'80%'});
+ svgEl(bk,'stop',{offset:'0','stop-color':'#33302a'});
+ svgEl(bk,'stop',{offset:'1','stop-color':'#080706'});
+ const mt=svgEl(defs,'linearGradient',{id:'spadeMetal',x1:0,y1:0,x2:1,y2:1});
+ svgEl(mt,'stop',{offset:'0','stop-color':'#e9e7e0'});
+ svgEl(mt,'stop',{offset:'1','stop-color':'#8d897f'});
+ // engraved arc: every stroke carries a faint light twin offset below (incised relief)
+ const engrave=(x1,y1,x2,y2,w)=>{
+ svgEl(s,'line',{x1,y1:y1+.8,x2,y2:y2+.8,stroke:'rgba(255,255,255,.13)','stroke-width':w});
+ svgEl(s,'line',{x1,y1,x2,y2,stroke:'#050404','stroke-width':w});};
+ for(let i=0;i<=40;i++){const v=i/4,a=sweep(v),major=i%4===0;
+ const [x1,y1]=polar(cx,cy,major?50:52,a),[x2,y2]=polar(cx,cy,58,a);
+ engrave(x1,y1,x2,y2,major?1.6:.9);
+ if(major){const [nx,ny]=polar(cx,cy,65,a);
+ svgEl(s,'text',{x:nx,y:ny+3.2,'text-anchor':'middle','font-size':7.5,'font-family':'var(--mono)',
+ fill:'rgba(255,255,255,.13)'}).textContent=v;
+ svgEl(s,'text',{x:nx,y:ny+2.4,'text-anchor':'middle','font-size':7.5,'font-family':'var(--mono)',
+ fill:'#0a0908'}).textContent=v;}}
+ spadeGrp=svgEl(s,'g',{});
+ svgEl(spadeGrp,'path',{d:`M ${cx-2} ${cy-28} L ${cx-4.5} ${cy-42} L ${cx} ${cy-54} L ${cx+4.5} ${cy-42} L ${cx+2} ${cy-28} Z`,
+ fill:'url(#spadeMetal)',stroke:'#55524a','stroke-width':.6});
+ svgEl(spadeGrp,'circle',{cx,cy,r:30,fill:'url(#spadeKnob)',stroke:'#000','stroke-width':.8});
+ svgEl(spadeGrp,'circle',{cx,cy,r:28.5,fill:'none',stroke:'#0a0908','stroke-width':3,'stroke-dasharray':'2.2 2.2'});
+ svgEl(spadeGrp,'circle',{cx,cy,r:22,fill:'url(#spadeKnob)'});
+ svgEl(spadeGrp,'ellipse',{cx:cx-8,cy:cy-9,rx:8,ry:5,fill:'rgba(255,255,255,.08)',transform:`rotate(-30,${cx-8},${cy-9})`});})();
+function setSpade(v){spadeV=Math.max(0,Math.min(10,v));
+ spadeGrp.setAttribute('transform',`rotate(${-80+spadeV/10*160},70,82)`);
+ setRd('R14',spadeV.toFixed(1));}
+dragDelta($('spade'),()=>spadeV,setSpade,{min:0,max:10,sens:.05});setSpade(8.3);
+
+/* R15 multi-band dial: nested arcs, one needle; bandspread selects the ring */
+const MBAND_RANGES=[[0.54,1.6],[1.6,5.1],[5.1,15.5],[15.5,30.5]];
+let mbandV=45,mbandB=2,mbNeedle=null,mbRings=[],mbSpread=null;
+(function(){const s=$('mband'),cx=62,cy=62,sweep=t=>-70+t*140;
+ const defs=svgEl(s,'defs',{});
+ const pf=svgEl(defs,'linearGradient',{id:'mbFace',x1:0,y1:0,x2:1,y2:1});
+ svgEl(pf,'stop',{offset:'0','stop-color':'#eee5c8'});
+ svgEl(pf,'stop',{offset:'1','stop-color':'#dcd2ae'});
+ svgEl(s,'rect',{x:4,y:4,width:182,height:102,rx:12,fill:'#171412',stroke:'#060505'});
+ svgEl(s,'rect',{x:9,y:9,width:172,height:92,rx:9,fill:'url(#mbFace)',stroke:'#0a0908'});
+ const INK='#2c2318';
+ [18,26,34,42].forEach((r,bi)=>{const ring=svgEl(s,'g',{});
+ const [x1,y1]=polar(cx,cy,r,-70),[x2,y2]=polar(cx,cy,r,70);
+ svgEl(ring,'path',{d:`M ${x1} ${y1} A ${r} ${r} 0 0 1 ${x2} ${y2}`,fill:'none',stroke:INK,'stroke-width':.9});
+ for(let i=0;i<=8;i++){const a=sweep(i/8),[tx1,ty1]=polar(cx,cy,r,a),[tx2,ty2]=polar(cx,cy,r+3,a);
+ svgEl(ring,'line',{x1:tx1,y1:ty1,x2:tx2,y2:ty2,stroke:INK,'stroke-width':.8});}
+ mbRings.push(ring);});
+ mbNeedle=svgEl(s,'line',{x1:cx,y1:cy,x2:cx,y2:cy-46,stroke:'#1a1613','stroke-width':1.6,'stroke-linecap':'round'});
+ svgEl(s,'circle',{cx,cy,r:7,fill:'url(#spadeKnob)',stroke:'#000','stroke-width':.6});
+ svgEl(s,'text',{x:14,y:100,'font-size':5,'letter-spacing':'.12em','font-family':'var(--mono)',
+ fill:INK,opacity:.8}).textContent='MEGACYCLES';
+ // bandspread dial (click = band select)
+ const bx=142,by=56;
+ for(let i=0;i<12;i++){const a=i*30,[x1,y1]=polar(bx,by,24,a),[x2,y2]=polar(bx,by,21,a);
+ svgEl(s,'line',{x1,y1,x2,y2,stroke:INK,'stroke-width':.8});}
+ svgEl(s,'circle',{cx:bx,cy:by,r:17,fill:'none',stroke:INK,'stroke-width':.7,opacity:.5});
+ mbSpread=svgEl(s,'line',{x1:bx,y1:by,x2:bx,y2:by-22,stroke:'#1a1613','stroke-width':1.4,'stroke-linecap':'round'});
+ svgEl(s,'circle',{cx:bx,cy:by,r:6,fill:'url(#spadeKnob)',stroke:'#000','stroke-width':.6});
+ svgEl(s,'text',{x:bx,y:96,'text-anchor':'middle','font-size':5,'letter-spacing':'.12em',
+ 'font-family':'var(--mono)',fill:INK,opacity:.8}).textContent='BANDSPREAD';
+ const dragHit=svgEl(s,'rect',{x:9,y:9,width:100,height:92,fill:'transparent'});
+ dragHit.style.cursor='ns-resize';
+ dragDelta(dragHit,()=>mbandV,v=>setMband(v,mbandB),{min:0,max:100});
+ const clickHit=svgEl(s,'rect',{x:112,y:9,width:69,height:92,fill:'transparent'});
+ clickHit.style.cursor='pointer';
+ clickHit.addEventListener('click',()=>setMband(mbandV,(mbandB+1)%4));})();
+function setMband(v,b){mbandV=Math.max(0,Math.min(100,v));mbandB=b;
+ mbNeedle.setAttribute('transform',`rotate(${-70+mbandV/100*140},62,62)`);
+ mbSpread.setAttribute('transform',`rotate(${-45+b*30},142,56)`);
+ mbRings.forEach((g,i)=>g.setAttribute('opacity',i===b?'1':'.4'));
+ const [lo,hi]=MBAND_RANGES[b];const mc=lo+mbandV/100*(hi-lo);
+ setRd('R15',`B${b+1} · ${mc.toFixed(2)} Mc`);}
+setMband(45,2);
+
+/* R16 entry keypad: worn keys feed the amber display; lamps watch state */
+let kpBuf='',kpDisp=null,kpLampTop=null,kpLampBot=null;
+(function(){const s=$('keypad');
+ const defs=svgEl(s,'defs',{});
+ const kg=svgEl(defs,'linearGradient',{id:'kpKey',x1:0,y1:0,x2:0,y2:1});
+ svgEl(kg,'stop',{offset:'0','stop-color':'#dbd8cf'});
+ svgEl(kg,'stop',{offset:'1','stop-color':'#a29d92'});
+ const ag=svgEl(defs,'linearGradient',{id:'kpAmber',x1:0,y1:0,x2:0,y2:1});
+ svgEl(ag,'stop',{offset:'0','stop-color':'var(--amber-grad-top)'});
+ svgEl(ag,'stop',{offset:'1','stop-color':'var(--amber-grad-mid)'});
+ // lamp pod
+ const lamp=cy=>{const l=svgEl(s,'circle',{cx:13,cy,r:6.5,fill:'#3a0f0a',stroke:'#14100e','stroke-width':1.5});return l;};
+ kpLampTop=lamp(20);kpLampBot=lamp(38);
+ // display window
+ svgEl(s,'rect',{x:26,y:8,width:116,height:32,rx:5,fill:'#0a0806',stroke:'#2c261d','stroke-width':2});
+ kpDisp=svgEl(s,'text',{x:84,y:31,'text-anchor':'middle','font-size':16,'letter-spacing':'.22em',
+ 'font-family':'var(--mono)',fill:'var(--gold-hi)'});
+ // key plate
+ svgEl(s,'rect',{x:24,y:48,width:118,height:138,rx:8,fill:'#1a1714',stroke:'#0a0908','stroke-width':1.5});
+ const KEYS=[['1','2','3'],['4','5','6'],['7','8','9'],['✓','0','✗']];
+ const jitter=[-2,1,-1,2,0,-2,1,-1,2,0,-1,1];
+ KEYS.forEach((row,r)=>row.forEach((k,c)=>{
+ const x=47+c*36,y=68+r*32,amber=(k==='✓'||k==='✗');
+ const g=svgEl(s,'g',{});g.style.cursor='pointer';g.style.transition='transform .07s';
+ svgEl(g,'rect',{x:x-14,y:y-11,width:28,height:24,rx:4,fill:amber?'url(#kpAmber)':'url(#kpKey)',
+ stroke:'#4e4a42','stroke-width':1,'stroke-opacity':.8});
+ svgEl(g,'text',{x,y:y+6,'text-anchor':'middle','font-size':13,'font-weight':700,
+ 'font-family':'var(--mono)',fill:k==='✓'?'#3f5a1f':k==='✗'?'#7a2a1a':'#2b2721',
+ transform:`rotate(${jitter[r*3+c]},${x},${y})`}).textContent=k;
+ g.addEventListener('click',()=>{g.style.transform='translateY(1.5px)';
+ setTimeout(()=>g.style.transform='',80);kpPress(k);});}));
+ })();
+function kpRender(){kpDisp.textContent=kpBuf.padEnd(6,'–');
+ kpLampTop.setAttribute('fill',kpBuf?'var(--jewel-r)':'#3a0f0a');}
+function kpPress(k){
+ if(k==='✓'){setRd('R16',kpBuf?'OK · '+kpBuf:'empty');kpBuf='';kpRender();return;}
+ if(k==='✗'){kpBuf='';kpRender();setRd('R16','cleared');
+ kpLampBot.setAttribute('fill','var(--jewel-r)');
+ setTimeout(()=>kpLampBot.setAttribute('fill','#3a0f0a'),350);return;}
+ if(kpBuf.length<6){kpBuf+=k;kpRender();setRd('R16',kpBuf);}}
+kpRender();setRd('R16','enter a code');
+
+/* R17 round CRT scope: pale phosphor face, live trace */
+let rcrtPh=0,rcrtTrace=null;
+(function(){const s=$('rcrt'),cx=55,cy=52;
+ const defs=svgEl(s,'defs',{});
+ const ph=svgEl(defs,'radialGradient',{id:'rcrtFace',cx:'50%',cy:'44%',r:'70%'});
+ svgEl(ph,'stop',{offset:'0','stop-color':'#b9d8c0'});
+ svgEl(ph,'stop',{offset:'1','stop-color':'#8bb296'});
+ const clip=svgEl(defs,'clipPath',{id:'rcrtClip'});
+ svgEl(clip,'circle',{cx,cy,r:38});
+ svgEl(s,'circle',{cx,cy,r:48,fill:'#141110',stroke:'#060505','stroke-width':2});
+ for(let k=0;k<4;k++){const [x,y]=polar(cx,cy,43,45+k*90);
+ svgEl(s,'circle',{cx:x,cy:y,r:2.6,fill:'url(#sfScrew)',stroke:'#0a0908','stroke-width':.5});}
+ svgEl(s,'circle',{cx,cy,r:38,fill:'url(#rcrtFace)'});
+ const g=svgEl(s,'g',{'clip-path':'url(#rcrtClip)'});
+ for(let i=-4;i<=4;i++){
+ svgEl(g,'line',{x1:cx+i*9,y1:cy-38,x2:cx+i*9,y2:cy+38,stroke:'#3d5c46','stroke-width':i===0?.9:.5,opacity:.8});
+ svgEl(g,'line',{x1:cx-38,y1:cy+i*9,x2:cx+38,y2:cy+i*9,stroke:'#3d5c46','stroke-width':i===0?.9:.5,opacity:.8});}
+ svgEl(g,'polyline',{id:'rcrtGlow',points:'',fill:'none',stroke:'#eef7ee','stroke-width':3,opacity:.35,filter:'url(#avGlow)'});
+ rcrtTrace=svgEl(g,'polyline',{points:'',fill:'none',stroke:'#f4fcf4','stroke-width':1.3});
+ svgEl(s,'ellipse',{cx:cx-10,cy:cy-16,rx:20,ry:10,fill:'rgba(255,255,255,.10)',transform:`rotate(-20,${cx-10},${cy-16})`});})();
+function tickRcrt(){rcrtPh+=0.12;const amp=8+3*Math.sin(rcrtPh*0.35);let pts='';
+ for(let x=-38;x<=38;x+=2){const y=Math.sin(x*0.55+rcrtPh*2.5)*amp;
+ pts+=`${55+x},${(52+y).toFixed(1)} `;}
+ rcrtTrace.setAttribute('points',pts.trim());
+ document.getElementById('rcrtGlow').setAttribute('points',pts.trim());
+ setRd('R17','Vpp '+Math.round(amp*2*4.5));}
+tickRcrt();
+if(!matchMedia('(prefers-reduced-motion: reduce)').matches)setInterval(tickRcrt,80);
+
+/* R18 thumb-slide attenuator pair: lit numeral strip, side thumb tab */
+const THSL=[{name:'BLEND',v:74},{name:'MIX',v:92}];
+const thslParts=[];
+(function(){const s=$('thumbsl'),y0=22,y1=122;
+ const defs=svgEl(s,'defs',{});
+ const rg=svgEl(defs,'linearGradient',{id:'thRail',x1:0,y1:0,x2:1,y2:0});
+ svgEl(rg,'stop',{offset:'0','stop-color':'#3a3733'});
+ svgEl(rg,'stop',{offset:'.5','stop-color':'#211f1c'});
+ svgEl(rg,'stop',{offset:'1','stop-color':'#161412'});
+ const tg=svgEl(defs,'linearGradient',{id:'thTab',x1:0,y1:0,x2:0,y2:1});
+ svgEl(tg,'stop',{offset:'0','stop-color':'#f2efe6'});
+ svgEl(tg,'stop',{offset:'1','stop-color':'#c6c1b3'});
+ THSL.forEach((ch,i)=>{const x=40+i*50;
+ svgEl(s,'rect',{x:x-9,y:y0-10,width:18,height:y1-y0+20,rx:3,fill:'url(#thRail)',stroke:'#0a0908','stroke-width':1.2});
+ for(const sy of [y0-6,y1+6]){svgEl(s,'circle',{cx:x,cy:sy,r:2.4,fill:'url(#sfScrew)',stroke:'#0a0908','stroke-width':.5});
+ svgEl(s,'line',{x1:x-1.8,y1:sy-1,x2:x+1.8,y2:sy+1,stroke:'#14110e','stroke-width':.8});}
+ svgEl(s,'rect',{x:x-5,y:y0,width:10,height:y1-y0,fill:'#0d0a08',stroke:'#050404'});
+ for(let n=0;n<=10;n++){const val=100-n*10,y=y0+6+n*(y1-y0-12)/10;
+ svgEl(s,'text',{x,y:y+2,'text-anchor':'middle','font-size':5.5,'font-family':'var(--mono)',
+ fill:'var(--gold)',opacity:.55}).textContent=val;}
+ const tab=svgEl(s,'g',{});
+ svgEl(tab,'rect',{x:x+7,y:-6,width:8,height:12,rx:2,fill:'url(#thTab)',stroke:'#7a766a','stroke-width':.6});
+ svgEl(tab,'rect',{x:x+8.2,y:-1,width:5.6,height:1.6,fill:'rgba(0,0,0,.25)'});
+ svgEl(s,'text',{x,y:145,'text-anchor':'middle','font-size':6,'letter-spacing':'.14em',
+ 'font-family':'var(--mono)',fill:'var(--steel)'}).textContent=ch.name;
+ const hit=svgEl(s,'rect',{x:x-12,y:y0-10,width:30,height:y1-y0+20,fill:'transparent'});
+ hit.style.cursor='ns-resize';
+ thslParts.push({tab,nums:[...s.querySelectorAll('text')].filter(t=>t.getAttribute('x')==String(x)&&t.textContent!==ch.name)});
+ dragY(hit,pct=>setThsl(i,pct));});
+ })();
+function setThsl(i,v){v=Math.max(0,Math.min(100,Math.round(v)));THSL[i].v=v;
+ const p=thslParts[i];
+ p.tab.setAttribute('transform',`translate(0,${28+(100-v)*0.88})`);
+ p.nums.forEach(t=>{const on=Math.abs(parseInt(t.textContent)-v)<=5;
+ t.setAttribute('fill',on?'var(--gold-hi)':'var(--gold)');t.setAttribute('opacity',on?'1':'.55');});
+ setRd('R18',`${THSL[0].name} ${THSL[0].v} · ${THSL[1].name} ${THSL[1].v}`);}
+setThsl(0,74);setThsl(1,92);
+
+/* R19 waveform region editor: monochrome LCD, draggable S/E flags */
+let wrS=22,wrE=76,wrBars=[],wrFlagS=null,wrFlagE=null;
+(function(){const s=$('wregion'),x0=10,x1=180,yMid=48,N=85;
+ svgEl(s,'rect',{x:1,y:1,width:188,height:98,rx:6,fill:'#0b0c0b',stroke:'#2a2c2a','stroke-width':2});
+ svgEl(s,'text',{x:12,y:13,'font-size':7,'font-family':'var(--mono)',fill:'#e8eae8'}).textContent='C1:START';
+ svgEl(s,'text',{x:78,y:13,'font-size':7,'font-family':'var(--mono)',fill:'#e8eae8'}).textContent='C2:OFF';
+ svgEl(s,'text',{x:136,y:13,'font-size':7,'font-family':'var(--mono)',fill:'#e8eae8'}).textContent='C3:END';
+ svgEl(s,'line',{x1:x0,y1:yMid,x2:x1,y2:yMid,stroke:'#3a3c3a','stroke-width':.6,'stroke-dasharray':'1.5 2'});
+ for(let i=0;i<N;i++){const x=x0+(i/(N-1))*(x1-x0);
+ const env=Math.abs(Math.sin(i*0.19))*Math.abs(Math.sin(i*0.045))*(i%17<11?1:.25);
+ const h=Math.max(1.2,env*26);
+ wrBars.push(svgEl(s,'rect',{x:x-0.8,y:yMid-h,width:1.6,height:h*2,fill:'#5a5c5a'}));}
+ const flag=(lbl)=>{const g=svgEl(s,'g',{});
+ svgEl(g,'line',{x1:0,y1:18,x2:0,y2:78,stroke:'#f2f4f2','stroke-width':1});
+ svgEl(g,'rect',{x:lbl==='S'?0:-8,y:70,width:8,height:8,fill:'#f2f4f2'});
+ svgEl(g,'text',{x:lbl==='S'?4:-4,y:76.5,'text-anchor':'middle','font-size':6.5,'font-weight':700,
+ 'font-family':'var(--mono)',fill:'#0b0c0b'}).textContent=lbl;return g;};
+ wrFlagS=flag('S');wrFlagE=flag('E');
+ svgEl(s,'rect',{x:10,y:84,width:78,height:11,fill:'#e8eae8'});
+ svgEl(s,'text',{x:14,y:92.5,'font-size':6.5,'font-family':'var(--mono)',fill:'#0b0c0b'}).textContent='ENC:ZOOM(1x)';
+ svgEl(s,'text',{x:96,y:92.5,'font-size':6.5,'font-family':'var(--mono)',fill:'#e8eae8'}).textContent='A-3 M:[S]';
+ svgEl(s,'rect',{x:148,y:84,width:32,height:11,fill:'#e8eae8'});
+ svgEl(s,'text',{x:164,y:92.5,'text-anchor':'middle','font-size':6.5,'font-weight':700,
+ 'font-family':'var(--mono)',fill:'#0b0c0b'}).textContent='MENU';
+ s.style.cursor='ew-resize';
+ dragX(s,pct=>{
+ // move whichever flag is nearer the pointer
+ if(Math.abs(pct-wrS)<=Math.abs(pct-wrE))setWregion(Math.min(pct,wrE-4),wrE);
+ else setWregion(wrS,Math.max(pct,wrS+4));});})();
+function setWregion(sv,ev){wrS=Math.max(0,Math.min(96,sv));wrE=Math.max(4,Math.min(100,ev));
+ const x0=10,x1=180,xOf=p=>x0+p/100*(x1-x0);
+ wrFlagS.setAttribute('transform',`translate(${xOf(wrS)},0)`);
+ wrFlagE.setAttribute('transform',`translate(${xOf(wrE)},0)`);
+ wrBars.forEach((b,i)=>{const p=i/(wrBars.length-1)*100;
+ b.setAttribute('fill',(p>=wrS&&p<=wrE)?'#f2f4f2':'#5a5c5a');});
+ setRd('R19',`S ${Math.round(wrS)}% · E ${Math.round(wrE)}%`);}
+setWregion(22,76);
+
+/* R20 drum roller selector: numbered drum in a window, center chip reads it */
+const DRUMR=[{name:'HIGH',v:6},{name:'LOW',v:8}];
+const drumrGrps=[];
+(function(){const s=$('drumr'),cy=76,step=17;
+ const defs=svgEl(s,'defs',{});
+ const paper=svgEl(defs,'linearGradient',{id:'drPaper',x1:0,y1:0,x2:1,y2:0});
+ svgEl(paper,'stop',{offset:'0','stop-color':'#cfc6a8'});
+ svgEl(paper,'stop',{offset:'.5','stop-color':'#ece4c8'});
+ svgEl(paper,'stop',{offset:'1','stop-color':'#c6bd9e'});
+ const curve=svgEl(defs,'linearGradient',{id:'drCurve',x1:0,y1:0,x2:0,y2:1});
+ svgEl(curve,'stop',{offset:'0','stop-color':'rgba(0,0,0,.4)'});
+ svgEl(curve,'stop',{offset:'.28','stop-color':'rgba(0,0,0,0)'});
+ svgEl(curve,'stop',{offset:'.72','stop-color':'rgba(0,0,0,0)'});
+ svgEl(curve,'stop',{offset:'1','stop-color':'rgba(0,0,0,.4)'});
+ svgEl(s,'text',{x:65,y:12,'text-anchor':'middle','font-size':7,'letter-spacing':'.18em',
+ 'font-family':'var(--mono)',fill:'var(--steel)'}).textContent='EQUALIZER';
+ DRUMR.forEach((ch,i)=>{const x=45+i*50;
+ svgEl(s,'text',{x:x+18,y:34,'text-anchor':'middle','font-size':8,fill:'var(--steel)'}).textContent='+';
+ svgEl(s,'text',{x:x+18,y:124,'text-anchor':'middle','font-size':8,fill:'var(--steel)'}).textContent='−';
+ svgEl(s,'rect',{x:x-12,y:24,width:24,height:104,rx:4,fill:'url(#thRail)',stroke:'#0a0908','stroke-width':1.2});
+ const clip=svgEl(defs,'clipPath',{id:'drClip'+i});
+ svgEl(clip,'rect',{x:x-9,y:28,width:18,height:96});
+ svgEl(s,'rect',{x:x-9,y:28,width:18,height:96,fill:'url(#drPaper)'});
+ const g=svgEl(s,'g',{'clip-path':`url(#drClip${i})`});
+ const nums=svgEl(g,'g',{});nums.style.transition='transform .12s';
+ for(let n=1;n<=10;n++)
+ svgEl(nums,'text',{x,y:cy+3+(ch.v-n)*step,'text-anchor':'middle','font-size':9,'font-weight':700,
+ 'font-family':'var(--mono)',fill:'#2b2418'}).textContent=n;
+ svgEl(g,'rect',{x:x-9,y:28,width:18,height:96,fill:'url(#drCurve)','pointer-events':'none'});
+ svgEl(s,'rect',{x:x-8,y:cy-6.5,width:16,height:13,rx:1.5,fill:'#1a1613',opacity:.92});
+ const chip=svgEl(s,'text',{x,y:cy+3,'text-anchor':'middle','font-size':9,'font-weight':700,
+ 'font-family':'var(--mono)',fill:'var(--cream)'});
+ svgEl(s,'text',{x,y:136,'text-anchor':'middle','font-size':6,'letter-spacing':'.12em',
+ 'font-family':'var(--mono)',fill:'var(--steel)'}).textContent=ch.name;
+ const hit=svgEl(s,'rect',{x:x-14,y:24,width:28,height:104,fill:'transparent'});
+ hit.style.cursor='ns-resize';
+ drumrGrps.push({nums,chip,base:ch.v});
+ dragDelta(hit,()=>DRUMR[i].v,v=>setDrumr(i,v),{min:1,max:10,sens:.08});});
+ })();
+function setDrumr(i,v){v=Math.max(1,Math.min(10,v));DRUMR[i].v=v;
+ const p=drumrGrps[i];
+ p.nums.style.transform=`translateY(${(v-p.base)*17}px)`;
+ p.chip.textContent=Math.round(v);
+ setRd('R20',`${DRUMR[0].name} ${Math.round(DRUMR[0].v)} · ${DRUMR[1].name} ${Math.round(DRUMR[1].v)}`);}
+setDrumr(0,6);setDrumr(1,8);
+
+/* R21 LED program row: exclusive select, the LED carries the state */
+const LEDROW_PROGS=['Sm Hall B','VocPlate','Lg Hall B','Chamber','ParcPlate','Sm Hall A','Room A','Const Plate'];
+let ledrowI=5,ledrowLeds=[];
+(function(){const s=$('ledrow');
+ const defs=svgEl(s,'defs',{});
+ const kb=svgEl(defs,'linearGradient',{id:'lrKey',x1:0,y1:0,x2:0,y2:1});
+ svgEl(kb,'stop',{offset:'0','stop-color':'#2b2823'});
+ svgEl(kb,'stop',{offset:'1','stop-color':'#171512'});
+ LEDROW_PROGS.forEach((name,i)=>{const x=16+i*22.6;
+ svgEl(s,'text',{x,y:9,'text-anchor':'middle','font-size':6,'font-family':'var(--mono)',
+ fill:'var(--steel)'}).textContent=i+1;
+ ledrowLeds.push(svgEl(s,'circle',{cx:x,cy:17,r:2.4,fill:'#3a0f0a'}));
+ const g=svgEl(s,'g',{});g.style.cursor='pointer';g.style.transition='transform .07s';
+ svgEl(g,'rect',{x:x-8.5,y:24,width:17,height:22,rx:2.5,fill:'url(#lrKey)',stroke:'#0a0908','stroke-width':1});
+ svgEl(g,'rect',{x:x-6.5,y:26.5,width:13,height:3,rx:1.5,fill:'rgba(255,255,255,.06)'});
+ g.addEventListener('click',()=>{g.style.transform='translateY(1.5px)';
+ setTimeout(()=>g.style.transform='',80);setLedrow(i);});});
+ svgEl(s,'text',{x:95,y:56,'text-anchor':'middle','font-size':6,'letter-spacing':'.16em',
+ 'font-family':'var(--mono)',fill:'var(--steel)'}).textContent='PROGRAM';})();
+function setLedrow(i){ledrowI=i;
+ ledrowLeds.forEach((l,k)=>{const on=k===i;
+ l.setAttribute('fill',on?'var(--jewel-r)':'#3a0f0a');
+ l.setAttribute('style',on?'filter:drop-shadow(0 0 3px rgba(255,91,69,.8))':'');});
+ setRd('R21',`${ledrowI+1} · ${LEDROW_PROGS[ledrowI]}`);}
+setLedrow(5);
+
+/* R22 three-position slide: chrome pill, detents, honest LED pair */
+const VARSL_POS=['A','AB','B'];
+let varslI=1,varslPill=null,varslLbls=[],varslLeds=[];
+(function(){const s=$('varslide');const detX=[34,55,76];
+ svgEl(s,'text',{x:55,y:10,'text-anchor':'middle','font-size':5.5,'letter-spacing':'.16em',
+ 'font-family':'var(--mono)',fill:'var(--steel)'}).textContent='BASIC · VARIATION';
+ svgEl(s,'rect',{x:20,y:16,width:70,height:14,rx:7,fill:'#0b0a09',stroke:'#000','stroke-width':1});
+ svgEl(s,'rect',{x:21,y:17,width:68,height:5,rx:2.5,fill:'rgba(255,255,255,.04)'});
+ varslPill=svgEl(s,'rect',{x:-13,y:18.5,width:26,height:9,rx:4.5,fill:'url(#sfChrome)',stroke:'#4e4a42','stroke-width':.6});
+ varslPill.style.transition='transform .12s';
+ VARSL_POS.forEach((lbl,i)=>{
+ varslLbls.push(svgEl(s,'text',{x:detX[i],y:40,'text-anchor':'middle','font-size':6.5,
+ 'font-family':'var(--mono)',fill:'var(--dim)'}));
+ varslLbls[i].textContent=lbl;});
+ svgEl(s,'rect',{x:32,y:45,width:46,height:11,rx:2,fill:'#141210',stroke:'#060505'});
+ [44,66].forEach(x=>varslLeds.push(svgEl(s,'circle',{cx:x,cy:50.5,r:2.4,fill:'#3a0f0a'})));
+ s.addEventListener('click',e=>{const r=s.getBoundingClientRect();
+ const x=(e.clientX-r.left)/r.width*110;
+ setVarsl(x<45?0:x<66?1:2);});})();
+function setVarsl(i){varslI=i;const detX=[34,55,76];
+ varslPill.setAttribute('transform',`translate(${detX[i]},0)`);
+ varslLbls.forEach((t,k)=>t.setAttribute('fill',k===i?'var(--gold-hi)':'var(--dim)'));
+ const lit=[i===0||i===1,i===2||i===1];
+ varslLeds.forEach((l,k)=>l.setAttribute('fill',lit[k]?'var(--jewel-r)':'#3a0f0a'));
+ setRd('R22',VARSL_POS[i]);}
+setVarsl(1);
+
+/* R23 spun-aluminum knob: machined rings in a knurled grip */
+let spunV=62,spunIdx=null;
+(function(){const s=$('spunk'),cx=55,cy=52;
+ const defs=svgEl(s,'defs',{});
+ const al=svgEl(defs,'radialGradient',{id:'spunFace',cx:'42%',cy:'34%',r:'85%'});
+ svgEl(al,'stop',{offset:'0','stop-color':'#e8e6e0'});
+ svgEl(al,'stop',{offset:'.7','stop-color':'#b3b0a8'});
+ svgEl(al,'stop',{offset:'1','stop-color':'#8a877e'});
+ for(let k=0;k<8;k++){const [x,y]=polar(cx,cy,45,-135+k*38.6);
+ svgEl(s,'circle',{cx:x,cy:y,r:1.3,fill:'var(--steel)'});}
+ for(let k=0;k<22;k++){const [x,y]=polar(cx,cy,36,k*16.36);
+ svgEl(s,'circle',{cx:x,cy:y,r:2.6,fill:'#14110e'});}
+ svgEl(s,'circle',{cx,cy,r:36,fill:'#1a1714',stroke:'#000','stroke-width':.8});
+ svgEl(s,'circle',{cx,cy,r:30,fill:'url(#spunFace)',stroke:'#6e6b63','stroke-width':.8});
+ for(const r of [24,18,12,6])
+ svgEl(s,'circle',{cx,cy,r,fill:'none',stroke:r%12===0?'rgba(0,0,0,.12)':'rgba(255,255,255,.3)','stroke-width':.6});
+ spunIdx=svgEl(s,'line',{x1:cx,y1:cy-28,x2:cx,y2:cy-10,stroke:'var(--fail)','stroke-width':2.6,'stroke-linecap':'round'});
+ svgEl(s,'ellipse',{cx:cx-9,cy:cy-11,rx:9,ry:5,fill:'rgba(255,255,255,.28)',transform:`rotate(-32,${cx-9},${cy-11})`});
+ svgEl(s,'text',{x:cx,y:103,'text-anchor':'middle','font-size':6,'letter-spacing':'.16em',
+ 'font-family':'var(--mono)',fill:'var(--steel)'}).textContent='SPEED';})();
+function setSpun(v){spunV=Math.max(0,Math.min(100,v));
+ spunIdx.setAttribute('transform',`rotate(${-135+spunV/100*270},55,52)`);
+ setRd('R23',Math.round(spunV)+'%');}
+dragDelta($('spunk'),()=>spunV,setSpun,{min:0,max:100});setSpun(62);
+
+/* R24 stomp switch + jewel: press to engage, the jewel reports */
+let stompOn=false,stompDome=null,stompJewel=null,stompGlow=null;
+(function(){const s=$('stomp'),cx=55;
+ const defs=svgEl(s,'defs',{});
+ const dg=svgEl(defs,'radialGradient',{id:'stompDome',cx:'40%',cy:'30%',r:'80%'});
+ svgEl(dg,'stop',{offset:'0','stop-color':'#f4f2ec'});
+ svgEl(dg,'stop',{offset:'.55','stop-color':'#b9b6ae'});
+ svgEl(dg,'stop',{offset:'1','stop-color':'#6e6b63'});
+ const jg=svgEl(defs,'radialGradient',{id:'stompJewel',cx:'38%',cy:'30%',r:'80%'});
+ svgEl(jg,'stop',{offset:'0','stop-color':'#ffe9b0'});
+ svgEl(jg,'stop',{offset:'.45','stop-color':'var(--jewel-a)'});
+ svgEl(jg,'stop',{offset:'1','stop-color':'#5c3d0c'});
+ stompGlow=svgEl(s,'circle',{cx,cy:22,r:14,fill:'rgba(255,180,58,.35)',filter:'url(#avGlow)',opacity:0});
+ stompJewel=svgEl(s,'circle',{cx,cy:22,r:9,fill:'#241f1b',stroke:'#0a0908','stroke-width':1.5});
+ for(let k=0;k<6;k++){const a1=k*60,a2=k*60+30;
+ const [x1,y1]=polar(cx,22,9,a1),[x2,y2]=polar(cx,22,9,a2);
+ svgEl(s,'path',{d:`M ${cx} 22 L ${x1} ${y1} A 9 9 0 0 1 ${x2} ${y2} Z`,
+ fill:k%2?'rgba(255,255,255,.09)':'rgba(0,0,0,.10)','pointer-events':'none'});}
+ for(let k=0;k<20;k++){const [x,y]=polar(cx,72,25,k*18);
+ svgEl(s,'circle',{cx:x,cy:y,r:2.4,fill:'#14110e'});}
+ svgEl(s,'circle',{cx,cy:72,r:25,fill:'#1a1714',stroke:'#000','stroke-width':.8});
+ stompDome=svgEl(s,'g',{});stompDome.style.transition='transform .08s';
+ svgEl(stompDome,'circle',{cx,cy:72,r:19,fill:'url(#stompDome)',stroke:'#55524a','stroke-width':.8});
+ svgEl(stompDome,'ellipse',{cx:cx-6,cy:64,rx:8,ry:4.5,fill:'rgba(255,255,255,.5)',transform:`rotate(-24,${cx-6},64)`});
+ $('stomp').onclick=()=>{stompDome.style.transform='translateY(1.5px)';
+ setTimeout(()=>stompDome.style.transform='',90);setStomp(!stompOn);};})();
+function setStomp(on){stompOn=on;
+ stompJewel.setAttribute('fill',on?'url(#stompJewel)':'#241f1b');
+ stompGlow.setAttribute('opacity',on?'1':'0');
+ setRd('R24',on?'ENGAGED':'bypass');}
+setStomp(false);
+
+/* R27 winged gain selector: red T-bar over a dot ring, stepped detents */
+const WINGK_STEPS=[-80,-70,-60,-50,-40,-30,-20,-10,-5,0,5,10];
+let wingI=7,wingGrp=null;
+(function(){const s=$('wingk'),cx=55,cy=52;
+ const defs=svgEl(s,'defs',{});
+ const rg2=svgEl(defs,'radialGradient',{id:'wingRed',cx:'40%',cy:'32%',r:'80%'});
+ svgEl(rg2,'stop',{offset:'0','stop-color':'#d98a6f'});
+ svgEl(rg2,'stop',{offset:'.6','stop-color':'var(--fail)'});
+ svgEl(rg2,'stop',{offset:'1','stop-color':'#6e2415'});
+ WINGK_STEPS.forEach((db,i)=>{const a=-135+i/(WINGK_STEPS.length-1)*270;
+ const [dx,dy]=polar(cx,cy,38,a);
+ svgEl(s,'circle',{cx:dx,cy:dy,r:1.5,fill:'var(--steel)'});
+ if(i%2===1||db===0||db===10||db===-80){const [tx,ty]=polar(cx,cy,46.5,a);
+ svgEl(s,'text',{x:tx,y:ty+2.2,'text-anchor':'middle','font-size':5.5,'font-family':'var(--mono)',
+ fill:'var(--steel)'}).textContent=db>0?'+'+db:db;}});
+ wingGrp=svgEl(s,'g',{});wingGrp.style.transition='transform .09s';
+ svgEl(wingGrp,'rect',{x:cx-6.5,y:cy-30,width:13,height:60,rx:6,fill:'url(#wingRed)',stroke:'#4e150a','stroke-width':.8});
+ svgEl(wingGrp,'circle',{cx,cy,r:15,fill:'url(#wingRed)',stroke:'#4e150a','stroke-width':.8});
+ svgEl(wingGrp,'line',{x1:cx,y1:cy-28,x2:cx,y2:cy-18,stroke:'var(--cream)','stroke-width':2,'stroke-linecap':'round'});
+ svgEl(wingGrp,'ellipse',{cx:cx-4,cy:cy-8,rx:5,ry:3,fill:'rgba(255,255,255,.18)',transform:`rotate(-30,${cx-4},${cy-8})`});})();
+function setWing(v){const i=Math.max(0,Math.min(WINGK_STEPS.length-1,Math.round(v)));wingI=i;
+ wingGrp.style.transform=`rotate(${-135+i/(WINGK_STEPS.length-1)*270}deg)`;
+ wingGrp.style.transformOrigin='55px 52px';
+ const db=WINGK_STEPS[i];
+ setRd('R27',(db>0?'+':'')+db+' dB');}
+dragDelta($('wingk'),()=>wingI,setWing,{min:0,max:WINGK_STEPS.length-1,sens:.05});setWing(7);
+
+/* R28 rotary disc switch: the whole disc turns between heavy positions */
+const DISCSW_POS=[['OFF',-45],['ON',45],['COMBINE',135]];
+let discI=1,discGrp=null,discLbls=[];
+(function(){const s=$('discsw'),cx=55,cy=58;
+ const defs=svgEl(s,'defs',{});
+ const rr=svgEl(defs,'radialGradient',{id:'discRed',cx:'42%',cy:'34%',r:'85%'});
+ svgEl(rr,'stop',{offset:'0','stop-color':'#d98a6f'});
+ svgEl(rr,'stop',{offset:'.65','stop-color':'var(--fail)'});
+ svgEl(rr,'stop',{offset:'1','stop-color':'#7a2a1a'});
+ svgEl(s,'circle',{cx,cy,r:48,fill:'#1a1714',stroke:'#060505','stroke-width':1.5});
+ for(let k=0;k<4;k++){const [x,y]=polar(cx,cy,44,45+k*90);
+ svgEl(s,'circle',{cx:x,cy:y,r:2.6,fill:'url(#sfScrew)',stroke:'#0a0908','stroke-width':.5});}
+ DISCSW_POS.forEach(([lbl,a],i)=>{const [tx,ty]=polar(cx,cy,42,a);
+ const t=svgEl(s,'text',{x:tx,y:ty+2.4,'text-anchor':'middle','font-size':5.8,'letter-spacing':'.06em',
+ 'font-family':'var(--mono)',fill:'var(--dim)'});t.textContent=lbl;discLbls.push(t);});
+ svgEl(s,'circle',{cx,cy,r:36,fill:'url(#discRed)',stroke:'#4e150a','stroke-width':1});
+ discGrp=svgEl(s,'g',{});discGrp.style.transition='transform .15s';discGrp.style.transformOrigin=`${cx}px ${cy}px`;
+ svgEl(discGrp,'rect',{x:cx-27,y:cy-8,width:54,height:16,rx:8,fill:'url(#discRed)',stroke:'#8f3520','stroke-width':1});
+ svgEl(discGrp,'rect',{x:cx-25,y:cy-6.5,width:50,height:4,rx:2,fill:'rgba(255,255,255,.16)'});
+ svgEl(discGrp,'line',{x1:cx+20,y1:cy,x2:cx+26,y2:cy,stroke:'var(--cream)','stroke-width':2.5,'stroke-linecap':'round'});
+ svgEl(s,'ellipse',{cx:cx-12,cy:cy-14,rx:12,ry:6,fill:'rgba(255,255,255,.10)',transform:`rotate(-28,${cx-12},${cy-14})`});
+ $('discsw').onclick=()=>setDisc((discI+1)%DISCSW_POS.length);})();
+function setDisc(i){discI=i;
+ discGrp.style.transform=`rotate(${DISCSW_POS[i][1]}deg)`;
+ discLbls.forEach((t,k)=>t.setAttribute('fill',k===i?'var(--gold-hi)':'var(--dim)'));
+ setRd('R28',DISCSW_POS[i][0]);}
+setDisc(1);
+
+/* R29 guarded toggle: guard posts + red collar mark the critical throw */
+let guardOn=true,guardLever=null,guardLblOn=null,guardLblOff=null;
+(function(){const s=$('guardsw'),cx=45,cy=52;
+ guardLblOn=svgEl(s,'text',{x:cx,y:12,'text-anchor':'middle','font-size':7,'letter-spacing':'.1em',
+ 'font-family':'var(--mono)',fill:'var(--gold-hi)'});guardLblOn.textContent='ON';
+ guardLblOff=svgEl(s,'text',{x:cx,y:96,'text-anchor':'middle','font-size':7,'letter-spacing':'.1em',
+ 'font-family':'var(--mono)',fill:'var(--dim)'});guardLblOff.textContent='OFF';
+ svgEl(s,'circle',{cx,cy,r:13,fill:'url(#discRed)',stroke:'#4e150a','stroke-width':1});
+ const pts=[];for(let k=0;k<6;k++){const a=(k*60+30)*Math.PI/180;pts.push((cx+11*Math.cos(a))+','+(cy+11*Math.sin(a)));}
+ svgEl(s,'polygon',{points:pts.join(' '),fill:'url(#nutG)',stroke:'#2b2822'});
+ svgEl(s,'circle',{cx,cy,r:6,fill:'#14110e',stroke:'#000'});
+ for(const gx of [16,74]){
+ svgEl(s,'rect',{x:gx-6,y:cy-24,width:12,height:48,rx:6,fill:'url(#nutG)',stroke:'#2b2822','stroke-width':1});
+ svgEl(s,'rect',{x:gx-4,y:cy-21,width:3.5,height:42,rx:2,fill:'rgba(255,255,255,.14)'});}
+ guardLever=svgEl(s,'g',{});
+ svgEl(guardLever,'path',{d:`M ${cx-3} ${cy} L ${cx-2} 26 L ${cx+2} 26 L ${cx+3} ${cy} Z`,fill:'url(#chromeG)',stroke:'#4e4a42','stroke-width':.5});
+ svgEl(guardLever,'rect',{x:cx-4.5,y:16,width:9,height:12,rx:2,fill:'url(#tipG)',stroke:'#5e5a52','stroke-width':.6});
+ for(let r=0;r<4;r++)svgEl(guardLever,'line',{x1:cx-3.5,y1:18.5+r*2.4,x2:cx+3.5,y2:18.5+r*2.4,stroke:'rgba(0,0,0,.25)','stroke-width':.8});
+ guardLever.style.transformOrigin=`${cx}px ${cy}px`;guardLever.style.transition='transform .12s';
+ $('guardsw').onclick=()=>setGuard(!guardOn);})();
+function setGuard(on){guardOn=on;guardLever.style.transform=on?'rotate(0deg)':'rotate(180deg)';
+ guardLblOn.setAttribute('fill',on?'var(--gold-hi)':'var(--dim)');
+ guardLblOff.setAttribute('fill',on?'var(--dim)':'var(--gold-hi)');
+ setRd('R29',on?'ON':'OFF');}
+setGuard(true);
+
+/* R25 fourteen-segment display: the starburst that spells */
+const SEG14_WORDS=['ZOOM','ECHO','TAPE','MOOD','HALL','COMP'];
+const SEG14_MAP={A:['a','b','c','e','f','g1','g2'],C:['a','d','e','f'],
+ D:['a','b','c','d','i','l'],E:['a','d','e','f','g1','g2'],H:['b','c','e','f','g1','g2'],
+ L:['d','e','f'],M:['b','c','e','f','h','j'],O:['a','b','c','d','e','f'],
+ P:['a','b','e','f','g1','g2'],T:['a','i','l'],Z:['a','d','j','k']};
+let seg14I=0,seg14Cells=[];
+(function(){const s=$('seg14');
+ svgEl(s,'rect',{x:1,y:1,width:128,height:52,rx:5,fill:'#0a0f08',stroke:'#1c2a16','stroke-width':2});
+ // segment shapes in a 22x36 local box (x0,y0 top-left)
+ const TH=2.6,W=22,H=36,mid=H/2;
+ const segs={
+ a:[[2,0],[W-2,0],[W-4,TH],[4,TH]],
+ d:[[2,H],[W-2,H],[W-4,H-TH],[4,H-TH]],
+ f:[[0,2],[TH,4],[TH,mid-2],[0,mid-1]],
+ e:[[0,H-2],[TH,H-4],[TH,mid+2],[0,mid+1]],
+ b:[[W,2],[W-TH,4],[W-TH,mid-2],[W,mid-1]],
+ c:[[W,H-2],[W-TH,H-4],[W-TH,mid+2],[W,mid+1]],
+ g1:[[2,mid],[4,mid-TH/2],[W/2-1,mid-TH/2],[W/2-1,mid+TH/2],[4,mid+TH/2]],
+ g2:[[W-2,mid],[W-4,mid-TH/2],[W/2+1,mid-TH/2],[W/2+1,mid+TH/2],[W-4,mid+TH/2]],
+ i:[[W/2-TH/2,3],[W/2+TH/2,3],[W/2+TH/2,mid-2],[W/2-TH/2,mid-2]],
+ l:[[W/2-TH/2,H-3],[W/2+TH/2,H-3],[W/2+TH/2,mid+2],[W/2-TH/2,mid+2]],
+ h:[[3,3],[5.5,3],[W/2-2,mid-3],[W/2-4.5,mid-3]],
+ j:[[W-3,3],[W-5.5,3],[W/2+2,mid-3],[W/2+4.5,mid-3]],
+ k:[[3,H-3],[5.5,H-3],[W/2-2,mid+3],[W/2-4.5,mid+3]],
+ m:[[W-3,H-3],[W-5.5,H-3],[W/2+2,mid+3],[W/2+4.5,mid+3]]};
+ for(let d=0;d<4;d++){const x0=13+d*28,y0=9,cell={};
+ for(const k in segs){
+ cell[k]=svgEl(s,'polygon',{points:segs[k].map(p=>`${x0+p[0]},${y0+p[1]}`).join(' '),
+ fill:'var(--sevoff)'});}
+ seg14Cells.push(cell);}
+ $('seg14').onclick=()=>setSeg14((seg14I+1)%SEG14_WORDS.length);})();
+function setSeg14(i){seg14I=i;const word=SEG14_WORDS[i].padEnd(4,' ');
+ seg14Cells.forEach((cell,d)=>{const lit=SEG14_MAP[word[d]]||[];
+ for(const k in cell){const on=lit.includes(k);
+ cell[k].setAttribute('fill',on?'var(--sevgrn)':'var(--sevoff)');
+ cell[k].setAttribute('style',on?'filter:drop-shadow(0 0 2.5px rgba(87,211,87,.6))':'');}});
+ setRd('R25',SEG14_WORDS[i]);}
+setSeg14(0);
+
+/* R26 response graph: log-frequency axes, a draggable amber peak */
+const RG={x0:30,x1:182,y0:8,y1:86,fLo:Math.log10(32),fHi:Math.log10(16000),db:12};
+let rgFc=1200,rgGain=6.5,rgCurve=null,rgGlowLine=null,rgHandle=null;
+(function(){const s=$('rgraph');
+ svgEl(s,'rect',{x:1,y:1,width:188,height:108,rx:5,fill:'#0d1410',stroke:'#22301f','stroke-width':2});
+ const FREQS=[32,64,128,250,500,1000,2000,4000,8000,16000];
+ FREQS.forEach(f=>{const x=RG.x0+(Math.log10(f)-RG.fLo)/(RG.fHi-RG.fLo)*(RG.x1-RG.x0);
+ svgEl(s,'line',{x1:x,y1:RG.y0,x2:x,y2:RG.y1,stroke:'#22301f','stroke-width':.6});
+ svgEl(s,'text',{x,y:RG.y1+9,'text-anchor':'middle','font-size':4.8,'font-family':'var(--mono)',
+ fill:'var(--steel)'}).textContent=f<1000?f:(f/1000)+'k';});
+ for(const db of [12,6,0,-6,-12]){const y=RG.y0+(RG.db-db)/(2*RG.db)*(RG.y1-RG.y0);
+ svgEl(s,'line',{x1:RG.x0,y1:y,x2:RG.x1,y2:y,stroke:'#22301f','stroke-width':db===0?1:.6});
+ svgEl(s,'text',{x:RG.x0-4,y:y+2,'text-anchor':'end','font-size':4.8,'font-family':'var(--mono)',
+ fill:'var(--steel)'}).textContent=(db>0?'+':'')+db;}
+ rgGlowLine=svgEl(s,'polyline',{points:'',fill:'none',stroke:'var(--gold-hi)','stroke-width':3,
+ opacity:.35,filter:'url(#avGlow)'});
+ rgCurve=svgEl(s,'polyline',{points:'',fill:'none',stroke:'var(--gold)','stroke-width':1.6});
+ rgHandle=svgEl(s,'circle',{r:4,fill:'var(--gold-hi)',stroke:'#7d5c16','stroke-width':1});
+ rgHandle.style.cursor='move';
+ // 2D drag: the handle (and the plot) place the peak in both axes at once
+ s.style.touchAction='none';
+ s.addEventListener('pointerdown',e=>{s.setPointerCapture(e.pointerId);
+ const move=ev=>{const r=s.getBoundingClientRect(),sx=190/r.width,sy=110/r.height;
+ const px=(ev.clientX-r.left)*sx,py=(ev.clientY-r.top)*sy;
+ const lf=RG.fLo+Math.max(0,Math.min(1,(px-RG.x0)/(RG.x1-RG.x0)))*(RG.fHi-RG.fLo);
+ const g=RG.db-Math.max(0,Math.min(1,(py-RG.y0)/(RG.y1-RG.y0)))*2*RG.db;
+ setRgraph(Math.pow(10,lf),g);};
+ move(e);
+ const up=()=>{s.removeEventListener('pointermove',move);s.removeEventListener('pointerup',up);s.removeEventListener('pointercancel',up);};
+ s.addEventListener('pointermove',move);s.addEventListener('pointerup',up);s.addEventListener('pointercancel',up);
+ e.preventDefault();});})();
+function setRgraph(fc,gain){rgFc=Math.max(32,Math.min(16000,fc));rgGain=Math.max(-12,Math.min(12,gain));
+ const xOf=f=>RG.x0+(Math.log10(f)-RG.fLo)/(RG.fHi-RG.fLo)*(RG.x1-RG.x0);
+ const yOf=db=>RG.y0+(RG.db-db)/(2*RG.db)*(RG.y1-RG.y0);
+ const sigma=0.28;let pts='';
+ for(let i=0;i<=76;i++){const lf=RG.fLo+i/76*(RG.fHi-RG.fLo);
+ const db=rgGain*Math.exp(-Math.pow(lf-Math.log10(rgFc),2)/(2*sigma*sigma));
+ pts+=`${xOf(Math.pow(10,lf)).toFixed(1)},${yOf(db).toFixed(1)} `;}
+ rgCurve.setAttribute('points',pts.trim());rgGlowLine.setAttribute('points',pts.trim());
+ rgHandle.setAttribute('cx',xOf(rgFc));rgHandle.setAttribute('cy',yOf(rgGain));
+ const fLbl=rgFc<1000?Math.round(rgFc)+' Hz':(rgFc/1000).toFixed(1)+' kHz';
+ setRd('R26',`${fLbl} · ${rgGain>=0?'+':''}${rgGain.toFixed(1)} dB`);}
+setRgraph(1200,6.5);
+
+/* ============ 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'));
+ setMcVu(.5);
+}
+
+if(!reduced){
+ setInterval(fastTick,80);
+ setInterval(tickMcVu,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>