/* spinopelvic.css — layout & components for the Spinopelvic Motion Lab.
   Depends on design tokens from /assets/css/tokens.css. Self-contained otherwise. */
.m-spinopelvic{font-size:14px}
/* Objectives list inside the shared .module-objectives disclosure. */
.m-spinopelvic .objectives{margin:0;padding-left:20px}
.m-spinopelvic .objectives li{margin:2px 0}
/* ---- inline info popups ---- */
/* The marker; the popup itself is a single body-level element (.info-pop) positioned by JS, so it is never
   clipped by the sticky sidebar's scroll container or any card overflow. */
/* The "i" is DRAWN (dot + stem) rather than typeset: a lowercase glyph is centred by font ascent/descent,
   which leaves it visibly off-centre in a small circle and shifts again if the webfont falls back.
   Geometry below is symmetric about the box centre, so it is exact in any font. currentColor keeps
   the mark in sync with the hover/focus state. */
/* WCAG 2.5.8: the visible dot stays 15px, but the element is 24x24 so the TARGET meets the minimum.
   background-clip:content-box paints the circle only inside the padding, and the negative vertical margins
   stop the taller box from stretching the label's line box. */
.m-spinopelvic .info{position:relative;display:inline-block;box-sizing:border-box;width:24px;height:24px;padding:4.5px;
  border-radius:50%;background:var(--line);background-clip:content-box;color:var(--ink);font-size:0;cursor:help;
  vertical-align:middle;margin:-5px 0 -5px 3px;user-select:none;flex:none}
.m-spinopelvic .info::before, .m-spinopelvic .info::after{content:"";position:absolute;left:50%;transform:translateX(-50%);background:currentColor}
.m-spinopelvic .info::before{top:7.5px;width:2.5px;height:2.5px;border-radius:50%}
/* tittle */
.m-spinopelvic .info::after{top:11px;width:2.5px;height:5.5px;border-radius:1.25px}
/* stem → mark centred in the 24px box */
.m-spinopelvic .info:hover{background:var(--blue);background-clip:content-box;color:#fff}
/* 2.4.7: the focus ring must never be suppressed here; an earlier revision of this rule removed it. */
.m-spinopelvic .info:focus-visible{background:var(--blue);background-clip:content-box;color:#fff;
  outline:3px solid #4c8fe8;outline-offset:1px}
/* 1.4.13: the tip must be hoverable (so it can be reached to read or select) and must not vanish on its own. */
.info-pop{position:fixed;z-index:9999;max-width:260px;background:var(--ink);color:#fff;
  font:400 11.5px/1.5 var(--sans);text-align:left;padding:8px 10px;border-radius:8px;
  box-shadow:0 6px 20px rgba(0,0,0,.28);opacity:0;visibility:hidden;transition:opacity .12s}
.info-pop.show{opacity:1;visibility:visible}
/* ---- references block ---- */
.m-spinopelvic .srcs li{font-size:12px}
.m-spinopelvic .tiny code{font-family:var(--mono);font-size:.92em;background:var(--wash);padding:1px 5px;border-radius:5px}
.m-spinopelvic .simulator-main{max-width:min(1720px,95vw);margin:auto;padding:14px 18px 28px;display:grid;grid-template-columns:340px minmax(0,1fr);gap:14px}
.m-spinopelvic .simulator-main>*{min-width:0}
.m-spinopelvic .card{background:var(--surface);border:1px solid var(--line);border-radius:14px;box-shadow:0 5px 20px rgba(22,32,43,.06)}
.m-spinopelvic aside{padding:15px;align-self:start;position:sticky;top:10px;max-height:calc(100vh - 20px);overflow-y:auto;overflow-x:hidden}
.m-spinopelvic .section{padding:13px 0;border-top:1px solid var(--line)}
.m-spinopelvic .section:first-child{padding-top:0;border:0}
.m-spinopelvic h2{font-family:var(--serif);font-size:14px;font-weight:600;margin:0 0 9px}
.m-spinopelvic .presets{display:grid;grid-template-columns:1fr 1fr;gap:6px}
.m-spinopelvic button{min-height:44px;padding:8px 9px;border:1px solid var(--line);border-radius:8px;background:#fff;font-family:var(--sans);font-weight:600;color:var(--ink);cursor:pointer}
.m-spinopelvic .preset{min-height:44px;font-size:11px;text-align:left;line-height:1.2}
.m-spinopelvic .preset .g{display:block;font-size:9px;color:var(--muted);font-weight:700;letter-spacing:.5px}
.m-spinopelvic .preset.active{background:var(--wash);border-color:var(--blue);color:var(--blue)}
.m-spinopelvic .preset.active .g{color:var(--blue)}
.m-spinopelvic .actions{display:flex;gap:7px}
.m-spinopelvic .actions button{flex:1}
.m-spinopelvic .primary{background:var(--blue);border-color:var(--blue);color:#fff}
.m-spinopelvic .control{display:grid;grid-template-columns:1fr 68px;gap:8px;align-items:center;margin:8px 0}
.m-spinopelvic .control label{font-size:11px;color:var(--muted);line-height:1.25}
/* 1.4.11: a control's boundary needs 3:1. The token --line is 1.29:1 on white — fine for decorative card
   edges, not for something that has to read as an input. Scoped to controls so card borders keep the light look. */
.m-spinopelvic .control input[type=number]{width:68px;min-height:44px;padding:6px 8px;border:1px solid #8f9499;border-radius:7px;font-family:var(--mono)}
.m-spinopelvic .control input[type=number]:focus-visible{outline:3px solid #4c8fe8;outline-offset:1px;border-color:var(--blue)}
.m-spinopelvic input[type=range]:focus-visible{outline:3px solid #4c8fe8;outline-offset:3px}
.m-spinopelvic .wide{width:100%}
.m-spinopelvic details summary{cursor:pointer;font-weight:700;font-size:12px}
.m-spinopelvic .tiny{font-size:10px;color:var(--muted);line-height:1.4}
.m-spinopelvic .workspace{display:grid;gap:12px}
/* ---- guided first task ---- */
.m-spinopelvic .tour{padding:13px 15px;border-left:3px solid var(--blue)}
.m-spinopelvic .tour-head{display:flex;align-items:center;gap:9px;margin-bottom:6px}
.m-spinopelvic .tour-head h3{font-family:var(--serif);font-size:14px;font-weight:600;margin:0;color:var(--ink);flex:1}
.m-spinopelvic .tour-step{font-family:var(--mono);font-size:10px;color:var(--muted);letter-spacing:.04em}
.m-spinopelvic .tour-text{margin:0 0 4px;font-size:12.5px;line-height:1.55;color:var(--ink);max-width:78ch}
.m-spinopelvic .tour-take{margin:0 0 10px;font-size:12.5px;line-height:1.55;color:var(--blue);max-width:78ch}

/* Pinned step readouts — the numbers the current step's claim rests on, beside the claim. */
.m-spinopelvic .tour-watch{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 8px}
.m-spinopelvic .tour-watch[hidden]{display:none}
.m-spinopelvic .tour-watch-item{display:inline-flex;align-items:baseline;gap:6px;padding:5px 10px;
  border:1px solid var(--line);border-left:3px solid #F2B01E;border-radius:8px;background:#fffdf5}
.m-spinopelvic .tour-watch-label{font-size:11px;color:var(--muted)}
.m-spinopelvic .tour-watch-value{font-size:14px;font-variant-numeric:tabular-nums;color:var(--ink)}

/* Spotlight — the veil fades in so the eye is led to the cutout rather than startled by it.
   The ring is the only moving part; it must never suggest an interactive control. */
.m-spinopelvic .spot-veil{transition:opacity .28s ease-out}
@starting-style{ .m-spinopelvic .spot-veil{opacity:0} }
.m-spinopelvic .spot-ring{animation:spotPulse 2.4s ease-in-out infinite}
@keyframes spotPulse{0%,100%{opacity:.95}50%{opacity:.45}}
@media (prefers-reduced-motion: reduce){
  /* No pulsing and no fade: the cutout still directs the eye, it just does not move. */
  .m-spinopelvic .spot-ring{animation:none}
  .m-spinopelvic .spot-veil{transition:none}
}
.m-spinopelvic .tour-note{margin:8px 0 0;font-size:10.5px;color:var(--muted)}
.m-spinopelvic .tour:focus-visible{outline:3px solid #4c8fe8;outline-offset:2px}
.m-spinopelvic .tour-actions{display:flex;gap:7px}
.m-spinopelvic .tour-actions button{min-height:44px;padding:6px 13px;font-size:11.5px}
.m-spinopelvic .tour-actions button:disabled{opacity:.4;cursor:default}
.m-spinopelvic .tour-reopen{padding:7px 14px;font-size:12px;color:#fff;background:var(--blue);
  border:1px solid var(--blue);border-radius:8px}
.m-spinopelvic .tour-reopen:hover{background:var(--blue-dark);border-color:var(--blue-dark)}
.m-spinopelvic .nowrap{white-space:nowrap}
.m-spinopelvic .topline{padding:11px 14px;display:flex;justify-content:space-between;align-items:center;gap:10px;flex-wrap:wrap}
.m-spinopelvic .phase{font-weight:600}
.m-spinopelvic .phase span{color:var(--blue);font-weight:700}
.m-spinopelvic .badge{display:inline-block;border-radius:999px;padding:4px 8px;font-size:10px;font-weight:700}
/* 1.4.3: badge text is 10px bold, which is NOT "large" under WCAG (that needs 18.66px bold), so these
   need the full 4.5:1. The stock green and amber measured 4.35 and 3.25 against their washes. */
.m-spinopelvic .good{background:#E4F2EA;color:#197c4a}
.m-spinopelvic .warn{background:#FBF1DE;color:#966319}
.m-spinopelvic .bad{background:#F7E4E3;color:var(--red)}
.m-spinopelvic .grp{background:#ECE7F7;color:var(--purple)}
/* The figure canvas is cropped to its real content (portrait ~0.82), so its column is capped near
   height x 0.82 — any wider and the SVG would letterbox and re-introduce dead space inside the panel.
   The right column takes the remainder and stacks the graph + comparison table to balance the row. */
.m-spinopelvic .views{display:grid;grid-template-columns:minmax(380px,560px) minmax(320px,1fr);gap:14px;align-items:start}
.m-spinopelvic .panel{padding:10px}
.m-spinopelvic .panel h3{font-family:var(--serif);font-size:12px;font-weight:600;margin:0 0 7px;color:var(--ink)}
.m-spinopelvic .svgbox{background:linear-gradient(#ffffff,var(--wash));border:1px solid var(--line);border-radius:10px;overflow:hidden}
.m-spinopelvic .svgbox svg{width:100%;height:auto;display:block}
/* cap the near-square anatomy so it doesn't force a very tall row on standard monitors, and cap its
   width so it never floats in an oversized panel when the workspace is single-column (tablet/laptop). */
.m-spinopelvic #anatomy{max-height:min(74vh,680px);margin-inline:auto}
/* right-column panels stack full-width so each stays legible; capped so they never stretch on ultra-wide screens. */
.m-spinopelvic .rightcol{display:grid;grid-template-columns:1fr;gap:12px;align-content:start}
.m-spinopelvic #graph{max-width:620px;margin-inline:auto}
/* live readouts — kept deliberately compact so the strip costs one short row, not a band of boxes */
.m-spinopelvic .metrics{display:grid;grid-template-columns:repeat(10,1fr);gap:5px}
.m-spinopelvic .metric{padding:4px 6px 5px;border:1px solid var(--line);border-radius:8px;background:var(--wash)}
.m-spinopelvic .metric b{display:block;font-family:var(--mono);font-size:14px;line-height:1.2}
.m-spinopelvic .metric span{display:block;font-size:8.5px;line-height:1.25;color:var(--muted)}
/* Metric labels containing an info control need a real two-column row. The general
   `.metric span` rule otherwise makes the nested icon a block, so it drops beneath the
   label and its expanded touch target appears visibly offset. The icon still keeps its
   44px hit region; negative margins reduce only the space that region contributes. */
.m-spinopelvic .metric>span:has(>.info){display:grid;grid-template-columns:minmax(0,1fr) 24px;
  align-items:center;column-gap:2px;padding-right:0}
.m-spinopelvic .metric>span>.info{display:inline-block;justify-self:center;align-self:center;
  margin:-10px;width:44px;height:44px;vertical-align:middle;font-size:0}
.m-spinopelvic .cmp{width:100%;border-collapse:collapse;font-size:11px}
.m-spinopelvic .cmp th, .m-spinopelvic .cmp td{padding:5px 7px;text-align:right;border-bottom:1px solid var(--line)}
.m-spinopelvic .cmp td:not(:first-child){font-family:var(--mono)}
.m-spinopelvic .cmp th:first-child, .m-spinopelvic .cmp td:first-child{text-align:left;color:var(--muted)}
.m-spinopelvic .cmp thead th{font-size:10px;color:var(--ink)}
.m-spinopelvic .cmp .hl{font-weight:700}
/* Row labels are now <th scope="row"> for 1.3.1; keep them looking exactly as they did as <td>. */
.m-spinopelvic .cmp tbody th{font-weight:400}
.m-spinopelvic .lower{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.m-spinopelvic .textpanel{padding:12px}
.m-spinopelvic .textpanel h3{font-family:var(--serif);font-weight:600}
.m-spinopelvic .textpanel p{font-size:12px;line-height:1.48;margin:7px 0}
.m-spinopelvic .bars{margin-top:8px}
.m-spinopelvic .barrow{display:grid;grid-template-columns:82px 1fr 34px;gap:6px;align-items:center;font-size:10px;margin:6px 0}
.m-spinopelvic .barrow b{font-family:var(--mono)}
.m-spinopelvic .bar{height:7px;background:#E7ECF2;border-radius:999px;overflow:hidden}
.m-spinopelvic .fill{height:100%;background:var(--blue)}
.m-spinopelvic .legend{display:flex;flex-wrap:wrap;gap:8px;margin-top:6px;font-size:9px;color:var(--muted)}
.m-spinopelvic .sw{display:inline-block;width:12px;height:3px;margin-right:4px;vertical-align:middle}
.m-spinopelvic .guide{font-size:12px;line-height:1.5}
.m-spinopelvic .guide b{color:var(--ink)}
/* --- WIDE workspace (>=1100px): rail + figure + right column all visible together. --- */
@media(min-width:1100px) and (max-width:1550px){.m-spinopelvic .metrics{grid-template-columns:repeat(5,1fr)}}
@media(min-width:1100px) and (max-width:1320px){
  .m-spinopelvic .views{grid-template-columns:1fr}
  .m-spinopelvic .lower{grid-template-columns:1fr 1fr}
}
/* ====================================================================================
   §8 Responsive learning workspace — three layout modes.
   Teaching task: REACTIVE 2D SIMULATION, so the standard's prescribed patterns apply —
   figure and controls together while they fit, and in the focused mode a persistent model
   above a result strip, controls in a sheet, secondary panels in named tabs.
   Breakpoints are content-driven, taken from where THIS layout actually breaks:
     >=1100px  WIDE     340px control rail + figure + right column all coexist.
     760-1099  COMPACT  the right column can no longer hold a legible graph beside the
                        figure, so it drops below and the rail narrows to 264px.
     <760px    FOCUSED  a 264px rail plus a legible figure no longer coexist.
   ==================================================================================== */

/* ---- COMPACT: keep the visualisation, narrow the rail, stack the secondary column ---- */
@media(min-width:760px) and (max-width:1099px){
  .m-spinopelvic .simulator-main{grid-template-columns:264px minmax(0,1fr);gap:12px}
  .m-spinopelvic .views{grid-template-columns:minmax(0,1fr)}
  .m-spinopelvic #anatomy{max-height:min(58vh,520px)}
  .m-spinopelvic .metrics{grid-template-columns:repeat(5,1fr)}
  .m-spinopelvic .lower{grid-template-columns:1fr 1fr}
}

/* ---- FOCUSED: visualisation-first; controls and secondary panels move into the sheet ----
   The hidden regions are MOVED into the sheet at runtime, never cloned, so control state,
   accessible names and focus behaviour stay single-sourced. */
@media(max-width:759px), (max-width:950px) and (max-height:520px){
  /* Reveals the shared Start Here entry action (module-patterns.css). Hidden at wider
     sizes, where the module is already visible and there is no workspace to open. */
  .m-spinopelvic .module-start-actions,.module-start-actions{--enter-action:inline-flex;}
  /* Flex + order, not block: the aside is FIRST in the DOM (correct for desktop and for reading
     order without CSS), but on a phone the model must come first so the sticky figure sits above
     the controls the learner is operating. */
  .m-spinopelvic .simulator-main{display:flex;flex-direction:column;padding:10px 10px 0}
  .m-spinopelvic #module-controls{order:2;display:none}
  /* Everything that is not the model leaves the interaction path. The walkthrough card and its
     note were sitting between the figure and the controls; they are reachable from Start here
     and from the sheet, so they must not occupy the loop. */
  .m-spinopelvic .rightcol,
  .m-spinopelvic .metrics,
  .m-spinopelvic .lower,
  .m-spinopelvic .topline,
  .m-spinopelvic .tour-note{display:none}
  /* The phone default is the model, not a compressed desktop rail. Adjust opens the real
     controls in a bottom sheet while the dock keeps every task one tap away. */
  .m-spinopelvic #module-controls{padding:10px 12px;margin:0;border-radius:12px}
  .m-spinopelvic #module-controls .section.is-primary{padding:9px 0}
  .m-spinopelvic #module-controls .section.is-primary:first-of-type{padding-top:0;border-top:0}
  .m-spinopelvic .presets{grid-template-columns:repeat(2,1fr);gap:5px}
  .m-spinopelvic .preset{font-size:10.5px;padding:7px 8px}
  .m-spinopelvic .fw-sheet-body #module-controls{display:block}
  .m-spinopelvic .fw-sheet-body #module-controls>details{display:block}
  /* The walkthrough must still be able to OPEN on a phone. It is hidden by its own [hidden]
     attribute until launched, so a blanket display:none here made it unopenable — never add
     .tour to the list above. When open it sits directly under the figure it is narrating. */
  /* The walkthrough must sit ABOVE the sticky figure. .views carries z-index:12 and an opaque
     background, so an unpositioned .tour was painted under it and the figure also intercepted the
     taps — Next looked dead. Give the panel its own stacking context with a higher z-index, and
     pin it to the bottom of the viewport so it is reachable no matter where the page is scrolled. */
  .m-spinopelvic .tour{position:sticky;z-index:30;margin:10px 0 0;padding:11px 12px;
    /* Clear the fixed contextual bar (~62px + safe area) which is also bottom-anchored, or the
       walkthrough's Back/Next row hides behind it. */
    bottom:calc(70px + env(safe-area-inset-bottom,0px));
    box-shadow:0 -6px 18px rgba(22,32,43,.18)}
  .m-spinopelvic .tour[hidden]{display:none}
  .m-spinopelvic .views{grid-template-columns:1fr;gap:0}
  /* Sticky needs a scrolling ancestor that spans BOTH the figure and the controls. The figure's
     nearest one is .workspace, which ends before #module-controls begins — sticking the figure
     there would release it exactly as the controls come into view. So .views (figure + result
     strip, the part that must stay visible) is the sticky element, and .workspace is made
     `display:contents` so .views becomes a direct child of .simulator-main, which spans both. */
  .m-spinopelvic .workspace{display:contents}
  .m-spinopelvic #module-visualization{margin:0}
  .m-spinopelvic .views{position:sticky;top:8px;z-index:12;order:1;background:var(--bg);
    padding-bottom:6px;box-shadow:0 6px 12px -8px rgba(22,32,43,.35)}
  .m-spinopelvic .tour{order:3}   /* after the controls in flow; sticky-bottom keeps it on screen */
  .m-spinopelvic #anatomy{max-height:min(52svh,520px)}
  .m-spinopelvic #module-visualization .legend{display:none}
  /* Beat the base `aside{position:sticky}` rule: two sticky regions would fight each other. */
  .m-spinopelvic aside#module-controls{position:static;max-height:none}
  .m-spinopelvic .module-evidence,
  .m-spinopelvic .module-bottom-actions{margin-bottom:82px}
}
/* Short viewports (landscape phone, 200% zoom): the figure must stay interpretable. */
@media(max-width:950px) and (max-height:520px){
  .m-spinopelvic #anatomy{max-height:62svh}
  .m-spinopelvic .fw-sheet-panel{max-height:min(88dvh,520px)}
}

/* Result strip — the concise current result the standard requires beside the model.
   Same ordering hazard as the bar: visibility lives in one query, not in the base rule. */
.m-spinopelvic .fw-strip{display:block;margin:8px 0 0;padding:8px 10px;border-radius:8px;
  background:var(--wash);color:var(--ink);font:600 12px/1.45 var(--sans)}
@media(min-width:760px) and (min-height:521px), (min-width:951px){.m-spinopelvic .fw-strip{display:none}}

/* ---- Dedicated portrait workspace (768-1023) ------------------------------------------
   The figure takes the dominant area and the controls sit in a persistent rail beside it,
   with no dependence on the phone sheet. Input density remains capability-driven below. */
@media (min-width:768px) and (max-width:1023px) and (orientation:portrait){
  .m-spinopelvic .simulator-main{grid-template-columns:minmax(0,1fr) 300px;gap:14px;align-items:start}
  .m-spinopelvic #module-controls{order:2;position:sticky;top:10px;max-height:calc(100dvh - 24px);
    overflow-y:auto;padding:14px}
  .m-spinopelvic .workspace{order:1;display:grid;gap:12px}
  .m-spinopelvic .views{grid-template-columns:1fr}
  .m-spinopelvic #anatomy{max-height:min(62dvh,700px)}
  .m-spinopelvic .presets{grid-template-columns:1fr 1fr}
  .m-spinopelvic .control{grid-template-columns:1fr 84px;margin:11px 0}
  .m-spinopelvic .control input[type=number]{width:84px}
  .m-spinopelvic .metrics{grid-template-columns:repeat(5,1fr)}
  .m-spinopelvic .lower{grid-template-columns:1fr}
  .m-spinopelvic .fw-dock,.m-spinopelvic .fw-bar{display:none}
}
/* Tablet landscape keeps side-by-side, but touch-sized rather than desktop-dense. */
@media (min-width:1024px) and (max-width:1366px) and (orientation:landscape) and (pointer:coarse){
  .m-spinopelvic .simulator-main{grid-template-columns:320px minmax(0,1fr)}
  /* Redundant with the generic (pointer:coarse) rule; kept as explicit layout intent. */
  .m-spinopelvic .presets{gap:9px}
  .m-spinopelvic .control{margin:11px 0}
}

/* Contextual bar — compact, and visually distinct from the global site header.
   Its VISIBILITY is owned by the single min-width query below, never by a bare `display` here.
   A previous revision declared display:none in this base rule, which sat AFTER the focused-mode
   `display:flex` at equal specificity (0,2,0) and silently won — leaving phone users with the
   model and no way to reach the controls. Keep display out of this block. */
.m-spinopelvic .fw-bar{position:fixed;left:0;right:0;bottom:0;z-index:40;
  display:flex;align-items:center;gap:10px;padding:9px 12px calc(9px + env(safe-area-inset-bottom,0px));
  background:var(--ink);color:#fff;box-shadow:0 -4px 16px rgba(22,32,43,.24)}
/* JS owns the hidden attribute; [hidden] must beat the flex above, hence !important. */
.m-spinopelvic .fw-bar[hidden]{display:none!important}
/* Wide and compact modes have the controls on the page, so the bar is not needed there. */
@media(min-width:760px) and (min-height:521px), (min-width:951px){.m-spinopelvic .fw-bar{display:none!important}}
.m-spinopelvic .fw-bar-state{flex:1;min-width:0;font:600 11.5px/1.35 var(--mono);color:#dfe6f0}

/* Controls sheet — titled, closeable, size-limited; it never covers the result strip. */
.m-spinopelvic .fw-sheet{position:fixed;inset:0;z-index:60;display:flex;align-items:flex-end}
.m-spinopelvic .fw-sheet[hidden]{display:none}
.m-spinopelvic .fw-sheet-scrim{position:absolute;inset:0;background:rgba(22,32,43,.34)}
.m-spinopelvic .fw-sheet-panel{position:relative;width:100%;max-height:min(72dvh,560px);
  display:flex;flex-direction:column;background:var(--surface);border-radius:16px 16px 0 0;
  box-shadow:0 -10px 30px rgba(22,32,43,.3);padding-bottom:env(safe-area-inset-bottom,0px);
  transition:transform .18s ease}
@media(prefers-reduced-motion:reduce){.m-spinopelvic .fw-sheet-panel{transition:none}}
.m-spinopelvic .fw-sheet-panel:focus-visible{outline:3px solid #4c8fe8;outline-offset:-3px}
.m-spinopelvic .fw-sheet-head{display:flex;align-items:center;gap:10px;padding:12px 14px 6px}
.m-spinopelvic .fw-sheet-title{flex:1;margin:0;font:600 15px/1.2 var(--serif);color:var(--ink)}
.m-spinopelvic .fw-sheet-x{flex:none;width:44px;height:44px;border:1px solid var(--line);
  border-radius:50%;background:var(--surface);color:var(--ink);font-size:14px;line-height:1}
.m-spinopelvic .fw-tabs{display:flex;gap:4px;padding:0 14px;border-bottom:1px solid var(--line)}
.m-spinopelvic .fw-tabs button{min-height:44px;padding:8px 11px;border:0;border-radius:0;
  border-bottom:2px solid transparent;background:none;color:var(--muted);font:600 12px/1.2 var(--sans)}
.m-spinopelvic .fw-tabs button[aria-selected=true]{color:var(--blue);border-bottom-color:var(--blue)}
.m-spinopelvic .fw-sheet-body{flex:1;overflow-y:auto;-webkit-overflow-scrolling:touch;padding:12px 14px 18px}
/* Regions are moved in, so neutralise the desktop card chrome they carry. */
.m-spinopelvic .fw-sheet-body>*{display:block!important;position:static!important;
  max-height:none!important;width:auto!important;margin:0 0 12px!important;
  box-shadow:none!important;border:0!important;padding:0!important}
.m-spinopelvic .fw-sheet-body .metrics{display:grid!important;grid-template-columns:repeat(2,1fr)!important;gap:6px}
.m-spinopelvic .fw-sheet-body .rightcol,
.m-spinopelvic .fw-sheet-body .lower{display:grid!important;grid-template-columns:1fr!important;gap:12px}

/* "What this means" is expanded by default so interpretation remains visible beside/below the
   model on desktop. It stays a disclosure so learners may collapse it when they need more space. */
.m-spinopelvic #whatThisMeans>summary{list-style:none;cursor:pointer;
  font:600 12px/1.3 var(--serif);color:var(--ink);padding:2px 0}
.m-spinopelvic #whatThisMeans>summary::-webkit-details-marker{display:none}
.m-spinopelvic #whatThisMeans>summary::before{content:"\25B8  ";color:var(--muted)}
.m-spinopelvic #whatThisMeans[open]>summary::before{content:"\25BE  "}
.m-spinopelvic #whatThisMeans>summary:focus-visible{outline:3px solid #4c8fe8;outline-offset:2px;border-radius:6px}


/* ---- §8 direct interaction: the femur drag handle ----------------------------------
   The handle is the only direct manipulation; cup anteversion and component sizing are
   numeric implant parameters and stay as conventional controls under Advanced. */
.m-spinopelvic #hits [data-fem]{cursor:grab}
.m-spinopelvic #hits [data-fem]:active{cursor:grabbing}
.m-spinopelvic #hits [data-fem]:focus-visible{outline:3px solid #4c8fe8;outline-offset:2px}

/* §8 target size: 44x44 for primary, repeated, navigation, tutorial and direct-model controls.
   The info markers keep a 24px visible mark because they sit inline in label text, where a 44px
   box would break the line box. Their hit region is expanded with an outline-less transparent
   border instead — NOT with ::after, which already draws the "i" stem and would be erased. */
.m-spinopelvic .info{border:10px solid transparent;background-clip:content-box;
  width:44px;height:44px;padding:4.5px;margin:-15px 0 -15px -7px}

/* ---- §8 input capability ------------------------------------------------------------
   Capability is independent of workspace size: a 1180 px tablet gets the WIDE layout and is
   still touch-only, while a narrow desktop window gets the FOCUSED layout with a mouse and
   keyboard. These queries key off the input, never off width, and adjust presentation only —
   behaviour and validation stay identical across every input route. */
@media (pointer: coarse), (hover: none) {
  /* Comfortable separation for fingers. Targets are already 44px in the base layer; this adds
     the spacing the standard asks for so adjacent controls are not mis-activated. */
  .m-spinopelvic .presets{gap:9px}
  .m-spinopelvic .actions{gap:10px}
  .m-spinopelvic .tour-actions{gap:10px;flex-wrap:wrap}
  .m-spinopelvic .fw-tabs{gap:8px}
  .m-spinopelvic .control{margin:11px 0}
  /* The drag handle is the one direct-manipulation target; make it unmistakably grabbable. */
  .m-spinopelvic #hits [data-fem] circle:nth-of-type(2){stroke-width:3}
}
@media (hover: hover) and (pointer: fine) {
  /* Hover is supplementary only — every one of these is also reachable by tap, click,
     focus and keyboard, so nothing here is required to discover or operate a feature. */
  .m-spinopelvic .preset:hover{border-color:var(--blue)}
  .m-spinopelvic #hits [data-fem]:hover circle:nth-of-type(2){stroke-width:3}
}

/* ---- Task dock (focused workspace) ---------------------------------------------------
   A persistent 4-task dock replaces the old single "More controls" button: each entry opens
   the sheet directly at its section, so reaching a task is one tap. */
.m-spinopelvic .fw-dock{position:fixed;left:0;right:0;bottom:0;z-index:45;display:none;
  grid-template-columns:repeat(5,minmax(0,1fr));gap:2px;
  padding:4px max(6px,env(safe-area-inset-left)) calc(4px + env(safe-area-inset-bottom)) max(6px,env(safe-area-inset-right));
  background:var(--ink);border-top:1px solid rgba(255,255,255,.15);box-shadow:0 -5px 18px rgba(0,0,0,.28)}
.m-spinopelvic .fw-dock[hidden]{display:none}
.m-spinopelvic .fw-dock button{display:grid;grid-template-rows:18px auto;place-items:center;
  min-width:0;min-height:50px;padding:3px 2px;border:0;border-radius:8px;background:transparent;
  color:#c3d0dd;font:750 9.5px/1 var(--sans);cursor:pointer;
  /* Five tasks have to fit a 320px phone without wrapping or clipping a label. */
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.m-spinopelvic .fw-dock button>span{color:#9ec2f5;font:800 15px/1 var(--mono)}
.m-spinopelvic .fw-dock button.is-active{color:#fff;background:rgba(158,194,245,.16)}
.m-spinopelvic .fw-dock button.is-active>span{color:#fff}
.m-spinopelvic .fw-dock button:focus-visible{outline:3px solid #9ec2f5;outline-offset:-2px}
@media(max-width:759px), (max-width:950px) and (max-height:520px){
  .m-spinopelvic .fw-dock{display:grid}
  /* Clear the dock: page tail, sheet and walkthrough must not sit under it. */
  .m-spinopelvic .module-evidence,
  .m-spinopelvic .module-bottom-actions{margin-bottom:calc(76px + env(safe-area-inset-bottom))}
  .m-spinopelvic .fw-sheet-panel{padding-bottom:calc(58px + env(safe-area-inset-bottom))}
  .m-spinopelvic .tour{bottom:calc(76px + env(safe-area-inset-bottom))}
}
/* The old single-button bar no longer exists; the bar now carries only the state readout. */
.m-spinopelvic .fw-bar{bottom:calc(58px + env(safe-area-inset-bottom))}

/* ---- Workspace mode -------------------------------------------------------------------------
   Entered from "Open interactive workspace" on small/touch screens. The old behaviour was an
   anchor that scrolled, leaving the hero and prose above the figure so it still read as a page.
   Here the teaching surface owns the viewport and everything explanatory steps aside until the
   learner exits. This is a reversible class on <main>, not the Fullscreen API — see the note in
   spinopelvic.js for why. */
.m-spinopelvic .fw-exit{position:fixed;top:calc(8px + env(safe-area-inset-top));
  left:max(8px,env(safe-area-inset-left));z-index:50;display:inline-flex;align-items:center;gap:6px;
  min-height:44px;padding:9px 14px;border:1px solid rgba(255,255,255,.22);border-radius:999px;
  background:var(--ink);color:#fff;font:750 12.5px/1 var(--sans);cursor:pointer;
  box-shadow:0 3px 14px rgba(0,0,0,.3)}
.m-spinopelvic .fw-exit[hidden]{display:none}
.m-spinopelvic .fw-exit:focus-visible{outline:3px solid #9ec2f5;outline-offset:2px}

/* Scroll lock belongs on the root so the page behind cannot scroll under the workspace. */
.sp-workspace-lock, .sp-workspace-lock body{overflow:hidden}

@media(max-width:759px), (max-width:950px) and (max-height:520px){
  /* Everything that explains the module rather than being the module. */
  .m-spinopelvic.is-workspace .tool-hero,
  .m-spinopelvic.is-workspace .notice-band,
  .m-spinopelvic.is-workspace .module-start,
  .m-spinopelvic.is-workspace .module-evidence,
  .m-spinopelvic.is-workspace .module-bottom-actions{display:none}
  /* The SITE header and footer are siblings of <main>, not descendants, so no rule scoped under
     .m-spinopelvic can reach them — the first version of this mode left half a header and half a
     footer framing the workspace. The state class is mirrored onto <html> for exactly this reason;
     scope anything outside <main> to that, never to .m-spinopelvic. */
  .sp-workspace-lock .site-header,
  .sp-workspace-lock .site-footer{display:none}
  /* .workspace is display:contents in focused mode (see the sticky note above), so padding on it is
     discarded — the figure ended up under the fixed Exit button. Put the offset on the grid that
     actually generates a box. */
  .m-spinopelvic.is-workspace .simulator-main{gap:8px;padding-top:calc(56px + env(safe-area-inset-top))}
  .m-spinopelvic.is-workspace #anatomy{max-height:calc(100dvh - 210px - env(safe-area-inset-bottom))}
  /* The walkthrough inside workspace mode. It is reached from the dock's Tour task, so it must sit
     clear of the dock (76px) AND of the figure, and it must not be pushed off-screen by the
     figure's own height — hence a hard cap with its own scroll rather than relying on the page. */
  .m-spinopelvic.is-workspace .tour{
    bottom:calc(84px + env(safe-area-inset-bottom,0px));
    max-height:min(46dvh,340px);overflow-y:auto;
    box-shadow:0 -8px 22px rgba(22,32,43,.26)}
  /* With the walkthrough open the figure yields height to it, so both stay on screen at once —
     a spotlight the learner has to scroll to find is not directing anything. */
  .m-spinopelvic.is-workspace:has(.tour:not([hidden])) #anatomy{
    max-height:calc(100dvh - 210px - min(46dvh,340px) - env(safe-area-inset-bottom))}
}
/* Workspace mode is a small-screen affordance only. If the viewport grows past the focused
   breakpoint the class may still be present for one frame before the resize handler clears it;
   this makes that frame harmless rather than a page with its hero missing. */
@media(min-width:760px){
  .sp-workspace-lock .site-header,
  .sp-workspace-lock .site-footer{display:revert}
  .m-spinopelvic.is-workspace .tool-hero,
  .m-spinopelvic.is-workspace .notice-band,
  .m-spinopelvic.is-workspace .module-start,
  .m-spinopelvic.is-workspace .module-evidence,
  .m-spinopelvic.is-workspace .module-bottom-actions{display:revert}
  .m-spinopelvic .fw-exit{display:none}
}
