/* User 2026-05-18: Lumi + dreamer text → Play. Import the webfont here
   so 'Play' resolves wherever this stylesheet loads — the site (which
   also supplies --font-play via next/font) and the porthole standalone. */
@import url('https://fonts.googleapis.com/css2?family=Barlow:wght@400;600;700;800&family=Play:wght@400;700&family=Plus+Jakarta+Sans:wght@600;700;800&display=swap');

:root {
  --stage-w: 1440;
  --stage-h: 1058;
  --design-scale: 0.8333333333;
  --scale: 1;
  --bg-a: #1a1534;
  --bg-b: #2d2557;
  --cyan: #85d5e6;
  --pink: #f486e5;
  --cream: #fcf38f;
  --text: #f4f4f6;
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  min-height: 100%;
  background: var(--bg-a);
  color: var(--text);
  font-family: "Plus Jakarta Sans", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}

body {
  overflow-x: hidden;
  overflow-y: auto;
}

button {
  font: inherit;
}

.viewport-shell {
  min-height: 100vh;
  width: 100vw;
  display: flex;
  justify-content: center;
  align-items: flex-start;
  background: linear-gradient(144deg, #1a1534 0%, #2d2557 50%, #1a1534 100%);
}

.scale-host {
  width: min(100vw, 1440px);
  height: calc(1058px * var(--scale));
  position: relative;
  overflow: hidden;
}

.figma-stage {
  position: absolute;
  left: 0;
  top: 0;
  width: 1728px;
  height: 1269px;
  transform: scale(calc(var(--scale) * var(--design-scale)));
  transform-origin: top left;
  overflow: hidden;
  background:
    radial-gradient(390px 255px at 50% 55%, rgba(252, 243, 143, 0.19), rgba(244, 174, 245, 0.16) 50%, transparent 78%),
    linear-gradient(144deg, #1a1534 0%, #2d2557 50%, #1a1534 100%);
  /* User 2026-05-15: "Lumi text / dreamer avatar looks pixelated".
     Force high-quality text + image rendering on the entire scaled
     stage so non-integer transform doesn't cause nearest-neighbor
     blurring. backface-visibility:hidden promotes to a GPU layer
     (smoother sub-pixel resampling). */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: geometricPrecision;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}

/* User 2026-05-16: "I need nice transitions between floors, right now
   it's like a jump cut." When the React phase flips data-screen
   (F0→F1→F2→F2.1) the layout swaps instantly. F0.tsx re-triggers this
   animation on every screen change so the new floor settles in with a
   soft fade instead of a hard cut. opacity-only — the stage's
   transform carries the scale and must not be touched by the anim. */
@keyframes floor-cross-fade {
  0%   { opacity: 0.15; }
  100% { opacity: 1; }
}
/* All images inside the stage (dreamer avatar, agent avatars, Lumi
   orb, monday/Gemini/Grok/Claude logos, adventure logo) — use high-
   quality bicubic resampling instead of nearest-neighbor. */
.figma-stage img {
  image-rendering: -webkit-optimize-contrast;
  image-rendering: high-quality;
}

.glow-main {
  position: absolute;
  left: 686px;
  top: 472px;
  width: 422px;
  height: 270px;
  border-radius: 9999px;
  opacity: 0.92;
  filter: blur(64px);
  background: linear-gradient(123deg, rgba(252, 243, 143, 0.3), rgba(244, 174, 245, 0.2) 50%, transparent);
}

.title {
  /* User 2026-05-15: "make the adventure text 1.5 bigger" → 40 → 60.
     line-height tightened from 96 → 1 so the line-box equals the
     visible glyph height (no excess leading), so the Adventure
     text occupies y=13→~73 instead of y=13→109. This frees space
     above the agents while keeping the visible text bigger. */
  position: absolute;
  left: 0;
  width: 1728px;
  margin: 0;
  text-align: center;
  font-weight: 800;
  font-size: 60px;
  line-height: 1;
  letter-spacing: 0;
}

.title-top {
  /* User 2026-05-15: "less padding between top adventure section and
     logo" → 13 → 4. Then "more padding between bottom hero to agents
     above the agents, more 8px. so agents sections and logo goes down
     8" → 4 → 12. */
  top: 12px;
  left: 50%;
  width: max-content;
  transform: translateX(-50%);
  color: rgba(0, 0, 0, 0);
  background-image: linear-gradient(
    90deg,
    #85d5e6 0%,
    #accbea 14%,
    #ccb1ef 29%,
    #f4aef5 50%,
    #f7ced0 71%,
    #fae1b3 86%,
    #fcf38f 100%
  );
  background-clip: text;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  filter: drop-shadow(0 0 20px rgba(255, 255, 255, 0.3));
}

.title-bottom {
  /* User 2026-05-15: "remove the dream team text" + "remove also this
     line for f1 — business and strategy, and for F2 — branding". The
     bottom title is now hidden on all floors. ::before content rules
     for F1/F2 below still set `content:` but the parent is hidden so
     nothing renders. */
  display: none;
}
/* Belt-and-suspenders: the F1/F2 ::before content also gets 800
   (was overriding to 600 earlier). */
.figma-stage[data-screen]:not([data-screen="F0"]) .title-bottom::before {
  font-weight: 800;
}
/* Belt-and-suspenders: the F1/F2 floor-specific ::before pseudo holds
   the text via `content:`. Pseudos inherit font-weight from the
   element, but some browsers serialize the rule cascade weirdly when
   the parent also has background-clip: text. Pin 600 on the pseudo too. */
.figma-stage[data-screen]:not([data-screen="F0"]) .title-bottom::before {
  font-weight: 600;
}

.team {
  /* User 2026-05-15: "move 2 agents to the right of the logo and two
     agents two the left then move all element below upwards, with 48
     px padding from top row" — agents share the top row with the logo
     at top: 4. Then "more padding between bottom hero to agents above
     the agents, more 8px. so agents sections and logo goes down 8"
     → 4 → 12. Top-row bottom now at 12 + 157 = 169; panels stay at
     top 209 (40 px gap). F1/F2 keep their own .member-monday top:164
     override via the non-F0 cascade below. */
  position: absolute;
  top: 12px;
  width: 150px;
  height: 156px;
  text-align: center;
  color: #edecf0;
  font-weight: 800;
}

/* Figma F0 team avatar absolute x positions (avatar = team-left + 39):
   monday=548, Gemini=745, Grok=925, Claude=1105. */
/* User 2026-05-15: "move two agents to the right of the logo and two
   agents to the left" — 2 agents on each side of the logo (logo
   centered at stage x=832, visible x=599-1065). Avatar centers
   symmetric around logo: 175, 435 | 1229, 1489 (gaps 260, 397, 397, 260). */
/* User 2026-05-18: swapped monday ↔ Gemini on F0 — Gemini now sits on
   the far left, monday next to it. (F1/F2 keep their own overrides.) */
.member-gemini { left: 100px; }
.member-monday { left: 360px; }
.member-grok { left: 1154px; }
.member-claude { left: 1414px; }

.team-name,
.team-role {
  /* Shared positioning + size — font-family differs per element below
     (user 2026-05-15: "match only font style for names and roles" —
     names stay sans, roles switch to serif). */
  position: absolute;
  left: -54px;
  width: 259px;
  font-size: 20px;
  line-height: 25px;
}

.team-name {
  top: 0;
  height: 63px;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Sans-serif name — matches Figma agent label */
  /* User 2026-05-18: agent names → Plus Jakarta Sans. */
  font-family: var(--font-plus-jakarta), "Plus Jakarta Sans", system-ui, sans-serif;
  font-weight: 800;
}

.team-role {
  top: 132px;
  /* User 2026-05-15: serif font for roles. Bumped weight 500 → 700
     ("make roles more bold"). */
  /* User 2026-05-18: agent roles → Plus Jakarta Sans. */
  font-family: var(--font-plus-jakarta), "Plus Jakarta Sans", system-ui, sans-serif;
  font-weight: 700;
}

.team-avatar {
  position: absolute;
  left: 39px;
  top: 51px;
  width: 73px;
  height: 72px;
  border-radius: 999px;
  display: grid;
  place-items: center;
  /* User 2026-05-17: neumorphic surface — soft light gradient. The
     per-agent coloured glow (below) stays as the outer halo; the
     inset highlight/shadow on each glow rule adds the extruded depth. */
  background: linear-gradient(145deg, #ffffff, #e6e6ee);
  overflow: hidden;
}

.team-avatar img {
  width: 48px;
  height: 48px;
  display: block;
  object-fit: contain;
}

.panel {
  /* User 2026-05-15: agents in row with logo. Panels shifted up
     cumulative −14 → 195. F1/F2 panels stay at 282 via non-F0
     override below.
     User 2026-05-17: neumorphism — soft-extruded translucent surface,
     borderless. Outer light/dark shadows lift it off the stage; the
     inset highlight/shadow give the soft-plastic curvature. */
  position: absolute;
  top: 195px;
  width: 362px;
  height: 670px;
  border-radius: 20px;
  background: linear-gradient(150deg, rgba(255, 255, 255, 0.06), rgba(255, 255, 255, 0.015));
  box-shadow:
    -8px -8px 20px rgba(255, 255, 255, 0.045),
    12px 12px 30px rgba(0, 0, 0, 0.55),
    inset 2px 2px 5px rgba(255, 255, 255, 0.10),
    inset -3px -3px 8px rgba(0, 0, 0, 0.32);
  overflow: hidden;
}

.status-panel { left: 64px; }
.inputs-panel { left: 1302px; }

.panel-head {
  position: absolute;
  left: -2px;
  top: 0;
  width: 362px;
  height: 48px;
  display: grid;
  place-items: center;
  border-bottom: 1px solid rgba(255, 255, 255, 0.2);
  color: rgba(255, 255, 255, 0.95);
  /* User 2026-05-18: panel headers (Status / Outputs) → Barlow. */
  font-family: var(--font-barlow), "Barlow", system-ui, sans-serif;
  font-size: 20px;
  font-weight: 800;
  line-height: 30px;
}

.status-head {
  background: linear-gradient(90deg, rgba(133, 213, 230, 0.4), rgba(133, 213, 230, 0.3), rgba(133, 213, 230, 0.4));
}

.inputs-head {
  background: linear-gradient(90deg, rgba(248, 134, 229, 0.4), rgba(248, 134, 229, 0.3), rgba(248, 134, 229, 0.4));
}

.status-row {
  position: absolute;
  left: 15px;
  width: 331px;
  height: 64px;
  display: flex;
  align-items: center;
  padding: 0 13px;
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.05);
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
  /* User 2026-05-18: status-row text (Active, Floor, Vision Score,
     Venture ID) → Barlow, 18px (+2px). status-label/value inherit. */
  font-family: var(--font-barlow), "Barlow", system-ui, sans-serif;
  font-size: 18px;
  font-weight: 600;
  line-height: 24px;
}

.active-row {
  top: 80px;
  justify-content: space-between;
}

/* Status panel rows: Active, Floor, Vision Score, Venture ID.
   User 2026-05-18: the Floor pill was inserted between Active and
   Vision Score, so score-row + id-row shift down one 88px stride. */
.floor-row { top: 168px; }
.score-row { top: 256px; }
.id-row { top: 344px; }

/* MVP progress strip — restored 2026-05-18 (user). Lives in the Status
   panel on every floor F0→Roof; the fill reflects REAL pipeline
   progress (intake → F1 → F2 → build → roof), driven inline by React. */
.status-mvp {
  position: absolute;
  left: 15px;
  width: 331px;
  /* User 2026-05-18: pinned to the panel bottom with the same 32px gap
     as the Status header → Active row (panel-head 48px → active-row 80). */
  bottom: 32px;
}
.status-mvp-label {
  margin: 0 0 10px;
  text-align: center;
  font-size: 16px;
  font-weight: 600;
  color: rgba(255, 255, 255, 0.95);
}
.status-mvp-frame {
  /* Figma F3 node 3:83/3:84 — the FRAME around the bar: a 64-tall
     rounded-20 box, translucent cyan→pink→cream gradient (0.2), 2px
     white-0.3 border, soft drop-shadow. Flex-centres the bar inside
     (Figma 3:84 padding 20px 0). */
  height: 64px;
  box-sizing: border-box;
  padding: 0 19px;
  display: flex;
  align-items: center;
  border-radius: 20px;
  background: linear-gradient(
    90deg,
    rgba(133, 213, 230, 0.2) 0%,
    rgba(244, 174, 245, 0.2) 50%,
    rgba(252, 243, 143, 0.2) 100%
  );
  border: 2px solid rgba(255, 255, 255, 0.3);
  box-shadow: 0 8px 32px rgba(133, 213, 230, 0.3);
}
.status-mvp-track {
  /* Figma F3 node 3:82 — the recessed progress bar INSIDE the frame:
     rounded-32, translucent white, 1px border, inset shadow.
     overflow visible so the marble logo can ride the fill edge. */
  width: 100%;
  height: 22px;
  border-radius: 32px;
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.3);
  box-shadow: inset 0 2px 8px rgba(0, 0, 0, 0.1);
  overflow: visible;
}
.status-mvp-fill {
  /* The progressed portion — the signature gradient at full opacity. */
  position: relative;
  height: 100%;
  border-radius: 32px;
  background: linear-gradient(90deg, #85d5e6 0%, #f4aef5 50%, #fcf38f 100%);
  transition: width 0.8s ease;
}
.status-mvp-marble {
  /* The Dream x Destiny marble logo riding the fill's leading edge —
     clean, no ring/shadow. */
  position: absolute;
  right: -13px;
  top: 50%;
  transform: translateY(-50%);
  width: 26px;
  height: 26px;
  object-fit: contain;
}
/* User 2026-05-19: before the vision is accepted (data-prestart) the
   bar sits EMPTY — the frame and recessed track stay visible (they ARE
   the progress-bar UI), the fill is 0% so there is no gradient streak,
   and the marble simply rests tucked at the very start of the track.
   (Earlier this stripped the frame + track entirely, which read as a
   broken/missing UI — a lone marble under the label.) */
.status-mvp[data-prestart='true'] .status-mvp-marble {
  right: auto;
  left: 0;
}

/* All status rows: split label (left, muted) from value (right, bright)
   so they don't stack on top of each other. .active-row already had
   justify-content space-between; this generalises that pattern. */
.status-row {
  justify-content: space-between;
}
.status-label {
  /* User 2026-05-15: "text in the status section for tabs is off."
     Per Figma F0 nodes 63:245/278/280: labels are Plus Jakarta Sans
     SemiBold 16px / leading 24, plain case (no uppercase), #f4f4f6.
     Was: 14px / 500 / uppercase / muted. */
  color: #f4f4f6;
  font-weight: 600;
  /* User 2026-05-18: status text +2px → 18px. */
  font-size: 18px;
  letter-spacing: 0;
  text-transform: none;
}
.status-value {
  /* User 2026-05-15: "remove the dash and container around — for both
     Vision Score and Venture ID. This information will just appear
     there later, no style." Plain text only — no pill background,
     no inset shadow, no letter-spacing tricks. The JSX no longer
     renders the "—" placeholder either; the span only appears when
     a real value lands. */
  color: #f4f4f6;
  font-weight: 600;
  /* User 2026-05-18: status text +2px → 18px. */
  font-size: 18px;
  letter-spacing: 0;
  white-space: nowrap;
}

.switch {
  /* User 2026-05-14: Neumorphism (matches .next-button + .add-button).
     Track appears "carved into" the dark panel via INSET shadows
     (dark BR depth + light TL highlight = pressed-in look), while the
     thumb is "raised" via OUTSET shadows that mirror the button
     neumorphism. Off = neutral grey; .on swaps the track tint to
     green #7feba0 per Figma F1/F2/F2.1 state. */
  width: 54px;
  height: 24px;
  padding: 3px;
  border-radius: 50px;
  background: linear-gradient(145deg, #2a214c, #3a2e64);
  box-shadow:
    inset 3px 3px 6px rgba(0, 0, 0, 0.55),
    inset -2px -2px 5px rgba(255, 255, 255, 0.10);
  display: flex;
  align-items: center;
}

.switch.on {
  background: linear-gradient(145deg, #5cd687, #87f3a8);
  box-shadow:
    inset 3px 3px 6px rgba(0, 0, 0, 0.40),
    inset -2px -2px 5px rgba(255, 255, 255, 0.25);
}
.switch.on span {
  margin-left: auto;
}

.switch span {
  /* Thumb — raised via OUTSET shadow language used on the +/next
     buttons (light TL highlight + dark BR depth + inner bevel). */
  display: block;
  width: 19px;
  height: 19px;
  border-radius: 999px;
  background: linear-gradient(145deg, #ffffff, #d6d6d6);
  box-shadow:
    -2px -2px 5px rgba(255, 255, 255, 0.18),
    3px 3px 7px rgba(0, 0, 0, 0.55),
    inset 1px 1px 2px rgba(255, 255, 255, 0.85),
    inset -1px -1px 2px rgba(0, 0, 0, 0.18);
}

/* User 2026-05-15: Figma F1/F2/F3/Roof all show the Active toggle in
   its ON state (green track, thumb right) — being on any non-F0 floor
   means the adventure is running. Force the visual ON state via CSS
   so the toggle reflects reality even when the polling API returns a
   stale "off" state (e.g., on ?id=draft preview routes). */
.figma-stage[data-screen]:not([data-screen="F0"]) .switch {
  background: linear-gradient(145deg, #5cd687, #87f3a8);
  box-shadow:
    inset 3px 3px 6px rgba(0, 0, 0, 0.40),
    inset -2px -2px 5px rgba(255, 255, 255, 0.25);
}
.figma-stage[data-screen]:not([data-screen="F0"]) .switch span {
  margin-left: auto;
}

.glass-card {
  /* User 2026-05-17: neumorphism — the frosted-glass surface (backdrop
     blur kept) now reads as a soft-extruded panel: outer light/dark
     shadows lift it off the dark stage, inset highlight/shadow give the
     curvature, borderless. Glass + neumorphism is the locked F0
     aesthetic. The blur keeps it from vanishing against the gradient. */
  position: absolute;
  left: 518px;
  width: 692px;
  height: 310px;
  border-radius: 20px;
  background: linear-gradient(150deg, rgba(255, 255, 255, 0.12), rgba(255, 255, 255, 0.05));
  box-shadow:
    -8px -8px 20px rgba(255, 255, 255, 0.05),
    12px 12px 30px rgba(0, 0, 0, 0.50),
    inset 2px 2px 5px rgba(255, 255, 255, 0.18),
    inset -3px -3px 8px rgba(0, 0, 0, 0.22);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
}

.prompt-card {
  /* Matches .panel — cumulative −14 from below-agents shifts → 195. */
  top: 195px;
  height: 310px;
}

.prompt-line {
  position: absolute;
  left: 27px;
  margin: 0 0 12px;
  color: rgba(255, 255, 255, 0.93);
  font-size: 17px;
  line-height: 24px;
  letter-spacing: 0;
  white-space: nowrap;
}

.prompt-hey {
  top: 28px;
}

.prompt-build {
  top: 58px;
}

.prompt-exchange {
  top: 88px;
}

.prompt-cash {
  left: 50px;
  top: 136px;
}

.prompt-free {
  left: 50px;
  top: 174px;
}

.prompt-equity {
  left: 50px;
  top: 212px;
}

.prompt-question {
  top: 250px;
}

.dot {
  position: absolute;
  display: block;
  width: 14px;
  height: 14px;
  border-radius: 999px;
}

.dot-pink {
  left: -24px;
  top: 2px;
  background: linear-gradient(90deg, #f886e5, #f4aef5);
  box-shadow: 0 0 10px rgba(248, 134, 229, 0.5);
}

.dot-green {
  left: -24px;
  top: 2px;
  background: linear-gradient(90deg, #8dfab0, #9ff7b2);
  box-shadow: 0 0 10px rgba(141, 250, 176, 0.5);
}

.dot-blue {
  left: -24px;
  top: 2px;
  background: linear-gradient(90deg, #86e9f8, #85d5e6);
  box-shadow: 0 0 10px rgba(134, 233, 248, 0.5);
}

.lower-card {
  /* Panels at top:195 + height:670 → bottom 865. Lower-card
     height 310 → top 555 (bottom-aligned with panels). */
  top: 555px;
}

.ai-avatar {
  /* User 2026-05-15 iter: scaled DOWN 20% (140→112), now scaled UP
     20% (112→134) per "make Lumi bigger 20%". Plus "Lumi avatar need
     to go down 5px" → top 586 → 591. Then shifted up 73 with rest of
     below-row → 518. Then cumulative −9 with below-agents → 509.
     Then "fix lumi position … up, to be about the middle of the
     bottom framer box" → 470 (straddles lower-card top edge).
     Then another −5 with below-agents → 465.
     MCP-measured 2026-05-15: PNG (1024×1536) only fills y=404→1227,
     so 26 % empty padding on top + 20 % on bottom. With container at
     465, the VISIBLE character bottom landed at design y ≈ 609 (53
     px below lower-card top 555) — Lumi looked floating mid-card.
     User: "keep size, move her HIGHER … with only her feet touching
     the top edge". Visible bottom must equal lower-card top (555):
       container_top + 180·(1227/1536) = 555
       container_top = 555 − 143.9 = 411
     So top: 465 → 411. Now her visible character sits FULLY above
     the lower-card, with only her feet on the seam. */
  position: absolute;
  /* User 2026-05-16: "center Lumi's avatar" — was left 817 (center
     884, 20px right of the stage centre). 134-wide avatar centred on
     the stage centre 864 → left = 864 − 67 = 797. Matches the
     dreamer-ring, which is already centred. */
  left: 797px;
  top: 411px;
  width: 134px;
  height: 180px;
  overflow: hidden;
  z-index: 50;
}

.ai-avatar img {
  /* Image scaled to match the up-sized container (134×180). */
  position: absolute;
  left: 0;
  top: 0;
  width: 120px;
  height: 180px;
  display: block;
  object-fit: contain;
  pointer-events: none;
}

.tiny-trail {
  position: absolute;
  left: 27px;
  top: 20px;
  width: 42px;
  height: 24px;
  color: #fff;
  font-size: 16px;
  font-weight: 700;
  line-height: 24px;
}

.tiny-trail span {
  position: absolute;
  left: 0;
  top: 0;
}

.tiny-trail i {
  position: absolute;
  left: 32px;
  top: 0;
  width: 2px;
  height: 15px;
  background: linear-gradient(180deg, #85d5e6, #bdd9e0);
  box-shadow: 0 0 10px rgba(133, 213, 230, 0.6);
}

.tiny-trail b {
  position: absolute;
  left: 29px;
  top: 13px;
  width: 8px;
  height: 8px;
  border: 2px solid #85d5e6;
  border-radius: 999px;
  background: #fff;
  box-shadow: 0 0 15px rgba(133, 213, 230, 0.8);
}

.add-button {
  /* Figma F0 node 63:299 / F2.1 node 2:18: button at panel-relative
     (163, 600).

     User 2026-05-18: the + button now uses the FULL .next-button style
     — a 51×51 cyan→pink→yellow gradient circle with the same pink-glow
     neumorphism — only the glyph differs (a + instead of the arrow).
     It keeps the previous centre (was 48×46 at 163,592 → centre-x 187)
     and the 32px bottom clearance: 51-tall → top 587 (panel h 670 −
     51 − 32); 51-wide centred → left 161.5 ≈ 161. */
  position: absolute;
  left: 161px;
  top: 587px;
  width: 51px;
  height: 51px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #85d5e6, #f4aef5 58%, #fcf38f);
  color: #2b1748;
  /* User 2026-05-18: the + glyph was too bold — weight 700 → 400. */
  font-size: 30px;
  line-height: 1;
  font-weight: 400;
  box-shadow:
    0 8px 20px -4px rgba(244, 174, 245, 0.45),
    5px 5px 13px rgba(0, 0, 0, 0.40),
    inset 1.5px 1.5px 3px rgba(255, 255, 255, 0.45),
    inset -2px -2px 4px rgba(0, 0, 0, 0.22);
}

/* Outputs-panel download button. Stays greyed until /api/adventure/:id/outputs
   reports download_locked:false (F2 PASS / manifest ARCHIVED).
   Figma F2.1 node 2:18: panel-relative (157, 599), 48×46. The + button
   that shares this class on F0/F1/F2 cooking sits at (163, 600) per
   F0 node 63:299 — override here for the download variant only. */
.download-button {
  /* User 2026-05-16: "there is no button, it's just a square" — the
     rule set position/opacity/colour but NO background, border, radius
     or size, so the browser rendered the native <button> default: a
     grey square. Now styled with the SAME neumorphism as .add-button
     (its sibling in this panel slot) — 48×46 per Figma F2.1 node 2:18,
     translucent-light surface extruded from the dark panel via layered
     light/dark shadows + inset highlights. */
  /* User 2026-05-18: identical to .next-button — a 51×51 cyan→pink→
     yellow gradient circle with the same neumorphism.
     User 2026-05-19: the arrow inside points DOWN (it's a download),
     in the same #59534D ink as the next-button arrow. */
  position: absolute;
  left: 156px;
  top: 597px;
  width: 51px;
  height: 51px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #85d5e6, #f4aef5 58%, #fcf38f);
  color: #2b1748;
  box-shadow:
    0 8px 20px -4px rgba(244, 174, 245, 0.45),
    5px 5px 13px rgba(0, 0, 0, 0.40),
    inset 1.5px 1.5px 3px rgba(255, 255, 255, 0.45),
    inset -2px -2px 4px rgba(0, 0, 0, 0.22);
  opacity: 0.45;
  cursor: not-allowed;
  transition: transform 0.12s ease, filter 0.15s ease, opacity 0.15s ease;
}

.download-button:not([disabled]) {
  opacity: 1;
  cursor: pointer;
}

.download-button:not([disabled]):hover {
  transform: scale(1.06);
}

.download-button:not([disabled]):active {
  transform: translateY(1px);
}

.download-button img,
.download-button svg {
  display: block;
  width: 20px;
  height: 20px;
}

/* ─── Outputs panel 5-PDF grid (F2.1 redesign 2026-05-13, Figma
   DBykjAWT5vLNHaKMq4kQF7 node 9:44) ────────────────────────────────
   Five rows: agent BADGE on the left (panel-x 64) + PDF icon on the
   right (panel-x 249). Each row paired by Y. Stride 98px.
   PDFs are smaller now (53×50 vs the previous 71×71). */
.outputs-grid {
  /* Hide the legacy upload wrap if any sneaks in. */
}

.outputs-grid .inputs-upload-wrap {
  display: none;
}

.outputs-pdf-slot {
  /* F2.1 redesign: right-side PDF column. Per Figma F2.1 (2026-05-15),
     each slot recolors the shared pdf-icon.svg to its agent's accent —
     pink/green/purple/cyan/red. Rendered via CSS mask so a single SVG
     asset drives all five tints. */
  position: absolute;
  left: 249px;
  width: 53px;
  height: 50px;
  cursor: pointer;
  -webkit-mask: url(/porthole/v2/assets/pdf-icon.svg) center / contain no-repeat;
          mask: url(/porthole/v2/assets/pdf-icon.svg) center / contain no-repeat;
  background-color: var(--pdf-color, #EB5757);
  /* User 2026-05-18: the PDF icons read as pale — give each one a glow
     in its own agent colour so they look lit, not washed out. */
  filter: drop-shadow(0 0 7px var(--pdf-color, #EB5757));
  transition: transform 0.18s ease, filter 0.18s ease, opacity 0.18s ease;
}

.outputs-pdf-slot[data-kind="lumi"]   { --pdf-color: #F5A5F2; }
.outputs-pdf-slot[data-kind="monday"] { --pdf-color: #81EEA1; }
.outputs-pdf-slot[data-kind="gemini"] { --pdf-color: #D8BDF1; }
.outputs-pdf-slot[data-kind="grok"]   { --pdf-color: #85D5E6; }
.outputs-pdf-slot[data-kind="dxd"]    { --pdf-color: #F88686; }

.outputs-pdf-slot img {
  /* The icon body now comes from the CSS mask — hide the inline <img>
     to avoid double-rendering. Kept in the DOM for alt/a11y. */
  display: none;
}

.outputs-pdf-slot.is-locked {
  /* User 2026-05-18: locked still glows (keeps the base drop-shadow) —
     just a touch dimmer than ready so the gate still reads. Was 0.45
     (too pale). */
  cursor: not-allowed;
  opacity: 0.78;
}

.outputs-pdf-slot.is-ready:hover {
  transform: scale(1.06);
  filter: drop-shadow(0 0 14px var(--pdf-color, #EB5757));
}

/* User 2026-05-19: F3's Outputs panel is display-only — the 5 venture
   PDFs are saved to the dreamer's personal zone, never downloaded here.
   The slot keeps its lit agent colour but is not interactive. */
.outputs-pdf-slot.is-personal-zone {
  cursor: default;
}
.outputs-pdf-slot.is-personal-zone:hover {
  transform: none;
  filter: drop-shadow(0 0 7px var(--pdf-color, #EB5757));
}

/* Agent badges — left column of the Outputs panel. Lumi (slot 1) is
   the full orb portrait (88×135); the other 4 are circular logos
   (54×54), confirmation seal is slightly larger (60×60). Clean look —
   no extra background rings; the logos already have their own bg.
   Default left:62 matches Figma ellipse 181 (Gemini) at (62, 274).
   Lumi (left:47) and seal (left:61) override below. */
.outputs-agent-badge {
  position: absolute;
  left: 62px;
  width: 54px;
  height: 54px;
  display: grid;
  place-items: center;
  pointer-events: none;
}

.outputs-agent-badge img {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: 999px;
  object-fit: contain;
}

.outputs-agent-badge--lumi {
  /* Figma F2.1: Lumi character (1:338) at panel (47, 46), 88×135. The
     image is the orb-with-trail, not a circular crop. */
  left: 47px;
  width: 88px;
  height: 135px;
  overflow: visible;
}

.outputs-agent-badge--lumi img {
  border-radius: 0;
  object-fit: contain;
}

.outputs-agent-badge--logo {
  /* F2.1 logo badge — a 54×54 disc holding the vendor mark (~32×32).
     User 2026-05-17: match the floor agent avatars exactly — the same
     neumorphic light-gradient surface, the same inset highlight/shadow,
     and the same per-agent coloured halo (set by [data-agent] below).
     A logo badge with no data-agent match keeps the neutral white halo
     from `.team .team-avatar`. */
  background: linear-gradient(145deg, #ffffff, #e6e6ee);
  border-radius: 999px;
  box-shadow:
    0 0 14px rgba(255, 255, 255, 0.22),
    inset 2.5px 2.5px 5px rgba(255, 255, 255, 0.70),
    inset -3px -3px 6px rgba(0, 0, 0, 0.12);
}

/* Per-agent halo — identical rgba/blur to the floor `.team-avatar`
   per-agent rules so the Outputs logos read as the same component as
   the agents on F0/F1/F2 (user 2026-05-17). */
.outputs-agent-badge--logo[data-agent="monday"] {
  box-shadow:
    0 0 16px rgba(133, 213, 230, 0.50),
    0 0 32px rgba(133, 213, 230, 0.24),
    inset 2.5px 2.5px 5px rgba(255, 255, 255, 0.70),
    inset -3px -3px 6px rgba(0, 0, 0, 0.12);
}

.outputs-agent-badge--logo[data-agent="Gemini"] {
  box-shadow:
    0 0 16px rgba(244, 174, 245, 0.52),
    0 0 32px rgba(244, 174, 245, 0.26),
    inset 2.5px 2.5px 5px rgba(255, 255, 255, 0.70),
    inset -3px -3px 6px rgba(0, 0, 0, 0.12);
}

.outputs-agent-badge--logo[data-agent="Grok"] {
  box-shadow:
    0 0 16px rgba(252, 243, 143, 0.46),
    0 0 32px rgba(252, 243, 143, 0.22),
    inset 2.5px 2.5px 5px rgba(255, 255, 255, 0.70),
    inset -3px -3px 6px rgba(0, 0, 0, 0.12);
}

.outputs-agent-badge--logo img {
  /* Inner mark sits centered inside the white disc per Figma ellipse
     181 + ellipse 176/162 pairing (32px mark on 54px disc). */
  width: 32px;
  height: 32px;
  border-radius: 0;
  object-fit: contain;
}

.outputs-agent-badge--seal {
  /* The Dream x Destiny mark is its own finished circular logo — no
     white neumorphic disc. User 2026-05-18: it must read the SAME
     diameter as the monday/Gemini/Grok circles; the PNG has a ~12%
     transparent margin, so the image is scaled up + clipped to a
     circle so the visible sphere matches the 54px discs. */
  background: transparent;
  border-radius: 999px;
  box-shadow: none;
  overflow: hidden;
}

.outputs-agent-badge--seal img {
  width: 114%;
  height: 114%;
  border-radius: 0;
  object-fit: contain;
}

.outputs-agent-badge--seal svg {
  /* Fallback SVG checkmark (only used when no badge.src is supplied);
     kept for safety until every adventure ships a real dxd asset. */
  display: block;
  width: 28px;
  height: 28px;
  filter: drop-shadow(0 0 6px rgba(252, 243, 143, 0.45));
}

/* Lumi typing-cursor: cyan vertical line + white-cyan dot, positioned
   right after the "..." placeholder inside the lower (dreamer) card.
   Mimics a static text caret so the dreamer knows where their typing
   will land. Hidden once they start typing (see figma-runtime.js). */
.lumi-typing-cursor {
  /* Figma F0 node 63:288: line + dot caret, positioned past the "..."
     placeholder with a real text-cursor padding.

     User 2026-05-14: final dial-in.
       - Placeholder ends at design x≈579 (with trailing letter-spacing).
       - Caret container is 8px wide and holds two visible glyphs:
           i (vertical line) at internal left:3 → 2px wide
           b (round dot)     at internal left:0 → 8px wide
         So the dot's LEFT edge equals the container's left edge.
       - 590 (too far) → 578 (dot overlapped last placeholder dot by
         ~1px) → 584: gives 5 design px clear space from placeholder
         end to the cursor-dot left edge — the "nice padding next to
         it like a real mouse cursor relative to text" feel. */
  /* User 2026-05-15 (final): placeholder tightened to "···" at 17px /
     1px letter-spacing = ~22 design px wide. Textarea origin at design
     x=546, placeholder ends at ~568. left:575 puts the caret-dot 7
     design px past the last placeholder dot — tight real-text-cursor
     gap, no overlap. */
  position: absolute;
  left: 575px;
  /* User 2026-05-15: cursor centered on the "···" placeholder line
     (lower-card.top + 21). After −5 below-agents shift lower-card
     top is 555 → placeholder at 576 → cursor at 578. */
  top: 578px;
  width: 8px;
  height: 21px;
  pointer-events: none;
  z-index: 41;
}

/* The decorative cursor's left/top are set inline by figma-runtime.js
   based on the textarea's current text length — see positionLumiCursor.
   When the textarea is empty it sits at the CSS default (left:92 top:64,
   just past the "..." placeholder). When the dreamer types, the JS
   moves it to the end of the text on every input event. */

.lumi-typing-cursor i {
  /* User 2026-05-15: "cursor is still pulsing" — removed the blink
     animation. Cursor line stays static like a paused caret. */
  display: block;
  position: absolute;
  left: 3px;
  top: 0;
  width: 2px;
  height: 15px;
  background: linear-gradient(180deg, #85d5e6, #bdd9e0);
  box-shadow: 0 0 10px rgba(133, 213, 230, 0.6);
}

.lumi-typing-cursor b {
  /* User 2026-05-18: the caret circle now has a SLOW pulse. */
  display: block;
  position: absolute;
  left: 0;
  top: 13px;
  width: 8px;
  height: 8px;
  border: 2px solid #85d5e6;
  border-radius: 999px;
  background: #fff;
  box-shadow: 0 0 15px rgba(133, 213, 230, 0.8);
  animation: dreamer-caret-pulse 2.6s ease-in-out infinite;
}

@keyframes dreamer-caret-blink {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0; }
}

@keyframes dreamer-caret-pulse {
  /* User 2026-05-19: slow + MILD — a gentle breath, not a throb. */
  0%, 100% {
    transform: scale(1);
    box-shadow: 0 0 9px rgba(133, 213, 230, 0.5);
  }
  50% {
    transform: scale(1.08);
    box-shadow: 0 0 14px rgba(133, 213, 230, 0.78);
  }
}

/* User 2026-05-17: when the dreamer clicks into the text box, the
   cursor's circle pulses — a slow, gentle breathing pulse (not a fast
   blink). :has() lets the focused textarea (inside .lower-card) drive
   the cursor, which is a sibling of the card. */
.figma-stage:has(.figma-textarea:focus) .lumi-typing-cursor b {
  animation: dreamer-caret-pulse 2.4s ease-in-out infinite;
}

.dreamer-ring {
  /* User 2026-05-17: clean circular avatar — no black frame, no ring,
     no halo. The avatar PNG is itself circular (transparent corners);
     this box only positions it and circle-clips. Centre stays on the
     lower-card bottom edge (y=865 → 72-tall box top 829). */
  position: absolute;
  left: 828px;
  top: 829px;
  width: 72px;
  height: 72px;
  box-sizing: border-box;
  border-radius: 999px;
  overflow: hidden;
  /* User 2026-05-17: neumorphism — soft-extruded depth (outer light/dark
     + inset highlight/shadow). Not a hard ring — shadow-based curvature. */
  box-shadow:
    -4px -4px 10px rgba(255, 255, 255, 0.06),
    6px 6px 14px rgba(0, 0, 0, 0.45),
    inset 2px 2px 4px rgba(255, 255, 255, 0.22),
    inset -2px -2px 5px rgba(0, 0, 0, 0.20);
}

.dreamer-ring img {
  /* Circular avatar PNG fills the box edge-to-edge. */
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  border-radius: 999px;
}

.next-button {
  /* User 2026-05-15: per Figma F0 node 63:290, button is a simple
     60×60 gradient circle with a soft pink glow halo — no heavy
     neumorphism shadows. Arrow inside is centred via flex.
     - keeps cyan→pink→yellow gradient (button identity)
     - drops the layered raised-from-surface shadow
     - adds soft pink drop-shadow halo (matches Figma's projection-
       oval graphic that extends past the button bounds) */
  /* User 2026-05-15: "next button -15%" → 60×60 → 51×51. Left
     shifted 834 → 838.5 ≈ 839 to keep the smaller button visually
     centred in its prior 60×60 footprint. */
  position: absolute;
  /* User 2026-05-16: centred — 51-wide button on stage centre 864
     → left = 864 − 25.5 = 838.5 (was 839). */
  left: 838.5px;
  top: 1009px;
  width: 51px;
  height: 51px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #85d5e6, #f4aef5 58%, #fcf38f);
  color: #2b1748;
  font-size: 24px;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  /* User 2026-05-17: neumorphism re-added (reverses the 2026-05-15
     "no neumorphism shadows" note above) — keeps the pink identity
     glow, adds soft-extruded depth via the dark outer + inset layers. */
  box-shadow:
    0 8px 20px -4px rgba(244, 174, 245, 0.45),
    5px 5px 13px rgba(0, 0, 0, 0.40),
    inset 1.5px 1.5px 3px rgba(255, 255, 255, 0.45),
    inset -2px -2px 4px rgba(0, 0, 0, 0.22);
}

/* Lumi-thinking indicator (driven by data-sending="true" on the stage).
   Pulses the next-button so it's clear the system is working, and
   surfaces a "Lumi is thinking…" caption beneath it. */
.figma-stage[data-sending="true"] .next-button {
  cursor: progress;
  animation: lumi-next-pulse 1.4s ease-in-out infinite;
}

@keyframes lumi-next-pulse {
  0%, 100% {
    box-shadow: 0 0 25px rgba(244, 174, 245, 0.5);
    transform: scale(1);
  }
  50% {
    box-shadow: 0 0 38px rgba(244, 174, 245, 0.85),
                0 0 60px rgba(133, 213, 230, 0.45);
    transform: scale(1.04);
  }
}

/* In-chat-box thinking line. Renders inside the prompt-card body when
   state.sending === true (index.html substitutes the promptHtml). The
   caption fades softly, the trailing dots crawl, so the dreamer sees
   movement and knows Lumi hasn't frozen. */
.prompt-body .lumi-thinking-line {
  margin: 0;
  font-style: italic;
  font-weight: 600;
  color: rgba(255, 255, 255, 0.82);
  animation: lumi-thinking-fade 1.6s ease-in-out infinite;
}

/* User 2026-05-19: three bold signature-coloured dots that bounce
   UP and DOWN (was a sideways clip-path reveal of an ellipsis). */
.prompt-body .lumi-thinking-line .lumi-thinking-dots {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-left: 8px;
  vertical-align: middle;
}
.prompt-body .lumi-thinking-line .lumi-thinking-dots i {
  display: block;
  width: 9px;
  height: 9px;
  border-radius: 999px;
  animation: lumi-thinking-bounce 0.9s ease-in-out infinite;
}
.prompt-body .lumi-thinking-line .lumi-thinking-dots i:nth-child(1) {
  background: #85d5e6;
  animation-delay: 0s;
}
.prompt-body .lumi-thinking-line .lumi-thinking-dots i:nth-child(2) {
  background: #f4aef5;
  animation-delay: 0.15s;
}
.prompt-body .lumi-thinking-line .lumi-thinking-dots i:nth-child(3) {
  background: #fcf38f;
  animation-delay: 0.3s;
}

@keyframes lumi-thinking-fade {
  0%, 100% { opacity: 0.55; }
  50%      { opacity: 1; }
}

@keyframes lumi-thinking-bounce {
  0%, 100% { transform: translateY(0); opacity: 0.55; }
  50%      { transform: translateY(-8px); opacity: 1; }
}

.figma-stage[data-screen="F1"] .title-bottom::before { content: "Product & Business"; }
.figma-stage[data-screen="F2"] .title-bottom::before { content: "Branding, Marketing & UI/UX"; }
.figma-stage[data-screen="F3"] .title-bottom::before { content: "Software Build"; }
.figma-stage[data-screen="Roof"] .title-bottom::before { content: "Software Test"; }
.figma-stage[data-screen]:not([data-screen="F0"]) .title-bottom { font-size: 40px; color: transparent; }
.figma-stage[data-screen]:not([data-screen="F0"]) .title-bottom::before {
  color: transparent;
  background-image: linear-gradient(90deg, #85d5e6 0%, #ccb1ef 29%, #f4aef5 50%, #fae1b3 86%, #fcf38f 100%);
  background-clip: text;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
}

/* Per-floor subtitle colors per Figma get_design_context (2026-05-13):
     F0 → #91d1e7 (solid blue, set on default .title-bottom above)
     F1 → #d8bdf1 (solid lavender, node 1:257)
     F2 → #85d5e6 (solid cyan, node 1:258 in EGWpq... file)
     F3 / Roof → keep the cyan-pink-yellow gradient as designed.
   All non-F0 share the same pink drop-shadow at 30px blur. */
.figma-stage[data-screen="F1"] .title-bottom::before {
  /* User 2026-05-15: title color didn't match Figma — gradient rule
     above had equal specificity but came later in source order, so
     it won. !important pins the lavender #d8bdf1 per Figma node 1:257. */
  background-image: none !important;
  color: #d8bdf1 !important;
  -webkit-text-fill-color: #d8bdf1 !important;
}
.figma-stage[data-screen="F2"] .title-bottom::before {
  /* User 2026-05-15: !important to beat the higher-specificity
     non-F0 gradient rule (same fix pattern as F1's lavender). */
  background-image: none !important;
  color: #85d5e6 !important;
  -webkit-text-fill-color: #85d5e6 !important;
}
.figma-stage[data-screen="F1"] .title-bottom,
.figma-stage[data-screen="F2"] .title-bottom {
  filter: drop-shadow(0 0 30px rgba(244, 174, 245, 0.5));
}

.figma-stage[data-screen]:not([data-screen="F0"]) .member-gemini,
.figma-stage[data-screen]:not([data-screen="F0"]) .member-grok,
.figma-stage[data-screen]:not([data-screen="F0"]) .member-claude { display: none; }

/* User 2026-05-15: "on F1 and F2 (and F2.1) The Adventure logo should
   disappear, only the two working agents with the pulse in the middle
   should be seen." Hide the gradient logo on every non-F0 floor — the
   agent row + pulsing connector becomes the visual focus. */
.figma-stage[data-screen]:not([data-screen="F0"]) .title-top {
  display: none !important;
}
.figma-stage[data-screen]:not([data-screen="F0"]) .member-monday { left: 651px; top: 164px; }
/* Per-file team avatar positions. F1/F2 design files have monday at
   x=680 (avatar at 680, .member left = 680-39 = 641); F2.1 redesign
   has monday at x=690 (kept as the non-F0 default above, left=651).
   Similarly partner avatar (Gemini for F1, Grok for F2/F2.1) is at
   x=1015 in F1/F2 vs x=1005 in F2.1. */
/* User 2026-05-15: "match monday and gemini position to F0" — F1
   now uses F0's slot-1 + slot-2 positions (monday at design x=548,
   Gemini at design x=745). F2 keeps its Figma F2 placement. */
.figma-stage[data-screen="F2"] .member-monday { left: 641px !important; }
.figma-stage[data-screen="F1"] .member-monday {
  /* User 2026-05-15: revert to Figma F1 spec (monday avatar at design
     x=680) so the gap between monday (752 right) and Gemini (1015
     left) = 263 px fits the full 3+box+3 dash cluster (79+24+49+24+79
     = 255). The earlier F0-slot-1 position (548) gave only 125 px
     gap, forcing us to hide 4 of 6 dashes. */
  left: 641px !important;
}
.figma-stage[data-screen="F2"] .single-agent { left: 922px !important; }
.figma-stage[data-screen="F1"] .single-agent {
  /* Gemini avatar at design x=1015 (single-agent wrapper offset 93 →
     1015-93 = 922). Matches Figma F1 spec; gives the dash cluster
     room to render all 6 segments. */
  left: 922px !important;
}
.figma-stage[data-screen]:not([data-screen="F0"]) .single-agent { display: block; }
.single-agent { display: none; }
.figma-stage[data-screen]:not([data-screen="F0"]) .panel { top: 282px; }
.figma-stage[data-screen]:not([data-screen="F0"]) .panel.status-panel { left: 64px; }
.figma-stage[data-screen]:not([data-screen="F0"]) .panel.inputs-panel { left: 1302px; }
.figma-stage[data-screen]:not([data-screen="F0"]) .prompt-card { left: 518px; top: 282px; height: 310px; }
/* Figma F1 / F2 verbatim positions: lower card at (518, 816) — same
   as F0 (we matched F0 to Figma in iter 1). Lumi orb at (803, 521)
   140×106 in F1 (node 1:297) and (803, 563) 140×115 in F2 (node 1:337).
   The non-F0 override below uses the F1 value; F2's slightly-lower
   y=563 is handled by a more specific override later if needed. */
.figma-stage[data-screen]:not([data-screen="F0"]) .lower-card { left: 518px; top: 642px; }
.figma-stage[data-screen]:not([data-screen="F0"]) .ai-avatar {
  /* Match F0 sizing: 134×180 + top 591 (was 112×150 + top 586).
     User 2026-05-16: "center Lumi's avatar" — left 817 → 797 so the
     134-wide avatar is centred on stage centre 864 (dreamer-ring). */
  left: 797px;
  top: 591px;
  width: 134px;
  height: 180px;
  overflow: visible;
}
.figma-stage[data-screen]:not([data-screen="F0"]) .dreamer-ring { left: 828px; top: 980px; }
/* User 2026-05-16: "center the next button in all screens" — left 834
   put its centre at 859.5 (5px left of stage centre 864). 51-wide
   button centred → left = 864 − 25.5 = 838.5. Matches F0. */
.figma-stage[data-screen]:not([data-screen="F0"]) .next-button { left: 838.5px; top: 1082px; }
/* User 2026-05-15: "cursor is off" — F1 was using Figma F1's literal
   x=565, but the placeholder font is now 18px (bigger than Figma's
   16px), so 565 overlapped the dots. Removing the F1 override so all
   non-F0 floors inherit the base cursor (left:586) that was dialled
   in for F0's 18px placeholder. Result: consistent cursor across all
   floors, all sitting just past the "..." with proper padding. */
/* User 2026-05-15: "Dashed line between monday and Gemini is way off
   to the right." The .dash absolute coords (760, 789, 818, 928, 957,
   986) are meant as ABSOLUTE design x, but .agent-dashes parent at
   left:768 was offsetting them by 768 → dashes rendered at x=1528+.
   Reset the F1 parent to left:0 with full stage width so dashes
   land at their literal Figma-spec coords. */
.figma-stage[data-screen="F1"] .agent-dashes,
.figma-stage[data-screen="F2"] .agent-dashes {
  /* User 2026-05-15: dashes + box rendered ~226px too low because the
     parent .agent-dashes had top:226, stacking with each child's top
     to push them to design y=442. Pinning parent to (0,0) full-stage
     lets children use absolute Figma design coords for top/left.
     Extended to F2 so its dashes/box also land correctly. */
  left: 0 !important;
  top: 0 !important;
  width: 1664px !important;
  height: 1248px !important;
}
/* User 2026-05-15: "emoji box is very to the left." A later .dash-box
   rule (around line 1295) overrode Figma's left:859 with left:91, so
   the white centre square was rendering at design x=91 (render x=56)
   instead of design 859 (between dash3 and dash4). Pin Figma F1
   coords with !important. Also shift up 12px since the agent row moved
   from y=227 → y=215. */
.figma-stage[data-screen="F1"] .dash-box,
.figma-stage[data-screen="F2"] .dash-box {
  /* User 2026-05-15: .agent-dashes parent pinned to top:0 (was 226).
     Box top is absolute design y. Row icons span y=215-287 (center
     251). 43-tall box centered: top = 251 - 21.5 = 229. F2 inherits
     the same vertical centering as F1. NOTE the F2 left:859 in the
     dash block below overrides the !important here for F2; left:859
     is the same value so it's harmless. */
  left: 859px !important;
  top: 229px !important;
  width: 49px !important;
  height: 43px !important;
}

/* F2/Roof keep their own y-offset (Lumi orb sits 23px lower than F1).
   User 2026-05-15: also scale height 20% smaller (115 → 92) to match
   the F0 size reduction. Width inherits 112 from the non-F0 default. */
.figma-stage[data-screen="F2"] .ai-avatar,
.figma-stage[data-screen="Roof"] .ai-avatar {
  /* 1.2× upsize: 92 → 110 height. top 582 → 587 (down 5). */
  top: 587px;
  height: 110px;
}

/* F2 team avatars sit at y=215 (matches F0 — same row geometry as the
   intro). F1 sits 12px lower at y=227 (Figma F1 nodes 2:11 and 2:18).
   .team-avatar top is 49 by default; bump to 51 globally and let F1
   override push the entire .team container down 12px to get to 227. */
/* User 2026-05-15: "match each floor like the last design you did for
   the website for F0" — removed the F1 12px-down shift (was top:181)
   so F1's agent row aligns with F0's at y=215. Default .single-agent
   top:164 + team-avatar internal top:51 = 215 design. team-role gets
   the default 132 offset (matches F0). */

.single-agent {
  /* Matches .team. */
  position: absolute;
  top: 112px;
  left: 912px;
  width: 259px;
  height: 156px;
  text-align: center;
  color: #edecf0;
  font-weight: 800;
}
.single-agent .team-name,
.single-agent .team-role {
  position: absolute;
  left: 0;
  width: 259px;
  font-size: 20px;
  line-height: 25px;
}
.single-agent .team-name {
  top: 0;
  height: 63px;
  display: flex;
  align-items: center;
  justify-content: center;
  /* User 2026-05-18: agent names → Plus Jakarta Sans. */
  font-family: var(--font-plus-jakarta), "Plus Jakarta Sans", system-ui, sans-serif;
  font-weight: 800;
}
.single-agent .team-role {
  top: 132px;
  /* User 2026-05-18: agent roles → Plus Jakarta Sans. */
  font-family: var(--font-plus-jakarta), "Plus Jakarta Sans", system-ui, sans-serif;
  font-weight: 700;
}
.single-agent .team-avatar { left: 93px; top: 51px; }
.single-agent[data-agent="Gemini"] .team-avatar img { width: 48px; height: 48px; }

.agent-dashes { display: none; }
.figma-stage[data-screen]:not([data-screen="F0"]) .agent-dashes { display: block; }
.dash {
  /* Figma F1/F2/F2.1 (Rectangle 1..6): solid #9dd7e4 with 1px white border,
     21×5, border-radius 4 (NOT pill).
     User 2026-05-15: agent row shifted up to F0's y=215 (was 227), so
     dashes shift up by 12 to stay vertically centred on the icons:
     246 → 234. */
  position: absolute;
  top: 234px;
  width: 21px;
  height: 5px;
  border: 1px solid #ffffff;
  border-radius: 4px;
  background: #9dd7e4;
}
/* Default dash positions match F2 (770/799/828 left, 918/947/976 right) and
   F2.1 (same). F1 design uses a different set — handled below. */
.dash.d1 { left: 770px; } .dash.d2 { left: 799px; } .dash.d3 { left: 828px; }
.dash.d4 { left: 918px; } .dash.d5 { left: 947px; } .dash.d6 { left: 976px; }
/* F1 design file places monday at x=680 (vs 690 in F2.1), partner at 1015
   (vs 1005). Dash strips shift 10px outward to match. Only F1 needs
   the override — F2 keeps the default. */
/* User 2026-05-15: after moving F1 agents to F0 slots 1+2 (monday at
   548, Gemini at 745), the gap shrinks from 263 → 125 design px.
   3 dashes per side at 21 wide don't fit. Keep only the middle dash
   on each side (d2 + d5), hide the outer ones, and center the box.
     - monday right edge = 620
     - dash d2: left=628 (8 pad), 21 wide → ends 649
     - 9 pad → box left=658, w=49 → right=707
     - 9 pad → dash d5: left=716, ends 737
     - 8 pad → Gemini left edge = 745
   Symmetric 8/9/9/8 padding pattern, mirror of Figma F1's spec. */
/* User 2026-05-15: restore all 6 dashes (3 per side of the box) now
   that agents are at Figma F1 positions (gap=263 fits the full
   cluster). Coords from Figma F1 spec node 2:92-2:99 + 2:101. */
/* User 2026-05-15: "nice padding between agent and dashed line".
   Bumped agent↔dash padding from 8 → 20 design px (12 more). The
   inner cluster (d3↔box) padding compresses to 5 to keep the layout
   symmetric within the same agent gap of 263. */
.figma-stage[data-screen="F1"] .dash.d1 { left: 772px !important; }
.figma-stage[data-screen="F1"] .dash.d2 { left: 802px !important; }
.figma-stage[data-screen="F1"] .dash.d3 { left: 832px !important; }
.figma-stage[data-screen="F1"] .dash.d4 { left: 913px !important; }
.figma-stage[data-screen="F1"] .dash.d5 { left: 943px !important; }
.figma-stage[data-screen="F1"] .dash.d6 { left: 973px !important; }
.figma-stage[data-screen="F1"] .dash-box { left: 859px !important; }
.dash-box {
  /* Figma F1/F2/F2.1 (Rectangle 7): white fill, solid #9dd7e4 border,
     49×43, border-radius 8.
     User 2026-05-15: shifted up 12 (228 → 216) to keep centred on the
     agent row after it moved from y=227 → y=215. */
  position: absolute;
  left: 859px;
  top: 216px;
  width: 49px;
  height: 43px;
  border: 1px solid #9dd7e4;
  border-radius: 8px;
  background: #ffffff;
}

.figma-textarea {
  /* User 2026-05-15: "when dreamer will type it needs to be 17 px"
     — typed text 18 → 17 so it matches Lumi's body text size. The
     inset uses symmetric 28 left/right padding to match the Lumi
     prompt-body L/R padding (user 2026-05-15: "make sure text fields
     for dreamer and Lumi both have same padding for text from both
     right and left"). */
  position: absolute;
  inset: 54px 28px 28px 28px;
  border: 0;
  outline: 0;
  resize: none;
  background: transparent;
  color: #f4f4f6;
  /* User 2026-05-18: dreamer's typed text → Play (was Podkova). Play
     tops out at 700, so bold is 700 (was 800). */
  font-weight: 700;
  font-size: 17px;
  line-height: 1.45;
  font-family: var(--font-play), 'Play', sans-serif;
}
.figma-textarea::placeholder { color: rgba(255,255,255,.78); }
.figma-stage[data-screen="F0"] .figma-textarea {
  /* User 2026-05-15: equalised L/R padding (was 64/29 to leave a
     long right "drift" past the placeholder). Now 28/28 to match
     the .prompt-body L/R padding for the upper Lumi card. */
  inset: 35px 28px 58px 28px;
}
.prompt-card.dynamic .prompt-line { white-space: normal; }
.prompt-body {
  /* User 2026-05-15 iter: "padding for Lumi text, 2 px to the right
     2 px up" + "decrease padding so what I will see in one screen
     without scrolling is the text [full intro]". Left 28 → 30 (text
     shifts right 2). Top 21 → 12 (visible content moves up).
     Then "move text in Lumi box 3 px left and 3 px up": shift the
     whole block by decreasing left 30 → 27, growing right 28 → 31
     (both edges 3 px leftward) and top 12 → 9. */
  position: absolute;
  left: 27px;
  right: 31px;
  top: 9px;
  max-height: 298px;
  overflow: hidden;
  color: rgba(255,255,255,.93);
  /* User 2026-05-18: Lumi's text → Play (was Podkova). Play tops out
     at 700, so bold is 700 (was 800). */
  font-family: var(--font-play), 'Play', sans-serif;
  /* User 2026-05-18: Lumi text +1px → 18 (line-height 22 → 23 to keep
     the proportion). */
  font-size: 18px;
  line-height: 23px;
  font-weight: 700;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: geometricPrecision;
}
.prompt-body p { margin: 0 0 10px; }
/* User 2026-05-15: "move the text 'Do you have any question' 5 px up"
   — the F0 intro's final CTA paragraph gets `.lumi-cta-line` (added
   in F0.tsx introHtml). Negative margin-top lifts it 5px closer to
   the bullet list above. Other phases / other floors are unaffected. */
/* User 2026-05-15: "last line of text needs to be the same space
   above as between hey dreamer and do you" — the p→p gap is 16 (from
   .prompt-body p { margin: 0 0 16px }). Match ul→cta by setting ul
   margin-bottom to 16 and zeroing the cta-line's prior negative
   margin-top. */
.prompt-body .lumi-cta-line { margin-top: 0; }
.prompt-body ul { margin: 6px 0 10px; padding: 0 0 0 24px; list-style: none; }
/* Bullets in the dynamic Lumi chat carry colored gradient dots — match
   the F0 intro card pattern. Each li is relative so the absolutely
   positioned .dot (left: -24px) sits in the padding gutter.
   Per Figma F2.1 (2026-05-15) bullets sit at y=406/446/486 → 40px
   center-to-center, ~17.5px visible gap between rows. 8px collapsed
   margin previously rendered them too tight. */
.prompt-body li { margin: 0 0 8px; position: relative; padding-left: 0; }
.prompt-body li:last-child { margin-bottom: 0; }
.prompt-body a {
  color: #9fe7f4;
  text-decoration: underline;
  text-decoration-color: rgba(159, 231, 244, 0.85);
  text-underline-offset: 2px;
  font-weight: 800;
}
.prompt-body a:hover {
  color: #c9f4fb;
}
.prompt-card.dynamic .prompt-line { display: none; }
.prompt-card.dynamic .prompt-body { display: block; }
.prompt-body { display: none; }
.error-line {
  position: absolute;
  left: 27px;
  bottom: 18px;
  color: #ffb8e9;
  font-size: 14px;
  font-weight: 800;
}


/* Interaction hardening: the lower card is a real typing surface, not just a visual card. */
.lower-card {
  z-index: 30;
  cursor: text;
}

.figma-textarea {
  z-index: 40;
  pointer-events: auto;
  caret-color: #85d5e6;
  color: #f4f4f6;
  -webkit-user-select: text;
  user-select: text;
}

.figma-textarea:focus {
  outline: none;
}

.figma-textarea::placeholder {
  /* Figma F0/F1 node 63:258 / 1:273 — placeholder "..." at 16px.
     User 2026-05-15: "it's .. but should be ...". Plus Jakarta Sans
     was still ligating "..." into a horizontal ellipsis (U+2026)
     despite font-feature-settings: liga 0 — the OS-level browser
     font shaper applies the ligature before CSS rules see it.
     Hide the native placeholder; render the dots via a pseudo
     element below so they stay 3 distinct glyphs. */
  color: transparent;
}

/* Replacement "..." placeholder rendered via the lower-card so the
   Plus Jakarta Sans ligature is bypassed. Each '.' is wrapped in a
   word-spacing buffer to ensure no glyph substitution happens. */
.lower-card::before {
  /* User 2026-05-15 (iter): ". . ." with spaces + 6px letter-spacing
     rendered as ".    .    ." (too spaced). Switched to three literal
     middle-dot glyphs "···" with letter-spacing 1 — visually tight
     "..." but each dot stays distinct (no horizontal-ellipsis ligature
     because U+00B7 doesn't participate in one). */
  content: "···";
  position: absolute;
  left: 28px;
  /* User 2026-05-17: "… position is too much up" — 21 → 35. The F0
     textarea inset moves with it so typed text starts at the same y. */
  top: 35px;
  color: rgba(255, 255, 255, 0.9);
  font: 700 17px/1 "Plus Jakarta Sans", system-ui, sans-serif;
  letter-spacing: 1px;
  pointer-events: none;
  z-index: 39;
}
.figma-stage[data-screen="F0"] .lower-card.has-text::before,
.figma-stage[data-screen]:not([data-screen="F0"]) .lower-card.has-text::before {
  display: none;
}

.next-button {
  z-index: 45;
}


/* Clean typing/fail-state pass: keep Dreamer text, caret, and gate feedback from colliding. */
.lower-card {
  overflow: visible;
}

.figma-textarea {
  /* User 2026-05-15: equalised L/R padding to match Lumi prompt-body
     (28/28). */
  inset: 35px 28px 58px 28px;
  z-index: 40;
  overflow-y: auto;
  /* User 2026-05-20 (Batch 6): bumped 72→110 so a paragraph-length
     pasted vision clears both the next-button AND the dreamer-ring
     (the avatar). The earlier 72px was tuned for the next-button only. */
  padding: 0 0 110px;
  /* User 2026-05-18: dreamer's typed text → Play (was Podkova). Play
     tops out at 700, so bold is 700 (was 800).
     User 2026-05-18: dreamer text +1px → 18, matching Lumi text. */
  font-weight: 700;
  font-size: 18px;
  line-height: 1.42;
  font-family: var(--font-play), 'Play', sans-serif;
  /* Batch 9 (2026-05-20): caret-color synced to universal DxD cyan
     standard. The decorative .lumi-typing-cursor overlay hides this
     native caret while focused; the base color matches the app rule. */
  caret-color: #85d5e6;
  text-shadow: none;
  white-space: pre-wrap;
}

.figma-textarea:focus {
  /* User 2026-05-14: "when I type a rectangle appears, remove it" —
     dropped the cyan inset focus ring. Keep keyboard a11y via the
     blinking caret + outline:none stays from the base rule. */
  box-shadow: none;
}

.error-line {
  left: 48px;
  right: 48px;
  top: calc(100% + 18px);
  bottom: auto;
  width: auto;
  max-height: 88px;
  overflow-y: auto;
  padding: 12px 14px;
  border: 1px solid rgba(244, 174, 245, 0.34);
  border-radius: 12px;
  background: rgba(26, 21, 52, 0.86);
  color: #f4aef5;
  font-size: 14px;
  line-height: 1.35;
  font-weight: 800;
  z-index: 60;
}

.prompt-card.dynamic .prompt-body {
  /* iter 4: 28 → 21 to compensate for line-height leading so the
     visible top padding matches the 28px left padding.
     User 2026-05-15: "move text in Lumi box 3 px left and 3 px up"
     — 21 → 18 (the L/R 3-px shift is on base .prompt-body). */
  top: 18px;
  max-height: 289px;
  font-size: 17px;
  line-height: 1.42;
}


/* Lumi chat pass: preserve readable model responses in the upper card. */
.prompt-card.dynamic .prompt-body {
  overflow-y: auto;
  padding-right: 10px;
}

.prompt-card.dynamic .prompt-body p {
  margin: 0 0 8px;
  line-height: 1.32;
}


/* Mild per-agent halo on logo avatars (Lumi intentionally excluded). */
.team .team-avatar,
.single-agent .team-avatar {
  box-shadow:
    0 0 14px rgba(255, 255, 255, 0.22),
    inset 2.5px 2.5px 5px rgba(255, 255, 255, 0.70),
    inset -3px -3px 6px rgba(0, 0, 0, 0.12);
}

.member-monday .team-avatar {
  box-shadow:
    0 0 16px rgba(133, 213, 230, 0.50),
    0 0 32px rgba(133, 213, 230, 0.24),
    inset 2.5px 2.5px 5px rgba(255, 255, 255, 0.70),
    inset -3px -3px 6px rgba(0, 0, 0, 0.12);
}

.member-gemini .team-avatar,
.single-agent[data-agent="Gemini"] .team-avatar {
  box-shadow:
    0 0 16px rgba(244, 174, 245, 0.52),
    0 0 32px rgba(244, 174, 245, 0.26),
    inset 2.5px 2.5px 5px rgba(255, 255, 255, 0.70),
    inset -3px -3px 6px rgba(0, 0, 0, 0.12);
}

.member-grok .team-avatar,
.single-agent[data-agent="Grok"] .team-avatar {
  box-shadow:
    0 0 16px rgba(252, 243, 143, 0.46),
    0 0 32px rgba(252, 243, 143, 0.22),
    inset 2.5px 2.5px 5px rgba(255, 255, 255, 0.70),
    inset -3px -3px 6px rgba(0, 0, 0, 0.12);
}

.member-claude .team-avatar,
.single-agent[data-agent="Claude"] .team-avatar {
  box-shadow:
    0 0 16px rgba(134, 233, 248, 0.50),
    0 0 32px rgba(134, 233, 248, 0.24),
    inset 2.5px 2.5px 5px rgba(255, 255, 255, 0.70),
    inset -3px -3px 6px rgba(0, 0, 0, 0.12);
}


/* Agent label spacing polish: clean, even rhythm above/below avatars. */
/* User 2026-05-15: agents now flank the logo in one row at top:4
   (matches logo top). Names sit y=6-46, avatars y=53-125, roles
   y=133-161. Logo y=4-139 next to them. F1/F2 unaffected — their
   monday has non-F0 override top:164.
   User 2026-05-16: "equal gap above/below the agent row." Was top:4 →
   4px above / 22px below. The agent row has 27px of slack before the
   panels; centring it → top:13 gives ~13px above / ~13px below. */
.team {
  top: 13px;
  height: 168px;
}

.team-name,
.team-role,
.single-agent .team-name,
.single-agent .team-role {
  width: 259px;
  text-align: center;
  line-height: 1.12;
}

.team-name,
.single-agent .team-name {
  top: 2px;
  height: 40px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.team-avatar,
.single-agent .team-avatar {
  top: 49px;
}

.team-role,
.single-agent .team-role {
  top: 129px;
  min-height: 28px;
  display: flex;
  align-items: flex-start;
  justify-content: center;
}

/* Keep F0 and single-agent modes consistent. */
.single-agent {
  top: 211px;
  height: 168px;
}


/* Floor connector: stable geometry and clear dash rhythm between monday and agent. */
.agent-dashes {
  position: absolute;
  left: 768px;
  top: 226px;
  width: 238px;
  height: 52px;
  pointer-events: none;
}

.dash {
  /* User 2026-05-15: parent .agent-dashes pinned to (0,0) for F1, so
     dash top must be ABSOLUTE design y. Was 19 (relative to old parent
     at 226), now 246 to match Figma F1 spec exactly (dash row at
     design y=246). */
  top: 246px;
  width: 22px;
  height: 5px;
  border-radius: 999px;
  background: linear-gradient(90deg, #9fe7f4, #b9eef8);
  box-shadow: 0 0 6px rgba(159, 231, 244, 0.45);
}

.dash.d1 { left: 0; }
.dash.d2 { left: 30px; }
.dash.d3 { left: 60px; }
.dash-box {
  /* User 2026-05-15: same parent shift as .dash — top now absolute
     design y (was 1 relative to old parent 226). 216 puts the white
     centre square at the top of the agent row (matches Figma F1
     spec box top:228 shifted up 12 to follow the y=215 row). */
  left: 91px;
  top: 216px;
  width: 50px;
  height: 44px;
}
.dash.d4 { left: 150px; }
.dash.d5 { left: 180px; }
.dash.d6 { left: 210px; }

/* Emoji pulse around Lumi orb (mild, continuous). */
.ai-avatar {
  will-change: transform, filter;
  animation: lumi-breathe 2.8s ease-in-out infinite;
  transform-origin: 52% 56%;
}

@keyframes lumi-breathe {
  0%, 100% {
    transform: translateZ(0) scale(1);
    filter: drop-shadow(0 0 10px rgba(180, 226, 255, 0.35));
  }
  50% {
    transform: translateZ(0) scale(1.045);
    filter: drop-shadow(0 0 18px rgba(196, 235, 255, 0.55));
  }
}


/* Clear heartbeat state: visible even when previous pulse looked static. */
.ai-avatar {
  position: absolute;
  isolation: isolate;
  will-change: transform, filter, opacity;
  animation: lumi-float 2.2s ease-in-out infinite;
}

/* Decorative halo behind the orb — REMOVED 2026-05-13.
   The animation was disabled (clean18) but `transform: none !important;`
   in the disable block was overriding the centering translate, leaving
   the 92×92 halo positioned at top-left=(50%, 50%) of the orb container
   instead of centered. Overflow:hidden then clipped it to a rectangle
   visible next to the orb. Figma F0 has NO such halo on the orb — the
   sphere PNG already carries its own glow. Removing the pseudo entirely
   is the clean fix. */
.ai-avatar::before {
  content: none;
}

.ai-avatar img {
  animation: lumi-core 1.3s ease-in-out infinite;
  transform-origin: 50% 55%;
}

@keyframes lumi-float {
  0%, 100% { transform: translateY(0px); }
  50% { transform: translateY(-3px); }
}

@keyframes lumi-core {
  0%, 100% { transform: scale(1); filter: drop-shadow(0 0 10px rgba(176, 228, 255, 0.40)); }
  35% { transform: scale(1.06); filter: drop-shadow(0 0 18px rgba(190, 236, 255, 0.62)); }
  70% { transform: scale(1.02); filter: drop-shadow(0 0 13px rgba(182, 232, 255, 0.50)); }
}

@keyframes lumi-heart {
  0% { transform: translate(-50%, -50%) scale(0.84); opacity: 0.35; }
  70% { transform: translate(-50%, -50%) scale(1.22); opacity: 0.14; }
  100% { transform: translate(-50%, -50%) scale(1.36); opacity: 0; }
}


/* clean18: heartbeat belongs on monday<->floor-agent connector, not on Lumi */
.ai-avatar,
.ai-avatar::before,
.ai-avatar img {
  animation: none !important;
  transform: none !important;
}

.figma-stage[data-screen]:not([data-screen="F0"]) .dash-box {
  position: absolute;
  overflow: visible;
}

.figma-stage[data-screen]:not([data-screen="F0"]) .dash-emoji {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%) scale(1);
  font-size: 22px;
  line-height: 1;
  opacity: 0.95;
  filter: drop-shadow(0 0 10px rgba(133, 233, 248, 0.6));
  animation: none;
  will-change: transform, opacity, filter;
  pointer-events: none;
}

.figma-stage[data-screen]:not([data-screen="F0"]) .agent-dashes .dash {
  animation: none;
}

/* While a floor is running, the emoji + dashes pulse continuously so
   the dreamer can see something is happening. Restored 2026-05-13 from
   the previous "15-second-only-blink-once" cycle (which was effectively
   invisible). The pulse stops when the floor reaches PASS. */
/* User 2026-05-15 (later): restore the white centre square (.dash-box)
   on F1 + F2 so the dashed connector reads as 3-dashes + box + 3-dashes
   per Figma. Keep .dash-emoji hidden — the box stays empty (no agent
   emoji), matching the static "currently in progress" feel. */
.figma-stage[data-screen]:not([data-screen="F0"]) .dash-emoji {
  display: none;
}

/* User 2026-05-15: "only pulsing dashed lines and three colorful dots
   inside the rectangle" — drop the .heartbeat-active gate so the
   dashes pulse by default on every non-F0 floor. The poller that used
   to add .heartbeat-active is no longer running in the Next.js port. */
.figma-stage[data-screen]:not([data-screen="F0"]) .agent-dashes .dash {
  animation: connector-dash-pulse 1.6s ease-in-out infinite;
}

/* Avatar pulse removed 2026-05-15 — user feedback "avatar pulse looks
   broken". The dashed-line pulse alone is the activity signal now. */

@keyframes connector-emoji-pulse {
  0%, 100% {
    transform: translate(-50%, -50%) scale(1);
    filter: drop-shadow(0 0 8px rgba(133, 233, 248, 0.5));
    opacity: 0.85;
  }
  50% {
    transform: translate(-50%, -50%) scale(1.18);
    filter: drop-shadow(0 0 16px rgba(244, 174, 245, 0.75));
    opacity: 1;
  }
}

@keyframes connector-dash-pulse {
  0%, 100% { opacity: 0.6; }
  50%      { opacity: 1;   }
}

/* User 2026-05-15: "I want this three dots to show pulse of floor,
   also the dashed lines next to it. Nice animation flow."
   ── 3 small dots inside .dash-box pulse in sequence (typing-indicator
      pattern), and the 6 dashes form a continuous wave from monday →
      box → agent. Active on F1/F2 (non-F0) by default — no heartbeat-
      active class needed. */
.figma-stage[data-screen]:not([data-screen="F0"]) .box-pulse-dots {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  pointer-events: none;
}
.figma-stage[data-screen]:not([data-screen="F0"]) .box-pulse-dot {
  width: 6px;
  height: 6px;
  border-radius: 999px;
  animation: box-dot-pulse 1.2s ease-in-out infinite;
}
/* User 2026-05-15: "three colorful dots inside the rectangle" — match
   the Lumi prompt-card dot palette (green / pink / blue from .dot-green,
   .dot-pink, .dot-blue). Each dot pulses with a 0.2s stagger so the eye
   reads them as a left-to-right wave. */
.figma-stage[data-screen]:not([data-screen="F0"]) .box-pulse-dot.pd1 {
  background: linear-gradient(90deg, #8dfab0, #9ff7b2);
  box-shadow: 0 0 6px rgba(141, 250, 176, 0.55);
  animation-delay: 0s;
}
.figma-stage[data-screen]:not([data-screen="F0"]) .box-pulse-dot.pd2 {
  background: linear-gradient(90deg, #f886e5, #f4aef5);
  box-shadow: 0 0 6px rgba(248, 134, 229, 0.55);
  animation-delay: 0.2s;
}
.figma-stage[data-screen]:not([data-screen="F0"]) .box-pulse-dot.pd3 {
  background: linear-gradient(90deg, #86e9f8, #85d5e6);
  box-shadow: 0 0 6px rgba(134, 233, 248, 0.55);
  animation-delay: 0.4s;
}

/* User 2026-05-19: punchier — a big scale + opacity swing so the
   working-floor pulse is unmistakably moving. */
@keyframes box-dot-pulse {
  0%, 100% { opacity: 0.18; transform: scale(0.5); }
  50%      { opacity: 1;    transform: scale(1.55); }
}

/* Dash wave — always-on for F1/F2. Each dash fires the pulse with an
   incremental delay so the eye perceives a left-to-right flow that
   converges on the box, then continues out to the agent. */
.figma-stage[data-screen]:not([data-screen="F0"]) .agent-dashes .dash {
  animation: connector-dash-wave 1.6s ease-in-out infinite;
}
.figma-stage[data-screen]:not([data-screen="F0"]) .agent-dashes .dash.d1 { animation-delay: 0.00s; }
.figma-stage[data-screen]:not([data-screen="F0"]) .agent-dashes .dash.d2 { animation-delay: 0.12s; }
.figma-stage[data-screen]:not([data-screen="F0"]) .agent-dashes .dash.d3 { animation-delay: 0.24s; }
.figma-stage[data-screen]:not([data-screen="F0"]) .agent-dashes .dash.d4 { animation-delay: 0.48s; }
.figma-stage[data-screen]:not([data-screen="F0"]) .agent-dashes .dash.d5 { animation-delay: 0.60s; }
.figma-stage[data-screen]:not([data-screen="F0"]) .agent-dashes .dash.d6 { animation-delay: 0.72s; }

@keyframes connector-dash-wave {
  0%, 100% { opacity: 0.22; transform: translateY(0) scaleY(1); }
  50%      { opacity: 1;    transform: translateY(-5px) scaleY(1.6); }
}

@keyframes single-agent-pulse {
  0%, 100% {
    transform: scale(1);
    filter: drop-shadow(0 0 8px rgba(133, 233, 248, 0.35));
  }
  50% {
    transform: scale(1.05);
    filter: drop-shadow(0 0 14px rgba(244, 174, 245, 0.55));
  }
}



/* clean20 final positioning and visibility fixes */
.single-agent {
  top: 164px !important;
  height: 156px !important;
}

.single-agent .team-name {
  top: 0 !important;
  height: 63px !important;
}

.single-agent .team-avatar {
  top: 51px !important;
}

.single-agent .team-role {
  top: 132px !important;
  min-height: 25px !important;
}

.figma-stage[data-screen]:not([data-screen="F0"]) .dreamer-ring,
.figma-stage[data-screen="F0"] .dreamer-ring {
  display: block !important;
  z-index: 48 !important;
  opacity: 1 !important;
}


/* clean21 css stabilization */
.figma-stage {
  -webkit-font-smoothing: antialiased;
  text-rendering: geometricPrecision;
}

/* Final source-of-truth for F1/F2/F3 agent geometry */
.single-agent {
  top: 164px !important;
  left: 912px !important;
  width: 259px !important;
  height: 156px !important;
}
.single-agent .team-name { top: 0 !important; height: 63px !important; }
.single-agent .team-avatar { top: 51px !important; left: 93px !important; }
.single-agent .team-role { top: 132px !important; min-height: 25px !important; }

/* Keep Dreamer avatar always visible */
.dreamer-ring {
  z-index: 48 !important;
  opacity: 1 !important;
  display: block !important;
  visibility: visible !important;
}

/* Inputs/Outputs panel should not expose internal notes */
.inputs-panel .parked-fallback-list { display: none !important; }
.inputs-panel .panel-head { white-space: nowrap; }

/* Card text stability */
.prompt-body {
  overflow-y: auto !important;
  overflow-x: hidden !important;
}
.figma-textarea {
  /* Batch 9.5 (2026-05-20): the decorative .lumi-typing-cursor is
     killed (display: none below). The native browser caret returns
     in the universal DxD cyan. Matches every other input. */
  color: #f4f4f6 !important;
  caret-color: #85d5e6 !important;
}

.lumi-typing-cursor { display: none !important; }

.prompt-body a,
.prompt-card a {
  color: #9fe7f4 !important;
  text-decoration: underline !important;
  text-underline-offset: 2px;
}

/* Inline "log in" link at F2 PASS — a real button-like trigger inside
   the Lumi message. Separate from the next-arrow (which submits email);
   this one navigates to the login stub. */
.prompt-body a.lumi-inline-login,
.prompt-card a.lumi-inline-login {
  color: #d8bdf1 !important;
  font-weight: 800;
  cursor: pointer;
  text-decoration-color: rgba(216, 189, 241, 0.6) !important;
  transition: color 0.15s, text-decoration-color 0.15s;
}

.prompt-body a.lumi-inline-login:hover,
.prompt-card a.lumi-inline-login:hover {
  color: #f4aef5 !important;
  text-decoration-color: #f4aef5 !important;
}

.figma-stage[data-screen="F3"] .prompt-body p {
  margin: 0 0 12px 0;
  line-height: 1.44;
}

.figma-stage[data-screen="F3"] .prompt-body ul {
  margin: 8px 0 12px 0;
  padding-left: 18px;
}

.figma-stage[data-screen="F3"] .prompt-body li {
  margin: 0 0 8px 0;
  line-height: 1.42;
}

/* Connector heartbeat only (Lumi remains static) */
.ai-avatar, .ai-avatar::before, .ai-avatar img {
  animation: none !important;
  transform: none !important;
}


/* clean24 upload panel styling */
.inputs-upload-wrap {
  position: absolute;
  left: 14px;
  right: 14px;
  top: 58px;
  bottom: 58px;
  overflow: auto;
}
.inputs-empty {
  margin: 10px;
  padding: 10px 12px;
  border: 1px dashed rgba(255,255,255,0.22);
  border-radius: 10px;
  color: rgba(255,255,255,0.72);
  font-size: 13px;
  font-weight: 600;
}
.inputs-upload-list {
  list-style: none;
  margin: 0;
  padding: 0 4px 8px;
  display: grid;
  gap: 8px;
}
.inputs-upload-item {
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 10px;
  background: rgba(255,255,255,0.04);
  padding: 8px 10px;
}
.inputs-upload-item .file-name {
  color: #f4f4f6;
  font-size: 12px;
  font-weight: 700;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.inputs-upload-item .file-meta {
  margin-top: 2px;
  color: rgba(255,255,255,0.68);
  font-size: 11px;
  font-weight: 600;
}

/* F0 only — Next button sits ABOVE the Dreamer avatar with a 16px gap,
   per Figma file jTJhFMdTvwR91g8x8Z5WKb node 63:235:
     - 63:290 (next button)   left=834 top=904 size=60×60
     - 63:286 (dreamer ring)  left=828 top=980 size=72×72
   The base .next-button rule (line 719) places it at top=1082 which is
   below the dreamer — correct for F1/F2/F3 (kept by :not(F0) selector
   on line 852). On F0 the order flips: button up, avatar down. The
   16px gap (980 - (904+60) = 16) is the user-quoted spacing 2026-05-14. */
.figma-stage[data-screen="F0"] .next-button {
  /* User 2026-05-15: F0 row restructure shifted everything below the
     agent-row up by 73 px. Next-button-above-dreamer follows: 904 → 831.
     Then "dreamer and next buttons went way down, move them together"
     — dreamer-ring + next-button both −73 to keep them glued.
     Then another −5 with below-agents shift → 758 → 753. */
  top: 753px !important;
}
.figma-stage[data-screen="F1"] .next-button,
.figma-stage[data-screen="F2"] .next-button {
  /* F1/F2 unaffected by the F0 row restructure — keep above-dreamer
     at 904. */
  top: 904px !important;
}

/* F1 is BEFORE outputs exist — always greyed regardless of polling
   state (the API defaults aria-disabled to false in some env). For F2
   we keep aria-disabled-gated behaviour so it flips to enabled at PASS. */
.figma-stage[data-screen="F1"] .download-button {
  opacity: 0.45 !important;
  cursor: not-allowed !important;
  pointer-events: none;
}
.figma-stage[data-screen="F2"] .download-button[aria-disabled="true"] {
  opacity: 0.45 !important;
  cursor: not-allowed !important;
  pointer-events: none;
}

/* User 2026-05-15: F2 dash padding matches F1 — agent↔dash 20 design
   px instead of the default 8. Same symmetric layout: 3 dashes +
   box + 3 dashes between monday (680, right=752) and Grok (1015). */
.figma-stage[data-screen="F2"] .dash.d1 { left: 772px !important; }
.figma-stage[data-screen="F2"] .dash.d2 { left: 802px !important; }
.figma-stage[data-screen="F2"] .dash.d3 { left: 832px !important; }
.figma-stage[data-screen="F2"] .dash.d4 { left: 913px !important; }
.figma-stage[data-screen="F2"] .dash.d5 { left: 943px !important; }
.figma-stage[data-screen="F2"] .dash.d6 { left: 973px !important; }
.figma-stage[data-screen="F2"] .dash-box { left: 859px !important; }

/* User 2026-05-15: align Grok/Gemini label boxes with monday's.
   The .single-agent .team-name was forced to height:63 + top:0 by
   an earlier !important rule, while .member-monday .team-name kept
   the default height:40 + top:2. These overrides re-align the
   partner's label box to monday's spec on F1 AND F2 (so both audit
   floors share one visual rhythm). */
.figma-stage[data-screen="F1"] .single-agent .team-name,
.figma-stage[data-screen="F2"] .single-agent .team-name {
  top: 2px !important;
  height: 40px !important;
}
.figma-stage[data-screen="F1"] .single-agent .team-role,
.figma-stage[data-screen="F2"] .single-agent .team-role {
  top: 129px !important;
  height: 28px !important;
  min-height: 28px !important;
}

/* ═══════════════════════════════════════════════════════════════════
   User 2026-05-15: "match UI of floor 1, 2 and 2.1 to F0 — elements
   below the agent need to go up."

   The non-F0 floors had accumulated a separate set of layout
   coordinates (agent row at y=164, panels at 282, lower-card at 642,
   Lumi at 591, dreamer/next at 980/904) while F0 was tuned to a
   tighter layout (agents at 4, panels 195, lower-card 555, Lumi 411,
   dreamer 829, next 753). This authoritative block — last in the
   cascade, so it wins — pins EVERY non-F0 floor to F0's exact
   coordinates. F1/F2/F2.1 are now visually identical to F0; the only
   difference is the agent-row CONTENT (F0: logo + 4 members; non-F0:
   monday + one single-agent + the pulsing dashed connector, no logo).
   ═══════════════════════════════════════════════════════════════════ */

/* Agent row → F0's y=4 (was 164). */
.figma-stage[data-screen]:not([data-screen="F0"]) .member-monday,
.figma-stage[data-screen]:not([data-screen="F0"]) .single-agent {
  top: 4px !important;
}
/* Pulsing connector follows the agent row up. F0 avatar centre sits at
   design y≈89 (team.top 4 + avatar.top 49 + 36). Dashes (5 tall) centre
   there → top 87; the box (43 tall) → top 68. */
.figma-stage[data-screen]:not([data-screen="F0"]) .agent-dashes .dash {
  top: 87px !important;
}
.figma-stage[data-screen]:not([data-screen="F0"]) .dash-box {
  top: 68px !important;
}

/* Below-agent elements → F0 coordinates. */
.figma-stage[data-screen]:not([data-screen="F0"]) .panel {
  top: 195px !important;
}
.figma-stage[data-screen]:not([data-screen="F0"]) .prompt-card {
  top: 195px !important;
}
.figma-stage[data-screen]:not([data-screen="F0"]) .lower-card {
  top: 555px !important;
}
.figma-stage[data-screen]:not([data-screen="F0"]) .ai-avatar {
  top: 411px !important;
  width: 134px !important;
  height: 180px !important;
}
.figma-stage[data-screen]:not([data-screen="F0"]) .dreamer-ring {
  top: 829px !important;
}
.figma-stage[data-screen]:not([data-screen="F0"]) .next-button {
  top: 753px !important;
}
/* Lumi typing-cursor static fallback → F0's y (the JS repositions it
   live on input; this only governs the empty-textarea rest state). */
.figma-stage[data-screen]:not([data-screen="F0"]) .lumi-typing-cursor {
  top: 578px !important;
}
