/* =============================================================================
   Ciral Fusion: /testing/ ("Real data. Coming soon.")
   Loaded after site.css: tokens, type scale, nav, sheet, buttons, tags, captions and footer.

   One idea: two halves of one picture. The left half is computed (one face of a published
   simulation cut); the right half is the measured half, an empty frame of the same size whose
   vertical axis is the cut plane. Nothing is plotted in it. The chrome is monochrome; the only
   colour on the page is the render.

   Motion is a single arrival (about 2.7 s, once): the render fades up, the frame draws itself from
   the cut plane, one scan crosses the empty half and finds nothing, and the frame reports that it
   is waiting. Then everything is still. CSS only, gated on html.js and no-preference, and every
   animation ends on the visible state, so nothing can stay hidden.
   ========================================================================== */

/* ---------- Section ---------------------------------------------------------- */
.tst {
  position: relative; display: grid; align-content: center;
  /* one screen, capped so tall windows and full-page captures keep the composition */
  min-height: min(calc(100vh - var(--nav-h)), 1040px);
  min-height: min(calc(100svh - var(--nav-h)), 1040px);
  padding-block: clamp(28px, 2.6vw, 44px);
}
.tst__grid { align-items: center; row-gap: clamp(48px, 8vw, 72px); }
.tst__copy { grid-column: 1 / span 6; }
.tst__fig { grid-column: 7 / -1; justify-self: end; }

/* Two-tone, as the homepage hero: the setup dim, the payoff bright. Tied to the window height too,
   so a short laptop window keeps the stage and its captions on the first screen. */
.tst__h {
  font-size: min(clamp(2.75rem, 1.5rem + 5.1vw, 6rem), max(11svh, 2.75rem));
  line-height: 0.96; letter-spacing: var(--tr-hero); font-weight: 600;
  margin-bottom: clamp(22px, 2.4vw, 34px);
}
.tst__h > span { display: block; }
.tst__h .dim { color: var(--text-3); }
.tst__lead {
  font-size: clamp(1.1875rem, 1.11rem + 0.32vw, 1.3125rem); line-height: 1.45; letter-spacing: var(--tr-lead);
  color: var(--text-2); max-width: 27em; margin-bottom: clamp(26px, 2.8vw, 38px);
  text-wrap: pretty;
}
.tst__lead strong { color: var(--text); font-weight: 500; }

/* ---------- The stage -------------------------------------------------------- */
/* Each half is 970 x 2075 source pixels: the left face of the 1790 x 2075 cut stops 4 px short of
   the cut plane (x = 974), so no pixel of the other face ever shows. The width follows the window
   height on desktop so the stage and its captions fit one screen. */
.duo {
  /* the floor is low enough that a short laptop window (1366 x 625 viewport) still shows the whole stage and
     its "Simulation" tag on the first screen; below about 500 px the mono lines wrap as two units (see captions) */
  width: min(100%, max(400px, calc((100vh - var(--nav-h) - 156px) * 0.935)));
  width: min(100%, max(400px, calc((100svh - var(--nav-h) - 156px) * 0.935)));
  margin: 0;
}
.duo__stage {
  position: relative; display: grid; grid-template-columns: 1fr 1fr;
  aspect-ratio: 1940 / 2075; background: var(--night-0);
}
.duo__sim { position: relative; overflow: hidden; }
.duo__sim picture, .duo__sim img {
  position: absolute; top: 0; left: 0; height: 100%; width: auto; max-width: none;
}

/* The measured half */
.duo__meas { position: relative; overflow: hidden; contain: paint; container-type: inline-size; }
.duo__marks { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.duo__marks path { fill: none; vector-effect: non-scaling-stroke; stroke-width: 1px; }
/* plot furniture only: a faint grid on the major divisions, a closed edge, ruler ticks on the cut
   plane and the baseline. No numbers, no points, no traces: nothing here can be read as a value. */
.duo__grid { stroke: rgba(246, 244, 239, 0.055); }
.duo__edge { stroke: var(--line); }
.duo__minor { stroke: rgba(246, 244, 239, 0.26); }
.duo__major { stroke: rgba(246, 244, 239, 0.44); }
.duo__corner { stroke: var(--line-strong); }

.duo__line { position: absolute; display: block; background: var(--line-strong); }
.duo__line--axis { left: 0; top: 0; bottom: 0; width: 1px; transform-origin: 50% 100%; }   /* the cut plane */
.duo__line--base { left: 0; right: 0; bottom: 0; height: 1px; transform-origin: 0 50%; }
/* No stronger line across the middle of the frame: a lone horizontal rule in an instrument frame reads as a
   flat trace. The collision plane is one more grid row, at grid weight, and the label sits on it. */

.duo__wait {
  /* centred on the collision plane without a transform, so the patch never lands on a half pixel */
  position: absolute; z-index: 1; top: 0; bottom: 0; left: clamp(18px, 9%, 34px);
  height: max-content; margin-block: auto;
  width: max-content; max-width: calc(100% - 28px);
  padding: 4px 10px; background: var(--night-0);
  font-family: var(--font-mono); font-size: 0.8125rem; line-height: 1.5; letter-spacing: var(--tr-mono);
  color: var(--text-2);
}

/* a narrow frame sets the label on two lines, so its patch hugs the words */
@container (max-width: 270px) {
  .duo__wait { padding: 3px 8px; left: 14px; }
  .duo__wait > span { display: block; }
}

/* The scan: one hairline crossing the empty half from the cut plane outward, once. */
.duo__scan { position: absolute; inset: 0; pointer-events: none; opacity: 0; }
.duo__scan::before {
  content: ""; position: absolute; top: 0; bottom: 0; left: 0; width: 1px;
  background: rgba(246, 244, 239, 0.7);
}
.duo__scan::after {
  content: ""; position: absolute; top: 0; bottom: 0; right: 100%; width: 26%;
  background: linear-gradient(90deg, rgba(246, 244, 239, 0), rgba(246, 244, 239, 0.05));
}

/* Captions: one under each half; the second starts on the cut plane. */
.duo__caps { display: grid; grid-template-columns: 1fr 1fr; margin-top: 18px; }
.duo__cap { padding-right: clamp(12px, 2vw, 28px); }
.duo__cap + .duo__cap { padding-right: 0; }
/* inline, not flex, so a narrow caption wraps word by word and never strands the middle dot */
.duo__cap .cap__line { display: block; }
.duo__cap .cap__line > :first-child { margin-right: 0.6ch; }
/* the status after the dot is one unit: a narrow caption breaks after "Simulation ·", never inside the status */
.duo__cap .cap__line > :last-child { display: inline-block; }
.duo__cap .cap__text { margin-top: 6px; max-width: 34ch; }
/* plain mono, deliberately not the honesty-tag weight: nothing on this side is labelled as data */
.duo__label { white-space: nowrap; color: var(--text-3); }
.cap__line > .duo__label::after { content: "\00a0\00b7"; }

/* ---------- Arrival ----------------------------------------------------------- */
@media (prefers-reduced-motion: no-preference) {
  .tst__copy > * { animation: tstIn var(--t-fade) var(--ease-out) both; }
  .tst__copy > :nth-child(2) { animation-delay: 70ms; }
  .tst__copy > :nth-child(3) { animation-delay: 140ms; }
  .tst__copy > :nth-child(4) { animation-delay: 210ms; }

  /* about 2.7 s end to end, so the frame's label has landed before a visitor has finished the headline */
  html.js .duo__sim { animation: tstFade 900ms var(--ease-std) 120ms both; }
  html.js .duo__line--axis { animation: tstDrawY 900ms var(--ease-out) 280ms both; }
  html.js .duo__line--base { animation: tstDrawX 900ms var(--ease-out) 440ms both; }
  html.js .duo__marks path { animation: tstFade 600ms var(--ease-std) 640ms both; }
  html.js .duo__marks .duo__corner, html.js .duo__marks .duo__edge { animation-delay: 760ms; }
  html.js .duo__marks .duo__grid { animation-duration: 900ms; animation-delay: 860ms; }
  html.js .duo__scan { animation: tstScan 1500ms cubic-bezier(0.45, 0, 0.25, 1) 1050ms both; }
  html.js .duo__wait { animation: tstFade 600ms var(--ease-std) 2100ms both; }
}
@keyframes tstIn { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
@keyframes tstFade { from { opacity: 0; } to { opacity: 1; } }
@keyframes tstDrawY { from { transform: scaleY(0); } to { transform: none; } }
@keyframes tstDrawX { from { transform: scaleX(0); } to { transform: none; } }
@keyframes tstScan {
  0%   { transform: translateX(0); opacity: 0; }
  10%  { opacity: 1; }
  82%  { opacity: 1; }
  100% { transform: translateX(100%); opacity: 0; }
}

/* ---------- Breakpoints ------------------------------------------------------ */
@media (max-width: 1079px) {
  .tst { min-height: 0; align-content: start; padding-block: clamp(36px, 6vw, 64px) clamp(56px, 8vw, 96px); }
  .tst__copy, .tst__fig { grid-column: 1 / -1; }
  .tst__fig { justify-self: end; }   /* copy top left, the stage below it on the right: the desktop diagonal, stacked */
  .duo { width: min(100%, 600px); }
}
@media (max-width: 819px) {
  .duo { width: 100%; }
}
@media (max-width: 559px) {
  .duo__caps { grid-template-columns: 1fr; row-gap: 14px; }
  .duo__cap .cap__text { max-width: 60ch; }
  .duo__wait { font-size: 0.75rem; left: 12px; max-width: calc(100% - 16px); }
}

@media (forced-colors: active) {
  .duo__line, .duo__scan::before { background: CanvasText; }
  .duo__marks path { stroke: CanvasText; }
  .duo__marks .duo__grid { stroke: GrayText; }   /* the grid stays quieter than the frame */
  .duo__scan::after { display: none; }
}
@media print {
  .duo__scan { display: none; }
}

/* Short page on very tall screens: the footer sits on the bottom edge, the night fills the rest. */
body.page-testing { display: flex; flex-direction: column; min-height: 100vh; min-height: 100svh; }
body.page-testing > main { flex: 1 0 auto; }
