/* ═══════════════════════════════════════════════════════════════════════════
   THE CAMPAIGN VESSEL — THE CANONICAL IMPLEMENTATION

   ONE INSTRUMENT, ONE FILE, EVERY SURFACE. This is the campaign's vertical
   vessel: the thing that says where the campaign stands. It was declared
   inside campaign.css as `.camp .core*` and was therefore only available to
   post 3248; the thank-you page needed the same instrument and the only way to
   have it was to restate its geometry in a second namespace, which is how two
   implementations of one drawing start to drift.

   SO THE RULES MOVED HERE AND THE `.camp` SCOPE CAME OFF. campaign.css no
   longer declares them; it loads this file (see class-campaign.php,
   `jsf-campaign-vessel`, a dependency of `jsf-campaign`). The landing page's
   own LAYOUT of the instrument — how wide the scale gutter is inside `#engine`
   at each breakpoint, where the legend sits — stays in campaign.css, because
   that is the engine's composition and not the component.

   GEOMETRY IS FIXED. PALETTE IS A CONTRACT. Every colour is a `--vessel-*`
   custom property whose FALLBACK is the value campaign.css shipped, so a
   surface that sets nothing renders exactly what post 3248 renders today. A
   surface on a light ground — the thank-you page's cream closing section —
   sets the properties and inherits every pixel of the geometry. There is no
   second copy of the drawing, and there is no `--onPaper` variant class: a
   ground is values, not a component.

   THE MARKUP CONTRACT (as post 3248 ships it):

     .core
       .core .core__ticks            scale marks, absolutely positioned by `bottom:%`
         span > em [+ small]   figure, and optionally a caption
         span.core__tick--cap  the $100,000 match cap, marked in gold
       .core .core__tube
         .core .core__fill           height set inline, as a % of the goal
           .core .core__seg--donor   the lower band  (column-reverse: first = bottom)
           .core .core__seg--match   the upper band
           .core .core__meniscus     the lit surface, rides the top of the fill
         .core .core__lens .core__inlet .core__beam--donor .core__beam--match
       .core .core__legend           optional

   Every child is OPTIONAL. A surface that renders no legend, no beams and no
   tick captions simply gets none — there is nothing to switch off.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── WHY EVERY DESCENDANT IS WRITTEN `.core .core__x` ─────────────────────
   NOT DECORATION — SPECIFICITY PARITY. In campaign.css these rules were
   `.camp .core__x`, i.e. (0,2,0). Dropped to a bare `.core__x` they become
   (0,1,0) and TIE with campaign.css's own base reset,
   `.camp :where(…, p, …) { color: inherit }` — which loads afterwards and
   therefore wins. The legend's colour silently became the page's body ink.
   qa/vessel/parity.mjs caught it; `.core .core__x` restores (0,2,0) and the
   landing page renders exactly what it rendered before. */

.core { position: relative; display: flex; flex-direction: column; align-items: center; }

.core .core__ticks { position: absolute; inset: 0 auto 0 0; left: -6px; width: 100%; pointer-events: none; }
/* The scale labels live in the 84px gutter left of the tube; without a cap the
   longest of them ran under the connector rule and into the tube itself. */
.core .core__ticks span { position: absolute; left: 0; transform: translateY(50%); display: flex; flex-direction: column; align-items: flex-start; gap: 0; line-height: 1.15; font-variant-numeric: tabular-nums; max-width: 92px; }
.core .core__ticks em { font-style: normal; font-size: 0.72rem; color: var(--vessel-tick, rgba(244, 239, 226, 0.6)); }
.core .core__ticks small { font-size: 0.58rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--vessel-tick-sub, rgba(244, 239, 226, 0.56)); } /* .42 measured 3.70:1 at 9.9px on the stage (WCAG 1.4.3 asks 4.5); .56 clears it. Design audit 2026-10-03. */
.core .core__ticks span::before { content: ""; position: absolute; left: 82px; top: 50%; width: 10px; height: 1px; background: var(--vessel-tick-rule, rgba(244, 239, 226, 0.2)); }
.core .core__tick--cap em { color: var(--vessel-cap, var(--gold)); }
.core .core__tick--cap small { color: var(--vessel-cap-sub, var(--color-sand)); }
.core .core__tick--cap::before { background: var(--vessel-cap, var(--gold)) !important; height: 2px !important; }

.core .core__tube { position: relative; width: clamp(104px, 13vw, 148px); flex: 1; margin-left: 96px; border-radius: 74px;
  background: var(--vessel-tube-bg, linear-gradient(180deg, rgba(255,255,255,0.05), rgba(0,0,0,0.35)));
  border: 1px solid var(--vessel-tube-edge, rgba(218, 165, 32, 0.18)); overflow: hidden;
  box-shadow: var(--vessel-tube-shadow, inset 0 0 40px rgba(0,0,0,0.6), inset 6px 0 16px rgba(255,255,255,0.04)); }
.core .core__tube::after { content: ""; position: absolute; top: 6px; left: 12%; width: 10%; height: 88%; border-radius: 40px; background: var(--vessel-sheen, linear-gradient(180deg, rgba(255,255,255,0.14), transparent 40%)); z-index: 3; }

.core .core__fill { position: absolute; left: 0; right: 0; bottom: 0; border-radius: 0 0 74px 74px;
  display: flex; flex-direction: column-reverse; transition: height var(--vessel-dur, var(--dur-slow)) var(--ease-out); }
.core .core__seg { display: block; width: 100%; transition: height var(--vessel-dur, var(--dur-slow)) var(--ease-out); }
.core .core__seg--donor { background: var(--vessel-seg-donor, linear-gradient(180deg, rgba(246, 211, 107, 0.22), rgba(120, 96, 30, 0.42))); }
.core .core__seg--match { background: var(--vessel-seg-match, linear-gradient(180deg, rgba(218, 165, 32, 0.62), rgba(218, 165, 32, 0.34))); border-top: 1px solid var(--vessel-seg-match-edge, rgba(255, 240, 200, 0.35)); box-shadow: var(--vessel-seg-match-glow, 0 -1px 10px rgba(218,165,32,0.35)); }
.core .core__meniscus { position: absolute; top: -2px; left: 0; right: 0; height: 4px; z-index: 2; background: linear-gradient(90deg, #f6d36b, #daa520, #f6d36b); box-shadow: var(--vessel-meniscus-glow, 0 0 18px 2px rgba(218, 165, 32, 0.85)); border-radius: 3px; }
.core .core__lens { position: absolute; left: 8%; right: 8%; bottom: 12%; height: 2px; background: var(--gold); box-shadow: 0 0 16px 3px rgba(218, 165, 32, 0.7); opacity: var(--vessel-lens-opacity, 0.5); }
.core .core__inlet { position: absolute; left: 50%; bottom: 0; width: 14px; height: 14px; transform: translateX(-50%); border-radius: 50%; background: radial-gradient(circle, #ffe9a8, rgba(218,165,32,0)); opacity: 0.7; }
.core .core__beam { position: absolute; bottom: 12%; width: 2px; height: 0; opacity: 0; }
.core .core__beam--donor { left: 38%; background: linear-gradient(180deg, #fff, transparent); }
.core .core__beam--match { left: 62%; background: linear-gradient(180deg, var(--gold), transparent); }

.core .core__legend { display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: 6px; font-size: 0.68rem; letter-spacing: 0.04em; text-transform: uppercase; color: var(--vessel-tick, rgba(244, 239, 226, 0.6)); margin: 14px 0 0; text-align: center; line-height: 1.7; }
/* key + label travel together, so a swatch can never be orphaned at a line end */
.core .core__legend-item { display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
.core .core__key { width: 11px; height: 11px; border-radius: 3px; display: inline-block; }
.core .core__key--donor { background: linear-gradient(180deg, rgba(246,211,107,0.5), rgba(120,96,30,0.6)); }
.core .core__key--match { background: var(--gold); }

/* THE SCALE GUTTER NARROWS WITH THE TYPE IT HOLDS. Component behaviour, not
   engine layout: any surface that hangs this instrument in a narrow frame
   needs it. Lifted verbatim from campaign.css's own `@media (max-width: 480px)`
   block, where it sat among landing-page rules. */
@media (max-width: 480px) {
  .core .core__tube { margin-left: 78px; }
  .core .core__ticks span::before { left: 66px; }
}
