/* Designtools core UI — one interface for every tool and brand (the brand belongs to the result,
   not to the tool). Layers, in order: font, base tokens, dock building blocks, UI layer, skeleton
   (dock head and foot, stage tools, inspector, settings dialog, stepper), symbols.
   Principles: docs/QS/; the principles in three units; what one block needs stands at the block (patterns/). */

/* The atoms: every token, light and dark decided there only (core/tokens.css). */
@import url("tokens.css?v=0.7.16");

/* Inter (SIL Open Font License, core/fonts/LICENSE-Inter.txt), variable weight, self-hosted. */
@font-face { font-family: 'Inter UI'; font-style: normal; font-weight: 100 900; font-display: block;
  src: url("fonts/inter-latin-wght-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; }
@font-face { font-family: 'Inter UI'; font-style: normal; font-weight: 100 900; font-display: block;
  src: url("fonts/inter-latin-ext-wght-normal.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; }

/* Until every face is loaded (core/ui.js DT_FONTS) no stage shows a fallback face (user, 28.10.2026: „bitte hier nicht mit
   Default-Schrift beim Laden“); the text of the UI waits by font-display: block. */
html.fonts-pending canvas { visibility: hidden; }
/* The page appears whole (user, 28.10.2026: „die tools/layouts blitzen beim laden“): core/boot.js marks html.preload before
   the first paint; until the core has its fonts and the tool its first frame (core/ui.js) the page is not shown and nothing
   transitions – Darstellung, sizes and panels set on loading take their place at once, not by a fade. */
html.preload body { opacity: 0; }
/* it fades in instead of popping up (user, 28.10.2026: „die tools starten alle noch leer und blitzen auf“) */
body { transition: opacity var(--motion-move) var(--motion-easing); }
html.preload *, html.preload *::before, html.preload *::after { transition: none !important; }

/* Dock and panel building blocks (from THA Designtools 0.29.7). */

* { box-sizing: border-box; }
html, body {
  margin: 0;
  height: 100%;
  overflow: hidden;
  background: var(--color-surface-room);
  color: var(--color-text);
  font-family: var(--type-family);
}
/* Set on <body> whenever Format is a fixed ratio (not "Free") — see each
   tool's resize()/ratioForFormat() call site. Gives the canvas a visible
   edge against the page without relying on the border/shadow alone. */
body.format-fixed {
  background: var(--color-surface-page);
}

#field {
  position: fixed;
  touch-action: none;
  transition: border-radius var(--motion-move) ease, box-shadow var(--motion-move) ease, border-color var(--motion-move) ease;
}

/* ==== Pattern Dock (Organismus) ===========================================================================
   Klassen: .dock (.collapsed, .quer, .dock-secondary, .dock-recessed, .dock-closed) > .dock-header > a.dock-title +
   .icon-row + .dock-min · .dock-body · .dock-foot
   Zusammenspiel: sets --button-width for its foot; .quer sets the Button in its head small; --dock-quer-rechts from
   the page */
.dock {
  position: fixed;
  z-index: 3;
  top: 50%;
  right: var(--space-window);
  transform: translateY(-50%);
  width: var(--panel-width);
  max-height: 88vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--panel-bg);
  border: none;
  backdrop-filter: var(--panel-blur);
  -webkit-backdrop-filter: var(--panel-blur);
  box-shadow: var(--elevation-panel);
  transition: right var(--motion-move) var(--motion-easing), box-shadow var(--motion-move) ease;   /* it slides beside the inspector */
  user-select: none;
  -webkit-user-select: none;
}
.dock.dock-closed { display: none; }
.dock.dock-recessed { box-shadow: var(--elevation-recessed); }   /* the one not touched last stands further back */
.dock.dock-secondary { top: calc(50% + var(--space-24)); right: calc(var(--space-window) + var(--space-24)); }
@media (max-width: 560px) {   /* a phone: the dock as a sheet at the lower edge, a second one at the upper */
  .dock { left: var(--space-12); right: var(--space-12); top: auto; bottom: var(--space-12); width: auto; max-height: 60dvh; transform: none; }
  .dock.dock-secondary { top: var(--space-12); bottom: auto; left: var(--space-12); right: var(--space-12); max-height: 40dvh; }
}
.dock-header {
  display: flex;
  align-items: center;
  gap: var(--space-8);
  flex-shrink: 0;
  padding: var(--space-16) var(--space-16) var(--space-8) var(--space-panel);
  cursor: grab;
  user-select: none;
  touch-action: none;
}
.dock-header:active { cursor: grabbing; }
.dock.collapsed .dock-header { padding-bottom: var(--space-16); }   /* folded: the head as high above as below */
.dock-grip { display: none; }
.dock-title {
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: var(--type-title);
  font-weight: var(--type-weight-bold);
  letter-spacing: -0.01em;
  color: var(--color-text);
}
a.dock-title { display: inline-flex; align-items: center; min-height: var(--size-target); color: inherit; text-decoration: none; -webkit-user-drag: none; user-select: none; }   /* a link, part of the grip */
a.dock-title:hover { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: var(--type-underline-offset); }
a.dock-title:focus-visible { outline: var(--focus-width) solid var(--color-focus); outline-offset: var(--focus-offset); border-radius: var(--radius-small); }
.dock-min {
  width: var(--size-control-small);
  height: var(--size-control-small);
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  border-radius: 50%;
  background: transparent;
  color: var(--color-text);
  cursor: pointer;
  transition: transform var(--motion-move) var(--motion-easing-spring), background var(--motion-hover) ease;
}
.dock-min svg { width: var(--size-icon); height: var(--size-icon); flex-shrink: 0; }
.dock-min:hover { background: var(--color-fill-1); }
.dock-min:focus-visible { outline: var(--focus-width) solid var(--color-focus); outline-offset: 1px; }
.dock.collapsed .dock-min { transform: rotate(-90deg); }
.dock-body {
  display: flex;
  flex-direction: column;
  gap: var(--space-group);
  padding: var(--space-12) var(--space-panel) var(--space-panel);
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--color-border) transparent;
  /* what scrolls fades out at both edges, inside the padding */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, black var(--panel-fade-top), black calc(100% - var(--panel-fade-bottom)), transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0, black var(--panel-fade-top), black calc(100% - var(--panel-fade-bottom)), transparent 100%);
}
.dock-body::-webkit-scrollbar { width: var(--panel-scrollbar); }
.dock-body::-webkit-scrollbar-track { background: transparent; }
.dock-body::-webkit-scrollbar-thumb { background: var(--color-border); border-radius: var(--radius-pill); }
.dock.collapsed .dock-body { display: none; }
.dock-foot { flex-shrink: 0; padding: var(--space-12) var(--foot-seite, var(--space-16)) var(--foot-unten, var(--space-16)); --button-width: 100%; }
/* quer: under the stage, fixed to the window, as high as it holds; Speichern in its head */
.dock.quer { top: auto; bottom: var(--space-window); left: var(--space-window); right: var(--dock-quer-rechts, calc(var(--inspector-width) + var(--space-8))); width: auto; transform: none; backdrop-filter: none; -webkit-backdrop-filter: none; }
.dock.quer .dock-header, .dock.quer .dock-header:active { cursor: default; }   /* it does not move */
.dock.quer .dock-header { --button-flex: none; --button-height: var(--size-control-small); --button-padding: 0 var(--space-20); --button-gap: var(--space-4); --button-icon: var(--size-icon-small); }
.dock.quer .dock-min { transform: none; }
.dock.quer.collapsed .dock-min { transform: rotate(180deg); }
.dock.quer > .dock-body { padding: var(--space-8) var(--space-panel); overflow-x: auto; overflow-y: hidden; }
.dock.quer > .dock-body[hidden] { display: none; }

/* A plain wrapper div used to show/hide a whole run of sections together
   (e.g. Static mode's Arrangement/Batch blocks) sits inside .dock-body but
   isn't itself a flex child of it — without its own gap, an <hr> and the
   h2 right after it end up flush against each other. */
.section-stack { display: flex; flex-direction: column; gap: var(--space-16); }
/* Without this, the [hidden] attribute is a no-op here — .section-stack's
   own display:flex (author stylesheet) always beats the UA stylesheet's
   [hidden]{display:none}, regardless of selector specificity, so a
   "hidden" section-stack stayed fully visible and interactive (e.g. HMI/
   HELIO Logo's Arrangement seed slider was still touchable in Animated
   mode, corrupting the in-flight cell-swap transition it wasn't meant to
   run during). */
.section-stack[hidden] { display: none; }



.dock h2 {
  margin: 0;
  /* Matches .dock-title's own size — see the comment there for the
     fs-sm / 1.1 derivation and the `0.13.5` bump from 11px to 13px. */
  font-size: var(--type-label);
  font-weight: var(--type-weight-medium);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--color-text);
}

.section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
/* ==== Icon button ========================================================================================
   Klassen: .icon-row > .icon-btn (Selected: [role=switch][aria-checked=true] oder [aria-pressed=true] ohne data-toggle)
   Tokens: --icon-button-*; ein Container setzt sie, nie die Klassen */
.icon-row { display: flex; gap: var(--icon-button-gap); }
.icon-btn {
  width: var(--icon-button-size);
  height: var(--icon-button-size);
  margin: var(--icon-button-margin, 0);
  align-self: var(--icon-button-align, auto);
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  border: none;
  border-radius: var(--icon-button-radius);
  background: transparent;
  color: var(--color-text);
  line-height: 1;
  cursor: pointer;
  transition: transform var(--motion-move) var(--motion-easing-spring), background var(--motion-hover) ease;
}
.icon-btn svg { width: var(--icon-button-icon); height: var(--icon-button-icon); flex-shrink: 0; }
.icon-btn:hover { background: var(--icon-button-bg-hover); }
.icon-btn:active { transform: scale(var(--icon-button-pressed-scale)); background: var(--icon-button-bg-pressed); }
.icon-btn:focus-visible { outline: var(--focus-width) solid var(--focus-color); outline-offset: 1px; }
.icon-btn:disabled { opacity: var(--icon-button-disabled-opacity); cursor: not-allowed; }
.icon-btn[aria-expanded="true"] { transform: rotate(180deg); }
.icon-btn[role="switch"][aria-checked="true"], .icon-btn[aria-pressed="true"]:not([data-toggle]) { background: var(--icon-button-selected-bg); color: var(--icon-button-selected-fg); }
/* Collapsible icon-selection grid (HMI Faces' eyes/mouth pools, HMI/HELIO
   Logo's square/wide icon pools) — a checkbox per icon, toggling whether
   the composition's random pick is allowed to use it. */

#orientBtn[aria-pressed="true"] { transform: rotate(90deg); }

.detail-group {
  display: flex;
  flex-direction: column;
  gap: var(--space-12);
  padding: var(--space-12);
  border: 1px solid var(--panel-border);
  /* Concentric with .dock's own r-2xl, R1 = R2 - D — but D (dock's
     border + .dock-body's 16px padding, ~17px) exceeds R2 (20px), so the
     "pure" concentric radius would be ~3px, reading as almost square.
     Floored at r-sm instead — see README's Radius nesting rule. */
  border-radius: var(--radius-small);
  background: var(--color-fill-1);
}
.detail-group[hidden] { display: none; }
/* Same reason: .field-row's display:flex would otherwise beat [hidden]. */
.field-row[hidden] { display: none; }
/* Concentric with .detail-group's own (now r-sm) radius — its 13px
   inset (border + --space-12 padding) exceeds even that, so this floors to
   r-sm as well rather than going negative. */
.detail-group { --button-radius: var(--radius-small); }

/* ==== Segmented control =================================================================================
   Klassen: .img-mode-row[role=group] > .mode-btn (.active = Selected) · Tokens: --segmented-* */
.img-mode-row {
  width: var(--segmented-width, auto);
  --r-in: var(--segmented-radius-in);
  --edge: var(--segmented-inset);
  display: flex;
  gap: var(--segmented-gap);
  padding: var(--edge);
  background: var(--segmented-track);
}
.mode-btn:not(.preset-btn) {
  flex: 1;
  min-height: calc(var(--segmented-height) - 2 * var(--edge));
  padding: var(--type-caps-nudge) var(--space-8) 0;
  font-size: var(--type-label);
  font-weight: var(--type-weight-medium);
  white-space: nowrap;
  border: none;
  border-radius: var(--r-in);
  background: transparent;
  color: var(--color-text);
  cursor: pointer;
  transition: background var(--motion-hover) ease, color var(--motion-hover) ease, transform var(--motion-move) var(--motion-easing-spring);
}
.mode-btn:not(.preset-btn) > svg { width: var(--size-icon); height: var(--size-icon); display: block; margin: 0 auto; }
.mode-btn:not(.preset-btn):hover { background: var(--segmented-bg-hover); }
.mode-btn:not(.preset-btn).active, .mode-btn:not(.preset-btn).active:hover { background: var(--segmented-selected-bg); color: var(--segmented-selected-fg); box-shadow: none; }
.mode-btn:not(.preset-btn):active { transform: scale(var(--segmented-pressed-scale)); }
.mode-btn:not(.preset-btn):focus-visible { outline: var(--focus-width) solid var(--focus-color); outline-offset: 1px; }
.mode-btn:not(.preset-btn).active:focus-visible { outline: var(--focus-width) solid var(--segmented-selected-fg); outline-offset: -5px; }   /* inside the fill: one shape */
.mode-btn:not(.preset-btn):disabled, .mode-btn:not(.preset-btn):disabled:hover { opacity: var(--segmented-disabled-opacity); cursor: not-allowed; background: none; transform: none; }

/* ==== Tabs ===============================================================================================
   Klassen: .tabs[role=tablist] > .tab[data-tab] (.active / aria-selected = Selected) · Tokens: --tabs-*
   Navigation, kein Wert: Wörter, der aktuelle unterstrichen, an der Kante der Reihe */
.tabs { display: flex; gap: var(--tabs-gap); margin: var(--tabs-margin, 0); padding: 0; box-shadow: inset 0 -1px var(--tabs-track); }
.tab {
  flex: none;
  min-width: var(--size-target);
  min-height: var(--size-control-small);
  padding: var(--space-8) 0;
  font-size: var(--type-label);
  font-weight: var(--type-weight-medium);
  white-space: nowrap;
  text-decoration: none;
  border: none;
  border-radius: 0;
  background: none;
  color: var(--color-text);
  cursor: pointer;
  transition: box-shadow var(--motion-hover) ease;
}
.tab:hover { box-shadow: inset 0 -2px var(--tabs-track); }
.tab.active, .tab[aria-selected="true"] { box-shadow: inset 0 -2px var(--tabs-selected); }
.tab:focus-visible { outline: var(--focus-width) solid var(--focus-color); outline-offset: 1px; }
.tab[hidden] { display: none; }

/* Scoped to the Theme row only — every other .mode-btn (Format, EC
   level, Module/Corner shape, ...) stays text-only. */
#themeRow .mode-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-4);
}
#themeRow .mode-btn svg { width: 12px; height: 12px; flex-shrink: 0; }

/* ==== Form field =========================================================================================
   Klassen: .field-row > .lbl (Name + Wert) + eine Komponente · .lbl bringt sein Layout selbst mit, in jedem Eltern-Element
   (Form field, Section head der Varianten-Zeile) · Tokens: --form-field-gap */
.field-row { display: flex; flex-direction: column; gap: var(--form-field-gap); }

/* ==== Section ============================================================================================
   Klassen: .section (section im Inspector, div im Panel) > h2 | .section-head + Zeilen (Form field, Toggle, Button …)
   Tokens: --section-row-gap zwischen den Zeilen, --section-head-gap zwischen Überschrift und erster Zeile */
.section { display: flex; flex-direction: column; gap: var(--section-row-gap); }
.section[hidden] { display: none; }
.section > :is(h2, .section-head) { margin-bottom: calc(var(--section-head-gap) - var(--section-row-gap)); }
.lbl {
  display: flex;
  justify-content: space-between;
  /* One step down from --type-label, not --type-label itself (`0.13.6`) — the dock's
     section captions (.dock-title/.dock h2, "THEME"/"MODE"/...) sit right
     above these field labels in the same panel and got bumped to 13px in
     `0.13.5`, which left barely any size gap to a 14px --type-label label
     directly underneath. --type-weight-regular (already set below) was already
     correct — this was purely a size-hierarchy fix. */
  font-size: var(--type-label);
  color: var(--color-text);
  font-variant-numeric: tabular-nums;
  /* Same role as .switch-row (an inline label paired with a control) —
     was implicitly the browser default (400) here while .switch-row set
     500 explicitly, the one real weight inconsistency found in an
     otherwise-consistent-by-role app. */
  font-weight: var(--type-weight-regular);
}
/* ==== Slider =============================================================================================
   Klassen: input[type=range] (.stufen) · Tokens: --slider-* · the fill up to the value as --pct (syncSliderFill) */
input[type="range"] {
  -webkit-appearance: none;
  width: 100%;
  height: var(--slider-height);   /* a 24 px target around a hairline track */
  margin: -4px 0;
  border-radius: var(--radius-pill);
  background: transparent;
  outline: none;
}
input[type="range"]::-webkit-slider-runnable-track { height: var(--slider-line); border-radius: 1px;
  background: linear-gradient(to right, var(--slider-fill) var(--pct, 0%), var(--slider-track) var(--pct, 0%)); }
input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: var(--slider-knob);
  height: var(--slider-knob);
  margin-top: calc((var(--slider-line) - var(--slider-knob)) / 2);   /* the knob's centre on the track's */
  border: none;
  border-radius: 50%;
  background: var(--slider-knob-bg);
  cursor: pointer;
  transition: transform var(--motion-move) var(--motion-easing-spring);
}
input[type="range"]:hover::-webkit-slider-thumb { transform: scale(var(--slider-hover-scale)); }
input[type="range"]:active::-webkit-slider-thumb { transform: scale(var(--slider-pressed-scale)); }
input[type="range"]:focus-visible::-webkit-slider-thumb { box-shadow: 0 0 0 2px var(--color-text-inverse), 0 0 0 4px var(--focus-color); }
input[type="range"]::-moz-range-track { height: var(--slider-line); border-radius: var(--radius-pill); background: var(--slider-track); }
input[type="range"]::-moz-range-progress { height: var(--slider-line); border-radius: var(--radius-pill); background: var(--slider-fill); }
input[type="range"]::-moz-range-thumb { width: var(--slider-knob); height: var(--slider-knob); border: none; border-radius: 50%; background: var(--slider-knob-bg); box-shadow: none; cursor: pointer; }
input[type="range"]:focus-visible::-moz-range-thumb { box-shadow: 0 0 0 2px var(--color-text-inverse), 0 0 0 4px var(--focus-color); }
input[type="range"]:disabled { opacity: var(--slider-disabled-opacity); }
input[type="range"]:disabled::-webkit-slider-thumb { cursor: not-allowed; }
input[type="range"].stufen { background: var(--stufen, none); }   /* Stufen: a dot above the line for each value (syncSliderFill) */

/* ==== Toggle =============================================================================================
   Klassen: .switch-row > span + button.switch[role=switch][aria-checked]
   Tokens: --toggle-* */
.switch-row { display: flex; align-items: center; justify-content: space-between; font-size: var(--type-label); font-weight: var(--type-weight-regular); letter-spacing: 0; }
.switch-row[hidden] { display: none; }
.switch {
  position: relative;
  width: var(--toggle-width);
  height: var(--toggle-height);
  flex-shrink: 0;
  border: none;
  border-radius: var(--toggle-radius);
  background: var(--toggle-track);
  box-shadow: var(--toggle-track-edge);
  cursor: pointer;
  transition: background var(--motion-hover) ease;
}
.switch::after {
  content: '';
  position: absolute;
  top: var(--toggle-inset);
  left: var(--toggle-inset);
  width: var(--toggle-knob-size);
  height: var(--toggle-knob-size);
  border-radius: 50%;
  background: var(--toggle-knob-off);   /* an object on the track, white in both modes */
  transition: transform var(--motion-move) var(--motion-easing-spring), width var(--motion-hover) ease, background var(--motion-hover) ease;
}
.switch:active::after { width: var(--toggle-knob-pressed); }
.switch[aria-checked="true"] { background: var(--toggle-track-on); }
.switch[aria-checked="true"]::after { background: var(--toggle-knob-on); transform: translateX(var(--toggle-travel)); }
.switch[aria-checked="true"]:active::after { transform: translateX(var(--toggle-travel-pressed)); }   /* the wider knob stays at the end */
.switch:focus-visible { outline: var(--focus-width) solid var(--focus-color); outline-offset: var(--focus-offset); }
.switch:disabled { opacity: var(--toggle-disabled-opacity); cursor: not-allowed; }

/* border-top, not a 1px background fill: a hairline background color
   inside a backdrop-filter:blur() ancestor (see .dock) renders reliably
   invisible in practice, even though it computes correctly — the header's
   border-bottom (same --color-border token) is the proof it's a paint-path issue,
   not a token/opacity one. */
.divider { height: 0; background: none; border: none; border-top: 1px solid var(--color-border); margin: 0; }

/* ==== Button =============================================================================================
   Klassen: .btn-row (.stack) > :is(button, a).action (.save = Primary, .recording = Busy) > svg + .btn-label
   Tokens: --button-* (core/tokens.css); a container sets them, never the classes */
.btn-row { display: flex; flex-wrap: wrap; gap: var(--space-element); margin-top: var(--space-4); }
.btn-row[hidden] { display: none; }
.btn-row.stack { flex-direction: column; }
:is(button, a).action {
  --bg: var(--button-secondary-bg); --fg: var(--button-secondary-fg);
  --bg-hover: var(--button-secondary-bg-hover); --fg-hover: var(--button-secondary-fg-hover);
  flex: var(--button-flex);
  width: var(--button-width);
  min-width: var(--button-min-width);
  min-height: var(--button-height);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--button-gap);
  padding: var(--button-padding);
  font-size: var(--button-font-size);
  font-weight: var(--button-font-weight);
  white-space: nowrap;
  text-decoration: none;
  border: none;
  border-radius: var(--button-radius);
  background: var(--bg);
  color: var(--fg);
  cursor: pointer;
  transition: background var(--motion-hover) ease, color var(--motion-hover) ease, transform var(--motion-move) var(--motion-easing-spring);
}
:is(button, a).action.save {
  --bg: var(--button-primary-bg); --fg: var(--button-primary-fg);
  --bg-hover: var(--button-primary-bg-hover); --fg-hover: var(--button-primary-fg-hover);
}
:is(button, a).action svg { width: var(--button-icon); height: var(--button-icon); flex-shrink: 0; }
:is(button, a).action:hover, :is(button, a).action.recording { background: var(--bg-hover); color: var(--fg-hover); }
:is(button, a).action:focus-visible { outline: var(--focus-width) solid var(--button-focus); outline-offset: var(--focus-offset); }
:is(button, a).action:active { transform: scale(var(--button-pressed-scale)); }
:is(button, a).action:disabled { opacity: var(--button-disabled-opacity); cursor: not-allowed; }
:is(button, a).action.recording:disabled { opacity: 1; }   /* Busy: disabled against a second click, not greyed out */
@keyframes recordingPulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.7; }
}

/* ==== Start card =========================================================================================
   Klassen: .start-card > h1 + p + .btn-row · Tokens: --start-card-* · what one sees before the first step (camera or
   photo), on the surface of the Modal; placed by the tool over its stage */
.start-card {
  --r-in: var(--radius-control);
  --edge: var(--space-16);
  position: fixed;
  z-index: 2;
  left: 0;
  top: 0;
  width: min(var(--start-card-width), calc(100vw - 2 * var(--space-16)));
  padding: var(--space-panel) var(--space-panel) var(--space-20);
  border: 1px solid var(--color-border-panel);
  border-radius: calc(var(--r-in) + var(--edge));
  background: var(--start-card-bg);
  backdrop-filter: var(--blur-surface);
  -webkit-backdrop-filter: var(--blur-surface);
  box-shadow: var(--elevation-panel);
  color: var(--color-text);
  text-align: left;
}
.start-card[hidden] { display: none; }
.start-card h1 { margin: 0 0 var(--space-8); font-size: var(--type-title); font-weight: var(--type-weight-bold); }
.start-card p { margin: 0 0 var(--space-16); font-size: var(--type-label); line-height: 1.45; }

/* ==== Toast ==============================================================================================
   Klassen: #toast.toast (.show, .mit-handlung, .mehrzeilig) · dockChrome.showToast(text), showNotice(text, actions) ·
   Tokens: --toast-* · anchored to the window's lower edge (100dvh where known: iOS' toolbar) */
.toast {
  position: fixed;
  z-index: 1000;   /* above every panel, however often one was brought forward */
  left: 50%;
  bottom: var(--toast-distance);
  transform: translate(-50%, var(--toast-travel));
  max-width: calc(100vw - 2 * var(--space-16));
  padding: var(--space-8) var(--space-16);
  border-radius: var(--toast-radius);
  background: var(--toast-bg);
  color: var(--toast-fg);
  font-size: var(--type-label);
  font-weight: var(--type-weight-medium);
  text-align: center;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--motion-move) ease, transform var(--motion-move) ease;
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }
@supports (top: 100dvh) {   /* bottom must be cleared, or the box stretches between top and bottom */
  .toast { bottom: auto; top: 100dvh; transform: translate(-50%, calc(-100% - var(--toast-distance) + var(--toast-travel))); }
  .toast.show { transform: translate(-50%, calc(-100% - var(--toast-distance))); }
}
/* with actions: it stays until the matter is solved, steps back while a Modal is open; one line: the pill, more: a container */
.toast.mit-handlung { display: flex; align-items: baseline; gap: var(--space-12); text-align: left; pointer-events: auto; }
.toast.mit-handlung.mehrzeilig { flex-wrap: wrap; --r-in: var(--radius-field); --edge: var(--space-8); border-radius: calc(var(--r-in) + var(--edge)); }
.toast.mit-handlung button { border: none; background: none; padding: 0; color: inherit; font: inherit; font-weight: var(--type-weight-medium); cursor: pointer; }
.toast.mit-handlung button:focus-visible { outline: var(--focus-width) solid var(--focus-color); outline-offset: var(--focus-offset); }
body:has(> .img-overlay.open, > dialog[open]) :is(.toast.mit-handlung, .stage-hint, .stage-tools, .abspielleiste) { visibility: hidden; }
body:has(.toast.mit-handlung.show) .stage-hint { opacity: 0; }
body:has(.toast.mit-handlung.show) #toast { bottom: calc(var(--toast-distance) + var(--size-control) + var(--space-8)); }   /* a passing toast above it */

@media (prefers-reduced-motion: reduce) {
  .switch::after, .toast, #field { transition: none; }
  :is(button, a).action:active, .icon-btn:active, .mode-btn:active, .switch:active { transform: none; }
  .icon-btn, .switch, :is(button, a).action, .mode-btn, input[type="range"]::-webkit-slider-thumb {
    transition-duration: 0.01s;
  }
  :is(button, a).action.recording { animation: none; }
}

/* ==== Select =============================================================================================
   Klassen: .select-wrap > select.select-input · Tokens: --select-* · the open list stays the system's own */
.select-wrap { position: relative; display: block; width: var(--select-width, auto); }
.select-wrap[hidden] { display: none; }
.select-wrap::after {   /* the Carbon chevron, drawn as a mask in the text colour */
  content: ''; position: absolute; right: var(--space-12); top: 50%; width: var(--select-chevron); height: var(--select-chevron); margin-top: calc(var(--select-chevron) / -2);
  background: var(--color-text); pointer-events: none;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath d='M16 22L6 12 7.4 10.6 16 19.2 24.6 10.6 26 12z'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Cpath d='M16 22L6 12 7.4 10.6 16 19.2 24.6 10.6 26 12z'/%3E%3C/svg%3E") center / contain no-repeat;
}
.select-input {
  appearance: none; -webkit-appearance: none;
  position: relative;
  width: 100%;
  min-height: var(--select-height);
  padding: var(--type-caps-nudge) var(--space-32) 0 var(--space-12);
  font-size: var(--type-label);
  font-weight: var(--type-weight-medium);
  border: none;
  border-radius: var(--select-radius);
  background: var(--select-bg);
  background-image: none;
  color: var(--color-text);
  transition: background var(--motion-hover) ease;
}
.select-input:hover { background: var(--select-bg-hover); }
.select-input:focus-visible { outline: var(--focus-width) solid var(--focus-color); outline-offset: 0; }

/* ==== Swatches ===========================================================================================
   Klassen: .presets[role=group] > .preset-btn (.selected / .active = Selected; .save = Hinzufügen) > .rm ·
   .preset-save-row · Tokens: --swatch-* · the colour is content: set by the tool (pairSwatch, gradientSwatch).
   A swatch row that behaves like a segment row carries .mode-btn for wireModeRow only – it takes no segment style */
.presets { display: flex; flex-wrap: wrap; gap: var(--swatch-gap); }
.preset-btn {
  position: relative;
  flex: none;
  width: var(--swatch-size);
  height: var(--swatch-size);
  padding: 0;
  border: none;
  border-radius: 50%;
  box-shadow: var(--swatch-edge);
  cursor: pointer;
  transition: transform var(--motion-move) var(--motion-easing-spring), box-shadow var(--motion-move) var(--motion-easing);
}
.preset-btn:hover { transform: scale(var(--swatch-hover-scale)); }
.preset-btn:active { transform: scale(var(--swatch-pressed-scale)); }
.preset-btn:focus-visible { outline: var(--focus-width) solid var(--focus-color); outline-offset: 4px; }
/* Selected: a ring with a real gap; a white swatch keeps a dark edge in the dark */
.preset-btn.selected, .preset-btn.active { outline: var(--focus-width) solid var(--swatch-ring); outline-offset: var(--swatch-ring-gap); box-shadow: var(--swatch-edge-selected); }
.preset-btn[data-colour="white-red"], .preset-btn[data-colour="white-black"] { box-shadow: none; }
.preset-btn[data-colour="white-red"]:is(.selected, .active), .preset-btn[data-colour="white-black"]:is(.selected, .active) { box-shadow: var(--swatch-edge-dark); }
.preset-btn.save { display: flex; align-items: center; justify-content: center; border: 1.5px dashed var(--color-text); background: transparent; color: var(--color-text); font-size: var(--type-section); }
.preset-btn .rm {   /* remove an own template: shown on hover, focus and when chosen */
  position: absolute; top: -6px; right: -6px;
  width: 15px; height: 15px;
  display: flex; align-items: center; justify-content: center;
  padding: 0; border: none; border-radius: 50%;
  background: var(--color-text); color: var(--color-text-inverse);
  font-size: var(--type-label); line-height: 15px;
  cursor: pointer; opacity: 0;
  transition: opacity var(--motion-hover) ease;
}
.preset-btn .rm::before { content: ''; position: absolute; inset: -4px; }   /* a 24 px target */
.preset-btn:hover .rm, .preset-btn:focus-within .rm, .preset-btn.selected .rm { opacity: 1; }
.preset-save-row { display: flex; gap: var(--space-8); }
.preset-save-row input[type="text"] { flex: 1; min-width: 0; font-size: var(--type-label); padding: var(--space-8); border-radius: var(--radius-field); border: 1px solid var(--color-border-panel); background: transparent; color: var(--color-text); }
.preset-save-row input[type="text"]:focus-visible { outline: var(--focus-width) solid var(--focus-color); outline-offset: 1px; }
.preset-save-row button { font-size: var(--type-label); font-weight: var(--type-weight-medium); padding: 0 var(--space-12); border: none; border-radius: var(--radius-field); background: var(--color-text); color: var(--color-text-inverse); cursor: pointer; }
/* Swatches, variant editable: .chips > button.chip (.sel) > .rm · .bg-swatch – pick, drag to reorder, remove (×), add
   (Icon button). The same size, edge and remove mark as the swatches above; the colour is content (data-fill) */
.chips { display: flex; flex-wrap: wrap; gap: var(--swatch-gap); }
.chip, .bg-swatch {
  position: relative;
  flex-shrink: 0;
  width: var(--swatch-size);
  height: var(--swatch-size);
  padding: 0;
  border: none;
  border-radius: 50%;
  box-shadow: var(--swatch-edit-edge);   /* a white field on the light panel needs its edge */
}
.chip { cursor: grab; touch-action: none; transition: transform var(--motion-press) ease, opacity var(--motion-press) ease, outline var(--motion-press) ease; }
.bg-swatch { cursor: pointer; }
.chip:active { transform: scale(var(--swatch-drag-scale)); opacity: 0.85; }
.chip:focus-visible, .bg-swatch:focus-visible { outline: var(--focus-width) solid var(--focus-color); outline-offset: var(--focus-offset); }
.chip.chip-dragging { cursor: grabbing; z-index: 10; box-shadow: var(--elevation-lifted); pointer-events: none; }
.chip.chip-drop-target { outline: var(--focus-width) dashed var(--color-text); outline-offset: 3px; }
.chip .rm {
  position: absolute; top: -6px; right: -6px;
  width: var(--swatch-remove); height: var(--swatch-remove);
  display: flex; align-items: center; justify-content: center;
  padding: 0; border: none; border-radius: 50%;
  background: var(--color-text); color: var(--color-text-inverse);
  box-shadow: 0 0 0 1.5px var(--color-text-inverse);   /* the × stays visible on a field of its own colour */
  font-size: var(--type-label); line-height: var(--swatch-remove);
  cursor: pointer; opacity: 0;
  transition: opacity var(--motion-hover) ease;
}
.chip .rm::before { content: ''; position: absolute; inset: -4px; }   /* a 24 px target */
.chip:hover .rm, .chip:focus-within .rm { opacity: 1; }
.rm > svg { width: 10px; height: 10px; display: block; flex: none; }
@media (prefers-reduced-motion: reduce) { .chip .rm { transition: none; } .chip:active { transform: none; } }


/* ==== Text input =========================================================================================
   Klassen: .text-input (input | textarea, .grow-text) · .num-field > .text-input + .unit · .smart-text · Tokens: --text-input-* */
.text-input {
  box-sizing: border-box;
  width: var(--text-input-width, 100%);
  margin: var(--text-input-margin, 0);
  min-height: var(--text-input-height);
  padding: var(--type-caps-nudge) var(--space-12) 0;
  font-size: var(--type-label);
  font-weight: var(--type-weight-regular);
  line-height: 1.35;
  border: none;
  border-radius: var(--text-input-radius);
  background: var(--text-input-bg);
  color: var(--color-text);
  user-select: text;
  -webkit-user-select: text;
  transition: background var(--motion-hover) ease;
}
.text-input:hover { background: var(--text-input-bg-hover); }
.text-input:focus-visible { outline: var(--focus-width) solid var(--focus-color); outline-offset: 0; }
textarea.text-input { resize: vertical; min-height: var(--text-input-area-height); display: block; padding: var(--space-8) var(--space-12); }   /* several lines: an even edge */
textarea.grow-text { resize: none; overflow: hidden; min-height: 0; }   /* grows with what is typed, never scrolls */
.num-field { position: relative; }
.num-field .text-input { padding-right: var(--space-32); font-feature-settings: 'tnum'; }
.num-field .unit { position: absolute; right: var(--text-input-unit-right); top: 50%; transform: translateY(-50%); pointer-events: none; font-size: var(--type-label); }

/* Choice popover: a short list of options opened by a button (e.g. Save PNG → size).
   Anchored above the button, closes on a pick, Escape or a click elsewhere. */
.choice-pop {
  position: fixed;
  z-index: 1001;
  min-width: 200px;
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: 2px;
  background: var(--color-surface-raised);
  border: 1px solid var(--panel-border);
  box-shadow: var(--elevation-panel);
}
.choice-pop .choice-title {
  font-size: var(--type-label);
  color: var(--color-text);
  padding: var(--space-4) var(--space-8);
}
.choice-btn {
  display: flex;
  justify-content: space-between;
  gap: var(--space-12);
  font-family: var(--type-family);
  font-size: var(--type-label);
  font-weight: var(--type-weight-medium);
  text-align: left;
  padding: var(--space-8) var(--space-8);
  border: none;
  border-radius: calc(var(--radius-control) - var(--space-4));
  background: transparent;
  color: var(--color-text);
  cursor: pointer;
}
.choice-btn span:last-child { color: var(--color-text); font-weight: var(--type-weight-regular); font-variant-numeric: tabular-nums; }
.choice-btn:hover { background: var(--color-fill-2); }
.choice-btn:focus-visible { outline: 3px solid var(--color-focus); outline-offset: -1px; }

/* UI layer: Inter, monochrome and flat, no grey text, hierarchy from size, weight and space,
   spacing after the law of proximity (developed in the lab, THA Designtools/prototypes/dock-labor). */

/* ---- Bühne (patterns/: Bühne) ---------------------------------------------------
   The result on the ground (--color-surface-page): 10 px corners, one hairline, the soft drop — set by stageFrame() in
   core/ui.js, never by a tool's own styles. Frei (no format): the result is the whole ground, no frame. */
.buehne { border: 0; border-radius: var(--radius-field); box-shadow: var(--elevation-canvas); }
.buehne.frei { border-radius: 0; box-shadow: none; }
/* Bühne, wählbar (0.9.29): a stage one chooses is a button; the chosen one in the blue of editing (block Marken auf der Bühne) */
button.buehne { display: block; padding: 0; background: none; cursor: pointer; }
button.buehne > canvas { display: block; border-radius: inherit; }
.buehne[aria-pressed="true"] { outline: 2px solid var(--color-edit); outline-offset: 3px; }
button.buehne:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 3px; }

/* ---- Base ------------------------------------------------------------------ */
html, body,
.mode-btn, :is(button, a).action, .select-input, .text-input, .choice-btn,
.preset-save-row input[type="text"], .preset-save-row button {
  font-family: var(--type-family);
  font-feature-settings: 'cv11', 'ss03';
  -webkit-font-smoothing: antialiased;
}



/* Whitespace separates sections; the line goes. */
hr.divider, .divider { display: none; }

/* ---- Type hierarchy -------------------------------------------------------- */
.dock h2 {
  font-size: var(--type-section);
  font-weight: var(--type-weight-bold);
  letter-spacing: -0.005em;
  text-transform: none;
}
/* Spacing follows the law of proximity (user, 22.10.2026): what belongs together sits at most
   half as far apart as what does not. Three steps, measured from the visible edges:
   label → its control ~12 px · item → item ~28 px · section → section ~40 px.
   (Before, one 10 px gap did all three: label and slider were exactly as far apart
   as the slider and the next label, 20 : 20.) */
.lbl {
  font-size: var(--type-label);
  font-weight: var(--type-weight-regular);
  letter-spacing: 0;
}
/* The value: same ink, a step heavier, figures of equal width. */
.lbl span + span {
  font-weight: var(--type-weight-medium);
  font-feature-settings: 'tnum', 'cv11';
}
/* A head as tall as its title: its icon button hangs over above and below and takes no room, so a title with a button
   has the same air above and below as one without (user, 01.11.2026: „der abstand modulation sieht aber falsch aus“ –
   gemessen: 40 + 5,5 px über „Modulation“, 12 + 5,5 px darunter) */
.section-head { --icon-button-margin: calc(var(--icon-button-size) / -2) 0; }

#randomBtn:active svg { transform: rotate(90deg); }
#randomBtn svg { transition: transform var(--motion-move) var(--motion-easing-spring); }

/* ---- Dependent group: material, not a box ---------------------------------- */
.detail-group {
  border: none;
  background: var(--color-fill-1);
  border-radius: var(--radius-control);
  padding: var(--space-12);
  gap: var(--space-22);
}







/* ---- Popover and toast ----------------------------------------------------- */
.choice-pop { border: none; background: var(--panel-bg); backdrop-filter: blur(28px) saturate(180%); -webkit-backdrop-filter: blur(28px) saturate(180%); }
.choice-pop .choice-title { color: var(--color-text); font-weight: var(--type-weight-bold); }
.choice-btn { font-size: var(--type-label); border-radius: var(--radius-field); }
.choice-btn span:last-child { color: var(--color-text); font-feature-settings: 'tnum'; }
.choice-btn:hover { background: var(--color-fill-1); }

@media (prefers-reduced-motion: reduce) {
  .switch::after, .mode-btn, :is(button, a).action, .icon-btn, .preset-btn, input[type="range"]::-webkit-slider-thumb { transition-duration: 0.01s; }
}

/* ---- Skeleton (from the IA lab) ---- */
/* Stage: points are placed and dragged on the canvas itself. */

.stage-tools { position: fixed; left: var(--space-16); bottom: var(--space-16); z-index: 2; display: flex; gap: var(--space-8); }
.stage-chip { width: var(--size-control); height: var(--size-control); border-radius: 50%; border: none; display: flex; align-items: center; justify-content: center;
  background: var(--panel-bg); color: var(--color-text); backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px); box-shadow: var(--elevation-panel); cursor: pointer; }
.stage-chip svg { width: var(--size-16); height: var(--size-16); }
.stage-tools[hidden] { display: none; }
.stage-chip[aria-checked="true"] { background: var(--color-text); color: var(--color-text-inverse); }
.stage-chip:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }
.stage-chip.wert { width: auto; min-width: var(--size-control); padding: 0 var(--space-12); border-radius: var(--radius-pill); font-size: var(--type-label); font-variant-numeric: tabular-nums; }   /* a chip with its value (Zoom „150 %“); a click opens its choices (0.9.27) */
/* Vollbild (initStageFull): the panels go, the stage takes the screen; only the button to come back stays */
body.stage-full .dock, body.stage-full .inspector, body.stage-full .stage-hint, body.stage-full .stage-options { display: none !important; }
body.stage-full .stage-tools > :not(.stage-full-btn) { display: none; }
body.stage-full .stage-tools[hidden] { display: flex; }
body.stage-full .film { right: 0; }   /* the Motion Composer: the film takes the whole window */
body.stage-full .film-stage { padding-bottom: var(--space-16); }
body.stage-full .film-stage > .icon-row { opacity: 0; transition: opacity var(--motion-move); }
body.stage-full .film-stage:hover > .icon-row { opacity: 1; }
.stage-hint { position: fixed; left: 50%; bottom: var(--space-20); transform: translateX(-50%); z-index: 2; pointer-events: none;
  font-size: var(--type-label); padding: var(--space-8) var(--space-12); color: var(--color-text); transition: opacity var(--motion-enter) ease;
  max-width: calc(100vw - 2 * (4 * var(--size-control) + 5 * var(--space-8))); text-align: center; text-wrap: balance; }
/* never under the stage chips at the bottom left: it keeps their room on both sides, wraps in a narrow window and goes in a
   very narrow one (user, 28.10.2026: „achtung schmale fenster“) */
@media (max-width: 760px) { .stage-hint { display: none; } }
@media (max-width: 1100px) { body.inspecting .stage-hint { display: none; } }
/* the hint is text on the ground, never a framed pill: a frame reads as an unfilled button (user, 28.10.2026: „commands mit
   outline-rahmen verboten (wie ungefüllter button)“) */
.stage-hint.gone { opacity: 0; }
/* Inspektor (Advanced): docked at the right edge, like the inspector in Apple's apps and Safari's Web Inspector;
   unlocked in the settings. The dock moves to its left, so tools stay on one side and the stage stays free. */
/* Layers: the inspector belongs to the ground (with the stage), flat and opaque, behind the floating dock —
   expert settings recede instead of floating in front (user, 22.10.2026). Same tone as the page around the
   stage, no shadow, no blur, no line: the ground simply continues. */
.inspector { position: fixed; right: 0; top: 0; bottom: 0; width: var(--inspector-width); z-index: 2; display: flex; flex-direction: column;
  background: var(--color-surface-page); }   /* the ground in every tool and at every format (user, 24.10.2026) — it was --color-text-inverse unless the format was fixed */
.inspector[hidden] { display: none; }
@media (max-width: 560px) {   /* a phone (user, 28.10.2026: „Sheet von unten“): a sheet from the lower edge over the panel, the stage stays visible above */
  .inspector { top: auto; left: 0; width: auto; height: var(--inspector-sheet-height); z-index: 4;
    border-radius: var(--radius-surface) var(--radius-surface) 0 0; box-shadow: var(--elevation-panel); }
  body.inspecting { --toast-distance: calc(var(--inspector-sheet-height) + var(--space-16)); }   /* a toast above the sheet */
}
.insp-head { display: flex; align-items: center; gap: var(--space-8); padding: var(--space-16) var(--space-12) var(--space-8) var(--space-22); }
.insp-title { font-size: var(--type-title); font-weight: var(--type-weight-bold); letter-spacing: -0.01em; }   /* the role Titel, as the dock's (atom Schrift; it was a fixed 15 px) */
.inspector { --tabs-margin: 0 var(--space-panel) var(--space-8); }
.insp-sel { flex: 1; font: 11px/1.3 var(--type-family-mono); min-width: 0; }
/* Blue = what is being edited on the stage (handles, guides, labels there). The inspector's name of the
   selected object takes the same blue, so the eye ties the two together (user, 22.10.2026). Only for
   references to an object on the stage — the readouts (Werte) stay in ink. In dark mode a lighter blue:
   the canvas blue would read 3.7 : 1 on the dark panel (tokens --color-edit, --color-mark). */
.insp-sel.is-sel { color: var(--color-edit); }
/* The tabs jump to a section: navigation, not a choice (user, 22.10.2026: they looked like a segment
   row, i.e. a setting). So they look like an index: plain words, the current one underlined. */
/* Tabs show where one is (state), links lead somewhere (action) — they must not look alike
   (user, 22.10.2026). A link is a thin underline hugging the word; the tab bar is a track along the
   row with a bar under the current tab, at the row's edge, never under the text itself. */
.insp-body { flex: 1; overflow-y: auto; padding: var(--space-12) var(--space-22) var(--space-40); display: flex; flex-direction: column; gap: var(--space-40);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, black 14px, black calc(100% - 20px), transparent 100%);
  mask-image: linear-gradient(to bottom, transparent 0, black 14px, black calc(100% - 20px), transparent 100%); }
.section h2.sub { margin-top: var(--space-8); }   /* Teil der Section, in Panel und Inspector gleich */
.insp-body section { scroll-margin-top: 8px; transition: background var(--motion-flash) ease; border-radius: var(--radius-control); }
.insp-body section.flash { background: var(--color-fill-1); }
/* one column for the names in every list of the Werte – the values of the Version and of the settings stand under each other
   (user, 28.10.2026: „kamera: typo verstoss styleguide“) */
/* Werte in the type of the Kennwerte – one type for „Name, Wert“ in the inspector, no monospace (user, 27.10.2026: „warum sind da
   oben andere schriften?? > pattern lib“ – „ja“) */
.insp-values { margin: 0; display: grid; grid-template-columns: minmax(0, var(--dl-term-share)) 1fr; gap: var(--dl-gap); font-size: var(--type-label); line-height: 1.3; }
.insp-values dt { font-weight: var(--type-weight-regular); }
.insp-values dd { margin: 0; font-weight: var(--type-weight-medium); font-variant-numeric: tabular-nums; overflow-wrap: anywhere; }
body.inspecting .stage-hint { left: calc(50% - 170px); max-width: calc(100vw - var(--size-340) - 2 * (4 * var(--size-control) + 5 * var(--space-8))); }
.inspector h2 { margin: 0; font-size: var(--type-section, 13px); font-weight: 600; letter-spacing: -0.005em; }
/* Abschnitt und Gruppe (block Abschnitt): the heading of a section is the same wherever the section stands – dock,
   inspector, pattern library (user, 25.10.2026: the block must work as itself, not only inside a dock) */
:where(.section, .section > .section-head) > h2 { margin: 0;   /* lowest weight: the dock, inspector and partitur keep their own spacing */ font-size: var(--type-section); font-weight: var(--type-weight-bold); letter-spacing: -0.005em; }
/* Link underline, one look everywhere: thin, 1 px under the baseline, broken at descenders.
   Browsers do not agree on breaking it (Safari ran it through the g even with skip-ink), so the core
   does it: initLinkUnderlines() wraps the text in runs; only runs without descenders are underlined. */
body.inspecting .dock h2[data-insp]:not(.no-sec), .link-u { cursor: pointer; text-decoration: none; }   /* .no-sec: eine Überschrift ohne Abschnitt im Inspector */
body.inspecting .dock h2[data-insp]:not(.no-sec) .lu, .link-u .lu { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 1px; text-decoration-skip-ink: none; }
/* heading → its control 10 px, not 6: room for the underline of a jump heading (user, 22.10.2026) */
.dock h2 { margin-bottom: var(--space-4); }
/* ==== Number input =======================================================================================
   Klassen: .stepper[data-for] > .step-btn + .step-val + .step-btn; initSteppers() · Tokens: --number-input-* */
.stepper { display: flex; align-items: center; gap: var(--number-input-gap); }
.step-btn {
  width: var(--number-input-button); height: var(--number-input-button);
  display: flex; align-items: center; justify-content: center;
  padding: 0 0 1.8px;   /* − and + of Inter sit 0.9 px low (measured): lifted onto the middle */
  border: none; border-radius: 50%;
  background: var(--number-input-bg); color: var(--color-text);
  font: var(--type-weight-medium) var(--number-input-glyph)/1 var(--type-family);
  cursor: pointer;
  transition: background var(--motion-hover) ease, transform var(--motion-move) ease;
}
.step-btn:hover { background: var(--number-input-bg-hover); }
.step-btn:active { transform: scale(var(--number-input-pressed-scale)); }
.step-btn:focus-visible { outline: var(--focus-width) solid var(--focus-color); outline-offset: var(--focus-offset); }
.step-val { min-width: var(--number-input-value-width); text-align: center; font-size: var(--type-label); font-weight: var(--type-weight-medium); font-feature-settings: 'tnum'; }
/* Probe: settings dialog — centred, modal, the page dims behind it (Figur und Grund). */
.settings { padding: 0; width: min(var(--modal-width), calc(100vw - 32px)); color: var(--color-text); font-family: var(--type-family, system-ui);
  /* the same surface as the dock (user, 23.10.2026: "das einstellungsfenster ist nicht so richtig in unserem
     designsystem"): panel ground, its hairline, its radius, its blur and shadow */
  background: var(--panel-bg); border: 1px solid var(--panel-border);
  backdrop-filter: var(--blur-surface); -webkit-backdrop-filter: var(--blur-surface); box-shadow: var(--elevation-panel); }
.settings:focus { outline: none; }
/* a dialog stands from the top: it grows downwards when a format shows its fields, its rows above never jump (user, 28.10.2026:
   „umschalten beim speichern: die vertikale neuausrichtung ist unpraktisch, da die tableiste springt“) */
.settings { margin: max(var(--space-24), 10vh) auto auto; }
.img-overlay { align-items: flex-start; padding-top: max(var(--space-24), 10vh); }
.img-modal { max-height: calc(100vh - 2 * max(var(--size-24), 10vh)); }   /* the whole dialog in the window, its foot with the same edge as Speichern */
.settings::backdrop { background: var(--color-scrim); backdrop-filter: blur(2px); }
.settings-body { padding: var(--edge) var(--edge) var(--space-8); display: flex; flex-direction: column; gap: var(--space-22); }
.settings-list { display: flex; flex-direction: column; gap: var(--space-22); }   /* the settings renderSettings writes, as far apart as the body's parts */
.settings h2 { margin: 0 0 2px; font-size: var(--type-title); font-weight: var(--type-weight-bold); letter-spacing: -0.01em; text-transform: none; }   /* the role Titel (atom Schrift; it was +4 px) */
.settings .switch-row > span { display: flex; flex-direction: column; gap: var(--space-4); font-size: var(--type-label); }
.settings small { font-size: var(--type-label); line-height: 1.3; }
.settings-foot { display: flex; gap: var(--space-8); padding: var(--space-12) var(--edge) var(--edge); }

/* Symbols: IBM Carbon, 18 px in 28 px buttons (decided 22.10.2026). Buttons have no padding: the
   browser's default padding squeezed every symbol in a 28 px button to 16 px. */
.stage-chip svg { width: var(--size-18); height: var(--size-18); flex-shrink: 0; }
/* Hoch/Quer shows the current orientation */
#orientBtn .ic-landscape { display: none; }
#orientBtn[aria-pressed="false"] .ic-portrait { display: none; }
#orientBtn[aria-pressed="false"] .ic-landscape { display: block; }
#orientBtn[aria-pressed="true"] { transform: none; }


/* The tool's name leads back to the overview (dashboard), where the settings are (user, 22.10.2026). */

/* Options of a chosen object on the stage (patterns: Marken auf der Bühne): beside the object, a row of choices and Löschen. */
.stage-options { position: fixed; z-index: 1200; display: flex; gap: var(--space-4); padding: var(--edge); background: var(--panel-bg); box-shadow: var(--elevation-panel);
  backdrop-filter: var(--blur-surface); -webkit-backdrop-filter: var(--blur-surface); }
.stage-options > button { min-width: 44px; height: 44px; padding: 0 var(--space-12); border: none; border-radius: var(--radius-field); background: var(--color-fill-1); color: var(--color-text);
  font: var(--type-weight-medium) var(--type-label) var(--type-family); cursor: pointer; display: flex; align-items: center; justify-content: center; }
.stage-options > button:hover { background: var(--color-fill-2); }
.stage-options > button.on { background: var(--color-text); color: var(--color-text-inverse); }
.stage-options > button:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 1px; }
.stage-options > button svg { height: 26px; width: auto; display: block; }   /* only the bar's own buttons: a control of the core in it (Stepper, Schalter) keeps its own look (user, 25.10.2026: „das können wir so nicht lassen“) */

/* ==== Chip group =========================================================================================
   Klassen: .pill-stack > button.pill (.sel = Selected, .special) · Tokens: --chip-* · an object: click chooses it,
   Cmd+C / Cmd+V copy and paste it. A container sets --chip-direction, --chip-height, --chip-stack-margin */
.pill-stack { display: flex; flex-direction: var(--chip-direction, column); flex-wrap: wrap; align-items: flex-start; gap: var(--chip-stack-gap, var(--space-4)); margin: var(--chip-stack-margin, 0); }
.pill {
  position: relative;
  display: inline-flex;
  align-items: center;
  max-width: 100%;
  min-height: var(--chip-height);
  padding: 0 var(--space-8);
  border: none;
  border-radius: var(--chip-radius);
  background: var(--chip-bg);
  color: var(--color-text);
  font: var(--type-weight-medium) var(--type-label)/1.1 var(--type-family);
  text-align: left;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  cursor: pointer;
}
.pill::after { content: ""; position: absolute; inset: calc((var(--chip-height) - var(--size-target)) / 2) 0; }   /* always a 24 px target */
.pill:hover { background: var(--chip-bg-hover); }
.pill.sel { background: var(--chip-selected-bg); color: var(--chip-selected-fg); }
.pill.special { background: transparent; box-shadow: inset 0 0 0 1px var(--color-text); }
.pill:focus-visible { outline: var(--focus-width) solid var(--focus-color); outline-offset: var(--focus-offset); }

/* ==== Description list ===================================================================================
   Klassen: dl.readouts (Werte, Zahlen untereinander) · dl.insp-values (Werte im Inspector) · dl.facts (Steckbrief) > dt + dd ·
   Tokens: --dl-* */
.readouts { display: grid; grid-template-columns: max-content 1fr; gap: var(--dl-gap); margin: 0; font-size: var(--type-label); line-height: 1.3; }
.readouts dt { font-weight: var(--type-weight-regular); }
.readouts dd { margin: 0; font-weight: var(--type-weight-medium); font-variant-numeric: tabular-nums; }

/* [hidden] always hides (22.10.2026). An author rule's display:flex beats the UA's [hidden], which hid
   nothing several times (select-wrap, the dashboard's reset); one rule instead of one per class. */
[hidden] { display: none !important; }

/* ==== Tile group =========================================================================================
   Klassen: .icon-tiles | .style-tiles > label.icon-tile | .style-tile > input + img | svg (svg.dir) · Tokens: --tile-*
   each choice shown as itself; chosen = a ring inside its edge */
.icon-tiles, .style-tiles { display: flex; flex-wrap: wrap; gap: var(--tile-gap); }
.icon-tile, .style-tile {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-4);
  flex: none;
  height: var(--tile-height);
  padding: 0 var(--space-8);
  border-radius: var(--tile-radius);
  background: transparent;
  color: var(--color-text);
  cursor: pointer;
  transition: background var(--motion-hover) ease, transform var(--motion-move) var(--motion-easing-spring);
}
.icon-tile:hover, .style-tile:hover { background: var(--tile-bg-hover); }
.icon-tile:active, .style-tile:active { transform: scale(var(--tile-pressed-scale)); }
.icon-tile input, .style-tile input { position: absolute; inset: 0; margin: 0; opacity: 0; cursor: pointer; }
.icon-tile img, .style-tile svg { height: var(--tile-content); width: auto; max-width: none; pointer-events: none; }
.icon-tile img { filter: var(--art-filter); }   /* black artwork, light on the dark ground */
.style-tile svg.dir { width: 10px; height: 10px; align-self: flex-end; margin-bottom: var(--space-8); }   /* what tells two alike apart */
.icon-tile:has(input:checked), .style-tile:has(input:checked) { box-shadow: inset 0 0 0 2px var(--tile-selected); }
.icon-tile:has(input:focus-visible), .style-tile:has(input:focus-visible) { outline: var(--focus-width) solid var(--focus-color); outline-offset: var(--focus-offset); }
/* Block „Zonen“ (patterns/blocks.js; user, 23.10.2026: approved from the Keyvisual probe winkelzonen) — one range
   cut into zones by draggable bounds, each zone named by its look. From Keyvisual: */
/* Probe: angle zones — one scale 0–180°, three boundaries, four zones (rund · Knick · rund · Spitz).
   Drawn like a THA Tools bar (user, 22.10.2026): square, flat, boundaries as thin reference strokes
   labelled directly with their value, Spitz in the THA Tools hatch (6 px tile, 0.7 px lines). */
/* the hatch is a token (--hatch, core/tokens.css) */
.zones { position: relative; height: 34px; touch-action: none; cursor: pointer; }
.zone-track { position: absolute; left: 0; right: 0; top: var(--space-16); height: 12px; display: flex; }
.zone { display: block; height: 100%; }
.z-rund { background: var(--color-fill-2); }
.z-knick { background: var(--color-text); }
.z-spitz { background: var(--hatch); }
.zone-thumb { position: absolute; top: 0; width: var(--size-24); height: 34px; margin-left: -12px; padding: 0; border: none; background: none; cursor: ew-resize; color: var(--color-text); }
.zone-thumb::after { content: ''; position: absolute; left: 11px; top: 13px; width: 2px; height: var(--size-18); background: var(--color-text); box-shadow: 0 0 0 1.5px var(--panel-bg); }
.zone-thumb .zv { position: absolute; left: 50%; top: 0; transform: translateX(-50%); font: 500 11px/1 var(--type-family, system-ui); font-feature-settings: 'tnum'; white-space: nowrap; }
.zone-thumb:hover::after, .zone-thumb.active::after { width: 3px; left: 10.5px; }
.zone-thumb:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 0; }
.zone-labels { position: relative; height: 14px; margin-top: 2px; font-size: var(--type-label); }
.zone-labels span { position: absolute; transform: translateX(-50%); white-space: nowrap; }
.zone-presets { display: flex; gap: var(--space-12); }
.zone-preset { display: inline-flex; align-items: center; min-height: var(--size-24); border: none; background: none; padding: 0; font: inherit; color: var(--color-text); cursor: pointer; }   /* underline: .link-u (core); a 24 px target (QS 3 §3.3) */
.zone-preset:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }
/* Block „Seed-Zeile“ (patterns/blocks.js; user, 24.10.2026): name and value on one line, „Neuer Seed“ after them,
   the slider below — the same in every tool with a seed (it was a style of its own in seven). */
.seed-head .lbl { flex: 1; margin-right: var(--space-12); }
/* Block „Textfeld“, the field that is always whole (from Keyvisual, approved 22.10.2026): it grows with its text,
   in capitals as the band sets it; words that find no straight are marked with a drawn wave in a mirror layer. */
.smart-text { position: relative; }
.smart-text .text-input, .st-mirror { font: 500 var(--type-label)/1.45 var(--type-family, system-ui); letter-spacing: 0.02em; text-transform: uppercase;
  padding: var(--space-8) var(--space-12); white-space: pre-wrap; overflow-wrap: break-word; border-radius: var(--radius-field); }
.smart-text .text-input { position: relative; display: block; width: 100%; resize: none; overflow: hidden; background: transparent; min-height: 0; }
.st-mirror { position: absolute; inset: 0; color: transparent; background: var(--color-fill-1); pointer-events: none; }
.st-mirror mark { color: transparent; background: none; position: relative; }
/* The wave is drawn, not a wavy text decoration: the browser flattens that as it gets thicker
   (user, 22.10.2026). 1.5 px line, 3 px high, 8 px period; in the ink colour through a mask. */
.st-mirror mark::after { content: ''; position: absolute; left: 0; right: 0; bottom: -0.18em; height: 4px; background: var(--color-text);
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='4'%3E%3Cpath d='M0 2 Q2 0 4 2 T8 2' fill='none' stroke='black' stroke-width='1.5'/%3E%3C/svg%3E") repeat-x 0 0 / 8px 4px;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='8' height='4'%3E%3Cpath d='M0 2 Q2 0 4 2 T8 2' fill='none' stroke='black' stroke-width='1.5'/%3E%3C/svg%3E") repeat-x 0 0 / 8px 4px; }
.inspector .detail-group { background: none; padding: 0; }   /* in the inspector a detail group lies on the ground like its section (Keyvisual animiert) */
/* Block „Inspektor“ (approved 24.10.2026): the choice's name in the head shortens, never pushes the actions out;
   without a dock (Case Film) Speichern is the inspector's foot, in line with its body */
.insp-sel { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.insp-sel a { color: inherit; text-decoration: none; }
.inspector { --foot-seite: var(--space-panel); --foot-unten: var(--space-20); }
/* Block „Verhalten“ (Feldzeile, approved 24.10.2026, from the Case Film): only what is active stands there — its
   name, its value, Entfernen as a symbol beside it, its settings under it; Besonderes (beyond the rules) framed like
   its pill; the pills stand under their object and over the inspector as an overview */
.beh-row > .lbl, .beh-row.section-head { align-items: center; }
.beh-row .lbl .val { margin-left: auto; margin-right: var(--space-8); }
.beh-row { --icon-button-margin: calc(-1 * var(--space-8)) calc(-1 * var(--space-8)) calc(-1 * var(--space-8)) 0; }
.beh-row.flash { background: var(--color-fill-1); border-radius: var(--radius-field); }
.switch-row.special > span:first-child { box-shadow: inset 0 0 0 1px var(--color-text); border-radius: var(--radius-control); padding: var(--space-4) var(--space-8); margin-left: calc(-1 * var(--space-8)); }
.tile, .pic { --chip-stack-margin: var(--space-8) 0 0; }
.inspector { --chip-stack-margin: 0 0 var(--space-4); }
/* ==== Timeline: cards =================================================================================
   Klassen: .chips.bilder > .chip.bild (.sel, .now, .gruppe) > canvas | img + small · .chips.bilder.marke (pictures of a brand)
   Tokens: --timeline-card-* */
/* Palette, Variante Bild – a picture of the stage instead of a colour (block Partitur; user, 24.10.2026: "müsste die
   partitur nicht einfach eine querformatige palette sein?"): chosen with a click (ring in ink), ordered by dragging
   (the drop target as the Palette's), added with the Symbol-Knopf plus; its length or name under it */
.chips.bilder { flex-wrap: nowrap; align-items: flex-start; gap: var(--space-8); }
.chip.bild { width: var(--timeline-card-width); height: auto; display: flex; flex-direction: column; gap: var(--space-4); padding: 0; border-radius: var(--radius-small);
  background: none; box-shadow: none; color: var(--color-text); cursor: pointer; text-align: left; touch-action: auto; }
.chip.bild > :is(canvas, img) { width: 100%; aspect-ratio: 16 / 9; display: block; object-fit: contain; border-radius: var(--radius-small); background: var(--color-fill-1); box-shadow: 0 0 0 1px var(--color-fill-2); }
.chip.bild > small, .chip.bild .gruppe-kopf > small { font-size: var(--type-label); line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.chip.bild.sel > :is(canvas, img) { box-shadow: 0 0 0 2px var(--timeline-card-selected); }
/* Variant Marke (brand libraries, brandAssets; user, 26.10.2026: „die darstellung mit den grauen flächen ist unglücklich, weil es genau
   dadurch nicht mehr on-brand ist“): each asset in its own shape on the ground – no tinted field, no hairline, all as high, the row wraps */
.chips.bilder.marke { flex-wrap: wrap; gap: var(--space-20) var(--space-24); align-items: flex-end; }
.chips.bilder.marke > .chip.bild { width: auto; flex: none; cursor: default; }
.chips.bilder.marke > .chip.bild > img { width: auto; height: calc(var(--space-32) * 2); aspect-ratio: auto; background: none; box-shadow: none; border-radius: 0; filter: var(--art-filter); }   /* black artwork, light on the dark ground – as .icon-tile img */
.chip.bild.now > :is(canvas, img) { box-shadow: 0 0 0 2px var(--timeline-card-now); }
/* Gruppe – tools at the same time (Partitur): closed, its picture on a small stack of the others; open, a tinted shelf
   with its tools side by side, the beats under all */
.chip.bild.gruppe > canvas { box-shadow: 0 0 0 1px var(--color-fill-2), 3px -3px 0 -1px var(--color-text-inverse), 3px -3px 0 0 var(--color-fill-3), 6px -6px 0 -1px var(--color-text-inverse), 6px -6px 0 0 var(--color-fill-3); }
.chip.bild.gruppe.sel > canvas { box-shadow: 0 0 0 2px var(--color-text), 4px -4px 0 0 var(--color-text-inverse), 4px -4px 0 1px var(--color-fill-3), 7px -7px 0 0 var(--color-text-inverse), 7px -7px 0 1px var(--color-fill-3); }
.gruppe-offen { flex: none; display: flex; flex-direction: column; gap: var(--space-4); padding: var(--edge) var(--space-8); background: var(--color-fill-1); cursor: pointer; }
.gruppe-offen.sel { box-shadow: inset 0 0 0 2px var(--color-text); }
.gruppe-offen.chip-drop-target { outline: 2px dashed var(--color-text); outline-offset: 3px; }
.gruppe-kopf { display: flex; align-items: center; gap: var(--space-4); font-size: var(--type-label); min-width: 0; }
/* Schläge – the beats of a tool under its picture (Partitur): a dot each, the Eins in ink; with a sound (.laut) each dot as
   large as the music there (--d), a change of section a short upright mark; a Verhalten changes on a ring (wechsel) or
   just after the beat (mit); the playing beat in the stage's mark. The music of an act as a fine filled line
   (.schlaege-musik, drawn in --color-fill-3, its section changes in --color-mark), a Verlauf as a ramp (.schlaege-verlauf),
   its values from start to end in the inspector (.von-bis). The words in data-b. */
.schlaege { display: flex; gap: var(--space-4); height: 6px; align-items: center; cursor: pointer; margin-bottom: var(--space-8); }   /* the beats keep their distance to the behaviours under them (user, 25.10.2026: „Abstand Punkte/Verhalten zu eng“) */
.schlaege i { flex: none; width: 5px; height: 5px; border-radius: 50%; background: color-mix(in srgb, var(--color-text) 38%, transparent); }   /* the other beats readable beside the One (user: „kleine Takte kaum zu erkennen“); they were 4 px in --color-fill-3 */
.schlaege.laut i { width: var(--d, 5px); height: var(--d, 5px); }
.schlaege i[data-b~="eins"] { background: var(--color-text); }
.schlaege i[data-b~="jetzt"] { background: var(--color-mark); }
.schlaege i[data-b~="nach"] { opacity: var(--timeline-beat-after); }   /* past the end of the music */
.schlaege i[data-b~="teil"] { width: 2px; height: 8px; border-radius: var(--radius-pill); background: var(--color-mark); }
.schlaege i[data-b~="wechsel"] { box-shadow: 0 0 0 1.5px var(--color-text-inverse), 0 0 0 3px var(--color-mark); }
.schlaege i[data-b~="mit"] { position: relative; }
.schlaege i[data-b~="mit"]::after { content: ""; position: absolute; left: calc(100% + 0.5px); top: -3px; width: 1.5px; height: calc(100% + 6px); background: var(--color-mark); }
.schlaege-musik { display: block; width: 100%; height: var(--size-16); color: var(--color-fill-3); border-top: 0 solid var(--color-mark); }   /* its row is there with or without a sound: the Partitur keeps its height when one is loaded (user: „höhe partitur springt, wenn audio geladen wird“) */   /* colours read by the canvas */
.schlaege-verlauf { position: relative; height: var(--size-18); }
.schlaege-verlauf svg { position: absolute; inset: 0 var(--space-12) 0 0; width: calc(100% - var(--space-12)); height: 100%; overflow: visible; }
.schlaege-verlauf span { position: absolute; right: 0; font-size: var(--type-label); line-height: 1; font-weight: var(--type-weight-bold); transform: translateY(-50%); }
.von-bis { display: grid; grid-template-columns: 1fr 14px 1fr; align-items: center; gap: var(--space-4); }
.von-bis span { text-align: center; }
/* Partitur – the film in time (block Partitur): each act an Abschnitt (its name, length and place; a broken rule as a
   Status), its tools a Palette of pictures; acts 40 px apart, as sections are (atom Abstände) */
.partitur { display: flex; gap: var(--space-40); align-items: flex-start; min-height: 100%; }
.partitur > .section { flex: none; --section-row-gap: var(--space-8); --section-head-gap: var(--space-8); }
.partitur .section-head { display: flex; justify-content: flex-start; gap: var(--space-8); align-items: baseline; min-height: 0; font-size: var(--type-label); white-space: nowrap; }
/* a short act keeps its head inside its own length (user, 26.10.2026: „unschöne überschneidung“): the name stays, the length and time
   give way with an ellipsis, nothing runs into the next act */
.partitur .section-head { overflow: hidden; padding-right: var(--space-8); }
.partitur .section-head > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.partitur .section-head h2 { margin: 0; font-size: var(--type-section); font-weight: var(--type-weight-bold); }
.partitur { --icon-button-align: center; }
/* Vorlage Case Film – the Bühne over the Partitur on one ground, the inspector at the edge (block vorlage-film) */
.film { position: fixed; inset: 0; right: var(--inspector-width); overflow: hidden; background: var(--color-surface-page);
  display: grid; grid-template-columns: 1fr; grid-template-rows: 1fr var(--row-h, 33.333vh); user-select: none; }   /* the Partitur a third high (user, 25.10.2026) */
.film.no-insp { right: 0; }
.film.no-insp > .inspector:not(.unten) { display: none; }
.film-stage { position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--space-8);
  min-width: 0; min-height: 0; padding: var(--space-24) 28px var(--space-16); }
.film-stage > canvas { max-width: 100%; max-height: calc(100% - 42px); min-height: 0; aspect-ratio: 16 / 9; cursor: pointer; }
.film-stage > .icon-row { flex: none; align-items: center; gap: var(--space-8); width: min(100%, 720px); font-size: var(--type-label); font-variant-numeric: tabular-nums; white-space: nowrap; }   /* the time on the scale, not the browser's 16 px (user, 25.10.2026: „warum ist das so riesig > widerspricht designsystem“) */
.film-stage > .icon-row input[type="range"] { flex: 1 1 auto; width: auto; min-width: 80px; }
/* Abspielleiste (block, 0.9.26): the play row under a stage that moves – the Motion Composer's, as a block of its own (user,
   26.10.2026: „sollten wir bei bewegen nicht einfach die filmsteuerung wie bei case verwenden?“ – „doch in die library“) */
.abspielleiste { display: flex; align-items: center; gap: var(--space-8); font-size: var(--type-label); font-variant-numeric: tabular-nums; white-space: nowrap; }
.abspielleiste input[type="range"] { flex: 1 1 auto; width: auto; min-width: 80px; }
body.stage-full .abspielleiste { opacity: 0; transition: opacity var(--motion-move); }
body.stage-full .abspielleiste:hover { opacity: 1; }
.insp-grip { position: absolute; left: 0; right: 0; bottom: calc(-1 * var(--space-4)); height: 9px; cursor: ns-resize; z-index: 2; touch-action: none; }
.insp-grip::after { content: ''; position: absolute; left: 50%; top: 3px; width: var(--size-36); height: 3px; transform: translateX(-50%); border-radius: var(--radius-pill); background: var(--color-fill-3); opacity: 0; transition: opacity var(--motion-hover); }
.insp-grip:hover::after, .insp-grip.on::after { opacity: 1; }
.insp-pills { padding: 0 var(--space-22) var(--space-12); }   /* what acts on the choice, as its pills, under the inspector's head */


.img-overlay {
  position: fixed;
  inset: 0;
  z-index: 20;
  display: none;
  align-items: center;
  justify-content: center;
  background: var(--color-scrim);
  padding: var(--space-24);
}
.img-overlay.open { display: flex; }
.img-modal {
  background: var(--color-surface-raised);
  border-radius: var(--radius-surface);
  box-shadow: var(--elevation-panel);
  max-height: 88vh;
  max-width: 92vw;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
}
.img-modal-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--space-12) var(--space-16);
  font-size: var(--type-label);
  font-weight: var(--type-weight-bold);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--color-text);
  flex-shrink: 0;
}

.img-canvas-wrap {
  position: relative;
  display: inline-block;
  max-width: min(560px, 86vw);
  margin: var(--space-16);
  border-radius: var(--radius-control);
  overflow: hidden;
  line-height: 0;
  background: var(--color-fill-2);
  align-self: center;
}
.img-canvas-wrap img {
  display: block;
  width: 100%;
  height: auto;
  max-height: 62vh;
  object-fit: contain;
}
.img-point {
  position: absolute;
  width: var(--size-24);
  height: var(--size-24);
  margin-left: -12px;
  margin-top: -12px;
  border-radius: 50%;
  box-shadow: inset 0 0 0 2px white, 0 0 0 1px var(--color-mark);   /* a handle by the one rule (patterns: Marken auf der Bühne): white with a blue edge, no shadow */
  cursor: grab;
  touch-action: none;
}
.img-point:active { cursor: grabbing; }
.img-point:focus-visible { outline: 3px solid var(--color-focus); outline-offset: 2px; }
.img-modal-head[data-griff] { cursor: grab; touch-action: none; user-select: none; }   /* Varianten (0.11.2): the head moves the dialog (initVariants) */
.img-modal-head[data-griff]:active { cursor: grabbing; }
.varianten { display: grid; grid-template-columns: repeat(3, auto); gap: var(--space-12); padding: var(--space-8) var(--space-16); justify-content: center; }   /* Varianten (0.9.29): a Dialog whose content is Bühnen, wählbar */
.img-modal-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-8);
  padding: var(--space-12) var(--space-16) var(--space-16);
  flex-shrink: 0;
}

@media (max-width: 720px) {
  .img-canvas-wrap { max-width: 100%; }
}


.color-popover {
  position: fixed;
  /* Above any realistic panel z-index: initPanel() bumps .dock's z-index
     by 1 on every click inside it (see shared/dock.js), so a plain
     constant just above the panel's *starting* z-index (3) only survives
     a couple of interactions before the panel overtakes it. This is a
     transient, modal-style popover — it should always render on top
     regardless of how long the session has been running. */
  z-index: 1000;
  display: none;
  flex-direction: column;
  gap: var(--space-8);
  background: var(--panel-bg);
  backdrop-filter: var(--blur-surface);
  -webkit-backdrop-filter: var(--blur-surface);
  box-shadow: var(--elevation-panel);
  padding: var(--edge);
}
.color-popover.open { display: flex; }
.color-popover-row {
  display: flex;
  align-items: center;
  gap: var(--space-8);
}
.color-popover-swatches {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  max-width: var(--color-picker-width);
}
.color-popover-swatches:empty { display: none; }
.color-popover-swatches button {
  width: var(--color-picker-swatch);
  height: var(--color-picker-swatch);
  border-radius: 50%;
  box-shadow: 0 0 0 1px var(--color-border-panel);
  padding: 0;
  cursor: pointer;
}
.color-popover-swatches button:focus-visible { outline: var(--focus-width) solid var(--focus-color); outline-offset: 1px; }
/* Concentric with .color-popover's own r-lg, not just a flat step down
   the scale: R1 = R2 - D, where D is the popover's 7px padding — see
   README's Radius nesting rule. Floored at r-sm since the raw result
   (5px) would otherwise dip below the smallest token. */
.color-popover input[type="color"] {
  width: var(--size-control-small);
  height: var(--size-control-small);
  border: none;
  border-radius: var(--r-in);   /* as the field beside it: the popover's container rule */
  padding: 0;
  background: none;
  cursor: pointer;
}
#hexInput { width: 84px; }   /* the field is the core Textfeld (.text-input); here only its width */

/* One Dialog in every tool (user, 28.10.2026: „speichern: bricht mit regeln für dialog. manche haben blur, manche nicht.
   speichern ist heller, varianten ist dunkler.“): the surface, the backdrop, the title and the foot of Speichern and
   Einstellungen (.settings) – the dock's ground, its hairline, blur and shadow; the title in the role Titel; the foot's
   Handlungen side by side as wide as each other */
.img-modal { background: var(--panel-bg); border: 1px solid var(--panel-border); backdrop-filter: var(--blur-surface); -webkit-backdrop-filter: var(--blur-surface); box-shadow: var(--elevation-panel); color: var(--color-text); }
.img-overlay { backdrop-filter: blur(2px); -webkit-backdrop-filter: blur(2px); }
.img-modal-head { border-bottom: none; text-transform: none; letter-spacing: 0; padding: var(--edge) var(--edge) var(--space-8); }
.img-modal-head h2 { margin: 0; font-size: var(--type-title); font-weight: var(--type-weight-bold); letter-spacing: -0.01em; }
#imgModeRow { margin: 0 var(--edge); }
.img-modal-foot { padding: var(--space-12) var(--edge) var(--edge); justify-content: stretch; }
.img-modal-foot, .settings-foot { --button-flex: 1 1 0; }

/* ==== Übersicht und Dokumentation (user, 24.10.2026: "übersicht und pattern lib halten sich selbst nicht an die pattern lib")
   The blocks the project dashboard and the pattern library are built of — the same core every tool loads, no page has
   styles of its own. Template „Übersicht“; organisms Seitenkopf, Navigation, Datenfluss, Dokument, Baustein-Karte;
   molecules Status, Etikett, Tabelle, Steckbrief (patterns/blocks.js). */

/* Vorlage Übersicht: a page on the ground, one column, or with the navigation beside it */
.overview { min-height: 100vh; background: var(--color-surface-page); color: var(--color-text); }
/* the page scrolls in html, not in body: a body with overflow would be the scroll box that never scrolls, and the
   sticky navigation would scroll away with the page (user, 24.10.2026: „unpraktisch, dass die Navleiste wegscrollt“) */
html:has(> body > .overview) { height: auto; overflow: auto; background: var(--color-surface-page); }
body:has(> .overview) { height: auto; overflow: visible; background: var(--color-surface-page); }
.overview-main { max-width: 1480px; margin: 0 auto; padding: var(--space-32) var(--space-24) 64px; transition: margin-right var(--motion-move) var(--motion-easing); }
.overview.with-nav { display: grid; grid-template-columns: var(--inspector-width) minmax(0, 1fr); }   /* as wide as the inspector */
.overview.with-nav > .overview-main { max-width: 1080px; margin: 0; padding: var(--space-40) 48px 120px; }
body.detail-open .overview-main { margin-right: var(--overview-detail-width); }
.overview-main > p { font-size: var(--type-label); line-height: 1.55; max-width: 72ch; margin: 0 0 var(--space-8); }
.overview-section { padding-top: 48px; }
.overview-section > h2 { margin: 0 0 var(--space-8); font-size: var(--type-title); font-weight: var(--type-weight-bold); letter-spacing: -0.01em; }
.overview-section > p { margin: 0; font-size: var(--type-label); line-height: 1.5; max-width: 72ch; }

/* Tool-Kachel – a tool in a brand's Brandtools: its picture (16:9, a preview per theme), name and text on the
   floating palette's surface; opens the tool, can be moved (.lifted). Spacing by proximity: name and text 6,
   picture to name 12, tile to tile 28 (atom Abstände); its edge 16 as every surface's, its corner the picture's plus the edge (atom Form). Was each Brandtools page's own style (`.tile`, the Partitur's class too). */
.tool-tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 28px; }
.tool-tile {
  display: flex; flex-direction: column; gap: var(--space-12); padding: var(--edge);
  background: var(--panel-bg); box-shadow: var(--elevation-panel);
  backdrop-filter: blur(28px) saturate(180%); -webkit-backdrop-filter: blur(28px) saturate(180%);
  color: var(--color-text); text-decoration: none; cursor: pointer; touch-action: manipulation;
  user-select: none; -webkit-user-select: none; -webkit-user-drag: none;
  transition: box-shadow var(--motion-move) ease;
}
.tool-tile:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }
.tool-tile.lifted { position: relative; z-index: 2; cursor: grabbing; box-shadow: var(--elevation-lifted); transition: none; }
.tool-tile .stage { display: block; aspect-ratio: 16 / 9; overflow: hidden; border-radius: var(--radius-control); box-shadow: 0 0 0 1px var(--panel-border); }
.tool-tile .stage img, .tool-tile .stage canvas { width: 100%; height: 100%; object-fit: cover; display: block; pointer-events: none; }   /* a motion tool's tile draws on a canvas (toolTileLive) */
.tool-tile .words { display: flex; flex-direction: column; gap: var(--space-4); }   /* the text on the surface's edge, as the picture */
.tool-tile .name { font-size: var(--type-title); font-weight: var(--type-weight-bold); letter-spacing: -0.01em; }
.tool-tile .text { font-size: var(--type-label); line-height: 1.4; }
/* A preview per theme where the tool has two (tool.json previewDark); previewInvert turns a black-ground
   preview against the dashboard (HELIO, from the HMI dashboard). The mode is the tokens' (core/tokens.css). */
.tool-tile .stage .dark { display: var(--only-dark); }
.tool-tile .stage .light.has-dark { display: var(--only-light); }
.tool-tile .stage .invert { filter: var(--art-filter); }
@media (max-width: 900px) { .overview.with-nav { grid-template-columns: 1fr; } .overview.with-nav > .overview-main { padding: var(--space-24) var(--space-16) 80px; } }

/* Seitenkopf: the page's title, then its bar — view, filter, links, legend (12 · 28 · 40 px) */
/* Seitenkopf in three rows (user, 24.10.2026: "besseres responsives Konzept, vor allem der Kopfbereich"): the title with
   what concerns the whole (Changelog, QS), the bar to look (Ansicht, Brand, Filter; legend right) */
.page-head { margin-bottom: var(--space-40); display: flex; flex-direction: column; gap: 28px; }
.page-title { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-12) 28px; }
.page-head h1 { margin: 0; font-size: var(--type-headline); font-weight: var(--type-weight-bold); letter-spacing: -0.01em; }
.page-meta { margin-left: auto; display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-12) 28px; font-size: var(--type-label); }
.page-bar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-12); font-size: var(--type-label); }
.page-bar { --segmented-width: var(--page-bar-control); --text-input-width: var(--page-bar-control); --select-width: var(--page-bar-control); --legend-margin: 0 0 0 auto; }   /* its controls at one width, the legend to the right */
@media (max-width: 760px) {   /* narrow: everything stacked, the controls the full width */
  .page-meta { margin-left: 0; }
  .page-bar { --segmented-width: 100%; --text-input-width: 100%; --select-width: 100%; --legend-margin: 0; }
}

/* Navigation: the column beside the content, its own search, links by group */
.side-nav { position: sticky; top: 0; align-self: start; height: 100vh; overflow: auto; padding: 28px var(--space-20) var(--space-40) var(--space-24); box-sizing: border-box; }
.side-nav h1 { margin: 0 0 var(--space-4); font-size: var(--type-headline); font-weight: var(--type-weight-bold); letter-spacing: -0.01em; }
.side-nav .side-meta { font-size: var(--type-label); font-weight: var(--type-weight-medium); margin: 0 0 var(--space-16); }
.side-nav { --text-input-margin: 0 0 var(--space-16); }
.side-nav h2 { margin: var(--space-16) 0 var(--space-8); font-size: var(--type-label); font-weight: var(--type-weight-bold); }
.side-nav a { display: block; padding: var(--space-4) 0; font-size: var(--type-label); color: var(--color-text); text-decoration: none; }
.side-nav a:hover { text-decoration: underline; text-underline-offset: 3px; }
@media (max-width: 900px) { .side-nav { position: static; height: auto; } }

/* Status: a dot and its word — the traffic light of the alignment; the colour never stands alone */
/* ==== Status indicator ===================================================================================
   Klassen: .status.status-ok|warn|error|lab > .status-dot + Wort · .legend · Tokens: --status-* */
.status { display: inline-flex; align-items: baseline; gap: var(--space-8); white-space: nowrap; }   /* the word on the baseline, so a Status stands on the line of its neighbours (Tabelle, Steckbrief) */
.status .status-dot { align-self: center; }
.status-dot { display: inline-block; width: var(--status-dot); height: var(--status-dot); border-radius: 50%; flex: none; background: var(--color-fill-3); }
.status-ok .status-dot, .status-dot.status-ok { background: var(--status-ok); }
.status-warn .status-dot, .status-dot.status-warn { background: transparent; box-shadow: inset 0 0 0 1.5px var(--status-warn); animation: status-breathe var(--motion-pulse) ease-in-out infinite; }
@keyframes status-breathe { 50% { opacity: 0.3; } }   /* the Zwischenstand breathes, slowly – never a hard blink */
@media (prefers-reduced-motion: reduce) { .status-warn .status-dot, .status-dot.status-warn { animation: none; } }
.status-error .status-dot, .status-dot.status-error { background: var(--status-error); }
.legend { margin: var(--legend-margin, 0); display: flex; flex-wrap: wrap; gap: var(--space-8) var(--space-16); align-items: center; font-size: var(--type-label); }

/* Etikett: a short fact beside a name (level, phase, version) */
/* ==== Tag ================================================================================================
   Klassen: span.tag (.mono) · Tokens: --tag-* */
.tag { display: inline-block; white-space: nowrap; font-size: var(--type-label); font-weight: var(--type-weight-medium); padding: 2px var(--space-8); border-radius: var(--tag-radius); box-shadow: inset 0 0 0 1px var(--tag-border); }

/* Monospace for what a machine writes or reads – a value one compares, copies or looks up (Atom Schrift, user,
   24.10.2026): versions, seeds, sizes in px, paths and file names, ids, code, state. Names, text and controls stay Inter.
   .mono on any element of a block that shows such a value (Tabelle, Steckbrief, Etikett). */
.mono { font-family: var(--type-family-mono); font-size: 0.92em; font-variant-numeric: normal; }
.tag.mono { font-size: var(--type-label); }   /* an Etikett keeps its size in monospace too (user, 24.10.2026: "die versionsnummern in diesen dingern könnten kleiner sein") */
/* Tabelle: rows of things of one kind; values in monospace; a row that opens something takes the pointer */
/* ==== Data table =========================================================================================
   Klassen: table.data-table (.compact) · tr.opens · td.mono · Tokens: --table-* */
.data-table { width: 100%; border-collapse: collapse; font-size: var(--type-label); }
.data-table th { text-align: left; font-weight: var(--type-weight-bold); padding: var(--space-8) var(--space-12) var(--space-8) 0; }
.data-table td { padding: var(--space-8) var(--space-12) var(--space-8) 0; vertical-align: baseline; }   /* a row on the baseline of its first line – monospace values are smaller (user, 24.10.2026: "auch hier gibt's ein Problem mit der Typo-Ausrichtung vertikal") */
.data-table tbody tr { box-shadow: inset 0 1px var(--table-line); }
.data-table tr.opens { cursor: pointer; }
.data-table tr.opens:hover { background: var(--table-row-hover); }
.data-table.compact th { font: var(--type-label)/1.4 var(--type-family-mono); }
.data-table.compact { font-size: var(--type-label); }
.data-table.compact th, .data-table.compact td { padding: var(--space-4) var(--space-8) var(--space-4) 0; vertical-align: middle; font-weight: var(--type-weight-medium); white-space: nowrap; }
.data-table.compact tbody tr { box-shadow: none; }
.data-table.compact code { font-size: var(--type-label); white-space: var(--table-code-wrap, normal); word-break: var(--table-code-break, break-word); }

/* Steckbrief: names and values in two columns */
dl.facts { margin: 0; display: grid; grid-template-columns: var(--dl-term-width) minmax(0, 1fr); gap: var(--space-8) var(--space-12); font-size: var(--type-label); line-height: 1.5; align-items: baseline; }   /* name and value on the first line of the value – a code box or list starts lower (user, 24.10.2026: „vertikale Ausrichtung checken“) */
dl.facts dt { font-weight: var(--type-weight-bold); }
dl.facts dd { margin: 0; min-width: 0; }
dl.facts ul { margin: 0; padding-left: var(--space-16); }
dl.facts li + li { margin-top: var(--space-4); }
dl.facts a { color: var(--color-text); text-underline-offset: var(--type-underline-offset); }
dl.facts code, dl.facts pre { font: var(--type-label)/1.45 var(--type-family-mono); }
dl.facts pre { margin: 0; padding: var(--space-8); border-radius: var(--radius-field); background: var(--color-fill-1); white-space: pre-wrap; }
dl.facts details summary { cursor: pointer; font-size: var(--type-label); }
dl.facts details pre { margin-top: var(--space-8); max-height: var(--dl-code-height); overflow: auto; }
dl.facts + .action { margin-top: 28px; }

/* Dokument: a Markdown text read in place (the dashboard's panel) */
.doc { font-size: var(--type-label); line-height: 1.5; }
.doc h1, .doc h2, .doc h3 { font-size: var(--type-section); font-weight: var(--type-weight-bold); margin: 28px 0 var(--space-8); letter-spacing: -0.005em; }
.doc h1 { font-size: var(--type-title); margin-top: 0; }
.doc p, .doc ul, .doc ol, .doc table, .doc pre { margin: 0 0 var(--space-12); }
.doc ul, .doc ol { padding-left: var(--space-16); }
.doc li { margin-bottom: var(--space-4); }
.doc code, .doc pre { font: 12px var(--type-family-mono); }
.doc pre { white-space: pre-wrap; }
.doc table { font-size: var(--type-label); border-collapse: collapse; }
.doc th, .doc td { text-align: left; vertical-align: top; padding: var(--space-4) var(--space-8) var(--space-4) 0; }
.doc a { color: var(--color-text); }

/* the inspector as a reading panel (dashboard): wider, no sections */
.inspector.wide { width: 480px; }
/* Inspektor unten (initEdgePanel): the same panel at the lower edge of the page grid, as wide as its column – its edge a
   line (--color-border) with the grip on it, the head of the inspector with its collapse button, the body scrolls sideways */
.inspector.unten { position: relative; inset: auto; width: auto; min-width: 0; min-height: 0; z-index: 1; grid-column: 1; grid-row: 2; border-top: 1px solid var(--color-border); }
.inspector.unten > .insp-grip { top: calc(-1 * var(--space-4)); bottom: auto; }
.inspector.unten > .insp-body { overflow: auto; padding-bottom: var(--space-16); }
.inspector.unten .insp-head [data-panel-toggle] svg { transition: transform var(--motion-hover) ease; }
.inspector.unten .insp-head [data-panel-toggle][aria-expanded="false"] svg { transform: rotate(-90deg); }
.inspector.wide .insp-body { gap: 0; }
.inspector.wide .insp-title { flex: 1; min-width: 0; }
.inspector.wide .insp-body > .btn-row:first-child { margin-bottom: var(--space-20); }   /* its actions on top, then what it says */


/* Datenfluss: columns of fields, the lines drawn behind them (as in THA Tools) */
.flow { position: relative; display: grid; grid-template-columns: repeat(var(--flow-cols, 6), minmax(0, 1fr)); gap: 0 var(--space-40); min-width: calc(var(--flow-cols, 6) * 150px); }   /* narrow: the page scrolls sideways, fields never squeeze */
.overview-main:has(> .flow) { overflow-x: auto; }
.flow > svg { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; overflow: visible; }
.flow-col > h2 { margin: 0 0 var(--space-12); font-size: var(--type-section); font-weight: var(--type-weight-bold); letter-spacing: -0.005em; }
.flow-group { position: relative; display: table; padding-right: var(--space-8); background: var(--color-surface-page); font-size: var(--type-label); font-weight: var(--type-weight-medium); margin: 0 0 var(--space-12); }   /* lines pass behind */
.flow-group ~ .flow-group { margin-top: 28px; }
.flow-node { position: relative; display: flex; align-items: center; gap: var(--space-8); width: 100%; min-height: var(--size-control); margin-bottom: var(--space-8); padding: var(--edge) var(--space-12); border: none;
  --node-bg: color-mix(in srgb, var(--color-text) 7%, var(--color-surface-page)); background: var(--node-bg); color: var(--color-text); font: inherit; font-size: var(--type-label); font-weight: var(--type-weight-bold); text-align: left; cursor: pointer; }
.flow-node:hover { background: color-mix(in srgb, var(--color-text) 12%, var(--color-surface-page)); }
.flow-node:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }
.flow-node.on { box-shadow: 0 0 0 2px var(--color-text); }
.flow-node.picked { box-shadow: 0 0 0 2px var(--color-surface-page), 0 0 0 4px var(--color-text); }   /* the field whose panel is open: a ring with air – black is a brand's */
/* Labor: what was never committed – hatched, as in THA Tools (user, 24.10.2026: "soll entwickeln den status zeigen? dann anders
   visualisieren"; "lass uns labor schraffieren, wie bei THA tools, nicht umranden") */
.flow-node.lab { background-image: linear-gradient(color-mix(in srgb, var(--node-bg) 50%, transparent) 0 0), var(--hatch);   /* the hatch at half strength */
  text-shadow: 0 0 2px var(--node-bg), 0 0 2px var(--node-bg), 0 0 3px var(--node-bg); }   /* and the name outlined in the field's colour, readable over it (user, 24.10.2026: "bitte outline um texte vor schraffur. schraffur kann 50% deckkraft haben") */
.flow-node.brand.lab { background-image: linear-gradient(color-mix(in srgb, var(--node-bg) 50%, transparent) 0 0), var(--hatch-inv); }
.flow-node.brand { --node-bg: var(--color-text); background: var(--color-text); color: var(--color-text-inverse); --status-ok: var(--color-text-inverse); --status-warn: var(--color-text-inverse); }   /* what belongs to a brand is black, what is general stays light (user, 24.10.2026: "die unterscheidung ist zu schwach"; "oder brandbezogen schwarz?") */
.flow-node.brand:hover { background: color-mix(in srgb, var(--color-text) 82%, var(--color-surface-page)); }
.flow-node.launch:hover, .flow-node.brand.launch:hover { background: var(--node-bg); }   /* a Brandtools field is no button itself – only its name and Starten are, so it does not light up (user, 24.10.2026: "rollover-button kollidiert mit rollover-fläche") */
.status-lab .status-dot { width: var(--status-lab); height: var(--status-lab); border-radius: calc(var(--radius-small) / 2);   /* a small square field, not a dot: it shows a kind of field (user, 24.10.2026: "labor icon muss grösser sein, es visualisiert etwas anderes"; "quadratisch, schraffur 50% grösse") */
  background: linear-gradient(color-mix(in srgb, var(--color-fill-2) 50%, transparent) 0 0), var(--hatch) 0 0 / 3px 3px, var(--color-fill-2); }
.flow-node, .flow-face { flex-wrap: nowrap; }   /* the dot stays with the name: a long name breaks in itself, the version keeps its place */
.flow-node > .mono, .flow-face > .mono, .flow-node > .status-dot, .flow-face > .status-dot { flex: none; }
.flow-node .mono { margin-left: auto; font-size: var(--type-label); font-weight: var(--type-weight-regular); }   /* the version: plain text at the field's end, one step down (Schrift: monospace) */
/* Brandtools: taller, with Starten (the field opens the panel, the button the dashboard) */
.flow-node.launch { flex-direction: column; align-items: stretch; gap: var(--space-8); padding: var(--edge); cursor: default; }   /* Starten at the rim on all sides */
.flow-node.launch > .flow-face { padding: var(--space-4) var(--space-4) 0; }   /* the name at the field's text edge (8 + 4 = 12), Starten close to the rim (8) */   /* the field's edge (12, as every field's text) for name and Starten alike; the corner Starten's plus that edge (atoms Abstände, Form; user, 24.10.2026: "neue abstandsregeln innen") */
.flow-face { display: flex; align-items: center; gap: var(--space-8); padding: 0; border: none; background: none; color: inherit; font: inherit; text-align: left; cursor: pointer; }
.flow-face .mono { margin-left: auto; }
.flow-node.launch .action { justify-content: center; flex: none; background: color-mix(in srgb, var(--color-surface-raised) 14%, var(--color-text)); color: var(--color-text-inverse); }   /* the secondary button on the black field: the tint over it, dark grey – as Zurücksetzen on a dark ground (user, 24.10.2026: "können wir hier die secondary buttons verwenden?"; "dunkelgrau statt schwarz") */
.flow-node.launch .action:hover { background: var(--color-surface-raised); color: var(--color-text); }
.qs-frame { position: fixed; left: -20000px; top: 0; width: 1440px; height: 900px; border: 0; visibility: hidden; }   /* a page the QS renders off the screen to compare it with the library */
.flow-edge { fill: none; stroke: color-mix(in srgb, var(--color-text) 26%, var(--color-surface-page)); stroke-width: 1; }   /* thin (user, 25.10.2026: "können wir die linien dünner machen") */
.flow-edge.on { stroke: var(--color-text); stroke-width: 1.5; }
.away { display: none !important; }   /* filtered out (Datenfluss, Navigation, Baustein-Karte) */

/* Baustein-Karte: the head, the live example in light and dark side by side, then its facts (pattern library; user,
   25.10.2026: „Hell und Dunkel nebeneinander“). Each example is a Modus-Bereich (data-theme, core/tokens.css): the
   page only sets the attribute, the values come from the tokens. A template stands wide, its two examples one above
   the other. */
.block-card { padding: var(--space-32) 0; scroll-margin-top: 16px; }
.block-card.page { padding: var(--space-20) 0; }
.block-demo { position: relative; background: var(--color-surface-raised); color: var(--color-text); border-radius: var(--radius-control); padding: var(--space-24); display: flex; flex-direction: column; gap: var(--space-12); margin: 0 0 var(--space-24); box-sizing: content-box; }
/* the example at its size in a tool (user, 25.10.2026: „in echter Tool-Größe“): what stands in the dock at the dock's
   width, what fills a side panel at the panel's, a page as wide as the card */
.block-demo[data-size="dock"] { width: calc(var(--panel-width) - 2 * var(--space-panel)); padding: var(--space-12) var(--space-panel) var(--space-panel); gap: var(--space-row); background: var(--panel-bg); }   /* as in a section of the dock: its width, its edge, its rows, its surface */
.block-demo[data-size="panel"] { width: var(--inspector-width); padding: 0; background: var(--color-surface-page); }   /* as the inspector: its width and ground */
.block-demo[data-size="free"] { width: max-content; max-width: 100%; }
.block-demo[data-size="wide"] { box-sizing: border-box; overflow-x: auto; }
/* a window of a tool: what is fixed in a tool (dock, inspector, toast, dialog) stands in it as in the tool – the demo is
   their containing block (transform) and has the ground and the proportion of a screen */
.block-demo[data-size="screen"] { position: relative; transform: translateZ(0); overflow: hidden; padding: 0; background: var(--color-surface-page); box-sizing: border-box; width: 100%; height: 80vh; align-items: center; justify-content: center; }   /* about a screen: what a tool sizes by the screen (vh) fits as there */
.block-demo[data-size="panel-body"] { width: calc(var(--inspector-width) - 2 * var(--space-panel)); padding: var(--space-16) var(--space-panel); background: var(--color-surface-page); }   /* inside the inspector */
.block-demo[data-size="settings"] { width: min(var(--modal-width), calc(100vw - 32px)); }   /* the settings dialog's width (.settings) */
/* a template is the real page, at a screen's proportion */
.block-demo:has(> .block-page) { padding: 0; overflow: hidden; }
/* the window stands for the page grid: a panel at the lower edge (.inspector.unten) lies along the bottom, beside the inspector */
.block-demo[data-size="screen"] > .inspector.unten { position: absolute; left: 0; right: var(--inspector-width); bottom: 0; height: 40%; display: flex; }
.block-page { display: block; width: 100%; aspect-ratio: 16 / 10; border: 0; }
.block-head { display: flex; align-items: baseline; gap: var(--space-8); margin: 0 0 var(--space-8); }
.block-head h3 { margin: 0; font-size: var(--type-title); font-weight: var(--type-weight-bold); }
.block-head > code, .block-head > a { margin-left: auto; font: 12px var(--type-family-mono); color: var(--color-text); text-underline-offset: 3px; }
.block-measures { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: var(--space-4) var(--space-12); }
.block-measures span { font-feature-settings: 'tnum'; }
/* Varianten × States: one row per state, every variant in its own cell at its own width – nothing wraps, labels on the
   middle of the controls */
.state-matrix th, .state-matrix td { vertical-align: middle; padding: var(--space-12) var(--space-24) var(--space-12) 0; }
.state-cell { display: flex; align-items: center; width: max-content; min-height: var(--size-control); white-space: nowrap; }
.state-cell > * { flex-wrap: nowrap; margin: 0; }
.state-cell > input[type="range"] { width: var(--size-140); }
.token-table { --table-code-wrap: nowrap; --table-code-break: normal; white-space: nowrap; }   /* a name and a value never break */
.token-table, .state-matrix { display: block; max-width: 100%; overflow-x: auto; }   /* wider than the column: it scrolls, the page does not */
.block-measures b { font-weight: var(--type-weight-medium); }
.token-ground { display: inline-flex; width: 34px; height: var(--size-24); border-radius: var(--radius-small); align-items: center; justify-content: center; margin-right: var(--space-8); vertical-align: middle; background: var(--color-surface-page); }   /* a Modus-Bereich: the token on the ground of its mode */
.token-sample { display: block; width: var(--size-18); height: 14px; border-radius: var(--radius-small); }
.curves { display: flex; flex-wrap: wrap; gap: var(--space-12); }
.curve { margin: 0; font-size: var(--type-label); } .curve svg { display: block; overflow: visible; }
.sym-sizes { display: flex; gap: var(--space-22); align-items: end; flex-wrap: wrap; font-size: var(--type-label); }
.sym-sizes figure { margin: 0; display: flex; flex-direction: column; align-items: center; gap: var(--space-8); }
.sym-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: var(--space-8) var(--space-12); margin-top: var(--space-4); }
.sym { display: grid; grid-template-columns: 28px minmax(0, 1fr); gap: 2px var(--space-8); align-items: center; font-size: var(--type-label); line-height: 1.35; }
.sym svg { width: var(--size-18); height: var(--size-18); justify-self: center; grid-row: span 2; }
.sym b { font: 500 11px var(--type-family-mono); }
.sym em { font-style: normal; }
.link-u, .link-u:visited { color: var(--color-text); }   /* a link is ink, never the browser's blue or purple – in a bar, a navigation, a page head */

/* Container – one rule for every surface that holds rounded things (atoms Form and Abstände; user, 24.10.2026: "es ist
   ja ein container, kein button"; "sollte aus einer regel stammen"): it has an edge (--edge) and holds things with the
   corner --r-in; its own corner is their sum, so the curves run parallel. A container sets only these two. */
.dock, .img-modal, .settings, .tool-tile { --r-in: var(--radius-control); --edge: var(--space-16); }   /* a button inside, at the surface's edge */
.flow-node { --r-in: var(--radius-control); --edge: var(--space-8); }   /* every field of the Datenfluss: its version, Starten, at 8 px from the rim (user, 24.10.2026: "müsste auch alle anderen kacheln in dieser ansicht betreffen") */
.choice-pop { --r-in: var(--radius-field); --edge: var(--space-4); }
.stage-options { --r-in: var(--radius-field); --edge: var(--space-8); }
.color-popover { --r-in: var(--radius-field); --edge: var(--space-8); }   /* Farbwahl: the hex field and the colour well at 8 px */
.gruppe-offen { --r-in: var(--radius-small); --edge: var(--space-4); }
.dock, .img-modal, .settings, .tool-tile, .flow-node, .img-mode-row, .color-popover, .choice-pop, .stage-options, .gruppe-offen { --r-container: calc(var(--r-in) + var(--edge)); border-radius: var(--r-container); }

/* Bearbeitungsmodus (Motion Composer): the real tool over the film, a head with ← and the title, Verwerfen · Übernehmen once
   something changed (user, 23.10.2026) */
.edit-mode { position: fixed; inset: 0; z-index: 60; display: flex; flex-direction: column; background: var(--color-surface-page); }   /* the whole window: its foot runs from edge to edge (user, 26.10.2026: „hier hätte ich gerne eine durchgezogene leiste über die komplette breite“) */
.edit-head { display: flex; align-items: center; gap: var(--space-8); padding: var(--space-8) var(--space-12); }
.edit-title { flex: 1; font-size: var(--type-label); font-weight: 600; }
.edit-tool { flex: 1; width: 100%; border: 0; }
.edit-foot { flex: none; display: flex; gap: var(--space-8); padding: var(--space-12) var(--space-16) var(--space-16); justify-content: flex-end; background: var(--color-surface-raised); color: var(--color-text); }   /* a bar of the other mode (data-theme set by openEditMode), edge to edge; its buttons at their own width, to the right (user, 26.10.2026: „button breite macht keinen sinn“, „buttons rechtsbündig“) */
.edit-foot { --button-flex: 0 0 auto; --button-min-width: var(--button-foot-width); }
.edit-foot.flash > .action.save { box-shadow: 0 0 0 3px var(--color-focus); }   /* back with changes: the foot asks */
.stage-options { align-items: center; }   /* a control of the core stands in the bar on its middle */
/* Tool im Einsatz (Motion Composer, film „Brandtools“): the real tool over the stage, its page at the film's size scaled to the stage;
   it takes no pointer – the Zeiger works it */
.tool-demo { position: absolute; z-index: 2; overflow: hidden; pointer-events: none; }
.tool-demo[hidden] { display: none; }
.tool-demo-cam { position: absolute; inset: 0; transform-origin: 0 0; }   /* the camera of a tool at work: zooms onto the detail clicked */
.tool-demo-frame { position: absolute; left: 0; top: 0; border: 0; transform-origin: 0 0; pointer-events: none; background: var(--bg); }
.tool-demo-frame[hidden] { display: none; }
/* Zeiger (stageCursor): a mouse arrow in ink with a light rim, 22 px, over what it shows; a click a ring in the stage blue */
.zeiger { position: absolute; left: -4px; top: -2px; width: 22px; height: 22px; z-index: 5; pointer-events: none; transform-origin: 4px 2px; }   /* scaled about its tip (stageCursor scale) */
.zeiger svg { width: 100%; height: 100%; display: block; overflow: visible; }
.zeiger path { fill: var(--color-text); stroke: var(--color-text-inverse); stroke-width: 1.5px; stroke-linejoin: round; }
.zeiger-ring { position: absolute; width: var(--size-24); height: var(--size-24); margin: -12px 0 0 -12px; border-radius: 50%; border: 1.5px solid var(--color-mark); opacity: 0; z-index: 4; pointer-events: none; }
.zeiger[hidden], .zeiger-ring[hidden] { display: none; }
/* with a head (openStageOptions opts.title): the name of what it belongs to, its controls in a row under it with room between them,
   a tip on it (user, 26.10.2026: „abstände zu eng, unklar worauf es sich bezieht“) */
.stage-options.mit-kopf { flex-direction: column; align-items: stretch; gap: var(--space-12); padding: var(--space-12) var(--space-16) var(--space-16); }
.stage-options-kopf { display: flex; align-items: baseline; gap: var(--space-8); white-space: nowrap; }
.stage-options-kopf b { font-size: var(--type-section); font-weight: var(--type-weight-bold); }
.stage-options-kopf span { font-size: var(--type-label); }
.stage-options-zeile { display: flex; align-items: center; gap: var(--space-16); }
.stage-options-zeile > button { min-width: 44px; height: var(--size-36); padding: 0 var(--space-16); border: none; border-radius: var(--radius-field); background: var(--color-fill-1); color: var(--color-text);
  font: var(--type-weight-medium) var(--type-label) var(--type-family); cursor: pointer; display: flex; align-items: center; justify-content: center; gap: var(--space-8); }
.stage-options > button.primary, .stage-options-zeile > button.primary { background: var(--color-text); color: var(--color-text-inverse); }
.stage-options-zeile > button svg { width: var(--size-18); height: var(--size-18); display: block; flex: none; }
.stage-options.pfeil-unten::after, .stage-options.pfeil-oben::after { content: ""; position: absolute; left: var(--pfeil-x, 50%); width: 0; height: 0; border: 8px solid transparent; transform: translateX(-50%); }
.stage-options.pfeil-unten::after { top: 100%; border-top-color: var(--panel-bg); }
.stage-options.pfeil-oben::after { bottom: 100%; border-bottom-color: var(--panel-bg); }

/* Partitur in time (user, 25.10.2026: „Breite = Länge“): a sprite is as wide as its bars (--timeline-bar each), side by
   side without a gap of their own – the space between them is inside each one; above each act its Lineal in bars and
   time, under it the music; an open group shows its tools as tracks one under the other (Split-Screen) */
.partitur .chips.bilder { gap: 0; }
.partitur .chips.bilder > .chip.bild, .partitur .chips.bilder > .gruppe-offen { box-sizing: border-box; padding-right: var(--space-8); }
.partitur .gruppe-offen { padding-right: var(--space-8); background: none; }
.partitur .gruppe-offen > .chips.bilder { flex-direction: column; gap: var(--space-4); }
.partitur .gruppe-offen > .chips.bilder > .chip.bild { width: 100%; padding-right: 0; }
.partitur .chip.bild > :is(canvas, img) { aspect-ratio: auto; height: calc(var(--timeline-bar) * 9 / 8); }   /* every picture as high as a 2-bar one, however long (user, 25.10.2026: „die riesenbilder irritieren mich und brauchen extrem viel platz“) */
.lineal { position: relative; height: var(--size-18); flex: none; }
.lineal i { position: absolute; top: 0; width: 1px; height: 6px; background: var(--color-fill-3); }
.lineal i.eins { height: 10px; background: var(--color-text); }
.lineal span { position: absolute; top: 0; margin-left: var(--space-4); font-size: var(--type-label); line-height: 1; }   /* beside the Eins's mark, its time from it to the right – under it, the mark ran into the digits (user, 26.10.2026: „abstand ziffern/skala suboptimal“) */
.partitur .schlaege { display: grid; grid-auto-flow: column; grid-auto-columns: calc(var(--timeline-bar) / var(--bpb, 4)); gap: 0; }   /* a beat where the Lineal has it (--bpb to the bar: the Taktart, user 25.10.2026) */

/* Dock quer (user, 25.10.2026: „ICH WILL SOWAS IN QUER!!! für die partitur“, „Ja, alles so“): the Dock of the tools lying
   under the stage, 8 px from the inspector, as high as it holds (no scrolling up and down), the stage gives way
   (--dock-h, initDockQuer); Speichern stands in its head, so folded only the head stays; it folds down. In it the Partitur as a
   Palette: × removes, dragging lifts and shows where it lands (beside: a mark in --color-mark; onto: dashed) */
.film { grid-template-rows: 1fr; }
.film-stage { padding-bottom: calc(var(--dock-h, 0px) + var(--space-32) + var(--space-16)); }   /* the Dock, its edge to the window and a gap */
.film.no-insp { --dock-quer-rechts: var(--space-window); }
.dock.quer .partitur { min-height: 0; }
.dock.quer { --chip-direction: row; --chip-stack-gap: 2px; --chip-height: 18px; }   /* the words under the beats side by side and small */
.partitur .chip.bild, .partitur .gruppe-offen { position: relative; touch-action: none; cursor: grab; }
.partitur .chip.bild > .rm { position: absolute; top: -6px; right: 2px; display: flex; align-items: center; justify-content: center; z-index: 1; }   /* the × centred as in the Palette (there the chip, a button, centres it) */
.partitur .chip.bild:hover > .rm, .partitur .chip.bild:focus-within > .rm { opacity: 1; }
.partitur .chip.bild, .partitur .chip.bild:active { transition: none; transform: none; opacity: 1; }   /* no press-scale or slide of the Palette's round field: the lifted picture follows the pointer exactly */
.partitur .chip.chip-dragging, .partitur .chip.chip-drop-target { box-shadow: none; outline: none; }   /* the marks are on the picture only, not around picture, beats and words */
.partitur .chip-dragging { z-index: 10; pointer-events: none; cursor: grabbing; }
.partitur:has(.chip-dragging) .rm { opacity: 0; }   /* while one is lifted, no × flickers up on the tools it passes */
.partitur .chip-dragging > canvas { box-shadow: var(--elevation-lifted), 0 0 0 2px var(--color-text); }
.partitur .chip-drop-target > canvas { outline: 2px dashed var(--color-text); outline-offset: 3px; }
.partitur .chip-drop-before::before, .partitur .chip-drop-after::after { content: ""; position: absolute; top: 0; height: calc(var(--timeline-bar) * 9 / 8);
  width: 2px; border-radius: 1px; background: var(--color-mark); }
.partitur .chip-drop-before::before { left: -5px; }
.partitur .chip-drop-after::after { right: 3px; }

/* Kontextmenü (block Speichern, chooseOption; user, 25.10.2026: „besser mit gruppen arbeiten. überschrift von einträgen
   absetzen“): the heading apart from the entries, groups under a sub-heading, the hint small under the name */
.choice-pop .choice-title { margin-bottom: var(--space-8); }
.choice-group { padding: var(--space-8) var(--space-8) var(--space-4); font-size: var(--type-label); font-weight: var(--type-weight-bold); }
.choice-title + .choice-group { padding-top: 0; }
.choice-btn { flex-direction: column; justify-content: flex-start; align-items: flex-start; gap: 2px; }
.choice-btn span:last-child { font-size: var(--type-label); }
.choice-btn span:last-child:empty { display: none; }
.choice-btn:disabled { opacity: 0.4; cursor: not-allowed; background: none; }   /* a format of the other state (saveChoices): there, not to be picked */
