/* Product Integration v0.1 -- Round 3 Product Web Shell styles.
   Mobile-first, single responsive layout (no separate "mobile mode" -- one layout that works
   from a phone viewport up), no external fonts/CDNs (system font stack only). */

* { box-sizing: border-box; }

:root {
  --bg: #faf7f2;
  --surface: #ffffff;
  --ink: #241f2e;
  --ink-soft: #635c6e;
  --accent: #7a4fd8;
  --accent-ink: #ffffff;
  --border: #e7e1f2;
  --danger-bg: #fdecec;
  --danger-ink: #9a2b2b;
  --warn-bg: #fff6e6;
  --warn-ink: #8a5a00;
  --notice-bg: #f1ecfb;
  --notice-ink: #4b3a7a;
  --radius: 14px;
}

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", "Segoe UI", Roboto, sans-serif;
  -webkit-text-size-adjust: 100%;
}

.app-shell {
  min-height: 100vh;
  display: flex;
  justify-content: center;
}

.loading-boot {
  padding: 40px 20px;
  color: var(--ink-soft);
  text-align: center;
  width: 100%;
}

.scene {
  width: 100%;
  max-width: 480px;
  min-height: 100vh;
  background: var(--surface);
  padding: 28px 20px 40px;
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.scene h1 {
  font-size: 1.35rem;
  margin: 0 0 4px;
  line-height: 1.4;
}

.scene h2 {
  font-size: 1.05rem;
  margin: 0 0 2px;
  color: var(--ink);
}

.scene p {
  margin: 0;
  line-height: 1.6;
  color: var(--ink-soft);
  font-size: 0.95rem;
}

.step-indicator {
  font-size: 0.8rem;
  color: var(--ink-soft);
  letter-spacing: 0.02em;
}

.choice-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-top: 6px;
}

.choice-btn {
  text-align: left;
  padding: 14px 16px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--ink);
  font-size: 0.95rem;
  cursor: pointer;
  min-height: 48px;
}

.choice-btn:active { background: var(--notice-bg); }

.field-group {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.field-group label {
  font-size: 0.85rem;
  color: var(--ink-soft);
}

.field-row {
  display: flex;
  gap: 8px;
}

input[type="number"], select {
  width: 100%;
  padding: 12px 12px;
  border-radius: 10px;
  border: 1px solid var(--border);
  font-size: 1rem;
  background: var(--surface);
  color: var(--ink);
  min-height: 44px;
}

.checkbox-row {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 0.9rem;
  color: var(--ink-soft);
}

.checkbox-row input { width: 18px; height: 18px; }

.primary-btn {
  padding: 15px 18px;
  border-radius: var(--radius);
  border: none;
  background: var(--accent);
  color: var(--accent-ink);
  font-size: 1rem;
  font-weight: 600;
  cursor: pointer;
  min-height: 50px;
}

.primary-btn:disabled { opacity: 0.55; cursor: not-allowed; }

.secondary-btn {
  padding: 13px 16px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--ink);
  font-size: 0.92rem;
  cursor: pointer;
  min-height: 46px;
}

.ghost-link {
  background: none;
  border: none;
  color: var(--accent);
  font-size: 0.88rem;
  text-decoration: underline;
  cursor: pointer;
  padding: 4px 0;
  align-self: flex-start;
}

.inline-error {
  background: var(--danger-bg);
  color: var(--danger-ink);
  padding: 12px 14px;
  border-radius: 10px;
  font-size: 0.88rem;
  line-height: 1.5;
}

.notice-panel {
  background: var(--notice-bg);
  color: var(--notice-ink);
  padding: 12px 14px;
  border-radius: 10px;
  font-size: 0.88rem;
  line-height: 1.6;
}

.notice-panel .notice-dim {
  font-weight: 700;
  display: block;
  margin-bottom: 2px;
}

.spinner {
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 3px solid var(--border);
  border-top-color: var(--accent);
  animation: spin 0.9s linear infinite;
  align-self: center;
}

@keyframes spin { to { transform: rotate(360deg); } }

.result-blocks {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.result-block {
  padding: 14px 16px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface);
  font-size: 0.95rem;
  line-height: 1.65;
}

.result-block.frame {
  border-style: dashed;
  color: var(--ink-soft);
  font-style: italic;
}

.paywall-card {
  padding: 20px 18px;
  border-radius: var(--radius);
  background: linear-gradient(160deg, #efe6ff, #fbeff7);
  border: 1px solid var(--border);
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.qa-panel {
  margin-top: 8px;
  padding: 10px 12px;
  border-radius: 10px;
  border: 1px dashed #c9a94a;
  background: #fffaf0;
  font-size: 0.8rem;
  color: #7a5a00;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.status-line {
  font-size: 0.8rem;
  color: var(--ink-soft);
}

.error-scene .inline-error { font-size: 0.95rem; }

.share-row {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

/* Q4 Safe Context Boundary (Intake v1, 2026-08-28) -- free-text scene + Paid-result recall panel. */
.q4-textarea {
  width: 100%;
  min-height: 140px;
  padding: 14px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--ink);
  font-size: 0.95rem;
  line-height: 1.6;
  font-family: inherit;
  resize: vertical;
}

.q4-counter {
  align-self: flex-end;
  font-size: 0.78rem;
  color: var(--ink-soft);
  margin-top: -10px;
}

.q4-recall-panel {
  padding: 14px 16px;
  border-radius: var(--radius);
  border: 1px dashed var(--border);
  background: var(--notice-bg);
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.q4-recall-panel h2 {
  color: var(--notice-ink);
}

.q4-recall-line {
  margin: 0;
  font-size: 0.9rem;
  line-height: 1.6;
  color: var(--notice-ink);
}

/* Entertainment/Reference Notice + Landing birth-requirement notice -- v22 Entertainment /
   Reference Notice Rule: small and clearly visible, but never an intrusive full-panel warning
   that undercuts the product promise. */
.reference-notice {
  font-size: 0.76rem;
  line-height: 1.5;
  color: var(--ink-soft);
  padding-top: 10px;
  margin-top: 4px;
  border-top: 1px solid var(--border);
}

.birth-requirement-notice {
  font-size: 0.82rem;
  line-height: 1.5;
  color: var(--ink-soft);
}

/* ---------------------------------------------------------------------------------------------
   Slice 1 -- Landing / Opening (lucero_landing_svg_v1_1_fixed, HUMAN APPROVED, source v35
   0.0-B/0.0-C). Full-bleed 9:16 video stage; overrides the generic .scene card layout every other
   scene in this app uses. landing_overlay.svg is shown as-is -- never redrawn/reinterpreted here
   (v35 0.0-E Handoff Rule: "landing_overlay.svg를 HTML/CSS로 다시 그리지 않는다").
   ------------------------------------------------------------------------------------------- */
.scene.lucero-stage-scene {
  max-width: none;
  width: 100%;
  min-height: 100svh;
  margin: 0;
  padding: 0;
  gap: 0;
  background: #000;
  display: grid;
  place-items: center;
  overflow: hidden;
}

.lucero-stage-scene .stage {
  position: relative;
  width: min(100vw, calc(100svh * 9 / 16));
  aspect-ratio: 9 / 16;
  overflow: hidden;
  background: #000;
  isolation: isolate;
}

.lucero-stage-scene .stage-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  object-fit: fill;
  background: #000;
}

.lucero-stage-scene .stage-overlay {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  pointer-events: none;
  user-select: none;
  -webkit-user-drag: none;
}

/* Illustrator CTA vector (1080x1920 stage): x=166.649 y=1715.5176 w=727.3043 h=130.4348, as
   percentages of the stage -- see lucero_landing_svg_v1_1_fixed/README.txt. Do not re-derive
   these from a redrawn layout. */
.lucero-stage-scene .stage-cta {
  position: absolute;
  z-index: 2;
  left: 15.430462963%;
  top: 89.349875%;
  width: 67.342990741%;
  height: 6.793479167%;
  padding: 0;
  border: 0;
  border-radius: 22%;
  background: transparent;
  color: transparent;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

.lucero-stage-scene .stage-cta:focus-visible {
  outline: 3px solid rgba(255, 236, 184, 0.95);
  outline-offset: 4px;
}

/* `들어가기` CTA (01 end, source v37 5-A.2 Threshold Interaction). A separate class from
   .stage-cta above -- Landing's CTA rect/behavior is untouched by this addition. Coordinates come
   from the <rect> actually drawn in the provided SVG (01_입장 CTA/SVG.svg: x=276 y=1502.677
   w=528 h=145.8369 on the 1080x1920 stage), not the task instruction's Illustrator-Transform-
   derived approximation (~2px off on the left edge only -- see app.js comment for detail). */
.lucero-stage-scene .stage-cta-enter {
  position: absolute;
  z-index: 2;
  left: 25.5555556%;
  top: 78.2644271%;
  width: 48.8888889%;
  height: 7.5957031%;
  padding: 0;
  border: 0;
  border-radius: 22%;
  background: transparent;
  color: transparent;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

.lucero-stage-scene .stage-cta-enter:focus-visible {
  outline: 3px solid rgba(255, 236, 184, 0.95);
  outline-offset: 4px;
}

.lucero-stage-scene .stage-cta-enter:disabled {
  cursor: default;
}

/* `인사하기` CTA (02~03 end). Separate class from .stage-cta / .stage-cta-enter above -- neither
   is touched by this addition. Coordinates come from the <rect> actually drawn in the provided SVG
   (2-3.인사_SVG.svg: x=276 y=1502.3133 w=528 h=145.8369 on the 1080x1920 stage) -- this round the
   Illustrator-Transform-derived value matched the SVG's own rect exactly (no correction needed,
   unlike 들어가기's ~2px case). No glow/shadow/border/background/animation added -- the SVG alone
   is Visual Authority (instruction item 20). */
.lucero-stage-scene .stage-cta-greet {
  position: absolute;
  z-index: 2;
  left: 25.5555556%;
  top: 78.2454844%;
  width: 48.8888889%;
  height: 7.5956719%;
  padding: 0;
  border: 0;
  border-radius: 22%;
  background: transparent;
  color: transparent;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

.lucero-stage-scene .stage-cta-greet:focus-visible {
  outline: 3px solid rgba(255, 236, 184, 0.95);
  outline-offset: 4px;
}

.lucero-stage-scene .stage-cta-greet:disabled {
  cursor: default;
}

/* Sound Toggle (instruction 2026-09-02, "Slice 1 오디오 동작 바로잡기"; tap-target fix instruction
   2026-09-02 follow-up). Small circular Utility Control(보조 조작 컨트롤), deliberately plain --
   no glow/shadow, not confusable with the CTA buttons above. Position is PROVISIONAL
   (instruction 4-2): a real usable top-right slot for now, final placement to be tuned later once
   SKIP exists alongside it. Icon color is white via `color` -- the inlined volume.svg/
   volume-off.svg markup uses stroke="currentColor".
   Tap-target fix: unlike the CTAs above, this is a Utility UI, not bound to the 1080x1920 visual
   coordinate system -- the ACTUAL <button> (this rule) is now the real hitbox, sized with
   max(percentage, 44px) so it never shrinks below a 44x44 CSS px touch target on a real mobile
   Stage even though 6.4815%/3.6458% alone would compute to ~26x26px there (unchanged/grows on a
   large Stage, exactly as before). The VISIBLE dark circle + icon moved to the nested
   .lucero-sound-toggle-icon span below, kept at a small fixed size so it still reads as quiet/
   understated -- the invisible button is simply larger than what it shows, the same "big hitbox,
   smaller visible mark" pattern the CTA buttons already use (transparent <button> + separate
   visual layer), applied here between the button and its own icon instead of an SVG overlay. */
.lucero-stage-scene .lucero-sound-toggle {
  position: absolute;
  z-index: 3;
  top: 3%;
  right: 4%;
  width: max(6.4815%, 44px);
  height: max(3.6458%, 44px);
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

.lucero-stage-scene .lucero-sound-toggle:focus-visible {
  outline: 2px solid rgba(255, 255, 255, 0.9);
  outline-offset: 2px;
}

.lucero-stage-scene .lucero-sound-toggle-icon {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: rgba(0, 0, 0, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
}

.lucero-stage-scene .lucero-sound-toggle-icon svg {
  width: 60%;
  height: 60%;
  display: block;
}

/* SKIP (source v44 0.0-E / 0.0-H, Scene-level SKIP -- 01/02~03/04 only). Small Utility Control,
   bottom-RIGHT (finalized this round, per explicit human instruction -- supersedes the original
   top-left placement): shares the top-RIGHT Sound Toggle's own `right` value and "large invisible
   hitbox (>=44px CSS px, same max(percentage, 44px) formula) + smaller visible mark" split above,
   rather than a new sizing/safe-area pattern. `bottom` mirrors that same max(percentage, px)
   approach, folding in env(safe-area-inset-bottom) so a device's own home-indicator/gesture-bar
   inset is respected without a new global Safe Area system. Top-LEFT is deliberately left
   completely empty -- reserved for a future Q1~Q4 Back Button (source v44 0.0-H), no placeholder
   added this round. No glow/shadow, no large filled button, no strong accent color, so it reads
   quieter than the CTA buttons and never competes with the video subject/character. */
.lucero-stage-scene .lucero-skip-button {
  position: absolute;
  z-index: 3;
  right: 4%;
  bottom: max(6%, calc(env(safe-area-inset-bottom, 0px) + 16px));
  min-width: max(6.4815%, 44px);
  height: max(3.6458%, 44px);
  padding: 0 8px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

.lucero-stage-scene .lucero-skip-button:focus-visible {
  outline: 2px solid rgba(255, 255, 255, 0.9);
  outline-offset: 2px;
}

.lucero-stage-scene .lucero-skip-button:disabled {
  cursor: default;
}

.lucero-stage-scene .lucero-skip-button-label {
  padding: 6px 12px;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.4);
  color: rgba(255, 255, 255, 0.88);
  font-size: 0.78rem;
  font-weight: 500;
  line-height: 1;
  white-space: nowrap;
}

/* -------------------------------------------------------------------------------------------
   05 Low-motion Loop + Q1 Baseline Composite (2026-09-02). Scope: this round only composites the
   real 05 video with a functional Q1 test UI so a Human Review can judge the layout -- nothing
   here is a final, LOCKed visual design (see app.js's own header comment on this section for the
   full context). Brand Bible V4.1 principles this styling follows: Content First / System
   Beneath (Section 15 Journey Visual Dominance -- "Q1~Q4: 캐릭터 + 대화 + 상호작용이 주요 화면,
   Master System은 입력/선택 규칙만 지원"), and Character Dominance Rule (Section 16 -- Entry/
   Relationship Intake 구간에서 캐릭터가 Primary Visual Surface를 차지, UI는 이를 덮지 않는다).
   ------------------------------------------------------------------------------------------- */

/* Pretendard(프리텐다드) -- Brand Bible Section 13's Product UI / Functional typeface. Sourced
   from the already-deployed local file (web/fonts/Pretendard.woff2, the Pretendard Variable
   package, axis wght 45-930) -- no external font CDN, no new download (instruction item 13).
   Scoped via font-family, NOT applied to html/body globally -- every other existing scene keeps
   its current system-font stack untouched; only the new .lucero-q1-* elements below opt in. */
@font-face {
  font-family: 'Pretendard';
  src: url('/fonts/Pretendard.woff2') format('woff2');
  font-weight: 45 930;
  font-style: normal;
  font-display: swap;
}

/* Baseline Composite overlay -- layered on top of the playing 05 stage-video, anchored to the
   LOWER portion of the 9:16 stage only (never a full-stage cover). This placement comes from a
   real frame-by-frame check of 05_F_Web_60fps.mp4: the character's face sits in roughly the top
   third of the 1080x1920 frame (y=150-650 of 1920px) and the upper body extends to roughly two-
   thirds down -- top:48% stays well clear of the face, and the gradient itself starts fully
   transparent at that line, only gradually warming to a dark translucent tone toward the very
   bottom, so it never visibly "begins" over anything. (Adjusted from an initial 60% during this
   round's own real-browser QA at a 390x844-class viewport: 60% left the 5-option list ~78px short
   of fitting on one screen even at the 44px touch-target floor, forcing the internal-scroll
   safety net on every device, not just short ones -- 48% was the smallest downward move that let
   all 5 options fit without scrolling there while keeping the face/upper body clearly visible; see
   completion report. Exact placement is still not LOCKed -- this is this round's best-attempt
   baseline for Human Review, not a final value.) The gradient itself (transparent -> warm-tinted
   dark) is the "very weak dark translucent surface" the instruction allows for legibility,
   deliberately NOT a solid white/opaque card -- Character Dominance stays intact where it sits. */
.lucero-stage-scene.q1-scene .lucero-q1-overlay {
  position: absolute;
  z-index: 2;
  left: 0;
  right: 0;
  bottom: 0;
  /* Real-device Human Review fix round (2026-09-03): top moved 44% -> 38% to give the overlay more
     vertical capacity so the question can render on ONE line (see .lucero-q1-question below) and
     the 5 options can render with zero internal scroll -- both were confirmed broken on a real
     mobile device even though this app's own (WebM-substitute, fallback-font) headless QA harness
     did not catch it. Root cause of the miss: that harness's copy of web/ was missing
     fonts/Pretendard.woff2 entirely, so line-wrap width was being measured against a narrower
     fallback system font instead of real Pretendard Bold 800 -- fixed for this round's own
     re-verification. This is the FIRST lever from this round's fix-priority list (vertical capacity
     before touching the question's own width/size) -- see the horizontal padding note below and the
     completion report's Viewport Results for the measured fit at 375x812/390x844/393x852/430x932.
     Real-asset face-clearance at 38% (vs. the previously-confirmed-safe 44%) could only be verified
     against a WebM stand-in clip here, not the real 05 production asset/a real device -- flagged for
     Human Review confirmation in the report rather than asserted as visually verified. */
  top: 38%;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  /* Q1 UI polish round (instruction item C): with the Category Label removed, this gap now sits
     purely between the question and the first option -- bumped from 10px to 24px (+14px, within
     the requested 12~18px increase) so the question reads as its own headline block instead of
     running straight into the option list. (Trimmed from an initial 26px -> 24px purely to close
     the H1 no-scroll fit at 390x844 -- see the .lucero-q1-options / .lucero-q1-option adjustments
     below and the completion report's mobile check; still comfortably inside the requested band.)
     Unchanged this round -- gap:24px, unrelated to the top:38% move above. */
  gap: 24px;
  /* Q1 UI polish round (instruction item F): bottom padding bumped from 20px to 24px (+4px) so the
     last option isn't pinned to the screen edge. Top padding trimmed 22px -> 14px as part of the
     same 390x844 no-scroll fit pass (item F explicitly allows fine-tuning block position/gaps/button
     heights to make all 5 options fit). Vertical padding unchanged this round.
     Real-device Human Review fix round (2026-09-03): horizontal padding trimmed 20px -> 16px (the
     SECOND lever from this round's fix list -- expand the question's available width before ever
     touching its font-size) -- this alone, combined with the top:38% move above, was enough to get
     the question onto one real line at every required viewport with zero font-size/letter-spacing
     change, so neither was needed (see .lucero-q1-question below). */
  padding: 14px 16px calc(24px + env(safe-area-inset-bottom, 0px));
  background: linear-gradient(
    180deg,
    rgba(23, 17, 12, 0) 0%,
    rgba(23, 17, 12, 0.55) 28%,
    rgba(23, 17, 12, 0.82) 100%
  );
  pointer-events: none; /* re-enabled per-element below, so empty gradient space never blocks the video */
}

.lucero-stage-scene.q1-scene .lucero-q1-overlay > * {
  pointer-events: auto;
}

/* Category Label removed (Q1 UI polish round, instruction item A) -- the small provisional line
   that used to sit above the question ("재회 사주 · 첫 번째 질문") is gone from the DOM (see
   renderLuceroQ1Overlay() in app.js), so its CSS rule is removed here too rather than left dead. */

/* Q1 UI polish round (instruction item B): the question is now the clear headline of the screen --
   font-size raised from clamp(1.02rem, 4.6vw, 1.2rem) to clamp(1.4rem, 6.2vw, 1.65rem) (~1.35-1.4x
   across the clamp range) and font-weight raised two steps, 600 -> 800. Copy itself is unchanged
   (still LUCERO_Q1_QUESTION verbatim) -- only the visual treatment changed. */
.lucero-stage-scene.q1-scene .lucero-q1-question {
  font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  font-weight: 800;
  font-size: clamp(1.4rem, 6.2vw, 1.65rem);
  /* line-height tightened 1.3 -> 1.15 as part of the 390x844 no-scroll fit pass -- still comfortably
     legible for a short 1-2 line bold headline (tighter leading is standard practice for larger
     bold display text), and frees up vertical room for the option list below. */
  line-height: 1.15;
  color: #fff9ef;
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.45);
  margin: 0;
  /* Q1 Layout final round (2026-09-03, Human Decision): the previous round's single-line `nowrap`
     fix is REMOVED here -- real-device Human Review found the edge-to-edge single line too visually
     tight. This element is now a plain block (unchanged default h1 display) containing two fixed
     <span class="lucero-q1-question-line"> children (see app.js's renderLuceroQ1Overlay()) instead
     of a single text node -- each span is itself `display: block` (see below), so ordinary block
     flow alone stacks them into two lines with no flexbox needed. font-size/font-weight/line-height/
     color/text-shadow above are all UNCHANGED this round -- the Human Decision was explicitly to
     keep the question's existing visual size/presence and only change where it breaks. */
}

/* Q1 Layout final round (2026-09-03, Human Decision): each line of the question is its own block
   with `white-space: nowrap` -- this is what actually enforces the fixed Editorial Line Break
   ("지금 두 사람은" / "어떻게 지내고 있어요?"), never a browser Auto Wrap. If a line's own text were
   ever too wide for the stage, this would show as a visible horizontal overflow on that line rather
   than silently re-wrapping into a 3rd line -- verified not to happen at any required viewport down
   to 360px in this round's own measurement (see completion report). */
.lucero-stage-scene.q1-scene .lucero-q1-question-line {
  display: block;
  white-space: nowrap;
}

.lucero-stage-scene.q1-scene .lucero-q1-options {
  display: flex;
  flex-direction: column;
  /* Q1 UI polish round (instruction item E): gap between option buttons bumped from 6px to 9px so
     the five options read as separate cards rather than a packed list -- re-verified at 390x844
     that all 5 still fit on one screen without scrolling together with items C/F's extra space.
     (Trimmed from an initial 10px -> 9px purely for the no-scroll fit -- still a +3px increase
     over the original 6px.) */
  gap: 9px;
  /* Q1 Layout final round (2026-09-03, Human Decision): the internal-scroll safety net
     (max-height:46vh + overflow-y:auto) is REMOVED. Product UX decision: Q1 is a Fixed
     Composition(고정 구성) -- question + all 5 options are always simultaneously visible, never a
     scrollable sub-region. `overflow: visible` below is the explicit (matches the initial value,
     stated here on purpose rather than left implicit) confirmation that this is not a "hide the
     scrollbar but keep clipping" trick -- if content ever doesn't fit, it will visibly overflow the
     stage rather than silently clip or scroll, which is intentionally more obvious/debuggable than a
     hidden truncation. See the completion report's Viewport Results for the measured fit (down to
     360px) that makes this removal safe today. */
  overflow: visible;
}

.lucero-stage-scene.q1-scene .lucero-q1-option {
  /* Q1 micro-adjust round (final): min-height bumped 40px -> 46px, padding left at the original
     12px 14px (not increased). Rev.2 scaled this down from an initial 1rem/50px/13px pass that
     needed a much bigger overlay-top move than "minimal" allowed; the remaining 23px 390x844 fit
     deficit at this size is absorbed by moving .lucero-q1-overlay's `top` 48% -> 44% instead of
     shrinking this further (Human Review confirmed sufficient clearance to the character's face for
     that move) -- see completion report's fit-check table for the measured numbers. */
  min-height: 46px;
  padding: 12px 14px;
  border-radius: 12px;
  border: 1px solid rgba(255, 255, 255, 0.22);
  background: rgba(23, 17, 12, 0.4);
  color: #fdf8ee;
  font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  font-weight: 500;
  /* Q1 micro-adjust round (rev.2): option text size bumped 0.9rem -> 0.95rem (scaled down from an
     initial 1rem for the same fit-budget reason above) -- a one-notch bump toward the question's
     visual weight, not a size match. */
  font-size: 0.95rem;
  line-height: 1.4;
  /* Q1 UI polish round (instruction item D): option text centered (was left-aligned). Button width
     still spans the layout naturally -- only the text alignment inside each button changed. */
  text-align: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  /* Q1 UI polish round (instruction item G): short, restrained color cross-fade only -- no scale/
     glow/bounce -- so the tap-flash -> settle transition (see app.js) reads as a quiet state change
     rather than an animation. */
  transition: background-color 0.15s ease, border-color 0.15s ease;
}

.lucero-stage-scene.q1-scene .lucero-q1-option:active {
  background: rgba(23, 17, 12, 0.6);
}

/* Tap flash (Q1 UI polish round, instruction item G) -- the immediate, brief, stronger highlight
   shown the instant an option is tapped (held ~0.25s in app.js, then swapped for .is-selected
   below). Same warm gold as .is-selected, just more saturated/opaque, so the flash reads as "this
   one, right now" before calming into the persistent selected look -- no new hue, no glow/scale. */
.lucero-stage-scene.q1-scene .lucero-q1-option.is-tapped {
  border-color: rgba(255, 236, 184, 1);
  background: rgba(255, 236, 184, 0.32);
}

/* Selected state -- reuses the same warm gold already established for this file's CTA
   focus-visible outlines (rgba(255, 236, 184, ...)) rather than introducing a new, not-yet-LOCKed
   Product Accent hex for web UI (Brand Bible's Warm Amber is confirmed for Product Artwork/scene
   color but has no LOCKed CSS hex for functional UI fills as of this round -- see completion
   report). Kept subtle: a border + faint fill shift, no glow/animation. */
.lucero-stage-scene.q1-scene .lucero-q1-option.is-selected {
  border-color: rgba(255, 236, 184, 0.85);
  background: rgba(255, 236, 184, 0.16);
}

.lucero-stage-scene.q1-scene .lucero-q1-option:focus-visible {
  outline: 2px solid rgba(255, 236, 184, 0.95);
  outline-offset: 2px;
}

/* ---------------------------------------------------------------------------------------------
   Q2 Baseline Composite (2026-09-03). Reached only via app.js's goToNextQ1Step() adding a
   'q2-scene' class onto the EXISTING scene div (never a new sceneRoot()/video) -- same 05 video,
   same Visual Language as Q1 above: Pretendard, white Bold question, 2-line Editorial Break, warm
   dark translucent surface, centered options, same border/radius/highlight colors, same 250ms tap
   interaction. Every .lucero-q1-* rule above is UNCHANGED by this block -- Q2 gets its own
   selectors throughout. The one real difference driving the values below: 7 options instead of
   Q1's 5, which needed its own Q2-only vertical-fit values (top/gaps/option size) rather than
   reusing Q1's exact numbers. These were chosen up front from the priority order in this round's
   instruction (vertical capacity -> question/options gap -> options-gap -> option min-height ->
   padding -> font-size, only as a last resort) and then MEASURED via Playwright against the real
   Pretendard font and the real 7 q2_mainFriction strings across all 6 required viewports
   (360x780/800, 375x812, 390x844, 393x852, 430x932): all 6 passed with zero internal scroll, zero
   horizontal overflow, and every option >= the 44px floor on the first pass, so no iterative
   adjustment was needed -- see completion report's Viewport Matrix for the per-viewport numbers.
   ------------------------------------------------------------------------------------------- */
.lucero-stage-scene.q2-scene .lucero-q2-overlay {
  position: absolute;
  z-index: 2;
  left: 0;
  right: 0;
  bottom: 0;
  /* Fit priority lever #1 (vertical capacity): Q2 needs noticeably more room than Q1's top:38% left
     for 2 extra options, so this starts from a higher position -- see the block comment above for
     how this and the other fit-priority values below were chosen and measured. */
  top: 27%;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  /* Fit priority lever #2 (question<->options gap): Q1 uses 24px; within the instruction's allowed
     16-20px band for Q2, using the lower end to buy back vertical room before ever touching option
     size/font. */
  gap: 16px;
  padding: 12px 16px calc(20px + env(safe-area-inset-bottom, 0px));
  background: linear-gradient(
    180deg,
    rgba(23, 17, 12, 0) 0%,
    rgba(23, 17, 12, 0.55) 22%,
    rgba(23, 17, 12, 0.85) 100%
  );
  pointer-events: none; /* re-enabled per-element below, same pattern as Q1 */
}

.lucero-stage-scene.q2-scene .lucero-q2-overlay > * {
  pointer-events: auto;
}

/* Font-size/weight/line-height/color/text-shadow identical to Q1's .lucero-q1-question -- explicitly
   NOT reduced (instruction section 3: "먼저 Q1 스타일을 최대한 유지해서 측정한다"). If a future
   measurement pass ever needs a font-size cut, that is the LAST lever in the priority list, not the
   first -- see the report for why it wasn't needed this round. */
.lucero-stage-scene.q2-scene .lucero-q2-question {
  font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  font-weight: 800;
  font-size: clamp(1.4rem, 6.2vw, 1.65rem);
  line-height: 1.15;
  color: #fff9ef;
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.45);
  margin: 0;
}

/* Same fixed Editorial Line Break mechanism as .lucero-q1-question-line -- each line is its own
   nowrap block, so the break only ever happens where app.js's two <span> children put it. */
.lucero-stage-scene.q2-scene .lucero-q2-question-line {
  display: block;
  white-space: nowrap;
}

.lucero-stage-scene.q2-scene .lucero-q2-options {
  display: flex;
  flex-direction: column;
  /* Fit priority lever #3 (options gap): Q1 uses 9px; within the instruction's allowed 5-7px band
     for Q2's 7 options. */
  gap: 6px;
  /* No internal-scroll safety net, same Fixed Composition decision as Q1 (instruction section 8:
     "Q2도... Options 내부 Scroll을 사용하지 않는다") -- explicit `overflow: visible`, not an
     implicit default, for the same "never silently clip/scroll" reasoning as Q1's own rule. */
  overflow: visible;
}

.lucero-stage-scene.q2-scene .lucero-q2-option {
  /* Fit priority lever #4 (option min-height): Q1 uses 46px; instruction floor for Q2 is 44px
     (never below) -- used here as part of fitting 7 options, still >= the real minimum tap target. */
  min-height: 44px;
  /* Fit priority lever #5 (vertical padding): trimmed slightly from Q1's 12px 14px to buy a little
     more room per button across 7 of them; horizontal padding unchanged. */
  padding: 9px 14px;
  border-radius: 12px;
  border: 1px solid rgba(255, 255, 255, 0.22);
  background: rgba(23, 17, 12, 0.4);
  color: #fdf8ee;
  font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  font-weight: 500;
  font-size: 0.95rem;
  line-height: 1.3;
  text-align: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  transition: background-color 0.15s ease, border-color 0.15s ease;
}

.lucero-stage-scene.q2-scene .lucero-q2-option:active {
  background: rgba(23, 17, 12, 0.6);
}

.lucero-stage-scene.q2-scene .lucero-q2-option.is-tapped {
  border-color: rgba(255, 236, 184, 1);
  background: rgba(255, 236, 184, 0.32);
}

.lucero-stage-scene.q2-scene .lucero-q2-option.is-selected {
  border-color: rgba(255, 236, 184, 0.85);
  background: rgba(255, 236, 184, 0.16);
}

.lucero-stage-scene.q2-scene .lucero-q2-option:focus-visible {
  outline: 2px solid rgba(255, 236, 184, 0.95);
  outline-offset: 2px;
}

/* ---------------------------------------------------------------------------------------------
   Q3 Baseline Composite (2026-09-03). Reached only via app.js's goToNextQ2Step() replacing
   'q1-scene q2-scene' with 'q3-scene' on the EXISTING scene div (never a new sceneRoot()/video) --
   same 05 video, same Visual Language as Q1/Q2 above. Every existing .lucero-q1- and .lucero-q2-
   prefixed rule above is UNCHANGED by this block -- Q3 gets its own selectors throughout.

   Q3 has 5 options, same count as Q1 (not Q2's 7), so per this round's instruction the values below
   START from Q1's own baseline numbers (top:38%, gap:24px, padding:14px 16px, options gap:9px,
   option min-height:46px/padding:12px 14px/font-size:0.95rem) rather than inventing new numbers or
   copying Q2's tighter 7-option fit values. These were then MEASURED via Playwright against the
   real Pretendard font and the real 5 q3_curiosity strings across all 6 required viewports
   (360x780/800, 375x812, 390x844, 393x852, 430x932): the Q1 baseline values fit with zero internal
   scroll and zero horizontal overflow with no adjustment needed -- see completion report's Viewport
   Matrix for the per-viewport numbers. */
.lucero-stage-scene.q3-scene .lucero-q3-overlay {
  position: absolute;
  z-index: 2;
  left: 0;
  right: 0;
  bottom: 0;
  top: 38%;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 24px;
  padding: 14px 16px calc(24px + env(safe-area-inset-bottom, 0px));
  background: linear-gradient(
    180deg,
    rgba(23, 17, 12, 0) 0%,
    rgba(23, 17, 12, 0.55) 28%,
    rgba(23, 17, 12, 0.82) 100%
  );
  pointer-events: none; /* re-enabled per-element below, same pattern as Q1/Q2 */
}

.lucero-stage-scene.q3-scene .lucero-q3-overlay > * {
  pointer-events: auto;
}

/* Font-size/weight/line-height/color/text-shadow identical to Q1/Q2's own question rules --
   unchanged, same Q1 baseline this whole block starts from. */
.lucero-stage-scene.q3-scene .lucero-q3-question {
  font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  font-weight: 800;
  font-size: clamp(1.4rem, 6.2vw, 1.65rem);
  line-height: 1.15;
  color: #fff9ef;
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.45);
  margin: 0;
}

/* Same fixed Editorial Line Break mechanism as .lucero-q1-question-line/.lucero-q2-question-line --
   each line is its own nowrap block, so the break only ever happens where app.js's two <span>
   children put it. */
.lucero-stage-scene.q3-scene .lucero-q3-question-line {
  display: block;
  white-space: nowrap;
}

.lucero-stage-scene.q3-scene .lucero-q3-options {
  display: flex;
  flex-direction: column;
  gap: 9px;
  /* No internal-scroll safety net, same Fixed Composition decision as Q1/Q2 -- explicit
     `overflow: visible`, not an implicit default, for the same "never silently clip/scroll"
     reasoning as their own rules. */
  overflow: visible;
}

.lucero-stage-scene.q3-scene .lucero-q3-option {
  min-height: 46px;
  padding: 12px 14px;
  border-radius: 12px;
  border: 1px solid rgba(255, 255, 255, 0.22);
  background: rgba(23, 17, 12, 0.4);
  color: #fdf8ee;
  font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  font-weight: 500;
  font-size: 0.95rem;
  line-height: 1.4;
  text-align: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  transition: background-color 0.15s ease, border-color 0.15s ease;
}

.lucero-stage-scene.q3-scene .lucero-q3-option:active {
  background: rgba(23, 17, 12, 0.6);
}

.lucero-stage-scene.q3-scene .lucero-q3-option.is-tapped {
  border-color: rgba(255, 236, 184, 1);
  background: rgba(255, 236, 184, 0.32);
}

.lucero-stage-scene.q3-scene .lucero-q3-option.is-selected {
  border-color: rgba(255, 236, 184, 0.85);
  background: rgba(255, 236, 184, 0.16);
}

.lucero-stage-scene.q3-scene .lucero-q3-option:focus-visible {
  outline: 2px solid rgba(255, 236, 184, 0.95);
  outline-offset: 2px;
}

/* ---------------------------------------------------------------------------------------------
   Q4 Baseline Composite (2026-09-03, continues the same-day Q3 Composite work). Reached only via
   app.js's goToNextQ3Step() replacing 'q3-scene' with 'q4-scene' on the EXISTING scene div (never
   a new sceneRoot()/video) -- same 05 video, same accent-color/world language as Q1/Q2/Q3 above.
   Every existing .lucero-q1-/.lucero-q2-/.lucero-q3- prefixed rule above is UNCHANGED by this
   block -- Q4 gets its own selectors throughout.

   Q4's content shape (question + notice + free-text textarea + live counter + two actions) is
   structurally different from Q1/Q2/Q3's short choice list, so these values are NOT a mechanical
   copy of Q3's top/gap/padding numbers -- they are a fresh 1st-pass baseline sized to fit the
   extra vertical content (notably the textarea), starting further up than Q3's top:38% the same
   way Q2's top:27% started further up than Q1's for its extra options. Per this round's explicit
   "don't over-tune" instruction, these are reasonable first-pass numbers checked against the
   Playwright viewport matrix (360x800/390x844/430x932) for zero horizontal overflow and zero
   forced internal scroll, not hand-measured pixel-by-pixel like Q1-3's option lists -- final
   numbers are expected to move after real-device Human Review. */

/* -----------------------------------------------------------------------------------------------
   HISTORY -- rounds 2/3's breakpoint approach (REMOVED this round, see ROUND 4 below):
   Round 2 (real Android + Kakao in-app browser): `100svh`/`100lvh` in the shared Stage width
   formula both shrank Q4's Stage under an open keyboard, so Q4 was given its own `width: 100%`
   rule -- a plain percentage through a chain measured (ancestor-by-ancestor) to be completely
   height-independent, fixing the keyboard-shrink bug.
   Round 3 (PC report): that `width: 100%` rule had no media query, so it also applied on desktop,
   stretching `.stage` to the full 1920px viewport width and (via the still-inherited
   `aspect-ratio: 9/16`) crushing the visible frame down to just the character's face. It was
   wrapped in `@media (max-width: 767px)` so it only fired on phones and PC fell back to the shared
   base rule below, unchanged.

   BUGFIX ROUND 4 (2026-09-03, Galaxy Fold unfolded-state report): round 3's rule broke Q4 (only
   Q4 -- Q1/Q2/Q3 were fine) specifically on an unfolded Fold. ROOT CAUSE: round 3 branched on
   VIEWPORT WIDTH alone. An unfolded Fold's width sits in the gap between "phone" and "PC" -- wide
   enough to land on the wrong side of the 767px line, so Q4 fell through to the shared base rule's
   `min(100vw, calc(100svh * 9/16))` in a state that rule was never designed for, producing an
   oversized Stage/video and pushing the question off-screen. WHY NOT JUST MOVE THE NUMBER: any
   fixed width threshold has this same failure mode built in -- there will always be some real
   device (a bigger fold, a small tablet, a narrow PC window) sitting on the wrong side of it. The
   actual condition Q4 ever needed to react to was never "is this device a phone", it was always
   "is the on-screen keyboard open right now" -- a state, not a width -- so this round replaces the
   breakpoint with real keyboard-state detection (see the `renderLuceroQ4Overlay()` JS in app.js).

   NEW STRUCTURE: Q4's Stage carries NO unconditional width override anymore. In its default state
   (no `q4-keyboard-open` class) the rule below simply does not match, so `.stage` falls straight
   through to the shared base rule -- meaning Q4's keyboard-closed sizing is now byte-identical to
   Q1/Q2/Q3's by construction, on every device including an unfolded Fold, since it is the literal
   same `.stage`/`#lucero-05-video` element with zero Q4-specific CSS applying until JS confirms a
   real keyboard-open. Only once app.js's `visualViewport`-based detection confirms the keyboard is
   actually open does it (a) add `q4-keyboard-open` to the scene root and (b) set
   `--q4-keyboard-stage-width` (an inline custom property, on `.stage` itself) to the Stage width
   that was measured immediately before the keyboard opened -- never the already-shrunk width, so
   the original Android bug cannot reproduce under this new mechanism either. `aspect-ratio: 9/16`
   still governs HEIGHT from that locked width, so a shortened viewport can only change how much of
   the fixed Stage is currently visible (page scroll compensates, same fallback as every prior
   round) -- never the Stage's width. On keyboard-close, JS removes both the class and the custom
   property, so this rule stops matching and `.stage` returns to the exact same shared calculation
   Q1-3 use -- there is no separate "PC" or "mobile" code path here at all any more. */
.lucero-stage-scene.q4-scene.q4-keyboard-open .stage {
  width: var(--q4-keyboard-stage-width, 100%);
}

.lucero-stage-scene.q4-scene .lucero-q4-overlay {
  position: absolute;
  z-index: 2;
  left: 0;
  right: 0;
  bottom: 0;
  top: 24%;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 12px;
  padding: 14px 16px calc(18px + env(safe-area-inset-bottom, 0px));
  background: linear-gradient(
    180deg,
    rgba(23, 17, 12, 0) 0%,
    rgba(23, 17, 12, 0.55) 18%,
    rgba(23, 17, 12, 0.88) 100%
  );
  pointer-events: none; /* re-enabled per-element below, same pattern as Q1/Q2/Q3 */
}

.lucero-stage-scene.q4-scene .lucero-q4-overlay > * {
  pointer-events: auto;
}

/* Smaller than Q1/Q2/Q3's clamp(1.4rem,6.2vw,1.65rem) -- Q4's question is a longer single
   sentence (not a short 2-line editorial break) and this round's content has to share room with
   the textarea below it, so the "vertical capacity" lever is applied to the question first here,
   same fit-priority reasoning Q2's block comment above documents. Family/weight/color/text-shadow
   still identical to Q1/Q2/Q3 -- same Pretendard functional-UI stack, same visual language. */
.lucero-stage-scene.q4-scene .lucero-q4-question {
  font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  font-weight: 800;
  font-size: clamp(1.15rem, 5.4vw, 1.4rem);
  line-height: 1.28;
  color: #fff9ef;
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.45);
  margin: 0;
}

/* Deliberately lower visual hierarchy than .lucero-q4-question (instruction section 2: must read
   as in-world character dialogue, not a generic form description) -- smaller size, softer/lower-
   opacity color, no text-shadow emphasis, but still Pretendard/on-brand rather than a muted system
   default. */
.lucero-stage-scene.q4-scene .lucero-q4-notice {
  font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  font-weight: 500;
  font-size: 0.82rem;
  line-height: 1.5;
  color: rgba(255, 249, 239, 0.78);
  margin: 0;
}

/* Free-text input -- the one element in this block with no Q1/Q2/Q3 precedent. `resize: none`
   (instruction: user must not be able to resize it); font-size fixed at 16px (not rem/clamp) which
   is the standard iOS Safari threshold to prevent the page auto-zooming when the textarea gets
   focus and the on-screen keyboard opens. Border/background/radius reuse Q1-3's option-button
   translucent-panel language so it still reads as part of the same world, not a bare HTML form
   field. */
.lucero-stage-scene.q4-scene .lucero-q4-textarea {
  width: 100%;
  min-height: 92px;
  max-height: 132px;
  box-sizing: border-box;
  resize: none;
  border-radius: 12px;
  border: 1px solid rgba(255, 255, 255, 0.22);
  background: rgba(23, 17, 12, 0.42);
  color: #fdf8ee;
  font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  font-weight: 400;
  font-size: 16px;
  line-height: 1.45;
  padding: 10px 12px;
  -webkit-tap-highlight-color: transparent;
  transition: border-color 0.15s ease;
}

.lucero-stage-scene.q4-scene .lucero-q4-textarea::placeholder {
  color: rgba(253, 248, 238, 0.45);
}

.lucero-stage-scene.q4-scene .lucero-q4-textarea:focus {
  outline: none;
  border-color: rgba(255, 236, 184, 0.85);
}

.lucero-stage-scene.q4-scene .lucero-q4-textarea:focus-visible {
  outline: 2px solid rgba(255, 236, 184, 0.95);
  outline-offset: 2px;
}

/* Secondary info (instruction section 4: "읽을 수 있는 보조 정보" -- accessible/readable, but
   never competing with the question/notice above it). Right-aligned under the textarea it counts,
   same placement convention a native form counter would use. */
.lucero-stage-scene.q4-scene .lucero-q4-counter {
  font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  font-weight: 500;
  font-size: 0.72rem;
  line-height: 1.2;
  color: rgba(255, 249, 239, 0.55);
  text-align: right;
  margin: 0;
}

.lucero-stage-scene.q4-scene .lucero-q4-actions {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

/* Primary CTA ("다 적었어요"). Same accent-color family (rgba(255,236,184,*)) and same
   is-tapped/is-selected two-step settle Q1/Q2/Q3's options use, so tapping it doesn't introduce a
   new visual idiom -- just applied to a single full-width action button instead of one of several
   equal choices. min-height 46px matches Q3's own option floor, comfortably over the 44px tap-
   target requirement. */
.lucero-stage-scene.q4-scene .lucero-q4-primary {
  min-height: 46px;
  padding: 12px 14px;
  border-radius: 12px;
  border: 1px solid rgba(255, 236, 184, 0.55);
  background: rgba(255, 236, 184, 0.14);
  color: #fff9ef;
  font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  font-weight: 700;
  font-size: 0.95rem;
  line-height: 1.3;
  text-align: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  transition: background-color 0.15s ease, border-color 0.15s ease, opacity 0.15s ease;
}

/* Disabled while the textarea is empty (instruction section 6-A) -- dimmed rather than hidden, so
   the button's position in the question -> notice -> textarea -> counter -> CTA -> 없어요 reading
   order never shifts. */
.lucero-stage-scene.q4-scene .lucero-q4-primary:disabled {
  opacity: 0.42;
  cursor: not-allowed;
}

.lucero-stage-scene.q4-scene .lucero-q4-primary:not(:disabled):active {
  background: rgba(255, 236, 184, 0.28);
}

.lucero-stage-scene.q4-scene .lucero-q4-primary.is-tapped {
  border-color: rgba(255, 236, 184, 1);
  background: rgba(255, 236, 184, 0.32);
}

.lucero-stage-scene.q4-scene .lucero-q4-primary.is-selected {
  border-color: rgba(255, 236, 184, 0.85);
  background: rgba(255, 236, 184, 0.16);
}

.lucero-stage-scene.q4-scene .lucero-q4-primary:focus-visible {
  outline: 2px solid rgba(255, 236, 184, 0.95);
  outline-offset: 2px;
}

/* Secondary path ("없어요"). Deliberately quieter than the primary CTA -- flat/no fill, muted
   text -- so it reads as the lower-emphasis option without needing extra copy (instruction:
   "(선택)" in the question already conveys optionality, no extra explanation needed here).
   Padding alone (not a filled box) still clears the 44px tap-target floor. */
.lucero-stage-scene.q4-scene .lucero-q4-secondary {
  min-height: 44px;
  padding: 10px 14px;
  border-radius: 12px;
  border: 1px solid transparent;
  background: transparent;
  color: rgba(255, 249, 239, 0.62);
  font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  font-weight: 500;
  font-size: 0.88rem;
  line-height: 1.3;
  text-align: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  transition: color 0.15s ease, background-color 0.15s ease, border-color 0.15s ease;
}

.lucero-stage-scene.q4-scene .lucero-q4-secondary:active {
  color: rgba(255, 249, 239, 0.85);
}

.lucero-stage-scene.q4-scene .lucero-q4-secondary.is-tapped {
  border-color: rgba(255, 236, 184, 0.7);
  background: rgba(255, 236, 184, 0.14);
  color: #fff9ef;
}

.lucero-stage-scene.q4-scene .lucero-q4-secondary.is-selected {
  border-color: rgba(255, 236, 184, 0.5);
  background: rgba(255, 236, 184, 0.08);
  color: #fff9ef;
}

.lucero-stage-scene.q4-scene .lucero-q4-secondary:focus-visible {
  outline: 2px solid rgba(255, 236, 184, 0.95);
  outline-offset: 2px;
}

/* ---------------------------------------------------------------------------------------------
   Character Micro-payoff (캐릭터 짧은 감정 회수) round (2026-09-04, continues the same-week Q4
   Composite work). Reached only via app.js's settleQ4() replacing 'q4-scene' with
   'micro-payoff-scene' on the EXISTING scene div (never a new sceneRoot()/video) -- same 05 video,
   same accent-color/world language as Q1/Q2/Q3/Q4 above.

   Stage sizing (instruction section 9): deliberately NO rule here targets `.stage` itself -- this
   scene has no textarea, so it has no reason to ever apply Q4's keyboard-width-lock mechanism
   (the `.lucero-stage-scene.q4-scene.q4-keyboard-open .stage` rule above only ever matches while
   'q4-scene' is present, and app.js's settleQ4()/q4TeardownKeyboardListeners() strip that class and
   its custom property before this scene's class is even added). `.stage` therefore falls straight
   through to the shared base rule (`.lucero-stage-scene .stage` near the top of this file) --
   byte-identical Shared Stage Sizing to Q1/Q2/Q3, on every device including PC and an unfolded
   Fold, by construction rather than by a second copy of that math. */

/* Dark Scrim (Human Direction section 6, 2026-09-04 round) -- sits between the untouched, still-
   playing/looping #lucero-05-video and the static image. Exists only to prevent a visible double-
   exposure ghost during the video->image handoff: 05's live pose (leaning forward, one arm toward
   the bottle) and 06_micropayoff.png's pose (both forearms folded on the counter) are different
   enough that a plain opacity crossfade visibly doubles the face/arms for a few frames (verified
   directly by blending the two source frames at 50/50 -- a real, not hypothetical, artifact).
   Briefly dimming the video first, then crossfading the static image in over the dimmed layer,
   avoids ever showing two clear, competing photos at once -- #lucero-05-video itself is still never
   touched (no filter/opacity/pause applied to it); this is a new layer stacked on top of it, same
   technique the image layer below already uses. */
.lucero-stage-scene.micro-payoff-scene .lucero-micropayoff-scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  background: #0a0806;
  opacity: 0;
  transition: opacity 120ms ease;
  pointer-events: none;
}

.lucero-stage-scene.micro-payoff-scene .lucero-micropayoff-scrim.is-visible {
  /* 1차 기준 0.40 (Human Direction section 6) -- 실제 화면에서 이중노출이 남아있으면 0.45~0.55까지
     조정 가능. 완전 암전(1.0에 가까운 값)으로 보이면 안 됨. */
  opacity: 0.40;
}

/* Static image -- plain crossfade-in layer on top of the (now Dark-Scrim-dimmed) #lucero-05-video.
   opacity-only transition, no scale/zoom/parallax. z-index bumped to 2 now that the Scrim sits at 1
   beneath it, dialogue at 3 above it.
   object-fit: the source image (06_micropayoff.png, 941x1672) is 0.5629 wide:tall vs. this Stage's
   locked 9:16 = 0.5625 -- under a 0.1% difference, i.e. sub-pixel at any real viewport, so `cover`
   crops a fraction of a pixel off either side and preserves the image's own aspect ratio exactly;
   face/arms/counter composition are unaffected, so no object-position adjustment is needed.

   Background Continuity Bugfix (2026-09-04, Birth Name Scene round): this same `<img>` DOM node is
   deliberately kept alive across the Micro-payoff -> Birth Name Scene handoff (app.js's
   goToBirthNameScene() removes only the dialogue/CTA layers, never this image) -- but this selector
   was scoped to `.micro-payoff-scene` only, so once that class is swapped for `.birth-name-scene`
   the rule stopped matching and the image silently lost position/size/crop/opacity, risking
   #lucero-05-video showing back through and/or the image dropping into Normal Flow as a stray
   fragment near the bottom of the page. Fixed by scoping this rule (and `.is-visible` below) to
   BOTH scene classes -- no property value changed, only which scene classes the selector matches.

   Birth Intake round 2 (2026-09-04, Birth Gender Scene): the same `<img>` DOM node is kept alive one
   step further into `.birth-gender-scene` (app.js's goToBirthGenderScene() removes only Birth Name
   Scene's own overlay, never this image) -- `.birth-gender-scene` is added to this selector (and
   `.is-visible` below) for the same reason as `.birth-name-scene` above: without it, the image would
   again silently lose its Visual State the moment the scene class changes. No property value changed,
   only which scene classes the selector matches.

   Birth Intake round 3 (2026-09-05, Birth Date / Birth Time Scenes): the same `<img>` DOM node is kept
   alive two steps further, into `.birth-date-scene` and `.birth-time-scene` (app.js's
   goToBirthDateScene()/goToBirthTimeScene() each remove only the PREVIOUS scene's own overlay, never
   this image). Added to this selector (and `.is-visible` below) for the identical reason as every
   scene class before it -- again, no property value changed, only which scene classes the selector
   matches.

   Product Runtime Bridge round (2026-09-05, Analysis Transition Scene): the same `<img>` DOM node is
   kept alive one step further still, into `.analysis-transition-scene` (app.js's
   goToAnalysisTransitionScene() removes only Birth Time Scene's own overlay, never this image) --
   spec section 12 requires no new video/design, just this existing image reused exactly as-is. Added
   to this selector (and `.is-visible` below) for the identical reason as every scene class before it
   -- again, no property value changed, only which scene classes the selector matches. */
.lucero-stage-scene.micro-payoff-scene .lucero-micropayoff-image,
.lucero-stage-scene.birth-name-scene .lucero-micropayoff-image,
.lucero-stage-scene.birth-gender-scene .lucero-micropayoff-image,
.lucero-stage-scene.birth-date-scene .lucero-micropayoff-image,
.lucero-stage-scene.birth-time-scene .lucero-micropayoff-image,
.lucero-stage-scene.analysis-transition-scene .lucero-micropayoff-image {
  position: absolute;
  inset: 0;
  z-index: 2;
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
  object-position: center;
  background: #000;
  opacity: 0;
  transition: opacity 220ms ease;
  pointer-events: none;
  user-select: none;
  -webkit-user-drag: none;
}

.lucero-stage-scene.micro-payoff-scene .lucero-micropayoff-image.is-visible,
.lucero-stage-scene.birth-name-scene .lucero-micropayoff-image.is-visible,
.lucero-stage-scene.birth-gender-scene .lucero-micropayoff-image.is-visible,
.lucero-stage-scene.birth-date-scene .lucero-micropayoff-image.is-visible,
.lucero-stage-scene.birth-time-scene .lucero-micropayoff-image.is-visible,
.lucero-stage-scene.analysis-transition-scene .lucero-micropayoff-image.is-visible {
  opacity: 1;
}

/* ---------------------------------------------------------------------------------------------
   Analysis Transition Scene (Product Runtime Bridge round, 2026-09-05, spec sections 12/13).
   Reached only via app.js's goToAnalysisTransitionScene() swapping 'birth-time-scene' for
   'analysis-transition-scene' on the EXISTING scene div (never a new sceneRoot()/video) -- the
   shared `.lucero-micropayoff-image` rule above is what keeps 06_micropayoff.png's position/size/
   crop/opacity identical across this swap, nothing in this block touches that image.

   Copy is exactly the two fixed lines app.js provides (LUCERO_ANALYSIS_TRANSITION_LINE1/2) -- no
   percentage/progress/step/ETA UI is styled here, only a small quiet 3-dot pulse in place of a
   spinner (spec section 13). */
.lucero-analysis-transition-overlay {
  position: absolute;
  inset: 0;
  z-index: 3;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  padding: 24px;
  text-align: center;
  opacity: 0;
  transition: opacity 320ms ease;
  pointer-events: none;
}

.lucero-analysis-transition-overlay.is-visible {
  opacity: 1;
}

.lucero-analysis-transition-line {
  margin: 0;
  color: #fff;
  font-family: 'Pretendard', sans-serif;
  font-size: 20px;
  font-weight: 600;
  line-height: 1.4;
  text-shadow: 0 2px 12px rgba(0, 0, 0, 0.45);
}

.lucero-analysis-transition-dots {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 6px;
}

.lucero-analysis-transition-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.85);
  animation: lucero-analysis-dot-pulse 1.2s ease-in-out infinite;
}

.lucero-analysis-transition-dot:nth-child(2) {
  animation-delay: 0.15s;
}

.lucero-analysis-transition-dot:nth-child(3) {
  animation-delay: 0.3s;
}

@keyframes lucero-analysis-dot-pulse {
  0%, 80%, 100% {
    opacity: 0.25;
    transform: scale(0.85);
  }
  40% {
    opacity: 1;
    transform: scale(1);
  }
}

/* Dialogue text (subtitle-typography round, 2026-09-04 -- derived from direct frame-by-frame review
   of 자막 테스트02.mp4, the Human Reference for this round; supersedes the previous round's smaller/
   cramped-near-CTA layout, which was declared FAIL). Still NOT a Speech Bubble, NOT a Gradient
   Panel, NOT a Question Card -- no background of any kind, text sits directly on the image.
   Line 1 and the Line-2 group are now two INDEPENDENTLY positioned blocks (not one flex-column stack
   with a small `gap`) so the large inter-sentence "breath" the reference shows is a real placed gap,
   not a small flex gap value. `.lucero-micropayoff-overlay` itself is just a full-Stage positioning
   context (`inset:0`) with no visual styling of its own. */
.lucero-stage-scene.micro-payoff-scene .lucero-micropayoff-overlay {
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
}

/* Line 1 ("이야기해주신 건 잘 들었어요.") -- placed independently at ~48% of Stage height, ~10% from
   the left. Fades in on its own (opacity-only, see Human Decision below) and is never hidden again
   once shown. */
.lucero-stage-scene.micro-payoff-scene .lucero-micropayoff-line1 {
  position: absolute;
  left: 10%;
  top: 48%;
  max-width: 86%;
  opacity: 0;
  transition: opacity 400ms linear;
}

.lucero-stage-scene.micro-payoff-scene .lucero-micropayoff-line1.is-visible {
  opacity: 1;
}

/* Line-2 group ("그럼 이제," / "두 사람의 사주를 같이 볼게요.") -- placed independently at ~59% of
   Stage height, same left margin as Line 1, well below it (the large gap between 48%/59% IS the
   "breath" the reference video shows between the two sentences). Two DELIBERATE line elements inside
   this one wrapper (app.js -- never browser auto-wrap: `white-space: nowrap` on each sub-line below
   enforces this even if a future copy edit makes a line longer than expected). Both sub-lines fade in
   TOGETHER as a single unit -- the reference never staggers them -- so only this wrapper's own
   opacity is toggled; the sub-lines underneath carry no opacity/transition of their own. */
.lucero-stage-scene.micro-payoff-scene .lucero-micropayoff-line2-group {
  position: absolute;
  left: 10%;
  top: 59%;
  max-width: 86%;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  opacity: 0;
  transition: opacity 500ms linear;
}

.lucero-stage-scene.micro-payoff-scene .lucero-micropayoff-line2-group.is-visible {
  opacity: 1;
}

/* Shared line styling -- font scale is a formula, not a fixed clamp() ceiling, so it keeps tracking
   the reference's "large, confident caption" scale at every viewport rather than plateauing on
   larger screens the way the previous round's `clamp(1.02rem, 4.6vw, 1.2rem)` did. `min(6vw,
   3.375svh)` self-corrects for the Shared 9:16 Stage's own letterboxing on wide/PC viewports: once
   the Stage becomes height-constrained there, `3.375svh` (height-based) naturally wins the `min()`
   over `6vw` (full-viewport-width-based), so the rendered size still tracks the STAGE's width rather
   than the browser window's. Human Decision (section 9, this round): Text Stroke is removed entirely
   -- even though the reference video itself shows a faint outline -- because it visibly roughens
   small Korean glyph strokes at this weight; Text Shadow alone carries all the legibility work now.
   line-height 1.32 is tuned for the Line-2 group's own two sub-lines (~1.30-1.35 per the reference);
   it has no visible effect on Line 1, which is only ever one line. */
.lucero-stage-scene.micro-payoff-scene .lucero-micropayoff-line {
  font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  font-weight: 600;
  font-size: min(6vw, 3.375svh);
  line-height: 1.32;
  color: #fff9ef;
  text-shadow: 0 2px 6px rgba(0, 0, 0, 0.70);
  text-align: left;
  white-space: nowrap;
  margin: 0;
}

/* CTA ("네, 좋아요", Human Direction sections 11-14) -- the previous round's CSS-drawn
   `.lucero-micropayoff-cta` (which reused .lucero-q4-primary's look) is retired entirely. Visual
   Authority is micropayoff_overlay.svg (byte-identical copy of the human-provided
   Q4~Q5.사이_SVG.svg, never redrawn in CSS/HTML), used exactly like enter_overlay.svg/
   greet_overlay.svg: a full 1080x1920 `.stage-overlay` image with the button art baked in at its own
   coordinates, transparent everywhere else. This second class only adds the Reveal fade-in the
   enter/greet CTAs never needed (those appear already-visible; this one must stay hidden until
   2.25s -- subtitle-typography round, 2026-09-04: only the trigger offset moved later to make room
   for the retimed dialogue schedule above; this CTA's own CSS -- opacity/duration/easing/coordinates
   -- is unchanged this round). */
.lucero-stage-scene.micro-payoff-scene .lucero-micropayoff-cta-image {
  z-index: 4;
  opacity: 0;
  transition: opacity 300ms ease;
}

.lucero-stage-scene.micro-payoff-scene .lucero-micropayoff-cta-image.is-visible {
  opacity: 1;
}

/* Transparent hitbox only -- the SVG above owns 100% of the visual, so is-tapped/is-selected
   (app.js) intentionally carry NO border/background/text styling here (Human Direction section 14:
   "HTML 버튼에 Q4 스타일의 테두리/배경/텍스트를 다시 그리지 않는다"). Same coordinate structure as
   `.stage-cta-greet` (left/top/width/height percentages match to the 4th decimal -- Human Direction
   section 12), but its own separate class -- `.stage-cta-greet` itself is not touched by this round.
   Starts `disabled` (app.js) until the Reveal timeline enables it at 2.55s (subtitle-typography
   round, 2026-09-04 -- offset only, same trigger-later note as above), so it can never be tapped
   while still fading in. */
.lucero-stage-scene.micro-payoff-scene .stage-cta-micropayoff {
  position: absolute;
  z-index: 5;
  left: 25.5555556%;
  top: 78.2454844%;
  width: 48.8888889%;
  height: 7.5956719%;
  padding: 0;
  border: 0;
  border-radius: 22%;
  background: transparent;
  color: transparent;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

.lucero-stage-scene.micro-payoff-scene .stage-cta-micropayoff:focus-visible {
  outline: 3px solid rgba(255, 236, 184, 0.95);
  outline-offset: 4px;
}

.lucero-stage-scene.micro-payoff-scene .stage-cta-micropayoff:disabled {
  cursor: default;
  pointer-events: none;
}

/* ---------------------------------------------------------------------------------------------
   Birth Name Scene (Conversational Birth Intake round 1, 2026-09-04; CSS-scope bugfix same day, see
   below). Reached only via app.js's goToBirthNameScene() replacing 'micro-payoff-scene' with
   'birth-name-scene' on the EXISTING scene div (never a new sceneRoot()/video) -- same 05 video,
   same accent-color/world language as Q1-Q4/Micro-payoff above. Only Micro-payoff's dialogue/CTA
   layers were removed by app.js before this class swap; `.lucero-micropayoff-image` is the SAME
   `<img>` DOM node Micro-payoff already faded in -- app.js never removes/re-creates/re-fades it.
   Its Visual State (position/size/crop/opacity/z-index) is owned by the shared rule above
   (`.lucero-stage-scene.micro-payoff-scene .lucero-micropayoff-image, .lucero-stage-scene.birth-
   name-scene .lucero-micropayoff-image, .lucero-stage-scene.birth-gender-scene
   .lucero-micropayoff-image { ... }`), which Micro-payoff, this scene, AND Birth Gender Scene all
   match at once -- that is what keeps position/size/crop/opacity identical across every scene-class
   swap, not any rule inside this Birth Name Scene block (nothing below targets
   `.lucero-micropayoff-image`).

   Stage sizing: no unconditional width rule here, same reasoning as Q4/Micro-payoff above -- only
   the birth-name-keyboard-open rule immediately below ever overrides it, and only once app.js
   confirms a real keyboard-open. */
.lucero-stage-scene.birth-name-scene.birth-name-keyboard-open .stage {
  width: var(--birth-name-keyboard-stage-width, 100%);
}

/* Question + Input + CTA (instruction sections 6/19): fewer/simpler elements than Q4 (no notice, no
   free-text/counter), so `top` starts a little lower than Q4's 24% -- more vertical room per element
   is available, first-pass value checked against the Responsive QA viewport matrix (section 21) for
   zero overflow/clipping; adjustable per the instruction's Fit Priority order (overlay top first,
   font size only as a last resort) without needing to touch the question's font-size. Gradient reuses
   Q3's own (not Q4's) 180deg stops -- instruction section 8 explicitly allows "Q4보다 조금 단순한
   Gradient" for this question+input scene, and Q3's is already the established simpler one (Q4's
   ramps darker/faster: 0.55@18% vs Q3/this scene's 0.55@28%). No opaque full-screen panel, no white
   Form Card -- the character stays the Primary Visual Surface (instruction section 8/Brand Bible
   DO/DON'T). Fades in as one unit (`opacity` only, ~200ms) once Micro-payoff's own layers are gone
   (instruction section 19) -- the static image underneath is never re-faded. */
.lucero-stage-scene.birth-name-scene .lucero-birth-name-overlay {
  position: absolute;
  z-index: 2;
  left: 0;
  right: 0;
  bottom: 0;
  top: 30%;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 14px;
  padding: 14px 16px calc(20px + env(safe-area-inset-bottom, 0px));
  background: linear-gradient(
    180deg,
    rgba(23, 17, 12, 0) 0%,
    rgba(23, 17, 12, 0.55) 28%,
    rgba(23, 17, 12, 0.82) 100%
  );
  opacity: 0;
  transition: opacity 200ms ease;
  pointer-events: none; /* re-enabled per-element below, same pattern as Q1-4 */
}

.lucero-stage-scene.birth-name-scene .lucero-birth-name-overlay.is-visible {
  opacity: 1;
}

.lucero-stage-scene.birth-name-scene .lucero-birth-name-overlay > * {
  pointer-events: auto;
}

/* Question style (instruction section 7): Q1-Q3's own baseline values, 1st pass -- same
   family/weight/size/line-height/color/text-shadow as Q1/Q2/Q3's questions above (not mechanically
   forced smaller the way Q4's was, since this scene has far less competing vertical content). If a
   later Human Review finds Input/CTA don't fit comfortably, the Fit Priority order in the instruction
   adjusts overlay top / gaps / Input height first -- this rule is the last lever, not the first. */
.lucero-stage-scene.birth-name-scene .lucero-birth-name-question {
  font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  font-weight: 800;
  font-size: clamp(1.4rem, 6.2vw, 1.65rem);
  line-height: 1.15;
  color: #fff9ef;
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.45);
  margin: 0;
}

/* Same fixed Editorial Line Break mechanism as Q1/Q2/Q3's own question-line spans (instruction
   section 6: never Browser Auto Wrap) -- each line is its own nowrap block, break only ever happens
   where app.js's two <span> children put it. */
.lucero-stage-scene.birth-name-scene .lucero-birth-name-question-line {
  display: block;
  white-space: nowrap;
}

/* Name input (instruction sections 9/10). Single-line text input, NOT a resize-able textarea.
   font-size fixed at 16px (not rem/clamp) -- the standard iOS Safari threshold that prevents the page
   auto-zooming when this input gets focus and the on-screen keyboard opens (same reasoning as Q4's
   textarea). Border/background/radius reuse the same translucent-panel language as Q1-4's
   options/textarea so it still reads as part of the same world, not a bare HTML form field. */
.lucero-stage-scene.birth-name-scene .lucero-birth-name-input {
  width: 100%;
  height: 54px;
  box-sizing: border-box;
  border-radius: 12px;
  border: 1px solid rgba(255, 255, 255, 0.22);
  background: rgba(23, 17, 12, 0.42);
  color: #fdf8ee;
  font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  font-weight: 500;
  font-size: 16px;
  padding: 0 15px;
  -webkit-tap-highlight-color: transparent;
  transition: border-color 0.15s ease;
}

.lucero-stage-scene.birth-name-scene .lucero-birth-name-input::placeholder {
  color: rgba(253, 248, 238, 0.45);
}

.lucero-stage-scene.birth-name-scene .lucero-birth-name-input:focus {
  outline: none;
  border-color: rgba(255, 236, 184, 0.85);
}

.lucero-stage-scene.birth-name-scene .lucero-birth-name-input:focus-visible {
  outline: 2px solid rgba(255, 236, 184, 0.95);
  outline-offset: 2px;
}

/* CTA (instruction sections 11-14) -- PROVISIONAL 1st-pass CSS button, no SVG asset yet. A single
   near-full-width Primary CTA, not a Q1-3-style option card and not an ad-banner: same warm-gold
   accent family (rgba(255,236,184,*)) and the same is-tapped/is-selected two-step settle pattern
   every other action in this file uses, so tapping it doesn't introduce a new visual idiom. */
.lucero-stage-scene.birth-name-scene .lucero-birth-name-cta {
  width: 100%;
  min-height: 48px;
  padding: 12px 16px;
  border-radius: 13px;
  border: 1px solid rgba(255, 236, 184, 0.55);
  background: rgba(255, 236, 184, 0.16);
  color: #fff9ef;
  font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  font-weight: 700;
  font-size: 0.98rem;
  line-height: 1.3;
  text-align: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  transition: background-color 0.15s ease, border-color 0.15s ease, opacity 0.15s ease;
}

/* Disabled while the input is empty/whitespace-only (instruction section 13) -- dimmed, not hidden,
   so the question -> input -> CTA reading order never shifts. */
.lucero-stage-scene.birth-name-scene .lucero-birth-name-cta:disabled {
  opacity: 0.42;
  cursor: not-allowed;
}

.lucero-stage-scene.birth-name-scene .lucero-birth-name-cta:not(:disabled):active {
  background: rgba(255, 236, 184, 0.28);
}

.lucero-stage-scene.birth-name-scene .lucero-birth-name-cta.is-tapped {
  border-color: rgba(255, 236, 184, 1);
  background: rgba(255, 236, 184, 0.32);
}

.lucero-stage-scene.birth-name-scene .lucero-birth-name-cta.is-selected {
  border-color: rgba(255, 236, 184, 0.85);
  background: rgba(255, 236, 184, 0.16);
}

.lucero-stage-scene.birth-name-scene .lucero-birth-name-cta:focus-visible {
  outline: 2px solid rgba(255, 236, 184, 0.95);
  outline-offset: 2px;
}

/* ---------------------------------------------------------------------------------------------
   Birth Gender Scene (Conversational Birth Intake round 2, 2026-09-04). Reached only via app.js's
   goToBirthGenderScene() replacing 'birth-name-scene' with 'birth-gender-scene' on the EXISTING scene
   div (never a new sceneRoot()/video) -- same 05 video, same accent-color/world language as
   Q1-Q4/Micro-payoff/Birth Name Scene above. Only Birth Name Scene's own overlay was removed by app.js
   before this class swap; `.lucero-micropayoff-image` is the SAME `<img>` DOM node Micro-payoff
   already faded in -- app.js never removes/re-creates/re-fades it. Its Visual State is owned by the
   shared rule far above (now scoped to all three scene classes), not anything in this block.

   Stage sizing: no unconditional width rule and no keyboard-open rule here -- this scene has no text
   input, so no keyboard-open Stage-width lock is needed (instruction section 13/Scope Guard). */

/* Overlay (instruction sections 7/14): same top/flex/gradient/fade-in language as Birth Name Scene's
   own overlay above, so the two screens read as one continuous conversation rather than a new visual
   idiom. No opaque full-screen panel, no white Form Card -- the character stays the Primary Visual
   Surface. */
.lucero-stage-scene.birth-gender-scene .lucero-birth-gender-overlay {
  position: absolute;
  z-index: 2;
  left: 0;
  right: 0;
  bottom: 0;
  top: 30%;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 14px;
  padding: 14px 16px calc(20px + env(safe-area-inset-bottom, 0px));
  background: linear-gradient(
    180deg,
    rgba(23, 17, 12, 0) 0%,
    rgba(23, 17, 12, 0.55) 28%,
    rgba(23, 17, 12, 0.82) 100%
  );
  opacity: 0;
  transition: opacity 200ms ease;
  pointer-events: none; /* re-enabled per-element below, same pattern as Q1-4/Birth Name Scene */
}

.lucero-stage-scene.birth-gender-scene .lucero-birth-gender-overlay.is-visible {
  opacity: 1;
}

.lucero-stage-scene.birth-gender-scene .lucero-birth-gender-overlay > * {
  pointer-events: auto;
}

/* Question style (instruction section 7): identical family/weight/size/line-height/color/text-shadow
   to Birth Name Scene's own question above -- same conversational flow, not a new visual step. */
.lucero-stage-scene.birth-gender-scene .lucero-birth-gender-question {
  font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  font-weight: 800;
  font-size: clamp(1.4rem, 6.2vw, 1.65rem);
  line-height: 1.15;
  color: #fff9ef;
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.45);
  margin: 0;
}

/* Same fixed Editorial Line Break mechanism as Q1-Q3/Birth Name Scene's own question-line spans
   (instruction section 2: never Browser Auto Wrap) -- each line is its own nowrap block, break only
   ever happens where app.js's two <span> children put it. */
.lucero-stage-scene.birth-gender-scene .lucero-birth-gender-question-line {
  display: block;
  white-space: nowrap;
}

.lucero-stage-scene.birth-gender-scene .lucero-birth-gender-options {
  display: flex;
  flex-direction: column;
  /* instruction section 8, 1st-pass recommendation: ~14px, a little more breathing room than Q1-Q3's
     9px gap since this is real Birth Data, not a relationship quiz -- reduces mis-tap risk between
     the two options without introducing a new visual idiom. */
  gap: 14px;
}

/* Choice buttons (instruction section 8): same visual language as Q1-Q3's own options (Pretendard,
   translucent panel, warm-gold is-tapped/is-selected), sized a little larger/roomier than Q1-Q3's
   (min-height 52px vs Q1's 46px) because this value is real Birth Data -- reduces mis-tap risk given
   no Back Button exists yet (instruction section 15). No new Hue -- background/border reuse the same
   rgba(23,17,12,*) / rgba(255,255,255,0.22) / warm-gold rgba(255,236,184,*) families already
   established by Q1-Q4/Birth Name Scene above. */
.lucero-stage-scene.birth-gender-scene .lucero-birth-gender-option {
  min-height: 52px;
  padding: 13px 16px;
  border-radius: 13px;
  border: 1px solid rgba(255, 255, 255, 0.22);
  background: rgba(23, 17, 12, 0.42);
  color: #fdf8ee;
  font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  font-weight: 600;
  font-size: 0.98rem;
  line-height: 1.3;
  text-align: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  transition: background-color 0.15s ease, border-color 0.15s ease;
}

.lucero-stage-scene.birth-gender-scene .lucero-birth-gender-option:active {
  background: rgba(23, 17, 12, 0.6);
}

/* Tap flash / selected state -- same warm gold as Q1-Q3's options and Birth Name Scene's CTA above,
   same is-tapped(strong, ~250ms) -> is-selected(quieter, persistent) two-step settle. */
.lucero-stage-scene.birth-gender-scene .lucero-birth-gender-option.is-tapped {
  border-color: rgba(255, 236, 184, 1);
  background: rgba(255, 236, 184, 0.32);
}

.lucero-stage-scene.birth-gender-scene .lucero-birth-gender-option.is-selected {
  border-color: rgba(255, 236, 184, 0.85);
  background: rgba(255, 236, 184, 0.16);
}

.lucero-stage-scene.birth-gender-scene .lucero-birth-gender-option:focus-visible {
  outline: 2px solid rgba(255, 236, 184, 0.95);
  outline-offset: 2px;
}

/* ---------------------------------------------------------------------------------------------
   Birth Date Scene (Conversational Birth Intake round 3, 2026-09-05). Reached only via app.js's
   goToBirthDateScene() replacing 'birth-gender-scene' with 'birth-date-scene' on the EXISTING scene
   div (never a new sceneRoot()/video) -- same 05 video, same accent-color/world language as every
   prior Birth Intake scene. Only Birth Gender Scene's own overlay was removed by app.js before this
   class swap; `.lucero-micropayoff-image` is the SAME `<img>` DOM node kept alive by the shared rule
   far above (now scoped to all five scene classes), not anything in this block.

   Stage sizing: no unconditional width rule here, same reasoning as Birth Name above -- only the
   birth-date-keyboard-open rule immediately below ever overrides it, and only once app.js confirms a
   real keyboard-open across any of the three date inputs. */
.lucero-stage-scene.birth-date-scene.birth-date-keyboard-open .stage {
  width: var(--birth-date-keyboard-stage-width, 100%);
}

/* Overlay (instruction section 29): same top/flex/gradient/fade-in LANGUAGE as every prior Birth
   Intake overlay, so this scene reads as a continuation of the same conversation, not a new visual
   idiom -- but `top` starts noticeably higher (20% vs Birth Name/Gender's 30%) because this scene has
   more controls stacked below the question (Calendar Type + 3 date inputs + conditional 윤달 + CTA).
   Per the instruction's Fit Priority order, `top`/gaps/control-heights are the levers used to make
   room -- the question's own font-size is never reduced to fit. No opaque full-screen panel, no white
   Form Card -- the character stays the Primary Visual Surface. */
.lucero-stage-scene.birth-date-scene .lucero-birth-date-overlay {
  position: absolute;
  z-index: 2;
  left: 0;
  right: 0;
  bottom: 0;
  top: 20%;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 12px;
  padding: 14px 16px calc(20px + env(safe-area-inset-bottom, 0px));
  background: linear-gradient(
    180deg,
    rgba(23, 17, 12, 0) 0%,
    rgba(23, 17, 12, 0.55) 22%,
    rgba(23, 17, 12, 0.86) 100%
  );
  opacity: 0;
  transition: opacity 200ms ease;
  pointer-events: none; /* re-enabled per-element below, same pattern as every prior scene */
}

.lucero-stage-scene.birth-date-scene .lucero-birth-date-overlay.is-visible {
  opacity: 1;
}

.lucero-stage-scene.birth-date-scene .lucero-birth-date-overlay > * {
  pointer-events: auto;
}

/* Question style (instruction section 29): identical family/weight/size/line-height/color/text-shadow
   to every prior Birth Intake question -- same conversational flow, not a new visual step. */
.lucero-stage-scene.birth-date-scene .lucero-birth-date-question {
  font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  font-weight: 800;
  font-size: clamp(1.4rem, 6.2vw, 1.65rem);
  line-height: 1.15;
  color: #fff9ef;
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.45);
  margin: 0;
}

.lucero-stage-scene.birth-date-scene .lucero-birth-date-question-line {
  display: block;
  white-space: nowrap;
}

/* Calendar Type selector (instruction sections 6/30): 2-column equal-width pressable buttons, same
   visual language as Birth Gender's own options (translucent panel, warm-gold is-selected,
   aria-pressed) -- NOT a Scene-Transition Choice-as-CTA, so there is no is-tapped flash step here,
   only a persistent is-selected once tapped (toggling between the two, never both). */
/* Progressive Reveal (Birth Date/Time UX round, 2026-09-05): starts at opacity:0 and only gains
   `.is-revealed` once app.js removes the `hidden` attribute AND the next animation frame runs (same
   rAF-then-class mechanism as this overlay's own is-visible entrance) -- ~200ms opacity-only fade,
   no scale/glow/slide. `[hidden]` itself still fully removes it from layout/accessibility tree
   before that point; no CSS override of the `hidden` attribute's default `display: none` is added
   here. */
.lucero-stage-scene.birth-date-scene .lucero-birth-date-calendar-group {
  display: flex;
  flex-direction: row;
  gap: 10px;
  opacity: 0;
  transition: opacity 200ms ease;
}

.lucero-stage-scene.birth-date-scene .lucero-birth-date-calendar-group.is-revealed {
  opacity: 1;
}

.lucero-stage-scene.birth-date-scene .lucero-birth-date-calendar-option {
  flex: 1 1 0;
  min-height: 46px;
  padding: 11px 12px;
  border-radius: 13px;
  border: 1px solid rgba(255, 255, 255, 0.22);
  background: rgba(23, 17, 12, 0.42);
  color: #fdf8ee;
  font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  font-weight: 600;
  font-size: 0.95rem;
  line-height: 1.3;
  text-align: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  transition: background-color 0.15s ease, border-color 0.15s ease;
}

.lucero-stage-scene.birth-date-scene .lucero-birth-date-calendar-option:active {
  background: rgba(23, 17, 12, 0.6);
}

.lucero-stage-scene.birth-date-scene .lucero-birth-date-calendar-option.is-selected {
  border-color: rgba(255, 236, 184, 0.85);
  background: rgba(255, 236, 184, 0.16);
}

.lucero-stage-scene.birth-date-scene .lucero-birth-date-calendar-option:focus-visible {
  outline: 2px solid rgba(255, 236, 184, 0.95);
  outline-offset: 2px;
}

/* Date input row (instruction sections 8/30): 3 equal-width inputs, same translucent-panel visual
   family as Birth Name's own input above (border/background/radius/font all reused) -- only the width
   is divided three ways here since there are three fields, not one. font-size fixed at 16px, same
   iOS-Safari-auto-zoom-prevention reasoning as Birth Name's input. */
.lucero-stage-scene.birth-date-scene .lucero-birth-date-input-row {
  display: flex;
  flex-direction: row;
  gap: 8px;
}

.lucero-stage-scene.birth-date-scene .lucero-birth-date-input {
  flex: 1 1 0;
  min-width: 0; /* allow equal shrinking in a 3-up row on the narrowest viewports */
  height: 50px;
  box-sizing: border-box;
  border-radius: 12px;
  border: 1px solid rgba(255, 255, 255, 0.22);
  background: rgba(23, 17, 12, 0.42);
  color: #fdf8ee;
  font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  font-weight: 500;
  font-size: 16px;
  text-align: center;
  padding: 0 6px;
  -webkit-tap-highlight-color: transparent;
  transition: border-color 0.15s ease;
}

.lucero-stage-scene.birth-date-scene .lucero-birth-date-input::placeholder {
  color: rgba(253, 248, 238, 0.45);
}

.lucero-stage-scene.birth-date-scene .lucero-birth-date-input:focus {
  outline: none;
  border-color: rgba(255, 236, 184, 0.85);
}

.lucero-stage-scene.birth-date-scene .lucero-birth-date-input:focus-visible {
  outline: 2px solid rgba(255, 236, 184, 0.95);
  outline-offset: 2px;
}

.lucero-stage-scene.birth-date-scene .lucero-birth-date-input:disabled {
  opacity: 0.65;
}

/* 윤달 control (instruction sections 7/30): full-width secondary pressable choice control, same
   warm-gold is-selected language as every option above -- hidden entirely (`[hidden]`) unless 음력 is
   the current Calendar Type selection (app.js toggles the `hidden` DOM property, not this rule). */
.lucero-stage-scene.birth-date-scene .lucero-birth-date-leap-month {
  width: 100%;
  min-height: 46px;
  padding: 11px 16px;
  border-radius: 13px;
  border: 1px solid rgba(255, 255, 255, 0.22);
  background: rgba(23, 17, 12, 0.42);
  color: #fdf8ee;
  font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  font-weight: 600;
  font-size: 0.92rem;
  line-height: 1.3;
  text-align: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  transition: background-color 0.15s ease, border-color 0.15s ease;
}

.lucero-stage-scene.birth-date-scene .lucero-birth-date-leap-month:active {
  background: rgba(23, 17, 12, 0.6);
}

.lucero-stage-scene.birth-date-scene .lucero-birth-date-leap-month.is-selected {
  border-color: rgba(255, 236, 184, 0.85);
  background: rgba(255, 236, 184, 0.16);
}

.lucero-stage-scene.birth-date-scene .lucero-birth-date-leap-month:focus-visible {
  outline: 2px solid rgba(255, 236, 184, 0.95);
  outline-offset: 2px;
}

/* CTA (instruction sections 13/30): identical visual language to Birth Name's own CTA -- same
   near-full-width Primary CTA, same warm-gold is-tapped/is-selected two-step settle. */
.lucero-stage-scene.birth-date-scene .lucero-birth-date-cta {
  width: 100%;
  min-height: 48px;
  padding: 12px 16px;
  border-radius: 13px;
  border: 1px solid rgba(255, 236, 184, 0.55);
  background: rgba(255, 236, 184, 0.16);
  color: #fff9ef;
  font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  font-weight: 700;
  font-size: 0.98rem;
  line-height: 1.3;
  text-align: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  transition: background-color 0.15s ease, border-color 0.15s ease, opacity 0.15s ease;
}

.lucero-stage-scene.birth-date-scene .lucero-birth-date-cta:disabled {
  opacity: 0.42;
  cursor: not-allowed;
}

.lucero-stage-scene.birth-date-scene .lucero-birth-date-cta:not(:disabled):active {
  background: rgba(255, 236, 184, 0.28);
}

.lucero-stage-scene.birth-date-scene .lucero-birth-date-cta.is-tapped {
  border-color: rgba(255, 236, 184, 1);
  background: rgba(255, 236, 184, 0.32);
}

.lucero-stage-scene.birth-date-scene .lucero-birth-date-cta.is-selected {
  border-color: rgba(255, 236, 184, 0.85);
  background: rgba(255, 236, 184, 0.16);
}

.lucero-stage-scene.birth-date-scene .lucero-birth-date-cta:focus-visible {
  outline: 2px solid rgba(255, 236, 184, 0.95);
  outline-offset: 2px;
}

/* ---------------------------------------------------------------------------------------------
   Birth Time Scene (Conversational Birth Intake round 3, 2026-09-05). Reached only via app.js's
   goToBirthTimeScene() replacing 'birth-date-scene' with 'birth-time-scene' on the EXISTING scene div
   (never a new sceneRoot()/video) -- same 05 video, same accent-color/world language as every prior
   Birth Intake scene. Only Birth Date Scene's own overlay was removed by app.js before this class
   swap; `.lucero-micropayoff-image` is the SAME `<img>` DOM node kept alive by the shared rule far
   above (now scoped to all five scene classes), not anything in this block.

   This scene has fewer stacked elements than Birth Date (instruction section 31: "Birth Date보다
   element 수가 적다고 해서 새로운 디자인을 만들지 않는다"), so `top` sits between Birth Date's 20% and
   Birth Name/Gender's 30% rather than introducing a third distinct layout language. */
.lucero-stage-scene.birth-time-scene.birth-time-keyboard-open .stage {
  width: var(--birth-time-keyboard-stage-width, 100%);
}

.lucero-stage-scene.birth-time-scene .lucero-birth-time-overlay {
  position: absolute;
  z-index: 2;
  left: 0;
  right: 0;
  bottom: 0;
  top: 26%;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 14px;
  padding: 14px 16px calc(20px + env(safe-area-inset-bottom, 0px));
  background: linear-gradient(
    180deg,
    rgba(23, 17, 12, 0) 0%,
    rgba(23, 17, 12, 0.55) 26%,
    rgba(23, 17, 12, 0.84) 100%
  );
  opacity: 0;
  transition: opacity 200ms ease;
  pointer-events: none;
}

.lucero-stage-scene.birth-time-scene .lucero-birth-time-overlay.is-visible {
  opacity: 1;
}

.lucero-stage-scene.birth-time-scene .lucero-birth-time-overlay > * {
  pointer-events: auto;
}

.lucero-stage-scene.birth-time-scene .lucero-birth-time-question {
  font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  font-weight: 800;
  font-size: clamp(1.4rem, 6.2vw, 1.65rem);
  line-height: 1.15;
  color: #fff9ef;
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.45);
  margin: 0;
}

.lucero-stage-scene.birth-time-scene .lucero-birth-time-question-line {
  display: block;
  white-space: nowrap;
}

/* AM/PM selector (Birth Date/Time UX round, 2026-09-05): 2-column equal-width pressable buttons,
   identical visual language to Birth Date's own Calendar Type options -- translucent panel, warm-gold
   is-selected, aria-pressed, no is-tapped flash step (not a Scene-Transition Choice-as-CTA). */
.lucero-stage-scene.birth-time-scene .lucero-birth-time-ampm-group {
  display: flex;
  flex-direction: row;
  gap: 10px;
}

.lucero-stage-scene.birth-time-scene .lucero-birth-time-ampm-option {
  flex: 1 1 0;
  min-height: 46px;
  padding: 11px 12px;
  border-radius: 13px;
  border: 1px solid rgba(255, 255, 255, 0.22);
  background: rgba(23, 17, 12, 0.42);
  color: #fdf8ee;
  font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  font-weight: 600;
  font-size: 0.95rem;
  line-height: 1.3;
  text-align: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  transition: background-color 0.15s ease, border-color 0.15s ease;
}

.lucero-stage-scene.birth-time-scene .lucero-birth-time-ampm-option:active {
  background: rgba(23, 17, 12, 0.6);
}

.lucero-stage-scene.birth-time-scene .lucero-birth-time-ampm-option.is-selected {
  border-color: rgba(255, 236, 184, 0.85);
  background: rgba(255, 236, 184, 0.16);
}

.lucero-stage-scene.birth-time-scene .lucero-birth-time-ampm-option:focus-visible {
  outline: 2px solid rgba(255, 236, 184, 0.95);
  outline-offset: 2px;
}

/* Disabled visual state (Birth Time Targeted Fix round, 2026-09-05, section 7): only reached while
   "태어난 시간을 몰라요" is selected. Same weak-disabled treatment as this file's own numeric-input
   disabled rule above (opacity-only, no new color/design language) so 오전/오후 reads as clearly
   inactive rather than a normal pressable button. Deselecting Unknown removes `disabled` and this
   rule stops applying -- the buttons return to their exact original appearance, nothing to reset. */
.lucero-stage-scene.birth-time-scene .lucero-birth-time-ampm-option:disabled {
  opacity: 0.55;
  cursor: default;
}

/* Time input row (instruction sections 16/31): 2-column equal-width inputs, same translucent-panel
   family as Birth Date's own date inputs (this file's shared numeric-input visual language), now with
   a purely-visual colon between them. */
.lucero-stage-scene.birth-time-scene .lucero-birth-time-input-row {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 10px;
}

/* Visual colon (instruction section 18): non-interactive (`aria-hidden`), matches the Birth Input
   typography family used by the two inputs it sits between. */
.lucero-stage-scene.birth-time-scene .lucero-birth-time-colon {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fdf8ee;
  font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  font-weight: 600;
  font-size: 18px;
  line-height: 1;
  user-select: none;
}

.lucero-stage-scene.birth-time-scene .lucero-birth-time-input {
  flex: 1 1 0;
  min-width: 0;
  height: 50px;
  box-sizing: border-box;
  border-radius: 12px;
  border: 1px solid rgba(255, 255, 255, 0.22);
  background: rgba(23, 17, 12, 0.42);
  color: #fdf8ee;
  font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  font-weight: 500;
  font-size: 16px;
  text-align: center;
  padding: 0 6px;
  -webkit-tap-highlight-color: transparent;
  transition: border-color 0.15s ease;
}

.lucero-stage-scene.birth-time-scene .lucero-birth-time-input::placeholder {
  color: rgba(253, 248, 238, 0.45);
}

.lucero-stage-scene.birth-time-scene .lucero-birth-time-input:focus {
  outline: none;
  border-color: rgba(255, 236, 184, 0.85);
}

.lucero-stage-scene.birth-time-scene .lucero-birth-time-input:focus-visible {
  outline: 2px solid rgba(255, 236, 184, 0.95);
  outline-offset: 2px;
}

.lucero-stage-scene.birth-time-scene .lucero-birth-time-input:disabled {
  opacity: 0.65;
}

/* "태어난 시간을 몰라요" (instruction sections 19/31): full-width secondary pressable choice control,
   same warm-gold is-selected language as Birth Date's 윤달 control. */
.lucero-stage-scene.birth-time-scene .lucero-birth-time-unknown {
  width: 100%;
  min-height: 46px;
  padding: 11px 16px;
  border-radius: 13px;
  border: 1px solid rgba(255, 255, 255, 0.22);
  background: rgba(23, 17, 12, 0.42);
  color: #fdf8ee;
  font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  font-weight: 600;
  font-size: 0.92rem;
  line-height: 1.3;
  text-align: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  transition: background-color 0.15s ease, border-color 0.15s ease;
}

.lucero-stage-scene.birth-time-scene .lucero-birth-time-unknown:active {
  background: rgba(23, 17, 12, 0.6);
}

.lucero-stage-scene.birth-time-scene .lucero-birth-time-unknown.is-selected {
  border-color: rgba(255, 236, 184, 0.85);
  background: rgba(255, 236, 184, 0.16);
}

.lucero-stage-scene.birth-time-scene .lucero-birth-time-unknown:focus-visible {
  outline: 2px solid rgba(255, 236, 184, 0.95);
  outline-offset: 2px;
}

/* CTA (instruction section 21/31): identical visual language to every prior Birth Intake CTA. */
.lucero-stage-scene.birth-time-scene .lucero-birth-time-cta {
  width: 100%;
  min-height: 48px;
  padding: 12px 16px;
  border-radius: 13px;
  border: 1px solid rgba(255, 236, 184, 0.55);
  background: rgba(255, 236, 184, 0.16);
  color: #fff9ef;
  font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  font-weight: 700;
  font-size: 0.98rem;
  line-height: 1.3;
  text-align: center;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  transition: background-color 0.15s ease, border-color 0.15s ease, opacity 0.15s ease;
}

.lucero-stage-scene.birth-time-scene .lucero-birth-time-cta:disabled {
  opacity: 0.42;
  cursor: not-allowed;
}

.lucero-stage-scene.birth-time-scene .lucero-birth-time-cta:not(:disabled):active {
  background: rgba(255, 236, 184, 0.28);
}

.lucero-stage-scene.birth-time-scene .lucero-birth-time-cta.is-tapped {
  border-color: rgba(255, 236, 184, 1);
  background: rgba(255, 236, 184, 0.32);
}

.lucero-stage-scene.birth-time-scene .lucero-birth-time-cta.is-selected {
  border-color: rgba(255, 236, 184, 0.85);
  background: rgba(255, 236, 184, 0.16);
}

.lucero-stage-scene.birth-time-scene .lucero-birth-time-cta:focus-visible {
  outline: 2px solid rgba(255, 236, 184, 0.95);
  outline-offset: 2px;
}

/* ------------------------------------------------------------------------------------------
   PG Review Build A -- Paywall (paywall-scene). Product name / price / product-nature notice /
   5-item Paid Result Promise list / CTA. Functional UI text (Brand Bible Section 13) follows
   the same Pretendard functional-typeface stack already used by Q1-Q4 above; no new color
   tokens -- reuses the existing --accent/--border/--ink/--ink-soft system for everything OUTSIDE
   .paywall-card. Inside .paywall-card is the one exception: that card's own background is a
   fixed light gradient (#efe6ff -> #fbeff7, pre-existing, unchanged here) that does NOT flip
   with --surface/--ink in Dark Mode -- the same way .qa-panel below already uses fixed literal
   colors rather than the --ink variables for that reason. Product name/price/notice reuse that
   same fixed-literal-color pattern (this round's Chromium/dark-mode QA screenshot caught --ink
   going near-white-on-near-white here) so the price stays legible in both Light and Dark. */
.paywall-product {
  font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  font-size: 1rem;
  font-weight: 600;
  color: #635c6e;
}

.paywall-price {
  font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  font-size: 1.65rem;
  font-weight: 800;
  color: #241f2e;
}

/* Compound selector (rather than a bare .paywall-product-notice class) is required here, not
   stylistic: this element is a <p>, and the pre-existing global ".scene p { color: var(--ink-soft);
   font-size: 0.95rem; line-height: 1.6; margin: 0; }" rule (specificity 0,1,1) otherwise outranks
   a single-class rule (0,1,0) and silently wins the cascade -- in Dark Mode that resolved to
   --ink-soft's dark-surface value (#b3aac2, light text) sitting on this card's own background,
   which is a fixed LIGHT gradient in both themes, producing very low contrast. Scoping under
   .paywall-card (0,2,0) beats .scene p's specificity so this rule's own color/size/line-height/
   margin actually apply. Color reuses this same card's existing --ink literal (#241f2e, already
   used by .paywall-price above) instead of the lighter --ink-soft tone, because this notice is
   required information for a PG reviewer, not decorative secondary copy -- it must read at the
   same clarity as the product name/price in both Light and Dark Mode. No new color introduced. */
.paywall-card .paywall-product-notice {
  font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  font-size: 0.85rem;
  line-height: 1.55;
  color: #241f2e;
  margin: 2px 0 0;
}

.paywall-promise-lead {
  font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  font-size: 0.92rem;
  font-weight: 700;
  color: var(--ink);
  margin-top: 2px;
}

.paywall-promise-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.paywall-promise-item {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 12px 14px;
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--surface);
}

.paywall-promise-num {
  font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  font-size: 0.85rem;
  font-weight: 700;
  color: var(--accent);
  min-width: 22px;
  flex-shrink: 0;
}

.paywall-promise-text {
  font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
  font-size: 0.95rem;
  line-height: 1.5;
  color: var(--ink);
}

/* CTA (spec section 6/10): scoped to .paywall-scene only -- does not touch the shared
   .primary-btn class used by every other scene's CTA. */
.paywall-scene .primary-btn {
  font-family: 'Pretendard', -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #17131f;
    --surface: #221c2e;
    --ink: #f1edf9;
    --ink-soft: #b3aac2;
    --border: #34293f;
    --danger-bg: #3a1f22;
    --danger-ink: #ff9d9d;
    --warn-bg: #3a2f13;
    --warn-ink: #ffd479;
    --notice-bg: #2b2340;
    --notice-ink: #d8caff;
  }
}

/* -------------------------------------------------------------------------------------------
   Round 8 -- PG Legal Surface: site-wide Footer, Paywall Pre-checkout Notice, standalone
   /terms /privacy /refund pages. All colors reuse the existing --bg/--ink/--border tokens above,
   so dark mode is automatic -- nothing here is redefined inside the dark-mode block.
   ------------------------------------------------------------------------------------------- */

.site-footer {
  width: 100%;
  max-width: 480px;
  margin: 0 auto;
  padding: 18px 20px 32px;
  font-size: 0.74rem;
  line-height: 1.7;
  color: var(--ink-soft);
  border-top: 1px solid var(--border);
}

.site-footer-links {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 12px;
  margin-bottom: 8px;
}

.site-footer-links a {
  color: var(--ink-soft);
  text-decoration: underline;
}

.site-footer-biz {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.site-footer-biz a {
  color: var(--ink-soft);
  align-self: flex-start;
}

.site-footer-biz-pending {
  color: var(--ink-soft);
}

/* Pre-checkout Notice (spec section 7): summary only -- full text lives on /terms /privacy /refund. */
.precheckout-notice {
  padding: 12px 14px;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--bg);
  font-size: 0.76rem;
  line-height: 1.6;
  color: var(--ink-soft);
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.precheckout-notice p { margin: 0; }

.precheckout-notice-links {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 10px;
}

.precheckout-notice-links a {
  color: var(--accent);
}

/* Standalone /terms /privacy /refund pages -- plain, readable document layout, distinct from the
   immersive product scenes (spec section 3/4/5: simple document-type screen, doesn't compete with
   the product's own visual design). */
.policy-scene { gap: 14px; }

.policy-back-link {
  align-self: flex-start;
  color: var(--accent);
  font-size: 0.88rem;
  text-decoration: underline;
}

.policy-section h2 { margin-top: 6px; }

.policy-section p {
  font-size: 0.9rem;
  line-height: 1.7;
  color: var(--ink);
  margin: 0 0 8px;
}

.policy-pending-note {
  font-size: 0.8rem;
  color: var(--ink-soft);
  font-style: italic;
  padding-top: 10px;
  border-top: 1px dashed var(--border);
}
