/* ── Sauce Labs AURA tokens — light ──────────────────────────────
   This panel is chrome around an artwork canvas, so it recedes: white
   surface, pine ink, Signature for the one primary action. Lime is a
   focus/active accent only — as a fill it read as phosphor-on-black, and
   it is one of the duotone inks, so the UI competed with its own output.

   Deliberately NOT the documented sauce-labs-brand product system
   (Proxima Nova + Blue 700). UI blue fights AURA duotone output, and this
   tool is not the product. See docs/superpowers/specs.

   Nothing here styles a bare p / span / button. The previous stylesheet's
   "hacker terminal" feel came almost entirely from three global selectors
   applying uppercase mono to every label and control. Everything below is
   class-scoped so that cannot come back. */
@import url("vendor/fonts/fonts.css");

:root {
  /* AURA palette */
  --sl-deep-green: #0a140a;
  --sl-pine: #192319;
  --sl-slate: #2d372d;
  --sl-moss: #3c483c;
  --sl-signature: #043423;
  --sl-olive: #6d7344;
  --sl-khaki: #abad6c;
  --sl-highlight: #abe082;
  --sl-ivory: #f0f0ec;
  --sl-warm-gray: #dcdcd7;
  --sl-stone: #c8c8be;
  --sl-flare: #f55524;
  --sl-crimson: #961001;
  --bg-subtle: #eeece4;

  /* Surfaces & ink */
  --surface: #fff;
  --hairline: #e7e5dc;
  --field: #fbfbf9;
  --ink: var(--sl-pine);
  --ink-label: rgba(25, 35, 25, 0.74);
  --ink-muted: rgba(25, 35, 25, 0.46);
  --ink-faint: rgba(25, 35, 25, 0.4);

  --font-body: "Atkinson Hyperlegible Next", system-ui, sans-serif;
  --font-mono: "Atkinson Hyperlegible Mono", ui-monospace, monospace;

  --radius-xs: 7px;
  --radius-md: 16px;
  --radius-pill: 999px;

  --shadow-panel:
    0 1px 2px rgba(25, 35, 25, 0.04), 0 12px 32px rgba(25, 35, 25, 0.09);
  --shadow-canvas: 0 8px 36px rgba(25, 35, 25, 0.16);
}

* {
  box-sizing: border-box;
}

html,
body {
  height: 100%;
  font-family: var(--font-body);
}

body {
  overflow: hidden;
  padding: 0;
  margin: 0;
  /* warm ivory transparency checker, calmed */
  background: conic-gradient(
    var(--sl-ivory) 90deg,
    var(--bg-subtle) 90deg 180deg,
    var(--sl-ivory) 180deg 270deg,
    var(--bg-subtle) 270deg
  );
  background-size: 22px 22px;
}

/* Scoped to p5's own canvas (it tags it .p5Canvas). A bare `canvas` selector
   also caught the prep preview's canvas and yanked it out of flow — the same
   over-broad-selector mistake this stylesheet was written to get rid of. */
canvas.p5Canvas {
  position: absolute;
  z-index: 0;
  margin: auto;
  top: 0;
  left: 0;
  background-color: transparent;
  box-shadow: var(--shadow-canvas);
  border-radius: var(--radius-xs);
}

#p5_loading {
  display: none;
}

/* ── Panel shell ─────────────────────────────────────────────────
   Hugs its content (height:auto + max-height) rather than stretching
   top-to-bottom, which was costing ~200px of empty card. Wide on steps 1–2
   (one column gets the whole width); narrow on step 3, where it only ever
   holds Source+Image stacked — Style is its own panel (#stylePanel). */
#controls {
  position: fixed;
  top: 14px;
  left: 14px;
  width: 1020px;
  max-height: calc(100vh - 28px);
  background: var(--surface);
  border: none;
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-panel);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  color: var(--ink);
  margin: 0;
  padding: 0;
  z-index: 1;
}

#controls[data-step="3"] {
  width: 340px;
}

#panelTitle {
  font-size: 0.9375rem;
  font-weight: 700;
  letter-spacing: -0.005em;
  color: var(--sl-signature);
  margin: 0;
  padding: 16px 20px 12px;
}

/* Source and Image stack in a single column — one shows at a time on
   steps 1–2 (full width), both show together on step 3. */
#grid {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  padding: 2px 20px 4px;
}

/* Only step 3 shows both columns at once, so only step 3 needs a divider
   between them. */
#grid > .col + .col {
  padding-top: 16px;
  margin-top: 16px;
  border-top: 1px solid var(--hairline);
}

#grid::-webkit-scrollbar {
  width: 4px;
}

#grid::-webkit-scrollbar-thumb {
  background: var(--sl-stone);
  border-radius: var(--radius-pill);
}

/* ── Style panel ───────────────────────────────────────────────────
   A second fixed panel, pinned to the right edge, mirroring #controls'
   own shell. Only step 3 shows it (getAvailableArea() in sketch.js
   reserves canvas space for it whenever it's visible). */
#stylePanel {
  display: none;
  position: fixed;
  top: 14px;
  right: 14px;
  width: 300px;
  max-height: calc(100vh - 28px);
  background: var(--surface);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-panel);
  overflow: hidden;
  flex-direction: column;
  color: var(--ink);
  z-index: 1;
}

#controls[data-step="3"] ~ #stylePanel {
  display: flex;
}

#stylePanel #styleCol {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  padding: 16px 20px 4px;
}

.section + .section {
  padding-top: 16px;
  margin-top: 16px;
  border-top: 1px solid var(--hairline);
}

.sectionHead {
  font: 500 0.6875rem/1 var(--font-mono);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--sl-olive);
  margin: 0 0 11px;
}

/* ── Label / value rows ──────────────────────────────────────────
   Label left, value right — scans as a spec list instead of a telemetry
   dump ("CONTRAST: 40"). */
.row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  margin: 0 0 5px;
}

.lbl {
  font-size: 0.8125rem;
  color: var(--ink-label);
  white-space: nowrap;
}

.lbl .unit {
  color: var(--ink-faint);
}

.val {
  font: 400 0.8125rem/1 var(--font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}

.ctrl + .row {
  margin-top: 13px;
}

.hint {
  font-size: 0.6875rem;
  line-height: 1.4;
  color: var(--ink-muted);
  margin: 6px 0 0;
}

/* ── Controls ────────────────────────────────────────────────────  */
input[type="range"].ctrl {
  width: 100%;
  margin: 1px 0 0;
  accent-color: var(--sl-signature);
  display: block;
}

input[type="text"] {
  width: 100%;
  padding: 8px 9px;
  margin: 0;
  background: var(--field);
  color: var(--ink);
  border: 1px solid var(--sl-warm-gray);
  border-radius: var(--radius-xs);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
}

select {
  padding: 8px 9px;
  margin: 0;
  background: var(--field);
  color: var(--ink);
  border: 1px solid var(--sl-warm-gray);
  border-radius: var(--radius-xs);
  font-family: var(--font-body);
  font-size: 0.8125rem;
}

:focus-visible {
  outline: 2px solid var(--sl-highlight);
  outline-offset: 2px;
}

/* ── Source: segmented control ───────────────────────────────────
   White active thumb on an ivory track, replacing the lime pill pair. */
.sourceToggle {
  display: flex;
  gap: 2px;
  padding: 3px;
  margin: 0 0 13px;
  background: var(--sl-ivory);
  border-radius: var(--radius-pill);
}

.sourceToggle button {
  flex: 1;
  border: none;
  cursor: pointer;
  padding: 6px 0;
  margin: 0;
  border-radius: var(--radius-pill);
  background: transparent;
  font-family: var(--font-body);
  font-size: 0.8125rem;
  color: var(--ink-muted);
  transition:
    background 140ms ease,
    color 140ms ease;
}

.sourceToggle button.toggleActive {
  background: var(--surface);
  color: var(--sl-signature);
  font-weight: 600;
  box-shadow: 0 1px 2px rgba(25, 35, 25, 0.1);
}

/* 52px source chip instead of a 150px preview — one of the bigger height wins */
.srcRow {
  display: flex;
  gap: 9px;
  align-items: center;
}

.srcRow img {
  width: 52px;
  height: 52px;
  flex: 0 0 52px;
  object-fit: cover;
  border-radius: var(--radius-xs);
  border: 1px solid var(--hairline);
}

/* ── Source panes ────────────────────────────────────────────────────
   The toggle swaps which pane exists. Only one mode's controls are ever on
   screen, so the step asks one question at a time. */
#controls[data-source="url"] .uploadPane,
#controls[data-source="upload"] .urlPane {
  display: none;
}

.srcPane {
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-height: 0;
}

/* The zone is the control — clicking it opens the picker, so the browser's
   own "Choose File / No file chosen" never needs to be visible. */
.dropZone {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 120px;
  padding: 18px;
  border: 1.5px dashed var(--sl-stone);
  border-radius: var(--radius-md);
  background: var(--field);
  cursor: pointer;
  text-align: center;
  transition:
    border-color 120ms ease,
    background 120ms ease;
}

.dropZone:hover {
  border-color: var(--sl-olive);
  background: #fff;
}

.dropZone.isOver {
  border-color: var(--sl-signature);
  border-style: solid;
  background: #fff;
}

/* Visually gone, still the thing that opens the file picker. */
.dropZone input[type="file"] {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.dropPrompt {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.dropTitle {
  font-family: var(--font-body);
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--ink);
}

.dropHint {
  font-family: var(--font-body);
  font-size: 0.6875rem;
  color: var(--ink-muted);
}

/* Once an image is in, it speaks for itself and the prompt steps aside. */
.dropZone.hasImage .dropPrompt {
  display: none;
}

.uploadName {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  color: var(--ink-label);
  overflow-wrap: anywhere;
}

.uploadThumb {
  width: 52px;
  height: 52px;
  object-fit: cover;
  border-radius: var(--radius-xs);
  border: 1px solid var(--hairline);
  margin-top: 8px;
}

/* ── Checkbox rows ───────────────────────────────────────────────
   p5's createCheckbox emits <div><label><input><span>text</span></label></div>
   — the input is nested INSIDE the label, so the flex row that spaces the box
   from its text has to be the label, not the wrapper. */
.toggleRow {
  margin: 15px 0 9px;
}

.toggleRow label {
  display: flex;
  align-items: center;
  gap: 8px;
}

.toggleRow input[type="checkbox"] {
  accent-color: var(--sl-signature);
  width: 15px;
  height: 15px;
  margin: 0;
  flex: 0 0 auto;
}

.toggleRow label,
.toggleRow span {
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--ink);
  cursor: pointer;
}

/* ── Prep preview ────────────────────────────────────────────────
   The renderer's-eye view: one cell per tile, skipped tiles left blank. The
   checker shows through those gaps, which is what the exported PNG does too
   when Show background is off. */
#prepPreviewWrap {
  border: 1px solid var(--hairline);
  border-radius: var(--radius-xs);
  overflow: hidden;
  background: conic-gradient(
      #fff 90deg,
      var(--field) 90deg 180deg,
      #fff 180deg 270deg,
      var(--field) 270deg
    )
    0 0 / 10px 10px;
  line-height: 0;
  padding: 4px;
  display: flex;
  justify-content: center;
  align-items: center;
  height: 132px; /* default: Style step's narrow Image column */
}

/* Tune step: the prep result is the whole point of this page, so it takes
   every pixel the sliders and the key don't need — same element, just given
   more box to fill (see updatePrepPreview(), which sizes off this box, not a
   constant). A fixed 480px here is what pushed the key below the fold. */
#controls[data-step="2"] #prepPreviewWrap {
  flex: 1 1 auto;
  height: auto;
  min-height: 140px;
}

#prepPreviewCanvas {
  display: block;
  /* Nearest-neighbour: the tile grid is the information here, and smoothing
     would blur away exactly the thing being judged. */
  image-rendering: pixelated;
}

/* ── Style layout: controls on the left, a duotone rail on the right ──  */
.styleBody {
  display: flex;
  gap: 12px;
  align-items: flex-start;
}

.styleMain {
  flex: 1;
  min-width: 0;
}

.swatchRail {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.swatch {
  -webkit-appearance: none;
  appearance: none;
  width: 34px;
  height: 34px;
  padding: 0;
  margin: 0;
  border-radius: 50%;
  border: 1px solid rgba(25, 35, 25, 0.14);
  overflow: hidden;
  cursor: pointer;
  flex: none;
  transition:
    transform 90ms ease,
    box-shadow 140ms ease;
}

.swatch:hover {
  transform: scale(1.1);
  box-shadow: 0 2px 6px rgba(25, 35, 25, 0.18);
}

/* ── Pattern swatches ────────────────────────────────────────────
   A generic colour chip told you the colour but not what it did. Each of
   these renders its own actual output and stays clickable to recolour. */
.patternGroup {
  display: flex;
  gap: 11px;
  align-items: flex-start;
}

.patternGroup .fields {
  flex: 1;
  min-width: 0;
}

.patSwatch {
  flex: 0 0 58px;
  width: 58px;
  height: 58px;
  padding: 0;
  margin: 0;
  cursor: pointer;
  border: 1px solid var(--sl-warm-gray);
  border-radius: var(--radius-xs);
  background: var(--field);
  overflow: hidden;
  position: relative;
  transition:
    border-color 140ms ease,
    box-shadow 140ms ease;
}

.patSwatch:hover {
  border-color: var(--sl-olive);
  box-shadow: 0 2px 8px rgba(25, 35, 25, 0.13);
}

.patSwatch svg {
  display: block;
  width: 100%;
  height: 100%;
}

.patSwatch .pip {
  position: absolute;
  right: 3px;
  bottom: 3px;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  border: 1.5px solid #fff;
  box-shadow: 0 0 0 1px rgba(25, 35, 25, 0.22);
}

/* Background genuinely is a flat field — no pattern to show. */
.flatSwatch {
  flex: 0 0 58px;
  width: 58px;
  height: 32px;
  cursor: pointer;
  padding: 0;
  margin: 0;
  border: 1px solid var(--sl-warm-gray);
  border-radius: var(--radius-xs);
}

/* ── Combined output preview ─────────────────────────────────────  */
#previewWrap {
  border: 1px solid var(--hairline);
  border-radius: var(--radius-xs);
  overflow: hidden;
  background: var(--sl-ivory);
  line-height: 0;
}

#previewWrap svg {
  display: block;
  width: 100%;
  height: auto;
}

/* ── Brand colour popover ────────────────────────────────────────
   Anchored outside the panel's right edge so it never covers the control
   it edits. */
#pop {
  position: fixed;
  z-index: 50;
  display: none;
  background: var(--surface);
  border: 1px solid var(--sl-warm-gray);
  border-radius: 12px;
  box-shadow: 0 8px 28px rgba(25, 35, 25, 0.2);
  padding: 11px;
  width: 212px;
}

#pop.open {
  display: block;
}

#pop .popHead {
  font: 500 0.625rem/1 var(--font-mono);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--sl-olive);
  margin: 0 0 9px;
}

#pop .brandGrid {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 6px;
}

#pop .brandGrid button {
  width: 100%;
  aspect-ratio: 1;
  border-radius: 50%;
  cursor: pointer;
  padding: 0;
  margin: 0;
  border: 1px solid rgba(25, 35, 25, 0.16);
  transition: transform 90ms ease;
}

#pop .brandGrid button:hover {
  transform: scale(1.14);
}

#pop .brandGrid button[aria-current="true"] {
  box-shadow: 0 0 0 2px var(--sl-signature);
}

/* Custom hex — Full Sauce only. The popover is brand-only by design; this
   is the escape hatch, and it stays hidden unless full=1. */
#pop .customRow {
  display: none;
  align-items: center;
  gap: 7px;
  margin: 10px 0 0;
  padding-top: 9px;
  border-top: 1px solid var(--hairline);
}

#pop.hasCustom .customRow {
  display: flex;
}

#pop .customRow .customLbl {
  font-size: 0.6875rem;
  color: var(--ink-muted);
}

#pop .customRow input[type="color"] {
  width: 34px;
  height: 24px;
  padding: 0;
  margin: 0;
  border: 1px solid var(--sl-warm-gray);
  border-radius: var(--radius-xs);
  background: var(--field);
  cursor: pointer;
}

/* The live value store for each colour. Presentation is the swatch above;
   these only surface as the Full Sauce custom input inside the popover. */
.colorStore {
  display: none;
}

/* ── Messages to humans ──────────────────────────────────────────  */
.uploadError,
.prepStatus {
  font-family: var(--font-body);
  font-size: 0.6875rem;
  line-height: 1.45;
  margin: 8px 0 0;
}

.uploadError {
  color: var(--sl-crimson);
}

.prepStatus {
  color: var(--ink-muted);
}

/* Something went wrong and the render stopped. */
.prepStatus.isError {
  color: var(--sl-crimson);
}

/* It worked, but the result may surprise you. */
.prepStatus.isWarning {
  color: var(--sl-olive);
}

/* ── Footer — stacked, lives in the narrow Style panel ────────────  */
#footer {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 10px;
  padding: 16px 20px;
  border-top: 1px solid var(--hairline);
}

#footer .fLbl {
  font-size: 0.75rem;
  color: var(--ink-muted);
  white-space: nowrap;
  margin: 0;
}

#footer select {
  width: 100%;
}

#footer .spacer {
  display: none;
}

/* ── Render progress ─────────────────────────────────────────────────
   Under the canvas and centred on it, because that is where the person is
   looking during a render. positionRenderProgress() sets left/top from the
   canvas's own box; the translate re-centres on that point. */
#renderProgress {
  position: fixed;
  transform: translateX(-50%);
  z-index: 2;
  width: min(340px, 34vw);
  padding: 12px 16px 13px;
  background: var(--surface);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-panel);
  text-align: center;
}

#renderProgress .rpLabel {
  margin: 0 0 8px;
  font-family: var(--font-body);
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--ink);
}

#renderProgress .rpTrack {
  height: 4px;
  border-radius: var(--radius-pill);
  background: var(--sl-warm-gray);
  overflow: hidden;
}

#renderProgress .rpTrack i {
  display: block;
  height: 100%;
  width: 0;
  background: var(--sl-signature);
  border-radius: inherit;
  /* Rows land unevenly — a hatch row is ~40x faster than a paint row — so the
     fill eases between updates instead of stepping. */
  transition: width 220ms ease-out;
}

#renderProgress .rpPct {
  margin: 7px 0 0;
  font: 400 0.6875rem/1 var(--font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--ink-muted);
}

#footer #resetButton,
#footer #renderButton {
  width: 100%;
  text-align: center;
}

#renderButton {
  padding: 11px 30px;
  margin: 0;
  cursor: pointer;
  border: none;
  border-radius: var(--radius-pill);
  background: var(--sl-signature);
  color: var(--sl-ivory);
  font-family: var(--font-body);
  font-size: 0.8125rem;
  font-weight: 600;
  transition:
    background 140ms ease,
    transform 80ms ease;
}

#renderButton:active {
  transform: scale(0.98);
}

#resetButton {
  padding: 9px 16px;
  margin: 0;
  cursor: pointer;
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--ink-label);
  border: 1px solid var(--sl-warm-gray);
  font-family: var(--font-body);
  font-size: 0.75rem;
  white-space: nowrap;
  transition: background 140ms ease;
}

#resetButton:hover {
  background: var(--sl-ivory);
}

/* Below the two-column minimum the grid scrolls internally. Deliberate:
   an internal scroll is better than a clipped panel. */
@media (max-width: 900px) {
  #controls {
    width: calc(100vw - 28px);
  }
}

/* ── Source extras: wildlife fetch + crop trigger ─────────────────  */
.wildlifeBtn {
  display: block;
  width: 100%;
  margin: 8px 0 0;
  padding: 8px 0;
  cursor: pointer;
  border: 1px solid var(--sl-warm-gray);
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--ink-label);
  font-family: var(--font-body);
  font-size: 0.75rem;
  transition: background 140ms ease;
}

.wildlifeBtn:hover {
  background: var(--sl-ivory);
}

.wildlifeBtn:disabled {
  opacity: 0.5;
  cursor: default;
}

/* ── Crop modal ────────────────────────────────────────────────────  */
#cropModal {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 60;
  align-items: center;
  justify-content: center;
  background: rgba(10, 20, 10, 0.55);
}

#cropModal.open {
  display: flex;
}

#cropCard {
  background: var(--surface);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-panel);
  padding: 16px;
  max-width: min(80vw, 640px);
}

.cropHint {
  font-size: 0.75rem;
  color: var(--ink-muted);
  margin: 0 0 10px;
}

#cropStage {
  position: relative;
  display: inline-block;
  max-width: 100%;
  line-height: 0;
  cursor: crosshair;
}

#cropStage img {
  display: block;
  max-width: 100%;
  max-height: 60vh;
  border-radius: var(--radius-xs);
  user-select: none;
  -webkit-user-drag: none;
}

#cropRect {
  position: absolute;
  border: 2px dashed var(--sl-signature);
  background: rgba(171, 224, 130, 0.25);
  pointer-events: none;
}

#cropActions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 12px;
}

#cropCancelBtn {
  padding: 9px 16px;
  cursor: pointer;
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--ink-label);
  border: 1px solid var(--sl-warm-gray);
  font-family: var(--font-body);
  font-size: 0.75rem;
}

#cropApplyBtn {
  padding: 9px 18px;
  cursor: pointer;
  border: none;
  border-radius: var(--radius-pill);
  background: var(--sl-signature);
  color: var(--sl-ivory);
  font-family: var(--font-body);
  font-size: 0.8125rem;
  font-weight: 600;
}

/* ── Step wizard ───────────────────────────────────────────────────  */
#stepIndicator {
  display: flex;
  gap: 16px;
  padding: 0 20px 12px;
}

.stepDot {
  font: 500 0.6875rem/1 var(--font-mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.stepDot.active {
  color: var(--sl-signature);
}

#wizardFooter {
  display: none;
  align-items: center;
  gap: 10px;
  padding: 12px 20px 14px;
  border-top: 1px solid var(--hairline);
}

#wizardFooter .spacer {
  flex: 1;
}

.wizardNavBtn {
  padding: 11px 26px;
  margin: 0;
  cursor: pointer;
  border: none;
  border-radius: var(--radius-pill);
  background: var(--sl-signature);
  color: var(--sl-ivory);
  font-family: var(--font-body);
  font-size: 0.8125rem;
  font-weight: 600;
}

.wizardNavBtn:disabled {
  opacity: 0.4;
  cursor: default;
}

.wizardNavBtn.ghostNav {
  background: transparent;
  color: var(--ink-label);
  border: 1px solid var(--sl-warm-gray);
  font-weight: 400;
}

/* Steps 1–2 show one column at a time, full width (#grid is a single flex
   column now, so no grid-column spanning is needed). Step 3 shows both
   Source and Image stacked — Style lives in its own #stylePanel (below),
   so there's no step-3 case to write here at all. */
#controls[data-step="1"] #wizardFooter,
#controls[data-step="2"] #wizardFooter {
  display: flex;
}

#controls[data-step="1"] #imageCol {
  display: none;
}

#controls[data-step="2"] #sourceCol {
  display: none;
}

/* ── Step-change entrance animation ──────────────────────────────
   Fires whenever a step's content flips from display:none to visible —
   the element has no box while hidden, so the animation always restarts
   fresh on entry. Applied to the actual elements whose `display` toggles
   per step (#sourceCol/#imageCol inside #grid, #stylePanel itself), not a
   static ancestor that would never re-trigger it. */
@keyframes stepIn {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

#sourceCol,
#imageCol,
#stylePanel {
  animation: stepIn 280ms cubic-bezier(0.16, 1, 0.3, 1);
}

@media (prefers-reduced-motion: reduce) {
  #sourceCol,
  #imageCol,
  #stylePanel {
    animation: none;
  }
}

/* ── Step 1: one screenful, image first ──────────────────────────────
   The card fills the window and the image absorbs every pixel the other
   controls don't need, so the step fits any window without a scrollbar.
   A fixed image height was what forced one on shorter screens. */
/* Step 1 has no canvas beside it, so the panel takes the middle of the
   screen rather than hugging the left edge the way steps 2 and 3 do. */
#controls[data-step="1"] {
  height: calc(100vh - 28px);
  width: min(1020px, calc(100vw - 28px));
  left: 50%;
  transform: translateX(-50%);
}

#controls[data-step="1"] #grid {
  overflow: hidden;
}

#controls[data-step="1"] #sourceCol,
#controls[data-step="1"] .srcSec {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
}

#controls[data-step="1"] .srcSec {
  width: 100%;
  max-width: 780px;
  margin: 0 auto;
  gap: 10px;
}

/* Spacing here comes from the gap. The children's own margins are stacked on
   top of it and, being unshrinkable, they pushed the last control past the
   panel's edge on short windows. */
#controls[data-step="1"] .srcSec > * {
  margin-top: 0;
  margin-bottom: 0;
}

/* The active pane takes the height, and inside it the preview takes what the
   pane's own controls don't need. */
#controls[data-step="1"] .srcPane,
#controls[data-step="1"] .srcRow,
#controls[data-step="1"] .dropZone {
  flex: 1 1 auto;
  min-height: 0;
}

#controls[data-step="1"] .srcRow {
  flex-direction: column;
  align-items: stretch;
  gap: 12px;
}

/* The previews are the only things allowed to grow. min-height:0 is what
   lets them shrink past their intrinsic size on a short window instead of
   pushing the card taller than the screen. */
#controls[data-step="1"] .srcRow img,
#controls[data-step="1"] .uploadThumb {
  flex: 1 1 auto;
  width: 100%;
  height: auto;
  min-height: 0;
  object-fit: contain;
}

#controls[data-step="1"] .srcRow input {
  flex: 0 0 auto;
}

/* In the zone the image fills the box it was dropped into. */
#controls[data-step="1"] .dropZone .uploadThumb {
  max-height: 100%;
}

/* Short windows: the chrome gives up its space so the preview keeps its own.
   Without this the image is the only flexible box on the step, so it was the
   only thing that shrank — down to a 41px sliver at 560px tall. */
@media (max-height: 820px) {
  #controls[data-step="1"] .srcSec,
  #controls[data-step="1"] .srcRow {
    gap: 6px;
  }
}

@media (max-height: 680px) {
  #controls[data-step="1"] .sectionHead,
  #controls[data-step="1"] .srcSec > .row,
  #controls[data-step="1"] .srcSec > .hint {
    display: none;
  }

  #controls[data-step="1"] .wildlifeBtn {
    padding-top: 7px;
    padding-bottom: 7px;
  }
}

/* ── Step 2 redesign: a large Auto-Prep preview, sliders below it ────
   Same DOM as step 3's stacked Image column — .prepGroup/.tuneGroup are
   unstyled plain divs there, so step 3 is unaffected. The preview is the
   whole point of this page, so it spans the full width above the sliders
   instead of sharing a row with them. */
/* One screenful, like step 1: the column fills the panel and the preview
   absorbs the slack, so the key and the sliders stay in view at any height.
   Centred for the same reason step 1 is — there is no canvas beside it yet. */
#controls[data-step="2"] {
  height: calc(100vh - 28px);
  width: min(1020px, calc(100vw - 28px));
  left: 50%;
  transform: translateX(-50%);
}

#controls[data-step="2"] #grid {
  overflow: hidden;
}

#controls[data-step="2"] #imageCol,
#controls[data-step="2"] .imgSec,
#controls[data-step="2"] .prepGroup {
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
  min-height: 0;
}

#controls[data-step="2"] .imgSec {
  gap: 20px;
}

#controls[data-step="2"] .prepGroup {
  gap: 4px;
}

/* Two toggles, one row. Stacked they cost the preview ~90px of height. */
.prepToggles {
  display: flex;
  gap: 28px;
  margin-bottom: 4px;
}

.prepToggles .prepToggle {
  flex: 1 1 0;
  min-width: 0;
}

/* Style's column is 340px — side by side there would be two squashed lines. */
#controls[data-step="3"] .prepToggles {
  flex-direction: column;
  gap: 10px;
}

/* Whatever else is on the step, the preview stays big enough to read. */
#controls[data-step="2"] #prepPreviewWrap {
  min-height: 240px;
}

#controls[data-step="2"] .imgSec > .sectionHead,
#controls[data-step="2"] .tuneGroup,
#controls[data-step="2"] .prepGroup > .hint,
#controls[data-step="2"] .prepGroup > .row,
#controls[data-step="2"] .prepLegend {
  flex: 0 0 auto;
}

/* Hide threshold sliders without deleting them. They remain in the DOM and
   continue to be read by .value() calls throughout the render pipeline.
   !important because input[type="range"].ctrl { display: block } outranks a
   bare class — which is why the labels vanished but the bars stayed. */
.ctrlHidden {
  display: none !important;
}

/* Tune is for one decision — Contrast. White balance still lives on Style. */
#controls[data-step="2"] .tuneOnlyHidden {
  display: none !important;
}

/* ── Prep preview key ────────────────────────────────────────────────
   Wraps rather than truncates, so it survives Style's 340px column. */
.prepLegend {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 16px;
  margin-top: 8px;
}

.prepLegend .lgd {
  display: flex;
  align-items: center;
  gap: 6px;
  font-family: var(--font-body);
  font-size: 0.6875rem;
  color: var(--ink-muted);
}

.prepLegend i {
  width: 10px;
  height: 10px;
  flex: none;
}

.prepLegend .lgdHatch {
  background: var(--sl-signature);
}

.prepLegend .lgdPaint {
  border-radius: 50%;
  background: rgba(245, 85, 36, 0.55);
  box-shadow: inset 0 0 0 1px rgba(150, 16, 1, 0.75);
}

/* ── Auto-Prep loader ────────────────────────────────────────────────
   A tile grid that inks itself along a 45° sweep — the same diagonal the
   hatching runs at — so the wait previews the output instead of spinning.
   Replaces a line of muted 11px text nobody could see. */
#prepLoader {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  padding: 20px 0 6px;
}

.loaderGrid {
  display: grid;
  grid-template-columns: repeat(16, 1fr);
  gap: 3px;
  width: 100%;
  max-width: 380px;
}

/* Opacity only, and nothing else.
   The first version animated background-color and scale on 144 cells: colour
   is a paint property, so every frame repainted the whole grid, and the 30%
   scale pop read as jitter. Opacity is composited — the animation runs off the
   main thread and stays smooth while the model is busy saturating it, which is
   precisely when this thing is on screen. */
.loaderGrid i {
  aspect-ratio: 1;
  border-radius: 1px;
  background: var(--sl-signature);
  opacity: 0.08;
  will-change: opacity;
  /* linear, not ease-in-out: the easing applies to every keyframe segment
     separately, so each one accelerated and decelerated again and the ramp
     came out lumpy. The bell below carries the shape instead. */
  animation: tileInk 2.4s linear infinite;
  /* Negative delay spanning exactly one period. Each cell starts partway
     through the same loop, so the diagonal never restarts — the old delays
     ran 0→1.265s against a 1.9s cycle and the wave collided with itself. */
  animation-delay: calc(var(--p) * -2.4s);
}

/* A wide, soft bell rather than a spike. The grid has 24 diagonals, so a pulse
   confined to a fifth of the period puts the whole rising edge into ~5 of them
   and neighbouring bands jump 0.31 in opacity — visible as banding. Spreading
   the rise and fall across most of the loop drops that to ~0.13, which is what
   makes it read as a wave passing rather than rows switching on. */
@keyframes tileInk {
  0% {
    opacity: 0.07;
  }
  10% {
    opacity: 0.18;
  }
  20% {
    opacity: 0.42;
  }
  30% {
    opacity: 0.72;
  }
  40% {
    opacity: 0.94;
  }
  48% {
    opacity: 1;
  }
  58% {
    opacity: 0.85;
  }
  68% {
    opacity: 0.6;
  }
  78% {
    opacity: 0.32;
  }
  88% {
    opacity: 0.14;
  }
  96%,
  100% {
    opacity: 0.07;
  }
}

.loaderMsg {
  margin: 0;
  font-family: var(--font-body);
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1.4;
  color: var(--ink);
  text-align: center;
}

@media (prefers-reduced-motion: reduce) {
  .loaderGrid i {
    animation: none;
    opacity: 0.35;
  }
}

/* ── Zoom background composer (step 4) ─────────────────────────────
   A full-screen overlay: header bar, 16:9 stage, lockup tray. Built in
   sketch.js on first open; inline display toggles visibility. */

#zoomBtn {
  display: none;
  width: calc(100% - 40px);
  margin: 0 20px 20px;
  padding: 11px 30px;
  cursor: pointer;
  border: 1.5px solid var(--sl-signature);
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--sl-signature);
  font-family: var(--font-body);
  font-size: 0.8125rem;
  font-weight: 600;
  transition: background 140ms ease;
}

#zoomBtn:hover {
  background: rgba(4, 52, 35, 0.07);
}

#zoomOverlay {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: none;
  flex-direction: column;
  background: var(--bg-subtle);
}

#zoomHead {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 20px;
  background: var(--surface);
  border-bottom: 1px solid var(--hairline);
}

#zoomHead .spacer {
  flex: 1;
}

#zoomTitle {
  margin: 0;
  font-family: var(--font-body);
  font-size: 0.9375rem;
  font-weight: 700;
  color: var(--ink);
}

#zoomHint {
  margin: 0;
  font-family: var(--font-body);
  font-size: 0.8125rem;
  color: var(--ink-muted);
}

#zoomSizeLbl {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-body);
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--ink-label);
}

#zoomHead button {
  padding: 9px 18px;
  cursor: pointer;
  border: none;
  border-radius: var(--radius-pill);
  font-family: var(--font-body);
  font-size: 0.8125rem;
  font-weight: 600;
}

#zoomDelete {
  background: transparent;
  border: 1.5px solid var(--hairline);
  color: var(--ink-label);
}

#zoomDelete:disabled {
  opacity: 0.35;
  cursor: default;
}

#zoomBackBtn {
  background: transparent;
  border: 1.5px solid var(--sl-signature);
  color: var(--sl-signature);
}

#zoomSaveBtn {
  background: var(--sl-highlight);
  color: var(--sl-deep-green);
}

#zoomStageWrap {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 0;
  padding: 24px;
}

#zoomStage {
  position: relative;
  aspect-ratio: 16 / 9;
  max-width: 100%;
  max-height: 100%;
  width: min(100%, calc((100vh - 260px) * 16 / 9));
  border-radius: var(--radius-xs);
  box-shadow: var(--shadow-canvas);
  overflow: hidden;
  touch-action: none;
}

.zoomLogo {
  position: absolute;
  transform: translate(-50%, -50%);
  cursor: grab;
  touch-action: none;
  user-select: none;
}

.zoomLogo.selected {
  outline: 2px dashed var(--sl-flare);
  outline-offset: 6px;
}

.zoomGhost {
  position: fixed;
  z-index: 70;
  width: 180px;
  transform: translate(-50%, -50%);
  pointer-events: none;
  opacity: 0.85;
}

#zoomTrayWrap {
  padding: 12px 20px 16px;
  background: var(--surface);
  border-top: 1px solid var(--hairline);
}

#zoomTray {
  display: flex;
  gap: 10px;
  overflow-x: auto;
  padding-bottom: 4px;
}

/* Chip background is set inline to the artwork's field colour — the tray
   doubles as a live contrast preview. */
.zoomChip {
  flex: 0 0 auto;
  width: 118px;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: grab;
  border: 1px solid var(--hairline);
  border-radius: var(--radius-xs);
  touch-action: none;
}

#zoomTrayNote {
  margin: 0 0 8px;
  font-family: var(--font-body);
  font-size: 0.75rem;
  color: var(--ink-muted);
}

.zoomChip img {
  width: 92px;
  pointer-events: none;
}

#zoomMirrorHint {
  margin: 10px 0 0;
  font-family: var(--font-body);
  font-size: 0.75rem;
  color: var(--ink-faint);
}

/* ── Start from: gallery + arrange stage (step 1) ─────────────────── */
#controls[data-source="start"] .urlPane,
#controls[data-source="start"] .uploadPane,
#controls[data-source="start"] .srcSec > .wildlifeBtn,
#controls:not([data-source="start"]) .startPane {
  display: none;
}

.startPane {
  display: grid;
  grid-template-columns: minmax(0, 300px) minmax(0, 1fr);
  gap: 18px;
  align-items: start;
}

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

.subjTile {
  display: grid;
  gap: 5px;
  padding: 0;
  border: none;
  background: none;
  cursor: pointer;
  text-align: left;
  font: 500 0.8125rem var(--font-body);
  color: var(--ink-label);
}

.subjTile img {
  width: 100%;
  aspect-ratio: 1300 / 734;
  object-fit: cover;
  border-radius: var(--radius-xs);
  border: 1px solid var(--hairline);
  transition: transform 140ms ease, box-shadow 140ms ease;
}

.subjTile:hover img,
.subjTile:focus-visible img {
  transform: translateY(-1px);
  box-shadow: 0 0 0 2px var(--sl-signature);
}

.subjTile:focus-visible {
  outline: none;
}

.composeCol {
  display: grid;
  gap: 10px;
  min-width: 0;
}

.composeStage {
  position: relative;
  aspect-ratio: 1300 / 734;
  background: #fff;
  border: 1.5px dashed var(--sl-stone);
  border-radius: var(--radius-xs);
  overflow: hidden;
  touch-action: none;
}

.composeStage.hasObjects {
  border-style: solid;
  border-color: var(--hairline);
}

.composeEmpty {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  margin: 0;
  padding: 20px;
  text-align: center;
  font-size: 0.875rem;
  color: var(--ink-muted);
}

.composeStage.hasObjects .composeEmpty {
  display: none;
}

.composeObj {
  position: absolute;
  transform: translate(-50%, -50%);
  cursor: grab;
  user-select: none;
}

.composeObj.selected {
  outline: 2px solid var(--sl-signature);
  outline-offset: 3px;
  border-radius: 4px;
}

.composeTools {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.composeSizeLbl {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: 1 1 180px;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--ink-label);
}

.composeSizeLbl input {
  flex: 1;
  accent-color: var(--sl-signature);
}

.composeTools button {
  padding: 7px 14px;
  border: 1.5px solid var(--hairline);
  border-radius: var(--radius-pill);
  background: var(--surface);
  font: 600 0.8125rem var(--font-body);
  color: var(--ink-label);
  cursor: pointer;
}

.composeTools button:disabled,
.composeTools input:disabled {
  opacity: 0.35;
  cursor: default;
}

/* ── Export overlay ──────────────────────────────────────────────── */
#exportOverlay {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: none;
  flex-direction: column;
  background: var(--bg-subtle);
}

#exportHead {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 20px;
  background: var(--surface);
  border-bottom: 1px solid var(--hairline);
}

#exportHead .spacer {
  flex: 1;
}

#exportTitle {
  margin: 0;
  font-size: 0.9375rem;
  font-weight: 700;
  color: var(--ink);
}

#exportHint {
  margin: 0;
  font-size: 0.8125rem;
  color: var(--ink-muted);
}

#exportHead button {
  padding: 9px 18px;
  cursor: pointer;
  border: none;
  border-radius: var(--radius-pill);
  font: 600 0.8125rem var(--font-body);
}

#exportBackBtn {
  background: transparent;
  border: 1.5px solid var(--sl-signature) !important;
  color: var(--sl-signature);
}

#exportSaveBtn {
  background: var(--sl-highlight);
  color: var(--sl-deep-green);
}

#exportBody {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 380px;
}

#exportMain {
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-height: 0;
  padding: 20px 24px;
}

#exportUses {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.useChip {
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
  padding: 8px 14px;
  border: 1.5px solid var(--hairline);
  border-radius: var(--radius-pill);
  background: var(--surface);
  font: 600 0.8125rem var(--font-body);
  color: var(--ink-label);
  cursor: pointer;
}

.useChip small {
  font: 400 0.75rem var(--font-mono);
  color: var(--ink-muted);
}

.useChip.on {
  background: var(--sl-signature);
  border-color: var(--sl-signature);
  color: var(--sl-ivory);
}

.useChip.on small {
  color: var(--sl-highlight);
}

.useChip:focus-visible {
  outline: 2px solid var(--sl-signature);
  outline-offset: 2px;
}

#exportStageWrap {
  flex: 1;
  min-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

#exportStage {
  position: relative;
  flex: none;
  overflow: hidden;
  border-radius: 4px;
  box-shadow: var(--shadow-canvas);
  background-color: var(--surface);
  cursor: grab;
  touch-action: none;
}

#exportStage.fixed {
  cursor: default;
}

#exportArtImg {
  position: absolute;
  user-select: none;
  pointer-events: none;
}

#exportFrameTools {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
}

#exportFrameTools.off label,
#exportFrameTools.off button {
  visibility: hidden;
}

#exportZoomLbl {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 260px;
  font-size: 0.8125rem;
  font-weight: 600;
  color: var(--ink-label);
}

#exportZoomLbl input {
  flex: 1;
  accent-color: var(--sl-signature);
}

#exportFitBtn {
  padding: 7px 14px;
  border: 1.5px solid var(--hairline);
  border-radius: var(--radius-pill);
  background: var(--surface);
  font: 600 0.8125rem var(--font-body);
  color: var(--ink-label);
  cursor: pointer;
}

#exportNote {
  margin: 0;
  font-size: 0.8125rem;
  color: var(--ink-label);
}

#exportCtxCol {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 20px;
  background: var(--surface);
  border-left: 1px solid var(--hairline);
  overflow-y: auto;
}

.exportCtxHead {
  margin: 0;
  font: 500 0.6875rem/1 var(--font-mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--sl-olive);
}

#exportCtxCap {
  margin: 0;
  font: 0.75rem var(--font-mono);
  color: var(--ink-muted);
}

.ctxNone {
  font-size: 0.875rem;
  color: var(--ink-muted);
}

.ctxArt {
  display: block;
  width: 100%;
  outline: 2px solid #334bc3;
  outline-offset: -2px;
}

.ctxHub {
  display: grid;
  gap: 10px;
  padding: 12px;
  border: 1px solid var(--hairline);
  border-radius: 8px;
}

.ctxHubNav {
  display: flex;
  gap: 12px;
  font-size: 0.75rem;
  color: var(--ink-muted);
  border-bottom: 1px solid var(--hairline);
  padding-bottom: 8px;
}

.ctxHubNav b {
  margin-right: auto;
  color: var(--sl-signature);
}

.ctxHubGrid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}

.ctxPost:first-child {
  grid-column: 1 / -1;
}

.ctxPost {
  display: grid;
  gap: 4px;
  min-width: 0;
}

.ctxPost img {
  width: 100%;
  aspect-ratio: 1300 / 734;
  object-fit: cover;
  border-radius: 4px;
  display: block;
}

.ctxPost span {
  font: 500 0.625rem var(--font-mono);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--sl-olive);
}

.ctxPost b {
  font-size: 0.8125rem;
  color: var(--ink);
}

.ctxFeed,
.ctxPhone {
  display: grid;
  gap: 8px;
  padding: 10px 0;
  border: 1px solid var(--hairline);
  border-radius: 8px;
}

.ctxFeed > p,
.ctxPhone > p,
.ctxFeedHead,
.ctxPhoneHead,
.ctxBars,
.ctxFeedLink {
  margin: 0;
  padding-inline: 10px;
  font-size: 0.8125rem;
}

.ctxFeedHead,
.ctxPhoneHead {
  display: flex;
  gap: 8px;
  align-items: center;
}

.ctxFeedHead div,
.ctxFeedLink {
  display: grid;
}

.ctxFeedHead small,
.ctxFeedLink small {
  font-size: 0.6875rem;
  color: var(--ink-muted);
}

.ctxAv {
  width: 30px;
  height: 30px;
  flex: none;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--sl-signature);
  color: var(--sl-highlight);
  font: 700 0.8125rem var(--font-body);
  font-style: normal;
}

.ctxBars {
  display: flex;
  gap: 8px;
}

.ctxBars i {
  height: 8px;
  width: 54px;
  border-radius: var(--radius-pill);
  background: var(--hairline);
}

.ctxPhone {
  width: 260px;
  justify-self: center;
  border: 9px solid var(--sl-deep-green);
  border-radius: 26px;
}

.ctxCall {
  display: grid;
  gap: 8px;
  padding: 8px;
  border-radius: 10px;
  background: #1e2620;
}

.ctxTile {
  position: relative;
  overflow: hidden;
  border-radius: 6px;
}

.ctxPerson {
  position: absolute;
  left: 50%;
  bottom: 0;
  width: 40%;
  transform: translateX(-50%);
}

.ctxName {
  position: absolute;
  left: 6px;
  bottom: 6px;
  padding: 2px 7px;
  border-radius: 4px;
  background: rgba(10, 20, 10, 0.65);
  color: #fff;
  font-size: 0.6875rem;
}

.ctxCallBar {
  display: flex;
  justify-content: center;
  gap: 8px;
}

.ctxCallBar i {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--sl-moss);
}

.ctxCallBar i.end {
  background: var(--sl-flare);
}

/* On Style the panel is narrow: stack the gallery over the stage. */
#controls[data-step="3"] .startPane {
  grid-template-columns: minmax(0, 1fr);
  gap: 10px;
}

#controls[data-step="3"] .startGallery {
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 6px;
}

#controls[data-step="3"] .subjTile span {
  display: none;
}
