/* portal-event-setup.css — the Event set-up card (scripts/portal-event-setup.js).
   Own file, deliberately: portal.css is edited by many sessions at once, and this card's
   rules are self-contained. Tokens come from portal.css (--onyx, --ivory, --border, --ease). */
.es-card{background:var(--ivory,#FBF7EF);border:1px solid var(--border,var(--border-d,rgba(30,11,14,.13)));padding:28px 28px 20px;margin:0 24px 24px;position:relative;font-family:'Montserrat',sans-serif}
.es-howto{position:absolute;top:8px;padding:6px 0;right:18px;font-size:var(--text-micro);letter-spacing:.14em;text-transform:uppercase;color:var(--onyx,#1E0B0E);opacity:.6;text-decoration:none;border-bottom:1px solid currentColor} /* WCAG 2.2 2.5.8: measured 113×13 on a phone; padded to a 25px target (§35, 2026-09-01) */
.es-howto:hover,.es-howto:focus-visible{opacity:1}
.es-hd{display:flex;justify-content:space-between;gap:24px;align-items:flex-end;flex-wrap:wrap;margin-bottom:18px}
/* ── THE ONE-LINE HEADER (2026-09-14, portal-simplify) ────────────────────────────────
   Owner's brief: no introduction before the first question — progress is "a single
   discreet line 'Section 2 of 6' (+ the section title)" and the save state sits beside it.
   It is deliberately quieter than a section heading: the eye should land on the open
   section's own title, which is 1.15rem Crimson two rows below. House eyebrow shape
   (§8.10: var(--sans) 500, var(--text-xs), .18em, uppercase, --ch8-onyx-62). */
.es-hd:not(.es-hd-done){align-items:baseline;margin-bottom:10px;padding-bottom:8px;border-bottom:1px solid var(--border-s,var(--ch8-onyx-12,#DDD6CE))}
.es-step{font-family:'Montserrat',sans-serif;font-size:var(--text-xs,.72rem);font-weight:500;letter-spacing:.18em;text-transform:uppercase;color:var(--ch8-onyx-62,#6B6864)}
/* The section's own name is the useful half of the line and reads better in sentence case;
   it is hidden on a narrow phone, where "SECTION 2 OF 6" alone still fits one row. */
.es-step-t{letter-spacing:.04em;text-transform:none;color:var(--ch8-onyx-78,#464542)}
@media (max-width:480px){.es-step-t{display:none}}
/* "How to use this" moved OUT of the card's top-right corner and down to the foot (same
   brief: "keep it, but as a small discreet link at the foot of the card, not a button above
   the title"). The base rule above is position:absolute against .es-card; inside the foot it
   is an ordinary inline control, and it keeps its own 6px padding / 24px floor. */
.es-howto-foot{justify-content:flex-start;margin-top:14px;padding-top:12px;border-top:1px solid var(--border-s,var(--ch8-onyx-12,#DDD6CE))}
.es-howto-foot .es-howto{position:static;top:auto;right:auto}
/* ← Back sits opposite Next. .es-mod-foot is flex-end, so the Back link takes the far side. */
.es-back{margin-right:auto}
.es-title{font-family:'Crimson Pro',Georgia,serif;font-weight:400;font-size:1.35rem;line-height:1.2;margin:6px 0 6px}
.es-prog{min-width:220px;display:flex;flex-direction:column;gap:4px;font-size:.68rem;letter-spacing:.06em}
.es-prog-bar{height:3px;background:var(--border,rgba(30,11,14,.08))}
.es-prog-fill{height:3px;background:var(--onyx,#1E0B0E);transition:width var(--dur-considered,.5s) var(--ease,ease)}
/* ⚠ OPACITY IS NOT A COLOUR (EVR-099, WCAG 1.4.3, 2026-09-09). This line's ink is
   already --ch8-onyx-62 (#6B6864 — 4.94:1 on Linen), set by portal-v15.css:738; the
   `opacity:.7` here re-mixed it against the Linen behind it and shipped #95918b,
   MEASURED at 2.79:1 by scripts/portal-a11y-audit.mjs on the Today room at 12.5px.
   An opacity chosen for a mood throws away a ratio that was chosen for a reason, and
   nothing in the file records that it did. The step is NAMED here instead.
   --ch8-onyx-62 is the LIGHTEST chapter-08 step that clears 4.5:1 as text
   (tokens.css:158); --ch8-onyx-48 is 3.18:1 and is the PENDING step, never small text.
   `.is-saving` meant "at full strength" and said it in opacity, which is exactly what
   had to go: it now says it in ink, one step darker (--ch8-onyx-78, 8.55:1). */
.es-save{font-size:var(--text-micro);color:var(--ch8-onyx-62,#6B6864)}.es-save.is-saving{color:var(--ch8-onyx-78,#464542)}.es-save.is-error{color:var(--bloodstone,#B02A45);opacity:1}
/* --gold-ink, the house amber TEXT token (CPT-080, 2026-08-26). This line is
   the set-up card's live region: it carries save conflicts, validation
   refusals and send failures, so it is an ATTENTION colour, not an error one
   -- --brick is reserved for errors and most of these are not errors. Was a
   literal #6B3A22 belonging to no scale. Both clear AA on ivory (8.72:1 and
   5.09:1); the token is the lighter of the two, which is correct for a line
   that is usually informational. */
.es-live{font-size:var(--text-sm);color:var(--gold-ink,#846439);min-height:1em;margin-bottom:6px}
.es-mod{border-top:1px solid var(--border,var(--border-d,rgba(30,11,14,.13)))}
.es-mod-hd{width:100%;display:grid;grid-template-columns:2.4em 1fr auto;align-items:center;gap:12px;padding:14px 4px;background:none;border:0;cursor:pointer;text-align:left;font-family:inherit;color:inherit}
.es-mod-hd:focus-visible{outline:2px solid var(--onyx,#1E0B0E);outline-offset:2px}
.es-mod-num{font-size:var(--text-xs);letter-spacing:.18em;opacity:.55}
.es-mod-title{font-family:'Crimson Pro',Georgia,serif;font-size:1.15rem}
.es-mod-title em{font-family:'Montserrat',sans-serif;font-style:normal;font-size:.58rem;letter-spacing:.16em;text-transform:uppercase;opacity:.62;margin-left:8px} /* .55 was 4.15:1 on ivory; .62 = 5.2:1 (§35, 2026-09-01) */
.es-mod-status{font-size:.66rem;letter-spacing:.06em;color:var(--ch8-onyx-62,#6B6864);white-space:nowrap} /* EVR-099: was opacity:.7 -> the same #95918b at 2.79:1, on all six section chips. Named step, same reasoning as .es-save above. */
/* --success (= --forest), the house success token. Was a literal #2F6B3A.
   The selector is `.is-done`, so success is exactly what it means. 5.36:1 on
   ivory, AA clear. */
.es-mod.is-done .es-mod-status{color:var(--success,#317254);opacity:1}
.es-mod-body{padding:4px 4px 18px}
.es-intro{font-size:.82rem;opacity:.75;margin:0 0 14px}
/* A card holds two of the old modules (GROUPS, owner 2026-09-08). The sub-head keeps each
   one's own title and intro on screen — the list of things to open got shorter, the writing
   did not get thinner. Same serif as .es-mod-title, one step down, with a hairline above so
   the eye finds the seam without a second border weight.

   ⚠ THE FALLBACK IS THE CHAPTER-08 STEP, NOT THE RETIRED INK the older hairlines in this file
   still carry (AINS §24, row 24-a). `--border` is the token either way and is what actually
   paints — portal-v15.css binds it to `--ch8-onyx-12`, so nothing on screen differs. What
   changes is the value a document that loads this sheet WITHOUT the rebind would fall back to:
   the retired `rgba(30,11,14,.13)` in the neighbouring rules is counted by
   scripts/portal-palette-census.mjs as a retired reference, and a new rule has no business
   adding one. The rules above are row 24-a's migration work, not this one's. */
.es-part + .es-part{border-top:1px solid var(--border,var(--ch8-onyx-12,#DDD6CE));padding-top:16px;margin-top:4px}
.es-part-hd{font-family:'Crimson Pro',Georgia,serif;font-weight:400;font-size:1rem;letter-spacing:.01em;margin:0 0 4px}
.es-part-intro{font-size:.78rem;opacity:.72;margin:0 0 14px}
.es-q{border:0;padding:0;margin:0 0 18px;min-width:0}
.es-q legend{padding:0}
.es-q-issue .fld-input{border-color:var(--bloodstone,#B02A45)}
.es-q-deferred legend{opacity:.6}
.es-req{color:var(--bloodstone,#B02A45)}.es-opt,.es-sens{font-size:.58rem;letter-spacing:.12em;text-transform:uppercase;opacity:.62;margin-left:6px} /* .55 was 4.15:1; .62 = 5.2:1 (§35, 2026-09-01) */
.es-sens{border:1px solid currentColor;padding:1px 4px}
.es-pills{display:flex;flex-wrap:wrap;gap:8px;margin-top:6px}
/* `display:flex` above beats the UA's [hidden], so an answer the plan has already given ("Included in
   The Whole Event — Evorrah handles this. Change") still drew all five choices under it (owner
   2026-09-23: "if we are handling, why ask?"). The choices appear only after Change. */
.es-pills[hidden]{display:none}
/* ⚠ THESE PILLS WERE PAINTING IN BROWSER DEFAULT GREY (2026-08-25). The rule
   here set geometry only — min-height, padding, line-height — and no background,
   colour or border, so every one of them fell back to the user agent's button
   style: `rgb(0,0,0)` on `rgb(239,239,239)`, reproduced from the COMMITTED
   stylesheet in artifacts/es-pill-dna-20260825/A-live.png.
   ⚠ COUNTED, because an earlier draft of this comment said "19" — that was one
   module's worth on screen, not the card. Executed against the blueprint
   (packages/contracts/briefing-blueprint.js, `MODULES`): **271 pills across 70
   questions in 12 modules** — 205 pick-one (160 `choice` + 45 `ownership`) and
   66 pick-many. Module G alone, the one the owner screenshotted, renders 20. The markup asks for
   `class="po-choice es-pill"` and carries `is-on` for the selected state, but
   **`.po-choice` has no CSS declaration anywhere in the product** — grep for
   `.po-` across app/styles and app/assets returns nothing. The class was
   written expecting styling that does not exist.
   ⚠ THE SELECTED STATE WAS THE WORSE HALF. `is-on` was likewise undeclared, so
   a chosen answer painted **identically to an unchosen one** — on a pick-many
   question a client could not see what they had already ticked. That is a
   correctness defect, not a cosmetic one.

   THE RECIPE IS NOT NEW. It is `.dp-pill` (portal.css) — the portal's OWN
   answer pill, the one this same client already meets in the briefing form's
   design-piece picker — copied property for property: ivory ground, hairline
   border, .79rem Montserrat, hover to sage, selected as a sage border over a
   6% sage wash with the small square filled. No colour and no gesture enters
   the portal that was not already in it. A solid sage FILL was tried first and
   rejected (B-tree.png in that same folder): it reads as a second, louder
   selection convention beside the picker's, which is the drift this card was
   already suffering from.

   THE MARKER IS ONLY ON PICK-MANY QUESTIONS. `pill()` already emits
   `data-es-multi`, so the square — which is a checkbox in the house's language
   — appears exactly where several answers are allowed. A pick-one question
   confirms with border, wash and sage text instead, so the two kinds of
   question cannot be mistaken for each other. */
.es-pill{
  display:inline-flex;align-items:center;gap:8px;
  min-height:34px;padding:8px 12px;line-height:1.2;
  font-family:'Montserrat',sans-serif;font-size:var(--text-sm);font-weight:400;
  color:var(--onyx,#1E0B0E);
  background:var(--white,#FBF7EF);
  border:1px solid var(--border-d,var(--border-d,rgba(30,11,14,.13)));
  border-radius:0;cursor:pointer;user-select:none;
  transition:all 200ms var(--ease,ease);
  /* A <button> centres its text by default, so an answer long enough to wrap read as a centred
     paragraph (owner 2026-09-23, the WhatsApp choice: "this needs to be left aligned"). */
  text-align:left;
}
/* ⚠ THIS BORDER WAS FAILING WCAG 1.4.11 AND NOTHING WAS MEASURING IT (row 24-a, 2026-09-03).
   The square is the only thing that says "several answers are allowed", so it is visual
   information identifying a control's state and owes 3:1 against the pill's ground
   (`--white` -> `--ch8-linen`). Sage at .5 composited on Linen is #8FA39C = 2.39:1.
   --ch8-onyx-48 is the LIGHTEST sanctioned step that clears the floor at 3.18:1; onyx-34 is
   2.16 and onyx-20 lighter again, so this is the step the requirement picks, not a preference. */
.es-pill[data-es-multi="1"]::before{content:'';width:8px;height:8px;flex:0 0 8px;border:1px solid var(--ch8-onyx-48);transition:all 200ms var(--ease,ease)}
.es-pill:hover{border-color:var(--sage,#265450)}
/* ⚠ COMPOUND DIMMING — the wash and the ink have to move TOGETHER (row 24-a, 2026-09-03).
   `--sage` is rebound to --ch8-onyx-62, so the INK already moved and the 6% wash did not;
   onyx-62 on the sage wash (#EBE8DE) is 4.52:1, a hair over AA. Taking the wash to Onyx 6%
   (#EAE4DA) alone would drop that pair to 4.38 — under AA — which is precisely the class
   portal-v10.css records: every part separately correct, the pair below the floor. So the ink
   is named here rather than left to the rebind, and the pair goes 4.52 -> 7.58:1.
   The border stays a token read: onyx-62 on Linen is 4.94, clear of 1.4.11's 3:1. */
.es-pill.is-on{border-color:var(--sage,#265450);background:color-mix(in srgb, var(--ch8-onyx) 6%, transparent);color:var(--ch8-onyx-78)}
.es-pill.is-on::before{background:var(--sage,#265450);border-color:var(--sage,#265450)}
.es-pill:focus-visible{outline:2px solid var(--onyx,#1E0B0E);outline-offset:2px}
.es-explain{flex-basis:100%;font-size:var(--text-xs);opacity:.8;margin:-2px 0 4px;line-height:1.45}
.es-why{font-size:var(--text-xs);opacity:.7;margin:8px 0 0;font-style:italic}
/* The recommendation strip carried a flat `rgba(30,11,14,.04)` band with no
   border — the one shape on the card that belonged to no house recipe, so it
   read as unfinished rather than as advice. It is now `.piece-loading-hint`
   (portal.css), the portal's existing advisory note: a 6% sage wash behind a
   2px sage left rule. Same device as .rev-remaining-banner and the four
   bloodstone left-rule notices — the house draws emphasis with a rule, not a
   fill (brand.json forbids drop shadows as decoration). */
/* The 6% wash follows the left rule onto the quiet layer: chapter 8.2 has no structural teal.
   On the card's Linen the wash goes #EBE8DE -> #EAE4DA and the Onyx ink over it 15.03 -> 14.57:1. */
.es-rec{font-size:var(--text-sm);line-height:1.55;margin:10px 0 0;padding:10px 14px;background:color-mix(in srgb, var(--ch8-onyx) 6%, transparent);border-left:2px solid var(--sage,#265450);color:var(--onyx,#1E0B0E)}
.es-rec strong{font-weight:600}
/* `color:inherit` made "Use it" and "I don't know yet" onyx — indistinguishable
   from the sentence around them. portal.css:7092 styles the ownership panel's
   "Change" links "to match `.es-link`, the house's existing inline text-button
   recipe" and paints them SAGE with a 3px underline offset; this rule, the thing
   that comment points at, did not. Brought onto the recipe it is said to be. */
.es-link{background:none;border:0;padding:0;font-family:'Montserrat',sans-serif;font-size:var(--text-xs);font-weight:500;letter-spacing:.06em;text-decoration:underline;text-underline-offset:3px;cursor:pointer;color:var(--sage,#265450)}
.es-link:hover{color:var(--bloodstone,#B02A45)}
.es-link:focus-visible{outline:2px solid var(--onyx,#1E0B0E);outline-offset:2px}
/* ⚠ BLOCK, NOT inline-block (2026-08-25). "I don't know yet" is an escape hatch
   BELOW the field — its own margin-top:8px says so — but .es-input is capped at
   max-width:32em, so an inline-level button had room to sit on the SAME LINE.
   Measured at 1280px: a 4px gap from the input's right border, and the link's
   baseline 13.5px above the input's bottom edge, i.e. floating against the box.
   width:max-content keeps the underline the width of the words rather than the
   whole column — the same idiom .es-rec .es-link already uses below. */
/* EVR-099: `opacity:.8` faded the same --ch8-onyx-62 ink to #87837e, MEASURED 3.35:1
   at 12.2px. Both colours below are the ones portal.css:8277-8278 already pins with
   !important for this control (--ch8-onyx-62 quiet, --ch8-onyx when it is on), so this
   states the same answer rather than a second one. */
/* EVR-101 (WCAG 2.5.8, 2026-09-09): MEASURED 91×19 on the phone and 102×22 on desktop by
   scripts/portal-a11y-audit.mjs — under the 24px minimum. portal.css:7896 gives .es-link
   min-height:24px, but this rule's display:block plus a 0-padding button collapsed the box;
   the floor is stated here, on the control itself, so no later display rule can drop it. */
.es-defer{display:flex;align-items:center;min-height:24px;width:max-content;margin-top:8px;color:var(--ch8-onyx-62,#6B6864)}.es-defer.is-on{color:var(--ch8-onyx,#141414);text-decoration:none}
.es-err{display:block;margin-top:6px}
.es-input{max-width:32em}
.es-stake-row{display:grid;grid-template-columns:1fr 1.3fr 1fr auto;gap:8px;margin-bottom:8px;align-items:center}
.es-perms{font-size:var(--text-xs);margin-top:10px;border-top:1px dashed var(--border,var(--border-d,rgba(30,11,14,.13)));padding-top:8px}
.es-perm-row{display:flex;justify-content:space-between;gap:12px;padding:3px 0;flex-wrap:wrap}
.es-mod-foot{display:flex;gap:16px;align-items:center;justify-content:flex-end;margin-top:10px;flex-wrap:wrap}
.es-foot-main{padding-top:16px;border-top:1px solid var(--border,var(--border-d,rgba(30,11,14,.13)))}
.es-callout{padding:12px 14px;margin:0 0 14px;font-size:var(--text-sm);border:1px solid var(--border,var(--border-d,rgba(30,11,14,.13)))}
.es-callout ul{margin:6px 0 0;padding-left:18px}
.es-callout-warn{border-color:var(--bloodstone,#B02A45)}.es-callout-ask{background:color-mix(in srgb, var(--ch8-onyx) 4%, transparent)}
.es-ask{display:flex;gap:12px;align-items:center;justify-content:space-between;flex-wrap:wrap;padding:6px 0}
/* A designer's free-text question is answered IN the card (P100 feature 4): the box takes a
   row of its own, and so do the operator's two optional lines — when it is wanted by, and
   what it holds up. 44px is the touch floor the rest of this card keeps. */
.es-ask>.fld-hint{flex:1 1 100%;margin:0}
.es-ask-answer{flex:1 1 100%;font:inherit;font-size:var(--text-sm);padding:8px 10px;min-height:44px;resize:vertical;background:transparent;color:inherit;border:1px solid color-mix(in srgb, var(--ch8-onyx) 14%, transparent)}
.es-review h3,.es-effects h3{font-family:'Crimson Pro',Georgia,serif;font-weight:400;font-size:1.05rem;margin:10px 0 8px}
.es-sum,.es-eff{font-size:var(--text-sm);margin:0 0 10px}.es-sum ul,.es-eff ul{margin:3px 0 0;padding-left:18px}
.es-past{color:var(--bloodstone,#B02A45);font-size:var(--text-xs)}
@media (max-width:720px){
  .es-card{margin:0 12px 16px;padding:18px 14px 14px}
  .es-title{font-size:1.2rem}
  .es-hd{flex-direction:column;align-items:stretch}
  .es-mod-hd{grid-template-columns:2em 1fr;grid-template-rows:auto auto;padding:12px 2px}
  .es-mod-status{grid-column:2;font-size:var(--text-micro)}
  .es-stake-row{grid-template-columns:1fr}
  .es-pill{flex:1 1 45%}
  .es-mod-foot{justify-content:stretch}.es-mod-foot .es-btn{width:100%}
}

/* The right-hand "Your project" aside (.portal-aside) is fixed at 400px on wide screens and
   every card above the tab panels reserves it with padding-right:420px (portal.css, the
   "#nextStepCard / #ownershipCard" block). Same rule here, same breakpoint. */
#eventSetupCard{padding-left:var(--portal-gutter,24px);box-sizing:border-box}
/* ⚠ BOTH inline margins, not just the left (2026-08-25). `.es-card` ships
   `margin:0 24px 24px`; only margin-LEFT was being zeroed here, so inside the
   Today panel the card's left edge sat on the panel gutter while its right edge
   stopped 24px short of every neighbour. MEASURED at five widths before the fix
   — .es-card right 358/712/968/896/1056 against #ownershipCard and
   #headcountCard at 370/736/992/920/1080 (390/768/1024/1280/1440). The left
   edges were already one line (the 2026-08-25 --portal-gutter work); this is the
   same property on the other side, and the card is the largest object on the
   room, so a 24px ragged right edge against three neighbours reads. */
#eventSetupCard .es-card{margin-left:0;margin-right:0}
@media (min-width:1025px){
  body.portal-aside-visible #eventSetupCard{padding-right:420px;box-sizing:border-box}
}
/* PX-005/PX-020 (2026-08-23): the card now lives INSIDE the Today panel
   (portal-rooms.js attachTodayCards), and `.tab-panel.active` already reserves
   the aside's 420px — so the rule above would stack a SECOND reserve on top and
   squeeze the form to ~330px (measured at 1280px). Inside a panel, the panel
   owns both gutters. Extra specificity so load order cannot decide the winner. */
body .tab-panel #eventSetupCard{padding-right:0;padding-left:0}
.es-btn{font-family:'Montserrat',sans-serif;font-size:.66rem;letter-spacing:.18em;text-transform:uppercase;font-weight:600;padding:12px 22px;background:var(--bloodstone,#B02A45);color:var(--ivory,#FBF7EF);border:1px solid var(--bloodstone,#B02A45);cursor:pointer;transition:background .2s var(--ease,ease)}
.es-btn:hover{background:var(--bloodstone-dk,#94233a)}.es-btn:disabled{opacity:.45;cursor:not-allowed}.es-btn:focus-visible{outline:2px solid var(--onyx,#1E0B0E);outline-offset:3px}

/* ── THE 44px TOUCH FLOOR ON PHONES (added 2026-08-23, Round 2) ─────────────────
   Measured on a real 375×812 phone before this block: .es-pill 34px, .es-btn 37px,
   .es-link 14px. The house floor is 44px (test/portal-touch-floor-rendered.test.mjs,
   written after the room rail shipped at 36px), but that test measures a fixed list
   of selectors, so this card escaped it entirely — the same "a guard that silently
   skips the new file" shape as the i18n date list. Both halves are fixed together:
   the floor is applied here and test/event-setup-touch-floor.test.mjs now measures
   these three classes at four phone sizes.
   .es-link keeps its inline look and grows its HIT AREA instead, so a sentence with
   "Use it" in it does not turn into a stack of buttons. */
/* ⚠ THE ARM IS 900px, NOT 720px, AND THAT IS THE POINT. A phone TURNED SIDEWAYS is
   844×390 (iPhone 14) or 852×393 — wider than 720, so a max-width:720px floor leaves
   the landscape case at 34px. Measured: with the 720 arm, landscape still reported
   po-choice:34 · es-btn:38 · es-link:16. 900px is the arm portal.css already uses for
   its own phone rules, and the house's floor test measures 844×390 deliberately. */
@media (max-width:900px){
  #eventSetupCard .es-pill{min-height:44px}
  #eventSetupCard .es-btn{min-height:44px;padding:12px 22px}
  #eventSetupCard .es-link{min-height:44px;display:inline-flex;align-items:center}
  /* …but a 44px inline-flex box sitting INSIDE the recommendation sentence
     inflates that line and opens a visible gap above it (measured at 375px).
     On a phone the link gets its own line instead — same 44px thumb target,
     no hole in the paragraph. */
  #eventSetupCard .es-rec .es-link{display:flex;width:max-content;margin-top:2px}
  /* Same exemption for the defer link: the 44px floor above sets
     display:inline-flex on every .es-link, which would put "I don't know
     yet" back beside the field on a phone. It keeps the 44px target. */
  #eventSetupCard .es-defer{display:flex;width:max-content;min-height:44px}
  #eventSetupCard .es-mod-hd{min-height:44px}
}

/* ── Display face + heading steps (2026-08-25) ─────────────────────────────
   THE FACE. These three rules were the ONLY live `Cormorant Garamond`
   declarations left in the Client Portal — every other occurrence under
   app/styles/ and app/assets/main.css is a comment (verified by grep). The
   house retired Cormorant for Crimson Pro on 2026-08-20 (brand.json
   tokens.display.$changed, 831 files swept); this file was written on 08-23,
   after that sweep, so it was never in its path.

   It was not cosmetic. MEASURED on the Today room at 1280: the page's own H1
   `.td-h` renders "5 things need you." in Crimson Pro at 31.5px, and
   `.es-title` rendered "Let's set up your celebration." in Cormorant at
   30.6px directly beneath it — two different serifs at nearly identical size,
   stacked, on the first screen a new client sees. That is the same defect the
   2026-07-31 note in portal.css describes for the advisory cards ("the panel
   showed two serifs at once"), and the fix is the same: one family per stack.

   THE STEPS. Crimson Pro has a larger x-height than Cormorant, so keeping
   1.7rem would have made the card title MORE competitive with the H1, not
   less. The card is now clearly subordinate: 1.75rem H1 > 1.35 card title >
   1.15 module title > 1.05 review/effects h3. That also corrects an inversion
   that predates this change — `.es-review h3` was 1.3rem against
   `.es-mod-title` 1.2rem, i.e. a sub-block heading set LARGER than the module
   heading containing it. The narrow-width override moves with it (1.4→1.2)
   so the phone title cannot exceed the desktop one. */

/* §39A (2026-09-02): the linked-events block — reads like the effects list it sits beside. A crunch day (two events' deadlines) is emphasised, never coloured red: it is a decision, not an error. */
.es-linked{margin:0 0 18px;padding:0 0 12px;border-bottom:1px solid var(--border-s)}.es-linked h3{margin:0 0 4px}.es-linked-events{margin:8px 0 12px;padding-left:18px}.es-linked-events li{margin:0 0 4px}.es-linked-primary>strong{font-weight:600}.es-linked-crunch{font-weight:600}
/* §39A bullet 3 (2026-09-03, row 39A-a): what a linked event RUNS, on the event it describes.
   Nested one level under its event, quiet by default — this is a disclosure of structure, not a
   list of tasks, and it must not read louder than the conflicts block above it. `.es-linked-na`
   (a rule this event genuinely has no use for) is dimmed rather than hidden: an empty rule
   rendered as nothing is how a capability disappears, which is what §39A is about.
   ⚠ THE SUGGESTION'S RULE IS `--ch8-moss`, NOT `var(--sage, #265450)`. The neighbouring `.es-rec`
   still carries that pair and it is 24-a's to migrate; writing a NEW one would have raised the
   retired-palette ratchet by two at once — the token read AND the hex fallback both count
   (scripts/portal-palette-census.mjs), which is exactly what it caught here. */
.es-linked-runs{margin:6px 0 10px;font-size:var(--text-sm)}
.es-linked-runs>strong,.es-linked-reused>strong,.es-linked-na>strong{display:block;margin:8px 0 2px;font-size:var(--text-xs);font-weight:600;letter-spacing:.02em;text-transform:uppercase}
.es-linked-runs ul{margin:0 0 6px;padding-left:18px}
.es-linked-runs>ul>li{margin:0 0 5px}
.es-linked-open{margin:3px 0 0;padding-left:16px;font-size:var(--text-xs)}
.es-linked-open li{margin:0 0 2px}
.es-rec-inline{display:block;padding-inline-start:8px;border-inline-start:2px solid var(--ch8-moss);margin-top:2px}
.es-rec-inline strong{font-weight:600}
.es-linked-na{opacity:.72}

/* ── YOUR VISION, INSIDE THIS CARD (owner 2026-09-08: "i prefer having it all in one place") ──
   scripts/portal-event-setup.js moves the WHOLE `<section id="tab-briefing">` in here, id and
   all, because portal-briefing-pager.js roots its paging CSS and its `form()` lookup at that id
   (see the long note at that file's mountVision). Nothing about the Vision markup changes; only
   where it hangs and how the panel behaves once it is no longer a room of its own.

   ⚠ `!important`, AND IT IS NOT DECORATION. `.tab-panel{display:none}` still applies to the
   nested panel, and showTab()'s teardown writes `p.style.display = ''` across EVERY .tab-panel
   on every room change — an inline style, which a plain rule here would lose to. `!important`
   beats both, so the brief cannot be blanked by a click in another room. The panel is inside a
   [hidden] body when the section is collapsed, and `[hidden]` is enforced below for the same
   reason: a display of our own would otherwise defeat it. */
.es-vision{border-top:1px solid var(--border-s);margin-top:4px}
.es-vision > .es-mod-hd .es-mod-num{letter-spacing:0}
/* ── AND IT HANGS INSIDE CARD C (owner 2026-09-09: "your vision shouldn't be in the bottom, it
   should be nestled inside creative direction") ──
   The mount is now written into "Your design and your pieces", between the Creative direction
   questions and the pieces, so two seams change:
     · the card body's own left padding already indents it — it needs air above, not a second
       border weight, so only the margin grows;
     · `.es-part + .es-part` no longer touches the pieces sub-head, because what precedes it is a
       <section>, not another .es-part. Without this the card would lose the hairline that says
       "second half" and the two blocks would run together. */
.es-mod-body > .es-vision{margin-top:14px}
.es-vision + .es-part{border-top:1px solid var(--border,var(--ch8-onyx-12,#DDD6CE));padding-top:16px;margin-top:4px}
#esVisionBody[hidden]{display:none!important}
#esVisionBody > #tab-briefing{display:block!important;min-height:0}
/* The panel was authored to fill a room: a 100svh floor, a full-bleed hero and 72px form
   gutters. Inside a card those read as a second page. Pull the gutters in and let the card's
   own padding carry the edge. */
#esVisionBody .form-wrap{padding-left:0;padding-right:0;padding-top:24px}
/* ⚠ THE PANEL'S OWN CHROME GOES, AND THIS IS THE HALF THAT IS EASY TO MISS. A SUBMITTED vision
   hides all of it already — lockVisionFormChrome() (portal-init-helpers.js) sets inline
   display:none on .brief-hero, .pkg-strip, .brief-prog and #briefForm the moment the brief is
   sent. So on a submitted fixture the nesting looks clean and NOTHING here appears to be needed.
   It is the UNSUBMITTED host — the only one who has to fill this in — who gets it all back:
     · .brief-hero — an <h1> "Tell us everything." nested inside a card in another room's panel.
       A page title two lines under the section header that already says Your Vision, and a
       heading-outline break (the card's own h2, then an h1 below it).
     · .brief-prog — the SAME #briefProgPct the section header already shows. Open the section
       and the card's "2 of 6 sections", the header's "33%" and this bar's "Vision — Section 1
       · 33%" stack inside 200px: three readings of two numbers.
   The section header carries the number; the card carries "saves as you go".
   ⚠ `.brief-reassure` STAYS. It is the owner-tuned payoff line (2026-07-31, "i like the
   warnings, but its too much" — two strips merged into one), and it is the only thing on the
   screen that says what finishing buys: the designer starts in 24 hours, moodboards in 48.
   Nothing else repeats it, so it is not chrome. */
#esVisionBody .brief-hero,
#esVisionBody .brief-prog,
#esVisionBody .bsp-hero-eyebrow{display:none}
/* ── AND THE REST OF IT GOES TOO (2026-09-14, portal-simplify) ───────────────────────────
   Owner's brief for this release: the Vision reads as Section C's SECOND HALF, "not as a
   separate 'Your Vision · your designer reads this' accordion with its own 33% and its own
   hero 'Your Vision, In Our Hands', pkg strip, progress bar, reassurance line, autosave
   hints, mobile progress — hide/remove that chrome for the unsubmitted AND the submitted
   state". Each line below, and where the fact it carried now lives:
     · `.bsp-hero` — the SUBMITTED read-back's own full-bleed page title. The eyebrow was
       already dropped above; the 2.4rem "Your Vision, In Our Hands" under it was the other
       half of the same page-inside-a-card. The state it announced is the section header's
       own word, "Sent" (portal-event-setup.js visionStatusText).
     · `#briefProgPayoff` / `.brief-reassure` — "About 10 minutes, and it saves as you go —
       finish and your designer begins within 24 hours, your moodboards in 3 business days."
       ⚠ THIS ONE IS A DELIBERATE REVERSAL of the note above and of
       test/event-setup-owns-vision.test.mjs case 6, which required it to stay. It is
       re-homed rather than deleted: the question's own `.sec` intro carries the promise the
       host is reading at the moment they act, the Today room's "With Evorrah" lane carries
       what happens after they send, and "saves as you go" was on this one screen SIX times.
       See `.es-vision-note` below, which is where it is now written once.
     · `#autosaveHintTop` / `#autosaveHint` — "● Saved 12:22 · safe on your account", the
       fourth and fifth save promises. The card's own quiet "Saved." is the one. They need
       `!important`: `_setSyncState()` force-sets display:block on every save.
     · `#briefMobileProgress` — "Section 1 of 10", a THIRD progress reading whose
       denominator (10, the Vision's own steps) disagreed with the card's (6, the sections).
       The pager's `N of M` inside the current step is the reading that is true of the form
       the client is looking at.
     · `#briefUrgencyBanner` — "Your designer is waiting." The queue on Today already says
       what needs them and when it is due, in one place, and this fired inside a card the
       client had to open to see it.
     · `.bsn-title` / `.bsn-foot` — "◆ Your Vision" above the section navigator (the section
       header says it two rows up) and "Saves as you go — stop and finish anytime." (the
       sixth). The navigator itself stays: it is how a client jumps between Vision steps. */
#esVisionBody .bsp-hero,
#esVisionBody #briefProgPayoff,
#esVisionBody .brief-reassure,
#esVisionBody #briefUrgencyBanner,
#esVisionBody .bsn-title,
#esVisionBody .bsn-foot{display:none!important}
#esVisionBody #autosaveHintTop,
#esVisionBody #autosaveHint,
#esVisionBody #briefMobileProgress{display:none!important}
/* The one sentence kept out of all of that, written once, in the section header's own
   register rather than as a banner. portal-event-setup.js writes it beside "Your Vision". */
.es-vision-note{display:block;font-family:'Montserrat',sans-serif;font-size:var(--text-xs,.72rem);line-height:1.6;color:var(--ch8-onyx-78,#464542);margin:2px 0 10px}
/* The section header is a sub-head of card C, not an accordion title of its own. */
.es-vision-hd .es-mod-title{font-size:1rem}
/* ⚠ THE PACKAGE STRIP IS DROPPED, NOT RESTYLED. It repeats Package · Occasion · Event Date,
   which the Today room states above this card; two copies on one screen is how they come to
   disagree. The node stays in the DOM because portal-init-helpers.js writes to #pkgTier and
   friends on load and would throw on a missing target. */
#esVisionBody #pkgStrip{display:none}
@media (max-width:720px){
  #esVisionBody .form-wrap{padding-top:16px}
}

/* ══ "ASK US TO CHANGE THIS" ON THE SUBMITTED VISION (P100 feature 3, 2026-09-15) ═══════════
   The control that gives api/briefing-change-request.js a caller — one button per locked
   answer on the read-only playback (#briefSubmittedPanel), painted by
   bspPaintChangeControls() in app/scripts/portal-init-helpers.js.

   ⚠ IT SITS IN THIS FILE, NOT BESIDE THE OTHER `.bsp-*` RULES IN portal.css, and that is a
   collision decision rather than a design one: portal.css was being held uncommitted by
   another session on the day. This sheet is loaded immediately after portal.css on every
   portal page (client-portal.html: "own file so portal.css stays untouched"), so the cascade
   is the same — but the rules belong with their siblings and should move there when
   portal.css is free.

   44px touch floor, the same one the set-up card keeps. */
.bsp-chg{display:flex;flex-wrap:wrap;gap:8px;align-items:center;margin-top:6px;width:100%}
.bsp-chg-btn,.bsp-chg-cancel{font:inherit;font-size:var(--text-xs);min-height:44px;padding:0 12px;cursor:pointer;
  background:transparent;color:inherit;border:1px solid color-mix(in srgb, var(--ch8-onyx) 22%, transparent)}
.bsp-chg-cancel{border-color:color-mix(in srgb, var(--ch8-onyx) 12%, transparent)}
.bsp-chg-btn[disabled]{cursor:default;opacity:.6}
.bsp-chg-edit{display:flex;flex-wrap:wrap;gap:8px;align-items:center;width:100%}
.bsp-chg-lbl{flex:1 1 100%;font-size:var(--text-xs);opacity:.75}
.bsp-chg-input{flex:1 1 240px;font:inherit;font-size:var(--text-sm);min-height:44px;padding:8px 10px;
  background:transparent;color:inherit;border:1px solid color-mix(in srgb, var(--ch8-onyx) 22%, transparent)}
.bsp-chg-state,.bsp-chg-why,.bsp-chg-say{flex:1 1 100%;font-size:var(--text-xs);line-height:1.5}
.bsp-chg-why,.bsp-chg-say{opacity:.75}
@media (max-width:720px){
  .bsp-chg-btn,.bsp-chg-cancel,.bsp-chg-input{flex:1 1 100%}
}
