← back to Quadrille Showroom
public/showroom.html
465 lines
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>The Quadrille House — Wallcovering Showroom</title>
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:wght@500;600;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="/css/showroom.css">
<style>
/* ---- Quadrille House additions (peruse, window controls, mobile d-pad) ---- */
:root { --qh-gold:#c9a96e; }
/* ============================================================
GUIDED MODE — senior-first primary navigation (DTD verdict A)
Big, high-contrast, word-labelled controls at bottom-centre so a
65-year-old needs NO keyboard and NO 3D walking. Tap targets >=56px tall.
============================================================ */
/* Bottom pager — smaller + viewport-responsive (Steve 2026-07-02: reduce the
button size, scale with website width, always show cleanly at the bottom).
Sits centred between the bottom-left/right corner hamburgers with margin to
spare; wraps on narrow screens via the media query below. */
#guided-bar {
position:fixed; left:50%; bottom:16px; transform:translateX(-50%);
z-index:40; display:flex; align-items:center; gap:clamp(6px,1vw,12px);
max-width:calc(100vw - 148px); /* clear the ~64px corner burgers on each side */
background:rgba(12,12,17,0.90); border:1.5px solid rgba(201,169,110,0.45);
border-radius:16px; padding:clamp(6px,0.9vw,10px) clamp(8px,1.2vw,14px);
backdrop-filter:blur(14px); box-shadow:0 18px 50px -12px rgba(0,0,0,0.75);
}
#guided-bar.hidden { display:none; }
.g-btn {
min-height:clamp(38px,5vw,48px); min-width:clamp(82px,11vw,124px);
padding:0 clamp(10px,1.5vw,18px);
display:inline-flex; align-items:center; justify-content:center; gap:6px;
font-size:clamp(12px,1.45vw,16px); font-weight:700; letter-spacing:.4px; cursor:pointer;
border-radius:11px; border:2px solid rgba(201,169,110,0.55);
background:rgba(255,255,255,0.06); color:#f0e6cf; white-space:nowrap;
transition:background .15s, transform .1s, border-color .15s;
-webkit-user-select:none; user-select:none;
}
.g-btn:hover { background:rgba(201,169,110,0.22); border-color:#c9a96e; }
.g-btn:active { transform:translateY(1px); }
.g-btn:disabled { opacity:.4; cursor:default; }
/* The primary Auto-Tour button — brass fill so it's the obvious hero action */
#g-tour {
min-width:clamp(120px,15vw,168px); font-size:clamp(13px,1.5vw,17px);
background:linear-gradient(180deg,#d8bd84,#b9933f); color:#1a1206;
border-color:#b9933f;
}
#g-tour:hover { background:linear-gradient(180deg,#e3cb95,#c5a04a); }
#g-tour.playing { background:linear-gradient(180deg,#d06a5a,#a8392b); color:#fff; border-color:#a8392b; }
/* The 'All Designs' grid button */
#g-grid { min-width:clamp(88px,11vw,118px); }
/* Always-on plain instruction strip above the guided bar */
#guided-instruction {
position:fixed; left:50%; bottom:96px; transform:translateX(-50%);
z-index:39; max-width:90vw; text-align:center;
font-size:18px; font-weight:600; letter-spacing:.3px; color:#f5efe2;
background:rgba(12,12,17,0.74); border:1px solid rgba(201,169,110,0.3);
padding:9px 22px; border-radius:24px; backdrop-filter:blur(8px);
text-shadow:0 1px 3px rgba(0,0,0,0.8);
}
#guided-instruction.hidden { display:none; }
/* Large readable pattern title shown top-centre in guided mode */
#guided-title {
position:fixed; left:50%; top:64px; transform:translateX(-50%);
z-index:38; text-align:center; pointer-events:none;
background:rgba(12,12,17,0.62); border:1px solid rgba(201,169,110,0.25);
border-radius:14px; padding:10px 28px; backdrop-filter:blur(8px);
box-shadow:0 8px 30px -10px rgba(0,0,0,0.6);
}
#guided-title.hidden { display:none; }
#guided-title .gt-name {
font-family:Georgia,'Times New Roman',serif; font-size:30px; font-weight:600;
color:#f5efdc; line-height:1.1; text-shadow:0 2px 6px rgba(0,0,0,0.7);
}
#guided-title .gt-sub {
font-size:16px; color:#d8cfba; margin-top:4px; letter-spacing:1px;
font-variant-numeric:tabular-nums;
}
/* Explore toggle — small, top-right, OFF by default (demotes WASD) */
#btn-explore {
font-size:12px; letter-spacing:1px; text-transform:uppercase;
padding:6px 14px; min-height:36px; border-radius:18px; cursor:pointer;
border:1px solid rgba(201,169,110,0.4); background:rgba(255,255,255,0.05);
color:#c9a96e; font-weight:600;
}
#btn-explore.active { background:rgba(201,169,110,0.85); color:#1a1206; border-color:#c9a96e; }
/* ALL DESIGNS — big-thumbnail grid overlay (even-simpler browse path) */
#grid-overlay {
position:fixed; inset:0; z-index:60; background:rgba(8,8,12,0.96);
display:none; flex-direction:column;
}
#grid-overlay.open { display:flex; }
.go-head {
display:flex; align-items:center; justify-content:space-between;
padding:18px 28px; border-bottom:1px solid rgba(201,169,110,0.2); flex-shrink:0;
}
.go-title { font-family:Georgia,serif; font-size:26px; color:#f0e6cf; letter-spacing:1px; }
.go-close {
min-height:52px; min-width:120px; font-size:18px; font-weight:700; cursor:pointer;
border-radius:12px; border:2px solid rgba(201,169,110,0.5);
background:rgba(201,169,110,0.12); color:#f0e6cf;
}
.go-close:hover { background:rgba(201,169,110,0.28); }
#grid-items {
flex:1; overflow-y:auto; padding:24px 28px;
display:grid; gap:20px;
grid-template-columns:repeat(auto-fill, minmax(220px, 1fr));
align-content:start;
}
.go-card {
cursor:pointer; border-radius:12px; overflow:hidden; background:#15151c;
border:1.5px solid rgba(201,169,110,0.22); transition:transform .12s, border-color .15s;
}
.go-card:hover { transform:translateY(-3px); border-color:#c9a96e; }
.go-card .go-img { width:100%; aspect-ratio:1/1.25; object-fit:cover; display:block; background:#1c1c24; }
.go-card .go-cap { padding:10px 12px; }
.go-card .go-pat { font-family:Georgia,serif; font-size:17px; color:#f0e6cf; line-height:1.2;
white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.go-card .go-col { font-size:13px; color:#a7a299; margin-top:2px; letter-spacing:.5px; }
/* Which nav surface shows depends on mode. Guided (default) = big bar + title;
Explore = compact Now-Viewing strip + bottom HUD instruction. One at a time. */
body.guided-mode #now-viewing { display:none !important; }
body.guided-mode #bottom-bar #info-text { visibility:hidden; } /* keep bar height + FPS, drop the keyboard hint */
body.guided-mode #minimap { display:none; } /* spatial minimap is an explore aid */
body.explore-mode #guided-bar,
body.explore-mode #guided-instruction,
body.explore-mode #guided-title { display:none !important; }
/* BOOK MODE keeps the ◀ Previous / Next ▶ pager visible even while walking (explore-mode),
so paging one design at a time through all 883 is always available. Placed AFTER the
explore-mode hide so equal-specificity !important resolves in book mode's favour. */
body.book-mode #guided-bar { display:flex !important; }
/* On small screens the pager wraps; clamp() already handles button sizing */
@media (max-width:720px){
#guided-bar { flex-wrap:wrap; max-width:calc(100vw - 24px); justify-content:center; }
#guided-title .gt-name { font-size:23px; }
}
.loader-logo, .logo-mark { letter-spacing:.04em; }
#btn-peruse {
background:linear-gradient(180deg,#d8bd84,#b9933f); color:#1a1206; border:none;
font-weight:700; letter-spacing:.06em; text-transform:uppercase; font-size:12px;
padding:8px 16px; border-radius:20px; cursor:pointer; box-shadow:0 2px 10px rgba(185,147,63,.4);
transition:transform .12s, box-shadow .12s;
}
#btn-peruse:hover { transform:translateY(-1px); box-shadow:0 4px 16px rgba(185,147,63,.55); }
#btn-peruse.active { background:linear-gradient(180deg,#d06a5a,#a8392b); color:#fff; box-shadow:0 2px 12px rgba(168,57,43,.55); }
#window-bar {
position:fixed; left:50%; transform:translateX(-50%); bottom:54px; z-index:30;
display:flex; align-items:center; gap:10px; background:rgba(14,14,20,.82);
border:1px solid rgba(201,169,110,.25); border-radius:24px; padding:6px 10px;
backdrop-filter:blur(8px); font-size:12px; color:#d8d4cc;
}
#window-bar button, #sort-select {
background:rgba(255,255,255,.06); color:#e8e4dc; border:1px solid rgba(201,169,110,.3);
border-radius:16px; padding:5px 12px; cursor:pointer; font-size:12px;
}
#window-bar button:hover { background:rgba(201,169,110,.2); }
#window-bar button:disabled { opacity:.35; cursor:default; }
#window-label { min-width:120px; text-align:center; color:var(--qh-gold); font-variant-numeric:tabular-nums; }
.density-wrap { display:flex; align-items:center; gap:6px; }
.density-wrap input { width:64px; }
/* Mobile touch d-pad — hidden on desktop, shown on coarse pointers */
#dpad { position:fixed; right:18px; bottom:90px; z-index:30; display:none;
grid-template-columns:repeat(3,44px); grid-template-rows:repeat(3,44px); gap:4px; }
#dpad button { background:rgba(14,14,20,.8); color:var(--qh-gold); border:1px solid rgba(201,169,110,.35);
border-radius:10px; font-size:18px; -webkit-user-select:none; user-select:none; touch-action:none; }
#dpad .dp-f { grid-column:2; grid-row:1; } #dpad .dp-l { grid-column:1; grid-row:2; }
#dpad .dp-r { grid-column:3; grid-row:2; } #dpad .dp-b { grid-column:2; grid-row:3; }
@media (pointer:coarse) { #dpad { display:grid; } }
.room-thumb { margin-top:8px; width:100%; border-radius:6px; display:none; }
/* PHOTOGRAPHIC DEPTH — a faint vignette + soft top-down directional gradient over
the WebGL canvas (CSS only, zero render cost — does NOT touch the GL pipeline,
so FPS is untouched). Sits above the canvas, below the HUD; never eats clicks.
Kept SUBTLE per ART-DIRECTION: a touch of photographic falloff, not a heavy
post stack. multiply blend so it darkens the room, not the HUD. */
#photo-depth {
position:fixed; inset:0; z-index:5; pointer-events:none; mix-blend-mode:multiply;
background:
linear-gradient(180deg, rgba(28,28,34,0.10) 0%, rgba(255,255,255,0) 26%, rgba(255,255,255,0) 80%, rgba(28,28,34,0.07) 100%),
radial-gradient(120% 90% at 50% 42%, rgba(255,255,255,0) 58%, rgba(20,18,22,0.10) 86%, rgba(16,14,18,0.20) 100%);
}
/* MINIMAL FIXED CAPTION BAR (Steve's pick) — a quiet static strip at the bottom centre.
NO transition / NO animation: it only ever changes its text. */
#wing-caption {
position:fixed; left:50%; bottom:18px; transform:translateX(-50%); z-index:24;
max-width:90vw; padding:7px 18px; border-radius:6px;
background:rgba(14,14,20,0.66); border:1px solid rgba(201,169,110,0.28);
color:#e9e1cf; font-family:Georgia,"Times New Roman",serif; font-size:15px;
letter-spacing:.04em; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
pointer-events:none; backdrop-filter:blur(6px);
}
#wing-caption:empty { display:none; }
/* In book mode the caption bar IS the SKU surface — keep the popping card + guided
surfaces out of the way so the view stays the quiet open mirrored book + caption. */
body.book-mode #wing-detail,
body.book-mode #now-viewing,
body.book-mode #guided-title,
body.book-mode #guided-instruction { display:none !important; }
/* ── Uniform control PILLS (Steve 2026-07-01): every control is the same-size pill;
the bottom #window-bar row is SMALL pills; panels stay tucked in the hamburger. ── */
.vm-chip,
#window-bar button, #window-bar #sort-select,
#vm-sample-addbtn, #vm-sample-add, .sr-btn {
border-radius: 999px !important;
min-height: 30px !important;
padding: 5px 16px !important;
font-size: 12px !important;
line-height: 1.1 !important;
box-sizing: border-box !important;
display: inline-flex !important;
align-items: center !important;
justify-content: center !important;
}
/* small pills along the bottom bar */
#window-bar { border-radius: 999px !important; }
#window-bar button, #window-bar #sort-select {
min-height: 26px !important;
padding: 3px 13px !important;
font-size: 11px !important;
}
</style>
</head>
<body class="guided-mode">
<!-- Loading Screen -->
<div id="loading-screen">
<div class="loader-content">
<div class="loader-logo">QH</div>
<div class="loader-title">The Quadrille House</div>
<div class="loader-sub">Wallcovering Showroom · featuring China Seas</div>
<div class="loader-bar"><div class="loader-fill" id="loadFill"></div></div>
<div class="loader-status" id="loadStatus">Initializing showroom...</div>
</div>
</div>
<!-- HUD Overlay -->
<div id="hud">
<div id="top-bar">
<div class="top-left">
<span class="logo-mark">QH</span>
<span class="showroom-title">The Quadrille House · Wallcoverings</span>
</div>
<div class="top-center">
<button id="btn-peruse" title="Auto-tour the collection (P)">▷ Peruse Collection</button>
<button class="nav-btn" data-section="wings" title="Wing Boards">Wings</button>
<button class="nav-btn active" data-section="overview" title="Full View">Overview</button>
</div>
<div class="top-right">
<button id="btn-explore" title="Turn on free walking with the keyboard (W A S D). Off by default.">Explore: Off</button>
<button id="btn-bookmatch" class="icon-btn active" title="Open board — wings open within 4 ft to present the full continuous design (B)">📖</button>
<button id="btn-walls" class="icon-btn active" title="Wallpaper the room walls on focus">▦</button>
<button id="btn-music" class="icon-btn" title="Listen to Music">♫</button>
<button id="btn-lighting" class="icon-btn" title="Lighting Mode">☼</button>
<button id="btn-fullscreen" class="icon-btn" title="Fullscreen">⛶</button>
</div>
</div>
<!-- Brand Sidebar -->
<div id="vendor-sidebar">
<div class="sidebar-header">Collection</div>
<div id="vendor-list"></div>
</div>
<!-- Wing Detail Panel — spec-sheet card (4-Horsemen / 21st design language) -->
<div id="wing-detail" class="hidden collapsed">
<button id="detail-collapse" class="collapse-btn" title="Show details">▸</button>
<button id="close-detail" class="close-btn">×</button>
<div class="wd-hero">
<img id="detail-room" alt="Room setting">
<div class="wd-hero-fade"></div>
</div>
<div class="wd-body">
<div id="detail-vendor" class="wd-eyebrow">Brand</div>
<div id="detail-pattern" class="wd-title">Pattern Name</div>
<div id="detail-color" class="wd-color">Color</div>
<div id="detail-sku" class="wd-sku">SKU</div>
<dl id="detail-spec-grid" class="wd-specs"></dl>
<div id="detail-flag" class="wd-flag"></div>
</div>
<!-- legacy node kept hidden so any stale ref doesn't throw -->
<div id="detail-specs" hidden></div>
<div class="detail-actions">
<div class="wing-skill-row">
<button class="action-btn primary" id="btn-fan-left">◀ Back</button>
<span class="wing-skill-label">Browse</span>
<button class="action-btn primary" id="btn-fan-right">Next ▶</button>
</div>
<button class="action-btn" id="btn-add-sample">+ Add to Sample Tray</button>
<button class="action-btn" id="btn-view-dw">View on Designer Wallcoverings</button>
<button class="action-btn" id="btn-back-wing">← Back to Showroom</button>
</div>
</div>
<!-- Sample Tray -->
<div id="sample-tray">
<div class="tray-header"><span>Sample Tray</span><span id="tray-count">0</span></div>
<div id="tray-items"></div>
<div id="tray-age">
<label for="tray-age-input">Your age <span class="tray-age-opt">(optional)</span></label>
<input id="tray-age-input" type="number" min="0" max="120" step="1" inputmode="numeric" placeholder="—" autocomplete="off">
</div>
<div id="tray-contact">
<input id="tray-name" class="tray-field" type="text" maxlength="120" placeholder="Name (optional)" autocomplete="name">
<input id="tray-email" class="tray-field" type="email" maxlength="160" placeholder="Email (optional)" autocomplete="email">
<input id="tray-phone" class="tray-field" type="tel" maxlength="40" placeholder="Phone (optional)" autocomplete="tel">
<textarea id="tray-notes" class="tray-field" maxlength="2000" rows="2" placeholder="Notes (optional)"></textarea>
</div>
<button id="tray-submit" type="button" disabled>Request Samples</button>
<div id="tray-consent">We'll use your details only to send the samples you requested.</div>
<div id="tray-status" role="status" aria-live="polite"></div>
</div>
<canvas id="minimap" width="160" height="128"></canvas>
<!-- Window / sort controls (sort + density standing rule) -->
<div id="window-bar">
<button id="btn-prev-window" title="Previous 50">◀ Prev</button>
<span id="window-label">1–50 of 883</span>
<button id="btn-next-window" title="Next 50">Next ▶</button>
<select id="sort-select" title="Sort">
<option value="natural">Sort: Curated</option>
<option value="newest">Newest</option>
<option value="title">Title A→Z</option>
<option value="sku">SKU A→Z</option>
<option value="book">Book</option>
</select>
<span class="density-wrap" title="Wings per wall">
<span>Boards</span><input type="range" id="density-range" min="10" max="50" step="2" value="50">
</span>
<span class="density-wrap" title="Open-board angle (0°=flat, dead-on)">
<span>Wing°</span><input type="range" id="angle-range" min="0" max="90" step="5" value="8"><span id="angle-val">8°</span>
</span>
<span class="density-wrap" title="How much of each closed board's pattern shows — wider edges = fewer boards, thinner slivers = more boards in the arc">
<span>Reveal</span><input type="range" id="reveal-range" min="0" max="100" step="5" value="70"><span id="reveal-val">70</span>
</span>
<span class="density-wrap" title="Open angle of the resting middle board (45° = the boot hero rake)">
<span>Open°</span><input type="range" id="open-range" min="20" max="90" step="5" value="45"><span id="open-val">45°</span>
</span>
<!-- ADJUSTABLE ROOM (Phase 2) — Width / Height / Depth sliders. Tears down + rebuilds
the room shell + wing arc + active room-type furniture via resizeRoom(w,d,h). -->
<span class="density-wrap" title="Room width (metres)">
<span>W</span><input type="range" id="room-w-range" min="3" max="14" step="0.2" value="6.1"><span id="room-w-val">6.1m</span>
</span>
<span class="density-wrap" title="Room depth (metres)">
<span>D</span><input type="range" id="room-d-range" min="3" max="14" step="0.2" value="6.1"><span id="room-d-val">6.1m</span>
</span>
<span class="density-wrap" title="Room height (metres)">
<span>H</span><input type="range" id="room-h-range" min="2.2" max="6" step="0.1" value="2.9"><span id="room-h-val">2.9m</span>
</span>
</div>
<!-- NOW VIEWING navigator — museum media-player strip (shown only on focus).
Brass-hairline + museum glass, conforms to ART-DIRECTION.md. Augments the
detail card's browse row: swatch · serif name · colorway · spec · transport. -->
<div id="now-viewing" class="hidden" aria-label="Now viewing navigator">
<div class="nv-progress"><div class="nv-progress-fill" id="nv-fill"></div></div>
<div class="nv-body">
<div class="nv-swatch"><img id="nv-thumb" alt=""></div>
<div class="nv-meta">
<div class="nv-eyebrow">Now Viewing</div>
<div class="nv-name" id="nv-name">Pattern</div>
<div class="nv-sub"><span id="nv-color" class="nv-color">Colorway</span><span class="nv-dot">·</span><span id="nv-spec" class="nv-spec">27″ × 27″</span></div>
</div>
<div class="nv-transport">
<button id="nv-back" class="nv-btn" title="Back (previous wingboard)" aria-label="Back">◀</button>
<button id="nv-play" class="nv-btn nv-play" title="Peruse (play / pause the tour)" aria-label="Peruse play-pause">▷</button>
<button id="nv-next" class="nv-btn" title="Next wingboard" aria-label="Next">▶</button>
</div>
<div class="nv-count"><span id="nv-index">1</span><span class="nv-of">of</span><span id="nv-total">50</span></div>
</div>
</div>
<div id="bottom-bar">
<span id="info-text">Scroll or ↑↓ to walk · drag or A/D to turn · ←→ change design · Click to inspect · ⊕ Center to return</span>
<span id="fps-counter">60 FPS</span>
</div>
<!-- MINIMAL FIXED CAPTION BAR (Steve's pick) — quiet static strip for the centred design.
Pattern · Colorway · SKU · Vendor. Never pops, slides, or animates; text only. -->
<div id="wing-caption" aria-live="polite"></div>
<!-- GUIDED MODE — large readable pattern title (top-centre) -->
<div id="guided-title">
<div class="gt-name" id="gt-name"> </div>
<div class="gt-sub"><span id="gt-color"></span><span id="gt-dot"> · </span><span id="gt-pos"></span></div>
</div>
<!-- GUIDED MODE — always-visible one-line plain instruction -->
<div id="guided-instruction">Tap <strong>Next</strong> to see the next design — or <strong>Auto Tour</strong> to watch them all.</div>
<!-- GUIDED MODE — big senior-first control bar (no keyboard, no walking) -->
<div id="guided-bar">
<button class="g-btn" id="g-prev" title="See the previous design">◀ Previous</button>
<button class="g-btn" id="g-tour" title="Watch every design hands-free">▷ Auto Tour</button>
<button class="g-btn" id="g-next" title="See the next design">Next ▶</button>
<button class="g-btn" id="g-center" title="Stand back in the middle of the room, facing the wall (C)">⊕ Center</button>
<button class="g-btn" id="g-grid" title="See all designs as big pictures">☷ All Designs</button>
</div>
</div>
<!-- ALL DESIGNS — big-thumbnail grid overlay (even-simpler browse path) -->
<div id="grid-overlay">
<div class="go-head">
<span class="go-title">All Designs — tap a picture to view it</span>
<button class="go-close" id="go-close">× Close</button>
</div>
<div id="grid-items"></div>
</div>
<!-- Welcome Tooltip — senior-first: explains the big buttons, not the keyboard -->
<div id="welcome-tip">
<div class="tip-title">HOW TO BROWSE</div>
<div class="tip-row"><kbd>Next ▶</kbd> See the next design</div>
<div class="tip-row"><kbd>◀ Previous</kbd> See the design before</div>
<div class="tip-row"><kbd>▷ Auto Tour</kbd> Watch them all by itself</div>
<div class="tip-row"><kbd>☷ All Designs</kbd> See every design as big pictures</div>
</div>
<canvas id="showroom-canvas"></canvas>
<!-- Photographic depth: subtle CSS vignette + soft directional gradient (no GL cost) -->
<div id="photo-depth"></div>
<!-- Mobile touch d-pad -->
<div id="dpad">
<button class="dp-f" data-dir="f">▲</button>
<button class="dp-l" data-dir="l">◀</button>
<button class="dp-r" data-dir="r">▶</button>
<button class="dp-b" data-dir="b">▼</button>
</div>
<!-- Music Player (hidden) -->
<div id="music-player" class="hidden">
<div class="music-header"><span>Showroom Ambiance</span><button id="close-music" class="close-btn">×</button></div>
<div class="music-controls">
<button id="music-prev" class="music-btn">◀◀</button>
<button id="music-play" class="music-btn">▶</button>
<button id="music-next" class="music-btn">▶▶</button>
</div>
<div id="music-track">Jazz Lounge</div>
<input type="range" id="music-volume" min="0" max="100" value="30">
</div>
<script src="/js/three.min.js"></script>
<script src="/js/OrbitControls.js"></script>
<script src="/js/GLTFLoader.js"></script>
<script src="/js/rack.js"></script>
<script src="/js/showroom.js"></script>
<script src="/js/viewmodes.js"></script>
<script src="/js/versions.js"></script>
<!-- Hamburger dock: stows every panel on load, re-launches each as a movable modal -->
<script src="/js/modal-rig.js"></script>
<script src="/js/dock.js"></script>
<!-- Furniture style selector: swaps the procedural table+chair set (Option A) -->
<script src="/js/furniture-styles.js"></script>
</body>
</html>