        * { margin: 0; padding: 0; box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
        /* These :root values MUST stay identical to THEMES.Espresso in js/ui/80-theme.js.
           Espresso is the default scheme, and since the split the browser paints this
           stylesheet before 80-theme.js (17th of 18 scripts) has run — so whatever is
           written here IS the first frame every visitor sees. They had drifted: eight
           vars were a shade off and --btn-text was #ffffff against the theme's #1a1612,
           which flashed white button text on every cold load. Re-synced 2026-07-21.
           Change a colour in one place and you must change it in the other. */
        :root {
            /* Fonts are system stacks, not webfonts: nothing is fetched from another
               origin, so the app has no runtime network I/O and works offline.
               Georgia is the closest ubiquitous match to Merriweather. */
            --font-display: Georgia, 'Iowan Old Style', 'Palatino Linotype', 'Times New Roman', serif;
            --font-ui: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
            --bg-primary: #1a1612;
            --bg-secondary: #2a2420;
            --bg-card: #352f28;
            --accent-primary: #d4a574;
            --accent-secondary: #8b7355;
            --accent-green: #8fb069;
            --accent-yellow: #d9bd6f;
            --text-primary: #efe7d8;
            --text-secondary: #b8a488;
            --border-color: #4a3f32;
            --beat-active: #d9bd6f;
            --beat-inactive: #2a2420;
            --beat-accent: #ff8c00;
            /* NOT Espresso's table value (#b49ad6). applyTheme() overrides every theme's
               --accent-violet with a violet derived from --accent-primary, so the table
               entry is never what actually paints. This is the derived one. */
            --accent-violet: #9c74d4;
            --btn-text: #1a1612;
            /* Reddish header tone, derived in JS (applyTheme) from --accent-primary. This is
               Espresso's first-paint value, read back out of the running app. */
            --header-accent: #d47a74;
            --texture-line: rgba(212, 165, 116, 0.025);
            /* Derived tones — recomputed in JS (with brightness/contrast). These are the
               first-paint values, so they are what applyTheme() produces for Espresso at
               neutral brightness/contrast, read back out of the running app rather than
               worked out on paper. */
            --accent-green-dk: #5d7244;
            --accent-secondary-dk: #61513b;
            --rand-text: #e0c3a1;
            --rand-bg: rgba(212, 165, 116, 0.13);
            --focus-ring: rgba(212, 165, 116, 0.30);
            --glow-primary: rgba(212, 165, 116, 0.45);
            --glow-green: rgba(143, 176, 105, 0.45);
            --glow-yellow: rgba(217, 189, 111, 0.50);
            /* css/seq.css colours the behaviour rows with these and :root never declared
               them, so every one was an invalid substitution until 80-theme.js ran. */
            --seq-cat-sound: #d4a574;
            --seq-cat-param: #d9bd6f;
            --seq-cat-density: #8fb069;
            --seq-cat-embellish: #9c74d4;
        }
        body {
            font-family: var(--font-ui);
            background: linear-gradient(135deg, var(--bg-primary) 0%, var(--bg-secondary) 100%);
            color: var(--text-primary);
            height: 100vh; height: 100dvh;
            overflow: hidden;
            touch-action: manipulation;
        }
        body::before {
            content: '';
            position: fixed; top: 0; left: 0; width: 100%; height: 100%;
            background-image: repeating-linear-gradient(0deg, transparent, transparent 3px,
                var(--texture-line) 3px, var(--texture-line) 6px);
            pointer-events: none; z-index: 1;
        }

