/* =========================================================================
   GIGA-GLOSSARY — KOSMIC CHORUS LAYOUT
   The shell for index-kosmic.html. Loads after giga-kosmic.css.
   Scoped to :is([data-theme="kosmic"],[data-theme="prismatic"]) plus the new structural classes.
   ========================================================================= */

/* =========================================================================
   THE ALTITUDE PALETTE — defined once
   These ten values were duplicated in five separate maps across two files
   with two different owners (three here, two in giga-kosmic.css) and a sync
   script that overwrites. Ten hex values in five places is a colour change
   that has to be made five times and will eventually be made in four.

   Now: the palette is tokens on the theme root, and every map reads the
   token. A colour change is one edit, in one place, whoever makes it.
   ========================================================================= */
:is([data-theme="kosmic"],[data-theme="prismatic"]) {
  --alt-infrared: #8f5450;
  --alt-magenta: #d05a9e;
  --alt-red: #e0483c;
  --alt-amber: #d9a13b;
  --alt-umber: #a1887f;
  --alt-orange: #e2703a;
  --alt-green: #5fb87a;
  --alt-teal: #2f95a8;
  --alt-turquoise: #45d6c8;
  --alt-indigo: #7c6ce0;
}

/* Each element carrying an alt-* class lifts its own --alt. One list for
   every component in this file: a new component with no entry here falls
   back to the accent, which is the bug that produced teal portholes on
   orange readings. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) :is(.voice, .focus, .focus-index-row, .ag-lane, .nx-row, .nx-panel).alt-infrared { --alt: var(--alt-infrared); }
:is([data-theme="kosmic"],[data-theme="prismatic"]) :is(.voice, .focus, .focus-index-row, .ag-lane, .nx-row, .nx-panel).alt-magenta { --alt: var(--alt-magenta); }
:is([data-theme="kosmic"],[data-theme="prismatic"]) :is(.voice, .focus, .focus-index-row, .ag-lane, .nx-row, .nx-panel).alt-red { --alt: var(--alt-red); }
:is([data-theme="kosmic"],[data-theme="prismatic"]) :is(.voice, .focus, .focus-index-row, .ag-lane, .nx-row, .nx-panel).alt-amber { --alt: var(--alt-amber); }
:is([data-theme="kosmic"],[data-theme="prismatic"]) :is(.voice, .focus, .focus-index-row, .ag-lane, .nx-row, .nx-panel).alt-umber { --alt: var(--alt-umber); }
:is([data-theme="kosmic"],[data-theme="prismatic"]) :is(.voice, .focus, .focus-index-row, .ag-lane, .nx-row, .nx-panel).alt-orange { --alt: var(--alt-orange); }
:is([data-theme="kosmic"],[data-theme="prismatic"]) :is(.voice, .focus, .focus-index-row, .ag-lane, .nx-row, .nx-panel).alt-green { --alt: var(--alt-green); }
:is([data-theme="kosmic"],[data-theme="prismatic"]) :is(.voice, .focus, .focus-index-row, .ag-lane, .nx-row, .nx-panel).alt-teal { --alt: var(--alt-teal); }
:is([data-theme="kosmic"],[data-theme="prismatic"]) :is(.voice, .focus, .focus-index-row, .ag-lane, .nx-row, .nx-panel).alt-turquoise { --alt: var(--alt-turquoise); }
:is([data-theme="kosmic"],[data-theme="prismatic"]) :is(.voice, .focus, .focus-index-row, .ag-lane, .nx-row, .nx-panel).alt-indigo { --alt: var(--alt-indigo); }

/* =========================================================================
   THRESHOLD — the empty state
   One composition: the ground image, one headline, the field, the starters,
   the constellations. Everything that has no meaning before a referent
   exists is hidden rather than rendered empty.
   ========================================================================= */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .threshold { display: none; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.is-empty .threshold,
body.is-empty :is([data-theme="kosmic"],[data-theme="prismatic"]) .threshold { display: block; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.is-empty .tune-strip,
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.is-empty .chorus-label,
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.is-empty #core,
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.is-empty #chorus,
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.is-empty .help-panel,
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.is-empty .add-more,
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.is-empty .stage { display: none; }

/* the header must not float over the composition it belongs to */
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.is-empty .app-header {
  position: relative;
  border-bottom-color: transparent;
  background: transparent;
  box-shadow: none;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.is-empty .app-header .header-right { opacity: .92; }

/* On the threshold there is no backdrop at all: true black, and the image
   lives in .th-plate at its native scale. A ~512px asset stretched across a
   2560px ground was visibly soft — the elegance is in not asking it to be
   something it isn't. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.is-empty .ground { display: none; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .threshold {
  position: relative;
  z-index: 1;
  /* 76px was generous when the header already takes 64–117px, and every
     pixel here pushes the referent field toward the fold */
  padding: 40px 32px 72px;
}

/* the instrument's field: a centre axis and a faint pool of light, at the
   threshold of visibility — the coordinate space as the only ornament */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .threshold::before {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(90deg, transparent calc(50% - .5px), rgba(155, 227, 221, .07) 50%, transparent calc(50% + .5px)),
    radial-gradient(46% 42% at 50% 30%, rgba(155, 227, 221, .05) 0%, transparent 70%);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-inner {
  position: relative;
  z-index: 1;
  max-width: 780px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-eyebrow {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .26em;
  text-transform: uppercase;
  color: var(--label);
}

/* 100vw includes the scrollbar's width, so the aperture would otherwise add
   a horizontal scrollbar of its own */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .threshold { overflow-x: clip; }

/* ---- the aperture: a slit cut through the page ----
   Capped at the media's native width — 1600px for the still, 1280px for the
   loop — so neither is ever upscaled. The side fades run to black, so the
   cap is invisible: on a wider screen it still reads as full-bleed. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-plate {
  position: relative;
  /* now below the field, so the top margin separates it from the starters */
  margin-top: 46px;
  /* no negative margin: .th-inner is a centred flex column, so an item wider
     than the container already overflows equally both sides. Adding the
     block-layout full-bleed trick double-counts and shifts it left. */
  width: 100vw;
  height: 300px;
  overflow: hidden;
  flex: none;
  background: var(--bg);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-plate img,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-plate video {
  position: absolute;
  top: 0;
  left: 50%;
  transform: translateX(-50%);
  height: 100%;
  width: 100%;
  /* cover is CORRECT here: the threshold aperture is a decorative full-bleed
     100vw slit where cropping is the intent. Under contain a 1600x900 source
     painted 533x300 and left 196px of empty band each side. The core's
     no-clip fix lives on .core-img-wrap, not here. */
  object-fit: cover;
  filter: none;
  transition: opacity .5s ease;
}

/* Both capped at 1280px — the video's native width. The still is the video's
   first frame, so matching widths is what makes the 2D image appear to start
   moving; a 1600px still would jump scale at the swap and break the effect. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-plate img,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-plate video { max-width: 1280px; }

/* fades on all four edges: the slit has no frame, it dissolves into the page */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-plate::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 2;
  pointer-events: none;
  background:
    linear-gradient(90deg, var(--bg) 0%, rgba(8, 9, 12, .55) 12%, transparent 30%, transparent 70%, rgba(8, 9, 12, .55) 88%, var(--bg) 100%),
    linear-gradient(180deg, var(--bg) 0%, rgba(8, 9, 12, .35) 18%, transparent 42%, transparent 58%, rgba(8, 9, 12, .35) 82%, var(--bg) 100%);
}

/* a hairline down the slit's centre, so it reads as an aperture */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-plate::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 0;
  bottom: 0;
  width: 1px;
  z-index: 3;
  background: linear-gradient(180deg, transparent, rgba(155, 227, 221, .18), transparent);
  pointer-events: none;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-head {
  margin: 20px 0 0;
  font-family: var(--font-display);
  font-size: clamp(38px, 5.6vw, 62px);
  font-weight: 400;
  line-height: 1.06;
  letter-spacing: -.015em;
  color: var(--text-hi);
  text-wrap: pretty;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-sub {
  margin: 16px 0 0;
  max-width: 560px;
  font-size: 17px;
  line-height: 1.6;
  color: var(--muted);
  text-wrap: pretty;
}

/* ---- the field, promoted to the subject of the page ---- */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-field { width: 100%; max-width: 720px; margin-top: 30px; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-field .input-wrap {
  max-width: none;
  min-width: 0;
  width: 100%;
  gap: 10px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-field .input-wrap input {
  /* border-box, or the 1px border makes this 62px against the buttons' 60
     and the whole field sits a pixel proud at each end */
  box-sizing: border-box;
  height: 60px;
  padding: 0 20px;
  font-size: 18px;
  border-radius: 12px;
  background: rgba(21, 24, 31, .9);
  border-color: var(--line-6);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-field .input-wrap input:focus { border-color: var(--accent); }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-field .input-wrap .primary,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-field .input-wrap .ghost {
  box-sizing: border-box;
  flex: none;
  height: 60px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 12px;
  white-space: nowrap;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-field .input-wrap .primary { padding: 0 30px; font-size: 16px; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-field .input-wrap .ghost { padding: 0 20px; font-size: 14px; }

/* ---- starters ---- */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-starters {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 10px;
  margin-top: 22px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-label {
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--label);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .chip-mount { display: contents; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-starters .chips { margin: 0; justify-content: center; gap: 8px; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-starters .chip { background: rgba(21, 24, 31, .8); }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-rule {
  width: 100%;
  max-width: 720px;
  height: 1px;
  background: rgba(255, 255, 255, .07);
  margin-top: 46px;
}

/* ---- constellations ---- */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-block {
  width: 100%;
  max-width: 720px;
  margin-top: 34px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 13px;
  text-align: left;
}

/* the whole advanced tier is one disclosure, so the first screen is
   headline / field / starters and nothing else */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-adv { width: 100%; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-adv-body {
  display: flex;
  flex-direction: column;
  gap: 15px;
  margin-top: 16px;
  padding-top: 16px;
  border-top: 1px solid rgba(255, 255, 255, .07);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-block .chips { margin: 0; gap: 8px; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-note {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.6;
  color: var(--dim);
  text-wrap: pretty;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-consts {
  width: 100%;
  display: flex;
  flex-direction: column;
  gap: 11px;
  margin-top: 4px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-block .chip {
  background: rgba(18, 20, 26, .82);
  border-color: var(--line);
  border-radius: 10px;
  padding: 11px 15px;
  font-size: 13px;
}

/* ---- constellations: real tiles, not pills.
   app.js adds .chip--sm carrying !important, so the overrides must match. ---- */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-block .chips {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 9px;
  width: 100%;
  margin: 0;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-block .chip,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-block .chip--sm {
  font-size: 13px !important;
  padding: 14px 15px !important;
  border-radius: 11px !important;
  text-align: left;
  line-height: 1.35;
  background: rgba(18, 20, 26, .82);
  border: 1px solid var(--line);
  color: var(--text);
  text-wrap: pretty;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-block .chip:hover,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-block .chip--sm:hover {
  background: rgba(24, 27, 35, .92);
  border-color: var(--accent);
  color: #fff;
  transform: none;
}

/* ---- the address selector, nested inside the "which addresses" block ---- */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-tune { width: 100%; max-width: none; margin: 0; text-align: left; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-help {
  width: 100%;
  max-width: 720px;
  margin-top: 14px;
  text-align: left;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-tune > summary,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-adv > summary,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-help > summary {
  list-style: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-tune > summary::-webkit-details-marker,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-adv > summary::-webkit-details-marker,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-help > summary::-webkit-details-marker { display: none; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-tune > summary::before,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-adv > summary::before,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-help > summary::before {
  content: '+';
  font-family: var(--font-mono);
  font-size: 13px;
  line-height: 1;
  color: var(--accent);
  opacity: .8;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-tune[open] > summary::before,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-adv[open] > summary::before,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-help[open] > summary::before { content: '−'; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-tune > summary:hover,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-adv > summary:hover,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-help > summary:hover { color: var(--muted); }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-tune #coordTools {
  margin-top: 14px;
  padding: 16px 18px;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: rgba(14, 16, 21, .8);
}

/* inside the threshold the selector is already disclosed — drop its own
   nested summary (the state is forced open in setStage), and drop the
   Constellations row, whose chips now live above in .th-block */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-tune #coordTools > details > summary { display: none; }

/* the inner <details> is force-opened on the threshold; belt-and-braces in
   CSS too, so a race with app.js can never leave controls clipped */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-tune #coordTools > details > .coord-tools-grid { display: grid !important; }

/* styles.css sets an explicit display on the grid, which beats the UA's
   details:not([open]) hiding — so a closed disclosure still paints 166px of
   controls outside its 31px box. Restore the collapse. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) #coordTools > details:not([open]) > .coord-tools-grid { display: none !important; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-tune #coordTools .left-col .row:first-child { display: none; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-help p {
  margin: 12px 0 0;
  font-size: 13.5px;
  line-height: 1.7;
  color: var(--label);
  text-wrap: pretty;
}

/* the formula, given room to be read as a formula */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-help .th-formula,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .help-panel .th-formula {
  margin: 15px 0 3px;
  padding: 11px 14px;
  border-radius: 9px;
  background: rgba(18, 20, 26, .8);
  border: 1px solid var(--line);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-help .th-formula code,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .help-panel .th-formula code {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: .04em;
  color: var(--accent);
  background: none;
  padding: 0;
}

@media (max-width: 700px) {
  :is([data-theme="kosmic"],[data-theme="prismatic"]) .threshold { padding: 32px 20px 56px; }
  :is([data-theme="kosmic"],[data-theme="prismatic"]) .th-field .input-wrap { flex-wrap: wrap; }
  :is([data-theme="kosmic"],[data-theme="prismatic"]) .th-field .input-wrap input { flex: 1 1 100%; }
}

/* ===== HEADER — let the controls wrap instead of colliding =====
   The base stylesheet pins the header to a fixed height, which overlaps Run /
   Random / Rich Context below ~1200px. Scoped to the new shell only. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .app-header {
  height: auto;
  min-height: 64px;
  flex-wrap: wrap;
  gap: 14px 20px;
  padding: 12px 32px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .app-header .input-wrap { min-width: 220px; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .app-header .header-right { flex-wrap: wrap; gap: 16px; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .app-header .toggle-group { min-width: 0; align-items: flex-start; }

/* Below ~1100px the two header groups can't both fit on one line, and the
   base stylesheet lets them overlap rather than wrap. Force two rows. */
@media (max-width: 1100px) {
  :is([data-theme="kosmic"],[data-theme="prismatic"]) .app-header { padding: 12px 24px; }
  :is([data-theme="kosmic"],[data-theme="prismatic"]) .app-header .header-left { flex: 1 1 100%; }
  :is([data-theme="kosmic"],[data-theme="prismatic"]) .app-header .header-right { flex: 1 1 100%; justify-content: flex-start; }
  :is([data-theme="kosmic"],[data-theme="prismatic"]) .app-header .input-wrap { max-width: none; }
}

/* ===== TUNE STRIP ===== */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .tune-strip {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 18px 32px 20px;
  border-bottom: 1px solid var(--line-soft);
  background: rgba(10, 12, 17, .72);
  backdrop-filter: blur(14px);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .tune-row {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .tune-label {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--ink-dim);
  white-space: nowrap;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .tune-row .chips { margin-bottom: 0; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .tune-strip .coord-tools { margin: 0; padding: 0; background: transparent; border: none; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .tune-hint { margin: 0; font-size: 12px; color: var(--grey-4); }

/* ===== STAGE + GROUND ===== */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .stage {
  position: relative;
  z-index: 1;
  padding: 40px 32px 80px;
  min-height: 70vh;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .ground {
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .ground img,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .ground video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: blur(2px) saturate(.75);
  transform: scale(1.06);
  transition: opacity .6s ease;
}

/* the veil is what keeps 4.5:1 text contrast over any generated image */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .ground-veil {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(90% 70% at 50% 42%, rgba(8, 9, 12, .70) 0%, rgba(8, 9, 12, .90) 55%, var(--bg) 100%),
    linear-gradient(180deg, rgba(8, 9, 12, .82) 0%, rgba(8, 9, 12, .93) 100%);
}

/* ===== CHORUS GRID ===== */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
  align-items: start;
}

/* #cards is a pass-through so its children are grid items of .chorus and
   app.js can still wipe and refill it freely */
:is([data-theme="kosmic"],[data-theme="prismatic"]) #cards { display: contents; }

/* ===== ARRANGEMENT BAR ===== */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .arrange {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: none;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .arrange-label {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--label);
  margin-right: 3px;
}

/* the Preview control governs card content, not layout — divide it from the
   arrangement cluster so the two dropdowns aren't read as a pair */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .arrange-sep {
  margin-left: 12px;
  padding-left: 15px;
  border-left: 1px solid var(--line-3);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .arr-btn {
  /* explicit height, shared with .arr-axis — see that rule */
  height: 28px;
  display: inline-flex;
  align-items: center;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .1em;
  text-transform: uppercase;
  padding: 0 11px;
  border-radius: 6px;
  border: 1px solid var(--line-3);
  background: var(--field);
  color: var(--label);
  cursor: pointer;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .arr-btn:hover { color: var(--text); border-color: var(--line-7); }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .arr-btn.is-on {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--bg);
}

/* THE SORT CONTROL — a segmented group, not a menu.

   A <select> could never sit flush in this run: the UA owns its line-height
   and reserves room for its own arrow, so matching the buttons needed
   appearance:none plus a hand-drawn caret — and it still read as a form
   control among buttons. Three short options was never a menu's job.

   The buttons carry .arr-btn as well, so they inherit the height, type and
   states of GRID/QUADRANTS/SPECTRUM and cannot drift from them. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .arr-axis {
  display: inline-flex;
  align-items: center;
  /* the same 28px as the arrangement buttons it sits beside: 24px content +
     2px padding + 1px border each side */
  box-sizing: border-box;
  height: 28px;
  gap: 3px;
  padding: 1px;
  border-radius: 8px;
  border: 1px solid var(--line-soft);
  background: var(--panel-3, transparent);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .arr-axis[hidden] { display: none; }

/* one notch quieter than the arrangement buttons: this chooses a sort
   WITHIN an arrangement, so it should not compete with the arrangement */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .arr-btn--axis {
  height: 24px;
  padding: 0 9px;
  font-size: 9.5px;
  border-color: transparent;
  background: transparent;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .arr-btn--axis:hover { border-color: var(--line-3); }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .arr-btn--axis.is-on {
  background: var(--line-soft);
  border-color: transparent;
  color: var(--text);
}

/* ===== ARRANGEMENT: QUADRANTS =====
   A TRUE 2x2. The previous build put interiors left and exteriors right with
   the core as a centre column, which collapsed AQAL's 2x2 to one axis — UL
   above LL was stacking order, not the individual/collective distinction.

   Rows: 1 = UL | UR, 2 = the core, 3 = LL | LR.
   Columns: 1 = interior, 2 = the GUTTER, 3 = exterior.

   The gutter is a real column rather than a hairline, so the vertical axis
   has width and two cards are never pressed against it from either side.
   The core spans all three columns as row 2, replacing the horizontal
   divider rather than displacing anything — nothing is reserved, and the
   meta-definition gets a full measure. ===== */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-quad {
  grid-template-columns: minmax(0, 1fr) clamp(28px, 4.5vw, 64px) minmax(0, 1fr);
  /* 1 quadrants · 2 core · 3 quadrants · 4 composing */
  grid-template-rows: auto auto auto auto;
  column-gap: 0;
  row-gap: 0;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-quad .arr-group {
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 9px;
  min-width: 0;
}

/* The axis lines are drawn on the GUTTER's inner edges, so the visible rule
   sits at the true centre and each quadrant's cards stop clear of it. Keyed
   off explicit classes, never nth-child: #cards also holds placeholders and
   filler tiles, so child indexes drift as those come and go. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-quad .ag-ul,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-quad .ag-ll { padding-right: clamp(14px, 1.6vw, 22px); border-right: 1px solid var(--line-2); }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-quad .ag-ur,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-quad .ag-lr { padding-left: clamp(14px, 1.6vw, 22px); }

/* the upper row's floor: the core plate below carries the rest of the
   separation, so this only needs to clear the cards */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-quad .ag-ul,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-quad .ag-ur { padding-bottom: 22px; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-quad .ag-ll,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-quad .ag-lr { padding-top: 22px; }

/* ---- the core AS the horizontal axis ---- */
/* The plate was grid: 132px + 1fr, but .meta-description inherits a max
   measure — so the text wrapped at ~550px and the rest of a 2500px row was
   empty black on the RIGHT. That reads as a broken layout rather than as
   margin.

   Flex + max-width + auto margins instead: the group is centred, so whatever
   space is left over becomes two equal gutters. Symmetry comes from the
   content being centred on the axis, which is also the thing the crossing is
   supposed to mean. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .core.is-axis {
  display: flex;
  align-items: stretch;
  justify-content: center;
  gap: 0;
  width: 100%;
  max-width: 1100px;
  margin: 0 auto;
  /* not sticky: it is a divider now, and a divider that slides out of its
     own row stops dividing anything */
  position: static;
  border-radius: 12px;
  border: 1px solid var(--line-3);
  cursor: pointer;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .core.is-axis .core-img-wrap {
  flex: 0 0 clamp(168px, 19vw, 232px);
  min-height: 0;
  height: auto;
  align-self: stretch;
  aspect-ratio: auto;
  border-radius: 11px 0 0 11px;
}

/* contain, not cover: the referent art is a centred graphic on a black
   ground with no croppable margin — cover ate the subject. The black meets
   the plate's own background, so contain shows no letterboxing. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .core.is-axis .core-img-wrap img,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .core.is-axis .core-img-wrap video {
  object-fit: contain;
  object-position: 50% 30%;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .core.is-axis .core-meta {
  flex: 1 1 auto;
  min-width: 0;
  padding: 20px 26px;
  gap: 9px;
  justify-content: center;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .core.is-axis .hero-title { font-size: clamp(27px, 3vw, 36px); line-height: 1.05; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .core.is-axis .meta-description {
  font-size: 15px;
  line-height: 1.6;
  max-width: 62ch;
}

/* In a DIAGRAM the centre should read as the object, not as an essay: the
   crossing of the axes wants a name and a face. So two lines by default,
   with the full definition one click away — the plate itself is the control.

   Collapsed keeps the plate short, which is what lets the four quadrants
   read as four quadrants rather than as two rows separated by a paragraph. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .core.is-axis:not(.is-open) .meta-description {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .core:not(.is-axis) .axis-more { display: none; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .axis-more {
  align-self: flex-start;
  margin-top: 2px;
  padding: 0;
  border: 0;
  background: none;
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--label);
  cursor: pointer;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .core.is-axis .axis-more:hover { color: var(--accent); }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .core.is-axis .meta-label,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .core.is-axis .core-actions,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .core.is-axis .meta-hint { display: none; }

/* ---- composing ---- */
/* Row 4, flanks only — never column 2. Full flank width keeps placeholders
   at the same measure as the cards that replace them, so nothing jumps when
   a reading lands. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-quad .ag-composing {
  --alt: var(--accent);
  margin: 22px 0 0;
  padding: 15px !important;
  border: 1px dashed var(--line-4);
  border-radius: 11px;
  align-self: start;
  min-width: 0;
}

/* one label for the pair, so it reads as one operation rather than two */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-quad .ag-composing-r .ag-head { display: none; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-quad .ag-composing .loading-card { width: auto; }

/* ---- COMPACT CARDS ----
   Full-size tiles are why a corner towered: six readings measured 1384px,
   so the diagram scrolled instead of being a diagram. In this arrangement a
   card is a ROW — altitude, short label, signature — and the quote is what
   goes, because the quadrant view is about WHERE a reading sits, and the
   voice is what the focus reader is for.

   A corner of six now fits in roughly the height two used to take, which is
   what lets a 6/2/4/2 distribution look composed rather than lopsided. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-quad .voice {
  min-height: 0;
  padding: 12px 14px;
  gap: 3px;
  border-radius: 8px;
  border-top-width: 1px;
  border-left: 2px solid var(--alt, var(--accent));
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-quad .voice-quote,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-quad .voice-more,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-quad .voice-quad { display: none; }

/* 12.5/7.5 was compaction for a lopsided distribution and it overshot —
   7.5px letterspaced mono is below what anyone reads comfortably. The fixed
   two-column bed means a busy corner no longer needs the type to shrink. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-quad .voice-title { font-size: 14px; line-height: 1.32; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-quad .voice-alt { font-size: 8.5px; letter-spacing: .14em; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-quad .voice-sig { font-size: 8.5px; }

/* EVERY corner is two columns, not just a busy one.

   Conditionally at 4+ readings, a zone with 2 cards used one full-width
   column while its neighbour with 4 used two half-width ones — so card
   widths differed left to right and the cross stopped looking like a cross.
   A fixed two-column bed makes every card the same width in every quadrant,
   which is the symmetry that was missing. A corner with one reading simply
   has an empty second column, which reads as room rather than as error.

   Two columns, which is also how 6 and 2 sit side by side
   without either looking wrong.

   NOT a container query: an element cannot be styled by its OWN container,
   so `.ag-zone { container-type }` plus `@container { .ag-zone { ... } }`
   silently applied the descendant rule (card width) and dropped the one on
   the zone itself (flex-direction) — two columns' worth of width stacked in
   one column. `:has()` on the zone works because it needs no container at
   all; the narrow stack is handled by body.gg-narrow below. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-quad .ag-zone {
  flex-direction: row;
  flex-wrap: wrap;
  align-content: flex-start;
  gap: 8px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-quad .ag-zone > .voice {
  width: calc(50% - 4px);
  min-width: 0;
}

/* the heading and the add control stay full width, so the pairs read as one
   list under one label rather than a grid with a card-shaped title in it */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-quad .ag-zone > .ag-head,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-quad .ag-zone > .voice-add,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-quad .ag-zone > .ag-add { width: 100%; flex: 0 0 100%; }

/* ---- narrow: the 2x2 cannot survive one column, so it stacks ---- */
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .chorus.arr-quad {
  grid-template-columns: minmax(0, 1fr);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .chorus.arr-quad .ag-ul,
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .chorus.arr-quad .ag-ll { padding-right: 0; border-right: 0; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .chorus.arr-quad .ag-ur,
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .chorus.arr-quad .ag-lr { padding-left: 0; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .chorus.arr-quad .ag-zone { flex-direction: column; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .chorus.arr-quad .ag-zone > .voice { width: auto; }

/* ===== ARRANGEMENT: SPECTRUM =====
   Altitude and state are sequences, so they get columns in order. Positions
   with no reading stay as slivers: the gap is information. ===== */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-spectrum {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 8px;
}

/* the core keeps its card proportions once lifted into the sticky wrapper */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .spec-head .core {
  grid-template-columns: minmax(0, 420px) minmax(0, 1fr);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .spec-head .core-img-wrap {
  aspect-ratio: 4 / 3;
  height: auto;
  max-height: 400px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .spec-head .core-img-wrap img,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .spec-head .core-img-wrap video { object-fit: contain; }

/* Sticky Spectrum runs a COMPACT core: pinned chrome has to stay well under
   half the viewport or the lanes have nowhere to be. The full-size core is
   for Grid, where nothing is pinned. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .spec-head .core {
  grid-template-columns: minmax(0, 260px) minmax(0, 1fr);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .spec-head .core-img-wrap {
  aspect-ratio: 1 / 1;
  height: auto;
  max-height: 190px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .spec-head .core-img-wrap img,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .spec-head .core-img-wrap video { object-fit: contain; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .spec-head .core-meta { padding: 16px 20px 18px; gap: 8px; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .spec-head .hero-title { font-size: 30px; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .spec-head .meta-hint { display: none; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .spec-head .meta-description {
  font-size: 16px;
  line-height: 1.5;
  margin-bottom: 0;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-spectrum .core {
  flex: 1 0 100%;
  margin-bottom: 10px;
  /* full width makes the 46% image cell enormous, and object-fit: cover then
     crops the top and bottom off the graphic. Cap the cell and show the whole
     image instead of filling the box. */
  grid-template-columns: minmax(0, 420px) minmax(0, 1fr);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-spectrum .core .core-img-wrap {
  aspect-ratio: 4 / 3;
  height: auto;
  max-height: 400px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-spectrum .core .core-img-wrap img,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-spectrum .core .core-img-wrap video {
  object-fit: contain;
}

/* the rail shell: the scroller plus its own controls. Native two-finger
   scrolling can't be the only way across — a horizontal trackpad gesture
   over a scroller navigates the browser back in Safari and Chrome. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-spectrum .ag-shell {
  flex: 1 0 100%;
  min-width: 0;
  max-width: 100%;
  position: relative;
  display: block;
  /* the gutters the arrows live in — on the SHELL, not the rail: padding on
     a scroll container scrolls away with its content, so an inset rail is
     the only way the arrows stay out of the cards' plane */
  padding-inline: 48px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-spectrum .ag-rail {
  min-width: 0;
  max-width: 100%;
  display: flex;
  flex-direction: row;
  overscroll-behavior-x: contain;
  /* No scroll-behavior: smooth — it swallows programmatic scrollLeft
     assignments in this engine, which killed both arrows and wheel pan. */
  flex-wrap: nowrap;
  align-items: stretch;
  gap: 8px;
  overflow-x: auto;
  overflow-y: hidden;
  padding-bottom: 10px;
  scrollbar-width: thin;
  scrollbar-color: var(--line-6) transparent;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-spectrum .ag-rail::-webkit-scrollbar { height: 10px; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-spectrum .ag-rail::-webkit-scrollbar-track { background: var(--panel-2); border-radius: 5px; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-spectrum .ag-rail::-webkit-scrollbar-thumb { background: var(--grey-1); border-radius: 5px; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .rail-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 3;
  width: 40px;
  height: 72px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--line-4);
  border-radius: 10px;
  background: rgba(12, 14, 19, .94);
  color: var(--text-2);
  font-family: var(--font-mono);
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
  transition: opacity .18s ease, border-color .18s ease;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .rail-nav:hover { border-color: var(--accent); color: #fff; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .rail-prev { left: 0; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .rail-next { right: 0; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .rail-nav.is-off { opacity: 0; pointer-events: none; }

/* lanes are columns; scoped to .ag-lane so it can never re-target the rail
   that contains them (equal specificity, and this rule sits later) */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-spectrum .ag-lane {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
}

/* an empty position is exactly where a reading is most wanted, so the
   sliver is itself the control */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-spectrum .ag-lane.is-empty {
  border: 1px dashed var(--line-4);
  border-radius: 9px;
  min-height: 180px;
  align-items: center;
  justify-content: flex-start;
  padding: 12px 0;
  cursor: pointer;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-spectrum .ag-lane.is-empty:hover {
  border-color: var(--accent);
  background: rgba(155, 227, 221, .05);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-spectrum .ag-lane.is-empty:hover .ag-code { color: var(--accent); }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-spectrum .ag-lane.is-empty .ag-head {
  writing-mode: vertical-rl;
  gap: 0;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-spectrum .ag-lane.is-empty .ag-code { color: var(--grey-4); }

/* wide lanes hold their readings in a small grid rather than one long strip */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-spectrum .ag-lane.is-wide {
  display: grid;
  grid-template-columns: repeat(var(--lane-cols, 1), minmax(0, 232px));
  grid-auto-rows: min-content;
  align-content: start;
  gap: 8px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-spectrum .ag-lane.is-wide .ag-head { grid-column: 1 / -1; }

/* lanes are adjacent, so a filled lane needs its own edge to read as a
   territory rather than running into its neighbour */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-spectrum .ag-lane:not(.is-empty) {
  padding: 0 12px 12px;
  border-left: 1px solid var(--line-2);
}

/* Lane heads carry their own altitude, so "by altitude" reads as a spectrum
   rather than nine grey columns. The tint comes from the palette at the top
   of this file via the shared carrier list. */

/* contextual add: legible at rest — hover changes colour, not opacity, so
   these are equally usable on touch */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-add.va-inline {
  min-height: 0;
  padding: 10px 12px;
  flex-direction: row;
  gap: 8px;
  transition: border-color .15s ease, color .15s ease;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-add.va-inline .va-plus { font-size: 13px; color: var(--label); }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-add.va-inline .va-text { font-size: 9px; letter-spacing: .14em; color: var(--label); }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-add.va-inline:hover { border-color: var(--accent); }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-add.va-inline:hover .va-plus,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-add.va-inline:hover .va-text { color: var(--accent); }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-spectrum .ag-lane.is-wide .voice-add.va-inline { grid-column: 1 / -1; }

/* vestigial: the image no longer regenerates as perspectives are added, so
   Lock has nothing to prevent, and Download duplicates a right-click */
:is([data-theme="kosmic"],[data-theme="prismatic"]) #imageLockBtn,
:is([data-theme="kosmic"],[data-theme="prismatic"]) #imageDownloadBtn { display: none; }

/* placeholders sit after the rail, at lane width */
/* placeholders are grouped into a trailing lane now, so they sit in the
   rail rather than in a band above it */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-spectrum .ag-composing .loading-card { width: auto; }

/* ===== GROUP HEADS (both arrangements) ===== */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .arr-group .ag-head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  min-width: 0;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .arr-group .ag-code {
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--text-2);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .arr-group .ag-pron,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .arr-group .ag-n {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: .14em;
  color: var(--dim);
}

/* zone heads span a wide cell, so the count sits at the far edge; spectrum
   lane heads are 232px wide and adjacent, where a right-aligned count lands
   8px from the NEXT lane's name and reads as its prefix. Keep it beside its
   own label there. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .arr-group .ag-n {
  margin-left: auto;
  padding-left: 6px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-spectrum .ag-lane .ag-n { margin-left: 0; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-spectrum .ag-lane:not(.is-empty) .ag-code { color: var(--alt, var(--text-2)); }

/* ===== CORE — the referent at the centre of its own enactments =====
   Grid placement (column span, row span) is set inline by
   giga-kosmic-view.js so it is always correct for the live column count. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .core {
  display: grid;
  grid-template-columns: minmax(0, 46%) minmax(0, 1fr);
  align-items: stretch;
  border: 1px solid var(--line-4);
  border-radius: 16px;
  background: radial-gradient(120% 160% at 22% 0%, rgba(25, 29, 40, .92) 0%, rgba(10, 12, 17, .94) 74%);
  overflow: hidden;
  box-shadow: 0 24px 60px -30px #000;
}

/* Below ~580px of core width the two-column split starves the
   meta-definition, so the image goes above the text instead. The class is
   set from the core's measured width in giga-kosmic-view.js, not from the
   grid's column count — the core only spans 2 of those columns. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .core.is-stacked { grid-template-columns: minmax(0, 1fr); }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .core.is-stacked .core-img-wrap { min-height: 200px; aspect-ratio: 16 / 9; height: auto; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .core.is-stacked .core-meta { padding: 20px 22px 22px; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .core.is-stacked .hero-title { font-size: 34px; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .core.is-stacked .meta-description { font-size: 18px; }

/* very narrow: shrink the display type and let the buttons wrap tidily */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .core.is-tight .core-img-wrap { min-height: 160px; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .core.is-tight .core-meta { padding: 16px 16px 18px; gap: 10px; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .core.is-tight .hero-title { font-size: 27px; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .core.is-tight .meta-description { font-size: 16.5px; line-height: 1.55; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .core.is-tight .core-actions .ghost { padding: 7px 10px; font-size: 11.5px; }

/* Before any reading exists the core spans the whole grid, so an unbounded
   image wrap gave the loading loop a full-viewport blow-up before it settled
   into a card. Cap it while the core is empty. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .core:not(.has-results) .core-img-wrap { max-height: 360px; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .core-img-wrap {
  position: relative;
  aspect-ratio: auto;
  width: 100%;
  height: 100%;
  min-height: 270px;
  border-radius: 0;
  background: var(--panel-4);
  overflow: hidden;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .core-img-wrap img,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .core-img-wrap video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  /* contain, not cover: the core cell is far wider than the square artwork,
     so cover crops the subject's top and bottom off in Grid and Quadrants.
     This is the LAST rule for this selector, so it is the one that decides —
     the spectrum and sticky-head `contain` overrides above are now
     redundant but harmless. */
  object-fit: contain;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .core-meta {
  padding: 26px 30px 28px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 12px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .core .hero-title {
  font-family: var(--font-display);
  font-size: 42px;
  line-height: 1;
  margin: 0;
  color: var(--text-hi);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .core .meta-description-container { margin: 0; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .core .meta-description { font-size: 20px; line-height: 1.5; margin-bottom: 10px; max-width: 62ch; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .core-actions { gap: 8px; flex-wrap: wrap; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .core-actions .ghost { padding: 8px 12px; font-size: 12px; }

/* ===== CHORUS LABEL ===== */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus-label {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 16px;
  row-gap: 10px;
  margin: 0 0 14px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus-label-text,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus-count {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--ink-dim);
  white-space: nowrap;
}

/* the rule fills what's left and yields entirely once the controls need their
   own row — without min-width:0 it holds a 619px arrange group outside the
   stage instead of letting it wrap */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus-rule { flex: 1 1 0; min-width: 0; height: 1px; background: var(--line-soft); }

/* the arrange group wraps as a unit, keeping its own controls on one line.
   flex must be SHRINKABLE, not `none` — a group locked at its 619px
   max-content width can never wrap its children, so the controls left the
   stage below ~700px however the parent was declared. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .arrange {
  flex: 0 1 auto;
  min-width: 0;
  flex-wrap: wrap;
  row-gap: 8px;
}

/* ===== VOICE TILE ===== */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus .voice {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 9px;
  margin: 0;
  min-height: 208px;
  padding: 16px 16px 18px;
  cursor: pointer;
  background: rgba(18, 20, 26, .82);
  border: 1px solid var(--line-soft);
  border-top: 3px solid var(--alt, var(--accent));
  border-radius: 4px 4px 12px 12px;
  box-shadow: 0 12px 34px -24px #000;
  backdrop-filter: blur(6px);
  transition: background .18s ease, border-color .18s ease, transform .18s ease;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus .voice:hover {
  background: rgba(24, 27, 35, .92);
  border-color: var(--line-4);
  border-top-color: var(--alt, var(--accent));
  transform: translateY(-2px);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-alt {
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--alt, var(--accent));
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-num {
  font-family: var(--font-mono);
  font-size: 9.5px;
  color: var(--ink-faint);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-coord {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: .05em;
  color: var(--grey-4);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-title {
  margin: 0;
  font-family: var(--font-family);
  font-size: 14.5px;
  font-weight: 600;
  line-height: 1.32;
  color: var(--text);
  text-wrap: pretty;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-quote {
  margin: 0;
  font-family: var(--font-display);
  font-size: 15.5px;
  line-height: 1.5;
  color: #a9abbb;
  text-wrap: pretty;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-quote::before { content: '“'; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-quote::after { content: '”'; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-more {
  margin-top: auto;
  padding-top: 8px;
  padding-right: 34px;
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--alt, var(--accent));
  opacity: .75;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus .voice:hover .voice-more { opacity: 1; }

/* the third-person description is a statement, not a quotation: no italics,
   no hanging quote marks, and a touch more ink since it carries the claim */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-quote.is-plain {
  font-style: normal;
  color: #b8bac8;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-quote.is-plain::before,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-quote.is-plain::after { content: none; }

/* ===== QUADRANT GLYPH =====
   The quadrant is the only coordinate with a native diagram. In the mono
   signature it read as one more word; in the corner it's legible at a glance,
   and the line it left fits without wrapping. ===== */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-quad {
  position: absolute;
  right: 14px;
  bottom: 12px;
  display: flex;
  align-items: center;
  gap: 6px;
  pointer-events: none;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .qg {
  display: grid;
  grid-template-columns: repeat(2, 9px);
  grid-template-rows: repeat(2, 9px);
  gap: 2px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .qg-cell {
  border: 1px solid var(--grey-2);
  border-radius: 1px;
  background: transparent;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .qg-cell.on {
  background: var(--alt, var(--accent));
  border-color: var(--alt, var(--accent));
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .qg-code {
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: .08em;
  color: var(--alt, var(--accent));
  opacity: .9;
}

/* ===== LOADING TILE =====
   app.js's placeholder card, reshaped to sit in the grid as a voice-sized
   tile so the layout doesn't jump when the real reading replaces it. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus .loading-card {
  display: flex;
  flex-direction: column;
  gap: 11px;
  margin: 0;
  min-height: 208px;
  padding: 16px 16px 18px;
  background: rgba(18, 20, 26, .82);
  border: 1px solid var(--line-soft);
  border-top: 3px solid var(--accent);
  border-radius: 4px 4px 12px 12px;
  box-shadow: 0 12px 34px -24px #000;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus .loading-card .card-head {
  order: 0;
  padding: 0;
  flex-direction: column;
  align-items: flex-start;
  gap: 9px;
  border: none;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus .loading-card .context-title {
  font-size: 17px;
  line-height: 1.2;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus .loading-card .address {
  order: 1;
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  padding: 0;
  border: none;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus .loading-card .address .skel-line {
  height: 18px !important;
  margin: 0;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus .loading-card .card-body { padding: 0; gap: 9px; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus .loading-card .card-body .skel-line { margin: 0 0 6px; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus .loading-card .loading-spinner { gap: 9px; }

/* ===== COMPOSING: STAND DOWN THE EXPENSIVE EFFECTS =====
   With 8 placeholders on screen Chrome was dropping frames badly while
   Safari and Firefox stayed smooth. Three main-thread costs stack in that
   state, and the third is Chrome-specific:

   1. .skel-line animates background-position on a 5-stop gradient — a full
      repaint of every line, every frame, ~30 of them.
   2. .voice / .loading-card each carry backdrop-filter: blur(6px).
   3. Those blurs sit over the ground, which during composing holds a PLAYING
      VIDEO — so every card's blur must re-read and re-composite its backdrop
      on every video frame. Chrome does this on demand; Safari and Firefox
      cache far more aggressively.

   So while composing: shimmer becomes a compositor-only opacity animation,
   and the blurs are swapped for flat fills. ===== */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus .loading-card .skel-line,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus .loading-card .address .skel-line {
  background: var(--skel) !important;
  background-size: auto !important;
  animation: gg-skel-fade 1.6s ease-in-out infinite !important;
  will-change: opacity;
}

@keyframes gg-skel-fade {
  0%, 100% { opacity: .5; }
  50% { opacity: .95; }
}

body.gg-composing :is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus .voice,
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-composing .chorus .voice,
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-composing .chorus .loading-card {
  backdrop-filter: none;
  background: var(--panel-2);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-composing .app-header {
  backdrop-filter: none;
  background: var(--panel-3);
}

/* A .ground video behind a stack of blurred cards is the worst case; keep it
   simple while the machine is working. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-composing .ground img,
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-composing .ground video { filter: none; }

@media (prefers-reduced-motion: reduce) {
  :is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus .loading-card .skel-line { animation: none !important; }
}
/* A sticky element can only stay pinned within its parent's content box, and
   styles.css sets html, body { height: 100% } — so the header unsticks after
   about one viewport of scroll and everything measured from it goes wrong.
   min-height keeps the full-height ground without capping the sticky range.

   The base colour moves to <html>: .ground is a fixed layer, and a painted
   body background paints in front of anything at z-index -1 — which hid the
   ground wherever the body box reached, leaving it visible only below. */
html:is([data-theme="kosmic"],[data-theme="prismatic"]),
html:is([data-theme="kosmic"],[data-theme="prismatic"]) body {
  height: auto;
  min-height: 100%;
}

html:is([data-theme="kosmic"],[data-theme="prismatic"]) { background: var(--bg); }
html:is([data-theme="kosmic"],[data-theme="prismatic"]) body { background: transparent; }

/* The header pins in every composed arrangement, not just Spectrum — the
   field and theme controls should stay reachable at any scroll depth. It
   stays static on the threshold, where it's part of the composition.
   Declared after the z-index block above, whose `relative` would win. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) body:not(.is-empty) .app-header,
body:not(.is-empty) :is([data-theme="kosmic"],[data-theme="prismatic"]) .app-header {
  position: sticky;
  top: 0;
  z-index: 7;
  background: var(--bg);
  border-bottom: 1px solid var(--panel-6);
}

/* the ground is a fixed layer, so the sticky header needs an opaque backing */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .ground { z-index: 0; }

/* every content layer sits above the ground */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .app-header,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .tune-strip,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .stage,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .spec-head,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .help-panel {
  position: relative;
  z-index: 1;
}

/* --ink-dim / --ink-faint are ~4.2:1 and ~2.4:1 on this ground: fine at body
   size, under the bar for the 9-10px letterspaced mono this theme uses. Swept
   in one pass rather than patched rule by rule. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-tune > summary,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-adv > summary,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-help > summary,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .tune-label,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus-label-text,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus-count,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .va-plus,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .va-text,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .arrange-label,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .arr-group .ag-pron,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .arr-group .ag-n { color: var(--label); }

/* dim with colour, never alpha: styles.css sets opacity .8 on .toggle-hint,
   which multiplied against an already-dim --ink-dim. Both header labels are
   the same 10px letterspaced mono as the sweep above. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.is-empty .app-header .header-right { opacity: .92; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .theme-label,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .toggle-hint { color: var(--label); }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .toggle-hint { opacity: 1; }

/* ===== SPECTRUM: the reference stays put =====
   The header, the arrangement bar and the core hold their place while the
   lanes scroll past, so you never lose the referent you are comparing
   against. Offsets come from measured heights (set in JS). ===== */
@media (min-width: 900px) and (min-height: 800px) {
  :is([data-theme="kosmic"],[data-theme="prismatic"]) body.arr-is-spectrum .spec-head,
  body.arr-is-spectrum :is([data-theme="kosmic"],[data-theme="prismatic"]) .spec-head {
    position: sticky;
    top: var(--sticky-hdr, 64px);
    z-index: 5;
    background: var(--bg);
    padding-bottom: 12px;
  }

  /* Set by JS when header + core + bar would take more than 45% of the
     viewport. Four pinned layers cannot share a short window; the core is
     the tall one, so it is the one that gives. */
  :is([data-theme="kosmic"],[data-theme="prismatic"]) body.arr-is-spectrum.gg-core-unpinned .spec-head,
  body.arr-is-spectrum.gg-core-unpinned :is([data-theme="kosmic"],[data-theme="prismatic"]) .spec-head {
    position: static;
  }

  /* pinned beneath the core, immediately above the lanes it governs */
  :is([data-theme="kosmic"],[data-theme="prismatic"]) body.arr-is-spectrum .chorus-label,
  body.arr-is-spectrum :is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus-label {
    position: sticky;
    top: calc(var(--sticky-hdr, 64px) + var(--sticky-core, 300px));
    z-index: 6;
    background: var(--bg);
    padding-top: 10px;
    padding-bottom: 10px;
    margin-bottom: 0;
  }

}

/* ===== THE META-DEFINITION REWRITING ITSELF =====
   Words are set one at a time behind a caret, and retracted before a new
   definition is written, so the machine visibly reconsiders rather than
   cross-fading. ===== */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .meta-description .mw {
  display: inline-block;
  opacity: 0;
  filter: blur(3px);
  transform: translateY(3px);
  transition: opacity .3s ease, filter .3s ease, transform .3s ease;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .meta-description .mw.is-in {
  opacity: 1;
  filter: blur(0);
  transform: none;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .meta-description .mw.is-out {
  opacity: 0;
  filter: blur(2px);
  transform: translateY(-2px);
  transition-duration: .16s;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .meta-description .mw-caret {
  display: inline-block;
  width: 2px;
  height: .95em;
  margin-left: 1px;
  vertical-align: -.12em;
  background: var(--accent);
  animation: mw-blink 1s steps(1) infinite;
}

@keyframes mw-blink {
  0%, 49% { opacity: 1; }
  50%, 100% { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  :is([data-theme="kosmic"],[data-theme="prismatic"]) .meta-description .mw {
    opacity: 1;
    filter: none;
    transform: none;
    transition: none;
  }
  :is([data-theme="kosmic"],[data-theme="prismatic"]) .meta-description .mw-caret { animation: none; }
}

/* ===== PENDING TILE — the planning phase =====
   The planner takes seconds; without these the stage is empty but for the
   core, which reads as nothing happening. Non-interactive by design. ===== */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-pending {
  min-height: 200px;
  border: 1px solid var(--panel-6);
  border-radius: 4px 4px 12px 12px;
  border-top: 3px solid var(--line);
  background: rgba(16, 18, 23, .5);
  padding: 18px 16px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  animation: vp-breathe 2.4s ease-in-out infinite;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-pending .vp-line {
  display: block;
  height: 9px;
  border-radius: 3px;
  background: linear-gradient(90deg, var(--line-soft), var(--line), var(--line-soft));
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-pending .vp-a { width: 38%; height: 8px; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-pending .vp-b { width: 82%; height: 13px; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-pending .vp-c { width: 64%; height: 13px; }

@keyframes vp-breathe {
  0%, 100% { opacity: .45; }
  50% { opacity: .85; }
}

@media (prefers-reduced-motion: reduce) {
  :is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-pending { animation: none; opacity: .6; }
}

/* ===== ADD-A-PERSPECTIVE TILE =====
   Fills the cells the voices don't, so the grid is never ragged — and turns
   the leftover space into the invitation to generate another reading. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-add {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-height: 208px;
  padding: 16px;
  cursor: pointer;
  border: 1px dashed var(--line-3);
  border-radius: 12px;
  background: rgba(14, 16, 21, .35);
  font-family: inherit;
  transition: border-color .18s ease, background .18s ease;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-add:hover {
  border-color: var(--accent);
  background: rgba(155, 227, 221, .05);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .va-plus {
  font-family: var(--font-mono);
  font-size: 18px;
  line-height: 1;
  color: var(--ink-dim);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .va-text {
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-add:hover .va-plus,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-add:hover .va-text { color: var(--accent); }

/* ===== ADD MORE / HELP ===== */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .add-more {
  display: flex;
  gap: 10px;
  align-items: center;
  flex-wrap: wrap;
  margin-top: 20px;
  padding: 14px 18px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .add-more select,
:is([data-theme="kosmic"],[data-theme="prismatic"]) #addMoreCount {
  background: var(--field);
  color: var(--text);
  border: 1px solid var(--line-3);
  border-radius: 7px;
  padding: 6px 9px;
  font-family: var(--font-mono);
  font-size: 12px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .help-panel { margin-top: 24px; max-width: 900px; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .help-panel p { font-size: 13.5px; color: var(--muted); }

/* ===== FOCUS READER ===== */
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.focus-open { overflow: hidden; }

.focus {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 32px;
  background: rgba(4, 5, 8, .78);
  backdrop-filter: blur(10px);
}

.focus[hidden] { display: none; }

.focus-sheet {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 272px;
  width: min(1180px, 100%);
  max-height: calc(100vh - 64px);
  overflow: auto;
  border: 1px solid var(--line-4);
  border-radius: 16px;
  background:
    linear-gradient(150deg, color-mix(in oklab, var(--alt, var(--accent)) 12%, transparent) 0%, var(--panel-4) 46%, var(--bg) 100%),
    var(--panel-4);
  box-shadow: 0 40px 90px -40px #000;
}

.focus-main {
  padding: 30px 32px 34px;
  display: flex;
  flex-direction: column;
  gap: 18px;
  min-width: 0;
}

.focus-head { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }

.focus-back {
  font-family: var(--font-mono) !important;
  font-size: 10px !important;
  letter-spacing: .12em;
  text-transform: uppercase;
}

.focus-stamp {
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--alt, var(--accent));
}

.focus-title {
  margin: 0;
  font-family: var(--font-display);
  font-size: 40px;
  font-weight: 400;
  line-height: 1.08;
  letter-spacing: -.01em;
  color: var(--text-5);
  text-wrap: pretty;
}

.focus-rule { width: 70px; height: 3px; background: var(--alt, var(--accent)); }

.focus-block { display: flex; flex-direction: column; gap: 8px; }

.focus-block .section-title {
  font-family: var(--font-mono);
  font-size: 9.5px;
  font-weight: 500;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--alt, var(--accent));
  margin: 0;
}

.focus-summary {
  font-size: 16px;
  line-height: 1.72;
  color: var(--text-3);
  max-width: 68ch;
  text-wrap: pretty;
}

.focus-exp {
  padding: 18px 20px;
  border-radius: 12px;
  background: rgba(255, 255, 255, .035);
  border-left: 2px solid var(--alt, var(--accent));
}

.focus-experience {
  font-family: var(--font-display);
  font-size: 20.5px;
  line-height: 1.56;
  color: var(--text-4);
  max-width: 62ch;
  text-wrap: pretty;
}

.focus-actions { display: flex; gap: 9px; margin-top: auto; padding-top: 8px; }

.focus-index {
  border-left: 1px solid rgba(255, 255, 255, .08);
  padding: 26px 18px 30px;
  background: rgba(8, 9, 12, .45);
}

.focus-index-label {
  font-family: var(--font-mono);
  font-size: 9.5px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--ink-dim, var(--faint));
  padding: 0 8px 12px;
}

.focus-index-row {
  display: flex;
  align-items: stretch;
  gap: 10px;
  width: 100%;
  text-align: left;
  padding: 9px 10px;
  border: none;
  border-radius: 8px;
  background: transparent;
  cursor: pointer;
  font-family: inherit;
}

.focus-index-row:hover { background: rgba(255, 255, 255, .045); }
.focus-index-row.is-on { background: rgba(255, 255, 255, .075); }

.fi-rule {
  width: 3px;
  min-height: 26px;
  border-radius: 2px;
  background: var(--alt, var(--accent));
  opacity: .4;
  flex: none;
}

.focus-index-row.is-on .fi-rule { opacity: 1; }

.fi-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }

.fi-alt {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--alt, var(--accent));
}

.fi-title { font-size: 12.5px; line-height: 1.4; color: var(--dim); }
.focus-index-row.is-on .fi-title { color: var(--text-5); }

/* ===== RESPONSIVE ===== */
@media (max-width: 1180px) {
  :is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .focus-sheet { grid-template-columns: minmax(0, 1fr); }
  .focus-index { border-left: none; border-top: 1px solid rgba(255, 255, 255, .08); }
}

@media (max-width: 860px) {
  :is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  :is([data-theme="kosmic"],[data-theme="prismatic"]) .stage { padding: 24px 18px 60px; }
  :is([data-theme="kosmic"],[data-theme="prismatic"]) .tune-strip { padding: 14px 18px 16px; }
}

@media (max-width: 560px) {
  :is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus { grid-template-columns: minmax(0, 1fr); }
  :is([data-theme="kosmic"],[data-theme="prismatic"]) .core .hero-title { font-size: 32px; }
  .focus { padding: 12px; }
  .focus-title { font-size: 28px; }
}


/* =========================================================================
   TUNER, AS AN ARRANGEMENT
   The console is drawn by giga-radio-view.js into #console and styled by
   giga-radio.css (scoped to that section's own data-theme). All this block
   does is get the chorus out of the way and mark the button.
   ========================================================================= */
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.arr-is-tuner #chorus,
body.arr-is-tuner :is([data-theme="kosmic"],[data-theme="prismatic"]) #chorus { display: none !important; }

/* the tuner reads one address at a time, so the chorus's own add-more panel
   and its count would both be describing something not on screen */
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.arr-is-tuner .add-more { display: none !important; }

/* Tuner is a different KIND of choice from the three arrangements — same
   control group, deliberately not the same visual run. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .arr-btn--tuner {
  border-color: var(--line-7);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .arr-btn--tuner.is-on {
  background: transparent;
  border-color: var(--accent);
  color: var(--accent);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) #console { margin-top: 4px; }

/* =========================================================================
   FOCUS PORTHOLE
   The reading opened from Grid / Quadrants / Spectrum gets the same
   altitude-lit eye the tuner uses, so a worldspace looks like itself
   whichever view you reached it from.
   ========================================================================= */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .focus-head {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .focus-porthole {
  position: relative;
  width: 104px;
  height: 104px;
  flex: none;
  margin-left: auto;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .focus-porthole-eye {
  position: absolute;
  inset: 9px;
  border-radius: 50%;
  overflow: hidden;
  background: var(--ink);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .focus-porthole-eye img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
  filter: grayscale(1) brightness(1.2) contrast(1.1);
}

/* multiply keeps the near-black ground black and lets the strokes take the
   altitude hue; a luminance-preserving blend would wash the ground out. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .focus-porthole-tint {
  position: absolute;
  inset: 0;
  background: var(--alt, var(--accent));
  mix-blend-mode: multiply;
  pointer-events: none;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .focus-porthole-ring {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 1px solid var(--alt, var(--accent));
  opacity: .5;
  pointer-events: none;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .focus-porthole-ring-2 {
  position: absolute;
  inset: 4px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, .09);
  pointer-events: none;
}

@media (max-width: 700px) {
  :is([data-theme="kosmic"],[data-theme="prismatic"]) .focus-porthole { width: 76px; height: 76px; }
}


/* =========================================================================
   STATUS BAR — out of flow
   In normal flow this bar pushed .stage down the moment planning started,
   so clicking Run visibly bumped the page and the aperture jumped. Anchored
   to the bottom of the viewport it reports the same thing and costs no
   layout at all.
   ========================================================================= */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .status,
:is([data-theme="kosmic"],[data-theme="prismatic"]) body .status {
  position: fixed;
  /* top/right must be reset explicitly: styles.css sets top: 0 on .status,
     and with bottom also set the box stretched the full viewport height —
     which border-radius: 999px then drew as a giant lozenge. */
  top: auto;
  right: auto;
  left: 50%;
  bottom: 22px;
  transform: translateX(-50%);
  z-index: 60;
  width: auto;
  height: auto;
  max-width: min(92vw, 460px);
  white-space: nowrap;
  padding: 11px 20px;
  border: 1px solid var(--line);
  border-radius: 999px;
  box-shadow: 0 12px 34px rgba(0, 0, 0, .38);
  animation: gg-status-in .28s ease-out;
}

@keyframes gg-status-in {
  from { opacity: 0; transform: translateX(-50%) translateY(8px); }
  to   { opacity: 1; transform: translateX(-50%) translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  :is([data-theme="kosmic"],[data-theme="prismatic"]) .status { animation: none; }
}


/* =========================================================================
   HEADER — QUIETER
   Live mode is gone (it told the user nothing actionable), the rich-context
   description now lives in a tooltip rather than a wrapping column, and the
   theme select recedes to a control you find rather than one you read.
   ========================================================================= */
:is([data-theme="kosmic"],[data-theme="prismatic"]) #modeIndicator { display: none !important; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .toggle-hint { display: none; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .toggle-group {
  display: flex;
  align-items: center;
  flex: none;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .toggle-label {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  white-space: nowrap;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .toggle-text {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--label);
  white-space: nowrap;
}

/* the select carries its own label via aria-label, so the visible "THEME"
   text is redundant chrome */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .theme-label { display: none; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) #themeSelect {
  height: 30px;
  padding: 0 6px;
  border-radius: 7px;
  border: 1px solid var(--line-soft);
  background: transparent;
  color: var(--label);
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: .04em;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) #themeSelect:hover { border-color: var(--line-3); color: var(--text-2); }

/* =========================================================================
   NARROW — TWO VIEWS, STACKED
   Grid and Quadrants are hidden below 760px by giga-kosmic-view.js: both
   need horizontal room to mean anything, and at one column they degrade into
   what Spectrum already does better. What is left is Spectrum (stacked,
   sticky meta-definition, full-width cards) and Tuner.
   ========================================================================= */


:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .app-header {
  padding: 10px 14px;
  gap: 10px 12px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .header-left { flex: 1 1 100%; gap: 10px; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .brand { font-size: 18px; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .header-right {
  flex: 1 1 100%;
  justify-content: space-between;
  gap: 10px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .input-wrap { flex: 1 1 100%; min-width: 0; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .input-wrap input { flex: 1; min-width: 0; }

/* Random is a second, quieter path to the same place as the starter chips
   right below the field — one of them can go on a phone */
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .header-left #randomBtn { display: none; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .stage { padding: 0 12px 44px; }

/* ---- the arrangement bar ---- */
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .chorus-label {
  flex-wrap: wrap;
  gap: 8px 10px;
  margin-bottom: 12px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .chorus-label-text { font-size: 10px; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .chorus-rule { display: none; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .arrange {
  flex: 1 1 100%;
  flex-wrap: wrap;
  gap: 6px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .arr-btn {
  flex: 1 1 auto;
  min-height: 38px;
  font-size: 10.5px;
  padding: 0 12px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .arrange-sep { display: none; }

/* ---- spectrum, stacked ---- */
/* the rail stops being a scroller and becomes ordinary flow */
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .chorus.arr-spectrum .ag-shell { position: static; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .chorus.arr-spectrum .ag-rail {
  flex-wrap: wrap;
  overflow: visible;
  padding-inline: 0;
  padding-bottom: 0;
  gap: 18px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .chorus.arr-spectrum .ag-lane { width: 100%; }

/* an unreached altitude is absent rather than a dead row: nine slivers
   would be most of the screen, and a sliver is not a tap target */
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .chorus.arr-spectrum .ag-lane.is-empty { display: none; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .chorus.arr-spectrum .voice { width: auto; }

/* the altitude head becomes a section rule you can scan past */
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .chorus.arr-spectrum .ag-lane .ag-head {
  position: sticky;
  top: 0;
  z-index: 3;
  padding: 8px 0;
  background: var(--bg);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .chorus.arr-spectrum .ag-lane .ag-code { font-size: 11.5px; }

/* ---- the sticky meta-definition ---- */
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .spec-head { padding: 0 0 10px; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .spec-head .core,
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .chorus.arr-spectrum .core {
  grid-template-columns: 92px minmax(0, 1fr);
  margin: 0;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .spec-head .core-img-wrap {
  min-height: 0;
  height: 100%;
  aspect-ratio: auto;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .spec-head .core-meta { padding: 12px 14px; gap: 7px; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .spec-head .hero-title { font-size: 21px; }

/* three lines of meta-definition is the most a phone can spare above the
   readings; the full text is still in the DOM for the focus reader */
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .spec-head .meta-description {
  font-size: 13.5px;
  line-height: 1.5;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .spec-head .core-actions,
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .spec-head .meta-label { display: none; }

/* ---- cards ---- */
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .chorus .voice { min-height: 0; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .voice-title { font-size: 17px; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .voice-quote { font-size: 15px; }

/* 44px minimum on anything tappable */
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .voice-more { min-height: 44px; display: flex; align-items: center; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .voice-add.va-inline { min-height: 48px; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .voice-add { min-height: 88px; }

/* ---- the tuner console ---- */
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow #console .con-body { grid-template-columns: minmax(0, 1fr); }
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow #console .deck { border-right: 0; border-bottom: 1px solid var(--line-soft); }
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow #console .bank { border-left: 0; border-top: 1px solid var(--line-soft); }


/* =========================================================================
   FOCUS PORTHOLE ON A PHONE
   Floated right of a two-line title it sat in dead space with nothing beside
   it. Centred above the title it reads as a seal on the reading, and earns
   being a little larger.
   ========================================================================= */

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .focus-head {
  flex-direction: column;
  align-items: stretch;
  gap: 14px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .focus-porthole {
  width: 116px;
  height: 116px;
  margin: 2px auto 0;
  order: 3;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .focus-back { align-self: flex-start; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .focus-stamp { order: 2; }


/* the composing lane reads as provisional: dashed like an open slot, and its
   head names what is happening rather than an altitude */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-spectrum .ag-composing {
  border: 1px dashed var(--line-4);
  border-radius: 11px;
  padding: 10px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-spectrum .ag-composing { --alt: var(--accent); }


/* =========================================================================
   NO HOVER ON THE META-DEFINITION
   styles.css gives .meta-description-container `transition: all`, so ANY
   property a stray hover rule touches animates into view — here a box-shadow
   and an identity transform, which read as a faint glowing panel around the
   text. The meta-definition is not interactive, so it should not respond to
   the pointer at all.

   Both properties are pinned rather than the transition being widened, and
   the transition itself is narrowed to opacity/colour so a future stray rule
   cannot reintroduce this.
   ========================================================================= */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .meta-description-container,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .meta-description-container:hover,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .meta-description,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .meta-description:hover {
  box-shadow: none !important;
  outline: none !important;
  transform: none !important;
  background: transparent !important;
  border-color: transparent !important;
  transition: opacity .25s ease, color .25s ease !important;
}


/* =========================================================================
   NARROW — THE ACCORDION
   One page, no view modes. The list is every reading at once (the whole);
   tapping one expands it in place (the tuning) without losing the others.
   Driven by body.gg-narrow, which giga-kosmic-view.js sets from the STAGE's
   measured width — so an embedded shortcode in a narrow column gets this
   too, which a viewport media query could not describe.
   ========================================================================= */

/* the tune disclosure — hidden entirely on a wide screen, where the Tuner
   is a first-class view instead */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .nx-tune { display: none; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .nx-tune {
  display: block;
  margin: 0 0 14px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .nx-tune > summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 9px;
  min-height: 44px;
  padding: 0 14px;
  border: 1px solid var(--line-soft);
  border-radius: 10px;
  background: var(--panel-2);
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--label);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .nx-tune > summary::-webkit-details-marker { display: none; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .nx-tune > summary::before {
  content: '+';
  font-size: 14px;
  line-height: 1;
  color: var(--accent);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .nx-tune[open] > summary::before { content: '−'; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .nx-tune[open] > summary { border-color: var(--accent); color: var(--text); }

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .nx-tune #console {
  margin: 10px 0 0;
  border-radius: 12px;
}

/* ---- the list ---- */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-narrow {
  display: block;
  grid-template-columns: none;
  gap: 0;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-narrow .nx-list {
  display: flex;
  flex-direction: column;
  gap: 7px;
  padding: 0;
}

/* the core sits above the list as a compact plate, not a card in it */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-narrow .core {
  grid-template-columns: 88px minmax(0, 1fr);
  margin: 0 0 14px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-narrow .core-img-wrap {
  min-height: 0;
  height: 100%;
  aspect-ratio: auto;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-narrow .core-meta { padding: 12px 14px; gap: 6px; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-narrow .hero-title { font-size: 20px; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-narrow .meta-label { display: none; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-narrow .core-actions { display: none; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-narrow .meta-description {
  font-size: 13px;
  line-height: 1.5;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* ---- a row ---- */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .nx-row {
  --alt: var(--accent);
  display: flex;
  align-items: flex-start;
  gap: 11px;
  width: 100%;
  min-height: 56px;
  padding: 11px 13px;
  border: 1px solid var(--line-soft);
  border-left: 3px solid var(--alt);
  border-radius: 9px;
  background: var(--panel-2);
  text-align: left;
  font-family: inherit;
  cursor: pointer;
  transition: border-color .15s ease, background .15s ease;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .nx-row:hover { border-color: var(--line-3); }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .nx-row.is-open {
  border-color: var(--alt);
  background: color-mix(in srgb, var(--alt) 10%, var(--panel-2));
  border-bottom-left-radius: 0;
  border-bottom-right-radius: 0;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .nx-n {
  font-family: var(--font-mono);
  font-size: 9px;
  /* --label, not --ghost: the index is content, and --ghost is a body-text
     tone that measures 2.98:1 at 9px. Third time in this project. */
  color: var(--label);
  padding-top: 3px;
  flex: none;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .nx-body {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .nx-alt {
  font-family: var(--font-mono);
  font-size: 8.5px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--alt);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .nx-short {
  font-size: 14.5px;
  font-weight: 600;
  line-height: 1.3;
  color: var(--text);
  text-wrap: pretty;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .nx-sig {
  font-family: var(--font-mono);
  font-size: 9px;
  color: var(--label);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* ---- the expanded reading ---- */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .nx-panel {
  --alt: var(--accent);
  display: flex;
  flex-direction: column;
  gap: 16px;
  margin: -7px 0 4px;
  padding: 20px 16px 18px;
  border: 1px solid var(--alt);
  border-top: 0;
  border-radius: 0 0 11px 11px;
  background: linear-gradient(180deg, color-mix(in srgb, var(--alt) 7%, var(--panel)) 0%, var(--panel) 40%);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .nx-title {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(26px, 7.4vw, 34px);
  font-weight: 400;
  line-height: 1.1;
  letter-spacing: -.01em;
  color: var(--text-hi, #f4f2f9);
  text-wrap: pretty;
}

/* the porthole, centred under the title as a seal on the reading */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .nx-porthole {
  position: relative;
  width: 116px;
  height: 116px;
  margin: 2px auto;
  flex: none;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .nx-porthole-eye {
  position: absolute;
  inset: 10px;
  border-radius: 50%;
  overflow: hidden;
  background: #05070a;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .nx-porthole-eye img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
  /* desaturate FIRST: multiply over a saturated source leaves the source's
     own hue dominant, which is what made an orange card show a green icon */
  filter: grayscale(1) brightness(1.2) contrast(1.1);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .nx-porthole-tint {
  position: absolute;
  inset: 0;
  background: var(--alt);
  mix-blend-mode: multiply;
  pointer-events: none;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .nx-porthole-ring {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 1px solid var(--alt);
  opacity: .5;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .nx-porthole-ring-2 {
  position: absolute;
  inset: 5px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, .09);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .nx-block { display: flex; flex-direction: column; gap: 8px; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .nx-label {
  font-family: var(--font-mono);
  font-size: 8.5px;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--label);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .nx-summary {
  margin: 0;
  font-size: 15px;
  line-height: 1.62;
  color: var(--text-2, #a5a7b8);
  text-wrap: pretty;
}

/* the first-person voice keeps the display face — it is the thing that makes
   the chorus read as voices rather than labels */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .nx-exp {
  margin: 0;
  font-family: var(--font-display);
  font-size: 19px;
  line-height: 1.5;
  color: #d8d5e4;
  text-wrap: pretty;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .nx-acts {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
  padding-top: 2px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .nx-acts .ghost { min-height: 40px; }

/* placeholders in the list read as pending rows, not cards */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-narrow .loading-card {
  width: auto;
  min-height: 56px;
  border-radius: 9px;
}




/* =========================================================================
   TUNE BUTTON + NARROW REPAIRS (build 20260909-1)
   ========================================================================= */

/* the single way into the Tuner, on every screen size */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .tune-open {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  min-height: 42px;
  padding: 0 16px;
  border: 1px solid var(--line-3);
  border-radius: 9px;
  background: transparent;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--label);
  cursor: pointer;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .tune-open::before { content: '◎'; font-size: 13px; color: var(--accent); }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .tune-open:hover { border-color: var(--accent); color: var(--text); }

/* the mobile disclosure is gone; keep any stale rules from applying */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .nx-tune { display: none !important; }

/* ---- narrow: the core image ----
   contain inside a full-width wrap left a tall black band above the meta
   (visible as a big empty box on a phone). The narrow core is a 2-column
   plate, so the image column needs a real aspect and cover, not contain. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .core-img-wrap {
  min-height: 0;
  aspect-ratio: 1;
  height: auto;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .core-img-wrap img,
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .core-img-wrap video {
  object-fit: cover;
}

/* ---- narrow: composing ----
   app.js's placeholders are .card, which carries a fixed grid measure — in
   a single column that overflowed and clipped its own heading. Make them
   row-shaped, like the readings they become. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .chorus .loading-card {
  width: auto !important;
  min-width: 0;
  max-width: 100%;
  grid-column: 1 / -1;
  padding: 14px 15px;
  border-radius: 10px;
  box-sizing: border-box;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .chorus .loading-card .card-head {
  font-size: 13px;
  line-height: 1.3;
  white-space: normal;
}

/* the pending cells the accordion builds sit full width too */
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .chorus.arr-narrow .ag-composing,
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .chorus.arr-narrow .nx-pending {
  width: auto;
  max-width: 100%;
  margin: 0;
  box-sizing: border-box;
}

/* the status pill should not sit under the list on a phone */
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .status { padding: 9px 14px; }


/* =========================================================================
   NARROW — SUPPRESS THE DESKTOP CARDS
   layoutNarrow() SYNTHESIZES .nx-row buttons from card data rather than
   moving the existing nodes (which is what layoutQuad and layoutSpectrum
   do). So the original .voice cards renderCards() left as direct children of
   #cards are never consumed, and every reading rendered twice on a phone:
   the tall desktop card, then the compact row.

   They are hidden, NOT removed. app.js calls
   cardsContainer.replaceChild(newCard, loadingEls[i]) and uses indexOf over
   #cards children — an earlier turn already lost a compose loop to exactly
   that. Hiding leaves the DOM contract intact, so readings(), cardOf() and
   the occupant counts all still see the set they expect.

   #cards is display:contents, so these participate directly in the chorus
   block flow; display:none on the child itself is what removes them from it.
   ========================================================================= */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-narrow > #cards > .voice,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-narrow > #cards > .voice-add {
  display: none !important;
}


/* =========================================================================
   THE [hidden] INVARIANT — restore it inside a host theme

   THE PLUGIN BUG: grid -> Tuner -> grid left the console on the page beneath
   the chorus. activate(false) does set con.hidden = true, and nothing in our
   stylesheets declares display on .console — both of which were verified, and
   both of which made the bug look impossible.

   The missing piece is that [hidden] is a UA-stylesheet rule
   (display: none) at the LOWEST possible author-facing precedence. Any
   author rule that sets display on a matching element beats it. A standalone
   page had no such rule. A WordPress theme very often does — a generic
   "section { display: block }", "main > * { display: block }" or a
   content-area reset is enough, and #console is a <section> inside
   <main class="stage"> inside the theme's content column.

   So the attribute silently stopped meaning anything the moment the markup
   moved into a themed page, and every element that relies on it was
   affected, not just the console: #threshold, #focus, #addMorePanel,
   #chipSource, #coordTools, #modeIndicator, the arrangement buttons.

   One rule, rather than a display declaration per component: any [hidden]
   inside our root is hidden, whatever the host theme has to say. Scoped to
   the plugin root and the standalone body so both contexts behave the same.
   ========================================================================= */
.giga-glossary-root [hidden],
.giga-glossary-root[hidden],
body:has(> .stage) [hidden] { display: none !important; }


/* =========================================================================
   THE SENSE GATE
   Shown when /resolve finds that a name covers several separately notable
   referents. It takes the stage the composing placeholders would have taken,
   because nothing has been spent yet and this is the reason why.

   Deliberately NOT a modal: there is nothing behind it to dim one beat after
   Run, and a scrim would make an improvement to the run look like a
   precondition for it.
   ========================================================================= */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .sense-gate {
  --alt: var(--accent);
  display: flex;
  flex-direction: column;
  gap: 20px;
  margin: 0 0 18px;
  padding: 26px 26px 22px;
  border: 1px solid var(--line-3);
  border-top: 3px solid var(--accent);
  border-radius: 4px 4px 14px 14px;
  background: linear-gradient(168deg, var(--panel-2) 0%, var(--panel) 62%);
}

/* The gate lives in .stage, which body.is-empty hides — and at gate time
   there are no readings yet, so is-empty is ALWAYS true. Without this the
   panel rendered at zero width inside a display:none subtree and could never
   be seen in the real flow. So while gated: the stage is shown, the
   threshold stands down, and the chorus scaffolding stays hidden rather than
   presenting an empty grid beneath the question. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-gated .stage { display: block !important; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-gated .threshold { display: none !important; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-gated #chorus,
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-gated .chorus-label,
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-gated .tune-strip,
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-gated .add-more { display: none !important; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .sg-head { display: flex; flex-direction: column; gap: 10px; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .sg-eyebrow {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--label);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .sg-title {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(30px, 4.4vw, 40px);
  font-weight: 400;
  line-height: 1.08;
  letter-spacing: -.01em;
  color: var(--text-hi, #f4f2f9);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .sg-title em { font-style: italic; color: var(--accent); }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .sg-sub {
  margin: 0;
  max-width: 62ch;
  font-size: 14.5px;
  line-height: 1.6;
  color: var(--text-2, #a5a7b8);
  text-wrap: pretty;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .sg-list { display: flex; flex-direction: column; gap: 8px; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .sg-sense {
  display: grid;
  grid-template-columns: 96px minmax(0, 1fr);
  align-items: center;
  gap: 18px;
  width: 100%;
  min-height: 64px;
  padding: 13px 16px;
  border: 1px solid var(--line-soft);
  border-radius: 10px;
  background: var(--panel);
  text-align: left;
  font-family: inherit;
  cursor: pointer;
  transition: border-color .15s ease, background .15s ease;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .sg-sense:hover,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .sg-sense:focus-visible {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 7%, var(--panel));
  outline: none;
}

/* The count, not the gloss, is the primary signal — a gloss is a
   dictionary's opinion, "12 readings here" is what this site has meant by
   the word, and it comes from the database rather than the model. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .sg-count {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 1px;
  padding-right: 18px;
  border-right: 1px solid var(--line-soft);
  text-align: right;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .sg-count b {
  font-family: var(--font-display);
  font-size: 30px;
  font-weight: 400;
  line-height: 1;
  color: var(--accent);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .sg-count b.sg-zero { color: var(--line-4); }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .sg-count i {
  font-style: normal;
  font-family: var(--font-mono);
  font-size: 8px;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--label);
  white-space: nowrap;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .sg-sense:not(.has-readings) .sg-count i { color: var(--faint); }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .sg-body { display: flex; flex-direction: column; gap: 4px; min-width: 0; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .sg-name {
  font-size: 16px;
  font-weight: 600;
  line-height: 1.3;
  color: var(--text);
  text-wrap: pretty;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .sg-gloss {
  font-size: 13px;
  line-height: 1.5;
  color: var(--text-2, #a5a7b8);
  text-wrap: pretty;
}

/* ---- the free-text escape ---- */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .sg-other {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding-top: 4px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .sg-other-label {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--label);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .sg-other-row { display: flex; gap: 8px; align-items: stretch; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .sg-other-row input {
  flex: 1;
  min-width: 0;
  height: 44px;
  padding: 0 14px;
  border: 1px solid var(--line-3);
  border-radius: 9px;
  background: var(--panel);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 14.5px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .sg-other-row input:focus { outline: none; border-color: var(--accent); }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .sg-other-row .primary { height: 44px; white-space: nowrap; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .sg-foot {
  display: flex;
  justify-content: flex-start;
  padding-top: 2px;
  border-top: 1px solid var(--line-soft);
  margin-top: 2px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .sg-foot .ghost { margin-top: 14px; min-height: 40px; }

/* ---- narrow ---- */
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .sense-gate { padding: 20px 16px 18px; gap: 16px; }

/* the count column becomes a badge above the name: at phone width a 96px
   gutter leaves the gloss about 20 characters a line */
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .sg-sense {
  grid-template-columns: minmax(0, 1fr);
  gap: 9px;
  padding: 14px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .sg-count {
  flex-direction: row;
  align-items: baseline;
  gap: 7px;
  padding: 0;
  border-right: 0;
  text-align: left;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .sg-count b { font-size: 21px; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .sg-other-row { flex-wrap: wrap; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .sg-other-row input { flex: 1 1 100%; }


/* =========================================================================
   FIRST PAINT — no flash of the composed state

   The markup's resting state IS the composed state: the tune strip, the
   arrangement bar, the core card and the help panel are all present and
   visible, and body.is-empty is added by JS at the first setStage(). So
   between first paint and boot the browser showed a referent-less composed
   page — an empty arrange bar, a core with a broken-image glyph where
   #heroImg has display:block and no src yet, and a duplicated "Tune a Kosmic
   Address" (the button plus the #coordTools disclosure JS later relocates).

   Suppressing it until booted, rather than reordering the markup, because
   the markup is generated into templates/kosmic.php and this has to hold
   whichever copy is live.

   Note what is NOT suppressed: .threshold. If the scripts fail entirely the
   visitor still gets the field and the starter chips, which is the correct
   degraded state — a working front door rather than a broken dashboard.
   ========================================================================= */
:is([data-theme="kosmic"],[data-theme="prismatic"]) body:not(.gg-booted) .tune-strip,
:is([data-theme="kosmic"],[data-theme="prismatic"]) body:not(.gg-booted) .stage,
:is([data-theme="kosmic"],[data-theme="prismatic"]) body:not(.gg-booted) #coordTools,
:is([data-theme="kosmic"],[data-theme="prismatic"]) body:not(.gg-booted) .help-panel,
:is([data-theme="kosmic"],[data-theme="prismatic"]) body:not(.gg-booted) .add-more { display: none !important; }

/* A srcless <img> renders the broken-image glyph and its alt text. #heroImg
   carries display:block in the markup so app.js can reveal it without
   touching layout, so guard on the attribute instead — this also covers the
   moment a referent changes and the old src is cleared. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) #heroImg:not([src]),
:is([data-theme="kosmic"],[data-theme="prismatic"]) #groundImg:not([src]),
:is([data-theme="kosmic"],[data-theme="prismatic"]) .porthole-eye img:not([src]),
:is([data-theme="kosmic"],[data-theme="prismatic"]) .focus-porthole-eye img:not([src]),
:is([data-theme="kosmic"],[data-theme="prismatic"]) .nx-porthole-eye img:not([src]) { visibility: hidden; }


/* =========================================================================
   CURATION — 12a on the tile, 12c in the reading

   The tile carries a MARK and no controls. Nine tiles x four controls is
   thirty-six controls on a glance surface however quietly they are drawn,
   and hover-reveal would be dead on touch anyway. Everything that acts on a
   reading lives in the reading, which is also where you can have read it
   before deciding to remove it.
   ========================================================================= */

/* 4px, in the altitude's own colour, inside the tile's top-right corner.
   Enough to answer "which of these are mine" while scanning; not enough to
   read as a control. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-mine {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--alt, var(--accent));
  flex: none;
  /* nudged to sit on the number's optical centre rather than its baseline */
  align-self: center;
  margin-right: 5px;
  pointer-events: none;
}

/* ---- the footer ---- */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .curation-foot {
  display: flex;
  flex-direction: column;
  gap: 16px;
  align-items: stretch;
  margin-top: 26px;
  padding-top: 18px;
  border-top: 1px solid var(--line-soft);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .cf-rate { display: flex; flex-direction: column; gap: 9px; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .cf-q {
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--label);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .cf-axes { display: flex; flex-wrap: wrap; gap: 7px; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .cf-ax {
  min-height: 40px;
  padding: 0 14px;
  border: 1px solid var(--line-soft);
  border-radius: 8px;
  background: transparent;
  color: var(--text-2, #a5a7b8);
  font-family: var(--font-sans);
  font-size: 13px;
  cursor: pointer;
  transition: border-color .15s ease, color .15s ease;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .cf-ax:hover { border-color: var(--line-3); color: var(--text); }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .cf-ax.is-on {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  color: #fff;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .cf-acts { display: flex; flex-wrap: wrap; gap: 7px; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .cf-acts .ghost { min-height: 40px; }

/* Regenerate and delete are marked, but only on hover — at rest they should
   not shout, since the common action in this footer is reading on. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .cf-regen:hover { border-color: var(--accent); color: #fff; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .cf-del:hover { border-color: #c96a5c; color: #fff; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .cf-del { margin-left: auto; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .cf-acts .ghost[disabled] { opacity: .55; cursor: default; }

/* one line, in place, about the reading on screen — a toast would put the
   result somewhere other than the thing it describes */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .cf-note {
  font-size: 13px;
  line-height: 1.55;
  color: var(--text-2, #a5a7b8);
  text-wrap: pretty;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .cf-note.is-ok { color: var(--accent); }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .cf-note.is-bad { color: #e8a094; }

@media (max-width: 760px) {
  :is([data-theme="kosmic"],[data-theme="prismatic"]) .cf-del { margin-left: 0; }
  :is([data-theme="kosmic"],[data-theme="prismatic"]) .cf-acts .ghost { flex: 1 1 auto; }
}


/* "Meta source: stored" is provenance for whoever is debugging the cache —
   it tells a reader nothing they can act on, and it sits directly under the
   meta-definition where it reads as part of the definition. app.js writes to
   #metaDebug unconditionally, so the node stays and only the display goes. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .meta-debug { display: none !important; }


/* ---- the mark and the number as one unit ----
   .voice-num was pushed right by margin-left:auto; the mark now takes that
   role so the two travel together. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-head { display: flex; align-items: baseline; gap: 0; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-alt { margin-right: auto; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-mine { margin-left: 0; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .nx-row .voice-mine { align-self: center; }

/* var(--ink-faint) is a KOSMIC-only token, so in Prismatic the declaration
   was invalid and the number inherited the card's body colour at 9.5px —
   which is why it read as a smudge rather than a number. --grey-1 exists in
   both themes and is tuned per theme for small type. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-num { color: var(--num-ink, #7c8093); }

/* the card index: quieter than the altitude label, still legible */
[data-theme="kosmic"] { --num-ink: #7c8093; }


/* =========================================================================
   HEADER

   The defects were alignment and vocabulary, not spacing:

     - The input, Run and Random sat on three different baselines because
       the row aligned on text baselines while the controls had different
       heights and paddings. One shared control height and align-items:
       center fixes it structurally, so it cannot drift again.
     - Four visual languages in one row: serif brand, sans-serif pills, an
       iOS slider, and a native <select> with OS chevrons. The slider and
       the select are both replaced by the same pill/segmented vocabulary
       the arrangement bar already uses.

   --ctl is the single height every header control answers to.
   ========================================================================= */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .app-header {
  --ctl: 40px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px 24px;
  flex-wrap: wrap;
  padding: 14px 24px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .header-left {
  display: flex;
  align-items: center;
  gap: 20px;
  min-width: 0;
  flex: 1 1 520px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .header-right {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 0 0 auto;
}

/* ---- brand ---- */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .brand {
  font-family: var(--font-display);
  font-size: 23px;
  line-height: 1;
  letter-spacing: -.005em;
  color: var(--accent);
  text-decoration: none;
  white-space: nowrap;
  flex: none;
  /* optical: a serif cap-height sits high against 40px controls */
  padding-bottom: 2px;
  transition: opacity .15s ease;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .brand:hover { opacity: .78; text-decoration: none; }

/* ---- the field: one height, one radius, one baseline ---- */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .field-mount { min-width: 0; flex: 1 1 auto; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .app-header .input-wrap {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  max-width: 560px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .app-header .input-wrap input {
  height: var(--ctl);
  min-width: 0;
  flex: 1 1 auto;
  padding: 0 14px;
  border-radius: 9px;
  border: 1px solid var(--line-3);
  background: var(--field, var(--panel-2));
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 14.5px;
  line-height: 1;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .app-header .input-wrap input:focus {
  outline: none;
  border-color: var(--accent);
}

/* height + centred content on BOTH buttons: they were pills with vertical
   padding, so each computed its own height from its own font metrics */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .app-header .input-wrap .primary,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .app-header .input-wrap .ghost {
  height: var(--ctl);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0 18px;
  border-radius: 9px;
  font-family: var(--font-sans);
  font-size: 14px;
  line-height: 1;
  white-space: nowrap;
  flex: none;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .app-header .input-wrap .ghost { font-size: 13.5px; padding: 0 14px; }

/* ---- rich context: a pill with an indicator, not an iOS slider ---- */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .toggle-group,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .toggle-slider,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .toggle-text,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .toggle-hint { display: none; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .rc-toggle {
  height: var(--ctl);
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 0 14px;
  border: 1px solid var(--line-soft);
  border-radius: 9px;
  background: transparent;
  cursor: pointer;
  user-select: none;
  transition: border-color .15s ease;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .rc-toggle:hover { border-color: var(--line-3); }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .rc-toggle .toggle-input { position: absolute; opacity: 0; pointer-events: none; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .rc-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  border: 1px solid var(--grey-2);
  background: transparent;
  flex: none;
  transition: background .15s ease, border-color .15s ease;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .rc-text {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--label);
  white-space: nowrap;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .rc-toggle:has(.toggle-input:checked),
:is([data-theme="kosmic"],[data-theme="prismatic"]) .rc-toggle.is-on {
  border-color: var(--accent);
  background: color-mix(in srgb, var(--accent) 10%, transparent);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .rc-toggle:has(.toggle-input:checked) .rc-dot,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .rc-toggle.is-on .rc-dot {
  background: var(--accent);
  border-color: var(--accent);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .rc-toggle:has(.toggle-input:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ---- theme: a segmented pair, each half showing its own ground ---- */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .theme-seg {
  height: var(--ctl);
  display: inline-flex;
  align-items: center;
  gap: 3px;
  padding: 3px;
  border: 1px solid var(--line-soft);
  border-radius: 10px;
  background: var(--panel-3, transparent);
  flex: none;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .theme-btn {
  height: 100%;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 0 11px;
  border: 0;
  border-radius: 7px;
  background: transparent;
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--grey-1);
  transition: background .15s ease, color .15s ease;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .theme-btn:hover { color: var(--text); }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .theme-btn.is-on {
  background: var(--panel-6, rgba(255,255,255,.08));
  color: var(--text);
}

/* the swatch is the theme's actual ground, so the control demonstrates
   rather than only labels */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .theme-chip {
  width: 11px;
  height: 11px;
  border-radius: 50%;
  border: 1px solid var(--line-4);
  flex: none;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .theme-btn[data-theme-val="kosmic"] .theme-chip { background: #0d1015; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .theme-btn[data-theme-val="prismatic"] .theme-chip {
  background: linear-gradient(135deg, #6d5b9e 0%, #8ea3c4 100%);
}

/* ---- narrow: the field takes its own row ---- */
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .app-header { --ctl: 40px; padding: 12px 14px; gap: 12px; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .header-left { flex: 1 1 100%; gap: 14px; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .brand { font-size: 19px; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .header-right { flex: 1 1 100%; justify-content: space-between; gap: 8px; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .app-header .input-wrap { max-width: none; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .rc-text { font-size: 9px; letter-spacing: .12em; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .theme-btn { padding: 0 9px; }


/* =========================================================================
   ADD, ONE AT A TIME

   The batch panel is gone. It made sense when the default spread was small;
   with eight readings arriving by default, a "Count / Add 3 random / Select
   perspectives…" bar offers a bulk operation nobody needs, and it was the
   one path still routing through app.js's addMoreRandom() — an extra /plan
   round-trip to choose addresses, then three composes. The add TILES compose
   one chosen address in one call, which is what "fill this cell" should
   cost.

   The nodes stay in the DOM: app.js binds listeners to #addMoreBtn,
   #addMoreCount and #addMoreSelectBtn unconditionally, so removing them
   would abort its init at the first null.
   ========================================================================= */
:is([data-theme="kosmic"],[data-theme="prismatic"]) #addMorePanel,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .add-more { display: none !important; }

/* the guaranteed tile, when the grid divides exactly and leaves no gap */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-add.va-wide {
  grid-column: 1 / -1;
  min-height: 58px;
  flex-direction: row;
  gap: 10px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-add.va-wide .va-plus { font-size: 15px; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) body.gg-narrow .voice-add.va-wide { min-height: 52px; }


/* =========================================================================
   HEADER — ALIGNMENT HARDENING

   In isolation every header control measures top:14 / height:40 / centre:34.
   Inside WordPress they drift by a few pixels each, which means the drift is
   not ours: the HOST THEME is styling bare `input`, `button` and `label`,
   and those rules reach our markup because our elements are bare input,
   button and label.

   The usual culprits, in order of how often themes do it:
     input, button { margin-bottom: … }     a vertical-rhythm rule
     input { vertical-align: middle }       differs from the button's baseline
     button { line-height: normal }         changes the content box
     * { box-sizing: content-box }          older resets; border adds height

   So the three properties that DEFINE the row are asserted rather than
   merely set. !important is right here and nowhere else in this file: these
   are layout invariants the design depends on, not aesthetic choices a theme
   could reasonably override. Anything a host theme wants to say about colour,
   radius or type still gets through.
   ========================================================================= */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .app-header .input-wrap input,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .app-header .input-wrap button,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .app-header .rc-toggle,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .app-header .rc-toggle .rc-dot,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .app-header .rc-toggle .rc-text,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .app-header .theme-seg,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .app-header .theme-btn,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .app-header .brand {
  margin: 0 !important;
  box-sizing: border-box !important;
  align-self: center !important;
  vertical-align: middle;
  float: none;
}

/* A host theme's line-height cascades into the content box and is what makes
   two 40px controls sit on different centres. Every header control centres
   its own content with flex, so the line-height only has to be neutral. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .app-header .input-wrap input,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .app-header .input-wrap button,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .app-header .rc-text,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .app-header .theme-btn {
  line-height: 1 !important;
}

/* min-height as well as height: a theme setting min-height on button or
   input wins against height alone and silently makes one control taller */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .app-header .input-wrap input,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .app-header .input-wrap .primary,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .app-header .input-wrap .ghost,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .app-header .rc-toggle,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .app-header .theme-seg {
  height: var(--ctl) !important;
  min-height: var(--ctl) !important;
  max-height: var(--ctl) !important;
}

/* the field row and the right-hand group both centre their children, so a
   stray align-items from a theme cannot stagger them */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .app-header .input-wrap,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .app-header .header-left,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .app-header .header-right { align-items: center !important; }


/* =========================================================================
   READER'S SUBJECT

   Picking an address says WHERE to look; a subject says WHAT to look at from
   there. Two surfaces offer it — the tuner, where the address is already
   fully chosen, and the add tile, where it is drawn at random — and every
   reading that has one shows it.
   ========================================================================= */

/* ---- the opt-in chip on an add tile ---- */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .va-about,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .va-random {
  margin-top: 2px;
  padding: 4px 9px;
  border-radius: 999px;
  border: 1px dashed var(--line-3);
  font-family: var(--font-mono);
  font-size: 8.5px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--label);
  cursor: pointer;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .va-about:hover,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .va-random:hover { border-color: var(--accent); color: var(--accent); border-style: solid; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .va-about:focus-visible,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .va-random:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ---- the form the chip opens ---- */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-add.va-form {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  justify-content: center;
  gap: 9px;
  padding: 14px;
  cursor: default;
  border-style: solid;
  border-color: var(--accent);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .vaf-label,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .rds-label {
  font-family: var(--font-mono);
  font-size: 8.5px;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--label);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .vaf-input,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .rds-input {
  width: 100%;
  height: 36px;
  min-width: 0;
  padding: 0 11px;
  border-radius: 8px;
  border: 1px solid var(--line-3);
  background: var(--field, var(--panel-2));
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 13.5px;
  line-height: 1;
  box-sizing: border-box;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .vaf-input:focus,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .rds-input:focus { outline: none; border-color: var(--accent); }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .vaf-input::placeholder,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .rds-input::placeholder { color: var(--grey-1); }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .vaf-acts { display: flex; gap: 6px; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .vaf-go,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .vaf-cancel {
  height: 32px;
  padding: 0 13px;
  border-radius: 7px;
  border: 1px solid transparent;
  font-family: var(--font-sans);
  font-size: 12.5px;
  line-height: 1;
  cursor: pointer;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .vaf-go { background: var(--accent); color: #08090c; font-weight: 600; flex: 1; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .vaf-go[disabled] { opacity: .6; cursor: default; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .vaf-cancel { background: transparent; border-color: var(--line-3); color: var(--text-2, #a5a7b8); }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .vaf-cancel:hover { border-color: var(--line-5); color: var(--text); }

/* the wide tile has room for one row */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-add.va-form.va-wide {
  flex-direction: row;
  align-items: center;
  gap: 12px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-add.va-form.va-wide .vaf-input { flex: 1 1 auto; width: auto; }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-add.va-form.va-wide .vaf-go { flex: none; }

/* ---- the tuner's field ---- */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .rd-subject {
  display: flex;
  flex-direction: column;
  gap: 7px;
  width: 100%;
  max-width: 420px;
  margin: 2px auto 0;
  text-align: left;
}

/* in the held pane it sits in the reading's own column, not centred */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .sig-inner > .rd-subject { margin-left: 0; margin-right: 0; max-width: 480px; }

/* ---- "asked about", on a reading that has one ---- */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .focus-asked,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .nx-asked,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .rd-asked {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 4px 10px;
  padding: 9px 12px;
  border-radius: 9px;
  border: 1px solid var(--line-soft);
  border-left: 2px solid var(--alt, var(--accent));
  background: var(--panel-3, transparent);
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .fa-label,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .rda-label {
  font-family: var(--font-mono);
  font-size: 8.5px;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--label);
  flex: none;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .fa-text,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .rda-text {
  font-size: 14px;
  line-height: 1.45;
  color: var(--text);
  text-wrap: pretty;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .focus-asked[hidden] { display: none; }


/* The tuner's host is .sig-actions, whose own rule is a horizontal row — so
   state the footer's stacking again at a specificity that reaches it. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .console .sig-actions.curation-foot {
  flex-direction: column;
  align-items: stretch;
  gap: 16px;
}


/* the bar's own labels share the controls' height so nothing sits a pixel or
   two high — see .arr-axis for why the select needed an explicit box */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .arrange-label,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus-count {
  display: inline-flex;
  align-items: center;
  height: 28px;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .arrange-sep {
  display: inline-flex;
  align-items: center;
  height: 28px;
}


/* The composed state's help panel carries the SAME copy as the threshold's,
   so it needs the same prose measure — it was written for a one-line formula
   and had none. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .help-panel p {
  max-width: 68ch;
  font-size: 14px;
  line-height: 1.7;
  color: var(--text-2, #a5a7b8);
  text-wrap: pretty;
}


/* Buttons in the arrangement run get the same inset focus ring, for the
   same reason: an offset outline grows the box and breaks the alignment the
   explicit 28px height establishes. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .arr-btn:focus-visible {
  outline: none;
  border-color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent);
}


/* A vertical head's inline axis is its HEIGHT, so cap it against the lane —
   otherwise a long line name ("Psychosexual", "Interpersonal") in a short
   lane overflows instead of ellipsising, and the overflow is what reaches
   the pinned bar. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-spectrum .ag-lane.is-empty .ag-head { max-height: calc(100% - 24px); }
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-spectrum .ag-lane.is-empty .ag-code { max-height: 100%; }


/* An empty lane centres its contents, which for a 21-lane spectrum put the
   vertical name in the middle of a very tall column — the user reads it as
   "below the fold". The name belongs at the top of the container it labels.
   align-self overrides the lane's align-items: center for this child only. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-spectrum .ag-lane.is-empty .ag-head {
  align-self: center;
  margin-top: 0;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-spectrum .ag-lane.is-empty {
  justify-content: flex-start;
}


/* The lane heads sit at the top of their lanes, in normal flow. The bar
   above them is sticky and opaque, so the rail needs a gap or the heads
   start flush against it and the first row of glyphs is clipped — which is
   what the vertical labels were losing. A gap is all that was wanted. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-spectrum .ag-rail { padding-top: 16px; }

/* and the empty lane's own top padding, so the vertical name starts inside
   its dashed box rather than on its edge */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .chorus.arr-spectrum .ag-lane.is-empty { padding-top: 16px; }


/* two chips need a row of their own under the tile's label, and the tile is
   a column — without this they stack and the tile grows */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-add > .va-about,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-add > .va-random { flex: none; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-add.va-wide { flex-wrap: wrap; }


/* the field and its buttons are one control — see the border-box note above */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .th-field .input-wrap { align-items: stretch; }

/* ---- the add tile's alternates ----
   One quiet line under the tile's own label, not two more buttons. The tile
   is the action; these change how its address is chosen (surprise me) or add
   to the request (context…). Bordered pills read as three peers, which they
   are not. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-add.va-wide {
  flex-direction: column;
  flex-wrap: nowrap;
  gap: 0;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .va-alts {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 6px 13px;
  /* clear air under the primary, so the row reads as a second tier rather
     than as a caption attached to the label */
  margin-top: 15px;
  /* the alternates are a list; the tile behind them is the action. Its own
     click must still reach the tile from the gaps between words. */
  pointer-events: none;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .va-alts > [role="button"] { pointer-events: auto; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .va-about,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .va-random {
  margin-top: 0;
  padding: 3px 2px;
  border: 0;
  border-radius: 0;
  background: none;
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--label);
  cursor: pointer;
  border-bottom: 1px solid transparent;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .va-about:hover,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .va-random:hover {
  color: var(--accent);
  border-bottom-color: var(--accent);
  border-style: solid;
  background: none;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .va-about:focus-visible,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .va-random:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

:is([data-theme="kosmic"],[data-theme="prismatic"]) .va-sep {
  width: 1px;
  height: 11px;
  background: var(--line-4);
  opacity: .7;
}

/* the form's label carries its own optional marker, like the tuner's */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .vaf-label i,
:is([data-theme="kosmic"],[data-theme="prismatic"]) .dk-label i {
  font-style: normal;
  opacity: .6;
  letter-spacing: .1em;
}


/* the label is the target — it should not be one of four equal words */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-add .va-text {
  font-size: 11px;
  letter-spacing: .2em;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .va-tune {
  margin-top: 0;
  padding: 3px 2px;
  border: 0;
  border-radius: 0;
  background: none;
  font-family: var(--font-mono);
  font-size: 9px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--label);
  cursor: pointer;
  border-bottom: 1px solid transparent;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .va-tune:hover {
  color: var(--accent);
  border-bottom-color: var(--accent);
  background: none;
}

:is([data-theme="kosmic"],[data-theme="prismatic"]) .va-tune:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }


/* "2 of 2" — see siblingRank(). Quieter than the coordinates it follows:
   it qualifies them rather than adding one. */
:is([data-theme="kosmic"],[data-theme="prismatic"]) .voice-sib {
  margin-left: 8px;
  padding-left: 8px;
  border-left: 1px solid var(--line-3);
  font-style: italic;
  color: var(--label);
  white-space: nowrap;
}
