/* GENERATED by bvc-controls sync.sh, edit in ~/Desktop/Code/bvc-controls */
/* bvc-controls · controls.css
   Load order: tokens.css, the app's theme.css, then this file. */

/* Every size in this sheet is a border-box size, whatever the app's own
   reset says, so a column, a chip or an indicator measures the same in every
   app and in the template. */
.cs-shell, .cs-shell *, .cs-shell *::before, .cs-shell *::after,
.cs-menu, .cs-menu *, .cs-panel, .cs-panel * { box-sizing: border-box; }

/* ───────────────────────── row grammar ───────────────────────── */
.cs-row {
  display: grid;
  grid-template-columns: var(--cs-row-cols);
  gap: var(--cs-row-gap);
  align-items: center;
  margin: var(--cs-row-my) 0;
  min-height: var(--cs-row-h);
  font: var(--cs-fs-row) / 1.45 var(--cs-font-ui);
  color: var(--cs-text);
}
.cs-label {
  color: var(--cs-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* A row driven by its animation track: colored, not dimmed, so it reads as
   animated rather than locked; its own controls take no input. */
.cs-row.is-animated .cs-label::after { content: ' \2022'; color: var(--cs-accent); }
.cs-row.is-animated .cs-label,
.cs-row.is-animated .cs-value { color: var(--cs-accent); }
.cs-row.is-animated .cs-range,
.cs-row.is-animated .cs-value,
.cs-row.is-animated .cs-pill,
.cs-row.is-animated .cs-chip,
.cs-row.is-animated .cs-seg-btn,
.cs-row.is-animated .cs-dd,
.cs-row.is-animated .cs-reset,
.cs-row.is-animated .cs-swatch { pointer-events: none; }
.cs-row.is-animated .cs-range:disabled,
.cs-row.is-animated .cs-value:disabled { opacity: 1; }
.cs-row.inactive { opacity: 0.35; }
.cs-row.inactive .cs-range,
.cs-row.inactive .cs-value,
.cs-row.inactive .cs-pill,
.cs-row.inactive .cs-chip,
.cs-row.inactive .cs-seg-btn,
.cs-row.inactive .cs-dd,
.cs-row.inactive .cs-curve-canvas,
.cs-row.inactive .cs-gradient-bar,
.cs-row.inactive .cs-gradient-handle,
.cs-row.inactive .cs-aux-btn,
.cs-row.inactive .cs-swatch { cursor: not-allowed; pointer-events: none; }
.cs-row > .cs-span { grid-column: 2 / span 3; }

/* ───────────────────────── slider ───────────────────────── */
.cs-range { width: 100%; min-width: 0; margin: 0; accent-color: var(--cs-accent); }
.cs-value {
  width: 100%;
  min-width: 0;
  text-align: right;
  color: var(--cs-muted);
  background: none;
  border: 1px solid transparent;
  border-radius: 3px;
  padding: 1px 3px;
  font: var(--cs-fs-value) / 1.4 var(--cs-font-mono);
}
.cs-value:hover { border-color: var(--cs-line-hi); }
.cs-value:focus {
  outline: none;
  border-color: var(--cs-accent);
  color: var(--cs-text-strong);
  background: var(--cs-bg-field);
}
.cs-aux { display: flex; align-items: center; justify-content: center; gap: 2px; min-width: 20px; }
.cs-reset {
  display: none;
  width: 18px;
  height: 18px;
  padding: 0;
  border-radius: var(--cs-r-sm);
  cursor: pointer;
  background: none;
  border: 1px solid var(--cs-line-hi);
  color: var(--cs-muted);
  font: 11px / 1 var(--cs-font-mono);
}
.cs-row.is-dirty .cs-reset { display: inline-flex; align-items: center; justify-content: center; }
.cs-reset:hover { color: var(--cs-accent); border-color: var(--cs-accent); }

/* ───────────────────────── toggle ───────────────────────── */
.cs-row[data-type="toggle"] .cs-pill { grid-column: 2 / span 3; justify-self: start; }
.cs-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px;
  border-radius: var(--cs-r-pill);
  cursor: pointer;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid var(--cs-line);
  color: var(--cs-muted);
  font: 600 9px / 1 var(--cs-font-head);
  letter-spacing: 1px;
  text-transform: uppercase;
  transition: border-color var(--cs-dur) var(--cs-ease), color var(--cs-dur) var(--cs-ease);
}
.cs-pill::before { content: ''; width: 8px; height: 8px; border-radius: 50%; background: rgba(255, 255, 255, 0.2); }
.cs-pill::after { content: 'Off'; }
.cs-pill[data-state="on"] { color: var(--cs-text-strong); border-color: var(--cs-accent); }
.cs-pill[data-state="on"]::before { background: var(--cs-accent); box-shadow: 0 0 8px rgba(var(--cs-accent-rgb), 0.6); }
.cs-pill[data-state="on"]::after { content: 'On'; }

/* ───────────────────────── choice: segmented / pull-down ───────────────────────── */
/* Four options or fewer are a one-row segmented control; five or more are a
   pull-down whose menu lists them. The native select stays in the DOM, hidden,
   as the value carrier. */
.cs-choice { grid-column: 2 / span 2; min-width: 0; }
.cs-enum-source { display: none !important; }

.cs-seg {
  display: flex;
  min-width: 0;
  border: 1px solid var(--cs-line);
  border-radius: 6px;
  overflow: hidden;
}
.cs-seg-btn {
  flex: 1 1 0;
  /* border-box, so the segments are equal outer widths rather than equal
     content widths beside the one that has no left border. */
  box-sizing: border-box;
  min-width: 0;
  height: 24px;
  padding: 0 4px;
  cursor: pointer;
  background: none;
  border: 0;
  border-left: 1px solid var(--cs-line);
  color: var(--cs-muted);
  font: 500 10px / 1.2 var(--cs-font-ui);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cs-seg-btn:first-child { border-left: 0; }
.cs-seg-btn:hover:not(:disabled) { background: var(--cs-bg-hover); color: var(--cs-text); }
.cs-seg-btn:focus-visible { outline: none; box-shadow: inset 0 0 0 1px var(--cs-accent); }
.cs-seg-btn.is-active { background: var(--cs-accent); color: #fff; }
.cs-seg-btn.is-disabled { opacity: 0.4; cursor: not-allowed; }

.cs-dd {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  width: 100%;
  min-width: 0;
  height: 28px;
  padding: 0 10px;
  border-radius: 6px;
  cursor: pointer;
  background: var(--cs-bg-field);
  border: 1px solid var(--cs-line);
  color: var(--cs-text);
  font: 500 var(--cs-fs-row) / 1 var(--cs-font-ui);
}
.cs-dd:hover:not(:disabled) { border-color: var(--cs-line-hi); }
.cs-dd.is-open { border-color: var(--cs-accent); }
.cs-dd:disabled { opacity: 0.4; cursor: not-allowed; }
.cs-dd-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cs-dd-chev { flex: 0 0 auto; display: block; color: var(--cs-muted); }
.cs-dd-chev svg { display: block; width: 14px; height: 14px; }

/* The menu is a child of <body>, never of the panel: the panel's own
   backdrop-filter would make it the containing block for a fixed child, and
   the scrolling panel body would then clip the menu. */
.cs-menu {
  position: fixed;
  z-index: 2000;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  max-height: calc(100vh - 16px);
  padding: 4px;
  border-radius: 8px;
  background: var(--cs-bg-menu);
  border: 1px solid var(--cs-line-hi);
  box-shadow: var(--cs-shadow-panel);
  color: var(--cs-text);
}
.cs-menu-list { display: flex; flex-direction: column; min-height: 0; overflow-y: auto; scrollbar-width: thin; }
.cs-menu.is-many .cs-menu-list { max-height: 130px; /* about five rows */ }
.cs-menu-row {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  height: 26px;
  padding: 0 8px;
  cursor: pointer;
  text-align: left;
  background: none;
  border: 0;
  border-radius: var(--cs-r-sm);
  color: var(--cs-text);
  font: var(--cs-fs-row) / 1 var(--cs-font-ui);
}
.cs-menu-row[hidden] { display: none; }
.cs-menu-row:hover:not(:disabled), .cs-menu-row.is-hover { background: var(--cs-bg-hover); }
.cs-menu-row.is-active { background: rgba(var(--cs-accent-rgb), 0.18); color: var(--cs-text-strong); }
.cs-menu-row.is-disabled { opacity: 0.4; cursor: not-allowed; }
.cs-menu-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cs-menu-check { flex: 0 0 auto; display: block; color: var(--cs-accent); }
.cs-menu-check svg { display: block; width: 12px; height: 12px; }
.cs-menu-filter { flex: 0 0 auto; margin-bottom: 4px; }
/* A heading over each run of options from one group: nothing to hover, and
   the filter takes it away with the last of its options. */
.cs-menu-group {
  flex: 0 0 auto;
  padding: 6px 8px 2px;
  color: var(--cs-muted-2);
  font: 600 9px / 1 var(--cs-font-head);
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.cs-menu-group[hidden] { display: none; }

/* ───────────────────────── chips (curve shapes, list filter) ───────────────────────── */
.cs-chip {
  padding: 3px 8px;
  font: var(--cs-fs-value) / 1.4 var(--cs-font-ui);
  border-radius: var(--cs-r-pill);
  cursor: pointer;
  border: 1px solid var(--cs-line);
  background: rgba(255, 255, 255, 0.04);
  color: var(--cs-muted);
}
.cs-chip.is-active { background: var(--cs-accent); border-color: var(--cs-accent); color: #fff; }
.cs-chip.is-disabled { opacity: 0.4; cursor: not-allowed; }
.cs-chip[hidden] { display: none; }
.cs-chips-filter {
  display: block;
  width: 100%;
  min-width: 0;
  text-align: left;
  color: var(--cs-text);
  background: var(--cs-bg-field);
  border: 1px solid var(--cs-line);
  border-radius: var(--cs-r-sm);
  padding: 3px 6px;
  margin-bottom: 2px;
  font: var(--cs-fs-value) / 1.4 var(--cs-font-mono);
}
.cs-chips-filter:hover { border-color: var(--cs-line-hi); }
.cs-chips-filter:focus {
  outline: none;
  border-color: var(--cs-accent);
  color: var(--cs-text-strong);
  background: var(--cs-bg-field);
}

/* ───────────────────────── color ───────────────────────── */
.cs-color { grid-column: 2 / span 2; display: grid; grid-template-columns: 1fr 64px; gap: 6px; align-items: center; }
.cs-swatch { position: relative; height: 18px; border-radius: var(--cs-r-sm); border: 1px solid var(--cs-line-hi); overflow: hidden; }
.cs-swatch input[type="color"] {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  min-width: 0;
  min-height: 0;
  opacity: 0;
  padding: 0;
  margin: 0;
  border: none;
  background: none;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}

/* ───────────────────────── text field ───────────────────────── */
.cs-row.is-bare > .cs-text { grid-column: 1 / -1; }
.cs-text {
  width: 100%;
  min-width: 0;
  box-sizing: border-box;
  text-align: left;
  color: var(--cs-text);
  background: var(--cs-bg-field);
  border: 1px solid var(--cs-line);
  border-radius: var(--cs-r-sm);
  padding: 6px 8px;
  font: var(--cs-fs-row) / 1.4 var(--cs-font-ui);
}
.cs-text:hover { border-color: var(--cs-line-hi); }
.cs-text:focus {
  outline: none;
  border-color: var(--cs-accent);
}

/* ───────────────────────── curve editor ───────────────────────── */
.cs-row[data-type="curve"] { align-items: start; }
.cs-row[data-type="curve"] .cs-label { padding-top: 4px; }
.cs-curve { min-width: 0; }
.cs-curve-plot { position: relative; }
.cs-curve-canvas {
  display: block;
  box-sizing: border-box;
  width: 100%;
  border: 1px solid var(--cs-line);
  border-radius: var(--cs-r-sm);
  background: var(--cs-bg-field);
  cursor: crosshair;
  touch-action: none;
}
.cs-curve-canvas:focus { outline: none; border-color: var(--cs-line-hi); }
.cs-curve-axis {
  position: absolute;
  left: 5px;
  pointer-events: none;
  color: var(--cs-muted-2);
  font: 10px / 1 var(--cs-font-mono);
}
.cs-curve-axis.is-max { top: 5px; }
.cs-curve-axis.is-min { bottom: 5px; }
/* The expanded editor: the confirm dialog's backdrop with a wide box in it.
   The canvas height is set by the editor from the viewport. */
.cs-curve-back { padding: 16px; }
.cs-curve-modal {
  box-sizing: border-box;
  width: min(900px, 100%);
  max-height: 100%;
  overflow: auto;
  padding: 14px 16px 16px;
  border-radius: var(--cs-panel-r);
  border: 1px solid var(--cs-line);
  background: var(--cs-glass);
  -webkit-backdrop-filter: var(--cs-blur);
  backdrop-filter: var(--cs-blur);
  box-shadow: var(--cs-shadow-panel), var(--cs-glass-hi);
  color: var(--cs-text);
}
.cs-curve-modal-head { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.cs-curve-modal-title {
  margin-right: auto;
  color: var(--cs-accent);
  font: 600 var(--cs-fs-head) / 1.3 var(--cs-font-head);
  letter-spacing: .12em;
  text-transform: uppercase;
}
.cs-curve-modal-close {
  width: 26px;
  height: 26px;
  padding: 0;
  border: 1px solid var(--cs-line);
  border-radius: var(--cs-r-sm);
  background: transparent;
  color: var(--cs-muted);
  font: 18px / 1 var(--cs-font-ui);
  cursor: pointer;
}
.cs-curve-modal-close:hover { color: var(--cs-text); border-color: var(--cs-line-hi); }
.cs-curve-modal .cs-curve-axis { font-size: 11px; }
.cs-curve-readout { display: flex; align-items: center; gap: 6px; margin-top: 6px; }
.cs-curve-readout-label { margin-right: auto; color: var(--cs-muted); font: var(--cs-fs-value) / 1.4 var(--cs-font-ui); }
.cs-curve-xy-label { color: var(--cs-muted-2); font: var(--cs-fs-value) / 1.4 var(--cs-font-mono); }
.cs-curve-xy { width: 76px; min-width: 0; text-align: right; color: var(--cs-text); font: var(--cs-fs-value) / 1.4 var(--cs-font-mono); }
.cs-curve-xy:disabled { opacity: .45; }
/* Five equal cells to a line: every chip is a glyph of the same size, so the
   row reads as one grid rather than a paragraph of words. A shapes subset
   simply leaves the last line partly filled. */
/* One line: the Shape button takes the room, the three glyph chips sit at
   the end. The shapes themselves live in the popout below. */
.cs-curve-chips { display: flex; align-items: center; gap: 4px; margin-top: 6px; }
.cs-curve-chips .cs-curve-shape-btn { flex: 1 1 auto; min-width: 0; height: 24px; }
.cs-curve-chips .cs-chip { flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center; width: 30px; height: 24px; padding: 0; }
.cs-curve-chips .cs-chip svg { display: block; width: 26px; height: 12px; }
.cs-curve-chips .cs-chip-glyph svg { width: 14px; height: 14px; }
.cs-curve-shape-menu { min-width: 180px; }
.cs-curve-shape-menu .cs-menu-row { gap: 10px; }
.cs-curve-shape-art { flex: 0 0 auto; display: inline-flex; color: var(--cs-muted); }
.cs-curve-shape-art svg { display: block; width: 26px; height: 12px; }
.cs-curve-shape-menu .cs-menu-row.is-active .cs-curve-shape-art { color: var(--cs-accent); }

.cs-curve-points { display: flex; align-items: center; gap: 4px; margin-top: 6px; }
.cs-curve-points-label { margin-right: auto; color: var(--cs-muted); font: var(--cs-fs-value) / 1.4 var(--cs-font-ui); }
.cs-curve-count { width: 34px; min-width: 0; text-align: center; color: var(--cs-text); font: var(--cs-fs-value) / 1.4 var(--cs-font-mono); }
/* The expand button shares the stepper's look but not its class: the last
   .cs-curve-step on a row is the +, and callers rely on that. */
.cs-curve-step, .cs-curve-expand, .cs-curve-loop {
  width: 22px;
  height: 20px;
  padding: 0;
  border-radius: var(--cs-r-sm);
  cursor: pointer;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid var(--cs-line);
  color: var(--cs-muted);
  font: 500 12px / 1 var(--cs-font-ui);
}
.cs-curve-step:hover:not(:disabled), .cs-curve-expand:hover, .cs-curve-loop:hover { color: var(--cs-text); border-color: var(--cs-line-hi); }
.cs-curve-step:disabled { opacity: 0.35; cursor: not-allowed; }
/* The button that opens the editor large sits at the end of the Points row,
   a little apart from the +. */
.cs-curve-expand { margin-left: 6px; padding: 3px; }
.cs-curve-expand svg { display: block; width: 100%; height: 100%; }
.cs-curve-loop { margin-left: 6px; padding: 3px; }
.cs-curve-loop svg { display: block; width: 100%; height: 100%; }
.cs-curve-loop.is-active { color: var(--cs-accent); border-color: var(--cs-accent); }

/* ───────────────────────── gradient editor ───────────────────────── */
.cs-row[data-type="gradient"] { align-items: start; }
.cs-row[data-type="gradient"] .cs-label { padding-top: 4px; }
.cs-gradient { min-width: 0; }
.cs-gradient-bar {
  height: 22px;
  border-radius: 6px;
  border: 1px solid var(--cs-line);
  cursor: copy;
}
/* The stops hang below the bar, so they never cover the color they set. */
.cs-gradient-strip { position: relative; height: 16px; }
.cs-gradient-handle {
  position: absolute;
  top: 2px;
  width: 12px;
  height: 12px;
  margin-left: -6px;
  padding: 0;
  border-radius: 50%;
  cursor: ew-resize;
  border: 2px solid #fff;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
  touch-action: none;
}
.cs-gradient-handle.is-selected {
  border-color: var(--cs-accent);
  box-shadow: 0 0 0 1px var(--cs-accent), 0 1px 3px rgba(0, 0, 0, 0.5);
}
.cs-gradient-stop {
  display: grid;
  grid-template-columns: 24px minmax(0, 1fr) minmax(0, 1fr) 18px 18px;
  gap: 6px;
  align-items: center;
}
.cs-gradient-stop .cs-value { text-align: left; }
.cs-aux-btn {
  width: 18px;
  height: 18px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--cs-r-sm);
  cursor: pointer;
  background: none;
  border: 1px solid var(--cs-line-hi);
  color: var(--cs-muted);
  font: 11px / 1 var(--cs-font-mono);
}
.cs-aux-btn:hover:not(:disabled) { color: var(--cs-accent); border-color: var(--cs-accent); }
.cs-aux-btn:disabled { opacity: 0.4; cursor: default; }

/* ───────────────────────── angle wheel ───────────────────────── */
.cs-row[data-type="wheels"] { align-items: start; }
.cs-row[data-type="wheels"] .cs-label { padding-top: 4px; }
.cs-wheels { display: flex; gap: 8px; align-items: flex-start; min-width: 0; }
.cs-wheels > .cs-wheel { flex: 1 1 0; min-width: 0; }
.cs-wheel { display: flex; flex-direction: column; align-items: center; gap: 4px; }
.cs-wheel-label {
  font: 600 var(--cs-fs-section) / 1 var(--cs-font-head);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--cs-muted-2);
}
.cs-wheel.is-animated .cs-wheel-label::after { content: ' \2022'; color: var(--cs-accent); }
.cs-wheel.is-animated .cs-wheel-label,
.cs-wheel.is-animated .cs-value { color: var(--cs-accent); }
.cs-wheel.is-animated .cs-wheel-canvas,
.cs-wheel.is-animated .cs-value,
.cs-wheel.is-animated .cs-reset { pointer-events: none; }
.cs-wheel.is-animated .cs-value:disabled { opacity: 1; }
.cs-wheel-canvas {
  display: block;
  width: 64px;
  height: 64px;
  border-radius: 50%;
  cursor: pointer;
  /* The pointer owns the gesture: without this the page scrolls under it. */
  touch-action: none;
}
.cs-wheel-canvas:focus { outline: none; }
.cs-wheel .cs-value { width: 100%; text-align: center; }
.cs-wheel.is-dirty .cs-reset { display: inline-flex; align-items: center; justify-content: center; }
.cs-wheel.inactive { opacity: 0.35; }
.cs-wheel.inactive .cs-wheel-canvas,
.cs-wheel.inactive .cs-value { cursor: not-allowed; pointer-events: none; }

/* ───────────────────────── card rows ───────────────────────── */
/* Every setting inside an open group (and inside a panel body of its own, the
   export panel) is a card: the name and the readout on the first line, the
   control across the second. Rows nested in a track card or a list keep the
   compact four-column grammar above, so the exceptions come last. */
.cs-group-body .cs-row,
.cs-panel-body .cs-row,
.cs-track-body > .cs-row {
  grid-template-columns: minmax(0, 1fr) auto auto;
  grid-template-areas:
    "label value aux"
    "ctl ctl ctl";
  gap: var(--cs-card-gap);
  align-items: center;
  /* Apps nest rows inside their own wrappers, where the body's own gap cannot
     reach them; a direct child takes the gap instead (the rule below). */
  margin: var(--cs-card-gap) 0 0;
  padding: var(--cs-card-pad);
  border-radius: var(--cs-card-r);
  background: var(--cs-card-bg);
  border: 1px solid var(--cs-card-line);
}
.cs-group-body > .cs-row { margin: 0; }
.cs-group-body .cs-row > *,
.cs-panel-body .cs-row > *,
.cs-track-body > .cs-row > * { grid-area: ctl; min-width: 0; }
.cs-group-body .cs-row > .cs-span,
.cs-panel-body .cs-row > .cs-span,
.cs-track-body > .cs-row > .cs-span { grid-area: ctl; }
.cs-group-body .cs-row > .cs-label,
.cs-panel-body .cs-row > .cs-label,
.cs-track-body > .cs-row > .cs-label {
  grid-area: label;
  padding-top: 0;
  color: var(--cs-text);
  font-weight: 500;
}
.cs-group-body .cs-row > .cs-value,
.cs-panel-body .cs-row > .cs-value,
.cs-track-body > .cs-row > .cs-value { grid-area: value; width: 52px; }
.cs-group-body .cs-row > .cs-aux,
.cs-panel-body .cs-row > .cs-aux,
.cs-track-body > .cs-row > .cs-aux { grid-area: aux; }
/* A toggle says everything on the first line, so it has no second one. */
.cs-group-body .cs-row[data-type="toggle"],
.cs-panel-body .cs-row[data-type="toggle"] { grid-template-areas: "label value aux"; }
.cs-group-body .cs-row[data-type="toggle"] > .cs-pill,
.cs-panel-body .cs-row[data-type="toggle"] > .cs-pill { grid-area: value; grid-column: value; justify-self: end; }
/* A label-less field (the Save panel's name) has no first line either. */
.cs-group-body .cs-row.is-bare,
.cs-panel-body .cs-row.is-bare { grid-template-areas: "ctl ctl ctl"; }
.cs-group-body .cs-row > .cs-color,
.cs-panel-body .cs-row > .cs-color { grid-template-columns: 1fr 72px; }

/* The compact grammar, kept for a row nested inside another widget: a list,
   or the gradient block's own row. Those are not settings of the group, so
   they are not cards, and a track card takes the card grammar above instead.
   `:is()` keeps the list readable; each rule still outranks its card
   counterpart above. */
:is(.cs-list-wrap, .cs-gradient) .cs-row {
  grid-template-columns: var(--cs-row-cols);
  grid-template-areas: none;
  gap: var(--cs-row-gap);
  margin: var(--cs-row-my) 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: none;
}
/* The card grammar names its children by class, so the compact one has to
   hand every named child back its ordinary place on the grid. */
:is(.cs-list-wrap, .cs-gradient) .cs-row > *,
:is(.cs-list-wrap, .cs-gradient) .cs-row > :is(.cs-label, .cs-value, .cs-aux) { grid-area: auto; }
:is(.cs-list-wrap, .cs-gradient) .cs-row > .cs-span { grid-column: 2 / span 3; }
:is(.cs-list-wrap, .cs-gradient) .cs-row > .cs-label { color: var(--cs-muted); font-weight: 400; }
:is(.cs-list-wrap, .cs-gradient) .cs-row > .cs-value { width: 100%; }
:is(.cs-list-wrap, .cs-gradient) .cs-row[data-type="toggle"] > .cs-pill { grid-column: 2 / span 3; justify-self: start; }

/* ───────────────────────── group ───────────────────────── */
.cs-group-head {
  width: 100%;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 0;
  background: none;
  border: none;
  border-top: 1px solid var(--cs-line);
  cursor: pointer;
  text-align: left;
}
/* The hairline sits between groups, so a group draws it only when another
   group precedes it. A sibling rule reads the same wherever the app wraps its
   groups (EMITR nests them under .panel > .panel-content, WYR under a plain
   div), which a :first-child rule on the panel body cannot. */
.cs-group > .cs-group-head { border-top-width: 0; }
.cs-group + .cs-group > .cs-group-head { border-top-width: 1px; }
.cs-group-ind {
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  border: 1px solid rgba(var(--cs-accent-rgb), 0.55);
  background: rgba(var(--cs-accent-rgb), 0.12);
  color: var(--cs-accent);
  font: 500 10px / 1 var(--cs-font-ui);
}
.cs-group-head:hover .cs-group-ind { filter: brightness(1.3); }
.cs-group-label {
  font: 600 var(--cs-fs-section) / 1 var(--cs-font-head);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--cs-muted-2);
}
.cs-group-head:hover .cs-group-label { color: var(--cs-text); }
/* The cards stand in a column of their own, with no left indent: the card
   edges already say what belongs to the group. */
.cs-group-body { display: flex; flex-direction: column; gap: var(--cs-card-gap); padding: 2px 0 8px 0; }
.cs-group-body[hidden] { display: none; }
.cs-group[hidden] { display: none; }
.cs-row[hidden] { display: none; }
.cs-actions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; }
/* Section 0: the one line a library panel says its last action in, under that
   panel's actions. Muted and small, so it reads as a report rather than a
   control. The engine's own messages stay outside the shell. */
.cs-status {
  margin: 6px 2px 0;
  color: var(--cs-muted-2);
  font: var(--cs-fs-value) / 1.5 var(--cs-font-ui);
}
/* Secondary: the plain outlined pill, no fill. */
.cs-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 6px 12px;
  border-radius: var(--cs-r-pill);
  cursor: pointer;
  font: var(--cs-fs-row) / 1.2 var(--cs-font-ui);
  background: transparent;
  color: var(--cs-accent);
  border: 1px solid var(--cs-line);
  transition: background var(--cs-dur) var(--cs-ease), border-color var(--cs-dur) var(--cs-ease), color var(--cs-dur) var(--cs-ease);
}
.cs-btn[hidden] { display: none; }
.cs-btn:hover:not(:disabled) { background: var(--cs-bg-hover); }
.cs-btn:disabled { opacity: 0.5; cursor: default; }
.cs-btn-icon { display: inline-flex; width: 16px; height: 16px; flex: 0 0 auto; }
.cs-btn-icon svg { width: 16px; height: 16px; display: block; }
/* Primary: one per panel, filled, full width. Every primary pill is the same
   38px tall, with or without an icon: the splash's and the share dialog's too. */
.cs-btn.primary {
  flex: 1 1 100%;
  box-sizing: border-box;
  min-height: 38px;
  padding: 0 14px;
  background: var(--cs-accent);
  color: #fff;
  border-color: var(--cs-accent);
  font-weight: 600;
  letter-spacing: .04em;
}
.cs-btn.primary:hover:not(:disabled) { filter: brightness(1.08); background: var(--cs-accent); }
/* Danger: destructive actions, outlined; armed (filled) while a press waits
   for the second one that commits it (share's Revoke?). */
.cs-btn.danger { color: var(--cs-danger); border-color: var(--cs-danger); }
.cs-btn.danger:hover:not(:disabled) { background: rgba(var(--cs-danger-rgb), 0.12); }
.cs-btn.danger.armed { background: var(--cs-danger); color: #fff; }
.cs-btn.danger.armed:hover:not(:disabled) { filter: brightness(1.08); background: var(--cs-danger); }
/* Small: a per-row primary, not the one full-width primary per panel. */
.cs-btn.primary.small, .cs-btn.small { flex: 0 0 auto; width: auto; min-height: 0; padding: 3px 10px; }
/* Icon button: a 24px square carrying a glyph instead of a word. The trash
   uses it everywhere a list or a track card deletes something. */
.cs-btn.cs-icon-btn {
  width: 24px;
  height: 24px;
  flex: 0 0 auto;
  padding: 0;
  gap: 0;
  border-radius: var(--cs-r-sm);
}
.cs-btn.cs-icon-btn svg { display: block; width: 14px; height: 14px; }

/* ───────────────────────── list ───────────────────────── */
.cs-list-wrap { display: flex; flex-direction: column; min-width: 0; }
.cs-list { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.cs-list.is-cards { display: grid; gap: 10px; }
.cs-list-empty { margin: 8px 2px; color: var(--cs-muted-2); font: var(--cs-fs-row) / 1.5 var(--cs-font-ui); }
/* The heading over a run of items that named a group. It reads as the group
   header it stands in for, and in a card grid it takes the whole width so the
   run below it starts on a fresh line. */
.cs-list-group {
  margin: 6px 2px 0;
  font: 600 var(--cs-fs-section) / 1 var(--cs-font-head);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--cs-muted-2);
}
.cs-list.is-cards .cs-list-group { grid-column: 1 / -1; }
.cs-list-group:first-child { margin-top: 0; }

.cs-list-row {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  padding: 5px 6px;
  border-radius: var(--cs-r-sm);
  border: 1px solid transparent;
  cursor: pointer;
}
.cs-list-row:hover { background: var(--cs-bg-hover); }
.cs-list-row:focus-visible { outline: none; border-color: var(--cs-accent); }
.cs-list-row.is-selected { border-color: var(--cs-accent); background: rgba(var(--cs-accent-rgb), 0.10); }
.cs-list-name {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--cs-text);
}
.cs-list-when { flex: 0 0 auto; color: var(--cs-muted-2); font: var(--cs-fs-value) / 1.4 var(--cs-font-mono); }
.cs-list-meta {
  flex: 0 0 auto;
  max-width: 40%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--cs-muted);
  font: var(--cs-fs-value) / 1.4 var(--cs-font-ui);
}
.cs-list-btns { flex: 0 0 auto; display: flex; gap: 4px; }

/* Cards: EMITR's preset-card look, scrolling with the panel body. */
.cs-card {
  display: flex;
  flex-direction: column;
  min-width: 0;
  background: rgba(255, 255, 255, 0.05);
  border: 2px solid var(--cs-line-hi);
  border-radius: 10px;
  overflow: hidden;
  cursor: pointer;
  transition: border-color var(--cs-dur) var(--cs-ease);
}
.cs-card:hover, .cs-card:focus-within { border-color: rgba(var(--cs-accent-rgb), 0.6); }
.cs-card:focus-visible { outline: none; border-color: var(--cs-accent); }
.cs-card.is-selected { border-color: var(--cs-accent); box-shadow: 0 0 0 1px var(--cs-accent); }
.cs-card-thumb {
  position: relative;
  aspect-ratio: 16 / 9;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  background: rgba(0, 0, 0, 0.3);
}
.cs-card-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.cs-card-thumb.is-placeholder::before {
  content: '';
  width: 22px;
  height: 22px;
  border-radius: 4px;
  border: 1px dashed var(--cs-line-hi);
}
.cs-card-name {
  padding: 6px 8px 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--cs-text);
  font: var(--cs-fs-row) / 1.3 var(--cs-font-ui);
}
.cs-card-meta { padding: 0 8px; color: var(--cs-muted-2); font: var(--cs-fs-value) / 1.4 var(--cs-font-mono); }
/* The tier badge on a card's thumbnail corner: Free reads quiet, Pro in the
   accent. The same word rides a list row as a small pill. */
.cs-card-badge, .cs-list-badge {
  display: inline-block;
  padding: 2px 7px;
  border-radius: var(--cs-r-pill);
  font: 600 10px / 1.3 var(--cs-font-head);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--cs-muted);
  background: rgba(0, 0, 0, 0.55);
  border: 1px solid rgba(255, 255, 255, 0.14);
  pointer-events: none;
}
/* Top-right: the lock keeps the top-left corner. */
.cs-card-badge { position: absolute; top: 6px; right: 6px; }
.cs-list-badge { flex: 0 0 auto; margin-left: 6px; }
.cs-card-badge.is-pro, .cs-list-badge.is-pro { color: #fff; background: rgba(var(--cs-accent-rgb), 0.85); border-color: rgba(var(--cs-accent-rgb), 0.9); }
.cs-card-badge.is-free, .cs-list-badge.is-free { color: var(--cs-text); }
/* The filter field keeps clear of the first run heading below it. */
.cs-list-wrap > .cs-chips-filter { margin-bottom: 10px; }
.cs-card-btns {
  display: flex;
  gap: 4px;
  padding: 6px 8px 8px;
  opacity: 0;
  transition: opacity var(--cs-dur) var(--cs-ease);
}
.cs-card:hover .cs-card-btns, .cs-card:focus-within .cs-card-btns { opacity: 1; }
/* The card's only button: the trash, in the thumbnail's top-right corner, so
   the card itself stays one loading target. It fades in with the card; its
   press asks the confirm dialog before anything is deleted. */
.cs-card-trash { position: absolute; top: 6px; right: 6px; display: flex; gap: 4px; }
.cs-card-trash .cs-btn {
  background: rgba(0, 0, 0, 0.55);
  opacity: 0;
  transition: opacity var(--cs-dur) var(--cs-ease), background var(--cs-dur) var(--cs-ease);
}
.cs-card:hover .cs-card-trash .cs-btn,
.cs-card:focus-within .cs-card-trash .cs-btn { opacity: 1; }
@media (hover: none) { .cs-card-trash .cs-btn, .cs-card-btns { opacity: 1; } }

/* An item that is in the list but cannot be used yet: the padlock where the
   card's badge would sit, and the whole item held back a little. It is never
   hidden and never disabled, because clicking it is how the app is asked for
   the upgrade. */
.cs-card-lock {
  position: absolute;
  top: 6px;
  left: 6px;
  display: flex;
  padding: 3px;
  border-radius: var(--cs-r-sm);
  background: rgba(0, 0, 0, 0.55);
  color: var(--cs-text);
}
.cs-card-lock svg, .cs-list-lock svg { display: block; width: 13px; height: 13px; }
.cs-list-lock { display: flex; color: var(--cs-muted-2); }
.cs-card.is-locked .cs-card-thumb img { opacity: 0.45; }
.cs-list-row.is-locked .cs-list-name { color: var(--cs-muted-2); }

/* ───────────────────────── tracks panel ───────────────────────── */
/* A track is a card on the same surface as a setting card, and the rows
   inside it are the panel's ordinary two-line rows: the card is the card, so
   they drop its chrome and take a hairline between them instead. */
.cs-track-list { display: flex; flex-direction: column; gap: 8px; min-width: 0; max-width: 100%; }
/* A canvas inside a flex or grid item is sized by its backing store in Safari
   unless every ancestor may shrink below its content. */
.cs-track, .cs-track-body, .cs-curve, .cs-curve-plot { min-width: 0; max-width: 100%; }
.cs-curve-canvas { max-width: 100%; }
.cs-track {
  padding: 12px;
  border-radius: var(--cs-card-r);
  background: var(--cs-card-bg);
  border: 1px solid var(--cs-card-line);
}
.cs-track.is-off { opacity: 0.55; }
.cs-track.is-unavailable .cs-track-body { opacity: 0.5; }
.cs-track-head {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: var(--cs-row-h);
  font: var(--cs-fs-row) / 1.45 var(--cs-font-ui);
}
.cs-track-fold {
  width: 18px;
  height: 18px;
  flex: 0 0 auto;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: 0;
  color: var(--cs-muted);
  cursor: pointer;
}
.cs-track-fold svg { width: 10px; height: 10px; display: block; transition: transform var(--cs-dur) var(--cs-ease); }
.cs-track-fold.is-closed svg { transform: rotate(-90deg); }
.cs-track-fold:hover { color: var(--cs-accent); }
.cs-track-title {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--cs-text-strong);
}
/* The group the parameter comes from, as a suffix on the name. */
.cs-track-meta { color: var(--cs-muted-2); font-size: 11px; }
/* The summary stands in for the card while it is folded away. */
.cs-track-sum {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--cs-muted-2);
  font: var(--cs-fs-value) / 1.4 var(--cs-font-mono);
}
.cs-track:not(.is-folded) .cs-track-sum { display: none; }
.cs-track-head .cs-pill { flex: 0 0 auto; }
.cs-track-remove {
  width: 24px;
  height: 24px;
  flex: 0 0 auto;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--cs-r-sm);
  cursor: pointer;
  background: none;
  border: 1px solid rgba(var(--cs-danger-rgb), 0.4);
  color: var(--cs-danger);
}
.cs-track-remove:hover { border-color: var(--cs-danger); background: rgba(var(--cs-danger-rgb), 0.12); }
.cs-track-remove svg { display: block; width: 14px; height: 14px; }
.cs-track-body[hidden] { display: none; }
.cs-track-body > .cs-curve { margin: 6px 0 2px; }
.cs-track-body > .cs-row {
  margin: 0;
  padding: 8px 0;
  border: 0;
  border-radius: 0;
  background: none;
}
.cs-track-body > .cs-row + .cs-row { border-top: 1px solid var(--cs-line); }
.cs-track-empty { margin: 8px 0; color: var(--cs-muted-2); font: var(--cs-fs-row) / 1.5 var(--cs-font-ui); }
.cs-track-note { margin: 6px 0 0; color: var(--cs-muted-2); font: var(--cs-fs-row) / 1.5 var(--cs-font-ui); }
.cs-loop-btn svg { width: 12px; height: 12px; display: block; }

/* ───────────────────────── shell ───────────────────────── */
/* One column on the left, full height: rail, then the open panel. */
.cs-shell {
  position: absolute;
  inset: var(--cs-shell-inset);
  top: var(--cs-shell-top);
  pointer-events: none;
  z-index: 100;
  display: flex;
  gap: var(--cs-shell-gap);
  align-items: stretch;
}
.cs-shell[hidden] { display: none; }
@media (max-width: 767px) { .cs-shell { display: none; } }
.cs-rail {
  pointer-events: auto;
  display: flex;
  flex-direction: column;
  gap: var(--cs-rail-gap);
  overflow-y: auto;
  scrollbar-width: none;
  flex: 0 0 auto;
}
.cs-rail::-webkit-scrollbar { display: none; }
/* The buttons sit in the middle of the column, not against its top. Auto
   margins on the ends centre the block and still let a rail taller than the
   viewport scroll from its first button (justify-content would clip it). */
.cs-rail > :first-child { margin-top: auto; }
.cs-rail > :last-child { margin-bottom: auto; }
/* The break between the rail's three sections: a 16px gap with a hairline
   centred in it. Not a button, and never focusable. */
.cs-rail-sep {
  flex: 0 0 auto;
  height: 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}
.cs-rail-sep::before {
  content: '';
  width: 24px;
  height: 1px;
  background: var(--cs-line);
}
.cs-rail-btn {
  width: var(--cs-rail-btn);
  height: var(--cs-rail-btn);
  padding: 0;
  border-radius: var(--cs-rail-r);
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--cs-muted);
  flex: 0 0 auto;
  background: var(--cs-glass);
  -webkit-backdrop-filter: var(--cs-blur);
  backdrop-filter: var(--cs-blur);
  border: 1px solid rgba(var(--cs-accent-rgb), 0.22);
  box-shadow: var(--cs-glass-hi), 0 1px 2px rgba(0, 0, 0, 0.3), 0 0 10px rgba(var(--cs-accent-rgb), 0.12);
  /* The active fill is not transitioned: it must read as the accent the moment
     the panel opens, and an interpolating background is what a reader sees. */
  transition: border-color var(--cs-dur) var(--cs-ease), color var(--cs-dur) var(--cs-ease);
}
/* Glyphs keep their own fill/stroke attributes; only the size is imposed. */
.cs-rail-btn svg { width: var(--cs-rail-glyph); height: var(--cs-rail-glyph); display: block; }
.cs-rail-btn:hover { border-color: rgba(var(--cs-accent-rgb), 0.7); color: var(--cs-text-strong); }
.cs-rail-btn.active { background: var(--cs-accent); border-color: var(--cs-accent); color: #fff; }
/* A rail button's name, to its right, in place of the browser's tooltip. Fixed
   and placed by controls.js from the button's box (left is 10px off the button's
   right edge, top is the button's middle). It emerges from the button: it starts
   8px nearer (2px clear of the button's edge, never over it), a touch narrower
   from its left side, and eases out to rest as it fades in. It never takes a
   press. The panel's glass and the panel title's type; the ink is the app's:
   `--cs-rail-label-ink` is any CSS background (a gradient, say), clipped to the
   text, and defaults to the strong text color. */
.cs-rail-label {
  position: fixed; z-index: 60; left: 0; top: 0;
  transform-origin: 0 50%;
  transform: translate(0, -50%);
  padding: 6px 10px; border-radius: 9px;
  border: 1px solid var(--cs-line);
  background: var(--cs-glass);
  -webkit-backdrop-filter: var(--cs-blur); backdrop-filter: var(--cs-blur);
  box-shadow: var(--cs-glass-hi), 0 4px 14px rgba(0, 0, 0, 0.35);
  font: 600 11px / 1 var(--cs-font-ui); letter-spacing: .08em; text-transform: uppercase; white-space: nowrap;
  opacity: 0; pointer-events: none;
  /* Leaving is brisk (this rule); arriving is unhurried (the .is-on rule). */
  transition: opacity 160ms var(--cs-ease);
}
.cs-rail-label.is-on { opacity: 1; transition: opacity 320ms var(--cs-ease); }
/* The travel out of the button is an animation, not a transition, so it can
   replay on every button while the opacity stays where it is: a name that is
   already lit re-emerges from the next button without fading out first. */
.cs-rail-label.is-emerging { animation: cs-rail-emerge 440ms cubic-bezier(0.2, 0.8, 0.2, 1) both; }
@keyframes cs-rail-emerge {
  from { transform: translate(-8px, -50%) scaleX(0.94); }
  to { transform: translate(0, -50%) scaleX(1); }
}
.cs-rail-label-text {
  display: block;
  background: var(--cs-rail-label-ink, linear-gradient(var(--cs-text-strong), var(--cs-text-strong)));
  -webkit-background-clip: text; background-clip: text;
  color: transparent; -webkit-text-fill-color: transparent;
}
@media (prefers-reduced-motion: reduce) { .cs-rail-label, .cs-rail-label.is-on { transition: none; } .cs-rail-label.is-emerging { animation: none; } }

/* ───────────────────────── panel chrome ───────────────────────── */
.cs-panel {
  pointer-events: auto;
  width: var(--cs-panel-w);
  max-width: calc(100vw - var(--cs-shell-inset) * 2 - var(--cs-rail-btn) - var(--cs-shell-gap));
  display: flex;
  flex-direction: column;
  /* Only as tall as its settings: the panel hugs its content, its top on
     the first rail button and its bottom never past the last (makeShell
     measures the block); anything longer scrolls inside. */
  align-self: flex-start;
  margin-top: var(--cs-panel-top, 0px);
  max-height: var(--cs-panel-max, 100%);
  border-radius: var(--cs-panel-r);
  background: var(--cs-glass);
  -webkit-backdrop-filter: var(--cs-blur);
  backdrop-filter: var(--cs-blur);
  border: 1px solid var(--cs-line);
  box-shadow: var(--cs-glass-hi), var(--cs-shadow-panel);
  color: var(--cs-text);
  font: var(--cs-fs-row) / 1.45 var(--cs-font-ui);
  box-sizing: border-box;
  overflow: hidden;
}
.cs-panel[hidden] { display: none; }
.cs-panel-title {
  flex: 0 0 auto;
  margin: 0;
  padding: 14px 16px 8px;
  font: 700 var(--cs-fs-head) / 1 var(--cs-font-head);
  letter-spacing: 2.5px;
  text-transform: uppercase;
  color: var(--cs-accent);
  border-bottom: 1px solid var(--cs-line);
}
.cs-panel-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: var(--cs-panel-pad);
  scrollbar-width: thin;
  scrollbar-color: rgba(var(--cs-accent-rgb), 0.55) transparent;
}
.cs-panel-body::-webkit-scrollbar { width: 6px; }
.cs-panel-body::-webkit-scrollbar-thumb { background: rgba(var(--cs-accent-rgb), 0.55); border-radius: 3px; }
.cs-panel-body::-webkit-scrollbar-track { background: transparent; }
/* "More below": a fade over the bottom edge and a chevron sitting in it;
   "more above": a fade at the top. makeShell sets the classes as the body
   scrolls or resizes. The overlays never take the pointer. */
.cs-panel { position: relative; }
.cs-panel::before, .cs-panel::after {
  content: '';
  position: absolute;
  left: 1px;
  right: 1px;
  height: 36px;
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--cs-dur) var(--cs-ease);
  z-index: 1;
}
.cs-panel::before {
  top: calc(var(--cs-fs-head) + 23px);
  background: linear-gradient(180deg, var(--cs-bg-panel), transparent);
}
.cs-panel::after {
  bottom: 0;
  border-radius: 0 0 var(--cs-panel-r) var(--cs-panel-r);
  background:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E") center bottom 6px / 14px 14px no-repeat,
    linear-gradient(0deg, var(--cs-bg-panel), transparent);
}
.cs-panel.has-more-above::before { opacity: 1; }
.cs-panel.has-more-below::after { opacity: 1; }

/* ───────────────────────── confirm ───────────────────────── */
/* The package's one dialog: a question in front of a press that cannot be
   taken back. Glass on the panel's own surface, over a dimmed stage. */
.cs-confirm-back {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background: rgba(0, 0, 0, 0.52);
}
.cs-confirm {
  width: min(360px, 100%);
  padding: 18px 20px 16px;
  border-radius: var(--cs-panel-r);
  border: 1px solid var(--cs-line);
  background: var(--cs-glass);
  -webkit-backdrop-filter: var(--cs-blur);
  backdrop-filter: var(--cs-blur);
  box-shadow: var(--cs-shadow-panel), var(--cs-glass-hi);
  color: var(--cs-text);
}
.cs-confirm-title {
  margin: 0 0 8px;
  color: var(--cs-accent);
  font: 600 var(--cs-fs-head) / 1.3 var(--cs-font-head);
  letter-spacing: .12em;
  text-transform: uppercase;
  overflow-wrap: anywhere;
}
/* The word a card wants seen: the app's ink clipped to the letters. */
.cs-accent-text {
  font-weight: 700;
  background: var(--cs-accent-ink, linear-gradient(rgb(var(--cs-accent-rgb)), rgb(var(--cs-accent-rgb))));
  -webkit-background-clip: text; background-clip: text;
  color: transparent; -webkit-text-fill-color: transparent;
}
.cs-confirm-text {
  margin: 0 0 6px;
  color: var(--cs-muted);
  font: var(--cs-fs-row) / 1.55 var(--cs-font-ui);
}
.cs-confirm-actions { margin-top: 14px; }
.cs-confirm-actions .cs-btn.primary,
.cs-confirm-actions .cs-btn.danger { flex: 1 1 auto; }
.cs-confirm .cs-btn:focus-visible { outline: 2px solid var(--cs-accent); outline-offset: 2px; }

/* ───────────────────────── quick start ─────────────────────────
   The step-by-step menu over the stage's top third: a plain vertical stack,
   every block sharing one left edge and one right edge. Top to bottom: a
   title strip (the app's wordmark and heading, and the skip action) under
   a rule, its own intro line, a step heading line (the title, its progress
   segments and the count), the tiles row, then a footer under its own rule
   (the startup toggle at the left, Back and Next at the right). It never
   dims or blurs the stage: the artwork changing behind it is the feedback.
   The panel has ONE fixed width for the whole session (below), not one
   that hugs each step's own tiles: a step with 2 tiles and a step with 6
   no longer resize the panel, wrap the strip or lurch the footer as the
   user presses Next. The root is the panel's transparent positioned
   wrapper, pointer-events: none outside it (never CSS grid, whose own
   track sizing fights a fixed width the same way fit-content used to). */
.cs-quickstart {
  position: fixed; z-index: 9000; box-sizing: border-box; pointer-events: none;
  top: calc(var(--cs-shell-top, 0px) + 24px); left: 0; right: 0; margin-inline: auto;
  width: min(760px, calc(100vw - 32px));
  color: var(--cs-text); font: var(--cs-fs-row) / 1.45 var(--cs-font-ui);
}
.cs-quickstart-panel {
  box-sizing: border-box; min-width: 0; max-width: 100%; pointer-events: auto;
  display: flex; flex-direction: column;
  padding: 22px 28px 20px;
  border-radius: 22px; border: 1px solid var(--cs-line);
  background: var(--cs-glass);
  -webkit-backdrop-filter: var(--cs-blur); backdrop-filter: var(--cs-blur);
  box-shadow: var(--cs-glass-hi), var(--cs-shadow-panel);
}
.cs-quickstart-top {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 8px 14px;
  padding-bottom: 16px; border-bottom: 1px solid var(--cs-line);
}
.cs-quickstart-brand {
  margin: 0; flex: 0 0 auto;
  color: var(--cs-text); font: 700 15px / 1 var(--cs-font-head);
  letter-spacing: 0.28em; text-transform: uppercase;
}
/* align-self: center, not baseline: an empty box has no text baseline of
   its own, so leaving it in the strip's baseline alignment would fall back
   to its bottom margin edge and throw the whole row off. The brand and the
   heading both stay in the strip's own align-items: baseline (deliberately
   NOT overridden here) so their text shares one baseline with skip's. */
.cs-quickstart-brand-rule { flex: 0 0 auto; align-self: center; width: 1px; height: 18px; background: var(--cs-line); }
.cs-quickstart-heading {
  margin: 0; flex: 0 0 auto;
  color: var(--cs-accent); font: 700 12px / 1 var(--cs-font-head);
  letter-spacing: 0.16em; text-transform: uppercase;
}
.cs-quickstart-skip {
  margin-left: auto; flex: 0 0 auto; padding: 0; border: 0; background: none;
  color: var(--cs-muted); font: 12px / 1 var(--cs-font-ui); cursor: pointer;
  text-decoration: underline; text-underline-offset: 3px;
}
.cs-quickstart-skip:hover { color: var(--cs-text); }
.cs-quickstart-intro { margin: 18px 0 0; color: var(--cs-text); font: 15px / 1.4 var(--cs-font-ui); }
/* The step heading line: title, its progress segments, and the (visible)
   count, baseline-aligned. 18px normally; 22px when it follows an intro
   line instead of sitting right under the strip's rule. */
.cs-quickstart-head { margin-top: 18px; display: flex; align-items: baseline; gap: 14px; }
.cs-quickstart-intro + .cs-quickstart-head { margin-top: 22px; }
/* No color and no !important here on purpose: the title is the one block an
   app's palette layer repaints (EMITR fills it with its own button gradient as
   background-clip: text), so a plain `.cs-quickstart .cs-quickstart-title` rule
   in theme.css wins on specificity alone, with no fight. It keeps its own
   ellipsis safety net and its title attribute either way. */
.cs-quickstart-title {
  margin: 0; flex: 1 1 auto; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  font: 600 22px / 1.15 var(--cs-font-head);
}
.cs-quickstart-dots { flex: 0 0 auto; align-self: center; display: flex; gap: 2px; }
.cs-quickstart-dots span { width: 6px; height: 4px; border-radius: 2px; background: var(--cs-line-hi); }
.cs-quickstart-dots span.is-on { width: 16px; background: rgb(var(--cs-accent-rgb)); }
.cs-quickstart-count {
  margin: 0 0 0 auto; flex: 0 0 auto;
  color: var(--cs-muted); font: 12px / 1 var(--cs-font-ui); letter-spacing: 0.04em; white-space: nowrap;
}
/* The tiles row carries 6px of padding, cancelled by a matching negative
   margin so the tiles still start at the shared left edge: the padding
   gives the selected tile's outward ring (accent, offset 2px, so it
   reaches 4px past the tile) and the focus ring (a box-shadow reaching
   6px past the tile) room to paint without being clipped. Without it,
   .cs-quickstart-tiles' own overflow-x: auto forces its overflow-y to
   resolve to auto too (per the CSS overflow spec, one axis can't stay
   'visible' once the other isn't), clipping both axes flush to the row's
   padding box; since that box used to have zero padding, any ring
   reaching past a tile's own edge, top, bottom, or at the first/last
   tile's outer side, was cut straight off. 8px top margin (14px minus the
   6px the padding already adds) keeps the visual gap from the step
   heading at 14px. */
.cs-quickstart-tiles {
  display: flex; align-items: flex-end; gap: 14px; overflow-x: auto; overflow-y: hidden; scrollbar-width: thin;
  box-sizing: border-box; padding: 6px; margin: 8px -6px -6px;
}
/* A group is a caption over a run of consecutive same-`group` options (e.g.
   "Solid" then "Gradient" in EMITR's Color step): a column of its own label
   above its own tile row, 6px apart. It sits at the tiles row's own gap
   (14px) from its neighbor plus this extra 14px, so two groups read 28px
   apart, clearly more than the 14px between plain tiles or tiles inside one
   group; align-items: flex-end on the row above keeps a step's own bare
   tiles (no caption above them) bottom-aligned with a group's tiles, not
   the group's caption, when the two sit side by side. Every tile shares the
   row equally (flex: 1 1 0 on .cs-quickstart-tile, below), so a group is
   given flex-grow, in quickstart.js, equal to its own tile count, claiming
   that many tiles' worth of space; its flex-basis there is its own internal
   gap total ((n-1) * 14px), not 0, so that once its own gaps are
   subtracted, the group's share still splits n ways to the exact width a
   bare tile gets from its 1-share, 0-basis slot. */
.cs-quickstart-group { display: flex; flex-direction: column; align-items: flex-start; gap: 6px; }
.cs-quickstart-group:not(:first-child) { margin-left: 14px; }
.cs-quickstart-group-label {
  margin: 0; color: var(--cs-muted); font: 11px / 1 var(--cs-font-ui);
  text-transform: uppercase; letter-spacing: 0.12em;
}
/* align-self: stretch overrides the group's own align-items: flex-start
   (needed so the caption above stays left-aligned rather than stretching):
   without it this row sizes to its tiles' min-content instead of the
   group's own assigned share of the shared row, leaving the group's own
   box wider than its tiles actually use and every grouped tile stuck at
   its min-width instead of its fair share. */
.cs-quickstart-group-tiles { display: flex; gap: 14px; align-self: stretch; }
/* Every tile shares the row equally: flex-grow 1 on a 0 basis splits the
   available width evenly, min-width keeps a tile usable (below that, the
   row scrolls, same as before), max-width stops a 2-tile step's tiles from
   growing past a sane size; any leftover space then sits at the row's own
   end (default justify-content: flex-start), so a capped-out step's tiles
   stay flush left like everything else, not centred or spread out. Height
   stays fixed at 92px: a step's tiles get wider or narrower, never taller. */
.cs-quickstart-tile {
  flex: 1 1 0; min-width: 96px; max-width: 200px;
  position: relative; height: 92px; padding: 0; border: 0;
  border-radius: 12px; overflow: hidden; background: rgba(255, 255, 255, 0.04); cursor: pointer;
  outline: 1px solid var(--cs-line); outline-offset: -1px;
}
.cs-quickstart-thumb { position: relative; display: block; width: 100%; height: 100%; }
.cs-quickstart-thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
/* A glyph tile has nothing to protect its label from (no image under it), so
   the glyph and its label are one centered group instead: the label is a
   normal-flow child of the thumb now (see quickstart.js), and the thumb lays
   the pair out as a flex column, 6px apart, both centered. */
.cs-quickstart-thumb.is-glyph { box-sizing: border-box; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px; }
.cs-quickstart-glyph { width: 48px; height: 48px; color: var(--cs-text); }
.cs-quickstart-glyph svg { display: block; width: 100%; height: 100%; }
.cs-quickstart-tile[aria-selected="true"] .cs-quickstart-glyph { color: rgb(var(--cs-accent-rgb)); }
.cs-quickstart-tile.is-locked .cs-quickstart-glyph { opacity: 0.45; }
/* A glyph tile's label has nothing to protect from (see above): no scrim, no
   absolute overlay, just centred text under the glyph, in flow. */
.cs-quickstart-thumb.is-glyph .cs-quickstart-label { position: static; padding: 0 8px; text-align: center; background: none; }
.cs-quickstart-tile:hover, .cs-quickstart-tile:focus-visible { outline-color: rgba(var(--cs-accent-rgb), 0.6); }
/* The focus ring is a box-shadow, painted under the outline, reaching
   further out (6px) than the selected ring's outline (4px = 2px offset +
   2px width), so a tile that is both selected and focused shows both:
   the accent ring, and the focus ring still visible just outside it. */
.cs-quickstart-tile:focus-visible { box-shadow: 0 0 0 6px rgba(255, 255, 255, 0.55); }
.cs-quickstart-tile[aria-selected="true"] { outline: 2px solid rgb(var(--cs-accent-rgb)); outline-offset: 2px; }
.cs-quickstart-tile.is-locked { cursor: not-allowed; }
.cs-quickstart-tile.is-locked .cs-quickstart-thumb img { opacity: 0.5; }
.cs-quickstart-label {
  position: absolute; left: 0; right: 0; bottom: 0; padding: 16px 12px 8px; text-align: left;
  font-size: 13px; color: var(--cs-text);
  background: linear-gradient(to top, rgba(0, 0, 0, 0.82), rgba(0, 0, 0, 0));
}
/* The control row: the picked option's own control (a color, a slider or a row
   of swatch chips), built from makeColor / makeSlider or the chips below, on
   the same shared left edge as every other block and spanning the panel's inner
   width. A flex column, not a plain block, so the .cs-row inside keeps its own
   5px margins instead of collapsing them out of the panel. The [hidden] rule is
   explicit: a class rule setting `display` outranks the UA's own
   `[hidden] { display: none }`. 32px is one ordinary row (22px plus its 2 x 5px
   margins) and 38px is a row of 28px chips; the box takes the taller of the
   two, so a slider row, a color row and a chips row are all the same height.
   The box is hidden whenever the picked option has no control, so nothing is
   reserved under the tiles. */
.cs-quickstart-control {
  margin-top: 14px; min-height: 38px;
  display: flex; flex-direction: column; justify-content: center;
}
.cs-quickstart-control[hidden] { display: none; }
/* A step's hint: one quiet line under the tiles (and the control row). */
.cs-quickstart-hint { margin: 14px 0 0; color: var(--cs-muted); font: 13px / 1.4 var(--cs-font-ui); }
.cs-quickstart-hint[hidden] { display: none; }
.cs-quickstart-control .cs-row { max-width: 360px; }
/* A choices row sizes its chips to content in column 2 rather than taking the
   ordinary four-column row grid, whose second column is too narrow for five
   44px chips. */
.cs-quickstart-control .cs-row[data-type="choices"] {
  grid-template-columns: minmax(0, 1.3fr) auto;
  max-width: 520px;
}
.cs-quickstart-choices { grid-column: 2; display: flex; gap: 6px; }
.cs-quickstart-chip {
  flex: 0 0 auto; width: 44px; height: 28px; padding: 0;
  border: 1px solid var(--cs-line-hi); border-radius: var(--cs-r-sm);
  cursor: pointer; background-clip: padding-box;
}
.cs-quickstart-chip:hover { border-color: rgba(var(--cs-accent-rgb), 0.6); }
.cs-quickstart-chip[aria-checked="true"] { outline: 2px solid rgb(var(--cs-accent-rgb)); outline-offset: 2px; }
.cs-quickstart-chip:focus-visible { box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.45); }
.cs-quickstart-foot {
  margin-top: 20px; padding-top: 16px; border-top: 1px solid var(--cs-line);
  display: flex; align-items: center; gap: 10px;
}
.cs-quickstart-startup { display: inline-flex; align-items: center; gap: 7px; font-size: 12px; color: var(--cs-muted); cursor: pointer; user-select: none; }
.cs-quickstart-startup input { accent-color: rgb(var(--cs-accent-rgb)); margin: 0; width: 14px; height: 14px; }
.cs-quickstart-nav { margin-left: auto; flex: 0 0 auto; display: flex; align-items: center; gap: 10px; }
.cs-quickstart-back {
  flex: 0 0 auto; width: 40px; height: 40px; padding: 0; border-radius: 50%;
  border: 1px solid var(--cs-line); background: none; color: var(--cs-text); cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.cs-quickstart-back:hover:not(:disabled) { border-color: var(--cs-line-hi); background: var(--cs-bg-hover); }
.cs-quickstart-back:disabled { color: var(--cs-muted-2); cursor: default; }
.cs-quickstart-back svg { display: block; }
.cs-btn.cs-quickstart-next { flex: 0 0 auto; height: 40px; padding: 0 18px; gap: 6px; font-size: 13px; white-space: nowrap; }
.cs-quickstart-next svg { display: block; }

@media (max-width: 600px) {
  .cs-quickstart { top: calc(var(--cs-shell-top, 0px) + 12px); width: calc(100vw - 24px); }
  .cs-quickstart-panel { width: 100%; padding: 16px 16px 16px; }
  /* Fixed size, not a share of the row: grow and shrink reset to 0 (the
     desktop rule's flex: 1 1 0 would otherwise stretch a short step's few
     tiles to fill the row's spare width). */
  .cs-quickstart-tile { flex: 0 0 124px; width: 124px; height: 78px; }
  /* A group's desktop flex-grow (set inline, per instance, in
     quickstart.js) is for sharing the row's fixed width; the phone row
     isn't fixed-width shared, its tiles are fixed-size and scroll, so a
     group here sizes to its own content like it always has. !important
     because an inline style otherwise outranks any stylesheet rule. */
  .cs-quickstart-group { flex: 0 0 auto !important; }
  .cs-quickstart-foot { flex-wrap: wrap; row-gap: 10px; }
  .cs-quickstart-glyph { width: 40px; height: 40px; }
}

/* ---- Launch splash (master section 19) ---------------------------------- */
/* The whole page dims and the card sits in its middle: unlike the quick start,
   nothing behind it is live, so the box takes pointer events and a press on it
   (not on the card) is the secondary way in. */
.cs-splash {
  position: fixed; inset: 0; z-index: 9100; box-sizing: border-box;
  display: flex; align-items: center; justify-content: center; padding: 16px;
  background: rgba(4, 7, 11, 0.62);
  color: var(--cs-text); font: var(--cs-fs-row) / 1.45 var(--cs-font-ui);
}
.cs-splash-card {
  box-sizing: border-box; width: min(560px, 100%); max-height: 100%; overflow: hidden auto;
  display: flex; flex-direction: column;
  border-radius: 22px; border: 1px solid var(--cs-line);
  background: var(--cs-glass);
  -webkit-backdrop-filter: var(--cs-blur); backdrop-filter: var(--cs-blur);
  box-shadow: var(--cs-glass-hi), var(--cs-shadow-panel);
}
.cs-splash-image { position: relative; flex: 0 0 auto; aspect-ratio: 16 / 9; background: rgba(255, 255, 255, 0.04); }
.cs-splash-image[hidden] { display: none; }
.cs-splash-image img { display: block; width: 100%; height: 100%; object-fit: cover; user-select: none; }
.cs-splash-body { display: flex; flex-direction: column; padding: 22px 28px 20px; }
.cs-splash-brand { margin: 0; font: 600 15px / 1.2 var(--cs-font-title, var(--cs-font-ui)); letter-spacing: .32em; text-transform: uppercase; color: var(--cs-text); }
/* Over the image the wordmark is large and sits at the lower left, on a scrim
   that only darkens the image's foot, so it reads over any picture. */
.cs-splash-image .cs-splash-brand {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 56px 28px 18px;
  font-size: 34px; letter-spacing: .38em; color: #fff;
  text-shadow: 0 1px 12px rgba(0, 0, 0, 0.55);
  background: linear-gradient(180deg, rgba(4, 7, 11, 0) 0%, rgba(4, 7, 11, 0.72) 100%);
  pointer-events: none;
}
.cs-splash-intro { margin: 10px 0 0; color: var(--cs-text); font: 15px / 1.4 var(--cs-font-ui); }
.cs-splash-actions { display: flex; gap: 10px; margin-top: 20px; }
.cs-splash-actions .cs-btn { flex: 1 1 0; width: auto; box-sizing: border-box; height: 38px; padding: 0 18px; white-space: nowrap; }
.cs-splash-startup { align-self: flex-start; display: inline-flex; align-items: center; gap: 7px; margin-top: 16px; font-size: 12px; color: var(--cs-muted); cursor: pointer; user-select: none; }
.cs-splash-startup input { accent-color: rgb(var(--cs-accent-rgb)); margin: 0; width: 14px; height: 14px; }
@media (max-width: 520px) {
  .cs-splash-body { padding: 18px 16px 16px; }
  .cs-splash-image .cs-splash-brand { padding: 40px 16px 12px; font-size: 26px; }
  .cs-splash-actions { flex-direction: column; }
  .cs-splash-actions .cs-btn { flex: 0 0 auto; width: 100%; }
}

/* ---- Share dialog (master section 20) ----------------------------------- */
.cs-share {
  position: fixed; inset: 0; z-index: 9100; box-sizing: border-box;
  display: flex; align-items: center; justify-content: center; padding: 16px;
  background: rgba(4, 7, 11, 0.62);
  color: var(--cs-text); font: var(--cs-fs-row) / 1.45 var(--cs-font-ui);
}
.cs-share-card {
  box-sizing: border-box; width: min(560px, 100%); max-height: min(720px, 100%);
  display: flex; flex-direction: column; padding: 22px 28px 20px;
  border-radius: 22px; border: 1px solid var(--cs-line);
  background: var(--cs-glass);
  -webkit-backdrop-filter: var(--cs-blur); backdrop-filter: var(--cs-blur);
  box-shadow: var(--cs-glass-hi), var(--cs-shadow-panel);
}
.cs-share-head { display: flex; align-items: baseline; gap: 14px; }
.cs-share-brand { font: 600 12px / 1.2 var(--cs-font-title, var(--cs-font-ui)); letter-spacing: .32em; text-transform: uppercase; color: var(--cs-text); }
.cs-share-brand-rule { align-self: center; width: 1px; height: 18px; background: var(--cs-line); }
.cs-share-title { margin: 0; flex: 1 1 auto; font: 600 12px / 1.2 var(--cs-font-title, var(--cs-font-ui)); letter-spacing: .22em; text-transform: uppercase; color: rgb(var(--cs-accent-rgb)); }
.cs-share-close { flex: 0 0 auto; padding: 0; border: 0; background: none; color: var(--cs-muted); font: 12px / 1 var(--cs-font-ui); text-decoration: underline; text-underline-offset: 3px; cursor: pointer; }
.cs-share-close:hover { color: var(--cs-text-strong); }
.cs-share-intro { margin: 16px 0 0; color: var(--cs-text); font: 15px / 1.4 var(--cs-font-ui); }
.cs-share-make { display: flex; gap: 10px; margin-top: 18px; }
.cs-share-name-input {
  flex: 1 1 auto; min-width: 0; box-sizing: border-box; height: 40px; padding: 0 12px;
  border-radius: 10px; border: 1px solid var(--cs-line); background: rgba(0, 0, 0, 0.28);
  color: var(--cs-text-strong); font: 13px / 1 var(--cs-font-ui); outline: none;
}
.cs-share-name-input::placeholder { color: var(--cs-muted-2); }
.cs-share-name-input:focus-visible { border-color: rgba(var(--cs-accent-rgb), 0.8); }
.cs-share-make .cs-btn.primary { flex: 0 0 auto; width: auto; height: 38px; padding: 0 18px; white-space: nowrap; }
.cs-share-notice { margin: 12px 0 0; font-size: 12px; color: var(--cs-muted); }
.cs-share-error { margin: 12px 0 0; padding: 9px 12px; border-radius: 10px; border: 1px solid rgba(var(--cs-danger-rgb), 0.3); background: rgba(var(--cs-danger-rgb), 0.08); color: var(--cs-danger); font-size: 12px; }
.cs-share-error[hidden] { display: none; }
.cs-share-subhead { margin: 22px 0 10px; font: 600 11px / 1 var(--cs-font-ui); letter-spacing: .14em; text-transform: uppercase; color: var(--cs-muted); }
.cs-share-library { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.cs-share-list { list-style: none; margin: 0; padding: 0; overflow-y: auto; min-height: 0; display: flex; flex-direction: column; gap: 8px; scrollbar-width: thin; }
.cs-share-row {
  display: flex; align-items: center; gap: 12px; padding: 8px;
  border-radius: 12px; border: 1px solid var(--cs-line); background: rgba(255, 255, 255, 0.03);
}
.cs-share-row.is-new { border-color: rgba(var(--cs-accent-rgb), 0.7); background: rgba(var(--cs-accent-rgb), 0.08); }
.cs-share-thumb { flex: 0 0 auto; width: 80px; aspect-ratio: 16 / 9; border-radius: 7px; overflow: hidden; background: rgba(255, 255, 255, 0.05); }
.cs-share-thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
.cs-share-text { flex: 1 1 auto; min-width: 0; }
.cs-share-name { color: var(--cs-text-strong); font-weight: 600; font-size: 13px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cs-share-url { margin-top: 2px; color: var(--cs-muted); font: 11px / 1.3 var(--cs-font-mono, ui-monospace, monospace); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cs-share-url.is-full { white-space: normal; overflow: visible; word-break: break-all; user-select: all; -webkit-user-select: all; color: var(--cs-text); }
.cs-share-meta { margin-top: 4px; display: flex; gap: 10px; font-size: 11px; color: var(--cs-muted); }
.cs-share-opens { color: var(--cs-text); font-weight: 600; }
.cs-share-actions { flex: 0 0 auto; display: flex; gap: 6px; }
.cs-share-actions .cs-btn.small { padding: 6px 10px; font-size: 11px; white-space: nowrap; }
.cs-share-row { flex-wrap: wrap; }
.cs-share-targets { flex: 1 1 100%; display: flex; flex-wrap: wrap; gap: 4px 14px; padding: 2px 2px 0; font-size: 11px; }
.cs-share-targets a { color: var(--cs-muted); text-decoration: underline; text-underline-offset: 3px; }
.cs-share-targets a:hover { color: var(--cs-text-strong); }
.cs-share-empty, .cs-share-loading { margin: 0; padding: 18px 0 6px; color: var(--cs-muted); font-size: 13px; }
@media (max-width: 520px) {
  .cs-share-card { padding: 18px 16px 16px; }
  .cs-share-make { flex-direction: column; }
  .cs-share-make .cs-btn.primary { width: 100%; }
  .cs-share-thumb { width: 56px; }
  .cs-share-actions { flex-direction: column; }
}
