<!-- SOLUV · part 463 -->
oice arrives as a letter, every letter lands alive.',
    'Here the world and the word are one room. Walk in free.'
  ].join('\n');

  function h(tag, cls, text) {
    var e = document.createElement(tag);
    if (cls) e.className = cls;
    if (text != null) e.textContent = text;
    return e;
  }
  function hash(s) { var x = 2166136261; for (var i = 0; i < s.length; i++) { x ^= s.charCodeAt(i); x = Math.imul(x, 16777619); } return x >>> 0; }
  function colorsFor(key) { var hue = hash(key) % 360; return { face: 'hsl(' + hue + ',52%,38%)', name: 'hsl(' + hue + ',62%,28%)', tag: 'hsl(' + hue + ',75%,70%)' }; }
  function initial(name) { var m = String(name || '?').trim().replace(/^(king|queen|the)\s+/i, '').match(/[A-Za-z0-9\u00C0-\uFFFF]/); return m ? m[0].toUpperCase() : '?'; }
  function hhmm(t) { var d = new Date(t); return d.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' }); }
  function newKey() { return 'k' + Date.now().toString(36) + Math.random().toString(36).slice(2, 10); }

  function mount(el, opts) {
    if (!el || !el.appendChild) throw new Error('SoluvRoom.mount needs a container element');
    opts = opts || {};
    var api = opts.api || '/api/soluv-room';
    var reduceMotion = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches;

    var me = { name: 'Guest', username: null, king: false, csrf: null };
    var lastId = 0;
    var byId = Object.create(null);       // server id -> node
    var byKey = Object.create(null);      // localKey -> node (my pending letters)
    var es = null, pollTimer = null, pollBusy = false, destroyed = false;
    var newCount = 0;
    var loadingHistory = true;
    var cleanups = [];

    // ---------- DOM ----------
    var dense = !!opts.dense;
    var root = h('section', 'sr-room' + (opts.fitViewport ? ' sr-fit' : '') + (dense ? ' sr-dense' : ''));
    root.setAttribute('aria-label', opts.title || 'The Soluv Room');
    var status = h('div', 'sr-status'); status.setAttribute('role', 'status'); status.setAttribute('aria-live', 'polite');
    var dot = h('span', 'sr-dot'); var statusText = h('span', null, dense ? '…' : 'Connecting…');
    status.appendChild(dot); status.appendChild(statusText);
    var jump = h('button', 'sr-btn sr-jump', dense ? '↓' : 'Latest ↓'); jump.type = 'button'; jump.disabled = true;
    jump.setAttribute('aria-label', 'Jump to latest');
    var errors = h('div', 'sr-errors'); errors.setAttribute('role', 'alert');
    var list = h('div', 'sr-list'); list.setAttribute('aria-live', 'polite');

    var compose = h('form', 'sr-compose');
    var row = h('div', 'sr-row');
    var input = h('textarea', 'sr-input'); input.rows = 1; input.maxLength = MAX_LEN;
    input.placeholder = dense ? 'Write…' : 'Write your letter…'; input.setAttribute('aria-label', 'Your message');
    input.setAttribute('enterkeyhint', 'send');
    var mic = h('button', 'sr-btn sr-mic', '🎤'); mic.type = 'button'; mic.setAttribute('aria-label', 'Talk to type'); mic.setAttribute('aria-pressed', 'false');
    var send = h('button', 'sr-btn sr-send', 'Send'); send.type = 'submit';
    row.appendChild(input); row.appendChild(mic); row.appendChild(send);
    var micNote = h('span', 'sr-micnote', '');
    var count = h('span', 'sr-count', '0 / ' + MAX_LEN);
    var meLine, read = null, aMinus = null, aPlus = null;

    if (!dense) {
      var head = h('header', 'sr-head');
      var title = h('h2', 'sr-title', opts.title || 'The Soluv Room');
      meLine = h('div', 'sr-me', 'Checking who you are…');
      head.appendChild(title); head.appendChild(status); head.appendChild(jump); head.appendChild(meLine);
      var foot = h('div', 'sr-foot');
      foot.appendChild(micNote); foot.appendChild(count);
      compose.appendChild(row); compose.appendChild(foot);
      root.appendChild(head); root.appendChild(errors); root.appendChild(list); root.appendChild(compose);
    } else {
      // Dense: ONE thin fixed bar at the bottom holds every control. It never moves or hides.
      var bar = h('div', 'sr-bar');
      read = h('div', 'sr-read', 'Checking who you are…'); read.setAttribute('aria-live', 'polite');
      meLine = h('span', null, '');
      aMinus = h('button', 'sr-btn sr-aminus', 'A−'); aMinus.type = 'button'; aMinus.setAttribute('aria-label', 'Smaller text');
      aPlus = h('button', 'sr-btn sr-aplus', 'A+'); aPlus.type = 'button'; aPlus.setAttribute('aria-label', 'Bigger text');
      bar.appendChild(status); bar.appendChild(read); bar.appendChild(aMinus); bar.appendChild(aPlus); bar.appendChild(jump);
      compose.appendChild(bar); compose.appendChild(row);
      root.appendChild(errors); root.appendChild(list); root.appendChild(compose);
    }
    // Dense readout line: who you are by default; tapped line's time, typing count, mic notes, text size.
    var readBase = '';
    function info(text) { if (read) read.textContent = text; }
    el.appendChild(root);

    // ---------- visible errors -----