/* public/css/builder-chat.css — Phase 2 of the refactor (REFACTOR_PLAN.md §7).
   Copied verbatim from public/dashboard-v2.css ranges:
     3853..5622  (chat surface + empty/loading + form/choice cards + Lovable flow + launch-done)
     6750..7124  (inline form-card chat-message)
     12313..12550 (refinement protocol action UI)
*/

/* === Claude-style chat surface ========================================
   Empty state: vertically-centered logo + serif greeting + rounded
   input + suggestion chips. No page header. When state="ready",
   layout becomes 2-column (chat left, preview right that slid in). */

/* Plan footer ("Builder · A$39.99/mo · Renews 28 May | Billing · Support")
   doesn't belong on the chat surface. Hide whenever the AI builder is
   mounted, regardless of state. */
main.dash:has(.builder-shell--centered) .foot { display: none !important; }

/* Sidebar collapse for first-run AI Builder users.
   Body class `is-builder-firstrun` is added by JS on AI builder mount
   when there's no site yet, removed when state transitions to ready.
   The sidebar slides out + the content area fills the freed width.
   The existing .side-opener button stays visible as a tiny hamburger
   so the user can still navigate if they want.
   ====================================================================== */
body.is-builder-firstrun .side {
  transform: translateX(-100%);
  pointer-events: none;
}
/* Builder chat surface (Lovable-style): sidebar hidden so the chat
   gets full-bleed width. Body class added by the AI builder shell on
   mount, removed when navigating away. */
body.is-builder-chat .side {
  transform: translateX(-100%);
  pointer-events: none;
}
/* Mobile exception: the drawer pattern relies on the sidebar sitting
   in place at left:0 with the card sliding over/away from it. The
   desktop builder rule above pushes the sidebar fully off-screen
   for the full-bleed preview, which breaks the drawer on mobile
   (tap hamburger → card slides right → reveals empty space because
   the sidebar isn't there). Restore the mobile drawer behaviour
   by reverting the transform + pointer-events at narrow widths. */
@media (max-width: 720px) {
  body.is-builder-chat .side {
    transform: none;
    pointer-events: auto;
  }
  /* The .shell carries padding-top: 52px on mobile to clear the
     topbar. But on this page the topbar is position:sticky (see
     inline rule at dashboard-v2-page.html:5634), so it already takes
     52px of flow — adding shell padding too would leave a 52px gap
     above the chat surface and the sidebar would show through it.
     Zero both the shell padding AND the prior main.dash padding-top
     reset (which was a leftover from when the topbar was assumed to
     be position:fixed). The topbar's own z-index:70 keeps it above
     everything, so no extra offset is needed. */
  body.is-builder-chat .shell { padding-top: 0 !important; }
  body.is-builder-chat .shell > main.dash { padding-top: 0 !important; }
  /* Founder ask 2026-05-29 — chat messages were sitting too far from
     the viewport edges on mobile. The base .dash rule sets 18px
     horizontal padding (mobile breakpoint at line 1370) which adds up
     with the chat-pane wrap to a visible ~30px indent. Tighten to 10px
     in builder-chat mode so AI text + user bubbles read closer to the
     screen edges (Lovable/ChatGPT pattern). */
  body.is-builder-chat .shell > main.dash {
    padding-left: 10px !important;
    padding-right: 10px !important;
  }
}
body.is-builder-chat .shell {
  grid-template-columns: 1fr !important;
}
body.is-builder-chat .shell > main.dash {
  grid-column: 1 / -1 !important;
}
/* Builder mode replaces the side-opener corner icon with a Back button. */
body.is-builder-chat .side-opener {
  display: none !important;
}
.builder-back-btn {
  display: none;
  position: fixed;
  top: 14px;
  left: 14px;
  z-index: 60;
  align-items: center;
  gap: 6px;
  padding: 7px 12px 7px 9px;
  border: 1px solid var(--hairline-2);
  border-radius: 8px;
  background: var(--paper, var(--cream-2));
  color: var(--ink-mute);
  text-decoration: none;
  font-family: inherit;
  font-size: 0.82rem;
  font-weight: 500;
  letter-spacing: -0.005em;
  cursor: pointer;
  box-shadow: 0 1px 2px rgba(0,0,0,0.06);
  transition: background 0.18s cubic-bezier(0.22, 1, 0.36, 1), color 0.18s, border-color 0.18s, transform 0.18s cubic-bezier(0.22, 1, 0.36, 1), box-shadow 0.18s;
}
.builder-back-btn:hover {
  color: var(--ink);
  background: var(--cream-3, #F7F7F7);
  border-color: var(--hairline);
  box-shadow: 0 4px 14px -6px rgba(31, 22, 17, 0.20);
  transform: translateX(-1px);
}
.builder-back-btn:active { transform: translateX(0); }
.builder-back-btn svg { display: block; transition: transform 0.18s cubic-bezier(0.22, 1, 0.36, 1); }
.builder-back-btn:hover svg { transform: translateX(-2px); }
body.is-builder-chat .builder-back-btn { display: inline-flex; }
/* Mobile: tuck the floating Back pill away when the drawer is open so
   it doesn't sit on top of the sidebar header. The sidebar's nav links
   already give the user a way out, so the Back affordance is redundant
   in that state. */
@media (max-width: 720px) {
  /* 2026-05-22 — burger menu covers the same top-left slot on mobile
     and opens the drawer (which contains the same nav as Back); the
     floating Back pill ends up duplicated underneath the burger and
     visible at the edge as "ack". Hide it on all mobile builder
     states; desktop still gets the inline-flex back affordance. */
  body.is-builder-chat .builder-back-btn { display: none !important; }
}
body.is-builder-firstrun .pg,
body.is-builder-firstrun .dashboard-shell {
  grid-template-columns: 1fr !important;
}
body.is-builder-firstrun .side-opener {
  display: inline-flex !important;
}

.builder-shell--centered {
  grid-template-columns: 1fr;
  width: 100% !important;
  max-width: 880px !important;
  margin: 0 auto !important;
  gap: 0;
  /* Was 120px — that pushed the input bar visibly higher than the
     viewport bottom. 32px keeps it near the bottom edge while still
     clearing the optional verify-email banner. */
  height: calc(100vh - 32px);
  min-height: 580px;
  transition: max-width 0.5s cubic-bezier(0.65, 0, 0.35, 1);
}
/* Zero out main.dash bottom padding under the AI builder so the input
   bar isn't lifted off the viewport bottom by page chrome. */
main.dash:has(.builder-shell--centered) { padding-bottom: 0 !important; }

/* Ready state needs the parent .dash cap lifted too. The base .dash
   rule sets max-width: 940px + 32px side padding, so even with
   .builder-shell--centered going `width: 100% !important; max-width:
   none !important`, "100%" only fills 940px of the viewport — leaving
   the preview pane centered with empty space on either side. Drop the
   cap + side padding only while the builder is in ready state. */
main.dash:has(.builder-shell--centered[data-builder-state="ready"]) {
  max-width: none !important;
  padding-left: 0 !important;
  padding-right: 0 !important;
}
/* Ready state: Lovable-style split layout. Narrow chat column on the
   left holds the full conversation history + refine composer. Wide
   preview column on the right holds the iframe, edge-to-edge. The
   shell goes full-bleed (the .builder-shell--centered base rule has
   max-width: 880px !important so we have to !important the override
   too). */
.builder-shell--centered[data-builder-state="ready"] {
  /* 50/50 even split per founder. Mins kick in below ~1000px
     viewport, stacking via the mobile media query at line 4875. */
  grid-template-columns: minmax(420px, 1fr) minmax(520px, 1fr) !important;
  max-width: none !important;
  width: 100% !important;
  margin: 0 !important;
  gap: 16px;
  padding: 0;
}
.builder-shell--centered .builder-preview-pane { display: none; }
.builder-shell--centered[data-builder-state="ready"] .builder-preview-pane {
  display: flex;
  width: 100%;
  min-width: 0;
  animation: builderPreviewSlideIn 0.55s cubic-bezier(0.22, 1, 0.36, 1);
}
@keyframes builderPreviewSlideIn {
  from { opacity: 0; transform: translateX(24px); }
  to   { opacity: 1; transform: translateX(0); }
}

/* Chat pane — drops all card chrome in the centered/empty state. */
.builder-shell--centered .builder-chat-pane {
  border: 0;
  background: transparent;
  display: flex;
  flex-direction: column;
  /* Side padding 0 here is overridden downstream by higher-specificity
     state rules; the founder-facing message inset (2026-06-02) is applied
     to the message rows themselves via the inline rule in
     dashboard-v2-page.html (which wins the cascade). Bottom padding lifts
     the composer off the page edge. */
  padding: 0 0 22px;
  width: 100% !important;
  min-width: 0;
  box-sizing: border-box;
  /* Default (empty): centre everything vertically. */
  justify-content: center;
}
/* 2026-05-16 v4: founder feedback — "the text after I clicked build
   my site is stuck to the bottom text bar". The old rule used
   `justify-content: flex-end` when the chat had content, which pinned
   ALL chat rows to the bottom of the pane and pushed the new AI reply
   right up against the composer. Switch to `flex-start` so the chat
   body fills from the top and scrolls naturally; the composer stays
   at the bottom because chat-body has `flex: 1 1 auto`. Adds breathing
   room between the latest message and the composer. */
.builder-shell--centered .builder-chat-pane:has(.builder-chat-body:not(:empty)) {
  justify-content: flex-start;
}

.builder-chat-body {
  flex: 1 1 auto;
  overflow-y: auto;
  min-height: 0;
  /* Bottom padding inside the scroll viewport so the last message
     never sits flush against the composer when scrolled to the end. */
  padding-bottom: 24px;
  /* Flex-column so the content block can anchor to the bottom of the
     scroll viewport when shorter than it. Without this, a short
     form-card / first AI message sits at the top of the chat-body with
     a yawning gap above the composer (because chat-body fills the
     pane). Pairing display:flex+flex-direction:column with
     margin-top:auto on the first child lifts the entire content block
     to the bottom edge — every "last item" (form's Build button,
     latest AI reply, user message) ends up the same hairline gap above
     the chat bar that shellSyncChatPanePadBot reserves. When content
     overflows, auto resolves to 0 and the scroll behaves normally. */
  display: flex;
  flex-direction: column;
}
/* Specificity-boosted (2 classes + pseudo) to beat
   .builder-msg-timestamp:first-child { margin-top: 8px } at line 3760. */
.builder-shell--centered .builder-chat-body > :first-child { margin-top: auto !important; }
/* 2026-05-22 founder ask — on mobile, stack chat content from the TOP
   of chat-body instead of pinning it to the bottom. Previously the
   auto-margin above pushed short chats down toward the composer so
   the first message ended up well below the topbar fade band — that
   left a visible cream gap above the chat and meant the fade band had
   no content to actually fade. With margin-top: 0 the first message
   sits flush with the top of chat-body (behind the topbar at y=0),
   so messages scroll up through the fade band naturally and the
   topbar's blur always has real content to work on. Desktop keeps
   the auto-margin (chat-pane has its own composer-aligned layout). */
@media (max-width: 720px) {
  .builder-shell--centered:not([data-builder-state="ready"]) .builder-chat-body > :first-child {
    margin-top: 0 !important;
  }
}
.builder-chat-body:empty { display: none; flex: 0; padding-bottom: 0; }

/* Empty hero block — logo + serif italic greeting on a single horizontal row.
   2026-05-12: shrunk for Lovable parity. Previous clamp(2.2,3) was bigger
   than Lovable's headline; 1.65-2.2rem lands closer without going so small
   that the page feels timid. Logo dropped 56→36 to stay paired. */
.builder-empty-hero {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  margin: 0 auto 24px;
}
.builder-empty-mark { display: inline-flex; align-items: center; }
.builder-empty-mark img {
  display: block;
  width: 36px;
  height: 36px;
}
/* Refine mode (returning user with a live site): drop the diamond logo
   above the greeting. It pulls attention away from the "Want to refine
   your website?" headline and from the orange wave illustration. The
   logo stays on the cold-start "Let's build your website." state where
   it gives the empty hero some visual weight. */
body.has-live-site .builder-empty-mark { display: none; }
.builder-empty-greeting {
  font-family: 'Newsreader', Georgia, serif;
  font-style: italic;
  font-weight: 500;
  font-size: clamp(1.65rem, 2.8vw, 2.2rem);
  letter-spacing: -0.02em;
  color: var(--ink);
  margin: 0;
  line-height: 1.15;
  text-align: left;
}
.builder-chat-pane:has(.builder-chat-body:not(:empty)) .builder-empty-hero { display: none; }

/* Instruction line — calm, single-sentence under the hero. Auto-hidden
   once the chat thread starts. */
.builder-instruction {
  text-align: center;
  font-size: 0.95rem;
  color: var(--ink-mute);
  margin: 0 auto 28px;
  max-width: 540px;
  line-height: 1.5;
}
.builder-chat-pane:has(.builder-chat-body:not(:empty)) .builder-instruction { display: none; }

/* Refine-mode (set by dashboard-v2.js when the user already has at least
   one generated site): the trade-name chips beneath the chat input are
   build prompts ("Sparky in Newtown..."), not refine prompts. Hide them
   so the home-page chat reads cleanly as "tell me what to change about
   your existing site" instead of mixing creation and iteration. */
.is-refine-mode .builder-suggestion-row { display: none; }

/* === Avatar pattern for AI messages (Claude / ChatGPT style) ===
   AI message rows are flex with the BookingSprint logo on the left,
   message body to the right. AI messages drop the bubble background
   and read as flowing text. User messages stay right-aligned bubbles. */
.builder-msg-row {
  display: flex;
  gap: 12px;
  align-items: flex-start;
  /* 2026-05-09: bump vertical spacing between message rows. The thread
     was reading as a wall of text — Lovable / ChatGPT both let messages
     breathe with ~16-22px between rows. */
  margin: 16px 0 0;
  /* Premium reveal — every chat row eases in instead of snapping. */
  animation: builderRowEnter 0.4s cubic-bezier(0.22, 1, 0.36, 1) both;
}
.builder-msg-row:first-child { margin-top: 0; }
/* User-after-AI gets a wider gap than AI-after-user, so the rhythm of
   "user asks, AI answers" reads as paired turns rather than a flat list. */
.builder-msg-row.is-user { margin-top: 26px; }
.builder-msg-row.is-ai + .builder-msg-row.is-user { margin-top: 32px; }

/* Centered timestamp divider above user messages — Lovable-style.
   Format: "May 5 at 11:20 AM" — lets the user place the conversation
   in time without having to hover or open a tooltip. */
.builder-msg-timestamp {
  text-align: center;
  font-size: 0.78rem;
  color: var(--ink-mute);
  opacity: 0.7;
  margin: 28px 0 12px;
  letter-spacing: 0.01em;
}
.builder-msg-timestamp:first-child { margin-top: 8px; }

/* Action row under each AI message — retry / thumbs / copy / more.
   Quiet at rest, slightly more visible on hover. Persists in the DOM
   so users don't have to hover the message to find them; the icons
   themselves are muted enough to recede until needed. */
.builder-msg-actions {
  display: flex;
  align-items: center;
  /* 2026-05-24 — minimal icon row, no pill. Tight to the message
     above via small negative margin; -4px left aligns the first
     icon's hit-box with the message's left edge. */
  gap: 0;
  margin: -2px 0 0 -4px;
  padding: 0;
}
.builder-msg-action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  background: transparent;
  border: 0;
  border-radius: 5px;
  color: var(--ink-mute);
  cursor: pointer;
  opacity: 0.6;
  transition: opacity 0.15s, background 0.15s, color 0.15s, transform 0.18s;
}
/* Override the inline width/height on the SVGs (set to 14px in JS) so
   the visible glyph shrinks alongside the button. CSS wins over inline
   attrs for SVG sizing in modern browsers. */
.builder-msg-action svg { width: 12px !important; height: 12px !important; }
.builder-msg-action:hover {
  opacity: 1;
  color: var(--ink);
  background: rgba(31, 22, 17, 0.06);
}
.builder-msg-action:active { transform: scale(0.94); }
.builder-msg-action.is-on {
  opacity: 1;
  color: var(--ink);
  background: rgba(31, 22, 17, 0.08);
}
/* Copy success — short tick state. */
.builder-msg-action.is-copied {
  opacity: 1;
  color: var(--ink);
  background: rgba(31, 22, 17, 0.08);
}
.builder-msg-action.is-copied svg { display: none; }
.builder-msg-action.is-copied::after {
  content: '';
  width: 10px;
  height: 10px;
  border: 2px solid currentColor;
  border-top: 0;
  border-right: 0;
  transform: rotate(-50deg) translate(1px, -1px);
}
@keyframes builderRowEnter {
  0%   { opacity: 0; transform: translateY(6px); }
  100% { opacity: 1; transform: translateY(0); }
}
.builder-msg-row.is-user {
  justify-content: flex-end;
  /* 2026-05-24 — scrollIntoView({block:'start'}) on a user row anchors
     it flush with the scroll container's top edge, but the fixed
     topbar (52px) overlays that area so the message ends up tucked
     UNDER the topbar. scroll-margin-top reserves room above the
     anchor target so the row lands just below the topbar with a small
     breathing gap, instead of disappearing behind it. */
  scroll-margin-top: 88px;
}
@media (prefers-reduced-motion: reduce) {
  .builder-msg-row { animation: none; }
}
.builder-msg-avatar {
  width: 26px;
  height: 26px;
  flex-shrink: 0;
  margin-top: 4px;
  border-radius: 4px;
}
/* 2026-05-16 v4: founder asked for no logos in the chat thread.
   Hide the AI anchor entirely as a CSS safety net even if some code
   path still calls shellPlaceAiAnchor — only the empty-state hero
   shows the brand mark now. */
.builder-ai-anchor,
[data-builder-ai-anchor] {
  display: none !important;
}
.builder-ai-anchor--legacy {
  display: flex;
  align-items: center;
  padding: 8px 0 4px;
  margin-top: 2px;
}
.builder-ai-anchor img {
  display: block;
  width: 20px;
  height: 20px;
  opacity: 0.85;
  transform-origin: center;
}
@keyframes builderAnchorBreathe {
  0%, 100% { opacity: 0.45; transform: scale(0.94); }
  50%      { opacity: 1.00; transform: scale(1.04); }
}
@media (prefers-reduced-motion: reduce) {
  .builder-ai-anchor img { animation: none; opacity: 0.7; }
}
/* Override the legacy bubble for AI messages inside the row wrapper —
   plain text reads better with the single anchor logo beneath the
   latest reply (Lovable pattern). */
.builder-msg-row.is-ai .builder-msg {
  background: transparent !important;
  color: var(--ink) !important;
  align-self: auto !important;
  max-width: none;
  padding: 2px 0;
  /* 2026-05-24 founder: bumped to 1.06rem for a touch more readability. */
  font-size: 1.06rem;
  line-height: 1.5;
}
/* Auto-linkified URLs inside AI messages (e.g. "your site is live at
   smithys.bookingsprint.com"). Warm-stone palette, underline on hover. */
.builder-msg-link {
  color: var(--orange-deep, #c2470a);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
  font-weight: 500;
}
.builder-msg-link:hover {
  text-decoration-thickness: 1.5px;
}
/* User bubbles stay as bubbles, max-width 75% so they don't span the
   full row when long. */
.builder-msg-row.is-user .builder-msg {
  /* Widened from 75% so user pills reach closer to the screen edge,
     matching Lovable's pattern. */
  max-width: 92%;
  /* 2026-05-24 founder: bumped to 1rem for a touch more readability.
     Overrides the .builder-msg base size (L8449). */
  font-size: 1rem;
}

/* Submission card — USER-side recap of the brief, rendered after the
   user clicks Build my site. Reads as the user's structured answer to
   the form question. Cream-stone bubble matching standard user-bubble
   styling, with key/value rows for each captured field. Right-aligned
   automatically via `.builder-msg-row.is-user { justify-content: flex-end }`. */
.builder-msg.is-user.builder-submission-card {
  display: flex !important;
  flex-direction: column;
  gap: 8px;
  padding: 14px 18px !important;
  border-radius: 14px !important;
  text-align: left;
  font-size: 0.875rem;
  line-height: 1.45;
  min-width: 260px;
  max-width: 420px;
  background: var(--cream-3, #E5E3DD) !important;
  color: var(--ink, #1F1611) !important;
  border: 1px solid rgba(31, 22, 17, 0.06) !important;
  box-shadow: 0 1px 2px rgba(31, 22, 17, 0.04);
}
.builder-submission-row {
  display: flex;
  justify-content: space-between;
  gap: 18px;
  align-items: baseline;
}
.builder-submission-label {
  color: rgba(31, 22, 17, 0.50);
  font-size: 0.72rem;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  flex-shrink: 0;
}
.builder-submission-value {
  font-weight: 500;
  text-align: right;
  color: var(--ink, #1F1611);
  word-break: break-word;
}

/* === Loading animation === pulsing BookingSprint logo where the
   AI avatar would go. Used in place of the "..." typing indicator
   while a chat turn is in flight. */
.builder-loading-msg {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 12px;
  padding: 4px 0;
}
.builder-loading-logo {
  display: inline-block;
  width: 26px;
  height: 26px;
  animation: builderLogoPulse 1.4s ease-in-out infinite;
  transform-origin: center;
}
@keyframes builderLogoPulse {
  0%   { opacity: 0.45; transform: scale(0.92) rotate(0deg); }
  50%  { opacity: 1;    transform: scale(1.06) rotate(180deg); }
  100% { opacity: 0.45; transform: scale(0.92) rotate(360deg); }
}
@media (prefers-reduced-motion: reduce) {
  .builder-loading-logo { animation: builderLogoPulseFade 1.4s ease-in-out infinite; }
}
@keyframes builderLogoPulseFade {
  0%, 100% { opacity: 0.4; }
  50%      { opacity: 1; }
}

/* Progress message: rolling stage label that updates while site
   generation is in flight. Three pulsing dots stagger so the message
   visibly animates even if the runner sits at one fraction for a
   while (Sonnet streaming output dominates wall-clock time). */
.builder-msg.is-progress {
  color: var(--ink-mute, #6b6660);
  font-size: 0.94rem;
  background: transparent;
  padding: 4px 0;
}
.builder-progress-dots {
  display: inline-flex;
  gap: 3px;
  align-items: center;
}
.builder-progress-dots > span {
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.35;
  animation: builderProgressDots 1.2s ease-in-out infinite;
}
.builder-progress-dots > span:nth-child(2) { animation-delay: 0.15s; }
.builder-progress-dots > span:nth-child(3) { animation-delay: 0.30s; }
@keyframes builderProgressDots {
  0%, 100% { opacity: 0.25; transform: translateY(0); }
  50%      { opacity: 1;    transform: translateY(-2px); }
}
@media (prefers-reduced-motion: reduce) {
  .builder-progress-dots > span { animation: builderLogoPulseFade 1.4s ease-in-out infinite; }
}

/* === Design-choice popover (Phase 14g) ================================
   Floats above the input bar like Claude's command menu. Renders the
   four design questions (scope/palette/typography/layout) one at a
   time with a step counter; on completion, slides back into the
   input bar and a tight one-line summary lands in the chat. */
.builder-input-wrap {
  position: relative;
}
.builder-design-popover {
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(100% + 8px);
  background: #fff;
  border: 1px solid rgba(15, 25, 50, 0.08);
  border-radius: 16px;
  box-shadow: 0 12px 32px rgba(20, 14, 8, 0.08), 0 2px 6px rgba(20, 14, 8, 0.04);
  padding: 16px 18px 14px;
  transform: translateY(16px);
  opacity: 0;
  transition: transform 0.26s cubic-bezier(0.2, 0.7, 0.25, 1), opacity 0.22s ease;
  pointer-events: none;
  z-index: 5;
}
.builder-design-popover.is-visible {
  transform: translateY(0);
  opacity: 1;
  pointer-events: auto;
}
.builder-design-popover-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin: 0 0 12px;
}
.builder-design-popover-step {
  font-size: 0.78rem;
  font-weight: 500;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-mute, #6b6660);
}
.builder-design-popover-close {
  font-size: 0.82rem;
  color: var(--ink-mute, #6b6660);
  background: transparent;
  border: 0;
  padding: 4px 8px;
  border-radius: 6px;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}
.builder-design-popover-close:hover {
  background: rgba(15, 25, 50, 0.05);
  color: var(--ink, #1f1611);
}
/* Inside the popover: trim default qcard chrome since the popover
   already provides the card frame. */
.builder-design-popover .builder-qcard {
  background: transparent;
  border: 0;
  padding: 0;
}
.builder-design-popover .builder-qcard-head {
  margin-bottom: 10px;
}
.builder-design-popover .builder-qcard-q {
  font-size: 1rem;
  font-weight: 600;
  margin: 0 0 2px;
  color: var(--ink, #1f1611);
}
.builder-design-popover .builder-qcard-hint {
  font-size: 0.78rem;
  color: var(--ink-mute, #6b6660);
}
.builder-design-popover .builder-qcard-foot {
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px solid rgba(15, 25, 50, 0.06);
  display: flex;
  align-items: center;
  gap: 8px;
}
.builder-design-popover .builder-qcard-spacer { flex: 1 1 auto; }

/* Tight inline summary that replaces the chunky multi-line plan pill
   after the user finishes the four design questions. */
.builder-msg.builder-plan-summary {
  background: transparent;
  color: var(--ink-mute, #6b6660);
  font-size: 0.92rem;
  padding: 4px 0;
}
.builder-msg.builder-plan-summary strong {
  color: var(--ink, #1f1611);
  font-weight: 500;
}

/* === Animated diamond logo (inline SVG) ================================
   Three animation modes for different states:
     .bs-anim-cascade  — clockwise pulse around the ring (typing/thinking)
     .bs-anim-construct — assemble + dissolve loop (actively building)
     .bs-anim-sonar    — pulse from centre outward (calm "I'm listening")

   Each variant sets up the inner <rect> with transform-box: fill-box so
   transform animations preserve the parent <g>'s positioning. */
.bs-anim svg { display: block; }
.bs-anim .bs-d rect {
  fill: var(--ink);
  transform-origin: center;
  transform-box: fill-box;
}

/* Cascade — opacity wave clockwise around the perimeter */
.bs-anim-cascade .bs-d { opacity: 0.22; animation: bs-anim-cascade 1.6s linear infinite; }
.bs-anim-cascade .bs-d:nth-child(1) { animation-delay: 0.0s; }
.bs-anim-cascade .bs-d:nth-child(3) { animation-delay: 0.2s; }
.bs-anim-cascade .bs-d:nth-child(5) { animation-delay: 0.4s; }
.bs-anim-cascade .bs-d:nth-child(7) { animation-delay: 0.6s; }
.bs-anim-cascade .bs-d:nth-child(8) { animation-delay: 0.8s; }
.bs-anim-cascade .bs-d:nth-child(6) { animation-delay: 1.0s; }
.bs-anim-cascade .bs-d:nth-child(4) { animation-delay: 1.2s; }
.bs-anim-cascade .bs-d:nth-child(2) { animation-delay: 1.4s; }
@keyframes bs-anim-cascade {
  0%, 80%, 100% { opacity: 0.22; }
  20%, 35%      { opacity: 1; }
}

/* Construct — diamonds assemble + dissolve in sequence */
.bs-anim-construct .bs-d rect { opacity: 0; animation: bs-anim-construct 2.4s ease-in-out infinite; }
.bs-anim-construct .bs-d:nth-child(1) rect { animation-delay: 0.00s; }
.bs-anim-construct .bs-d:nth-child(2) rect { animation-delay: 0.10s; }
.bs-anim-construct .bs-d:nth-child(3) rect { animation-delay: 0.20s; }
.bs-anim-construct .bs-d:nth-child(4) rect { animation-delay: 0.30s; }
.bs-anim-construct .bs-d:nth-child(5) rect { animation-delay: 0.40s; }
.bs-anim-construct .bs-d:nth-child(6) rect { animation-delay: 0.50s; }
.bs-anim-construct .bs-d:nth-child(7) rect { animation-delay: 0.60s; }
.bs-anim-construct .bs-d:nth-child(8) rect { animation-delay: 0.70s; }
@keyframes bs-anim-construct {
  0%   { opacity: 0; transform: scale(0.4) rotate(-25deg); }
  25%  { opacity: 1; transform: scale(1.0) rotate(0); }
  75%  { opacity: 1; transform: scale(1.0) rotate(0); }
  100% { opacity: 0; transform: scale(0.4) rotate(25deg); }
}

/* Sonar — pulse from centre outward in three rings */
.bs-anim-sonar .bs-d rect { animation: bs-anim-sonar 1.4s ease-in-out infinite; }
.bs-anim-sonar .bs-d:nth-child(2) rect,
.bs-anim-sonar .bs-d:nth-child(3) rect,
.bs-anim-sonar .bs-d:nth-child(6) rect,
.bs-anim-sonar .bs-d:nth-child(7) rect { animation-delay: 0s; }
.bs-anim-sonar .bs-d:nth-child(1) rect,
.bs-anim-sonar .bs-d:nth-child(8) rect { animation-delay: 0.25s; }
.bs-anim-sonar .bs-d:nth-child(4) rect,
.bs-anim-sonar .bs-d:nth-child(5) rect { animation-delay: 0.50s; }
@keyframes bs-anim-sonar {
  0%, 100% { opacity: 0.30; transform: scale(0.75); }
  35%      { opacity: 1.00; transform: scale(1.10); }
}
@media (prefers-reduced-motion: reduce) {
  .bs-anim .bs-d, .bs-anim .bs-d rect { animation: none !important; opacity: 1 !important; }
}

/* === AI builder · in-thread build message ============================
   Rich AI message that fires when the user submits the form-card. Two
   columns: stepped checklist on the left, terminal-style config stream
   on the right. The avatar at the row level uses bs-anim-construct
   while the build is in flight, settling once all steps are done. */
.builder-msg-row.is-build {
  align-items: flex-start;
  width: 100%;
}
.builder-msg-row.is-build .bs-anim {
  width: 26px;
  height: 26px;
  flex-shrink: 0;
  margin-top: 4px;
}
/* Pin the message body to fill the rest of the row so the build grid
   always renders at the wide position regardless of how short any
   given step's log lines happen to be. */
.builder-msg-row.is-build .builder-msg {
  flex: 1 1 0 !important;
  min-width: 0 !important;
  max-width: none !important;
  width: 100%;
}
.builder-build {
  margin-top: 4px;
  width: 100%;
}
.builder-build-head {
  margin-bottom: 14px;
}
.builder-build-eye {
  display: block;
  font-family: 'JetBrains Mono', 'Geist Mono', monospace;
  font-size: 10px;
  letter-spacing: 0.14em;
  color: var(--ink-mute);
  text-transform: uppercase;
  margin: 0 0 4px;
}
.builder-build-title {
  font-family: 'Newsreader', serif;
  font-style: italic;
  font-weight: 500;
  font-size: 18px;
  line-height: 1.2;
  margin: 0;
  color: var(--ink);
}
.builder-build-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
  background: var(--cream-2);
  border: 1px solid var(--hairline);
  border-radius: 12px;
  overflow: hidden;
}
.builder-build-steps {
  list-style: none;
  margin: 0;
  padding: 14px 16px;
  border-right: 1px solid var(--hairline);
}
.builder-build-step {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 0;
  font-size: 13px;
  color: var(--ink-mute);
  transition: color 0.2s ease;
}
.builder-build-step.is-active,
.builder-build-step.is-done { color: var(--ink); }
.builder-build-step-dot {
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.builder-build-step-dot .ring {
  width: 11px;
  height: 11px;
  border-radius: 50%;
  border: 1.4px solid rgba(27, 25, 22, 0.18);
  box-sizing: border-box;
}
.builder-build-step.is-active .builder-build-step-dot .ring {
  border-color: #C2410C;
  border-top-color: transparent;
  animation: builder-build-spin 0.7s linear infinite;
}
.builder-build-step.is-done .builder-build-step-dot .ring { display: none; }
.builder-build-step.is-done .builder-build-step-dot::after {
  content: '';
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: var(--ink);
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'><polyline points='2 6 5 9 10 3' fill='none' stroke='%23FAF6EE' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-repeat: no-repeat;
  background-position: center;
}
@keyframes builder-build-spin { to { transform: rotate(360deg); } }

/* Terminal-style code stream on the right */
.builder-build-log {
  padding: 14px 16px;
  font-family: 'JetBrains Mono', 'Geist Mono', monospace;
  font-size: 11.5px;
  color: var(--ink-mute);
  line-height: 1.7;
  overflow: hidden;
  max-height: 180px;
  background: #15110D;
  color: #E8DDC5;
  font-feature-settings: 'liga' 0;
}
.builder-build-log-line {
  opacity: 0;
  animation: builder-build-log-in 0.18s ease-out forwards;
  white-space: pre;
}
.builder-build-log-line .k { color: #F7B061; }
.builder-build-log-line .s { color: #A8D88A; }
.builder-build-log-line .c { color: rgba(232, 221, 197, 0.5); }
@keyframes builder-build-log-in { to { opacity: 1; } }
.builder-build-log .caret {
  display: inline-block;
  width: 6px;
  height: 12px;
  background: #E8DDC5;
  vertical-align: text-bottom;
  margin-left: 2px;
  animation: builder-build-blink 0.9s steps(1) infinite;
}
@keyframes builder-build-blink { 50% { opacity: 0; } }

@media (max-width: 720px) {
  .builder-build-grid { grid-template-columns: 1fr; }
  .builder-build-steps { border-right: 0; border-bottom: 1px solid var(--hairline); }
  .builder-build-log { max-height: 120px; }
}

/* === Lovable-style guided flow ========================================
   Thinking message + question cards + launch-done card. Replaces the
   form-card flow as the primary "tell me what you want" surface. */

/* Thinking message — small "Thought for Ns" header + status card */
.builder-thinking {
  margin-top: 4px;
  width: 100%;
}
.builder-thinking-eye {
  font-size: 13px;
  color: var(--ink-mute);
  margin: 0 0 10px;
}
.builder-thinking-card {
  border: 1px solid var(--hairline);
  border-radius: 12px;
  padding: 16px 18px;
  background: var(--cream-2);
  display: flex;
  align-items: center;
  gap: 12px;
}
/* Bare variant — no box, just the cascading logo + thinking text inline.
   !important on each property because the base .builder-thinking-card
   rule has accumulated a couple of overrides over time and this needs
   to win deterministically. */
.builder-thinking-card--bare {
  border: 0 !important;
  background: transparent !important;
  padding: 0 !important;
  border-radius: 0 !important;
  box-shadow: none !important;
}
/* Cycling-phrase thinking pulse (Variant 2). Words sit DARK at rest; a
   narrow LIGHT band slides left-to-right across them at 1.3s, the
   "thinking pulse" passing through. Faster + more contrasty than a
   shimmer so the direction reads clearly. .is-fading swaps phrase
   content cleanly; .is-settled freezes the band for the 'Got it.' beat.
   Math: bg-size 220%, bright spot at 50% of gradient = 110% of
   container; P=105% places it just off-left, P=-5% places it just
   off-right. Animating P down sweeps the band rightward. */
.builder-thinking-pulse {
  font-size: 14px;
  font-weight: 500;
  background: linear-gradient(
    90deg,
    rgba(31, 22, 17, 1.00)  0%,
    rgba(31, 22, 17, 1.00) 42%,
    rgba(31, 22, 17, 0.18) 50%,
    rgba(31, 22, 17, 1.00) 58%,
    rgba(31, 22, 17, 1.00) 100%
  );
  background-size: 220% 100%;
  background-clip: text;
  -webkit-background-clip: text;
  color: transparent;
  -webkit-text-fill-color: transparent;
  animation: builderThinkSlide 2.4s linear infinite;
  transition: opacity 0.22s ease;
}
.builder-thinking-pulse.is-fading { opacity: 0; }
.builder-thinking-pulse.is-settled {
  animation: none;
  background: none;
  color: var(--ink);
  -webkit-text-fill-color: var(--ink);
  opacity: 1;
}
@keyframes builderThinkSlide {
  0%   { background-position: 105% 0; }
  100% { background-position: -5% 0; }
}
@media (prefers-reduced-motion: reduce) {
  .builder-thinking-pulse { animation: none; }
}

/* ── Build animation (30s ticker → image card) ─────────────────────
   Plays after the review card's "Build my site" tap on the
   Emergency-First (ef) branch. Total runtime 30s:
     0–5s   pulse alone (the .builder-thinking-pulse above keeps
            cycling phrases; this block stays empty)
     5–20s  line phase: trunk drops, globe fades in, tasks stream
            into a domino stack, then the close sequence wipes the
            words right-to-left, fades the globe, retracts the line
     20–30s image-card phase: 240×150 hero-photo card sits anchored
            below the pulse
   At 30s the JS removes the row and shellTransitionToReady fires.
   Sequence + close keyframes were tuned on the /_demo-thinking3
   demo before being lifted here; CSS deltas vs the demo are the
   open delays (5000ms / 5820ms instead of 2000ms / 2820ms) so
   phase 1 holds the pulse alone for the full 5 seconds. */
.bs-build-anim {
  position: relative;
  /* Force a fixed working width — the .builder-msg parent is a flex
     item that shrinks to fit the short pulse text ("Polishing copy"),
     which was clipping the 240px image card to ~half-width and wrapping
     row text mid-word. 320px gives the 240px card + 38px row indent +
     breathing room; max-width:100% protects narrow viewports. */
  width: 320px;
  max-width: 100%;
  height: 240px;
  margin-top: 14px;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 70px, #000 100%);
          mask-image: linear-gradient(180deg, transparent 0, #000 70px, #000 100%);
}
.bs-build-anim__trunk {
  position: absolute;
  left: 22px;
  top: 0;
  bottom: 30px;
  width: 1.5px;
  background: rgba(31, 22, 17, 0.16);
  pointer-events: none;
  transform-origin: top;
  transform: scaleY(0);
  animation: bsBuildAnimTrunkDrop 820ms cubic-bezier(0.65, 0, 0.35, 1) 5000ms forwards;
}
@keyframes bsBuildAnimTrunkDrop {
  0%   { transform: scaleY(0); }
  100% { transform: scaleY(1); }
}
.bs-build-anim__globe {
  position: absolute;
  left: 15px;
  bottom: 14px;
  width: 16px;
  height: 16px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  z-index: 2;
  pointer-events: none;
  color: rgba(31, 22, 17, 0.32);
  opacity: 0;
  transform: scale(0.55);
  animation: bsBuildAnimGlobeIn 380ms cubic-bezier(0.22, 1, 0.36, 1) 5820ms forwards;
  transform-origin: center;
}
.bs-build-anim__globe svg { width: 16px; height: 16px; display: block; }
@keyframes bsBuildAnimGlobeIn {
  0%   { opacity: 0; transform: scale(0.55); }
  100% { opacity: 1; transform: scale(1); }
}
.bs-build-anim__list {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 38px;
  pointer-events: none;
}
.bs-build-anim__row {
  --row-h: 30px;
  position: absolute;
  left: 0;
  right: 0;
  bottom: calc(var(--idx, 0) * var(--row-h));
  padding: 0 14px 0 38px;
  height: var(--row-h);
  display: flex;
  align-items: center;
  font-size: 0.86rem;
  color: #4A3D32;
  letter-spacing: -0.005em;
  line-height: 1.3;
  /* Explicit clip-path: inset(0 0 0 0) starting state so the
     close-rule can animate to inset(0 100% 0 0). Without it,
     browsers refuse to interpolate from the implicit default. */
  clip-path: inset(0 0 0 0);
  -webkit-clip-path: inset(0 0 0 0);
  transition:
    bottom 360ms cubic-bezier(0.22, 1, 0.36, 1),
    opacity 200ms ease-out,
    clip-path 460ms cubic-bezier(0.65, 0, 0.35, 1),
    -webkit-clip-path 460ms cubic-bezier(0.65, 0, 0.35, 1);
  opacity: 1;
}
.bs-build-anim__row::before {
  content: '';
  position: absolute;
  left: 22px;
  top: 50%;
  transform: translateY(-50%);
  width: 10px;
  height: 1.5px;
  background: rgba(31, 22, 17, 0.14);
}
.bs-build-anim__row.is-entering {
  bottom: calc((var(--idx, 0) - 1) * var(--row-h));
  opacity: 0;
  transition: none;
}
.bs-build-anim__row.is-leaving { opacity: 0; }
.bs-build-anim__row-text { display: inline-block; }

/* Close sequence — beats:
     0–460ms    words wipe right-to-left (clip-path on each row)
     460–800ms  globe shrinks + fades (animation-name swap)
     800–1520ms line retracts upward (transform-origin: top)
     +1500ms    image card lands (JS toggles .is-open)
   fill-mode 'both' on the close keyframes holds the open's
   end-state during the delay so trunk/globe don't snap back to
   the base hidden style when .is-closing lands. */
.bs-build-anim.is-closing .bs-build-anim__row {
  clip-path: inset(0 100% 0 0);
  -webkit-clip-path: inset(0 100% 0 0);
}
.bs-build-anim.is-closing .bs-build-anim__globe {
  animation: bsBuildAnimGlobeOut 340ms cubic-bezier(0.65, 0, 0.35, 1) 460ms both;
}
@keyframes bsBuildAnimGlobeOut {
  0%   { opacity: 1; transform: scale(1); }
  100% { opacity: 0; transform: scale(0.55); }
}
.bs-build-anim.is-closing .bs-build-anim__trunk {
  transform-origin: top;
  animation: bsBuildAnimTrunkRetract 720ms cubic-bezier(0.65, 0, 0.35, 1) 800ms both;
}
@keyframes bsBuildAnimTrunkRetract {
  0%   { transform: scaleY(1); }
  100% { transform: scaleY(0); }
}
.bs-build-anim.is-closing {
  -webkit-mask-image: none;
          mask-image: none;
}

.bs-build-anim__card {
  position: absolute;
  top: 0;
  left: 0;
  transform: translateY(-14px);
  opacity: 0;
  transition:
    opacity 380ms ease-out,
    transform 520ms cubic-bezier(0.16, 1, 0.3, 1);
  pointer-events: none;
  z-index: 3;
}
.bs-build-anim__card.is-open {
  opacity: 1;
  transform: translateY(0);
}
.bs-build-anim__card-inner {
  display: inline-flex;
  flex-direction: column;
  background: #FFF;
  border: 1px solid rgba(31, 22, 17, 0.10);
  border-radius: 12px;
  padding: 8px 8px 10px;
  box-shadow:
    0 1px 2px rgba(31, 22, 17, 0.04),
    0 12px 28px -10px rgba(31, 22, 17, 0.18);
}
.bs-build-anim__card-img {
  width: 240px;
  height: 150px;
  border-radius: 6px;
  background: linear-gradient(135deg, #3B5C7E 0%, #6A7C8A 55%, #C5A47E 100%);
  overflow: hidden;
}
.bs-build-anim__card-cap {
  font-size: 0.76rem;
  color: #6B5A4C;
  margin-top: 8px;
  text-align: center;
  font-weight: 500;
  letter-spacing: 0.005em;
}
@media (prefers-reduced-motion: reduce) {
  .bs-build-anim__trunk,
  .bs-build-anim__globe,
  .bs-build-anim__row,
  .bs-build-anim__card { animation: none !important; transition: none !important; opacity: 1; transform: none; }
}

/* Build thread — cascading-logo bar above a stack of tool cards that
   swap as the build progresses through phases (design → content →
   forms → polish → done). Logo stays put; cards swap. */
.builder-build-thread {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
}
.builder-build-logo-bar {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  padding: 0;
  margin-bottom: 4px;
}
.builder-build-logo-bar .bs-anim {
  width: 24px;
  height: 24px;
  flex-shrink: 0;
}
.builder-build-logo-bar .builder-thinking-pulse {
  font-size: 0.92rem;
  letter-spacing: -0.005em;
  margin-left: 2px;
}
.builder-build-stack {
  position: relative;
  width: 100%;
  max-width: 480px;
}
/* Tool card — sits in the stack, slides in on entry, fades out on
   leaving. New ones replace old ones to give the impression of the
   AI moving through tools. */
.builder-build-tool-card {
  border: 1px solid var(--hairline);
  border-radius: 12px;
  padding: 14px 16px;
  background: var(--paper, #fff);
  box-shadow: 0 1px 2px rgba(31, 22, 17, 0.04);
  animation: builderToolCardIn 0.42s cubic-bezier(0.22, 1, 0.36, 1);
  transition: opacity 0.2s ease, transform 0.2s ease;
}
.builder-build-tool-card.is-leaving {
  opacity: 0;
  transform: translateY(-8px);
}
@keyframes builderToolCardIn {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .builder-build-tool-card { animation: none; }
  .builder-build-tool-card.is-leaving { transition: none; }
}
/* Final "Launched" card — solid ink check + business name, no steps. */
.builder-build-done-card .builder-build-task-head { padding-bottom: 0; border-bottom: 0; }
.builder-build-done-check {
  color: var(--ink);
  flex-shrink: 0;
}
.builder-build-task-head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--hairline);
}
.builder-build-task-head .bs-anim {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
}
.builder-build-task-title {
  font-size: 0.92rem;
  font-weight: 500;
  color: var(--ink);
  letter-spacing: -0.005em;
  flex: 1;
}
.builder-build-task-eye {
  font-size: 0.72rem;
  font-weight: 400;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
}
.builder-build-task-steps {
  list-style: none;
  margin: 12px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 9px;
}
.builder-build-step {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 0.84rem;
  line-height: 1.4;
  color: var(--ink-faint);
  transition: color 0.3s ease;
}
.builder-build-step.is-active { color: var(--ink); font-weight: 500; }
.builder-build-step.is-done   { color: var(--ink-mute); }
.builder-build-step-bullet {
  width: 13px;
  height: 13px;
  border-radius: 50%;
  border: 1.5px solid var(--ink-faint);
  background: transparent;
  flex-shrink: 0;
  position: relative;
  transition: border-color 0.3s ease, background 0.3s ease;
}
.builder-build-step.is-active .builder-build-step-bullet {
  border-color: var(--ink);
  animation: builderBuildBulletPulse 1.4s ease-in-out infinite;
}
.builder-build-step.is-active .builder-build-step-bullet::after {
  content: '';
  position: absolute;
  inset: 3px;
  border-radius: 50%;
  background: var(--ink);
}
.builder-build-step.is-done .builder-build-step-bullet {
  border-color: var(--ink);
  background: var(--ink);
}
.builder-build-step.is-done .builder-build-step-bullet::after {
  content: '';
  position: absolute;
  left: 3.5px;
  top: 1.5px;
  width: 4px;
  height: 7px;
  border: solid var(--paper, #fff);
  border-width: 0 1.5px 1.5px 0;
  transform: rotate(45deg);
}
@keyframes builderBuildBulletPulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.18); }
}
@media (prefers-reduced-motion: reduce) {
  .builder-build-step.is-active .builder-build-step-bullet { animation: none; }
}
.builder-thinking-card .bs-anim {
  width: 22px;
  height: 22px;
  flex-shrink: 0;
}
.builder-thinking-card-text {
  font-size: 14px;
  color: var(--ink);
}
.builder-thinking-card-sub {
  font-size: 12px;
  color: var(--ink-mute);
  display: block;
  margin-top: 2px;
}

/* Question card — shared shell for all four question types */
.builder-qcard {
  margin-top: 14px;
  border: 1px solid var(--hairline);
  border-radius: 14px;
  background: var(--cream-2);
  overflow: hidden;
  width: 100%;
}
.builder-qcard-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 20px 12px;
}
.builder-qcard-q {
  font-size: 16px;
  font-weight: 500;
  color: var(--ink);
  margin: 0;
}
.builder-qcard-hint {
  font-size: 12px;
  color: var(--ink-mute);
}
.builder-qcard-body {
  padding: 0 20px 16px;
}
.builder-qcard-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
}
.builder-qcard-grid.is-list { grid-template-columns: 1fr; gap: 6px; }

/* Each option in the grid */
.builder-qopt {
  border: 1.5px solid transparent;
  border-radius: 12px;
  padding: 14px 16px;
  background: rgba(255, 255, 255, 0.55);
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 12px;
  transition: border-color 0.15s ease, background 0.15s ease;
  text-align: left;
  font: inherit;
  color: var(--ink);
}
.builder-qopt:hover { background: #fff; }
.builder-qopt.is-selected {
  border-color: #1B1916;
  background: #fff;
}
.builder-qopt-radio {
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  border: 1.5px solid rgba(0, 0, 0, 0.22);
  box-sizing: border-box;
}
.builder-qopt.is-selected .builder-qopt-radio {
  border-color: #1B1916;
  background: radial-gradient(circle, #1B1916 40%, transparent 45%);
}
.builder-qopt-text { flex: 1; min-width: 0; }
.builder-qopt-title { font-size: 14px; font-weight: 500; display: block; }
.builder-qopt-sub { font-size: 12px; color: var(--ink-mute); display: block; margin-top: 1px; }

/* List variant (for "What should the site include?") — radio + title + sub */
.builder-qcard-grid.is-list .builder-qopt { padding: 12px 14px; border-radius: 10px; }

/* Visual variant — option contains an SVG/preview, title sits below */
.builder-qopt.is-visual {
  flex-direction: column;
  align-items: stretch;
  padding: 14px;
  gap: 10px;
}
.builder-qopt.is-visual .builder-qopt-preview {
  height: 90px;
  border-radius: 8px;
  background: var(--cream);
  border: 1px solid var(--hairline);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.builder-qopt.is-visual .builder-qopt-preview svg { display: block; max-width: 100%; max-height: 100%; }
.builder-qopt.is-visual .builder-qopt-text { text-align: center; }

/* Typography option: large sample text */
.builder-qopt.is-type {
  flex-direction: column;
  align-items: center;
  padding: 22px 14px 18px;
  gap: 4px;
}
.builder-qopt.is-type .builder-qopt-display {
  font-size: 22px;
  font-weight: 500;
  font-family: var(--qopt-display, 'Newsreader', serif);
  font-style: var(--qopt-display-style, italic);
  color: var(--ink);
}
.builder-qopt.is-type .builder-qopt-body {
  font-size: 12px;
  color: var(--ink-mute);
  font-family: var(--qopt-body, 'Geist', sans-serif);
}

/* Palette option: row of 4 colour swatches */
.builder-qopt.is-palette {
  flex-direction: column;
  align-items: stretch;
  gap: 10px;
  padding: 12px;
}
.builder-qopt.is-palette .builder-qopt-swatches {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0;
  width: 100%;
  height: 64px;
  border-radius: 8px;
  overflow: hidden;
}
.builder-qopt.is-palette .builder-qopt-swatches > span {
  display: block;
  width: 100%;
  height: 100%;
}
.builder-qopt.is-palette .builder-qopt-name { font-size: 12px; color: var(--ink-mute); text-align: center; }
/* Same alignment fix for type + visual variants so they fill their cell */
.builder-qopt.is-type, .builder-qopt.is-visual { align-items: stretch !important; }

/* Layout option: wireframe sketch */
.builder-qopt.is-layout .builder-qopt-preview svg rect { fill: rgba(0,0,0,0.18); }

/* "Describe your own" row at the bottom of the card */
.builder-qcard-own {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 6px 0;
  font-size: 13px;
  color: var(--ink-mute);
  cursor: pointer;
  border: 0;
  background: transparent;
  font-family: inherit;
}
.builder-qcard-own .builder-qopt-radio { width: 12px; height: 12px; }

/* Footer nav (prev/next/skip/Next button) */
.builder-qcard-foot {
  display: flex;
  align-items: center;
  padding: 12px 16px;
  border-top: 1px solid var(--hairline);
  background: rgba(255, 255, 255, 0.5);
  gap: 8px;
}
.builder-qcard-nav-arrow {
  width: 28px; height: 28px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 0;
  background: transparent;
  color: var(--ink-mute);
  cursor: pointer;
  border-radius: 6px;
}
.builder-qcard-nav-arrow:hover:not([disabled]) { background: var(--cream); color: var(--ink); }
.builder-qcard-nav-arrow[disabled] { opacity: 0.3; cursor: not-allowed; }
.builder-qcard-spacer { flex: 1; }
.builder-qcard-skip {
  background: transparent;
  border: 0;
  font: inherit;
  font-size: 13px;
  color: var(--ink-mute);
  cursor: pointer;
  padding: 6px 10px;
  border-radius: 6px;
}
.builder-qcard-skip:hover { color: var(--ink); }
.builder-qcard-cta {
  background: #1B1916;
  color: var(--cream);
  border: 0;
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  padding: 8px 16px;
  border-radius: 8px;
  cursor: pointer;
}
.builder-qcard-cta:hover { background: #000; }
.builder-qcard.is-answered { opacity: 0.6; }
.builder-qcard.is-answered .builder-qcard-foot { display: none; }

/* === Launch-done card ================================================ */
.builder-launch {
  margin-top: 14px;
  border: 1.5px solid #C2A4FF;
  border-radius: 14px;
  background: var(--cream-2);
  overflow: hidden;
  width: 100%;
}
.builder-launch-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 20px 12px;
}
.builder-launch-title {
  font-size: 16px;
  font-weight: 500;
  margin: 0;
  color: var(--ink);
}
.builder-launch-bookmark {
  background: transparent; border: 0; padding: 4px;
  color: var(--ink-mute); cursor: pointer; border-radius: 6px;
}
.builder-launch-bookmark:hover { color: var(--ink); background: var(--cream); }
.builder-launch-checklist {
  list-style: none;
  margin: 0;
  padding: 6px 20px 12px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.builder-launch-checklist li {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13.5px;
  color: var(--ink);
}
.builder-launch-checklist .ring {
  width: 14px; height: 14px;
  border-radius: 50%;
  border: 1.5px solid rgba(0,0,0,0.22);
  flex-shrink: 0;
}
.builder-launch-actions {
  display: grid;
  grid-template-columns: 1fr 1fr;
  border-top: 1px solid var(--hairline);
}
.builder-launch-actions button {
  background: transparent;
  border: 0;
  font: inherit;
  font-size: 13px;
  color: var(--ink);
  padding: 12px 16px;
  cursor: pointer;
}
.builder-launch-actions button + button { border-left: 1px solid var(--hairline); }
.builder-launch-actions button:hover { background: var(--cream); }

/* Summary paragraph below the card */
.builder-launch-summary {
  font-size: 14px;
  color: var(--ink);
  line-height: 1.55;
  margin: 14px 0 8px;
}
.builder-launch-summary-more {
  background: transparent; border: 0; cursor: pointer;
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: 50%;
  margin-top: 4px;
  color: var(--ink-mute);
}
.builder-launch-summary-more:hover { color: var(--ink); background: var(--cream); }

/* Next-action chips */
.builder-launch-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 12px;
}
.builder-launch-chip {
  background: transparent;
  border: 1px solid var(--hairline);
  border-radius: 999px;
  padding: 6px 14px;
  font: inherit;
  font-size: 12.5px;
  color: var(--ink);
  cursor: pointer;
}
.builder-launch-chip:hover { background: var(--cream); border-color: rgba(0,0,0,0.22); }

/* Details form card — same shell as the question cards but with text
   inputs + chip pickers for the practical business data the site
   needs (name / phone / suburbs / licence / services). */
.builder-detailcard {
  margin-top: 14px;
  border: 1px solid var(--hairline);
  border-radius: 14px;
  background: var(--cream-2);
  overflow: hidden;
  width: 100%;
}
.builder-detailcard-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px 20px 12px;
}
.builder-detailcard-q {
  font-size: 16px;
  font-weight: 500;
  margin: 0;
}
.builder-detailcard-hint {
  font-size: 12px;
  color: var(--ink-mute);
}
.builder-detailcard-body {
  padding: 0 20px 16px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.builder-detailcard-field { display: flex; flex-direction: column; gap: 6px; }
.builder-detailcard-label {
  font-size: 12px;
  font-weight: 500;
  color: var(--ink-mute);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.builder-detailcard-input {
  background: #fff;
  border: 1px solid var(--hairline);
  border-radius: 8px;
  padding: 10px 12px;
  font: inherit;
  font-size: 14px;
  color: var(--ink);
  outline: 0;
  width: 100%;
  box-sizing: border-box;
}
.builder-detailcard-input:focus { border-color: rgba(0,0,0,0.4); }
.builder-detailcard-help { font-size: 11.5px; color: var(--ink-mute); margin: 2px 0 0; }
.builder-detailcard-chips {
  background: #fff;
  border: 1px solid var(--hairline);
  border-radius: 8px;
  padding: 8px 10px;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
}
.builder-detailcard-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: var(--cream-2);
  border: 1px solid var(--hairline);
  border-radius: 999px;
  padding: 4px 8px 4px 10px;
  font-size: 12.5px;
  color: var(--ink);
}
.builder-detailcard-chip-remove {
  background: transparent; border: 0;
  width: 14px; height: 14px;
  display: inline-flex; align-items: center; justify-content: center;
  cursor: pointer;
  color: var(--ink-mute);
  font-size: 14px;
  line-height: 1;
  padding: 0;
  border-radius: 50%;
}
.builder-detailcard-chip-remove:hover { color: var(--ink); background: rgba(0,0,0,0.05); }
.builder-detailcard-chip-input {
  background: transparent;
  border: 0;
  outline: 0;
  font: inherit;
  font-size: 13px;
  color: var(--ink);
  flex: 1;
  min-width: 80px;
  padding: 4px 6px;
}
.builder-detailcard-suggest {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 6px;
}
.builder-detailcard-suggest-chip {
  background: transparent;
  border: 1px dashed var(--hairline);
  border-radius: 999px;
  padding: 4px 10px;
  font: inherit;
  font-size: 12px;
  color: var(--ink-mute);
  cursor: pointer;
}
.builder-detailcard-suggest-chip:hover { color: var(--ink); border-color: var(--ink-mute); border-style: solid; }
.builder-detailcard.has-error .builder-detailcard-input.is-invalid,
.builder-detailcard.has-error .builder-detailcard-chips.is-invalid {
  border-color: #C2410C;
}

/* Plan summary pill (right-aligned, before questions) */
.builder-plan-pill {
  align-self: flex-end;
  max-width: 70%;
  background: var(--cream-2);
  border: 1px solid var(--hairline);
  border-radius: 14px;
  padding: 12px 16px;
  margin: 0 0 14px;
  font-size: 13px;
  color: var(--ink-mute);
  font-style: italic;
}
.builder-plan-pill .k { color: var(--ink); font-style: normal; font-weight: 500; }

/* ──── builder-chat.css range 2: source lines 6750..7124 ──── */
/* === AI Builder inline form-card chat-message ===
   Sits in .builder-msg-row.is-ai so it gets the BookingSprint-logo avatar
   on the left. The card itself is the right-hand bubble — flush with how
   an AI message would render, but containing a small inline form. */
.builder-form-row { width: 100%; }
.builder-form-card {
  flex: 1 1 auto;
  min-width: 0;
  max-width: 560px;
  background: var(--paper, #fff);
  border: 1px solid var(--hairline);
  border-radius: 16px;
  padding: 18px 20px 16px;
  box-shadow: 0 6px 22px -10px rgba(31, 22, 17, 0.10), 0 1px 2px rgba(31, 22, 17, 0.04);
  display: flex;
  flex-direction: column;
  gap: 12px;
  box-sizing: border-box;
  /* Premium reveal — slide up + fade + tiny scale, then stagger children. */
  animation: builderFormCardEnter 0.55s cubic-bezier(0.22, 1, 0.36, 1) both;
  transform-origin: top center;
  will-change: transform, opacity;
}
@keyframes builderFormCardEnter {
  0%   { opacity: 0; transform: translateY(18px) scale(0.985); }
  60%  { opacity: 1; }
  100% { opacity: 1; transform: translateY(0) scale(1); }
}
/* Stagger every child of the card so the form composes itself in. */
.builder-form-card > .builder-form-header,
.builder-form-card > .builder-form-fields > .builder-form-field,
.builder-form-card > .builder-form-submit {
  animation: builderFormChildEnter 0.5s cubic-bezier(0.22, 1, 0.36, 1) both;
  opacity: 0;
}
@keyframes builderFormChildEnter {
  0%   { opacity: 0; transform: translateY(8px); }
  100% { opacity: 1; transform: translateY(0); }
}
.builder-form-card > .builder-form-header                     { animation-delay: 0.10s; }
.builder-form-card > .builder-form-fields > .builder-form-field:nth-child(1) { animation-delay: 0.18s; }
.builder-form-card > .builder-form-fields > .builder-form-field:nth-child(2) { animation-delay: 0.24s; }
.builder-form-card > .builder-form-fields > .builder-form-field:nth-child(3) { animation-delay: 0.30s; }
.builder-form-card > .builder-form-fields > .builder-form-field:nth-child(4) { animation-delay: 0.36s; }
.builder-form-card > .builder-form-fields > .builder-form-field:nth-child(5) { animation-delay: 0.42s; }
.builder-form-card > .builder-form-fields > .builder-form-field:nth-child(6) { animation-delay: 0.48s; }
.builder-form-card > .builder-form-submit                     { animation-delay: 0.55s; }
@media (prefers-reduced-motion: reduce) {
  .builder-form-card,
  .builder-form-card > .builder-form-header,
  .builder-form-card > .builder-form-fields > .builder-form-field,
  .builder-form-card > .builder-form-submit { animation: none; opacity: 1; transform: none; }
}

/* 2026-05-16 v8: smoother, slower form-card collapse on Build-my-site.
   The previous 380ms was abrupt and read as "clanky" — opacity dropped
   to 0 by 60% while the height was still 1200px, then snapped down.
   New curve: opacity fades over the FULL duration so the card visibly
   recedes rather than blinking out; scale settles to 0.93 with the
   ease-out-quart curve so it feels like the form is folding into the
   message stream. Duration bumped to 620ms. Recap card append is
   delayed by ~280ms in JS so the two motions don't fight. */
.builder-form-row.is-collapsing,
.builder-form-card.is-collapsing {
  animation: builderFormCollapse 0.62s cubic-bezier(0.65, 0, 0.35, 1) forwards;
  transform-origin: top center;
  overflow: hidden;
  pointer-events: none;
}
@keyframes builderFormCollapse {
  0%   { opacity: 1;    transform: scale(1)    translateY(0);    max-height: 1200px; filter: blur(0); }
  35%  { opacity: 0.65; transform: scale(0.985) translateY(-2px); max-height: 1200px; filter: blur(0); }
  70%  { opacity: 0.15; transform: scale(0.95) translateY(-6px); max-height: 380px;  filter: blur(0.3px); }
  100% { opacity: 0;    transform: scale(0.93) translateY(-10px); max-height: 0; margin: 0; padding-top: 0; padding-bottom: 0; filter: blur(0.6px); }
}
@media (prefers-reduced-motion: reduce) {
  .builder-form-row.is-collapsing,
  .builder-form-card.is-collapsing { animation: none; opacity: 0; max-height: 0; }
}

/* Textarea variant of .builder-form-input — keeps the same underline
   treatment but allows multi-line copy. */
.builder-form-textarea {
  resize: vertical;
  min-height: 60px;
  font-family: inherit;
  line-height: 1.5;
}

/* Segmented control — three side-by-side options for the flow-type
   field ("Book a job / Get a quote / Both"). Sits as a single rounded
   pill row with the active option in solid ink, the rest as muted
   ghost buttons. */
.builder-form-segmented {
  display: inline-flex;
  border: 1px solid var(--hairline);
  border-radius: 10px;
  overflow: hidden;
  background: var(--paper, #fff);
  width: 100%;
}
.builder-form-seg {
  flex: 1 1 0;
  padding: 9px 12px;
  font-family: inherit;
  font-size: 0.84rem;
  font-weight: 450;
  color: var(--ink-mute);
  background: transparent;
  border: 0;
  cursor: pointer;
  transition: background 0.15s, color 0.15s;
  border-right: 1px solid var(--hairline);
}
.builder-form-seg:last-child { border-right: 0; }
.builder-form-seg:hover { background: var(--cream-2); color: var(--ink); }
.builder-form-seg.is-on {
  background: var(--ink);
  color: var(--paper, #fff);
  font-weight: 500;
}
.builder-form-header {
  font-size: 0.95rem;
  line-height: 1.5;
  color: var(--ink);
  padding-bottom: 6px;
  border-bottom: 1px solid var(--hairline);
}

/* ──────────────────────────────────────────────────────────────────────
   Choice cards (2026-05-15, Option A): the two multi-choice questions
   that follow the form-card — template (3 text tiles) and palette
   (4 swatch tiles). Reuses .builder-form-card as the surface; this block
   adds the grid + tile + selected/disabled treatments. Renderer:
   shellAppendChoiceCard() in dashboard-v2-page.html.
   ────────────────────────────────────────────────────────────────────── */
.builder-choice-card { max-width: 600px; }
.builder-choice-sub {
  margin: -4px 0 4px;
  font-size: 0.82rem;
  color: var(--ink-mute);
  line-height: 1.45;
}
.builder-choice-grid {
  display: grid;
  gap: 10px;
}
.builder-choice-grid--text {
  /* 3 template tiles — single column at narrow widths, side-by-side
     where there's room. Each tile is a small card with label + sub copy. */
  grid-template-columns: repeat(auto-fit, minmax(168px, 1fr));
}
.builder-choice-grid--palette {
  /* 4 palette tiles — 2x2 below 480px, 4-across above. */
  grid-template-columns: repeat(2, 1fr);
}
@media (min-width: 480px) {
  .builder-choice-grid--palette { grid-template-columns: repeat(4, 1fr); }
}
.builder-choice-tile {
  background: var(--paper, #fff);
  border: 1px solid var(--hairline);
  border-radius: 12px;
  padding: 12px 14px;
  font-family: inherit;
  color: var(--ink);
  text-align: left;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  gap: 6px;
  transition: background 0.15s, border-color 0.15s, transform 0.15s, box-shadow 0.15s;
}
.builder-choice-tile:hover:not(:disabled):not(.is-selected) {
  background: var(--cream-2);
  border-color: var(--ink-mute);
  transform: translateY(-1px);
  box-shadow: 0 4px 12px -6px rgba(31, 22, 17, 0.16);
}
.builder-choice-tile:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}
.builder-choice-tile.is-selected {
  background: var(--paper, #fff);
  border-color: var(--ink);
  color: var(--ink);
  cursor: default;
  box-shadow: 0 0 0 1px var(--ink);
}
.builder-choice-tile.is-selected .builder-choice-tile-sub { color: var(--ink-mute); }
.builder-choice-tile:disabled:not(.is-selected) {
  opacity: 0.45;
  cursor: default;
}
.builder-choice-label {
  font-size: 0.92rem;
  font-weight: 500;
  letter-spacing: -0.005em;
}
.builder-choice-tile-sub {
  font-size: 0.78rem;
  color: var(--ink-mute);
  line-height: 1.4;
}

/* Palette tile: 3 stacked swatches (bg / fg / accent) above the label.
   The swatch row reads as a colour preview while the label names it. */
.builder-choice-grid--palette .builder-choice-tile {
  padding: 0;
  overflow: hidden;
}
.builder-choice-swatches {
  display: flex;
  height: 56px;
}
.builder-choice-swatch {
  flex: 1 1 0;
  display: block;
}
.builder-choice-grid--palette .builder-choice-label {
  padding: 8px 12px 10px;
  font-size: 0.82rem;
}
.builder-choice-grid--palette .builder-choice-tile.is-selected .builder-choice-label {
  background: var(--ink);
  color: var(--paper, #fff);
}

/* The card stops animating tiles when one's picked — locks the choice
   visually so the conversation thread is unambiguous. */
.builder-choice-card.is-picked .builder-choice-tile:not(.is-selected) {
  pointer-events: none;
}

/* 2026-05-16 v4: OpenAI/Claude-flavoured choice card chrome.
   - Outer dock: cream-2 surround so paper-white tiles read as raised cards.
   - Title left, uppercase eyebrow "SELECT ONE" pill right.
   - Tiles: paper-white with hairline + inset highlight + micro-shadow.
   - Selected: subtle ink ring + paper bg, mockup shapes go ink (NOT indigo —
     stays in the warm-stone/ink palette per OpenAI/Claude monochrome aesthetic).
   - Skeleton page-shape mockup at the top of each template tile so the
     three options read as different homepage structures, not three
     identical text rectangles. */
.builder-choice-card.builder-choice-card--v2 {
  max-width: 720px;
  background: var(--cream-2, #F1F1F1);
  border: 1px solid rgba(31, 22, 17, 0.06);
  border-radius: 18px;
  padding: 22px 22px 14px;
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.6) inset,
    0 1px 2px rgba(31, 22, 17, 0.03),
    0 12px 32px -12px rgba(31, 22, 17, 0.10);
}
.builder-choice-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 0 0 16px;
}
.builder-choice-title {
  font-family: 'Geist', 'Inter Tight', 'Inter', sans-serif;
  font-size: 1.0625rem;
  font-weight: 600;
  color: var(--ink, #1F1611);
  letter-spacing: -0.01em;
  line-height: 1.3;
}
.builder-choice-select-one {
  font-size: 0.75rem;
  font-weight: 500;
  color: #8A7868;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding: 3px 8px;
  border-radius: 999px;
  background: rgba(31, 22, 17, 0.04);
  flex: 0 0 auto;
}
.builder-choice-card--v2 .builder-choice-grid {
  gap: 10px;
  margin: 0;
}
.builder-choice-card--v2 .builder-choice-grid--text {
  grid-template-columns: repeat(3, 1fr);
}
@media (max-width: 560px) {
  .builder-choice-card--v2 .builder-choice-grid--text {
    grid-template-columns: 1fr;
  }
}
.builder-choice-card--v2 .builder-choice-tile {
  background: #FBFBFB;
  padding: 14px 14px 12px;
  border: 1px solid rgba(31, 22, 17, 0.07);
  border-radius: 14px;
  min-height: 140px;
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.7) inset,
    0 1px 2px rgba(31, 22, 17, 0.04);
  transition:
    background 0.14s ease,
    border-color 0.14s ease,
    box-shadow 0.18s ease,
    transform 0.18s cubic-bezier(0.22, 1, 0.36, 1);
}
.builder-choice-card--v2 .builder-choice-tile:hover:not(:disabled):not(.is-selected) {
  background: #FFFFFF;
  border-color: rgba(31, 22, 17, 0.14);
  transform: translateY(-1px);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.8) inset,
    0 2px 4px rgba(31, 22, 17, 0.05),
    0 8px 18px -10px rgba(31, 22, 17, 0.12);
}
.builder-choice-card--v2 .builder-choice-tile:focus-visible {
  outline: none;
  border-color: rgba(31, 22, 17, 0.18);
  box-shadow:
    0 0 0 2px #FBFBFB,
    0 0 0 4px rgba(31, 22, 17, 0.28);
}
.builder-choice-card--v2 .builder-choice-tile.is-selected {
  background: #FFFFFF;
  border-color: var(--ink, #1F1611);
  color: var(--ink, #1F1611);
  box-shadow:
    0 0 0 1px var(--ink, #1F1611),
    0 1px 0 rgba(255, 255, 255, 0.8) inset,
    0 2px 6px rgba(31, 22, 17, 0.06);
}
.builder-choice-card--v2 .builder-choice-tile.is-selected .builder-choice-tile-sub {
  color: var(--ink-mute, #6B5A4C);
}
.builder-choice-card--v2 .builder-choice-grid--palette .builder-choice-tile {
  min-height: 0;
  padding: 0;
  overflow: hidden;
}
.builder-choice-card--v2 .builder-choice-grid--palette .builder-choice-swatches {
  height: 64px;
}

/* Skeleton page-shape mockup inside each template tile. Same primitive
   shapes used in the picker dock v3 (lay-*) but with a `cm-` prefix to
   live alongside the choice-tile structure. Shapes use warm-grey fill
   with a subtle gradient for depth; on hover they darken; when the tile
   is selected they go full ink (monochrome — no indigo, OpenAI/Claude
   aesthetic). */
.builder-choice-mockup {
  display: flex !important;
  width: 100%;
  height: 64px;
  padding: 7px;
  margin: 0 0 4px;
  background: #F1F1F1;
  border: 1px solid rgba(31, 22, 17, 0.05);
  border-radius: 8px;
  box-sizing: border-box;
}
/* hero-columns: dominant hero (50%) + a short title strip + a row of 3
   service-card cells below. The title strip + slightly taller cm-row
   together break the "three thin bars" silhouette so this pattern reads
   clearly as "homepage hero + service cards" — visually distinct from
   the stacked editorial pattern next door. */
.builder-choice-mockup[data-mockup="hero-columns"] {
  flex-direction: column !important;
  gap: 4px;
  justify-content: flex-start;
  align-items: stretch;
}
.builder-choice-mockup[data-mockup="hero-columns"] > * {
  flex-shrink: 0;

/* ──── builder-chat.css range 3: source lines 12313..12550 ──── */
/* === Refinement protocol action UI (2026-05-09) ====================
   Backend /api/builder/chat returns an `actions` array. Each action
   type has its own renderer in dashboard-v2-page.html. Styles below
   live in the warm-stone palette and reuse existing tokens
   (--ink, --ink-mute, --paper, --cream-2, --hairline). No new colours.
   ================================================================== */

/* ask: panel docked INSIDE .builder-input-box (as its first child) so it
   shares the composer's border and shadow — reads as part of the input,
   not as a floating row. Bottom hairline separates it from the textarea
   below. Slides up on mount so the surface feels alive. */
.builder-input-box .builder-action-ask-panel {
  position: relative;
  padding: 10px 14px 10px;
  margin: 0;
  border-bottom: 1px solid rgba(31, 22, 17, 0.08);
  background: transparent;
  animation: builderAskSlideUp 0.32s cubic-bezier(0.22, 1, 0.36, 1) both;
}
.builder-action-ask-prompt {
  font-size: 0.82rem;
  color: var(--ink-mute);
  letter-spacing: -0.005em;
  margin: 0 0 8px;
}
.builder-action-ask-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.builder-action-ask-chip {
  font-family: inherit;
  font-size: 0.82rem;
  font-weight: 500;
  color: var(--ink);
  background: var(--cream-2, #F5F5F5);
  border: 1px solid rgba(31, 22, 17, 0.08);
  border-radius: 999px;
  padding: 5px 12px;
  cursor: pointer;
  letter-spacing: -0.005em;
  transition: background 0.18s ease, border-color 0.18s ease, transform 0.18s ease;
}
.builder-action-ask-chip:hover {
  background: var(--cream, #ECECEC);
  border-color: rgba(31, 22, 17, 0.18);
  transform: translateY(-1px);
}
.builder-action-ask-chip:active { transform: translateY(0); }
.builder-action-ask-chip--other {
  background: transparent;
  border-style: dashed;
  color: var(--ink-mute);
}
.builder-action-ask-chip--other:hover {
  background: var(--cream-2, #F5F5F5);
  color: var(--ink);
  border-style: solid;
}

@keyframes builderAskSlideUp {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* While the ask panel is mounted on the composer, hide the regular
   refine-row chips so they don't compete visually. The data-attribute
   is set by shellRenderActionAsk and cleared on dismiss. */
.builder-input-wrap[data-builder-ask-active] .builder-refine-row {
  display: none !important;
}

/* form: AI-side inline card. Cousin of .builder-form-card but lighter
   (no animation cascade — refinement should feel snappy, not theatrical). */
.builder-action-form-row { width: 100%; }
.builder-action-form-card {
  flex: 1 1 auto;
  min-width: 0;
  max-width: 520px;
  background: var(--cream-2);
  border: 1px solid var(--hairline);
  border-radius: 14px;
  padding: 14px 16px 12px;
  box-shadow: 0 4px 14px -8px rgba(31, 22, 17, 0.08), 0 1px 2px rgba(31, 22, 17, 0.03);
  display: flex;
  flex-direction: column;
  gap: 10px;
  box-sizing: border-box;
  animation: builderActionFade 0.4s cubic-bezier(0.22, 1, 0.36, 1) both;
}
.builder-action-form-title {
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--ink);
  line-height: 1.4;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--hairline);
}
.builder-action-form-fields {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.builder-action-form-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.builder-action-form-label {
  font-size: 0.75rem;
  font-weight: 500;
  color: var(--ink-mute);
  letter-spacing: 0.005em;
}
.builder-action-form-input {
  border: 1px solid var(--hairline);
  background: var(--paper, #fff);
  border-radius: 8px;
  padding: 8px 10px;
  font-family: inherit;
  font-size: 0.9rem;
  color: var(--ink);
  transition: border-color 0.18s, box-shadow 0.18s;
  outline: none;
  width: 100%;
  box-sizing: border-box;
}
.builder-action-form-input::placeholder { color: var(--ink-soft, var(--ink-mute)); opacity: 0.7; }
.builder-action-form-input:focus {
  border-color: var(--ink);
  box-shadow: 0 0 0 2px rgba(31, 22, 17, 0.08);
}
.builder-action-form-actions {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 4px;
}
.builder-action-form-submit {
  background: var(--ink);
  color: var(--cream, #FAFAFA);
  border: 0;
  border-radius: 8px;
  padding: 9px 16px;
  font-family: inherit;
  font-size: 0.88rem;
  font-weight: 500;
  cursor: pointer;
  letter-spacing: -0.005em;
  transition: background 0.18s ease, transform 0.18s cubic-bezier(0.22, 1, 0.36, 1), box-shadow 0.18s ease;
  box-shadow: 0 1px 0 rgba(31, 22, 17, 0.06), 0 3px 8px -3px rgba(31, 22, 17, 0.25);
}
.builder-action-form-submit:hover { transform: translateY(-1px); box-shadow: 0 1px 0 rgba(31, 22, 17, 0.06), 0 6px 14px -5px rgba(31, 22, 17, 0.32); }
.builder-action-form-submit:active { transform: translateY(0); }
.builder-action-form-cancel {
  background: transparent;
  border: 0;
  color: var(--ink-mute);
  font-family: inherit;
  font-size: 0.82rem;
  cursor: pointer;
  padding: 6px 4px;
  text-decoration: underline;
  text-underline-offset: 2px;
  text-decoration-thickness: 1px;
  text-decoration-color: rgba(31, 22, 17, 0.25);
}
.builder-action-form-cancel:hover { color: var(--ink); }

/* apply: small "Updating..." pill that lands inline in the AI column. */
.builder-action-applying-row { width: 100%; }
.builder-action-applying {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: transparent;
  color: var(--ink-mute);
  border: 1px solid var(--hairline);
  border-radius: 999px;
  padding: 5px 12px 5px 10px;
  font-size: 0.8rem;
  font-family: inherit;
  font-weight: 450;
  letter-spacing: 0.005em;
  animation: builderActionFade 0.28s cubic-bezier(0.22, 1, 0.36, 1) both;
}
.builder-action-applying-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: transparent;
  border: 1.5px solid var(--ink-mute);
  border-top-color: transparent;
  animation: builderActionSpin 0.9s linear infinite;
  display: inline-block;
}
.builder-action-applying.is-done .builder-action-applying-dot {
  animation: none;
  border-color: var(--ink);
  background: var(--ink);
  position: relative;
}
.builder-action-applying.is-done .builder-action-applying-dot::after {
  content: '';
  position: absolute;
  top: 1px; left: 2.5px;
  width: 2px; height: 4px;
  border: solid var(--cream, #FAFAFA);
  border-width: 0 1.5px 1.5px 0;
  transform: rotate(45deg);
}
.builder-action-applying.is-done { color: var(--ink); }
@keyframes builderActionSpin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .builder-action-applying-dot { animation: none; border-top-color: var(--ink-mute); }
}

/* suggestions: chip row below an AI reply. Reuses .builder-suggestion-chip
   visual; this just lays them out and adds the rationale-tooltip cursor. */
.builder-action-suggestions-row { width: 100%; }
.builder-action-suggestion-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: -2px;
}
.builder-action-suggestion-chip { font-size: 0.82rem; padding: 6px 12px; cursor: help; }
.builder-action-suggestion-chip:hover { cursor: pointer; }

@keyframes builderActionFade {
  0%   { opacity: 0; transform: translateY(4px); }
  100% { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .builder-action-ask-options,
  .builder-action-form-card,
  .builder-action-applying { animation: none; }
}
