/* Layout shell. .tpl-form-card chrome lives in public/css/templates.css
   (single source) — this file only carries the start-screen-specific
   layout, typography, and form-control rules that don't generalise. */
/* THE GAP ABOVE THE PAGE HEADING IS HALVED (2026-08-26), and it is a token now.
   padding-top was the literal 48px — the distance from the nav to the kicker on setup and
   to the h1 on manage, the same declaration serving both. Halved to 24px, which is
   --space-lg on tokens.css's own scale, so this is a value the page already knows rather
   than 48/2 written down. Measured before and after at 1280: 48 -> 24 on
   /templates/blank_ms/start (to the kicker) and /f/WPROBE01/session (to the h1).
   The 24px sides and 80px bottom are untouched and still literal; only the top was asked
   for and only the top is a token, which is honest about which one has been thought about. */
.tpl-start{position:relative;max-width:var(--tpl-canvas-width,1100px);margin:0 auto;padding:var(--space-lg) 24px 80px;}
/* ── <=640: THE PAGE'S TOP INSET IS THE ONE GAP (2026-08-31) ───────────────────────
   var(--space-lg) computes 36px here, which is a third distance above a page whose every
   other distance is --tpl-gap. The space above the FIRST object is the same relationship
   as the space between two objects, so it reads the same token — and on a phone that token
   is retuned (templates.css, THE PHONE RETUNES THE ONE GAP), so this follows automatically
   instead of needing its own number.
   [HARD] IT LIVES HERE, BESIDE THE SHORTHAND, AND NOT WITH THE TOKEN. The base padding is a
   SHORTHAND in this file; this style block is pushed after templates.css, so a longhand
   `padding-top` written there loses to it at equal specificity however late in that file it
   sits. Written there first and measured: the switcher did not move a pixel. A longhand
   above a shorthand is a deletion, not an override — and across two files it is not even
   visible as one. */
@media(max-width:640px){
    .tpl-start{padding-top:var(--tpl-gap);}
}
/* Setup AND manage (not slim): narrow the shared content cards so they sit
   between the 700px Session Title and the old ~1050px full width. The cards live
   inside the setup <form id="tpl-start-form"> (a wrapper between .tpl-start and the
   cards), so the path threads through it; the `#tpl-start-form >` child combinator
   then targets ONLY the top-level shared cards + the structural-region wrapper and
   stays off the nested criterion/section cards, which correctly fill their 840px
   parent. Manage now rides the SAME band as setup so the shared cards (Session
   Overview, Welcome, sections, Completion, Advanced) match width across both pages
   — the manage-only cards (Response Management, Results & Analysis, Documents) are
   each wrapped in their own .tpl-manage container, so the `>` child combinator
   never reaches them and they keep their full 1100px width. The slim
   availability-poll keeps its own two-card layout. The submit-button row
   (.tpl-actions) rides the SAME band so its flex-end button lands on the cards'
   right edge, not the far viewport edge. */
.tpl-start:not(.slim-mode) #tpl-start-form > .tpl-form-card,
.tpl-start:not(.slim-mode) #tpl-start-form > #tpl-structural-region,
.tpl-start:not(.slim-mode) #tpl-start-form > .tpl-actions,
/* Slim (Availability Poll) heading card rides the SAME 840px band as standard
   setup cards — ONLY #tpl-session-setup-card (Meeting Name). The wide calendar
   card (Card 2, the flat items .tpl-form-card holding #tpl-slim-cal-mount) is
   deliberately NOT matched, so it keeps full width. */
/* [HARD] THIS IS THE LAST SELECTOR IN THE LIST AND IT CARRIES THE DECLARATION
   BLOCK FOR ALL OF THEM. `.tpl-start > .tpl-switcher` used to sit here and hold
   the braces; deleting that LINE (rather than the selector) left every selector
   above it dangling with no block, which silently swallows the next rule. It cost
   nothing in pixels — under the rail the cards are grid items in a 680px column,
   so an 840px cap is not binding — and the setup page's order guard caught it anyway,
   because that guard asserts the band rule EXISTS and carries auto side margins.
   If another selector is ever removed from this list, move the block, do not
   delete the line that holds it. */
.tpl-start.slim-mode #tpl-start-form > #tpl-session-setup-card{max-width:840px;margin-left:auto;margin-right:auto;}

/* Vertical placement — pull the switcher up into .tpl-start's 48px padding-top
   with a tight --space-sm (8px) below it. */
/* ── THE SWITCHER'S PRE-RAIL POSITIONING IS GONE (swept here) ──────────────────
   Four rules stood here and above, all scoped `.tpl-start > .tpl-switcher`: an
   840px band cap with auto margins, a −29px pull-up over the heading card, and a
   ≤640 arm making the trigger a full-width bar. They put the template picker
   top-right of the card, which is the first of the three families
   setup-sidebar.css named as "the old layout … in use".

   THEY WERE NOT DEAD BECAUSE SLIM STOPPED USING THEM. They are dead because
   setup-sidebar.js RELOCATES #tpl-switcher into the right rail on every page, so
   the DIRECT-CHILD selector stops matching the moment the picker moves — and it
   has not matched on any shape since the rail shipped, slim included. Slim's
   adoption changed nothing about them; it only removed the last reason to believe
   they were still needed.

   Measured, not reasoned: a census of every selector in templates.css,
   setup-sidebar.css and this file, run against all six shapes on create AND
   manage, found `.tpl-start > .tpl-switcher` matching NOTHING on all eleven pages.
   Neutralising all four rules at runtime moved zero pixels on blank, blank_dm,
   availability and the DM manage page.

   NOTHING FOLDED IN, because the rail never depended on them — it already
   restates what it needs. setup-sidebar.css says so at its own trigger rule: the
   `max-width:none` there exists precisely BECAUSE "the page's own release of that
   cap is scoped `.tpl-start > .tpl-switcher` — a direct-child selector the picker
   stops matching the moment it is relocated anywhere". That note is now the only
   description of a rule that no longer exists; it is corrected in place. */
@media(max-width:640px){
  /* Trigger-box width — inset the switcher container by the SAME horizontal
     padding .tpl-form-card carries at this breakpoint (16px, templates.css
     ≤640) so the full-width trigger's left/right edges land on the inset
     SESSION TITLE .tpl-flat-subcard well below (which sits flush in the card's
     content box), not the card's outer edge. It reads the CARD'S OWN PADDING PAIR
     (--col-card-pad-l / -r, 2026-08-24) rather than --tpl-card-pad: the two sides
     are no longer the same number, and reading the symmetric token would have put
     this trigger's right edge where nothing else on the card ends. The mirror it
     used to keep by hand ("there is no shared width token, so mirror the literal")
     is still gone and there is still nothing to keep in step. box-sizing:border-box (tokens.css) keeps the
     width:100% trigger inside the padded content box. Scoped to the page
     switcher's own #tpl-switcher id ONLY, so the shared home / method / hero /
     participant custom-select switchers are untouched (menu positioning is
     JS-owned, so container padding never touches the open panel). */
  #tpl-switcher{padding-left:var(--col-card-pad-l);padding-right:var(--col-card-pad-r);}
  /* Menu positioning (drop directly beneath the trigger, viewport-clamped) is now
     owned by template-switcher.js's fixed-overlay anchor — the old left:0/right:0/
     width:100% menu override here was deleted so it can't fight the JS inline
     coords. */
}
/* Typography from the canonical .tpl-page-title (applied on the h1s); only layout here. */
.tpl-start h1{line-height:var(--type-page-title-line);margin-bottom:var(--inset-panel);}
/* DELETED: `.tpl-start .tpl-kicker` — do not re-add; the reason is T01 in the decision record. */
/* Page-identity heading block above the Session Overview card (create, non-slim):
   the red .tpl-kicker (template type) over a "Session Setup" heading. The heading
   reuses the canonical Tier-2 .tpl-sublabel (Bebas uppercase) but at a page-title
   40px — larger than both the .tpl-start .tpl-sublabel card-heading override
   (--tpl-heading 20px) and the base 30px — so it reads as the page title over the
   20px session-name fields. The kicker sits TIGHT to the heading (a small
   margin-bottom overriding the base .tpl-kicker 14px). Centred by the
   .tpl-start-intro text-align rule. THE GAP TO THE CARD IS NOT THIS BLOCK'S ANY MORE
   (2026-08-27): it is --tpl-gap, stated once on .tpl-start as a row-gap, the same value
   and the same mechanism as every other card-to-card distance on the page. This sentence
   used to end "the block margin-bottom sets the gap to the card"; see the tombstone
   directly below for why that margin is gone. */
/* DELETED: `.tpl-start .tpl-setup-identity{margin-bottom:var(--space-md)}` — do not re-add; the reason is T02 in the decision record. */
/* THE KICKER IS THE CARD LABEL TIER, SCALED — SIZE IS THE ONLY THING IT CHANGES.
   .tpl-crit-tag is worn in the markup, so family (Bebas), tracking (0.08em), case and
   colour (--accent) come from the one place SESSION TITLE and GROUP / TEAM read them and
   cannot drift from them. Only the size steps up, to --tpl-heading — the next value the
   scale declares above .tpl-crit-tag's own --tpl-kicker-size (14 -> 20), not a literal.
   margin-bottom overrides the tier's 6px: the kicker and the heading are ONE object, so
   their step is tighter than any gap between two objects on the surface. */
.tpl-start .tpl-setup-identity > .tpl-crit-tag{font-size:var(--tpl-heading);margin-bottom:var(--nudge);}
/* NO GROUP NAME ⇒ NO KICKER, NOT AN EMPTY BOX (2026-08-29). #tpl-manage-group-kicker
   (manage only) mirrors Group / Team Name and is genuinely empty — not a fallback
   default — whenever that field is: _bindHeadingMirror's `def` is captured from this
   element's own server-rendered text, which is '' when there is no group name, so an
   empty input keeps writing '' back rather than falling back to placeholder copy.
   :empty is the existing pattern for "holds nothing is the actual condition" on this
   page (#tpl-ws-auth-slot, .tpl-project-confirm) — no JS class toggle, no display:none
   default undone by the mirror. The kicker's own margin-bottom:2px goes with it, since
   :empty removes the box entirely; nothing else needs zeroing to close the gap. */
#tpl-manage-group-kicker:empty{display:none;}
/* DELETED: `.tpl-start .tpl-setup-identity .tpl-sublabel{font-size:40px}` — do not re-add; the reason is T03 in the decision record. */
/* Intro wrapper — centres kicker, h1, and the operator instructions block.
   The block-renderer's <p class="block-body-text"> carries inline
   text-align:left, so !important is required to override it. */
.tpl-start .tpl-start-intro,
.tpl-start .tpl-start-intro *{text-align:center !important;}

.tpl-start .field-label{display:block;font-family:var(--font-mono);font-size:var(--tpl-field-label);letter-spacing:var(--type-caption-tracking);text-transform:uppercase;color:var(--color-text-primary);margin-bottom:var(--gap-row);}
/* DELETED: THE WHOLE RULE (above `.tpl-start .tpl-errors-banner`) — do not re-add; the reason is T04 in the decision record. */

/* Server-side validation summary banner. Rendered conditionally above
   the form; per-field red outline (.field-invalid in blocks.css) lights
   up each offending input below. */
.tpl-start .tpl-errors-banner{
  background:rgba(var(--red-rgb),0.05);
  border:1px solid rgba(var(--red-rgb),0.2);
  padding:1rem 1.25rem;
  /* DELETED: margin-bottom:1.5rem — do not re-add; the reason is T05 in the decision record. */
  font-family:var(--font-mono);
  font-size:var(--type-caption);
  color:var(--red);
}
.tpl-start .tpl-errors-banner strong{
  font-family:var(--font-heading);
  font-size:var(--type-label);
  letter-spacing:var(--type-label-tracking-wide);
  text-transform:uppercase;
  display:block;
  margin-bottom:0.4rem;
}
.tpl-start .tpl-errors-banner ul{margin:0;padding-left:1.25rem;}

/* Form-card spacing tweaks scoped to start.blade.php so the .tpl-form-card
   chrome (in templates.css) stays generic. The default 14px gap between
   cards is comfortable; field-labels inside cards drop their bottom margin
   so they sit close to the input below. */
/* DELETED: `.tpl-start .tpl-form-card{margin-bottom:18px}` — do not re-add; the reason is T06 in the decision record. */
/* SESSION OVERVIEW now shows full .tpl-form-card chrome (fill + border + side
   padding + radius) so it reads as ONE card holding the Individual/Group mode
   toggle, Session Title, Group Name and the Self-Paced/Workshop toggle. The old
   :not(.slim-mode) chrome-strip was removed; slim/Availability Poll keeps its own
   boxed two-card design via its slim-scoped rules. */
/* Criteria wrapper — a single .tpl-form-card box holds the CRITERIA heading,
   every criterion row, and the Add button (mirroring the items card). Each
   per-criterion .tpl-form-card inside drops its own card chrome — border,
   background, and side padding — so it reads as a row within the one wrapper
   rather than a nested box. Internal layout (header, name input, prompt,
   toggles, items list) is untouched; only the outer box is removed. The
   wrapper's own 22px side padding now provides the content inset. */
/* DELETED: `.tpl-criteria-card > .tpl-section-block.tpl-form-card` — do not re-add; the reason is T07 in the decision record. */
/* ── MS section card: a VISIBLE hairline, because the merge spent the separator ──
   A section used to open with a lighter .tpl-flat-subcard well, and that band was
   doing the work of saying "a new card starts here". Merging the card to one
   background (2026-08-02) removed it, and what was left holding the boundary was an
   18px gap plus a card/page contrast of SEVEN RGB units (--card-bg #EAE3D6 on the
   body's #E3DDD0) with --card-border set to `transparent`. Measured, not estimated.

   So the card takes the border it always had a slot for. --color-border is the existing
   hairline the page's FIELD BOXES draw — .tpl-issue, .tpl-inline-edit > input, the section
   prompt input and the weight stepper — no new value.

   [HARD] IT IS NOT "every well and question sub-card", WHICH IS WHAT THIS SENTENCE USED TO
   SAY (corrected 2026-08-26). Wells draw no hairline at all: .tpl-flat-subcard is skinless
   and setup:well-probe FAILS a run in which one computes --color-border with a non-zero
   width. [data-question-wrap] is `border:0` (templates.css). The elements that really draw
   this token all sit on a WHITE fill, where a #E0DDD8 line reads; on the tan card it scores
   1.06:1 and is invisible, which is how the row adders came to be given a box nobody could
   see. Cite the field boxes as the precedent, never the wells.

   SCOPED to MS, deliberately, in both directions. `border-color` only (not `border`)
   so the 1px width + style still come from .tpl-form-card — one place owns the box.
   :has(#tpl-add-section-btn) keeps it off every other .tpl-form-card on the page,
   which is what --card-border:transparent is a global decision about; and the DM
   criterion card is untouched twice over, since it never matches this selector and
   its own rule above already strips its chrome to nothing. */
.tpl-start:has(#tpl-add-section-btn) .tpl-section-block.tpl-form-card{border-color:var(--color-border);}
/* DELETED: The #tpl-weighting-card rules that sat here — its  (above `.tpl-start .tpl-form-card .field-label`) — do not re-add; the reason is T08 in the decision record. */
.tpl-start .tpl-form-card .field-label{margin-bottom:var(--gap-tight);}
/* ── THE CARD'S BOTTOM GAP IS THE CARD'S PADDING ──────────────────────────────
   A trailing child margin is not card padding, but it renders as if it were: with
   padding-bottom:18px and a last child carrying margin-bottom:14px, the card measures
   33px at the bottom against 19px at the top, and the asymmetry moves card by card
   depending on what happens to be last in it. Measured before this rule, at 1440:
   Overview 33, Options To Compare 33, Welcome/Completion/Advanced 27, Criteria 17 —
   four different values for one intended standard.

   Zeroing the last child's bottom margin makes the padding the only source, so every
   card is 19/19 (15/15 at ≤640, 15/15 at ≤480) from the one declaration above. The
   margins themselves are NOT deleted: they are real gaps BETWEEN children and still do
   that job everywhere except in the one position where there is no next child.

   [HARD] IT CANNOT REACH A LAST CHILD WITH A HIDDEN SIBLING AFTER IT. :last-child is
   STRUCTURAL — it ignores display — so a card that ends with a display:none row leaves
   its last VISIBLE child's trailing margin standing. Flat's Options To Compare card is
   one: it measures 47px of bottom inset against every other card's 33. The mirror-image
   remedy (`+ *` on the next sibling) is NOT the fix — it is blind to a display:none
   PREVIOUS sibling in exactly the same way, measured on the survey shape. See the note
   at .tpl-flat-subcard for what it would actually take.

   [HARD] SCOPED .tpl-start AND LIVING HERE, NOT IN templates.css, FOR A MEASURED
   REASON. Written unscoped in templates.css the rule is (0,2,0) and LOSES to a
   (0,2,0) later-document declaration (`.tpl-start .tpl-flat-subcard{margin-bottom:14px}`
   was the one measured) and ties with `.tpl-start .tpl-form-card
   .field-label{margin-bottom:6px}` a few lines above.
   Measured that way: Overview stayed at 33 and Welcome landed on 25 instead of 19 — a
   rule that reads as authoritative and is not. Scoped, it is (0,3,0) and sits after both,
   so it wins on specificity and on order. */
.tpl-start .tpl-form-card > *:last-child{margin-bottom:0;}
/* The card hint — the muted line under a card heading (WELCOME / COMPLETION /
   ADVANCED). Was three copies of an inline `style="margin:6px 0 8px"`, which is the
   one thing the rule above cannot reach.
   • the 6px TOP is deleted outright: it collapsed against .tpl-block-header-row's own
     bottom margin and so only ever won when that margin was smaller than 6 — it never
     was, and now it is exactly 6, so it was describing a gap it did not set;
   • the 8px BOTTOM moves to the element it actually separates this line FROM. The
     revealed body below already carries margin-top:8px, so the open state is unchanged
     to the pixel — and the CLOSED state stops leaking 8px into the card's padding,
     which is the whole 27-vs-19 discrepancy above. Spacing belongs to the block that
     occupies space. */
.tpl-start .tpl-form-card > .tpl-block-header-row + .field-label{margin:0;}
.tpl-start .tpl-form-card > .tpl-issue,
.tpl-start .tpl-form-card > .tpl-section-block-fields > .tpl-issue{margin-bottom:0;}

/* .tpl-mode-seg + .tpl-mode-btn rules live in public/css/templates.css
   (single source for the segmented control). */

/* .tpl-issue typography (font, size, color, ::placeholder) lives once
   in public/css/templates.css and applies to every input/textarea on
   this screen — facilitator name + email, session title, group/team
   name, overall question/issue, and items-to-rank rows (where
   .tpl-issue composes with .tpl-item-input). The layout below
   (:not(.tpl-item-input)) excludes items so the per-row flex sizing
   and tighter underline on .tpl-item-input still win for that one
   context.

   Visual treatment (Concept B mockup): the five user-entry fields
   render as full bordered boxes — 1px #D5D0CA border, 4px radius,
   white fill, 8px 12px padding. Replaces the previous underline-
   only treatment. Comparison-question fields inside criterion cards
   keep their own soft-box styling on .tpl-section-prompt-input. */
/* [HARD] `background-color`, NOT the `background` SHORTHAND (2026-08-25). The
   shorthand resets background-image to none, so this rule silently painted out any
   glyph a consumer tried to draw — which is exactly how every <select> on this
   surface lost its caret. Same correction on .tpl-timedate-calsel below. The colour
   is unchanged; only the property is narrowed to the one thing it meant. */
/* [HARD] THE RIGHT PADDING IS NOT THIS RULE'S TO STATE (2026-09-01). The shorthand
   `padding:8px 12px` set padding-right: 12px at (0,2,0), which OUT-RANKS the badge
   lane's own textarea arm — `.tpl-start textarea:where(…)`, deliberately lowered to
   (0,1,1) on 2026-08-29 so a multi-line caption's focus lane could win at its natural
   specificity. That change's note says it altered nothing about WHICH textareas match,
   which was true, and did not consider which rules then out-rank it. The badge is
   painted as a background layer over the last --tpl-badge-inset + --tpl-badge-size =
   38px of the field, so a field reserving 12 paints the ring/pencil/tick ON the value
   it is marking — the exact defect the lane exists to prevent, and what
   `setup:badge-probe` has been reporting on blank_survey and blank_quiz.

   CENSUSED BEFORE NARROWING, not assumed: across blank / dm / ms / ms?probe=qms /
   survey / quiz / availability?slim=1 / the WPROBE01 manage page, 24 .tpl-issue
   elements render, and this declaration was the WINNING padding-right on exactly ONE
   of them — textarea.qt-guidance-input, at 12px against a 38px lane. Every other one
   is either .tpl-item-input (excluded by the :not() above), an <input> whose lane arm
   wins at (0,11,1) → 56px, or the <select> whose caret lane already wins → 44px. So
   the three sides that are this box's own affair stay stated here as longhands, and
   the RIGHT side is left to whichever lane rule owns the field. */
.tpl-issue:not(.tpl-item-input){width:100%;box-sizing:border-box;border:1px solid var(--color-border);border-radius:var(--radius-field);background-color:var(--color-white);padding-top:var(--inset-control);padding-bottom:var(--inset-control);padding-left:var(--inset-box);outline:none;-webkit-appearance:none;appearance:none;}

/* Session Set Up card — the Session Title row and the Group / Team Name row share
   the SAME treatment: the line column — --col-line-x as the offset, --col-line-width
   as the width, like every other field line on the page.
   The Save To Project block is a card-level absolute block (top-right of
   #tpl-session-setup-card), NOT on this row. */
/* DELETED: `.tpl-start .tpl-form-card #tpl-session-title-row` — do not re-add; the reason is T09 in the decision record. */
/* ── SLIM (Availability Poll) CARD 1 — ONE BAND, NOT THREE CONTAINERS ──────────
   Card 1's four blocks (Meeting / Event Title row, Where row, Description body,
   Participant Instructions body) used to sit in a 70% column while the title BOX
   inside it was capped to --tpl-name-span. Two different width contracts in one
   card: at 1280 the title measured 520 against 556 for the Description textarea
   and its label, so the labels hung 18px outside the box edge they were labelling.
   Route the CONTAINERS onto the box's own contract instead — --tpl-name-span is
   the shared name-line span every identity field already keys off, so the title
   box, the Description, the Instructions line and the facilitator Name/Email pair
   below them now all resolve to ONE outer edge by construction rather than by two
   values that happened to be close. max-width:100% is the same cap the box itself
   carries, so nothing overflows once the card content is narrower than the band
   (measured at 481 / 500 / 540 / 640: contained and equal at every step).

   --col-line-width, redeclared HERE and not overridden per field: the Participant
   Instructions line is the SHARED question component's prompt row, so its width is
   the D-COLUMNS line token (620px fixed on desktop, applied as width AND min-width
   by question-types.js). min-width beats max-width, so in a 556px column it did not
   shrink — it overhung the card by 64px. The component reads the token; the token is
   the lever. In this card the prompt row has no numeral, no type dropdown and no
   ×/▾ cluster, so the line IS the column: 100%. No availability-only width rule, and
   the component is untouched. */
/* ── AND THE BAND IS LEFT-ALIGNED ON THE LINE COLUMN, NOT CENTRED (2026-08-23) ──
   Slim's four containers take the same offset as every other row on the page: see
   THE IDENTITY ROWS JOIN THE LINE COLUMN below, which is the single note for the
   whole de-centring. Slim is not an exception to it — its Overview is structurally
   the same card (the same .tpl-setup-fields-well, the same #tpl-session-title-row);
   what differs is that its Description and Participant Instructions are BOXED fields
   (.tpl-issue's border + fill) rather than underlined ones, so they draw no rust rule
   and setup:header-lane cannot see them. Their BOX edges are on the column even so. */
/* (`.tpl-start.slim-mode .tpl-setup-fields-well > .tpl-timedate-length` LEFT THIS LIST
   2026-09-09, and it is a deletion rather than a move. It joined on 2026-08-25 because
   MEETING/ EVENT LENGTH was being carried out of .tpl-timedate-controls — whose own
   `margin-left:var(--col-line-x)` puts the whole control row on this column — and into
   the Overview card's well, where it had to read the offset itself. It is not carried
   out any more: it stays in the Meeting Options card, inside the mount, where the
   controls row's margin is once again the thing that puts it on V3 (see the slim arm at
   THE MEETING OPTIONS LADDER below). A selector for a relocation that no longer happens
   is a rule describing a thing that is not true.) */
.tpl-start.slim-mode .tpl-form-card #tpl-session-title-row,
.tpl-start.slim-mode #tpl-where-row,
.tpl-start.slim-mode #tpl-where-place,
.tpl-start.slim-mode #tpl-welcome-intro-body,
.tpl-start.slim-mode #tpl-flat-questions-body{
    width:var(--col-line-width);
    margin-left:var(--col-line-x);margin-right:0;
}
/* [HARD] THE BRACE CLOSES THE LIST ON THE LAST SURVIVING SELECTOR, AND IT HAS TO STAY THERE.
   From `1049b7ef` (2026-09-10) to this commit these five selectors had NO declaration block
   at all. That commit deleted a SIXTH selector from the END of the list and took the block
   with it, so the list ran on through the comments below and merged into
   `.tpl-start .tpl-block-header-row--centred{justify-content:center}` — slim's five
   containers stopped reading --col-line-x / --col-line-width and inherited a
   `justify-content` they have no use for. Nothing errored, the page rendered, and the
   commit's own message asserted the opposite: *"#tpl-where-row falls back to the shared
   ladder rule, full --col-line-width at --col-line-x, like the title row above it."*
   `setup:header-lane` went red on it and stayed red for 289 commits (RR-110).
   Two rules elsewhere in this file already assume this block exists and only make sense
   with it: the `margin-left:0` overrides at THE SECOND CHAIN THAT HAS ALREADY PAID (~2127)
   name `#tpl-flat-questions-body{margin-left:var(--col-line-x)}` as the spend they give
   back. When deleting a selector from a list, delete the SELECTOR LINE and leave the brace
   on the one above it. */
/* DELETED: `.tpl-start.slim-mode.manage-mode .tpl-setup-fields-well > .tpl-tim…` — do not re-add; the reason is T10 in the decision record. */
/* DELETED: The one-commit hold on #tpl-welcome-intro-body — do not re-add; the reason is T11 in the decision record. */
/* ── THE MEETING OPTIONS LADDER (2026-09-09) ─────────────────────────────────────
   MEETING/ EVENT LENGTH and LOCATION shared a row here for one day. They do not any
   more: Length lives in the Meeting Options card above HOST TIMEZONE, Location is back
   on its own full-width line in the Overview card. EVERYTHING THE PAIRING REQUIRED IS
   DELETED RATHER THAN CARRIED ALONG — the well's `flex-flow:row wrap`, the `width:auto`
   that let the two size to content, and the `margin-left:0` that stopped the
   right-hand group paying the ladder a second time. With one control on each side of
   the split none of the three has a subject:

     · the well is a column again, so the 24px column gap it was spending
       (`gap:var(--space-lg)`) goes back to being unspendable, as it was before;
     · #tpl-where-row falls back to the ladder rule above — full --col-line-width at
       --col-line-x, exactly like the title row and the agenda body it now sits under,
       which is what "reading correctly on its own" means here;
     · nothing states a width for the length any more: inside the mount it is a block
       in a column and the controls row's own margin puts the column on V3.

   THE HOISTED LENGTH TAKES THE ROW'S LEFT, NOT ITS OWN. .tpl-timedate-controls carries
   `margin:0 0 18px var(--col-line-x)`; the length is lifted OUT of it to sit above, so
   it would otherwise start on the mount's content edge while the row below it starts on
   V3 — the "four left edges in one control row" the V3 note above this file's controls
   block records. One margin, the same token, so the two lines share one vertical.

   AND THE DISTANCE IS STATED BY THE LOWER CHILD. The gap between the length and the
   control row is the ROW's margin-top, not the length's margin-bottom — the invariant
   the Message card's double gap came from.

   16px, NOT THE ROW'S OWN 18, AND THE TWO PIXELS ARE THE POINT. The row already states
   `margin-bottom:18px` down to the calendar, and both ends of THAT are painted boxes —
   a <select> and the month grid — so 18 declared renders 18 of ink. The rung above ends
   at the length FIELD's box and begins at the HOST TIMEZONE label's TEXT, whose line box
   carries ~2px of leading above the glyphs, so 18 declared renders 20 of ink and the
   ladder reads uneven by exactly that. Declared 16, measured 18 against the row's 18 —
   equal as rendered, which is the thing being matched. Both label-to-field gaps measure
   12 already and needed nothing. */
/* ── THE MEETING OPTIONS HEADING, CENTRED AND UNNUMBERED (2026-09-10) ────────
   Manage only, and the class is emitted only there. The card moved out from under
   Overview and Message to sit directly beneath the Availability card, so it stopped
   being a rung of the numbered ladder — its header drops [data-card-badge-host]
   rather than hiding a badge, because a hidden badge still claims a place in
   _numberCards()' sequence and this card now sorts ABOVE Overview.
   `justify-content:center` is the whole of it: the row is already a flex row
   (templates.css), the badge is genuinely absent rather than invisible, so there is
   no reserved lane to centre around and the label centres on the card. */
.tpl-start .tpl-block-header-row--centred{justify-content:center;}
/* ── AND THE BADGE LANE GOES WITH THE BADGE ──────────────────────────────────
   `.tpl-block-header-row:not([data-card-badge-host]) > .tpl-sublabel` sets
   `margin-left:var(--col-line-x)` — 74px measured — so an unbadged header still
   starts its label on the column anchor the fields below it use. That is right for
   a LEFT-aligned heading and meaningless for a centred one: it pushed this label
   37px right of the card's middle, which read as a heading that had missed rather
   than one that was centred (measured +29 off centre against AVAILABILITY's −8).
   Centring IS the alignment here, so the column anchor is not also claimed.
   Written at (0,5,0) — the repeated class plus the same `:not()` — because the rule
   it has to beat is (0,4,0) and a tie would have left this to source order. It
   declares margin-left and nothing else, so nothing else moves with it. */
.tpl-start .tpl-block-header-row.tpl-block-header-row--centred:not([data-card-badge-host]) > .tpl-sublabel{
    margin-left:0;
}
/* `:not(.manage-mode)` DELETED 2026-09-10 (D-DEBT-75). It was there because only the
   create page hoisted the length into the mount; both pages do now, and the exclusion
   would have left the manage twin's hoisted control on the mount's content edge with no
   rung above the controls row. Same two declarations, one page fewer excluded. */
.tpl-start.slim-mode #tpl-slim-cal-mount [data-q-config] > .tpl-timedate-length{
    margin-left:var(--col-line-x);
}
.tpl-start.slim-mode #tpl-slim-cal-mount [data-q-config] > .tpl-timedate-length + .tpl-timedate-controls{
    margin-top:var(--inset-panel);
}
/* ── AND THE RULE UNDER THE LENGTH FIELD GOES, BUT THE BADGE LANE DOES NOT ────────
   A rule spanning the whole line said "this line is one field". It is two now, so the
   line goes and the length field's completeness is carried by its badge alone.

   `border-bottom-style:none`, NOT a zero width and NOT a transparent colour, and the
   difference is the other arms. FIELD STATES paints this same border in four states —
   rust while empty, ink when filled, ink on :focus-within (line ~997), and
   `.field-invalid{border:2px solid !important}` for a refused value. A transparent
   COLOUR would be repainted by the first three the moment they fire; a zero WIDTH would
   also silence the invalid arm, which must still show. `style:none` computes the used
   width to zero whatever colour is set on top of it, and the `!important` invalid arm
   re-states `style:solid`, so it alone still paints. One declaration, three arms
   silenced, the fourth deliberately not.

   [HARD] THE BADGE IS ON THIS ELEMENT AND IT NEEDED THE PADDING, WHICH IS WHY THE LANE
   IS RESERVED HERE RATHER THAN LEFT ALONE. The tick is a background-image on
   .tpl-inline-edit at `right var(--tpl-badge-inset)`, so it hangs off THIS box's right
   edge — and this box was 454px holding 257px of content, which is the only reason the
   disc has been sitting in clear space. Sizing the group to its content pulls that edge
   in behind the ALL-DAY seat and paints the tick straight over it. The reserve is the
   platform's existing badge-lane expression, the same one .qt-budget-amount states, so
   the lane is declared rather than inherited from slack. */
.tpl-start.slim-mode:not(.manage-mode) .tpl-timedate-length-fields > .tpl-inline-edit.tpl-rust-rule{
    border-bottom-style:none;
    padding-right:calc(var(--tpl-badge-inset) + var(--tpl-badge-size) + 6px);
}

/* [HARD] THE `--col-line-width:100%` REDECLARATION MOVED OFF THESE CONTAINERS AND ONTO
   A DESCENDANT, AND IT HAD TO. A custom property redeclared in a rule applies to that
   rule's OWN declarations, so `width:var(--col-line-width)` and `--col-line-width:100%`
   in one block is a self-reference: the container would read its own 100% and the width
   token would do nothing. Its consumer was never the container anyway — it is the
   Participant Instructions row inside, which is the shared question component and reads
   the token as its line width. In this card that row has no numeral, no type dropdown
   and no x/chevron cluster, so its line IS its container: 100%. */
.tpl-start.slim-mode #tpl-flat-questions-body .tpl-questions-list{--col-line-width:100%;}
/* ── SLIM'S HANDLE GOES IN THE DRAG COLUMN, NOT IN FRONT OF THE FIELD (2026-08-24) ──
   [HARD] SLIM IS THE ONE SHAPE WHERE THE FIELD REALLY MOVED WITH THE HANDLE, and it is
   the reason this rule is not a tidy-up. Measured at 1280 on /templates/availability/
   start?slim=1: with ONE question the prompt field sits at 410 and is 438 wide; add a
   second (the handle is emitted at questions.length > 1) and the field jumps to 436 and
   shrinks to 412. Nothing else on the page moves. That is the defect the reserve exists
   to remove, on the one surface that showed it.

   WHY SLIM ALONE. On every other shape the handle's sibling is the numeral, which carries
   --col-num-x unconditionally, so cancelling the handle's advance is enough. Slim's
   question is lockType, so renderList appends NO numeral — the handle's sibling is the
   field itself — and this card has already spent --col-line-x as the CONTAINER's
   margin-left (the rule above). So the handle here has to give back the whole container
   offset, not just the gutter, and then re-add the badge column it does not occupy.

   THE TWO MARGINS ARE ONE STATEMENT: net advance zero, handle in the shared drag column.
     margin-left  = -1 * --col-line-x            -> the handle lands at the row band's own
                                                    left edge, i.e. x=348, the SAME drag
                                                    column DM's and MS's handles sit in.
     margin-right = --col-line-x − --col-drag − --col-gap
                                                 -> gives back everything the handle and
                                                    its following gap did not spend, so the
                                                    field stays at 410 at 438 wide.
   Spelt with --col-drag and --col-gap rather than --col-num-x deliberately: --col-num-x is
   forced to 0 at ≤640 while drag+gap there is 0+6, so the composite would be 6px out on a
   phone. It is moot today (the handle is display:none at ≤640) and it would not have
   stayed moot.

   The empty badge column between the handle and the field is the reserve rendering as
   space, which is exactly what it is meant to look like on a row with no badge. */
.tpl-start.slim-mode .qt-q-row > .tpl-question-drag-handle,
.tpl-start.slim-mode [data-question-wrap] > .tpl-question-drag-handle{
    margin-left:calc(-1 * var(--col-line-x));
    margin-right:calc(var(--col-line-x) - var(--col-drag) - var(--col-gap));
}
/* [DECLARED EXCEPTION] SLIM'S QUESTIONS BODY PAYS NO SECTION INSET, because on slim it
   is not the thing that inset is for. The base
   `.tpl-flat-questions-body{padding-inline:calc(--tpl-section-inset - --tpl-card-pad)}`
   converts a child of the CARD's content box into a child of the WELL's content box —
   that is what makes survey's and quiz's question rows land on the same column as an
   item row. On slim this container is a member of the band above (it takes the band's
   own margin-left), so it is already on the column and the inset is a second one:
   measured at 1280 before this, slim's Participant Instructions field sat at 425
   against every other field on the card at 410. Stated here, in the rule that puts slim
   on the band, rather than as a separate slim override elsewhere. */
.tpl-start.slim-mode #tpl-flat-questions-body{padding-left:0;padding-right:0;}
/* Base .tpl-ws-group-name (shared with the workshop/mode toggle rows): 70% centred.
   The Group / Team Name FIELD (#tpl-group-name-wrap) is widened to full width for
   non-slim below so its underline matches the Facilitator pair; the toggle rows
   keep this 70%.
   THE 14px TOP MARGIN IS GONE. It was never live: both of the class's two consumers
   overrode it — #tpl-group-name-wrap to 8px and #tpl-workshop-toggle-row to 8px —
   so it described a rhythm nothing rendered. It is dropped rather than left in place
   because the #tpl-group-name-wrap override is deleted below, and a dead value that
   springs back to life the moment its only overrider goes is not a base value, it is
   a trap. #tpl-workshop-toggle-row still carries its own explicit 8px (next rule);
   it is NOT in the fields well, so its spacing IS a margin's job. */
/* DELETED: `text-align:center` — do not re-add; the reason is T12 in the decision record. */
.tpl-start .tpl-form-card .tpl-ws-group-name{width:70%;margin-left:auto;margin-right:auto;}
/* "How will participants respond?" section: hairline divider above it removed, and
   its top margin tightened (14px -> 8px) so it sits closer to the Individual/Group
   toggle above. Scoped to this section; the Group/Team Name field keeps its 14px. */
/* DELETED: `margin-top:8px` — do not re-add; the reason is T13 in the decision record. */
/* DELETED: `#tpl-group-name-wrap{margin-top:var(--space-sm)}` — do not re-add; the reason is T14 in the decision record. */
/* Session Title + Group / Team Name are BOXED fields (Session 175): the two title
   inputs reuse the facilitator .tpl-fac-input box. The Bebas caption that used to sit
   above each is gone (Session 176) — the drawn placeholder labels the box now — so the
   row is a column holding just the box, and the ROW is the line (2026-08-23): it takes
   --col-line-x and --col-line-width from the shared contract, so the box inside simply
   fills it. Slim and non-slim reach that from two arms because their wells differ in
   nothing else; both land on the same edges. */
/* align-items:STRETCH, not center: the row is the band, so its label and its field
   both take the band's full width and each lands its first glyph on the band's own
   left edge via the --tpl-field-inset they already carry. `center` shrink-wrapped the
   label to its text and floated it to the band's middle, which is the other half of
   the de-centring (the field's text-align was the first). */
.tpl-start .tpl-form-card #tpl-session-title-row,
.tpl-start .tpl-form-card #tpl-group-name-wrap{display:flex;flex-direction:column;align-items:stretch;}
/* DELETED: `#tpl-session-title-row > input.tpl-fac-input, #tpl-group-name-wrap…` — do not re-add; the reason is T15 in the decision record. */
/* DELETED: The Bebas .tpl-title-caption that used to sit ABOVE each box — do not re-add; the reason is T16 in the decision record. */
/* Non-slim (create / manage, group mode): the Session Title + Group / Team Name ROWS
   ARE the line, left-aligned on the column — the same contract slim already uses for
   its own rows above.

   THEY USED TO BE width:100% WITH THE BOX CENTRED INSIDE THEM, and that had to change
   when the fields took the Criteria Name treatment: the rust rule under each field is
   the ROW's border-bottom (exactly as it is .tpl-crit-part--name's), so a full-card row
   would have drawn a full-card rule under a 520px field. Making the row the band puts
   the rule on the field's own edges by construction rather than by a second width
   declaration that has to agree with the box's.
   It also retires the .tpl-fac-ph band-offset override that used to re-measure the
   overlay's insets from the band — row and band are one edge now, so the base
   --tpl-field-inset is already right. max-width:100% keeps it correct once the card
   content is narrower than the band (which is also what makes the ≤480 arm's
   width:100% redundant for these two rather than losing to this rule's specificity). */
/* ── [HARD] THE IDENTITY ROWS JOIN THE LINE COLUMN (2026-08-23) ────────────────
   THE MECHANISM IS THE ITEM ROW'S, STATED DIRECTLY BECAUSE THERE IS NO BADGE TO
   STATE IT. An item row reaches column 3 by spending --col-num-x on its badge and
   --col-gap after it; the sum of those terms IS --col-line-x, and .tpl-edit-field
   then takes --col-line-width. These rows have no badge and no drag handle, so the
   same offset is spent as a margin instead. Nothing new is introduced: the offset is
   the shared token, and the rows sit in the fields well, whose content box is the
   SAME box the item rows sit in — so `100%` here and `100%` inside --col-line-width
   resolve against the same width.

   [HARD] max-width IS `100% - --col-line-x`, NOT `100%`. A percentage in a custom
   property — and in a plain max-width — resolves AT THE POINT OF USE, against this
   row's containing block, which is the well's CONTENT box. The margin has already
   spent --col-line-x out of that box, so a bare `100%` lets the row run --col-line-x
   past the well's right edge on any card narrower than the band. Measured before the
   subtraction was added: 30px of overhang at 390 on every shape.

   THE ROW WAS CENTRED BY `margin-left:auto;margin-right:auto` — NOT BY A GRID.
   The brief for this change described the Overview fields as centred by "a real
   grid, the only one on the middle panel besides slim's calendar". They were not:
   the only grid on this card is .tpl-ws-card-top on the HEADING row, and that grid
   is itself dead — setup-sidebar.css's `[data-card-badge-host]{display:flex}` is
   (0,3,0) against its (0,2,0), so every rail page (which is every setup page)
   computes `display:flex` on it. Measured, by walking document.styleSheets for the
   rules that match: `#tpl-session-setup-card-head` on create computes flex this way,
   with `grid-template-columns:1fr auto 1fr` sitting inert beside it. (`#mgmt-respond-header`
   on manage computed flex the same way at the time of this measurement; since 2026-08-29
   it no longer carries [data-card-badge-host] — its own id-scoped `display:flex` rule,
   added V3 2026-08-24, is what computes it now, the grid still inert beside it.) Those
   declarations are NOT touched here — the grid is on the card's
   HEADING row, not on a field line, it has three consumers of which two are behind
   auth or a mode this pass cannot render, and one of its siblings
   (`.tpl-ws-card-top .tpl-block-header-toggles{margin-left:0}`) is live and exists to
   neutralise a flex auto-margin the grid was supposed to have replaced. Removing dead
   grid declarations from under a live compensator is its own change with its own
   proof; see the report.

   ── AND THE WIDTH IS --col-line-width (2026-08-23, the commit after the move) ──
   THIS RETIRES --tpl-name-span, AND THAT REVERSES A THIRD LOGGED DECISION. The [HARD]
   note at --col-line-max (templates.css) said:

     "75ch IS PER-FONT, AND TWO OF THE MOST PROMINENT FIELDS ON THE PAGE ARE NOT ON THIS
      MECHANISM AT ALL. Session Title and Group / Team Name are Bebas Neue 20px at
      7.69px/char and take their width from --tpl-name-span (a flat 520px) … They are a
      SECOND, UNRELATED CAP with a name of its own. Do not wire them onto this token to
      make one story: the fonts differ, so one character measure cannot serve both, and
      the two bands are deliberately different shapes — a centred fixed band for the
      identity pair, a column-relative min() for the rows."

   HALF OF THAT PREMISE WENT IN THE COMMIT BEFORE THIS ONE: there is no centred fixed
   band any more, so "two deliberately different shapes" is down to one shape. The other
   half is TRUE AND IS THE PRICE, stated rather than hidden: at 1280 this field goes from
   520px to 438px, which at Bebas 20's measured 7.69px/char is about 56 characters down
   to about 47. --col-line-max is a DM Mono measure and binds only above ~1600, where it
   would give this field ~100 Bebas characters. One track means one character measure and
   this surface has two fonts; that is a real cost and it is the width lever's problem,
   not the alignment's. See the report for the numbers at all three widths.

   `max-width` is GONE with the fixed width. --col-line-width is already
   `min(--col-line-max, 100% - --col-line-x - --col-right)`, and its `100%` resolves at
   the point of use — this row's containing block, the well's content box — so it has
   already paid the offset the margin spends and cannot overhang. A second cap here would
   be a second place for the width to be decided, which is the thing this removes. */
.tpl-start:not(.slim-mode) .tpl-form-card #tpl-session-title-row,
.tpl-start:not(.slim-mode) .tpl-form-card #tpl-group-name-wrap{
    width:var(--col-line-width);
    margin-left:var(--col-line-x);margin-right:0;
}
/* ── THE HEADING FIELDS TAKE THE CRITERIA NAME CHROME ─────────────────────────
   The SINGLE source, shared by the two title fields (signed-in AND signed-out) AND the
   signed-out organiser Name/Email pair. .tpl-fac-input has exactly these four emitters
   — all of them _identity-field — so this rule IS the heading section's chrome and
   there is nothing else to scope it against.

   IT IS NO LONGER A BOX. White fill, hairline border and radius are gone; the field is
   transparent and the rust rule under it is the ROW's border-bottom. That is not a new
   treatment — it is the one .tpl-crit-part--name already renders further down the same
   page (`.tpl-crit-part input{background:transparent;border:0;border-radius:0;padding:0}`
   plus the part's own `border-bottom:2px solid var(--red)`), reached from the structure
   these fields actually have. The TYPE was already shared: all four carry
   .tpl-card-name-input, so they and the criterion name read THE CARD-NAME TIER
   (--tpl-cardname-*) from one declaration in templates.css.

   padding stays --tpl-field-inset horizontally — the same token the criterion part
   insets its text and its .tpl-crit-tag by, so the label above and the value below land
   on one left edge. height:34px stays: it is what .tpl-fac-ph's overlay geometry is
   measured against, and a single-line field centres its text in it regardless of the
   tier's 1.1 line-height.
   (0,2,1) beats the global .tpl-start input[type=text/email] fill. */
.tpl-start input.tpl-fac-input{height:var(--tpl-field-height);box-sizing:border-box;width:100%;background-color:transparent;border:0;border-radius:var(--radius-none);padding:0 var(--tpl-field-inset) 0 0;color:var(--color-text-primary);outline:none;-webkit-appearance:none;appearance:none;}
/* The label above each field. It is the shared .tpl-crit-tag — rust, Bebas,
   --tpl-field-label, uppercase — and needs nothing but the field's own horizontal
   inset, so the label's first glyph sits over the value's first glyph exactly as it
   does inside a criterion part (where the PART's padding gives both of them the inset
   at once; here the input owns its padding, so the label is told the same token). */
/* [HARD] THE SELECTOR IS `> .tpl-crit-tag`, NOT `> label.tpl-crit-tag` (2026-08-24), AND
   THE LEFT PADDING IS 0. Two things were wrong in one line. The `label` qualifier matched
   SESSION TITLE and GROUP / TEAM — which are <label>s — and missed OVERALL QUESTION and
   OPTIONS TO COMPARE, which are <span>s carrying .field-required. Measured at 1280 before:
   the two <label>s inked at 400, on the text they caption; the two <span>s inked at 388,
   12px to its left. One tag, two elements, two verticals, because of an element name in a
   selector. The left inset is then 0 for all four, because the inset moved out of the box
   and into --col-line-x — so the caption, the value and the underline share V3 by
   construction rather than by three declarations agreeing. */
.tpl-start .tpl-block-row > .tpl-crit-tag{padding-left:0;padding-right:var(--tpl-field-inset);}
/* DELETED: `background` — do not re-add; the reason is T17 in the decision record. */
.tpl-start input.tpl-fac-input:-webkit-autofill,
.tpl-start input.tpl-fac-input:-webkit-autofill:hover,
.tpl-start input.tpl-fac-input:-webkit-autofill:focus{-webkit-box-shadow:0 0 0 1000px var(--card-bg) inset;box-shadow:0 0 0 1000px var(--card-bg) inset;-webkit-text-fill-color:var(--color-text-primary);}
.tpl-start input.tpl-fac-input:disabled{opacity:0.55;cursor:not-allowed;}
/* FOCUS AND INVALID MOVED OFF THE INPUT, because the properties they used are gone.
   Both used border-color, and the field has no border any more.
     - FOCUS is the row's rule going ink, which is the page's existing focus vocabulary
       (`.tpl-inline-edit > input:focus{border-color:var(--border-strong)}`) applied to the element
       that now carries the border. Colour only — no width change — so nothing reflows.
     - INVALID cannot be "the rule goes red": the rule is ALREADY red, so the error state
       would be indistinguishable from the resting one. It is a faint rust wash on the
       field instead, at the same --red-rgb the errors banner uses, which reads against
       the card without adding chrome back. background-COLOR, never the `background`
       shorthand — the completion badge on these fields is a background-IMAGE layer and
       the shorthand silently wipes it. */
/* [HARD] (`.tpl-start .tpl-rust-rule:focus-within{border-bottom-color:var(--tpl-rule-ink)}`
   is DELETED, and it must not come back.) It was "focus turns the line ink" — and this
   rule's own neighbour already explains why that cannot work: the line IS the completion
   state, rust when empty and ink when filled. So on a FILLED field, focus asked the line
   for a colour it was already showing, and the field had no focus indication at all.
   Measured on a filled Session Title, item row and DM criterion name: nothing changed on
   focus, and `outline` is none surface-wide, so there was no fallback.
   That is exactly the collision the INVALID note below records — "the rule is ALREADY red,
   so the error state would be indistinguishable from the resting one" — one state over.
   Focus is a white FILL now, which is orthogonal to whatever the line is saying. See THE
   FOCUS TREATMENT in templates.css. */
.tpl-start input.tpl-fac-input.field-invalid{background-color:rgba(var(--red-rgb),0.07);}
/* Placeholder and typed value are ONE case, from the field's own token — the same
   declaration the input side reads. Inert for Session Title / Group / Team Name
   (their native placeholder is transparent, see below); [CORRECTED 2026-09-19]
   reads --tpl-field-case now, not --tpl-cardname-case, tracking those two fields'
   move off the card-name tier. */
.tpl-start input.tpl-fac-input::placeholder{text-transform:var(--tpl-field-case);}
.tpl-fac-req{color:var(--red);}
/* (HELPER COPY UNDER A FIELD LABEL is DELETED, 2026-09-21. `.tpl-field-help` and
   _identity-field's `ifHelp` slot were both minted by 57722d89 for one consumer,
   #tpl-participant-contact — the setup control for the address participants see. That
   control is gone (the address is the session owner's, resolved at render), the slot had
   no other caller, and the tokens it read have other consumers and stay. A field that
   wants help copy again should re-mint this deliberately rather than find it lying
   around with nothing using it. */
/* ── IDENTITY FIELDS: the placeholder IS the label (Session 176) ────────────────
   The SESSION TITLE / GROUP / TEAM / ORGANISER / FACILITATOR headings above these
   four boxes are gone, so the empty state carries all of the labelling. That forced
   two changes, both of which are about the placeholder being CONTENT now rather than
   a hint:

   1. TYPE. [CORRECTED 2026-09-19, TWICE] The boxes no longer join THE CARD-NAME TIER
      (templates.css) for anything. They used to take size/tracking/case/line-height
      from it (font-family had already moved off it in an earlier pass); by operator
      decision they are now the SAME CONTROL as the Overall Question field and every
      other .tpl-field-text consumer, not a similar-looking one — face, size and case
      all come from .tpl-field-text + .tpl-abel (also on the input, templates.css),
      the same declaration every other text-entry field on the surface reads. The
      overlay below follows it to the same tokens so the placeholder and the typed
      value still agree. .tpl-card-name-input stays in the markup as a bare marker —
      see its own note in templates.css — but carries no type any more.
   2. A DRAWN PLACEHOLDER. The required marker has to be red (--red) while the prompt
      copy stays --color-label, and a native ::placeholder is ONE colour for the whole
      string. So the native one is made transparent and .tpl-fac-ph draws the visible
      prompt as an overlay span, with the asterisk in the shared .tpl-fac-req.

   [HARD] THE placeholder ATTRIBUTE STAYS ON THE INPUT and is never emptied. The
   completion badge and this overlay's own show/hide gate both key on
   :placeholder-shown, and — the part that bites — :not(:placeholder-shown) MATCHES an
   input with no placeholder attribute at all, so emptying it would not remove the
   badge, it would light it permanently on an empty box. It also remains the fallback
   accessible name; the visually-hidden
   <label for> is the primary one. Nothing here is ever submitted: the overlay is a
   sibling span, not part of the input's value, so the asterisk cannot reach the POST
   or the empty check. */
.tpl-start input.tpl-fac-input.tpl-card-name-input::placeholder{color:transparent;}
/* DELETED: `.tpl-start input.tpl-fac-input.tpl-card-name-input, .tpl-start .tp…` — do not re-add; the reason is T18 in the decision record. */
/* DELETED: THE ORGANISER PAIR'S left-align EXCEPTION — do not re-add; the reason is T19 in the decision record. */
/* The overlay is laid over the input's own content box — left/right at the shared
   --tpl-field-inset (the SAME token the box's padding uses), bottom-anchored over the
   34px box exactly as the ✓ overlay is, so it tracks the box and not the row. That
   shared geometry is what makes the centring above land identically in both states:
   the overlay's box IS the input's content box, so "centred" resolves to the same
   axis for the drawn prompt and for the typed value.
   display:block + line-height:34px rather than the ✓'s flex centring, deliberately: a
   flex container would ignore text-align. Line-height is the box height because a
   single-line input centres its content in the box regardless of the tier's 1.1 —
   that value describes wrapped heading text and has nothing to apply to here. */
.tpl-start .tpl-fac-ph{
    position:absolute;
    pointer-events:none;
    /* LEFT IS 0 SINCE 2026-08-24 — the drawn prompt shares the typed value's axis, and
       that axis is now the field's own box edge (the inset moved into --col-line-x). The
       RIGHT keeps the inset for the same reason the field does: the completion badge. */
    left:0;
    right:var(--tpl-field-inset);
    /* [HARD] BOTTOM-ANCHORED AGAIN, AND FOR A DIFFERENT REASON THAN THE FIRST TIME.
       The original `bottom:8px` was tracking .tpl-fac-input's margin-bottom — a
       literal that pinned the margin in place — and was replaced by top:0 when that
       margin went, because the input was then the row's FIRST in-flow child.
       It is not any more: the .tpl-crit-tag label is in flow above it, so top:0 now
       lands on the LABEL and the drawn prompt would sit over the wrong element.
       bottom:0 is exact rather than approximate here, and needs no literal: absolute
       offsets resolve against the containing block's PADDING box, which excludes the
       row's rust border-bottom, and the input is the last in-flow child with no
       margin — so bottom:0 IS the input's bottom edge and height:34px covers exactly
       the input. The invariant this depends on is stated in _identity-field.blade.php:
       nothing in flow may be added below the input. */
    bottom:0;
    height:34px;
    line-height:34px;
    display:block;
    overflow:hidden;
    white-space:nowrap;
    /* [CORRECTED 2026-09-19, TWICE] All four terms were --tpl-cardname-* (Bebas /
       20px / 0.02em / uppercase). The input side reads NONE of those any more — see
       the note above this rule — so the overlay follows it to the --tpl-field-*
       set, the same tokens .tpl-field-text supplies the typed value through,
       keeping the drawn prompt and the typed text one face, one size, one case.
       This box is not an <input>, so it cannot carry .tpl-field-text itself and
       states the four terms directly; line-height stays the box's own (34px, see
       above) rather than reading --tpl-field-line — there is no such token, the
       tier states it as a box height here, not a text line-height. */
    font-family:var(--tpl-field-font);
    font-size:var(--tpl-field-size);
    letter-spacing:var(--tpl-field-tracking);
    text-transform:var(--tpl-field-case);
    /* (No colour here. The overlay is a placeholder, so it reads --tpl-ph-color from the
       scope-wide FIELD STATES rule in templates.css together with every native
       ::placeholder on the surface — that shared declaration is the only reason a drawn
       prompt and a native one resolve to the same grey.) */
}
/* Empty-state only. :not(:placeholder-shown) is the SAME trigger the fill and the ✓
   use, so the three can never disagree about whether a field is filled. Deliberately
   NOT keyed on :focus — the prompt is the only cue INSIDE the box (the field's
   .tpl-crit-tag caption sits above it, so "the only label" — which this note used to say
   — is wrong), and clearing it on focus would leave a tabbed-into empty box. */
.tpl-start .tpl-block-row:has(> input.tpl-fac-input:not(:placeholder-shown)) > .tpl-fac-ph{display:none;}
/* Match the box's own :disabled dimming so a gated field reads as one thing. */
.tpl-start .tpl-block-row:has(> input.tpl-fac-input:disabled) > .tpl-fac-ph{opacity:0.55;}
/* DELETED: The Session Title / Group Name band-offset override that sat here — do not re-add; the reason is T20 in the decision record. */
/* ── EXPERIMENT (revertible in one commit): box the content-card entry fields ───
   Swap the .tpl-inline-edit underline (and the comparison box) for the header
   .tpl-fac-input box: white box + border + radius; FILLED → the completion badge and
   nothing else (the parchment fill this used to name is DELETED, Session 176 — see
   FIELD STATES in templates.css); Abel → DM Mono (per-field size kept; Bebas card names
   keep Bebas via their higher-specificity rule). Numerals / letters / [Edit] / × /
   static Bebas labels are untouched (they sit outside the wrapper or keep their own
   rules). Width still comes from --col-line-width. Revert this whole commit to undo. */
/* `background:transparent` is DELETED from this rule. It asserted the DEFAULT — the base
   .tpl-inline-edit in templates.css declares no background — while out-specifying the
   canonical focus fill (0,3,0 against 0,2,0), so the one thing it actually did was stop
   every inline-edit field from filling white on focus. See THE FOCUS TREATMENT. */
.tpl-start .tpl-inline-edit{border:none;align-items:center;position:relative;}
/* DELETED: `.tpl-start .tpl-inline-edit:focus-within` — do not re-add; the reason is T21 in the decision record. */
.tpl-start .tpl-inline-edit > input{background:var(--color-white);border:1px solid var(--color-border);border-radius:var(--radius-field);height:34px;padding:0 var(--tpl-field-inset) 0 0;box-sizing:border-box;-webkit-appearance:none;appearance:none;}
.tpl-start .tpl-section-prompt-input{background:var(--color-white);-webkit-appearance:none;appearance:none;}
/* DELETED: The DM criterion / MS section-name PART FILL — do not re-add; the reason is T22 in the decision record. */
/* ── SINGLE SOURCE for facilitator text-input SIZE (root-cause consolidation) ──
   Every facilitator-entered text input — the name/email + Session Title boxes
   (.tpl-fac-input), every .tpl-inline-edit input (item text, comparison prompt,
   welcome/completion, AND the survey question, which is .tpl-abel but wrapped so
   it resolves here), and the comparison-question box (.tpl-section-prompt-input)
   — reads ONE token instead of each carrying its own font-size. --tpl-input-size
   is 14px on desktop and drops to the DM Mono label size (--tpl-field-label, 12px)
   at ≤640 via the token override further below, so these inputs can never drift
   from each other or out-grow the "CONTEXT / INSTRUCTIONS" labels again. This
   REPLACES the three per-rule font-size:14px declarations and the old
   multi-selector ≤640 shrink patch. Heading-tier inputs keep their own size by
   higher specificity (.tpl-card-name-input 20px Bebas, .tpl-vl-row-label-input
   15px). .tpl-abel (18px) stays the shared results/participant body tier — its
   value is untouched; its size is simply overridden here on setup inputs. */
/* 16px, up from 14px (2026-08-04). Raising the TOKEN rather than either field is the
   point: the question prompt and the Overall Question field must diverge together or not
   at all, and everything else that reads this tier moves with them by construction —
   every item row, the DM criterion / MS section Participant Question, the criteria and
   section description textareas, the Welcome and Completion bodies, the invite textarea,
   the roster add-form, the segment-option inputs and the closing-date field. That IS the
   blast radius; it is a surface-wide body-tier bump, not a two-field one, and inventing a
   second token to narrow it would have split a tier that exists to be one thing.
   The ≤640 arm below is deliberately NOT moved with it — see the note there. */
.tpl-start{--tpl-input-size:var(--type-field);}
/* ── THE CARD PADDING SCALE, AS A TOKEN ───────────────────────────────────────
   18px desktop / 14px ≤640 are .tpl-form-card's own two vertical values (19/15 measured
   with its border, from 95c1c686). They were literals repeated across three media arms,
   and the question row needed the same pair — so rather than a fourth and fifth copy,
   the pair becomes one token that .tpl-form-card and the question row both read. Nothing
   moves on the cards: same values, one home. */
/* THE CARD'S INSET — ONE VALUE VERTICALLY, EVERY CARD, ONE SOURCE.
   [HARD] IT IS NO LONGER "ALL FOUR SIDES", AND THIS HEADING USED TO SAY IT WAS
   (corrected 2026-08-24). The two HORIZONTAL sides are --col-card-pad-l / -r, declared
   immediately below; this token is the vertical inset and the scale the horizontal pair is
   derived from. A note asserting the opposite of what its rule does is worse than no note —
   see the width:auto history in question-types.js for what that costs.
   The first of the three numbers in the vertical rhythm: 32 inside a card's edge, 26
   between one card and the next (--tpl-gap, templates.css — which is also the page's
   horizontal gutter and inter-column gap), 24 between two objects inside a card
   (--stack-gap), 6 from an eyebrow to the field it names (.tpl-crit-tag).

   IT WAS --tpl-card-pad-y AND IT IS NOT A VERTICAL-ONLY TERM ANY MORE. The horizontal
   side was a bare 22px literal restated in .tpl-form-card and both of its media arms —
   deliberately left alone when the vertical became a token, which is what made a card's
   bottom inset read larger than its sides. A card has ONE inset; it is written here and
   nowhere else, and the media arms below move THIS rather than restating a shorthand.
   --tpl-section-inset-l / -r (the MS section band's and panel's row inset) are derived from
   the horizontal pair, not from this token, so the MS rows and the DM well's rows cannot go
   out of step; `php artisan setup:desc-align` and `setup:well-probe` measure that
   relationship and both still hold.

   [HARD] 32 -> 24 AT >=641 ONLY (2026-08-27), AND IT MOVES THE FIELD LINES 16px. Changing
   this token is NOT a vertical-only edit, because --col-card-pad-r below derives from it:
   `2 * (--tpl-card-pad + --tpl-well-inset) - --col-card-pad-l - --tpl-field-inset`, so 8px
   off the token takes 16px off the card's RIGHT padding and the row content box grows by
   exactly that. Measured across 16 cells at 1280: 250 boxes gained 16px of width, 67 moved
   16px right, and the field line's right end went 837 -> 853 with its left end unmoved at
   400. setup:header-lane stays green because it asserts the shapes AGREE and they all moved
   together; it is not a check that the lines did not move.

   NOTHING COMPENSATES FOR THAT, DELIBERATELY. Pinning --col-card-pad-r to hold the old
   line length would put a second, independent number on the page for the card's right
   inset — the exact thing the paragraph above says this token exists to prevent — so the
   derivation is left to do its job and the consequence is recorded here instead.

   The narrow arms are UNCHANGED and stay literal: 16px at <=640, 10px at <=480. Measured
   at 390 across the same 16 cells, not one box moved. They are not expressed as a fraction
   of this value because no clean one exists (16 is 2/3 of 24, 10 is 5/12) and a derived
   pair would put the phone's inset at the mercy of a desktop judgement. */
.tpl-start{--tpl-card-pad:24px;}
/* ── THE CARD'S HORIZONTAL INSET IS ASYMMETRIC, AND IT IS FORCED (2026-08-24) ──────
   THE ONE NUMBER: --col-card-pad-l is the card's LEFT padding, so the row band — the drag
   column, and therefore every badge and every line on the card — begins at
   `1px border + --col-card-pad-l` from the card's edge. Reduce this and the whole interior
   moves left together. It is the only horizontal number on the surface a designer needs.

   [HARD] WHY THE RIGHT SIDE IS NOT THE SAME NUMBER, AND WHY THAT IS NOT SLOPPINESS.
   Three things are pinned at once and the third follows from the first two:
     (a) the CARD's box does not move (the page gutter is out of scope);
     (b) the LINE does not grow — --col-line-width must still render 438 at 1280 and 226 at
         390, and it is `min(--col-line-max, 100% − --col-line-x − --col-right)` where 100%
         RESOLVES AT THE POINT OF USE against the row's containing block. So the row band's
         WIDTH is what pins the line, and it must not change.
   Card width − row-band width is therefore a constant, and it is the pair of insets. Move
   the left one in and the right one MUST take up the slack: the line shifts left, it does
   not lengthen. There is no symmetric solution — asking for a smaller left indent, a fixed
   card and an unchanged measure is asking for asymmetry, and this is where it is written
   down rather than discovered later as drift.

   --col-card-pad-r is that complement, expressed so it CANNOT drift: twice the inset the
   card used to spend on each side (its own padding plus the well's), minus whatever the
   left now takes. At the old --col-card-pad-l:32px it computes 32px and every box on the
   page is where it was, which is how this was checked before the number moved.

   THE WELL NO LONGER INSETS HORIZONTALLY, AND THAT IS THE OTHER HALF OF ONE EDIT. A row
   badge used to sit inside .tpl-flat-subcard's own 15px (1px border + 14px padding) and a
   card badge did not, which is the entire reason OVERVIEW's numeral sat 15px left of a
   section's. The well's horizontal inset is now 0, so both families sit at the card's
   content edge + --col-num-x and there is nothing left to keep in step. --tpl-well-inset
   survives ONLY inside --col-card-pad-r, as the width the card has to give back — it is
   the memory of the inset, not a second one.
   That also retires the coincidence A.2.2 of the 2026-08-23 audit names: flat/DM reached
   x=348 as 33+15 and MS as 1+47, "arithmetic agreement between two independent numbers, in
   two files, with no assertion tying them". There is now one number and one file. */
.tpl-start{
    --tpl-well-inset:15px;
    /* ── THE NUMBER, AND WHERE IT COMES FROM ──────────────────────────────────────
       THE INDENT IS --tpl-gap: 26px from the card's border box to the row band, of which
       1px is the card's own border, so the padding is 25.

       --tpl-gap is already the page's ONE horizontal spacing value — the page gutter, the
       gap between the two rails and the middle column, and (in the other axis) the gap
       between one card and the next. Using it here means the whitespace OUTSIDE a card's
       left edge and the whitespace INSIDE it are the same number from the same token, and
       there is no new number on the page to justify or to keep in step.
       It also happens to equal --col-num-x at ≥641 (drag 16 + gap 10 = 26), so the card
       edge → drag column → badge reads as two equal steps. That is a coincidence of two
       tokens, not a derivation, and nothing is wired to it — but it is why 26 looks
       deliberate rather than merely smaller.

       THE RANGE WAS [15, 33] AND THIS IS 26. The ceiling was 33 (1 + --tpl-card-pad, then
       32; it is 25 since 2026-08-27, i.e. BELOW this value now): at
       that value the row band merely joins the card's existing content edge, every badge
       aligns, and the CARD numerals do not move at all — alignment without a reduction.
       The floor is 15 (1 + the well's old 14): below that the drag grip crowds the card's
       border against a card that still pads --tpl-card-pad top and bottom, and the right-hand slack
       (which grows by exactly what the left gives up — see above) starts to read as a
       mistake rather than as a margin. All four were rendered at 1280 on blank_ms and
       compared; 15 looked like the content was falling off the left edge and 33 did not
       look reduced. 26 is 46% off the row indent (48 → 26) and 21% off the card's (33 → 26).

       [HARD] IT IS A JUDGEMENT, NOT A DERIVATION, AND THE DERIVATION IS THE TOKEN.
       Do not "correct" this to a literal 25px or 26px: the point is that the number has one
       home, and if --tpl-gap ever moves this follows it. */
    --col-card-pad-l:calc(var(--tpl-gap) - 1px);
    /* ROUTE B (2026-08-24): the card's right padding gives back --tpl-field-inset, which is
       what --col-line-x gained when the field's left inset moved out of the box. The row
       content box grows by exactly that, so --col-line-width still renders 438 at 1280 and
       226 at 390 and --col-right still clears the widest cluster by the same 5.48 / 0.00.
       Measured before choosing: pushing the line's right edge into --col-right instead would
       have overrun the row box by 6.52px at 1280 and 12.00px at 390. The LEFT inset is
       untouched — badges stay at 352 / 35 and nothing gives back the card-indent commit. */
    --col-card-pad-r:calc(2 * (var(--tpl-card-pad) + var(--tpl-well-inset)) - var(--col-card-pad-l) - var(--tpl-field-inset));
}
/* ── AND THE NARROW ARM IS NOT THE DESKTOP NUMBER (2026-08-24) ─────────────────────
   [HARD] BELOW 641 THE LEFT INSET FOLLOWS --tpl-card-pad AND IS NOT REDUCED FURTHER.
   Two reasons, and the first is arithmetic: a phone card is 342px wide against 680, and it
   already pads only 16px (10 below 481). There is nothing to take. The desktop number is a
   judgement about a large card's whitespace; applying it to a phone would make the inset
   BIGGER at 390 than it is today, which is the opposite of the ask — measured, a flat 19px
   here put every badge at 44 instead of 35.
   The second is that the phone's ladder is a different shape and always has been:
   --col-drag collapses to 0 at ≤640, so a row has no drag column to sit behind and the
   badge IS the row's first ink. The alignment still lands — both families read this one
   token — but the INDENT it produces is 11px (1px border + 10px), against 20px at ≥641.
   Written as var(--tpl-card-pad) rather than as 16px/10px literals so it keeps following
   the ≤640 and ≤480 arms of the card scale, which is where those two numbers live. */
@media(max-width:640px){.tpl-start{--col-card-pad-l:var(--tpl-card-pad);}}
/* ── AND BELOW 641 THE TWO SIDES ARE THE SAME NUMBER (2026-08-31) ──────────────────
   THE ASYMMETRY'S OWN JUSTIFICATION IS ALREADY DEAD AT THIS WIDTH, and that is the whole
   argument for this line. --col-card-pad-r is the complement that holds the ROW BAND's
   width constant while the left indent shrank, and the [HARD] note above states the pin it
   exists to serve: "the LINE does not grow — --col-line-width must still render 438 at
   1280 and 226 at 390". The phone half of that stopped being true on 2026-08-31, when
   --col-right went to 0 at <=640 and a field line was made to run to its card's content
   edge: the line at 390 is 333px, not 226, and its right edge is the card's, not a
   reserve's. A complement that holds a width nothing states any more is holding nothing.

   WHAT IT WAS DOING INSTEAD, measured on DM at 390: a criterion sub-card sat 10px from
   its parent card's left edge and 28px from its right — the parent's own padding, one
   token on each side, 18px apart. Every card's CONTENT sat 11 in from the left and 29 in
   from the right for the same reason. One source for both sides now; the sub-card is
   10/10 and 18px wider, and every line inside it moves with it and stays on the one right
   edge --col-line-width already gives them.

   THE DESKTOP HALF OF THE PIN STANDS AND IS NOT TOUCHED. At >=641 --col-right is 84px, the
   line IS 438, and the complement is still what keeps it there — which is why this is a
   <=640 arm beside the left one and not an edit to the derivation above. */
@media(max-width:640px){.tpl-start{--col-card-pad-r:var(--col-card-pad-l);}}
/* The two narrow arms live HERE, beside the value they replace, and not in templates.css
   with the .tpl-form-card rule that reads them: this inline <style> loads after that
   sheet, so a token arm written there loses to this declaration at every width and the
   card would never tighten. They were `.tpl-form-card{padding:… 16px}` / `… 10px`
   shorthand restatements; moving the number instead keeps "one value, all four sides"
   true at all three widths. */
@media(max-width:640px){.tpl-start{--tpl-card-pad:16px;}}
@media(max-width:480px){.tpl-start{--tpl-card-pad:10px;}}
/* SINGLE SOURCE for the horizontal inset of a setup field's TEXT from its own box edge.
   The four-column contract aligns the BOXES; this aligns the text inside them, which is
   what the eye actually reads down. Both consumers must use it or they drift by exactly
   the difference: the DM criterion pair briefly used a hand-matched 13px against this
   rule's 12px, and the measured description text landed 1px off the item text. One
   declaration, two consumers — same rule as the column tokens above. */
.tpl-start{--tpl-field-inset:12px;}
/* DELETED: `.tpl-start input.tpl-fac-input, .tpl-start .tpl-inline-edit > inpu…` — do not re-add; the reason is T23 in the decision record. */
/* ── THE PANEL FIELDS JOIN THE BODY TIER ───────────────────────────────────────
   Four fields were the last Abel-18 holdouts on the surface: they carry .tpl-abel
   (templates.css:100), which is the shared RESULTS/PARTICIPANT body tier and must
   not be edited for a setup-page reason, so they are routed here instead.

   Two of the four are manage-only markup (_manage-chrome). The rule still lives in
   THIS file, with the rest of the tier, on purpose: manage renders templates.start,
   so this <style> reaches them, and splitting one tier decision across two files is
   how the surface got four sizes for one role in the first place.

   SPECIFICITY, not source order: tokens.css's iOS focus-zoom floor
   `input:not([type=checkbox]):not([type=radio]):not([type=range])` is (0,3,1) and
   would otherwise pin these to 16px at ≤640, exactly as it does today. An id gives
   (1,1,0) outright.

   [HARD] AN ID SELECTOR ONLY REACHES A SINGLETON, AND ON THIS SURFACE THE SECOND
   COPY IS USUALLY THE ONE BUILT IN JAVASCRIPT. The viewer-link password box is
   emitted TWICE: once in the create form (_manage-chrome:765, id="tpl-vl-password")
   and once per existing link by a JS string builder (_manage-chrome:1209,
   data-vl-password, NO id). `#tpl-vl-password` reached the first and silently
   missed the second, so two instances of one field rendered at two sizes — Abel
   18px on the row, DM Mono 14px in the form. Found by re-running the
   literal-winner check, not by reading the rule.

   Hence the class+attribute selector for that one: `.tpl-start
   input.tpl-vl-input[type="password"]` is (0,3,1), which TIES the floor rather
   than beating it, and wins because this <style> is inline in the page and comes
   after tokens.css. The [type="password"] half is load-bearing — bare
   .tpl-vl-input would also catch #tpl-vl-label, which is a LABEL and belongs to
   --tpl-body-case.

   The other two ids stay ids: each was checked and has exactly one emitter
   (.tpl-project-create-input _save-project-block:62, .tpl-invite-textarea
   _manage-chrome:617). When adding a field here, grep the CLASS across
   .blade.php AND .js before reaching for its id.
   (A third, .tpl-segment-custom-input, was the participant-field custom-field
   box; DELETED with it 2026-08-31 — a custom field's name now types into the
   same .tpl-pd-namebox input every other field uses, so there is no longer a
   bespoke case here at all.)

   SIZE AND FAMILY ARE THE SAME FOR ALL OF THEM. CASE IS NOT, and the split is by
   what the field CONTAINS, not by which panel it happens to sit in:

     - a LABEL — something the facilitator names so it can be read back as a
       heading — is tier (b) and takes --tpl-body-case with every other label on
       the surface.
     - PROSE and a CREDENTIAL are neither. An invitation email body set in caps
       shouts at the recipient, and a password box has no case to display at all
       (the characters render as dots), so uppercasing it is meaningless noise in
       the rule. Both take --tpl-prose-case.

   The viewer-link LABEL (#tpl-vl-label) is not listed here and does not need to
   be: it is already inside a .tpl-inline-edit wrapper, so it reads the body tier
   — family, size AND --tpl-body-case — through the shared rule above. Adding it
   would be a second source for a field that already has one. */
/* DELETED: `.tpl-start #tpl-new-project-name, .tpl-start input.tpl-vl-input[ty…` — do not re-add; the reason is T24 in the decision record. */
/* (c) FOCUS = WHITE. A filled box is the parchment valid fill (rules above, keyed on
   :not(:placeholder-shown)); while it is focused for editing it must read as a
   plain white edit surface, not stay blue. This rule sits AFTER the blue fill
   rules and shares their specificity, so source-order lets focus win — and it
   also carries the ink focus border (folded in from the old :focus rule).
   Scoped to .tpl-inline-edit > input so it never leaks to other inputs. */
/* DELETED: `.tpl-start .tpl-inline-edit > input:focus` — do not re-add; the reason is T25 in the decision record. */
/* ── COMPLETION MARK — MOVED OUT, NOT REMOVED ───────────────────────────────────
   The shared `content:'\2713'` glyph, its enumerated :has() positioning hosts, their
   per-host vertical anchors, and the whole .tpl-no-valid-fill block (the identity
   fields' fill reversal and their circle-badge arms) are DELETED and replaced by ONE
   rule: FIELD STATES in templates.css. .tpl-no-valid-fill itself is gone — it existed to
   keep one field family off a fill that no longer exists anywhere.

   Why the mechanism changed rather than just the glyph. An ::after needs a POSITIONED
   WRAPPER per field, so it could only ever mark fields that happened to have one: the
   audit found the instructions textarea, the guidance textarea, the roster inputs and
   the Slide-canvas fields had no wrapper and therefore no completion mark at all, and
   .tpl-instructions-title had the fill but no tick because the fill rule omitted
   :not(:disabled) where the tick rule had it. Painting the badge as a BACKGROUND on the
   field itself needs no wrapper, so it reaches every field including the JS-built rows.

   [HARD] THE position:relative HOSTS BELOW ARE NOT PART OF THIS DELETION. They host
   .tpl-fac-ph — the drawn placeholder, the only cue inside those four boxes (they carry a
   visible .tpl-crit-tag caption above them; this note used to call the prompt their only
   label and that is wrong) — as well as the old ✓. Removing them because the ✓ is gone
   is exactly what took this page down on 2026-08-03; see their own comment.

   [HARD] Do not reintroduce a fill here. There is no --field-valid-fill any more — the
   token is deleted from tokens.css. A completed field differs from an empty one by the
   badge and by nothing else. */
/* DELETED: `--tpl-badge-inset + --tpl-badge-size + 6px` — do not re-add; the reason is T26 in the decision record. */
/* [HARD] POSITIONING CONTEXT FOR **TWO** ABSOLUTE OVERLAYS, NOT ONE. Scoped by
   :has() to only the wrappers that actually hold a .tpl-fac-input, so no other
   .tpl-block-row is made relative.

   THE TWO CONSUMERS, both position:absolute, both resolving against this rule:
     1. the completion mark on the four identity boxes;
     2. **.tpl-fac-ph — the DRAWN PLACEHOLDER**, the only cue inside the box. (Not
        their only LABEL: each carries a visible .tpl-crit-tag caption above it — see
        _identity-field.blade.php. This line used to say otherwise.)

   This comment used to name only (1). On 2026-08-03 a sweep that removed the ✓
   read the rule as orphaned scaffolding on the strength of that comment, deleted
   it, and took the setup page down: with no positioned ancestor the four overlays
   resolved against main.tpl-start and stacked in the page's bottom-right corner,
   leaving four empty boxes. All three route smoke checks returned 200 throughout —
   HTTP status cannot see this.

   So: a comment naming one consumer is NOT evidence there is only one. Before
   deleting this rule — or any rule — on the strength of what its comment says it is
   for, remove it and MEASURE what moves. */
.tpl-start .tpl-block-row:has(> input.tpl-fac-input){position:relative;}
/* ── THE RUST RULE — the same object .tpl-crit-part--name draws, on the element that
   plays the same part here ────────────────────────────────────────────────────────
   On the criterion card the rule is `border-bottom:2px solid var(--red)` on the PART
   that holds the name field, not on the input. The identity rows are that part: they
   hold the label, the field and nothing else, so the border belongs to them for the
   same reason — a border on the input would be inside the badge lane's padding box and
   would have to be re-measured every time the lane changed.

   ONE WEIGHT EVERYWHERE, AND IT IS A CLASS NOW. The rule used to be drawn by five
   separate structural selectors at two weights — 2px on the identity pair, the Overall
   Question and the DM criterion name; 1px on the organiser pair and the item rows — to
   separate primary fields from secondary ones. That distinction is retired by decision:
   the thicker weight is the reference and every rust underline takes it.

   THE CLASS IS THE POINT, not the value. Five selectors agreeing on a weight is the
   drift this codebase keeps paying for; one class carried in the markup cannot disagree
   with itself. It rides on nine emitters — the two identity rows, the two organiser
   columns, the Overall Question line, the DM criterion name (Blade AND its JS builder),
   and the item row in both item-list builders — which is exactly the set the five
   selectors reached, no more. Verified by walking the rendered page: every rust
   border-bottom inside the form carries .tpl-rust-rule and measures 2px, and nothing
   carries the class without drawing one.

   [HARD] AS OF 2026-08-20 question-types.js IS A THIRD EMITTER, for OPTION rows only, and
   the paragraph below records why it was excluded — a reason that has since expired. It
   said the survey/quiz question card "is a different treatment and giving its rows a rust
   rule is a design change wearing a refactor's clothes". The treatment is no longer
   different: a question block is DM's criterion block and an option row is a row in a
   list inside it, which is the same object as a DM item row. So it takes the same rule,
   in the markup, from this one class. QUESTION rows still do NOT take it — a question is
   a criterion NAME, and its rust rule comes from .tpl-crit-part--name carrying the class.

   [HARD] THE ITEM-ROW EMITTERS ARE THE TWO IN THIS FILE'S OWN IIFE, NOT question-types.js.
   That file also builds .tpl-item-row and wraps inputs in .tpl-inline-edit, for question
   rows and option rows — which the old selector excluded twice over (they sit in
   .tpl-questions-list, and their wrapper is nested in .qt-input-col rather than being a
   direct child of the row). They must not gain the class: the survey/quiz question card
   is a different treatment and giving its rows a rust rule is a design change wearing a
   refactor's clothes.

   The tokens exist so the weight and the two colours are stated once. --tpl-rule-ink is
   not simply --ink at the point of use: it is "this field is done", which is a role, and
   the MS section bar below reads the same three tokens without being a border at all. */
.tpl-start{
    /* ONE WEIGHT, AND IT IS 1px NOW (was 2px). The page carried FOUR underline
       treatments — a 2px red on the required fields, a 1px red on the item rows before
       .tpl-rust-rule unified them, nothing at all under the description textarea, and a
       1px hairline under the comparison question that stopped 13px short at each end.
       A 2px rule beside a 1px one reads as two different kinds of line; there is one
       weight, and the colours below are the only variable.

       [HARD] TWO COLOURS, AND THEY ARE STATES, NOT IMPORTANCE (2026-08-20, second pass).
       THIS SUPERSEDES "RUST FOR A REQUIRED FIELD, HAIRLINE FOR AN OPTIONAL ONE", which
       stood here earlier today and is deleted rather than kept as history — including
       --tpl-rule-hairline itself, which had no other consumer.

       RUST = this field is empty and is waiting for you. INK = it holds something.
       Every fillable field on the surface, optional or not: LOW LABEL and HIGH LABEL and
       the question hint answer to it exactly as the criterion name does. Importance is
       already carried by the asterisk, and a reader could not tell the old hairline from
       the rust without knowing which fields were required — i.e. the line was answering a
       question its reader could not ask. State is a question the line can answer, because
       the reader can see the field. */
    /* DELETED: --tpl-type-chip-w — do not re-add; the reason is T27 in the decision record. */
    --tpl-rule-weight:1px;
    --tpl-rule-color:var(--red);
    --tpl-rule-ink:var(--border-strong);
}
/* ── [HARD] THE CHIP SITS ABOVE ITS ROW, ON A LINE OF ITS OWN ─────────────────────
   EVERY RULE ON THIS PAGE ENDS AT ONE X. Not one length for headers and another for
   fields — one length, full stop. `php artisan setup:header-lane` asserts it across DM,
   MS, survey and quiz.

   THAT IS ONLY POSSIBLE IF THE TYPE CHIP TAKES NOTHING FROM A ROW, so it takes a row.
   It is an ordinary member of the pair, above the name, captioned in the field-label
   tier because a control alone on a line has nothing saying what it is for.

   THE TWO ALTERNATIVES, BOTH BUILT AND BOTH MEASURED, SO THIS IS NOT REOPENED:

     (a) A SECOND COLUMN ON HEADER ROWS ONLY — the chip beside the name, 145px + a gap
         carved out of the content column. Shipped for one pass. It produced TWO rule
         lengths: 436.19..666.81 on a header row against 436.19..821.81 on every other,
         on every shape. Consistent, asserted, and still two lengths where the page has
         one column. Rejected on that alone.

     (b) THE CHIP IN THE SHARED CONTROL LANE — --col-right grows from 84px to ~232px to
         hold it. One rule length, and it costs about 155px off EVERY rule on the page,
         on every card and every shape, to place a control that two of the four shapes
         have. Rejected: the page pays platform-wide for a per-shape control.

   The chip's own line costs vertical space on the two shapes that have a chip, and
   nothing at all on the two that do not. --tpl-type-chip-w and the 155px header column
   are DELETED, not repurposed; there is no header lane and nothing to re-derive it from.

   DM IS UNCHANGED AND UNCOMPENSATED. A criterion has no type control, so its card has no
   type line — and because the chip no longer takes anything from a row, DM needs no empty
   column standing in for one. That is the difference between this and (a), where DM paid
   155px of line length for a column that held nothing.

   The row is a .tpl-crit-part like any other, so it draws the shared rule, ends where
   every other rule ends, and reads the shared completed arm — it holds no fillable field,
   so it is complete by construction (see A FILLED FIELD'S RULE GOES INK). */
/* DELETED: THE TWO .qt-type-row RULES — do not re-add; the reason is T28 in the decision record. */
/* ── [HARD] NOTHING TRUNCATES — IT WRAPS ──────────────────────────────────────────
   PLATFORM RULE: when content exceeds its lane or its line it moves to another row. It is
   never cut off and never ellipsised. An ellipsis keeps the geometry and destroys the
   content, which on a control whose entire job is to say which type this is makes
   "Rank Items…" and "Rank Images…" the same string.

   IT HAS NO ACTIVE CONSUMER HERE ANY MORE, AND IT STAYS. The chip was sized to a 145px
   budget for one pass and three names wrapped inside it; on its own line it is as wide as
   it needs to be and nothing wraps. The declarations below are kept because the rule is
   the platform's, not this control's — the next control given a budget inherits the
   behaviour instead of rediscovering that an ellipsis was never an option. They are inert
   at every width the chip currently renders at, which is the correct state for a rule
   that describes what must happen IF.

   The chip is a flex row (label + caret) and the CARET must not wrap away from the
   label, so the label wraps inside itself and the caret stays put.

   ── [HARD][OPEN 2026-08-21] THIS RULE IS CONTRADICTED ELSEWHERE, KNOWINGLY ───────────
      THE CARD-NAME TIER in templates.css declares `text-overflow:ellipsis` on the three
      card-name fields, with its own reasoning: truncation is a property of a display-face
      name. That is the direct opposite of this rule, and both are marked [HARD]. The
      contradiction is not new and was not introduced by the field that surfaced it — the
      tier has ellipsised since fab942b7.

      IT IS OPEN, NOT AN OVERSIGHT, AND IT IS NOT YOURS TO SETTLE IN PASSING. The
      resolution waits on a pending change to the setup card's WIDTHS: a wider lane may
      remove the need for either mechanism to yield, and converting a name to a control
      that CAN wrap (a textarea) before the lane is settled would be rebuilding against a
      moving target. The operator holds that decision.

      If you are here because a name truncates, do not delete either statement and do not
      add a third that splits the difference. See CLAUDE.md, Outstanding. ── */
/* DELETED: `.tpl-start .qt-type-col .qt-tag-label` — do not re-add; the reason is T29 in the decision record. */
/* ── A PAIRED FIELD ROW — TWO FIELDS, ONE ROW, ONE RULE ───────────────────────────
   .qt-pair-row IS a .tpl-crit-part. It takes the rule, the padding, the badge lane and
   the state from the shared field-row declarations exactly as a single-field part does —
   nothing about a pair is restated here except how its two cells divide the row.

   TWO CELLS AT HALF THE COLUMN EACH, not at the content's natural width. Min and Max
   hold two digits and could be far narrower, but a row whose cells are sized to their
   contents puts LOW LABEL's field in a different place from MIN's, and the column is the
   thing this surface keeps. One flex-basis for every pair.

   [HARD] BELOW 640 EVERY PAIR STACKS, INCLUDING MIN/MAX, WHICH WOULD STILL FIT.
   Measured at 390: the column is 167.5px, so a half is ~72px — usable for two digits and
   useless for "Strongly disagree". Keeping MIN/MAX paired there because it happens to fit
   would make the pairing rule true at one width and false at another, i.e. two rules, and
   the next person would have to rediscover which pairs survive a viewport. One predicate:
   pairs at desktop, stacks below 640.

   The rule stays on the ROW when stacked, so a stacked pair still shows one line under
   the pair rather than one per cell. That follows from the row being the field row; it is
   not a second arrangement. */
.tpl-start .qt-pair-row{display:flex;column-gap:var(--col-gap);}
.tpl-start .qt-pair-row > .qt-pair-cell{flex:1 1 0;min-width:0;}
.tpl-start .qt-pair-row > .qt-pair-cell > input{width:100%;}
.tpl-start .tpl-rust-rule,
.tpl-start.setup-sidebar .tpl-section-block .tpl-crit-part--desc,
.tpl-start.setup-sidebar .tpl-section-block .tpl-crit-part--q,
.tpl-start.setup-sidebar .tpl-questions-list .tpl-crit-part--desc,
.tpl-start.setup-sidebar .tpl-questions-list .tpl-crit-part--q{
    border-bottom:var(--tpl-rule-weight) solid var(--tpl-rule-color);
}
/* ── THE SAME RULE, ON THE CONTENT FIELDS ────────────────────────────────────────
   The Overall Question and the Options To Compare rows join the system. Their host is
   .tpl-inline-edit, and putting the border there is not a new mechanism — it is that
   element's ORIGINAL one: templates.css:1664 still declares
   `.tpl-inline-edit{border-bottom:1px solid var(--input-underline)}`, and the boxed
   treatment above (THE EXPERIMENT, ~line 1540) overrode it to `border:none` when these
   fields were given white boxes. The box is what goes; the underline it replaced comes
   back in the heading section's colour.

   BOTH TAKE .tpl-rust-rule NOW, in the markup, at the one weight. The Overall Question
   used to draw 2px and an item row 1px, on the reasoning that ten items under ten thick
   rules read as ten headings. That distinction is retired by decision, and the two
   declarations that carried it are DELETED rather than left sitting at equal values —
   two rules agreeing by hand is exactly what the class exists to prevent.

   THE SCOPE BELOW IS WHAT THE CLASS INHERITED, and it is why the class is applied in the
   two item-list builders in this file's own IIFE and nowhere else.
   `.tpl-items-list:not(.tpl-questions-list)` was the surface's existing idiom for
   "an item list, not a question list" — the same expression the gap and numeral rules a
   few hundred lines down already use — and it is what makes this ONE rule reach the
   three shapes that share the item-row builder: flat's #tpl-items-list, DM's shared
   #tpl-items-list, and every MS section's per-section .tpl-items-list. It deliberately
   does NOT reach the survey / quiz question rows: those are .qt-q-row inside
   .tpl-questions-list, a different component (question-types.js) with its own card
   treatment, and their .tpl-inline-edit is nested in .qt-input-col rather than being a
   direct child of the row — so the `>` combinator excludes them twice over.

   TYPE IS UNTOUCHED. Neither of these fields joins the card-name tier: they keep
   --font-mono at --tpl-input-size, which is what they render at today. Only the CHROME
   changes. */
/* DELETED: The two border-bottom declarations that stood here — do not re-add; the reason is T30 in the decision record. */
/* The field inside goes chrome-less, the same four declarations the identity fields
   take. padding stays --tpl-field-inset horizontally so the value's first glyph sits
   under its label's first glyph, as it does inside a criterion part.
   SPECIFICITY: both arms out-rank the (0,2,1) box rule, the first on its id and the
   second on five classes.

   [HARD] `:not(:focus)` IS LOAD-BEARING, AND IT IS THE SCAR OF A HOST THAT MOVED. These
   two arms used to read `> input` flat, and the paragraph here used to end "so a focused
   field stays transparent without a :focus arm of its own" — which was CORRECT while the
   focus fill was painted on the WRAPPER (.tpl-inline-edit:focus-within): the field had to
   stay transparent for the wrapper's white to show through it.
   The fill is on the FIELD now (templates.css), and that inverts this rule's effect: an
   unconditional `background-color:transparent` on an ID selector (1,3,1) out-ranks the
   fill (0,10,1) and cancels it outright. Measured, not reasoned: the flat Overall Question
   took focus and stayed transparent while every field around it filled.
   So the arms are scoped to the RESTING state, which is all they were ever describing —
   a chrome-less field at rest — and the focused state is left to the one rule that owns
   it. Do not drop `:not(:focus)` to "simplify" the selector; it re-breaks exactly one
   field, the one with the id, and only when it is focused.

   [HARD] background-COLOR, NEVER THE `background` SHORTHAND. The completion badge is a
   background-IMAGE layer painted on the field itself (FIELD STATES, templates.css), and
   the shorthand resets background-image to none. This is written down in two other
   places in this codebase and it still bit here, because the two arms fail DIFFERENTLY
   and only one of them fails visibly: the item arm is (0,5,1) and LOSES to the badge
   rule's ~(0,12,1), so its shorthand only ever reached background-color and the ring
   survived — while the Overall Question arm carries an id, beat the badge rule outright,
   and rendered with no ring when empty and no green tick when filled. An arm that is
   wrong and an arm that is right looked identical in the CSS. Caught in a screenshot. */
/* AND SLIM'S PLACE FIELD JOINED THEM 2026-08-25, FOR THE SAME REASON AND BY THE SAME
   MEANS. It was an .tpl-issue box (white fill, 1px border, 4px radius); the class-set
   conversion drops .tpl-issue and puts .tpl-rust-rule on its wrapper, and then the field
   needs exactly the four declarations these arms already carry. A rule of its own would
   have been a second mechanism saying the same thing — the note below is the precedent
   and it is being followed, not re-derived. (0,4,1), same shape as its neighbours, and it
   states no padding-right so the badge keeps its lane.
   The shared .tpl-issue rule is untouched: ~23 other consumers in this file and 9 in
   question-types.js still read it. */
/* SLIM'S PROMPT JOINED THESE ARMS 2026-08-24, IT DID NOT GET ITS OWN RULE. It is the
   same field as the flat Overall Question — an .tpl-inline-edit-wrapped
   .tpl-issue.tpl-section-prompt-input — so it wants the same four declarations, and
   adding a selector to a list is the difference between one mechanism and two. (0,4,1)
   out-ranks the (0,2,1) box rule and the (0,2,0) .tpl-section-prompt-input fill, and
   states no padding-right, so the badge keeps its lane. */
.tpl-start #tpl-flat-compare-fields .tpl-inline-edit > input:not(:focus),
.tpl-start.slim-mode .qt-input-col > .tpl-inline-edit > input:not(:focus),
.tpl-start .qt-opt-row > .tpl-inline-edit > input:not(:focus),
.tpl-start .tpl-items-list:not(.tpl-questions-list) > .tpl-item-row > .tpl-inline-edit > input:not(:focus),
.tpl-start.slim-mode .tpl-where-place > .tpl-inline-edit > input:not(:focus),
.tpl-start .tpl-timedate-length-fields > .tpl-inline-edit > select:not(:focus){
    background-color:transparent;border:0;border-radius:var(--radius-none);padding-top:0;padding-bottom:0;padding-left:0;
}
/* The chrome half of the same two arms, unconditionally: border, radius and padding are
   the field's resting AND focused chrome — only the BACKGROUND is state-dependent, and
   splitting them is what lets the arm above carry :not(:focus) without a focused field
   growing a border back. */
/* PADDING-RIGHT IS NOT STATED IN EITHER ARM (2026-08-20). The right inset is the
   BADGE'S LANE and has one owner (THE BADGE'S LANE, templates.css); these two arms carry
   an id and a five-class chain, so stating a shorthand here out-specified it and the flat
   Overall Question reserved 12px against a 38px badge. Found by setup:badge-probe's lane
   census, not by reading — the same way this block's own note records the ring being lost
   to a shorthand. State the left inset, which really is this field's chrome, and let the
   lane come from the badge. */
.tpl-start #tpl-flat-compare-fields .tpl-inline-edit > input,
.tpl-start.slim-mode .qt-input-col > .tpl-inline-edit > input,
.tpl-start .qt-opt-row > .tpl-inline-edit > input,
.tpl-start .tpl-items-list:not(.tpl-questions-list) > .tpl-item-row > .tpl-inline-edit > input,
.tpl-start.slim-mode .tpl-where-place > .tpl-inline-edit > input,
.tpl-start .tpl-timedate-length-fields > .tpl-inline-edit > select{
    border:0;border-radius:var(--radius-none);padding-top:0;padding-bottom:0;padding-left:0;
}
/* ── A FILLED FIELD'S RULE GOES INK, AND STAYS THERE ──────────────────────────
   (Was "A FILLED NAME FIELD'S…". It is every field now — see TWO COLOURS, AND THEY ARE
   STATES above, which supersedes the required/optional split this arm used to sit beside.)

   Rust says "this line is waiting for you"; once the field holds a valid value the line
   has nothing left to ask for, so it settles to --ink. It is the same claim the green
   completion badge makes, which is why it rides THE SAME GATE —
   `:not(:placeholder-shown):not(:disabled):valid`, the exact expression FIELD STATES
   (templates.css) uses for the tick. Copying the gate is deliberate and the two must
   never diverge: a field showing a tick over a rust rule would be telling the operator
   two different things about one box. :valid is vacuously true where no constraint
   exists, so it only bites on the organiser email — a half-typed address keeps its rust
   rule and its hollow ring together, which is the one case where "done" being wrong
   costs a participant their link.

   THE FOUR :has() ARMS ARE FOUR SHAPES OF THE SAME FIELD ROW, not four rules:
     > input      — the identity rows, the organiser columns, .tpl-crit-part--name, and
                    every one-line config field (MIN, MAX, LOW LABEL, BUDGET TOTAL…).
     > textarea   — the descriptions and the question hint. A textarea matches no input
                    selector, which is exactly why the rule is drawn on the ROW and not
                    on the field; see the note in setup-sidebar.css.
     > * > input  — a field wrapped one level deeper: an option row's .tpl-inline-edit,
                    the budget amount's .qt-budget-wrap, and whatever the next one is.
                    Written as a wildcard rather than as a list of wrapper classes because
                    the list is exactly what goes stale — BUDGET TOTAL was found stuck rust
                    by census precisely because its wrapper was not on it. .qt-pair-cell is
                    excluded because a pair is answered by the arm below, not by this one.
     .qt-pair-row — A PAIR IS COMPLETE WHEN BOTH ITS FIELDS ARE, which is why it cannot
                    ride the wildcard arm: that asks "has any field here been filled", and
                    on a two-field row that is half the question. Fill LOW LABEL, leave
                    HIGH LABEL empty, and the wildcard would settle the line to ink while
                    the row is still waiting. Stated as "no field in it is still showing a
                    placeholder" — the same gate read from the other end, not a second
                    mechanism. Falsified: filling one cell of the pair leaves it rust.
     :not(:has(a fillable field)) — A ROW WITH NOTHING TO TYPE IN IS COMPLETE BY
                    CONSTRUCTION. MODE and RESPONSE MODE are segmented buttons, the
                    time/date columns are <select>s, "Include I don't know" is a
                    checkbox: all of them always hold a value, so there is no state in
                    which the line is waiting for anything. Leaving them rust would make
                    a permanently-unfinishable row, which is the opposite of what the
                    colour means. Checkboxes and radios are excluded from "fillable" for
                    the same reason — they cannot be empty.

   [HARD] A FIELD THAT CANNOT BE EMPTY IS ALWAYS INK, AND THAT IS THE ANSWER, NOT A GAP.
   MIN, MAX and BUDGET TOTAL are number inputs the editor keeps populated (coerce()
   never lets them go blank), so they resolve completed the instant they render and
   their line never shows rust. Correct: the rule reports whether the field still wants
   something, and these never do.

   (The MS `+ .tpl-flat-subcard::before` arm is DELETED. That bar no longer exists — MS's
   section name carries .tpl-rust-rule in the markup like every other name field, so it is
   covered by the first arm above. Colouring a pseudo-element nothing paints is the kind
   of dead rule that reads as a second mechanism to whoever finds it next.) */
:is(.tpl-start .tpl-rust-rule,
    .tpl-start.setup-sidebar .tpl-section-block .tpl-crit-part--desc,
    .tpl-start.setup-sidebar .tpl-section-block .tpl-crit-part--q,
    .tpl-start.setup-sidebar .tpl-questions-list .tpl-crit-part--desc,
    .tpl-start.setup-sidebar .tpl-questions-list .tpl-crit-part--q):is(
    :has(> input:not(:placeholder-shown):not(:disabled):valid),
    :has(> textarea:not(:placeholder-shown):not(:disabled):valid),
    :has(> *:not(.qt-pair-cell) > input:not(:placeholder-shown):not(:disabled):valid),
    .qt-pair-row:not(:has(input:placeholder-shown)),
    :not(:has(input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"]), textarea))
){
    border-bottom-color:var(--tpl-rule-ink);
}
/* [HARD] The ✓ is position:absolute, so its HOST must be positioned or it resolves
   against the nearest positioned ancestor — which for the criterion parts was
   main.tpl-start, i.e. right:10px/bottom:0 of the WHOLE PAGE. Every tick then piled
   up in the page's bottom-right corner and none appeared on any field. It reads as
   one stray glyph floating on the background, and the fill still worked, so the
   fields looked merely tick-less rather than broken. This rule is not optional
   decoration — it is half of the mechanism; the enumeration that found it checked
   every element's ::after and found the hosts fine and the glyph nowhere near them. */
.tpl-start .tpl-crit-part{position:relative;}
/* (The two title rows' band-offset `right` override goes with the glyph it positioned —
   the background badge paints inside the field's own box and needs no per-host
   horizontal origin. Their :has() position:relative host above STAYS: it is
   .tpl-fac-ph's containing block.) */
/* The budget amount is RIGHT-aligned, so its digits grow toward the badge — the one
   case where an overlap would land on the value rather than on empty space. Keep the
   reserved lane, measured from the shared badge tokens rather than the old 26px. */
/* ── THE BUDGET TOTAL IS A FIGURE, SO IT READS AT THE FIGURE TIER ─────────────────
   It carried NO tier of its own: as an unclassed input inside [data-q-config] it fell
   through to that panel's blanket `font-family:--font-mono;font-size:--tpl-field-label`
   — DM Mono 12px, the config micro-field size. A currency total is the largest number a
   question holds and it was the smallest thing on the card.

   It joins .tpl-weight-strip-status (added in the markup), which is the platform's
   existing tier for a figure of this kind — the Total Weighting strip's own number:
   --font-heading, --tpl-input-size, --tpl-cardname-case, --tpl-cardname-line, --ink.
   Nothing is restated here and no tier is invented; the class IS the join.

   [HARD] IT JOINS FOR SIZE, CASE AND COLOUR, AND NOT FOR FAMILY — MEASURED, AND LEFT
   THAT WAY DELIBERATELY. CORRECTS AN EARLIER REPORT that said the tier declares no
   font-family: it DOES (`font-family:var(--font-heading)`, with the size/case/colour in
   a second block), and every one of its rail consumers renders Bebas Neue. This one
   renders DM Mono because it is the only consumer that sits INSIDE a .tpl-crit-part,
   where the chrome-less field declaration
   (`.tpl-start .tpl-crit-pair .tpl-crit-part input:not([type="checkbox"]):not([type="radio"]):not([type="color"])`)
   is (0,6,1) — each :not() carries its argument's weight — against the tier's (0,2,0).
   Size and case still land because nothing else claims them.

   NOT FIXED, AND THE REASON IS THE FIELD CONVERGENCE: every field on this card is one
   chrome-less DM Mono field now, and winning this would mean either mirroring that
   three-:not() chain or carving this class out of the shared field rule. Both put one
   figure's typeface above the convergence, for a field that already reads at the strip's
   size, case and colour. If it is to change, change it at the field rule as a decision
   about fields, not with a higher-specificity arm aimed at one input.

   GREY WHILE EMPTY, INK ONCE ENTERED comes free and is not declared anywhere: --ink is
   the tier's colour, and an empty field shows its ::placeholder in --tpl-ph-color like
   every other field on the surface. That is the existing convention, not a new state. */
.tpl-start .qt-budget-amount{padding-right:calc(var(--tpl-badge-inset) + var(--tpl-badge-size) + 6px);}
/* The config toggle row carries no divider: .tpl-end-toggle's border-top separates a
   card's LAST row from the list above it, and this row is one control inside a type's
   panel, not the end of a card. The gap above it is the config container's one structural
   rule, like every other part. */
.tpl-start .qt-config-toggle{border-top:0;margin-top:0;padding-top:0;}
/* Kept from the deleted ✓ block: the sliding-scale label box is locked to 34px so it
   matches every other single-line field. Nothing to do with the completion mark. */
.tpl-start .qt-labelled-box > input.qcfg-text{height:34px;}
/* Boxes are taller than lines — a touch more row breathing room. */
.tpl-start .tpl-item-row{margin-bottom:var(--gap-row);}
/* (a) SIZE is owned by the single --tpl-input-size token above — every field
   below shares it (Bebas card names keep their own size via higher specificity).

   CASE: THIS GROUP IS TIER (c), NOT (b). The line is what the facilitator is
   writing, not which box it sits in: (b) is a short LABEL the facilitator applies
   to something; (c) is CONTENT the facilitator authors for a participant to read.
   Items, questions, options and prompts are content — they are the words a
   respondent sees — so they render as typed, capitals intact.

   [HARD] --tpl-prose-case IS `none`, NOT `lowercase`. text-transform:lowercase is
   the original defect this whole exercise removed: it rendered a facilitator's
   typed "Y Combinator" as "y combinator" on screen. If any rule in this family
   ever reads `lowercase` again that is a bug, not a preference.

   BOTH STATES MOVE TOGETHER, and they do so for free: text-transform is inherited
   and ::placeholder inherits from its originating element, so this one declaration
   governs the empty state and the typed state. That is what keeps
   placeholder-vs-value parity at zero — a placeholder left uppercase over a
   sentence-case value would be case-change-on-fill, the exact thing parity
   measures.

   THE :not() CHAIN IS THE (b) LIST, INLINE. The field families that share these two
   selectors and stay tier (b) are excluded here and given --tpl-body-case in the rule
   directly below, rather than fighting this one on specificity:
     #tpl-location-place      the slim poll's "Place"
     #tpl-vl-label            the viewer-link label
   (.tpl-instructions-title LEFT this list 2026-08-24 — see the rule below.)
   (.qcfg-text is excluded from BOTH arms: it carries .tpl-section-prompt-input as
   well as sitting in an inline-edit wrapper.) Bebas card names and value-ladder
   labels stay excluded as before — they are tier (a) and read --tpl-cardname-case. */
.tpl-start .tpl-inline-edit > input:not(.tpl-card-name-input):not(.tpl-vl-row-label-input):not(#tpl-vl-label),
.tpl-start .tpl-section-prompt-input{text-transform:var(--tpl-prose-case);}
/* The (b) half of the same two selectors: short labels the facilitator applies.
   No specificity contest — the rule above excludes exactly these. */
/* (.qcfg-text — the rating scale's Low / High labels — LEFT THIS LIST 2026-08-20 and
   joined tier (c) above. It was called "a short label the facilitator applies", but the
   thing it labels is a PARTICIPANT'S SLIDER, and what the facilitator types goes on that
   participant's screen — which makes it content, the same as an item, an option or a
   question. The tell was in its own placeholder: the lang string is "e.g. Strongly
   disagree", sentence case, and tier (b) shouted it back as E.G. STRONGLY DISAGREE. The
   two remaining entries really are labels of the facilitator's own chrome. */
/* [HARD] .tpl-instructions-title LEFT THIS LIST 2026-08-24 AND JOINED TIER (c) ABOVE,
   FOR THE REASON .qcfg-text LEFT IT ON 2026-08-20 — the note for that move is directly
   above and reads as though it were written for this one. It was called "a short label the
   facilitator applies", but these two fields are the Introduction Page's and the Completion
   Message's HEADINGS, and what the facilitator types goes on a PARTICIPANT'S screen — the
   welcome screen's heading and the completion message's heading. That makes them content,
   like the bodies beneath them, which tokens.css already lists under tier (c) by name
   ("welcome and completion bodies"). The heading was the odd half of its own pair.
   The tell was the same tell: the placeholders are `e.g. Welcome` and `e.g. Thank you`,
   sentence case in the lang file, and tier (b) shouted them back as E.G. WELCOME and
   E.G. THANK YOU. tokens.css's own words for tier (c) settle it — "it renders as typed,
   capitals intact, because the editor should look like what gets sent".
   BOTH STATES MOVE TOGETHER: ::placeholder inherits text-transform from its originating
   element, so the typed value stops shouting in the same declaration and
   placeholder-vs-value parity stays at zero. Storage was never affected either way. */
/* DELETED: `uppercase` — do not re-add; the reason is T31 in the decision record. */
.tpl-start #tpl-vl-label{text-transform:var(--tpl-body-case);}
/* Facilitator body textareas (Welcome/Introduction, Criteria/Section Description,
   Completion Message, Display Text body — the shared .tpl-instructions-textarea)
   render IDENTICALLY to their card HEADING (.tpl-inline-edit > input) at EVERY
   width: DM Mono, --tpl-input-size, typed lowercase + UPPERCASE placeholder.
   Promoted here out of the ≤640 block (was S173, mobile-only, so desktop fell to
   .tpl-abel Abel 18px — the reported bug). --tpl-input-size is itself responsive
   (14px desktop / 12px mobile), so this ONE base rule covers both widths — no
   per-width size fork. (0,2,0) clears .tpl-abel (0,1,0). Casing is DISPLAY-ONLY —
   the stored body keeps its case (S155/S156) — and comes from --tpl-body-case, the
   same token the heading input reads, so the two cannot drift. Its ::placeholder
   arm is deleted with the input one above: the pseudo inherits text-transform. */
/* DELETED: `.tpl-start .tpl-instructions-textarea` — do not re-add; the reason is T32 in the decision record. */
/* (The id-scoped Welcome/Completion prose rule that sat here is FOLDED INTO the
   base rule above, not dropped: .tpl-instructions-textarea now reads
   --tpl-prose-case for all THREE of its consumers — the Welcome body, the
   Completion body and the Display Text question's body (question-types.js,
   JS-built, no id). The id rule existed only to move two of the three without
   moving the third; now that the third is tier (c) as well, keeping it would be
   a second source for one value. The [HARD] note it carried still applies and is
   worth restating: .tpl-instructions-textarea has three consumers, one of them
   built in JavaScript with no id, so anything that should NOT move must be
   excluded here by class — never by scoping the rule to the two ids you can
   see in the Blade. */
/* (Session 177) HEADING + BOX restructure (DM criteria + MS sections): a Bebas heading
   sits ABOVE each name/question box — mirrors the typed name (names) or is static
   "CRITERIA/SECTION QUESTION" (questions). (Non-workshop only; workshop name keeps
   .tpl-card-name-input Bebas.)
   It used to say "reusing the .tpl-title-caption tokens" and then hand-copy the five
   values, which is how that pair drifted; .tpl-title-caption is gone (Session 176) and
   this now reads the --tpl-cardname-* set directly. It keeps its own line-height and
   colour ON PURPOSE: it is a heading printed above a box, not the empty state of one,
   so the tier's placeholder colour and wrapped-text leading do not apply. */
.tpl-start .tpl-card-heading{
    font-family:var(--tpl-cardname-font);
    font-size:var(--tpl-cardname-size);
    letter-spacing:var(--tpl-cardname-tracking);
    text-transform:var(--tpl-cardname-case);
    color:var(--color-text-primary);
    line-height:var(--type-card-name-line);
    margin-bottom:var(--gap-tight);
}
/* Mobile (≤640) field typography. This block no longer shrinks anything: the ≤640
   arm that dropped every facilitator TEXT input to the DM Mono label size
   (--tpl-field-label, 12px, via --tpl-input-size) is deleted, and the block below
   records why and what replaced it.

   [HARD] KEPT BECAUSE IT IS WHAT MAKES THE DELETION WORK, AND WHAT WOULD MAKE ANY
   RE-SHRINKING FAIL SILENTLY. The iOS focus-zoom floor is the ≤640 arm at the end of
   tokens.css
       input:not([type=checkbox]):not([type=radio]):not([type=range]),
       select, textarea { font-size:16px }
   and the input arm's REAL specificity is (0,3,1) — each :not([attr]) adds a
   class-level bump — NOT the (0,0,1) a "bare element" reading suggests. That error once
   made every "shrink on mobile" input rule too weak: the single-source selectors
   (`.tpl-start input.tpl-fac-input` / `.tpl-inline-edit > input` /
   `.tpl-section-prompt-input`, all ≤ (0,2,1)) AND the old `.tpl-abel`/`.tpl-issue`
   overrides here all LOSE to the floor, so those inputs silently rendered at 16px, not
   12px (only the placeholders, on their own ::placeholder rules, actually shrank — so a
   typed value read LARGER than its placeholder). ANY future mobile font-size override
   on an <input> MUST exceed (0,3,1) to take effect — and, now, must also answer the
   decision below before it is written at all. The bare `select, textarea` arm is
   (0,0,1) and loses to almost anything, which is why a textarea can still be shrunk
   here by accident where an input cannot. */
@media(max-width:640px){
  /* ── THE PHONE'S FIELDS SIT ON THE FLOOR, NOT UNDER IT (2026-08-31) ──────────────
     THREE DECLARATIONS ARE DELETED HERE, and what replaces them is nothing: the fields
     fall back to tokens.css's own ≤640 arm,
         input:not([type=checkbox]):not([type=radio]):not([type=range]), select,
         textarea { font-size:16px }
     which exists for exactly one purpose and says so — "iOS focus-zoom floor: raise
     every input that would otherwise inherit < 16px so focusing it doesn't zoom the
     page." The deleted rules were the only things on this surface reaching under it:

       .tpl-start{--tpl-input-size:var(--tpl-field-label)}                 (12px)
       .tpl-start .tpl-inline-edit > input:not(…):not(…){font-size:…}      (0,4,1)
       .tpl-start #tpl-session-setup-card input.tpl-fac-input:not(…){…}    (1,2,1)

     The last two existed ONLY to out-specify that floor — their own note above says so
     — so with the token back at 16 they would restate it, and a rule that restates a
     floor is not an override. All three go together or none of them do.

     WHAT THIS COSTS, STATED PLAINLY. The [HARD] note that stood here recorded the
     opposite decision: the mobile field size was TIED to the label tier so "a field and
     its label read at one size on a phone", with the focus-zoom named and accepted as
     its price. The operator's rule for a focused field on a phone is now that the ONLY
     thing that changes is its background going white — nothing zooms, resizes or
     shifts — and no CSS can hold both. Measured before this: every setup field at 390
     computed 12px except the 20px heading inputs, i.e. every one of them zoomed the
     viewport on focus. Field and label now read 16 against 12; that is the price of
     the other side of the same trade, and it is the side that was chosen.

     Nothing is added. The floor is a mechanism this codebase already had. */
  /* DELETED: The narrow override that halved this to 14px — do not re-add; the reason is T33 in the decision record. */
  /* DELETED: `.tpl-start .qt-guidance-input{text-transform:lowercase}` — do not re-add; the reason is T34 in the decision record. */
}
/* Flat / blank ranking — THE QUESTION line, the item rows and the "+ Add Items" button
   render IDENTICALLY in Individual and Group mode. Both modes fall through to the shared
   flat base rules (#tpl-items-list, .tpl-edit-row and #tpl-add-item, all anchored on
   --tpl-crit-indent, which is 0 for flat blank), so the input lines take the full card
   width (the longer, Group-mode length) and the Add button sits flush at the content-left.
   The old Individual-only band (a 70%-centred column holding a 700px/85% inner line, to
   echo the centred Session Title) was removed so there is ONE flat card-stack layout. */
/* Facilitator block inside the card header row — 3-column grid: empty
   spacer (col 1) | facilitator centred (col 2) | empty (col 3). The reserved
   left/right 1fr columns keep the facilitator centred in col 2 in every mode.
   (Save To Project used to sit in col 3 here; it is now a card-level absolute
   block anchored to #tpl-session-setup-card's top-right, outside this grid.)

   [HARD] THE 18px MOVED OUT OF THIS RULE, and the move is what makes the class
   reusable. `margin-bottom:18px` lived here and served exactly ONE element: its
   two consumers were #tpl-session-setup-header, which overrides it to 0 a few
   rules below, and #mgmt-respond-header, which wants it. So it was never the
   contract — it was one card's spacing riding on the contract's back, and any
   third row that adopted the grid inherited a gap belonging to a different card.
   The OVERVIEW header row is now that third row. The 18px sits on
   #mgmt-respond-header instead (below), .tpl-ws-card-top inherits
   .tpl-block-header-row's standard 10px, and every adopter keeps the margin it
   already had. What is left here is alignment and nothing else. */
.tpl-start .tpl-ws-card-top{display:grid;grid-template-columns:1fr auto 1fr;align-items:start;gap:var(--inset-panel);}
/* The 18px's real owner. RESPONSE MANAGEMENT's heading→buttons gap; the same
   value _manage-chrome sets on the plain manage card headings
   (.tpl-manage > .tpl-form-card > .tpl-sublabel), which is what "shared standard"
   meant — the VALUE is shared, the declaration was only ever for this row. */
.tpl-start #mgmt-respond-header{margin-bottom:var(--inset-panel);}
/* ── V3: AND IT IS A FLEX HEADER ROW LIKE EVERY OTHER ONE (2026-08-24) ─────────────
   This row carries .tpl-ws-card-top, whose `display:grid; 1fr auto 1fr; gap:16px` exists to
   centre the OVERVIEW heading on the create page. Response Management is not that card — it
   is an ordinary card with a heading (numbered until 2026-08-29, now one of the two manage
   cards that take no number — see [data-card-badge-host] below) — and the grid put its
   heading at 398 while every other card heading sat at 388, an outlier that predates this
   commit and that the lead would have carried to 410. Stating it as flex with the page's own
   --col-gap makes it the same row as the others, so the lead lands it on V3 by the same
   arithmetic instead of by a correction sized to this one card. Scoped to the id: the create
   page's Overview keeps the grid it needs. */
.tpl-start #mgmt-respond-header{display:flex;align-items:baseline;gap:var(--col-gap);}
/* AND ITS SPACER GOES WITH THE GRID. .tpl-ws-card-spacer is a ZERO-WIDTH element whose only
   job is to be Overview's first 1fr grid column. In a flex row it still costs a --col-gap,
   which is why this heading measured 398 against every other card heading's 388 — one extra
   gap, from an element that paints nothing and is 0 wide. Removing it from the flow here is
   what makes the lead land on V3 by the shared arithmetic; Overview's copy is untouched. */
.tpl-start #mgmt-respond-header > .tpl-ws-card-spacer{display:none;}
/* ── THE SPACING BELONGS TO THE BLOCK THAT OCCUPIES SPACE ──────────────────────
   The facilitator name/email row sits BELOW Group / Team Name and just ABOVE the
   Individual / Group toggle. Its gaps above and below both consume the SAME
   --space-sm rhythm token so the field cluster reads evenly. That has not
   changed. What changed is WHICH ELEMENT CARRIES IT.

   [HARD] IT USED TO BE ON THE HEADER GRID, GUARDED BY :has(.tpl-facilitator-cols),
   AND THAT GUARD TESTED THE WRONG THING. (That class no longer exists — the organiser
   pair was deleted — so do not go looking for it. The lesson is about :has(), not about
   this class, and it still applies to every display:none subtree.) In Individual mode the whole
   .tpl-ws-facilitator block is display:none — but .tpl-facilitator-cols is still
   IN THE DOM inside it, so :has() matched, the 8px/8px stayed, and a grid with
   height 0 reserved 16px of empty space at the bottom of the fields well. Measured
   at both widths: 13px above the Session Title box against 37px below it, of which
   16px was this. :has() asks "is it present", and the question here is "does it
   occupy space" — those differ for every display:none subtree, which is why no
   grep for visibility:hidden would ever have found it.

   Putting the margins on .tpl-ws-facilitator itself makes the two questions the
   same one: the element that has the margins is the element that has the height,
   so when it goes, they go with it. No predicate to get wrong.

   Group mode is unchanged, and not by luck: a grid item's margins do not collapse
   through its container, so the 16px that used to sit outside the grid now sits
   inside it and the grid grows by exactly that much. Verified by measurement at
   1280 and 390 — all four Group gaps identical to the pixel.

   The header's own margins are zero unconditionally in create mode, which is what
   the :not(:has(...)) arm was already doing for signed-in hosts; the two conditional
   rules collapse into one unconditional one and the predicate that caused the bug is
   deleted rather than corrected.

   …AND THE `:not(.manage-mode)` IS NOW GONE TOO, for the same class of reason. It
   said "manage keeps its own header rule below", and that rule was
   `margin-bottom:6px` — which was not a manage rhythm, it was a partial override of
   .tpl-ws-card-top's base 18px, dating from when this header rendered ABOVE the
   title. Deleting the 6px on its own therefore made things WORSE, not neutral: the
   base 18px surfaced and the manage well went 13px top against 31px bottom (measured
   at 1280 and 390, flat-group manage). The header is the WELL's last child in both
   modes now, and the well's gap + padding own every edge inside it, so the mode
   predicate was the stale part — not the value. One unconditional rule; manage
   measures 13/13 like create.

   [HARD] THE BASE 18px IS NOT DELETED, and must not be: .tpl-ws-card-top's other
   consumer is #mgmt-respond-header on the Response Management card, where the header
   IS a card header with body below it and 18px is its real spacing. This rule narrows
   to the one id that is a well child; that card is untouched. */
.tpl-start #tpl-session-setup-header{margin-top:0;margin-bottom:0;}
/* [HARD] THE GRID DOES NOT RENDER AT ALL, IN ANY STATE. Enumerated: it has exactly two
   children, .tpl-ws-card-spacer (a 1fr grid column, height 0) and .tpl-ws-facilitator,
   which is `.tpl-group-only` and — since the signed-out branch was deleted — holds nothing
   but the pair of hidden inputs carrying the owner's name/email into the submit. Neither
   paints, in either mode, on either page. A grid that renders nothing should not be in the
   flow, and once it is out the well's gap applies only between the items that ARE there.

   [HARD] THE SCOPE WAS WRONG AND THE CLAIM ABOVE IT WAS TOO (corrected 2026-08-27). This
   read `:not(.manage-mode) #tpl-start-form:not([data-mode="group"])`, which fires in ONE of
   the four states the sentence describes: create + Individual. It never fired on manage in
   either mode, nor on create in Group — and the [HARD] line then claimed "both modes come
   out symmetric from one mechanism", which was true of the one state it reached and false
   of the other three. The element renders for a signed-in visitor only, so signed OUT there
   is nothing to hide and the mistake was invisible: every browser probe on this page drives
   an unauthenticated GET.

   WHAT IT COST, measured signed in and in Group at 1280: the header stayed in the flow as
   the well's last child, the well paid it a full --stack-gap, and Overview measured 25.2 top
   against 49.8 bottom — a 24.6px strip below the GROUP / TEAM underline with nothing in it.

   IT IS THE HEADER THAT IS GATED, NOT THE SPACER. .tpl-ws-card-spacer keeps its job — it is
   this grid's first 1fr column, and #mgmt-respond-header already has its own rule dropping
   it from a flex row — so it is neither deleted nor given a third override. Hiding the
   header does not affect the submit: display:none does not stop a hidden input posting. */
.tpl-start #tpl-session-setup-header{display:none;}
.tpl-start .tpl-ws-card-top > .tpl-ws-card-spacer{grid-column:1;}
/* Col-2 centred content — the facilitator block on Session Overview, the card
   heading (.tpl-sublabel) on the Response Management card, and now the OVERVIEW
   heading on the Session Overview card itself, all of which share this 3-col
   header so the heading stays centred while a control sits right (col-3). */
.tpl-start .tpl-ws-card-top > .tpl-ws-facilitator,
.tpl-start .tpl-ws-card-top > .tpl-sublabel{grid-column:2;justify-self:center;}
/* Col-3 right. TWO shapes of right-hand control, because the two cards wrap it
   differently and neither wrapper is worth rewriting: Response Management puts a
   bare .tpl-ws-card-toggle in the row, OVERVIEW puts Save To Project inside the
   shared .tpl-block-header-toggles. In flex that wrapper right-aligned itself with
   margin-left:auto; under grid the auto margin is neutralised by the rule below,
   so it needs the explicit column — without it the wrapper auto-places into col 1
   and Save To Project jumps to the LEFT of the heading. */
.tpl-start .tpl-ws-card-top > .tpl-ws-card-toggle,
.tpl-start .tpl-ws-card-top > .tpl-block-header-toggles{grid-column:3;justify-self:end;}
.tpl-start .tpl-ws-card-top > .tpl-ws-card-toggle{display:flex;flex-direction:column;align-items:flex-end;}
.tpl-start .tpl-ws-card-top .tpl-block-header-toggles{margin-left:0;}
/* Signed-in owner's email shown in the top nav (2026-07-01, moved out of the
   session-setup card) — Abel value, no mono/uppercase, sitting among the menu links
   inside the right-aligned .hv2-nav-items cluster. The Home / Sessions / Account text
   links use the standard .hv2-nav-items a chrome. */
/* (.hv2-nav-fac-value moved to home-v2.css 2026-09-21 — the element is in TWO navs
   now, this one and the marketing homepage's, and home-v2.css is the sheet both of
   them load. A rule for a shared element in the setup-only sheet is a rule the other
   page does not get.) */
/* DELETED: `#tpl-session-setup-header{margin-bottom:6px}` — do not re-add; the reason is T35 in the decision record. */
/* DELETED: `.tpl-start label[for="tpl-session-title"]{text-align:center}` — do not re-add; the reason is T36 in the decision record. */

/* DELETED: `.tpl-items-list{margin-bottom:14px}` — do not re-add; the reason is T37 in the decision record. */
/* Sibling-combinator: gap between the + Images toggle row and the items
   list that immediately follows. Fires on the flat OPTIONS TO RANK
   card (no inline margin-top set there) and is harmlessly redundant
   with the inline style="margin-top:14px" on the seeded + JS-built
   MS cards. */
.tpl-inline-toggles + .tpl-items-list{margin-top:14px;}
.tpl-item-row{display:flex;align-items:center;gap:var(--col-gap);margin-bottom:var(--inset-control);}
/* Item row typography on the start screen — scope-overrides the
   global .tpl-item-num (Bebas 24px) and .tpl-issue (Abel 18px) so each
   item input + its leading number visually match the Comparison
   Question input below them (Abel 14px, muted grey). The participant /
   confirm views keep the bigger global treatment.
   - Empty rows: number reads in var(--grey); the input placeholder uses the
     canonical ink from the global ::placeholder rule in tokens.css.
   - Active rows: number flips to var(--grey) via the existing
     .tpl-item-num--active class wired in the JS bind path.
   Typed text is black (var(--ink)); seeded default values carry grey via
   .is-default-value (tokens.css). Placeholder colour is not set here — it
   inherits the single global ::placeholder rule. */
.tpl-start .tpl-item-num{letter-spacing:0;line-height:1.4;}
.tpl-start .tpl-item-num--active{color:var(--grey);}
/* THE ROW × — ONE DECLARATION FOR THE WHOLE SETUP SURFACE. .tpl-card-remove used to
   carry a hand-copy of this as an inline style attribute, emitted three times (the
   _card-row-controls partial and both JS card builders below) — same values, minus the
   hover, and unreachable by any rule because an attribute beats every selector. It is a
   seat in this rule now and the three copies are deleted. The padding is for the
   NON-cluster use (question-editor option rows); inside .tpl-row-controls the cluster's
   own rule zeroes it, which is why joining is inert. */
.tpl-item-remove,
.tpl-card-remove{background:none;border:none;color:var(--color-text-primary);cursor:pointer;font-size:var(--type-prose);padding:0 var(--gap-tight);line-height:1;}
.tpl-item-remove:hover,
.tpl-card-remove:hover{color:var(--red);}
/* ── Item-list rows + add buttons redesign. Scoped to item lists only
   via the established :not(.tpl-questions-list) convention so the
   question editor's option/question rows are untouched. Ghost number
   Bebas ~22px muted grey; standalone bordered input (no container);
   6px column gap; the plain muted × (.tpl-item-remove above) already
   matches. ── */
.tpl-start .tpl-items-list:not(.tpl-questions-list){display:flex;flex-direction:column;row-gap:var(--step-row);}
.tpl-start .tpl-items-list:not(.tpl-questions-list) .tpl-item-row{margin-bottom:0;}
/* Canonical sequential-number numeral: the criteria/section card-header "01"
   and the compare item-row "01/02/03" render from ONE rule so size, font,
   colour and spacing stay identical everywhere. Question-row numbers are
   deliberately excluded — they stay muted grey-ghost (set in
   question-types.js). Card-header spans now carry only data-card-num (their
   inline styles were removed); item rows keep .tpl-item-num for their
   layout/active-toggle machinery. */
/* ── TWO BADGES, ONE SIZE, ONE TYPE ──────────────────────────────────────────────
   A NUMERAL IN AN INK SQUARE names a card; A LETTER IN A RED CIRCLE names a member of
   a list. Both are --col-num-left across, which is the ordinal COLUMN's own width
   (26px, from --tpl-card-num-width) — so the badge fills the column it already
   occupied and nothing after it moves. That is why there is no new size token here:
   the size was already declared, as a column.

   [HARD] --col-num-left, NOT a 24/26px literal. --col-line-x is
   `--col-drag + --col-gap + --col-num-left + --col-gap`, so a badge wider or narrower
   than the column would either overflow into the field's lane or leave a gap the four-
   column contract does not know about. One token decides both.

   THE LETTER BADGE REACHES EXACTLY THE TWO CONSUMERS THIS DECLARATION ALREADY HAD —
   the card-header ordinal ([data-card-num]: DM criteria, MS sections, workshop slides)
   and the item row's ordinal. Question rows and option rows are excluded by
   `:not(.tpl-questions-list)` and by the `> ` combinator, as they were before: their
   markers are 01/02 and roman sub-lists from question-types.js, a different sequence
   with its own meaning.

   --active KEEPS ITS SEAT IN THE SELECTOR AND LOSES ITS JOB. It used to swap the
   numeral between muted and ink to say "this row has text". A filled badge cannot say
   that with colour — it is filled either way — so the row's own field says it instead.
   The seat stays so `.tpl-start .tpl-item-num--active` (0,2,0) cannot win back the
   colour at (0,4,0).

   BADGES CENTRE ON THE FIELD'S TEXT, NOT ITS BOX. Every field beside a badge carries
   its underline as a border-bottom, so its border box is --tpl-rule-weight taller than
   its text line and flex centring lands the badge half a rule low. margin-bottom of
   exactly that token lifts it back — one declaration reading the same value the rule
   itself is drawn at, so it holds at both badge sizes and at whatever weight the rule
   becomes. Not a per-case nudge: there is no number here. */
.tpl-start{--tpl-badge-size:var(--col-num-left);}
/* [data-card-badge-host] > [data-card-num] JOINS BOTH LISTS, AND THE :not() BELOW IS WHY
   IT HAS TO. The MS section band is a .tpl-edit-row--header AND the section card's badge
   host, so without the exclusion it would match the circle arm and the square arm at
   once and the winner would be whichever rule happened to sit later. The predicate is the
   same one _numberCards() uses to decide what to write: an ordinal inside a card's
   heading row is that card's NUMERAL; anywhere else it is a member's LETTER. One
   discriminator, read by the CSS and the JS from the same attribute. */
/* ── [HARD] A BADGE ALIGNS TO THE TEXT IT LABELS, NOT TO THE CONTAINER THAT HOLDS IT ──
   One sentence, and it explains every badge defect this surface has had.

   A badge is a marker FOR something — the row it numbers, the card it names. What it must
   line up with is that thing's TEXT. The mistake is always the same and always looks
   reasonable while you are making it: you align the badge to the box it happens to sit
   beside, because in a flex row that is what `align-items` offers you. Where the box and
   its text are the same height nothing goes wrong, and the habit survives. Where they
   differ, the badge walks off.

   THREE FAMILIES WERE OUT AT ONCE (measured, 2026-08-20):
     −16.00px  the question ordinal. `align-self:flex-start` pinned it to the top of a
               field COLUMN that is a name, an instruction and a type's own parts, while
               the name it numbers sits at the bottom of that column's first row.
     −6.00px   the MS section badge, centred on a BAND whose tallest child is a part with
               padding above the name and a rule below it.
     −1.50px   option rows, centred on a 34px field box.
   The reference is .tpl-item-num on an item row at +0.00 — the one case where the badge
   and the field are the same height, so aligning to the box happened to be right.

   THE SHAPE OF THE FIX, every time: put the badge at the START of the line its text is on
   (`align-self:flex-start` plus the containing part's own top padding), and make that line
   --tpl-badge-size tall so the two share a centre by arithmetic. Never nudge the text, and
   never tune a margin against a height the CSS cannot name — if the row's height comes
   from something else (a chip, a control), pin THAT to the badge's token first.

   ASSERTED by `php artisan setup:badge-probe`, which measures badge centre minus the
   centre of the text beside it on every badge on four pages, and separately requires a
   badged FIELD to be at least --tpl-badge-size tall (below that the badge is clipped —
   five question types shipped that way). Both falsified before being trusted. The
   tolerance is 2.0px, not 0, and the constant says exactly what stops it being 0.

── WHAT THE BADGE AUDIT ACTUALLY DROVE (2026-08-20) ──────────────────────────────
   The two declarations below are the only place a numeral or letter is painted on a
   filled square or circle on the setup surface, and a platform-wide sweep was run to
   check that nothing else reimplements them. It reported ZERO non-canonical badges —
   but that claim is SCOPED TO WHAT WAS DRIVEN, and the scope is not everything:

     MEASURED, in a real browser, computed styles read off the rendered element:
       - the four create pages (flat, DM, MS in both section modes, survey, quiz),
         including a survey/quiz question with its option rows expanded
       - the DM manage page (/f/WPROBE01/session)
       - the results scorecard, reached unauthenticated through an existing viewer link
         (51 resting + 14 active .q-scale-circle; results design system, out of scope)

     NOT MEASURED, and therefore NOT covered by "zero":
       - the PARTICIPANT question screen (.q-scale-pt, .q-opt-dot)
       - the WORKSHOP STAGE
     Both redirect to sign-in, and the only unauthenticated route to them writes a
     response to the production database. They are read-from-source only: both look like
     participant-system controls rather than row markers, which is consistent with what
     the results sweep measured, but consistent-with is not the same as measured. If a
     badge copy exists anywhere on this platform, those two screens are where it is.
     Re-run the sweep against them with a test login before treating "zero" as total. */
/* THE QUESTION ORDINAL JOINS BOTH LISTS (2026-08-20), and it is written as
   `.tpl-questions-list > [data-question-wrap] > .tpl-item-num` — a CHILD chain, never the
   `:not(.tpl-questions-list)` descendant form beside it. That is not style: .tpl-item-num
   also names the numerals inside a type's OPTION rows, which are descendants of a question
   wrap, so a descendant selector would turn every option number into a rust disc too.
   Two combinators are what keeps the badge on the row's own marker. */
.tpl-start .tpl-edit-row--header > [data-card-num],
.tpl-start .tpl-items-list:not(.tpl-questions-list) .tpl-item-num,
.tpl-start .tpl-items-list:not(.tpl-questions-list) .tpl-item-num--active,
.tpl-start .tpl-questions-list > [data-question-wrap] > .tpl-item-num,
.tpl-start .qt-opt-row > .tpl-item-num,
.tpl-start [data-card-badge-host] > [data-card-num],
.tpl-start .tpl-card-badge{
    font-family:var(--font-heading);
    font-size:var(--tpl-heading);
    /* [HARD] THIS 2px STAYS, AND IT WAS TRIED THE OTHER WAY. It is this surface's hand
       compensation for Bebas sitting high in its box, and the shared mechanism beside
       .tpl-field-text in templates.css is meant to replace exactly this kind of nudge.
       Measured 2026-09-17: swapping it for `text-box: trim-both cap alphabetic` moved
       both badges from 0.00 to -1.00 at 1440 AND 375 — worse than the nudge, not better.
       WHY IT CANNOT JOIN: text-box trims an element's own line box, and these badges are
       `inline-flex` holding their OWN text, so the text lives in an ANONYMOUS FLEX ITEM
       the declaration does not reach. .qt-tag-label takes the mechanism because it is a
       span INSIDE a flex parent, which is the shape that works. Giving these a text-holding
       child would let them join; that is a markup change across two JS builders and a
       Blade partial, and it is not worth 1px. */
    padding-top:var(--nudge);
    letter-spacing:var(--tpl-cardname-tracking);
    line-height:var(--type-card-name-line);
    box-sizing:border-box;
    display:inline-flex;
    align-items:center;
    justify-content:center;
    flex:0 0 var(--tpl-badge-size);
    width:var(--tpl-badge-size);
    height:var(--tpl-badge-size);
    /* NO align-self. Each row already declares how it aligns its children and both
       answers are right: the card header row is `align-items:baseline`, which puts the
       badge's letter on the same line as the name it labels; an item row is
       `align-items:center`, which centres the badge on the field's BORDER box. Only the
       second needs correcting, and margin-bottom is the correction — on a centre-aligned
       flex item a bottom margin lifts it by HALF, which is exactly the half-rule the
       underline adds below the text. Inert under baseline alignment.

       [CORRECTED 2026-09-08] THERE IS A THIRD ROW SHAPE, AND THIS DECLARATION IS WRONG ON
       IT. The sentence that stood here — "one declaration serves both rows" — enumerated
       the two rows that existed when it was written. Row 1 of the question card is a
       third: centre-aligned like an item row, and NOTHING on it draws a rule (its members
       are the ordinal, the type tag and the ×/⧉/▸ cluster; the underlined prompt is a line
       below). So the lift had nothing to compensate and sat the ordinal exactly half a
       rule above the centre of the tag beside it — measured at +0.50px, taken to 0.000 by
       cancelling it. Cancelled AT THE BADGE, for that row only, beside the margin-top
       canceller already there: `.tpl-start:not(.slim-mode) [data-question-wrap] >
       .tpl-item-num` in question-types.js. This declaration is unchanged and still right
       for the two rows it was written for. If a fourth centre-aligned row appears with no
       rule on it, cancel it there too rather than making this conditional. */
    margin-bottom:var(--tpl-rule-weight);
    color:var(--color-white);
}
/* A member of a list: red, round. */
.tpl-start .tpl-edit-row--header:not([data-card-badge-host]) > [data-card-num],
.tpl-start .tpl-items-list:not(.tpl-questions-list) .tpl-item-num,
.tpl-start .tpl-items-list:not(.tpl-questions-list) .tpl-item-num--active,
.tpl-start .tpl-questions-list > [data-question-wrap] > .tpl-item-num,
.tpl-start .qt-opt-row > .tpl-item-num{
    background-color:var(--red);
    border-radius:var(--radius-disc);
}
/* ── THE QUIZ ANSWER BADGE — THE BADGE IS THE ANSWER ──────────────────────────────
   On a quiz the option's letter badge is the CONTROL that marks the correct answer, and
   the marked state is the COMPLETION BADGE this surface already paints on a finished
   field: the same --quiz-correct disc and the same --quiz-tick-svg white check, from the
   same two tokens. Nothing green is invented here, and the standalone radio row it
   replaces is deleted rather than hidden.

   THE BADGE IS INTERACTIVE HERE AND DECORATIVE EVERYWHERE ELSE, which is a real
   difference and gets a real cursor. The hint under the list says so in words; this says
   it to the hand. Scoped to .qt-answer-badge, which only a quiz option emits, so no other
   badge on the platform gains a pointer.

   THE LETTER GOES WHEN THE TICK ARRIVES: `color:transparent`, not display:none on a
   child — the badge has no child, its letter IS its text, and the element must keep its
   size and its accessible name. The tick is a background layer over the disc, exactly as
   the completion badge composes it on a field. */
.tpl-start .qt-answer-badge{cursor:pointer;}
/* [HARD] (0,4,0), and it has to be. The badge's rust disc and white letter come from
   `.tpl-start .qt-opt-row > .tpl-item-num` at (0,3,0), so a (0,2,0) `.qt-answer-badge--on`
   LOSES to them however late it sits in the file — measured: the marked badge rendered a
   white tick over a rust disc with the letter still showing through, three marks in one
   26px circle. The extra class in the chain is what makes this the same element's later
   state rather than a competing rule. */
.tpl-start .qt-opt-row > .tpl-item-num.qt-answer-badge--on{
    background-color:var(--quiz-correct);
    color:transparent;
    background-image:var(--quiz-tick-svg);
    background-repeat:no-repeat;
    /* 2/3 of the disc, centred — the completion badge's own proportion, so the two marks
       are the same object at the same scale rather than two greens that nearly match. */
    background-size:calc(var(--tpl-badge-size) * 2 / 3) calc(var(--tpl-badge-size) * 2 / 3);
    background-position:center;
}
/* The word beside the marked option. It is a LABEL for a configuration state, so it takes
   the quiet tier like every other configuration label — see THE TWO LABEL TIERS. */
.tpl-start .qt-answer-word{flex:0 0 auto;margin-bottom:0;}
/* The hint under the option list. Same tier, and it is the list's own trailing line —
   the gap above it is the config container's one structural rule, not a margin here. */
/* [HARD] `margin:0` BECOMES `margin:0 0 0 var(--col-nest-x)` (2026-08-24). This caption
   names the option LIST, so it belongs on V5 with the option text it explains — and
   question-types.js says so, in the one place --col-nest-x is read. But `.tpl-start
   .qt-answer-hint` is (0,2,0) against the emitter's (0,1,0), so the shorthand here won and
   the caption stayed at the subcard's edge, 36px left of every option. A shorthand that
   silently outranks the component's own rule is the trap; the token is read here too rather
   than the rule being weakened. */
.tpl-start .qt-answer-hint{margin:0 0 0 var(--col-nest-x);}
/* A card: ink, square — the same white-on-ink rectangle the ON/OFF knob and the logo
   mark are. border-radius:0 is stated rather than inherited, exactly as the knob
   states it, because square corners are the platform convention and not a default. */
.tpl-start [data-card-badge-host] > [data-card-num],
.tpl-start .tpl-card-badge{
    background-color:var(--ink);
    border-radius:var(--radius-square);
}
/* ── THE CARD-BADGE COLUMN, AND THE GRIP'S RESERVED GUTTER ────────────────────────
   Every card badge starts at the same x, whether or not its card has a drag grip in
   front of it. The column is --col-num-x — "every numeral/letter LEFT edge (skips the
   reserved drag gutter)", the D-COLUMNS token every item letter and criterion letter
   already sits on — so a card's numeral and its rows' letters share one left edge and
   there is no second number to keep in step.

   THE GRIP IS LAID OUT IN THE GUTTER RATHER THAN IN FRONT OF IT. It keeps its place in
   normal flow (it is the SortableJS handle and must stay hit-testable and focusable in
   source order) and gives back exactly the horizontal advance it took: its own
   --col-drag plus the row's --col-gap, which is --col-num-x. The net advance is zero, so
   the badge that follows lands on the column whether the grip is there or not, and a
   card without one simply leaves the gutter empty. That is why the Overview heading gets
   NO margin of its own — the offset is the column, declared once for every card badge.

   Bare-minus on a token, not a literal: change --tpl-drag-width or --col-gap and the
   gutter and the column move together by construction.

   ── EVERY HEADER ROW JOINS, NOT ONLY THE BADGE HOSTS (2026-08-24) ─────────────────
   [HARD] THIS IS THE WHOLE OF THE RESERVE, AND IT IS UNCONDITIONAL. Until today the pair
   above was scoped to [data-card-badge-host], which the MS band carries only when
   $_msHeaderBox is true and the DM criterion header never carries at all. Those rows
   reached the column by the OTHER arm — the handle's own 16px box plus the row's gap,
   which sums to the same --col-num-x — so they were right only while a handle was there
   to spend it. The moment one is not, the letter falls back to the row's content edge and
   sits 26px left of every item letter under it. That is not hypothetical: it was measured
   on a structurally-locked MS session (letter at 330.5 against six question numerals at
   356.5) and patched with a .structural-locked-scoped rule which is now DELETED, because
   `.structural-locked` was a PROXY for "no handle" and DM — same shape, same arm, no such
   patch — was never covered by it at all.

   So the badge takes --col-num-x on every header row and the handle gives it back on
   every header row. One mechanism, two rules, no branch. A row's indent stops being a
   function of the handle's presence, and `:has(> .tpl-section-drag-handle)` — which
   matches a display:none element and therefore cannot express "occupied" — is not needed
   and must not come back.

   THE TWO ARMS NO LONGER EXIST TO AGREE, so nothing has to be kept in step: the handle's
   cancel and the badge's offset are the SAME token, with a sign between them. */
.tpl-start [data-card-badge-host] > [data-card-num],
.tpl-start [data-card-badge-host] > .tpl-card-badge,
.tpl-start .tpl-edit-row--header > [data-card-num]{margin-left:var(--col-num-x);}
/* ── V3: AN ITEM ROW'S FIELD TAKES THE LEAD TOO ───────────────────────────────────
   Same shape as .tpl-edit-field (templates.css): an item row is `[badge] gap [field]`, the
   field draws the rule, and flow puts it one lead short of V3. Scoped to .tpl-rust-rule so
   it reaches only the boxes that DRAW a line — a nested option row's .tpl-inline-edit does
   not carry that class (the option ROW draws its rule, and the nested pair has its own
   reserve; see V4/V5 in question-types.js), so this cannot reach one level down. */
/* [HARD] `:not(.tpl-edit-field *)` IS LOAD-BEARING: THE LEAD IS SPENT ONCE PER CHAIN.
   Flat's Overall Question is a .tpl-inline-edit.tpl-rust-rule INSIDE a .tpl-edit-field, and
   that outer box already takes the lead (templates.css). Without the exclusion both take it
   and the field lands at 424 against every other rule's 400 — measured, on blank, before
   this clause. Every other .tpl-rust-rule on the surface is a row's own field with no
   .tpl-edit-field above it, so the exclusion costs those nothing. */
.tpl-start .tpl-inline-edit.tpl-rust-rule:not(.tpl-edit-field *){margin-left:var(--col-field-lead);}
/* [HARD] SLIM'S PROMPT IS THE SECOND CHAIN THAT HAS ALREADY PAID, AND IT PAYS IN A
   DIFFERENT CURRENCY (2026-08-24). The clause above excludes flat's Overall Question
   because a .tpl-edit-field ANCESTOR took the lead. Slim's PARTICIPANT INSTRUCTIONS has no
   such ancestor — what it has is `#tpl-flat-questions-body{margin-left:var(--col-line-x)}`
   (the slim layout block below), which is the WHOLE column offset, lead included. So the
   `:not(.tpl-edit-field *)` test says "not yet spent" and it is wrong, because the spend
   happened further up in a different property.
   Measured before this rule: 412..850 against every other line on the page at 400..838 at
   1280, and 89..315 against 77..303 at 390 — a clean +12, which is --col-field-lead to the
   pixel at both widths.
   IT IS A SEPARATE RULE, NOT A SECOND `:not()` ARM, and that is deliberate: the container
   is addressed by ID, so folding `#tpl-flat-questions-body *` into the `:not()` above would
   take that selector's specificity from (0,4,0) to (1,3,0) — :not() carries its most
   specific argument — and silently out-rank things the lead rule has no business beating.
   A (0,5,0) override states the same fact and changes nothing else. */
.tpl-start.slim-mode .qt-input-col > .tpl-inline-edit.tpl-rust-rule,
.tpl-start.slim-mode .tpl-timedate-length-fields > .tpl-inline-edit.tpl-rust-rule,
.tpl-start.slim-mode .tpl-where-place > .tpl-inline-edit.tpl-rust-rule{margin-left:0;}
/* ── V3: A CARD HEADING IS TEXT, SO IT SITS ON THE TEXT VERTICAL (2026-08-24) ──────
   The heading follows its badge in the header row, so the row's own --col-gap put it at
   badge + 26 + 10 — the FIELD BOX's old left edge. That edge has moved onto the text (see
   THE FIELD'S LEFT INSET IS PART OF THE COLUMN in templates.css) and the heading has to
   move with it, because what a heading lines up with is the labels and values under it,
   not the box that used to draw a rule 12px to their left.

   THE OFFSET IS A DIFFERENCE OF COMPOSITES, NEVER A LITERAL 12. It is everything
   --col-line-x spends beyond the badge column and the row's own gap — which is exactly
   --tpl-field-inset today and follows any of the four tokens if one moves. Writing 12px
   here would be a fifth place to change and the one nobody would find.

   THE BADGE DOES NOT MOVE, so the gap between a badge and its heading GROWS by this
   amount. That is accepted and is the same trade the whole ladder makes: two verticals
   held exactly, at the cost of a wider gutter between them. */
/* `.tpl-crit-tag` JOINS THE SELECTOR because on two cards the heading IS one: flat's
   OVERALL QUESTION (#tpl-flat-compare-heading) and OPTIONS TO COMPARE
   (#tpl-flat-items-label) are .tpl-crit-tag.field-required inside the header row, not
   .tpl-sublabel. Measured before this clause: both sat at 388 while every other card
   heading had moved to 400 — the same "one tag, two elements" shape as the <label>/<span>
   split in the block-row rule above, and caught the same way. Naming the ROW and taking
   whatever heading it holds is what stops a third element type doing it again. */
.tpl-start [data-card-badge-host] > .tpl-sublabel,
.tpl-start [data-card-badge-host] > .tpl-crit-tag,
.tpl-start .tpl-block-header-row > .tpl-sublabel,
.tpl-start .tpl-block-header-row > .tpl-crit-tag{
    margin-left:var(--col-field-lead);
}
/* [HARD] A HEADER ROW WITH NO BADGE REACHES V3 A DIFFERENT WAY (2026-08-29).
   --col-field-lead is algebraically --tpl-field-inset (the two cancel: --col-line-x
   is defined AS --col-num-x + --col-num-left + --col-gap + --tpl-field-inset, so
   subtracting the first three back out leaves --tpl-field-inset exactly) — it is the
   REMAINDER after a badge box already spent --col-num-x + its own width + one flex
   gap. A [data-card-badge-host] row always has that badge box as a preceding flex
   sibling, so the remainder is all that is left to pay. A row with NO
   data-card-badge-host has nothing preceding the heading at all, so the rule above
   left it --col-num-x + badge-width + gap short — measured 338 against every other
   heading's 400 for Results & Analysis, the first header row on this page that was
   ever badge-less. Reaching V3 without a badge box means paying the FULL distance
   directly, so this pays --col-line-x instead of the badge remainder. Scoped to
   :not([data-card-badge-host]) — a row that gets a badge back keeps paying the
   remainder above, unchanged. */
.tpl-start .tpl-block-header-row:not([data-card-badge-host]) > .tpl-sublabel,
.tpl-start .tpl-block-header-row:not([data-card-badge-host]) > .tpl-crit-tag{
    margin-left:var(--col-line-x);
}
.tpl-start [data-card-badge-host] > .tpl-section-drag-handle,
.tpl-start .tpl-edit-row--header > .tpl-section-drag-handle{margin-right:calc(-1 * var(--col-num-x));}
/* Item-input typography comes from .tpl-abel (Abel, canonical size) — no
   per-field font override here. The old boxed border was retired in the Session
   142 inline-edit rollout; the box/focus chrome is provided by the shared wrapper
   (.tpl-inline-edit + :focus-within). */
/* The inline-edit wrapper fills the item/option/question row between the number
   and the × (with the [ Edit ] cue trailing), exactly as the bare input did. */
/* Item-input underline width — matches the criteria-name / comparison-question
   underline width (those now live inside .tpl-edit-field, which owns the 460px), so
   every card-row underline terminates at the same x, just before the [Edit] / ×
   controls. The item × sits tight in its .tpl-row-controls cluster; only the line
   shortens. */
.tpl-start .tpl-item-row > .tpl-inline-edit{flex:0 0 auto;width:var(--col-flow-width);min-width:var(--col-flow-width);max-width:100%;box-sizing:border-box;}
/* ROW add buttons — items (#tpl-add-item, also images mode), per-section item adds, and
   question adds (flat #tpl-flat-add-question + per-section [data-add-question]). Excludes
   option adds. Selector-based so JS-built buttons get the style too. The "+" glyph and
   label typography come from the .tpl-add-item-plus / .tpl-add-item-label .tpl-start
   rules below; .tpl-add-btn is the canonical type tier (UI-MONO-1) and no adder restates it.
   The box (1px border / secondary fill / 4px 10px padding / inline-flex) is applied to the
   SAME selectors in public/css/templates.css, so JS-built buttons inherit it too. This
   selector list is retained ONLY for the shared margin-left default (per-button overrides
   follow below).
   THE CARD ADDERS ARE NOT IN THIS FAMILY. #tpl-add-section-btn / #tpl-add-criterion-btn are
   filled ink pills from setup-sidebar.css — a card adder appends a CARD, a row adder appends
   a ROW to a list inside one, and the two tiers do not share paint. Their old description
   here as "plain buttons styled identically to #tpl-add-item, no card chrome" outlived the
   rail by months and is corrected rather than kept.
   The participant "+ ADD ITEM" wears .tpl-add-box and is NOT boxed — see that rule's own
   note; the class name is the trap, not the treatment. */
/* DELETED: `.tpl-start #tpl-add-item` — do not re-add; the reason is T38 in the decision record. */
/* Add Section button — indented by --tpl-crit-indent inside its #tpl-add-section-slot
   wrapper, exactly like the per-section Add Items button and DM's Add Criterion, so
   the three add-button left edges line up. The wrapper (an invisible .tpl-form-card,
   below) supplies the SAME 840px band + horizontal card padding the section cards
   have, so crit-indent lands the button on the section content column. */
/* The slot reuses .tpl-form-card ONLY for its band centring (the shared
   #tpl-start-form > .tpl-form-card 840px rule) + horizontal padding; strip the visible
   card chrome and vertical padding so it reads as plain whitespace holding the button.
   The .tpl-form-card margin-bottom (18px) keeps the gap before the Completion card. */
/* KEYED ON THE SHARED MARKER, NOT ON MS's ID. DM's Add Criterion button moved into the
   same kind of slot when the criteria wrapper was deleted, and it rendered as a VISIBLE
   card until this rule stopped being MS-only — the slot's whole job is to borrow
   .tpl-form-card's band centring and horizontal padding WITHOUT its chrome, and that is
   true of both shapes' slots or neither. */
.tpl-start [data-add-card-slot]{border:none;background:none;border-radius:var(--radius-none);padding-top:0;padding-bottom:0;}
/* DELETED: `margin-left:0` — do not re-add; the reason is T39 in the decision record. */
/* DELETED: `.tpl-start #tpl-add-section-btn{margin-left:0}` — do not re-add; the reason is T40 in the decision record. */
/* THE DISTANCE ABOVE THE CRITERIA ADDER BELONGS TO THE RELATIONSHIP, NOT THE BUTTON.
   It was `#tpl-add-criterion-btn{margin-top:18px}` — a per-element vertical margin, and
   its own comment gave the source as "the 18px card rhythm (.tpl-form-card
   margin-bottom)". That margin is zeroed on .tpl-start now and card-to-card is
   --tpl-gap (26), so the number was left pointing at a source that had moved. What
   this gap actually is: the criterion RUN and the adder are two objects on a card's
   surface, which is --stack-gap, the one number for that role. Stated on the slot's
   relationship to whatever precedes it, the form the rhythm doctrine asks for, so it
   fires only where there IS something above. Add Section is not in it: its slot is a
   card in a card list and takes --tpl-gap from #tpl-structural-region's own row-gap
   (the `* + *` margin that used to supply it is deleted — see templates.css). Two
   adders, two containers, each stating its own distance once. */
/* DELETED: `margin-top` — do not re-add; the reason is T41 in the decision record. */
.tpl-start #tpl-criteria-card{display:flex;flex-direction:column;row-gap:var(--step-row);}
/* [HARD] THIS BUTTON HAS NO TOP MARGIN OF ITS OWN, AND THE RULE ABOVE IS WHY (2026-08-26).
   `.tpl-start #tpl-add-criterion-btn{margin-top:var(--stack-gap)}` is DELETED. It was never
   a decision — it was the residue of one. The distance was moved off the button and onto the
   slot deliberately (the paragraph above records deleting `#tpl-add-criterion-btn
   {margin-top:18px}` and says why), but the button's SELECTOR stayed glued to the front of
   the slot's declaration, so the per-element margin the edit removed was handed straight
   back. Splitting the tie in 61e3c138 preserved both halves and made the arithmetic visible:
   the slot has padding 0 and the button is inline-flex, so the two do NOT collapse — DM
   measured a 58px slot around a 34px button, 24 above it and 24 inside it, 48px total where
   the comment above describes ONE --stack-gap.
   NO COMPENSATING VALUE REPLACES IT. The slot's margin-top is the whole distance, which is
   what the recorded decision says it should be.
   CHECKED AGAINST MS, NOT AGAINST A NUMBER. #tpl-add-section-slot has always been the shape
   this one was supposed to be — its button carries no margin and its slot's height equals its
   button's. After the deletion DM reads the same on both counts, at 1280 and at 390: button
   margin-top 0, slot height 34 against a 34px button, no inner gap. Two adders, two
   containers, each stating its distance once — the sentence above, now true of both. */
/* Equal vertical rhythm below the criteria list: last card → + Add Criterion → Total
   Weighting strip → card bottom, all one --space-md gap. .tpl-criteria-card is block so
   button.margin-top / strip.margin-top collapse to --space-md against their 0/6px
   neighbours, and the criteria card's own padding-bottom supplies the strip→bottom gap. */
/* DELETED: `padding-bottom:var(--space-md)` — do not re-add; the reason is T42 in the decision record. */
/* MS "+ Add Items" box left edge aligns with the item-input boxes above it (and the
   per-section question add button, which already sits at --tpl-crit-indent via its
   block indent). The grouped rule above sets 42px; override to the shared indent. */
/* DM / flat shared RANK ITEMS card — mirror the criteria header's number + name
   columns so the item rows line up column-for-column with the criteria cards
   above: the item NUMBER sits under the criteria number, and the item INPUT
   starts on the comparison-question line (--tpl-crit-indent). The criteria header
   is [drag ~10px][gap 10][num --tpl-card-num-width, digits left][gap 10][name,
   −4px pull], so its number offset is drag+gap and its name/question line is
   --tpl-crit-indent. The list wrapper is offset to the number column, and the
   item number reuses --tpl-card-num-width less the name's 4px pull so [num + gap]
   lands the input exactly on --tpl-crit-indent — fixed on the wrapper + number
   column, no compensating child margins. The "+ Add Items" button aligns its "+"
   under the input column (--tpl-crit-indent), like "+ Add Criteria", plus the
   same 20px top breathing room. Scoped to the shared list's IDs, so MS
   per-section item lists are untouched. max(0px, …) clamps the offset: DM now
   zeroes --tpl-crit-indent too (:has(#tpl-add-criterion-btn) above), so — exactly
   like flat blank (--tpl-crit-indent 0 in both modes) — the raw calc goes negative
   and the list flushes to 0 (number at content-left), matching the survey questions
   list. The clamp is what makes the flush layout fall out for every 0-indent scope. */
.tpl-start #tpl-items-list{margin-left:max(0px, calc(var(--tpl-crit-indent, 0px) - var(--tpl-card-num-width, 26px) - 10px + 4px));}
.tpl-start #tpl-items-list .tpl-item-num{width:var(--col-num-left);margin-left:var(--col-num-x);text-align:left;}
/* MS per-section compare lists now live INSIDE a .tpl-flat-subcard well. The item-num
   width rule stays (descendant selector, well-safe). */
.tpl-start .tpl-section-block .tpl-items-list:not(.tpl-questions-list) .tpl-item-num{width:var(--col-num-left);margin-left:var(--col-num-x);text-align:left;}
/* ── MS section sub-card wells — extend the flat two-well language (bd0d987 / 256656d2)
   to multi-section section cards. REUSE .tpl-flat-subcard verbatim; MS-only deviations are
   scoped via :has(#tpl-add-section-btn).

   [HARD] "(fill / border / 8px radius / padding)" IS DELETED FROM THAT LINE, 2026-08-26.
   The class has none of the first three: it is SKINLESS, and setup:well-probe asserts it on
   every deploy ("base rule: .tpl-flat-subcard declares no skin", "no rule repaints the class
   — the invariant has no exception"). What reusing it verbatim actually buys is the BOX —
   the padding and the 1px transparent border that carries the inset — and nothing painted.
   The parenthesis outlived the skin and read as a live description of one.

   (d) WIDTH: the wells span the SAME flush full-card width as the [data-question-wrap]
   question sub-cards. Root cause of the old inset was --tpl-crit-indent; zero it for MS
   exactly as flat does for ITS well layout (:has(#tpl-rank-type-toggle){--tpl-crit-indent:0}
   below). One shared source — every section-body element (both wells, the ITEMS heading,
   the Add buttons, the intro textarea) then sits flush to the card, matching the question
   cards. This SUPERSEDES (and replaces) the three per-well margin/padding rules the
   previous pass added — no layered override. */
.tpl-start:has(#tpl-add-section-btn){--tpl-crit-indent:0px;}
/* DM criteria cards join the flush layout: zero --tpl-crit-indent exactly as MS
   (above) and flat (:has(#tpl-rank-type-toggle) in templates.css) do, so every DM
   body element — the criteria name / comparison wells, the RANK ITEMS heading +
   toggle + item rows, the "+ Add Criteria" / "+ Add Items" buttons, the description
   textarea, the Respondent Comments toggle — sits flush to the card, at the SAME
   left edge as flat/MS. The header name-field's crit-indent-based calc (templates.css)
   would go negative here, but the :has(#tpl-add-criterion-btn) margin-left:0 override
   below already pins the name after the number (the calc trap, pre-empted). */
.tpl-start:has(#tpl-add-criterion-btn){--tpl-crit-indent:0px;}
/* The header name field's left margin (templates.css) is a crit-indent-based calc that
   aligned the name underline to the OLD body content column. With MS crit-indent now 0,
   that calc goes strongly negative (≈ -(drag+num+20)) and pulls the name OVER the "01"
   number. For MS, pin the name field to its natural position AFTER the number — the edit
   row's own 10px gap supplies the spacing. (DM's crit-indent is now 0 too — line 936.) */
/* MS: the Section Name line matches the comparison-question / item lines — same
   --col-line-width as the merged-well lines, from the shared column token (no
   literal). Same flex:0 1 auto + width as the comparison line, so it is the identical
   length (shrinking to fit only when the card is too narrow for band + number + controls).
   margin-left:0 keeps the name after the number (not the crit-indent calc).

   :not(.tpl-section-band) NARROWS this rule rather than being out-specified by a second
   one. A BAND's name field is elastic and capped short of the centred pill (see THE NAME
   FIELD'S RIGHT RESERVE), which is the opposite of a fixed --col-line-width, and the
   min-width here would have won against any cap regardless of specificity — a fixed
   min-width and a max-width smaller than it is a contradiction the cascade resolves in
   favour of the min. Two rules describing one element's width is how that becomes
   invisible; one rule per shape is why the exclusion is HERE. The workshop MS header row
   (no band) and DM's criterion row both still match. */
/* ── A QUESTION BLOCK SITS ON ITS CARD'S CONTENT COLUMN, LIKE EVERY OTHER LIST ────
   [HARD] THE COLUMN IS A PERCENTAGE, SO IT IS THE CONTAINING BLOCK THAT WAS WRONG, NOT
   THE WIDTH. --col-line-width is `min(598px, calc(100% - --col-line-x - --col-right))`
   and a percentage in a custom property resolves AT THE POINT OF USE. The survey / quiz
   questions list read the same token every other block reads and still came out 30px
   wider, because it was the only list sitting straight on the card's PADDING box while
   every other one sits in a well a further --tpl-section-inset in: MS's rows in the
   section panel, flat's in the items well, DM's criterion parts in the header row.

   Measured at 1280 before: the question card's rules ran 421.19..836.81 against DM's
   436.19..821.81, and its lane stood at 847.81 against every other lane's 832.81 — one
   token, two answers, because two containing blocks.

   The difference between a card's padding and its content column WAS exactly the well's
   own 15px, and since 2026-08-24 that difference is ZERO: a card's content box and its row
   band are the same box now, so a child of the card is already on the column and there is
   nothing to convert. Kept as a declaration rather than deleted because it is the one
   place that states the relationship, and 0 is the correct value of it — not an absence.
   THIS IS ALSO WHY SURVEY'S AND QUIZ'S CARD-2 NUMERAL JOINS THE OTHER CARD NUMERALS. That
   header row is emitted INSIDE this container, so it paid this inset while every other
   card's numeral did not: measured at 1280 before, 374 against 359 everywhere else, and at
   390, 50 against 35. It is the "same component, two ladder positions" the 2026-08-23
   audit flags at A.6, and it corrects itself here rather than needing a rule of its own.
   Nothing about --col-line-width, the rules or the lane is touched. */
.tpl-start .tpl-flat-questions-body{
    padding-left:0;
    padding-right:0;
}
/* [HARD] `margin-left` IS THE LEAD HERE, NOT 0 (2026-08-24). It was 0 to cancel an older
   crit-indent calc that pulled the name field OVER its numeral — that calc is long gone and
   the 0 outlived it, which is why this read as correct. It is not any more: the lead is what
   puts a flow-positioned field on V3, and a hard 0 here left DM's three criterion parts and
   MS's section-name part at 389 while every other rule on the page sat at 400/401. Measured
   before the fix. If a header field ever needs pinning again, pin it to the lead. */
.tpl-start:has(#tpl-add-section-btn) .tpl-edit-row--header > .tpl-edit-field,
.tpl-start:has(#tpl-add-criterion-btn) .tpl-edit-row--header > .tpl-edit-field{margin-left:var(--col-field-lead);flex:0 0 auto;width:var(--col-flow-width);min-width:var(--col-flow-width);max-width:100%;}
/* "Section A Type" label + Items/Images/Questions chooser — REUSES the Session Type
   mechanism verbatim (.tpl-modes-row: centred flex column + 8px label→toggle gap; label
   .tpl-mono.tpl-workshop-mode-label). RELOCATED to sit BETWEEN the name sub-card and the
   question/items sub-card: EQUAL top + bottom margin (14px), so the gap from the name
   sub-card down to the toggle equals the gap from the toggle down to the next sub-card
   (.tpl-section-block is a normal block, so these margins collapse against the neighbouring
   sub-cards' own 14px, landing ~14px each side). */
/* MS section content-type dropdown — the question-type .qt-tag control (styled by
   question-types.js) now lives INSIDE the section-name card, directly under the name line
   and ABOVE the description/comment checkbox row, left-aligned to the name. Hidden on
   collapse like that checkbox row. */
/* DELETED: The two .tpl-edit-field > .tpl-section-type-select — do not re-add; the reason is T43 in the decision record. */
/* The reference trigger sizes via .qt-type-col in a horizontal flex ROW (flex-basis =
   width, .qt-tag height:100% fills the short row). Here .qt-type-col sits in the flex-COLUMN
   .tpl-edit-field, where flex-basis:190px becomes a 190px HEIGHT and .qt-tag fills it -> a
   tall broken box. Pin the wrapper to content height and let the tag be its natural
   padding-based height; the 190px width + caret-right still come from the reused .qt-type-col
   rules. (Extend the scope, don't clone the CSS.) */
/* DELETED: .tpl-edit-field > .tpl-section-type-select.qt-type-col{flex:0 0 auto} — do not re-add; the reason is T44 in the decision record. */
/* ── THE SECTION TYPE PILL ────────────────────────────────────────────────────────
   The section type is now the SAME OBJECT as the question type, drawn by the same
   declarations. It was the last captioned field on this card: a rust "SECTION TYPE"
   micro-label over a full-width chrome-less trigger, sitting in a bonded part of its own.
   The caption is deleted for the reason QUESTION / ITEM TYPE was in slice 2 — the control
   already names its own value, so a label above it is a second name for one thing — and
   the part goes with it, because a pill inside a bordered strip is the box-in-a-box the
   card design removes. The header box is now TWO members, name and description.

   WHERE THE PILL GOES: its own line under the name, INSIDE the name part, not on the name
   line beside the ×/▾. Chosen from the width contract, measured rather than eyeballed. At
   390 the name part's content box is 344px and the ×/▾ cluster takes 48.5 of it, leaving
   289.5 for the name; the widest pill ("Compare Images ▾") measures 154.7, so a name-line
   layout would leave a realistic section name 128.8px — under half a line at the 20px
   card-name tier, and it SQUEEZES rather than wraps, which is the failure the width
   contract exists to catch. One layout at both widths beats a name-line/own-line media
   split, so the own-line form wins outright rather than only at 390: flex-basis:100% on a
   wrapping name part puts it on row 2 deterministically at every width.

   THE PILL'S OWN SIZING. .qt-type-col ships `flex:0 0 190px;width:190px` — a COLUMN
   width written for the horizontal question row. In the name part (a flex ROW) that
   basis is again a width, and a 190px box round a 100px pill left it floating in dead
   space. flex-basis is spent on the line break instead and the width comes back to
   content; align-items:flex-start stops .qt-type-col's `> .qt-tag-wrap{align-self:stretch}`
   from re-stretching the trigger to the part's full width, which also keeps the popover
   anchored to the PILL rather than to the part.

   FOUR RULES DELETED HERE, not left inert — all three of their live claims are now made
   by THE CHIP further down, and one of them never made any:
     • `.tpl-crit-part--type > .tpl-section-type-select{width:100%}` and
       `.tpl-crit-part--type .qt-tag{border:0;background:transparent;border-radius:0;
       padding:0;width:100%}` and `.tpl-crit-part--type .qt-popover{width:100%}` —
       the part they were written for no longer exists (this partial and its JS mirror
       were its only two emitters in the repo, so .tpl-crit-part--type / --pair--type are
       gone from the codebase, collapse arm included).
     • Their SECOND arm, `.tpl-questions-list .qt-type-col .qt-tag` / `.qt-popover`, was
       already dead weight: measured on pristine HEAD, the question chip computes
       border-top 1px, background rgba(178,74,58,.1), radius 999px, padding 13/12px,
       width 115.3px, and its popover width auto / min-width 240px — i.e. every one of
       those declarations already lost the cascade to THE CHIP.
     • `.tpl-questions-list > [data-question-wrap] > .qt-type-col > .qt-tag-wrap` matched
       ZERO elements (measured, count 0). It is the DOM-depth trap again: the real chain
       is [data-question-wrap] > .qt-card > .qt-q-row > .qt-type-col, so the child
       combinator skipped two real wrappers. Third instance of this exact mistake on this
       card; the ancestor chain was dumped for every element touched here before a
       selector was written for it.
   `.tpl-section-type-select .qt-tag{height:auto}` goes too: THE CHIP sets height:auto for
   both controls, and the two can only ever co-occur (the pill rules and this control are
   both gated on the MS page). */
/* DELETED: THE PILL NO LONGER LIVES IN THE NAME PART, so the  (above `.tpl-start:has(#tpl-add-section-btn) .tpl-crit-pair--name`) — do not re-add; the reason is T45 in the decision record. */
/* ── The header trio reads as ONE attached stack: name -> type -> description ──────
   Before this, the name box and the description box merely TOUCHED — two 1px borders
   meeting at the same y, i.e. a 2px double line (measured: name 845..879, pair 879..955)
   — and the dropdown floated 10px below. Same collapse technique and the SAME tokens as
   the MS BONDED STACK above: square the joins, pull each member up 1px so the two borders
   occupy one line, and repaint that joint in the pair's split token. No third border
   treatment is introduced; this is the existing one applied to the header.

   THE NAME IS NOW A PAIR TOO (2026-08-02), so all three members are the same kind of
   thing and these rules stopped needing a second arm for the odd one out. The two
   `.tpl-edit-field > .tpl-inline-edit > input` arms that used to sit here — the one
   squaring the input's radius and the one giving it the box's top corners — are
   DELETED, not overridden: the input no longer carries a box at all (the part does,
   via .tpl-crit-pair in templates.css), so both selectors would have been styling a
   border that is not there.

   `:first-child` / `+` rather than a blanket rule: the opening member keeps the box's
   top corners and takes no pull, and only the members AFTER it collapse into their
   neighbour. Adjacent-sibling is exact here — .tpl-edit-field's children are the three
   pairs in document order, with nothing between them. */
/* ── THE HEADER STACK IS DELETED, BECAUSE IT HAS ONE MEMBER ───────────────────────
   The four rules that used to sit here — square every pair in the header box, restore
   4px on the first, restore 4px on the last, and pull each pair after the first up 1px
   onto its neighbour's border — described a RUN of bonded pairs. The description has
   left the header box, so .tpl-edit-field holds exactly one child, the name pair, and
   all four collapse to a no-op: :first-child and :last-child both match it, so the pair
   ends up with the plain 4px radius .tpl-crit-pair already gives it, and `+` matches
   nothing.
   Deleted rather than kept "in case a member comes back": a rule whose whole effect is
   to undo its own neighbour is the kind of thing that reads as load-bearing on the next
   pass. (This used to add "the bonded-stack technique is still written out in full on the
   MS BONDED STACK rules further down". It is not: those rules are deleted too, for the
   same reason and in the same pass — the run of members they bonded had come apart
   underneath them. If a second member ever rejoins this box, the technique is in the
   history, not further down this file.) */
/* ── THE NAME PART — a single-child box again ─────────────────────────────────────
   It held three things (name, ×/▾ cluster, type pill) and now holds one, the name. The
   cluster and the pill are children of the BAND; see the deleted-emitter note in the
   card markup for why each left.

   What survives is what was always about the NAME: the flex row so the input can grow,
   and the tighter 4px vertical padding. That padding was chosen when the 30px collapse
   button set the part's height, and it is KEPT deliberately now that the button has
   gone — the band's own `align-items:center` puts the 30px controls beside this box
   rather than inside it, so the box is free to be as tall as its text, and 9px around a
   22px line would make the name box taller than the pill and the controls either side
   of it. Measured after the move, not inherited on faith.

   `gap` and `flex-wrap` are DELETED with the children that needed them: a gap between
   one item and nothing, and a wrap rule for a line that no longer exists.

   .tpl-inline-edit needs the flex override because its base rule (templates.css) is
   `width:400px;max-width:50%` for its stand-alone use, and the `.tpl-edit-field >`
   rule that used to widen it no longer matches — the wrapper is a child of the part
   now, not of the field. */
/* ── THE NAME IS NOT A BOX ────────────────────────────────────────────────────────
   The name was a white bordered field sitting on a card — a field painted on a field.
   It inherited that from when it lived in a bonded pair with the description and the
   type; both have left, and the box left its reason behind.

   SCOPED, NOT DELETED AT SOURCE, AND THAT IS THE POINT. The paint comes from the SHARED
   `.tpl-crit-pair` base rule in templates.css, which the description pair still depends
   on for its border, radius and white fill — editing it would strip the description box
   too. So the removal is stated on the two MS-only classes that name this instance
   (2 emitters each, both MS), and the base rule is untouched. Proven, not assumed: the
   description pair renders byte-identical before and after.

   The typography does NOT come from the pair — the card-name tier is keyed on
   `.tpl-start .tpl-inline-edit > input.tpl-card-name-input` (templates.css), so Bebas 20
   survives the box's removal without a second declaration. Checked before relying on it.

   The ring/tick slot is untouched: it is a background-IMAGE layer on the input, and
   nothing here writes the `background` shorthand that would wipe it. */
/* [HARD] THE BORDER GOES TRANSPARENT, NOT TO ZERO (2026-08-20). It was `border:0`, and
   that is a WIDTH change wearing a paint change's clothes: the shared .tpl-crit-pair
   carries `border:1px solid` (transparent on DM, visible when .field-invalid), so every
   part on the page sits 1px inside its pair. Zeroing it here pulled the section NAME's
   part out to 435.19..822.81 against its own description's 436.19..821.81 — one card,
   two rule lengths, differing by the width of a border nobody can see. Transparent
   removes the paint and keeps the column. */
.tpl-start:has(#tpl-add-section-btn) .tpl-crit-pair--name{
    background-color:transparent;
    border:1px solid transparent;
    border-radius:var(--radius-none);
}
/* THE HORIZONTAL ZEROING IS DELETED, AND IT IS THE LAST EDGE ON THE CARD THAT WAS NOT
   THE OTHERS'. `padding-left:0;padding-right:0` took --tpl-field-inset off the NAME and
   left it on every other part, so a section's name sat 13px left of its own description,
   comparison question and eyebrows — measured 425 against 438 at 1280. A criterion on
   multi-criteria has no such exception: its name, its description and its question all
   start at 438, and the contents indent from the name that introduces them. Removing the
   two lines is what gives the section card the same relationship, from the same shared
   `.tpl-crit-part{padding:9px var(--tpl-field-inset)}` both shapes already read.

   The vertical pair stays: 4px is the name line's own rhythm inside the band and has
   nothing to do with the column.

   [HARD] AND IT IS NOT WHAT PUTS A GAP UNDER THIS NAME (measured 2026-08-20). Deleting
   padding-bottom here was tried and REVERTED, because it treats a symptom that is not
   even attached to the cause: THIS FIELD HAS NO RULE OF ITS OWN. The rust line under the
   MS section name is a normal-flow ::before on the PANEL that follows the band — a
   different element, whose position is set by the band's height and the panel's layout,
   not by the field. Nothing about the name's own box moves that line, so trimming 4px off
   the name's padding only slides the name toward a rule it does not own.

   It is the ONLY field on the surface in that position: a census of all 22 authorable
   fields on DM, MS, flat and survey found 21 sitting on their own rule at exactly 0.00px
   and this one with no rule to sit on. Converging it means moving the line onto
   .tpl-crit-part--card-name as .tpl-rust-rule and deleting the ::before — which also
   moves the section card's whole top rhythm and retires setup:spacing-probe's
   `ms:rule-mb` role. That is a deliberate change to the band, not a tidy-up, and it is
   NOT made here. */
.tpl-start:has(#tpl-add-section-btn) .tpl-crit-part--card-name{
    display:flex;
    /* align-items:FLEX-END, not center. Dates from when the part also held the type chip
       (2026-08-20 — 2026-08-29, since moved to the full-bleed strip above the card; see
       THE SECTION TYPE STRIP): centring grew the row below the input and lifted the name's
       bottom edge off its own rust rule, which setup:badge-probe's resting field-to-rule
       assertion fails on. The part is single-child now, so this is moot either way, but
       untouched rather than churned — flex-end is exactly as correct as center for one
       flex item and there is no reason left to prefer one over the other. */
    align-items:flex-end;
    padding-top:var(--inset-tag);
    /* padding-bottom is 0 — the field's bottom edge IS its rule's top edge, which is what
       every other field on this surface does and what .tpl-crit-part ships. The 4px that
       stood here was the last thing between the two. */
    padding-bottom:0;
}
.tpl-start:has(#tpl-add-section-btn) .tpl-crit-part--card-name > .tpl-inline-edit{
    flex:1 1 auto;width:auto;min-width:0;max-width:none;
}
/* ── THE QUESTION DRAG HANDLE, INSIDE THE CARD IT REORDERS, HOVER-ONLY ────────────
   ONE handle now, not two. The SECTION handle's arms of these two rules are DELETED
   (2026-08-02): it is back in the leading --col-drag gutter, where DM's is and where the
   shared .tpl-section-drag-handle rules in templates.css already style it — always
   visible, gutter-width, no hover reveal, because in a reserved column it competes with
   nothing. `.tpl-crit-part--card-name > .tpl-section-drag-handle` would match nothing on
   any page, and an inert arm beside a live one reads as "MS still mounts one there".
   The QUESTION handle keeps this treatment unchanged: it genuinely does sit inside its
   card's top line, so it is in the content rather than in dead space beside it, and shown
   at rest it competes with the prompt and the type chip for the eye. opacity, not
   display, so it reserves its space and nothing reflows when it appears. :focus-within
   keeps it reachable from the keyboard — a hover-only control a keyboard cannot summon is
   not an affordance, it is a hidden one.

   [HARD] width:auto IS DELETED (2026-08-05), AND IT WAS THE DEFECT. It read "take the
   handle's content width back from the component's `width:var(--col-drag)`", and the note
   defending it — "that mattered when --col-drag was 0 here and it matters MORE now that it
   is 16px again" — states the inverse of its own effect. When the gutter is 0, `auto` is
   harmless; when it is 16, `auto` is exactly what breaks the rail. A comment asserting the
   opposite of what its rule does is worse than no comment, and it is why this survived
   three passes over this card.

   THE COMPONENT'S TWO GUTTER ARMS AGREE BY CONSTRUCTION, from the same two tokens:

       no handle  ->  .tpl-item-num margin-left: --col-num-x,
                      which IS calc(var(--col-drag) + var(--col-gap))
       handle     ->  handle width var(--col-drag) + the row's gap var(--col-gap),
                      and the numeral's margin drops to 0

   Same two tokens, same sum, every state and every breakpoint; neither arm can drift
   without the other. `width:auto` replaced var(--col-drag) with the braille grip's CONTENT
   width — 11.72 against 16 — so the handle arm landed 4.28px short and the question column
   moved 4.28px left the moment a section had a second question (the handle is emitted at
   questions.length > 1). Measured on cfe85708: 1 question 325.50, 2 questions 321.22,
   3 questions 321.22. Shipped, and invisible in every single-question fixture.

   THE BRANCH IS NOT THE DEFECT AND IS NOT REMOVED. A conditional gutter whose two arms
   resolve to the same x from the same tokens is one mechanism written twice, not two
   mechanisms kept in sync by hand. Mounting the handle unconditionally would have meant
   changing the shared question component's DOM for flat, survey, quiz and DM to fix a bug
   this page introduced in its own override.

   (No prefers-reduced-motion carve-out: this page has no such block to join, and adding
   a global one is a change to every animation on it, not to this rule.) */
.tpl-start:has(#tpl-add-section-btn) .tpl-section-block .tpl-questions-list > [data-question-wrap] > .tpl-question-drag-handle{
    flex:0 0 auto;
    /* DELETED: `margin:0` — do not re-add; the reason is T46 in the decision record. */
    opacity:0;
    transition:opacity 0.15s;
}
.tpl-start:has(#tpl-add-section-btn) .tpl-section-block .tpl-questions-list > [data-question-wrap]:hover > .tpl-question-drag-handle,
.tpl-start:has(#tpl-add-section-btn) .tpl-section-block .tpl-questions-list > [data-question-wrap]:focus-within > .tpl-question-drag-handle{
    opacity:1;
}
/* DELETED: COLLAPSED — the two rules that used to sit here — do not re-add; the reason is T47 in the decision record. */
/* DELETED: The [data-section-mode] rule that used to round th — do not re-add; the reason is T48 in the decision record. */
/* NOT DONE — the Questions / Quiz stack does not close. See the report / D-DEBT.
   (a) and (b) shipped: each question
   row carries its rust "QUESTION / ITEM" label. The BOX was attempted and reverted: giving
   the prompt, the instructions strip and the type control a border each is only half the
   job, and with the row's own spacing still open (measured 35 / 8 / 9 / 31px between
   members) it renders as a column of DISCONNECTED boxes — visibly worse than the
   unbordered rows it replaced. Closing it needs the row's internal spacing resolved
   member by member, which is its own pass. */
/* ── THE HEADER BOX ENDS AT THE DESCRIPTION ───────────────────────────────────────
   It used to run on into the comparison question and the item list as ONE box from the
   section name to the last item. It does not any more: the header box holds only what
   CONFIGURES a section — name, type, description — and the comparison question, which is
   something a respondent reads, has left for its own card below (see THE COMPARISON
   QUESTION CARD). So the header's own margin-bottom is restored as the gap to whatever
   follows, and the two rules that pulled the comparison pair up 1px and squared its top
   corners are DELETED: they described a member of a run that no longer contains it, and
   left in place they would have squared the top of a stand-alone card. */
/* ── AND THE INSET COMPENSATION IS DELETED WITH THE BOUNDARY IT CROSSED ───────────
   This rule used to add `margin-left/right:var(--tpl-subcard-inset)` to the MS header
   row, because the header sat OUTSIDE the section body panel while every rail entry
   under it sat inside one: without the margin the section letter landed 15px left of
   every numeral and the rail was broken.
   The header is now the panel's FIRST CHILD (see THE SECTION BODY PANEL OPENS in the
   card markup), so there is no boundary left to compensate for — one container, one
   content edge, and the letter and the numerals share a column by construction. Kept,
   the margin would not be redundant but WRONG: it would inset the header a further
   15px inside a panel that has already applied that inset as padding.
   Its third declaration, `margin-bottom:10px`, went with it: it restated the value
   .tpl-edit-row--header already carries in templates.css (~1284), and nothing between
   the two overrides it. --tpl-subcard-inset had no other consumer and is deleted from
   the D-COLUMNS block too — a term nothing resolves is worse than no term.
   (The MS-scoped collapse pair below is the one thing the move DID need: see it.) */
.tpl-start:has(#tpl-add-section-btn) .tpl-section-block > .tpl-flat-subcard{margin-bottom:0;}
/* DELETED: `.tpl-section-block.tpl-card-collapsed > *:not(.tpl-edit-row--header)` — do not re-add; the reason is T49 in the decision record. */

/* ══ THE BAND ═════════════════════════════════════════════════════════════════════
   An MS section card is TWO surfaces stacked with no gap: a tinted band that names the
   section, and the body panel that holds it. One card, one border, one radius; the band
   is not a second card, it is the top of this one.

   ── THE INSET IS ONE TERM, AND IT IS LOAD-BEARING ────────────────────────────────
   --tpl-section-inset is the distance from the card's inner edge to the content edge
   that EVERY row on this card starts from — the letter, the description, the comparison
   question, the item numerals, the question rows. It is read in exactly two places, the
   band's padding and the body's padding, so band and body are inset identically by
   construction rather than by two numbers kept in step.

   Its VALUE is not free to change. It reproduces what the card's own 22px padding plus
   the body panel's 1px border + 14px padding produced before this commit (22 + 15 = 37),
   and that sum is what puts a question row's left edge where it already is. The question
   rows may not move — they are the reference the description aligns TO — so this term is
   pinned by that requirement, not chosen. If it ever has to change, the description's two
   margins below change with it and the alignment has to be re-measured, not assumed.

   WHY THE PANEL'S OWN HORIZONTAL PADDING IS NOW ZERO rather than the card's. A band that
   bleeds to the card's left and right borders cannot sit inside the card's padding, and a
   band inside the PANEL could not reach them either. So the card gives up its padding
   entirely, the panel gives up its horizontal padding, and the one inset moves onto the
   two children that need it. The panel keeps existing and keeps mattering — it is what
   the collapse rule hides and what the end-of-section toggle measures --col-line-x
   against — it just no longer supplies the inset.

   [HARD] NO overflow ON THE CARD, THE BAND, OR THE PANEL. The type pill's .qt-popover is
   position:absolute and opens downward past the band's bottom edge; any of the three
   given overflow:hidden (or auto, or clip on the wrong axis) cuts it off, and the same
   declaration turns the element into a scroll container, which is where the phantom 73px
   child offset came from the last time. The band's own corners are radiused instead —
   that is the whole reason the radius is on the band and not achieved by clipping. */
.tpl-start{
    /* DERIVED, NOT MIRRORED — and since 2026-08-24 it is derived from the CARD'S OWN
       PADDING PAIR rather than from a card-pad-plus-well sum. MS's section card pads 0 and
       its band carries the inset, so for an MS row to land where every other shape's card
       content lands, the band must pad exactly what an ordinary card pads. That is now
       literally the same two tokens, which is why the "+ 15px" is gone: the well it stood
       for no longer insets horizontally, so an MS row and a DM well's row agree because
       they read one pair, not because two independent sums happen to match. (That match was
       recorded as a coincidence with no assertion tying it — 2026-08-23 audit, A.2.2.)
       The old note's history stands: this was a 37px literal with hand-copied narrow arms
       (31px / 25px) spelling out "16 + 15" and "10 + 15", deleted when the term became
       readable. Two tokens now, because the two sides are no longer the same number. */
    --tpl-section-inset-l:var(--col-card-pad-l);
    --tpl-section-inset-r:var(--col-card-pad-r);
    }
/* ── THE SECTION TYPE STRIP — full-bleed tab strip, top edge of the MS section card ──
   Replaces the .qt-tag/.qt-popover chip that used to lead the section name (see THE MS
   SECTION TYPE CONTROL HAS LEFT THESE SELECTORS, above THE CHIP, further down this
   file). One tab per section type, all visible — no popover, so none of THE CHIP's
   overflow constraints are this element's to keep; the card, band and panel still carry
   none, for the OTHER popover still on this card (the per-question type chip).

   FULL-BLEED FOR FREE. `:has(> .tpl-section-band){padding:0}` below already zeroes the
   card's own padding whenever a band is a direct child (see THE INSET IS ONE TERM
   above); the strip is ALSO a direct child of the same card and gated on the same
   condition ($_msHeaderBox), so it inherits that same zero padding and needs no
   negative margin of its own to reach the card's edges.

   THE HAIRLINE IS THE PRIMARY SELECTION CUE; THE FILL IS REINFORCEMENT, NOT A
   SUBSTITUTE (2026-08-29, revised same day on a second look at the surface class).
   FIRST PASS: the strip read --card-bg-inset, DM's own recessed-card token, on the
   theory that the strip and DM's criteria card were the same surface class. Measured
   and found wrong: --card-bg-inset vs --card-bg is 3/255 per channel, indistinguishable
   in practice (CONFIRM 4 in the brief this shipped from). THE TWO ARE NOT THE SAME
   SURFACE CLASS. DM's card reads recessed off its BORDER and RADIUS — a bounded card
   inside a card, fill incidental — so --card-bg-inset's near-invisible fill costs it
   nothing there. The strip has no border of its own: an unbounded plane the selected
   tab sits in front of, where fill is the ONLY thing available to carry contrast, so
   the same near-invisible pairing that is fine on DM is a real defect here.
   SECOND PASS: --page-bg, not a new token. Checked --toggle-bg first (the platform's
   other "borderless container a raised/selected element sits on" token) — wrong
   direction, LIGHTER than --card-bg ("lifts... off the cards"), where this surface
   needs to recede. --page-bg already IS "the plane behind a raised card-toned
   element": every card on this page reads as lifted off the page via --card-bg vs
   --page-bg, and that is exactly the relationship the strip/tab pair needs — the strip
   reads as the page itself, showing through a notch in the card, and the selected tab
   reconnects with the actual card surface behind it. Reuse, not a sibling token: DM
   keeps --card-bg-inset as its only consumer, unchanged.
   What carries selection, in order:
     1. A 1px --color-border-tertiary hairline runs the strip's full width, ABSENT under
        the selected tab — drawn on the strip's own border-bottom, painted over by the
        selected tab's opaque fill pulled 1px past the strip's content edge (.active
        below). CSS cannot gap a border by position; covering it is the mechanism. This
        stays primary regardless of the fill pairing above or below it.
     2. Ink text on the selected tab, the standard placeholder colour on the rest — the
        same idiom .tpl-adv-sub[role="radiogroup"] .tpl-segment-option already uses for
        "which of these is the current mode" (templates.css). No green: ink is
        current-mode selection, green is boolean ON (UI-TOKEN-1).
     3. --page-bg vs --card-bg — kept, CLOSED 2026-08-29, not for its contrast. Once the
        label size and padding landed the strip already read as tabs on the hairline
        cue alone, confirming the fill was never load-bearing for legibility (~7/255,
        2.3x the rejected --card-bg-inset pairing, still not something a person spots
        unprompted). It stays because it is CORRECT independent of that: --page-bg is
        genuinely what this surface is — the page's own plane, showing through a notch
        in the card, with the selected tab reconnecting to the card behind it — the
        same status --card-bg-inset already holds on DM's card despite an equally
        invisible delta there. Do not widen it, do not add a sibling token, and do not
        re-open this looking for more contrast: the border/no-fill convention every
        other recessed surface on this page already uses is the reason it can stay
        exactly this quiet. Verified in a real browser, not assumed: strip samples
        exactly --page-bg (227,221,208), the selected tab and the card body below it
        both sample exactly --card-bg (234,227,214).

   RADIUS, NO OVERFLOW. The strip owns its own top-left corner (10px, matching the
   card's) rather than the card clipping it — the card/band/panel stay overflow:none,
   on purpose (see [HARD] NO overflow ON THE CARD... above), so the per-question
   chip's .qt-popover can still escape downward past the band. `.active:first-child`
   takes the matching corner so a selected first tab's opaque fill cannot square off
   past the strip's curve.

   CONTENT-WIDTH, PACKED LEFT (2026-08-29, operator correction). Tabs were briefly
   `flex:1 1 0`, stretched to fill the card — "a segmented control filling a
   container", rejected: the effect wanted is "tabs on a folder", which is
   content-width tabs sitting together at the strip's left edge with the remainder
   of the strip showing as empty --page-bg background to their right. That
   remainder is also why there is no `.active:last-child` corner rule any more: the
   last tab reaching the strip's right edge was only ever guaranteed under equal-
   width stretch, and un-stretched it does not happen in the general case — a rule
   for a geometry that no longer occurs is dead weight, not a safety net.

   TYPE IS BEBAS, THROUGH THE CANONICAL CLASS, NOT A NEW FONT DECLARATION. Each tab
   carries .tpl-card-heading (start.blade.php, ~line 1941) — the SAME tier the
   .tpl-card-heading above the DM comparison box uses (_criteria-compare-line.blade.php)
   — for font-family/tracking/case; colour is overridden below (ink / placeholder is a
   selection cue, not a type-tier property, and .tpl-card-heading's own color:var(--ink)
   would otherwise paint every tab ink regardless of state). margin-bottom:0 cancels the
   tier's own 6px (spacing below a heading ABOVE a box — not applicable to a tab's own
   padding-bottom).

   SIZE SITS BETWEEN TWO SCALE STEPS, NOT ON ONE (2026-08-29, operator correction,
   twice). THE FACILITATOR SETUP TYPE TIERS block in tokens.css declares the scale in
   one place: --tpl-sublabel 30 → --tpl-heading/--tpl-cardname-size 20 (what
   .tpl-card-heading ships, and the tier's own default) → --tpl-kicker-size 14 →
   --mono-utility-size/--tpl-menu-size 12 → --tpl-toggle-label 9. One step down from 20
   (14) shipped first and read too small; 20 itself is the tier's own size and was
   rejected before that. THERE IS NO DECLARED STEP BETWEEN 20 AND 14, so the size below
   is the MIDPOINT OF THE TWO BRACKETING TOKENS, not a literal picked by eye — the same
   derivation --step-lift uses (a value computed from two existing steps, never invented
   whole). calc((--tpl-heading + --tpl-kicker-size) / 2) = 17. If the scale ever gains a
   16 or 18 step, prefer that named token over this calc(); until then this is the
   non-literal way to sit between the two that exist.

   PADDING READS --tpl-card-pad, THE CARD'S OWN PADDING TOKEN (2026-08-29), not a
   literal — "more room either side so the labels breathe and the dividers sit clear
   of the text", from an existing spacing token rather than an invented one. 24px at
   1280, following the same token's own responsive steps (16px at <=640, 10px at
   <=480) with no separate breakpoint rule needed here. Vertical padding is untouched
   (not asked for). Not a 45th Bebas literal and not a new spacing literal either: size,
   family, tracking, case and now horizontal padding all read tokens through one shared
   class or one shared property. */
/* [HARD] overflow-x:hidden HERE ONLY, NEVER ON THE CARD (2026-08-29). At <=480 four
   content-width tabs can exceed the strip's own width (open finding: which tabs stay
   reachable there is unresolved, not this rule's job). Un-clipped, that overflow
   inflated .tpl-section-block's scrollWidth (340px content in a 342px box became
   360px), which cascaded into EVERY OTHER ROW ON THE PAGE ending 15px short of where
   every other shape's rows end at 390 — a real, page-wide regression, confirmed to
   disappear with horizontal clipping alone (min row-right returned from 287 to 302,
   matching every other shape). Scoped to the strip alone: the "no overflow on the
   card/band/panel" rule above is about the PER-QUESTION chip's .qt-popover escaping
   downward past the band, a completely different element that lives in the panel, not
   the strip — this clips only the strip's own overflow, on an axis (x) the popover
   never uses.

   [HARD] overflow:clip WITH overflow-clip-margin:2px, NOT overflow-x:hidden ALONE
   (2026-08-29, second pass — a real defect shipped between the two). CSS forces a
   'visible' axis to 'auto' whenever its paired axis is anything else non-visible —
   overflow-x:hidden with overflow-y unset computed overflow-y:auto, and the active
   tab's own 1px hairline-eating overhang (.active below: padding-bottom 9 vs 8,
   margin-bottom -1 — a deliberate overlap, not a bug) was enough real scrollable
   overflow to make a browser using classic (non-overlay) scrollbars paint one: a
   bordered box, split into up/down arrow halves, at the strip's right edge. Invisible
   to every DOM/CSS scan — scrollbars are UA-rendered chrome, not DOM nodes — and
   invisible in this box's own headless Chrome, which defaults to overlay scrollbars;
   reproduced and confirmed only from a real screenshot taken elsewhere. Plain
   overflow:hidden on both axes stops the scrollbar but ALSO clips the active tab's
   overhang, which reopens the hairline under the selected tab — tested and rejected,
   pixel-sampled. overflow-clip-margin lets the 2px tolerance absorb that deliberate
   1px without permitting the FAR larger horizontal tab-overflow this rule exists to
   catch. Verified in a real browser, not assumed, after: no scrollbar at any width,
   the hairline still absent under the active tab and present under the rest
   (pixel-sampled both), and the <=480 horizontal clip and its page-wide fix above both
   still hold (min row-right still 302 at 390). */
.tpl-start .tpl-section-type-select{
    display:flex;
    justify-content:flex-start;
    background:var(--page-bg);
    border-radius:var(--radius-panel) var(--radius-panel) 0 0;
    border-bottom:1px solid var(--color-border-tertiary);
    overflow:clip;
    overflow-clip-margin:2px;
}
.tpl-start .tpl-section-type-tab{
    appearance:none;-webkit-appearance:none;
    flex:0 0 auto;
    margin:0 0 0;
    border:0;
    border-left:1px solid var(--color-border-tertiary);
    background:transparent;
    padding:8px var(--tpl-card-pad);
    font-size:calc((var(--tpl-heading) + var(--tpl-kicker-size)) / 2);
    white-space:nowrap;
    color:var(--tpl-ph-color);
    cursor:pointer;
}
.tpl-start .tpl-section-type-tab:first-child{border-left:0;}
/* The divider between two UNSELECTED tabs is the shared border-left above — suppressed
   on BOTH sides of the selected tab: its own (the divider to its left) and the
   following tab's (the divider to ITS left, i.e. the boundary on the selected tab's
   right), so the selected tab reads as one unbroken shape with no seam either side. */
.tpl-start .tpl-section-type-tab.active,
.tpl-start .tpl-section-type-tab.active + .tpl-section-type-tab{
    border-left-color:transparent;
}
.tpl-start .tpl-section-type-tab.active{
    background:var(--card-bg);
    color:var(--color-text-primary);
    /* Eats the strip's own border-bottom for exactly this tab's width: pulled 1px past
       the strip's content edge, into where that border paints, opaque enough to cover
       it. This is what "joins the card" means in practice — a border cannot be
       conditionally gapped by selector, only painted over. */
    margin-bottom:-1px;
    padding-bottom:9px;
}
.tpl-start .tpl-section-type-tab.active:first-child{border-top-left-radius:10px;}
/* LOCKED: unselected tabs are not rendered at all (a Blade branch in
   _section-type-select.blade.php, not a CSS hide) and the selected type shows as a
   plain label in the strip's position — no tab chrome, no background, no border, no
   hairline to eat because there is nothing else on the strip to divide it from. */
.tpl-start .tpl-section-type-select--locked{
    background:transparent;
    border-bottom:0;
    padding:8px var(--inset-box);
}
/* .tpl-card-heading (Blade) supplies type; ink is already that class's own colour,
   nothing to override here — see TYPE IS BEBAS above. */
.tpl-start .tpl-section-type-locked-label{
    margin-bottom:0;
}
.tpl-start .tpl-section-block:has(> .tpl-section-band){padding:0;}
.tpl-start .tpl-section-band{
    position:relative;
    display:flex;
    /* [HARD] NO align-items HERE (2026-08-21). It said `center`, and DELETING it is what
       puts this header on one line. The band's field is a COLUMN of parts, so centring
       aligned the drag handle, the letter and the ×/▾ cluster on the field's vertical
       middle — which is the gap BETWEEN the name row and the type row, not either of
       them. Hence a cluster floating between two lines, which is what a person saw.

       With this gone the band falls through to `.tpl-edit-row--header{align-items:baseline}`
       in templates.css — the SAME declaration DM's criterion header has always read, and
       DM's field is four parts tall and still puts its handle, letter and cluster on the
       criterion NAME. Baseline takes the field's FIRST baseline, which is the first part's,
       which is why the Blade/JS reorder above and this deletion are one change: the order
       chooses the row, the shared rule aligns to it.

       So MS is not given a matching copy of DM's rule — it stops overriding it. Do not
       re-add an align-items here to nudge something; move the part instead. */
    gap:var(--col-gap);
    margin:0;
    /* ── THE BAND OWNS THE GAP BELOW THE NAME, AND IT IS THE ONLY THING THAT DOES ──
       The distance from the section name's BASELINE to the rust rule was 42px against
       DM's 15px, and it was a sum: 6px of line box below the baseline + 4px of the name
       part's own padding-bottom + 14px here + 18px of panel padding-top (which was
       supposed to be 0 and was not — see the panel rule below). Four contributors, none
       of them owning the number, which is why nobody noticed it drifting.
       Now: the panel's top padding is 0 and the rule has no top offset, so the only two
       terms left are the name field's own 10px, which is intrinsic to the field and the
       same on both shapes, and this. 15 - 10 = 5. The number is READ OFF DM rather than
       chosen — DM's 15px was measured from pixels (both placeholders are Bebas 20 all
       caps, so the lowest text row IS the baseline) and the two shapes now agree to 0px.
       NOT symmetric with the inset above, deliberately: padding-top is the card's top
       inset and padding-bottom is the gap to the rule. Different jobs, so one value
       changing must not drag the other with it. */
    /* ── A CARD HAS ONE CONTENT COLUMN, AND THE BAND IS ON IT ─────────────────────
       [HARD] HORIZONTALLY IT READS --tpl-section-inset (2026-08-20). THIS SUPERSEDES
       "the band is a card heading row, so it sits at the card's inset", which stood here
       and read --tpl-card-pad. That earlier note is deleted rather than kept: it argued
       from where other cards put their HEADINGS, and the thing it produced was a card
       with two content columns — the band 15px wider each side than the panel below it.

       Measured at 1280 before: the band's field block ran 420.19..863.30 while the
       panel's description, comparison question and item rows all ran 435.19..822.81, so
       the section name's rule was 15px longer at each end than every rule beneath it and
       the band's control lane stood at 873.30 against the item rows' 832.81. Two lanes,
       two rule lengths, one card.

       DM IS THE REFERENCE AND DM HAS ONE INSET: its criterion card's heading row and its
       body rows share a single content column, which is why its three rules and its lane
       agree without anything being restated. A 15px difference between a heading's inset
       and a body's is a distinction only this card was drawing.

       CONSEQUENCE, ACCEPTED DELIBERATELY: the section card's badge and drag handle move
       15px right, onto the same column as the item letters below them. That is what the
       old note called "the item-letter column instead of the card-badge column" — and it
       is what DM does, where the criterion badge and the item badges share an x. One
       column means one column for everything on it, not for the rules alone.
       Its top padding is the card's inset for the same reason: a card has ONE inset.

       [HARD] THE 5px BOTTOM IS DELETED (2026-08-20) AND THE WHOLE NOTE ABOVE IT IS
       HISTORY, not instruction. It was "the gap to the rule" — computed as 15 − 10 to
       match DM — and it existed because the rule was somewhere else: a ::before on the
       PANEL below, so the space between the name and its line had to be built out of
       the band's padding and the panel's. The rule is the NAME FIELD'S OWN border now,
       exactly as it is on DM's criterion name and on every other field on this surface,
       so the field and its line share an edge by construction and there is no gap left
       here to own. What used to be below the rule is below it still — it belongs to the
       PANEL, which states it once as --stack-gap.

       [HARD] THE TOP TERM ABSORBS --step-group NOW (2026-08-29), FOR THE SAME REASON
       --step-lift EXISTS: flex gap and padding ADD. .tpl-section-block is one of THE
       THREE STEPS' GROUP containers (`row-gap:var(--step-group)`, templates.css), which
       makes no difference while the band is the card's first child — row-gap has
       nothing before the first child to apply to. It stopped being the first child when
       THE SECTION TYPE STRIP took that slot (a sibling BEFORE the band, both gated on
       the same $_msHeaderBox, so they always co-occur): row-gap now ALSO fires between
       the strip and the band, and this padding was still contributing the full card
       inset on top of it. Measured before fixing: strip hairline to band's own top
       edge was --step-group (16px, not a token value anyone chose to add — the flex
       gap, unrequested), then this padding added its full --tpl-card-pad on top,
       40px total against the 24px the inset has always meant. Per THE STEP IS THE
       ENTIRE DISTANCE above: held space at a junction the step now governs is absorbed,
       not left to add to it. `calc(var(--tpl-card-pad) - var(--step-group))` — not a
       new number, the existing inset minus the newly-arrived step, so the total from
       the strip's hairline to the band's content stays exactly what it was when the
       band alone supplied it. Verified in a real browser: strip-hairline-to-badge
       measured 31.5px both before the strip existed (card-top-to-badge, band flush at
       the card edge) and after this fix (strip-hairline-to-badge, band offset by the
       row-gap and this reduced padding) — same number, not assumed equal. */
    padding:calc(var(--tpl-card-pad) - var(--step-group)) var(--tpl-section-inset-r) 0 var(--tpl-section-inset-l);
}
/* ── THE RULE ─────────────────────────────────────────────────────────────────────
   The band is no longer a tinted bar — it is the card's own surface with a 2px rust
   rule under it. THE TINT AND BOTH RADII ARE DELETED, not made transparent: with no
   background the `10px 10px 0 0` painted nothing, and the collapsed-state
   `border-radius:10px` that re-closed the card's bottom corners had nothing left to
   close, so both went with it.

   [HARD] THE RULE IS A NORMAL-FLOW CHILD OF THE PANEL, AND IT HAS TO BE.
   --tpl-section-col-l / -r are the content column, and the Compare arm of that pair is
   `calc(100% - var(--col-line-x) - var(--col-line-width))` — "whatever the line leaves".
   A percentage in a MARGIN resolves against the containing block's width, so those
   properties are only correct on a normal-flow child of the panel, whose containing
   block IS the panel's content box. Position it absolutely — on the band or on the panel
   — and the same expression resolves against the PADDING box instead and comes out wrong
   by --tpl-section-inset on the left and 2x it on the right. Measured that trap rather
   than reasoned past it: the rule would have sat 37px left of the rows it is supposed to
   agree with. So no third value is derived, and the properties are read where they mean
   what they say.

   The panel's block-start padding moves onto the rule's own margin-bottom rather than
   being cancelled by a negative margin: the rule sits ON the band/panel boundary and
   still leaves the same 18px above the description, with no compensating arithmetic and
   nothing to keep in sync. The selector guarantees it only exists where a band does. */
/* [HARD] THE PANEL'S BLOCK-START PADDING IS ZERO, AND IT IS STATED IN THE SHORTHAND.
   It used to be a standalone `padding-block-start:0` declared here, ABOVE the
   `padding:18px var(--tpl-section-inset)` shorthand further down. Same selector, same
   specificity, shorthand later — so the shorthand reset it to 18px and the longhand had
   never once applied. The comment above described a card that did not exist: the panel
   was carrying 18px of top padding AND the rule was carrying 18px of margin-bottom, and
   the gap between the section name and the rust rule was the sum of that, the band's
   14px padding-bottom and the name field's own 4px.
   Merged into the one shorthand below rather than reordered, so there is no longhand
   sitting next to a shorthand that could swallow it again. */
/* MS's section rule reads the SAME THREE TOKENS as .tpl-rust-rule without being that
   class, and that is deliberate rather than an omission: it is a normal-flow ::before
   bar, not a border, because it carries `margin-bottom:var(--stack-gap)` — the 14px
   between it and the description below. Turning it into a border-bottom on the band
   would collapse that gap and move the whole card body up. Same colour, same weight,
   same "done" ink, one mechanism each. */
/* ── THE RULE IS THE NAME'S OWN BORDER NOW — THE ::before IS DELETED (2026-08-20) ──
   It read `content:''; height:--tpl-rule-weight; background:--tpl-rule-color; margin:0
   --tpl-section-col-r --stack-gap --tpl-section-col-l` on the PANEL that follows the
   band, and it was the last place on the setup surface where a field's line belonged to
   a different element.

   WHY THAT MATTERED, measured rather than argued: a census of all 22 authorable fields on
   DM, MS, flat and survey found 21 sitting on their own rule at exactly 0.00px and this
   one with no rule to sit on — so setup:badge-probe's resting field-to-rule assertion had
   to SKIP it, and reported the skip by name. A skipped field is a hole in a census; this
   closes it and the probe now asserts all 22.

   IT ALSO MADE THE GAP UNFIXABLE FROM THE FIELD. The distance from the name to its line
   was built out of the band's padding-bottom and this margin — two elements neither of
   which is the field — which is why trimming the name part's own padding moved the name
   toward a line it did not own instead of closing anything.

   The name part carries .tpl-rust-rule in the markup instead (Blade AND the JS builder),
   which is the one class every rust underline on this surface already reads, so the
   weight and the colour come from --tpl-rule-weight / --tpl-rule-color with nothing
   restated. The horizontal span the margin used to set is the PART's own width, which is
   the section's content column by construction — one fewer expression, same edges.

   WHAT MOVED, AND WHAT DID NOT: the rule rises 9px, from below the band's 5px padding to
   the name field's own bottom edge. Everything BELOW it is unchanged, because the 24px
   this margin carried moves to the panel's padding-top — same role (the rule is an
   object, the description is the next one), same token, stated once. Before/after in the
   commit message. */
/* DELETED: `border-radius:10px` — do not re-add; the reason is T50 in the decision record. */
.tpl-start .tpl-section-band + .tpl-flat-subcard{
    /* Bottom is the CARD's inset — the same number the band's top is, and the same one
       every other card's bottom is. It was an 18px literal, which was the old card-gap
       number, moved here wholesale when the panel's top padding went to zero and never
       re-read as a card inset in its own right.

       TOP IS --stack-gap SINCE 2026-08-20, and it was 0. It is the gap between the rust
       rule at the band's foot and the description below it — the distance the deleted
       ::before carried as its own margin-bottom, in the same token, for the same stated
       reason (the rule is an object on this surface and the description is the next one).
       Nothing about the distance changes; what changes is that the element the gap is
       INSIDE now owns it, instead of a pseudo-element that no longer exists.
       Stated in this shorthand rather than as a second rule for the same selector — two
       declarations for one element is how a later shorthand silently wins. */
    /* BOTH ends restored 2026-08-27. This is the MS section body panel — the same
       .tpl-flat-subcard box, so the same CATEGORY 2 positioning inset, and
       setup:well-probe pins it at 24px/25px. Zeroing the top made the band-to-
       description junction read the step alone and moved every question row on the
       card with it. The bottom was always the card's own inset. */
    padding:var(--stack-gap) var(--tpl-section-inset-r) var(--tpl-card-pad) var(--tpl-section-inset-l);
    border-width:0;
}
/* ── THE NAME FIELD'S RIGHT RESERVE ───────────────────────────────────────────────
   The name box is elastic (it was a fixed --col-line-width when it owned the row), and
   capped so its right edge stops short of the centred pill. 50% resolves against the
   band's CONTENT box, whose centre is the card's centre because the band's padding is
   symmetric — so this cap is measured from the same midpoint the pill is centred on,
   not from an approximation of it. --col-line-x comes off because the box starts one
   rail column in, after the drag handle and the letter. */
/* ── THE BAND'S NAME BOX AND ITS LANE JOIN THE CARD'S ONE COLUMN (2026-08-20) ─────
   TWO RULES ARE DELETED HERE, NOT OVERRIDDEN, and both existed to let the band size
   itself differently from every row beneath it:

     .tpl-section-band > .tpl-edit-field{flex:1 1 auto;width:auto;min-width:0;}
     .tpl-section-band > .tpl-row-controls{margin-left:auto;flex:0 0 auto;}

   The first let the name box STRETCH to whatever was left after the cluster, so its rule
   ran to 863.30 while the description, the comparison question and every item row below
   it stopped at 822.81. The second put the cluster on the card's content edge with
   margin-left:auto — its own note said "the band has no fourth column" — which is
   precisely the fourth column every other row on this card has, so the band's ×/▾ stood
   at 873.30 against the item rows' 832.81.

   The band's field now takes --col-line-width from the SAME declaration MS's other
   header rows and DM's criterion row read (the :not(.tpl-section-band) that excluded it
   is deleted with these), and its cluster follows the field on the band's own
   gap:var(--col-gap) exactly as DM's does. Nothing is restated: the band stopped being an
   exception instead of being given a matching copy of the rule. */
/* DELETED: `align-self:flex-start` — do not re-add; the reason is T51 in the decision record. */
/* ── THE TYPE PILL IS A NORMAL FLEX ITEM, AND ITS RULE HERE IS DELETED ────────────
   `.tpl-start .tpl-section-band > .tpl-section-type-select` IS DELETED 2026-08-21, with
   the lane note that sat under it. It sized the chip while the chip was a DIRECT CHILD of
   the band — a shape that ended on 2026-08-20, after which the child combinator matched
   nothing; measured at 0 elements on this branch and its parent, at 1280 and 390, before
   removal. The chip went inside the NAME part next and took its layout from
   `.tpl-start .qt-name-row > .qt-type-col` in question-types.js — since deleted too
   (2026-08-29), with the class's last consumer: the section type control is a full-bleed
   tab strip now, no chip, no name-part placement at all. See THE SECTION TYPE STRIP.

   [HARD] THE PARAGRAPH BELOW SURVIVES THE RULE, BECAUSE IT IS ABOUT THE CHIP, NOT ABOUT
   THIS SELECTOR. The absolute centring this rule replaced had a
   `transform:translate(-50%,-50%)` form that made the chip a STACKING CONTEXT, which
   trapped the .qt-popover's z-index:100 inside it: the whole subtree painted at the
   context's own z-index (auto) in DOM order, the band precedes the body panel, and two of
   the menu's four options could not be clicked — they returned .tpl-crit-part--desc and its
   textarea from elementFromPoint (cfe85708). An in-flow chip creates no context at all, so
   the failure mode is gone with the mechanism rather than guarded against.

   NOTHING may reintroduce transform, opacity below 1, or filter on the chip or ANY of its
   ancestors — and its ancestors changed on 2026-08-21, so the chain to re-check is now
   .qt-type-col → .tpl-crit-part--card-name → .tpl-crit-pair--name → .tpl-edit-field →
   .tpl-section-band → the card. The standing guard is elementFromPoint on every option in
   every section mode, not visibility and not the overflow chain. */
/* ── THE DESCRIPTION MEETS THE QUESTION LINE ──────────────────────────────────────
   Requirement: the description box's left and right edges equal the edges of the WHITE
   SURFACE a question is typed into. Both margins are that row's own box model re-expressed
   from this side of it, because (d) forbids touching the row itself:

     left   = wrap border 1 + wrap padding 12 + --col-line-x
     right  = --col-gap + the ×/⧉/▸ cluster + wrap padding 12 + wrap border 1

   [HARD] THE ANCHOR IS .qt-input-col, NOT THE <input> INSIDE IT. A question field is two
   nested white boxes: .qt-input-col paints rgb(255,255,255) and .tpl-inline-edit > input
   paints rgb(255,255,255) 12px inside it. The input therefore has NO RENDERED EDGE — it is
   white on white — and aligning to it puts this box 12px inside the only boundary a person
   can see, which reads as a misalignment rather than as an alignment. Measured both ways
   at 1280/640/480/430/390: anchored to the input, this box sits +12/-12 from the visible
   surface and its text +13/-13 from the question text; anchored to .qt-input-col, the
   surfaces agree exactly and the two texts agree within 1px — that 1px being this box's own
   border, which .qt-input-col does not have. Do not "fix" the 1px by shifting the box; it
   is the difference between a bordered field and an unbordered one.

   The 13px in each margin is the two literals (border 1 + padding 12) that the question
   row carries and this card cannot read. Everything else is a shared token, so both margins
   track the <=640 column block automatically.

   [HARD] --tpl-qrow-ctrl-w IS A MIRROR OF A RENDERED WIDTH, and it is the one number here
   that can drift. IT IS NOW READ AT <=640 ONLY (2026-08-20): at >=641 a question row sits
   on --col-line-width like every other row and this value has no consumer there. What it
   still mirrors, and where, is at THE SECTION'S CONTENT COLUMN below. It is a question row's .tpl-row-controls: × 10.516 + ⧉ 12 + ▸ 30 + two
   8px gaps = 68.516 measured. ADD OR REMOVE A CONTROL FROM A QUESTION ROW AND THIS GOES
   WRONG BY ~20px. It is a constant rather than a shared property on purpose and under
   protest: making the question row read a width token would mean a new selector matching
   inside a question row, which this task is forbidden to do. If that constraint is ever
   lifted, put the width on .tpl-row-controls and delete this term.
   It is PINNED AT 68.5, not 68.516, because 58 of it is geometric (⧉'s 12, ▸'s min-width
   30, two 8px gaps) and 10.516 is the × glyph's advance in the UA DEFAULT BUTTON FONT —
   the button sets no family, so this is not one of the three webfonts and does NOT move
   when they fail to load (checked: document.fonts reports all three loaded and the button
   still computes Arial). It moves only under platform font substitution, by tenths. Half a
   pixel is where the glyph rounds onto the device grid; a stable literal 0.016px from the
   truth here beats three decimal places of somebody else's font metrics.
   NOT LEFT TO A COMMENT: `php artisan setup:desc-align` (in the deploy gate) drives a real
   browser at 1280 and 390 and asserts both edges agree within 0.5px. Falsified twice before
   being trusted — a fourth control on a question row fails it by 20.016px, and mis-pinning
   this value by half a pixel fails it by 0.516px.

   THE GUTTER TO THE RIGHT IS INTENTIONAL. ~90px of empty card beside the description is
   the column the question rows' controls occupy, reserved down the whole card. */
.tpl-start{--tpl-qrow-ctrl-w:68.5px;}
/* ── THE SECTION'S CONTENT COLUMN ─────────────────────────────────────────────────
   ONE RULE: the description sits on the section's content column. It is a PAIR OF INSETS
   on the card, not a per-mode rule on the description, because the sentence has one
   subject and the column has two values — different facts, expressed separately. The
   description below reads the pair and knows nothing about section types.

   [HARD] THE TWO VALUES ARE A DEFECT, NOT A DESIGN (D-MS-COLUMN). Every row a section
   renders is supposed to sit on --col-line-x with width --col-line-width. The
   comparison-question card, the item rows, "+ Add Item" and the end-of-section toggle all
   do. A QUESTION ROW DOES NOT: [data-question-wrap] applies its own 1px border + 12px
   padding BEFORE the shared token, and its right edge is bounded by its ×/⧉/▸ cluster
   rather than by --col-right. Measured at 1280, panel content 250.50..1014.50:

       Items mode / Images mode           312.50 .. 932.50   (w 620.00)
       Questions / Quiz                   325.50 .. 922.98   (w 597.48)

   — 13.00px apart on the left, 9.52px on the right. Fixing THAT is what makes this one
   value, and it is the only thing that would; it is not fixed here because it moves the
   shared question component for every shape.

   SO WRITE IT SO THE COLLAPSE IS ONE EDIT. When the question row rejoins the column, the
   questions/quiz block below is DELETED and nothing else changes — not the description's
   rule, not the property names, not the consumer.

   The Compare pair carries NO literal. `100% - line-x - line-width` is "whatever the line
   leaves", exact in both column regimes: at >=889 --col-line-width is a fixed 620 and this
   is the leftover 82px; at <=640 --col-line-width is itself `100% - --col-line-x -
   --col-right`, so the 100%s cancel and it is --col-right exactly. One expression, no
   breakpoint arm, verified by measurement at 1280/640 rather than by trusting the algebra.

   The default is on the bare .tpl-section-block, not on [data-section-mode]: that
   attribute is written by _applySectionMode at runtime, and a card must be on its column
   in the server-rendered frame before any JS has run.

   [HARD] THESE TWO PROPERTIES ARE ONLY CORRECT IN NORMAL FLOW. --tpl-section-col-r's
   Compare arm contains a PERCENTAGE, and a percentage inside a custom property is not
   resolved where the property is declared — it is resolved AT THE POINT OF USE, against
   whatever containing block the consumer has. As a MARGIN on a normal-flow child of the
   panel that containing block is the panel's CONTENT box, which is the content column,
   which is what these mean.

   Use them on anything POSITIONED and they silently mean something else: an absolutely
   positioned consumer resolves against the PADDING box, so the value comes out
   --tpl-section-inset too small on the left and twice that on the right — 37px and 74px
   at 1280. That is not fixed by hanging the properties on a common ancestor; ancestry is
   not the variable, FLOW is. The band's rust rule hit exactly this and is a normal-flow
   ::before on the panel for that reason, not for tidiness. If you need this column on a
   positioned element, give it a normal-flow box to sit in rather than deriving a third
   value. */
.tpl-start .tpl-section-block{
    --tpl-section-col-l:var(--col-line-x);
    --tpl-section-col-r:calc(100% - var(--col-line-x) - var(--col-line-width));
}
/* ── THE questions/quiz ARM IS HALF DELETED, AND THE HALF THAT REMAINS IS A DIFFERENT
   FACT FROM THE ONE THAT WENT (2026-08-20) ──────────────────────────────────────────
   The note above said the collapse would be one edit. It was, at >=641: the underline
   convergence removed [data-question-wrap]'s own 1px border and 12px padding and gave
   .qt-card `width:var(--col-line-width)` — the same D-COLUMNS token the item rows and the
   comparison question read — so a question row IS on the column there. Measured by
   setup:desc-align at 1280: 4 modes x 2 counts, 12 edge assertions, all within 0.5px,
   where before the two columns were 13.00px apart on the left and 9.52px on the right.
   BOTH insets are gone; there is no `13px +` term left in this block.

   WHAT REMAINS IS NOT THAT DEFECT. --col-right is the reserve at the END of every line,
   and its <=640 value is 34px, described at its own declaration as "room for the trailing
   x". A QUESTION row's trailing cluster is x + dup + chevron — 69px measured, at BOTH
   widths, because the chevron carries a 30px min-width touch target that does not shrink.
   At >=641 the reserve is 84px and the cluster fits inside it; at <=640 it does not, so
   the flex row takes the difference off the card and a question line really is ~40px
   shorter than every other line on the section. The description tracks what is there.

   TWO ROUTES WERE MEASURED AND BOTH ARE WORSE. Raising --col-right at <=640 to fit the
   widest cluster shortens EVERY line on a phone by 35px — including item rows whose only
   trailing control is an 11px x, which would then carry 23px of dead lane. Letting the
   card keep the full column instead pushes the cluster 41px past the card's own edge.
   The remaining arm is the cheapest true statement of the situation.

   SO THE COLLAPSE IS STILL ONE EDIT, at a different file: give the trailing cluster a
   width the <=640 reserve can hold — or give that reserve the cluster's width without
   charging every other row for it — and this block goes with --tpl-qrow-ctrl-w.

   RE-TESTED 2026-08-20, after the question block became DM's criterion block: removed,
   setup:desc-align fails at 390 by the SAME 40.516px on all four question/quiz states.
   The restructure changed what the description anchors to (the block's own .tpl-crit-pair
   now, not a white .qt-input-col) and did not change this: the cluster is still 69px
   against a 34px reserve. Kept on evidence rather than on inheritance. */
/* DELETED: THE <=640 QUESTION-COLUMN ARM — do not re-add; the reason is T52 in the decision record. */
.tpl-start .tpl-section-desc{
    margin-left:var(--tpl-section-col-l);
    margin-right:var(--tpl-section-col-r);
    /* THIS BOX OWNS THE GAP TO THE COMPARISON QUESTION, AND IT IS THE ONLY THING THAT
       DOES. The gap used to be held twice — 10px here against the prompt wrap's own
       8px margin-top — and rendered 10 because adjacent margins collapse to the larger,
       so neither value was the number on screen and changing either one alone did
       nothing. The wrap's margin-top is zeroed in MS scope (see THE PROMPT WRAP'S TOP
       MARGIN below) and this is the single owner. */
    /* ── FIELD GROUP → FIELD GROUP, ONE STEP TIGHTER THAN CARD-LEVEL SIBLINGS ──
       --space-md (16px), not --stack-gap (24px, == --space-lg). It is the next value DOWN
       the scale tokens.css already declares, not a fourth number: --stack-gap IS
       --space-lg, so "one step tighter" has exactly one answer.

       WHY THERE ARE TWO ROLES HERE AND NOT ONE. --stack-gap means "two separate OBJECTS
       on a card's content surface" — a field and a list, a list and its adder, a row and
       the next row. A description and the question under it are not two objects a person
       is choosing between; they are two fields of one thing, read in order, and the
       distance says so. The gap BELOW the pair — to the items list — stays --stack-gap
       for the same reason: that really is the next object.

       STRUCTURAL, NOT PER-ELEMENT: this is the same single-owner declaration the note
       above argues for, with a different value. Nothing gains a margin of its own.
       Asserted by setup:spacing-probe, which now carries a 'group' role beside 'stack'
       and reads BOTH tokens off the page, so neither can move without the other noticing. */
    /* DELETED: `margin-bottom:--space-md` — do not re-add; the reason is T53 in the decision record. */
    margin-bottom:0;
}
/* ── <=640: THE BAND STACKS ───────────────────────────────────────────────────────
   THE CHIP STILL DROPS TO A ROW OF ITS OWN ON A PHONE, and that survives the move that
   put it inside the name part — the arm is re-expressed against its new position rather
   than deleted. Deleting it was tried and MEASURED at 390, twice, and both outcomes were
   worse than what it replaced:

     chip on the name's line, band wrapping   the card's badge orphaned on a line of its
                                              own and the name still cut to "INSERT
                                              SECTIO…" (flex:1 1 0 and min-width:0 down
                                              the whole chain did not change a pixel)
     chip on the name's line, band nowrap     everything on one line and the name crushed
                                              to "IN…"

   The chip is ~130px of fixed, unshrinkable control; a 390px phone does not have room for
   it beside a name worth reading. So the reflow is a real accommodation, not a leftover.

   WHAT DID CHANGE is which element wraps. The chip used to be a child of the BAND with
   `flex:0 0 100%`, so it took a band row below the name AND the controls. It is a child of
   the name PART now, so the PART wraps and the chip takes a line inside it — under the
   name, above the part's own rust rule. The rule therefore spans the part at every width,
   which is the point of the move; on a phone it simply has two lines above it instead of
   one. At >=641 nothing here applies and the chip sits on the name's line. */
@media(max-width:640px){
    /* DELETED: THE HEADER-COLUMN STACK — do not re-add; the reason is T54 in the decision record. */
    /* Every pair stacks — see A PAIRED FIELD ROW for why MIN/MAX stacks too. */
    .tpl-start .qt-pair-row{flex-direction:column;row-gap:var(--space-md);}
    .tpl-start .tpl-section-band{flex-wrap:wrap;}
    .tpl-start .tpl-section-band > .tpl-edit-field{max-width:none;}
    .tpl-start .tpl-section-band > .tpl-row-controls{order:2;}
    /* DELETED: `.tpl-crit-part--card-name{flex-wrap:wrap}` — do not re-add; the reason is T55 in the decision record. */
}}
/* ── .tpl-header-toggle-row — DELETED 2026-08-02, with its three rules ───────────
   It was the in-header strip that held the section checkboxes: a divider bled
   full-card-width by widening the label 300px each side (width:calc(100% + 600px) +
   margin-left:-300px + matching padding), clipped back by overflow-x on the header well.

   Both its occupants have left. The Section Description checkbox was deleted when the
   description became permanent; the End of Section Comment checkbox moved to the BOTTOM
   of the card, where it belongs. What remained was the defect: _applySectionMode hides
   the LABEL in Questions/Quiz mode but never the row, so the row rendered childless —
   an 11px grey band under a divider line (measured: visKids 0/1, h=11px, borderTop 1px).
   Deleting the wrapper is what clears it; a display rule keyed on "no visible children"
   would have been a workaround for markup that should not exist.

   (THE `.tpl-start:has(#tpl-add-section-btn) .tpl-section-block .tpl-section-end-toggle`
   RULE IS DELETED 2026-08-31, WITH THE THREE PARAGRAPHS THAT DESCRIBED IT. It set
   `margin-left:var(--col-line-x);width:fit-content` and matched NOTHING: the control's
   class is `.tpl-end-toggle`, emitted by _endToggleHtml() and by
   templates/_end-question-toggle.blade.php, and `.tpl-section-end-toggle` appears in no
   markup anywhere in the tree — only here, and in one row of the 2026-08-23 audit's class
   inventory. Its prose read as the live account of where this control's left edge comes
   from ("--col-line-x is the SAME token the '+ ADD ITEMS' and items-header rules read for
   exactly this"), which is the sentence that sent this session to the wrong rule first:
   the live owner is `.tpl-start .tpl-end-toggle{padding-left:...}` above, and it says the
   same thing where it is true. A dead rule describing itself accurately is worse than no
   rule, because it reads as certain.) */
/* The per-criterion "Customize Weighting" checkbox reuses the .qt-subcard-toggle
   look but NOT the description divider / bleed / collapse-hide above — it sits tight
   under the name like the old weight badge and stays visible on collapse. */
.tpl-start .tpl-weighting-enable{margin-top:0;}
/* Weighting row: the "Customise Weighting" checkbox (left) + the stepper (right). The
   stepper only shows when the (global) Customise Weighting checkbox is on — CSS :has so
   no JS toggle needed. margin-top matches the divider-to-description gap for balance. */
.tpl-start .tpl-weight-row{display:flex;align-items:center;justify-content:space-between;gap:var(--gap-row);flex-wrap:wrap;}
/* DELETED: `.tpl-start:has(#tpl-add-criterion-btn) .tpl-weight-row` — do not re-add; the reason is T56 in the decision record. */
.tpl-start .tpl-weight-row-toggles{display:flex;align-items:center;gap:var(--inset-panel);flex-wrap:wrap;}
.tpl-start .tpl-weight-row-toggles > .qt-subcard-toggle{margin-top:0;}
/* "CUSTOMISE WEIGHTING" steps up a type tier: --tpl-toggle-label (9px) to --tpl-field-label
   (12px). READ, not chosen — 12px is the tier the Total Weighting strip's own label already
   uses, so the two weighting labels on this card now match instead of being three px apart.
   SCOPED to .tpl-weighting-enable: .tpl-workshop-mode-label is shared with the workshop-mode
   toggle and the slide-view controls, and resizing the class would take all of them with it. */
/* DELETED: `.tpl-weighting-enable .tpl-workshop-mode-label` — do not re-add; the reason is T57 in the decision record. */
/* Stepper is ALWAYS visible. Default = locked/ghosted (unchecked = equal split); the
   :has(:checked) overrides wake it to the live state (ink border, editable, working +/−).
   Inertness is enforced in JS (disabled input + no-op handlers); this is the look. */
.tpl-start .tpl-weight-stepper{display:inline-flex;align-items:stretch;border:1px solid var(--color-border);flex-shrink:0;}
/* ── THE INKED STATE, RE-KEYED AND RE-SCOPED ────────────────────────────────
   These four rules are the stepper's "live" half: ink border, ink digits, ink %,
   real cursors. They were written as
     .tpl-weight-row:has(.tpl-weighting-enable-cb:checked) <stepper descendant>
   and syncWeightPanel() MOVES the stepper out of .tpl-weight-row into
   #tpl-sidebar-weight-rows — so the descendant half stopped matching and the
   stepper has rendered in its OFF palette (--color-border, --grey) in every state
   since the rail shipped, including while weighting is on.

   [HARD] THIS CORRECTS THE NOTE IN setup-sidebar.css THAT SAYS THEY STILL MATCH.
   Its reasoning is half right: the per-criterion checkboxes ARE still in the DOM
   and still synced, so the :has() subject resolves. What it missed is that the
   ELEMENT BEING STYLED left the row, which is the other half of a descendant
   selector.

   The gate is re-keyed to #tpl-weighting-toggle, which is what the rail actually
   drives and what the panel's own reveal already uses — one boolean, not a second
   copy of it. Two IDs give (2,1,0), which is specificity on merit rather than a
   pile of classes.

   [KNOWN] THE GHOSTED HALF IS NOW UNREACHABLE, and that is the panel's doing, not
   this rule's: #tpl-sidebar-weight-panel is display:none unless the same toggle is
   checked, so a visible stepper is always a live one. The condition is kept rather
   than dropped because it states the intent and costs nothing; it simply cannot go
   false while the stepper is on screen. */
.tpl-start #tpl-start-form:has(#tpl-weighting-toggle:checked) #tpl-sidebar-weight-rows .tpl-weight-stepper{border-color:var(--border-strong);}
.tpl-start .tpl-weight-step{border:none;background:none;font-family:var(--font-mono);font-size:var(--type-field);color:var(--grey-ghost);width:26px;cursor:default;line-height:var(--type-field-line);padding:0;display:flex;align-items:center;justify-content:center;}
.tpl-start #tpl-start-form:has(#tpl-weighting-toggle:checked) #tpl-sidebar-weight-rows .tpl-weight-step{color:var(--color-text-primary);cursor:pointer;}
.tpl-start .tpl-weight-step:disabled{cursor:default;}
/* [HARD] 26px IS .tpl-weight-step's OWN WIDTH, read off the cell beside it rather
   than picked — the three cells of the stepper are one width now. It fits because
   the 6px left padding goes with it: the widest value is "100", which at DM Mono
   --tpl-field-label (12px, 0.6em advance) measures 21.6px, and 26 - 1px border -
   1px + 1px padding leaves 23px. The -/+ cells are NOT touched: they are the hit
   targets, already only 26px, and trimming them is what the reduction must not do. */
.tpl-start .tpl-weight-step-input{width:26px;text-align:right;border:none;border-left:1px solid var(--color-border);font-size:var(--tpl-field-label);color:var(--grey);background:var(--color-white);padding:5px 1px;-moz-appearance:textfield;appearance:textfield;box-sizing:border-box;cursor:default;}
/* "%" suffix — carries the value cell's right border so [ − | 34% | + ] reads as one cell. */
/* THE INNER PADDING IS ONE DECLARATION, SHARED WITH THE TOTAL'S FIGURE.
   The total row was aligned to this cell's BOX edge, but the box carries 6px of
   right padding, so its "%" stops 6px short of it — measured, the two glyphs' right
   edges sat 8px apart. Split the padding out and hand it to the figure and the two
   cells are inset by the SAME declaration, so the glyphs land together because they
   share a source rather than because a number was tuned.

   [HARD] 2px OF THE 8px IS TWO BORDERS AND IS LEFT ALONE. `border-right:1px` on
   this cell (the divider before the +) and `border:1px` on .tpl-weight-stepper both
   sit inside the stepper and have no counterpart in the total row, which draws no
   box at all. Closing them would mean a transparent border placed by hand — a nudge
   wearing a border's clothes. */
.tpl-start .tpl-weight-step-pct,
.tpl-start .tpl-weight-strip-status{padding:0 6px 0 1px;}
.tpl-start .tpl-weight-step-pct{display:flex;align-items:center;border-right:1px solid var(--color-border);font-size:var(--type-caption);color:var(--grey);background:var(--color-white);}
.tpl-start #tpl-start-form:has(#tpl-weighting-toggle:checked) #tpl-sidebar-weight-rows .tpl-weight-step-input{color:var(--color-text-primary);border-left-color:var(--border-strong);cursor:text;}
.tpl-start #tpl-start-form:has(#tpl-weighting-toggle:checked) #tpl-sidebar-weight-rows .tpl-weight-step-pct{color:var(--color-text-primary);border-right-color:var(--border-strong);}
.tpl-start .tpl-weight-step-input::-webkit-outer-spin-button,.tpl-start .tpl-weight-step-input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0;}
/* ── DM weighting stepper — MOBILE ONLY (desktop keeps its current size / value font
   / always-visible ghosted-when-unchecked state, all defined above, untouched). DM
   only: the stepper renders only in the non-itemsPerSection (DM) branch; MS has no weighting. */
@media(max-width:640px){
    /* (a) Shorter + wider — a proper horizontal stepper. Height is driven by the value
       input's vertical padding (5px→3px); width by the −/+ cells (26→40) and the value
       cell (30→44). The −/+ glyph size + clamp/validation behaviour are untouched. */
    .tpl-start .tpl-weight-step{width:40px;}
    .tpl-start .tpl-weight-step-input{width:44px;padding-top:3px;padding-bottom:3px;}
    /* DELETED: `#tpl-sidebar-weight-rows input.tpl-weight-step-input` — do not re-add; the reason is T58 in the decision record. */
    .tpl-start .tpl-weight-step-pct{font-size:var(--tpl-input-size);}
    /* DELETED: `#tpl-sidebar-weight-panel{display:none}` — do not re-add; the reason is T59 in the decision record. */
}
/* Total weighting strip — ALWAYS rendered after the last criterion card. Default = muted
   (unchecked / equal split: transparent bg, soft border, grey text). JS toggles .is-on
   when Customise Weighting is on → the live ink bar (Balanced green / dark-red warning). */
/* Left label ("TOTAL WEIGHTING") aligns UNDER the + Add Criteria button: padding-left 10px
   matches that button's padding-left (both boxes at the card content-left with a 1px border),
   so the label's text lines up with the button's "+". The bar stays full-width and the % status
   stays at the right edge (space-between). */
/* THE BORDER IS 2px, AND THE BOX CARRIES THE CARD SURFACE.
   The colour is rgba(var(--ink-rgb),0.10) — an alpha built from an existing token, the same
   expression .sc-crit-card and .dm-winner draw their borders with, NOT a new token. It
   replaced --color-border-tertiary, which computes only 12 units of darkening on the page
   and was reported as not rendering; this is 21. At 2px it reads as a deliberate boundary
   rather than a hairline that has to be looked for.
   background-COLOR:var(--card-bg), never the `background` shorthand — the shorthand would
   wipe a background-IMAGE, which is how the ring/tick slot is drawn on every field on this
   page. The strip had `transparent` and therefore the PAGE behind it ever since the criteria
   wrapper was deleted and it stopped sitting on a card; this gives it the card surface back,
   so it reads as an object rather than as a line drawn on the background.
   THE RADIUS IS READ, NOT ASSUMED: 4px is .tpl-crit-pair's, the field family this strip now
   shares a column with.
   THE GAP ABOVE IS --stack-gap — two separate objects on the surface — and it is owned HERE
   rather than by the wrapper, whose card margins are zeroed below so the two cannot stack. */
/* THE STRIP NO LONGER PAINTS ANYTHING. Its background, border and radius moved to
   .tpl-weight-strip-card below, which is a .tpl-form-card and therefore ALREADY the
   criterion cards' width — same left, same right, by construction rather than by an edge
   anyone had to compute. Widening this element instead would have meant a padding-left of
   card-border + card-padding + row-border + row-padding + --col-line-x + its own 10px, i.e.
   restating the whole inset chain as one number; moving the paint outward keeps the chain
   doing its existing job and moves nothing.
   ITS PADDING AND POSITION ARE UNTOUCHED, which is what keeps the CONTENT where it was: the
   text still sits in .tpl-edit-field at --col-line-x, and this padding still offsets it from
   there. The strip is now purely the content's box.
   Its type declarations are gone too — both children carry the shared treatment below. */
/* ── THE TOTAL ROW ──────────────────────────────────────────────────────────
   Label left, figure right, one hairline above it — the rail's own row shape.
   The hairline is at INK weight, which is this component's own existing
   declaration: .tpl-weight-stepper draws `1px solid var(--color-border)` and
   flips to `var(--ink)` when weighting is on, so a full-ink 1px rule is already
   what this panel uses to say "live". Padding is the rail row's `8px 0`. */
/* NO `gap`. It was .tpl-sidebar-row's 10px, copied in when this row was built, and
   it is what held the figure 9px short of the column above: the figure has to ABUT
   the badge column for its right edge to land on the % cell's. The label's
   flex:1 is what separates them now — the same job .tpl-wp-name does one row up —
   so the separation is still declared, just not as a fixed gap. */
.tpl-start .tpl-weight-strip{display:flex;align-items:center;justify-content:space-between;padding:var(--inset-control) 0;margin:0;border-top:1px solid var(--border-strong);}
/* The two chrome-stripped wrappers. They exist ONLY to reproduce the inset chain a field
   sits behind — card band + card padding, then header border + header padding — so the
   column tokens below resolve against the same containing block they do on a criterion
   card. Neither may paint anything, and the card's vertical margins go to zero so the gap
   above the strip has exactly one owner — the WRAPPER's margin-top, below.

   [HARD] THE GAP ABOVE HAD THREE CONTRIBUTORS AND MEASURED 46px. The Add Criteria slot's
   18px card margin-bottom, the strip row's 12px subcard padding-top, and the strip's own
   14px margin-top, plus the two 1px borders. None of them owned it. The row's vertical
   padding goes to zero (its padding is there for the HORIZONTAL inset chain, not for
   space), the strip's margin goes to zero, and the wrapper's margin-top is the one owner;
   the slot above it drops its margin-bottom so the two cannot collapse to the larger and
   silently reinstate 18. */
/* [HARD] border-COLOR:transparent, NEVER border:none. The card's 1px border is part of the
   inset chain the field column is measured through, so removing the box (rather than the
   paint) moves everything inside it 1px left — which is exactly what happened: the strip
   landed at 319 against the fields' 320, at both widths, uniformly. Same rule the well
   treatment states for .tpl-flat-subcard, for the same reason. */
/* THE PAINTED BOX. It is a .tpl-form-card, so its width IS the criterion cards' width —
   the same 840px band and the same edges, read from the class rather than measured. The
   chrome-stripping that used to be here is gone from the horizontal axis: it keeps its
   left/right padding (the inset chain the content is positioned by) and now paints.
   The RADIUS is .tpl-form-card's own 10px, inherited by no longer overriding it to 0 —
   read, not chosen, and the right answer now that the box is card-width and card-coloured.
   background-COLOR, never the `background` shorthand: the shorthand wipes a
   background-IMAGE, which is how the ring/tick slot is drawn on every field on this page. */
/* The wrapper paints NOTHING now — it is only what syncWeightPanel() moves. Its
   card fill, 2px border and --stack-gap margins were the slab. */
.tpl-start .tpl-weight-strip-card{margin:0;}
/* .tpl-flat-subcard is what supplies the header inset — the criterion card's own header
   row carries it, and .tpl-edit-row--header has NO padding or border of its own (checked,
   not assumed: the 14px + 1px come from the subcard). Using the same class is what makes
   this row's content box the same box a criterion's is. It is skinless by the surface-wide
   invariant, so there is nothing to strip; it is declared in setup:well-probe's emitter
   census, which is the gate that forces a new instance to be looked at by a person. */
/* DELETED: `.tpl-weight-strip-row > .tpl-edit-field` — do not re-add; the reason is T60 in the decision record. */
/* DELETED: `#tpl-add-criterion-slot:has(+ .tpl-weight-strip-card)` — do not re-add; the reason is T61 in the decision record. */
/* The field's left offset. On a criterion card columns 1 and 2 are occupied by the drag
   handle and the letter, which is what puts .tpl-edit-field at --col-line-x; there is no
   handle or letter here, so the offset is stated. The WIDTH is not stated — .tpl-edit-field
   already takes --col-line-width from the criterion card's own rule, which is the point of
   nesting rather than re-deriving. */

/* THE ON / INVALID PAINT FOLLOWS THE PAINT OUTWARD. The JS is untouched — it still sets
   .is-on and data-state on the INNER #tpl-weight-strip — so the wrapper reads that state
   with :has() rather than the classes being moved and every JS reference re-pointed.
   background-COLOR throughout, never the shorthand.
   The two text colours stay ON the strip's children, because the shared type block below
   sets `color` on those children and an inherited value cannot beat it. */
/* ── THE FIGURE CARRIES THE BADGE ───────────────────────────────────────────
   Every rule the slab needed is deleted with it: the ink fill, the #8C2B1D
   off-balance fill, the white label/figure and the #8FD694 / #F5D9D3 status
   tints — five hard-coded colours, none of them tokens, all gone.

   What replaces them is FIELD STATES' completion badge, painted the SAME way it
   is painted on every field: two background layers, the glyph over a
   radial-gradient disc, sized and positioned off --tpl-badge-size. The only
   difference between the two states is the FILL and the GLYPH — one component,
   two fills, exactly as the ok/not-ok pair reads.

   The lane is reserved with padding-right so the figure sits BESIDE the badge
   rather than under it — the same anchoring lesson the segment option rows
   record. --tpl-badge-inset is the gap between the two, which is its documented
   job ("badge and text share one gutter").
   is-on gates both: with weighting off there is nothing to be balanced.

   THE DISC IS THE COMPONENT'S GLYPH SCALE, NOT ITS FIELD SCALE. --tpl-badge-size
   (18px) is the diameter the badge takes on a FIELD, where it sits beside 16px
   text in a ~40px box; `* 2 / 3` is the component's own expression for the 12px
   mark inside that disc, and 12 is the glyph's viewBox besides. Beside a 12px
   figure in a rail row the field diameter reads as a blob, so the disc takes the
   12 and the glyph takes the same 2/3 of it again (`* 4 / 9` = 8px) — the ratio
   the component draws at every size, one step down. Every number here is still
   --tpl-badge-size and the component's own arithmetic; none is written literally,
   so a change to the token still carries. The glyph's offset follows: centring a
   2/3 mark on its disc is disc/6, and disc is now size*2/3, hence size/9. */
/* The label takes the slack, exactly as .tpl-wp-name does one row up, so the
   figure and the badge column are pushed to the same right edge the stepper has. */
.tpl-start .tpl-weight-strip-label{flex:1 1 auto;min-width:0;}
/* THE BADGE IS PAINTED ON THE + COLUMN, CENTRED IN IT — no right-edge offsets and
   no reserved lane, because the box IS the column. align-self:stretch gives it the
   row's height (.tpl-weight-step declares a width and no height; inside the stepper
   it fills via align-items:stretch, and this row centres instead). background-image
   is set here rather than in the shorthand because .tpl-weight-step's own
   `background:none` would wipe it. */
.tpl-start .tpl-weight-strip .tpl-weight-step{
    align-self:stretch;
    background-repeat:no-repeat,no-repeat;
    background-size:
        calc(var(--tpl-badge-size) * 4 / 9) calc(var(--tpl-badge-size) * 4 / 9),
        calc(var(--tpl-badge-size) * 2 / 3) calc(var(--tpl-badge-size) * 2 / 3);
    background-position:center,center;
}
.tpl-start .tpl-weight-strip.is-on[data-state="ok"] .tpl-weight-strip-status{color:var(--color-text-primary);}
.tpl-start .tpl-weight-strip.is-on[data-state="ok"] .tpl-weight-step{
    background-image:
        var(--quiz-tick-svg),
        radial-gradient(circle closest-side, var(--quiz-correct) 98%, transparent 100%);
}
/* Off 100%, over or under. --red is the platform rust the OFF pill and the
   criteria letters already use; the disc, its size and its position are the ok
   arm's, unchanged. */
.tpl-start .tpl-weight-strip.is-on[data-state="invalid"] .tpl-weight-strip-status{color:var(--red);}
.tpl-start .tpl-weight-strip.is-on[data-state="invalid"] .tpl-weight-step{
    background-image:
        var(--quiz-cross-svg),
        radial-gradient(circle closest-side, var(--red) 98%, transparent 100%);
}
/* DELETED: `overflow-x:clip;overflow-y:visible` — do not re-add; the reason is T62 in the decision record. */
/* DM-b: the comparison-question line is the LAST child of the criteria name column
   (.tpl-edit-field), below the toggles — so the name + comparison read as one card while
   the ×/▾ controls stay on the name row (header stays flex-nowrap, no wrapping). No
   collapse-hide rule → it stays visible on collapse (per decision). DM only. */
.tpl-start:has(#tpl-add-criterion-btn) .tpl-section-block .tpl-edit-field > .tpl-section-prompt-wrap{justify-content:flex-start;}
/* The comparison-question line fills the name column so it is the SAME length as the
   Criteria Name line above it (overrides the centred-band width the MS merged-well
   comparison uses; higher specificity via .tpl-section-block wins over rule ~976). */
.tpl-start:has(#tpl-add-criterion-btn) .tpl-section-block .tpl-edit-field > .tpl-section-prompt-wrap > .tpl-edit-field{width:100%;max-width:none;flex:1 1 auto;}
/* (Session 177) The DM/MS "rich placeholder" overlay was retired — the "Question"
   label is now a static .tpl-card-heading ABOVE the box and the "e.g. …" shows as the
   box's own DM Mono placeholder. The transparent-placeholder + .tpl-prompt-richph*
   rules were removed with it. */
/* Checkbox+label toggle rows (Instructions / Section & Criteria Description / Section
   Comments / Customise Weighting — seeded AND JS-built). Alignment is fixed by NORMALISING
   the boxes, not by leaning on align-items:center. Contract for the whole family:
   - the "+" is now part of the SAME text run as the label (markup: "+ LABEL", one span,
     one baseline) — the old enlarged .qt-toggle-plus element is gone, so there is no
     second inline box to disagree with the text.
   - line-height:1 makes the label box exactly the 9px (--tpl-toggle-label) text, so its
     cross-size is deterministic.
   - the checkbox is pinned to a fixed 13px square with margin:0 (see .qt-subcard-toggle
     input in question-types.js) — the tallest child, so the flex row is 13px.
   Result: checkbox offset 0px, label offset (13−9)/2 = 2px — both WHOLE pixels. */
.tpl-start .qt-subcard-toggle .tpl-workshop-mode-label{line-height:var(--type-badge-line);}
/* Match the heading→first-row gap to the CRITERIA card's. Both card headings
   sit in a .tpl-block-header-row (margin-bottom:10px), but the CRITERIA row is
   taller (its stacked "Customize Weighting" control) and centre-aligned, so its
   heading floats ~8px higher than the RANK ITEMS heading, which is bottom-aligned
   (flex-end) tight against its 10px margin. Add that ~8px on the items list
   container so the first item row sits the same distance below its heading as the
   first criterion card does. */
/* DELETED: `#tpl-items-list{margin-top:8px}` — do not re-add; the reason is T63 in the decision record. */
/* [HARD] A LIST WHOSE ADDER CARRIES THE GAP HAS NO BOTTOM MARGIN OF ITS OWN — and now
   NO LIST HAS ONE, so this is a property of the base rather than a cancellation applied
   list by list. The "+ Add …" button below every list carries its own --stack-gap
   margin-top from the one shared rule further down, and that is the only mechanism left.

   The two selectors that used to sit here (`#tpl-items-list` and `.tpl-questions-list`,
   both `margin-bottom:0`) are DELETED with the base `.tpl-items-list{margin-bottom:14px}`
   they existed to cancel — see the note at that deletion. Zeroing two of three lists left
   the third holding the gap twice, which is how the ownership stayed wrong while the
   number stayed right.

   WHY IT MATTERED AT ALL, kept because it is the reason a bottom margin here is a trap
   rather than a redundancy: whether the two mechanisms collapse depends on the ADDER's
   display, which is not the same on every shape. Flat/DM's adder is inline-flex and an
   inline-level box never margin-collapses with a sibling, so both live gave 28px; MS's
   adder is display:flex and collapsed to 14. Same two declarations, two different gaps,
   neither of them owned. */
/* Item text column + line band are no longer bespoke tokens: every line (name /
   comparison / item / question prompt / flat Overall Q) now sits at --col-line-x and
   spans --col-line-width — the shared D-COLUMNS geometry defined on .tpl-start in
   templates.css. See the --col-* block there for the single source. */
/* --stack-gap = the ONE explicit vertical gap for every LIST-level "+ Add …" button —
   Add Item AND Add Question, flat / DM / MS, all modes — sourced ONCE here. A list and
   the adder under it are two separate objects on the card's surface, which is the token's
   role verbatim; it was the literal 14 that the role was read off in the first place.
   Making it an explicit property of each button (not a by-product of the list's
   margin-bottom collapsing) is the single source of truth, and the list-side half of that
   is now gone entirely — see A LIST WHOSE ADDER CARRIES THE GAP above.
   The MS section adder (962) and DM adder (973) keep their own layout declarations
   (flex / fit-content) but inherit THIS gap, so no context can drift. Card-level adders
   (Add Section / Add Criterion) are a separate family on the 18px card rhythm — see
   #tpl-add-criterion-btn. */
/* [HARD] ONE STEP TIGHTER THAN --stack-gap, 2026-08-26: --space-md (16px), NOT
   --stack-gap (24px, == --space-lg). The scale tokens.css declares is the whole answer —
   --space-lg is the object-to-object step and --space-md is the one below it, so "one step
   smaller" has exactly one value and there is no literal here.
   WHY THE ADDER LEFT THE OBJECT STEP. A list and its adder are not two objects a person
   chooses between; the adder belongs TO the list it appends to, and at 24 it read as a
   third object floating between the rows and the control under it. Same reasoning the
   description/prompt pair already uses one rule down the scale (see FIELD GROUP -> FIELD
   GROUP, ONE STEP TIGHTER), and the same token.
   STILL SOURCED ONCE, for all four adders. Giving Add Item 16 and Add Question 24 would be
   the drift this rule was factored to prevent — one owner, every context. */
.tpl-start #tpl-add-item,
.tpl-start #tpl-flat-add-question,
/* DELETED: `.tpl-add-item[data-add-question]{margin-top:--space-md}` — do not re-add; the reason is T64 in the decision record. */
/* DELETED: `.tpl-start .tpl-section-block .tpl-add-item:not([data-add-question…` — do not re-add; the reason is T65 in the decision record. */
/* ── [HARD] THE OVERALL QUESTION IS BACK ON THE LINE COLUMN (2026-08-23) ─────────
   THIS REVERSES A LOGGED DECISION, AND THE DECISION IS QUOTED SO NOBODY HAS TO GUESS
   WHETHER IT WAS SEEN. What stood here read:

     "THE OVERALL QUESTION JOINS THE IDENTITY BAND, NOT THE ITEM COLUMN. It used to sit
      at --col-line-x and span --col-line-width so it lined up with the item rows below
      it. It now takes --tpl-name-span, centred — the SAME band the Session Title and
      Group / Team fields take — so those three share one left and right edge down the
      page." (--tpl-name-span has since been deleted; see its note.) That is a deliberate trade, not an oversight … The two alignments cannot
      both be had, and the identity one is the one asked for."

   The trade it describes was real and its premise has gone: the identity band is no
   longer centred and no longer a band of its own (see THE IDENTITY ROWS JOIN THE LINE
   COLUMN above), so "line up with the identity fields" and "line up with the item rows"
   are now the SAME alignment. There is nothing left to trade. This line takes
   --col-line-x back for exactly the reason the old note gave for removing it — it
   stands in for the numeral an item row has and this line does not — and
   justify-content goes to flex-start because there is no longer a band to centre.

   Flat blank only (#tpl-flat-compare-fields is blank-only); DM / MS comparison prompts
   are a different partial (_criteria-compare-line) and keep their own --col-line-x /
   --col-line-width arms — which is now the same arm this one uses. */
#tpl-flat-compare-fields > .tpl-section-prompt-wrap{padding-left:var(--col-line-x);padding-right:0;justify-content:flex-start;}
/* DELETED: `min(--col-line-max, 100% - --col-right)` — do not re-add; the reason is T66 in the decision record. */
/* [HARD] THE TWO-TERM FORM, NOT --col-line-width, AND THE WRAP IS WHY. This field sits
   in a wrap that has ALREADY PAID --col-line-x as padding (the rule above), so the `100%`
   inside --col-line-width would resolve against the wrap's CONTENT box and subtract the
   offset a second time — 376px against the item rows' 438 at 1280. This is the same trap
   the MS comparison field carries, so it takes the same expression MS's arm does; the two
   are now one form in two places rather than two forms. */
/* [HARD] AND IT TAKES NO LEAD, FOR THE SAME REASON IT TAKES THE TWO-TERM WIDTH (2026-08-24).
   Its wrap has ALREADY PAID --col-line-x as padding-left (the rule above), and --col-line-x
   now carries the field inset — so the lead .tpl-edit-field takes everywhere else would be
   the second half of a term already spent here. Measured on blank before this line: this one
   field sat at 412 against every other rule on the page at 400. Same trap, same two
   consumers, as the two-term width note at --col-line-width in templates.css; read that one
   before touching either. */
#tpl-flat-compare-fields > .tpl-section-prompt-wrap > .tpl-edit-field{flex:0 0 auto;width:min(var(--col-line-max), calc(100% - var(--col-right)));min-width:0;max-width:100%;margin-left:0;}
/* Flat Ranking sub-card — the near-white card that the OVERALL QUESTION and the
   ITEMS well render in, INSIDE the merged tan .tpl-form-card panel. Identical to
   the section question sub-card ([data-question-wrap], question-types.js): same
   shared fill/border TOKENS, same 8px radius + 12/14 padding literals (matching
   that rule; there is no token for those and we deliberately don't touch the
   [data-question-wrap] rule the mobile reflow keys off), same 14px inter-card gap.
   A plain block, so — exactly like a section question card fills its section — it
   fills the panel's content area and is inset by the panel's OWN padding (~23px
   desktop / ~13px ≤480). That is what makes a flat sub-card indistinguishable from
   a section sub-card at both breakpoints.
   The horizontal padding is a LITERAL again (2026-08-02). It spent one commit hoisted to
   a --tpl-subcard-pad-x D-COLUMNS term, for the single case where MS's header row sat
   outside this panel and had to match its content edge from the outside. The header is
   inside now, nothing outside a panel has to land on a panel's column, and a token read
   only by its own declaration is a term with no contract behind it. */
.tpl-start .tpl-flat-subcard{
    background:transparent;
    /* [HARD] HORIZONTAL BORDER AND PADDING ARE BOTH 0 (2026-08-24), AND BOTH HALVES MATTER.
       This well is the row band's box. Its 15px left inset (1px transparent border + 14px
       padding) is exactly what put a row badge 15px right of a card badge, on every shape,
       at both widths — so zeroing the padding alone would leave a 1px misalignment from a
       border that paints nothing, which is the worst kind: invisible, and enough to make
       "one vertical" false. The width the card owes back for this lives in
       --col-card-pad-r; see THE CARD'S HORIZONTAL INSET IS ASYMMETRIC.
       The vertical border stays 1px transparent — it is part of this box's vertical rhythm
       and nothing here is a claim about it. */
    border:1px solid transparent;
    border-left-width:0;
    border-right-width:0;
    /* [HARD] AND THE BOTTOM ONE TOO (2026-08-27). The well is the LAST RENDERED CHILD of
       its card in all 20 measured cells, so its trailing edge is the card's visible bottom
       inset and every strip it holds there is added to --tpl-card-pad. 1px of transparent
       border is invisible on its own and is not invisible in that sum. The TOP border
       stays: it is inside the card, between the heading and the first row, where the box's
       vertical rhythm is a real relationship. */
    border-bottom-width:0;
    border-radius:var(--radius-none);
    /* THE TRAILING PADDING IS 0, AND THAT IS THE c9e4e51a DIRECTION INVARIANT APPLIED TO A
       BOX RATHER THAN A MARGIN. `padding:12px 0` put 12px below the well's last row, and
       the well is last in its card everywhere, so those 12px separated nothing and simply
       moved every card's visible bottom edge 12px further from its ink than its top.
       The LEADING 12px stays untouched: it is the distance from the card's heading to the
       first row, which is a gap between two things that both render. */
    padding:var(--inset-box) 0 0;
    /* DELETED: `margin-bottom:14px` — do not re-add; the reason is T67 in the decision record. */
}
/* ── THE WELL HAS NO SKIN, AND NEITHER DOES THE DM CRITERION HEADER ANY MORE ──────
   Slice 1 stripped three named wells (Overview, flat Overall Question, flat Options To
   Compare). Slice 2 added the last two — DM's items well and the MS section body panel —
   leaving FIVE of six stripped and ONE exception: the DM criterion header, which was not a
   second-level box inside a card but WAS the card, its outer .tpl-form-card having been
   stripped to nothing by the criteria wrapper (rule ~1119). The exception's own note ended
   "if the DM criterion card should get chrome of its own, this exception is what
   disappears". IT HAS, AND IT DID: the criterion is now identified the way an MS section
   is, by a rust rule rather than by a tint, so the last painted .tpl-flat-subcard is
   unpainted and THERE IS NO LONGER AN EXCEPTION TO STATE. The declaration is deleted
   rather than neutralised — `background:transparent` written a second time here would be
   a rule that exists to say nothing.

   The default stays inverted (above) for the reason it was inverted: the two sites slice 2
   added are a BARE `.tpl-flat-subcard` with no id and no distinguishing class, so
   enumerating them would have meant :has() predicates or invented markup classes. What
   used to make that inversion risky — a new .tpl-flat-subcard silently inheriting "no
   skin" — is what `php artisan setup:well-probe` exists to make visible, and with the
   exception gone that probe's invariant is a single sentence.

   ── THE CRITERION'S IDENTITY IS A RULE ───────────────────────────────────────────
   Same change as the MS band (a7aa1c86), on the surface that is DM's equivalent of it.
   The tint is deleted, the name stops being a box, and a 2px rust rule says where the
   name ends and the criterion's content begins.

   [HARD] THE PAIR KEEPS ITS 1px BORDER BOX. Only the COLOUR goes. That is not timidity
   about `border:0` — it is measured. The criterion's text and the item rows' text both
   land on x=333 at 1280, and they do so by the same arithmetic from two different
   directions: an item's input is a 320..940 box with a 1px border and --tpl-field-inset
   padding (320+1+12), and a criterion part is a 12px inset inside the pair's 321..939
   content box, which is 320..940 minus that same 1px. Delete the pair's border and every
   part moves to 332 — including the question rows in the fourth part — and the alignment
   the parts' inset exists to produce (templates.css ~1047: "so the description/question
   text lines up with the item text") is off by one everywhere. So: border-COLOR to
   transparent, background-COLOR to transparent, and the box is untouched.

   THE RULE IS THE FIRST BOUNDARY BELOW THE NAME, and it is stated as that — `--name +
   .tpl-crit-part` — not as ".tpl-crit-part--desc". The description is what follows the
   name today; the sentence being expressed is "the name ends here", which stays true if
   the description ever stops being second.

   [HARD] IT SPANS 321..939, NOT the 320..940 the MS band's rule spans, and this is the
   one place DM cannot mirror MS exactly. MS's rule is a normal-flow ::before on the panel
   that FOLLOWS the band, so it reads --tpl-section-col-l/-r against the panel's content
   box and lands on the item box precisely. DM has no such sibling: the name and the
   description are parts of ONE element, so any rule between them is inside the pair, and
   the pair's content edge is 1px inside its border box. The alternatives were measured and
   both are worse — deleting the border moves every field in the pair by 1px (above), and
   an absolutely-positioned ::after with `left:-1px;right:-1px` is compensating arithmetic
   for a border that is deliberately still there. 1px at each end of a 620px rule, stated
   here rather than discovered later.

   The rule REPLACES the 1px hairline at that boundary rather than joining it, so the
   criterion grows 1px taller. That is the 2px rule being 2px, not drift.

   `:not(.field-invalid)` on the border-colour arm, and ONLY that arm, so that the
   sentence this rule states is "a RESTING pair is unpainted" rather than "a pair is
   unpainted". MEASURED, because the first version of this note reasoned it out and got the
   mechanism wrong: the error border does NOT come from
   `.tpl-crit-pair.field-invalid{border-color:var(--accent)}` (templates.css ~1043) at all.
   It comes from `.field-invalid{border:2px solid var(--error-red) !important}`
   (blocks.css ~484), and an invalid pair computes rgb(200,64,26) at 2px — NOT --accent's
   rgb(178,74,58) at 1px. Which also means that templates.css rule has been dead for as
   long as the !important has existed; noted rather than removed, because it belongs to the
   shared pair and this is a DM pass.

   So the carve-out is not what saves the error highlight — the !important already does.
   It is here so that this rule does not quietly depend on another file's !important for
   its meaning to be right. Verified in a browser both ways: resting computes a transparent
   1px border, invalid computes the 2px error red. */
/* ── THE CRITERION IS A BOUNDED CARD IN THE CRITERIA CARD (2026-08-28) ────────────
   #tpl-criteria-card is the card; each criterion is now a card of its own inside it —
   Director's decision, replacing the flush-strip-plus-hairline treatment two passes
   just spent getting right (4353650e, 578a3fe9). That whole mechanism existed only to
   position a hairline correctly inside a zero-border gap; a bordered box carries its
   own boundary and needs no separate hairline-placement hack, so it is gone outright,
   not disabled or left commented — margin-top/padding-top cancel-and-respend pair,
   border-top, all of it, plus the `+ .tpl-section-block` sibling selector that only
   existed to reach "every criterion but the first" for that hairline.

   background-color:var(--card-bg-inset), NEVER the `background` shorthand — the same
   warning the pair rules carry: the ring/tick completion badge on the fields inside is
   a background-IMAGE layer and the shorthand wipes it. --card-bg-inset (tokens.css) is
   a NEW token, confirmed necessary before adding it: every existing "surface" token
   (--surface-warm, --color-background-secondary) was checked against this card's own
   --card-bg and is either near-identical to it (--surface-warm, ~2 RGB units off) or
   already measured elsewhere in this codebase at 1.14:1 contrast against this exact
   tan (SetupWellProbe's own numbers) — invisible either way. Derived, not eyeballed:
   see the token's own comment.

   border:1px solid var(--color-border-tertiary) — the SAME hairline token the deleted
   mechanism used, reused as a real border rather than invented as a second border
   token. border-radius:10px matches .tpl-form-card's own (templates.css ~35), the one
   radius token this page uses for "this is a card" — there is no nested-sub-card radius
   precedent to diverge to (.tpl-flat-subcard wells are explicitly unskinned/border-
   radius-less by design, per setup-geometry.md).

   padding:var(--tpl-card-pad) 0 — VERTICAL ONLY. Horizontal stays 0, on purpose: this
   is the exact double-inset trap the ORIGINAL "criterion is a block" note above (now
   superseded) already found and rejected — "keeping any horizontal padding here would
   double the inset and move every field inside a criterion 22px right", off the badge
   column every other numbered card on this page shares. The border's left/right edges
   sit exactly where the flush strip's edges already did; only top/bottom gain the
   token's breathing room, which is what makes the card read as bounded rather than a
   plain rule wearing a border. --tpl-card-pad is the outer .tpl-form-card's own
   vertical inset token (24px, responsive at ≤640/≤480) — reused so a criterion's
   internal spacing matches every other card's, not invented.

   margin-bottom:0 — #tpl-criteria-card's row-gap (--step-row, untouched, above) is now
   what separates one bounded card from the next; a margin here would be a second,
   independent answer to the same distance the container already states once. */
/* [HARD] margin-inline:-1px CANCELS THE BORDER, IT DOES NOT NUDGE ANYTHING.
   A 1px border on a block-level box moves its CONTENT box 1px inwards on each side,
   and the horizontal padding being 0 does not change that — padding and border are
   two separate insets and only one of them was set to zero. So every field inside a
   criterion sat 1..2px (subpixel rounding) off the column every other card's fields
   share, which `setup:header-lane` asserts and which went red the moment this rule
   landed (f2cfb6d9, red for two days). The value is not a fudge: it is exactly the
   border-width above it, pulling the margin box out by what the border took in, so
   the content box lands where it did before the card was bounded. Change the border
   width and this changes with it.

   The commit that introduced the border verified "badge and field left edges
   identical across all three criteria" — internal consistency, which was true and
   is not the claim. The claim is alignment with the rest of the page.

   The 1px the card gains on each side is spent into #tpl-criteria-card's own 22px
   padding, so nothing else moves. */
.tpl-start #tpl-criteria-card > .tpl-section-block{
    border:1px solid var(--color-border-tertiary);
    border-radius:var(--radius-panel);
    background-color:var(--card-bg-inset);
    padding:var(--tpl-card-pad) 0;
    margin-bottom:0;
    margin-inline:-1px;
}
/* The adder loses the invisible slot's role too: inside the card it is simply the run's
   last row, at the same rhythm as the criteria above it. [data-add-card-slot] keeps the
   class only because addCriterionCard() resolves the insertion point by that attribute. */
.tpl-start #tpl-criteria-card > #tpl-add-criterion-slot{
    border:0;
    /* No border to cancel, so no pull-out either — the rule above sets margin-inline
       for a box that has one, and this box does not. */
    margin-inline:0;
    background-color:transparent;
    padding:0;
    margin-bottom:0;
}
/* ── THE GATE BECOMES A SCOPE: EVERY SECTION AND CRITERION CARD ──────────────────
   These read `:has(#tpl-add-criterion-btn)` — a PAGE-SHAPE gate meaning "this is a
   multi-criteria page" — and that is why multi-section rendered the same two fields as
   white boxes while multi-criteria drew them as lines. Same field, same role, two
   controls. The scope is `.tpl-section-block` now: the criterion card and the section
   card both carry it, so the treatment follows the CARD rather than the page.

   [HARD] IT REACHES NOTHING ELSE. .tpl-crit-pair is emitted only by the criterion
   card's bonded pair and by the section card's three single-part pairs — a workshop
   slide has none on either shape ($_dmPair and $_msHeaderBox both exclude workshop, and
   _criteria-compare-line's workshop arm renders a .tpl-inline-edit, not a pair). Counted
   on a rendered workshop page, not inferred: 0. */
/* THESE TWO RULES ARE DELETED (2026-08-24) — THE DEFAULT IS THE TREATMENT NOW.
   They unpainted .tpl-crit-pair's box for `.tpl-section-block` and `.tpl-questions-list`,
   and the note above still claimed the box "reaches nothing else". That stopped being true
   when the Introduction Page / Completion Message cards took the pair, and it was false in a
   way nobody could see from here: those two cards ARE .tpl-section-block, so they were caught
   by these rules and looked right, while slim's Overview card is not — so slim's Description
   was the one field on the surface still wearing the old white box, on create and on manage.
   Fixed at .tpl-crit-pair itself (templates.css), which is where the box was declared;
   scoping a THIRD unpaint rule for slim would have left the page saying "a pair is not a box"
   in three places and still being wrong for the fourth consumer.
   `:not(.field-invalid)` went with them and is not needed: the base is transparent, so
   `.tpl-crit-pair.field-invalid{border-color:var(--accent)}` colours it with nothing to
   out-rank. */
/* ── THE FIELDS ARE WHITE; ONLY THE NAME IS NOT ───────────────────────────────────
   Unpainting the pair above took the white off the NAME, which is what it was for, and
   off the DESCRIPTION and QUESTION with it, which it was not. Those two never declared a
   white of their own — they were transparent parts showing the pair's fill — so removing
   the pair's fill left them on the card's sand while MS's equivalents stayed white. MS
   does not have this problem because MS puts each field in its OWN `.tpl-crit-pair`,
   which still gets the shared white; DM has one pair holding all four parts, so the
   name and the fields could not be told apart by the fill alone. Now they can: the fill
   moves off the pair and onto the parts that are fields.

   `--name ~ .tpl-crit-part` — the general sibling, i.e. EVERY part after the name, not
   `--desc` and `--q` enumerated. That is the same sentence the rule above states from the
   other side ("the name is not a box"), and it keeps the fourth part (the end-of-section
   questions) white too, which is what it was before the band rework and what it must stay:
   it holds question sub-cards that assume a white ground.

   background-COLOR, never the `background` shorthand — the ring/tick badge on these
   fields is a background-IMAGE layer, and the shorthand silently wipes it.

   The parts USED TO read as one white block split by interior hairlines. They no longer
   do: each is its own white field, --stack-gap from the next, exactly as MS renders the
   same three things. See THE PARTS COME APART below. */
/* DELETED: `.tpl-start .tpl-section-block .tpl-crit-part--name ~ .tpl-crit-part` — do not re-add; the reason is T68 in the decision record. */
/* ── THE PARTS COME APART ─────────────────────────────────────────────────────────
   REPORTED: on DM there is no gap between the rust rule and "Criteria description", and
   none between the description and "Participant question" — the parts butt together.
   They did, and the measurement said so: name->description and description->question both
   rendered 0, against --stack-gap between every other pair of objects on the page.

   THE FOURTH PART WAS ALREADY OUT. `.tpl-crit-part--questions` carries --stack-gap and has
   for some time, so the card was ALREADY half-bonded and half-spaced: three parts fused,
   the fourth standing off. There was no version of this card where the bond was the whole
   sentence, which is the tell that it had stopped being one.

   ONE ROLE, NOT TWO. It was worth asking whether "between parts of a bonded pair" is a
   second role in the scale needing its own mechanism. It is not, because the answer to
   the defect is that the pair STOPS BEING BONDED — and once the parts are separate white
   fields on the card's surface, they are the same kind of thing as MS's description and
   comparison question, which is the role --stack-gap already names. A second role would
   have been a way of keeping the bond while denying its consequence.

   THE RUST RULE MOVES FROM THE DESCRIPTION'S TOP TO THE NAME'S BOTTOM, and it has to.
   It was `--name + .tpl-crit-part{border-top:2px solid var(--red)}` — a border on the
   DESCRIPTION, which read as "under the name" only because the two were flush. Separate
   them and that rule travels DOWN with the description, leaving the name bare and the
   rule floating on top of a field --stack-gap below it. As the name's own border-bottom
   it stays where it has always looked like it was, and the gap below it is then the
   ordinary part-to-part gap. This is exactly MS's arrangement, where the rule is a
   normal-flow ::before whose margin-bottom is --stack-gap — same two objects, same
   distance, reached from the two different structures each shape actually has.

   The general sibling for the gap, matching the fill rule above rather than enumerating
   --desc and --q: every part after the name is a field, and every field stands off from
   the one before it. The fourth part matches this too and is unchanged by it — it was
   already at --stack-gap via .tpl-instructions-body, so the card gains no new value, only
   one rule that says the whole thing instead of two that each said half. */
/* DELETED: `.tpl-crit-part--name{border-bottom:2px solid var(--red)}` — do not re-add; the reason is T69 in the decision record. */
/* THE VALUE IS --space-md NOW, AND THE FOURTH PART IS EXCLUDED (2026-08-20). See FIELD
   GROUP -> FIELD GROUP at .tpl-section-desc for the reasoning; DM's three fields are the
   same relationship MS's two are, and one value has to serve both or the two cards drift.
   :not(--questions) because the fourth part is NOT a field — it is the end-of-section
   question LIST, i.e. the next object, which is what --stack-gap means. It keeps that
   distance from .tpl-instructions-body, which has always owned it (see the note this
   replaces), so excluding it here changes nothing about where it sits. */
/* DELETED: `--space-md` — do not re-add; the reason is T70 in the decision record. */
.tpl-start .tpl-section-block .tpl-crit-part--name ~ .tpl-crit-part:not(.tpl-crit-part--questions),
.tpl-start .tpl-questions-list .tpl-crit-part--name ~ .tpl-crit-part{
    margin-top:0;
}
/* Add Items / Add Questions / Criteria / Section adders take the CANONICAL
   outlined "+ Add" box from templates.css verbatim — square corners
   (border-radius:0) + a visible 1px var(--ink) border on var(--surface-warm).
   The former sub-card restyle here (8px radius + faint --color-border) was
   removed so there is ONE add-button look platform-wide, sourced only from the
   templates.css box rule (and templates.css:2343 for #tpl-flat-add-question).
   Do NOT reintroduce a local border/border-radius override for these buttons. */
/* Flat blank item rows — the text underline spans the shared --col-line-width (the same
   line every row type uses). flex:0 0 auto + width:--col-line-width fills the line; the
   input keeps flex:1 so the [Edit] cue stays pinned to its right end. Flat, MS section
   item rows and DM item rows all join the SAME rule, so every underline is identical
   width — one declaration, no per-context literal. */
.tpl-start:has(#tpl-rank-type-toggle) #tpl-items-list .tpl-item-row > .tpl-inline-edit,
.tpl-start:has(#tpl-add-section-btn) .tpl-section-block .tpl-item-row > .tpl-inline-edit,
.tpl-start:has(#tpl-add-criterion-btn) #tpl-items-list .tpl-item-row > .tpl-inline-edit{flex:0 0 auto;width:var(--col-flow-width);min-width:var(--col-flow-width);max-width:100%;}
/* The line is a fixed --col-line-width at --col-line-x, so its right edge is constant and
   the same as the Overall Question line, regardless of the × glyph's own width (it sits
   natural-width right after the line — see the col-4 cluster note below). */
/* Trailing ×/▾ cluster (col 4): the line is a fixed --col-line-width at --col-line-x,
   so its right edge is already constant; the cluster sits natural-width right after it
   (base .tpl-row-controls), landing every row type's glyphs at the same left edge. */
.tpl-start:has(#tpl-rank-type-toggle) #tpl-items-list .tpl-item-row > .tpl-row-controls{flex-shrink:0;}
/* [HARD] FLAT'S ITEM LIST NEEDS A DEFINITE WIDTH, and it is the only shape that lacked
   one: DM declares it (:has(#tpl-add-criterion-btn), ~3951) and MS declares it
   (:has(#tpl-add-section-btn), ~3404); flat never did, because with --col-line-width a
   fixed length nothing in the row asked its parent how wide it was. It does now — the
   token's fluid arm is `100% − …` — and a percentage inside a shrink-to-fit parent is
   circular. Measured: flat's item rows collapsed from 620px to ~463px on the DEFAULT
   page the first time the token change landed, while DM, MS, survey and quiz were
   untouched. This is the third copy of a rule two shapes already had, not a new idea. */
.tpl-start:has(#tpl-rank-type-toggle) #tpl-items-list:not(.tpl-questions-list){width:100%;box-sizing:border-box;}
.tpl-start:has(#tpl-rank-type-toggle) #tpl-items-list:not(.tpl-questions-list) > .tpl-item-row{width:100%;max-width:none;}
/* "+ ADD ITEMS" now lives INSIDE the .tpl-flat-subcard well as its last child, sharing the
   well container with the item rows. For MS (per-section .tpl-add-item) and DM (the shared
   #tpl-add-item) it left-aligns to the item TEXT column at --col-line-x, so the button
   sits directly under the rows it appends to (width:fit-content + margin-right:auto). Flat
   Individual keeps its plain text-col rule (its rows are left-aligned, not banded). */
/* MS: the button is the section BODY PANEL's child again — it went back inside a
   .tpl-flat-subcard with the item rows it appends to. The bare-card form of this selector
   (`.tpl-section-block > .tpl-add-item…`), added when the 2026-08-02 merge made it a direct
   card child, is DELETED rather than left beside the well form: it now matches nothing on
   any page, and a dead selector next to a live one reads as though two shapes are still
   supported. The :not() pair still excludes the question / option adders. */
.tpl-start:has(#tpl-add-section-btn) .tpl-section-block .tpl-flat-subcard > .tpl-add-item:not([data-add-question]):not([data-add-option]){display:flex;width:fit-content;margin-right:auto;}
/* DM (flush grid): the items well now MIRRORS the criteria header's column grid so
   item rows line up under the criteria letter/name. Both are .tpl-flat-subcard with 14px
   h-padding inside identical-width .tpl-form-cards, so their content-lefts coincide (H).
   Criteria header = [drag 16][gap 10][letter --tpl-card-num-width][gap 10][name band].
   The items well has no drag handle, so an empty gutter of width (drag+gap) precedes the
   numeral, the numeral is the SAME --tpl-card-num-width column (below, overriding the −4
   flat variant), and the underline is the same band — so numeral↔letter and
   underline↔name coincide exactly. The heading (Options To Compare) + toggle + Add Item
   sit on the item NUMBER column (the gutter = drag+gap) so they flush-left with the
   "01"/"02" numerals and the criteria letters — one card-left edge. DM-scoped; flat/MS untouched. */
.tpl-start:has(#tpl-add-criterion-btn) .tpl-flat-subcard > #tpl-add-item{display:flex;width:fit-content;margin-right:auto;}
.tpl-start:has(#tpl-add-criterion-btn) #tpl-items-list .tpl-item-num{width:var(--col-num-left);margin-left:var(--col-num-x);}
/* DELETED: `#tpl-rank-type-toggle.tpl-rank-type-toggle-incard` — do not re-add; the reason is T71 in the decision record. */
/* IMAGES sub-tab: the image upload block (thumbnail + URL field + Upload) left-aligns to
   the item/label TEXT column at --col-line-x and spans --col-line-width, so each image
   sits directly under its own label (overriding the base margin-left:38px; its top/bottom
   margins are kept).
   Flat Individual (#tpl-rank-type-toggle), MS section cards (#tpl-add-section-btn) AND DM
   criteria (#tpl-add-criterion-btn — the shared #tpl-items-list) share this ONE
   rule/declaration; participant image lists keep the base. */
.tpl-start:has(#tpl-rank-type-toggle) #tpl-items-list > .tpl-item-image-row{box-sizing:border-box;margin-left:var(--col-line-x);margin-right:0;width:auto;max-width:var(--col-line-width);padding-left:0;}
/* DM + MS images sub-tab: flush like the text rows — the thumbnail block sits on the item
   TEXT column (gutter + numeral + gap) and spans the same band, so each image lines up
   under its own label. Left-aligned (not the centred band). */
.tpl-start:has(#tpl-add-criterion-btn) #tpl-items-list > .tpl-item-image-row,
.tpl-start:has(#tpl-add-section-btn) .tpl-section-block .tpl-items-list > .tpl-item-image-row{box-sizing:border-box;margin-left:var(--col-line-x);margin-right:0;width:auto;max-width:var(--col-line-width);padding-left:0;}
/* (2d) MS section AND DM criteria lines share the SAME --col-line-x / --col-line-width as
   the flat lines above, so the comparison-question line + item / image rows match the
   flat Ranking question/item width exactly (one geometry, no matching literal). So the
   criteria/section name, comparison line and item rows all read at one width, their left
   edges landing on --col-line-x. MS is scoped
   via :has(#tpl-add-section-btn); DM joins each rule via a parallel :has(#tpl-add-criterion-btn)
   selector (its item list is the shared #tpl-items-list, not the per-section .tpl-items-list,
   so it needs its own selector but the identical declarations — extend, don't fork). */
/* MS (flush grid): same column system as DM. The section letter/name live in the header
   sub-card; the comparison + item rows live in the merged well below. Both sub-cards are
   .tpl-flat-subcard (14px pad) in the same-width card, so their content-lefts coincide (H).
   - Section name: H+62 (header flex, after [drag][letter][gap]).
   - Comparison: no numeral, so inset the full text column (drag+gap+num+gap) -> H+62 == name.
   - Item numeral: drag+gap gutter -> H+26 == letter; item underline: --col-line-width -> == name.
   Every line renders at --col-line-width from --col-line-x, so all right edges land together. */
/* Section question is a standalone prompt line — position it on col 3 via the WRAP's
   padding-left (the SAME mechanism the flat Overall Question uses, #tpl-flat-compare-fields
   above), not an inner-field margin. The field just fills the line column, no left offset. */
.tpl-start:has(#tpl-add-section-btn) .tpl-section-block .tpl-section-prompt-wrap{justify-content:flex-start;padding-left:var(--col-line-x);}
/* [HARD] THE SAME DOUBLE-SUBTRACT AS FLAT'S OVERALL QUESTION — see the note there; the
   correction that used to live in a max-width:888px query further down this file is
   folded in here and that query is DELETED. */
.tpl-start:has(#tpl-add-section-btn) .tpl-section-block .tpl-section-prompt-wrap > .tpl-edit-field{flex:0 0 auto;width:min(var(--col-line-max), calc(100% - var(--col-right)));min-width:0;max-width:100%;margin-left:0;}
/* ── THE COMPARISON QUESTION CARD ──────────────────────────────────────────────────
   It used to be a part of the header box, bonded above the item stack. It is not a
   configuration field: it is the thing a respondent is asked, so it reads as a card on
   the same terms the question cards do — anything a respondent reads gets a card.

   AND THE RAIL STAYS EMPTY BESIDE IT. Rail entries are NUMBERED things; this is
   section-level, so there is no number and nothing takes the column. No spacer element
   is added for it: the wrap's padding-left is already --col-line-x (the rule directly
   above), which is exactly the rail plus its gap, so the card lands on the same left
   edge as a question card by reading the same token, with the rail simply unoccupied.

   The card is the .tpl-crit-pair that is already there. It keeps the border, the white
   fill, the 4px radius and the field's chrome-less contract from the pair mechanism; all
   this adds is the card's padding rhythm and the question card's typography, so the two
   cards are the same object with different content. */
/* (THE COMPARISON FIELD'S DOUBLE-SUBTRACT CORRECTION MOVED, 2026-08-18.) It was a
   max-width:888px query here, holding `width:calc(100% - var(--col-right));min-width:0`.
   It is now unconditional, on the field's own rule above, as
   `min(var(--col-line-max), calc(100% - var(--col-right)))`.
   TWO THINGS THE CAP BUYS, and the second is why the old form could not simply be
   unscoped. (1) --col-line-width is capped-not-pinned now, so its fluid arm fires
   whenever the COLUMN is short rather than only when the viewport is, and a
   viewport-scoped correction would miss the rail case entirely. (2) The uncapped form
   was tried unconditional before and rejected on a measurement recorded here: it made
   the comparison card 618px against 620px for the header box, the question cards and the
   item rows, at 1440.
   THAT REJECTION IS NOW OVERTURNED, and the measurement is why. 618 was the correct
   value and the 620 it was compared against was 2px over — the four column numbers did
   not agree, and --col-line-max is now 618 for exactly the reason this note measured.
   The cap and this expression therefore agree on the default page, and the comparison
   card lines up with the header box, the question cards and the item rows because all
   four are 618. See the --col-line-max derivation in templates.css. */
/* DELETED: `.tpl-crit-pair{padding:10px 12px 11px}` — do not re-add; the reason is T72 in the decision record. */
/* DELETED: `.tpl-crit-part--q > .tpl-crit-tag{margin-bottom:6px}` — do not re-add; the reason is T73 in the decision record. */
.tpl-start:has(#tpl-add-section-btn) .tpl-section-block .tpl-items-list:not(.tpl-questions-list){align-items:stretch;width:100%;box-sizing:border-box;}
.tpl-start:has(#tpl-add-section-btn) .tpl-section-block .tpl-items-list:not(.tpl-questions-list) > .tpl-item-row{width:100%;max-width:none;}
.tpl-start:has(#tpl-add-section-btn) .tpl-section-block .tpl-items-list:not(.tpl-questions-list) .tpl-item-num{width:var(--col-num-left);margin-left:var(--col-num-x);}
.tpl-start:has(#tpl-add-section-btn) .tpl-section-block .tpl-items-list:not(.tpl-questions-list) .tpl-item-row > .tpl-inline-edit{flex:0 0 auto;width:var(--col-flow-width);min-width:var(--col-flow-width);max-width:100%;}
/* ── THE MARKER RAIL — ONE column, THREE tiers ─────────────────────────────────────
   The section letter and every question / item number are one vertical rail, and the
   COLUMN they share is already the contract's: --col-num-left wide, at --col-num-x,
   with everything after it starting at --col-line-x. Nothing horizontal is set here —
   the letter's width joined --col-num-left in templates.css and the numerals already
   read it; this rule is only about what the rail LOOKS like.

   TWO TIERS NOW, NOT THREE (2026-08-03). It was three — letter 23px --accent, question
   number 20px --color-label, ITEM number 17px --color-label — each naming a smaller kind
   of thing than the one above it. The ITEM tier is RETIRED: an MS item number is the same
   object as a DM / flat item number (a member of the list of things being compared) and
   now renders identically to one, which is what it should have done from the start.

   RETIRED BY DELETING THE OVERRIDE, not by restating DM's values on MS. The canonical
   numeral rule near the top of this file already covers `.tpl-items-list:not(.tpl-
   questions-list) .tpl-item-num` for EVERY shape — Bebas, 22px, --accent, 0.02em, line-
   height 1 — and MS's rows match that selector. MS only ever looked different because a
   `:has(#tpl-add-section-btn)` rule overrode font-size and color on top of it. Both
   declarations are gone, so MS and DM read one declaration and cannot drift again; a copy
   of `font-size:22px;color:var(--accent)` scoped to MS would have been a second source of
   the same number. letter-spacing and line-height come along for free — they are 0.02em
   and 1, so they scale with the size rather than needing their own values (measured:
   0.34px → 0.44px, 17px → 22px, matching DM exactly).

   The QUESTION tier stays 20px --color-label: a question number names a question, not a
   member of a compare list, and nothing was asked about it. So an MS section now shows
   22px rust numerals in Items/Images mode and 20px muted ones in Questions/Quiz mode.

   CENTRED, not left-aligned, and that is unchanged. It is what makes the remaining sizes
   read as one rail — the glyphs share a vertical axis instead of a left edge — and it is
   MS-wide: the letter and the question numerals are centred too, so left-aligning ONLY
   the item numerals to match DM's cell alignment would have staggered MS's own rail by
   8px. The consequence is that an MS item glyph sits ~3.7px right of a DM one inside the
   same 26px column (measured, ink box: DM 364.0, MS 367.7). That difference is
   pre-existing and MS-wide — MS's section letter already sits 8.2px right of DM's for
   exactly this reason — not something the size/colour change introduced.
   Placed AFTER the two width rules above rather than merged into them: those set the
   column, this sets the mark inside it, and the item-numeral rule two lines up is the one
   that would otherwise win the text-align tie on source order. */
.tpl-start:has(#tpl-add-section-btn) .tpl-edit-row--header > [data-card-num]{
    font-size:var(--type-panel-title);
    text-align:center;
}
/* DELETED: `.tpl-start.structural-locked:has(#tpl-add-section-btn) .tpl-edit-r…` — do not re-add; the reason is T74 in the decision record. */
/* [HARD] font-size AND color ARE DELETED HERE, AND THE COMMENT THAT USED TO FOLLOW THIS
   RULE IS DELETED WITH THEM (2026-08-20). That comment claimed both had been removed on
   2026-08-03. They had not: they were still here, and `:has(#id)` gives this selector ID
   weight, so `color:var(--color-label)` beat the shared badge declaration's
   `color:var(--color-white)` on every MS question. Measured on Advanced Ranking:
   fg rgb(140,128,120) on bg rgb(178,74,58) — a grey numeral on a rust disc, against
   white-on-rust for the same class on all six other surfaces. A note asserting its own
   fix is why this survived the badge scheme landing, so it is not corrected, it is gone.

   font-size:20px went too, and it was never wrong — that is the point. --tpl-heading IS
   20px, so the literal agreed with the token by hand and would have parted from it
   silently at the first change to either.

   text-align:center is all this rule ever legitimately said: the shared declaration
   centres its glyph with flex, and this is the one arm that needs the text centred
   because MS numerals can reach two digits. */
.tpl-start:has(#tpl-add-section-btn) .tpl-section-block .tpl-questions-list .tpl-item-num{
    text-align:center;
}

.tpl-start:has(#tpl-add-section-btn) .tpl-section-block .tpl-items-list:not(.tpl-questions-list) .tpl-item-num{
    text-align:center;
}
/* ── MS BONDED STACK — DELETED, ALL SIX RULES ────────────────────────────────────
   It made the MS item rows read as ONE bordered box split by hairlines: square corners
   on every member, a -1px pull so adjacent borders shared a line, rounded ends on the
   first and last, a box invented for the images row so it could join, and `gap:0` on the
   list to close the flex gap the pull could not.

   THE REASON IT EXISTED IS GONE, AND WAS ALREADY GONE. Its own heading says it: "the
   COMPARISON QUESTION and its item rows read as ONE box", because a question and the
   options it compares are one thing. The comparison question then LEFT for a card of its
   own — that is recorded two rules up, where its arm was struck from the square-corners
   list. What was left bonded was items to items, which is not the sentence the family was
   written to say, and nothing restated it. The result on screen is the reported defect:
   MS's 01/02/03 flush against each other while DM's Options To Compare — same kind of
   row, same page, same component — sit --stack-gap apart.

   DELETED RATHER THAN JUST UN-ZEROED. `gap:0` is the rule that produces the symptom, and
   removing only that one leaves five rules compensating for a stack that no longer
   exists: rows with squared-off corners, pulled up 1px into the row above, with the first
   and last rounded — i.e. a bonded box with 14px of daylight through it. The five are not
   collateral; each one is only true WHILE the members are adjacent.

   WHAT COMES BACK, from rules that were there all along and needed no reinstating:
     • gap        the list is a flex column at var(--stack-gap) — the shared declaration
                  DM and flat already read, so MS now gets the identical treatment from
                  the identical source rather than from a matching literal.
     • radius     4px per row, from the item field's own base rule.
     • the images row goes back to being a thumb + (url, upload) group with NO box, which
       is what it is on DM and flat. Its box was invented HERE, purely to let it join the
       stack ("The images row never had a box — give it the same one so it can join"), so
       it goes with the stack. Its --col-line-x margin is untouched and lives elsewhere.

   The [HARD] note about why this was never .tpl-crit-pair goes too, and deliberately: it
   argued against consolidating a bonded stack into a container class, and there is no
   bonded stack to consolidate. The DM criterion pair's own hairline/radius tokens are
   documented at that pair. */
/* DELETED: `margin-bottom:10px` — do not re-add; the reason is T75 in the decision record. */
/* ── THE PROMPT WRAP'S TOP MARGIN — ZEROED SO THE DESCRIPTION CAN OWN THE GAP ──────
   The base carries `margin-top:8px`, and above it on an MS card sits .tpl-section-desc's
   margin-bottom. Adjacent margins collapse to the larger, so the 8 never once decided
   the gap and the 10 above it only appeared to — the number on screen was max(10,8).
   The description owns it now (--stack-gap), so this goes to zero rather than to a value
   that would have to be kept in step with it. MS scope only: on flat the same wrap is
   the compare well's first child with no preceding sibling, so its 8px is a real inset
   and is left alone. */
.tpl-start:has(#tpl-add-section-btn) .tpl-section-block .tpl-section-prompt-wrap{margin-top:0;}
/* DELETED: `gap:0` — do not re-add; the reason is T76 in the decision record. */
/* ── THE END-OF-SECTION TOGGLE ────────────────────────────────────────────────────
   Divider, Bebas label, one line of DM Mono sub-copy, shared ON/OFF pill on the right.
   ONE family for both shapes, from the one partial each card includes.

   A 2-COLUMN GRID, NOT A FLEX ROW WITH A NESTED COLUMN. The label and the hint are
   siblings in the markup rather than wrapped in a text div, and the grid places them in
   rows 1 and 2 of column 1 while the pill spans both rows of column 2. That keeps the
   markup one level flat and — the reason that matters — keeps the pill vertically centred
   against the PAIR of text lines without anything having to know their heights.

   THE DIVIDER IS border-top ON THIS ELEMENT, not a separate rule or a ::before. It has one
   job and one owner, and it lands on the same content column as everything else on the
   card because of the margins below.

   GAPS ARE --stack-gap ABOVE AND BELOW, per the scale: the divider separates two objects
   on the card's surface, so the distance either side of it is the one distance this card
   knows. margin-top is the gap above; padding-top is the gap below (the border sits
   between them, which is exactly what a border-top plus padding-top expresses). One
   positive owner each, no negative margin, nothing to keep in sync. */
.tpl-start .tpl-end-toggle{
    /* FLEX, NOT GRID — and the grid is DELETED rather than reduced to one row.
       It was a 2-column grid so the label could sit in row 1 and a DM Mono sub-copy line in
       row 2 with the pill spanning both. The sub-copy is gone, so the pair of lines it was
       centring against is gone, and a one-row grid with two children is a flex row that has
       not noticed. The three placement rules it needed go with it: every one of them
       existed only to place things around the second line. */
    /* [HARD] A COLUMN, NOT A ROW (2026-08-26) — THE LABEL SITS ABOVE THE PILL.
       It was a flex ROW with the caption one --col-gap to the left of the pill. Every other
       in-card toggle on this platform captions from ABOVE — LOCATION (#tpl-where-row, a
       flex column with gap:6px) and MEETING/ EVENT LENGTH (.tpl-timedate-length, its
       .tpl-crit-tag as its own first child) — so this is the odd one, not a variant.
       The stack is LOCATION's verbatim: column, flex-start, 6px. --col-gap was the
       horizontal gutter this row shared with the item rows; a column does not want it, and
       6px is the label-to-control step the other two already read.
       The row's left edge and its text column are UNTOUCHED (padding-left:--col-line-x
       below), so setup:spacing-probe's endrow-label-l / endrow-edge-l still measure what
       they measured — the pill moves under the label, the label does not move. */
    display:flex;
    flex-direction:column;
    align-items:flex-start;
    /* [HARD] --space-md, AND IT IS THE SAME NUMBER AS THE TWO GAPS AROUND THE ADDER ABOVE
       (2026-08-26). The three distances in this corner of the card — into the adder, out of
       the adder, and from this caption to its pill — were 24 / 24 / 6 and read as three
       different relationships when they are one cluster. They are one value now, one step
       below --stack-gap on tokens.css's own scale.
       THE 6px LITERAL THAT STOOD HERE IS GONE. It was copied from #tpl-where-row's
       label-to-control step when this row became a column, and a literal is exactly what
       cannot be moved with the scale. */
    gap:var(--step-tight);
    /* ── THE LABEL SITS ON THE TEXT COLUMN OF THE ROWS IT SITS AMONG ───────────
       ONE IDEA, AND IT REPLACES THREE ARRANGEMENTS (2026-08-20). The row used to be
       `justify-content:space-between` with `padding:0 var(--tpl-field-inset)`, so the
       label sat 12px inside the card while "+ Add item" — the row directly above it —
       sat at --col-line-x, and the pill was thrown to the far edge of the card. Measured
       at 1280 before: label 385.19 against the adder's 435.19 on flat, and a 300.81px
       void between the label and its own pill.

       THE COLUMN IS JOINED, NOT RESTATED: this is the same token `.tpl-add-item` reads
       for its own margin-left, so the label and the adder cannot drift apart — there is
       no second value to keep in step. It became --col-flow-x on 2026-08-31 when the item
       adders did: an adder appends to a badge-led list and pays the flow offset, and this
       label follows the adder by construction rather than by a matching number. Measured
       at 390 on MS before: label 19 against the adder's 61, and DM's equivalent label
       already at 62 — the two shapes had disagreed by one badge column, invisibly, for as
       long as both were on the wrong one together. At >=641 --col-flow-x is pinned to
       --col-line-x, so 1280 is unchanged: 400/401 before and after.
       DM IS NOT IN THIS: `.tpl-crit-ctrls > .tpl-end-toggle` overrides the padding to 1px
       below, for the reason stated there — a criterion card has no item list and no adder
       above this control, so its column is the criterion's field text. It is a padding rather than
       a margin because the ROW's left edge is a separate fact, asserted against the item
       rows by setup:spacing-probe (endrow-edge-l); moving the text must not move the box.

       space-between is DELETED, not overridden. It made the gap a function of the card's
       width, so the same control read differently on every shape and at every viewport —
       the pill was not placed, it was left over. The label and the pill are one control
       and now sit one --col-gap apart, the same gutter this row already declared for
       them. There is nothing to right-align to: the row has no right-hand column.

       (padding-right went with space-between. It existed to inset a pill pushed against
       the card's far edge, and nothing is pushed there any more.) */
    /* --space-md, matching the adder's own margin-top above it: the adder and this control
       are the same cluster and the distance between them is the cluster's, not the card's
       object step. */
    margin-top:var(--space-md);
    padding-left:var(--col-flow-x);
}
/* Bebas, at the card's own body size so the control label sits level with the fields it
   governs rather than reading as a second card heading. Case / tracking / leading come
   from the card-name tier tokens, so this cannot drift from the rest of the card's Bebas. */
/* ONE TREATMENT, THREE CONSUMERS — the end-of-section label and BOTH halves of the Total
   Weighting strip. Factored as one declaration block with three selectors rather than
   copied: the strip's label and its value must match that label exactly, and two labels
   agreeing because the same numbers were typed twice is the failure this card keeps
   repeating. There is no value here that exists in more than one place.
   The strip makes no distinction between label and value — both are the same tier, so both
   are in the same selector list rather than one deriving from the other. */
/* THE FAMILY AND TRACKING ARE ONE DECLARATION, SHARED WITH THE STEPPER CELLS.
   The per-criterion NN% and the total's figure are the same reading in two places,
   so they are in one selector list rather than two rules that happen to agree —
   which is what stops them drifting. Split out of the block below rather than
   copied into a second one: each declaration still appears exactly once.
   The stepper cells take ONLY these two. Size, colour and line-height stay with
   their own rules, because those carry state the total row has no equivalent of:
   the value is --grey until weighting is on and --ink after, and its 12px is
   re-declared for the mobile stepper. Both already match the total row at 12px
   and 400, which is why neither needs to move. */
/* DELETED: .tpl-end-toggle-label IS NO LONGER IN THIS LIST, o (above `.tpl-start .tpl-weight-strip-label`) — do not re-add; the reason is T77 in the decision record. */
/* THE WEIGHTING QUESTION'S BUDGET-TOTAL INPUT JOINS THIS LIST, AND ITS SELECTOR IS
   LONG FOR A REASON (2026-09-08). It already wore .tpl-weight-strip-status, so it
   was already in this list at (0,2,0) — and it still computed DM Mono 16px,
   because `.tpl-start .tpl-crit-pair .tpl-crit-part input` declares
   font-family:var(--font-mono) at (0,3,1) and every question-config field is one
   of those parts. Read off the element with CSS.getMatchedStylesForNode, not
   inferred from source order.

   The extra arm is the SAME element addressed through the box it sits in, which is
   what lifts this list to (0,4,1) for that one input and nothing else. It is not a
   specificity digit bought for its own sake, and it does not widen or re-weight the
   shared arm above it: css-specificity.md's rule is that raising a shared rule
   retypes everything relying on losing to it, and this adds a selector rather than
   touching one. Removing the competitor's font-family would have been the other
   route and it is far worse — that arm types every question-config input on DM, MS,
   survey and quiz.

   NO DECLARATION IS RESTATED: the arm joins this block, so the family and the
   tracking still exist exactly once. */
.tpl-start .tpl-weight-strip-label,
.tpl-start .tpl-weight-strip-status,
.tpl-start .tpl-weight-step-input,
.tpl-start .tpl-weight-step-pct,
.tpl-start .tpl-crit-pair .tpl-crit-part input.tpl-weight-strip-status,
.tpl-start .tpl-segment-tag,
.tpl-start .tpl-adv-label{
    font-family:var(--font-heading);
    letter-spacing:var(--tpl-cardname-tracking, 0.02em);
}
/* The segment chips and the + Custom Field link join the label half of the tier
   too — family, size, weight, tracking and colour all reach them from HERE, so the
   chip text and the TOTAL label have one source and cannot drift. Weight is the
   one that changes by omission: this block declares none, so they inherit 400 and
   drop the 700 the segment tier gave them. Their BOX is untouched — the white
   fill, the hairline, the 30px height and the 16px padding all stay on
   .tpl-segment-tag's own rule, which is the point of the two being separate. */
.tpl-start .tpl-weight-strip-label,
.tpl-start .tpl-weight-strip-status,
.tpl-start .tpl-segment-tag,
.tpl-start .tpl-adv-label{
    font-size:var(--tpl-input-size, 16px);
    text-transform:var(--tpl-cardname-case, uppercase);
    line-height:var(--tpl-cardname-line, 1.1);
    color:var(--color-text-primary);
}
/* DELETED: .tpl-end-toggle-hint's whole rule — DM Mono at --t — do not re-add; the reason is T78 in the decision record. */
/* MS ONLY: put the control on the CONTENT column, the same one the rust rule and every
   field box sit on. DM needs none of this — its criterion controls are already inside
   .tpl-edit-field, which IS column 3, so applying these would inset it twice.

   [HARD] THE SELECTOR IS ANCHORED ON THE PANEL, AND THE ANCHOR IS THE WHOLE POINT.
   --tpl-section-col-r contains a PERCENTAGE, and a percentage in a custom property is not
   resolved where it is declared — it is resolved AT THE POINT OF USE, against whatever
   containing block the consumer has. These values mean "the content column" only for a
   normal-flow child of the section body panel, which is the same containing block the
   rust rule's ::before uses. So the selector names that panel (`.tpl-section-band +
   .tpl-flat-subcard >`) rather than the card.

   Written first as `.tpl-section-block > .tpl-end-toggle`, which matched NOTHING — on MS
   the control is inside the panel, so the card is its grandparent — and the divider
   rendered at the panel's full width instead, visibly wider than the rust rule directly
   above it. Loosening that to a descendant selector would have "fixed" it and quietly
   armed the percentage trap for the WORKSHOP MS card, which has no band and therefore no
   panel: there the same expression resolves against the card's own padding box and comes
   out --tpl-section-inset wrong on the left and twice that on the right. A workshop MS
   card gets no margins at all and sits at the card's content edge, like its compare line.
   Do not position this element, and do not widen this selector. */
/* DELETED: `margin-left:var(--tpl-section-col-l)` — do not re-add; the reason is T79 in the decision record. */
/* DM: it takes a full row of the criterion's controls, with the weighting row below it. */
/* DM: it takes a full row of the criterion's controls, with the weighting row below it.
   ITS COLUMN IS THE CRITERION'S FIELD TEXT, AND THAT IS THE SAME RULE, NOT AN EXCEPTION.
   A criterion card holds no item list — DM's items live in their own well on the session
   card — so there is no "+ Add item" above this toggle to align to; the rows it sits
   among are the name / description / question FIELDS, whose text starts one field border
   plus --tpl-field-inset inside the card. `1px +` is the page's existing idiom for
   clearing that border (the question adder's own margin reads
   `calc(1px + var(--tpl-field-inset) + var(--col-line-x))`), not a new measurement.
   Measured at 1280: label 447.19 against the criterion name's 448.19 before, both 448.19
   after. Forcing --col-line-x here would put the label at 497.19, level with nothing. */
/* [HARD] `--tpl-field-inset` IS GONE FROM THIS PADDING (2026-08-24), 1px REMAINS. The note
   above describes what it cleared: "one field border plus --tpl-field-inset inside the
   card". The field inset is not inside the card any more — it moved into --col-line-x when
   the underline came onto the text — so keeping the term double-counted it and put this
   label 12px right of the criterion name it lines up with. Caught by setup:spacing-probe
   (any:endrow-label-l is 12px and must be 0), which is precisely the relationship it
   watches. The 1px is still the pair's border and still real. */
/* ONE MECHANISM FOR THE LABEL STEP, NOT TWO — the same rule #tpl-where-row states for the
   same reason. This row is a flex column whose `gap` supplies its rhythm; .tpl-crit-tag also
   carries margin-bottom:6px, and both live would read 12px against LOCATION's 6. The
   label's own margin is the redundant one, so it is zeroed here rather than the gap being
   set to 0 — the gap is the row's, the margin is the tier's, and the row is what differs. */
.tpl-start .tpl-end-toggle > .tpl-crit-tag{margin-bottom:0;}
.tpl-start:has(#tpl-add-criterion-btn) .tpl-crit-ctrls > .tpl-end-toggle{
    flex:0 0 100%;
    padding-left:1px;
}
/* ── MS QUESTION ROWS — no tinted card, no gap; the 01/02 markers do the grouping ──
   A Questions / Quiz section rendered each question as a tinted bordered sub-card with
   14px between them, so one section read as a stack of cards. The rows now sit on the
   SECTION BODY PANEL's background exactly as the item rows do (it was the section card's
   own background until the panel was added; either way it is ONE surface shared with the
   item rows, which is the point), and the NUMBERS carry the grouping — which is why
   nothing replaces the border.

   MS ONLY, and it must stay that way: [data-question-wrap] is the SHARED question
   component (flat, survey and DM render the same card). The :has(#tpl-add-section-btn)
   gate is absent from every one of those pages, so the override cannot reach them —
   verified by element count, not by reading. question-types.js keeps declaring the card;
   this only switches it off here.

   The bonded-box treatment those rows briefly got is GONE — see THE MS QUESTION CARD
   below. A question is a thing in its own right, so it gets a card of its own; this rule
   stays because the card is now painted by .qt-card, one level in, and the wrap is the
   rail-plus-card ROW around it. */
/* DELETED: `background:transparent;border:0;padding:0` — do not re-add; the reason is T80 in the decision record. */
/* DELETED: `margin-bottom:0 !important` — do not re-add; the reason is T81 in the decision record. */
/* ── THE MS QUESTION CARD ──────────────────────────────────────────────────────────
   [HARD] THIS REPLACES THE BONDED STACK, it does not layer over it. Everything the
   two previous passes built for that shape is DELETED here, not overridden: the three
   members' shared border/width/padding block, the -1px seams, the opening/closing
   radius rules (including the `:not(:has(~ [data-question-wrap]))` last-row form and
   the "list joins the card's one box" pair), the .qt-type-col flex/order/align-self
   neutralisation, the wrap-level --col-line-x offsets, the chrome-less type-control
   height reset, the empty-config margin kill, and the .qt-subcard STACK-BREAK CARVE-OUT
   with its reopening pair. A restyle that leaves the old rules inert underneath is a
   failed restyle, and every one of those selectors would now be inert: the members are
   inside a card, not bonded to each other.

   THE SHAPE. The wrap is a ROW: [drag][01][card]. The rail entries mount at wrap level
   from renderList's stacked branch, so the marker sits BESIDE the card — a rail entry
   belongs to the rail, not to the thing it numbers. The card's own three lines are the
   .qt-q-row (type chip + the ×/⧉/▸ cluster), .qt-input-col (the prompt), .qt-guidance
   (the hint), plus the type's config inside it.

   GEOMETRY IS THE CONTRACT, NOT A LITERAL. The wrap reuses .tpl-item-row's flex + gap,
   so the card starts where every other line on this card starts — the drag gutter and
   the numeral column place it, exactly as they place an item's underline. Nothing here
   sets a left offset. */
/* DELETED: `display:flex;align-items:flex-start;gap:var(--col-gap)` — do not re-add; the reason is T82 in the decision record. */
/* THE RAIL ENTRIES, beside the card's first line. Their COLUMN — width, the drag-gutter
   offset, and the way that offset drops when a drag handle is present to occupy it — is
   the component's, which now enumerates both of the containers it mounts these in. None
   of it is restated here. */
/* DELETED: `align-self:flex-start;margin-top:11px` — do not re-add; the reason is T83 in the decision record. */
/* DELETED: `.tpl-questions-list > [data-question-wrap] > .tpl-question-drag-handle` — do not re-add; the reason is T84 in the decision record. */
/* DELETED: `:has(#tpl-add-section-btn) .tpl-section-block .tpl-questions-list` — do not re-add; the reason is T85 in the decision record. */
/* DELETED: `.tpl-start .qt-type-col .qt-tag` — do not re-add; the reason is T86 in the decision record. */
/* The menu is the chip's menu, so it opens on the chip's left edge at a readable width
   rather than inheriting the full-width form the bonded member had. min-width beats the
   control's own narrow measure; max-width keeps it inside the card.

   SOLE CONSUMER NOW: the per-question type chip (.qt-type-col). The MS section type
   control had a `.tpl-section-band .qt-popover` arm here through 2026-08-29 — deleted
   with the popover itself; the tab strip that replaced it opens no menu, so there is
   nothing left to anchor. See THE MS SECTION TYPE CONTROL HAS LEFT THESE SELECTORS
   above THE CHIP.

   [HARD] READ THE ANCHOR OFF THE CHIP'S POSITION IN ITS ROW, NEVER OFF THIS FILE'S
   HISTORY. The invariant is "the menu opens away from the card's nearer edge": a chip at
   the START of a row opens left (this is left:0), one at the END opens right. If the
   question card's chip moves again, change this WITH it in the same commit and verify
   with elementFromPoint — the failure renders as a perfectly visible box with no
   ancestor transform, opacity or filter, so visibility and bounding-box checks both pass
   while the menu is off the card.

   `max-width:100%` is NOT what keeps it on the card: the percentage resolves against the
   containing block, which is .qt-tag-wrap — the chip itself, ~97-132px — so min-width
   240px wins and 100% of a narrow trigger constrains nothing. It stays as the right cap
   if the menu ever gains a wider intrinsic measure; it is simply not load-bearing.
   right:auto is stated because the component's own .qt-popover sets both edges; without
   it they pin and the menu stretches to the trigger's width. */
.tpl-start .qt-type-col .qt-popover{
    width:auto;
    min-width:240px;
    max-width:100%;
    left:0;
    right:auto;
}
/* (THE PROMPT's metrics, THE HINT and THE TYPE'S CONFIG moved to question-types.js with
   the card — same reason, same place. Two of them also CHANGED on the way:

   • THE HINT lost its caption rules entirely. `> .qt-guidance{display:flex;gap:9px}` plus
     `> .field-label{flex:0 0 auto;padding-top:4px;white-space:nowrap}` existed to lay a
     caption BESIDE the field. The caption is gone from the markup, so the flex row it was
     half of is gone with it.
   • THE PROMPT lost its conditional hairline. `:has(> .qt-input-col ~ *)` drew a rule
     under the prompt whenever something followed it inside the card — MS's texture, and
     not Slide's: the canvas heading carries no underline and its instruction sits
     straight below it. That declaration is SHARED with the comparison card, whose arm is
     untouched and still live; only the question-card arm went. */
/* ── QUIZ ANSWERS: the caption-hide and "restyled radio group" rules that sat here
   DELETED (P6c, 2026-09-18) — both targeted .qt-subcard-label and .qt-correct-label,
   the standalone radio row's classes, and neither has an emitter anywhere. Do not
   re-add; docs/type-scale-proposal-2026-09-18.md §1.3. */
/* The circle takes the column the option numeral used to hold, so the numeral goes: two
   markers in one column is the thing the rail rules out everywhere else on this card, and
   between "01" and "which one is right" the second is what a quiz author is looking for. */
.tpl-start:has(#tpl-add-section-btn) .tpl-section-block .tpl-questions-list .qt-card .qt-opt-row:has(.qt-correct-radio) > .tpl-item-num{
    display:none;
}
.tpl-start:has(#tpl-add-section-btn) .tpl-section-block .tpl-questions-list .qt-card .qt-opt-row{
    align-items:center;
    /* [HARD] NOWRAP. The component ships .qt-opt-row{flex-wrap:wrap} for the layout where
       the "Correct" control took a whole second line by design (it carries
       `order:1;flex:1 0 100%`). Here the row is circle → answer → badge → ×, and at 390
       the four did not fit, so it wrapped: measured, the badge and the × dropped below
       their own answer and the second option's × landed alone under it, reading as a
       control belonging to nothing. The answer field is the only elastic member and
       already carries min-width:0, so forbidding the break makes it shrink instead —
       which is what should give, since the other three are fixed-size marks. */
    flex-wrap:nowrap;
    gap:10px;
    margin-bottom:2px;
    padding:5px 8px 5px 6px;
    border-radius:var(--radius-inset-row);
}
.tpl-start:has(#tpl-add-section-btn) .tpl-section-block .tpl-questions-list .qt-card .qt-correct-radio{
    order:-1;
    flex:0 0 auto;
    -webkit-appearance:none;
    appearance:none;
    width:19px;
    height:19px;
    border:1.5px solid var(--color-border);
    border-radius:var(--radius-disc);
    background:var(--color-white);
    cursor:pointer;
}
/* CHECKED: filled in --quiz-correct with a white tick.
   [HARD] NO NEW TOKEN WAS MINTED FOR THIS, and one nearly was. The quiz "correct" green
   was the one value this restyle expected to have to invent — but tokens.css already
   carries a whole quiz family (--quiz-correct / --quiz-correct-bg / --quiz-correct-strong
   / --quiz-correct-line), swept onto the brand green in the 2026-07-13 results colour
   consolidation and read today by the results scorecard's answer pills and ticks. A
   fresh --quiz-correct declared earlier in the same file simply LOST to it, which is how
   the collision surfaced: the row tint took the new channel while the circle and the
   badge took the old hue, so the two greens on one row disagreed. Measured, then deleted.
   Using the family instead is also the better answer on its own terms: the colour a
   facilitator marks an answer with and the colour a respondent sees it marked in are now
   one decision, and the tint has an authored --quiz-correct-bg rather than an alpha wash
   invented here.
   The tick is a data-URI SVG background rather than a pseudo-element because ::after on
   an input is only reliable once appearance:none has made it non-replaced, and that is
   engine-dependent; a background paints the same on all of them. `data:` is already in
   the CSP's img-src, so this adds no directive.
   THE GLYPH ITSELF MOVED to --quiz-tick-svg in tokens.css (Session 176), because the
   wizard identity fields' completion badge is the same circle+check at a smaller scale.
   The data-URI was the one part of this mark that would have had to be copied to get a
   second one, so it is the part that became a token; the family's colours were already
   there. Only the diameter and background-size differ between the two consumers. */
.tpl-start:has(#tpl-add-section-btn) .tpl-section-block .tpl-questions-list .qt-card .qt-correct-radio:checked{
    border-color:var(--quiz-correct);
    background-color:var(--quiz-correct);
    background-image:var(--quiz-tick-svg);
    background-repeat:no-repeat;
    background-position:center;
    background-size:13px 13px;
}
.tpl-start:has(#tpl-add-section-btn) .tpl-section-block .tpl-questions-list .qt-card .qt-correct-radio:focus-visible{
    outline:2px solid var(--quiz-correct);
    outline-offset:2px;
}
/* THE BADGE — .qt-correct-label > span's "Correct" word DELETED here (P6c,
   2026-09-18), both the resting rule (font-size:11px, one of the P6c census's 8
   dead sites) and its opacity:1 arm below — .qt-correct-label has no emitter
   anywhere. Do not re-add; docs/type-scale-proposal-2026-09-18.md §1.3. */
/* The whole row carries the state, in the family's own authored tint — --quiz-correct-bg
   is the pale green the results scorecard already fills a correct answer pill with, so
   the two surfaces agree without either one picking a colour. */
.tpl-start:has(#tpl-add-section-btn) .tpl-section-block .tpl-questions-list .qt-card .qt-opt-row:has(.qt-correct-radio:checked){
    background:var(--quiz-correct-bg);
}
/* DM (flush): the comparison line fills the criteria NAME column (it is a child of the
   name .tpl-edit-field), so name + question share one left edge and length. The item list
   is left-aligned (not the centred band); each row carries the empty drag+gap gutter so its
   numeral lands under the criteria letter and its band underline under the name/question. */
.tpl-start:has(#tpl-add-criterion-btn) .tpl-section-block .tpl-section-prompt-wrap{justify-content:flex-start;}
.tpl-start:has(#tpl-add-criterion-btn) .tpl-section-block .tpl-section-prompt-wrap > .tpl-edit-field{flex:1 1 auto;width:100%;max-width:none;}
.tpl-start:has(#tpl-add-criterion-btn) #tpl-items-list:not(.tpl-questions-list){align-items:stretch;width:100%;box-sizing:border-box;}
.tpl-start:has(#tpl-add-criterion-btn) #tpl-items-list:not(.tpl-questions-list) > .tpl-item-row{width:100%;max-width:none;}

/* + Item / + Question / + (per-section name) add buttons. The dashed
   border that used to wrap this button is gone — the button now reads
   as a continuation of the numbered item rows above it: the "+" glyph
   sits in a 32px right-aligned column (matching .tpl-item-num) and the
   trailing label span starts at the same x-position as the item-input
   text (32px + 10px gap = 42px from row left). Same flex columns + gap
   as .tpl-item-row, so the alignment stays exact regardless of which
   items list this button trails. Margin/padding both 0 so the gap from
   the last .tpl-item-row's margin-bottom (8px) is the only spacing —
   matching the inter-item rhythm. */
.tpl-add-item{margin:0;padding:0;background:none;border:none;letter-spacing:var(--type-caption-tracking);cursor:pointer;display:flex;align-items:center;gap:var(--gap-tight);}
.tpl-add-item:hover{color:var(--color-text-primary);}
.tpl-add-item-plus{flex-shrink:0;width:2rem;text-align:right;font-family:var(--font-heading);font-size:var(--type-panel-title);color:var(--color-text-primary);line-height:1;}
/* DELETED: `.tpl-add-item-label{letter-spacing:0}` — do not re-add; the reason is T87 in the decision record. */

/* NO margin-top: this is a form-grid child, so the gap above it is the grid's
   row-gap like every other card's. The 14px that stood here was inert only because
   the element is display:none until an error fires. */
.tpl-error{font-family:var(--font-mono);font-size:var(--type-caption);color:var(--error-red);display:none;}
.tpl-error.shown{display:block;}

/* Lock-on-responses: once a session has real (non-preview) responses its
   structural content — section / criteria cards, their items, questions and
   images — is read-only (updateFromSetup ignores posted structural data when
   locked). The cards stay VISIBLE and can still be expanded/collapsed so the
   facilitator can review their content; only the editable inputs are inert
   (dimmed) and the structural mutation controls (add / remove / drag / mode
   switch) are hidden.

   Scoping is by structural marker, NOT the shared .tpl-section-block class:
   per-section cards carry .tpl-added-card; the flat item list is
   #tpl-items-list. The SCALAR setting cards — Welcome/Intro
   (#tpl-welcome-page-card), Completion message (#tpl-completion-message-card)
   and Advanced Settings — also carry .tpl-section-block but are deliberately
   NOT matched here, so they remain fully editable + saveable (the server's
   scalar half persists them even when locked). */

/* Editable guts: visible but inert + dimmed.
   The old `.tpl-added-card > :not(.tpl-edit-row--header)` carve-out is gone: it
   tried to keep the card header interactive by NOT freezing it, but every
   .tpl-added-card lives inside #tpl-structural-region, whose blanket
   pointer-events:none (below) froze the header anyway — including the collapse
   chevron, so a locked session's cards could not be opened to read. Exempting an
   element from one `pointer-events:none` rule cannot undo another; only an
   explicit `pointer-events:auto` can, which is what the chevron now gets below.
   Its opacity half was redundant too (the region rule dims the same children). */
.tpl-start.structural-locked #tpl-items-list{pointer-events:none;opacity:0.55;}

/* Structural mutation controls — hidden entirely when locked.
   .tpl-section-type-select is NOT in this list (2026-08-29): it used to hide the whole
   type control on lock, leaving nothing to show which type a locked section was. Now
   _section-type-select.blade.php renders a DIFFERENT, non-interactive markup when
   $structuralLocked — .tpl-section-type-select--locked, a plain label, no tabs to hide —
   so there is nothing left for a display:none rule to do here; hiding it would hide the
   label the locked branch exists to show. */
.tpl-start.structural-locked .tpl-added-card .tpl-section-drag-handle,
.tpl-start.structural-locked .tpl-added-card .tpl-card-remove,
.tpl-start.structural-locked .tpl-added-card .tpl-section-mode-seg,
.tpl-start.structural-locked .tpl-add-item,
.tpl-start.structural-locked .tpl-item-remove{display:none;}
/* Participant Data's field editor is the same case, one surface along:
   participant_fields are scalar settings that keep auto-saving on a locked
   session, so borrowing the shared row × for the custom-field dismiss would
   otherwise let the lock sweep above hide it and strand the form open with no
   way back. Same exemption, same reason — reusing the shared class means
   inheriting its rules, including this one. SCOPED TO #tpl-participant-data-card,
   NOT #tpl-sidebar-segment-panel — the field editor moved out of the rail into
   the card 2026-08-31; the card holds no OTHER .tpl-item-remove, so the whole
   card is the exemption's scope, same as the rail panel was. */
.tpl-start.structural-locked #tpl-participant-data-card .tpl-item-remove{display:inline-block;}
/* #FBF3E7 / #E4C893 - no token, one-off warning-amber lock note */
.tpl-structural-lock-note{margin:0 auto var(--inset-panel);max-width:760px;background:#FBF3E7;border:1px solid #E4C893;border-radius:var(--radius-notice);padding:var(--inset-box) var(--inset-panel);line-height:var(--type-line-prose);text-align:center;}
/* Structural lock — when responses exist (<main>.structural-locked) every
   interactive control inside the items/questions/sections editor is frozen:
   pointer-events:none kills focus / clicks / drag, the editor content dims,
   and the add/remove affordances are hidden. The lock banner (first child of
   the items card) is exempted from the dim so it stays legible. The Welcome /
   Completion / Advanced settings cards live OUTSIDE #tpl-structural-region and
   are unaffected — they keep auto-saving. */
.tpl-start.structural-locked #tpl-structural-region{pointer-events:none;}
.tpl-start.structural-locked #tpl-structural-region .tpl-form-card > *:not(.tpl-structural-lock-note){opacity:0.55;}
.tpl-start.structural-locked #tpl-structural-region .tpl-add-item,
.tpl-start.structural-locked #tpl-structural-region .tpl-item-remove{display:none;}
/* …with exactly one exception: the collapse/expand chevron. Reading a locked
   session is allowed — only editing it isn't — and the cards render collapsed,
   so freezing the chevron made a locked session's own content unreachable.
   pointer-events is re-enabled on .tpl-card-collapse ONLY, never on the whole
   .tpl-edit-row--header: the header also carries the section-name inline edit,
   which must stay inert. */
.tpl-start.structural-locked #tpl-structural-region .tpl-card-collapse{pointer-events:auto;cursor:pointer;}

/* ── AN AVAILABILITY POLL'S MANAGE PAGE WEARS NONE OF THE ABOVE (2026-09-10) ──
   AND THERE IS NO RULE HERE FOR IT, WHICH IS THE POINT. The class is simply not
   emitted for a poll (TemplateController::editViewVars), so the badge, the
   labels, the opacity and the pointer-events all follow together instead of
   needing an override each. The earlier
   `.structural-locked.slim-mode #tpl-slim-cal-mount{pointer-events:auto;opacity:1}`
   carve-out is DELETED with it — it existed only to reach past this block, and a
   poll no longer enters it.

   Every other template is untouched: `.structural-locked` still means what it
   always did, and still gets it whenever responses exist. */
/* Auto-save feedback flag — a small "Saved" / "Save failed" label rendered
   next to a field after a /meta auto-save. Saved fades out; failed stays red.
   Font is the canonical DM Mono 12px .tpl-mono (added on the element in JS);
   text-transform:uppercase is scoped HERE rather than on .tpl-mono because that
   shared tier also styles data displays (viewer-link / image URLs, filenames,
   embed code, project names) that must NOT be force-uppercased. */
.tpl-autosave-flag{display:inline-block;margin-left:var(--inset-control);letter-spacing:var(--type-caption-tracking-tight);vertical-align:middle;text-transform:uppercase;transition:opacity 0.4s ease;}
.tpl-autosave-flag--ok{color:var(--success);}
.tpl-autosave-flag--err{color:var(--red-dark);}
/* A refusal carries the server's own sentence, which is longer than "Save failed" and
   is a sentence rather than a label — so the error state alone drops the uppercase and
   is allowed to wrap inside the rail. The OK state is untouched: it is still the small
   uppercase "Saved" flag, and nothing about its geometry moves. */
.tpl-autosave-flag--err{
    text-transform:none;
    letter-spacing:var(--type-caption-tracking-none);
    max-width:100%;
    white-space:normal;
    line-height:1.35;
}
/* Toggle saves anchor the flag to their .tpl-pill-toggle (so it lands AT the
   toggle, not after the whole header/advanced row). When the flag is the pill's
   immediate sibling, drop it onto its own full-width line so it sits directly
   UNDER the toggle (right-aligned, matching the right-hand toggle). flex-basis is
   for the flex toggle rows (.tpl-block-header-toggles etc.); width covers the
   non-flex ones. Field-blur flags aren't after a pill, so they keep inline. */
.tpl-pill-toggle + .tpl-autosave-flag{flex-basis:100%;width:100%;margin:var(--nudge) 0 0;text-align:right;}

/* Save & Continue — the draft trigger at the foot of the Overview card.

   GREEN AGAINST THE RED PRIMARY, AND THE TWO NEVER SHARE A ROW. --red is this
   page's primary-action colour and it belongs to the one button that finishes
   setup (.tpl-continue, at the bottom of the form). Green is the palette's
   open/on colour, and that is close enough to what this button does — it brings
   the session into existence — to be read rather than decoded. They are ~800px
   apart in the layout and never adjacent, so the pairing is sequential (save as
   you go, here; finish, there), not a choice between two equally-weighted CTAs.
   Deliberately SMALLER than .tpl-continue — 44px against 48px, 2rem of side
   padding against 2.5rem — so nothing about it competes for primary.

   IT HAS A DISABLED STATE, WHICH .tpl-continue DELIBERATELY DOES NOT. That button
   is always enabled because its validation is a whole form and the useful thing
   to do on failure is point at the field; this one has exactly one precondition
   (a title), the facilitator is looking straight at the field, and there is
   nothing to explain. The server enforces the same rule regardless — a disabled
   control is never the enforcement point. */
.tpl-draft-save-row{display:flex;justify-content:center;margin-top:20px;}
.tpl-draft-save{
    background:var(--green);
    color:var(--color-white);
    border:none;
    border-radius:var(--radius-square);
    font-family:var(--font-heading);
    font-size:var(--tpl-cta-size);
    letter-spacing:var(--type-caption-tracking-wide);
    padding:0 2rem;
    height:44px;
    cursor:pointer;
}
.tpl-draft-save:hover:not([disabled]){background:var(--green-dark);}
.tpl-draft-save[disabled]{opacity:0.4;cursor:default;}
.tpl-draft-save-row[hidden]{display:none;}
@media(max-width:640px){
    .tpl-draft-save{width:100%;}
}

/* Project dropdown — switcher-styled. Reuses .tpl-switcher-trigger /
   .tpl-switcher-menu / .tpl-switcher-item from templates.css so it matches
   the page's template switcher exactly. Start-screen-specific bits only:
   anchor the absolute menu, the muted placeholder + clear item, the "Create
   New Project" divider row, the inline create input, and the open-state
   chevron/border (the shared rules key off .tpl-switcher, not this wrapper).
   The menu items are <button>s (inside the form), so they need a button
   reset + their own hover — the shared a.tpl-switcher-item:hover only targets
   <a>. No border-radius (D-CSS-NO-BORDER-RADIUS-CARDS). */
/* (The guest "Save Details" switcher root / trigger / menu rules were removed
   with the dropdown itself — see _save-project-block.blade.php.) */
/* Template switcher (setup / manage) — max-content fix. The 300px min-width floor
   made the menu wider than its content; right-
   aligned to the trigger at the 840px card's right edge it read as "pushed right
   with empty space to its left". Dropping the floor lets the menu hug its content
   directly under the trigger (hint spans are display:none, so max-content tracks
   the longest visible label, not the hidden hint text). Scoped to #tpl-switcher-menu
   so the home/method switchers, the project menu and the participant custom-select
   — all sharing .tpl-switcher-menu — are untouched. Same
   template-switcher.js fixed-overlay right-align. */
#tpl-switcher-menu{min-width:0;width:max-content;}
/* Save To Project — heading + ON/OFF slider toggle + in-flow project panel,
   stacked (right-aligned). The trigger button the dropdown used to have is gone:
   the .tpl-pill-toggle now gates the panel. */
.tpl-project-toggle-wrap{display:flex;flex-direction:column;align-items:flex-end;}
/* Save To Project block — ONE canonical position for EVERY session shape (flat /
   DM / MS / survey / slim) on BOTH setup and manage, and for signed-in AND guest:
   the top-right corner of the session-fields well (.tpl-setup-fields-well). The well
   is the positioning context (position:relative) and the block is absolutely anchored
   to its top-right, out of flow, so the centred Session Title below is untouched
   and sits tight beneath it. This single rule REPLACED three divergent per-shape
   treatments — the old modes-row anchor (top:-6px;right:0), the MS
   :has(#tpl-add-section-btn) down-and-left nudge (top:12px;right:80px), and the
   slim toggle top:11px nudge — plus the guest in-flow modes-row workaround. Do NOT
   reintroduce a per-shape override; adjust this one anchor instead. The
   .tpl-project-toggle-wrap is a flex COLUMN (align-items:flex-end) so the label —
   and, when the toggle is ON, the project panel — flow DOWNWARD below the toggle,
   right-aligned. z-index keeps the open panel above the cards beneath. */
/* Header (Session Overview) card — BALANCED top/bottom padding, defined ONCE via the
   shared --space scale so every shape reads symmetrically: equal whitespace above the
   first content (Session Title) and below the last. --space-lg (24px) ≈ the card's
   22px horizontal inset (uniform box all round) and is a generous increase over the
   old signed-in-create 6px top tuck (removed above). Every shape — flat / DM / MS /
   survey and slim — shares this one value. Slim's S153 top-chrome hides (mode toggle
   #tpl-modes-block + the empty facilitator header) stay hidden, so this is real
   whitespace, not padding around a reserved empty box. position:relative is kept for
   safety, but the Save To Project block now anchors to the inner session-fields well
   (.tpl-setup-fields-well), not this card — see below. */
/* [HARD] NO padding override here any more (Session 176). This card carried
   padding-top/bottom:var(--space-lg) (24px) against every other card's 18px, so its
   heading sat 6px lower than all five siblings. The comment justifying it said the
   balanced 24px gave "equal whitespace above the first content (Session Title) and
   below the last" — which was true only while this was the ONE card with no heading:
   its first content was an input, not a header row. It has a heading now, so it is the
   same shape as every sibling and takes the same .tpl-form-card padding. Do not
   reintroduce a per-card override; if the card padding is wrong it is wrong for all of
   them and belongs on .tpl-form-card. */
.tpl-start #tpl-session-setup-card{position:relative;}
/* (The margin-bottom:0 reset for #tpl-modes-block as a DIRECT child of this card is
   gone with the toggle: the Individual/Group control no longer renders inside the
   card on any shape — it sits in the MODE CONTROLS slot above it — so the selector
   could never match again. Its base .tpl-modes-block 20px bottom margin is now the
   wanted gap between the mode controls and the card below them.) */
/* The Save To Project block is IN FLOW, in the sub-card's header row beside the
   SESSION DETAILS heading — the same slot the WELCOME / COMPLETION / ADVANCED cards put
   their toggle in. It used to be position:absolute, pinned top:6px/right:12px against
   the well; that pin is GONE and must not come back. See the header-row markup for the
   two measured reasons (the old input-alignment was a coincidence that degrades from
   -6px to -40px the moment a heading exists; and ≤480 already rendered this block in
   flow, so flow removes a desktop/mobile divergence rather than creating one).

   z-index:20 is KEPT, and is not vestigial: the project picker panel (.tpl-project-menu)
   is position:static INSIDE this block, so an open panel is painted by this block and
   still has to stack above the cards beneath it.

   .tpl-setup-fields-well keeps position:relative — it is the positioning context for
   .tpl-fac-ph, the drawn placeholder on the four identity fields. It is NOT left over
   from the deleted pin. (Removing a position:relative because "the thing it positioned
   is gone" is precisely what took this page down on 2026-08-03.) */
.tpl-start .tpl-setup-fields-well{
    position:relative;
    /* THE CONTAINER OWNS THE RHYTHM. The fields used to space themselves — every
       .tpl-fac-input carried margin-bottom:8px, and the facilitator block carried
       a relocated 8px above and below. A child owning spacing that belongs to the
       row is why Individual mode ended up with 13px above the field and 21px
       below: the trailing margin had nothing after it to separate from. A gap
       applies only BETWEEN rendered flex items, so it cannot leave a trailing
       edge, and it needs no per-mode reset — Individual (one rendered item) and
       Group (three) come out symmetric from the same declaration.
       Column flex keeps the block behaviour the children already had:
       align-items defaults to stretch, so every row is still full-width.

       --stack-gap (14px), DOWN FROM --space-md (16px). The well's rows each carry a
       .tpl-crit-tag label above the field now, and a label adds its own 12px + 4px to
       every perceived gap — at 16px the matched pair read as two separate objects
       with a corridor between them instead of as one heading block.
       --stack-gap is not a new number: it is the setup card's ONE object-to-object
       vertical role (templates.css, and the setup:spacing-probe gate asserts it for
       every other card-internal pair on this page), so the heading well now keeps the
       same rhythm as the criterion parts, the section bodies and the item rows rather
       than holding a private value one step off them. --space-md was chosen when
       these rows were four bare boxes with no labels; that premise is gone. */
    display:flex;
    flex-direction:column;
    row-gap:var(--step-row);
}
/* SLIM (Availability Poll) takes the next step up the same scale, because its rows
   are LABELLED — Description and Participant Instructions each carry a caption above
   the box, so the same gap reads tighter there than it does between four bare boxes.
   This is the container owning it for slim too: the three `margin-top:18px` child
   margins that used to sit on #tpl-where-row / #tpl-welcome-intro-body /
   #tpl-flat-questions-body are DELETED with this line, so slim stops being 26/26/26/8
   (the facilitator row 18px tighter than everything above it — the same defect the
   non-slim card was reported for) and becomes one even 24px throughout. Net: three
   declarations out, one in, and the well has a single owner on BOTH shapes. */
.tpl-start.slim-mode .tpl-setup-fields-well{gap:var(--space-lg);}
.tpl-start #tpl-save-project-block{position:relative;z-index:var(--z-raised);}
.tpl-project-toggle-heading{margin:var(--nudge) 0 0;white-space:nowrap;}
/* Selected-project confirmation beside / below the toggle (hidden when empty). */
.tpl-project-confirm:empty{display:none;}
.tpl-project-item.is-selected{color:var(--color-text-primary);background:rgba(var(--red-rgb),0.06);}
/* Project panel stacks IN-FLOW within the block: overriding the shared
   .tpl-switcher-menu (position:absolute) to position:static drops the open panel
   into normal flow inside #tpl-save-project-block, below the toggle + label
   (.tpl-project-toggle-wrap is a flex column), so the picker grows the block's own
   height downward. Because the block itself is absolutely anchored to the card's
   top-right (out of the card's flow), an open panel overlays the fields beneath it
   — matching the flat design. No footprint when the toggle is OFF (the JS sets
   [hidden]). This is a slider-gated persistent picker, NOT a transient dropdown, so
   it deliberately stays in-flow within the block — it is NOT migrated to the fixed
   overlay. */
.tpl-project-menu{position:static;margin-top:var(--gap-tight);width:max-content;max-width:100%;}
.tpl-project-menu .tpl-switcher-item{width:100%;background:none;border:none;text-align:left;cursor:pointer;}
.tpl-project-item:hover,.tpl-project-create-item:hover{background:var(--wash);}
.tpl-project-create-row{border-top:1px solid var(--rule-weak);margin-top:var(--gap-tight);padding-top:var(--gap-tight);}
.tpl-project-create-form{margin-top:var(--inset-control);display:flex;gap:var(--gap-tight);align-items:stretch;justify-content:flex-end;}
.tpl-project-create-input{width:150px;max-width:100%;box-sizing:border-box;border:1px solid var(--border-strong);border-radius:var(--radius-square);background:var(--color-white);padding:7px 12px;outline:none;}
.tpl-project-create-save{flex-shrink:0;background:var(--ink);color:var(--on-ink);border:1px solid var(--border-strong);border-radius:var(--radius-square);font-family:var(--font-heading);font-size:var(--type-caption);letter-spacing:var(--type-caption-tracking-wider);text-transform:uppercase;padding:0 var(--inset-box);cursor:pointer;}
.tpl-project-create-save:hover{background:#000;} /* no token - pure-black hover, one-off */

/* DM "RANK ITEMS" card header — the mode heading STACKED above its Items | Images
   toggle, both left-aligned to the --tpl-crit-indent column so their left edge
   matches the item-row input below them (the same anchor as the criterion NAME
   text, the comparison-question line, and the "+ Add Item" / "+ Add Criteria"
   buttons). flex-direction:column stacks heading → toggle.

   `align-items:flex-start` DELETED. Its job was "keep each child at the row's left
   so the per-child indent below governs their edge" — and there is no longer a
   per-child indent, nor a second child: the heading left this row for
   _flat-items-heading, and the toggle now centres under that heading via
   margin-inline:auto below. Auto margins beat align-* for free space anyway, so
   keeping it would have been a declaration that reads as the authority on this
   row's alignment while losing to the line under it. */
.tpl-flat-items-header{flex-direction:column;gap:var(--inset-control);}
/* DELETED: `.tpl-flat-items-header #tpl-flat-items-label` — do not re-add; the reason is T88 in the decision record. */
/* Toggle directly below the centred OPTIONS TO COMPARE heading, centred with it —
   the SAME expression flat blank's #tpl-rank-type-toggle uses, so the one control
   centres by one mechanism on both shapes that render it. margin-inline replaces
   the old margin-left:var(--col-num-x) crit-indent anchor (and made its DM
   companion `…:has(#tpl-add-criterion-btn) … #tpl-stype-toggle{margin-left:0}`
   dead, deleted above). Auto margins absorb the cross-axis free space in a column
   flex, which is what centres an inline-flex child of content width. */
.tpl-flat-items-header #tpl-stype-toggle{margin-inline:auto;}
/* DELETED: `#tpl-flat-items-label{font-size:var(--tpl-heading)}` — do not re-add; the reason is T89 in the decision record. */
/* Self-Paced / Workshop toggle slot (every non-slim type: flat blank, DM,
   multi-section) — the centred flex container in the whitespace between the Overview
   card and the Welcome / Introduction Page card, holding the relocated
   #tpl-workshop-toggle-row. Empty in Individual mode (and flat-blank Ranking mode) →
   collapses so it adds no gap; when the toggle is revealed (Group mode; flat blank in
   Survey mode) it spaces it. Margin: flat blank via .flat-survey; DM / multi-section
   via Group mode (the :not(:has(#tpl-rank-type-toggle)) arm excludes flat blank, which
   would otherwise gap in Group + Ranking where the toggle is hidden). */
#tpl-workshop-toggle-slot{display:flex;justify-content:center;}
/* DELETED: `margin:6px 0 16px` — do not re-add; the reason is T90 in the decision record. */
/* Items | Images sub-toggle in its in-card home under "The Items". The toggle is an
   inline-flex .tpl-stype-toggle; the base rule makes it a fit-content block. Hidden in
   Survey mode by _applyFlatMode (by id). The "The Items" sublabel's own
   .tpl-block-header-row margin is tightened so the toggle sits snug beneath the heading
   (overrides the default 10px). Both Individual and Group mode anchor the toggle's left
   edge to var(--tpl-crit-indent) — 0 for flat blank — so it lines up under the left edge
   of the "The Items" heading text (same crit-indent in both modes), matching the item
   rows and the Add button. */
/* DELETED: `#tpl-flat-items-sublabel{margin-bottom:2px}` — do not re-add; the reason is T91 in the decision record. */
/* ── THE CENTRED SECTION HEADINGS ARE DELETED ─────────────────────────────────
   What stood here: OVERALL QUESTION · OPTIONS TO COMPARE · SURVEY QUESTIONS AND ITEMS ·
   CRITERIA, centred over the content column with justify-content, plus a second rule
   giving OVERALL QUESTION its own copy because it did not match the shared selector.

   ALL OF IT GOES, because the thing it centred is no longer only words. Every one of
   those rows is a numbered card's heading now, and a numeral centred with its heading
   floats in the middle of a card whose every field, eyebrow, letter and item starts at
   the left. The page had two heading alignments — these four centred, and Overview /
   Welcome / Completion / Response Management left — and one of them had to go for the
   badges to read as a column you can run your eye down. One rule places them all now:
   `[data-card-badge-host]` in setup-sidebar.css.

   OVERALL QUESTION's FIELD KEEPS ITS CENTRING, and that is not an inconsistency left
   behind: it is a centred identity band, exactly like Session Title and Group / Team in
   the Overview card above it, whose heading is also left with a badge. Heading left,
   identity band centred, on both cards — the same pair, stated once.

   Slide renders none of these rows (all four sit inside #tpl-structural-region, which
   Slide replaces with the rail + canvas), so nothing there changes either way. */
/* DELETED: `.tpl-start #tpl-flat-compare-prompt{text-align:center}` — do not re-add; the reason is T92 in the decision record. */
/* The TEXT | IMAGES toggle sits directly under the centred OPTIONS TO COMPARE
   heading, so it centres with it — width:fit-content was already there, and
   margin-inline:auto is what turns that into centring.

   TWO RULES DELETED HERE, both made dead by this line and neither worth keeping as
   a no-op:
     • `…:has(#tpl-rank-type-toggle) …{margin-left:var(--tpl-crit-indent)}` — the
       left anchor this replaces. --tpl-crit-indent is 0px on flat blank (the only
       shape with #tpl-rank-type-toggle), so it pinned the toggle to the card's
       content-left; margin-inline:auto now overrides margin-left anyway, which
       would have left a rule that reads as authoritative and does nothing.
     • its ≤640 companion, which set margin-inline:auto for group mode ONLY — a
       mobile-only patch for the desktop left-anchor above ("on a phone that reads
       as off-centre"). With the anchor gone the toggle is centred at every width in
       both modes, so the media query has nothing left to correct. */
/* DELETED: `margin-bottom:12px` — do not re-add; the reason is T93 in the decision record. */
#tpl-rank-type-toggle.tpl-rank-type-toggle-incard{display:flex;width:fit-content;margin-inline:auto;}
/* ── THE TOGGLE SITS ON THE HEADING'S ROW, AND GIVES WAY TO IT ───────────────────────
   (2026-08-31 on a phone; AT EVERY WIDTH from 2026-09-02, when the rail's COMPARISON TYPE
   band was deleted and MOVES sent both toggle ids here unconditionally.)
   `MOVES` delivers #tpl-rank-type-toggle and #tpl-stype-toggle into
   #tpl-flat-items-sublabel, the OPTIONS TO COMPARE heading row. This rule is what makes
   them fit there, and it is keyed on WHERE THE NODE IS rather than on a width: the
   selector describes the arrangement (`the toggle, inside the heading row`), so it cannot
   fire in the authored position, and a width query would be a second copy of a condition
   the DOM already states. That is why promoting the phone arrangement to every width
   needed no CSS change here beyond naming the second id.

   [HARD] THE HEADING AND ITS BADGE MAY NOT MOVE, AND THE ROW'S HEIGHT IS WHY.
   `[data-card-badge-host]:not(.tpl-edit-row--header){align-items:center}` (setup-sidebar.css)
   centres the badge against the ROW — so anything that changes the row's height re-centres
   the badge and the label with it. Measured at 390 before: row 25.66 tall (set by the
   label), badge 24 tall at +0.33, label 25.66. The toggle is 30 tall — 22px seats plus its
   own 3px block padding and 1px border each side — so joining the row unchanged would have
   grown it to 30 and dropped the badge 2.67px and the label 2.17px.

   SO THE TOGGLE GIVES WAY, AND IT GIVES UP THE ONE THING THAT IS NOT ITS SEATS. Removing
   the block padding takes the box to 24 (22 + 2 border), under the row's 25.66, and the
   row's height is still the label's. THE SEATS ARE UNTOUCHED — 52.73 x 22 each, before and
   after — which is the other half of the instruction: the control keeps its size, its
   equal-width seats, its click handler and its FLAT_MODE marker.

   margin-inline:auto goes with it. It centred the toggle in a row of its own; as a flex
   item after the label an auto inline margin absorbs the row's free space and would push
   the toggle to the far edge. The distance from the label is the ROW's own `gap`
   (--col-gap, 6px at <=640) — the same gap the badge already keeps from the label, so the
   line reads on one rhythm and nothing new is declared. */
/* BOTH IDS ARE NAMED, and that is the lesson the deleted rail rule carried: flat's
   toggle is reached by an ID rule (#tpl-rank-type-toggle.tpl-rank-type-toggle-incard,
   above), so a class-only selector does not release it — multi-criteria's #tpl-stype-
   toggle has no such id rule to fight but needs the same give-way, so both are listed
   rather than one being assumed to cover the other. */
#tpl-flat-items-sublabel > #tpl-rank-type-toggle.tpl-rank-type-toggle-incard,
#tpl-flat-items-sublabel > #tpl-stype-toggle{
    margin-inline:0;
    padding-block:0;
    height:calc(var(--tpl-seat-h) - 2 * var(--tpl-seat-pad-block));
}
/* The top-level RANKING | SURVEY toggle (#tpl-stype-toggle-row) was removed
   (type is fixed by the template now), so its centring rules went with it. */
.tpl-start:not(.flat-survey):has(#tpl-rank-type-toggle) #tpl-workshop-toggle-slot #tpl-workshop-toggle-row{display:none !important;}
#tpl-workshop-toggle-slot #tpl-workshop-toggle-row{display:flex;flex-direction:column;align-items:center;row-gap:var(--step-tight);width:auto;margin:0;}

/* Closing Date and Response Notifications are meaningless once the session runs
   live in one sitting — Workshop/Conference has no async close and no "notify me
   later". EVERY shape, unlike S-SURVEY-WORKSHOP below (that section is scoped to
   .flat-survey on purpose, for survey-specific copy/layout changes); the only
   condition here is .workshop-mode, mirroring the same right-rail rows
   #tpl-close-date-block / #tpl-notifications-block that setup-sidebar.js parks
   under Save To Project. Same S156 pattern as the rules below: the inputs stay in
   the DOM and enabled, so a previously-set closing date / notification choice
   round-trips when the facilitator flips back to Asynchronous — this hides,
   it does not wipe. */
.tpl-start.workshop-mode #tpl-close-date-block,
.tpl-start.workshop-mode #tpl-notifications-block{display:none !important;}

/* Completion Message never shows to a participant in Workshop/Conference mode, on
   ANY shape — ParticipantController::completionRedirect() sends every non-preview
   participant straight to /waiting whenever $session->isWorkshop() is true, before
   the pre-results step the completion message renders on. That check has no shape
   condition, so this is the SAME .workshop-mode signal as Closing Date / Response
   Notifications above, not the tmpl-workshop-conference one below: a plain New
   Survey (or any other shape) the facilitator switches to Workshop by hand hits the
   exact same redirect and hides the row too. #tpl-sidebar-ctrl-completion has no id
   of its own to key on, so :has() reaches the row from its control slot. S156 as
   above — completion_message_enabled and its heading/text keep posting from under
   display:none, so a message set before switching to Workshop is still there if the
   facilitator switches back. (The row is the left-rail toggle only; the CARD it
   opens, #tpl-completion-message-card, already hides under .flat-survey.workshop-
   mode below — narrower than this, on shape alone, a pre-existing gap on other
   shapes left as found rather than widened here.) */
.tpl-start.workshop-mode .tpl-sidebar-row:has(#tpl-sidebar-ctrl-completion){display:none !important;}

/* Respondent Mode (#tpl-workshop-toggle-row) is redundant on the switcher's
   synthetic "Workshop/ Conference Slides" entry — that entry only ever opens
   blank_survey pre-toggled to Workshop, so the toggle offers a choice this
   template has already made for the facilitator. .tmpl-workshop-conference is
   a DIFFERENT signal than .workshop-mode above: it is TemplateController's
   $isWorkshopConferenceEntry, true only while $switcherCurrentKey resolves to
   the entry's distinct key, so it does NOT also hide the toggle on a plain New
   Survey the facilitator toggled to Workshop by hand. It is a CREATE-time-only
   signal (?presenter=1) — see the note at $isWorkshopConferenceEntry: nothing
   persists this into the session, so the row reappears on that session's own
   MANAGE page, where the facilitator is free to switch it back off. S156 as
   above: the row's hidden/checkbox pair keeps posting workshop_mode from under
   display:none, so hiding it here is not what sets the value. */
.tpl-start.tmpl-workshop-conference #tpl-workshop-toggle-row{display:none !important;}

/* ── SURVEY + WORKSHOP/CONFERENCE mode — reactive UI (S-SURVEY-WORKSHOP) ──────
   Driven purely off two classes: .flat-survey (survey type, static from
   $flatInitMode==='questions') + .workshop-mode (mirrors the #tpl-presenter-mode
   toggle live via JS ~5065). BOTH must be present, so this NEVER touches an
   async survey (no .workshop-mode) or any ranking-in-workshop (no .flat-survey).
   Three display-only changes; all hidden fields stay in the DOM + enabled, so
   their values still POST and round-trip when the facilitator flips back to
   Asynchronous (S156 — hide, don't wipe). */
/* (a) "SURVEY QUESTIONS" heading reads "QUESTIONS" (both spans rendered; swap the
   visible one). Scoped to the flat-questions heading row's own id. */
#tpl-flat-questions-sublabel .tpl-sublabel [data-hdr-workshop]{display:none;}
.tpl-start.flat-survey.workshop-mode #tpl-flat-questions-sublabel .tpl-sublabel [data-hdr-default]{display:none;}
.tpl-start.flat-survey.workshop-mode #tpl-flat-questions-sublabel .tpl-sublabel [data-hdr-workshop]{display:inline;}
/* Quiz (blank_quiz create OR a quiz-typed session on manage/edit) — same
   "QUESTIONS" heading, reusing the SAME data-hdr-workshop span so a quiz that is
   ALSO in Workshop/ Conference mode never doubles the heading. Scoped identically. */
.tpl-start.flat-survey.quiz-mode #tpl-flat-questions-sublabel .tpl-sublabel [data-hdr-default]{display:none;}
.tpl-start.flat-survey.quiz-mode #tpl-flat-questions-sublabel .tpl-sublabel [data-hdr-workshop]{display:inline;}
/* (b) Hide the entire Completion Message card (inputs keep posting — CSS only). */
.tpl-start.flat-survey.workshop-mode #tpl-completion-message-card{display:none !important;}
/* (c) Advanced Settings offers NOTHING in this mode, so the row goes with the panel.
   It used to hide the panel's other five rows and leave Data Segmentation standing
   alone in it; segmentation is its own rail row now, so hiding those five empties
   the panel completely and the toggle above it would open a blank box. Hiding the
   ROW is the honest version of what that rule was reaching for — and it replaces
   the flatten JS that made this toggle double as the Respondent-Data on/off.
   The inputs keep posting from under display:none exactly as they did before. */
/* [HARD] THE GATE MOVES TO THE ROWS, AT THE SAME CONDITION. It used to hide the
   Advanced row and its panel, which suppressed these three as children. With the
   panel gone they have no parent to inherit visibility from, so without this they
   would APPEAR in survey + Workshop/Conference mode — a comparison setting on a
   session that has no comparisons. Same selector condition, three subjects instead
   of one. The inputs keep posting from under display:none exactly as before. */
.tpl-start.flat-survey.workshop-mode .tpl-sidebar-row:has(#tpl-allow-skips),
.tpl-start.flat-survey.workshop-mode #tpl-allow-ties-row,
.tpl-start.flat-survey.workshop-mode .tpl-sidebar-row:has(#tpl-allow-comments){display:none !important;}
/* Pure quiz (.quiz-mode): a quiz has no comparisons, so hide Skip Comparison,
   Enable Ties (which requires Skip) and Comments On Comparisons (mirrors the
   workshop rows above; idempotent if a quiz is ALSO in workshop mode). Closing
   dates + notifications stay. */
.tpl-start.flat-survey.quiz-mode .tpl-sidebar-row:has(#tpl-allow-skips),
.tpl-start.flat-survey.quiz-mode #tpl-allow-ties-row,
.tpl-start.flat-survey.quiz-mode .tpl-sidebar-row:has(#tpl-allow-comments){display:none !important;}
/* DELETED: The rule that hid the segmentation block's own header row in this mode — do not re-add; the reason is T94 in the decision record. */
/* Content-type slider — shared chrome for EVERY flat/DM type control: the blank
   top-level Ranking | Questions slider (#tpl-stype-toggle-row, Session Overview /
   manage-header), the blank Items | Images sub-toggle (#tpl-rank-type-toggle,
   items-card heading row) and the non-blank heading-row #tpl-stype-toggle. Mimics
   the .tpl-pill-toggle slider: the SAME shared --toggle-bg track, square corners,
   and the SAME borderless-platform-wide treatment — a 1px TRANSPARENT border
   (kept, not removed, so the border-box seat geometry is unchanged) instead of
   the visible var(--ink) box every other toggle dropped. --toggle-bg is the
   single source shared with .tpl-pill-toggle, so both toggle families restyle
   together. The active seat is the ink knob (var(--ink), white DM Mono 9px
   uppercase) — ink = "current mode" platform-wide; green is reserved for boolean
   ON. The inactive seats are the faded ghosts (opacity 0.4). The seats ARE the
   .tpl-flat-mode-btn buttons wired by the single _applyFlatMode/FLAT_MODE path;
   flex seats lay 2 out evenly. */
/* THE SEAT GROUP'S HEIGHT AND ITS BLOCK PADDING ARE TOKENS, and they are tokens for one
   consumer: the phone's OPTIONS TO COMPARE heading row, where this control has to fit
   inside a line box it is not allowed to grow. `box-sizing:border-box` means the SEATS'
   height is `--tpl-seat-h` minus the border and minus twice `--tpl-seat-pad-block` — 22px
   as declared — so an exception that drops the padding has to add the same amount back to
   the height or the seats shrink with it (measured: `height:auto` took the seats to 9px).
   Naming the two terms is what lets that exception be stated as arithmetic rather than as
   a second 24px literal 200 lines away from the 30 it is derived from. Values unchanged. */
.tpl-stype-toggle{--tpl-seat-h:30px;--tpl-seat-pad-block:3px;display:inline-flex;box-sizing:border-box;border:1px solid transparent;background:var(--toggle-bg);border-radius:var(--radius-square);height:var(--tpl-seat-h);overflow:hidden;padding:var(--tpl-seat-pad-block) 2px;}
.tpl-stype-toggle .tpl-flat-mode-btn{appearance:none;-webkit-appearance:none;border:none;background:transparent;cursor:pointer;display:flex;align-items:center;justify-content:center;padding:0 var(--inset-panel);font-family:var(--font-mono);font-size:var(--tpl-toggle-label);font-weight:var(--type-weight-bold);letter-spacing:var(--type-toggle-word-tracking);text-transform:uppercase;line-height:1;color:var(--color-text-primary);opacity:0.4;white-space:nowrap;transition:background 0.15s,color 0.15s,opacity 0.15s;}
.tpl-stype-toggle .tpl-flat-mode-btn.active{background:var(--mode-selected);color:var(--on-ink);opacity:1;}
/* Survey (questions) flat sessions are always group-mode (server-forced, S156).
   The Individual/Group toggle is NOT rendered for a survey (the _mode-toggle
   include is gated off for $flatInitMode==='questions', mirroring group-only
   Multi-Section) — $_modeValue is pinned to 'group' and the load-time
   applyModeFields('group') surfaces Group Name + the other group-only fields with
   no toggle to read from. So there is no .flat-survey toggle-hide rule here: there
   is simply no toggle to hide. (Slim / Availability Poll is the one survey shape
   that still renders a toggle — read-only + slim-CSS-hidden below — because its
   two-card layout predates the removal; its disabled state keeps the
   _applyFlatMode recursion guard terminating.) */

/* .tpl-section-block is now a marker class on the per-section
   .tpl-form-card cards. The chrome (bg/border/padding) lives in
   .tpl-form-card; this rule only carries section-specific layout
   tweaks (the section name's spacing). */
.tpl-section-block .field-label{margin-bottom:var(--gap-tight);}

/* Per-section comparison-question input — group-mode only. The wrap
   element gets style="display:none" by default and applyModeFields()
   toggles it on for group mode. The default value comes from
   $sectionFields[i]['prompt'] (resolved __($criterion['prompt_key'])) so
   leaving it untouched preserves the existing prompt. */
/* margin-bottom is --stack-gap, not a 14px literal. It is the object-to-object gap
   between the comparison question and whatever follows it, which is exactly the role the
   token names — it agreed with the token by coincidence while --stack-gap was also 14 and
   stopped agreeing the moment the rhythm moved to 24. Caught by setup:spacing-probe
   (ms:prompt->items), which is what that check is for. margin-top keeps its 8: it is an
   inset from the top of the flat compare well, not a gap between two objects, and MS
   zeroes it in its own rule below. */
/* [HARD] THE TRAILING HALF MOVED TO THE LOWER OBJECT (2026-08-27) — c9e4e51a's invariant.
   `margin-bottom:var(--stack-gap)` stood here and had exactly two contexts, measured across
   20 cells: inside an MS section's well it separates the comparison question from the item
   list below it (gap 24, which setup:spacing-probe pins as ms:prompt->items), and inside
   flat's #tpl-flat-compare-fields the wrap is the ONLY child, so the same 24px was stranded
   between the last field and the card's padding. That is what made Overall Question the
   worst card on the page: 25 top against 62 bottom.
   Stated by the item list now, so it exists only where an item list does. margin-top keeps
   its 8: it is an inset from the top of the flat compare well, not a gap between two
   objects, and MS zeroes it in its own rule below. */
.tpl-section-prompt-wrap{margin-top:var(--inset-control);}
/* `+`, not `~`, and not on .tpl-items-list alone: the class is also worn by the option list
   inside a question row, where nothing precedes it and a leading margin would be wrong —
   measured 5 item lists against 3 prompt wraps on MS in questions mode. The pair only
   co-occurs in a Compare-mode section's well, where both always render. */
/* GROUP inside a ROW container: the well runs at --step-row, and the item list
   opens a new group, so it spends only the difference. */
.tpl-start .tpl-flat-subcard > .tpl-section-prompt-wrap + .tpl-items-list{margin-top:var(--step-lift);}
/* MS-only: left-align the item-number badge so "01"/"02" sit flush at
   the card's left edge alongside the other label rows above (Section
   Name, Comparison Question). DM cards carry .tpl-section-block but
   no items inside, and flat items card has neither — both keep the
   global right-aligned 2rem column from public/css/templates.css. */
.tpl-start .tpl-section-block .tpl-item-num{text-align:left;}
/* ...but that selector is too broad: it also catches the QUESTION-card number
   (.qt-q-row > .tpl-item-num), which must match the flat/survey question number
   EXACTLY - i.e. keep the global right-aligned 2rem column (the "01" sits at the
   right of the box, giving the same left margin flat has). Without this, the MS
   question "01" was left-aligned = flush to the sub-card edge, diverging from
   flat. Restores right-align for section question numbers at both breakpoints
   (the item numbers above stay left). */
/* "+ Add Additional Item" button styling — applies to every items-
   list add button on the start screen (MS per-section, DM/flat shared
   items list at the top, End Questions list). The Add Section / Add
   Criterion button at the bottom of the cards stack is also a
   .tpl-add-item and now renders identically to #tpl-add-item (its
   old .tpl-form-card / .tpl-add-card wrapper + hint were removed).
   - margin-left:42px = .tpl-item-num width (2rem = 32px) +
     .tpl-item-row flex gap (10px) = the x-offset of .tpl-item-input
     from the row's content-edge. "+" lands at the input field's
     left edge.
   - text-align:left + width:auto on the "+" column makes it hug the
     glyph so the label sits right after via the button's flex gap.
   - Label switches to Bebas Neue (black) with 0.06em tracking +
     uppercase for the CTA feel. The "+" glyph keeps its red
     .tpl-add-item-plus colour. */
/* D-COLUMNS: THE single source for every "+ Add X" button left edge — Add Item /
   Question / Criteria / Section, all contexts — is "under the line start". That is the
   contract; --col-line-x is only the token that spelled it while there was one line
   vertical. All other add-button margin-left rules were removed so they cannot drift. */
.tpl-start .tpl-add-item{margin-left:var(--col-line-x);padding-left:0;}
/* ── AN ITEM ADDER APPENDS TO A FLOW LIST, SO IT PAYS THE FLOW OFFSET (2026-08-31) ──
   "Under the line start" stopped being one number when the phone ladder split the DIRECT
   group from the FLOW group. An item row is `[badge] gap [field]` with the badge IN FLOW,
   so its line starts at --col-flow-x; a question row's line starts at --col-line-x. The
   adders kept reading --col-line-x for both, which is right for the question adders and
   42px wrong for the item ones. Measured at 390 before this: + ADD ITEM at 19 under an
   item line at 61, on blank, blank_dm and blank_ms alike — the button was aligned to the
   BADGE column, not to the line above it.

   NOT WIDTH-SCOPED, AND IT DOES NOT NEED TO BE. --col-flow-x is pinned to --col-line-x at
   >=641 (see its [HARD] note in templates.css: the desktop slack is deliberate and out of
   scope), so this declaration resolves to exactly what the rule above gives at every width
   >= 641 and moves only where the two tokens diverge. Verified as a per-box census, not
   argued: 0 differing boxes at 641/700/888/1280 on every shape.

   THE TWO ITEM ADDERS, NAMED. #tpl-add-item is flat/DM's shared list; the
   .tpl-section-block arm is MS's per-section one. The QUESTION adders
   (#tpl-flat-add-question, [data-add-question]) are deliberately absent — their lists are
   direct, and the rule above is already right for them. The CARD adders sit on V2 and are
   a different tier entirely; see THE TWO CARD ADDERS SIT ON V2 below. */
.tpl-start #tpl-add-item,
.tpl-start .tpl-section-block .tpl-add-item:not([data-add-question]):not([data-add-option]){margin-left:var(--col-flow-x);}
/* DELETED: `.tpl-start #tpl-flat-add-question, .tpl-start .tpl-add-item[data-a…` — do not re-add; the reason is T95 in the decision record. */
/* ── THE TWO CARD ADDERS SIT ON V2, THE BADGE VERTICAL — BY WHAT THEY ADD ─────────
   + ADD CRITERIA and + ADD SECTION add a CARD; every other adder on the surface adds a ROW
   INSIDE one, and those sit on V3 with the rows they make. The split is stated by the
   control's JOB, not by how it is drawn — but the two agree here and that was verified
   rather than assumed: a census of every adder at 1280 returns filled black
   rgb(26,18,8) for exactly these two, on every shape. (The other half of that census —
   "rgba(0,0,0,0) for + Add Item, + Add Question and + Add Option" — is STILL TRUE of the
   fill on all three: the ROW adders were given a 1px --ink OUTLINE on 2026-08-26 and no
   fill at all. (An intermediate step that day gave them the secondary well fill; it scored
   1.14:1 on the tan card and was deleted the same day — see the row-adder rule in
   templates.css.) The agreement this census was cited for is unaffected either way, because
   it turns on the card adders being the only FILLED ones, which they are.) If a future card-adder is ever drawn as plain text it still
   belongs here, and a row-adder drawn as a button still belongs on V3.

   Sitting on V2 means starting where a badge starts: these buttons ARE the "add another
   one of those" affordance for the numbered cards above them, so they line up with the
   numerals rather than with the text. --col-num-x is the same token every badge reads. */
.tpl-start #tpl-add-criterion-btn,
.tpl-start #tpl-add-section-btn{margin-left:var(--col-num-x);}
.tpl-start .tpl-add-item-plus{text-align:left;width:auto;}
.tpl-start .tpl-add-item-label{letter-spacing:var(--type-caption-tracking);}
/* ── THE PHONE'S ADD LABEL WEARS THE TOGGLE-LABEL TREATMENT (2026-08-31) ───────────
   The two were already one tier in everything but this: measured at 390, an add label
   and a .tpl-mono.tpl-workshop-mode-label both compute DM Mono / 12px / 400 / uppercase
   / rgb(26,18,8), and differ on letter-spacing alone — 0.72px against normal. The 0.06em
   is a survival of the retired Bebas CTA treatment ("Label switches to Bebas Neue (black)
   with 0.06em tracking + uppercase for the CTA feel"), which the label has not worn for a
   long time; the tracking outlived the family it was drawn for.
   <=640 ONLY, because desktop is out of this session's scope and deleting the declaration
   outright would move every add button's width at 1280. That makes this the one place on
   the surface where the two tiers still disagree, and the reason is a scope boundary, not
   a design one. */
@media(max-width:640px){
  .tpl-start .tpl-add-item-label{letter-spacing:normal;}
}
/* Quiet "N items = X comparisons" hint under the add-item row — muted label
   text, left-aligned to the add button (same --col-line-x inset); no badge,
   no warning colour. */
.tpl-start .tpl-compare-count{margin-left:var(--col-line-x);width:var(--col-line-width);max-width:100%;box-sizing:border-box;/* margin-top was 6 (TIGHT to the adder). Inside a container already running at
   --step-row it ADDED and the junction rendered 22; TIGHT is not expressible
   there without a negative margin, so the counter takes the row step and is
   reassigned MEDIUM in the report. padding-top STAYS: it is the inset from this
   element's OWN painted border-top, a named exception, not a step. */padding-top:var(--gap-tight);border-top:1px solid var(--border-strong);border-radius:var(--radius-none);font-family:var(--font-mono);font-size:var(--type-badge);line-height:1.4;color:var(--color-text-primary);text-transform:uppercase;text-align:left;}
/* MS-only desktop: constrain the items input area to 80% of the card
   width so the rows render as a narrower column, matching the
   Comparison Question's 40%-on-desktop treatment in spirit (just
   wider since item text is the primary entry on these cards).
   Mobile keeps the full-width default for thumb-friendly tap targets. */
@media (min-width:768px){
    /* Flat single list (#tpl-items-list), per-section lists, and the pairwise
       question type's items-to-compare list (.tpl-pairwise-items, rendered by
       question-types.js inside a question config) all share the same 80%
       column width so the three item-entry surfaces match. */
    .tpl-start .tpl-section-block .tpl-items-list,
    .tpl-start #tpl-items-list,
    .tpl-start .tpl-pairwise-items{width:80%;}
}
/* Availability-poll (time_date_selector) editor. ONE control row
   (.tpl-timedate-controls) directly above the month grid carries Length (label
   above the number + unit) + Host timezone (label above the select) on the LEFT
   and the month/year dropdowns + ‹ › month arrows on the RIGHT (.tpl-timedate-
   navmount, margin-left:auto). The unit decides the mode (minutes/hours = timed
   chips with a start time + derived end; days = date-range chips). The tz select
   is width-capped so the full IANA list never blows out the row. Self-contained
   .tpl-timedate-* family. */
/* ── V3: SLIM'S CONTROL ROW STARTS ON THE SHARED VERTICAL (2026-08-24) ────────────
   This row sat on the CARD's content edge — 326 at 1280 against every other line's 400 —
   which is the "slim is on a third ladder entirely, four left edges in one control row"
   the 2026-08-23 audit records (A.1.6 / A.20.3, which also measured that joining the shared
   column costs slim nothing functional). MEETING/ EVENT LENGTH is the FIRST control in the row, so
   it is the one that takes the vertical; HOST TIMEZONE and the month/year mount keep their
   internal arrangement and follow it along, exactly as MIN/MAX and MODE / MAX WORDS do.
   The row is not restructured — one margin, no change to its flex, its gaps or its order. */
.tpl-start .tpl-timedate-controls{
    display:flex;
    flex-wrap:wrap;
    align-items:flex-end;
    gap:28px;
    /* [HARD] THE LEFT IS IN THE SHORTHAND, NOT BESIDE IT. Written as a separate
       `margin-left` ABOVE this line it was silently reset to 0 by this very shorthand and
       the row stayed on the card edge — measured, MEETING/ EVENT LENGTH at 326 while the probe
       said V3 was 400. A longhand before a shorthand for the same property is not an
       override, it is a deletion. */
    margin:0 0 18px var(--col-line-x);
}
.tpl-start .tpl-timedate-length,
.tpl-start .tpl-timedate-hosttz{
    display:flex;
    flex-direction:column;
    /* The MEETING/ EVENT LENGTH / HOST TIMEZONE captions now use the shared .field-label
       (which carries margin-bottom:6px in a .tpl-form-card), so the column gap is
       0 — the label's own margin provides the 6px label→field rhythm. */
    gap:0;
    /* Stretch both columns to the control row's height and push the FIELD to the
       bottom (margin-top:auto, below) so the two LABELS share the top baseline. The
       native tz <select> renders a few px taller than the number+unit cluster, and
       the row's align-items:flex-end was turning that delta into a label offset
       (HOST TIMEZONE caption sitting higher than MEETING/ EVENT LENGTH). Now the labels
       align at the top and the fields stay bottom-aligned, independent of the
       control-height delta. navmount (shorter, no label) keeps its own flex-end. */
    align-self:stretch;
}
/* min-width:0 — the flexbox correction, on the ROW rather than only on the field
   inside it. A flex item defaults to min-width:auto and refuses to shrink below its
   content, so with the number field's width override gone this row carried number +
   select straight past its 438px parent (measured: content right edge 951 against a
   line ending at 838). The number's own flex sizing cannot fix that from inside a row
   that is itself refusing to shrink. */
.tpl-start .tpl-timedate-length-fields{display:flex;align-items:center;gap:var(--inset-control);margin-top:auto;min-width:0;}
.tpl-start .tpl-timedate-hosttz > .tpl-timedate-tz{margin-top:auto;}
.tpl-start .tpl-timedate-navmount{margin-left:auto;display:flex;flex-direction:column;align-items:flex-end;gap:var(--gap-tight);}
/* DELETED: `.tpl-start .tpl-timedate-length-num{flex:0 0 auto;width:72px}` — do not re-add; the reason is T96 in the decision record. */
.tpl-start .tpl-timedate-row{flex-wrap:wrap;}
/* DELETED: `.tpl-start .tpl-timedate-length-num` — do not re-add; the reason is T97 in the decision record. */
.tpl-start .tpl-timedate-date,
.tpl-start .tpl-timedate-time,
.tpl-start .tpl-timedate-tz{
    flex:0 0 auto;
    border:1px solid var(--border-strong);
    border-radius:var(--radius-square);
    padding:6px 8px;
    /* background-color, not the shorthand — third and last of the three that were
       painting out the select caret. See the note on .tpl-issue. */
    background-color:var(--color-white);
}
/* ── MEETING/ EVENT LENGTH IS A FULL-WIDTH LINE AGAIN (2026-08-25) ──────────────────────
   THE SHORT LINE IS DELETED, and with it the ONE RULE LENGTH exclusion it forced. It read
   `flex:0 0 auto; width:40%` here (175.19/90.39px on screen), which made this the only
   rule on the surface that did not end where every other rule ends — the header-lane
   harness had to be taught to skip it. Both halves are gone: the line is the field line
   again, same width, left edge and right edge as MEETING / EVENT TITLE and AGENDA /
   PURPOSE, and the shortness moved to the CONTROL inside it. The row reads as one phrase —
   a narrow number, the unit immediately after it, then empty line, then the field-state
   glyph at the line's end, where it sits on every other field. */
.tpl-start .tpl-timedate-length-fields > .tpl-inline-edit{
    flex:1 1 auto;
    /* BASELINE, NOT flex-end. Aligning the BOXES at the bottom left the unit sitting low
       against the number, because the number's box is 34px tall and the select's is its own
       content height — two different boxes with the same bottom edge do not put their TEXT
       on one line. `baseline` is what .tpl-inline-edit's own base declaration uses
       (templates.css), so this restores the class's value rather than inventing one, and it
       is what makes "1 Hours" read as one phrase on the rule. */
    /* `.tpl-inline-edit` base carries `width:400px; max-width:50%`, which capped this at
       219px — exactly half the 438 line — at >=641 while <=640 read full. Released the
       same way `.tpl-edit-field > .tpl-inline-edit` already releases it (templates.css),
       so a wrapper that has to BE the row says so in the words that rule already uses. */
    width:100%;
    max-width:none;
    min-width:0;
    display:flex;
    align-items:baseline;
    /* GAP 0, BECAUSE THE FORMAT IS ONE TOKEN (2026-08-25). The row reads 00h:00m — a
       number and its unit letter are one word, and the colon separates the two halves.
       A 4px gap between every part spelled it `00 h : 00 m`, which reads as five things
       rather than one duration. The parts that DO need air carry it themselves: the mode
       seats keep their `margin-left:var(--tpl-field-inset)` below, and the all-day `days`
       suffix carries a non-breaking space in its content (question-types.js) because it
       is a word, not a unit letter. */
    gap:0;
    /* IT WRAPS (platform rule: nothing truncates). `HOURS / MINUTES` is a 205px control —
       longer than the `DURATION` it replaces — and at 390 the seats ran to 375 against a
       line ending at 303, a well ending at 337 and a CARD ending at 366: the control left
       the card. Wrapping drops the seats onto their own row under the value, still grouped
       left, at every width where they do not fit; at 1280 the whole row is 315px inside a
       438px line and nothing wraps. `row-gap` is inherited from the `gap:0` above, so the
       wrapped row costs no new spacing. */
    flex-wrap:wrap;
}
/* ── THE NUMERIC FIELDS' CLUSTER, REUSED (2026-08-25) ────────────────────────────
   The row is [hh] h [mm] m — or [n] days — so it has numeric inputs again, and what a
   numeric field in this row needs has not changed: a width, the spinner suppression, and a
   transparent resting fill. The cluster is REUSED rather than rebuilt.
   THE WIDTH IS ONE BADGE, NOT THREE. Each field holds at most two digits (24, 59, 60)
   where the old single field held four (1440), so it tracks --tpl-badge-size once: 26px at
   >=641, 24px at <=640. The token is the same one the glyph beside it is drawn at, so the
   fields and the badge scale together. */
.tpl-start .tpl-timedate-length-fields > .tpl-inline-edit > .tpl-timedate-length-num{
    /* [HARD] TWO DIGITS WIDE, IN THE FIELD'S OWN DIGITS (2026-08-25). The box has to be
       the width of what it holds or `00h` is not one token — measured at 1280, the box was
       35px around a 19.2px `00`, so the row read `00 h:00 m`. `ch` IS the digit: in DM Mono
       1ch is the `0` advance, so `2ch` is exactly two digits at 16px and at 12px alike,
       with no literal and no token invented for a width that is really a character count.
       The +2px is the 1px transparent border on each side (box-sizing is border-box).
       IT REPLACES `flex:0 0 var(--tpl-badge-size)`, WHICH NEVER TOOK EFFECT. Measured
       computed value on the live page: `flex: 0 0 auto` — the grow and shrink applied and
       the BASIS did not, so the field was sizing intrinsically and the badge token was
       never its width. Two wrongs cancelling: the token was the wrong measure for this box
       anyway (it exists so field and glyph scale together, which is a claim about a
       line-owning field), and it was not being read. Stated as longhands so there is no
       var() inside a shorthand to go quietly missing again. */
    flex:0 0 auto;
    width:calc(2ch + 2px);
    min-width:0;
    /* [HARD] AND IT GIVES BACK THE LINE'S TEXT INSET. `.tpl-start .tpl-inline-edit > input`
       declares `padding:0 var(--tpl-field-inset) 0 0` — 12px — which is right for a field
       that OWNS its line: it holds the typed value clear of the line's end. These three do
       not own the line; they are sub-controls inside it, and that 12px was landing between
       the number and its unit letter, which is precisely the gap this row must not have.
       Deleted rather than compensated for, per the note on --tpl-line-inset in CLAUDE.md:
       the inset belongs to the LINE, and this is not one. */
    padding-right:0;
    /* [HARD] LEFT, NOT RIGHT (2026-08-25). The field's BOX has always started on the
       ladder — measured at 400 / 77, the same vertical as MEETING / EVENT TITLE, AGENDA /
       PURPOSE and PLACE — but `text-align:right` parked the digits at the far side of it,
       so the only thing on screen started ~15px inside the line it sits on and the row
       looked indented against every field above it. The box was never the problem; the
       text was pointing the wrong way. Nothing compensates for this — no negative margin,
       no lead — because there was nothing to compensate for. */
    text-align:left;
    background-color:transparent;
}
/* ── THE CLOCK FIELDS TAKE THE NUMERAL FACE ──────────────────────────────────────
   The hours and minutes boxes are figures, and the figure face on this surface is the
   one the Customise Weighting stepper shows `100 %` in. That stepper declares NO
   family of its own (.tpl-weight-step-input, this file) — it inherits, and the value
   it inherits, measured on /templates/blank_dm/start with weighting on, is
   `"Bebas Neue", sans-serif`, which is exactly what --font-numeral resolves to. So the
   token is the claim, not a copy of the face: state the token and the two stay together
   however it is redefined.

   THE FIGURES ONLY, AND THE SUFFIXES STAY MONO AND LOWERCASE — SETTLED 2026-09-09
   AFTER TWO WRONG PASSES, BOTH RECORDED HERE BECAUSE THE SECOND WAS THE FIRST ONE'S
   FIX. Pass one put the face on the two clock inputs alone and `00h:00m` rendered
   `00h : 00m`; pass two chased that by carrying the face onto the `h` / `:` / `m` /
   ` days` suffixes as well, which closed the gap and cost the lowercase — Bebas Neue
   has no lowercase glyphs at all, so the unit letters drew as `00H:00M` and `60 DAYS`.
   Both passes were treating a WIDTH as a typeface problem.

   THE GAP WAS NEVER THE FACE. It is one measurement: in DM Mono at 16px every glyph
   gets the same 9.6px advance, and the colon's ink is 3px of it. `h` (ink 8) and `m`
   (ink 9) very nearly fill their cells, so they hug their figures either way; the
   separator sits in the middle of 6.6px of air, and Bebas figures being narrower than
   mono's is only what made that air visible. So the fix is on the separator's BOX and
   nothing else: the face question and the spacing question were never the same question.

   `span.tpl-mono + span.tpl-mono` IS THE SEPARATOR, structurally rather than by its
   text. The line is authored input, h, :, input, m, input, days, toggle (tdLenLine,
   question-types.js), so `:` is the ONLY suffix span directly preceded by another
   suffix span — which is what a separator IS here. Verified against the RENDERED
   children rather than the source, because they are not the same list: wrapInlineEdit
   puts a display:none `[ Edit ]` cue in at index 1, between the first input and `h`,
   and an nth-child count written off the source would have selected the wrong element.

   [HARD] BOTH `span`s ARE LOAD-BEARING, AND `.tpl-mono + .tpl-mono` IS THE BUG THEY
   FIX. The three number INPUTS carry .tpl-mono too, so the bare class-adjacency form
   matched four more elements than it named — the minutes input, `m`, the day input and
   ` days` all directly follow something with that class, and all four collapsed to the
   separator's width. Caught by measuring every visible child rather than the one under
   test. Typing the element on both sides is what makes the selector mean "a suffix
   directly after a suffix". No new class and no change in question-types.js.

   THE WIDTH IS STATED IN `ch`, NOT IN PIXELS, for the same reason the figures' own
   `calc(2ch + 2px)` is: `ch` resolves in the element's OWN font, so it tracks
   --tpl-input-size down to the <=640 arm where a literal would not. The colon's ink is
   3px against DM Mono's uniform 9.6px advance at 16px (canvas actualBoundingBox), i.e.
   a shade under 0.32ch; 0.4ch leaves the glyph a hair of room without giving the air
   back. The suffixes keep .tpl-mono's family, their lowercase, and the size the rule
   below gives them.

   [HARD] THE NEGATIVE `text-indent` IS THE OTHER HALF OF THE FIX, AND `text-align:center`
   IS NOT A SUBSTITUTE — IT WAS TRIED AND IT RENDERS IDENTICALLY TO NOTHING. Narrowing the
   box does not narrow the GLYPH'S ADVANCE: the text still lays out at 9.6px with its 3px
   of ink ~3.3px in, so a 0.4ch box leaves the ink starting just PAST its right edge,
   painted over the minutes field — `12h :45m` with the colon touching the 4, which is the
   same air moved, plus a collision. Centring does not recover it: Chrome sends an
   OVERFLOWING line box's excess to the end side only, so `text-align:center` computed
   correctly and moved the glyph 0px (measured with a Range over the text node: box
   424.41-428.23, text 424.41-434.02, before and after). Pulling the line is what works.

   THE INDENT IS DERIVED, NOT DIALLED IN: half the difference between the box and the
   advance, `calc((0.4ch - 1ch) / 2)`, which centres the glyph's own advance on the box's
   centre. `1ch` IS the advance here only because DM Mono is monospaced — every glyph gets
   the `0` advance — so this arithmetic is the font's, not a coincidence, and it scales
   with --tpl-input-size like the width beside it.

   scrollWidth STILL EXCEEDS clientWidth ON THIS ONE SPAN, harmlessly: it reports the
   9.6px LINE BOX, not the 3px of ink inside it, and `overflow` is visible so nothing is
   cut. Do not "fix" that reading by widening the box back — what to check here is the
   painted glyph, not the layout box.

   THE 2ch WIDTH ON THE FIGURES STILL HOLDS, and it holds BECAUSE it is stated in `ch`.
   That comment's arithmetic reads `1ch` as DM Mono's `0` advance; the unit is
   font-relative, so it is Bebas Neue's on these boxes now and `calc(2ch + 2px)` goes on
   meaning two of the field's OWN digits — 14.8px, and the day count (TD_MAX_DAY 60)
   needs exactly two of them. Measured with a value TYPED, not at rest: a placeholder
   can fit where a typed digit does not. */
.tpl-start .tpl-timedate-length-fields > .tpl-inline-edit > .tpl-timedate-length-num{
    font-family:var(--font-numeral);
}
/* ── ` days` JOINS ITS FIGURE (2026-09-10), REVERSING THE NOTE THAT KEPT IT OUT ──
   `840af2c6` put --font-numeral on the whole length token and told the day suffix
   apart on purpose — "the day input's placeholder is `0` where a clock field's is
   `00`, and ` days` is the only .tpl-mono sibling FOLLOWING that input" — so that the
   word stayed mono. `ebda58c7` then pulled the face back to the figures alone, which
   left `days` mono for a different reason. It is numeral now BY DECISION: the ALL-DAY
   arm reads as one token, its number and its unit in one face, the way `00h : 00m`
   does.
   SAME DISCRIMINATOR, because it is still the honest one: the placeholder is what
   separates a day field from a clock field at source, and it needs no new class.
   CONSEQUENCE, REPORTED NOT WORKED AROUND: Bebas Neue is caps-only, so the word
   renders `DAYS`. That is the same trade `840af2c6` recorded when the face briefly
   covered `h` and `m`; here it is the intended reading rather than a side effect.
   The HOURS-MINUTES / ALL-DAY seats are .tpl-stype-toggle, not .tpl-mono, so this
   selector cannot reach them — they stay mono. */
.tpl-start .tpl-timedate-length-fields .tpl-timedate-length-num[placeholder="0"] + .tpl-mono{
    font-family:var(--font-numeral);
}
/* ── THE SEPARATOR TREATMENT, NAMED ONCE AND SPENT TWICE ─────────────────────────
   Extracted from the length row's `:` so the chip's `–` inherits the mechanism rather
   than a second eyeballed width. The formula is the thing being shared: box = the
   glyph's own INK, and the line pulled back by half the difference between that and
   the cell it is laid out in, so the glyph sits centred in the narrower box instead of
   overflowing to the right (see the length row's note for the render that proved
   text-align cannot do it).
   --tpl-sep-ink is per GLYPH because the ink is: a colon measures ~0.31ch of DM Mono's
   uniform advance and an en dash more than half of it. Both are measured, neither is
   a guess, and the arithmetic below is written once. */
.tpl-timedate-sep{
    width:var(--tpl-sep-ink);
    text-indent:calc((var(--tpl-sep-ink) - 1ch) / 2);
}
/* The two inks, each measured with canvas actualBoundingBox against DM Mono's uniform
   6.6px advance at 11px: a colon is 3 (0.45ch... 0.31ch of the 9.6px advance it sits in
   at 16px), an en dash 5 of 6.6 = 0.76ch. Per glyph, because the ink is per glyph; the
   formula that spends them is stated once above.
   The structural `span.tpl-mono + span.tpl-mono` selector this replaces is DELETED: it
   named the length row's separator by its POSITION, which the chip's separator does not
   share, and a second copy of the arithmetic is exactly what the class exists to avoid. */
.tpl-timedate-len-sep{--tpl-sep-ink:0.4ch;}
/* font-size too: .tpl-mono carries 12px and the chip's figures are 11, so the separator
   sat a pixel taller than the two times it joins. `inherit` takes the chip's own size,
   which is also what keeps the <=640 arm below to one declaration. */
/* P6c: `inherit` is deliberate, not an unconverted scale member — docs/type-scale-proposal-2026-09-18.md §3.3. */
.tpl-timedate-chip-sep{--tpl-sep-ink:0.76ch;font-size:inherit;}
/* The native spinners are suppressed on every one of them: `appearance:none` on the input
   does not remove them in Blink — the pseudo-elements have to be named — and they would be
   drawn over a two-digit value. -moz-appearance:textfield is the Gecko half. */
.tpl-start .tpl-timedate-length-fields > .tpl-inline-edit > .tpl-timedate-length-num::-webkit-outer-spin-button,
.tpl-start .tpl-timedate-length-fields > .tpl-inline-edit > .tpl-timedate-length-num::-webkit-inner-spin-button{
    -webkit-appearance:none;
    appearance:none;
    margin:0;
    display:none;
}
.tpl-start .tpl-timedate-length-fields > .tpl-inline-edit > .tpl-timedate-length-num{
    -moz-appearance:textfield;
}
/* The h / m / days suffixes and the mode seats sit in the line beside the fields. The
   suffixes carry .tpl-mono, the surface's existing mono tier, and take the field's own size
   from the rule below rather than a size of their own. */
.tpl-start .tpl-timedate-length-fields > .tpl-inline-edit > .tpl-mono{
    flex:0 0 auto;
    font-size:var(--tpl-input-size);
}
.tpl-start .tpl-timedate-length-fields > .tpl-inline-edit > .tpl-stype-toggle{
    flex:0 0 auto;
    margin-left:var(--tpl-field-inset);
    /* [HARD] THE SEATS ARE NOT A BASELINE PARTICIPANT (2026-08-25). The line is
       `align-items:baseline`, which is right for the number and its suffixes — that is
       what puts `00h:00m` on one line of text. It is wrong for the toggle: a seat's own
       baseline is the baseline of 9px centred button text inside a 22px box, so aligning
       THAT to the number's baseline dropped the whole control below the text it sits
       beside (measured 3.00px low at 1280, 1.50px at 390). `align-self:center` takes the
       toggle out of the baseline group and centres it on the line instead, which is what
       it was always meant to read as. Corrected at the property that caused it — no
       margin nudge, which would have been width-dependent and silently wrong at the
       other breakpoint. */
    align-self:center;
}
/* ── THE WRAPPED ROW AT <=640 (2026-08-25) ────────────────────────────────────────
   `HOURS / MINUTES` + `ALL-DAY` is a 205px control against a 226px line, so at <=640 the
   seats always take the row below the value. Two consequences are handled here rather
   than left to the wrap's own arithmetic:

   1. THE SEATS START ON THE LINE, NOT 12px INSIDE IT. `margin-left:var(--tpl-field-inset)`
      is the gap between the value and the seats when they share a row; on a row of their
      own it is an indent off the ladder every other field on this card sits on. Zeroed for
      the width where they are never beside the value.
   2. THE BADGE MOVES TO THE VALUE'S ROW. The glyph is painted on the LINE, and the line is
      now two rows tall, so `center` put the disc-and-tick straight through the ALL-DAY seat
      below — measured on a render, and visible in the shot. It anchors to the top instead,
      which is where it belongs anyway: the badge marks the VALUE, and the value is on the
      first row. Same correction, same `top`, and the same reasoning as the textarea
      override in templates.css — a badge centred in a tall box floats away from the thing
      it is reporting on. The offsets are that override's, unchanged. */
@media(max-width:640px){
    .tpl-start .tpl-timedate-length-fields > .tpl-inline-edit > .tpl-stype-toggle{
        margin-left:0;
    }
    /* The tick's two layers are DIFFERENT sizes — the check is 2/3 the disc and is
       centred ON it — so the pair carries the same size/6 offset the resting rule
       computes for `center`. The ring's two layers are both full size and share one
       position. Split exactly as templates.css splits its two textarea overrides. */
    .tpl-start .tpl-timedate-length-fields > .tpl-inline-edit:has(> input:not(:placeholder-shown):not(:disabled):valid){
        background-position:
            right calc(var(--tpl-badge-inset) + var(--tpl-badge-size) / 6) top calc(8px + var(--tpl-badge-size) / 6),
            right var(--tpl-badge-inset) top 8px;
    }
    .tpl-start .tpl-timedate-length-fields > .tpl-inline-edit:has(> input):not(:has(> input:not(:placeholder-shown):not(:disabled):valid)){
        background-position:
            right var(--tpl-badge-inset) top 8px,
            right var(--tpl-badge-inset) top 8px;
    }
}
/* DELETED: `.tpl-start .tpl-timedate-length-fields > .tpl-inline-edit > select…` — do not re-add; the reason is T98 in the decision record. */
/* Spend --col-field-lead ONCE PER CHAIN: this wrapper's row is already on the column, so
   the shared `.tpl-inline-edit.tpl-rust-rule{margin-left:var(--col-field-lead)}` would be
   a second payment. Joined to the arm that already says this for slim's prompt rather
   than restated — see that rule. */
/* DELETED: `.tpl-start .tpl-timedate-length-num{min-width:0}` — do not re-add; the reason is T99 in the decision record. */
/* flex-grow:1 so the tz cluster fills the middle of the control row, pushing the
   month/year + arrows (.tpl-timedate-navmount) to the right on the SAME row; the
   smaller flex-basis/min-width keep the nav from wrapping to its own line in the
   slim question column. */
.tpl-start .tpl-timedate-hosttz{flex:1 1 220px;min-width:200px;max-width:440px;}
/* The tz <select> sits in a COLUMN flex wrapper (.tpl-timedate-hosttz), so a
   `flex:1 1 160px` here applied flex-basis:160px to the select's HEIGHT (main
   axis = vertical in a column) — rendering it as a tall white panel. Fill the
   wrapper WIDTH and let height be content-sized instead. */
.tpl-start .tpl-timedate-tz{flex:0 0 auto;width:100%;box-sizing:border-box;}
/* REAL CAUSE of the "hours/unit ↔ Host Timezone touching" report: the unit
   <select> is a .tpl-issue, which carries width:100% (the shared input rule).
   With no override it stretches the length cluster to fill the control row, so
   the row's 28px flex-gap before the timezone gets visually swallowed. Give the
   unit its natural width so the cluster stays compact and the gap actually shows
   — a structural fix, not another margin. */
/* Calendar-lite slot picker — week strip + click-to-add chips. Replaces the
   stacked date+time rows but writes the SAME q.items {id,date,time}; the server
   still stamps the instant. Cream/black/red, Bebas/mono, zero-radius. Timed
   chips carry an editable time + derived end (09:00 → 10:00); date-range chips
   show the inclusive range with no time. Built in public/js/question-types.js. */
.tpl-start .tpl-timedate-cal{margin:0;}
/* Month/year jump + ‹ › arrows — grouped on the RIGHT of the shared control row
   (.tpl-timedate-navmount), never a separate nav row. Square (zero radius), 1px
   solid black, mono. */
.tpl-start .tpl-timedate-calnav-tools{display:flex;align-items:center;gap:var(--inset-control);}
/* background-color, not the shorthand — see the note on .tpl-issue above. */
.tpl-start .tpl-timedate-calsel{appearance:none;border:1px solid var(--border-strong);border-radius:var(--radius-square);background-color:var(--color-white);height:30px;padding:0 var(--inset-control);cursor:pointer;}
.tpl-start .tpl-timedate-calsel:disabled{opacity:0.4;cursor:default;}
.tpl-start .tpl-timedate-calnav-arrow{appearance:none;border:1px solid var(--border-strong);background:var(--color-white);border-radius:var(--radius-square);width:30px;height:30px;cursor:pointer;font-size:var(--type-field);line-height:var(--type-field-line);color:var(--color-text-primary);display:inline-flex;align-items:center;justify-content:center;flex:0 0 auto;}
.tpl-start .tpl-timedate-calnav-arrow:hover{background:var(--ink);color:var(--on-ink);}
.tpl-start .tpl-timedate-calnav-arrow:disabled{opacity:0.3;cursor:default;}
/* FULL MONTH GRID (replaces the week strip). Mon–Sun columns × the month's
   weeks; tall roomy cells holding day number + that day's slot chips INSIDE the
   cell, Google-Calendar-month style. Square everywhere (zero radius), 1px solid
   black hairlines, Bebas/mono cream/black/red. The grid is a desktop setup
   surface — give it real height. */
/* ── [HARD] THE COLUMNS ARE minmax(0,1fr), NOT 1fr ──────────────────────────────
   `1fr` is shorthand for `minmax(auto,1fr)`, so each track's MINIMUM is its
   content's min-content. One slot chip in one column therefore pushed that
   column out to the chip's intrinsic width and the whole grid grew to suit —
   the grid's width was a function of what the facilitator had typed, not of the
   space it had. Measured before this changed, slots on all seven columns:
   the grid demanded 1055px and got 984, so it broke OUT of its own card at a
   1600 viewport, and at 900 it pushed the PAGE into horizontal scroll by 228px.

   minmax(0,1fr) lets a track shrink below its content, which moves the decision
   back to the container: seven equal columns of whatever the card can give. The
   chip is what yields now — see THE CHIP YIELDS below.

   Both the weekday header and the grid carry it, and they must stay in step or
   the header stops sitting over its own columns. */
/* The cell floor, derived above under THE CELL HAS A FLOOR. Declared here, beside
   the grid that reads it, and read in one place — the <=640 arm. */
.tpl-start{--tpl-timedate-cell-min:64px;}
.tpl-start .tpl-timedate-monthdow{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:0;border:1px solid var(--border-strong);border-bottom:none;}
.tpl-start .tpl-timedate-dow{padding:7px 4px;text-align:center;font-family:var(--font-mono);font-size:var(--type-badge);letter-spacing:0.08em;text-transform:uppercase;color:var(--grey);background:var(--surface-warm-hover);border-right:1px solid var(--rule-base);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.tpl-start .tpl-timedate-dow:last-child{border-right:none;}
.tpl-start .tpl-timedate-monthgrid{display:grid;grid-template-columns:repeat(7,minmax(0,1fr));gap:0;border:1px solid var(--border-strong);border-top:1px solid var(--rule-base);}
/* min-width:0 — a flex item's automatic minimum size is its content size, so
   without this the cell would re-impose the floor minmax(0,1fr) just removed,
   one level further down. Same reason on .tpl-timedate-mchips and the chip. */
.tpl-start .tpl-timedate-mcell{display:flex;flex-direction:column;gap:var(--inset-tag);min-width:0;min-height:104px;padding:5px 5px 7px;border-right:1px solid var(--rule-base);border-bottom:1px solid var(--rule-base);background:var(--color-white);cursor:pointer;}
.tpl-start .tpl-timedate-mcell:nth-child(7n){border-right:none;}
.tpl-start .tpl-timedate-mcell:hover{background:var(--surface-warm-hover);}
.tpl-start .tpl-timedate-mcell.is-out{background:var(--surface-warm-hover);cursor:pointer;}
.tpl-start .tpl-timedate-mcell.is-out .tpl-timedate-mnum{color:var(--grey);}
/* ── A PAST DAY IS DEAD, AND HAS TO LOOK IT ──────────────────────────────────────
   A past cell takes .is-out for the GREY — the out-of-month treatment, reused rather
   than a second disabled state invented — and .is-past for the one thing that
   treatment gets wrong here. `.is-out` explicitly sets `cursor:pointer`, because an
   out-of-month day IS clickable: clicking a trailing day adds a slot in the next
   month, deliberately. So the two states share a look and not a behaviour, and this
   is the half that has to differ. The click handler is not attached at all on a past
   cell (question-types.js) — this only stops the pointer promising otherwise.
   Same specificity as the rule above it and declared after, so it wins the cursor
   and inherits everything else. */
.tpl-start .tpl-timedate-mcell.is-past{cursor:default;}
.tpl-start .tpl-timedate-mcell.is-today .tpl-timedate-mnum{background:var(--red);color:var(--on-ink);}
.tpl-start .tpl-timedate-mnum{align-self:flex-start;min-width:22px;text-align:center;font-family:var(--font-heading);font-size:var(--type-field);line-height:var(--type-field-line-loose);color:var(--color-text-primary);}
.tpl-start .tpl-timedate-mchips{display:flex;flex-direction:column;gap:3px;min-width:0;}
/* ── THE CHIP YIELDS, AND IT WRAPS ─────────────────────────────────────────────
   Something has to give when seven columns share a narrow card, and it is the
   chip rather than the grid. flex-wrap:wrap is the platform's rule applied to
   this component — NOTHING TRUNCATES, IT WRAPS — so when the start time and the
   remove control cannot share a line, the × moves to a second line inside the
   same chip instead of being clipped or ellipsised. The cell's min-height (104px)
   already has room for two lines, so nothing else moves when it happens. */
/* ── THE CHIP SPENDS THE ROOM THE NATIVE CONTROL WAS TAKING (2026-09-09) ─────────
   padding 2px 4px, gap 4px and 11px type were all sized against a chip whose inner
   width was entirely consumed by <input type=time>'s ~44px floor. That control is gone,
   and the measurements say what is now affordable: at 1280 the chip fills its cell
   (76.1 of 77.1 usable — it always did, `align-items:stretch` in the column wrapper, so
   one slot and two look like the same component) and sits 38px short of the cell's
   height. Vertical room is free, horizontal room is not.
   [HARD] START + SEPARATOR + END STAY ON ONE LINE, AND THAT IS WHAT CAPS EVERY NUMBER
   HERE. The x has always wrapped below them; the times splitting apart would be a new wrap,
   and it is the one thing in the cell anyone reads as a unit. The line is 61px of content
   against 64.1 of inner width — measured, at 12px, with 5px sides and a 5px gap and the
   start input sized to a bare 5ch. Raising ANY of those four by ~1px drops the end onto its
   own row: 12px with 6px sides and a 4px-padded input measured 65 against 62.1 and did
   exactly that. The cell cannot give the difference back — seven of them share the card's
   content column, which is the page-wide measure and not this component's to widen. */
.tpl-start .tpl-timedate-chip{display:flex;flex-wrap:wrap;align-items:center;gap:5px;min-width:0;background:var(--surface-warm);border:1px solid var(--border-strong);border-radius:var(--radius-square);padding:6px 5px;font-family:var(--font-mono);font-size:var(--type-caption);color:var(--color-text-primary);}
/* THE INPUT TAKES THE COLUMN, UP TO 64px. It used to DECLARE 64px (and 48px in
   the <=640 arm), which is a floor stated in the one place that cannot know how
   much room there is. width:100% + max-width inverts that: the column decides,
   64px is the most it will ever want, and min-width:0 lets flex shrink it.
   A 12-hour or otherwise longer time format therefore cannot widen the grid —
   verified by rendering the input at 96px and 140px preferred width and
   measuring no change at all, at 1280 and at 390. */
/* ── [HARD] THE START FIELD SIZES TO ITS OWN FIGURES, NOT TO THE CHIP ────────────
   `width:100%` (with max-width:64px) is what made every previous measurement of "does
   an end time fit" really a measurement of this control: at 390 the chip's inner width
   is ~45px, so 100% took all of it and there was never room for anything beside it.
   It is a TEXT input now (question-types.js says why), so it can be sized in `ch` of
   its own face and the rest of the chip gets the remainder.
   5ch IS THE CONTENT — "09:00" — plus the 1px the transparent focus edge needs, the
   same arithmetic the length row's `calc(2ch + 2px)` uses and for the same reason: the
   unit is font-relative, so the box tracks the figures rather than a literal. */
/* P6c: `inherit` is deliberate, not an unconverted scale member — docs/type-scale-proposal-2026-09-18.md §3.3. */
.tpl-start .tpl-timedate-chip-time{
    width:5ch;
    max-width:none;
    min-width:0;
    border:none;border-radius:var(--radius-none);
    background:var(--color-white);
    font-family:var(--font-numeral);
    font-size:inherit;
    padding:var(--nudge) 0;
    text-align:center;
    color:var(--color-text-primary);
}
/* ── THE DERIVED END — SECONDARY BY CONSTRUCTION ─────────────────────────────────
   Same face and size as the start so the two read as one time and its consequence,
   and NOT the same weight or colour: lighter and dimmer, with no field chrome at all,
   so the chip reads as one editable time with a result beside it rather than a range
   with two ends you could type into. It is a <span>; there is nothing to focus. */
/* P6c: `inherit` is deliberate, not an unconverted scale member — docs/type-scale-proposal-2026-09-18.md §3.3. */
.tpl-start .tpl-timedate-chip-end{
    font-family:var(--font-numeral);
    font-size:inherit;
    color:var(--grey);
    white-space:nowrap;
    flex:0 0 auto;
}
/* Keep the native spinner / arrow-key stepping but hide the clock picker
   indicator that obscured the value in the narrow chip. */
.tpl-start .tpl-timedate-chip-time::-webkit-calendar-picker-indicator{display:none;}
/* DELETED: `.tpl-timedate-chip-end` — do not re-add; the reason is T100 in the decision record. */
/* white-space:normal — the date-range label is the days-mode chip's whole
   content, and nowrap made IT the column's min-content floor exactly as the time
   input did. It wraps now, per the platform rule. */
.tpl-start .tpl-timedate-chip-range{white-space:normal;overflow-wrap:anywhere;font-size:var(--type-badge);}
/* The x sits apart from the time and reads as a control, not a third figure: its own
   face and colour, and a hit area rather than a glyph — the vertical slack the chip had
   is exactly what pays for the padding. margin-left:auto keeps it at the far end of
   whichever line it lands on. */
.tpl-start .tpl-timedate-chip-rm{margin-left:auto;appearance:none;border:none;background:none;cursor:pointer;color:var(--red);font-family:var(--font-mono);font-size:var(--type-label);line-height:var(--type-label-line);padding:var(--nudge) var(--inset-tag);flex:0 0 auto;}
/* Append-only locked poll: a slot that already has responses is read-only —
   muted fill, dashed border, frozen time input; the × survives (reconcilePollSlots). */
/* A CONTINUATION — the same slot, drawn again on a later day it covers. It reads as an
   echo rather than a second option: no fill, a dotted edge and the grey the derived end
   time already uses for "this is a consequence, not a control". It carries no × (the
   builder omits it), so there is nothing here to disable. */
.tpl-start .tpl-timedate-chip.is-continued{background:transparent;border-style:dotted;color:var(--grey);}
/* DELETED: The .is-locked chip pair — do not re-add; the reason is T101 in the decision record. */
/* Hint sits directly above the month grid (first child of .tpl-timedate-cal),
   right-aligned and tight to the weekday header / table below it. */
.tpl-start .tpl-timedate-calhint{font-family:var(--font-mono);font-size:var(--type-badge);color:var(--grey);text-align:right;margin:0 0 var(--gap-tight);}
/* ── [HARD] THE CELL HAS A FLOOR, AND IT IS THE NATIVE CONTROL'S ───────────────
   Everything above lets the grid follow its container. It can only follow it so
   far: `input[type=time]` is a UA control with an intrinsic minimum width that
   CSS cannot cross. Measured, not assumed — forced to `width:1px;max-width:1px;
   min-width:0` it still renders 44px in this Chrome.

       44   the native time input, at its floor
     +  8   chip padding (2 x 4)
     +  2   chip border
     + 10   cell padding (2 x 5)
     = 64   the narrowest a cell can be and still hold an editable slot
     x 7
     = 448  the narrowest the grid can be

   Above 448px the columns track the container and nothing overflows. Below it —
   a phone — seven usable columns do not fit, and the choice is between a control
   too small to use and a scroll. The scroll wins, CONTAINED to the calendar so
   the PAGE never scrolls sideways: that is the defect being fixed, not a
   treatment being reintroduced. */
@media (max-width:640px){
    .tpl-start .tpl-timedate-cal{overflow-x:auto;}
    .tpl-start .tpl-timedate-monthdow,
    .tpl-start .tpl-timedate-monthgrid{grid-template-columns:repeat(7,minmax(var(--tpl-timedate-cell-min),1fr));min-width:calc(7 * var(--tpl-timedate-cell-min));}
    .tpl-start .tpl-timedate-mcell{min-height:78px;}
    /* ── THE CHIP'S THREE PARTS STAY ONE SIZE AT <=640 ───────────────────────────
       tokens.css raises every <input> to 16px here — the iOS focus-zoom floor, at a
       specificity (0,3,1) its own note warns a class-scoped size cannot beat — so the
       START field goes to 16px whether or not the chip asks. That floor is right and
       is not being fought: a field that zooms the viewport when tapped is worse than a
       tall chip. What WOULD be wrong is the start rendering at 16 beside an 11px end,
       so the derived half and the separator follow it up rather than the field being
       dragged down. --tpl-input-size is the same token the floor's value came from. */
    .tpl-start .tpl-timedate-chip-end,
    .tpl-start .tpl-timedate-chip-sep{font-size:var(--tpl-input-size);}
    /* ── AND <=640 KEEPS WHAT IT HAS ─────────────────────────────────────────────
       The desktop chip's new inset and type spend slack that only exists there. At 390
       the cell is 64 wide against 87, the chip is already three lines, and it clears the
       cell's height by 8px rather than 38. Measured, not assumed: with the desktop inset
       and the desktop input box the chip went 69 -> 76 and TOOK THE CELL WITH IT, 105 ->
       112. That is the one outcome this pass was told not to buy, so every value the
       desktop arm raises is put back here. It is not caution — at this width they are
       not slack, and the compromise is not one.
       P6c: left as a literal rather than folded to --type-caption (12px) or given its
       own step, per the operator's call on docs/type-scale-proposal-2026-09-18.md §6 Q3 —
       a +1px here is exactly what the note above forbids. */
    .tpl-start .tpl-timedate-chip{padding:var(--nudge) var(--inset-tag);gap:var(--inset-tag);font-size:11px;}
    .tpl-start .tpl-timedate-chip-time{width:calc(5ch + 2px);padding:1px 0;}
    .tpl-start .tpl-timedate-chip-rm{font-size:var(--type-note);padding:0 var(--nudge);}
    /* DELETED: `.tpl-timedate-chip-time{width:48px}` — do not re-add; the reason is T102 in the decision record. */
}
/* Slim "Quick Action" mode — the stripped Availability Poll front door. Hides
   the survey-builder + session scaffolding a single pre-set poll never needs,
   leaving the title + the availability question config (length/unit/host-tz +
   options). Display-only: nothing here changes what posts, so the created
   session is identical to a hand-built one (the form still posts through the
   same confirm() flat arm). The mode is forced GROUP via the gated #tpl-mode
   hidden input. The facilitator identity is NOT hidden — it is core session
   identity (run-by host/account), shown EDITABLE + defaulted to the logged-in
   user in the signed-in slim branch below, exactly like any other group session. */
/* Closing Date + Response Notifications: they used to be hidden here by
   `.tpl-start.slim-mode #tpl-advanced`, the wrapper they were authored inside. That
   wrapper is deleted, so they are named directly. Slim renders no rail, so without
   this they would appear in the CONTENT column mid-form — display only, the inputs
   still post exactly as they did. */
/* (Slim's LEFT rail is not hidden here — it is not EMITTED. See ABSENT, NOT EMPTY
   at the <aside> in the markup below for why CSS cannot do this one.) */
.tpl-start.slim-mode #tpl-close-date-block,
.tpl-start.slim-mode #tpl-notifications-block,
.tpl-start.slim-mode #tpl-stype-toggle,         /* type slider — heading-row (non-blank) */
.tpl-start.slim-mode #tpl-rank-type-toggle,     /* Items | Images sub-toggle — heading-row (blank) */
.tpl-start.slim-mode #tpl-flat-add-question,   /* + Add Question (single question only) */
.tpl-start.slim-mode #tpl-group-name-wrap,     /* Group / Team Name — irrelevant for a poll */
.tpl-start.slim-mode #tpl-completion-message-card, /* Completion message block */
.tpl-start.slim-mode #tpl-flat-items-label{    /* "Questions / Survey" card heading */
    display:none !important;
}
/* Self-Paced / Live toggle — hidden so the poll is FORCED self-paced. The row
   keeps its in-DOM <input type="hidden" name="workshop_mode" value="0">, which
   still POSTS under display:none (the checkbox is unchecked for a fresh slim
   session, so it can never override the 0) — i.e. workshop_mode=0 = self-paced,
   identical to choosing it manually. Its preceding hairline divider goes too. */
.tpl-start.slim-mode #tpl-workshop-toggle-row,
.tpl-start.slim-mode .tpl-section-divider:has(+ #tpl-workshop-toggle-row){
    display:none !important;
}
/* …but on the slim MANAGE page (an existing poll), surface the Workshop toggle
   so the facilitator can turn the mode off again — the manage "Workshop /
   Conference Mode" button turns it on. Create stays minimal (a fresh poll is
   never a workshop), so this is scoped to .manage-mode only. */
.tpl-start.slim-mode.manage-mode #tpl-workshop-toggle-row{display:flex !important;}
/* Slim MANAGE routes the toggle through the shared between-cards slot
   (#tpl-workshop-toggle-slot), identical to the normal manage page. Give it the
   same 6px/16px vertical rhythm the non-slim group slot uses so it sits evenly
   between the Overview card and the Response Management card. */
/* DELETED: DELETED 2026-08-31 with its two non-slim twins abo (above `.tpl-start.slim-mode .tpl-section-label`) — do not re-add; the reason is T103 in the decision record. */
/* The blanket slim-mode hide for .tpl-section-label ("Session Overview", "Welcome
   Page", "Items To Rank", …) DELETED here (P6c, 2026-09-18) — .tpl-section-label
   itself is deleted from templates.css as dead (no emitter anywhere), so a rule
   hiding it hides nothing. Do not re-add; docs/type-scale-proposal-2026-09-18.md §1.3. */
/* No slim override for .tpl-toggle-label: the only toggle label that renders on
   an Availability Poll is "Save To Project" (the section/criteria toggle labels
   belong to multi-section / DM editing, which a flat time_date_selector poll
   never has). It therefore renders through the canonical .tpl-toggle-label path,
   identical to every other session type, with no bespoke slim hide/re-show dance.
   The old blanket slim .tpl-toggle-label display:none plus its
   .tpl-project-toggle-heading re-exemption were removed as dead, self-cancelling
   divergence. */
/* ── FOUR CARDS (the shared .tpl-form-card mechanism, the SAME one the flat editor
   uses). Slim does NOT strip the card chrome or re-lay the fields loose — the page
   IIFE reparents the loose blocks into a card each:
     Card 1 "Overview"   = #tpl-session-setup-card — meeting name + the facilitator
       block. Its own markup; nothing is moved into it.
     Card 2 "Description"= #tpl-slim-description-card, receiving #tpl-welcome-intro-body.
     Card 3 "Message"    = #tpl-slim-instructions-card, receiving #tpl-flat-questions-body.
       Self-removes when that body is absent, which is every poll MANAGE page.
     Card 4 "Meeting Options" = the flat items .tpl-form-card — the availability
       calendar renders into #tpl-slim-cal-mount inside it (configMount).
   (It read "TWO BOXED CARDS" until 2026-08-25, when Description and Participant
   Instructions stopped being rows inside Card 1. Each card carries a .tpl-sublabel
   heading and a derived badge; the micro-label above each field names the FIELD, the
   heading names the CARD.)
   The cards use the STANDARD .tpl-start container width — the same full content
   width as the flat editor's cards (.tpl-start max-width:1100px, padding 24px);
   slim sets NO max-width of its own, so the two can never drift apart. Each field
   fills the card content width, so the calendar sizes to the card. Card padding +
   the standard field margins own the rhythm — the old bespoke 620px-centred-per-
   field column and 28px margin scale are gone.
   (Description = the Welcome/Introduction card body repurposed — heading input
   hidden, body textarea only; still posts as `instructions` → settings.intro.body.
   Place rides the reveal-with-disable pattern: .is-shown flips display, JS
   disables it when Online so it never posts a stale place.) */
/* The heading card (#tpl-session-setup-card) now rides the standard 840px band —
   same rule as standard setup cards (see the band group above). The wide calendar
   card (Card 2 / the flat items .tpl-form-card) falls through to the full-width
   .tpl-start container; the standard .tpl-form-card margin-bottom supplies the gap. */
/* DELETED: The two slim card captions that reused .tpl-sectio (above `.tpl-start .tpl-manage-date-created`) — do not re-add; the reason is T104 in the decision record. */
/* Manage-page "Date created" line — canonical inside-card mono label (.tpl-mono
   in markup: DM Mono 12px, --ink). Uppercase is applied HERE, scoped (the same
   pattern as .tpl-autosave-flag), not globally on .tpl-mono — which also styles
   URLs, filenames, embed code and project names where forced uppercase would be
   wrong. The lang value is sentence case ("Date created: :date"), so this is not
   a double-transform. margin:8px 10px gives even top/bottom rhythm between the
   title (14px bottom margin) and the switcher (0 top margin); 10px left/right
   preserves the old horizontal margin. No slim re-show rule is needed — the line
   no longer carries .tpl-section-label, so the blanket slim .tpl-section-label
   hide never touches it. */
.tpl-start .tpl-manage-date-created{margin:var(--inset-control) var(--gap-row);text-transform:uppercase;}
/* (The manage-chrome section captions that used to need a slim re-show exemption
   here — "Codes & Quick Actions" / "Responses & Results" — were moved INSIDE their
   cards as centred Tier-2 Bebas .tpl-sublabel headings, so the blanket
   .tpl-section-label slim hide no longer touches them and the re-show rule is gone.) */
/* Welcome card husk — its Description body is reparented into Card 1, so hide the
   now-empty card (beats applyModeFields' inline display via !important). */
.tpl-start.slim-mode #tpl-welcome-page-card{display:none !important;}
/* The welcome HEADING inline-edit line travels inside the reparented body — keep
   the whole underline wrapper hidden so only the Description survives. */
.tpl-start.slim-mode #tpl-welcome-intro-body > .tpl-inline-edit{display:none !important;}
/* Card 1 fields reuse the flat Session Title width/centring (70%, centred — the
   shared rule above); slim only adds the 18px vertical step between them. The
   input fills its 70% row via the shared #tpl-session-title rule, so no slim
   input-width rule is needed. */
/* DELETED: `margin-top:18px` — do not re-add; the reason is T105 in the decision record. */
/* Balanced heading card (setup + manage): make MEETING NAME the first VISIBLE
   element, flush at the card's shared balanced top padding (--space-lg), so the
   top gap mirrors the same padding below the last field. Two bits of top chrome
   otherwise reserve unmirrored space on a slim (Availability Poll) card:
     1. The Individual/Group mode toggle (#tpl-modes-block). A poll is inherently
        group, so it is rendered read-only and the flat-survey rule above hides
        it with visibility:hidden — which still RESERVES its box (~28px pill +
        20px margin-bottom = ~48px of invisible space pinned to the card top).
        display:none removes it from flow entirely. (Scoped to slim; flat-blank
        survey keeps its visibility:hidden kicker-stability behaviour.)
     2. The facilitator header (#tpl-session-setup-header) holds nothing visible on
        any slim page, yet still carries a bottom margin. It used to hold the
        signed-out organiser fields, so the collapse was gated on
        :not(:has(.tpl-facilitator-cols)) — "unless those fields are in it". Those
        fields are DELETED, so that gate could only ever be true, and a predicate
        that cannot be false reads as a condition somebody still has to satisfy.
        Removed; the collapse is unconditional on slim.
        What is left in the row is the aria-hidden spacer and, for a signed-in
        viewer, the two hidden organiser inputs — measured on the rendered page for
        BOTH viewers, not read off the Blade, and guarded by
        GroupSessionRequiresAccountTest::test_the_slim_setup_header_row_has_nothing
        _visible_left_in_it so a future visible child cannot be silently hidden here.
        Hidden inputs still POST under display:none — and since 2026-08-19 they are
        no longer the only carrier anyway: buildExtraSettings() falls back to the
        authenticated user. */
.tpl-start.slim-mode #tpl-modes-block{display:none;}
/* Nudge the Individual / Group toggle down a little from what sits above it — now the
   SESSION SETUP heading, since the toggle moved out of the card into the MODE CONTROLS
   slot. CREATE only: manage renders no heading above it, and slim hides it (rule
   above). The mobile media query tightens this to --space-xs. */
/* DELETED: `.tpl-start:not(.manage-mode) #tpl-modes-block` — do not re-add; the reason is T106 in the decision record. */
.tpl-start.slim-mode #tpl-session-setup-header{display:none;}
/* LOCATION (Online/In-person) and HOW WILL PARTICIPANTS RESPOND (Self-Paced/Live)
   rows share ONE layout: a centred flex column so the field label sits ABOVE a
   centred toggle, matching the centred inputs. The respond row reveals via
   applyModeFields (group-only) to this same CSS — no per-row override. */
/* LOCATION LEFT-ALIGNS NOW; the respondent row keeps the centring (2026-08-25).
   These two shared one declaration while BOTH sat in the rail, where a centred column
   was the rail's arrangement. LOCATION has moved into the Overview card, under Meeting
   Length, among left-aligned rows on the shared line column — so `align-items:center`
   would leave one row on the card centred against every other row's left edge. The rule
   is SPLIT rather than widened: #tpl-workshop-toggle-row still lives in the rail (and in
   the between-cards slot on manage) and its centring AND its 12px are unchanged.
   [HARD] --space-md, RE-RECORDED 2026-08-26 — A CAPTION OVER A CONTROL IS NOT A CAPTION
   OVER A FIELD. This read `gap:6px`, and its own note gave the reason: "THE 6px IS THE
   CARD'S LABEL-TO-CONTROL STEP, NOT A NUMBER PICKED HERE. Every other row in this well
   puts its control 6px under its caption — .tpl-crit-tag's own margin-bottom, measured 6
   on all three." That matched this caption to the FIELD captions around it, and the thing
   under this one is a TOGGLE.
   The end-of-section toggle's caption moved to --space-md in the same pass (its three
   surrounding gaps are one step now), so 6 here would have left the two in-card toggle
   captions disagreeing — which is the split this row's note was written to close, one
   control over. --space-md is the same token, read from tokens.css's scale, not a second
   literal: --stack-gap IS --space-lg and this is the step below it.
   WHAT IS DELIBERATELY NOT CHANGED: `.tpl-crit-tag{margin-bottom:6px}` in templates.css,
   the platform-wide caption-to-FIELD step. Every rust caption on the page reads it —
   SESSION TITLE, AGENDA / PURPOSE, MEETING/ EVENT LENGTH, SECTION DESCRIPTION and the
   rest — so moving it would re-space the whole surface to fix one control. Captions over
   fields stay at 6; captions over toggles are 16.
   The gap also spaces the revealed "in person" place field under the switcher, which is a
   sub-control of this row and moves with the row's step by construction. */
.tpl-start.slim-mode #tpl-where-row{display:flex;flex-direction:column;align-items:flex-start;gap:var(--space-md);}
.tpl-start.slim-mode #tpl-workshop-toggle-row{display:flex;flex-direction:column;align-items:center;gap:var(--inset-box);}
/* Respondent Mode label — canonical .tpl-mono (DM Mono 12px --ink) in markup;
   uppercase applied HERE the scoped way (not globally on .tpl-mono, which also
   styles URLs / filenames / embed code / project names). Applies in every context
   the row appears: the between-cards slot on setup + non-slim manage, and slim. */
/* The caption over a toggle, not the toggle: --tpl-rail-label (12px), NOT
   --tpl-toggle-label (9px, and built around the pill-slider's 76px knob — see the two
   tokens' notes). Both rails read this one class, so they move together by construction,
   and SETUP MODE in the centre column moves with them because it is the same kind of
   caption over the same kind of control — leaving it behind would open a new split of
   exactly the kind this change closes. */
/* (.tpl-workshop-mode-label's rule MOVED to public/css/templates.css 2026-09-02,
   beside .tpl-mono: the participant credit wears it too, and a page-scoped rule
   cannot reach another page. Same declaration, one home.) */
/* Label centred above the toggle; drop its own bottom margin so the row's 12px
   gap is the only spacing. Location uses .field-label; the Respondent Mode label
   uses the canonical .tpl-mono (.tpl-workshop-mode-label). */
/* DELETED: `> .field-label` — do not re-add; the reason is T107 in the decision record. */
.tpl-start.slim-mode #tpl-workshop-toggle-row > .tpl-workshop-mode-label{text-align:center;margin-bottom:0;}
/* THE CAP UNDER THE TOGGLE. Same object as .tpl-compare-count — a derived figure
   under the control that determines it — so it takes that treatment (mono 10px,
   --ink) rather than a third caption size. The column layout and the row's own
   12px gap place it; it only needs its own alignment because the row is centred in
   the between-cards slot and left-aligned nowhere. */
#tpl-workshop-toggle-row > .tpl-workshop-cap{font-size:var(--type-badge);line-height:var(--type-badge-line);text-align:center;}
/* ── <=640: RESPONDENT MODE'S CAPTION IS CENTRED TOO (2026-08-31, requested) ────────
   SESSION TYPE now stands above the rail as a centred [caption, slider] stack — the rail's
   `.tpl-sidebar .tpl-modes-block{text-align:left}` stops reaching it once it is out of the
   rail, so its caption centres from the base rule with nothing new written. RESPONDENT MODE
   is the same kind of object — a caption over a full-width slider — and it KEEPS its rail
   seat, so its caption needs saying here or the two read as different controls one under the
   other. Only the caption: the slider is width:100% in the rail and centring it would be a
   no-op, and the rows BELOW it (Closing Date, Response Notifications) are label-BESIDE-pill
   rows, a different shape, deliberately left alone.
   The same property, on the same element, as the slim rule directly above — that one is
   unconditional and slim-scoped, this one is <=640 and shape-blind; neither is a duplicate of
   the other at any width they both cover. */
/* [CORRECTED 2026-08-31, same day] "Only the caption" above was wrong on its own
   measurement, and the sentence that made it wrong is "the slider is width:100% in the
   rail and centring it would be a no-op". It is not a no-op out of the rail: measured at
   390 on the manage fixture, this row is a flex COLUMN with align-items:STRETCH, so the
   pill ran the full 359px of the lane while SESSION TYPE's identical control sat at
   240px, centred, with 67px of air each side. Two controls the [HARD] note calls
   deliberately identical, rendering as a full-bleed bar and a centred pill one under the
   other.
   ONE PROPERTY, THE ONE SESSION TYPE ALREADY USES. Its pill is centred by
   `align-items:center` on the flex parent (.tpl-mode-pair, measured); this row is already
   a flex column, so the same property on it centres both the caption and the control and
   there is no second mechanism. The caption's own `text-align:center` is DELETED with
   this edit — align-items shrinks the label to its content and centres it, so the
   declaration had nothing left to do.
   <=640 AND ON THIS ROW ONLY: the [HARD] shared-geometry rule stands. At >=641 this row
   keeps its rail seat, its stretch and its left-aligned caption, and Session Type is not
   touched at any width. */
/* (The <=640 rule this note describes lives in setup-sidebar.css's <=640 block, beside
   `#tpl-workshop-toggle-slot #tpl-workshop-toggle-row{align-items:stretch;width:100%}`
   and the rail's `> .tpl-pill-toggle{width:100%}` — the two declarations it has to
   release. Written here first at (1,1,0), it lost to the (2,1,0) stretch rule and
   measured no change at all, which is what sent it to the file that owns the row.) */
/* ONE MECHANISM FOR THE LABEL STEP, NOT TWO. This row is a flex column whose `gap`
   supplies its rhythm; .tpl-crit-tag also carries margin-bottom:6px, and together they
   read 12px against every other row's 6. The label's own margin is the redundant one
   here, so it is zeroed — which is the rule this row ALREADY had (it read
   `#tpl-where-row > .field-label{margin-bottom:0}` for exactly this reason) and it is
   re-pointed at the tier the label now wears rather than reinvented. */
.tpl-start.slim-mode #tpl-where-row > .tpl-crit-tag{margin-bottom:0;}
.tpl-start .tpl-where-place{width:100%;display:none;}
.tpl-start .tpl-where-place.is-shown{display:block;}
.tpl-start .tpl-where-place > .tpl-inline-edit{width:100%;max-width:none;text-align:left;}
.tpl-start.slim-mode #tpl-flat-questions-list{margin:0;}
/* The question prompt row holds only the prompt in slim (config is in Card 2). */
.tpl-start.slim-mode [data-question-wrap]{margin-bottom:0 !important;}
/* Drop the dead type-column caption spacer (an empty nbsp line emitted to align
   with the SELECT TYPE column, which the locked slim question never mounts). It
   was the extra space above the prompt — without it the Participant Instructions
   label sits on its box with the same standard .field-label gap as Description. */
.tpl-start.slim-mode [data-question-wrap] .qt-field-label{display:none;}
/* THE SLIM HEIGHT/RESIZE RULE IS DELETED (2026-08-24), NOT MOVED. It read
   `min-height:100px;resize:vertical` and both halves are now wrong rather than merely
   redundant: the field is inside a .tpl-crit-pair, so it takes the shared chrome-less
   textarea rule (resize:none, field-sizing:content, overflow:hidden) and grows with its
   own value. A min-height would hold a one-line description open at three lines, and a
   resize grip is the box chrome this commit is removing. The full editor's Introduction
   body never had either. */
/* Create Poll button keeps the standard .tpl-actions placement (no slim width). */
/* Drop the divider before the (hidden) blank-type toggle in slim (no stray line). */
/* Emphatic ZERO border-radius on slim boxes/inputs (other templates untouched). */
.tpl-start.slim-mode .tpl-issue,
.tpl-start.slim-mode .field-input,
.tpl-start.slim-mode .tpl-section-prompt-input,
.tpl-start.slim-mode #tpl-welcome-intro-body{border-radius:var(--radius-slim-flat) !important;}

/* The time_date config renders straight into Card 2's mount: kill the inner
   .qt-subcard frame so the calendar isn't boxed-within-a-box (the card IS the
   box). renderConfig re-emits .qt-subcard on EVERY rebuild, so gate the CLASS.
   (Its own "QUESTION N: Date & Time Options" heading used a .qt-subcard-label
   hide here too, until P6c deleted that class as dead, 2026-09-18 — the heading
   itself is unaffected, this file just stopped being the one hiding it.) */
.tpl-start.slim-mode [data-q-config].qt-subcard{border:none;background:transparent;padding:0;}
/* Comparison-question input inside each criterion / section card —
   deliberately a soft box, not an underline input. The five header
   fields (facilitator name + email, session title, group / team
   name, overall question / issue) use the .tpl-issue underline; this
   one prompt field renders as a subtle muted box. Typed text is black
   (var(--ink)); when the field still shows its pre-filled default the
   data-default handler adds .is-default-value, which carries the
   default-text grey (tokens.css). Only this class is affected — no
   change to .tpl-issue or any other input. */
.tpl-section-prompt-input{width:100%;box-sizing:border-box;border:1px solid var(--color-border);background:var(--color-field-row-bg);padding:7px 10px;outline:none;}
/* Desktop: constrain the Comparison Question input to 40% of the
   card's content width so it reads as a short prompt-tweak field
   rather than a primary entry. Mobile falls back to the base
   width:100% rule above. */
@media (min-width:768px){
    .tpl-section-prompt-input{width:40%;}
}

/* The end-of-section questions body is the next object down from whatever precedes it
   on the card — the adder on MS, the participant-question part on DM — so its top gap is
   the shared role, not a number of its own. */
.tpl-instructions-body{margin-top:var(--stack-gap);}
/* ── A WELL'S FIRST CHILD STACKS AGAINST THE PADDING, NOT AGAINST A PRECEDING
   OBJECT (2026-08-25) ────────────────────────────────────────────────────────────
   [HARD] THIS INVENTS NO SPACING. Both declarations only ever set an inset to ZERO, and
   only where something above is already claiming what is not true here. --stack-gap is a
   gap BETWEEN objects — .tpl-instructions-body's own comment calls it "the next object
   down from whatever precedes it on the card", and the slim well says the same of its
   `gap`: "a gap applies only BETWEEN items". A .tpl-crit-part's padding-top is the same
   kind of thing one level in: it clears whatever sits above the part INSIDE its pair,
   which on a DM criterion card is the name part and here is nothing. Both are second
   insets stacked on the well's own padding.
   Block layout would collapse a first child's top margin out of its parent and the first
   line would need no rule at all; .tpl-flat-subcard's padding-top is what blocks the
   collapse, so it restores what the box model would otherwise have done.
   RE-DERIVED BY REMOVAL, NOT ASSUMED (2026-08-25). The Description micro-label moved back
   INSIDE .tpl-crit-part--desc this commit, so the body is still the well's only child and
   the first line still bites: deleting it measures 53px heading-to-label against 29px with
   it. THE INSTRUCTIONS ARM WAS DELETED IN THE SAME PASS because the same test showed it
   changing nothing — #tpl-flat-questions-body carries no top margin, so that selector read
   as coverage and did none.
   THE SECOND LINE IS THE 9px THAT WAS LEFT. With only the first, the four cards'
   heading-to-label gaps read 19 / 29 / 19 / 19 at both widths — the Description card
   alone sitting 10px low, from its part's own top inset (9px) plus .tpl-crit-pair's 1px
   transparent border. Zeroing the inset lands it on 20. THE REMAINING 1px IS THE PAIR'S
   BORDER AND STAYS: it is load-bearing ([HARD] in templates.css — .field-invalid colours
   it, and it is why a part inside a pair measures 401 where a bare row measures 400).
   Scoped to the slim well's id, so the DM criterion card and the MS section description —
   where a first part genuinely does have a pair edge to clear — are not reached. */
.tpl-start.slim-mode .tpl-setup-fields-well > .tpl-instructions-body{margin-top:0;}
.tpl-start.slim-mode .tpl-setup-fields-well .tpl-crit-pair > .tpl-crit-part:first-child{padding-top:0;}
/* ── THE TWO OUTDENTED CARDS JOIN THE LADDER (2026-08-24) ─────────────────────────
   [HARD] THIS IS A DIFFERENT MECHANISM FROM THE REST OF THE LADDER, WHICH IS WHY IT IS ITS
   OWN COMMIT. Introduction Page (#tpl-welcome-intro-body) and Completion Message
   (#tpl-completion-message-body) read NO column token at all: both sat on the CARD's content
   edge — 326 at 1280, 26px left of the badge and 74px left of V3 — at widths of 292 and 584,
   which are half and all of the row content box. Nothing about them was derived; they simply
   filled whatever the card left. So they are not brought on with an offset, they are given
   the two tokens every other line on the page already reads: --col-line-x for where the line
   starts and --col-line-width for how long it is. One rule, one shared class, both cards.

   THE BOX IS THE V3 MEMBER, NOT THE TEXT INSIDE IT, and that is a real difference worth
   stating. Every other field on this surface is UNDERLINED, so its box edge and its text are
   the same x. These two are BOXED — a white fill with a 1px border and their own
   `padding:10px 14px` — and for a boxed control the border IS the field's left edge, exactly
   as an underline is for the others. So the border lands on V3 and the text sits its own
   15px inside it. That inset is the box's own affair, the same way every underlined field
   keeps its RIGHT inset for the completion badge; it is not a fifth vertical and nothing
   asserts against it. If these two are ever converted to the underlined treatment the rest of
   the page uses, that inset goes and the text joins V3 with the border — that is a design
   decision about the control, not a geometry fix, and it is not taken here. */
/* [HARD] SCOPED TO THE THREE IDs, NOT TO .tpl-instructions-body. That class has a FOURTH
   consumer — DM's end-of-criterion questions container carries
   `.tpl-crit-part.tpl-crit-part--questions.tpl-instructions-body` (the markup around line
   9218) — which is a nested part already on its own column and must not be moved. The class
   names "a body of instructions-like fields", not "one of these outdented cards".

   #tpl-participant-data-body JOINED 2026-08-31. Its content sat at the card's own edge for
   the same reason Introduction Page / Completion Message's did before this rule existed —
   read no column token at all — measured at the same 326/1280 the note above records for
   them. Same defect, same fix, same rule: give it the two tokens rather than an offset of
   its own. */
.tpl-start #tpl-welcome-intro-body,
.tpl-start #tpl-completion-message-body,
.tpl-start #tpl-participant-data-body{
    margin-left:var(--col-line-x);
    max-width:100%;
    box-sizing:border-box;
}
/* These two ARE a field line and nothing else, so the line width stays on the body.
   [HARD] #tpl-welcome-intro-body IS NOT ALWAYS A PAIR. In slim mode the pair is not
   rendered at all ($_instrPair = ! $slimMode) and the body holds .tpl-inline-edit /
   .tpl-block-row children directly, in a different card (#tpl-slim-description-card).
   Stating the width on `> .tpl-crit-pair` therefore reaches NOTHING there and the
   body runs to the card's content edge: caught by setup:header-lane at
   /templates/availability/start?slim=1 @1280 — its four field lines ended 769..854
   where every other shape ends at 853 — before it reached anyone. */
.tpl-start #tpl-welcome-intro-body,
.tpl-start #tpl-completion-message-body{
    width:var(--col-line-width);
}
/* ── [HARD] --col-right IS THE FIELD LINE'S RESERVE, SO IT IS STATED ON THE FIELD
   LINE (2026-09-01). `width:var(--col-line-width)` used to sit on the three BODIES
   above, which was true while a body held nothing but its Heading/Body pair — and
   silently wrong the moment one held a LIST as well. --col-right is 84px of held
   space at the end of a line, for the trailing control cluster that line's own
   [ Edit ] cue sits in. #tpl-participant-data-body's second child is the field
   editor, whose rows carry their own trailing cluster (Required · Track · Use Once · ×)
   INSIDE themselves, so it was reserving that space twice: 84px of the card
   surrendered to a control cluster that is nowhere near it. Measured at 1440, that
   is the whole of why the field row did not fit on one line — lane 588, contents
   617 — and the second row the rebuild grew was the symptom.

   ONLY THIS BODY. The first draft moved all three, on the strength of "each of the
   other two holds exactly one .tpl-crit-pair, so the width lands on the same box" —
   true of the markup this page renders by default and false in slim mode, where
   #tpl-welcome-intro-body has no pair at all. The width stays on those two bodies
   (above); this is the only one that holds more than a line.

   THE EXPRESSION LOSES ONE TERM AND THAT IS ARITHMETIC, NOT A DIFFERENT RULE. Its
   `100%` now resolves against the BODY, which has already spent --col-line-x as its
   margin, so the line pays only --col-right from here. `min(--col-line-max,
   calc(100% - var(--col-right)))` is the SAME form the two lines already inside a
   lead-paying container use (.tpl-section-prompt-wrap > .tpl-edit-field, twice in
   this file) — an existing pattern for this exact position, not a new one. ── */
.tpl-start #tpl-participant-data-body > .tpl-crit-pair{
    width:min(var(--col-line-max), calc(100% - var(--col-right)));
    max-width:100%;
    box-sizing:border-box;
}
/* ── THE TWO CHROME-CARD FIELDS ARE CHROME-LESS, LIKE EVERY OTHER FIELD (2026-08-24) ──
   [HARD] WHAT THIS RULE MUST NOT DO IS DRAW ANYTHING. These two carried the surface's only
   BOX treatment — `border:1px solid rgba(ink,0.18)`, a white fill and `padding:10..14px` —
   and a `resize:vertical` grip and a `min-height` with it. Every one of those is now
   supplied, or deliberately not supplied, by the shared mechanism the fields' new
   .tpl-crit-pair / .tpl-crit-part wrappers put them in: the PART draws the underline (rust
   while empty, ink once filled), the PAIR's textarea rule gives resize:none +
   field-sizing:content + overflow:hidden, and FIELD STATES gives the badge lane, the
   placeholder colour and the focus fill. So what is left here is the absence of chrome.

   THE BOX THIS REPLACED WAS ALREADY DEAD, AND SAYING SO MATTERS. `$sidebarLayout` is
   hard-coded true (line ~310), so every render carries .setup-sidebar and the old
   `border:1px … ; background:var(--color-white); padding:10px 14px` here was overridden on
   every page by setup-sidebar.css's half-conversion. It was never what shipped. Do not read
   this deletion as "the white fill was hiding the focus state" — MEASURED, the resting
   background was already transparent and the shared focus fill already worked on these two.
   What the override left behind, and what this commit actually removes, is a static
   `border-bottom` ON THE FIELD and a `padding: 7px 0` that cancelled the badge lane.

   THE FOCUS STATE IS ADOPTED, NOT SPECIFIED: `:focus{background-color:var(--color-white)}`
   on the field (THE FOCUS TREATMENT, templates.css). It is a DIFFERENT mechanism from
   --field-valid-fill, which was a COMPLETION fill and is deleted under the
   no-completion-fill rule — checked before adopting, and not reintroduced under this name.

   padding:0 stays STATED rather than omitted: the badge-lane rule in FIELD STATES sets
   padding-right for every field on the surface, and a shorthand here would reset it — which
   is exactly what setup-sidebar.css's `padding:7px 0` was doing, painting the completion
   badge on top of the value. Longhands only. */
.tpl-instructions-title,
.tpl-instructions-textarea{
    width:100%;
    box-sizing:border-box;
    background-color:transparent;
    border:0;
    border-radius:var(--radius-none);
    padding-top:0;
    padding-bottom:0;
    padding-left:0;
    outline:none;
}
.tpl-instructions-textarea{line-height:var(--type-line-prose);}
/* DELETED: The [data-section-intro-idx] indent rule — do not re-add; the reason is T108 in the decision record. */
/* Section/criteria QUESTION bodies render questions as full [data-question-wrap]
   cards — byte-for-byte the flat/survey question card. The old bare-number-column
   alignment machinery that used to live here (block margin-left:crit-indent, the
   -(num-width+6) questions-list pull, a narrowed 22px number-column width, and a
   --qt-prompt-inset:32px override) is RETIRED: a card fills its container flush, it
   does not align a bare number column to the criteria/items indent. The cards now
   inherit the flat geometry verbatim at BOTH breakpoints — number flush
   (position:absolute;left:-14px;top:6px), list + body flush — so an MS/DM question
   card == a flat question card. Only the DM-specific rules below remain (they match
   .qt-crit-line / the DM field-label, which the MS card layout never has). Do NOT
   re-introduce a section-scoped indent override here; that is exactly what made
   them diverge.
   (--qt-prompt-inset itself, which this paragraph used to cite for the 42px desktop
   / 1.5rem mobile figures, is deleted 2026-09-17 (docs/setup-manage-audit-2026-09-17.md
   §8.2 — proven unreachable, zero `var(--qt-prompt-inset)` anywhere). The geometry
   above does not come from it.) */
/* DM question prompt underline: same 460px as the criteria name / comparison-question
   lines, but its .tpl-inline-edit wrapper is nested in .qt-input-col — a narrower flex
   column than those lines' full-row parents — so the shared max-width:70% binds against
   the narrower column and the underline ends short. Use max-width:100% (not the
   shared 70%) so width:460px applies on desktop and the underline reaches the SAME
   right edge, while a sub-460px phone viewport still caps it to the parent instead
   of overflowing (flex-shrink:1 also shrinks it; flex-grow:0 keeps 460px the ceiling). */
   NARROWED 2026-08-01: `:not(.tpl-crit-part)`. This rule was written when the DM
   questions body was a CARD-LEVEL block that spanned the outer columns, so claiming
   the full --col-line-width was right. The block now lives INSIDE the criterion
   bonded pair, which is itself that column minus its border and text inset — so
   there the demand overflows the box by 87px. Because .tpl-crit-pair sets
   overflow:hidden it is a scroll container, and the overflow surfaced not as a wide
   row but as the BOX SCROLLING when "+ Add Question" focused the new input: every
   child rendered 74px left of a static, zero-margin parent. Narrowing the rule to
   the context it was written for is the fix; a counter-rule would have been a
   specificity race against this one (it is (0,4,0) and lives in a later stylesheet).
   The in-box case flex-fills instead — see .tpl-crit-part--questions in templates.css. */
.tpl-instructions-body[data-section-question-idx]:not(.tpl-crit-part) .qt-crit-line > .tpl-inline-edit{flex:0 0 auto;width:var(--col-line-width);min-width:var(--col-line-width);max-width:100%;}
/* The repeated "Additional Questions / Comments" .field-label above each DM question
   row: a little more space above (was margin-top:0), a little less below (was 6px), so
   it sits closer to its own prompt than to the row above. */
.tpl-instructions-body[data-section-question-idx] .qt-input-col > .field-label{margin-top:var(--gap-tight);margin-bottom:var(--inset-tag);}
/* Server-side validation error state for the inputs declared above.
   Sits next to the base rules so the page has one source of truth for
   "how a field looks". Selectors here use the element + class combo
   (input.field-invalid / textarea.field-invalid) under .tpl-start so
   specificity wins against .tpl-issue:not(.tpl-item-input) (0,2,0)
   and .tpl-section-prompt-input (0,1,0) — both define their own full
   box border with equal or higher specificity than a bare
   .field-invalid class would carry. The invalid state shows a full 2px
   red box border (with !important so it always wins over the base
   border) — an unmistakable error marker — plus a faint tinted
   background. Mirrors the base .field-invalid in blocks.css. */
.tpl-start input.field-invalid,
.tpl-start textarea.field-invalid,
.tpl-start select.field-invalid{
  border:2px solid var(--red) !important;
  background-color:rgba(var(--red-rgb),0.05);
}

/* Advanced Settings panel chrome moved to public/css/templates.css as
   the single shared definition (the .tpl-adv-* family).
   The master toggle still sits in a .tpl-block-header-row above.
   Segments picker chrome is start-screen specific and stays below. */
/* Segments picker chrome. */
/* ══ PARTICIPANT DATA — field editor, per docs/mockups/participant-data-card.html.
   That mockup is the decided design; every distance below is a named token,
   stated once, with the structural reason attached — see the tokens minted
   just above the field row rules, and setup-geometry.md's TIGHT/ROW/GROUP
   rhythm for everything else. Distances are stated by the LOWER element as
   margin-top; nothing here reaches upward. */

/* [HARD] THE CARD TITLE ROW MUST NOT WRAP — AT ANY WIDTH. .tpl-block-header-row
   {flex-wrap:wrap} (templates.css) is the shared rule every [data-card-badge-host]
   uses, and no other card's header row wraps at any width, because no other card
   puts its caption INSIDE the heading. This one does — the <p class="field-label">
   is nested in .tpl-sublabel so it inherits the heading's --col-field-lead column
   (see the [HARD] note on that markup) — and a flex line is collected using each
   item's max-content hypothetical width, which for that item is the caption on ONE
   unbroken line. Beside the badge that never fits, so the line wraps and the
   .tpl-sublabel drops below the badge, positioned by the host's own left edge +
   --col-field-lead instead of badge-right + gap + margin: 338 against 400 at 1280,
   and 31 against 61 at 390 (measured on all six badged headers — this is the only
   one that wraps).

   THE @media(min-width:641px) WRAPPER THAT USED TO SIT HERE IS DELETED, AND ITS
   STATED REASON WAS FALSE. It read "≤640 keeps the shared wrap so the caption can
   still drop to its own line on a phone-width card". The caption CANNOT drop to
   its own line: it is not a flex item, it is a block inside the heading, so the
   only thing the shared wrap can move is the heading-and-caption together, under
   the badge — the one outcome the rule exists to prevent. The exception was
   protecting a behaviour that does not exist. Nothing else changes: the heading
   still shrinks and wraps its own text, because a flex item's min-width:auto floor
   is its min-content, not its max-content.

   [HARD] IT IS SCOPED TO THE SHAPE, NOT TO THE CARD (2026-09-01). It read
   `#tpl-participant-data-card [data-card-badge-host]` — a card-scoped override
   whose real subject is not the card at all: it is any header row whose heading
   CONTAINS a block-level caption, because that is what makes the flex item's
   max-content the caption's own unbroken line. `:has(> .tpl-sublabel > .field-label)`
   says exactly that and nothing else. Two things follow that an id could not give:
   the second card to nest its caption is correct on arrival rather than wrapping
   until someone notices, and a card that ever moves its caption OUT — to the
   sibling <p> every other card uses — stops matching and gets the shared wrap back
   with no edit here. Today it selects the same single element the id did (censused
   across all six badged headers on blank/dm/ms at 1440 and 390: one match, same
   element, identical boxes before and after).

   WHY THE CAUSE IS NOT FIXED INSTEAD, having been established: the caption is
   nested in .tpl-sublabel deliberately, so it inherits the heading's
   --col-field-lead column. Lifting it out to a sibling <p> — what welcome /
   completion do — moves it from the heading's left edge (400 at 1440, 61 at 390)
   to the card's own content edge (325 / 19), which is a geometry change this
   session was told not to make. The other route, giving every
   .tpl-block-header-row > .tpl-sublabel `flex:1 1 0` so its hypothetical size stops
   being max-content, changes the layout algorithm for eight header rows to fix one.
   Scoping to the shape is the smallest statement that is also true. */
.tpl-block-header-row:has(> .tpl-sublabel > .field-label){flex-wrap:nowrap;}

/* Label→bar and bar→first-field are BOTH already stated — #tpl-segment-fields
   is on the page's existing "the rail runs the steps too" shared rule
   (`.tpl-start #tpl-segment-fields{display:flex;flex-direction:column;
   row-gap:var(--step-row)}`, further down this file), which puts a ROW step
   between every direct child: this label, the bar, and #tpl-segment-selected.
   The eyebrow's OWN margin-bottom (.tpl-crit-tag, templates.css,
   `margin-bottom:var(--step-tight)`) would ADD to that container gap rather
   than replace it — a container's row-gap does not collapse with a child's
   margin — so it is cancelled here exactly as .tpl-end-toggle > .tpl-crit-tag
   already does a few hundred lines down, for the identical reason: the
   container decided this gap, not the label. */
#tpl-participant-data-card .tpl-segment-fields > .tpl-crit-tag{margin-bottom:0;}

/* ── THE BAR — every preset in the decided order, Custom Field last and
   dashed. auto-fill grid sized for this card's real width (this card moved
   out of the 208px rail into the main column 2026-08-31); several-up at
   typical widths, 2-up narrow, no per-width column count baked in. ── */
.tpl-segment-tags{display:grid;grid-template-columns:repeat(auto-fill,minmax(140px,1fr));gap:var(--gap-tight);}
.tpl-segment-tag{
    box-sizing:border-box;border-radius:var(--radius-square);display:inline-flex;align-items:center;
    justify-content:space-between;gap:5px;
    padding:calc(3px + 2px) 16px 3px;
    background:var(--color-white);border:1px solid var(--hairline-strong);
    cursor:pointer;font-family:var(--font-heading);font-size:var(--type-field);letter-spacing:var(--type-field-tracking);
    text-transform:uppercase;color:var(--color-text-primary);line-height:var(--type-field-line);
    transition:background 0.15s,color 0.15s,border-color 0.15s;
}
.tpl-segment-tag:hover{border-color:var(--border-strong);}
.tpl-segment-tag-label{overflow:hidden;text-overflow:ellipsis;}
.tpl-segment-tag-plus{font-family:var(--font-body);font-size:var(--type-field);line-height:var(--type-field-line);color:var(--tpl-ph-color);flex:0 0 auto;}
/* Custom Field is dashed from the start — the odd one out on the bar, a
   perpetual "add another" rather than a single-use preset. It never gains
   .is-used: clicking it always appends a fresh field. */
.tpl-segment-tag--custom{border-style:dashed;color:var(--tpl-ph-color);}
/* A preset already on the session: still shown (a stable map of what a
   session can collect), but dashed, muted and inert with a tick where the +
   was — a status mark, not a control. Removing a field is the × on the field
   itself, never here. */
.tpl-segment-tag.is-used{background:none;border-style:dashed;color:var(--tpl-ph-color);cursor:default;}
.tpl-segment-tag.is-used:hover{border-color:var(--hairline-strong);}
.tpl-segment-tag.is-used .tpl-segment-tag-plus{color:var(--success);}

/* Bar→first-field is already stated too — see the note above the "Data type"
   label: #tpl-segment-fields's own row-gap puts a ROW step between the bar
   and #tpl-segment-selected. No margin-top here; that would be the SAME
   double-statement the label's margin-bottom was, measured at 32px against
   the declared 16 before it was removed. #tpl-segment-selected's OWN
   row-gap (a DIFFERENT, correctly-scoped rule further down this file, shared
   with .tpl-crit-pair/.tpl-questions-list/etc.) still governs the space
   BETWEEN each field row once there is more than one — that one is unrelated
   to this gap and stays. */

/* ── THE FIELD ROW. Two tokens minted here — nothing on this page already
   names "one field's name-box width" or "the field sub-card's own internal
   step", so neither reuses an existing token:
     --tpl-pd-name-w   one width for every field, so every switch beside it
                       starts at the same x
     --tpl-pd-stack    the sub-card's internal step, stated ONCE and spent
                       TWICE: sub-card top -> name box (this rule's
                       padding-top) and name box -> options (.tpl-pd-body's
                       margin-top). The two were 10 and 26 and read as
                       unequal because they were two separate statements;
                       one token cannot drift against itself.
   The answer-type segments size to their labels, which are the same on every
   row, so the dividers line up without a width token.
   The field indent (options under the name box) is NOT a third mint: it is
   drag-handle-width + row-gap, which --col-num-x (templates.css) already is,
   reused directly below rather than restated. ── */
#tpl-participant-data-card{
    --tpl-pd-name-w:170px;
    --tpl-pd-stack:12px;
}
/* THE SUB-CARD IS A LIGHTER PANEL, NOT A WHITE BLOCK. 34% white over the card's
   own surface — the mockup's `.fc` value — so the field reads as a raised area of
   the card rather than a separate white object sitting on it. (A solid fill is
   what shipped; it is the one thing on this card that reads louder than the card
   itself.) */
.tpl-segment-card{background:rgba(255,255,255,0.34);border:1px solid var(--hairline-base);padding:var(--tpl-pd-stack) 12px 12px;}
/* ONE ROW: grip . name box . answer-type switch . checks . x — every control
   the field has, on the line its name is on. It is not display:flex+row-gap from
   the shared "the rail runs the steps too" list any more (that rule described a
   column of PEERS; a field is a header and its options, not two peers), so the
   only vertical distance inside it is --tpl-pd-stack, stated by the lower child. */
.tpl-segment-card-header{display:flex;align-items:center;gap:var(--col-gap);}
/* The handle is templates.css's own .tpl-section-drag-handle/.tpl-drag-grip —
   SortableJS finds it by that class, exactly as it does for sections and
   criteria. --col-drag is what --col-num-x (the field indent, below) already
   assumes it costs, so its width here is that same token, not a literal. */
.tpl-segment-card-header > .tpl-section-drag-handle{flex:0 0 var(--col-drag);width:var(--col-drag);}
.tpl-pd-namebox{
    display:inline-flex;align-items:center;
    flex:0 0 var(--tpl-pd-name-w);width:var(--tpl-pd-name-w);min-width:0;
    border:1px solid var(--hairline-strong);background:var(--color-white);
    padding:calc(3px + 2px) 8px 3px;
}
.tpl-pd-namebox input{
    flex:1 1 auto;min-width:0;border:none;background:transparent;outline:none;padding:0;
    font-family:var(--font-heading);font-size:var(--type-field);letter-spacing:var(--type-field-tracking);
    text-transform:uppercase;line-height:var(--type-field-line);color:var(--color-text-primary);
}
/* DELETED: .tpl-pd-star — do not re-add; the reason is T109 in the decision record. */
.tpl-pd-switch{display:inline-flex;border:1px solid var(--hairline-base);background:var(--color-white);flex:0 0 auto;}
.tpl-pd-switch button{
    border:0;background:none;cursor:pointer;padding:var(--gap-tight) var(--space-sm) var(--inset-tag);color:var(--tpl-ph-color);
    flex:0 0 auto;text-align:center;
    font-family:var(--font-heading);font-size:var(--type-label);letter-spacing:var(--type-label-tracking-tight);
    line-height:var(--type-label-line);text-transform:uppercase;white-space:nowrap;
}
.tpl-pd-switch button[aria-pressed="true"]{background:var(--mode-selected);color:var(--on-ink);}
/* THE CHECK CLUSTER IS ONE ITEM BELOW THE BREAKPOINT AND NO ITEM ABOVE IT.
   display:contents means the three checkboxes ARE the header's flex items at full
   width — the row is byte-identical to having no wrapper at all — while below
   --tpl-pd-onerow-min (see the band further down) the same element becomes a real
   flex item with a 100% basis, so the three wrap together onto one line instead of
   the flex algorithm splitting them wherever the arithmetic happens to run out.
   Measured before choosing: a plain flex-wrap on the header drops the × alone onto
   line 2 at 1440 and orphans Required from the checks after it at 1280. */
.tpl-pd-checks{display:contents;}
/* Pushes the checks and × to the row's right edge. Deliberately a
   real element, not `justify-content:space-between` on the header — the
   header's OWN children vary (Track / Use Once only render for a list), and a
   spacer absorbs that without changing how the fixed-width neighbours are
   measured. */
.tpl-pd-spacer{flex:1 1 auto;}
/* Required / Track / Use Once — one pressable checkbox each, ONE component
   (segCheck in this file's script) so the two controls cannot drift apart
   the way three near-identical switches once did. */
.tpl-pd-check{
    display:inline-flex;align-items:center;gap:var(--gap-tight);background:none;border:0;cursor:pointer;padding:var(--inset-tag) var(--nudge);
    font-family:var(--font-mono);font-size:var(--tpl-toggle-label);letter-spacing:var(--type-badge-tracking-wide);
    text-transform:uppercase;color:var(--tpl-ph-color);line-height:var(--type-badge-line);white-space:nowrap;
}
.tpl-pd-check-box{
    width:13px;height:13px;flex:0 0 13px;border:1px solid var(--hairline-strong);background:var(--color-white);
    display:inline-flex;align-items:center;justify-content:center;font-size:var(--type-badge);color:transparent;
}
.tpl-pd-check[aria-pressed="true"]{color:var(--color-text-primary);}
.tpl-pd-check[aria-pressed="true"] .tpl-pd-check-box{background:var(--success);border-color:var(--success);color:var(--on-ink);}

/* DELETED: .tpl-pd-controls — do not re-add; the reason is T110 in the decision record. */

/* ── options, indented to the name box's left edge. field-indent = drag
   handle width + row gap = --col-num-x (templates.css) — the SAME token
   every item/section row already uses for this exact role, reused rather
   than restated. The distance ABOVE is --tpl-pd-stack, the same token the
   sub-card spends as its padding-top: one value, both gaps, so the two
   cannot render unequal. ── */
.tpl-pd-body{margin-top:var(--tpl-pd-stack);margin-left:var(--col-num-x);}
.tpl-pd-vals{display:flex;flex-wrap:wrap;gap:var(--gap-tight);align-items:center;}
.tpl-pd-vchip{
    display:inline-flex;align-items:center;gap:7px;
    background:var(--wash);border:1px solid var(--hairline-faint);
    padding:5px 8px 4px;font-family:var(--font-body);font-size:var(--type-field);line-height:var(--type-field-line-loose);
}
.tpl-pd-vchip button{background:none;border:0;padding:0;cursor:pointer;color:var(--tpl-ph-color);font-size:var(--type-note);line-height:var(--type-field-line);}
.tpl-pd-vchip button.tpl-pd-vchip-label{font-family:var(--font-body);font-size:var(--type-field);line-height:var(--type-field-line-loose);color:var(--color-text-primary);cursor:text;}
.tpl-pd-vchip button.tpl-pd-vchip-label:hover{text-decoration:underline;}
.tpl-pd-vchip button:hover{color:var(--error-red);}
/* A locked list's STORED chips (Phase 2 — responses received): dashed, read-only,
   no × — the same "inert status mark" treatment the bar's used tags carry. Scoped per
   chip, not per field: an option added in this editing session has no stored answers
   behind it yet, so it stays an ordinary editable chip until it is saved and reloaded. */
.tpl-pd-vchip.is-locked{background:transparent;border-style:dashed;}
.tpl-pd-vchip button.tpl-pd-vchip-label:disabled{cursor:default;}
.tpl-pd-vchip button.tpl-pd-vchip-label:disabled:hover{text-decoration:none;}
/* "+ Add option" is always the last item in the row, and carries the accent
   border while the list is empty. RENDERED EVEN WHEN THE LIST IS LOCKED
   (2026-09-01): adding an option takes nothing away from anyone who has already
   answered, so it is not one of the edits responses freeze — see segBuildField and
   TemplateController::mergeLockedOptions, which enforce the same split server-side. */
.tpl-pd-addopt{
    display:inline-flex;align-items:center;border:1px solid var(--hairline-strong);background:none;cursor:pointer;
    padding:calc(3px + 2px) 10px 3px;font-family:var(--font-heading);font-size:var(--type-label);letter-spacing:var(--type-label-tracking-tight);
    text-transform:uppercase;color:var(--tpl-ph-color);line-height:var(--type-label-line);
}
.tpl-pd-addopt:hover{color:var(--color-text-primary);border-color:var(--border-strong);}
.tpl-pd-addopt.is-needed{border-color:var(--accent);color:var(--accent);}
/* Country on Defined: no option editing, the full ISO list rides as
   real `options` already (IsoCountryList) — this note is the whole of what
   the editor shows for it. */
.tpl-pd-builtin{font-family:var(--font-mono);font-size:var(--type-note);color:var(--tpl-ph-color);}
/* font-size was a 15px literal at specificity (1,2,1), which beats the iOS focus-zoom
   floor at tokens.css's (0,3,1) — so this input rendered at 15px on a phone and zoomed
   the viewport on focus. var(--type-field) (16px) fixes it by landing AT the floor
   rather than beating it; see docs/type-scale-proposal-2026-09-18.md §4.2/§4.3. */
#tpl-participant-data-card input[type="text"].tpl-pd-newinput{
    font-family:var(--font-body);font-size:var(--type-field);padding:3px 6px;
    border:1px solid var(--border-strong);background:var(--color-white);width:120px;line-height:var(--type-field-line-loose);
}

/* ── [HARD] THE SINGLE ROW IS A >=1461px LAYOUT, AND THE NUMBER IS MEASURED ──────
   The breakpoint is where the row's controls stop fitting the header lane (the
   viewport minus 768, capped at 832). It was measured before Use Once and the
   three-way answer switch joined the row and no longer matches it: see
   docs/known-debt.md D-DEBT-116.

   BELOW IT, THE ARRANGEMENT THE NARROW LAYOUT ALREADY USES, one step earlier: the
   header wraps, the x leaves the flow into the header's own right-padding reserve so
   no line can be pushed past it, and the three checkboxes travel together onto the
   next line, ending on the same right edge every other line ends on. Nothing is
   dropped and no token is shrunk to force a fit — at these widths the controls
   genuinely do not fit one line, and the row says so instead of leaving the card.

   THE <=640 BLOCK BELOW INHERITS ALL OF THIS and only adds what is different there
   (no drag handle; the name box and toggle each take the full content width). The x
   reserve and the wrap used to be declared there; they are stated once, here. ── */
@media(max-width:1460px){
    #tpl-participant-data-card{
        /* The x is out of flow from here down, so the header holds its column as
           padding instead: the control's own box (an 18px glyph at padding:0 6px,
           22.52 measured) plus one --col-gap. */
        --tpl-pd-x-reserve:calc(23px + var(--col-gap));
    }
    .tpl-segment-card-header{flex-wrap:wrap;row-gap:var(--tpl-pd-stack);position:relative;padding-right:var(--tpl-pd-x-reserve);}
    .tpl-segment-card-header > .tpl-item-remove{position:absolute;right:0;top:2px;}
    /* One flex item, one line, ending on the header's content edge — which is where
       every other line ends, the x's reserve being outside it. */
    .tpl-pd-checks{display:flex;align-items:center;gap:var(--col-gap);flex:1 1 100%;justify-content:flex-end;}
}

/* ── NARROW: no drag handle; the name box and the toggle beneath it both take
   the header's full content width; the checks end on that same
   edge; × sits on the first line, out of flow, in the header's own right
   padding.

   [HARD] THE TWO WIDTHS MATCH BY CONSTRUCTION, NOT BY TWO NUMBERS THAT AGREE.
   What stood here re-valued the width tokens — --tpl-pd-name-w:100% and a
   toggle-half token at 50% — so the name box and the toggle were each computing
   their own way to "the same width", and the halves were computing their way to
   "half of it". They rendered equal, and nothing kept them equal: three
   expressions, one intent. The mockup does not do that and neither does this now
   — the name box GROWS into whatever the header line has left (flex:1 1 auto),
   the toggle TAKES A LINE (flex-basis:100%, so the wrap algorithm can never seat
   it beside anything), and each segment takes an equal share of THAT line
   (flex:1 1 0).
   Every width on this layout is the header's content box, measured once by the
   browser. --tpl-pd-name-w keeps its desktop value here, unread.

   The options indent is not re-valued either: --col-num-x is already 0px at
   ≤640 on .tpl-start (templates.css, THE RESERVE COLLAPSES AS A UNIT), so the
   copy of that declaration this block used to carry said nothing the card did
   not already inherit.

   VERTICAL: every gap inside a field sub-card is --tpl-pd-stack — card top to
   name box (the sub-card's padding-top), name box to toggle and toggle to
   the checks (this row-gap, since the header is what wraps them), and
   the checks to + Add option (.tpl-pd-body's margin-top). One token,
   four gaps. --step-tight stood on the row-gap and made two of the four 10
   against the other two's 12. ── */
@media(max-width:640px){
    /* (The x reserve, the header's flex-wrap/row-gap and the absolute x are NOT
       repeated here — the <=1460 band above already states them and this width is
       inside it. Only what is different at phone width lives here.) */
    #tpl-participant-data-card .tpl-section-drag-handle{display:none;}
    .tpl-pd-namebox{flex:1 1 auto;width:auto;}
    .tpl-pd-switch{flex:1 1 100%;}
    .tpl-pd-switch button{flex:1 1 0;width:auto;}
}
.criterion-weight-input::-webkit-outer-spin-button,.criterion-weight-input::-webkit-inner-spin-button{-webkit-appearance:none;margin:0;}
.criterion-weight-input:focus{border-color:var(--border-strong);}
.criterion-weight-input.invalid{border-color:var(--error-red);background:rgba(var(--error-rgb),0.06);}

/* NO margin-top. The distance to the card above is the form grid's row-gap
   (--tpl-gap, templates.css); the 40px that stood here was added ON TOP of it and
   rendered 72. */
.tpl-actions{display:flex;justify-content:flex-end;gap:var(--space-md);}
/* ── THE SECONDARY ACTION IS THE PRIMARY ONE INVERTED ────────────────────────────
   #tpl-slim-invite carries .tpl-continue as well, so every metric — the padding, the
   Bebas at --tpl-cta-size, the square corners, the mobile width:100% — comes from the
   one button definition and cannot drift from Create Poll beside it. Only the fill and
   the text colour swap, and the border it never had is what carries the shape once the
   fill is gone. Same `--secondary` idiom .tpl-facilitator-signin__btn--secondary uses
   further down this file, so this is the surface's existing pattern rather than a
   second one. The gap is --space-md, the container's, not a margin on either button. */
.tpl-continue--secondary{
    /* background-COLOR, not the `background` shorthand: the shorthand would reset
       background-image and take the envelope back off. .tpl-continue's own
       `background:var(--red)` in templates.css is a shorthand, and this rule wins
       per-property because the inline <style> loads after that sheet. */
    background-color:var(--invite-bg);
    color:var(--invite-ink);
    border:1px solid var(--invite-bg);
    /* The glyph is a token, drawn at its own aspect (16x12) and set in from the
       button's own padding so the label starts clear of it. */
    background-image:var(--invite-envelope-svg);
    background-repeat:no-repeat;
    background-position:left var(--space-md) center;
    background-size:16px 12px;
    padding-left:calc(var(--space-md) + 16px + var(--space-md));
}
/* ── BOTH BUTTONS AT THE WIDER ONE'S NATURAL WIDTH ──────────────────────────────
   ONE number, declared once, on the row rather than on either button — so neither
   repeats it and neither is the one the other is measured against in the stylesheet.
   --tpl-cta-w (tokens.css) is the INVITE button's own natural width, measured on the
   rendered page with the equalising off (invite 214.80, the primary 155.92 --
   re-measured 2026-09-19; the primary read 141 when this was written, before P6c/P6d
   moved the type); it is the wider of the two, so the narrower grows to it and nothing
   shrinks to anyone's content. The token is shared with the manage page's Response Management row, which
   measures the same 215 from its own widest button — see its note there.

   min-width, NOT width: a longer label — a translation, a rename — makes its button
   grow rather than clip, and the pair simply stops being equal, which is the failure
   worth having. THE <=640 ARM IS THE ROW'S, NOT THE BUTTON'S, AND THE CLAIM THAT
   STOOD HERE WAS ABOUT ONE BUTTON. It read: ".tpl-continue is already width:100%
   (templates.css) and 215 fits inside the narrowest supported gutter, so the arm needs
   nothing of its own." Both halves are true of ONE button and neither survives a second:
   width:100% is irrelevant once min-width floors the flex base, and the gutter has to
   hold two of them plus the row's gap. e165a32d made it two, and the floor then demanded
   215 + 16 + 215 = 446px inside a 374px row at 390 — a 454px document in a 390 viewport
   with 64px of Create Poll off-screen (RR-111). The row wraps at <=640 instead; see the
   @media arm at the foot of this block.

   A GRID WAS TRIED FIRST AND IS NOT WHAT THIS IS. `grid-auto-columns:1fr` inside a
   `width:max-content` row reads as "both at the widest natural width" and is not:
   measured, it sized both buttons to 332 against naturals of 215 and 141. The `1fr`
   tracks distribute the row's resolved width rather than resolving to a track's
   max-content, so the shrink-wrap and the fraction chase each other. */
.tpl-start.slim-mode:not(.manage-mode) .tpl-actions > .tpl-continue{
    min-width:var(--tpl-cta-w);
}
/* Manage page: the lone "Save Changes" button is centred (create keeps it
   right-aligned next to the flow). */
.tpl-start.manage-mode .tpl-actions{justify-content:center;}
/* DELETED: `.tpl-start.manage-mode .tpl-actions--structural` — do not re-add; the reason is T111 in the decision record. */
/* .tpl-continue + .tpl-continue:disabled + responsive width:100% moved to public/css/templates.css. */
@media(max-width:640px){
    /* [HARD] THE PHONE STACKS AN ACTION ROW; IT DOES NOT SHRINK ITS ACTIONS. Two
       .tpl-continue buttons on slim both carry min-width:--tpl-cta-w above, so the row
       has a 446px floor a 374px gutter cannot hold and nowrap (flex's default) made the
       PAGE scroll sideways rather than the row reflow — RR-111. flex-wrap is the cause:
       once the line can break, each button takes its own line at the width:100% it
       already has (templates.css), the floor is satisfied with room to spare, and the
       16px gap becomes the distance between them.
       NOT a narrower --tpl-cta-w and not a dropped floor: both put two actions of
       unequal weight side by side at half a phone's width, which says they are equal
       and clips the longer label. Weight is carried by fill here, not by width.
       Same answer .tpl-actions-row--trio already gives on manage (manage-chrome.css,
       @media(max-width:480px), grid-template-columns:1fr) — one mechanism, not two.
       Inert on every other shape: their .tpl-actions holds one button. */
    .tpl-actions{justify-content:stretch;flex-wrap:wrap;}
    /* DELETED: `.tpl-start{padding-left:16px; padding-right:16px}` — do not re-add; the reason is T112 in the decision record. */
    /* Section-card header (MS + DM) — mobile reflow to match the question card's
       number treatment, type-agnostic (Items / Images / Questions share this
       header). Hide the drag grip (like the question drag handle); pull the "01"
       number flush to the section card's left edge; reset the desktop name-field
       negative-margin calc (which assumed the grip + number widths) and let the
       name fill the row. The x / collapse controls already sit at the row end and
       the row does not wrap; [Edit] is already hidden on mobile globally.
       The number is NOT pulled to the section-card edge: the flat/MS question
       numbers sit at the section content-left (they ride sub-cards inset by the
       section's own padding), so the section "01" aligns there too - it falls back
       to the flex content-left, landing on the question cards' left edge (within
       ~1px of the question numbers), instead of flush to the card edge. */
    /* ONE mount again. The second arm — `.tpl-edit-row--header .tpl-crit-part--card-name >
       .tpl-section-drag-handle` — is DELETED (2026-08-02): it was added when MS moved this
       handle inside the name part, and MS has moved it back to the header row's first cell
       where DM's has always been, so the first arm covers every shape and the second would
       match nothing. No drag-reorder on a touch screen, and "hover-only" is not the same
       statement as "not there" — the row would still reserve the handle's width. */
    .tpl-start .tpl-edit-row--header > .tpl-section-drag-handle{display:none;}
    .tpl-start .tpl-edit-row--header > .tpl-edit-field{margin-left:0;flex:1 1 auto;width:auto;max-width:none;}
    /* DM card header: the × + collapse ▾ (.tpl-row-controls, ~51px, flex-shrink:0)
       are an in-flow flex sibling AFTER the full-width name field, so on mobile — where
       the field stays its rigid flush-column width (W−64) and the --col-right reserve is
       only 34px — the cluster is pushed past the card's right edge. The controls belong
       on the HEADING row (the "A CRITERIA" name line at the top), not sharing horizontal
       space with the name field. Lift them OUT of flow and pin them to the header's
       top-right so the name/question line keeps its full length AND nothing overflows:
       their right edge lands --col-right in from the content edge — directly above the
       name/question line's own right edge (which ends at that same --col-right reserve).
       right = --col-right (34) + the sub-card's 14px padding-right = 48px from the
       padding box; the header sub-card is made the positioning context. MOBILE ONLY;
       desktop keeps the in-flow layout where the 84px reserve leaves ample room.

       [HARD] DM ONLY (2026-08-02). The MS arms of these three rules are DELETED, not
       left as harmless duplicates: MS's cluster is no longer a child of the header row
       at all — it rides inside the header box on the name line — so
       `.tpl-edit-row--header > .tpl-row-controls` matches nothing there, and neither
       does the clearance rule's `> .tpl-edit-field > .tpl-inline-edit` (the wrapper is
       a child of .tpl-crit-part--card-name now). Two selectors that silently match
       nothing is exactly the failure mode the descendant-vs-`>` note on the question
       row records; an inert MS arm would read as "MS still needs this" to the next
       person. The problem itself is gone on MS, not worked around: in-flow inside the
       box, the cluster has the whole line to sit at the end of, and cannot reach the
       reserve to overflow it. */
    .tpl-start:has(#tpl-add-criterion-btn) .tpl-edit-row--header{position:relative;}
    /* right:0, NOT `--col-right + 14` (2026-08-31). Both terms of that sum are gone as
       reasons: --col-right is 0px on a phone now, and the 14px was the sub-card's own
       padding, which the cluster had to clear because it was pinned to the row's PADDING
       box with nothing reserved for it. The row reserves --col-ctrl-reserve at its own
       right end (THE ITEM ROW'S × ... exception, above) and the cluster is placed into
       that reserve, so the offset it needs is none. A cluster wider than the reserve grows
       LEFT into the field's badge lane, which holds no ink between the badge and the line's
       end — measured, not assumed. */
    .tpl-start:has(#tpl-add-criterion-btn) .tpl-edit-row--header > .tpl-row-controls{position:absolute;top:12px;right:0;}
    /* DELETED: THE NAME LINE'S 10px CLEARANCE — do not re-add; the reason is T113 in the decision record. */
    /* DELETED: THE MS QUESTION ROW'S MOBILE PIN — do not re-add; the reason is T114 in the decision record. */
}

/* ── Mobile (≤480px) — collapse the 70%-centred fields to full-width.
   The desktop rules above centre Session Title / Issue / Project picker
   at 70% of the card so they read as a balanced column on wide
   viewports. At narrow widths the 30% of empty gutter is wasted and
   the inputs feel cramped, so each row spans the card edge-to-edge. */
@media(max-width:480px){
    /* padding-TOP IS DELETED HERE (2026-08-31, second edit of the same day). The note
       that stood here was right that 36/60 were live and wrong that they should stay:
       36px was the page's top inset written as a literal at the ONE breakpoint where the
       page is tightest, and it silently outranked the <=640 arm beside the base shorthand
       — measured, that arm moved nothing at 390 until this line went. The top inset now
       reads var(--tpl-gap) from that one arm, which covers this breakpoint too.
       padding-BOTTOM stays: 60px below the last card is not the gap between two objects
       and has not been asked to be. The rest of the note holds — the shorthand's dead
       left/right 10px is why this is a longhand at all, and --tpl-page-margin is still
       the gutter mechanism. */
    .tpl-start{padding-bottom:60px;}
    /* THE BAND ROWS ARE NOT ON THIS LINE ANY MORE. `width:100%` here would put them
       --col-line-x past the well's right edge, because they now spend that offset as a
       margin (THE IDENTITY ROWS JOIN THE LINE COLUMN). Their base rules already cap
       them at `100% - --col-line-x`, which IS "full width" once the offset is paid, so
       there is nothing left for this arm to say about them.
       `#tpl-session-title-row` was additionally INERT here — (1,2,0) against the base
       arms' (1,3,0) — so removing it moves nothing at all; the three slim ids and
       .tpl-ws-group-name were live. .tpl-ws-group-name STAYS: its remaining consumer is
       the signed-out facilitator block, which is a control cluster and not a field
       line, and it keeps the behaviour it had. */
    .tpl-start .tpl-form-card .tpl-ws-group-name{width:100%;}
    .tpl-start .tpl-form-card{width:auto;}
    /* (d) Save Details → ABOVE the Session Title. #tpl-session-setup-card is a
       flex COLUMN at this tier (templates.css ≤480 block) with the title promoted
       to order:-1; drop the Save block out of its absolute top-right anchor into
       the flow at order:-2 so it sits above the title, right-aligned via
       align-self:flex-end, keeping its max-content width. The desktop absolute
       top-right anchor (base rule, no media query) is untouched — this only
       applies ≤480px. Same specificity as the base rule (.tpl-start #id = 1,1,0),
       later in source + inside the media query, so it wins on phones only. */
    .tpl-start #tpl-save-project-block{position:static;order:-2;align-self:flex-end;top:auto;right:auto;margin-bottom:var(--inset-tag);}
    /* Trigger-box width follows the card's ≤480 horizontal padding (10px,
       templates.css ≤480, down from 16px) so it stays edge-aligned with the
       SESSION TITLE well, whose inset also drops to 10px at this tier. Same
       mechanism as the ≤640 rule above. */
    #tpl-switcher{padding-left:var(--gap-row);padding-right:var(--gap-row);}
    /* (The old ≤480 flex-order hack that pushed the guest Facilitator block below
       Group Name is retired: the block now sits BELOW Group / Team Name and just
       ABOVE the Individual / Group toggle in DOM source order, so the natural
       order-0 stack already gives Save, Title, Group Name, Facilitator, Toggle on
       phones — no per-element `order` override needed. templates.css still keeps
       the title at order:-1 and Save is order:-2 above.) */
}

/* ── Facilitator identity line (signed in) + sign-in CTAs (signed out) ── */
.tpl-facilitator-identity{display:flex;flex-wrap:wrap;align-items:baseline;gap:6px;align-self:center;}
/* DELETED: THE TWO-COLUMN ORGANISER LAYOUT — .tpl-facilitator (above `@media(max-width:640px){`) — do not re-add; the reason is T115 in the decision record. */
/* DELETED: `--tpl-name-span:520px` — do not re-add; the reason is T116 in the decision record. */
@media(max-width:640px){
    /* Collapse the 1fr|auto|1fr card-top grid that pins the facilitator name/
       email to a content-sized CENTRE column (cramped on phones), so the fields
       grow to a comfortable — but not edge-to-edge — centred band. The Save
       Details block (card-level, absolute) is a SIBLING of this grid, so it is
       unaffected.

       NAMED, not `.tpl-ws-card-top` — this is about the two rows that carry a
       WIDE centre child (the facilitator name/email pair; Response Management's
       heading beside Track Respondents), which is what gets cramped. The OVERVIEW
       header row also uses the class now and must NOT collapse: its centre child
       is one short word, and dropping to a single column would put its explicitly
       placed .tpl-sublabel (grid-column:2) into an IMPLICIT second column — i.e.
       not centred at all, silently, at exactly the width nobody screenshots.
       Naming the two preserves their behaviour to the pixel. */
    .tpl-start #tpl-session-setup-header,
    .tpl-start #mgmt-respond-header{grid-template-columns:1fr;}
    .tpl-start .tpl-ws-card-top > .tpl-ws-card-spacer{display:none;}
    .tpl-start .tpl-ws-card-top > .tpl-ws-facilitator{grid-column:1;justify-self:stretch;}
    /* DELETED: The mobile stack for the organiser columns — do not re-add; the reason is T117 in the decision record. */
}
/* ── Mobile (≤640px) — flat-ranking band widths + toggle proximity ─────────
   (a) Widen the flat Overall Question line and each item row to the full card
   content box (the card's own 12px mobile padding is the inset) so the rows fill
   the width without touching the card edge. Applied in BOTH modes: Individual
   already centred this via the S168 band, but Group mode left the wrap flushed
   left + capped at --col-line-width (rules ~959-960) — reusing THIS same
   width:100% treatment (no mode gate) gives Group the identical full-width
   Overall Question line + item rows Individual has, on mobile only. Desktop is
   untouched; DM/MS have no #tpl-rank-type-toggle so they never match.
   (b) Pull the Individual/Group toggle closer to the Session Title
   (var(--space-md) 16px → --space-sm 8px). */
@media(max-width:640px){
    /* DELETED: `.tpl-edit-field` — do not re-add; the reason is T118 in the decision record. */
    .tpl-start:not(.slim-mode):has(#tpl-rank-type-toggle) #tpl-items-list > .tpl-item-row{width:100%;max-width:100%;}
    /* DELETED: `#tpl-flat-compare-fields > .tpl-section-prompt-wrap` — do not re-add; the reason is T119 in the decision record. */
    /* (The MS comparison field's double-count fix used to live here, mobile-only. It is
       PROMOTED to the unconditional rule beside the comparison card, because the
       condition it was scoped to is now true at every width — see the note there.) */
    /* (b)+(c) Session Title + Team/Group Name — match the Overall Question line's
       FULL card-content width with CENTRED heading text, in BOTH modes. The
       underline is the .tpl-inline-edit CONTAINER's border-bottom (templates.css
       :871), so widening that container to 100% (from the base 400px/50%) gives
       the full-width line on its own — the row/wrap also widen to 100% (were 70%)
       so the band tracks the card. The input KEEPS field-sizing:content (hugs its
       text) and the container's justify-content:center centres the input+asterisk
       group, so the red required marker sits immediately AFTER the heading text
       (not trailing at the line's right end) while the underline stays full-width. */
    /* Same as the ≤480 arm below: the two band rows are off this line. `text-align:center`
       goes with them — it was the phone half of the Overview centring, and the only other
       element it reached, the signed-out facilitator block, declares its own. */
    .tpl-start .tpl-form-card .tpl-ws-group-name{width:100%;margin-left:auto;margin-right:auto;}
    /* DELETED: b) DELETED (Session 176) — the mobile half of the desktop override — do not re-add; the reason is T120 in the decision record. */
}
/* ── MOBILE (<=640): THE PICKER TAKES THE EYEBROW'S PLACE, AND THE CONTENT-TYPE
      SEATS TAKE THE CARD'S (2026-08-31) ──────────────────────────────────────────
   Both halves are RELOCATIONS, and neither is done here — setup-sidebar.js's MOVES
   table has a phone column now and sends these two controls nowhere on a phone, so
   each renders where start.blade.php authors it: #tpl-switcher immediately above
   .tpl-start-intro (the eyebrow's own position) and #tpl-rank-type-toggle /
   #tpl-stype-toggle inside the items card, under its heading and above the rows.
   What is left for CSS is what those two positions need. */
@media(max-width:640px){
    /* (1) THE EYEBROW GOES, BECAUSE THE PICKER SAYS THE SAME WORD. The kicker renders
       $switcherLabel and the picker's trigger renders $switcherLabel — one string, two
       boxes, deliberately so they could not drift (see THE KICKER IS BACK, below). With
       the picker itself in the kicker's place they are stacked, and the page names its
       template twice in two type sizes. So this is a DE-DUPLICATION and the live control
       is the one that survives; nothing is hidden behind anything.
       NAMED BY THE SURVIVOR, not by the page mode. The manage arm's .tpl-crit-tag in this
       same wrapper is #tpl-manage-group-kicker — the Group / Team name mirror, a different
       fact that the picker does not repeat — so it is excluded by id rather than by a
       .manage-mode gate, which would go wrong the moment a third arm renders one.
       >=641 IS UNTOUCHED: the kicker still renders there, and whether it has a consumer
       left at that width is a desktop question this <=640-scoped session does not answer. */
    .tpl-start .tpl-setup-identity > .tpl-crit-tag:not(#tpl-manage-group-kicker){display:none;}
    /* DELETED: `.tpl-switcher{position:static;text-align:center}` — do not re-add; the reason is T121 in the decision record. */
    /* (3) THE CONTENT-TYPE SEATS ARE EQUAL, AND THE GRID IS WHAT MAKES THEM EQUAL.
       The seats are sized by their labels everywhere else — `padding:0 16px` on
       .tpl-flat-mode-btn plus whatever the word measures — so TEXT and IMAGES render
       different widths. Two 1fr columns inside a fit-content box resolve to the WIDER
       seat's max-content, both of them, so equality is a property of the track sizing
       rather than a width somebody typed; add a third seat and it still holds.
       SMALLER: the seat's horizontal padding drops 16px -> --space-sm (8px), from the
       spacing scale rather than a literal.
       [HARD] SCOPED TO THESE TWO IDS, NOT TO .tpl-stype-toggle. D-DEBT-3 records that
       Session Type and Respondent Mode are deliberately two-seat word sliders with
       IDENTICAL geometry, and that a previous session's divergence there was an
       instruction rather than a mistake. They share this component's class; naming the
       two content-type ids is what keeps this override off them. */
    .tpl-start #tpl-rank-type-toggle,
    .tpl-start #tpl-stype-toggle{display:grid;grid-template-columns:1fr 1fr;width:fit-content;}
    .tpl-start #tpl-rank-type-toggle .tpl-flat-mode-btn,
    .tpl-start #tpl-stype-toggle .tpl-flat-mode-btn{padding-left:var(--space-sm);padding-right:var(--space-sm);}
}
/* ── MOBILE (<=640): THE ITEM ROW'S × IS THE ONE DECLARED EXCEPTION TO THE CARD-EDGE
      RULE, AND IT IS A TOUCH TARGET (2026-08-31) ────────────────────────────────────
   --col-right is 0px at <=640 (templates.css, THE TRAILING RESERVE IS ZERO ON A PHONE),
   so every line on the surface ends on its card's content edge. One row type cannot: an
   item row carries a real in-flow .tpl-row-controls — the ×, 10.52px of glyph — which is
   not a background layer like the ring/tick/pencil and not a duplicate of anything else
   on the row, so a line running under it would put the value under a control.

   THE ROW PAYS IT, NOT THE COLUMN. padding-right on the row shrinks the row's CONTENT box,
   and --col-flow-width's `100%` resolves against that box at the point of use, so the
   field shortens by exactly the reserve with no second width token and no per-field rule.
   The row itself still ends on the card's content edge; only the line stops short, and
   only on rows that carry the ×.

   AND IT IS 44px BECAUSE IT IS A FINGER. The × was a 10.52px hit area on a phone. The
   reserve and the target are the same number by construction (--col-ctrl-reserve), so
   they cannot drift apart into a control that is reachable but overflowing, or reserved
   for and still too small.

   :has(> .tpl-row-controls) — KEYED ON THE CLUSTER, NOT ON A LIST OF ROW TYPES. A row
   without one takes no reserve and needs no exclusion; a new row that grows one is
   covered without being named. */
@media(max-width:640px){
    .tpl-start .tpl-item-row:has(> .tpl-row-controls),
    .tpl-start .tpl-edit-row--header:has(> .tpl-row-controls){position:relative;padding-right:var(--col-ctrl-reserve);}
    .tpl-start .tpl-item-row > .tpl-row-controls{
        position:absolute;right:0;top:50%;transform:translateY(-50%);
        width:var(--col-ctrl-reserve);height:var(--col-ctrl-reserve);
        align-items:center;justify-content:center;
    }
    .tpl-start .tpl-item-row > .tpl-row-controls > *{min-width:var(--col-ctrl-reserve);min-height:var(--col-ctrl-reserve);}
    /* THE RESERVE IS THE CLUSTER'S BAND, NOT THE WHOLE ROW'S — AND THE ROW IS THE ONLY
       BOX THAT CAN HOLD IT. DM's criterion header row is one row holding a PART SET: the
       name line the cluster sits beside, and under it the description, the participant
       question and the end-question toggle, which nothing sits beside. The row has to pay
       the reserve (that is what shrinks --col-flow-width's percentage), so the parts below
       the name line GIVE IT BACK — the same idiom the drag handle already uses to cancel
       its own advance, `margin-right:calc(-1 * var(--col-num-x))`, and derived from the
       same token so the two halves cannot disagree.
       Measured at 390 before this: description and question ended at 309 with 44px of
       empty card beside them and no control in it. */
    .tpl-start .tpl-edit-row--header:has(> .tpl-row-controls) .tpl-crit-pair > :not(.tpl-crit-part--name){margin-right:calc(-1 * var(--col-ctrl-reserve));}
}
/* ── Slim Availability Poll — Session Overview adopts the participant
   context-box voice ──────────────────────────────────────────────────────
   The facilitator block keeps the standard CENTRED card-top layout (the base
   3-column grid: spacer | facilitator centred | project toggle right; rules
   .tpl-ws-card-top above), matching every other centred Overview row on the
   slim poll editor — no slim grid/alignment override. Slim only quietens the
   label/value PAIRS to the participant context-box voice (q-avail-loc-tag:
   11px muted label ABOVE a clean Abel value), the same treatment the response
   screen's MEETING / ORGANISER boxes use. Slim-scoped + typography only (the
   markup is SHARED and untouched, so the standard overview card is unaffected).
   The old slim label/value quieten rules were removed with the .field-label —
   the fields now render as the boxed .tpl-fac-input treatment on slim too,
   matching slim's Meeting Name field. */
/* Signed-out auth affordances (relocated into the Session Overview card).
   Group mode: a "Save Details" dropdown in the card-top right column,
   switcher-styled like "Add To Project" (the .tpl-save-* rules are grouped
   with .tpl-project-* below). Individual mode: the two auth buttons + a
   centred muted hint sit in the card-top centre column, where the
   facilitator name/email appear once signed in. Both reuse the
   [data-auth-modal] hooks; presenterAuthSuccess() hides them on success. */
/* margin:0. The 18px bottom was written when this block sat ABOVE other content in the
   card; relocated into #tpl-ws-auth-slot it is the fields well's LAST child, so the 18
   stacked on the well's own padding and the card's — 86px from the buttons to the card
   edge against the 44 (well 12 + card 32) every other last-element-in-the-well gets. The
   nav copy already zeroed it (.hv2-nav #tpl-ws-auth-individual{margin:0}), so removing it
   here leaves ONE value for both contexts instead of a base and an override. */
.tpl-ws-auth-individual{display:flex;flex-direction:column;align-items:center;row-gap:var(--step-tight);text-align:center;margin:0;}
/* THE PAIR'S ROW SIZING, ON THE ROW (2026-09-25). flex:1 1 0 and the 130px cap sat on
   .tpl-facilitator-signin__btn itself, so the class that carries the button's LOOK also
   fixed its width; the HELP button (_template-switcher) wears the look and sizes to its
   label. Same values, scoped to the row they size; source order keeps the rule below
   winning where it always did. */
.tpl-facilitator-signin__btns > .tpl-facilitator-signin__btn{flex:1 1 0;max-width:130px;}
/* Individual-mode buttons: equal fixed width (sized to the wider "Create
   Account" label + padding) and single-line, mirroring the segmented mode
   control. Overrides the base .tpl-facilitator-signin__btn flex sizing so the
   two never differ in width or wrap. */
.tpl-ws-auth-individual .tpl-facilitator-signin__btn{flex:0 0 auto;width:150px;max-width:none;white-space:nowrap;}
/* The hint renders ONLY where the block has been moved into the Overview card, i.e. Group
   mode. In the nav (Individual) the same node is present and silent. Keyed on the SLOT it
   sits in rather than on a mode class, so the one thing that decides it is the one thing
   applyModeFields already does. */
.tpl-facilitator-signin__hint{display:none;margin:0;}
#tpl-ws-auth-slot .tpl-facilitator-signin__hint{display:block;}
/* AN EMPTY SLOT IS NOT A ROW. #tpl-ws-auth-slot is a flex child of the fields well, so
   with nothing in it it still consumed the well's --stack-gap — a zero-height box holding
   24px of space open. It is empty in two states, and both are ordinary: Individual mode,
   where placeAuthButtons() sends the pair back to the nav, and after an inline sign-in,
   where presenterAuthSuccess() sends it home before hiding it. Measured post-sign-in:
   70px from the Group / Team field to the card's bottom edge against the 44 every other
   last-element-in-the-well gets.

   :empty, not a class or a JS write, because "holds nothing" is the actual condition and
   the DOM already answers it — the pair is MOVED between two parents, never cloned, so
   there is no state to keep in step. !important because applyModeFields clears the slot's
   inline display:none on its .tpl-group-only sweep, and an inline style beats any
   selector; without it the rule would depend on the order of two independent writes. */
#tpl-ws-auth-slot:empty{display:none !important;}
.tpl-facilitator-signin__btns{display:flex;flex-wrap:wrap;align-items:center;justify-content:center;gap:var(--inset-box);}
.tpl-facilitator-signin__btn{font-family:var(--font-mono);font-size:var(--type-caption);letter-spacing:var(--type-caption-tracking);text-transform:uppercase;padding:5px 10px;border:1px solid var(--red);background:var(--red);color:var(--on-ink);cursor:pointer;text-align:center;}
/* Sign-in block relocated into the nav for guests (same slot as the facilitator
   name/email). Drop the card's bottom margin + the 150px button width so it fits the
   nav row; keeps its centred column layout from .tpl-ws-auth-individual. */
.hv2-nav #tpl-ws-auth-individual{margin:0;display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;gap:var(--gap-tight);}
.hv2-nav #tpl-ws-auth-individual .tpl-facilitator-signin__btns{display:flex;justify-content:center;align-items:center;flex-wrap:wrap;gap:var(--gap-row);width:100%;}
/* Restore the coloured button chrome — .hv2-nav-items button (0,1,1) strips
   background/border/colour/size from every nav <button>, so restate it at higher
   specificity: red-filled primary, white secondary, DM Mono 12px, centred. */
.hv2-nav #tpl-ws-auth-individual .tpl-facilitator-signin__btn{flex:0 0 auto;width:auto;font-family:var(--font-mono);font-size:var(--type-caption);letter-spacing:var(--type-caption-tracking);text-transform:uppercase;padding:5px 12px;background:var(--red);border:1px solid var(--red);color:var(--on-ink);cursor:pointer;}
.hv2-nav #tpl-ws-auth-individual .tpl-facilitator-signin__btn--secondary{background:var(--color-white);color:var(--red);}
.hv2-nav #tpl-ws-auth-individual .tpl-facilitator-signin__btn:hover{color:var(--on-ink);opacity:.85;}
.hv2-nav #tpl-ws-auth-individual .tpl-facilitator-signin__btn--secondary:hover{color:var(--red);}
.tpl-facilitator-signin__btn--secondary{background:var(--color-white);color:var(--red);}
.tpl-facilitator-signin__btn:hover{opacity:.85;}

