/* Grundea landing — replicas of in-app views (design spec §4 "Der Editor").

   Nothing in here is a screenshot. Every view is HTML, CSS and inline SVG in
   the app's own tokens and metrics (app.grundea.de/docs/design-system.md
   §3/§4): the plan and the section come out of the product renderer
   (app.grundea.de/scripts/gen-landing-views.mjs), the chrome around them is
   rebuilt here. That is why the pages scale, stay sharp and read in the same
   type as the app — and why a metric change in the app is a change here too.

   Load order: tokens.css → fonts/fonts.css → site.css → views.css.
   Prefix `.ui-` = app replica; nothing in site.css uses it. The first half is
   deliberately the complete primitive kit of design-system §3 (a few
   primitives — pills, alerts, the canvas grid — wait for their first replica);
   the second half holds the compositions and, marked as such, the
   landing-side layout rules they need (`.section-ink`, `.editor-legend`,
   `.feature-card`, the `.step` third column) — look here, not only in
   site.css, when one of those changes. */

/* ─── root ──────────────────────────────────────────────────────────────── */

.ui {
  color: var(--ink);
  font-family: "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  font-size: 14px;
  line-height: 20px;
  text-align: left;
  -webkit-font-smoothing: antialiased;
}
.ui *, .ui *::before, .ui *::after { box-sizing: border-box; }
.ui p, .ui h3, .ui h4, .ui ul, .ui ol, .ui dl, .ui dd { margin: 0; padding: 0; }
.ui li { list-style: none; }
.ui svg.i { width: 16px; height: 16px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }
.ui svg.i-sm { width: 14px; height: 14px; }
.ui svg.i-lg { width: 20px; height: 20px; }

.ui-mono, .ui .ui-mono {
  font-family: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  font-variant-numeric: tabular-nums;
}
/* `monoLabelClasses`: panel titles, sheet headings, list captions */
.ui-label {
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: 12px;
  line-height: 16px;
  font-weight: 500;
  letter-spacing: 1px;
  text-transform: uppercase;
  color: var(--muted);
}
.ui-xs { font-size: 12px; line-height: 16px; }
.ui-xxs { font-size: 11px; line-height: 16px; }
.ui-muted, .ui .ui-muted { color: var(--muted); }
.ui-faint, .ui .ui-faint { color: var(--faint); }
.ui-ink2, .ui .ui-ink2 { color: var(--ink-2); }
.ui-danger { color: var(--danger); }
.ui-success { color: var(--success); }
.ui-warning { color: var(--warning); }
.ui-accent { color: var(--accent-strong); }
.ui-right { text-align: right; }
.ui-truncate { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.ui-row { display: flex; align-items: center; gap: 8px; }
.ui-grow { flex: 1 1 auto; min-width: 0; }
.ui-gap-1 { gap: 4px; } .ui-gap-3 { gap: 12px; } .ui-gap-4 { gap: 16px; }

/* ─── fluid fitting: a fixed-width composition scaled to its container ──── */
/* `.ui-fit` measures the width, `.ui-fit-box` reserves the height from the
   design's aspect ratio, `.ui-fixed` is authored at --w × --h px and scaled
   down as one piece — text, strokes and gaps shrink together, nothing
   reflows. The factor (container width ÷ layout width) is set by `site.js`
   (`fitReplica`, kept fresh by a ResizeObserver) and deliberately not by
   CSS: a length divided by a length in calc() is typed arithmetic that only
   Chrome 140 and Safari 26 accept, and container units inside tan()/atan2()
   resolve against the viewport in Safari — the window came out at 1,7× and
   the cards showed the empty corner of a five-times-enlarged canvas.
   Without JavaScript the box keeps the design height and scrolls sideways. */
.ui-fit { width: 100%; }
.ui-fit-box { position: relative; width: 100%; height: calc(var(--h) * 1px); overflow-x: auto; }
.ui-fixed { position: relative; width: calc(var(--w) * 1px); height: calc(var(--h) * 1px); transform-origin: top left; }
/* `is-fit` is set by site.js the moment it has measured: only then does the
   box take the design's ratio and clip. Until then — and without JavaScript
   at all — the composition shows at its design size and scrolls sideways,
   never as a cropped corner. Keyed on the box, not on `html.js`: the `js`
   class is set by an inline script before site.js has run. */
.ui-fit-box.is-fit { height: auto; aspect-ratio: var(--w) / var(--h); overflow: hidden; }
.ui-fit-box.is-fit > .ui-fixed { position: absolute; inset: 0 auto auto 0; }

/* ─── chips (`Chip`, `ChipGroup`) ───────────────────────────────────────── */

.ui-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 28px;
  padding-inline: 10px;
  border: 1px solid transparent;
  border-radius: var(--radius-pill);
  background: var(--surface-alt);
  color: var(--ink-2);
  font-size: 12px;
  line-height: 16px;
  font-weight: 500;
  white-space: nowrap;
}
.ui-chip.is-on { border-color: var(--accent-soft-border); background: var(--accent-soft); color: var(--accent-strong); }
.ui-chip.ui-mono { font-weight: 500; }
.ui-chips { display: inline-flex; flex-wrap: wrap; gap: 6px; }

/* ─── buttons (`Button` sm/md, `IconButton`) ────────────────────────────── */

.ui-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  height: 32px;
  padding-inline: 12px;
  border: 1px solid transparent;
  border-radius: var(--radius-control);
  background: transparent;
  color: var(--ink-2);
  font: inherit;
  font-size: 14px;
  font-weight: 500;
  line-height: 20px;
  white-space: nowrap;
}
.ui-btn-md { height: 40px; padding-inline: 16px; }
.ui-btn-primary { background: var(--accent-strong); color: var(--ink-inverse); }
.ui-btn-secondary { background: var(--surface); border-color: var(--border-strong); color: var(--ink); }
.ui-btn-ghost { color: var(--ink-2); }
.ui-btn.is-pressed { background: var(--accent-soft); color: var(--accent-strong); }
.ui-iconbtn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: var(--radius-control);
  color: var(--ink-2);
}
.ui-iconbtn-sm { width: 28px; height: 28px; }

/* ─── top bar (editor header, 56 px) ────────────────────────────────────── */

.ui-topbar {
  display: flex;
  align-items: center;
  gap: 8px;
  height: 56px;
  padding-inline: 12px;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
}
.ui-crumb { display: inline-flex; align-items: center; gap: 6px; padding: 4px; color: var(--ink-2); font-size: 14px; }
.ui-crumb .sep { color: var(--faint); }
.ui-save { display: inline-flex; align-items: center; gap: 6px; height: 32px; padding-inline: 8px; color: var(--muted); font-size: 11px; }
.ui-save .dot { width: 8px; height: 8px; border-radius: var(--radius-pill); background: var(--success); }
.ui-spacer { flex: 1 1 auto; }
.ui-group { display: inline-flex; align-items: center; gap: 4px; }

/* ─── tool rail (`Toolbar`, 72 px pill; `ToolButton` 56 × 48) ──────────── */

.ui-rail {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  width: 72px;
  padding: 8px;
  border: 1px solid var(--border);
  border-radius: var(--radius-tool);
  background: var(--surface);
  box-shadow: var(--shadow-panel);
}
.ui-tool {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  width: 56px;
  height: 48px;
  border-radius: var(--radius-md);
  color: var(--ink-2);
  font-size: 12px;
  line-height: 16px;
  font-weight: 500;
}
.ui-tool svg.i { width: 20px; height: 20px; }
.ui-tool.is-active { background: var(--accent-soft); color: var(--accent-strong); }
.ui-rail-sep { width: 32px; height: 1px; margin-block: 4px; background: var(--border); }

/* ─── canvas + rulers ───────────────────────────────────────────────────── */

.ui-canvas { position: relative; overflow: hidden; background: var(--surface); }
.ui-ruler {
  position: absolute;
  z-index: 2;
  background: var(--surface-alt);
  color: var(--muted);
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: 9px;
  line-height: 1;
  pointer-events: none;
}
.ui-ruler-x { top: 0; left: 20px; right: 0; height: 20px; border-bottom: 1px solid var(--border); }
.ui-ruler-y { top: 0; left: 0; bottom: 0; width: 20px; border-right: 1px solid var(--border); }
.ui-ruler svg { display: block; width: 100%; height: 100%; overflow: visible; }
.ui-ruler svg line { stroke: var(--border-strong); stroke-width: 1; }
.ui-ruler svg text { fill: var(--muted); font: 9px "IBM Plex Mono", ui-monospace, monospace; }
.ui-canvas-grid {
  background-image:
    linear-gradient(var(--grid-minor) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid-minor) 1px, transparent 1px),
    linear-gradient(var(--grid-major) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid-major) 1px, transparent 1px);
  background-size: var(--minor, 13px) var(--minor, 13px), var(--minor, 13px) var(--minor, 13px), var(--major, 65px) var(--major, 65px), var(--major, 65px) var(--major, 65px);
}
.ui-float { position: absolute; z-index: 3; }

/* ─── panels (`Panel`, 288 px column) ───────────────────────────────────── */

.ui-panels {
  display: flex;
  flex-direction: column;
  gap: 8px;
  width: 288px;
  flex: none;
  padding: 8px;
  overflow: hidden;
}
.ui-panel {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--border);
  border-radius: var(--radius-panel);
  background: var(--surface);
  box-shadow: var(--shadow-panel);
  flex: none;
}
.ui-panel-head { display: flex; align-items: center; gap: 8px; height: 36px; padding-inline: 12px; }
.ui-panel.is-open > .ui-panel-head { border-bottom: 1px solid var(--border); }
.ui-panel-head .chev { color: var(--faint); }
.ui-panel-head .ui-label { flex: 1 1 auto; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.ui-panel-head .count { font-family: "IBM Plex Mono", ui-monospace, monospace; font-size: 11px; line-height: 16px; color: var(--faint); }
.ui-panel-head .count.ui-danger { color: var(--danger); }
.ui-panel-body { padding: 12px; }
.ui-panel-body.flush { padding: 0; }
.ui-panel-section { padding: 8px 12px 4px; }

/* element rows (`ElementsPanel`) */
.ui-el { display: flex; align-items: center; gap: 8px; height: 32px; padding-inline: 8px 10px; font-size: 14px; color: var(--ink); }
.ui-el .grip { color: var(--faint); }
.ui-el .dot { width: 8px; height: 8px; border-radius: var(--radius-pill); flex: none; }
.ui-el .name { flex: 1 1 auto; min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.ui-el .meta { color: var(--faint); }
.ui-el.is-selected { background: var(--accent-soft); }
.ui-el.is-hidden .name { color: var(--faint); }

/* ─── fields (`Field`, `Select`, `Checkbox`, `Switch`) ──────────────────── */

.ui-field { display: grid; gap: 4px; min-width: 0; }
.ui-field-label { font-size: 12px; line-height: 16px; font-weight: 500; color: var(--muted); }
.ui-input {
  display: flex;
  align-items: center;
  gap: 6px;
  height: 40px;
  padding-inline: 12px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-control);
  background: var(--surface);
  color: var(--ink);
  font-size: 14px;
  line-height: 20px;
  white-space: nowrap;
}
.ui-input-sm { height: 36px; }
.ui-input .unit { margin-left: auto; color: var(--muted); }
.ui-input .ph { color: var(--faint); }
.ui-input.is-focus { border-color: var(--ink); box-shadow: inset 0 0 0 1px var(--ink); }
.ui-select .chev { margin-left: auto; color: var(--muted); }
.ui-hint { font-size: 12px; line-height: 16px; color: var(--muted); }
.ui-fields-2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.ui-fields-3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
.ui-fields-4 { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; }

.ui-check { display: flex; align-items: flex-start; gap: 10px; font-size: 14px; line-height: 20px; color: var(--ink); }
.ui-check .box {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  margin-top: 2px;
  border: 1px solid var(--border-strong);
  border-radius: 3px;
  background: var(--surface);
  color: var(--ink-inverse);
  flex: none;
}
.ui-check .box svg { width: 12px; height: 12px; stroke-width: 2.5; display: none; }
.ui-check.is-checked .box { border-color: var(--accent-strong); background: var(--accent-strong); }
.ui-check.is-checked .box svg { display: block; }
.ui-check.is-disabled { opacity: .5; }
.ui-check .ui-hint { display: block; }

.ui-switch {
  position: relative;
  display: inline-flex;
  align-items: center;
  width: 36px;
  height: 20px;
  flex: none;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-pill);
  background: var(--surface-alt);
}
.ui-switch::after {
  content: "";
  display: block;
  width: 16px;
  height: 16px;
  border-radius: var(--radius-pill);
  background: var(--surface);
  box-shadow: var(--shadow-panel);
  transform: translateX(2px);
}
.ui-switch.is-on { border-color: var(--accent-strong); background: var(--accent-strong); }
.ui-switch.is-on::after { transform: translateX(16px); }
.ui-switch-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; }

/* ─── badges and pills (`LevelBadge`, `PlanChip`) ───────────────────────── */

.ui-pill {
  display: inline-flex;
  align-items: center;
  height: 18px;
  padding-inline: 6px;
  border: 1px solid var(--ink);
  border-radius: var(--radius-pill);
  background: var(--ink);
  color: var(--ink-inverse);
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: 12px;
  line-height: 16px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.ui-pill-soft {
  border-color: var(--border-strong);
  background: var(--surface-alt);
  color: var(--ink-2);
  padding-inline: 10px;
  height: 24px;
  letter-spacing: 1px;
  text-transform: uppercase;
  font-weight: 500;
}
.ui-plan { display: inline-flex; align-items: center; gap: 6px; height: 24px; padding-inline: 10px; border: 1px solid var(--accent-soft-border); border-radius: var(--radius-pill); background: var(--accent-soft); color: var(--accent-strong); font-size: 12px; font-weight: 500; }

/* ─── status bar (28 px) ────────────────────────────────────────────────── */

.ui-status {
  display: flex;
  align-items: center;
  gap: 12px;
  height: 28px;
  padding-inline: 12px;
  border-top: 1px solid var(--border);
  background: var(--surface);
  color: var(--muted);
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: 11px;
  line-height: 16px;
  white-space: nowrap;
  overflow: hidden;
}
.ui-status .hint { font-family: "IBM Plex Sans", system-ui, sans-serif; font-size: 12px; color: var(--faint); flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }

/* ─── section drawer ────────────────────────────────────────────────────── */

.ui-drawer { display: flex; flex-direction: column; border-top: 1px solid var(--border); background: var(--surface); }
.ui-drawer-handle { height: 6px; }
.ui-drawer-head { display: flex; align-items: center; gap: 12px; height: 40px; padding-inline: 12px; border-bottom: 1px solid var(--border); }
.ui-drawer-head .ui-label { font-size: 11px; letter-spacing: .08em; }
.ui-drawer-head .lbl { font-size: 12px; color: var(--faint); text-decoration: underline dotted; text-underline-offset: 2px; }
.ui-drawer-body { position: relative; padding: 8px 12px; background: var(--surface); }
.ui-caption { position: absolute; left: 68px; top: 16px; font-size: 12px; line-height: 16px; color: var(--muted); pointer-events: none; }
.ui-readout { position: absolute; right: 24px; top: 16px; font-family: "IBM Plex Mono", ui-monospace, monospace; font-size: 11px; line-height: 16px; color: var(--muted); }

/* ─── dialog / sheet ────────────────────────────────────────────────────── */

.ui-dialog {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--surface);
  box-shadow: var(--shadow-lift);
  padding: 24px;
}
/* `.x, .ui .x`: a <p> inside the landing's `.card`/`.step` is muted by
   site.css at (0,1,1); the app's tones have to outrank that. */
.ui-dialog-title, .ui .ui-dialog-title { font-size: 20px; line-height: 28px; font-weight: 600; color: var(--ink); letter-spacing: -0.01em; }
.ui-dialog-desc, .ui .ui-dialog-desc { margin-top: 4px; font-size: 14px; line-height: 20px; color: var(--muted); }
.ui-dialog-body { margin-top: 20px; display: grid; gap: 16px; }
.ui-dialog-foot { display: flex; justify-content: flex-end; gap: 8px; margin-top: 24px; }
.ui-dialog-close { position: absolute; right: 16px; top: 16px; color: var(--muted); }
.ui-eyebrow { font-size: 12px; line-height: 16px; font-weight: 500; letter-spacing: 1px; text-transform: uppercase; color: var(--muted); }
.ui-doc { border: 1px solid var(--border); border-radius: var(--radius-card); background: var(--surface); padding: 12px; }
.ui-doc.is-off { opacity: .5; }

/* ─── lists: rules, masses ──────────────────────────────────────────────── */

.ui-rule { display: flex; align-items: flex-start; gap: 8px; padding: 6px 12px; }
.ui-rule svg.i { margin-top: 2px; }
.ui-rule.ok svg.i { color: var(--success); }
.ui-rule.fail svg.i { color: var(--danger); }
.ui-rule.warn svg.i { color: var(--warning); }
.ui-rule.info svg.i { color: var(--muted); }
.ui-rule .ttl { font-size: 14px; line-height: 20px; color: var(--ink); }
.ui-rule .val { font-family: "IBM Plex Mono", ui-monospace, monospace; font-size: 12px; line-height: 16px; color: var(--muted); }
.ui-rule .hint { display: block; margin-top: 2px; font-size: 11px; line-height: 16px; color: var(--muted); }
.ui-rule .line { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 6px; }

.ui-table { width: 100%; border-collapse: collapse; font-size: 14px; line-height: 20px; }
.ui-table th { padding: 0 0 6px; font: 500 11px/16px "IBM Plex Mono", ui-monospace, monospace; letter-spacing: 1px; text-transform: uppercase; color: var(--muted); text-align: left; }
.ui-table td { padding: 3px 0; color: var(--ink); border-top: 1px solid var(--border); }
.ui-table .num, .ui-table th.num { text-align: right; font-family: "IBM Plex Mono", ui-monospace, monospace; font-variant-numeric: tabular-nums; }
.ui-table td.sub { font-size: 11px; line-height: 16px; color: var(--muted); }
.ui-total { display: flex; align-items: baseline; justify-content: space-between; gap: 8px; font-size: 14px; }
.ui-total .num { font-family: "IBM Plex Mono", ui-monospace, monospace; font-variant-numeric: tabular-nums; }

/* ─── alerts ────────────────────────────────────────────────────────────── */

.ui-alert { display: flex; gap: 10px; padding: 10px 12px; border: 1px solid var(--accent-soft-border); border-radius: var(--radius-control); background: var(--accent-soft); font-size: 13px; line-height: 18px; color: var(--ink-2); }
.ui-alert svg.i { color: var(--accent-strong); margin-top: 1px; }
.ui-alert.info { border-color: var(--border); background: var(--surface-alt); }
.ui-alert.warning { border-color: var(--warning-soft-border); background: var(--warning-soft); }
.ui-alert.warning svg.i { color: var(--warning); }

/* ═══ Der Editor — section and replica composition ═══════════════════════ */

/* ─── Der Editor (#editor): the ink band and the editor-window replica ──── */
/* Section ground. `isolation` gives the band its own stacking context, so the
   contour SVG copied from the hero (z-index −1) paints above the ink and below
   the content instead of vanishing behind the section background. */
.section-ink {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background: var(--ink);
  color: rgba(255, 255, 255, .72);
}
.section-ink .hero-contours { color: var(--ink-inverse); opacity: .08; }
.section-ink h2 { color: var(--ink-inverse); }
.section-ink .lead { color: rgba(255, 255, 255, .72); }

/* Eyebrow on ink: the level pill keeps its shape, only the tones invert. */
.eyebrow-inverse { color: rgba(255, 255, 255, .7); }
.eyebrow-inverse .level {
  border-color: rgba(255, 255, 255, .28);
  background: rgba(255, 255, 255, .08);
  color: var(--ink-inverse);
}

/* ─── composition: the editor window at 1120 × 862 ──────────────────────── */
/* Authored 1 px larger than the 1118 × 860 interior on each axis, because the
   1 px frame is part of the box (`box-sizing: border-box` in `.ui`). Inside:
   top bar 56 · body 776 = [canvas 480 + drawer 296 | panel column] · status 28.
   The drawer belongs to the canvas column, exactly as in `EditorFrame`: the
   panel column runs from the top bar to the status bar. */
.editor-stage { margin-top: 48px; }
/* shadow-lift is the ink colour at 12 % — on the ink band it is invisible, on
   any lighter ground it lifts the window. The fit box clips the composition,
   so the shadow has to sit on the box, not on the scaled window. */
.editor-fit .ui-fit-box { box-shadow: var(--shadow-lift); }
.ui-editor {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--paper);
  overflow: hidden;
}
.ui-editor > .ui-topbar, .ui-editor > .ui-status { flex: none; }
.editor-body { display: flex; flex: none; height: 776px; }
.editor-main { display: flex; flex-direction: column; flex: none; width: 822px; }
.editor-canvas { flex: none; width: 822px; height: 480px; }
/* The renderer's 822 × 480 plan is spliced into `.editor-plan`; the wrapper is
   what the phone layout moves, so the SVG's own `inset: 0` never has to be
   overridden. */
.editor-plan { position: absolute; inset: 0; }
.editor-drawer { flex: none; height: 296px; }
.editor-drawer .ui-drawer-body { flex: 1 1 auto; min-height: 0; overflow: hidden; }
.editor-cut { position: relative; width: 798px; height: 240px; }
/* 296 = the 288 px app column plus the spec's 8 px, so 822 + 296 + 2 = 1120. */
.editor-panels { width: 296px; height: 776px; }

/* Every button in the editor chrome is the app's `size="sm"` — 32 px high
   with 12 px text and 14 px icons (`Button.tsx`); the grid select is 32 × 104. */
.ui-editor .ui-btn { font-size: 12px; gap: 8px; }
.ui-editor .ui-btn svg.i { width: 14px; height: 14px; }
.ui-editor .ui-topbar .ui-select { width: 104px; height: 32px; padding-inline: 10px; font-size: 12px; }
/* The crumb is the only thing that may shrink — the app truncates it too. Its
   4 px padding is a hover hit area, invisible at rest; without it the full
   project / scene name clears the bar with a few pixels to spare. */
.ui-editor .ui-crumb { flex: 0 1 auto; min-width: 0; padding-inline: 0; }
/* The view controls push right by margin, not by a spacer: a spacer element is
   one more 8 px gap, and the bar is full to the pixel at 1118. */
.editor-view { gap: 8px; margin-left: auto; }
.editor-actions { gap: 6px; }

/* Tool rail: 15 tiles at 48 px are taller than a 480 px canvas; the app keeps
   the rail 12 px off the bottom edge and scrolls it. The replica shows the same
   cut — the tiles run out under the pill's bottom padding (`flex: none`, or the
   column would squeeze them to fit). 28 px from the left: clear of the y ruler,
   whose labels the app's rail covers. */
/* Cut on a tile boundary (8 tiles + padding): the app scrolls its rail at
   this height; a half icon under „Höhe“ read as an orphan. */
.editor-rail { left: 28px; top: 32px; max-height: 416px; overflow: hidden; }
.editor-rail > * { flex: none; }

/* Drawer head: one line, nothing wraps or shrinks; the action group is pushed
   right by its margin (the app's `ml-auto`) — a spacer would cost one more
   12 px gap, and the head has 5 px to spare at 822. */
.editor-drawer .ui-drawer-head > * { flex: none; }
.editor-drawer-actions { margin-left: auto; }
.editor-drawer .ui-drawer-head .ui-chips { flex-wrap: nowrap; }

/* Callout markers on the composition, and the same badge as list numbers. */
.ui-marker {
  position: absolute;
  z-index: 5;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border: 2px solid var(--surface);
  border-radius: var(--radius-pill);
  background: var(--accent);
  color: var(--ink-inverse);
  box-shadow: var(--shadow-panel);
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: 12px;
  line-height: 1;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

/* ─── legend ────────────────────────────────────────────────────────────── */
.editor-legend {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 32px 24px;
  margin-top: 40px;
}
.editor-legend li { display: grid; gap: 10px; align-content: start; }
/* Real text on the accent: `accent` reaches only 3.5:1 under white, the
   strong tone 5.0:1 — the badge keeps its look and passes AA. */
.editor-legend .ui-marker { position: static; background: var(--accent-strong); }
.editor-legend h3 { font-size: 1rem; line-height: 1.4; font-weight: 600; color: var(--ink-inverse); }
.editor-legend p { font-size: .875rem; line-height: 1.55; color: rgba(255, 255, 255, .72); }

@media (max-width: 960px) {
  .editor-legend { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 600px) {
  .editor-legend { grid-template-columns: minmax(0, 1fr); }
}

/* ─── phone: a crop of the same window instead of a scaled-down one ─────── */
/* Below 720 px the fluid scale would put the panel text at 4 px. The window
   reflows instead: crumb and "Exportieren" in the top bar, a 320 px canvas that
   shows the house at 1:1, the drawer with its head and a 200 px strip of the
   section, the status without the hint. Rulers, rail, panels and the callout
   markers are desktop-only — their positions belong to the 822 × 480 plan. */
/* Tablet (720–960): the whole 1120 px window scaled to 0,64 gave 7–9 px
   text. Show the canvas column alone at ~0,86 instead: no panel column, no
   view chips in the top bar, the two panel markers gone with the panels. */
@media (min-width: 720px) and (max-width: 960px) {
  .editor-fit .ui-fit-box { aspect-ratio: 824 / 862; }
  .editor-fit .ui-fixed { width: 824px; }
  .editor-fit .editor-panels, .editor-fit .editor-view,
  .editor-fit .ui-marker:nth-of-type(3), .editor-fit .ui-marker:nth-of-type(4) { display: none; }
  .editor-fit .editor-actions { margin-left: auto; }
}
@media (max-width: 719.98px) {
  .editor-fit .ui-fit-box { aspect-ratio: auto; height: auto; }
  .editor-fit .ui-fit-box > .ui-fixed { position: static; width: 100%; height: auto; transform: none; }
  .editor-fit .ui-topbar { gap: 8px; padding-inline: 8px; }
  .editor-fit .ui-topbar > :not(.ui-crumb):not(.editor-actions),
  .editor-fit .editor-actions > :not(.ui-btn-primary),
  .editor-fit .ui-ruler, .editor-fit .editor-rail, .editor-fit .editor-panels,
  .editor-fit .ui-marker, .editor-fit .ui-status .hint, .editor-fit .ui-readout { display: none; }
  .editor-actions { margin-left: auto; }
  .editor-body { flex-direction: column; height: auto; }
  .editor-main { width: 100%; }
  .editor-canvas { width: 100%; height: 320px; }
  .editor-plan, .editor-cut {
    inset: auto;
    left: 50%;
    top: 50%;
    width: 822px;
    height: 480px;
    transform: translate(-50%, -50%);
  }
  .editor-drawer { height: auto; }
  .editor-drawer .ui-drawer-head { flex-wrap: wrap; height: auto; padding-block: 6px; gap: 6px 12px; }
  .editor-drawer .ui-drawer-head .ui-chips { flex-wrap: wrap; }
  .editor-drawer .ui-drawer-body { height: 200px; }
  .editor-cut { position: absolute; width: 798px; height: 240px; }
}

/* ═══ Funktionen vignettes and Ablauf fragments ══════════════════════════ */

/* ─── vignettes (Funktionen cards, Ablauf steps) ────────────────────────── */
/* A `.vg` is the visual on top of a feature card or beside a step: a bordered
   box in the app's surface colour holding a compact replica — a corner of the
   canvas, one panel, one dialog. The block is aria-hidden as a whole, the
   section's real copy stands next to it, and nothing inside is a control
   (every "button" is a span). Dense compositions are authored at a fixed
   --w × --h inside .ui-fit/.ui-fit-box/.ui-fixed and scale as one piece; the
   flowing ones (panels) simply overflow the box bottom, which reads as a
   panel that scrolls. */

.vg {
  position: relative;
  width: 100%;
  aspect-ratio: 5 / 3;
  margin-bottom: 18px;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--surface);
  overflow: hidden;
}
.vg-paper { background: var(--paper); }
.vg .ui-fixed { overflow: hidden; }
.vg-plan > svg { display: block; }

/* 1 · mini canvas: plan under a scaled tool rail, snap chips and status bar */
.vg-draw .vg-plan { position: absolute; left: 0; top: 0; }
.vg-draw .ui-rail { position: absolute; left: 8px; top: 8px; z-index: 3; transform: scale(.85); transform-origin: top left; }
.vg-draw .ui-chips { position: absolute; right: 8px; top: 8px; z-index: 3; }
.vg-draw .ui-status { position: absolute; left: 0; right: 0; bottom: 0; z-index: 3; }

/* 2 · section drawer: head over the renderer's section, enlarged to the body */
.vg-drawer .ui-drawer-head { background: var(--surface); }
.vg-drawer .ui-drawer-body { display: flex; justify-content: center; align-items: flex-start; height: 260px; padding: 0; }
.vg-drawer .vg-plan { transform: scale(1.35); transform-origin: top center; }

/* 3/4 · a panel floating over the paper, cut by the box bottom.
   (`.ui p` resets padding at (0,1,1), so the paragraph rules carry `.ui`.) */
.vg-panel { padding: 10px 10px 0; }
/* The box bottom cuts wherever the card's ratio puts it — through a table
   row at tablet widths. A fade turns the cut into "more below". */
.vg-panel::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 28px; background: linear-gradient(transparent, var(--paper)); pointer-events: none; }
.ui .vg-summary { padding: 8px 12px 4px; }
.ui .vg-link { padding: 4px 12px 12px; color: var(--accent-strong); font-weight: 500; }
.vg-masses { display: grid; gap: 6px; }
.vg-total-lbl { display: inline-flex; align-items: center; gap: 6px; color: var(--ink); }
.vg-dot { width: 8px; height: 8px; border-radius: var(--radius-pill); }
.vg-dot.danger { background: var(--danger); }
.vg-dot.success { background: var(--success); }
.vg-masses .vg-net { padding-top: 6px; border-top: 1px solid var(--border); }
.vg-dl { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 2px 8px; }
.vg-masses .ui-table { margin-top: 6px; }
.vg .ui-table .sub { display: block; font-size: 11px; line-height: 16px; color: var(--faint); }

/* 5/6 · a dialog or sheet that is the whole box: the box border is its border.
   The export dialog is a little tighter than the app's 24 px so the box edge
   falls just under the Blickrichtungen row instead of through a document. */
.vg .ui-dialog { position: relative; }
/* …except the small floating ones over a mini canvas (steps 01/02). */
.vg .ui-dialog.vg-dialog-sm { position: absolute; }
.vg-fill { width: 100%; height: 100%; border: 0; border-radius: 0; box-shadow: none; }
/* 5 · the export dialog at 400 px, so the card shows it at ≥ 0,75 — at 560 it
   scaled to 0,55 and read as a thumbnail. One document column; the box edge
   cuts through the Blickrichtungen row, which reads as "more below". */
.vg-export { padding: 16px; }
.vg-export .ui-dialog-title, .ui .vg-export .ui-dialog-title { font-size: 16px; line-height: 22px; }
.vg-export .ui-dialog-close { right: 12px; top: 12px; }
.vg-export .ui-dialog-body { margin-top: 10px; gap: 10px; }
.vg-docs { display: grid; grid-template-columns: minmax(0, 1fr); gap: 6px; margin-top: 6px; }
.vg-docs .ui-doc { padding: 10px; }
.vg-docs .ui-check > span:last-child { min-width: 0; }
.vg-wrap { flex-wrap: wrap; }
.vg .ui-switch-row .ui-hint { display: block; }
.vg-lock { display: inline-flex; align-items: center; gap: 4px; letter-spacing: .04em; text-transform: uppercase; }
.vg-lock svg { width: 12px; height: 12px; }
/* 6 · share card full width, the saved versions beneath — 400 px for the
   same reason as the export dialog. */
.vg-share { display: grid; grid-template-columns: minmax(0, 1fr); gap: 10px; padding: 14px; align-content: start; }
.vg-share .ui-doc { display: grid; gap: 8px; align-content: start; }
.vg-strong { font-weight: 500; color: var(--ink); }
.ui-status-chip {
  display: inline-flex;
  align-items: center;
  height: 20px;
  padding-inline: 8px;
  border: 1px solid var(--success-soft-border);
  border-radius: var(--radius-pill);
  background: var(--success-soft);
  color: var(--success);
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: 11px;
  line-height: 16px;
  font-weight: 500;
  white-space: nowrap;
}
.ui .vg-versions ul { margin-top: 6px; }
.vg-versions li { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: 0 10px; padding-block: 6px; border-top: 1px solid var(--border); }
.vg-versions li:first-child { padding-top: 0; border-top: 0; }
.vg-versions li .ui-truncate, .vg-versions li .ui-xxs { min-width: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.vg-versions .ui-btn { height: 28px; padding-inline: 8px; font-size: 12px; }

/* Between 601 and 960 px the feature grid is one column and a card is up to
   ~720 px wide: a fixed composition scaled 2× there looks like a toy, so the
   vignette sits beside the copy at about half the card instead. */
@media (min-width: 601px) and (max-width: 960px) {
  .feature-card { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 4fr); gap: 0 24px; align-content: center; }
  .feature-card > .vg { grid-column: 1; grid-row: 1 / span 2; margin-bottom: 0; }
  .feature-card > h3 { grid-column: 2; align-self: end; }
  .feature-card > p { grid-column: 2; align-self: start; }
}

/* ─── Ablauf: index | copy | fragment ───────────────────────────────────── */
/* The fragment is a `.vg` without the card ratio: canvas minis fit 320 × 220
   as one piece, the Eigenschaften panel takes its natural height. Below
   960 px it moves under the copy, below 600 px it takes the whole width. */
.vg-step { aspect-ratio: auto; margin: 0; }
@media (min-width: 961px) {
  .step { grid-template-columns: 88px minmax(0, 1fr) 320px; column-gap: 32px; align-items: start; }
}
@media (max-width: 960px) {
  .vg-step { max-width: 320px; margin-top: 8px; }
}
@media (min-width: 721px) and (max-width: 960px) {
  .vg-step { grid-column: 2; }
}
@media (max-width: 600px) {
  .vg-step { max-width: none; }
}
.vg-mini .vg-plan { position: absolute; left: 0; top: 0; }
/* Narrow and stacked, so the dialog covers the empty right of the mini
   canvas and not the plot: the view is framed with the plot on the left. */
.vg-dialog-sm { position: absolute; z-index: 3; right: 10px; bottom: 10px; display: grid; gap: 6px; width: 168px; padding: 10px; box-shadow: var(--shadow-lift); }
.vg-dialog-sm .ui-fields-2 { grid-template-columns: minmax(0, 1fr); }
.vg-dialog-sm .ttl { font-size: 14px; line-height: 18px; font-weight: 500; color: var(--ink); }
.vg-dialog-sm .ui-fields-2 { gap: 6px; }
/* 30 px controls: with a two-line title the dialog otherwise outgrows the
   220 px box and loses its top edge to the clip. */
.vg-dialog-sm .ui-input, .vg-dialog-sm .ui-btn { height: 30px; padding-inline: 8px; }
.vg-dialog-sm .ui-btn { justify-self: end; }
.vg-props .ui-panel { border: 0; border-radius: 0; box-shadow: none; }
.vg-props .ui-panel-body { display: grid; gap: 10px; }
.vg-props .ui-fields-2 { gap: 8px; }
.vg-props .ui-btn { justify-self: start; margin-left: -12px; }

/* Step 04: the Regel-Check panel floating over the rule crop, sized like the
   small dialogs of steps 01/02 so the four fragments read as one series. */
.vg-panel-sm { position: absolute; z-index: 3; right: 10px; bottom: 10px; width: 210px; box-shadow: var(--shadow-lift); }
.vg-panel-sm.ui-panel { border-color: var(--border-strong); }
.ui .vg-panel-sm .vg-summary { padding: 6px 12px 0; }
.vg-panel-sm .ui-rule { padding: 4px 12px 10px; }

/* ─── "Im Raum": the editor's 3D view (section #raum) ───────────────────── */
/* The window is `.ui-editor` again — same border, radius and paper ground as
   the big editor replica, only its body is one canvas instead of the canvas
   plus panel columns. The chrome inside the canvas is the app's: a floating
   toolbar top left, the close control top right, the compass bottom left. */
.raum-stage { margin-top: 48px; }
.raum-fit .ui-fit-box { box-shadow: var(--shadow-lift); }
.raum-canvas { flex: none; width: 960px; height: 600px; }
/* The renderer's 960 × 600 projection is spliced into `.raum-view`. */
.raum-view { position: absolute; inset: 0; }
.raum-tools {
  position: absolute;
  left: 12px;
  top: 12px;
  z-index: 3;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px;
  border-radius: var(--radius-tool);
  background: var(--surface);
  box-shadow: var(--shadow-panel);
}
.raum-close { position: absolute; right: 12px; top: 12px; z-index: 3; background: var(--surface); box-shadow: var(--shadow-panel); }
.raum-compass {
  position: absolute;
  left: 12px;
  bottom: 12px;
  z-index: 3;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 28px;
  padding-inline: 8px;
  border-radius: var(--radius-pill);
  background: var(--surface);
  box-shadow: var(--shadow-panel);
  color: var(--muted);
  font-family: "IBM Plex Mono", ui-monospace, monospace;
  font-size: 11px;
  line-height: 16px;
}
/* North needle: the app turns it with the camera, the still shows plan north
   at this camera's azimuth (south-west, so north points up and to the right). */
.raum-compass svg { width: 14px; height: 14px; color: var(--ink); transform: rotate(45deg); }

/* The three claims under the window: the editor legend's type, without its
   numbered markers — nothing in the picture is keyed to them. */
.raum-legend {
  display: grid;
  gap: 24px 32px;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  margin: 40px 0 0;
  padding: 0;
  list-style: none;
}
.raum-legend h3 { margin: 0 0 6px; font-size: 17px; line-height: 24px; }
.raum-legend p { margin: 0; color: var(--ink-2); font-size: 15px; line-height: 24px; }

@media (max-width: 960px) {
  .raum-legend { grid-template-columns: minmax(0, 1fr); gap: 20px; }
}

/* Phone: a crop of the same window instead of a scaled-down one — the rule
   the editor replica follows. Below 720 px the fluid scale would put the
   chrome at 5 px and the level pills below legibility; the window reflows
   instead and the canvas shows the middle of the projection (house, Garage,
   Terrasse) at 1:1. Toolbar, compass and close control are desktop-only:
   their positions belong to the 960 × 600 canvas, and on a phone they would
   cover a third of the picture. The status line stays — truncated, it still
   says what the view does. */
@media (max-width: 719.98px) {
  .raum-fit .ui-fit-box { aspect-ratio: auto; height: auto; }
  .raum-fit .ui-fit-box > .ui-fixed { position: static; width: 100%; height: auto; transform: none; }
  .raum-fit .ui-topbar { gap: 8px; padding-inline: 8px; }
  .raum-fit .ui-topbar > :not(.ui-crumb):not(.editor-actions),
  .raum-fit .editor-actions > :not(.ui-btn-primary),
  .raum-fit .raum-tools,
  .raum-fit .raum-compass,
  .raum-fit .raum-close { display: none; }
  .raum-canvas { width: 100%; height: 300px; }
  /* 40 px below centre: the 300 px window then shows y 110 … 410 of the
     projection, which is the one band of it that cuts through no pill —
     `Garage −0,15` sits at y 138 … 156, `6 +0,36` at 390 … 408. */
  .raum-view {
    inset: auto;
    left: 50%;
    top: 50%;
    width: 960px;
    height: 600px;
    transform: translate(-50%, calc(-50% + 40px));
  }
}
