/* Milestone 1 (Safety Baseline and CSS Isolation): every selector in
   this file is now scoped beneath .emt-journey-studio and every
   var() reference renamed to the --emt-js-* prefix (see
   styles/tokens.css) — no behavior/appearance change, only isolation
   from a host WordPress page's own styles. */

/* Journey Studio modal (Modal Architecture milestone): a native
   <dialog>, centered by the browser's own UA stylesheet once shown via
   showModal() — this file only needs to reset <dialog>'s default
   chrome (border/padding/background/max-width/max-height, all
   otherwise fighting the real surface on .journey-booklet__frame
   below) and set the actual modal box size. The Question and Journey
   Summary columns mount real, live JourneyState-driven content
   generated by scripts/context-selection.js
   (renderCardsMarkup/bookletSummaryMarkup) — this file only restyles
   what those functions already produce, it never introduces new
   markup or logic of its own for them. */

.journey-booklet.emt-journey-studio {
  /* Resets <dialog>'s UA-stylesheet chrome — the visual surface
     (background, radius, shadow) lives entirely on
     .journey-booklet__frame below instead. */
  padding: 0;
  border: none;
  color: inherit;
  background: transparent;

  /* Desktop/tablet modal box. min(1180px, 94vw) / min(860px, 92dvh) —
     92dvh rather than 92vh so mobile browser chrome showing/hiding
     (address bar) can't cause the box to mis-measure against a stale
     100vh; dvh updates live. Reset to full-screen at the mobile
     breakpoint below. */
  width: min(1180px, 94vw);
  height: min(860px, 92dvh);
  max-width: min(1180px, 94vw);
  max-height: min(860px, 92dvh);
  margin: auto;
  /* Booklet Layout Polish milestone: one central height, referenced by
     .journey-booklet__frame below. */
  --journey-booklet-frame-height: 100%;
}

/* Restores the closed <dialog>'s own native invisibility. Not needed
   against a bare UA stylesheet — `dialog:not([open]) { display: none }`
   is a browser default this file never had to state itself — but at
   least one real host page (WordPress + TravelTour/GoodLayers) ships a
   legacy HTML5-element display reset (`article,aside,dialog,figure,...
   { display: block }` in the theme's own style-core.css) that, being
   author-origin CSS, overrides that UA default outright regardless of
   selector specificity. Without this rule the closed shell — and the
   closed leave-confirm dialog below, same defeated default — renders
   inline whatever context-selection.js has already populated into it
   at page-init time, wherever it sits in the DOM (this shell prints via
   wp_footer, so: near the bottom of the document). Scoped to
   .emt-journey-studio only, so it changes nothing about how any other
   <dialog> on a host page behaves. Once genuinely opened via
   showModal(), :modal's own separate UA rule (position: fixed) already
   takes over correctly and is untouched by this. */
dialog.emt-journey-studio:not([open]) {
  display: none;
}

/* Dims and inerts the page behind the modal — the one piece
   showModal() doesn't fully style on its own. Strengthened (was
   rgba(43,38,33,0.55), no blur) after review: at desktop the right-
   side launcher card stayed legible enough to compete with the modal
   itself. Darker + a very subtle blur keeps the host page faintly
   recognizable (never hidden/removed — the DOM behind it is untouched)
   while reading as clearly inert, not a second focal point. Selector
   targets only the dialog's own class combination (set directly in
   the shell markup, not anything fixture-specific), so this is the
   same rule a WordPress deployment gets for free. backdrop-filter
   degrades safely where unsupported — no @supports guard needed, the
   property is simply ignored, leaving the strengthened flat dim alone
   to carry the effect there. */
.journey-booklet.emt-journey-studio::backdrop {
  background: rgba(29, 25, 22, 0.62);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
}

@media (prefers-reduced-motion: no-preference) {
  .journey-booklet.emt-journey-studio::backdrop {
    transition: background var(--emt-js-motion-modal) var(--emt-js-ease-standard);
  }
}

/* Modal Architecture milestone: the small "Leave Journey Studio?"
   confirmation — its own independent <dialog>, shown nested on top of
   the still-open booklet dialog only when real progress would
   otherwise be discarded (scripts/journey-booklet.js's
   hasMeaningfulProgress()). Deliberately tiny and plain — a single
   question and two actions, not a second booklet spread. */
.emt-journey-studio .journey-booklet__leave-confirm {
  max-width: min(360px, 90vw);
  padding: var(--emt-js-space-4);
  border: none;
  border-radius: var(--emt-js-radius-lg);
  background: var(--emt-js-color-surface-quiet);
  box-shadow: var(--emt-js-shadow-card-elevated);
}

.emt-journey-studio .journey-booklet__leave-confirm::backdrop {
  background: rgba(43, 38, 33, 0.35);
}

.emt-journey-studio .journey-booklet__leave-confirm-title {
  margin: 0 0 var(--emt-js-space-1);
  font-size: var(--emt-js-text-card-title);
  font-weight: 500;
}

/* Phase 4.15A (Exit Confirmation Wording): the dialog's new supporting
   line — same muted/support treatment .studio-question__support
   already uses elsewhere, not a new style. */
.emt-journey-studio .journey-booklet__leave-confirm-support {
  margin: 0 0 var(--emt-js-space-3);
  font-size: var(--emt-js-text-support);
  color: var(--emt-js-color-ink-muted);
}

.emt-journey-studio .journey-booklet__leave-confirm-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--emt-js-space-2);
}

/* One shared outer surface for the header and all three columns
   together — this is what makes the shell read as one integrated
   spread rather than a header floating above three separate cards.
   No separate shadows on the columns themselves. */
.emt-journey-studio .journey-booklet__frame {
  position: relative;
  display: flex;
  flex-direction: column;
  height: 100%;
  background: var(--emt-js-color-surface-quiet);
  border-radius: 20px;
  box-shadow: var(--emt-js-shadow-card-elevated);
  overflow: hidden;
}

/* Header row: always-visible frame chrome, not part of the animated
   cover — spans the full frame width, one baseline, one subtle
   divider. Phase labels are static placeholders; not wired to real
   screen state yet (no page turning exists yet to track). */
.emt-journey-studio .journey-booklet__topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--emt-js-space-3);
  padding: var(--emt-js-space-3) var(--emt-js-space-4);
  border-bottom: 1px solid var(--emt-js-color-border);
  flex-wrap: wrap;
}

.emt-journey-studio .journey-booklet__topbar-intro {
  min-width: 0;
}

.emt-journey-studio .journey-booklet__brand {
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-size: var(--emt-js-text-eyebrow);
  color: var(--emt-js-color-terracotta-strong);
  white-space: nowrap;
  margin: 0;
}

/* Modal Architecture milestone: "Celebration • Anniversary"-style
   contextual metadata, kept current by context-selection.js's own
   render(). Empty text content collapses to zero height on its own
   (no visible gap) whenever there's no context/profile yet to show —
   no separate hidden-state class needed. */
.emt-journey-studio .journey-booklet__context-label {
  font-size: var(--emt-js-text-label);
  color: var(--emt-js-color-ink-muted);
  margin: 2px 0 0;
}

/* Mobile Header Polish: a compact status line shown only at mobile
   widths (see the mobile media query below) — desktop/tablet's header
   is unaffected, this stays display:none there so it never changes
   the approved desktop/tablet topbar. */
.emt-journey-studio .journey-booklet__status {
  display: none;
  margin: 0;
}

.emt-journey-studio .journey-booklet__topbar-phases {
  display: flex;
  gap: var(--emt-js-space-4);
  list-style: none;
  margin: 0;
  padding: 0;
}

.emt-journey-studio .journey-booklet__topbar-phase {
  font-size: var(--emt-js-text-label);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--emt-js-color-ink-muted);
}

.emt-journey-studio .journey-booklet__topbar-phase.is-active {
  color: var(--emt-js-color-terracotta-strong);
}

/* Modal Architecture milestone: a soft, always-visible X — replaces
   the previous "Back to Inspiration" text button (same element/wiring,
   [data-booklet-back] in scripts/journey-booklet.js, unchanged), since
   a modal launched from an arbitrary Celebration-page CTA has no
   "Inspiration" page of its own to name in the label. Deliberately
   quiet (no border, transparent until hover/focus) so it reads as
   frame chrome, not a competing call to action next to Continue. */
.emt-journey-studio .journey-booklet__close {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  padding: 0;
  border: none;
  border-radius: var(--emt-js-radius-sm);
  background: transparent;
  color: var(--emt-js-color-ink-muted);
  font-size: 1.5rem;
  line-height: 1;
  cursor: pointer;
}

.emt-journey-studio .journey-booklet__close:hover,
.emt-journey-studio .journey-booklet__close:focus-visible {
  background: rgba(43, 38, 33, 0.06);
  color: var(--emt-js-color-ink);
}

/* Positioning context shared by the real shell (.journey-booklet__grid)
   and the temporary brochure-opening scene, so the scene's cover can
   sit exactly on top of the shell during the transition (see
   transition.css and scripts/journey-booklet.js). Deliberately below
   the topbar, not wrapping it — the header never rotates with the
   cover. */
.emt-journey-studio .journey-booklet__stage {
  position: relative;
  flex: 1;
  /* Review Brochure Migration: a flex item's default min-height:auto
     would otherwise let the grid's own content (Review's long
     workspace column) become a floor stage can't shrink below, one
     level up from the same fix on .journey-booklet__workspace itself —
     without this, the frame's max-height above only clips Review's
     footer out of view instead of actually enabling internal scroll. */
  min-height: 0;
  /* Also Review Brochure Migration: makes stage a flex container so
     .journey-booklet__grid can size itself via flex:1 instead of
     height:100% — a percentage height on a block child doesn't
     reliably resolve against a parent whose own height only comes from
     flex-grow (no explicit height property), which is exactly why
     height:100% silently failed to cap the grid here; flex:1 is the
     same, already-proven-working mechanism this element itself uses
     one level up (against .journey-booklet__frame). flex-direction:
     column is essential here — without it the grid's flex:1 would
     apply to the horizontal axis instead (flexbox's row default),
     sizing the grid's *width* off its content instead of stretching it
     to stage's actual width via the (now-vertical) cross axis. */
  display: flex;
  flex-direction: column;
  /* The cover's small skewY/rotateZ deformation during opening can
     otherwise visually project past the stage's own top edge (3D
     transforms aren't confined to their layout box) — this keeps that
     contained to the stage itself rather than bleeding into the
     always-static topbar above it. */
  overflow: hidden;
}

/* 34% image / 43% question / 23% journey summary (Editorial Milestone:
   Private & Celebration first page) — the question column is the
   primary reading area now that it also hosts the compact card grid
   and each selected option's inline conditional controls, so it gets
   the largest share; the roadmap is deliberately narrower, matching
   its now-concise renderer. Minmax floors keep each column readable at
   the shell's narrower end before the tablet breakpoints take over
   entirely. */
.emt-journey-studio .journey-booklet__grid {
  display: grid;
  grid-template-columns: minmax(320px, 34fr) minmax(420px, 43fr) minmax(
      260px,
      23fr
    );
  /* Phase 4.8A desktop-viewport correction: grid's own outer box was
     already correctly height-constrained by flex:1 1 auto/min-height:0
     below (a flex item in a definite-height container is always capped
     to it) — but that says nothing about this grid's *internal* row
     track, which defaults to auto (fit-content) sizing, entirely
     independent of the container's own resolved height. An auto row
     happily grows past its own grid container's box to fit whichever
     column's content is tallest (verified live: the row grew to the
     roadmap summary's full content height, ~620px, while the grid's own
     box stayed correctly at ~502px) — and since this grid is
     overflow:visible by design (individual columns own their scroll,
     not the grid as a whole), that excess doesn't clip here, it spills
     into .journey-booklet__stage above, which *does* clip it via
     overflow:hidden, with no scrollbar. minmax(0, 1fr) makes the row
     itself respect the grid's own already-correct height instead of
     growing to content — align-items:stretch (below) then gives every
     column that same real height to work with, which is what each
     column's own min-height:0/overflow-y:auto (workspace/question,
     roadmap/roadmap-summary) needs in order to ever actually engage. */
  grid-template-rows: minmax(0, 1fr);
  align-items: stretch;
  /* Review Brochure Migration: was height:100%, which silently failed
     to resolve against .journey-booklet__stage's own flex-computed
     height (a percentage height needs an explicit height property on
     the containing block, which a plain flex-grow item doesn't have) —
     flex:1 1 auto is the same working mechanism stage itself already
     uses against the frame. min-height:0 stops this item's own content
     (the workspace column, potentially Review-length) from re-widening
     the floor stage was just constrained to. */
  flex: 1 1 auto;
  min-height: 0;
}

.emt-journey-studio .journey-booklet__workspace,
.emt-journey-studio .journey-booklet__roadmap {
  min-width: 0;
  /* Booklet Layout Polish milestone: was var(--emt-js-space-5) var(--emt-js-space-4)
     — reclaims 32px of vertical whitespace (top+bottom) toward fitting
     every non-Review screen without internal scrolling. */
  padding: var(--emt-js-space-4);
}

/* Review Brochure Migration: without this, a grid item's default
   min-height:auto lets its own content's natural height (here, the
   flex column containing .journey-booklet__question +
   .journey-booklet__footer) dictate the grid row's track size —
   .journey-booklet__question's own min-height:0/overflow-y:auto below
   can't take effect until this outer constraint exists too, since the
   grid would otherwise just grow the whole row (and the frame, capped
   at max-height above) to fit Review's long content instead of
   scrolling internally. Same class of fix as Contact's Country Code
   min-width:0 correction, one level up the containment chain.

   Phase 4.8A desktop-viewport correction: .journey-booklet__roadmap
   gets the identical outer min-height:0 here — it was left out
   originally on the assumption its summary content would always stay
   short ("the roadmap is deliberately narrower, matching its now-
   concise renderer," see the grid's own comment above). That held for
   every viewport tested until a real, shorter desktop browser window
   (verified reproducing identically in the standalone fixture at the
   same 1280x650 size, so this was never WordPress/TravelTour-specific)
   showed the roadmap's own accumulated summary rows can legitimately
   need more height than a short viewport leaves available — without
   this, the grid row (and the frame, capped at max-height) grew to fit
   it instead of scrolling internally, pushing Back/Continue below the
   visible modal. */
.emt-journey-studio .journey-booklet__workspace,
.emt-journey-studio .journey-booklet__roadmap {
  min-height: 0;
}

/* Review Brochure Migration: the question region scrolls internally
   when its content is taller than the fixed frame allows (Review's
   editorial summary is the first page long enough to need this — every
   earlier page always fit comfortably, so this is a no-op for them,
   never showing a scrollbar). min-height:0 overrides a flex item's
   default min-height:auto, which would otherwise let this element's
   own content force the column taller instead of scrolling — same fix
   as the min-width:0 correction Contact's Country Code field needed.
   The footer (a sibling, not a child, of this element) is never inside
   the scrollable area, so it stays visually pinned beneath it. */
.emt-journey-studio .journey-booklet__question {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}

/* Phase 4.8A desktop-viewport correction: same fix as
   .journey-booklet__question above, applied to the roadmap column's
   own scrollable content. .journey-booklet__roadmap becomes a flex
   column (heading + summary, mirroring .journey-booklet__workspace's
   own question+footer split just above) so only .roadmap-summary
   scrolls internally when it's taller than the space available — the
   "Your Journey" heading stays pinned above it, exactly as Back/
   Continue stay pinned beneath .journey-booklet__question. */
.emt-journey-studio .journey-booklet__roadmap {
  display: flex;
  flex-direction: column;
}

.emt-journey-studio .journey-booklet__roadmap-summary {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}

/* Review Brochure Migration: the three editorial group headings (About
   You / Your Journey / Final Touches) that visually organise Review's
   otherwise-flat section list in the booklet only — reuses
   .journey-booklet__label's existing eyebrow treatment as-is (same
   uppercase/letter-spacing/terracotta look already used for
   "INSPIRATION"), just adding the top spacing a group heading needs
   between sections that .journey-booklet__label alone never needed
   before (it was always the first thing in its own column). Legacy's
   flat, ungrouped section list is completely unaffected — this class
   only ever appears in the booklet's own renderBookletMarkup output. */
.emt-journey-studio .review-group-heading {
  margin-top: var(--emt-js-space-6);
}

.emt-journey-studio .review-group-heading:first-of-type {
  margin-top: 0;
}

/* Booklet Layout Polish milestone: Review's scroll affordance — a
   soft bottom fade (plus a very small chevron) hinting more content
   exists below, shown only via JS (updateReviewScrollCue() in
   context-selection.js) when the content actually overflows and the
   user hasn't reached the bottom yet. position:sticky keeps it pinned
   to the bottom of the *visible* scroll area without adding any of its
   own height to the scrollable content (margin-top cancels its own
   height out of flow) — it never covers section text or the footer,
   since the footer is a sibling outside this scrollable region
   entirely. Purely decorative (aria-hidden, pointer-events:none) —
   never a substitute for a real scrollbar, which stays native/default. */
.emt-journey-studio .journey-booklet__scroll-cue {
  position: sticky;
  bottom: 0;
  height: 56px;
  margin-top: -56px;
  pointer-events: none;
  background: linear-gradient(to bottom, transparent, var(--emt-js-color-surface-quiet) 65%);
  opacity: 0;
  transition: opacity var(--emt-js-motion-fast) var(--emt-js-ease-standard);
}

.emt-journey-studio .journey-booklet__scroll-cue.is-visible {
  opacity: 1;
}

.emt-journey-studio .journey-booklet__scroll-cue-chevron {
  position: absolute;
  bottom: 8px;
  left: 50%;
  transform: translateX(-50%);
  color: var(--emt-js-color-terracotta-strong);
  opacity: 0.6;
}

@media (prefers-reduced-motion: reduce) {
  .emt-journey-studio .journey-booklet__scroll-cue {
    transition: none;
  }
}

.emt-journey-studio .journey-booklet__workspace {
  border-right: 1px solid var(--emt-js-color-border);
  /* Top-aligned (refinement pass): centering the whole column
     (question + footer together) made the footer's own position
     shift whenever the question content's height changed (e.g.
     Family's inline detail vs. Couple's none) — Back/Continue must
     stay put, never jumping vertically. Content now varies far less
     anyway, since a selection collapses the grid down to one card. */
  display: flex;
  flex-direction: column;
}

.emt-journey-studio .journey-booklet__inspiration {
  min-width: 0;
  border-right: 1px solid var(--emt-js-color-border);
  /* No padding: the image bleeds to the column's edges (see
     __image-shell) rather than sitting in a small inset square. */
}

.emt-journey-studio .journey-booklet__label {
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-size: var(--emt-js-text-eyebrow);
  color: var(--emt-js-color-terracotta-strong);
  margin-bottom: var(--emt-js-space-2);
}

/* Editorial presentation of the real, live Travel Style question
   (scripts/context-selection.js's renderCardsMarkup, mounted here
   unchanged in logic — see index.html). Large typography, generous
   spacing, minimal — the same .studio-question/.option-card markup as
   the legacy builder, only restyled, and only within this column, so
   the legacy screen's own appearance is untouched. */
.emt-journey-studio .journey-booklet__workspace .studio-question__heading {
  /* Phase 4.15A (Desktop Question Heading Scale): was clamp(2rem,
     2.6vw, 2.75rem) — a 44px ceiling that staging QA found too
     dominant against the working area beneath it. A modest, mostly-flat
     ~28px reads clearly as the primary heading without competing with
     the option grid/cards below; kept as a narrow clamp rather than a
     bare value so it still has a little room to breathe on genuinely
     wide desktop viewports. Applies to every screen sharing this one
     class, including Success/Error's own outcome headings — the same
     shared heading treatment those screens already opt into
     deliberately, not an accidental catch. */
  font-size: clamp(1.75rem, 1.6vw, 1.875rem);
  line-height: 1.12;
  max-width: none;
  /* Booklet Layout Polish milestone: was the shared 24px
     (studio-workspace.css's .studio-question__heading) — a modest,
     booklet-only reduction toward fitting non-Review screens without
     internal scrolling. Legacy's own heading margin is untouched. */
  margin-bottom: var(--emt-js-space-1);
}

.emt-journey-studio .journey-booklet__workspace .studio-question__support {
  /* Booklet Layout Polish milestone: was 1.15rem, a booklet-only
     enlargement over the app's own established --emt-js-text-support size
     (1.05rem) — returning to that existing readable standard (not
     shrinking below it) was the last lever needed for Contact's
     WhatsApp state (two stacked support paragraphs) to fit without
     internal scrolling. */
  font-size: var(--emt-js-text-support);
  max-width: 46ch;
  /* Booklet Layout Polish milestone: was the inherited global 1.6 body
     line-height — a small, size-preserving density adjustment (last
     resort, per the preferred fix order) that closed the final gap for
     Contact's WhatsApp state, which stacks two support paragraphs. */
  line-height: 1.4;
}

.emt-journey-studio .journey-booklet__workspace .studio-question__subheading {
  /* Booklet Layout Polish milestone: was the shared 1.15rem
     (--emt-js-text-card-title) — a small, size-preserving-elsewhere reduction
     (this is the smallest sub-heading role, "Preferred response
     method"/"Ceremony Setting", not a primary heading) that helped
     close Contact's WhatsApp state's remaining gap. */
  font-size: 1rem;
}

.emt-journey-studio .journey-booklet__workspace .option-grid {
  /* Booklet Layout Polish milestone: was var(--emt-js-space-5) — reclaims 16px. */
  margin-top: var(--emt-js-space-4);
}

/* Compact titles-only cards (Editorial Milestone: Private & Celebration
   first page) — three columns at desktop, narrowing responsively.
   Overrides the shared auto-fit rule from studio-workspace.css for
   this column only; the legacy mount's own auto-fit .option-grid is
   untouched. */
.emt-journey-studio .journey-booklet__workspace .option-grid--compact {
  grid-template-columns: repeat(3, minmax(0, 1fr));
  /* Booklet Layout Polish milestone: gap/padding both trimmed one step
     (--emt-js-space-2/--emt-js-space-3 -> --emt-js-space-1/--emt-js-space-2) toward fitting every
     non-Review screen without internal scrolling. */
  gap: var(--emt-js-space-1);
}

.emt-journey-studio .journey-booklet__workspace .option-grid--compact .option-card__label {
  padding: var(--emt-js-space-2);
}

/* Once a selection is made (Card Behaviour refinement), the full grid
   collapses entirely to this one block — every other card simply
   isn't rendered any more (see context-selection.js's renderCardsMarkup
   compact branch), rather than staying visible and reflowing around an
   expanded one. Saves vertical space and keeps the booklet calm, per
   spec. Same visual language as a selected .option-card (left accent,
   tinted background) so it still reads as "the chosen answer." */
.emt-journey-studio .option-selected {
  border: 1px solid var(--emt-js-color-border);
  border-left: 3px solid var(--emt-js-color-terracotta-strong);
  border-radius: var(--emt-js-radius-lg);
  background: var(--emt-js-color-bg-alt);
  box-shadow: var(--emt-js-shadow-selected);
  /* Booklet Layout Polish milestone: was --emt-js-space-4 (32px) — reclaims
     16px, most needed by Wedding's collapsed block (heaviest content:
     a ceremony-setting grid plus adults/children steppers). */
  padding: var(--emt-js-space-3);
}

.emt-journey-studio .option-selected__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--emt-js-space-3);
}

/* Phase 4.15A (Selected/Preselected Profile Clarity): a check + the
   title, laid out inline like .btn's own icon+label pattern — no new
   layout primitive, just the same small-gap inline-flex this file
   already uses for buttons. Font-weight raised from the inherited
   body default to read clearly as "this is the answer," without
   filling the card's own light surface/accent treatment (unchanged
   above) with a dark block. */
.emt-journey-studio .option-selected__title {
  display: inline-flex;
  align-items: center;
  gap: var(--emt-js-space-1);
  font-family: var(--emt-js-font-display);
  font-size: var(--emt-js-text-card-title);
  font-weight: 600;
  color: var(--emt-js-color-ink);
}

/* Reuses the same checkmark glyph as the multi-select cards'
   .option-card__checkmark (ROADMAP_CHECK_ICON in context-selection.js)
   — a plain inline icon here, not that badge's own circular swatch,
   since this row has no unchecked state to distinguish from. */
.emt-journey-studio .option-selected__check {
  display: inline-flex;
  color: var(--emt-js-color-terracotta-strong);
  flex-shrink: 0;
}

/* Reuses the roadmap's own edit-pencil icon (ROADMAP_PENCIL_ICON) —
   .btn's own inline-flex + gap (components.css) already places this
   beside the "Change" label with no extra layout rule needed here. */
.emt-journey-studio .option-selected__change-icon {
  display: inline-flex;
}

/* The inline detail reuses GroupDetails.renderFieldsMarkup/
   WeddingDetails.renderCeremonyFieldsMarkup verbatim — no heading/
   support text at this point (Family Logic refinement: the counters
   and the "Family" label above them already explain themselves), just
   the steppers/child-ages/ceremony cards themselves. */
.emt-journey-studio .option-card__detail:not(:empty) {
  /* Booklet Layout Polish milestone: was --emt-js-space-4 (32px). */
  margin-top: var(--emt-js-space-3);
}

.emt-journey-studio .option-card__detail .group-details {
  max-width: none;
  /* Booklet Layout Polish milestone: was the shared 48px/32px
     (studio-workspace.css's .group-details) — .option-card__detail's
     own margin-top above already separates this from the card title,
     so the full shared margin was redundant height here; gap (between
     the Adults/Children steppers) is trimmed more modestly. Legacy's
     own .group-details (outside .option-card__detail) is untouched. */
  margin-top: var(--emt-js-space-1);
  gap: var(--emt-js-space-2);
}

.emt-journey-studio .option-card__detail .stepper {
  /* Booklet Layout Polish milestone: was the shared 24px
     (studio-workspace.css's .stepper). */
  padding-bottom: var(--emt-js-space-1);
}

.emt-journey-studio .option-card__detail .studio-question__subheading {
  font-size: 1rem;
}

.emt-journey-studio .option-card__group-fields {
  /* Booklet Layout Polish milestone: was --emt-js-space-4 (32px). */
  margin-top: var(--emt-js-space-3);
}

.emt-journey-studio .option-card__group-fields:first-child {
  margin-top: 0;
}

.emt-journey-studio .wedding-inline-fields .option-grid--compact {
  grid-template-columns: repeat(3, minmax(0, 1fr));
  /* Booklet Layout Polish milestone: was --emt-js-space-2/--emt-js-space-2 (16/16px). */
  gap: var(--emt-js-space-1);
  margin-top: var(--emt-js-space-1);
}

/* Travel Timing (Travel Timing Brochure Migration): a two-column,
   titles-only grid for the four timing-mode cards, reused as-is for the
   Season/Flexible follow-up sub-choices (also four description-less
   cards) — a dedicated modifier rather than reusing --compact's
   3-column layout, since 4 cards read better as 2x2 than 3+1. */
.emt-journey-studio .journey-booklet__workspace .option-grid--timing-compact {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  /* Booklet Layout Polish milestone: was --emt-js-space-2/--emt-js-space-3. */
  gap: var(--emt-js-space-1);
}

.emt-journey-studio .journey-booklet__workspace .option-grid--timing-compact .option-card__label {
  padding: var(--emt-js-space-2);
}

/* Journey Highlights (Journey Highlights Brochure Migration): a
   compact, titles-only 3x2 multi-select grid — six independent
   checkbox cards, none of which collapse away when checked (unlike
   Travel Timing's single-select collapse), so all six stay visible and
   comparable at once. A separate modifier from --timing-compact (kept
   untouched, approved) even though both are 2-column at the narrower
   breakpoint below. Declared before the 1300px breakpoint below so
   that override wins on source order (equal specificity) rather than
   being shadowed by this base 3-column rule. */
.emt-journey-studio .journey-booklet__workspace .option-grid--highlights-compact {
  /* Phase 4.15A (Option Grid — Desktop): was repeat(3, ...) — several
     of these six titles are genuinely descriptive/long ("Chefchaouen
     (Blue City)", "Kasbahs & Ancient Medinas", "Atlas Mountains &
     Gorges"), comparable in length to Experiences' own cited examples,
     and wrapped badly at a 3-column card width. 2 columns (already the
     ≤1300px behavior below) is now the desktop/tablet default too; the
     ≤1300px override below is unchanged and simply now redundant with
     this base rule, not a second, different 2-column rule. */
  grid-template-columns: repeat(2, minmax(0, 1fr));
  /* Booklet Layout Polish milestone: was --emt-js-space-2/--emt-js-space-3. */
  gap: var(--emt-js-space-1);
}

.emt-journey-studio .journey-booklet__workspace .option-grid--highlights-compact .option-card__label {
  padding: var(--emt-js-space-2);
}

/* Phase 4.15A: a wider 2-column card has room for a slightly larger,
   more legible title than the shared --emt-js-text-card-title token
   (18.4px) needs to stay conservative for — scoped to this grid only,
   not a change to that shared token or to any other option-card usage. */
.emt-journey-studio .journey-booklet__workspace .option-grid--highlights-compact .option-card__title {
  font-size: 1.0625rem;
  line-height: 1.3;
}

/* Experiences (Experiences Brochure Migration; rebalanced to six cards
   per page in the Experiences Content Rebalance correction): a
   dedicated modifier — not a reuse of --highlights-compact, even though
   both are 3-column — so Journey Highlights' approved CSS stays
   untouched regardless of any future change here. Both pages wrap a
   clean 3x2. Declared before the 1300px breakpoint below for the same
   source-order reason as --highlights-compact above. */
.emt-journey-studio .journey-booklet__workspace .option-grid--experiences-compact {
  /* Phase 4.15A (Option Grid — Desktop): was repeat(3, ...) — staging
     QA observed genuinely descriptive titles ("Traditional Hammam &
     Spa", "Moroccan Cooking Class", "Gnawa Performance", "Hot Air
     Balloon") wrapping badly at a 3-column card width. 2 columns
     (already the ≤1300px behavior below) is now the desktop/tablet
     default too; the ≤1300px override below is unchanged and simply
     now redundant with this base rule, not a second, different
     2-column rule. */
  grid-template-columns: repeat(2, minmax(0, 1fr));
  /* Booklet Layout Polish milestone: was --emt-js-space-2/--emt-js-space-3. */
  gap: var(--emt-js-space-1);
}

.emt-journey-studio .journey-booklet__workspace .option-grid--experiences-compact .option-card__label {
  padding: var(--emt-js-space-2);
}

/* Phase 4.15A: a wider 2-column card has room for a slightly larger,
   more legible title than the shared --emt-js-text-card-title token
   (18.4px) needs to stay conservative for — scoped to this grid only,
   not a change to that shared token or to any other option-card usage. */
.emt-journey-studio .journey-booklet__workspace .option-grid--experiences-compact .option-card__title {
  font-size: 1.0625rem;
  line-height: 1.3;
}

/* Stay Experience (Stay Experience Brochure Migration; corrected to
   remove the optional-preferences panel and the recommendation badge):
   the four primary styles are a single-select grid, always 2 columns
   (2x2) — even at the narrower breakpoint below, since 4 cards read
   best as 2x2/4x1, never a 3+1 wrap. A dedicated modifier, not a reuse
   of Travel Timing's own --timing-compact, even though both happen to
   be 2-column, keeping that approved page's CSS untouched. All four
   cards stay permanently visible (no collapse), so padding-right here
   (not the shared --multi modifier, which this single-select grid
   deliberately doesn't use) keeps the selected-card checkmark clear of
   the title. */
.emt-journey-studio .journey-booklet__workspace .option-grid--stay-compact {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  /* Booklet Layout Polish milestone: was --emt-js-space-2/--emt-js-space-3. */
  gap: var(--emt-js-space-1);
}

.emt-journey-studio .journey-booklet__workspace .option-grid--stay-compact .option-card__label {
  padding: var(--emt-js-space-2);
  padding-right: 2.75rem;
}

/* Contact (Contact Brochure Migration): the Email/WhatsApp reply-method
   choice, always 2 columns (2x2 never applies here — only 2 cards
   exist) — a dedicated modifier, not a reuse of Travel Timing's own
   --timing-compact, even though both happen to be 2-column, keeping
   that approved page's CSS untouched. */
.emt-journey-studio .journey-booklet__workspace .option-grid--contact-compact {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  /* Booklet Layout Polish milestone: was --emt-js-space-2/--emt-js-space-3. */
  gap: var(--emt-js-space-1);
}

.emt-journey-studio .journey-booklet__workspace .option-grid--contact-compact .option-card__label {
  padding: var(--emt-js-space-2);
}

/* Booklet Layout Polish milestone: booklet-scoped overrides for the
   shared, unscoped .timing-fields/.contact-method classes
   (studio-workspace.css) — Contact's Full Name field and its
   conditional Email/WhatsApp follow-up both use .timing-fields;
   legacy's own (much taller) #studio-main column never needed this
   trim, so these overrides apply only inside the booklet workspace,
   leaving the shared rules and legacy's own spacing untouched. */
.emt-journey-studio .journey-booklet__workspace .timing-fields {
  margin-top: var(--emt-js-space-2);
  gap: var(--emt-js-space-1);
}

.emt-journey-studio .journey-booklet__workspace .contact-method {
  /* Booklet Layout Polish milestone: a small explicit value (between
     --emt-js-space-1 and --emt-js-space-2) — the last few pixels needed to clear
     Contact's WhatsApp state's remaining sub-pixel-scale overflow. */
  margin-top: 0.65rem;
}

@media (max-width: 1300px) {
  .emt-journey-studio .journey-booklet__workspace .option-grid--compact,
  .emt-journey-studio .wedding-inline-fields .option-grid--compact {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .emt-journey-studio .journey-booklet__workspace .option-grid--highlights-compact {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .emt-journey-studio .journey-booklet__workspace .option-grid--experiences-compact {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* Shared booklet-only selected-state badge for multi-select checkbox
   cards (Shared Multi-Select Checkmark correction) — one visual
   treatment reused by Journey Highlights and both Experiences pages
   (their own bookletCardMarkup functions add the option-card--multi
   class and the .option-card__checkmark span), rather than a separate
   rule per screen. Never applied to single-select radio cards (Travel
   Style, Travel Timing's modes, Wedding's ceremony setting) — those
   keep only the existing .option-card__input:checked + .option-card__label
   border/background treatment in studio-workspace.css, unchanged here.
   Wedding Touches uses its own row layout (.wedding-touch, not
   .option-card) and doesn't participate — converting it to cards would
   be a layout change to an already-approved page, out of scope for this
   correction. The badge is a real, aria-hidden, non-interactive element,
   identically sized/positioned whether checked or not, so toggling it
   only ever recolors — never shifts the card's layout.

   Sizing/position refined (Checkmark Visual Refinement pass): 24px ->
   20px (~17% smaller) and nudged closer to the corner (top 24px->16px,
   right 24px->20px) so it reads as a quiet decorative badge rather than
   competing with the title for attention. padding-right on the label
   (below) is unchanged — the smaller, closer-to-corner badge already
   has *more* clearance from the title than before, not less, so the
   existing allowance stays more than sufficient. Purely a visual
   change: the label's own box (the real touch target) is untouched. */
.emt-journey-studio .journey-booklet__workspace .option-card--multi .option-card__label {
  /* Extra right-side room so the badge never overlaps longer titles
     (e.g. "Traditional Hammam & Spa", "Guided Medina Tour"). */
  padding-right: 2.75rem;
}

.emt-journey-studio .journey-booklet__workspace .option-card__checkmark {
  position: absolute;
  top: 16px;
  right: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--emt-js-color-surface);
  border: 1.5px solid var(--emt-js-color-border);
  color: transparent;
  pointer-events: none;
  transition: background-color var(--emt-js-motion-fast) var(--emt-js-ease-standard),
    border-color var(--emt-js-motion-fast) var(--emt-js-ease-standard),
    color var(--emt-js-motion-fast) var(--emt-js-ease-standard);
}

.emt-journey-studio .journey-booklet__workspace .option-card__checkmark svg {
  display: block;
}

.emt-journey-studio .journey-booklet__workspace .option-card__input:checked ~ .option-card__checkmark {
  background: var(--emt-js-color-terracotta-strong);
  border-color: var(--emt-js-color-terracotta-strong);
  color: var(--emt-js-color-surface);
}

/* Footer nav (Editorial Milestone) — Back/Continue beneath the
   question column, reusing .btn/.btn--primary/.btn--secondary; only
   placement is defined here. */
.emt-journey-studio .journey-booklet__footer {
  display: flex;
  justify-content: flex-end;
  gap: var(--emt-js-space-2);
  /* Booklet Layout Polish milestone: was --emt-js-space-5/--emt-js-space-4 (48/32px)
     — reclaims 24px toward fitting non-Review screens without
     internal scrolling. */
  margin-top: var(--emt-js-space-4);
  padding-top: var(--emt-js-space-3);
  border-top: 1px solid var(--emt-js-color-bg-alt);
  /* Review Brochure Migration: guarantees the footer never gets
     squeezed by its scrollable sibling (.journey-booklet__question)
     when content is long enough to need scrolling. */
  flex-shrink: 0;
}

/* Tall editorial image panel — fills the entire inspiration column
   edge-to-edge (no inset square, no gap beneath), stretching from
   just under the header to the bottom of the frame. Temporary mock
   photograph only (a warm gradient standing in for a real Morocco
   photograph) — supplied as the *default* of a custom property so a
   future admin-configured image is a value swap, not a structural
   change; nothing here assumes this specific mock. */
.emt-journey-studio .journey-booklet__image-shell {
  position: relative;
  height: 100%;
  min-height: 620px;
}

.emt-journey-studio .journey-booklet__image {
  position: absolute;
  inset: 0;
  background-image: var(
    --journey-booklet-image,
    linear-gradient(
      165deg,
      #f2dcb8 0%,
      #e0b17e 30%,
      #c98a55 58%,
      #9c5f3c 82%,
      #6f4128 100%
    )
  );
  background-size: cover;
  background-position: center;
  /* Per-travel-type / per-timing-mode image reaction (refinement pass;
     extended by the Travel Timing Brochure Migration to a second,
     screen-aware source): a soft crossfade only —
     context-selection.js's updateBookletImage() fades this to 0, swaps
     the --journey-booklet-image custom property (and, for Travel
     Timing, the image's accessible label), then fades back to 1. No
     slider, no movement, one image at a time. */
  transition: opacity var(--emt-js-motion-image-crossfade) var(--emt-js-ease-standard);
}

/* Phase 4.13B3 (optional hero video): one reusable layer, never 4 —
   scripts/context-selection.js's startHeroVideo()/stopHeroVideo() are
   the only things that ever set its src/poster or toggle .is-active.
   Sits directly on top of .journey-booklet__image (same inset:0 box,
   immediately after it in source order). Phase 4.13B3.1 removed the
   text-overlay layer (.journey-booklet__image-overlay/-copy/-eyebrow/
   -heading) that used to sit above this in source order — the
   photography/video is the inspiration layer now, so no z-index is
   needed anywhere in this stack. Hidden by default (display:none)
   rather than merely transparent, so an inactive slot never even has
   video decode/paint work to do. */
.emt-journey-studio .journey-booklet__video {
  display: none;
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
}

.emt-journey-studio .journey-booklet__video.is-active {
  display: block;
}

/* Journey Summary (Roadmap correction) — icon + status + edit rows,
   generated by context-selection.js's bookletSummaryMarkup()/
   roadmapRowMarkup(). Grid per row keeps the icon, the flexible
   label+value text, and the right-side status/edit group each in their
   own column regardless of how long the value text gets. This file's
   selectors only ever target the booklet's own .roadmap-row* classes. */
.emt-journey-studio .roadmap-row {
  display: grid;
  grid-template-columns: 24px minmax(0, 1fr) auto;
  align-items: start;
  column-gap: var(--emt-js-space-2);
  padding: var(--emt-js-space-2) 0;
  border-top: 1px solid var(--emt-js-color-border);
}

.emt-journey-studio .roadmap-row:first-child {
  border-top: none;
  padding-top: 0;
}

.emt-journey-studio .roadmap-row__icon {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 22px;
  color: var(--emt-js-color-ink-muted);
}

.emt-journey-studio .roadmap-row__text {
  min-width: 0;
}

.emt-journey-studio .roadmap-row__label {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--emt-js-color-ink-muted);
  margin: 0 0 0.15rem;
}

/* Reduced visual weight (kept from the previous refinement pass):
   concise roadmap reads as quiet companion notes, not a second,
   competing block of headlines. Long values (e.g. a full profile +
   group + ceremony-setting line) wrap rather than overflow. */
.emt-journey-studio .roadmap-row__value {
  font-family: var(--emt-js-font-display);
  font-size: 0.95rem;
  color: var(--emt-js-color-ink);
  margin: 0;
  overflow-wrap: anywhere;
}

.emt-journey-studio .roadmap-row__value--pending {
  color: var(--emt-js-color-ink-muted);
}

.emt-journey-studio .roadmap-row__actions {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  height: 22px;
}

.emt-journey-studio .roadmap-row__status {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}

.emt-journey-studio .roadmap-row__status--complete {
  color: var(--emt-js-color-success);
}

/* Quiet empty ring for a section not yet reached — never implies a
   decision has been made. */
.emt-journey-studio .roadmap-row__status--pending {
  border: 1.5px solid var(--emt-js-color-border);
  border-radius: 50%;
}

/* Restrained active marker for the section currently being answered —
   filled, but in the same accent used everywhere else for "in
   progress," never styled to look already complete. */
.emt-journey-studio .roadmap-row__status--active {
  border: 1.5px solid var(--emt-js-color-terracotta-strong);
  border-radius: 50%;
  background: var(--emt-js-color-terracotta-strong);
}

/* Real button, always visible beside the checkmark once a section is
   complete — never hover-only, never replacing the checkmark. */
.emt-journey-studio .roadmap-row__edit {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--emt-js-color-ink-muted);
  cursor: pointer;
  border-radius: var(--emt-js-radius-sm);
  transition: color var(--emt-js-motion-fast) var(--emt-js-ease-standard),
    background-color var(--emt-js-motion-fast) var(--emt-js-ease-standard);
}

.emt-journey-studio .roadmap-row__edit:hover {
  color: var(--emt-js-color-terracotta-strong);
  background: var(--emt-js-color-bg-alt);
}

.emt-journey-studio .roadmap-row__edit:focus-visible {
  outline: 2px solid var(--emt-js-color-focus);
  outline-offset: 2px;
}

/* Responsive (structural + column-proportion behaviour). */

/* Tablet: Question Workspace stays readable and gets a modest priority
   over the still-substantial image column; roadmap holds its share. */
@media (max-width: 1100px) and (min-width: 981px) {
  /* was 33/37/30 — the workspace column's own share increased (image's
     reduced correspondingly, roadmap's untouched, preserving its
     proportions as required) to more fully deliver on this rule's own
     already-documented intent ("Question Workspace stays readable...
     question stays dominant"), since narrower tablet widths otherwise
     wrap text onto enough extra lines to force internal scrolling. */
  .emt-journey-studio .journey-booklet__grid {
    grid-template-columns: 28fr 42fr 30fr;
  }

  .emt-journey-studio .journey-booklet__workspace,
  .emt-journey-studio .journey-booklet__roadmap {
    /* Booklet Layout Polish milestone: was var(--emt-js-space-4) var(--emt-js-space-3). */
    padding: var(--emt-js-space-3);
  }

  .emt-journey-studio .journey-booklet__image-shell {
    min-height: 480px;
  }

  /* Booklet Layout Polish milestone: Wedding's ceremony-setting grid
     wraps to 3 rows of 2 at this breakpoint (existing 1300px rule,
     unchanged) — the tallest single non-Review case found, so its own
     cards get one further, narrowly-scoped padding/gap trim here, on
     top of the already-reduced shared --compact values, without
     affecting Context's own (non-Wedding) compact grid at this same
     breakpoint. */
  .emt-journey-studio .wedding-inline-fields .option-grid--compact {
    gap: 0.4rem;
  }

  .emt-journey-studio .wedding-inline-fields .option-grid--compact .option-card__label {
    padding: var(--emt-js-space-1);
  }
}

/* Narrower tablet: image gives up a little more width; question stays
   dominant, roadmap stays readable. */
@media (max-width: 980px) and (min-width: 901px) {
  /* was 30/40/30 — same reasoning as the wider tablet breakpoint above. */
  .emt-journey-studio .journey-booklet__grid {
    grid-template-columns: 25fr 45fr 30fr;
  }

  .emt-journey-studio .journey-booklet__workspace,
  .emt-journey-studio .journey-booklet__roadmap {
    /* Booklet Layout Polish milestone: was var(--emt-js-space-4) var(--emt-js-space-3). */
    padding: var(--emt-js-space-3);
  }

  .emt-journey-studio .journey-booklet__image-shell {
    min-height: 420px;
  }

  /* Booklet Layout Polish milestone: same reasoning as the wider
     tablet breakpoint above. */
  .emt-journey-studio .wedding-inline-fields .option-grid--compact {
    gap: 0.4rem;
  }

  .emt-journey-studio .wedding-inline-fields .option-grid--compact .option-card__label {
    padding: var(--emt-js-space-1);
  }
}

/* Mobile: no forced three-column squeeze — single column, Question
   Workspace first, Roadmap second, Image last, landscape rather than
   portrait. The cover above this shell already becomes a full-width
   card at this breakpoint via layout.css's existing stack rule; the
   full hinge motion is skipped entirely in favour of the existing
   simple fade/expand (see scripts/journey-booklet.js). */
@media (max-width: 900px) {
  /* Modal Architecture milestone: full-screen app-style modal — no
     outer border radius, no margin, fills the real (dynamic) viewport
     via dvh so mobile browser chrome showing/hiding can't misjudge the
     available height. Unlike the previous "grow with the page"
     behavior this replaces, the frame is now a fixed 100% height, same
     paradigm as desktop, just sized differently — see
     .journey-booklet__grid below for the internal scroll region this
     now requires (mobile stacks every column into one, so the grid
     itself is the one scrollable region here, rather than desktop's
     per-column .journey-booklet__question scroll). */
  .journey-booklet.emt-journey-studio {
    width: 100%;
    height: 100dvh;
    max-width: 100%;
    max-height: 100dvh;
    margin: 0;
  }

  .emt-journey-studio .journey-booklet__frame {
    border-radius: 0;
  }

  .emt-journey-studio .journey-booklet__grid {
    grid-template-columns: 1fr;
    /* Phase 4.8A desktop-viewport correction's grid-template-rows:
       minmax(0, 1fr) is for the desktop single-row, three-column
       layout only — mobile stacks three full rows (one per column,
       reordered via `order` below) and wants every one of them at its
       own natural content height, with this grid's own overflow-y:auto
       as the *only* scroll region (see the comment below). Resetting
       to none here avoids applying a one-row sizing intent to a
       three-row context it was never meant for. */
    grid-template-rows: none;
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
  }

  /* Mobile full-screen fix: .journey-booklet__question's desktop-only
     flex:1 1 auto/min-height:0/overflow-y:auto (its own *per-column*
     scroll region, needed there because its grid row has a definite
     height to divide up) collapses it to 0 height here instead —
     .journey-booklet__workspace is now one of three stacked *rows*
     (mobile's grid-template-columns:1fr above), each auto-sized to its
     own content with no definite height for a flex-grow child to
     "grow into," and min-height:0 explicitly allows shrinking all the
     way to zero in exactly that indefinite-height case (confirmed live
     via getBoundingClientRect() — question measured 0px tall, pushing
     its own footer up to visually overlap the next stacked row).
     Resets it to plain natural-height flow instead, letting
     .journey-booklet__grid's own overflow-y:auto above be the one
     scroll region for the whole stacked column, exactly as intended. */
  .emt-journey-studio .journey-booklet__question {
    flex: none;
    min-height: auto;
    overflow-y: visible;
  }

  /* Same fix, one level up: .journey-booklet__workspace's own
     min-height:0 (also a desktop-only per-column-scroll enabler, see
     the Review Brochure Migration comment on its base rule) was
     otherwise still capping its grid-auto-row contribution to a
     min-content-ish size well under its now-natural-height children
     (confirmed live — question measured taller than its own claimed
     parent bounds). auto restores normal "grow to fit content" grid
     item sizing. */
  .emt-journey-studio .journey-booklet__workspace {
    min-height: auto;
  }

  /* Phase 4.8A desktop-viewport correction: same two-part reset as
     .journey-booklet__question/.journey-booklet__workspace just above,
     applied to the roadmap column's own desktop-only per-column scroll
     (added because a short desktop browser window can need it — see
     that fix's own comment on the base rule). Without this pair,
     .roadmap-summary would collapse to 0 height here for the identical
     reason .journey-booklet__question did: its flex parent
     (.journey-booklet__roadmap) is just one of three auto-stacked mobile
     rows with no definite height for a flex-grow child to size against. */
  .emt-journey-studio .journey-booklet__roadmap {
    min-height: auto;
  }

  .emt-journey-studio .journey-booklet__roadmap-summary {
    flex: none;
    min-height: auto;
    overflow-y: visible;
  }

  .emt-journey-studio .journey-booklet__workspace,
  .emt-journey-studio .journey-booklet__roadmap {
    padding: var(--emt-js-space-4) var(--emt-js-space-3);
    border-right: none;
    border-bottom: 1px solid var(--emt-js-color-border);
  }

  .emt-journey-studio .journey-booklet__inspiration {
    border-right: none;
  }

  /* Mobile UX Polish milestone: was workspace(1)/roadmap(2)/
     inspiration(3) — a plain stack of the desktop columns in DOM
     order, which put the editorial image last (after the interaction
     had already finished) and the roadmap between the question and the
     image. Reordered to match desktop's own storytelling order —
     image introduces the page, then question, then footer (already
     inside .journey-booklet__workspace, directly below the question),
     then roadmap last as a progress summary. No markup moved, no
     second image created — purely a flex `order` change on the three
     existing columns. */
  /* Phase 4.15A (Mobile Image Frame — Sticky Contextual Media):
     staging QA found the contextual image scrolled out of view as soon
     as the visitor scrolled through option cards, defeating the point
     of it changing per-selection — the visitor could no longer see it
     react. .journey-booklet__grid (the mobile stacked column's own
     overflow-y:auto, set in the base mobile rule above) is the actual
     scrolling ancestor here — .journey-booklet__topbar lives outside
     it entirely (a sibling in .journey-booklet__frame's own flex
     column, see the base rules above), so `position: sticky; top: 0`
     against this scroll container needs no extra offset math to land
     directly below the header/tabs, and pure CSS sticky needs no
     scroll-listener JS to achieve (Performance requirement). z-index
     keeps it visually above the workspace/roadmap content scrolling
     beneath it; nothing here touches the media mapping/state logic in
     context-selection.js, only where this one section paints. */
  .emt-journey-studio .journey-booklet__inspiration {
    order: 1;
    position: sticky;
    top: 0;
    z-index: 2;
  }

  .emt-journey-studio .journey-booklet__workspace {
    order: 2;
  }

  .emt-journey-studio .journey-booklet__roadmap {
    order: 3;
  }

  .emt-journey-studio .journey-booklet__image-shell {
    /* Phase 4.15A: was min-height:200px + aspect-ratio:16/9 (~219px at
       a 390px-wide phone) sized for the image's *former* non-sticky,
       scrolls-away role. A permanently sticky panel needs a fixed
       height instead. .journey-booklet__image/-video (both
       position:absolute; inset:0 with background-size/object-fit:
       cover, unchanged) fill whatever height this shell has, so
       cropping/focal-point behavior is otherwise identical, just
       against a shorter box.
       Phase 4.15A revision 1: 110px (measured ~106.7px) read as a thin
       banner, not a photo — raised to 140px.
       Phase 4.15A revision 2: 140px still read too small against the
       supplied visual reference — a proper visual panel, not a banner,
       needs real presence. 240px is the current target; the image
       stays clearly recognizable as it changes per-selection even
       while the visitor has scrolled well into the option cards below.
       See the short-viewport override below for the one case this is
       reduced back down for. */
    height: 240px;
    min-height: 240px;
    aspect-ratio: auto;
  }

  /* Consent-refinement milestone: scrollIntoView()'s native offset
     mechanism (no JS scroll listener, same "pure CSS" approach as the
     sticky panel above) — keeps the Review consent checkbox from
     landing behind .journey-booklet__inspiration's 240px sticky media
     panel when review.js's showConsentError() scrolls it into view on
     a failed Send Journey. +20px breathing room past the panel's own
     height so the checkbox doesn't land flush against its bottom edge.
     Set on the checkbox itself (scroll-margin only affects
     scrollIntoView() calls made on the element that carries it, not on
     an ancestor like .review-consent) — review.js calls
     checkbox.scrollIntoView() directly, since that's also the element
     it focuses immediately after. */
  .emt-journey-studio .review-consent__checkbox {
    scroll-margin-top: 260px;
  }

  /* Phase 4.13B3.2: mobile-only reduction from the base clamp()'s
     ~32px floor (styles/journey-booklet.css's own base rule above) to
     a fixed 28px — modest, not a new fluid range, since mobile has no
     viewport-width headroom for clamp()'s vw term to matter anyway.
     Desktop/tablet (outside this media query) keep the base clamp()
     untouched.
     Phase 4.15A (Mobile Question Heading Scale): staging QA found even
     28px too large at phone widths — the longest real questions (e.g.
     "Which parts of Morocco would you love to experience?") ran to
     ~3 lines and dominated the first viewport. 22px keeps the heading
     clearly the primary text on screen without that cost; line-height
     tightened slightly further (was 1.12) since 22px has less need for
     the breathing room a larger size wants. */
  .emt-journey-studio .journey-booklet__workspace .studio-question__heading {
    font-size: 1.375rem;
    line-height: 1.08;
  }

  .emt-journey-studio .journey-booklet__workspace .option-grid--compact,
  .emt-journey-studio .wedding-inline-fields .option-grid--compact,
  .emt-journey-studio .journey-booklet__workspace .option-grid--timing-compact,
  .emt-journey-studio .journey-booklet__workspace .option-grid--highlights-compact,
  .emt-journey-studio .journey-booklet__workspace .option-grid--experiences-compact,
  .emt-journey-studio .journey-booklet__workspace .option-grid--stay-compact,
  .emt-journey-studio .journey-booklet__workspace .option-grid--contact-compact {
    grid-template-columns: 1fr;
  }

  .emt-journey-studio .journey-booklet__footer {
    justify-content: space-between;
  }

  /* Phase 4.15A (Mobile Action Button Typography): staging QA found
     "BACK" wrapping awkwardly and "Save & Return to Review" oversized
     at phone widths (both at the shared .btn font-size, 16px). 14px on
     both footer buttons, plus the "Save & Review" label shortened at
     the JS source (context-selection.js), keeps Back/Save & Review on
     one line at normal phone widths. min-height stays the inherited
     44px from .btn (components.css) — only the type shrinks, not the
     tap target. Desktop/tablet (outside this media query) keep the
     base 16px, already balanced there. */
  .emt-journey-studio .journey-booklet__footer .btn {
    font-size: 0.875rem;
    padding-left: 1.1rem;
    padding-right: 1.1rem;
    white-space: nowrap;
  }

  /* Touch target minimum (DESIGN_PRINCIPLES.md) — grown in-flow rather
     than via a negative-margin overlay trick, so rows simply get a
     little taller instead of risking overlap with their neighbours. */
  .emt-journey-studio .roadmap-row__actions {
    height: 44px;
  }

  .emt-journey-studio .roadmap-row__edit {
    width: 44px;
    height: 44px;
  }

  /* Mobile UX Polish milestone: the roadmap now reads as a trailing
     progress summary, not a competing column — lighter vertical
     footprint via less padding around it and between its rows, not by
     removing any information (icons, values, checkmarks, and edit
     controls are all untouched; .roadmap-row__actions/.roadmap-row__edit
     above keep their own 44px touch target regardless of the row's own
     padding). Desktop/tablet's .journey-booklet__roadmap padding and
     .roadmap-row padding are completely unaffected — these overrides
     only exist inside this mobile media query. */
  .emt-journey-studio .journey-booklet__roadmap {
    padding-top: var(--emt-js-space-3);
    padding-bottom: var(--emt-js-space-3);
  }

  .emt-journey-studio .roadmap-row {
    padding: var(--emt-js-space-1) 0;
  }

  /* Phase 4.13B3.1 (Mobile Header Compaction): exactly two rows —
     "brand + inline context, close button" then "section tabs" — via
     CSS grid-template-areas rather than reordering the DOM, so the
     close button's own source position (a sibling of topbar-intro and
     topbar-phases, unchanged for its existing [data-booklet-back]
     wiring/aria) can still land in row 1 without needing a markup
     change. Replaces the previous column-stacked layout (brand row,
     context row, status row, phases row — up to four rows) and the
     previous mobile-only .journey-booklet__status line entirely (see
     that class's own rule above — now unconditionally display:none,
     same as desktop, freeing the vertical space it used to reserve).
     Desktop/tablet's own row-based flex layout (base rule above) is
     completely untouched — this grid only applies inside this mobile
     media query. */
  .emt-journey-studio .journey-booklet__topbar {
    display: grid;
    grid-template-columns: 1fr auto;
    grid-template-areas:
      "intro close"
      "phases phases";
    align-items: center;
    column-gap: var(--emt-js-space-2);
    row-gap: 0.35rem;
    padding: var(--emt-js-space-2) var(--emt-js-space-3);
  }

  /* Brand and context-label sit on one baseline instead of stacking —
     brand never shrinks/truncates, context-label takes whatever
     horizontal space is left and ellipsizes rather than wrapping to a
     second line or pushing the close button off-screen. min-width:0 on
     both the flex container and the truncating child is required for
     that shrink-to-fit-then-ellipsis behavior inside a grid/flex track
     (the default min-width:auto would let context-label's content
     force the row wider instead). */
  .emt-journey-studio .journey-booklet__topbar-intro {
    grid-area: intro;
    display: flex;
    align-items: baseline;
    gap: 0.35em;
    min-width: 0;
    /* Positioning context for the visually-hidden builder/separator
       spans below (position:absolute), same reasoning as
       studio-workspace.css's .option-card having position:relative
       for its own visually-hidden .option-card__input. */
    position: relative;
  }

  .emt-journey-studio .journey-booklet__topbar-intro .journey-booklet__brand {
    flex-shrink: 0;
  }

  .emt-journey-studio .journey-booklet__topbar-intro .journey-booklet__context-label {
    margin: 0;
    min-width: 0;
    flex: 1 1 auto;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
  }

  /* Renders the "·" separator between brand and context only when
     context-label actually has text — :empty still matches here since
     context-selection.js's updateBookletContextLabel() sets
     textContent = "" (no child nodes) whenever no profile is chosen
     yet, so no stray separator shows before a context exists. */
  .emt-journey-studio .journey-booklet__topbar-intro .journey-booklet__context-label:not(:empty)::before {
    content: "\00b7\00a0";
  }

  /* Phase 4.13B3.2: mobile shows only the selected profile ("Wedding")
     — the redundant builder prefix ("Celebration"/"Private") and its
     separator are dropped from view, since the ::before rule above
     already supplies mobile's own "· " separator ahead of whatever is
     visible. Visually hidden (the same clip-to-1px technique as
     studio-workspace.css's .option-card__input), not display:none —
     the full "Celebration • Wedding" text stays in the accessibility
     tree on mobile, only the visual presentation is reduced. Desktop
     (outside this media query) renders both spans normally, showing
     the full "Celebration • Wedding". */
  .emt-journey-studio .journey-booklet__topbar-intro .journey-booklet__context-builder,
  .emt-journey-studio .journey-booklet__topbar-intro .journey-booklet__context-sep {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }

  .emt-journey-studio .journey-booklet__close {
    grid-area: close;
  }

  .emt-journey-studio .journey-booklet__topbar-phases {
    grid-area: phases;
    gap: var(--emt-js-space-2);
    width: 100%;
  }

  /* Mobile Header Polish: smaller font/letter-spacing than desktop's
     --emt-js-text-label/0.08em — fits all three labels on one line each at
     375px/430px; at the narrowest supported width (320px) they may
     still wrap onto two lines, which is expected/acceptable ("graceful
     wrapping at very narrow widths" is a keep requirement, not
     something to eliminate) rather than forced nowrap risking
     horizontal overflow. */
  .emt-journey-studio .journey-booklet__topbar-phase {
    font-size: 0.62rem;
    letter-spacing: 0.02em;
  }

}

/* Phase 4.15A revision: on a genuinely short mobile viewport (older/
   smaller phones, or any phone in landscape — the width query alone
   can't see this, only max-height can) the full 240px sticky panel
   leaves too little vertical room for the question/cards beneath it.
   Reduces to 195px (mid-point of the 190-200px target) only in that
   specific case; ordinary phone-portrait heights (iPhone 390x844/
   430x932 and similar) are well above this threshold and keep the
   full 240px above. Still pure CSS, no scroll listener. */
@media (max-width: 900px) and (max-height: 700px) {
  .emt-journey-studio .journey-booklet__image-shell {
    height: 195px;
    min-height: 195px;
  }

  /* Consent-refinement milestone: matches the short-viewport sticky
     media height above (195px + the same 20px breathing room the
     normal-height rule uses). Set on the checkbox itself — see the
     normal-height rule's own comment for why. */
  .emt-journey-studio .review-consent__checkbox {
    scroll-margin-top: 215px;
  }
}

/* Mobile Header Polish: removes the redundant outer "Enchanted Morocco
   Tours" page eyebrow specifically while the booklet is the active,
   open surface on mobile — desktop/tablet always keep it (this rule
   only exists inside the mobile media query above's breakpoint), and
   it's still shown on mobile whenever the booklet itself is closed
   (Inspiration browsing). display:none removes it from layout
   entirely — no empty spacing left behind. Modal Architecture
   milestone: [open] is <dialog>'s own native, automatically-managed
   attribute (present exactly while showModal()/close() have it open) —
   replaces the retired `hidden`-attribute check this :has() rule used
   before #journey-booklet became a <dialog>. Purely a visual nicety
   now, not a functional necessity: the dialog's own top-layer
   rendering already fully covers this header at mobile regardless. */
@media (max-width: 900px) {
  .emt-journey-studio body:has(#journey-booklet[open]) .site-header {
    display: none;
  }
}

/* Phase 3.2 (Mobile Journey Studio Launcher): a dedicated, mobile-only
   generic entry point into Journey Studio. The desktop
   .journey-widget cover card (styles/layout.css) doesn't translate to
   mobile — it reads as a compressed sidebar, not a considered mobile
   moment — and a real Celebration page has no equivalent at all today
   (fixtures/celebration-page.html ships only the nine contextual CTAs
   embedded in page content, never a generic one). A quiet edge tab,
   not a chat bubble, FAB, or promo bar. Fully generic: the button
   carries the same data-launch-studio attribute the desktop cover CTA
   already uses, wired once, unconditionally, in journey-booklet.js —
   no new JS, no preselect, no contextual-session isolation, and
   closing restores focus to whichever of the two actually triggered
   the open. position: fixed keeps it out of document flow entirely,
   so appearing/disappearing (desktop vs. mobile, open vs. closed)
   never shifts any other layout.

   Phase 3.2.1 (visual polish only — lifecycle/API/accessibility
   untouched): moved from 58% to 42% down the viewport (still a
   percentage, not a hardcoded pixel offset, so it stays responsive
   across device heights) — the previous position sat too close to the
   page's own third-party chat widget (Chaty, visible in
   fixtures/celebration-page.html's real page content), and 42% reads
   as more comfortably mid-reach without competing with it. Palette
   inverted from a cream card with a terracotta accent to a solid
   terracotta-to-terracotta-deep fill with warm-ivory text — the same
   brand primary already used for every .btn--primary, so the contrast
   pairing (ivory-on-terracotta) is a reuse of an already-established,
   already-legible combination, not a new one. The border was dropped
   and the shadow softened (--emt-js-shadow-card, the app's most
   restrained resting shadow, was --emt-js-shadow-widget) — a filled
   brand-color tab reads its own edge through color contrast alone; a
   border on top of that reads as a bordered card, which this pass is
   explicitly moving away from. Slightly shorter (140px, was 152px)
   for less visual weight; width stays pinned at the 44px accessible
   touch-target floor (it already sat exactly there, so "narrower"
   isn't achievable without shrinking below the minimum).

   Phase 3.2.2 (clarity/motion polish only — position, breakpoint,
   visibility lifecycle, public API, contextual CTA behavior, modal
   behavior, state isolation, focus restoration, and the desktop
   launcher are all untouched): label copy changed again, "Journey
   Studio" (the workspace's own name, kept as the modal's actual
   product name) to "Plan My Trip" (what tapping the tab actually
   does), aria-label updated in step. A small double-chevron icon was
   added above the label to signal which way the tab opens.

   Phase 3.2.3 (discovery behavior — one-time reveal + gentle
   reminders, driven by scripts/mobile-journey-launcher.js; position,
   breakpoint, palette, public API, modal/contextual behavior, and
   focus restoration are all untouched): the resting state no longer
   shows any label text at all — icon only, per this milestone's
   explicit "no visible text in the resting state" requirement — so
   the tall, text-sized box from 3.2.1/3.2.2 (140px/156px) is gone;
   min-height drops to 64px, just enough for the 18px icon plus
   padding, comfortably over the 44px touch-target floor on both axes.
   The label element still exists in the DOM (needed for the one-time
   horizontal reveal below) but starts clipped to zero width and
   transparent; because it's revealed horizontally rather than
   vertically this time, its old writing-mode/rotate is gone too — it
   was only ever needed to match the old vertical tab shape. Label
   copy changed once more, "Plan My Trip" → "Plan My Celebration" (the
   launcher only ever appears on the Celebration page), aria-label to
   "Open Journey Studio to plan my celebration" — set once, statically,
   in markup, and left alone by the JS below: the accessible name
   never depended on which visual state (compact/expanded) is
   currently showing, so screen-reader users always get the full
   description immediately rather than waiting on a timed reveal.

   Two new classes, both JS-toggled, never applied by CSS alone:
   .is-expanded (button — widens from 44px to a fixed 236px so the
   width transition has two real pixel endpoints to interpolate
   between; width: auto doesn't transition reliably) and .is-nudging
   (icon only — a single one-shot inward nudge, replacing 3.2.2's
   infinite-looping keyframe now that nudges are imperative,
   count-limited events triggered by JS rather than a free-running
   decorative loop). Both transitions are ordinary CSS
   `transition: ...` rules, so both already collapse to
   near-instant under prefers-reduced-motion via the same existing
   blanket rule in styles/base.css every earlier phase's motion
   already relied on — no separate reduced-motion CSS was needed for
   either. */
.emt-journey-studio-mobile-launcher {
  display: none;
}

@media (max-width: 900px) {
  .emt-journey-studio-mobile-launcher {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    gap: var(--emt-js-space-1);
    position: fixed;
    top: 42%;
    right: 0;
    transform: translateY(-50%);
    z-index: 40;
    width: 44px;
    min-height: 64px;
    padding: var(--emt-js-space-1) var(--emt-js-space-0);
    padding-right: max(var(--emt-js-space-0), env(safe-area-inset-right, 0px));
    overflow: hidden;
    border-radius: var(--emt-js-radius-lg) 0 0 var(--emt-js-radius-lg);
    background: linear-gradient(
      175deg,
      var(--emt-js-color-terracotta-strong) 0%,
      var(--emt-js-color-terracotta-deep) 100%
    );
    box-shadow: var(--emt-js-shadow-card);
    cursor: pointer;
    transition: width 280ms var(--emt-js-ease-standard),
      transform var(--emt-js-motion-standard) var(--emt-js-ease-standard),
      box-shadow var(--emt-js-motion-standard) var(--emt-js-ease-standard);
  }

  /* Stage 1 (one-time introduction), scripts/mobile-journey-launcher.js:
     grows the tab from the 44px icon-only floor to a fixed 236px so
     "Plan My Celebration" fits on one line — width only (no scale, no
     transform), growing leftward/inward from the right-anchored edge
     since `right: 0` stays pinned regardless of width. overflow:hidden
     on the base rule clips both the icon+label pair before this class
     is added and the label's own reveal (below) consistently. */
  .emt-journey-studio-mobile-launcher.is-expanded {
    width: 236px;
    padding-left: var(--emt-js-space-2);
  }

  /* Spine cue: a quiet ivory hairline on the tab's inner edge (the one
     facing the page content it sits over) — the brochure-spine
     highlight a physical book's cover casts at its own hinge.
     Decorative only, never behind text, so it never affects contrast. */
  .emt-journey-studio-mobile-launcher::before {
    content: "";
    position: absolute;
    top: var(--emt-js-space-2);
    bottom: var(--emt-js-space-2);
    left: 0;
    width: 2px;
    border-radius: var(--emt-js-radius-sm);
    background: rgba(250, 246, 239, 0.3);
  }

  /* :hover only ever matches on a hover-capable pointer (desktop/mouse
     testing at this width) — touch devices don't trigger it, so this
     and :active below already separate cleanly by input modality with
     no extra media query needed. Subtle only: a small edge-ward nudge
     and one step of elevation, no added glow, no bounce. */
  .emt-journey-studio-mobile-launcher:hover,
  .emt-journey-studio-mobile-launcher:focus-visible {
    transform: translateY(-50%) translateX(-2px);
    box-shadow: var(--emt-js-shadow-card-elevated);
  }

  .emt-journey-studio-mobile-launcher:active {
    transform: translateY(-50%) translateX(-1px) scale(0.985);
  }

  /* Decorative direction cue, not the label — stays upright in both
     the compact and expanded states (never rotated). The nudge
     animation lives on this element alone, never the launcher itself,
     so "no movement of the full launcher" holds by construction: the
     button's own transform (translateY for centering, translateX/scale
     for hover/press) is a completely separate property on a completely
     separate element. */
  .emt-journey-studio-mobile-launcher__icon {
    flex-shrink: 0;
    color: var(--emt-js-color-bg);
    transition: transform 320ms var(--emt-js-ease-standard);
  }

  /* Stage 2 (gentle reminders): one JS-triggered, one-shot 2.5px
     inward nudge — added then removed by
     scripts/mobile-journey-launcher.js after ~320ms, never a
     free-running loop, so the total nudge count is exactly whatever
     the JS state machine decides (its own 2–3-reminder cap), not
     however many keyframe cycles happen to elapse. */
  .emt-journey-studio-mobile-launcher__icon.is-nudging {
    transform: translateX(-2.5px);
  }

  .emt-journey-studio-mobile-launcher__label {
    display: inline-block;
    max-width: 0;
    opacity: 0;
    font-family: var(--emt-js-font-display);
    font-weight: 500;
    font-size: 0.92rem;
    letter-spacing: 0.01em;
    color: var(--emt-js-color-bg);
    white-space: nowrap;
    overflow: hidden;
    transition: max-width 280ms var(--emt-js-ease-standard),
      opacity 280ms var(--emt-js-ease-standard);
  }

  .emt-journey-studio-mobile-launcher.is-expanded .emt-journey-studio-mobile-launcher__label {
    max-width: 200px;
    opacity: 1;
  }
}

/* Hidden the instant Journey Studio opens, reappears the instant it
   closes — [open] is <dialog>'s own native, automatically-managed
   attribute, the same reactive signal the site-header rule above
   already keys off. Needs no JS of its own. Not scoped under
   .emt-journey-studio: like .emt-journey-studio-scroll-lock
   (styles/base.css), this rule has to reach outside that boundary —
   the launcher and the dialog are both page-level siblings of <body>,
   not nested inside a shared .emt-journey-studio ancestor. */
@media (max-width: 900px) {
  body:has(#journey-booklet[open]) .emt-journey-studio-mobile-launcher {
    display: none;
  }
}
