← 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 &middot; 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 &middot; Wallcoverings</span>
      </div>
      <div class="top-center">
        <button id="btn-peruse" title="Auto-tour the collection (P)">&#9655; 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)">&#128214;</button>
        <button id="btn-walls" class="icon-btn active" title="Wallpaper the room walls on focus">&#9638;</button>
        <button id="btn-music" class="icon-btn" title="Listen to Music">&#9835;</button>
        <button id="btn-lighting" class="icon-btn" title="Lighting Mode">&#9788;</button>
        <button id="btn-fullscreen" class="icon-btn" title="Fullscreen">&#x26F6;</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">&#9656;</button>
      <button id="close-detail" class="close-btn">&times;</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">&#9664; Back</button>
          <span class="wing-skill-label">Browse</span>
          <button class="action-btn primary" id="btn-fan-right">Next &#9654;</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">&#8592; 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">&#9664; Prev</button>
      <span id="window-label">1–50 of 883</span>
      <button id="btn-next-window" title="Next 50">Next &#9654;</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&deg;</span><input type="range" id="angle-range" min="0" max="90" step="5" value="8"><span id="angle-val">8&deg;</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&deg;</span><input type="range" id="open-range" min="20" max="90" step="5" value="45"><span id="open-val">45&deg;</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">&middot;</span><span id="nv-spec" class="nv-spec">27&Prime; &times; 27&Prime;</span></div>
        </div>
        <div class="nv-transport">
          <button id="nv-back" class="nv-btn" title="Back (previous wingboard)" aria-label="Back">&#9664;</button>
          <button id="nv-play" class="nv-btn nv-play" title="Peruse (play / pause the tour)" aria-label="Peruse play-pause">&#9655;</button>
          <button id="nv-next" class="nv-btn" title="Next wingboard" aria-label="Next">&#9654;</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 &uarr;&darr; to walk &middot; drag or A/D to turn &middot; &larr;&rarr; change design &middot; Click to inspect &middot; &#8853; 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">&nbsp;</div>
      <div class="gt-sub"><span id="gt-color"></span><span id="gt-dot"> &middot; </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 &mdash; 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">&#9664; Previous</button>
      <button class="g-btn" id="g-tour" title="Watch every design hands-free">&#9655; Auto Tour</button>
      <button class="g-btn" id="g-next" title="See the next design">Next &#9654;</button>
      <button class="g-btn" id="g-center" title="Stand back in the middle of the room, facing the wall (C)">&#8853; Center</button>
      <button class="g-btn" id="g-grid" title="See all designs as big pictures">&#9783; 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 &mdash; tap a picture to view it</span>
      <button class="go-close" id="go-close">&times; 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 &#9654;</kbd> See the next design</div>
    <div class="tip-row"><kbd>&#9664; Previous</kbd> See the design before</div>
    <div class="tip-row"><kbd>&#9655; Auto Tour</kbd> Watch them all by itself</div>
    <div class="tip-row"><kbd>&#9783; 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">&#9650;</button>
    <button class="dp-l" data-dir="l">&#9664;</button>
    <button class="dp-r" data-dir="r">&#9654;</button>
    <button class="dp-b" data-dir="b">&#9660;</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">&times;</button></div>
    <div class="music-controls">
      <button id="music-prev" class="music-btn">&#9664;&#9664;</button>
      <button id="music-play" class="music-btn">&#9654;</button>
      <button id="music-next" class="music-btn">&#9654;&#9654;</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>