/*
 * Deploy scene v4 — alignment & 1:1 guide lines
 * Loaded last so these rules win over home-narrative / home-refined-v3 / typography-moticon.
 * Goal: left data card, centre model node and right capability rail share one vertical
 * axis; every guide line maps to exactly one capability module.
 */

.deploy-frame {
  --deploy-mid: 62%;
  --row-h: clamp(60px, 9.4vh, 88px);
  --row-gap: clamp(8px, 1.5vh, 14px);
  --rail-w: min(27vw, 350px);
  --card-w: min(39vw, 580px);
  --node-half: 66px;
}

/* ---- Model node: centered on the shared axis ---- */
.deploy-model-node {
  left: 51.5%;
  top: var(--deploy-mid);
  min-width: 132px;
  padding: 40px 16px;
  border: 1px solid rgba(42, 107, 150, .22);
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255, 255, 255, .97), rgba(222, 235, 243, .86));
  box-shadow: 0 0 0 18px rgba(68, 132, 170, .045), 0 0 70px rgba(58, 119, 157, .12);
  opacity: 1;
  transform: translate(-50%, -50%);
}

/* ---- Left data card: centered on the same axis ---- */
.rich-sensing-visual {
  left: 7vw;
  width: var(--card-w);
  top: var(--deploy-mid);
  height: clamp(296px, 42.5%, 424px);
  transform: translateY(-50%) scale(calc(1 - var(--p, 0) * .045));
}

/* ---- Right capability rail: 4 stacked modules, centered on the axis ---- */
.capability-constellation {
  right: 7vw;
  left: auto;
  top: var(--deploy-mid);
  width: var(--rail-w);
  display: grid;
  grid-template-columns: 1fr;
  grid-template-rows: repeat(4, var(--row-h));
  gap: var(--row-gap);
  transform: translateY(-50%);
}
.capability-constellation article {
  position: relative;
  overflow: hidden;
  min-height: 0;
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 14px;
  padding: 0 18px;
  border: 1px solid rgba(31, 77, 106, .09);
  border-radius: 14px;
  background: linear-gradient(145deg, rgba(255, 255, 255, .75), rgba(226, 236, 242, .54));
  box-shadow: 0 14px 36px rgba(38, 72, 94, .055);
  opacity: clamp(.24, calc((var(--p, 0) - .18) * 3), 1);
}
.capability-constellation .cap-no,
.capability-constellation .cap-label,
.capability-constellation .cap-code {
  position: static;
  left: auto;
  right: auto;
  top: auto;
  bottom: auto;
  margin: 0;
  align-self: center;
}
.capability-constellation .cap-no {
  color: #8ea1ad;
  font-weight: 650;
  line-height: 1;
}
.capability-constellation .cap-label {
  display: block;
  color: #193e56;
  font-size: 17px;
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -.01em;
}
.capability-constellation .cap-code {
  justify-self: end;
  color: #8297a4;
  line-height: 1;
}
/* Anchor dot: the exact point where this module's guide line terminates. */
.capability-constellation .cap-anchor {
  position: absolute;
  display: block;
  left: 5px;
  right: auto;
  top: 50%;
  bottom: auto;
  width: 9px;
  height: 9px;
  border: 0;
  border-radius: 50%;
  transform: translateY(-50%);
  background: #2e6fa6;
  box-shadow: 0 0 0 4px rgba(46, 111, 166, .14);
}

/* ---- Connector lines: 4 curves, one per module, geometry set from the DOM ---- */
.deploy-tree {
  position: absolute;
  z-index: 6;
  inset: 0;
  width: 100%;
  height: 100%;
  overflow: visible;
  pointer-events: none;
}
.deploy-tree path {
  fill: none;
  stroke: rgba(46, 111, 166, .5);
  stroke-width: 1.15;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}

/* =========================================================
   MOBILE / SMALL TABLET  (<= 820px): tidy vertical rail
   ========================================================= */
@media (max-width: 820px) {
  .deploy-frame {
    --deploy-mid: auto;
    --row-h: clamp(50px, 6.8svh, 62px);
    --row-gap: clamp(7px, 1.2svh, 10px);
    --rail-w: auto;
    --card-w: auto;
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
    padding: calc(78px + env(safe-area-inset-top, 0px)) 20px 22px;
    overflow: hidden;
    background-color: var(--v3-paper);
  }
  /* NOTE: .rich-sensing-visual is intentionally EXCLUDED — it must stay a
     positioned container so its absolutely-positioned SVG/heading/footer
     children remain anchored to it (otherwise the figure escapes and
     overlays the whole scene). It is handled separately below. */
  .deploy-frame > *:not(.deploy-tree):not(.rich-sensing-visual) {
    position: static !important;
    left: auto !important;
    right: auto !important;
    top: auto !important;
    bottom: auto !important;
    width: auto !important;
    height: auto !important;
    transform: none !important;
  }
  .deploy-tree { order: 0; position: absolute; inset: 0; width: 100%; height: 100%; }
  .deploy-copy { order: 1; margin: 0; }
  .deploy-copy h2 { font-size: clamp(32px, 9.4vw, 46px); }
  .deploy-meta-bar { order: 2; width: 100%; margin-top: 20px; }
  .rich-sensing-visual {
    order: 3;
    position: relative;
    left: auto;
    right: auto;
    top: auto;
    bottom: auto;
    width: 100%;
    height: auto;
    aspect-ratio: 760 / 400;
    transform: none;
    margin-top: 16px;
    overflow: hidden;
  }
  .deploy-model-node {
    order: 4;
    align-self: flex-start;
    margin: 22px 0 0;
    min-width: 92px;
    padding: 15px 10px;
    font-size: 11px;
  }
  .capability-constellation {
    order: 6;
    width: 100%;
    margin-top: 0;
    margin-left: 46px;
    grid-template-columns: 1fr;
    grid-template-rows: repeat(4, var(--row-h));
  }
  .capability-constellation article {
    padding: 0 16px;
    margin-left: 28px;
    opacity: clamp(.24, calc((var(--p, 0) - .18) * 3), 1);
  }
  /* Anchor dot stays visible on mobile so every guide line has a landing point. */
  .capability-constellation .cap-anchor {
    display: block;
    left: -1px;
    transform: translate(-50%, -50%);
  }
  .deploy-meta-bar span { padding: 9px 6px 0; }
  .deploy-meta-bar b { font-size: 9px; }
  .deploy-meta-bar em { display: none; }
}

/* Short landscape / small phones: shrink further so nothing clips */
@media (max-width: 820px) and (max-height: 720px) {
  .deploy-frame { padding-top: calc(64px + env(safe-area-inset-top, 0px)); }
  .deploy-copy h2 { font-size: clamp(28px, 8.4vw, 40px); }
  .rich-sensing-visual { margin-top: 12px; }
  .deploy-model-node { min-width: 78px; padding: 12px 8px; margin-top: 16px; }
  .deploy-meta-bar { margin-top: 14px; }
  .capability-constellation { --row-h: clamp(44px, 6svh, 54px); --row-gap: 6px; }
  .capability-constellation .cap-label { font-size: 15px; }
}

/* Desktop large screens keep generous spacing */
@media (min-width: 1280px) {
  .deploy-frame { --rail-w: min(26vw, 360px); --card-w: min(38vw, 600px); }
}

/* ============================================================================
 * Gait scene — annotation rail  (v20261009)
 * ----------------------------------------------------------------------------
 * "足底压力与重心轨迹" + "正常步行右脚示意 / 非个体诊断数据" used to be pinned to
 * fixed percentages, which dropped them straight on top of the footprint at most
 * viewports. They are now one rail that hugs the figure's right side:
 *   · home-narrative.js measures the *drawn* silhouette (settled at --p = 1) and
 *     writes --gait-note-x / -y / -w / -gap onto .gait-visual;
 *   · the rules below only consume those values and own the typography.
 * The static declarations double as a no-JS fallback (same place as before).
 * ========================================================================== */

.gait-visual {
  --gait-note-x: 14vw;
  --gait-note-y: 32%;
  --gait-note-w: 190px;
  --gait-note-gap: 42px;
}

.gait-visual .pressure-label,
.gait-visual .trajectory-note {
  left: var(--gait-note-x);
  width: var(--gait-note-w);
  max-width: var(--gait-note-w);
  text-align: left;
  text-wrap: pretty;
}

.gait-visual .pressure-label { top: var(--gait-note-y); }

.gait-visual .trajectory-note {
  top: calc(var(--gait-note-y) + var(--gait-note-gap));
  display: block;
  line-height: 1.52;
  color: #8b9ca8;
}

.gait-visual .trajectory-note i,
.gait-visual .trajectory-note em {
  display: block;
  font-style: normal;
  letter-spacing: .06em;
}

.gait-visual .trajectory-note i { color: #8293a0; }
.gait-visual .trajectory-note em { margin-top: 2px; color: #a6b2ba; }

@media (max-width: 820px) {
  .gait-visual {
    --gait-note-x: 8%;
    --gait-note-y: 31%;
    --gait-note-w: 160px;
    --gait-note-gap: 35px;
  }
}

@media (min-width: 821px) {
  /* "惯性信号" labels the IMU panel — park it over the panel's top-right corner
     so it lines up with the atlas / panel right margin and leaves the strip
     beside the figure free for the annotation rail. */
  .inertia-label { left: auto; right: 7vw; }

  /* Give that strip a little more headroom so the rail never has to fight the
     panel edge for space. */
  .waveform-field { top: 38%; height: 41%; }
}

/* ============================================================
   v20261010-labels2 — Scene 03 device wireframes + larger labels.
   (Scene 04 · English label colours/sizes follow v20261010-labels1.)
   Loaded last, so these win over home-refined-v3 / typography-moticon.
   ============================================================ */

/* --- Scene 03: the circular wireframe belongs on the five small devices,
       NOT on the central figure. It is centred on each 52px device icon, and
       its soft fill covers the first pixels of the guide line, so every line
       reads as connecting to the ring's edge. --- */
.device-silhouette svg {
  display: block;
  margin: 0 auto;
  position: relative;
  z-index: 1;
}
.device-silhouette::before {
  content: "";
  position: absolute;
  left: 50%;
  top: -8px;
  width: 68px;
  height: 68px;
  margin-left: -34px;
  border: 1px solid rgba(39, 105, 147, .30);
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255,255,255,.92) 56%, rgba(224,236,243,.62) 100%);
  pointer-events: none;
}

/* --- Scene 03: the "MEDICAL" device used to sit at top:28%, landing on top of
       the "KINETICS" band pill, so park it lower. Scoped to >=821px: the
       <=820px responsive rule (bottom:15%) must keep handling tablets/phones,
       otherwise the wireframe lands on the PERSONAL band (the "two English
       labels overlapping on the right" the user flagged). --- */
@media (min-width: 821px) {
  .device-medical { top: 42%; }
}

/* --- Tablet / small-laptop: the device ring crowds the bottom process row.
       Lift it clear of the "03 表征" step. --- */
@media (min-width: 821px) and (max-width: 1180px) {
  .device-ring { right: 28%; bottom: 18%; }
}

/* --- 721–1366px: the PERSONAL band otherwise drifts onto the figure's right
       edge (and, before the cascade fix, onto the MEDICAL device). Push it to
       the margin so the two right-side labels stay separated. --- */
@media (min-width: 721px) and (max-width: 1366px) {
  .representation-bands span:nth-child(4) { right: 5%; }
}

/* --- Scene 03: interface labels one more step up — the English labels and
       the bottom Chinese row (01 感知 / 02 对齐 / …) both grow, so the small
       type reads clearly while keeping the page's rhythm and hierarchy. --- */
@media (min-width: 721px) {
  .space-cloud strong small { font-size: 14px!important; font-weight: 650 !important; letter-spacing: .18em !important; }
  .space-cloud strong span { font-size: clamp(18px, 1.75vw, 24px) !important; font-weight: 600 !important; letter-spacing: .12em !important; }
  .representation-bands span { font-size: clamp(12px, 1.05vw, 15px) !important; font-weight: 650 !important; letter-spacing: .1em !important; padding: 9px 14px !important; }
  .space-annotation span { font-size: clamp(12px, 1.05vw, 15px) !important; font-weight: 650 !important; letter-spacing: .14em !important; }
  .space-annotation b { font-size: clamp(14px, 1.25vw, 17px) !important; font-weight: 600 !important; line-height: 1.5 !important; }
  .space-process i,
  .space-process b { font-size: clamp(12px, 1.05vw, 15px) !important; font-weight: 650 !important; letter-spacing: .1em !important; }
  .device-silhouette span { font-size: clamp(12px, .95vw, 14px) !important; font-weight: 650 !important; letter-spacing: .08em !important; }
  .device-silhouette svg { width: 52px !important; height: 52px !important; }
}

/* Phones keep a compact but still legible scale (the device orbit is hidden
   under 720px, so the wireframes never need to fit there). The figure grows
   relative to the viewport at this size, so shrink it and pin the four
   representation bands to the 20%-inset corners. The caption (annotation) is
   parked centred at the very top of the stage so it never lands on the
   top-right KINETICS band. */
@media (max-width: 720px) {
  .space-cloud { width: 40vw !important; }
  .space-annotation {
    top: 1% !important; left: 50% !important; right: auto !important;
    transform: translateX(-50%) !important;
    max-width: 58vw !important; text-align: center !important;
  }
  .representation-bands span { font-size: 9px!important; padding: 5px 9px !important; }
  .representation-bands span:nth-child(1) { left: 2%; top: 20%; }
  .representation-bands span:nth-child(2) { right: 2%; top: 20%; }
  .representation-bands span:nth-child(3) { left: 2%; bottom: 20%; }
  .representation-bands span:nth-child(4) { right: 2%; bottom: 20%; }
  .space-annotation span { font-size: 9px!important; }
  .space-process b { font-size: 10px!important; }
}

/* --- Scene 04: darken + enlarge the ENGLISH labels; Chinese stays as-is --- */
.model-data-heading span { color: #3f5d72 !important; font-size: clamp(10px, .95vw, 12px) !important; }
.model-section-labels text,
.model-bottom-meta text { fill: #2f4f66 !important; font: 650 12px/1 "YJ Rubik", Arial, sans-serif !important; letter-spacing: .06em !important; }
.model-bottom-meta text { font-size: 11px!important; }
.encoder-tokens text { fill: #244a66 !important; font: 650 11px/1 "YJ Rubik", Arial, sans-serif !important; letter-spacing: .05em !important; }
.latent-axes text { fill: #4d6472 !important; font: 650 10px/1 "YJ Rubik", Arial, sans-serif !important; }
.deploy-meta-bar i { color: #3b6077 !important; font-size: 11px!important; }
.deploy-meta-bar b { color: #1f4660 !important; font-size: 11px!important; }
.capability-constellation article > span { color: #2f4f66 !important; font-size: 11px!important; }
.capability-constellation em { color: #3e586c !important; font-size: 11px!important; }
.deploy-device b { color: #2f4a5e !important; font-size: 11px!important; }

/* ============================================================================
 * v20261012-type1 — type-scale pass across three scenes
 * ----------------------------------------------------------------------------
 * Loaded last (index.html line 17), so every rule below wins the cascade.
 * The screenshots reviewed were ~1920px wide, so the Scene-04 enlargements are
 * scoped to the >=821px layout; the <=820px layouts keep their own, already
 * tuned, compact scale and are left untouched.
 * ========================================================================== */

/* ---- (1) Scene 02 · foot annotation rail — +4 -----------------------------
   Desktop  label 13 → 17px, note 11 → 15px.
   Phones    label  9 → 13px, note  8 → 12px.
   Only the foot rail (the circled block) grows — "惯性信号" is left as-is. The
   accent rule under the label widens with it so the proportion still holds.
   The rail's position/width are measured from live rects in JS, so the bigger
   stack is re-seated automatically. ---------------------------------------- */
.gait-visual .pressure-label {
  font-size: 18px!important;
  font-weight: 650 !important;
  letter-spacing: .05em !important;
}
.gait-visual .trajectory-note {
  font-size: 16px!important;
  font-weight: 550 !important;
  line-height: 1.5 !important;
}
.gait-visual .trajectory-note i,
.gait-visual .trajectory-note em { line-height: 1.5; }
.gait-visual .trajectory-note em { color: #94a6b2; }

@media (min-width: 721px) {
  .gait-visual .observation-label::after { width: 34px; }
}
@media (max-width: 720px) {
  .gait-visual .pressure-label { font-size: 14px!important; }
  .gait-visual .trajectory-note { font-size: 13px!important; }
}

/* ---- (2) Scene 04 · meta strip — +3 and a bigger rectangle ----------------
   The strip keeps its hairline language (top rule + cell dividers) but gains
   height and width, so the block the user circled reads as a larger module
   instead of a thin caption band. ----------------------------------------- */
@media (min-width: 821px) {
  .deploy-meta-bar {
    width: min(44vw, 660px);
    border-top-color: rgba(31, 76, 105, .22);
  }
  .deploy-meta-bar span {
    padding: 20px 18px 6px;
    border-left-color: rgba(31, 76, 105, .12);
  }
  .deploy-meta-bar i,
  .deploy-meta-bar b,
  .deploy-meta-bar em { font-size: 14px!important; line-height: 1.2 !important; }
  .deploy-meta-bar i { font-weight: 650 !important; letter-spacing: .1em !important; }
  .deploy-meta-bar b { margin-top: 11px; font-weight: 650 !important; letter-spacing: .06em !important; }
  .deploy-meta-bar em { margin-top: 7px; font-weight: 550 !important; letter-spacing: .04em !important; }
}

/* ---- (2b) Scene 04 · right capability rail — bigger AND aligned -----------
   The rail is given the *same* height as the left data card and both sit on
   `top: --deploy-mid` with translateY(-50%), so the two columns now share one
   top edge and one bottom edge. Rows become 1fr so the four modules divide
   that height evenly instead of drifting with viewport height.
   The rail also repeats the card's settle-in scale (1 - p * .045): without it
   the left card shrinks ~4.5% as it animates in while the rail stayed put, so
   the two columns ended ~9px out of register at rest. --------------------- */
.deploy-frame { --rail-w: min(28vw, 372px); }
@media (min-width: 1280px) {
  .deploy-frame { --rail-w: min(27vw, 388px); }
}
@media (min-width: 821px) {
  .capability-constellation {
    height: clamp(296px, 42.5%, 424px);
    grid-template-rows: repeat(4, 1fr);
    transform: translateY(-50%) scale(calc(1 - var(--p, 0) * .045));
  }
  .capability-constellation article { padding: 0 20px; }
  .capability-constellation .cap-label { font-size: 19px!important; line-height: 1.2 !important; }
  .capability-constellation .cap-no { font-size: 14px!important; }
  .capability-constellation .cap-code { font-size: 13px!important; }
}

/* ---- (3) Scene 05 · time labels — +6, new typeface, clearer colour --------
   Dim 9px monospace (rgba(255,255,255,.35)) → the brand geometric sans at
   15px in a light steel blue, so the row reads clearly on the navy frame.
   The active step keeps the yellow accent and gains a soft glow. ---------- */
.time-labels {
  color: #c8dfee;
  font: 600 15px/1 "YJ Rubik", "PingFang SC", "Microsoft YaHei", Arial, sans-serif;
  letter-spacing: .04em;
}
.time-labels span.active { text-shadow: 0 0 16px rgba(212, 164, 55, .45); }

@media (max-width: 720px) {
  .time-labels { font-size: 14px; letter-spacing: .01em; }
}

/* ---- (4) Scene 03 · restore the five device figures on phones -------------
   Under 720px `home-refined-v3.css` sets `.device-orbit { display:none }`,
   which hides the wrapper that holds ALL five silhouettes — so FOOT / WRIST /
   RING / PHONE / MEDICAL vanished on phones (their reveal still ran, but a
   display:none wrapper gives every child a 0×0 box, so nothing painted).
   Re-enable the wrapper as one evenly-spaced row parked just inside the lower
   edge of the stage, shrink the icon + its wireframe so five fit across a
   ~355px column, and bring RING back too. `bottom: calc(15% + 12px)` tracks the
   stage's `bottom:15%`, keeping the row clear of the TEMPORAL/PERSONAL band
   pills above it and the process row below. ------------------------------- */
@media (max-width: 720px) {
  .device-orbit {
    display: flex !important;
    position: absolute !important;
    left: 18px !important;
    right: 18px !important;
    top: auto !important;
    bottom: calc(15% + 12px) !important;
    height: auto !important;
    align-items: flex-end !important;
    justify-content: space-between !important;
    gap: 2px !important;
    z-index: 6 !important;
  }
  .device-orbit .device-silhouette {
    position: relative !important;
    flex: 1 1 0 !important;
    width: auto !important;
    left: auto !important;
    right: auto !important;
    top: auto !important;
    bottom: auto !important;
  }
  .device-orbit .device-ring { display: block !important; }
  .device-silhouette svg { width: 30px !important; height: 30px !important; }
  .device-silhouette span {
    margin-top: 6px !important;
    font-size: 10px!important;
    letter-spacing: .05em !important;
  }
  .device-silhouette::before {
    top: -7px !important;
    width: 44px !important;
    height: 44px !important;
    margin-left: -22px !important;
  }
}

/* ============================================================================
 * v20261012-mobilefit — phone pass for Scene 02 (gait) + Scene 03 (space).
 * Loaded last, so these win over home-narrative / home-refined-v3.
 * ========================================================================== */

@media (max-width: 720px) {

  /* ---- Scene 02 · footprint vs the IMU chart ------------------------------
     `home-narrative.css` sized the foot 54vw and the IMU panel 57vw with only
     a 12px right inset. On a ~375px column the two boxes then overlapped by
     ~88 x 228px, so the sole sat straight on the chart's left channels (and on
     the "6-AXIS IMU / 200 HZ" heading). Give each element its own column — the
     figure leans left, the panel sits right — and step both down one size, so
     a real gutter opens between them. -------------------------------------- */
  .foot-observation {
    left: 1% !important;
    top: 32% !important;
    width: 40vw !important;
    height: 46% !important;
  }
  .waveform-field {
    right: 8px !important;
    top: 48% !important;
    width: 47vw !important;
  }

  /* ---- Scene 02 · MODEL READOUT vs the step-event row ---------------------
     The readout card rode at `bottom: 7%` while 落地/承重/支撑/抬跟/离地 rode at
     `bottom: 15%`: the card's top edge cut into the row and its frosted blur
     hid the first three labels. Lift the row a touch, drop the card into the
     bottom gutter and trim its padding, so the whole row reads clear. ------- */
  .gait-events { bottom: 16% !important; }
  .signal-reading {
    bottom: 26px !important;
    padding: 10px 13px !important;
  }

  /* ---- Scene 03 · the ring cluster must clear the English band pills ------
     The orbit ellipses (up to 72% x 62% of the stage) swept straight through
     KINEMATICS / KINETICS / TEMPORAL / PERSONAL, so on a phone the rings read
     as "big circles lying across the English". Pull the whole cluster in — the
     core disc 40vw -> 34vw and every ring ~28% smaller — so the arcs stay
     inside the pill rectangle, and give the pills an opaque fill plus a
     z-index above the rings, so their letters can never be overlaid. -------- */
  .space-cloud { width: 34vw !important; }
  .orbit-a { width: 46% !important; height: 26% !important; }
  .orbit-b { width: 34% !important; height: 40% !important; }
  .orbit-c { width: 50% !important; height: 40% !important; }
  .representation-bands { z-index: 4 !important; }
  .representation-bands span {
    background: rgba(255,255,255,.92) !important;
    box-shadow: 0 1px 5px rgba(31,76,104,.06);
  }
}

/* ============================================================================
 * v20261013-mac — Mac (721–1180px) occlusion pass for Scene 02 + Scene 03.
 * Loaded last, scoped to the Mac band so phones (<721) and large desktops
 * (>1180) keep their own tuned layouts. Addresses the two Mac screenshots:
 *   · Scene 02: the 4-column atlas bar (right module) was covering the 70vw
 *     title, and the readout card (bottom module) was covering the waveform /
 *     step-event row / footprint. Both are relocated to the clean bottom
 *     corners — there is no free horizontal strip beside a 70vw title.
 *   · Scene 03: FOOT + WRIST were parked left of the shared stage; moved
 *     inside it. The three orbit ellipses + core disc were oversized on the
 *     smaller stage, so shrunk; the device label font trimmed a touch.
 * ========================================================================== */

@media (min-width: 721px) and (max-width: 1180px) {

  /* ---- Scene 02 · signal atlas → compact 4-column strip, bottom-LEFT under the
     footprint (its signal context). Clears the title (top) and the wave/events
     (right). Re-anchors from top/right to bottom/left. ---- */
  .signal-atlas {
    top: auto;
    right: auto;
    left: 7vw;
    bottom: 2%;
    width: min(42vw, 400px);
    grid-template-columns: repeat(4, minmax(72px, 1fr));
    border-top: 1px solid rgba(32,75,103,.14);
  }
  .signal-atlas > span { padding: 9px 8px 8px 12px; }

  /* ---- Scene 02 · model readout → bottom-RIGHT corner, below the waveform and
     the step-event row, clear of the footprint (left) and the atlas (left). ---- */
  .signal-reading {
    left: auto;
    right: 5vw;
    bottom: 1.5%;
    width: min(280px, 32vw);
    padding: 9px 13px;
  }
  .signal-reading b { font-size: 15px; margin-top: 8px; }
  .signal-reading p { font-size: 11px; line-height: 1.45; }

  /* ---- Scene 03 · FOOT + WRIST now live inside the shared stage (they used to
     sit left of it). right-based so they land within the stage at every width
     in this band (stage = 34vw…39vw from the left). ---- */
  .device-foot  { left: auto !important; right: 44% !important; bottom: 30% !important; }
  .device-watch { left: auto !important; right: 53% !important; bottom: 18% !important; }

  /* ---- Scene 03 · the three orbit ellipses were oversized on the Mac stage —
     pull them in so the arcs stay inside the pill rectangle. ---- */
  .orbit-a { width: 42% !important; height: 24% !important; }
  .orbit-b { width: 33% !important; height: 40% !important; }
  .orbit-c { width: 52% !important; height: 44% !important; }
  .space-cloud { width: min(17vw, 230px) !important; }

  /* ---- Scene 03 · trim the device label + wireframe a touch (was clamp
     12–14px and a 68px ring). ---- */
  .device-silhouette span { font-size: clamp(10px, .78vw, 11.5px) !important; }
  .device-silhouette svg { width: 46px !important; height: 46px !important; }
  .device-silhouette::before {
    width: 58px !important; height: 58px !important;
    margin-left: -29px !important; top: -7px !important;
  }
}

/* ============================================================================
 * v20261015-mac2 — large-desktop (>=1181px) occlusion pass, Scene 02 + 03.
 * ----------------------------------------------------------------------------
 * Feedback from the Mac screenshots (window wider than 1180px, so none of the
 * earlier 721-1180 fixes applied there):
 *   · Scene 02: the 5.4vw title ran under the top-right signal atlas, and the
 *     frosted MODEL READOUT card rode over the IMU chart and the step-event
 *     row. Title is scaled to a calmer measure, the atlas is narrowed so the
 *     two never meet, the IMU panel moves down out of the annotation rail's
 *     way, and the readout card drops into the free bottom gutter.
 *   · Scene 03: FOOT + WRIST were parked OUTSIDE the shared stage (left of its
 *     39vw edge) — moved inside it, clear of the TEMPORAL band pill, the orbit
 *     arcs and the bottom process row; all five device modules scale -10%.
 * Canvas guide lines re-measure the devices from live rects, so they follow.
 * ========================================================================== */

@media (min-width: 1181px) {

  /* ---- Scene 02 · title vs signal atlas ---------------------------------
     Title 5.4vw/82px -> 4.3vw/64px (still the largest type in the scene, just
     no longer reaching across the whole row); atlas narrows 52vw/710px ->
     40vw/560px. Worst case (1181px): title ends ~611px, atlas starts ~626px. */
  .gait-copy h2 { font-size: clamp(38px, 4.3vw, 64px); }
  .signal-atlas { width: min(40vw, 560px); }

  /* ---- Scene 02 · annotation rail vs IMU panel ---------------------------
     The rail starts at the silhouette's top (~29%) and, in English, stacks up
     to ~140px. Drop the panel so its heading ("6-AXIS IMU / 200 HZ") sits
     below the rail at every width, and lift the step-event row to keep its
     own gutter under the panel. Panel bottom 78% still clears the events. */
  .waveform-field { top: 42% !important; height: 36% !important; }
  .gait-events { bottom: 15.5% !important; }

  /* ---- Scene 02 · MODEL READOUT card -> free bottom gutter ---------------
     Was bottom:9.5%, floating over the chart's lower channels and the first
     three event labels. Park it under both, trimmed to a caption-scale card. */
  .signal-reading {
    bottom: 2% !important;
    padding: 10px 16px !important;
  }
  .signal-reading b { font-size: 15px!important; margin-top: 8px !important; }
  .signal-reading p { font-size: 11px!important; margin-top: 6px !important; line-height: 1.6 !important; }

  /* ---- Scene 03 · FOOT + WRIST inside the shared stage -------------------
     Stage spans 39vw..95vw. FOOT lands in its lower-left inside area (below
     the TEMPORAL pill, which sits at stage bottom 25%), WRIST tucks between
     FOOT and RING with its base clear of the stage's bottom edge (12%) and
     the 01-04 process row (bottom 6%). */
  .device-foot  { left: auto !important; right: 47% !important; bottom: 15% !important; }
  .device-watch { left: auto !important; right: 38% !important; bottom: 13% !important; }

  /* ---- Scene 03 · five device modules -10% ------------------------------- */
  .device-silhouette { width: 63px !important; }
  .device-silhouette svg { width: 47px !important; height: 47px !important; }
  .device-silhouette::before {
    width: 61px !important; height: 61px !important;
    margin-left: -30.5px !important; top: -7px !important;
  }
  .device-silhouette span { font-size: clamp(11px, .85vw, 13px) !important; }
}

/* ============================================================================
 * v20261016-android1 — Android phone (<=720px) de-collision pass, Scene 02.
 * ----------------------------------------------------------------------------
 * Baseline: Android Chrome on a ~360 x 640 CSS-px viewport (the screenshots).
 * Headless measurement of that frame found four hard overlaps that no earlier
 * pass covered — every previous mobile rule was tuned for the *Chinese*
 * headline and for a taller frame:
 *   · EN  : "We understand motion." wraps to 2 lines and its second line ran
 *           straight into the atlas strip (26% top) — it read as "too low",
 *           with no breathing room under it;
 *   · EN  : the annotation rail wrapped to two lines per phrase and spilled
 *           over the IMU panel heading ("6-AXIS IMU / 200 HZ" + "Gait-cycle
 *           aligned") and over "Inertial signal";
 *   · CN  : "一次动作，不是一帧画面" wrapped to 2 lines in the readout card,
 *           whose top edge then cut into the step-event row (落地…离地);
 *   · the figure, the IMU panel, the step row and the card were all fighting
 *           for the last ~180px of a 640px frame.
 * Fix, band by band:
 *   1. copy      — lift the block, even out the index/headline gap, and give
 *                  the English headline its own smaller measure so the two
 *                  lines still end ~24px above the atlas.
 *   2. rail      — widen it to the frame margin and step the note down to 10px
 *                  so each phrase holds ONE line; the stack then ends well
 *                  above the IMU panel.
 *   3. middle    — trim the figure and the IMU panel a little, freeing the
 *                  space the raised step row needs.
 *   4. bottom    — raise the step-event row and park a trimmed readout card in
 *                  the bottom gutter, as asked ("画面整体往上移，下方留出位置").
 * Scoped to <=720px: the 721-1180 and >=1181 bands keep their tuned layouts.
 * ========================================================================== */

@media (max-width: 720px) {

  /* ---- (1) copy block · even rhythm above and below the headline ---------- */
  .gait-copy { top: 10% !important; }
  .gait-copy .scene-index { margin-bottom: 10px !important; }
  .gait-copy .motion-sentence { top: 16px !important; }
  /* Drop the clamp floor (36px) so the vw term governs on narrow phones and the
     中文 headline keeps its single line down to ~320px instead of re-wrapping
     onto a second line (which would then run into the atlas strip). */
  .gait-copy h2 { font-size: clamp(30px, 10.2vw, 53px) !important; }
  /* The English headline is two lines ("We understand" / "motion.") where the
     Chinese one is a single line, so it needs a smaller measure: 8.4vw keeps it
     one line with the baseline ~40px clear of the atlas strip. */
  html[lang="en"] .gait-copy h2 { font-size: clamp(26px, 8.4vw, 40px) !important; }

  /* ---- (2) annotation rail · one line per phrase, clear of the IMU panel --
     The rail's anchor (--gait-note-x) is measured from the drawn silhouette in
     JS, so keep consuming it — but pull the left edge 8px closer to the figure
     and let the block run out to the frame's 22px margin, which is the extra
     width the English phrases need to stay on one line. ------------------- */
  .gait-visual .pressure-label,
  .gait-visual .trajectory-note {
    left: calc(var(--gait-note-x, 30px) - 8px) !important;
    width: calc(100vw - 14px - var(--gait-note-x, 30px)) !important;
    max-width: none !important;
  }
  .gait-visual .pressure-label { font-size: 12px!important; letter-spacing: .03em !important; }
  .gait-visual .trajectory-note {
    font-size: 11px!important;
    letter-spacing: .02em !important;
    line-height: 1.45 !important;
  }

  /* ---- (3) middle band · trim the figure + the IMU panel ----------------- */
  .foot-observation { height: 41% !important; }
  .waveform-field { height: 25% !important; }

  /* ---- (4) bottom band · raise the step row, card into the gutter --------
     Step row 16% -> 22% lifts it clear of both the panel above and the card
     below; the card drops to the 14px gutter with a slightly wider measure so
     the Chinese readout holds one line instead of two. --------------------- */
  .gait-events { bottom: 22% !important; }
  .signal-reading {
    bottom: 14px !important;
    width: min(52vw, 220px) !important;
    padding: 10px 13px !important;
  }
}

/* Very narrow phones (~320px): the rail still needs a touch more measure for
   both English phrases to hold one line each, so claw back the right margin and
   step the label + note down half a point / one point. */
@media (max-width: 380px) {
  .gait-visual .pressure-label,
  .gait-visual .trajectory-note {
    left: calc(var(--gait-note-x, 30px) - 10px) !important;
    width: calc(100vw - 8px - var(--gait-note-x, 30px)) !important;
  }
  .gait-visual .pressure-label { font-size: 11.5px!important; }
  .gait-visual .trajectory-note { font-size: 10px!important; }
  /* On a 560-600px-tall frame the rail's two extra lines come within a few px
     of "惯性信号 / Inertial signal" (43%), so lift the whole rail 6px. */
  .gait-visual .pressure-label { top: calc(var(--gait-note-y, 31%) - 6px) !important; }
  .gait-visual .trajectory-note { top: calc(var(--gait-note-y, 31%) + var(--gait-note-gap, 32px) - 6px) !important; }
}

/* ============================================================================
 * v20261016-desk1 — large-desktop (>=1181px) Scene 03 polish.
 * ----------------------------------------------------------------------------
 * Feedback from the desktop screenshots (wide window, so this rides on top of
 * the v20261015-mac2 pass):
 *   · RING was protruding below the shared stage. mac2 had re-parked FOOT +
 *     WRIST inside the stage but left RING on its base `bottom:8%`, while the
 *     stage floor sits at `bottom:12%` — so the ring hung ~26-36px under the
 *     stage edge at every width >=1181px. Pin it to the same `bottom:15%` the
 *     other bottom-row modules use.
 *   · MEDICAL's launch line was not reaching the central ball. Its `data-enter`
 *     was `.66`, the last of the five, so the line only completed at p>=.90
 *     while the other four complete by p~.82 — in any mid-scroll screenshot the
 *     medical dot sits short of the ball. Brought forward to `.54` (a touch
 *     ahead of PHONE `.58`) so it connects in step with the rest. The canvas
 *     re-measures the cloud from live rects, so the geometry follows.
 *   · The shared stage (the big rectangle) was asked to be larger, with room on
 *     its left. The title block (.shared-copy) was occupying 7vw..41vw and
 *     sitting just above the stage's top, so first lift + narrow the title
 *     (left:5vw / top:9% / width:27vw -> right edge 32vw) to free the band, then
 *     push the stage left from 39vw to 33vw (right trimmed 5vw -> 4vw). That
 *     widens it ~12% and pulls its left edge into the freed space. The five
 *     device modules are anchored by right% to the frame, so they stay inside
 *     the widened stage; the cloud (53% of stage) drifts left a hair and the
 *     guide lines re-measure to it automatically.
 * ========================================================================== */

@media (min-width: 1181px) {

  /* ---- Scene 03 · title lifts + narrows so the stage can grow left -------- */
  .shared-copy { left: 5vw !important; top: 9% !important; width: 27vw !important; }

  /* ---- Scene 03 · shared stage grows left into the freed space ------------ */
  .shared-space-stage-v3 { left: 33vw !important; right: 4vw !important; }

  /* ---- Scene 03 · RING no longer protrudes below the stage ---------------- */
  .device-ring { left: auto !important; right: 28% !important; bottom: 15% !important; }
}

/* ============================================================================
 * v20261016-serif1 — Scene 04 (deploy) module: English type -> Merriweather
 * ----------------------------------------------------------------------------
 * Scope: ONLY the "多模态训练样本" card (`.rich-sensing-visual.model-data-visual`)
 * and only its Latin strings:
 *   · .model-data-heading span   "TRAINING WINDOW / 128 STEPS"
 *   · .model-section-labels text "01 / INPUT TENSOR" "02 / TEMPORAL ENCODER"
 *                                "03 / MOTION LATENT"
 *   · .encoder-tokens text       "PRESSURE MAP" "IMU SEQUENCE"
 *                                "TIME CONTEXT" "PERSON BASELINE"
 *   · .model-bottom-meta text    "12 CHANNELS" "ALIGNED TOKENS"
 *                                "SHARED MOTION SPACE"
 *   · .latent-axes text          "X" "Y" "T"
 * Chinese copy (card title 多模态训练样本 + the bottom 连续信号…/跨模态对齐/
 * 统一运动空间 line) is deliberately left alone.
 *
 * Font is self-hosted for the same reason as Roboto/Rubik — Windows, macOS and
 * mobile must render identically and no third-party CDN may be required.
 * assets/fonts/merriweather-latin-var.woff2 is the Google Fonts latin subset
 * variable cut (OFL, weights 300-900), so one 95 KB file covers every weight we
 * use (650 in the current rules). Visual order in the stack: Merriweather ->
 * Georgia -> Times New Roman -> serif, so nothing degrades to sans-serif if the
 * webfont is blocked.
 *
 * Merriweather is a wider, larger-x-height serif than Rubik, so the SVG pill
 * labels were re-checked for overflow (see CHANGELOG §17 — letter-spacing is
 * pulled in slightly to keep "PERSON BASELINE" inside its 122-unit pill).
 * ========================================================================== */

@font-face {
  font-family: "YJ Merriweather";
  src: url("fonts/merriweather-latin-var.woff2") format("woff2");
  font-style: normal;
  font-weight: 300 900;
  font-display: swap;
}

.model-data-visual .model-data-heading span,
.model-data-visual .model-section-labels text,
.model-data-visual .encoder-tokens text,
.model-data-visual .model-bottom-meta text,
.model-data-visual .latent-axes text {
  font-family: "YJ Merriweather", Georgia, "Times New Roman", serif !important;
  font-style: normal !important;
  letter-spacing: .03em !important;
}

/* Longest pill label ("PERSON BASELINE") ran ~7 units past its 122-unit pill
 * even under the old Rubik setting, so this was already broken. Merriweather is
 * a wide serif but carries a far larger x-height, so dropping the pill labels
 * from 11px to 10px leaves the perceived size unchanged while every label now
 * ends with a positive right gap — pills stay exactly as drawn, no SVG edit. */
.model-data-visual .encoder-tokens text {
  font-size: 11px!important;
  letter-spacing: .02em !important;
}
