/* s01.css — section 01's graphic styles only (the dependency stack).
   Owns: the slab-stack SVG type (ds-dim labels), the canvas box's
   proportion, and the slab readout's fixed-slot colouring. The shared
   shell (.spec-block / .spec-canvas / .spec-tag / .spec-readout) lives
   in research.css. HARD RULE: nothing here changes geometry on hover. */

/* cap the block at its original (pre-refactor) rendered width so it keeps
   the same size instead of stretching to the full graphic column; a fixed
   value, so geometry never varies with content */
.spec-01 {
  max-width: 391px;
}

/* the canvas box's aspect-ratio is set from JS (s01.js) once NSStack has
   computed its viewBox (0 0 W H), so the SVG (absolute-filled by the
   shared rule) fits without distortion and the box height is a pure
   function of width — immune to hover strokes. A fallback ratio holds
   the box's shape before JS runs / if JS is blocked. */
.spec-01 .spec-canvas {
  aspect-ratio: 355 / 149;
}

/* NSStack's shared layer labels + stack headers */
.spec-01 .spec-canvas text {
  font-family: "Geist Mono", ui-monospace, "SF Mono", Menlo, monospace;
  font-weight: 300;
  font-size: 10.5px;
  fill: currentColor;
}

.spec-01 .spec-canvas .ds-dim {
  opacity: 0.5;
}

/* the one-line slab readout — NSStack writes <span class="sl"> (blue
   layer name, reserved column) + <span class="sv"> (dim fact). The slot
   is fixed-width so the NSRoll glyph-roll swaps letters, never geometry.

   GEOMETRY LOCK: section 01's readouts now read COMPARATIVELY on hover
   (longer than the idle line), and a nowrap readout's intrinsic inline
   size feeds this flex-column block's width — so a longer hovered line
   would nudge the block toward its max-width cap (a ~0.4px hover wiggle,
   a regression of the hard rule). contain:inline-size makes the readout's
   inline size independent of its content, so no readout text — however
   long — can ever resize the block. Height (the reserved 1.4em slot) is
   untouched; the block stays pinned to its column width through hover. */
.spec-01 .spec-readout {
  contain: inline-size;
}

.spec-01 .spec-readout .sl {
  display: inline-block;
  min-width: 13ch; /* "consequence" + air */
  color: #2222ff;
}

.spec-01 .spec-readout .sv {
  color: var(--ink-dim);
}

/* ---------- enrichment (see s01.js) — pixels, never geometry ---------- */

/* CROSS-TOWER CONNECTOR. One dotted horizontal line per layer, drawn once
   inside the SVG's existing bounds (s01.js) and toggled by OPACITY only —
   the line always occupies its space, so nothing moves when it appears.
   Blue, hairline, dotted; revealed when the hovered slab lights its
   counterpart. vector-effect keeps the hairline crisp at any SVG scale. */
.spec-01 .spec-canvas .ds-link {
  stroke: #2222ff;
  stroke-width: 1;
  stroke-dasharray: 1 3;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
  opacity: 0;
  transition: opacity 140ms ease;
  pointer-events: none;
}
.spec-01 .spec-canvas .ds-link.is-on {
  opacity: 0.85;
}

/* BREATHING BLUE. The two ghost AI slabs (standard + measurement) get a
   slow edge breath — stroke-opacity 0.75↔1.0 over ~4s, barely alive. The
   hover highlight changes stroke-width, not stroke-opacity, so the breath
   and the hover heavier-edge compose without fighting. */
@keyframes ds-breathe {
  0%, 100% { stroke-opacity: 1; }
  50%      { stroke-opacity: 0.75; }
}
.spec-01 .spec-canvas .ds-breathe {
  animation: ds-breathe 4s ease-in-out infinite;
}

/* ASSEMBLE-ONCE. Each slab group starts hidden + nudged down, then settles
   in on first scroll-into-view (staggered bottom→top from s01.js). Pure
   opacity/transform inside the clipped fixed box — geometry is untouched.
   transform-box:fill-box so the tiny translate is in the group's own
   local units, not the whole SVG's. */
.spec-01 .spec-canvas .ds-pre {
  opacity: 0;
  transform: translateY(6px);
  transform-box: fill-box;
}
.spec-01 .spec-canvas .ds-in {
  opacity: 1;
  transform: translateY(0);
  transition: opacity 260ms ease, transform 260ms ease;
}

/* reduced motion: no breath, no assembly, no connector fade — instant.
   (s01.js also skips the JS side of assembly/breath under reduced motion;
   this backstops the connector's opacity transition and any residual.) */
@media (prefers-reduced-motion: reduce) {
  .spec-01 .spec-canvas .ds-breathe { animation: none; }
  .spec-01 .spec-canvas .ds-pre { opacity: 1; transform: none; }
  .spec-01 .spec-canvas .ds-in { transition: none; }
  .spec-01 .spec-canvas .ds-link { transition: none; }
}
