according to some schematics improve the following somehow functional code:


```


# Schematics for Auto-Fitting and Scaling a 6x10 Grid with Responsive Content

**Goal:**  
Create a grid container and individual grid cells arranged in exactly 6 rows by 10 columns which automatically scale up or down to fill available viewport space. The contents inside each cell (Chinese characters and transliterations) should also scale proportionally to remain clear and aesthetically pleasing.

---

## Core Principles

1. **Fixed Grid Dimensions:**  
   - The grid must have exactly 6 rows and 10 columns — these counts never change.  
   - No dynamic wrapping or additional rows/columns.

2. **Maintain Aspect Ratio Between Width and Height:**  
   - Since the cell count is fixed, the grid’s aspect ratio is fixed by:  
     **aspect_ratio = columns / rows = 10 / 6 ≈ 1.6667**  
   - The container’s width and height must scale to maintain this ratio so the cells remain proportional (ideally squares or consistent rectangles).

3. **Responsive Sizing:**  
   - The grid’s *maximum* width stretches to the viewport’s width (or defined max-width).  
   - The grid’s height scales according to the aspect ratio based on the width.  
   - If viewport’s vertical space is limiting (very short screens), scale grid width down proportionally to maintain aspect ratio and fit height.

4. **Cell Sizing:**  
   - Cells should automatically fill their grid area (one fraction per column/row).  
   - Cell widths and heights should be equal or proportional (to give a uniform “tile” look).  
   - Use CSS property `aspect-ratio` on cells for modern browsers to enforce square or fluid rectangles maintaining proportions.

5. **Content Scaling Within Cells:**  
   - Font sizes for characters and transliterations should use CSS `clamp()` or relative units (`vw`, `vh`, `%`) to adapt fluidly with cell size.  
   - Maintain line-heights and spacing consistent with font scaling for readability.

6. **Grid Gap & Padding:**  
   - Include consistent grid gaps (gutters) between cells that scale modestly with overall grid size. Too large gaps on small screens waste space; too small gaps on large screens feel cramped.  
   - Consider fixed or relative spacing (e.g., `0.5%` of container size or fixed pixel size capped by viewport).

7. **Scrollbar Considerations:**  
   - If other UI elements (such as score logs) introduce scrollbars, ensure that the grid container’s width or height calculation accommodates scrollbar size to avoid content shifting or overflow.  
   - Use CSS techniques like `scrollbar-gutter` where supported or reserve space via padding/margin.

8. **Centering & Layout:**  
   - Horizontally center the grid container inside the viewport or parent container.  
   - Vertically align or space grid and other UI parts for best UX.

---

## Suggested CSS Structure omitted to according implementation.


```



somehowcode:


```



<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Chinese Sexagenary Cycle – Clean Responsive + Original Tones</title>
<style>
  /* Reset and base */
  * {
    box-sizing: border-box;
  }
  html, body {
    margin: 0; padding: 0.25rem;
    height: 100%;
    background: #121212;
    color: #ddd;
    font-family: monospace, monospace;
    user-select: none;
  }
  body {
    display: flex;
    flex-direction: column;
    height: 100vh;
  }

  /* Container for all */
  #app-container {
    display: flex;
    flex-direction: column;
    width: 100vw;
    max-width: 100vw;
    height: 100%;
  }

  /* Row 1: Controls bars (buttons and speed) */
  #controls-top {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0 0.3rem;
    width: 100%;
  }
  /* Buttons and range aligned horizontally with minimal space */
  #controls-top > * {
    flex: none;
  }
  button {
    font-weight: 700;
    height: 36px;
    min-width: 65px;
    padding: 0 0.9rem;
    border-radius: 6px;
    border: 1.5px solid #00b4c0;
    background: #007a85;
    color: #d9dadc;
    cursor: pointer;
    transition: background-color 0.15s ease, border-color 0.15s ease;
    user-select: none;
  }
  button:disabled {
    background: #003b42;
    border-color: #002627;
    color: #666;
    cursor: default;
  }
  button:hover:not(:disabled) {
    background: #00d2e9;
    border-color: #00555e;
    color: #004143;
  }

  #speed-range {
    width: 140px;
    cursor: pointer;
    -webkit-appearance: none;
    background: transparent;
    flex: none;
  }
  #speed-range:focus {
    outline: none;
  }
  #speed-range::-webkit-slider-runnable-track {
    height: 6px;
    background: #009ba1;
    border-radius: 3px;
  }
  #speed-range::-webkit-slider-thumb {
    -webkit-appearance: none;
    width: 16px;
    height: 16px;
    background: #00e5ff;
    border-radius: 50%;
    margin-top: -5px;
    cursor: pointer;
    border: none;
  }
  #speed-range:focus::-webkit-slider-thumb {
    box-shadow: 0 0 5px #00e5ff;
  }
  #speed-range::-moz-range-track {
    height: 6px;
    background: #009ba1;
    border-radius: 3px;
  }
  #speed-range::-moz-range-thumb {
    width: 16px;
    height: 16px;
    background: #00e5ff;
    border-radius: 50%;
    border: none;
    cursor: pointer;
  }
  #speed-range:focus::-moz-range-thumb {
    box-shadow: 0 0 5px #00e5ff;
  }

  /* Row 2: Score log full width with reserved scrollbar space and overlay scrollbar */
  #seq-log {
    flex: 0 0 50px; /* fixed height to reserve scrollbar space */
    font-family: monospace;
    padding: 4px 8px;
    background: #222;
    color: #0df9ff;
    border: 1px solid #00b0c0;
    user-select: text;
    white-space: nowrap;
    overflow-x: auto;
    overflow-y: hidden;
    max-width: 100vw;
    box-sizing: border-box;
    margin: 0 0.3rem;
    line-height: 1.3;

    /* Prevent vertical layout shift with scrollbar-gutter */
    scrollbar-gutter: stable;
    scrollbar-width: thin;
    scrollbar-color: #00e5ff #222;
  }
  /* For Webkit based browsers, make scrollbar overlay and styled */
  #seq-log::-webkit-scrollbar {
    height: 12px;
    background: transparent;
  }
  #seq-log::-webkit-scrollbar-thumb {
    background-color: #00e5ffaa;
    border-radius: 8px;
    border: 2px solid transparent;
    background-clip: content-box;
  }
  #seq-log::-webkit-scrollbar-track {
    background: transparent;
  }

  /* Row 3: grid container that fills remaining vertical space */
  #sexagenary-cycle-grid {
    flex: 1 1 auto;
    display: grid;
    grid-template-columns: repeat(10, 1fr);
    grid-template-rows: repeat(6, 1fr);
    gap: 4px;
    padding: 0.3rem;
    margin: 0 0.3rem 0.3rem;
    max-width: 100vw;
    max-height: 100%;
    height: 100%;

    /* Align left edge with the score log's padding */
    padding-left: 8px;
    padding-right: 8px;
  }

  .cycle-cell {
    background: #006d75;
    border-radius: 5px;
    color: #d9dadc;
    font-weight: 600;
    font-size: clamp(0.75rem, 1.0vw, 1.1rem);
    line-height: 1.2;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    user-select: none;
    cursor: pointer;
    padding: 3px 0;
    aspect-ratio: 1 / 1;
    transition: background-color 0.2s ease, color 0.2s ease;
    outline-offset: 2px;
  }
  .cycle-cell:hover:not(.pressed), .cycle-cell:focus-visible {
    background-color: #009ba1;
    color: #ddf;
    outline: 2px solid #00e5ff;
    outline-offset: 2px;
  }
  .cycle-cell.pressed {
    background-color: #004d53;
    color: #7fffd4;
  }

  .cell-stem {
    font-size: clamp(1.1rem, 1.7vw, 1.35rem);
    opacity: 0.9;
    line-height: 1;
  }
  .cell-branch {
    font-size: clamp(1.6rem, 2.5vw, 1.9rem);
    font-weight: 900;
    margin-top: 2px;
    line-height: 1;
  }
  .cell-translit {
    font-size: clamp(0.6rem, 1.0vw, 0.75rem);
    margin-top: 2px;
    color: #a7a9ac;
    white-space: nowrap;
  }
</style>
</head>
<body>

<div id="app-container" role="main">

  <div id="controls-top" role="region" aria-label="Playback and recording controls">
    <button id="btn-rec" aria-pressed="false" aria-label="Start recording sequence">REC</button>
    <button id="btn-stop" aria-label="Stop recording or playback" disabled>STOP</button>
    <button id="btn-play" aria-label="Play recorded sequence" disabled>PLAY</button>
    <button id="btn-clear" aria-label="Clear recorded sequence" disabled>CLEAR</button>
    <input type="range" id="speed-range" min="0.1" max="4" step="0.05" value="1" aria-label="Playback speed control" title="Playback speed control" />
  </div>

  <div id="seq-log" aria-live="polite" aria-atomic="true" aria-relevant="additions" title="Recorded sequence (index@time ms)">
    (no sequence yet)
  </div>

  <div id="sexagenary-cycle-grid" tabindex="0" aria-label="Chinese Sexagenary Cycle grid with 60 items"></div>

</div>

<script>
  "use strict";

  // Data
  const stems = [
    {char:'甲',pinyin:'Jiǎ',tone:3},
    {char:'乙',pinyin:'Yǐ',tone:3},
    {char:'丙',pinyin:'Bǐng',tone:3},
    {char:'丁',pinyin:'Dīng',tone:1},
    {char:'戊',pinyin:'Wù',tone:4},
    {char:'己',pinyin:'Jǐ',tone:3},
    {char:'庚',pinyin:'Gēng',tone:1},
    {char:'辛',pinyin:'Xīn',tone:1},
    {char:'壬',pinyin:'Rén',tone:2},
    {char:'癸',pinyin:'Guǐ',tone:3}
  ];
  const branches = [
    {char:'子',pinyin:'Zǐ',tone:3,zodiac:'Rat'},
    {char:'丑',pinyin:'Chǒu',tone:3,zodiac:'Ox'},
    {char:'寅',pinyin:'Yín',tone:2,zodiac:'Tiger'},
    {char:'卯',pinyin:'Mǎo',tone:3,zodiac:'Rabbit'},
    {char:'辰',pinyin:'Chén',tone:2,zodiac:'Dragon'},
    {char:'巳',pinyin:'Sì',tone:4,zodiac:'Snake'},
    {char:'午',pinyin:'Wǔ',tone:3,zodiac:'Horse'},
    {char:'未',pinyin:'Wèi',tone:4,zodiac:'Goat'},
    {char:'申',pinyin:'Shēn',tone:1,zodiac:'Monkey'},
    {char:'酉',pinyin:'Yǒu',tone:3,zodiac:'Rooster'},
    {char:'戌',pinyin:'Xū',tone:1,zodiac:'Dog'},
    {char:'亥',pinyin:'Hài',tone:4,zodiac:'Pig'}
  ];

  // Tone contours to multiply base frequencies for glides (4-step pitch shapes)
  const stemToneContours = {
    1: [1.35, 1.35, 1.35, 1.35],        // High level tone
    2: [1.00, 1.10, 1.25, 1.30],        // Rising tone
    3: [1.30, 1.10, 1.25, 1.10],        // Dipping tone
    4: [1.30, 1.25, 1.15, 1.00]         // Falling tone
  };

  const branchToneContours = {
    1: [1.4, 1.4, 1.4, 1.4],           // High level tone - slightly brighter
    2: [1.0, 1.1, 1.3, 1.4],           // Rising tone, longer sweep
    3: [1.4, 1.15, 1.3, 1.15],         // Dipping tone with subtle vibrato
    4: [1.4, 1.3, 1.2, 1.0]            // Falling tone, strong drop
  };

  // Audio parameters
  const baseFreq = 110.0; // base frequency, A2-ish for warm sounds

  const vibratoFreq = 7.8; // Hz
  const vibratoDepthRaw = 0.0042; // Slightly increased depth for audibility

  // Elements references
  const grid = document.getElementById('sexagenary-cycle-grid');
  const seqLog = document.getElementById('seq-log');
  const btnRec = document.getElementById('btn-rec');
  const btnStop = document.getElementById('btn-stop');
  const btnPlay = document.getElementById('btn-play');
  const btnClear = document.getElementById('btn-clear');
  const speedRange = document.getElementById('speed-range');

  // Audio state
  let audioCtx = null;
  let masterGainNode = null;
  let compressorNode = null;

  // Map of index -> note objects
  let activeNotes = new Map();

  // Current recorded sequence
  let recordSequence = [];
  let isRecording = false;
  let isPlaying = false;
  let playbackSpeed = 1.0;
  // Scheduled event timers for playback
  let scheduledEvents = [];

  // --- Gain Stabilization Globals ---
  // Precomputed max polyphony for the recorded sequence (or dynamic)
  let maxPolyphony = 1;

  // Create or resume AudioContext and audio graph with gain stabilization
  async function ensureAudioCtx() {
    if (!audioCtx) {
      audioCtx = new (window.AudioContext || window.webkitAudioContext)();

      // Master Gain Node: user volume control
      masterGainNode = audioCtx.createGain();
      masterGainNode.gain.value = 0.24; // default master volume

      // Compressor node for mild leveling
      compressorNode = audioCtx.createDynamicsCompressor();
      compressorNode.threshold.setValueAtTime(-20, audioCtx.currentTime);
      compressorNode.knee.setValueAtTime(15, audioCtx.currentTime);
      compressorNode.ratio.setValueAtTime(3, audioCtx.currentTime);
      compressorNode.attack.setValueAtTime(0.02, audioCtx.currentTime);
      compressorNode.release.setValueAtTime(0.1, audioCtx.currentTime);

      // Connect audio graph: masterGain -> compressor -> destination
      masterGainNode.connect(compressorNode);
      compressorNode.connect(audioCtx.destination);
    }
    if (audioCtx.state === 'suspended') await audioCtx.resume();
  }

  // Set master volume from UI or programmatically (0 to 1)
  function setMasterVolume(value) {
    if (masterGainNode) {
      masterGainNode.gain.setTargetAtTime(value, audioCtx.currentTime, 0.01);
    }
  }

  // -------- Gain Normalization per polyphonic concurrency --------
  // Calculate max concurrent notes for the recorded sequence offline
  function calculateMaxPolyphony(sequence) {
    if (sequence.length === 0) return 1;

    // Create an array of {time, type: 'start'|'stop', index} events
    let events = [];

    for (let i = 0; i < sequence.length; i++) {
      const event = sequence[i];
      const startTime = event.time;
      // Determine stop time as next event time or start + 1000ms default
      const nextTime = (i < sequence.length -1) ? sequence[i + 1].time : (event.time + 1000);
      // Start event
      events.push({time: startTime, type: 'start'});
      // Stop event a bit before next start for natural envelope (use 90% duration)
      const stopTime = startTime + (nextTime - startTime) * 0.9;
      events.push({time: stopTime, type: 'stop'});
    }

    // Sort events by time, with stops before starts if tie (to reduce concurrency instantly)
    events.sort((a,b) => {
      const dt = a.time - b.time;
      if (dt !== 0) return dt;
      if (a.type === 'stop' && b.type === 'start') return -1;
      if (a.type === 'start' && b.type === 'stop') return 1;
      return 0;
    });

    let concurrency = 0;
    let maxConcurrency = 0;
    for (const e of events) {
      if (e.type === 'start') concurrency++;
      else if (e.type === 'stop') concurrency = Math.max(0, concurrency - 1);
      if (concurrency > maxConcurrency) maxConcurrency = concurrency;
    }
    return Math.max(1, maxConcurrency);
  }

  // For dynamic concurrency during playback, create a continuously updated gain factor per note
  // (Optional enhancement: For now apply global per-voice gain scale)

  // --- Note creation and management ---

  // Schedule frequency glide on AudioParam over duration (seconds)
  function scheduleFreqGlide(freqBase, contour, freqParam, durSec, startTime = audioCtx.currentTime) {
    freqParam.cancelScheduledValues(startTime);
    freqParam.setValueAtTime(freqBase * contour[0], startTime);
    const segment = durSec / (contour.length - 1);
    for (let i = 1; i < contour.length; i++) {
      const targetTime = startTime + i * segment;
      freqParam.linearRampToValueAtTime(freqBase * contour[i], targetTime);
    }
  }

  // Start a note (voice) at index, applying gain scaling based on maxPolyphony
  async function startNote(index) {
    await ensureAudioCtx();
    if (activeNotes.has(index)) return;

    const stemIndex = index % stems.length;
    const branchIndex = index % branches.length;
    const stem = stems[stemIndex];
    const branch = branches[branchIndex];

    // Gain scaling factor per voice (non-linear curve: sqrt inverse concurrency for smoother loudness)
    const gainScalePerVoice = 1 / Math.sqrt(maxPolyphony);

    // Create stem oscillators and envelope
    const oscStemPrimary = audioCtx.createOscillator();
    oscStemPrimary.type = 'triangle';
    const oscStemSecondary = audioCtx.createOscillator();
    oscStemSecondary.type = 'sawtooth';
    oscStemPrimary.detune.value = -4;
    oscStemSecondary.detune.value = 4;

    const gainStem = audioCtx.createGain();
    gainStem.gain.setValueAtTime(0, audioCtx.currentTime);

    // Create branch oscillators and envelope
    const oscBranchPrimary = audioCtx.createOscillator();
    oscBranchPrimary.type = 'triangle';
    const oscBranchSecondary = audioCtx.createOscillator();
    oscBranchSecondary.type = 'sawtooth';
    oscBranchPrimary.detune.value = 5;
    oscBranchSecondary.detune.value = -5;

    const gainBranch = audioCtx.createGain();
    gainBranch.gain.setValueAtTime(0, audioCtx.currentTime);

    // Vibrato LFO
    const vibratoLFO = audioCtx.createOscillator();
    vibratoLFO.type = 'sine';
    vibratoLFO.frequency.setValueAtTime(vibratoFreq, audioCtx.currentTime);
    const vibratoGain = audioCtx.createGain();
    vibratoGain.gain.setValueAtTime(vibratoDepthRaw * baseFreq * 3.5, audioCtx.currentTime);

    vibratoLFO.connect(vibratoGain);
    vibratoGain.connect(oscBranchPrimary.frequency);
    vibratoGain.connect(oscBranchSecondary.frequency);

    // Formant filters
    const formantStem = audioCtx.createBiquadFilter();
    formantStem.type = 'bandpass';
    formantStem.frequency.value = 800 + (stemIndex * 40);
    formantStem.Q.value = 8;

    const formantBranch = audioCtx.createBiquadFilter();
    formantBranch.type = 'bandpass';
    formantBranch.frequency.value = 1200 + (branchIndex * 55);
    formantBranch.Q.value = 7;

    // Stereo panning
    const pannerStem = audioCtx.createStereoPanner();
    pannerStem.pan.value = -0.35;
    const pannerBranch = audioCtx.createStereoPanner();
    pannerBranch.pan.value = 0.35;

    // Connect stem oscillator chain
    oscStemPrimary.connect(formantStem);
    oscStemSecondary.connect(formantStem);
    formantStem.connect(gainStem);
    gainStem.connect(pannerStem);
    pannerStem.connect(masterGainNode);

    // Connect branch oscillator chain
    oscBranchPrimary.connect(formantBranch);
    oscBranchSecondary.connect(formantBranch);
    formantBranch.connect(gainBranch);
    gainBranch.connect(pannerBranch);
    pannerBranch.connect(masterGainNode);

    const now = audioCtx.currentTime;

    // Schedule pitch glides (9s sustain)
    scheduleFreqGlide(baseFreq * 2, stemToneContours[stem.tone], oscStemPrimary.frequency, 9, now);
    scheduleFreqGlide(baseFreq * 2, stemToneContours[stem.tone], oscStemSecondary.frequency, 9, now);
    scheduleFreqGlide(baseFreq * 3, branchToneContours[branch.tone], oscBranchPrimary.frequency, 9, now);
    scheduleFreqGlide(baseFreq * 3, branchToneContours[branch.tone], oscBranchSecondary.frequency, 9, now);

    // Smooth ADSR amplitude envelope with gain normalization
    const attackTime = 0.03;
    const decayTime = 0.07;
    const sustainGain = 0.13 * gainScalePerVoice; // scaled sustain level
    const peakGainStem = 0.22 * gainScalePerVoice;
    const peakGainBranch = 0.20 * gainScalePerVoice;

    gainStem.gain.cancelScheduledValues(now);
    gainBranch.gain.cancelScheduledValues(now);
    gainStem.gain.setValueAtTime(0, now);
    gainBranch.gain.setValueAtTime(0, now);

    gainStem.gain.linearRampToValueAtTime(peakGainStem, now + attackTime);
    gainBranch.gain.linearRampToValueAtTime(peakGainBranch, now + attackTime);
    gainStem.gain.linearRampToValueAtTime(sustainGain, now + attackTime + decayTime);
    gainBranch.gain.linearRampToValueAtTime(sustainGain * 0.92, now + attackTime + decayTime);

    // Start oscillators
    vibratoLFO.start(now);
    oscStemPrimary.start(now);
    oscStemSecondary.start(now);
    oscBranchPrimary.start(now);
    oscBranchSecondary.start(now);

    // Store note references for stop
    activeNotes.set(index, {
      oscStemPrimary,
      oscStemSecondary,
      gainStem,
      pannerStem,
      formantStem,

      oscBranchPrimary,
      oscBranchSecondary,
      gainBranch,
      pannerBranch,
      formantBranch,

      vibratoLFO,
      vibratoGain,

      gainScalePerVoice, // stored for dynamic gain update (extension)
    });

    // Visual pressed cue
    const cell = grid.querySelector(`.cycle-cell[data-index="${index}"]`);
    if (cell) cell.classList.add('pressed');
  }

  // Stop a note smoothly with release envelope and cleanup
  function stopNote(index) {
    if (!activeNotes.has(index)) return;
    const note = activeNotes.get(index);
    const now = audioCtx.currentTime;

    note.gainStem.gain.cancelScheduledValues(now);
    note.gainBranch.gain.cancelScheduledValues(now);

    note.gainStem.gain.setTargetAtTime(0, now, 0.08);
    note.gainBranch.gain.setTargetAtTime(0, now, 0.08);

    const stopTime = now + 0.25;
    [note.oscStemPrimary, note.oscStemSecondary,
     note.oscBranchPrimary, note.oscBranchSecondary,
     note.vibratoLFO].forEach(n => {
      try { n.stop(stopTime); } catch {}
    });

    setTimeout(() => {
      try {
        note.oscStemPrimary.disconnect();
        note.oscStemSecondary.disconnect();
        note.oscBranchPrimary.disconnect();
        note.oscBranchSecondary.disconnect();
        note.vibratoLFO.disconnect();
        note.vibratoGain.disconnect();
        note.gainStem.disconnect();
        note.gainBranch.disconnect();
        note.pannerStem.disconnect();
        note.pannerBranch.disconnect();
        note.formantStem.disconnect();
        note.formantBranch.disconnect();
      } catch (e) {}
    }, 300);

    activeNotes.delete(index);

    // Visual cue reset
    const cell = grid.querySelector(`.cycle-cell[data-index="${index}"]`);
    if (cell) cell.classList.remove('pressed');
  }

  // Update recorded sequence log and buttons states
  function updateSequenceLog() {
    if (recordSequence.length === 0) {
      seqLog.textContent = '(no sequence yet)';
      btnPlay.disabled = true;
      btnClear.disabled = true;
      btnStop.disabled = !isRecording && !isPlaying;
      btnRec.setAttribute('aria-pressed', 'false');
      return;
    }
    // Format: hex index padded + time ms padded
    const seqStr = recordSequence.map(e =>
      e.index.toString(16).padStart(2,'0') + '@' + e.time.toFixed(0).padStart(4,' ')
    ).join(' ');
    seqLog.textContent = seqStr;
    btnPlay.disabled = false;
    btnClear.disabled = false;
    btnStop.disabled = false;
  }

  // User presses a cell: start note and optionally record
  function onPress(index) {
    if (isPlaying) return;

    if (!isRecording) {
      startNote(index);
      return;
    }

    const now = performance.now();
    if (recordSequence.length === 0) {
      recordSequence.push({index, time: 0});
      recordSequence.refTime = now;
    } else {
      recordSequence.push({index, time: now - recordSequence.refTime});
    }
    updateSequenceLog();
    startNote(index);
  }

  // User releases a cell: stop note
  function onRelease(index) {
    stopNote(index);
  }

  // Build the 60-cell sexagenary grid
  function buildGrid() {
    grid.innerHTML = '';
    for (let i = 0; i < 60; i++) {
      const stemIndex = i % stems.length;
      const branchIndex = i % branches.length;
      const stem = stems[stemIndex];
      const branch = branches[branchIndex];

      const cell = document.createElement('div');
      cell.className = 'cycle-cell';
      cell.tabIndex = 0;
      cell.dataset.index = i;
      cell.setAttribute('role', 'button');
      cell.setAttribute('aria-label', `${stem.char} (${stem.pinyin}), ${branch.char} (${branch.pinyin}), Zodiac ${branch.zodiac}`);

      cell.innerHTML = `
        <div class="cell-stem">${stem.char}</div>
        <div class="cell-branch">${branch.char}</div>
        <div class="cell-translit">${stem.pinyin} ${branch.pinyin}</div>
      `;

      cell.addEventListener('pointerdown', e => { e.preventDefault(); onPress(i); });
      cell.addEventListener('pointerup', e => { e.preventDefault(); onRelease(i); });
      cell.addEventListener('pointercancel', () => onRelease(i));
      cell.addEventListener('pointerleave', e => { if (e.pressure > 0) onRelease(i); });

      cell.addEventListener('keydown', e => {
        if (isPlaying) return;
        if (e.repeat) return;
        if (e.key === 'Enter' || e.key === ' ') {
          e.preventDefault();
          onPress(i);
        }
      });
      cell.addEventListener('keyup', e => {
        if (e.key === 'Enter' || e.key === ' ') {
          e.preventDefault();
          onRelease(i);
        }
      });

      grid.appendChild(cell);
    }
  }

  // Stop all notes currently playing immediately
  function stopAllNotes() {
    activeNotes.forEach((_, i) => stopNote(i));
  }

  // Clears all scheduled timeouts/events
  function clearScheduledEvents() {
    while (scheduledEvents.length) {
      clearTimeout(scheduledEvents.pop());
    }
  }

  // Enhanced playback sequence with adaptive gain normalization (using maxPolyphony)
  async function playSequence(speed = 1.0) {
    if (recordSequence.length === 0) return;
    if (isRecording) return;
    if (isPlaying) return;

    await ensureAudioCtx();

    // Calculate max polyphony once before playback
    maxPolyphony = calculateMaxPolyphony(recordSequence);

    isPlaying = true;
    btnPlay.disabled = true;
    btnRec.disabled = true;
    btnClear.disabled = true;
    btnStop.disabled = false;
    btnRec.setAttribute('aria-pressed', 'false');

    playbackSpeed = speed;

    clearScheduledEvents();
    stopAllNotes();

    // Duration of sequence loop (ms)
    const lastEventTime = recordSequence[recordSequence.length - 1].time;
    const loopDurationMs = (lastEventTime + 1000) / playbackSpeed;

    function scheduleLoop() {
      if (!isPlaying) return;

      let lastStopTime = 0;

      for (let i=0; i < recordSequence.length; i++) {
        const event = recordSequence[i];
        const nextEvent = recordSequence[(i + 1) % recordSequence.length];

        // Start time offset (ms) adjusted for speed
        const startDelay = event.time / playbackSpeed;

        // Duration until next event or 1s default
        const rawDuration = (i === recordSequence.length - 1) ?
          1000 / playbackSpeed :
          (nextEvent.time - event.time) / playbackSpeed;

        // Stop delay just before next start to let envelope release (~90%)
        const stopDelay = Math.max(70, rawDuration * 0.9);

        lastStopTime = Math.max(lastStopTime, startDelay + stopDelay);

        scheduledEvents.push(setTimeout(() => {
          // Start note with current maxPolyphony set for gain scaling
          startNote(event.index);
        }, startDelay));

        scheduledEvents.push(setTimeout(() => {
          stopNote(event.index);
        }, startDelay + stopDelay));
      }

      // Schedule next loop just before current one ends to avoid gap
      scheduledEvents.push(setTimeout(() => {
        if (isPlaying) {
          scheduledEvents.length = 0;
          scheduleLoop();
        }
      }, loopDurationMs));
    }

    scheduleLoop();
  }

  // Stop playback and recording gracefully
  function stopPlayback() {
    if (!isPlaying && !isRecording) return;
    isPlaying = false;
    isRecording = false;

    btnRec.disabled = false;
    btnPlay.disabled = recordSequence.length === 0;
    btnClear.disabled = recordSequence.length === 0;
    btnStop.disabled = true;
    btnRec.setAttribute('aria-pressed', 'false');

    clearScheduledEvents();
    stopAllNotes();
  }

  // Start recording session
  function startRecording() {
    stopPlayback();

    isRecording = true;
    recordSequence.length = 0;
    recordSequence.refTime = null;

    updateSequenceLog();

    btnRec.disabled = true;
    btnStop.disabled = false;
    btnPlay.disabled = true;
    btnClear.disabled = true;
    btnRec.setAttribute('aria-pressed', 'true');
  }

  // Clear recorded sequences and reset UI
  function clearSequence() {
    stopPlayback();
    recordSequence.length = 0;
    recordSequence.refTime = null;
    updateSequenceLog();
  }

  // Bind controls events
  btnRec.addEventListener('click', () => {
    if (!isRecording) startRecording();
  });
  btnStop.addEventListener('click', () => stopPlayback());
  btnPlay.addEventListener('click', () => {
    if (!isPlaying) playSequence(parseFloat(speedRange.value));
  });
  btnClear.addEventListener('click', () => clearSequence());
  speedRange.addEventListener('input', () => {
    playbackSpeed = parseFloat(speedRange.value);
    if (isPlaying) {
      stopPlayback();
      playSequence(playbackSpeed);
    }
  });

  // Keyboard shortcuts for controls when not typing
  window.addEventListener('keydown', e => {
    const a = document.activeElement;
    if (a && (a.tagName==='INPUT' || a.tagName==='TEXTAREA' || a.isContentEditable)) return;
    if (e.altKey || e.ctrlKey || e.metaKey) return;

    const k = e.key.toLowerCase();
    switch(k){
      case 'r': e.preventDefault(); btnRec.click(); break;
      case 'p': e.preventDefault(); btnPlay.click(); break;
      case 's': e.preventDefault(); btnStop.click(); break;
      case 'c': e.preventDefault(); btnClear.click(); break;
    }
  });

  // Responsive adjustment: dynamically fit grid height inside viewport minus controls + seq-log
  function resizeGridHeight() {
    const controlsHeight =
      document.getElementById('controls-top').offsetHeight +
      document.getElementById('seq-log').offsetHeight +
      24; // Extra margin

    // Available height for grid: viewport height minus controls heights
    const availHeight = window.innerHeight - controlsHeight;

    // Grid width and cells size
    const gridWidth = grid.clientWidth;
    const cellWidth = gridWidth / 10;
    let desiredHeight = cellWidth * 6; // 6 rows, square cells

    // Clamp within available height
    desiredHeight = Math.min(desiredHeight, availHeight);

    const scaledCellWidth = desiredHeight / 6;

    // Apply height and set CSS variable for font scale
    grid.style.height = desiredHeight + "px";

    const baseFontSizeBranchPx = 48; // approx base pixel size to normalize to
    const fontScale = scaledCellWidth / baseFontSizeBranchPx;
    grid.style.setProperty('--font-scale', fontScale.toFixed(3));
  }

  // Dynamic CSS for font scaling based on --font-scale property
  const dynamicStyle = document.createElement('style');
  dynamicStyle.textContent = `
    #sexagenary-cycle-grid .cell-stem {
      font-size: calc(clamp(1.1rem, 1.7vw, 1.35rem) * var(--font-scale,1));
    }
    #sexagenary-cycle-grid .cell-branch {
      font-size: calc(clamp(1.6rem, 2.5vw, 1.9rem) * var(--font-scale,1));
    }
    #sexagenary-cycle-grid .cell-translit {
      font-size: calc(clamp(0.6rem, 1.0vw, 0.75rem) * var(--font-scale,1));
    }
  `;
  document.head.appendChild(dynamicStyle);

  // Minimal user volume control UI - add a slider below controls (optional)
  // For demonstration, create dynamically
  function createVolumeControl() {
    const controlsTop = document.getElementById('controls-top');
    const volLabel = document.createElement('label');
    volLabel.textContent = 'Master Volume:';
    volLabel.style.marginLeft = '1rem';
    volLabel.style.userSelect = 'none';
    const volSlider = document.createElement('input');
    volSlider.type = 'range';
    volSlider.min = 0;
    volSlider.max = 1;
    volSlider.step = 0.01;
    volSlider.value = 0.24;
    volSlider.title = 'Master Volume Control';
    volSlider.style.width = '120px';
    volSlider.style.marginLeft = '0.5rem';
    volSlider.style.cursor = 'pointer';

    volSlider.addEventListener('input', () => {
      if (audioCtx) {
        setMasterVolume(parseFloat(volSlider.value));
      }
    });
    volLabel.appendChild(volSlider);
    controlsTop.appendChild(volLabel);
  }

  // Initialize app
  buildGrid();
  updateSequenceLog();
  resizeGridHeight();
  createVolumeControl();

  window.addEventListener('resize', resizeGridHeight);
</script>

</body>
</html>





```

wrap improved full code in one code block here.