/* =============================================================================
 * wizard.css — the evaluation wizard's own layout and screens
 * =============================================================================
 * Load order: tokens.css -> base.css -> components.css -> wizard.css.
 * Document defaults (box-sizing, body font, focus ring, reduced-motion reset) live
 * in base.css; this file is only what is specific to the wizard.
 *
 * Every value is a design-system token or an [OURS] token from tokens.css — no raw
 * hex here (tokens.test.js enforces it). Transparency is color-mix() over a token.
 *
 * Two surfaces: a white action column (what to do) and a navy stage (the evidence
 * that it worked). The column is the only part that scrolls; the stage stays put.
 * ========================================================================== */

/* --- Frame --------------------------------------------------------------- */
.wz {
  display: grid;
  /* The stage takes the larger share: its browser is where the evaluator acts. */
  grid-template-columns: minmax(420px, 38%) 1fr;
  height: 100vh;
  height: 100dvh;
  color: var(--c-neutral-body);
  font-size: var(--fs-text-sm);
  line-height: var(--lh-text-sm);
}
.col {
  display: flex;
  flex-direction: column;
  min-width: 0;
  overflow-y: auto;
  padding: var(--sp-md) var(--sp-lg) 0;
}
/* The foot's breathing room is a spacer that scrolls with the content, not bottom padding:
 * Chrome sticks the Back/Next bar above the scroller's padding, and the pane would show
 * through that strip under the bar. */
.col::after { content: ""; flex: 0 0 var(--sp-sm); }
.col > * { width: 100%; max-width: 520px; }
/* Ready and Expiry (one wide Start button): the intro and its button sit together in the
 * middle of the column instead of the button waiting at the foot. */
.col:has(> .actions.is-start) > .pane { flex: 0 0 auto; margin-top: auto; }
.col:has(> .actions.is-start) > .actions { margin-bottom: auto; padding-top: var(--sp-xs); }
.col-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 36px; }
/* Official logo from openvpn.net (assets/ovpn-logo.svg, 132x38). */
.logo { display: block; height: 28px; width: auto; }

/* Progress dots: done = navy, current = orange pill, future = light. */
.dots { display: flex; gap: 6px; align-items: center; margin: 0; padding: 0; list-style: none; }
.dots[hidden] { display: none; }
.dots li {
  width: 7px; height: 7px; border-radius: var(--radius-pill); background: var(--c-neutral-light);
  transition: width var(--dur-base) var(--ease-out), background-color var(--dur-base) var(--ease-out);
}
.dots li.is-done { background: var(--c-brand-blueActive); }
.dots li.is-current { width: 18px; background: var(--c-brand-orange); }

/* Step change: the pane leaves 16px towards where it came from and the next one enters
 * from the other side. Back mirrors it. `data-enter` is the start position, applied
 * with no transition, then removed so the transition carries it home. */
.pane { flex: 1; transition: opacity var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out); }
.pane[data-leave="forward"] { opacity: 0; transform: translateX(-16px); }
.pane[data-leave="back"]    { opacity: 0; transform: translateX(16px); }
.pane[data-enter="forward"] { opacity: 0; transform: translateX(16px); transition: none; }
.pane[data-enter="back"]    { opacity: 0; transform: translateX(-16px); transition: none; }

/* Kicker in the orange family, but the darkest step: --c-brand-orangeActive is 3.78:1 on
 * white, under AA for 14px text; --c-expected-fg clears it. */
.kicker { margin: 0 0 4px; font-size: var(--fs-text-sm); font-weight: var(--fw-semi-bold); color: var(--c-expected-fg); }
.step-title { margin: 0 0 8px; font-size: 26px; line-height: 34px; font-weight: 700; letter-spacing: -.01em; color: var(--c-neutral-title); }
/* Takes focus after Start, so the next Tab starts from the new step; not a control, no ring. */
.step-title:focus { outline: none; box-shadow: none; }
.lede { margin: 0 0 20px; font-size: 15px; line-height: 23px; color: var(--c-neutral-subtitle); }
.lede strong { color: var(--c-neutral-title); font-weight: var(--fw-semi-bold); }

/* --- Knowledge card: one per step, between the lede and the tasks ---------- */
.kcard { display: grid; grid-template-columns: 28px 1fr; gap: 12px; margin: 0 0 20px; padding: 12px 14px;
  background: var(--c-info-tint); border: 1px solid var(--c-info-light); border-radius: var(--radius-md); }
.kcard-icon { width: 28px; height: 28px; display: grid; place-items: center; border-radius: var(--radius-sm);
  background: var(--c-neutral-white); color: var(--c-primary-base); font-weight: 700; font-size: 13px; }
.kcard-title { margin: 0; color: var(--c-neutral-title); font-weight: var(--fw-semi-bold); }
.kcard-body { margin: 2px 0 0; color: var(--c-neutral-body); }
.kcard a, .col a { color: var(--c-primary-base); font-weight: var(--fw-medium); text-decoration: none; }
/* New-tab arrow: sized off the text so it tracks every font size it sits next to, and
   sitting on the baseline at cap height so it reads as part of the word, not a superscript. */
.ext-icon { display: inline-block; width: 0.7em; height: 0.7em; margin-left: 0.25em;
  vertical-align: 0; flex: none; }
.col a:hover { text-decoration: underline; }

/* --- Prereq: what to have before the tasks (warm like the active task, no ring) --- */
.prereq { display: grid; grid-template-columns: 24px 1fr; gap: 12px; margin: 0 -14px 8px; padding: 12px 14px;
  background: var(--c-active-tint); border-radius: var(--radius-md); }
.prereq-icon svg { width: 20px; height: 20px; margin-top: 2px; color: var(--c-brand-orange); }
.prereq-title { margin: 1px 0 0; font-size: 15px; line-height: 22px; font-weight: var(--fw-semi-bold); color: var(--c-neutral-title); }
.prereq-body { margin: 4px 0 10px; color: var(--c-neutral-body); }

/* --- Banner: full tunnel only, while connected ----------------------------- */
.banner { display: grid; grid-template-columns: 20px 1fr; gap: 10px; margin: 0 0 20px; padding: 10px 14px;
  background: var(--c-expected-bg); color: var(--c-expected-fg); border-radius: var(--radius-md); }
.banner[hidden] { display: none; }
.banner svg { width: 18px; height: 18px; margin-top: 1px; }
.banner strong { font-weight: var(--fw-semi-bold); }

/* --- Caution: a consequence to know before starting (full tunnel), always on --- */
.caution { display: grid; grid-template-columns: 20px 1fr; gap: 10px; margin: 0 0 20px; padding: 12px 14px;
  background: var(--c-expected-bg); color: var(--c-expected-fg); border-radius: var(--radius-md);
  border-left: 3px solid var(--c-expected-fg); }
.caution svg { width: 18px; height: 18px; margin-top: 2px; }
.caution-title { margin: 0; font-weight: var(--fw-semi-bold); }
.caution-body { margin: 2px 0 0; }

/* --- Tasks -------------------------------------------------------------------
 * One attribute drives a task: data-state = future | active | done. Only the active
 * task is open; a done task collapses to its done wording and, where it has one, a
 * one-line result. The recap on Done reuses the same ring, hence :is(.task, .recap li). */
.tasks { list-style: none; margin: 0; padding: 0; }
.task { display: grid; grid-template-columns: 24px 1fr; gap: 12px; padding: 12px 14px; margin: 0 -14px;
  border-radius: var(--radius-md); transition: background-color var(--dur-base) var(--ease-out); }
.task[data-state="active"] { background: var(--c-active-tint); }
.task-main { min-width: 0; }
.task-title { margin: 1px 0 0; font-size: 15px; line-height: 22px; font-weight: var(--fw-medium);
  color: var(--c-neutral-placeholder); transition: color var(--dur-base); }
.task[data-state="active"] .task-title { color: var(--c-neutral-title); font-weight: var(--fw-semi-bold); }
.task[data-state="done"] .task-title { color: var(--c-neutral-subtitle); }

/* Ring: five layers in one SVG. Future is a still dashed circle; active spins it orange
 * with a pulsing halo (the only ambient loop); done draws a green circle, fills it, then
 * draws the tick — each phase starting as the previous one ends. */
.ring { width: 22px; height: 22px; margin-top: 1px; overflow: visible; }
.ring-dash { fill: none; stroke: var(--c-neutral-border); stroke-width: 2; stroke-dasharray: 4 3.2;
  transform-origin: 12px 12px; transition: stroke var(--dur-base) var(--ease-out), opacity var(--dur-fast); }
.ring-halo { fill: none; stroke: var(--c-brand-orange); stroke-opacity: .25; stroke-width: 6; opacity: 0;
  transition: opacity var(--dur-base); }
.ring-draw { fill: none; stroke: var(--c-success-base); stroke-width: 2; stroke-dasharray: 63; stroke-dashoffset: 63;
  transform: rotate(-90deg); transform-origin: 12px 12px; }
.ring-fill { fill: var(--c-success-base); transform: scale(0); transform-origin: 12px 12px; }
.ring-tick { fill: none; stroke: var(--c-neutral-white); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round;
  stroke-dasharray: 14; stroke-dashoffset: 14; }
:is(.task, .recap li)[data-state="active"] .ring-dash { stroke: var(--c-brand-orange); animation: spin var(--dur-ambient) linear infinite; }
:is(.task, .recap li)[data-state="active"] .ring-halo { opacity: 1; animation: halo 2.4s ease-in-out infinite; }
:is(.task, .recap li)[data-state="done"] .ring-dash,
:is(.task, .recap li)[data-state="done"] .ring-halo { opacity: 0; animation: none; }
:is(.task, .recap li)[data-state="done"] .ring-draw { transition: stroke-dashoffset var(--dur-slow) var(--ease-out); stroke-dashoffset: 0; }
:is(.task, .recap li)[data-state="done"] .ring-fill { transition: transform var(--dur-base) var(--ease-out) var(--dur-slow); transform: scale(1); }
:is(.task, .recap li)[data-state="done"] .ring-tick {
  transition: stroke-dashoffset var(--dur-fast) var(--ease-out) calc(var(--dur-slow) + var(--dur-base)); stroke-dashoffset: 0; }
@keyframes halo { 50% { opacity: .35; } }

/* Arriving on a step (Next, Back, resume): states land without replaying. */
:is(.tasks, .recap).is-instant *, :is(.tasks, .recap).is-instant *::before, :is(.tasks, .recap).is-instant *::after {
  transition: none !important; }

/* Height animation without measuring: a one-row grid going 0fr -> 1fr. */
.collapse { display: grid; grid-template-rows: 0fr; transition: grid-template-rows var(--dur-base) var(--ease-in-out); }
.collapse-inner { overflow: hidden; min-height: 0; }
.task[data-state="active"] > .task-main > .collapse[data-body] { grid-template-rows: 1fr; }
/* A task whose body is still needed after it closes (the admin credentials) stays open. */
.task[data-state="done"] > .task-main > .collapse[data-body][data-keep-open] { grid-template-rows: 1fr; }
.task[data-state="done"] > .task-main > .collapse[data-body][data-keep-open] > .collapse-inner { visibility: visible; transition: none; }
/* Collapsed content stays out of the tab order and the accessibility tree. */
.task:not([data-state="active"]) > .task-main > .collapse[data-body] > .collapse-inner { visibility: hidden;
  transition: visibility 0s linear var(--dur-base); }
/* Result rows open once their task is reached, and stay open after it closes. */
.task:not([data-state="future"]) > .task-main > .collapse[data-rows] { grid-template-rows: 1fr; }
.task[data-state="future"] > .task-main > .collapse[data-rows] > .collapse-inner { visibility: hidden;
  transition: visibility 0s linear var(--dur-base); }
.task-how { margin: 4px 0 10px; color: var(--c-neutral-body); }
.task-how strong { color: var(--c-neutral-title); }
.task-chips { display: flex; flex-wrap: wrap; gap: 12px; margin: 0 0 10px; }
.task-chips:empty { display: none; }
/* The action leads (Open Admin, then sign in with these): space before the fields it opens onto. */
.task-action + .task-chips { margin-top: 12px; }
.task-action { display: inline-flex; align-items: center; min-height: 32px; margin: 0 0 4px; padding: 6px 12px;
  border-radius: var(--radius-sm); background: var(--c-brand-blue); color: var(--c-neutral-white) !important;
  font-size: 13px; font-weight: var(--fw-semi-bold); text-decoration: none !important; }
.task-action:hover { background: var(--c-brand-blueHover); }
/* The step's first need (Open Admin Web UI): full-size orange until the click closes its
 * task, then the quiet blue of every other action. Text on orange is always the title ink. */
.task[data-state="active"] .task-action.is-primary { min-height: 40px; padding: 9px 16px; font-size: var(--fs-text-sm);
  background: var(--c-brand-orange); color: var(--c-neutral-title) !important; }
.task[data-state="active"] .task-action.is-primary:hover { background: var(--c-brand-orangeHover); }
.task-action:focus-visible { box-shadow: var(--o-primary); outline: none; }
.task-hint { margin: 8px 0 0; padding: 8px 10px; border-radius: var(--radius-sm);
  background: var(--c-expected-bg); color: var(--c-expected-fg); font-size: 13px; }
.task-help { margin: 8px 0 0; font-size: 13px; color: var(--c-neutral-subtitle);
  animation: fade-in var(--dur-base) var(--ease-out); }
.task-help[hidden], .task-hint[hidden], .task-result[hidden] { display: none; }
@keyframes fade-in { from { opacity: 0; } }
.waiting { display: flex; align-items: center; gap: 8px; margin: 10px 0 2px; font-size: 13px; color: var(--c-neutral-subtitle); }
.waiting-dot { width: 6px; height: 6px; border-radius: var(--radius-full); background: var(--c-brand-orange);
  animation: blink 1.4s ease-in-out infinite; }
@keyframes blink { 50% { opacity: .25; } }
.task-result { margin: 4px 0 0; font-size: 13px; color: var(--c-neutral-subtitle); }
.task-result strong { font-weight: var(--fw-semi-bold); color: var(--c-neutral-title); }
.task-result strong[data-tone="success"] { color: var(--c-success-baseActive); }
.task-result strong[data-tone="expected"] { color: var(--c-expected-fg); }
.task-reimport { display: none; margin-top: 4px; font-size: 13px; }
.task[data-state="done"] .task-reimport { display: inline-block; }

/* Credential chip: the value, and a Copy button that reads "Copied ✓" for 1.5s. */
.chip { display: inline-flex; align-items: center; gap: 8px; padding: 4px 4px 4px 10px; background: var(--c-neutral-white);
  border: 1px solid var(--c-neutral-light); border-radius: var(--radius-sm); color: var(--c-neutral-title);
  font-weight: var(--fw-medium); font-variant-numeric: tabular-nums; }
.chip-copy { min-width: 72px; padding: 2px 8px; font: inherit; font-size: var(--fs-text-xs); cursor: pointer;
  background: var(--c-neutral-bg); border: 1px solid var(--c-neutral-light); border-radius: var(--radius-sm);
  color: var(--c-primary-base); transition: color var(--dur-fast), background-color var(--dur-fast), border-color var(--dur-fast); }
.chip-copy.is-copied { color: var(--c-success-baseActive); background: var(--c-success-tint); border-color: var(--c-success-light); }

/* A credential with its label above it: what the value is, before what to do with it. */
.field { display: inline-flex; flex-direction: column; align-items: flex-start; gap: 4px; }
.field-label { font-size: var(--fs-text-xs); line-height: 16px; font-weight: var(--fw-semi-bold); color: var(--c-neutral-subtitle); }
.fields { display: flex; flex-wrap: wrap; gap: 12px; margin: 8px 0 0; }

/* Result row: "Expected: …" first, the observed result slides in over it. Rows open when
 * their task is reached, before the result, so the evaluator knows what to look for. The
 * knowledge pill under it says why, and stays once the result lands. */
.result-rows { list-style: none; margin: 6px 0 0; padding: 0; }
.result-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 4px 12px; padding: 8px 0;
  font-size: 13px; border-bottom: 1px solid var(--c-neutral-light); }
/* --c-neutral-subtitle on --c-info-tint: 7.1:1. */
.kpill { grid-column: 1 / -1; justify-self: start; padding: 1px 8px; border-radius: var(--radius-pill);
  background: var(--c-info-tint); color: var(--c-neutral-subtitle); font-size: var(--fs-text-xs); line-height: 18px; }
.result-row:last-child { border-bottom: 0; }
.result-value { position: relative; min-width: 150px; height: 18px; text-align: right; font-variant-numeric: tabular-nums; }
.result-value > span { position: absolute; right: 0; top: 0; white-space: nowrap;
  transition: opacity var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out); }
.result-expected { color: var(--c-neutral-placeholder); font-size: var(--fs-text-xs); }
.result-got { opacity: 0; transform: translateY(6px); font-size: var(--fs-text-xs); font-weight: var(--fw-semi-bold);
  color: var(--c-neutral-title); }
.result-got[data-tone="success"] { color: var(--c-success-baseActive); }
.result-got[data-tone="expected"] { color: var(--c-expected-fg); }
.result-value[data-phase="checking"] .result-expected { color: transparent; border-radius: var(--radius-sm);
  background: linear-gradient(90deg, var(--c-neutral-bgHover) 0%, var(--c-neutral-white) 50%, var(--c-neutral-bgHover) 100%);
  background-size: 200% 100%; animation: shimmer 1.1s linear infinite; }
.result-value[data-phase="landed"] .result-expected { opacity: 0; transform: translateY(-6px); }
.result-value[data-phase="landed"] .result-got { opacity: 1; transform: none; }
@keyframes shimmer { to { background-position: -200% 0; } }

/* Why? — invisible while its task is still ahead; appears once the task is reached (the
 * explanation helps while waiting on the result, too) and stays after it closes. */
.why { margin-top: 10px; padding: 0; border: 0; background: none; cursor: pointer; font: inherit; font-size: 13px;
  font-weight: var(--fw-medium); color: var(--c-primary-base); visibility: hidden; opacity: 0;
  transition: opacity var(--dur-base) var(--ease-out), visibility 0s linear var(--dur-base); }
.task:not([data-state="future"]) .why { visibility: visible; opacity: 1; transition: opacity var(--dur-base) var(--ease-out) var(--dur-base); }
.why-caret { display: inline-block; transition: transform var(--dur-base) var(--ease-out); }
.why[aria-expanded="true"] .why-caret { transform: rotate(90deg); }
/* Open only while its task is reached: a task that goes back to future never keeps it open. */
.task:not([data-state="future"]) .why[aria-expanded="true"] + .why-collapse { grid-template-rows: 1fr; }
.why-collapse > .collapse-inner { visibility: hidden; transition: visibility 0s linear var(--dur-base); }
.task:not([data-state="future"]) .why[aria-expanded="true"] + .why-collapse > .collapse-inner { visibility: visible; transition: none; }
/* Opening one scrolls it into view (render-column.js): clear of the sticky Next below. */
.why-collapse, .optional-body, .task { scroll-margin: 16px 0 128px; }
.why-body { padding-top: 6px; font-size: 13px; color: var(--c-neutral-body); }
/* The diagram inside Why?: a thumbnail that opens full size. */
.why-figure { display: block; width: 100%; margin: 0 0 12px; padding: 8px; cursor: zoom-in; font: inherit;
  background: var(--c-neutral-white); border: 1px solid var(--c-neutral-light); border-radius: var(--radius-md);
  transition: border-color var(--dur-fast); }
.why-figure:hover { border-color: var(--c-primary-base); }
.why-figure img { display: block; width: 100%; height: auto; }
.why-figure-hint { display: block; margin-top: 6px; font-size: var(--fs-text-xs); font-weight: var(--fw-medium);
  color: var(--c-primary-base); text-align: left; }
.why-list { margin: 0; }
.why-list dt { font-weight: var(--fw-semi-bold); color: var(--c-neutral-title); }
.why-list dd { margin: 0 0 8px; }
.why-note { margin: 0; }

/* Optional section (split: Client Web UI) */
.optional { margin-top: 12px; font-size: 13px; color: var(--c-neutral-subtitle); }
.optional summary { cursor: pointer; color: var(--c-primary-base); font-weight: var(--fw-medium); }
.optional-body > p { margin: 8px 0 0; }

/* Recap (Done) */
.recap { list-style: none; margin: 0 0 16px; padding: 0; }
/* Only what the session saw gets a tick; the rest keeps a still, neutral dashed ring. */
.recap li { display: grid; grid-template-columns: 24px 1fr; gap: 12px; padding: 8px 0; color: var(--c-neutral-title);
  border-bottom: 1px solid var(--c-neutral-light); }
.recap li:last-child { border-bottom: 0; }
.recap li[data-state="future"] { color: var(--c-neutral-subtitle); }
.footnote { margin: 0; font-size: var(--fs-text-xs); line-height: var(--lh-text-xs); color: var(--c-neutral-placeholder); }

/* --- Ready: facts, numbered preview, Start button --------------------------- */
.facts { list-style: none; margin: 0 0 20px; padding: 0; display: grid; gap: 12px; }
.facts li { display: grid; grid-template-columns: 20px 1fr; gap: 10px; color: var(--c-neutral-body); }
.facts strong { color: var(--c-neutral-title); font-weight: var(--fw-semi-bold); }
.facts svg { width: 18px; height: 18px; color: var(--c-primary-base); margin-top: 1px; }
/* Assigning: what's being set up steps back while the button carries the wait. */
:is(.facts, .preview) { transition: opacity var(--dur-base) var(--ease-out); }
.pane.is-assigning :is(.facts, .preview) { opacity: .6; }
/* Dashed numbers: this is a real sequence, and none of it has started yet. */
.preview { list-style: none; margin: 0; padding: 0; display: grid; gap: 10px; counter-reset: p; }
.preview li { display: grid; grid-template-columns: 24px 1fr; gap: 12px; align-items: center; counter-increment: p; }
.preview li::before { content: counter(p); width: 22px; height: 22px; display: grid; place-items: center;
  border: 1.5px dashed var(--c-neutral-border); border-radius: var(--radius-full);
  font-size: var(--fs-text-xs); font-weight: var(--fw-semi-bold); color: var(--c-neutral-placeholder); }
.preview strong { color: var(--c-neutral-title); font-weight: var(--fw-semi-bold); }

/* The Start button is its own progress indicator while /try-now runs: amber, a spinner,
 * and a 3px bar that creeps along the bottom. The bar is not real progress — it only
 * never stops, so a multi-second assignment doesn't read as a hang. */
.start-btn { position: relative; overflow: hidden; width: 100%; min-height: 44px; padding: 10px 16px;
  display: inline-flex; align-items: center; justify-content: center; gap: 10px; cursor: pointer;
  font: inherit; font-size: var(--fs-text-md); font-weight: var(--fw-semi-bold);
  background: var(--c-brand-orange); color: var(--c-neutral-title); border: 1px solid var(--c-brand-orange);
  border-radius: var(--radius-sm); transition: background-color var(--dur-base) var(--ease-out); }
.start-btn:hover:not(.is-busy) { background: var(--c-brand-orangeHover); }
.start-btn.is-busy { cursor: progress; background: var(--c-expected-bg); border-color: var(--c-expected-bg);
  color: var(--c-expected-fg); font-size: var(--fs-text-sm); }
.start-btn .spinner { display: none; width: 14px; height: 14px; border-radius: var(--radius-full);
  border: 2px solid color-mix(in srgb, var(--c-expected-fg) 25%, transparent); border-top-color: var(--c-expected-fg);
  animation: spin 0.8s linear infinite; }
.start-btn.is-busy .spinner { display: block; }
.start-btn .bar { position: absolute; left: 0; bottom: 0; height: 3px; width: 0; background: var(--c-brand-orange); }
.start-btn.is-busy .bar { animation: start-bar 24s cubic-bezier(.1, .7, .2, 1) forwards; }
@keyframes start-bar { to { width: 92%; } }
@keyframes spin { to { transform: rotate(360deg); } }
.start-note { margin: 8px 0 0; text-align: center; font-size: var(--fs-text-xs); color: var(--c-neutral-placeholder); }
.alert { margin: 0 0 12px; color: var(--c-warning-base); font-weight: var(--fw-medium); }

/* --- Waiting room: Start found every server leased --------------------------
 * Not an error, so no red and no alert: the knowledge card's calm info tint, with the
 * "waiting" dot tasks already use as its only loop. Stop Waiting is the quiet way out. */
.queue { margin: 0 0 12px; padding: 14px 16px; background: var(--c-info-tint);
  border: 1px solid var(--c-info-light); border-radius: var(--radius-md);
  animation: fade-in var(--dur-base) var(--ease-out); }
.queue-title { margin: 0; color: var(--c-neutral-title); font-weight: var(--fw-semi-bold); outline: none; }
.queue-body { margin: 4px 0 0; color: var(--c-neutral-body); }
.queue-eta { margin: 8px 0 0; font-size: 13px; color: var(--c-neutral-subtitle); font-variant-numeric: tabular-nums; }
.queue .waiting { margin: 6px 0 0; }
.queue-notify { margin: 12px 0 0; }
.queue-notify[hidden], .queue-notify > [hidden] { display: none; }
.queue-notify-btn { font-size: 13px; }
.queue-notify-note { margin: 0; font-size: 13px; color: var(--c-neutral-subtitle); }
.queue-cancel { width: 100%; min-height: 44px; }

/* --- Actions: Back (ghost) + a wide Next ------------------------------------
 * Next is always clickable. It stays dim until the step's tasks close, then lights up
 * with one glow — never a repeating pulse. */
.actions { display: flex; gap: 8px; padding-top: 16px; transition: opacity var(--dur-base) var(--ease-out); }
/* Next stays in view while the column scrolls (an open Why? makes it long): stuck to the
 * foot of the column, with a short fade so the text scrolling under it doesn't cut hard. */
.actions:not(.is-start) { position: sticky; bottom: 0; z-index: 2; padding-bottom: 12px; background: var(--c-neutral-white); }
.actions:not(.is-start)::before { content: ""; position: absolute; left: 0; right: 0; bottom: 100%; height: 24px; pointer-events: none;
  background: linear-gradient(to bottom, color-mix(in srgb, var(--c-neutral-white) 0%, transparent), var(--c-neutral-white)); }
/* The fade only belongs over text in motion: at rest the pane's last line (the Optional
 * summary) would sit washed out under it, so the pane ends one fade-height above Next. */
.col:has(> .actions:not(.is-start)) > .pane { padding-bottom: 24px; }
.actions.is-leaving { opacity: 0; }
/* Ready and Expiry: one wide button with its note underneath instead of Back/Next. */
.actions.is-start { flex-direction: column; gap: 0; }
.actions[hidden] { display: none; }
/* .ovpn-btn sets display, which would otherwise beat the hidden attribute. */
.actions > [hidden] { display: none; }
.actions .ovpn-btn { font-size: var(--fs-text-sm); line-height: var(--lh-text-sm); font-weight: var(--fw-semi-bold); }
.next-btn {
  flex: 1; min-height: 40px; padding: 9px 16px; border-radius: var(--radius-sm); cursor: pointer;
  font: inherit; font-size: var(--fs-text-sm); font-weight: var(--fw-semi-bold);
  background: var(--c-neutral-bg); color: var(--c-neutral-placeholder); border: 1px solid var(--c-neutral-light);
  transition: background-color var(--dur-base) var(--ease-out), color var(--dur-base), border-color var(--dur-base);
}
.next-btn:hover { border-color: var(--c-neutral-border); }
.next-btn.is-ready {
  background: var(--c-brand-orange); color: var(--c-neutral-title); border-color: var(--c-brand-orange);
  animation: next-glow 1.2s var(--ease-out) 1;
}
.next-btn.is-settled { animation: none; }
.next-btn.is-ready:hover { background: var(--c-brand-orangeHover); border-color: var(--c-brand-orangeHover); }
@keyframes next-glow {
  0%   { box-shadow: 0 0 0 0 color-mix(in srgb, var(--c-brand-orange) 55%, transparent); }
  100% { box-shadow: 0 0 0 10px color-mix(in srgb, var(--c-brand-orange) 0%, transparent); }
}
.col-foot { display: flex; justify-content: space-between; gap: 16px; padding-top: 16px;
  font-size: var(--fs-text-xs); line-height: var(--lh-text-xs); color: var(--c-neutral-placeholder); }
.col-foot[hidden] { display: none; }
.col-foot button { all: unset; cursor: pointer; color: var(--c-primary-base); font-weight: var(--fw-medium); }
.col-foot button:focus-visible { box-shadow: var(--o-primary); border-radius: var(--radius-sm); }

/* --- Stage --------------------------------------------------------------- */
.stage {
  position: sticky; top: 0; height: 100vh; height: 100dvh; overflow: hidden;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 16px; padding: var(--sp-lg);
  background: var(--c-brand-blueActive); color: var(--c-stage-ink);
}
.stage::before { content: ""; position: absolute; inset: 0; opacity: .5; pointer-events: none;
  background-image: radial-gradient(circle at 1px 1px, color-mix(in srgb, var(--c-primary-light) 22%, transparent) 1px, transparent 0);
  background-size: 22px 22px; }
.stage-body { position: relative; z-index: 1; width: 100%; max-width: 820px;
  display: flex; flex-direction: column; align-items: center; gap: 16px;
  transition: opacity var(--dur-base) var(--ease-out); }
/* Step change: the stage fades out with the leaving column and back in with the next. */
.stage.is-leaving :is(.stage-body, .stage-caption) { opacity: 0; }
.countdown { position: absolute; top: 20px; right: 24px; z-index: 2; margin: 0; padding: 4px 10px;
  border-radius: var(--radius-pill); font-size: var(--fs-text-xs); font-variant-numeric: tabular-nums;
  color: var(--c-stage-ink); background: color-mix(in srgb, var(--c-neutral-white) 8%, transparent);
  border: 1px solid color-mix(in srgb, var(--c-neutral-white) 12%, transparent); }
.countdown[hidden] { display: none; }
.countdown b { color: var(--c-neutral-white); font-weight: var(--fw-semi-bold); }
.countdown.amber { background: var(--c-expected-bg); color: var(--c-expected-fg); border-color: transparent; }
.countdown.amber b { color: var(--c-expected-fg); }
.countdown.red { background: var(--c-warning-light); color: var(--c-warning-base); border-color: transparent; }
.countdown.red b { color: var(--c-warning-base); }
/* Right padding keeps the caption clear of the Zendesk launcher, bottom-right. */
.stage-caption { position: absolute; left: var(--sp-lg); right: 96px; bottom: var(--sp-md); z-index: 1; margin: 0;
  max-width: 480px; font-size: 13px; line-height: 20px; color: var(--c-stage-ink);
  transition: opacity var(--dur-base) var(--ease-out); }
.stage-caption strong { color: var(--c-neutral-white); font-weight: var(--fw-semi-bold); }
.stage-caption a { color: var(--c-primary-light); font-weight: var(--fw-medium); text-decoration: none; white-space: nowrap; }
.stage-caption.is-swapping { opacity: 0; }
/* The one orchestrated loading moment: while /try-now runs, the figure breathes. On the
 * figure, not the stage body, so the body's fade on the way out isn't overridden. */
.stage.is-breathing .stage-figure { animation: stage-breathe 2.4s var(--ease-in-out) infinite; }
@keyframes stage-breathe { 50% { transform: scale(.985); opacity: .85; } }

/* --- Cue: the instruction above the evidence, only while the action is on the stage --- */
.stage-cue { width: 100%; animation: fade-in var(--dur-base) var(--ease-out); }
.stage-cue[data-shown="false"] { display: none; }
.stage-cue-title { margin: 0; font-size: 22px; line-height: 30px; font-weight: 700; letter-spacing: -.01em; color: var(--c-neutral-white); }
.stage-cue-body { margin: 4px 0 0; font-size: 15px; line-height: 22px; color: var(--c-stage-ink); }
.stage-cue-body strong { color: var(--c-neutral-white); font-weight: var(--fw-semi-bold); }
/* A new cue calls attention to the evidence once: an orange ring, three beats, then rest.
 * An outline, not a box-shadow, so it never replaces the surface's own shadow. */
.is-calling { animation: stage-call 1.6s var(--ease-out) 3; }
@keyframes stage-call {
  0%   { outline: 3px solid color-mix(in srgb, var(--c-brand-orange) 70%, transparent); outline-offset: 0; }
  100% { outline: 3px solid color-mix(in srgb, var(--c-brand-orange) 0%, transparent); outline-offset: 14px; }
}

/* Figure card (Ready stage) */
/* width: 100% because the SVG has no intrinsic size to shrink-wrap around. */
.stage-figure { width: 100%; margin: 0; padding: var(--sp-sm); background: var(--c-neutral-white);
  border-radius: var(--radius-lg); box-shadow: var(--sh-stage); }
.stage-figure img { display: block; width: 100%; height: auto; }
.stage-figure-btn { position: relative; display: block; width: 100%; padding: 0; border: 0; background: none;
  cursor: zoom-in; border-radius: var(--radius-md); }
.stage-figure-btn:focus-visible { box-shadow: var(--o-primary); outline: none; }
.stage-figure-hint { position: absolute; right: 8px; bottom: 8px; padding: 2px 10px; border-radius: var(--radius-pill);
  background: var(--c-neutral-bg); border: 1px solid var(--c-neutral-light); font-size: var(--fs-text-xs);
  font-weight: var(--fw-medium); color: var(--c-primary-base); opacity: 0; transition: opacity var(--dur-fast); }
.stage-figure-btn:hover .stage-figure-hint, .stage-figure-btn:focus-visible .stage-figure-hint { opacity: 1; }

/* --- Browser frame: the SaaS sign-in and the ZTNA tabs ----------------------
 * A browser drawn on the stage, so the evidence reads as "a page you opened". The chrome
 * carries the page's address, Retest (one turn of its icon per click) and a way out to a
 * real tab; the foot says what the page answered, as a pill. */
.browser { position: relative; width: 100%; overflow: hidden; background: var(--c-neutral-white);
  border-radius: var(--radius-lg); box-shadow: var(--sh-stage); color: var(--c-neutral-body); }
.browser-chrome { display: flex; align-items: center; gap: 10px; padding: 8px 12px;
  background: var(--c-neutral-white); border-bottom: 1px solid var(--c-neutral-light); }
.browser-lights { display: flex; gap: 5px; flex: none; }
.browser-lights i { width: 9px; height: 9px; border-radius: var(--radius-full); background: var(--c-neutral-light); }
.browser-url { flex: 1; min-width: 0; display: flex; align-items: center; gap: 6px; padding: 3px 12px;
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
  background: var(--c-neutral-bg); border: 1px solid var(--c-neutral-light); border-radius: var(--radius-pill);
  font-size: var(--fs-text-xs); line-height: 18px; color: var(--c-neutral-subtitle); font-variant-numeric: tabular-nums; }
.browser-lock { font-size: 10px; }
/* Says the page is live and yours to use, not a picture of one. --c-expected-fg on
 * --c-expected-bg: 5.77:1. */
.browser-badge { flex: none; display: inline-flex; align-items: center; gap: 6px; padding: 2px 10px;
  border-radius: var(--radius-pill); background: var(--c-expected-bg); color: var(--c-expected-fg);
  font-size: var(--fs-text-xs); line-height: 18px; font-weight: var(--fw-semi-bold); }
.browser-badge-dot { width: 6px; height: 6px; border-radius: var(--radius-full); background: var(--c-brand-orange); }
.browser-retest { flex: none; display: inline-flex; align-items: center; gap: 5px; padding: 3px 6px; cursor: pointer;
  font: inherit; font-size: var(--fs-text-xs); font-weight: var(--fw-medium); color: var(--c-neutral-subtitle);
  background: none; border: 0; border-radius: var(--radius-sm); transition: color var(--dur-fast); }
.browser-retest:hover { color: var(--c-primary-base); }
.browser-retest svg { width: 14px; height: 14px; }
.browser-retest.is-spinning svg { animation: spin var(--dur-slow) var(--ease-out) 1; }
.browser-open { flex: none; font-size: var(--fs-text-xs); font-weight: var(--fw-medium); white-space: nowrap;
  color: var(--c-primary-base); text-decoration: none; }
.browser-open:hover { text-decoration: underline; }
/* Fits the stage with the caption under it on a laptop screen. */
.browser-iframe { display: block; width: 100%; height: clamp(360px, calc(100dvh - 340px), 620px); border: 0;
  background: var(--c-neutral-white); }
.browser-foot { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 10px 16px;
  border-top: 1px solid var(--c-neutral-light); font-size: 13px; color: var(--c-neutral-subtitle); }

/* --- Pill: an expectation (dashed) until a result fills it -------------------- */
.pill { display: inline-block; margin: 0; padding: 2px 10px; white-space: nowrap;
  font-size: var(--fs-text-xs); line-height: 18px; font-weight: var(--fw-semi-bold);
  color: var(--c-neutral-placeholder); border: 1px dashed var(--c-neutral-placeholder); border-radius: var(--radius-pill);
  transition: all var(--dur-base) var(--ease-out); }
.pill[data-tone="expected"] { background: var(--c-expected-bg); color: var(--c-expected-fg); border: 1px solid transparent; }
.pill[data-tone="success"] { background: var(--c-success-tint); color: var(--c-success-baseActive); border: 1px solid transparent; }
.pill[data-tone="neutral"] { background: var(--c-neutral-bg); color: var(--c-neutral-subtitle); border: 1px solid var(--c-neutral-light); }
.pill[hidden] { display: none; }

/* --- Tabs (ZTNA): one browser, the same server by name and by IP --------------
 * Each tab carries a status dot, so the contrast survives switching between them. */
.browser-tabs { display: flex; align-items: flex-end; gap: 12px; padding: 8px 10px 0 14px; background: var(--c-browser-chrome); }
.browser-tabs .browser-lights { align-self: center; padding-bottom: 8px; }
.browser-tablist { display: flex; align-items: flex-end; gap: 2px; min-width: 0; }
.browser-tab { position: relative; display: flex; align-items: center; gap: 8px; max-width: 220px; min-width: 0; padding: 7px 12px;
  cursor: pointer; font: inherit; font-size: var(--fs-text-xs); color: var(--c-neutral-subtitle); font-variant-numeric: tabular-nums;
  background: none; border: 0; border-radius: var(--radius-md) var(--radius-md) 0 0;
  transition: background-color var(--dur-fast), color var(--dur-fast); }
.browser-tab:hover { color: var(--c-neutral-title); }
.browser-tab[aria-selected="true"] { background: var(--c-neutral-white); color: var(--c-neutral-title); font-weight: var(--fw-medium); }
.browser-tab:focus-visible { box-shadow: var(--o-primary-inset); outline: none; }
.tab-host { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; }
.tab-dot { flex: none; width: 8px; height: 8px; border-radius: var(--radius-full);
  box-shadow: inset 0 0 0 1px var(--c-neutral-border); transition: background-color var(--dur-base), box-shadow var(--dur-base); }
.tab-dot[data-tone="success"] { background: var(--c-success-base); box-shadow: none; }
/* The failure the lesson expects: the amber of the pill, not the brand's action orange. */
.tab-dot[data-tone="expected"] { background: var(--c-expected-fg); box-shadow: none; }
.tab-dot[data-tone="neutral"] { background: var(--c-neutral-border); box-shadow: none; }
/* The IP tab calls for a click. Held: a warm tint and a solid orange edge, until the click
 * (so it still stands out once the motion rests). Moving: an orange ring that swells and
 * fades, four times, then rests (the active task's ring is the page's only loop). */
.browser-tab.is-pulsing { background: var(--c-active-tint); color: var(--c-neutral-title); font-weight: var(--fw-semi-bold);
  box-shadow: inset 0 0 0 2px var(--c-brand-orange); }
.browser-tab.is-pulsing::after { content: ""; position: absolute; inset: 0; border-radius: var(--radius-md) var(--radius-md) 0 0;
  border: 3px solid var(--c-brand-orange); pointer-events: none;
  animation: tab-call 1.8s ease-out 4 forwards; }
@keyframes tab-call { 0% { opacity: 1; transform: scale(1); } 70%, 100% { opacity: 0; transform: scale(1.18); } }
.browser-panel[hidden] { display: none; }
.browser-panel:focus-visible { box-shadow: var(--o-primary-inset); outline: none; }
.browser-page { min-height: 280px; padding: 32px; }
.pill--wait[data-checking="true"] { color: transparent; border-color: transparent; background-size: 200% 100%;
  background-image: linear-gradient(90deg, var(--c-neutral-bgHover) 0%, var(--c-neutral-white) 50%, var(--c-neutral-bgHover) 100%);
  animation: shimmer 1.1s linear infinite; }
/* The check's answer, drawn as the page the browser would have shown. */
.site { opacity: 0; transform: scale(.98); transform-origin: top left;
  transition: opacity var(--dur-slow) var(--ease-out), transform var(--dur-slow) var(--ease-out); }
.site[hidden] { display: none; }
.site.is-shown { opacity: 1; transform: none; }
.site.is-instant { transition: none; }
.site-icon { display: none; width: 36px; height: 36px; margin-bottom: 12px; place-items: center;
  background: var(--c-neutral-bg); border: 1px solid var(--c-neutral-light); border-radius: var(--radius-md); color: var(--c-neutral-placeholder); }
.site-icon svg { width: 18px; height: 18px; }
.site.is-error .site-icon { display: grid; }
.site-title { margin: 0 0 6px; font-size: var(--fs-text-md); line-height: 24px; font-weight: var(--fw-semi-bold); color: var(--c-neutral-title); }
.site-body { margin: 0; font-size: 13px; color: var(--c-neutral-subtitle); }
/* A quiet invitation to check the drawing against a real tab: it arrives after the result,
   never pulses, and stays one line of small muted text. */
.site-compare { display: inline-block; margin-top: 20px; font-size: 13px; color: var(--c-neutral-placeholder);
  opacity: 0; transition: opacity var(--dur-slow) var(--ease-out) var(--dur-slow), color var(--dur-fast) var(--ease-out); }
.site.is-shown .site-compare { opacity: 1; }
.site.is-instant .site-compare { transition: none; }
.site-compare:hover, .site-compare:focus-visible { color: var(--c-primary-base); }

/* --- IP swap (full tunnel): your IP, struck out, and the exit IP rising in -----
 * The card and the SaaS browser are two views sharing one grid cell; both keep their
 * space so the stage never jumps, and they crossfade. */
.ip-views { display: grid; width: 100%; }
.ip-view { grid-area: 1 / 1; align-self: center; display: flex; flex-direction: column; align-items: flex-start; gap: 12px;
  opacity: 0; visibility: hidden; transition: opacity var(--dur-base) var(--ease-out), visibility 0s linear var(--dur-base); }
.ip-views[data-view="ip"] > [data-view-pane="ip"],
.ip-views[data-view="saas"] > [data-view-pane="saas"] { opacity: 1; visibility: visible; transition: opacity var(--dur-base) var(--ease-out); }
.ip-card { width: 100%; padding: 22px 24px 8px; background: var(--c-neutral-white); border-radius: var(--radius-lg);
  box-shadow: var(--sh-stage); color: var(--c-neutral-body); }
.ip-label { margin: 0 0 6px; font-size: var(--fs-text-xs); color: var(--c-neutral-subtitle); }
.ip-swap { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 12px; margin: 0 0 4px; min-height: 36px;
  font-variant-numeric: tabular-nums; }
.ip-before { font-size: var(--fs-text-md); color: var(--c-neutral-placeholder);
  text-decoration: line-through; text-decoration-color: color-mix(in srgb, var(--c-neutral-placeholder) 60%, transparent); }
.ip-before[hidden] { display: none; }
.ip-current { font-size: 28px; line-height: 36px; font-weight: 700; letter-spacing: -.01em; color: var(--c-neutral-title); }
.ip-current[data-empty="true"] { width: 180px; height: 28px; border-radius: var(--radius-sm); background-size: 200% 100%;
  background-image: linear-gradient(90deg, var(--c-neutral-bgHover) 0%, var(--c-neutral-white) 50%, var(--c-neutral-bgHover) 100%);
  animation: shimmer 1.1s linear infinite; }
.ip-current.is-rising { animation: ip-rise 500ms var(--ease-out) both; }
@keyframes ip-rise { from { opacity: 0; transform: translateY(8px); } }
.ip-note { display: flex; align-items: center; gap: 6px; margin: 0 0 14px; font-size: var(--fs-text-xs); color: var(--c-neutral-placeholder); }
.ip-note[data-switched="true"] { color: var(--c-success-baseActive); font-weight: var(--fw-semi-bold); }
.ip-note[data-switched="true"]::before { content: ""; width: 6px; height: 6px; border-radius: var(--radius-full); background: currentColor; }
.ip-dests { margin: 0; border-top: 1px solid var(--c-neutral-light); }
.ip-dests .result-row { padding: 9px 0; }
.row-link { padding: 0; border: 0; background: none; cursor: pointer; font: inherit; color: var(--c-primary-base); }
.row-link:hover { text-decoration: underline; }
/* Links on the navy: the stage's own voice, not a button. */
.stage-link { padding: 0; border: 0; background: none; cursor: pointer; font: inherit; font-size: 13px;
  font-weight: var(--fw-medium); color: var(--c-primary-light); }
.stage-link:hover { text-decoration: underline; }
.stage-link:focus-visible { box-shadow: var(--o-primary); border-radius: var(--radius-sm); outline: none; }

/* --- Link list (Admin): five places worth a look ----------------------------- */
.link-list { list-style: none; margin: 0; padding: 0; width: 100%; display: grid; gap: 10px;
  border-radius: var(--radius-md); }
/* The caption is anchored to the stage's foot, out of flow: reserve its height (two lines
 * and its bottom inset) so the fifth row never runs into it. */
.stage:has(.link-list) { padding-bottom: calc(var(--sp-md) + 40px + var(--sp-sm)); }
.link-anchor { display: grid; grid-template-columns: 24px minmax(0, 1fr) auto; gap: 14px; align-items: center; padding: 14px 18px;
  background: var(--c-neutral-white); border-radius: var(--radius-md); box-shadow: var(--sh-sm); text-decoration: none; color: var(--c-neutral-body); }
.link-anchor:focus-visible { box-shadow: var(--o-primary); outline: none; }
.link-num { position: relative; width: 22px; height: 22px; display: grid; place-items: center; border-radius: var(--radius-full);
  border: 1.5px dashed var(--c-neutral-border); font-size: var(--fs-text-xs); font-weight: var(--fw-semi-bold); color: var(--c-neutral-placeholder);
  transition: background-color var(--dur-fast) var(--ease-out), border-color var(--dur-fast) var(--ease-out); }
.link-num svg { position: absolute; width: 14px; height: 14px; color: var(--c-success-baseActive); opacity: 0; transition: opacity var(--dur-fast); }
.link-n { transition: opacity var(--dur-fast); }
.link-row[data-opened="true"] .link-num { background: var(--c-success-tint); border: 1.5px solid var(--c-success-light); }
.link-row[data-opened="true"] .link-num svg { opacity: 1; }
.link-row[data-opened="true"] .link-n { opacity: 0; }
.link-text { display: grid; min-width: 0; }
.link-title { font-size: 15px; line-height: 22px; font-weight: var(--fw-semi-bold); color: var(--c-neutral-title); }
.link-detail { font-size: 13px; line-height: 19px; color: var(--c-neutral-subtitle); }
/* What to go and find there: the one line that invites the click. */
.link-try { margin-top: 6px; padding-left: 10px; border-left: 2px solid var(--c-brand-orange);
  font-size: 13px; line-height: 19px; font-weight: var(--fw-medium); color: var(--c-neutral-title); }
.link-menu { margin-top: 2px; font-size: 11px; line-height: 15px; color: var(--c-neutral-placeholder); }
.link-open { font-size: 13px; font-weight: var(--fw-semi-bold); color: var(--c-primary-base); white-space: nowrap; }
.link-anchor:hover .link-open { text-decoration: underline; }

/* --- Single layout (Done): one centered column, the CTA right under the recap --- */
.wz[data-layout="single"] { grid-template-columns: 1fr; }
.wz[data-layout="single"] .stage { display: none; }
.wz[data-layout="single"] .col { align-items: center; }
.wz[data-layout="single"] .col > .pane { flex: 0 0 auto; margin-top: auto; padding-bottom: 0; }
/* Back follows the content instead of waiting at the foot of the viewport. */
.wz[data-layout="single"] .col > .actions { position: static; margin-bottom: auto; }
.wz[data-layout="single"] .col > .actions::before { content: none; }
/* The stage's navy, brought into the column: the boldness stays in one place. */
.end-cta { margin-top: var(--sp-md); padding: var(--sp-md); border-radius: var(--radius-lg);
  background: var(--c-brand-blueActive); }
.end-cta .cta-heading { margin-bottom: 20px; font-size: 28px; line-height: 36px; color: var(--c-neutral-white); }
/* In the column, `.col a` would repaint both links in the column's blue: keep the stage's. */
.end-cta a.cta-primary { color: var(--c-neutral-title); text-decoration: none; }
.end-cta a.cta-secondary { color: var(--c-primary-light); }

/* --- CTA (Expiry): the one big sentence on the stage ------------------------- */
.stage-cta { width: 100%; max-width: 440px; color: var(--c-neutral-white); }
.cta-heading { margin: 0 0 24px; font-size: 40px; line-height: 48px; font-weight: 700; letter-spacing: var(--ls-display-xl); }
.cta-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 20px; margin: 0; }
.cta-primary { display: inline-flex; align-items: center; min-height: 44px; padding: 10px 20px; border-radius: var(--radius-sm);
  background: var(--c-brand-orange); color: var(--c-neutral-title); font-weight: var(--fw-semi-bold); text-decoration: none;
  transition: background-color var(--dur-fast); }
.cta-primary:hover { background: var(--c-brand-orangeHover); }
.cta-primary:focus-visible, .cta-secondary:focus-visible { box-shadow: var(--o-primary); outline: none; }
.cta-secondary { color: var(--c-primary-light); font-weight: var(--fw-medium); text-decoration: none; border-radius: var(--radius-sm); }
.cta-secondary:hover { text-decoration: underline; }

/* --- Lightbox: a diagram full size, over everything --------------------------- */
.lightbox { width: min(1200px, 94vw); max-width: none; max-height: 92vh; padding: var(--sp-sm); border: 0;
  border-radius: var(--radius-lg); background: var(--c-neutral-white); box-shadow: var(--sh-stage); }
.lightbox[open] { animation: fade-in var(--dur-base) var(--ease-out); }
.lightbox::backdrop { background: color-mix(in srgb, var(--c-brand-blueActive) 82%, transparent); }
.lightbox-figure { margin: 0; }
.lightbox-figure img { display: block; width: 100%; height: auto; max-height: calc(92vh - 64px); object-fit: contain; }
.lightbox-close { position: absolute; top: 8px; right: 8px; width: 36px; height: 36px; cursor: pointer; font: inherit;
  font-size: 16px; color: var(--c-neutral-subtitle); background: var(--c-neutral-bg);
  border: 1px solid var(--c-neutral-light); border-radius: var(--radius-full); }
.lightbox-close:hover { color: var(--c-neutral-title); }
.lightbox-close:focus-visible { box-shadow: var(--o-primary); outline: none; }

/* --- Below 960px (not the target, must not break): stack column over stage --- */
@media (max-width: 960px) {
  .wz { grid-template-columns: 1fr; height: auto; }
  .col { overflow: visible; padding: var(--sp-sm) var(--sp-xs); }
  .stage { position: relative; height: auto; min-height: 480px; padding: var(--sp-lg) var(--sp-xs) 96px; }
  .stage-caption { left: var(--sp-xs); }
}

/* --- Reduced motion: states swap instantly and nothing loops. base.css only shortens
 * transitions to 0.01ms, which still lets inherited properties (the collapsed body's
 * visibility) lag a frame behind their parent — so switch them off here. */
@media (prefers-reduced-motion: reduce) {
  .wz *, .wz *::before, .wz *::after, .lightbox { animation: none !important; transition: none !important; }
}
