← back to Gallery Agentabrams

builds/wall-of-sound/index.html

796 lines

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Wall of Sound — An Immersive Room</title>
<style>
  :root{
    --bg:#0d0d0f; --surface:#17171c; --surface-2:#1d1d24;
    --text:#f5f2ea; --muted:#8a8578;
    --gold:#c9a961; --bronze:#7d6a45;
    --line:rgba(201,169,97,.18);
    /* perspective-driven ambient accents (default: stage) */
    --amb1:#c9a961; --amb2:#7d6a45; --amb-glow:rgba(201,169,97,.18);
    --field:#c9a961;
    --pad:clamp(20px,5vw,64px);
    --ease:cubic-bezier(.22,1,.36,1);
  }
  *{box-sizing:border-box}
  html{scroll-behavior:smooth}
  body{
    margin:0; background:var(--bg); color:var(--text);
    font-family:-apple-system,'Segoe UI','Helvetica Neue',Arial,sans-serif;
    font-size:16px; line-height:1.65; letter-spacing:.01em;
    overflow-x:hidden;
    -webkit-font-smoothing:antialiased;
  }
  h1,h2,h3,.display{font-family:'Didot','Bodoni MT','Playfair Display',Georgia,serif;font-weight:400}
  ::selection{background:var(--gold);color:#0d0d0f}

  /* ambient drifting backdrop */
  .ambient{
    position:fixed;inset:0;z-index:0;pointer-events:none;
    background:
      radial-gradient(60vw 60vw at 22% 18%, var(--amb-glow), transparent 60%),
      radial-gradient(50vw 50vw at 82% 78%, rgba(125,106,69,.14), transparent 62%),
      radial-gradient(40vw 40vw at 50% 50%, rgba(201,169,97,.05), transparent 70%);
    transition:background 1.4s var(--ease);
    animation:drift 18s ease-in-out infinite alternate;
  }
  @keyframes drift{
    from{transform:translate3d(-1.5%,-1%,0) scale(1.02)}
    to{transform:translate3d(1.5%,1.5%,0) scale(1.06)}
  }
  body.quiet .ambient{animation:none}

  .wrap{position:relative;z-index:1;max-width:1200px;margin:0 auto;padding:0 var(--pad)}

  /* ---- utility ---- */
  .kicker{
    font-size:12px;letter-spacing:.15em;text-transform:uppercase;color:var(--muted);
    display:block;margin-bottom:12px;
  }
  .lead{font-size:clamp(17px,2.1vw,21px);color:var(--muted);max-width:62ch}
  .rule{height:1px;background:var(--line);border:0;margin:0}

  a.link{color:var(--gold);text-decoration:none;border-bottom:1px solid var(--line)}

  /* entrance */
  .fade{opacity:0;transform:translateY(28px)}
  .fade.in{animation:fadeUp .7s var(--ease) both}
  @keyframes fadeUp{from{opacity:0;transform:translateY(28px)}to{opacity:1;transform:none}}
  body.quiet .fade{opacity:1!important;transform:none!important;animation:none!important}

  /* ================= TOP BAR ================= */
  header.bar{
    position:sticky;top:0;z-index:40;
    display:flex;align-items:center;justify-content:space-between;gap:16px;
    padding:14px var(--pad);
    background:rgba(13,13,15,.72);backdrop-filter:blur(14px);
    border-bottom:1px solid var(--line);
  }
  .brand{display:flex;align-items:baseline;gap:12px;min-width:0}
  .brand .mark{font-family:'Didot',Georgia,serif;font-size:20px;letter-spacing:.02em;white-space:nowrap}
  .brand .sub{font-size:12px;letter-spacing:.15em;text-transform:uppercase;color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
  .bar-actions{display:flex;gap:8px;align-items:center;flex-shrink:0}
  .btn{
    font:inherit;font-size:12px;letter-spacing:.12em;text-transform:uppercase;
    color:var(--text);background:transparent;border:1px solid var(--line);
    padding:9px 14px;border-radius:10px;cursor:pointer;
    transition:all .2s var(--ease);white-space:nowrap;
  }
  .btn:hover,.btn:focus-visible{border-color:var(--gold);color:var(--gold);outline:none}
  .btn[aria-pressed="true"]{background:var(--gold);color:#0d0d0f;border-color:var(--gold)}
  :focus-visible{outline:2px solid var(--gold);outline-offset:3px;border-radius:6px}

  /* ================= HERO / STAGE ================= */
  .hero{padding:clamp(48px,9vw,96px) 0 40px;text-align:center}
  .hero h1{
    font-size:clamp(38px,8vw,67px);line-height:1.02;margin:0 auto 18px;
    max-width:16ch;letter-spacing:.01em;
  }
  .hero h1 em{font-style:italic;color:var(--gold)}
  .hero .lead{margin:0 auto 8px;text-align:center}

  /* installation frame */
  .installation{
    margin:44px auto 0;max-width:920px;position:relative;
    aspect-ratio:16/10;border:1px solid var(--line);border-radius:16px;
    background:
      radial-gradient(120% 120% at 50% 120%, rgba(201,169,97,.08), transparent 55%),
      linear-gradient(180deg,#101014,#0a0a0c);
    box-shadow:0 30px 90px rgba(0,0,0,.55), inset 0 1px 0 rgba(255,255,255,.03);
    overflow:hidden;
  }
  .installation svg{position:absolute;inset:0;width:100%;height:100%}
  .stage-label{
    position:absolute;left:16px;bottom:14px;
    font-size:12px;letter-spacing:.15em;text-transform:uppercase;color:var(--muted);
    z-index:5;
  }
  .stage-label b{color:var(--gold);font-weight:400}

  /* animated waveform + fields controlled by JS/CSS classes */
  .field-ring{transition:opacity 1s var(--ease), stroke 1.2s var(--ease)}
  .pulse{transform-origin:center;transform-box:fill-box}
  body:not(.quiet) .pulse.a{animation:ripple 5.5s var(--ease) infinite}
  body:not(.quiet) .pulse.b{animation:ripple 5.5s var(--ease) infinite .9s}
  body:not(.quiet) .pulse.c{animation:ripple 5.5s var(--ease) infinite 1.8s}
  body:not(.quiet) .pulse.d{animation:ripple 5.5s var(--ease) infinite 2.7s}
  @keyframes ripple{
    0%{opacity:.85;transform:scale(.28)}
    80%{opacity:0;transform:scale(1.9)}
    100%{opacity:0;transform:scale(1.9)}
  }
  .wave path{transition:opacity .6s var(--ease)}
  body:not(.quiet).demo-on .wave path{animation:wavemove 3s linear infinite}
  @keyframes wavemove{to{transform:translateX(-160px)}}
  .signal{stroke-dasharray:6 10;transition:stroke 1s var(--ease)}
  body:not(.quiet).demo-on .signal{animation:dash 2.2s linear infinite}
  @keyframes dash{to{stroke-dashoffset:-160}}

  .speaker-cell{transition:fill 1.1s var(--ease), opacity 1.1s var(--ease)}
  .listener{transition:transform 1.1s var(--ease), opacity 1s var(--ease)}
  body:not(.quiet).demo-on .lit-meter rect{animation:meter 1.4s var(--ease) infinite alternate}
  @keyframes meter{from{transform:scaleY(.35)}to{transform:scaleY(1)}}
  .lit-meter rect{transform-origin:bottom;transform-box:fill-box}

  /* ================= PERSPECTIVE SWITCH ================= */
  section{padding:clamp(56px,10vw,96px) 0;position:relative}
  section > .wrap { position:relative }
  h2.sec{font-size:clamp(28px,5vw,38px);margin:0 0 8px;letter-spacing:.01em}

  .persp-tabs{display:flex;flex-wrap:wrap;gap:10px;margin:26px 0 34px}
  .tab{
    flex:1 1 180px;text-align:left;
    background:var(--surface);border:1px solid var(--line);border-radius:14px;
    padding:16px 18px;cursor:pointer;transition:all .25s var(--ease);
    color:var(--text);font:inherit;position:relative;overflow:hidden;
  }
  .tab .n{font-size:12px;letter-spacing:.15em;text-transform:uppercase;color:var(--muted)}
  .tab .t{font-family:'Didot',Georgia,serif;font-size:22px;margin-top:6px}
  .tab::after{content:"";position:absolute;left:0;bottom:0;height:3px;width:0;background:var(--field);transition:width .35s var(--ease)}
  .tab:hover{transform:translateY(-3px);box-shadow:0 16px 48px rgba(0,0,0,.28)}
  .tab[aria-selected="true"]{border-color:var(--field);background:var(--surface-2)}
  .tab[aria-selected="true"]::after{width:100%}
  .tab[aria-selected="true"] .t{color:var(--field)}

  .persp-body{
    display:grid;grid-template-columns:1.1fr 1fr;gap:clamp(24px,4vw,48px);align-items:center;
  }
  .diagram{
    border:1px solid var(--line);border-radius:16px;overflow:hidden;position:relative;
    aspect-ratio:4/3;background:linear-gradient(180deg,#101014,#0b0b0e);
    box-shadow:0 20px 60px rgba(0,0,0,.4);
  }
  .diagram svg{width:100%;height:100%;display:block}
  .persp-text .kicker{color:var(--field)}
  .persp-text h3{font-size:clamp(24px,4vw,32px);margin:0 0 14px}
  .persp-text p{color:var(--muted);margin:0 0 18px}
  .meta-grid{display:grid;grid-template-columns:1fr 1fr;gap:14px;margin-top:8px}
  .meta{border-top:1px solid var(--line);padding-top:10px}
  .meta .k{font-size:12px;letter-spacing:.14em;text-transform:uppercase;color:var(--muted)}
  .meta .v{font-family:'Didot',Georgia,serif;font-size:19px;color:var(--text);margin-top:2px}

  /* ================= EXPLODED VIEW ================= */
  .exploded-stage{
    border:1px solid var(--line);border-radius:16px;overflow:hidden;
    background:linear-gradient(180deg,#101014,#0a0a0c);position:relative;
    box-shadow:0 24px 70px rgba(0,0,0,.45);
  }
  .exploded-stage svg{width:100%;height:auto;display:block}
  .layer{transition:transform .8s var(--ease), opacity .6s var(--ease)}
  .exploded .layer.l1{transform:translateY(-46px)}
  .exploded .layer.l2{transform:translateY(-16px)}
  .exploded .layer.l3{transform:translateY(16px)}
  .exploded .layer.l4{transform:translateY(46px)}
  .callout{opacity:0;transition:opacity .5s var(--ease) .2s}
  .exploded .callout{opacity:1}

  /* ================= CARDS GRID ================= */
  .grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:24px;margin-top:36px}
  .card{
    background:var(--surface);border:1px solid var(--line);border-radius:14px;
    padding:24px;transition:transform .25s var(--ease),box-shadow .25s var(--ease),border-color .25s var(--ease);
    position:relative;
  }
  .card:hover{transform:translateY(-4px);box-shadow:0 16px 48px rgba(0,0,0,.28);border-color:var(--gold)}
  .card .spec{font-size:12px;letter-spacing:.15em;text-transform:uppercase;color:var(--gold);margin-bottom:6px}
  .card h3{font-size:23px;margin:0 0 10px}
  .card p{color:var(--muted);font-size:15px;margin:0 0 14px}
  .card .stats{display:flex;flex-wrap:wrap;gap:8px}
  .chip{font-size:11px;letter-spacing:.1em;text-transform:uppercase;color:var(--muted);border:1px solid var(--line);border-radius:20px;padding:5px 11px}
  .card-icon{width:44px;height:44px;margin-bottom:16px;color:var(--gold)}

  /* history — timeline */
  .timeline{margin-top:36px;border-left:1px solid var(--line);padding-left:28px;display:grid;gap:34px}
  .tl{position:relative}
  .tl::before{content:"";position:absolute;left:-34px;top:6px;width:11px;height:11px;border-radius:50%;background:var(--gold);box-shadow:0 0 0 5px rgba(201,169,97,.12)}
  .tl .yr{font-family:'Didot',Georgia,serif;font-size:26px;color:var(--gold)}
  .tl h3{font-size:20px;margin:2px 0 8px}
  .tl p{color:var(--muted);margin:0;max-width:60ch}

  /* glossary */
  details.gl{
    border-bottom:1px solid var(--line);padding:4px 0;
  }
  details.gl summary{
    list-style:none;cursor:pointer;padding:18px 4px;display:flex;justify-content:space-between;align-items:baseline;gap:16px;
    transition:color .2s var(--ease);
  }
  details.gl summary::-webkit-details-marker{display:none}
  details.gl summary .term{font-family:'Didot',Georgia,serif;font-size:22px}
  details.gl summary .pron{font-size:12px;letter-spacing:.12em;text-transform:uppercase;color:var(--muted)}
  details.gl[open] summary .term{color:var(--gold)}
  details.gl .def{padding:0 4px 20px;color:var(--muted);max-width:70ch;animation:fadeUp .4s var(--ease) both}
  .plus{color:var(--gold);font-size:20px;transition:transform .3s var(--ease)}
  details.gl[open] .plus{transform:rotate(45deg)}

  footer{padding:64px var(--pad) 80px;border-top:1px solid var(--line);text-align:center;position:relative;z-index:1}
  footer .disc{max-width:64ch;margin:16px auto 0;font-size:13px;color:var(--muted)}

  .demo-note{
    display:inline-flex;align-items:center;gap:10px;margin-top:22px;
    font-size:12px;letter-spacing:.1em;text-transform:uppercase;color:var(--muted);
    border:1px solid var(--line);border-radius:20px;padding:8px 16px;
  }
  .dot{width:8px;height:8px;border-radius:50%;background:var(--muted);transition:background .3s}
  .demo-on .dot{background:var(--gold);box-shadow:0 0 12px var(--gold)}

  .quiet-flag{
    position:fixed;left:50%;bottom:24px;transform:translateX(-50%) translateY(140%);
    background:var(--surface-2);border:1px solid var(--gold);color:var(--gold);
    padding:10px 20px;border-radius:24px;z-index:60;
    font-size:12px;letter-spacing:.14em;text-transform:uppercase;
    transition:transform .5s var(--ease);box-shadow:0 10px 40px rgba(0,0,0,.5);
  }
  body.quiet .quiet-flag{transform:translateX(-50%) translateY(0)}

  .kbd{font-family:ui-monospace,Menlo,monospace;font-size:12px;background:var(--surface-2);border:1px solid var(--line);border-bottom-width:2px;border-radius:6px;padding:2px 7px;color:var(--text)}

  @media(max-width:760px){
    .persp-body{grid-template-columns:1fr}
    .brand .sub{display:none}
    .meta-grid{grid-template-columns:1fr}
  }
  @media(prefers-reduced-motion:reduce){
    *{animation:none!important;scroll-behavior:auto}
    .fade{opacity:1;transform:none}
  }
</style>
</head>
<body>
<div class="ambient" aria-hidden="true"></div>

<header class="bar">
  <div class="brand">
    <span class="mark">Wall of Sound</span>
    <span class="sub">An Immersive Room · Gallery Installation</span>
  </div>
  <div class="bar-actions">
    <button class="btn" id="demoBtn" aria-pressed="false" title="Toggle the honest visual simulation (no audio)">◈ Demo Signal</button>
    <button class="btn" id="quietBtn" aria-pressed="false" title="Stop all motion; preserve the design">Quiet Mode</button>
  </div>
</header>

<main>
  <!-- HERO -->
  <section class="hero" id="top">
    <div class="wrap">
      <span class="kicker fade">A Virtual Installation · Sound as Architecture</span>
      <h1 class="fade">Standing Inside the <em>Wall of Sound</em></h1>
      <p class="lead fade">In 1974 a band tried to remove distortion from live music by building a speaker system that was, in effect, a building. This room is a study of that ambition — a place to move between vantage points and watch how a single signal reshapes the air around you.</p>

      <div class="installation fade" role="img" aria-label="Abstract monumental speaker array with concentric sound fields and a moving waveform.">
        <svg viewBox="0 0 920 575" preserveAspectRatio="xMidYMid slice" id="heroSvg">
          <defs>
            <linearGradient id="col" x1="0" y1="0" x2="0" y2="1">
              <stop offset="0" stop-color="#22222a"/><stop offset="1" stop-color="#0c0c10"/>
            </linearGradient>
            <radialGradient id="pool" cx="50%" cy="82%" r="60%">
              <stop offset="0" stop-color="var(--amb1)" stop-opacity=".28"/>
              <stop offset="1" stop-color="var(--amb1)" stop-opacity="0"/>
            </radialGradient>
            <filter id="soft"><feGaussianBlur stdDeviation="2.2"/></filter>
          </defs>

          <!-- pool of light -->
          <rect x="0" y="0" width="920" height="575" fill="url(#pool)"/>

          <!-- concentric sound fields -->
          <g fill="none" stroke="var(--field)" stroke-opacity=".22">
            <circle class="field-ring" cx="460" cy="250" r="120"/>
            <circle class="field-ring" cx="460" cy="250" r="185"/>
            <circle class="field-ring" cx="460" cy="250" r="255"/>
            <circle class="field-ring" cx="460" cy="250" r="330"/>
          </g>
          <!-- animated pulses -->
          <g fill="none" stroke="var(--field)" stroke-width="1.4" stroke-opacity=".5">
            <circle class="pulse a" cx="460" cy="250" r="120"/>
            <circle class="pulse b" cx="460" cy="250" r="120"/>
            <circle class="pulse c" cx="460" cy="250" r="120"/>
            <circle class="pulse d" cx="460" cy="250" r="120"/>
          </g>

          <!-- THE ARRAY : abstract towers of speaker cells -->
          <g id="array">
            <!-- back scaffold -->
            <g stroke="#3a3527" stroke-width="1.5" stroke-opacity=".7">
              <line x1="300" y1="70" x2="300" y2="470"/><line x1="620" y1="70" x2="620" y2="470"/>
              <line x1="300" y1="70" x2="620" y2="70"/><line x1="300" y1="470" x2="620" y2="470"/>
              <line x1="360" y1="70" x2="360" y2="470"/><line x1="460" y1="70" x2="460" y2="470"/><line x1="560" y1="70" x2="560" y2="470"/>
            </g>
          </g>

          <!-- moving waveform band -->
          <g class="wave" opacity=".9">
            <path d="M-160,250 q40,-40 80,0 t80,0 t80,0 t80,0 t80,0 t80,0 t80,0 t80,0 t80,0 t80,0 t80,0 t80,0 t80,0 t80,0"
                  fill="none" stroke="var(--field)" stroke-width="1.6" stroke-opacity=".5"/>
          </g>

          <!-- signal path from board to array -->
          <path class="signal" d="M120,520 C260,520 300,360 460,320" fill="none" stroke="var(--amb1)" stroke-width="1.6" stroke-opacity=".8"/>
          <circle cx="120" cy="520" r="5" fill="var(--amb1)"/>

          <!-- level meter -->
          <g class="lit-meter" transform="translate(720,360)" opacity=".85">
            <rect x="0" width="8" height="70" fill="var(--field)" fill-opacity=".7"/>
            <rect x="14" width="8" height="70" fill="var(--field)" fill-opacity=".55"/>
            <rect x="28" width="8" height="70" fill="var(--field)" fill-opacity=".7"/>
            <rect x="42" width="8" height="70" fill="var(--field)" fill-opacity=".5"/>
          </g>
        </svg>
        <div class="stage-label">Perspective: <b id="stageName">Front Rail</b> · <span id="demoState">signal idle</span></div>
      </div>

      <div class="demo-note"><span class="dot"></span><span id="noteTxt">Visual simulation — this installation makes no sound. Toggle “Demo Signal” to animate the modeled signal path.</span></div>
    </div>
  </section>

  <hr class="rule"/>

  <!-- PERSPECTIVES -->
  <section id="perspectives">
    <div class="wrap">
      <span class="kicker fade" style="color:var(--field)">Four Listening Perspectives</span>
      <h2 class="sec fade">Where you stand is what you hear</h2>
      <p class="lead fade">A wall of sound is not one experience but a gradient of them. Choose a vantage point — the diagram, the ambient light, the interpretive text, and the modeled signal path all change with you.</p>

      <div class="persp-tabs fade" role="tablist" aria-label="Listening perspectives">
        <button class="tab" role="tab" aria-selected="false" data-p="stage" id="tab-stage">
          <span class="n">01 · On</span><span class="t">Stage</span>
        </button>
        <button class="tab" role="tab" aria-selected="true" data-p="rail" id="tab-rail">
          <span class="n">02 · The</span><span class="t">Front Rail</span>
        </button>
        <button class="tab" role="tab" aria-selected="false" data-p="board" id="tab-board">
          <span class="n">03 · At the</span><span class="t">Soundboard</span>
        </button>
        <button class="tab" role="tab" aria-selected="false" data-p="hill" id="tab-hill">
          <span class="n">04 · The</span><span class="t">Hillside</span>
        </button>
      </div>

      <div class="persp-body">
        <div class="diagram fade" id="diagram" role="img" aria-live="polite" aria-label="Spatial diagram of the chosen perspective.">
          <svg viewBox="0 0 480 360" id="planSvg">
            <defs>
              <radialGradient id="d-pool" cx="50%" cy="30%" r="70%">
                <stop offset="0" stop-color="var(--field)" stop-opacity=".22"/>
                <stop offset="1" stop-color="var(--field)" stop-opacity="0"/>
              </radialGradient>
            </defs>
            <rect x="0" y="0" width="480" height="360" fill="url(#d-pool)"/>
            <!-- the wall (fixed) -->
            <g id="wall">
              <rect x="150" y="26" width="180" height="40" rx="4" fill="none" stroke="var(--field)" stroke-opacity=".8"/>
              <g stroke="var(--field)" stroke-opacity=".4">
                <line x1="180" y1="26" x2="180" y2="66"/><line x1="210" y1="26" x2="210" y2="66"/>
                <line x1="240" y1="26" x2="240" y2="66"/><line x1="270" y1="26" x2="270" y2="66"/><line x1="300" y1="26" x2="300" y2="66"/>
              </g>
              <text x="240" y="18" text-anchor="middle" fill="var(--muted)" font-size="10" letter-spacing="2">THE ARRAY</text>
            </g>
            <!-- radiating field -->
            <g id="dfield" fill="none" stroke="var(--field)" stroke-opacity=".3">
              <path d="M240,66 Q140,150 120,300"/>
              <path d="M240,66 Q240,180 240,320"/>
              <path d="M240,66 Q340,150 360,300"/>
            </g>
            <!-- listener marker (moves per perspective) -->
            <g class="listener" id="listener">
              <circle cx="240" cy="250" r="9" fill="var(--field)"/>
              <circle cx="240" cy="250" r="18" fill="none" stroke="var(--field)" stroke-opacity=".5"/>
              <text x="240" y="285" text-anchor="middle" fill="var(--text)" font-size="10" letter-spacing="2" id="youTxt">YOU</text>
            </g>
            <!-- signal path (animated when demo on) -->
            <path class="signal" id="dsignal" d="M240,320 C240,200 240,140 240,66" fill="none" stroke="var(--amb1)" stroke-width="1.4"/>
          </svg>
        </div>

        <div class="persp-text fade">
          <span class="kicker" id="pKicker">Perspective 02</span>
          <h3 id="pTitle">The Front Rail</h3>
          <p id="pBody"></p>
          <div class="meta-grid">
            <div class="meta"><div class="k">Spatial Character</div><div class="v" id="mChar"></div></div>
            <div class="meta"><div class="k">Ambient Field</div><div class="v" id="mColor"></div></div>
            <div class="meta"><div class="k">Distance to Array</div><div class="v" id="mDist"></div></div>
            <div class="meta"><div class="k">Perceived Image</div><div class="v" id="mImage"></div></div>
          </div>
        </div>
      </div>
    </div>
  </section>

  <hr class="rule"/>

  <!-- EXPLODED VIEW -->
  <section id="exploded">
    <div class="wrap">
      <span class="kicker fade">Technical View · 1970s Engineering Drawing</span>
      <h2 class="sec fade">The array, taken apart</h2>
      <p class="lead fade">A monumental column separated into its functional strata. Toggle the exploded view to see how frequency was divided across dedicated banks — the design principle that let each driver do only one job.</p>
      <p class="fade" style="margin:22px 0"><button class="btn" id="explodeBtn" aria-pressed="false">⤢ Explode the Column</button></p>

      <div class="exploded-stage fade" id="explodeStage">
        <svg viewBox="0 0 900 460" role="img" aria-label="Exploded technical diagram of the speaker column, four layers.">
          <defs>
            <pattern id="grid" width="26" height="26" patternUnits="userSpaceOnUse">
              <path d="M26 0H0V26" fill="none" stroke="#26221a" stroke-width=".6"/>
            </pattern>
          </defs>
          <rect x="0" y="0" width="900" height="460" fill="url(#grid)"/>
          <!-- center axis -->
          <line x1="450" y1="20" x2="450" y2="440" stroke="var(--bronze)" stroke-dasharray="3 6" stroke-opacity=".5"/>

          <!-- Layer 4: sub-bass base -->
          <g class="layer l4">
            <rect x="330" y="330" width="240" height="70" rx="5" fill="#15150f" stroke="var(--gold)" stroke-opacity=".7"/>
            <circle cx="390" cy="365" r="22" fill="none" stroke="var(--gold)" stroke-opacity=".7"/>
            <circle cx="450" cy="365" r="22" fill="none" stroke="var(--gold)" stroke-opacity=".7"/>
            <circle cx="510" cy="365" r="22" fill="none" stroke="var(--gold)" stroke-opacity=".7"/>
            <g class="callout"><line x1="570" y1="365" x2="700" y2="365" stroke="var(--muted)"/><text x="706" y="362" fill="var(--muted)" font-size="12">Sub-bass bank · below 100 Hz</text><text x="706" y="378" fill="var(--muted)" font-size="10" letter-spacing="1">STRAIGHT-LINE, NO CROSSOVER</text></g>
          </g>
          <!-- Layer 3: low-mid -->
          <g class="layer l3">
            <rect x="355" y="250" width="190" height="66" rx="5" fill="#161610" stroke="var(--gold)" stroke-opacity=".7"/>
            <circle cx="410" cy="283" r="18" fill="none" stroke="var(--gold)" stroke-opacity=".7"/>
            <circle cx="450" cy="283" r="18" fill="none" stroke="var(--gold)" stroke-opacity=".7"/>
            <circle cx="490" cy="283" r="18" fill="none" stroke="var(--gold)" stroke-opacity=".7"/>
            <g class="callout"><line x1="545" y1="283" x2="700" y2="283" stroke="var(--muted)"/><text x="706" y="280" fill="var(--muted)" font-size="12">Low-mid drivers · 100–400 Hz</text></g>
          </g>
          <!-- Layer 2: mid -->
          <g class="layer l2">
            <rect x="375" y="180" width="150" height="56" rx="5" fill="#17170f" stroke="var(--gold)" stroke-opacity=".7"/>
            <rect x="395" y="196" width="26" height="26" fill="none" stroke="var(--gold)" stroke-opacity=".7"/>
            <rect x="437" y="196" width="26" height="26" fill="none" stroke="var(--gold)" stroke-opacity=".7"/>
            <rect x="479" y="196" width="26" height="26" fill="none" stroke="var(--gold)" stroke-opacity=".7"/>
            <g class="callout"><line x1="375" y1="208" x2="200" y2="208" stroke="var(--muted)"/><text x="196" y="205" text-anchor="end" fill="var(--muted)" font-size="12">Midrange cluster · 400 Hz–4 kHz</text></g>
          </g>
          <!-- Layer 1: tweeter crown -->
          <g class="layer l1">
            <rect x="398" y="120" width="104" height="44" rx="5" fill="#18180f" stroke="var(--gold)" stroke-opacity=".8"/>
            <polygon points="420,142 434,132 434,152" fill="none" stroke="var(--gold)" stroke-opacity=".8"/>
            <polygon points="452,142 466,132 466,152" fill="none" stroke="var(--gold)" stroke-opacity=".8"/>
            <g class="callout"><line x1="398" y1="142" x2="200" y2="142" stroke="var(--muted)"/><text x="196" y="139" text-anchor="end" fill="var(--muted)" font-size="12">Tweeter crown · above 4 kHz</text></g>
          </g>

          <text x="450" y="440" text-anchor="middle" fill="var(--muted)" font-size="10" letter-spacing="3">FIG. 1 — VERTICAL DRIVER STRATIFICATION · NOT TO SCALE</text>
        </svg>
      </div>
    </div>
  </section>

  <hr class="rule"/>

  <!-- HISTORY -->
  <section id="history">
    <div class="wrap">
      <span class="kicker fade">A Concise History</span>
      <h2 class="sec fade">The most ambitious PA ever built</h2>
      <p class="lead fade">Between 1973 and 1974 a touring band and its audio engineers pursued a radical idea: instead of amplifying a signal and pointing it at a crowd, build a system so transparent that the amplifier disappears and only the instrument remains.</p>

      <div class="timeline">
        <div class="tl fade"><div class="yr">1965–72</div><h3>The distortion problem</h3><p>Early rock PA systems muddied everything — vocals fought guitars through the same overtaxed columns, and musicians on stage couldn't hear themselves clearly. The dream took shape: a system with no compromise between fidelity and volume.</p></div>
        <div class="tl fade"><div class="yr">1973</div><h3>One driver, one job</h3><p>Engineers split the signal so each range of frequencies had its own dedicated bank of speakers. Instruments were kept on separate channels rather than mixed into a common muddy bus, letting each voice radiate cleanly from its own column.</p></div>
        <div class="tl fade"><div class="yr">1974</div><h3>The wall stands</h3><p>At full height the system rose behind the musicians as a towering array of hundreds of drivers — a monument of speaker cabinets that doubled as the band's own monitor. It projected startlingly clear sound across great distances, coherent even a quarter-mile away.</p></div>
        <div class="tl fade"><div class="yr">1974 →</div><h3>Beautiful and impossible</h3><p>It demanded enormous power, two full crews, and days to assemble. Retired within a year, it remains a landmark in the history of live audio — proof that a crowd could share not just a concert but a single, unified field of sound.</p></div>
      </div>
    </div>
  </section>

  <hr class="rule"/>

  <!-- EQUIPMENT -->
  <section id="equipment">
    <div class="wrap">
      <span class="kicker fade">Annotated Equipment</span>
      <h2 class="sec fade">What the room is made of</h2>
      <p class="lead fade">The installation abstracts real components into sculptural forms. Each card annotates the engineering intent behind a part of the array.</p>

      <div class="grid">
        <article class="card fade">
          <svg class="card-icon" viewBox="0 0 44 44" fill="none" stroke="currentColor" stroke-width="1.4"><rect x="6" y="4" width="32" height="36" rx="3"/><circle cx="22" cy="16" r="7"/><circle cx="22" cy="31" r="4"/></svg>
          <div class="spec">Component 01</div>
          <h3>Driver Column</h3>
          <p>A vertical stack of matched loudspeakers, each cell reproducing only a narrow band of frequencies so it never has to compromise. Stacked, they form the “wall.”</p>
          <div class="stats"><span class="chip">Full-range</span><span class="chip">Line-source</span><span class="chip">Modular</span></div>
        </article>

        <article class="card fade">
          <svg class="card-icon" viewBox="0 0 44 44" fill="none" stroke="currentColor" stroke-width="1.4"><path d="M4 22h8l4-12 6 24 5-16 3 8h10"/></svg>
          <div class="spec">Component 02</div>
          <h3>Active Crossover</h3>
          <p>Divides the incoming signal into frequency bands before amplification, sending highs, mids and lows to their own dedicated banks. The key to a clean, un-muddied field.</p>
          <div class="stats"><span class="chip">4-way split</span><span class="chip">Pre-amp</span><span class="chip">Phase-aligned</span></div>
        </article>

        <article class="card fade">
          <svg class="card-icon" viewBox="0 0 44 44" fill="none" stroke="currentColor" stroke-width="1.4"><rect x="5" y="10" width="34" height="24" rx="3"/><circle cx="14" cy="22" r="4"/><circle cx="26" cy="22" r="4"/><path d="M33 17v10"/></svg>
          <div class="spec">Component 03</div>
          <h3>Power Amplifiers</h3>
          <p>Rows of amplifiers deliver the immense, clean headroom the array requires. Generous power reserves keep transients sharp instead of clipping into distortion.</p>
          <div class="stats"><span class="chip">High headroom</span><span class="chip">Low noise</span><span class="chip">Redundant</span></div>
        </article>

        <article class="card fade">
          <svg class="card-icon" viewBox="0 0 44 44" fill="none" stroke="currentColor" stroke-width="1.4"><rect x="6" y="6" width="32" height="32" rx="3"/><path d="M12 14h20M12 22h20M12 30h20"/><circle cx="16" cy="14" r="1.6" fill="currentColor"/><circle cx="24" cy="22" r="1.6" fill="currentColor"/><circle cx="20" cy="30" r="1.6" fill="currentColor"/></svg>
          <div class="spec">Component 04</div>
          <h3>Mixing Console</h3>
          <p>The soundboard, positioned out in the audience, where the engineer balances each instrument's channel. Every source keeps its own path to its own speakers.</p>
          <div class="stats"><span class="chip">Multi-channel</span><span class="chip">Front-of-house</span><span class="chip">Per-source</span></div>
        </article>

        <article class="card fade">
          <svg class="card-icon" viewBox="0 0 44 44" fill="none" stroke="currentColor" stroke-width="1.4"><path d="M22 6v32M10 14v16M34 14v16M4 20v8M40 20v8"/></svg>
          <div class="spec">Component 05</div>
          <h3>Differential Mic Rig</h3>
          <p>Paired microphones cancel a vocalist's own monitor bleed, so the singer can stand directly in front of the wall without a feedback howl — letting the array serve as its own monitor.</p>
          <div class="stats"><span class="chip">Noise-cancelling</span><span class="chip">On-axis</span><span class="chip">Feedback-safe</span></div>
        </article>

        <article class="card fade">
          <svg class="card-icon" viewBox="0 0 44 44" fill="none" stroke="currentColor" stroke-width="1.4"><rect x="8" y="8" width="28" height="28"/><path d="M8 8l28 28M36 8L8 36"/></svg>
          <div class="spec">Component 06</div>
          <h3>Scaffold & Rigging</h3>
          <p>The structural steel that holds tons of cabinetry safely upright. Assembling and striking the tower took a dedicated crew and the better part of a day at each stop.</p>
          <div class="stats"><span class="chip">Load-rated</span><span class="chip">Tour-portable</span><span class="chip">Two crews</span></div>
        </article>
      </div>
    </div>
  </section>

  <hr class="rule"/>

  <!-- GLOSSARY -->
  <section id="glossary">
    <div class="wrap">
      <span class="kicker fade">Acoustics Glossary</span>
      <h2 class="sec fade">A short lexicon of the field</h2>
      <p class="lead fade">The vocabulary a listener needs to read this room. Open a term to expand its definition.</p>

      <div class="fade" style="margin-top:30px">
        <details class="gl"><summary><span><span class="term">Line Source</span> <span class="pron"> · ˈlīn sȯrs</span></span><span class="plus">+</span></summary><div class="def">A tall vertical column of drivers that behaves as a single continuous emitter. Its sound spreads cylindrically rather than spherically, so level falls off far more slowly with distance — the physical reason a wall of sound stays coherent across a large field.</div></details>
        <details class="gl"><summary><span><span class="term">Crossover</span> <span class="pron"> · ˈkrȯs-ˌō-vər</span></span><span class="plus">+</span></summary><div class="def">The circuit that splits a full-range signal into frequency bands and routes each to speakers built for it. An <em>active</em> crossover does this before amplification, giving each band its own clean amplifier and eliminating the interference that muddies a shared driver.</div></details>
        <details class="gl"><summary><span><span class="term">Headroom</span> <span class="pron"> · ˈhed-ˌrüm</span></span><span class="plus">+</span></summary><div class="def">The margin between the average signal level and the point of distortion. Abundant headroom lets sudden transients — a drum hit, a plucked string — reproduce cleanly instead of clipping, which is why the system carried far more power than its average output required.</div></details>
        <details class="gl"><summary><span><span class="term">Phase Coherence</span> <span class="pron"> · ˈfāz kō-ˈhir-əns</span></span><span class="plus">+</span></summary><div class="def">When multiple drivers radiate the same waveform in step, their outputs reinforce rather than cancel. Aligning phase across hundreds of speakers is what turns a crowd of cabinets into one unified sound field instead of a smear of echoes.</div></details>
        <details class="gl"><summary><span><span class="term">Standing Wave</span> <span class="pron"> · ˈstan-diŋ ˈwāv</span></span><span class="plus">+</span></summary><div class="def">A stationary pattern of loud and quiet zones formed when reflected sound overlaps the source. Large indoor systems fight standing waves with directivity and placement; outdoors, the open air lets the field radiate freely.</div></details>
        <details class="gl"><summary><span><span class="term">Directivity</span> <span class="pron"> · də-ˌrek-ˈti-və-tē</span></span><span class="plus">+</span></summary><div class="def">How tightly a source focuses its energy in a given direction. High directivity concentrates sound toward the audience and away from reflective surfaces, improving clarity and reducing the feedback that plagues open-stage vocals.</div></details>
        <details class="gl"><summary><span><span class="term">Transient</span> <span class="pron"> · ˈtran(t)-sh(ē-)ənt</span></span><span class="plus">+</span></summary><div class="def">The brief, sharp attack at the onset of a sound — the leading edge that carries much of its perceived realism. Preserving transients requires fast, un-clipped reproduction, one of the array's central design goals.</div></details>
      </div>
    </div>
  </section>
</main>

<footer>
  <div class="wrap">
    <span class="kicker">Wall of Sound · An Immersive Room</span>
    <p style="font-family:'Didot',Georgia,serif;font-size:clamp(22px,4vw,30px);margin:14px 0 0">“Not amplification — architecture.”</p>
    <p class="disc"><strong style="color:var(--gold);font-weight:400">On honesty:</strong> This is a silent visual installation. It plays no audio and simulates none. The “Demo Signal” control animates a <em>modeled</em> signal path — an illustration of how the system distributed sound — and produces no sound whatsoever. All motion can be stopped with Quiet Mode without losing any of the design.</p>
    <p class="disc" style="margin-top:18px">Keyboard: <span class="kbd">1</span>–<span class="kbd">4</span> switch perspectives · <span class="kbd">D</span> demo signal · <span class="kbd">Q</span> quiet mode · <span class="kbd">E</span> explode · <span class="kbd">← →</span> cycle perspective · <span class="kbd">Tab</span> to traverse controls.</p>
  </div>
</footer>

<div class="quiet-flag" role="status" aria-live="polite">Quiet Mode · Motion Stilled</div>

<script>
(function(){
  "use strict";
  var body = document.body;

  /* ---------- perspective data ---------- */
  var P = {
    stage: {
      idx:"01", name:"On Stage", label:"On Stage",
      body:"You stand where the musicians stood — with the wall directly behind you. Here the array is a monitor: your own voice returns to you clean and immediate, and the field radiates outward past your shoulders into the dark. The sensation is of being inside the source, not in front of it.",
      char:"Enveloping", color:"Amber Core", dist:"0 m · at the array", image:"Behind & around",
      amb1:"#c9a961", amb2:"#7d6a45", field:"#d8b869",
      listenY:76, listenX:240, you:"MUSICIAN", signal:"M240,300 C240,180 240,120 240,66"
    },
    rail: {
      idx:"02", name:"The Front Rail", label:"Front Rail",
      body:"Pressed against the barrier, you are inside the near field. Individual driver columns are still resolvable — you can almost point to where each instrument lives on the wall. The image is enormous and physical, the transients arriving as pressure you feel before you name it.",
      char:"Immediate · Physical", color:"Warm Gold", dist:"6 m · near field", image:"Wall-wide, resolvable",
      amb1:"#c9a961", amb2:"#8a6f3a", field:"#c9a961",
      listenY:150, listenX:240, you:"YOU", signal:"M240,320 C240,220 240,150 240,66"
    },
    board: {
      idx:"03", name:"At the Soundboard", label:"Soundboard",
      body:"Out in the crowd at front-of-house, you hear the mix as the engineer balances it. The columns have merged into a single coherent panorama; instruments occupy stable positions across a wide, even stage. This is the sweet spot the whole system was tuned to serve.",
      char:"Balanced · Coherent", color:"Bronze Neutral", dist:"30 m · far field", image:"Unified panorama",
      amb1:"#b79a5e", amb2:"#6f5d3c", field:"#a98f57",
      listenY:250, listenX:240, you:"ENGINEER", signal:"M240,340 C240,240 240,150 240,66"
    },
    hill: {
      idx:"04", name:"The Hillside", label:"Hillside",
      body:"Far back on the grass, a quarter-mile from the array, the wall proves its purpose. Level has barely fallen; clarity survives the distance where an ordinary system would have collapsed into mush. The field is now a shared atmosphere binding thousands of listeners into one audience.",
      char:"Vast · Communal", color:"Cool Dusk", dist:"400 m · distant field", image:"Atmospheric, shared",
      amb1:"#8f9bb0", amb2:"#5d6b52", field:"#9aa6b8",
      listenY:320, listenX:240, you:"CROWD", signal:"M240,352 C240,250 240,150 240,66"
    }
  };
  var order = ["stage","rail","board","hill"];
  var current = "rail";

  var tabs = Array.prototype.slice.call(document.querySelectorAll('.tab'));
  var el = {
    kicker:document.getElementById('pKicker'), title:document.getElementById('pTitle'),
    bodyt:document.getElementById('pBody'), char:document.getElementById('mChar'),
    color:document.getElementById('mColor'), dist:document.getElementById('mDist'),
    image:document.getElementById('mImage'), stageName:document.getElementById('stageName'),
    listener:document.getElementById('listener'), you:document.getElementById('youTxt'),
    dsignal:document.getElementById('dsignal')
  };

  function apply(key){
    var d = P[key]; if(!d) return;
    current = key;
    document.documentElement.style.setProperty('--amb1', d.amb1);
    document.documentElement.style.setProperty('--amb2', d.amb2);
    document.documentElement.style.setProperty('--amb-glow', hexA(d.amb1,.18));
    document.documentElement.style.setProperty('--field', d.field);

    el.kicker.textContent = "Perspective "+d.idx;
    el.title.textContent = d.name;
    el.bodyt.textContent = d.body;
    el.char.textContent = d.char;
    el.color.textContent = d.color;
    el.dist.textContent = d.dist;
    el.image.textContent = d.image;
    el.stageName.textContent = d.label;
    el.you.textContent = d.you;
    el.dsignal.setAttribute('d', d.signal);

    // move listener marker
    el.listener.setAttribute('transform','translate('+(d.listenX-240)+','+(d.listenY-250)+')');

    tabs.forEach(function(t){
      var on = t.getAttribute('data-p')===key;
      t.setAttribute('aria-selected', on?'true':'false');
    });
  }

  // convert hex + alpha -> rgba
  function hexA(hex,a){
    var h=hex.replace('#',''); if(h.length===3){h=h[0]+h[0]+h[1]+h[1]+h[2]+h[2];}
    var r=parseInt(h.substr(0,2),16),g=parseInt(h.substr(2,2),16),b=parseInt(h.substr(4,2),16);
    return 'rgba('+r+','+g+','+b+','+a+')';
  }

  tabs.forEach(function(t){
    t.addEventListener('click', function(){ apply(t.getAttribute('data-p')); });
    t.addEventListener('keydown', function(e){
      if(e.key==='ArrowRight'||e.key==='ArrowLeft'){
        e.preventDefault();
        var i=order.indexOf(current);
        i = e.key==='ArrowRight' ? (i+1)%order.length : (i-1+order.length)%order.length;
        apply(order[i]); tabs[i].focus();
      }
    });
  });

  /* ---------- demo signal ---------- */
  var demoBtn=document.getElementById('demoBtn');
  var demoState=document.getElementById('demoState');
  var noteTxt=document.getElementById('noteTxt');
  function setDemo(on){
    body.classList.toggle('demo-on', on);
    demoBtn.setAttribute('aria-pressed', on?'true':'false');
    demoState.textContent = on ? 'signal active (visual only)' : 'signal idle';
    noteTxt.textContent = on
      ? 'Demo Signal on — animating the MODELED signal path. No audio is produced; this is a silent illustration.'
      : 'Visual simulation — this installation makes no sound. Toggle “Demo Signal” to animate the modeled signal path.';
  }
  demoBtn.addEventListener('click', function(){ setDemo(!body.classList.contains('demo-on')); });

  /* ---------- quiet mode ---------- */
  var quietBtn=document.getElementById('quietBtn');
  function setQuiet(on){
    body.classList.toggle('quiet', on);
    quietBtn.setAttribute('aria-pressed', on?'true':'false');
    quietBtn.textContent = on ? 'Quiet Mode · On' : 'Quiet Mode';
  }
  quietBtn.addEventListener('click', function(){ setQuiet(!body.classList.contains('quiet')); });

  /* ---------- explode ---------- */
  var explodeBtn=document.getElementById('explodeBtn');
  var explodeStage=document.getElementById('explodeStage');
  explodeBtn.addEventListener('click', function(){
    var on = explodeStage.classList.toggle('exploded');
    explodeBtn.setAttribute('aria-pressed', on?'true':'false');
    explodeBtn.textContent = on ? '⤡ Reassemble the Column' : '⤢ Explode the Column';
  });

  /* ---------- keyboard shortcuts ---------- */
  document.addEventListener('keydown', function(e){
    if(/^(INPUT|TEXTAREA|SUMMARY)$/.test((e.target.tagName||''))) return;
    var k=e.key.toLowerCase();
    if(k==='1'){apply('stage');}
    else if(k==='2'){apply('rail');}
    else if(k==='3'){apply('board');}
    else if(k==='4'){apply('hill');}
    else if(k==='d'){setDemo(!body.classList.contains('demo-on'));}
    else if(k==='q'){setQuiet(!body.classList.contains('quiet'));}
    else if(k==='e'){explodeBtn.click();}
    else if(e.key==='ArrowRight'||e.key==='ArrowLeft'){
      if(document.activeElement && document.activeElement.classList.contains('tab')) return;
      var i=order.indexOf(current);
      i = e.key==='ArrowRight' ? (i+1)%order.length : (i-1+order.length)%order.length;
      apply(order[i]);
    }
  });

  /* ---------- build the array cells (hero) ---------- */
  (function buildArray(){
    var g=document.getElementById('array');
    var cols=[[300,360],[360,460],[460,560],[560,620]];
    var svgns="http://www.w3.org/2000/svg";
    for(var c=0;c<4;c++){
      var x0=cols[c][0], x1=cols[c][1], w=x1-x0-8;
      var rows = 10;
      for(var r=0;r<rows;r++){
        var y=78 + r*(384/rows);
        var cell=document.createElementNS(svgns,'rect');
        cell.setAttribute('class','speaker-cell');
        cell.setAttribute('x', x0+4); cell.setAttribute('y', y);
        cell.setAttribute('width', w); cell.setAttribute('height', (384/rows)-6);
        cell.setAttribute('rx','2');
        var op = 0.10 + Math.random()*0.28;
        cell.setAttribute('fill','var(--field)');
        cell.setAttribute('fill-opacity', op.toFixed(2));
        cell.setAttribute('stroke','var(--bronze)');
        cell.setAttribute('stroke-opacity','.35');
        // speaker cone hint
        g.appendChild(cell);
        var cone=document.createElementNS(svgns,'circle');
        cone.setAttribute('cx', x0+4+w/2); cone.setAttribute('cy', y+(384/rows-6)/2);
        cone.setAttribute('r', Math.min(w,384/rows-6)/2 - 3);
        cone.setAttribute('fill','none'); cone.setAttribute('stroke','var(--field)');
        cone.setAttribute('stroke-opacity','.25');
        g.appendChild(cone);
      }
    }
  })();

  /* ---------- scroll entrances ---------- */
  var io = ('IntersectionObserver' in window) ? new IntersectionObserver(function(entries){
    entries.forEach(function(en){ if(en.isIntersecting){ en.target.classList.add('in'); io.unobserve(en.target); } });
  }, {threshold:0.12, rootMargin:'0px 0px -8% 0px'}) : null;
  var fades=document.querySelectorAll('.fade');
  if(io){ fades.forEach(function(f){io.observe(f);}); }
  else { fades.forEach(function(f){f.classList.add('in');}); }

  /* stagger siblings a touch */
  document.querySelectorAll('.grid, .timeline, .persp-tabs').forEach(function(parent){
    Array.prototype.slice.call(parent.children).forEach(function(ch,i){
      ch.style.animationDelay = (i*0.09)+'s';
    });
  });

  /* init */
  apply('rail');
})();
</script>
</body>
</html>