  :root {
    --bg: #eef2f6;
    --panel: #ffffff;
    --ink: #13202f;
    --muted: #687586;
    --line: #d5dce5;
    --button: #1e293b;
    --button-ink: #ffffff;
    --accent: #0f766e;
  }

  * {
    box-sizing: border-box;
  }

  body {
    margin: 0;
    min-height: 100vh;
    color: var(--ink);
    background: var(--bg);
    font-family: "Segoe UI", Arial, sans-serif;
  }

  .shell {
    min-height: 100vh;
    display: grid;
    /* 410px of content + a permanently reserved scrollbar gutter (see .panel) so tabs
       never shift width when the scrollbar appears or disappears. */
    grid-template-columns: minmax(0, 1fr) 427px;
    gap: 16px;
    padding: 16px;
  }

  .stage-frame {
    position: relative;
    min-width: 0;
    display: grid;
    place-items: center;
    overflow: hidden;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: #f8fafc;
  }

  #stage {
    width: 100%;
    max-height: calc(100vh - 34px);
    aspect-ratio: 16 / 9;
    display: block;
  }

  #stage canvas {
    width: 100% !important;
    height: 100% !important;
    display: block;
  }

  /* Performance HUD (src/perf-hud.js). Border color follows data-severity; compact mode is
     for phones. Taps toggle full/compact so pointer events stay on. */
  .metrics-overlay {
    position: absolute;
    top: 12px;
    left: 12px;
    z-index: 4;
    max-width: calc(100% - 24px);
    max-height: calc(100% - 24px);
    margin: 0;
    padding: 10px 12px;
    overflow: hidden;
    border: 1px solid rgba(255, 255, 255, 0.22);
    border-left: 4px solid #2dd4bf;
    border-radius: 8px;
    color: #d9fff2;
    background: rgba(2, 13, 11, 0.82);
    box-shadow: 0 14px 30px rgba(0, 0, 0, 0.22);
    font: 12px/1.45 "Consolas", "Menlo", "Courier New", monospace;
    white-space: pre;
    user-select: none;
    -webkit-user-select: none;
    touch-action: manipulation;
    cursor: pointer;
    backdrop-filter: blur(6px);
  }

  .metrics-overlay[data-severity="warn"] {
    border-left-color: #fbbf24;
  }

  .metrics-overlay[data-severity="bad"] {
    border-left-color: #f87171;
  }

  .metrics-overlay[data-mode="compact"] {
    padding: 8px 10px;
    font-size: 11px;
  }

  @media (max-width: 700px) {
    .metrics-overlay {
      top: 6px;
      left: 6px;
      max-width: calc(100% - 12px);
      padding: 6px 8px;
      font-size: 10px;
      line-height: 1.35;
    }
  }

  .panel {
    min-width: 0;
    max-height: calc(100vh - 32px);
    overflow: auto;
    /* Always reserve the scrollbar's space, so short tabs and long tabs share the same content width. */
    scrollbar-gutter: stable;
    padding: 0;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: var(--panel);
  }

  .panel-header {
    position: sticky;
    top: 0;
    z-index: 5;
    padding: 18px 18px 12px;
    border-bottom: 1px solid var(--line);
    background: var(--panel);
  }

  h1 {
    margin: 0 0 4px;
    font-size: 22px;
    line-height: 1.2;
    letter-spacing: 0;
  }

  .meta {
    margin: 0 0 16px;
    color: var(--muted);
    font-size: 13px;
    line-height: 1.4;
  }

  /* Version badge next to the title (double-click opens the history dialog). */
  .title-row {
    display: flex;
    align-items: baseline;
    gap: 8px;
  }

  .title-row h1 {
    flex: 0 1 auto;
  }

  /* Plain footnote after the title: no box, monospace, muted. The pills inside the dialog keep a box. */
  .version-badge {
    margin: 0;
    padding: 0;
    border: 0;
    background: none;
    color: var(--muted);
    font: 12px/1 ui-monospace, "Cascadia Mono", Consolas, monospace;
    letter-spacing: 0.02em;
    cursor: help;
    user-select: none;
  }

  .title-row .version-badge {
    flex: 0 0 auto;
    align-self: baseline;
    padding: 0 0 2px;
  }

  .title-row .version-badge:hover {
    color: var(--ink);
  }

  /* Help button at the end of the title row. Opens help/ in a new tab, on the page of the
     tab you are looking at (src/app.js, updateHelpLink). */
  .help-link {
    flex: 0 0 auto;
    margin-left: auto;
    width: 20px;
    height: 20px;
    display: grid;
    place-items: center;
    align-self: center;
    border: 1px solid var(--line);
    border-radius: 999px;
    color: var(--muted);
    font: 600 12px/1 "Segoe UI", Arial, sans-serif;
    text-decoration: none;
  }

  .help-link:hover {
    border-color: var(--accent);
    color: var(--accent);
  }

  .history-entry .version-badge {
    padding: 3px 8px;
    border: 1px solid var(--line);
    border-radius: 999px;
    background: var(--bg);
  }

  .history-dialog {
    width: min(680px, 92vw);
    max-height: 85vh;
    padding: 0;
    border: 0;
    border-radius: 12px;
    background: var(--panel);
    color: var(--ink);
    box-shadow: 0 24px 60px rgba(15, 23, 42, 0.35);
  }

  .history-dialog::backdrop {
    background: rgba(15, 23, 42, 0.45);
  }

  .history-dialog .history-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 16px 20px;
    border-bottom: 1px solid var(--line);
  }

  .history-dialog .history-head h2 {
    margin: 0;
    font-size: 18px;
  }

  .history-dialog .history-head button {
    width: auto;
    padding: 6px 14px;
  }

  .history-dialog .history-body {
    max-height: calc(85vh - 70px);
    padding: 4px 20px 20px;
    overflow: auto;
  }

  .history-entry {
    padding: 14px 0;
    border-bottom: 1px solid var(--line);
  }

  .history-entry:last-child {
    border-bottom: 0;
  }

  .history-entry h3 {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 8px;
    margin: 0 0 6px;
    font-size: 15px;
  }

  .history-entry .history-date {
    color: var(--muted);
    font-size: 12px;
    font-weight: 400;
  }

  .history-entry .version-badge {
    cursor: default;
  }


  .history-entry.latest .version-badge {
    border-color: var(--accent);
    background: var(--accent);
    color: #ffffff;
  }

  .history-entry p {
    margin: 0 0 8px;
    font-size: 13px;
    line-height: 1.45;
  }

  .history-entry ul {
    margin: 0;
    padding-left: 18px;
    font-size: 13px;
    line-height: 1.45;
  }

  .history-entry li {
    margin: 4px 0;
  }

  .button-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
    margin-bottom: 12px;
  }

  /* Render PNG sequence (Settings tab, 14 September 2026): a full-page shade with a progress card
     while frames are written. It also keeps clicks off the controls, because the effect is read live
     every frame and an edit mid-render would change the later frames. */
  .render-overlay {
    position: fixed;
    inset: 0;
    z-index: 40;
    display: grid;
    place-items: center;
    background: rgba(19, 32, 47, 0.62);
  }

  .render-overlay[hidden] {
    display: none;
  }

  .render-card {
    width: min(460px, calc(100vw - 32px));
    padding: 20px 22px 18px;
    border-radius: 12px;
    background: var(--panel);
    box-shadow: 0 24px 60px rgba(0, 0, 0, 0.35);
  }

  .render-card h2 {
    margin: 0 0 10px;
    font-size: 18px;
  }

  .render-card .render-pass {
    margin: 0 0 8px;
    font-size: 14px;
  }

  .render-card progress {
    display: block;
    width: 100%;
    height: 14px;
    accent-color: var(--accent);
  }

  .render-card .render-text {
    margin: 8px 0 14px;
    color: var(--muted);
    font-size: 13px;
    font-variant-numeric: tabular-nums;
  }

  .render-card button {
    width: 100%;
  }

  #renderGroup .meta code {
    font-size: 12px;
  }

  .tab-bar {
    display: grid;
    /* Seven tabs since the Paths tab merged the two path tabs (12 Sep 2026): Settings is the long label, so it gets a wider column. */
    grid-template-columns: repeat(6, minmax(0, 1fr)) minmax(0, 1.35fr);
    gap: 5px;
  }

  /* Header mode row (14 September 2026): the system this design describes, fixed for the design, and
     Start over back to the start screen. Badge colours: gold coins, teal win lines, indigo atmospheric. */
  .mode-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: 8px;
    margin: 0 0 12px;
  }

  .mode-badge {
    display: block;
    min-height: 34px;
    padding: 7px 12px;
    border-radius: 8px;
    color: #ffffff;
    background: #c99a06;
    font-size: 13px;
    font-weight: 700;
    line-height: 20px;
  }

  .mode-badge[data-mode="lines"] {
    background: #0d9488;
  }

  .mode-badge[data-mode="atmospheric"] {
    background: #4f46e5;
  }

  .mode-badge[data-mode="flow"] {
    background: #0891b2;
  }

  .mode-row button {
    min-height: 34px;
    padding: 6px 12px;
  }

  /* Controls that only mean something for a flight (coins or lines), only for the coin flight
     journey (Win lines has its own "Play" select for the same thing), only for the
     atmospheric system, or only for the flow field (25 September 2026). */
  body[data-mode="atmospheric"] .flight-only,
  body[data-mode="flow"] .flight-only,
  body:not([data-mode="coins"]) .coins-only,
  body:not([data-mode="atmospheric"]) .atmos-only,
  body:not([data-mode="flow"]) .flow-only {
    display: none;
  }

  /* Start screen: a card over a shade, like the render overlay, with one big button per system. */
  .start-screen {
    position: fixed;
    inset: 0;
    z-index: 50;
    display: grid;
    place-items: center;
    padding: 16px;
    background: rgba(19, 32, 47, 0.72);
  }

  .start-screen[hidden] {
    display: none;
  }

  .start-card {
    width: min(820px, calc(100vw - 32px));
    padding: 22px 24px 20px;
    border-radius: 12px;
    background: var(--panel);
    box-shadow: 0 24px 60px rgba(0, 0, 0, 0.35);
  }

  .start-card h2 {
    margin: 0 0 6px;
    font-size: 20px;
  }

  .start-hint {
    margin: 0 0 16px;
    color: var(--muted);
    font-size: 13px;
    line-height: 1.45;
  }

  /* Four systems since 25 September 2026, in the owner's order (26 September 2026): Atmospheric, Flow, Coins, Win lines. */
  .start-choices {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 10px;
    margin-bottom: 14px;
  }

  .start-choice {
    display: grid;
    gap: 6px;
    min-height: 120px;
    padding: 14px 12px;
    border: 2px solid var(--line);
    border-radius: 10px;
    background: #f8fafc;
    color: var(--ink);
    text-align: left;
    font-size: 12px;
    line-height: 1.4;
  }

  .start-choice strong {
    font-size: 15px;
  }

  .start-choice span {
    color: var(--muted);
    font-weight: 400;
  }

  .start-choice:hover,
  .start-choice:focus-visible {
    border-color: var(--choice, #c99a06);
    background: color-mix(in srgb, var(--choice, #c99a06) 10%, #ffffff);
  }

  .start-choice[data-start-mode="coins"] { --choice: #c99a06; }
  .start-choice[data-start-mode="lines"] { --choice: #0d9488; }
  .start-choice[data-start-mode="atmospheric"] { --choice: #4f46e5; }
  .start-choice[data-start-mode="flow"] { --choice: #0891b2; }

  .start-actions {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px;
  }

  .start-actions button[hidden] {
    display: none;
  }

  .start-actions button:only-child {
    grid-column: 1 / -1;
  }

  @media (max-width: 900px) {
    .start-choices {
      grid-template-columns: repeat(2, minmax(0, 1fr));
    }
  }

  @media (max-width: 700px) {
    .start-choices {
      grid-template-columns: 1fr;
    }
    .start-choice {
      min-height: 0;
    }
  }

  .field[data-disabled="true"] {
    opacity: 0.55;
  }

  .preset-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 8px;
  }

  .preset-row.three {
    grid-template-columns: minmax(0, 1fr) auto auto;
  }

  .preset-row select {
    min-width: 0;
  }

  .line-set-grid {
    display: grid;
    grid-template-columns: repeat(10, minmax(0, 1fr));
    gap: 4px;
    margin-bottom: 8px;
  }

  .line-cell {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 30px;
    border: 1px solid var(--line);
    border-radius: 6px;
    background: #f8fafc;
    color: var(--muted);
    font-size: 11px;
    font-weight: 600;
    cursor: pointer;
    user-select: none;
  }

  .line-cell input {
    display: none;
  }

  .line-cell.on {
    color: #ffffff;
    border-color: var(--tab-accent);
    background: var(--tab-accent);
  }

  .line-set-actions {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 6px;
  }

  .line-set-actions button {
    min-height: 32px;
    padding: 6px 4px;
    font-size: 12px;
  }

  .tab-button[data-tab="board"],
  #tab-board {
    --tab-accent: #8b5a2b;
  }

  /* Paths is one tab for both modes: toxic green for the coin path, teal for win lines. */
  .tab-button[data-tab="paths"],
  #tab-paths {
    --tab-accent: #65a30d;
  }

  body[data-mode="lines"] .tab-button[data-tab="paths"],
  body[data-mode="lines"] #tab-paths {
    --tab-accent: #0d9488;
  }

  /* Atmospheric: the Paths tab holds the zones (indigo, night sky). */
  body[data-mode="atmospheric"] .tab-button[data-tab="paths"],
  body[data-mode="atmospheric"] #tab-paths {
    --tab-accent: #4f46e5;
  }

  /* Flow: the Paths tab holds the field (cyan, water and smoke). */
  body[data-mode="flow"] .tab-button[data-tab="paths"],
  body[data-mode="flow"] #tab-paths {
    --tab-accent: #0891b2;
  }

  /* A mode body that does not match the journey is hidden, so every tab always shows the live controls.
     data-mode-body is a space-separated list, so one body can serve two journeys ("atmospheric flow"
     on the Hit tab's fire-at dropdown and the render Duration). */
  body[data-mode="coins"] .mode-body:not([data-mode-body~="coins"]),
  body[data-mode="lines"] .mode-body:not([data-mode-body~="lines"]),
  body[data-mode="atmospheric"] .mode-body:not([data-mode-body~="atmospheric"]),
  body[data-mode="flow"] .mode-body:not([data-mode-body~="flow"]) {
    display: none;
  }

  /* Flow body (Paths tab): the spine's button row. */
  .flow-tools {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin: 6px 0 10px;
  }

  .flow-tools button {
    flex: 1 1 auto;
  }

  /* Zone cards (Atmospheric, Paths tab): layer cards with the zone's colour as the accent stripe. */
  .zone-card {
    --origin-color: var(--tab-accent);
  }

  .zone-card > summary .zone-dot {
    flex: 0 0 auto;
    width: 12px;
    height: 12px;
    border-radius: 50%;
    background: var(--origin-color);
    box-shadow: 0 0 0 2px #ffffff inset;
  }

  .zone-card .zone-actions {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 6px;
    margin: 6px 0 4px;
  }

  .zone-card .zone-actions button {
    min-height: 30px;
    padding: 5px 6px;
    font-size: 12px;
  }

  .zone-card .zone-actions button.active {
    color: #ffffff;
    background: var(--tab-accent);
    border-color: var(--tab-accent);
  }

  .atmos-note {
    margin: 4px 0 8px;
    color: var(--muted);
    font-size: 12px;
    line-height: 1.4;
  }

  .atmos-note.warn {
    color: #b45309;
  }

  .variant-list {
    display: grid;
    gap: 6px;
    margin: 4px 0 8px;
  }

  .variant-row {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    gap: 8px;
    align-items: center;
    font-size: 12px;
  }

  .variant-row .value {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .tab-button[data-tab="coin"],
  #tab-coin {
    --tab-accent: #c99a06;
  }

  .tab-button[data-tab="trails"],
  #tab-trails {
    --tab-accent: #c026d3;
  }

  .tab-button[data-tab="sparks"],
  #tab-sparks {
    --tab-accent: #ea8a00;
  }

  .tab-button[data-tab="hit"],
  #tab-hit {
    --tab-accent: #dc2626;
  }

  .tab-button[data-tab="settings"],
  #tab-settings {
    --tab-accent: #6b7280;
  }

  .tab-button {
    min-height: 34px;
    padding: 7px 1px;
    color: var(--ink);
    border-bottom: 3px solid var(--tab-accent);
    background: color-mix(in srgb, var(--tab-accent) 9%, #ffffff);
    font-size: 11px;
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .tab-button:hover {
    background: color-mix(in srgb, var(--tab-accent) 18%, #ffffff);
  }

  .tab-button.active {
    color: var(--button-ink);
    border-color: var(--tab-accent);
    background: var(--tab-accent);
  }

  /* The active tab's accent continues into its panel so it is always clear which section is open. */
  .tab-panel {
    border-top: 3px solid var(--tab-accent);
    padding-top: 2px;
  }

  .tab-panel input[type="range"],
  .tab-panel input[type="checkbox"] {
    accent-color: var(--tab-accent);
  }

  .tab-panel .section-head h3,
  .tab-panel .section-head .toggle span {
    color: var(--tab-accent);
    font-weight: 700;
  }

  .tab-panel .section-head {
    border-top-color: color-mix(in srgb, var(--tab-accent) 35%, var(--line));
  }

  .tab-panel .layer-card {
    border-color: color-mix(in srgb, var(--tab-accent) 35%, var(--line));
  }

  .tab-panel .layer-card > summary {
    border-left: 4px solid var(--tab-accent);
    border-radius: 8px 8px 0 0;
    background: color-mix(in srgb, var(--tab-accent) 10%, #f8fafc);
  }

  .tab-panel .layer-card:not([open]) > summary {
    border-radius: 8px;
  }

  .tab-panel .layer-card > summary::before,
  .tab-panel .layer-body details > summary::before,
  .tab-panel .collapsible-field > summary .label-row > span:first-child::before {
    color: var(--tab-accent);
  }

  .tab-panel .layer-body details > summary,
  .tab-panel .collapsible-field > summary .label-row > span:first-child {
    color: color-mix(in srgb, var(--tab-accent) 80%, var(--ink));
  }

  .tab-panel .pot-editor,
  .tab-panel .asset-upload-row {
    border-left: 4px solid color-mix(in srgb, var(--tab-accent) 55%, #ffffff);
  }

  .tab-panel button:not(.secondary):not(.icon-button):not(.solo-button):not(.mute-button) {
    background: var(--tab-accent);
    border-color: var(--tab-accent);
  }

  .tab-content {
    padding: 0 18px 18px;
  }

  .tab-panel[hidden] {
    display: none;
  }

  .header-controls {
    margin-bottom: 12px;
  }

  .panel-header .header-controls .field {
    padding: 8px 0;
  }

  .toggle-row {
    display: flex;
    flex-wrap: wrap;
    /* One fixed gap, so the distance between any two toggles is identical (owner ask,
       21 September 2026). Equal grid columns made it depend on the label lengths. */
    gap: 0 18px;
    border-top: 1px solid var(--line);
  }

  .toggle-row .field {
    border-top: 0;
  }

  .maintenance-readout {
    display: none;
  }

  button,
  select,
  input[type="number"] {
    min-height: 38px;
    border: 1px solid var(--line);
    border-radius: 8px;
    font: inherit;
  }

  button {
    padding: 8px 10px;
    color: var(--button-ink);
    background: var(--button);
    cursor: pointer;
  }

  button.secondary {
    color: var(--ink);
    background: #f8fafc;
  }

  /* Load preset with a pick in the dropdown that is not loaded yet: the accent, so the eye lands on it. */
  button.secondary.pending {
    color: var(--button-ink);
    background: var(--accent);
    border-color: var(--accent);
  }

  button:disabled,
  select:disabled,
  input:disabled {
    cursor: not-allowed;
    opacity: 0.5;
  }

  button:active {
    transform: translateY(1px);
  }

  .field,
  .slider {
    padding: 12px 0;
    border-top: 1px solid var(--line);
  }

  .label-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 8px;
    color: var(--ink);
    font-size: 13px;
    line-height: 1.3;
  }

  output,
  .value {
    color: var(--muted);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
  }

  output.editable-value {
    cursor: text;
    border-bottom: 1px dotted transparent;
  }

  output.editable-value:hover {
    color: var(--ink);
    border-bottom-color: var(--muted);
  }

  /* A typed number the slider track cannot show exactly (past its end, or between its steps): the thumb is
     parked at the nearest position and the readout carries the real value in the tab's colour. */
  output.editable-value[data-off-track="true"] {
    color: var(--tab-accent, var(--accent));
  }

  /* Control names that reset to their default on double-click (makeResetLabel). */
  .reset-label {
    cursor: default;
    user-select: none;
    border-bottom: 1px dotted transparent;
  }

  .reset-label:hover {
    border-bottom-color: var(--muted);
  }

  .slider[data-disabled="true"] .reset-label,
  .field[data-disabled="true"] .reset-label {
    pointer-events: none;
  }

  input.inline-value-editor[type="number"] {
    width: 82px;
    min-height: 24px;
    padding: 2px 6px;
    text-align: right;
    font: inherit;
  }

  input[type="range"] {
    width: 100%;
    accent-color: var(--accent);
  }

  select,
  input[type="number"],
  input[type="color"] {
    width: 100%;
    padding: 7px 9px;
    color: var(--ink);
    background: #ffffff;
  }

  input[type="color"] {
    height: 38px;
    padding: 4px;
  }

  .toggle {
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 38px;
    color: var(--ink);
    font-size: 14px;
  }

  .toggle input {
    width: 18px;
    height: 18px;
    accent-color: var(--accent);
  }

  .readout {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px 12px;
    margin-top: 14px;
    padding-top: 14px;
    border-top: 1px solid var(--line);
    font-size: 13px;
  }

  .readout span:nth-child(odd) {
    color: var(--muted);
  }

  .target-tools {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
  }

  .target-tools .field {
    border-top: 0;
    padding-top: 0;
  }

  .pot-fields {
    display: grid;
    gap: 10px;
    padding-top: 12px;
    border-top: 1px solid var(--line);
  }

  /* Inside the Board card (26 September 2026) Source count and Target count share one row. Win lines hides
     Source count (a payline reads the whole reel window), so Target count takes the whole row there. */
  body[data-mode="lines"] .element-board-card label[for="targetCount"] {
    grid-column: 1 / -1;
  }

  .asset-upload-actions {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
  }

  /* Stage elements (Board tab, 26 September 2026): one list, front-most first, with a heading per slot and a
     marker where the effect draws. Cards reuse .layer-card; the header is the drag handle for reordering. */
  .element-actions {
    display: grid;
  }

  .element-fit button {
    padding-left: 6px;
    padding-right: 6px;
    font-size: 12px;
  }

  .element-list {
    position: relative;
    display: grid;
    gap: 6px;
    margin: 4px 0 14px;
  }

  .element-index {
    flex: 0 0 auto;
    display: inline-grid;
    place-items: center;
    width: 20px;
    height: 20px;
    border-radius: 999px;
    background: var(--tab-accent);
    color: #ffffff;
    font-size: 11px;
    font-weight: 700;
  }

  .tab-panel .element-board-card > summary {
    background: color-mix(in srgb, var(--tab-accent) 22%, #f8fafc);
  }

  .element-board-name {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 13px;
    font-weight: 700;
  }

  .element-board-card > summary .value {
    flex: 0 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--muted);
    font-weight: 400;
  }

  /* Element 0, the effect: the one row of the stack that never moves, so it wears its own dark colour instead
     of the tab accent (owner ask, 26 September 2026). The badge on the left, the title on one line, the note under it. */
  .element-marker {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    column-gap: 10px;
    row-gap: 2px;
    align-items: center;
    padding: 8px 10px;
    border: 1px solid #0f172a;
    border-radius: 8px;
    background: var(--button);
    color: var(--button-ink);
    font-size: 12px;
    font-weight: 700;
    cursor: default;
  }

  .element-marker .element-index {
    grid-row: 1 / span 2;
    background: #ffffff;
    color: var(--button);
  }

  .element-marker .element-marker-title {
    grid-column: 2;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .element-marker .value {
    grid-column: 2;
    min-width: 0;
    color: #cbd5e1;
    font-size: 11px;
    font-weight: 400;
  }

  .element-card > summary,
  .element-board-card > summary {
    cursor: grab;
    user-select: none;
    touch-action: none;
  }

  .element-card.dragging,
  .element-board-card.dragging {
    opacity: 0.45;
  }

  .element-card.selected {
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--tab-accent) 70%, #ffffff);
  }

  .element-grip {
    flex: 0 0 auto;
    color: var(--muted);
    font-size: 15px;
    line-height: 1;
    letter-spacing: -2px;
  }

  .element-thumb {
    flex: 0 0 auto;
    width: 36px;
    height: 24px;
    border: 1px solid var(--line);
    border-radius: 4px;
    background: #1b1f2a;
  }

  .element-drop-indicator {
    position: absolute;
    left: 0;
    right: 0;
    height: 3px;
    margin-top: -4px;
    border-radius: 2px;
    background: var(--tab-accent);
    pointer-events: none;
  }

  body.element-drag,
  body.element-drag * {
    cursor: grabbing !important;
    user-select: none;
  }

  .element-fit {
    grid-template-columns: 1fr 1fr;
    padding-top: 6px;
  }

  .swatch-row {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    gap: 6px;
    margin-top: 8px;
  }

  .swatch {
    min-height: 26px;
    padding: 0;
    border: 1px solid var(--line);
    border-radius: 6px;
  }

  .asset-upload-list {
    display: grid;
    gap: 10px;
  }

  .asset-upload-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto auto auto;
    align-items: center;
    gap: 8px;
    padding: 10px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: #f8fafc;
  }

  .trail-color-input[type="color"] {
    width: 46px;
    min-height: 34px;
    height: 34px;
    padding: 2px;
  }


  .asset-upload-main {
    display: grid;
    gap: 4px;
    min-width: 0;
    font-size: 13px;
  }

  .asset-upload-title {
    display: flex;
    align-items: center;
    gap: 8px;
    font-weight: 700;
  }

  .asset-upload-status {
    overflow: hidden;
    color: var(--muted);
    font-size: 12px;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .pot-editor {
    display: grid;
    gap: 10px;
    padding: 12px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: #f8fafc;
  }

  .pot-editor-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    font-size: 13px;
    font-weight: 700;
  }

  .pot-chip {
    width: 20px;
    height: 20px;
    flex: 0 0 auto;
    border: 2px solid #ffffff;
    border-radius: 999px;
    box-shadow: 0 0 0 1px var(--line);
  }

  .pot-position-grid {
    display: grid;
    grid-template-columns: 70px 1fr 1fr;
    gap: 8px;
    align-items: end;
  }

  .pot-position-grid label {
    display: grid;
    gap: 4px;
    color: var(--muted);
    font-size: 12px;
  }

  .playback-row {
    display: grid;
    grid-template-columns: 74px minmax(0, 1fr);
    gap: 10px;
    align-items: center;
    margin-bottom: 10px;
  }

  .playback-row button.active {
    color: #ffffff;
    background: #b45309;
    border-color: #b45309;
  }

  .playback-sliders {
    display: grid;
    gap: 2px;
    min-width: 0;
  }

  .playback-sliders .label-row {
    margin-bottom: 0;
    font-size: 12px;
  }

  .playback-sliders output {
    white-space: nowrap;
  }

  /* The readout names a new flight after a Scrub pull snaps. */
  #scrubTimeValue.flash {
    animation: scrub-readout-flash 700ms ease-out;
  }

  @keyframes scrub-readout-flash {
    from {
      color: #dc2626;
    }
  }

  /* Scrub pull (27 September 2026): ghost balls the size of the slider ball, pulled out past either end of
     Scrub. They blink one after another toward the pointer while the pull holds, redden as it stretches
     (--pull-color, set per move), tremble near the snap and burst when it snaps. An overlay on the page,
     so the slider itself is untouched and the chain can reach past the panel edge. */
  .scrub-pull {
    --pull-color: #0f766e;
    --chase: 450ms;
    position: fixed;
    inset: 0;
    z-index: 60;
    pointer-events: none;
  }

  .scrub-pull[hidden] {
    display: none;
  }

  .scrub-pull span {
    position: absolute;
    box-sizing: border-box;
    width: 16px;
    height: 16px;
    border: 2px solid var(--pull-color);
    border-radius: 50%;
    background: color-mix(in srgb, var(--pull-color) 35%, transparent);
    animation: scrub-pull-chase var(--chase) linear infinite;
  }

  .scrub-pull span:nth-child(2) {
    animation-delay: calc(var(--chase) / 3);
  }

  .scrub-pull span:nth-child(3) {
    animation-delay: calc(var(--chase) * 2 / 3);
  }

  .scrub-pull span:nth-child(4) {
    animation-delay: var(--chase);
  }

  .scrub-pull.straining {
    --chase: 240ms;
    animation: scrub-pull-tremble 90ms linear infinite;
  }

  .scrub-pull.snapped span {
    animation: scrub-pull-snap 240ms ease-out forwards;
  }

  @keyframes scrub-pull-chase {
    0%,
    30% {
      opacity: 1;
    }

    34%,
    100% {
      opacity: 0.22;
    }
  }

  @keyframes scrub-pull-tremble {
    0%,
    100% {
      transform: translate(0, 0);
    }

    25% {
      transform: translate(1px, -1px);
    }

    75% {
      transform: translate(-1px, 1px);
    }
  }

  @keyframes scrub-pull-snap {
    from {
      opacity: 1;
      transform: scale(1);
    }

    to {
      opacity: 0;
      transform: scale(1.9);
    }
  }

  .section-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 10px 0 6px;
    border-top: 1px solid var(--line);
  }

  .section-head h3 {
    margin: 0;
    font-size: 14px;
  }

  .section-head .toggle {
    min-height: 30px;
  }

  .solo-button {
    flex: 0 0 auto;
    min-height: 28px;
    padding: 2px 8px;
    border-radius: 999px;
    color: var(--ink);
    background: #f8fafc;
    font-size: 12px;
    font-weight: 700;
  }

  .solo-button.active {
    color: #ffffff;
    background: #b45309;
    border-color: #b45309;
  }

  .mute-button {
    flex: 0 0 auto;
    min-height: 28px;
    padding: 2px 8px;
    border-radius: 999px;
    color: var(--ink);
    background: #f8fafc;
    font-size: 12px;
    font-weight: 700;
  }

  .mute-button.active {
    color: #ffffff;
    background: #475569;
    border-color: #475569;
  }

  .isolation-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-top: 10px;
    padding: 6px 10px;
    border: 1px solid #f6c453;
    border-radius: 8px;
    background: #fff7e0;
    font-size: 12px;
  }

  .isolation-bar[hidden] {
    display: none;
  }

  .isolation-bar .secondary {
    min-height: 26px;
    padding: 0 10px;
    font-size: 12px;
  }

  .icon-button {
    flex: 0 0 auto;
    min-height: 28px;
    min-width: 26px;
    padding: 0 5px;
    color: var(--ink);
    background: #ffffff;
    font-size: 12px;
    line-height: 1;
  }

  .layer-list {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 10px;
  }

  .layer-card {
    min-width: 0;
    max-width: 100%;
    overflow: hidden;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: #f8fafc;
  }

  .layer-card[data-disabled="true"] > summary {
    opacity: 0.6;
  }

  .slider[data-disabled="true"] {
    opacity: 0.5;
  }

  .slider[data-disabled="true"] .editable-value {
    pointer-events: none;
  }

  .layer-body details.system-life[data-disabled="true"] > summary,
  .layer-body details.system-life[data-disabled="true"] > .hint {
    opacity: 0.5;
  }

  .layer-card > summary {
    display: flex;
    align-items: center;
    gap: 5px;
    padding: 7px 8px;
    list-style: none;
    cursor: pointer;
  }

  .layer-card > summary::-webkit-details-marker {
    display: none;
  }

  .layer-card > summary::before {
    content: "\25B8";
    width: 14px;
    color: var(--ink);
    font-size: 15px;
    line-height: 1;
  }

  .layer-card[open] > summary::before {
    content: "\25BE";
  }

  .layer-card .layer-name {
    flex: 1 1 40px;
    width: 40px;
    min-width: 0;
    min-height: 28px;
    padding: 2px 6px;
    border: 1px solid transparent;
    border-radius: 6px;
    background: transparent;
    font: inherit;
    font-size: 13px;
    font-weight: 700;
  }

  .layer-card .layer-name:focus {
    border-color: var(--line);
    background: #ffffff;
    outline: none;
  }

  .layer-body {
    padding: 0 10px 10px;
    border-top: 1px solid var(--line);
  }

  .layer-body .field,
  .layer-body .slider,
  .layer-body .curve-editor,
  .layer-body .gradient-editor {
    padding: 8px 0;
  }

  .layer-body details {
    border-top: 1px solid var(--line);
  }

  .layer-body details:first-child {
    border-top: 0;
  }

  .layer-body details > summary {
    padding: 8px 0;
    color: var(--ink);
    font-size: 13px;
    font-weight: 700;
    cursor: pointer;
    list-style: none;
  }

  .layer-body details > summary::-webkit-details-marker {
    display: none;
  }

  .layer-body details > summary::before {
    content: "\25B8";
    display: inline-block;
    width: 14px;
    color: var(--ink);
    font-size: 15px;
    line-height: 1;
  }

  .layer-body details[open] > summary::before {
    content: "\25BE";
  }

  .layer-body details > summary .value {
    float: right;
    font-weight: 400;
  }

  .emitter-list {
    display: grid;
    gap: 4px;
    margin-bottom: 10px;
  }

  .emitter-row {
    padding: 8px 0 2px 8px;
    border-top: 1px dashed var(--line);
    border-left: 3px solid var(--emitter-color, transparent);
  }

  .emitter-dot {
    display: inline-block;
    width: 10px;
    height: 10px;
    margin-right: 6px;
    border-radius: 50%;
    background: var(--emitter-color, transparent);
    border: 1px solid rgba(17, 24, 39, 0.35);
    vertical-align: -1px;
  }

  /* A layer card that emits from an arm takes that arm's colour (set by applyOriginAccent). */
  .tab-panel .layer-card[data-origin] {
    border-color: color-mix(in srgb, var(--origin-color) 55%, var(--line));
  }

  .tab-panel .layer-card[data-origin] > summary {
    border-left-color: var(--origin-color);
    background: color-mix(in srgb, var(--origin-color) 22%, #f8fafc);
  }

  .emitter-row > .label-row {
    margin-bottom: 0;
  }

  .emitter-row .icon-button {
    padding: 2px 8px;
  }

  .inline-grid-2 {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 8px;
  }

  .inline-grid-3 {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 6px;
  }

  .inline-grid-3 label,
  .inline-grid-3 select,
  .layer-body select,
  .layer-body .asset-upload-actions button {
    min-width: 0;
    max-width: 100%;
  }

  .layer-body .asset-upload-actions {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .layer-body .asset-upload-actions button {
    padding-left: 6px;
    padding-right: 6px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .inline-grid-3 label,
  .inline-grid-2 label.stack {
    display: grid;
    gap: 4px;
    color: var(--muted);
    font-size: 11px;
  }

  /* A stage element hides the per-particle Start frame and Frames; the grid rule above would otherwise beat the attribute. */
  .inline-grid-3 label[hidden] {
    display: none;
  }

  .inline-grid-3 select,
  .inline-grid-2 label.stack select,
  .inline-grid-2 label.stack input[type="number"] {
    min-height: 32px;
    padding: 4px 6px;
    font-size: 12px;
  }

  .curve-editor,
  .gradient-editor {
    padding: 10px 0;
    border-top: 1px solid var(--line);
  }

  .curve-editor canvas,
  .gradient-editor canvas {
    display: block;
    width: 100%;
    border: 1px solid var(--line);
    border-radius: 6px;
    background: #ffffff;
    touch-action: none;
    cursor: crosshair;
  }

  .curve-editor canvas:focus,
  .gradient-editor canvas:focus {
    outline: 2px solid rgba(15, 118, 110, 0.35);
  }

  .curve-tools {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 6px;
  }

  .curve-tools select,
  .curve-tools button {
    width: auto;
    min-height: 28px;
    padding: 2px 8px;
    font-size: 12px;
  }

  .gradient-tools {
    display: grid;
    grid-template-columns: 46px 64px minmax(0, 1fr) auto;
    gap: 6px;
    align-items: center;
    margin-top: 6px;
  }

  .gradient-tools input[type="color"] {
    width: 46px;
    height: 32px;
    padding: 2px;
  }

  .gradient-tools input[type="number"] {
    min-height: 32px;
    padding: 4px 6px;
    font-size: 12px;
  }

  .gradient-tools button {
    min-height: 32px;
    padding: 2px 8px;
    font-size: 12px;
  }

  .collapsible-field {
    padding: 12px 0;
    border-top: 1px solid var(--line);
  }

  .collapsible-field > summary {
    list-style: none;
    cursor: pointer;
  }

  .collapsible-field > summary::-webkit-details-marker {
    display: none;
  }

  .collapsible-field > summary .label-row {
    margin-bottom: 0;
  }

  .collapsible-field > summary .label-row > span:first-child::before {
    content: "▸";
    display: inline-block;
    width: 14px;
    color: var(--ink);
    font-size: 15px;
    line-height: 1;
  }

  .collapsible-field > summary .label-row > span:first-child {
    font-weight: 700;
  }

  .collapsible-field[open] > summary .label-row > span:first-child::before {
    content: "▾";
  }

  .collapsible-field[open] > summary {
    margin-bottom: 8px;
  }

  .hint {
    margin: 4px 0 0;
    color: var(--muted);
    font-size: 11px;
    line-height: 1.4;
  }

  .seq-widget .asset-upload-actions {
    margin-bottom: 8px;
  }

  .transform-head {
    display: grid;
    grid-template-columns: 96px minmax(0, 1fr);
    gap: 10px;
    align-items: start;
    padding: 6px 0 4px;
  }

  .transform-preview {
    display: block;
    width: 96px;
    height: 96px;
    border: 1px solid var(--line);
    border-radius: 6px;
    background: #1b1f2a;
  }

  .transform-info {
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 0;
  }

  .transform-size {
    color: var(--ink);
    font-size: 12px;
    font-weight: 600;
  }

  .transform-hint {
    color: var(--muted);
    font-size: 11px;
    line-height: 1.4;
  }

  .transform-info button {
    align-self: flex-start;
    padding: 4px 10px;
    font-size: 12px;
  }

  .seq-status {
    display: block;
    overflow: hidden;
    color: var(--muted);
    font-size: 12px;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .seed-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto auto;
    gap: 6px;
    align-items: center;
  }

  .seed-row input[type="number"] {
    min-height: 32px;
    padding: 4px 6px;
    font-size: 12px;
  }

  .seed-row .toggle {
    min-height: 32px;
    font-size: 12px;
  }

  @media (max-width: 1100px) {
    .shell {
      grid-template-columns: 1fr;
    }

    .panel {
      max-height: none;
    }

    #stage {
      max-height: none;
    }
  }

  /* Auxiliary (non-particle) sections: collapsed by default, visually muted */
  .aux-section {
    margin-top: 14px;
    border-top: 1px dashed var(--line);
    opacity: 0.72;
    transition: opacity 0.15s ease;
  }

  .aux-section:hover,
  .aux-section[open] {
    opacity: 1;
  }

  .aux-section > summary .label-row > span:first-child {
    font-weight: 600;
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
  }

  .tab-panel .aux-section > summary .label-row > span:first-child,
  .tab-panel .aux-section > summary .label-row > span:first-child::before {
    color: var(--muted);
  }

  .aux-section > summary .value {
    font-size: 11px;
  }

  /* Splash (index.html #splash, src/splash.js): the ChixyFX art letterbox-fit on black over the
     whole page while the tool boots; src/splash.js fades it out after 4 s or on a click. The art is
     a fixed-ratio box so the version label can sit in percentages of the picture and stay glued to
     the right of the lettering at any window size. Swapping the art: change the src and width/height
     in index.html, --splash-ratio here, and the label's left / bottom / font-size below. */
  .splash {
    position: fixed;
    inset: 0;
    z-index: 9999;
    display: flex;
    align-items: center;
    justify-content: center;
    background: #000;
    cursor: pointer;
    transition: opacity 400ms ease;
  }

  .splash.is-leaving {
    opacity: 0;
    pointer-events: none;
  }

  .splash-art {
    --splash-ratio: 1179 / 1334;
    /* The art takes at most this share of the screen (owner: two thirds, never full height). */
    --splash-fill: 2 / 3;
    position: relative;
    /* Portrait art: height-limited on a landscape screen, width-limited on a narrow one. */
    width: min(100% * (var(--splash-fill)), 100vh * (var(--splash-fill)) * (var(--splash-ratio)));
    aspect-ratio: var(--splash-ratio);
    container-type: inline-size;
  }

  .splash-art img {
    display: block;
    width: 100%;
    height: 100%;
  }

  /* Version label right of the "FX", on the lettering's baseline. left/bottom are percentages of the
     art; cqw is a percentage of its width (the vh line is the fallback for browsers without container
     units). Dark shadow ring plays the part of the lettering's outline. */
  .splash-version {
    position: absolute;
    left: 60%;
    bottom: 2.6%;
    font-family: "Segoe UI", Arial, sans-serif;
    font-weight: 700;
    font-size: 3.9vh;
    font-size: 4.4cqw;
    line-height: 1;
    letter-spacing: 0.02em;
    color: #ffe9a3;
    text-shadow:
      -0.04em -0.04em 0 #3b1607,
      0.04em -0.04em 0 #3b1607,
      -0.04em 0.04em 0 #3b1607,
      0.04em 0.04em 0 #3b1607,
      0 0.08em 0.3em rgba(0, 0, 0, 0.7);
    white-space: nowrap;
    user-select: none;
  }
