/* =========================================================================
 * timeline.css — the DEDICATED timeline surface.
 *
 * Kept out of bl.css deliberately: this surface arrived in the 2026-08-12
 * second play-pass alongside a parallel pass over the 3D question chrome, and
 * two sessions editing one stylesheet is how rules get lost. It is also the
 * only surface that folds the 3D stage away, so it is genuinely its own layer.
 * Loaded after bl.css in index.html; uses bl.css tokens, defines none.
 * ========================================================================= */

/* ============================================================
   THE DEDICATED TIMELINE SURFACE  (2026-08-12, second play-pass)

   Timeline questions leave the skull: `body.tl-solo` folds the 3D stage away
   and turns the floating glass column into a full-width board on paper. Since
   2026-08-13 (round 2) EVERY strand runs vertically — see the vertical-board
   block below; the horizontal `.tltrack` is retired.

   Appended as one block rather than edited into the layout rules above, so it
   can be lifted out whole if the surface changes again.
   ============================================================ */

/* --- THE SCROLL FIX (round 2, Task 3) ------------------------------------
   bl.css opens with `html,body{height:100%;overflow:hidden}` — correct for the
   3D app, where the stage is a fixed full-viewport canvas and only the glass
   panel scrolls. `body.tl-solo` then makes that panel `position:static` and as
   tall as its content — but the DOCUMENT was still clamped to the viewport
   with overflow hidden, so everything past the fold was unreachable: the lower
   rows, every extra panel opened by 'check', and the grade pills.

   This is why it was never caught. The capture harness GROWS the emulated
   viewport before shooting, so the whole board is always inside the PNG and a
   packet of twenty passes over a surface the student cannot scroll. The guard
   is now programmatic instead — tools/scroll-check.js drives a constrained
   900×700 viewport and asserts the document actually scrolls.

   Both html and body are released: html carries the height/overflow pair, so
   releasing body alone leaves the root element as a clamped scroll container. */
html.tl-solo,body.tl-solo{height:auto;min-height:100%;overflow:visible}
body.tl-solo{background:var(--page)}
body.tl-solo .main{display:block;height:auto;min-height:100vh}
body.tl-solo #stage{display:none}
body.tl-solo .stagecap{display:none}
body.tl-solo #panel,body.tl-solo #panel.wide{
  position:static;inset:auto;width:auto;max-width:none;height:auto;
  padding:96px 28px 60px;overflow:visible;background:transparent;
  -webkit-mask-image:none;mask-image:none}
body.tl-solo .top{background:var(--paper);border-bottom:1px solid var(--line)}
body.tl-solo .top .brand,body.tl-solo .top .navchip,body.tl-solo .top .sub{color:var(--ink)}

.tlsurface{max-width:1120px;margin:0 auto}
.tlhead{display:flex;align-items:center;gap:8px;margin-bottom:14px}
.tltitle{font-family:var(--serif);font-size:26px;color:var(--ink);margin:0 0 4px}
.tlband{font-size:12.5px;color:var(--ink-2);margin-bottom:8px}
.tlintro{font-size:13.5px;color:var(--ink-2);margin:0 0 18px;max-width:70ch}

/* --- the strand picker --------------------------------------------------- */
.tlpick{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px}
.tlpickcard{display:flex;flex-direction:column;gap:5px;align-items:flex-start;text-align:left;
  background:var(--paper);border:1px solid var(--line);border-radius:var(--r-lg);
  padding:16px 18px;cursor:pointer;font:inherit;transition:border-color .12s,transform .12s}
.tlpickcard:hover{border-color:var(--mid-teal);transform:translateY(-1px)}
.tlpicklab{font-family:var(--serif);font-size:17px;color:var(--ink)}
.tlpickmeta{font-size:11.5px;color:var(--ink-3);text-transform:uppercase;letter-spacing:.08em}

/* --- the event tray ------------------------------------------------------ */
.tltraylab{font-size:10.5px;text-transform:uppercase;letter-spacing:.12em;color:var(--ink-3);
  margin:0 0 6px}
.tltraylab .faint{text-transform:none;letter-spacing:0;font-size:11.5px;color:var(--ink-3);opacity:.85}
.tltray{display:flex;flex-wrap:wrap;gap:8px;min-height:44px;padding:12px;
  background:var(--sunk);border:1px dashed var(--line);border-radius:var(--r-lg);margin-bottom:20px}
.tlcard{border:1px solid var(--line);border-radius:var(--r-pill);padding:7px 15px;font-size:13px;
  background:var(--paper);color:var(--ink);cursor:grab;user-select:none;touch-action:none;
  transition:border-color .12s,box-shadow .12s}
.tlcard:hover{border-color:var(--mid-teal);box-shadow:var(--sh-sm,0 1px 3px rgba(30,58,64,.10))}
.tlcard.sel{border-color:var(--deep-teal);background:var(--teal-50);box-shadow:0 0 0 2px var(--teal-100)}
.tlcard:active{cursor:grabbing}
.tlcard-empty{font-size:12px;color:var(--ink-3);padding:6px 4px}
/* a placed event can be picked back up and carried somewhere else */
.tlslot:not(.locked) .tlslotttl{cursor:grab;touch-action:none}
.tlslot.locked .tlslotttl{cursor:default}

/* the card in flight — follows the pointer, never intercepts the hit-test that
   finds the slot underneath it */
.tlfly{position:fixed;z-index:60;pointer-events:none;transform:translate(-50%,-50%) rotate(-1.5deg);
  background:var(--paper);border:1px solid var(--deep-teal);border-radius:var(--r-pill);
  padding:8px 16px;font-size:13px;color:var(--ink);box-shadow:0 10px 24px rgba(30,58,64,.22)}
body.tl-carrying{cursor:grabbing;user-select:none}
body.tl-carrying .tlslot{transition:none}

/* --- the placement slot -------------------------------------------------- */
/* bl.css pulls .tl-origin down onto the band with a negative bottom margin —
   here that puts the rail straight through the text. Reset it for this board. */
body.tl-solo .tl-origin{margin:4px 0 10px;color:var(--ink-3)}
/* RETIRED 2026-08-13 (round 2): `.tltrackwrap` / `.tltrack` — the horizontal
   `grid-auto-flow:column` rail. It divided a nine-movement strand into nine
   ~55px columns, so an event's extra information was present but unreadable,
   and after 'check' the whole reveal sat off to the side of a board the page
   could not scroll to. RULED: every strand renders on the labour board's
   VERTICAL spine (see the vertical-board block below). The rules are deleted
   rather than left orphaned — nothing emits `.tltrack` any more. */
.tlslot{display:inline-block;text-align:left;padding:11px 14px;font-size:13px;max-width:100%;
  border:1.5px dashed var(--teal-100);border-radius:var(--r-lg);background:var(--paper);
  transition:border-color .12s,background .12s}
.tlslot.over{border-color:var(--deep-teal);background:var(--teal-50)}
.tlslot.filled{border-style:solid;border-color:var(--line);box-shadow:var(--sh-sm,0 1px 3px rgba(30,58,64,.10))}
.tlslot.ok{border-color:var(--ok);background:var(--ok-soft)}
.tlslot.bad{border-color:var(--bad);background:var(--bad-soft)}
.tlslot.locked{cursor:default}
/* the pin rides the SPINE, not the slot — the date is the fixed point the row
   is anchored to, so it belongs beside the dot with the ordinal */
.tlpin{font-size:12.5px;font-weight:700;color:var(--deep-teal);letter-spacing:.03em}
.tlpinsub{display:block;font-weight:400;font-size:11px;color:var(--ink-3);letter-spacing:0;margin-top:2px}
.tlslotbody{font-size:13px;color:var(--ink)}
.tlslotttl{font-weight:600;line-height:1.35}
.tlslot .faint{color:var(--ink-3);font-size:12px}
.tlactions{display:flex;align-items:center;gap:12px;margin:22px 0 6px}
.tlfb{font-size:12.5px;color:var(--ink-2)}

/* --- extra information: the reveal, and its grey source line ------------- */
.tl-xinfo{margin-top:8px;padding-top:8px;border-top:1px solid var(--line)}
.tl-xlab{font-size:10.5px;text-transform:uppercase;letter-spacing:.12em;color:var(--ink-3);margin-bottom:5px}
.tl-xline{font-family:var(--serif);font-size:12.5px;color:var(--ink-2);margin:0 0 6px;line-height:1.55}
.tl-xbridge{font-family:var(--serif);font-size:12.5px;color:#5c7d2b;margin:0 0 6px;line-height:1.55}
.tl-xbridge b,.tl-xflag b{font-family:var(--sans);font-size:10.5px;text-transform:uppercase;letter-spacing:.1em}
.tl-xflag{font-family:var(--serif);font-size:12.5px;color:var(--bad);margin:0 0 6px;line-height:1.55}
.tl-src{display:block;font-size:11px;color:var(--ink-3);margin-top:6px;line-height:1.45}
.tl-why{font-size:12px;color:var(--ink-3);font-style:italic;margin:2px 0 4px}
.tl-offtrack{margin-top:16px;padding-top:12px;border-top:1px solid var(--line)}
.tl-fig{margin:8px 0 10px;padding:0}
.tl-fig img{display:block;max-width:100%;height:auto;border:1px solid var(--line);border-radius:var(--r-sm)}
.tl-fig figcaption{font-size:11.5px;color:var(--ink-2);margin-top:5px;line-height:1.45}
.tl-fig-missing{font-size:11.5px;color:var(--ink-3);padding:18px;text-align:center;
  border:1px dashed var(--line);border-radius:var(--r-sm);background:var(--sunk)}

@media(max-width:900px){
  body.tl-solo #panel,body.tl-solo #panel.wide{padding:88px 16px 48px}
}

/* a strand's OWN figure — the whole-sequence plate, as against a figure that
   belongs to one node. Leads the reveal, above the per-node rows. */
.tl-deckfigs{margin:0 0 16px;padding-top:0;border-top:0}
.tl-deckfigs .tl-fig img{max-width:min(100%,760px)}

/* ============================================================
   THE VERTICAL BOARD  (2026-08-13 — birth board; round 2: EVERY strand)

   One layout for all four strands. A VERTICAL spine with cards alternating
   either side of it, chips carrying the zone (or the date pin), and — on the
   birth board — a pivot where the clock restarts. The axis is ordinal: nothing
   here is drawn to scale, which is why the unit lives on the chip and not on a
   ruler.

   The vertical layout is what makes the tier rule affordable: every row has the
   full column width, so a node's extra information can open beside it on check
   without squeezing anything (the 55px-column problem the retired horizontal
   track hit). Round 2 extends it from the birth board — the one Omer approved —
   to pregnancy's date pins, the cardinal ordering and the community stages, so
   there is no second layout left in which an extra can be unreachable.
   ============================================================ */
.tlvboard{position:relative;max-width:960px;margin:0 auto}
.tlvboard::before{content:"";position:absolute;left:50%;top:0;bottom:0;width:4px;
  transform:translateX(-2px);background:var(--teal-100);border-radius:2px}
.tlvrow{position:relative;display:flex;align-items:flex-start;margin-bottom:18px}
.tlvrow .half{width:50%;padding:0 30px;box-sizing:border-box}
.tlvrow .half.L{text-align:right}
.tlvrow .half.R{text-align:left}
.tlvdot{position:absolute;left:50%;top:14px;width:15px;height:15px;transform:translate(-50%,0);
  border-radius:50%;background:var(--paper);border:3px solid var(--teal-100);z-index:2}
.tlvdot.filled{background:var(--deep-teal);border-color:var(--deep-teal)}
.tlvside{font-size:12.5px;font-weight:600;color:var(--ink-2);padding-top:10px}
.tlvside small{display:block;font-weight:400;color:var(--ink-3);font-size:11.5px;margin-top:2px}
.tlvcard{display:inline-block;text-align:left;background:var(--paper);border:1px solid var(--line);
  border-radius:var(--r-lg);padding:12px 15px;font-size:13px;max-width:100%;
  box-shadow:var(--sh-sm,0 1px 3px rgba(30,58,64,.10))}
.tlvcard .t{font-weight:700;color:var(--ink);margin-bottom:6px}
.tlvcard .tl-l1{font-size:12.5px;color:var(--ink-2);line-height:1.5;margin-top:4px}
.tlask{margin-top:8px}
/* ROUND 3 — the TAIL ROW (Task 5b): a fixed row at the END of a placement
   spine, styled like the pre-labour-markers row that opens the birth board so
   the question "looks like a stage" (Omer's words). It is not a slot: nothing
   drops on it and it never grades as ordering. The dashed leading edge is what
   says "this is on the line, but it is not one of the steps you ordered". */
.tlvcard.tltail{border-left:3px solid var(--mid-teal)}
.tltailrow{margin-top:26px}
.tltailrow .tlvdot{background:var(--mid-teal);border-color:var(--mid-teal)}
/* ROUND 3 — a slot the REVEAL filled, as against one the student got right.
   Both are correct, and they must not read as the same achievement: the
   revealed card is the answer being shown, so it is outlined rather than
   filled, and it says so. */
.tlslot.revealed{border-style:dashed;background:var(--paper)}
.tlslot.revealed::after{content:"shown";display:block;margin-top:6px;font-size:10.5px;
  letter-spacing:.06em;text-transform:uppercase;color:var(--mid-teal)}
/* a placement slot on the spine: same footprint as a fixed card, so a board of
   drop targets and a board of fixed rows read as one surface */
.tlvrow .tlslot{min-width:min(100%,240px)}
.tlvrow .half.L .tlslot,.tlvrow .half.L .tlvcard{text-align:left}
/* the pin rides the spine as a chip — a date pin is a FIXED point on the line,
   so it reads as a marker rather than as a caption on the card beside it */
.tlvside .tlpin{display:inline-block;padding:3px 12px;border-radius:var(--r-pill);
  background:var(--teal-50);border:1px solid var(--teal-100);color:var(--deep-teal)}
.tlvside .tlpinsub{display:block;margin-top:4px}

/* zone chips carry the UNIT — the axis itself is ordinal */
.tlzone{position:relative;z-index:3;text-align:center;margin:26px 0 20px}
.tlzone span{display:inline-block;padding:5px 16px;border-radius:var(--r-pill);color:var(--paper);
  font-size:12px;font-weight:700;letter-spacing:.05em;background:var(--deep-teal)}
.tlzone .unit{display:block;margin-top:5px;background:none;color:var(--ink-3);font-size:11px;
  font-weight:400;letter-spacing:0;padding:0}
.tlzone.pivot span{background:var(--bad);font-size:13px;padding:7px 22px}
.tlzone-postpartum span{background:var(--mid-teal)}
/* the unit is a caption, never a chip — declared last so it wins over the
   zone-colour rules above (the pivot's unit rendered as a full-width red bar) */
.tlzone span.unit{display:block;margin-top:5px;background:none;color:var(--ink-3);
  font-size:11px;font-weight:400;letter-spacing:0;padding:0}

/* --- the typed normals ---------------------------------------------------- */
.tlline{margin:5px 0;line-height:1.9;color:var(--ink)}
.tlbefore,.tlafter{font-size:12.5px;color:var(--ink-2)}
.tlblank{width:82px;padding:3px 8px;font:inherit;font-size:12.5px;text-align:center;
  border:1.5px dashed var(--mid-teal);border-radius:var(--r-sm);background:var(--teal-50);color:var(--ink)}
.tlblank-sel{width:auto;min-width:96px;text-align:left;border-style:solid}
.tlblank:focus{outline:none;border-color:var(--deep-teal);border-style:solid;background:var(--paper)}
.tlblank.okc{border-style:solid;border-color:var(--ok);background:var(--ok-soft)}
.tlblank.badc{border-style:solid;border-color:var(--bad);background:var(--bad-soft)}
.tlmcq{font-size:10.5px;color:var(--ink-3);border:1px solid var(--line);border-radius:var(--r-pill);
  padding:1px 8px;margin-left:6px;background:var(--paper);cursor:pointer;vertical-align:1px}
.tlmcq:hover{border-color:var(--mid-teal);color:var(--ink-2)}
.tlfix{font-size:12px;color:var(--ink-2);margin:2px 0 6px;line-height:1.5}
.tlfix b{color:var(--ink)}
/* ROUND 4, TASK 3 — the correction chip. It sits INSIDE the thing it corrects:
   in the red slot on a placement board, on the marked card in the bucket. The
   student reads what they got wrong and what belongs there without leaving the
   row. Deliberately quiet — the red border is the alarm, this is the answer. */
.tlfix-slot{margin:6px 0 4px;padding:5px 8px;border-left:2px solid var(--bad);
  background:var(--paper);border-radius:0 var(--r-sm) var(--r-sm) 0;font-size:11.5px}
.tlfix-slot b{font-weight:650}

/* --- the loose bucket: no slot count, on purpose -------------------------- */
.tlcombined .tltray{position:relative;z-index:1;background:var(--paper)}
.tlbucket{position:relative;z-index:1;border:1.5px dashed var(--mid-teal);border-radius:var(--r-lg);
  background:var(--teal-50);padding:14px 16px;margin:6px 0 20px}
.tlbucket.over{border-style:solid;border-color:var(--deep-teal);background:var(--teal-100)}
.tlbucket .bl{font-size:10.5px;letter-spacing:.08em;text-transform:uppercase;color:var(--deep-teal);
  font-weight:700;margin-bottom:10px}
.tlbucketdrop{display:flex;flex-direction:column;gap:8px}
.tlbuckethint{font-size:11.5px;color:var(--ink-3);margin-top:10px;line-height:1.5}
.tlbucket-empty{font-size:12px;color:var(--ink-3);padding:14px 4px;text-align:center}
.tlecard{background:var(--paper);border:1px solid var(--line);border-radius:var(--r-sm);padding:9px 12px;
  font-size:12.5px}
.tlecard.ok{border-color:var(--ok);background:var(--ok-soft)}
.tlecard.bad{border-color:var(--bad);background:var(--bad-soft)}
/* ROUND 4, TASK 3 — an event that BELONGED and was left out. Not the same error
   as a decoy that was put in, so not the same mark: dashed, because the student
   never placed this card, and red-bordered, because leaving it out is still
   wrong. Its chip says where it belongs. */
.tlecard.missed{border-color:var(--bad);border-style:dashed;background:var(--paper)}
/* the reveal put this in the bucket, the student did not — same distinction the
   revealed slot draws (round 3, Task 1a) */
.tlecard.revealed{border-style:dashed;background:var(--paper)}
.tlecardhead{display:flex;align-items:center;gap:6px}
/* ROUND 3, Task 4c: tap in, tap out. The ▲▼ pair went with the order grading
   it expressed and the × with it, so the card itself has to say it is takeable
   — an affordance with no control needs words. */
.tlbucket .tlecard{cursor:pointer}
.tlbucket .tlecard:hover .tltakeout{color:var(--deep-teal)}
.tltakeout{font-size:11px;white-space:nowrap}
.tlecardhead .t{font-weight:600;color:var(--ink)}

/* the post-check "everything else" block — expanded, never behind a click */
.tl-restx{margin:22px 0 0;padding-top:14px;border-top:1px solid var(--line)}
.tl-restx .tl-correct-row{margin-bottom:14px}

@media(max-width:820px){
  .tlvboard::before{left:14px}
  .tlvrow{flex-direction:column}
  .tlvrow .half{width:100%;text-align:left;padding:0 0 0 34px}
  .tlvrow .half.L{text-align:left}
  .tlvdot{left:14px;top:8px}
  .tlvside{padding-top:0;margin-bottom:4px}
  .tlvcard{display:block}
}
