/* Designer-i — Apple-grade glassmorphism.
 * Deep blur, inner highlights, spring physics, micro-interactions.
 * Every detail considered: the way messages land, buttons press,
 * light catches glass edges, and color breathes behind it all. */

* { box-sizing: border-box; }

:root {
  --ink: #f2f5fa;
  --ink-dim: #8e9bb3;
  --ink-faint: #5d6a84;
  --accent1: #5b8cff;
  --accent2: #3b5fe3;
  --accent-glow: rgba(91, 140, 255, 0.45);
  --good: #34d399;
  --spring: cubic-bezier(0.32, 0.72, 0, 1);
  --spring-bounce: cubic-bezier(0.34, 1.4, 0.44, 1);
  --glass-bg: rgba(255, 255, 255, 0.07);
  --glass-bright: rgba(255, 255, 255, 0.11);
}

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", "SF Pro Display", "Segoe UI", Roboto, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  background: #05070d;
  color: var(--ink);
  display: flex;
  justify-content: center;
  min-height: 100vh;
  min-height: 100dvh;
  overflow-x: hidden;
  letter-spacing: -0.011em;
}

::selection { background: rgba(91, 140, 255, 0.4); }

/* ------- ambient aurora: slow-drifting color, film grain, vignette ------- */
.bg-blobs { position: fixed; inset: 0; z-index: 0; overflow: hidden; pointer-events: none; }
.bg-blobs::after {
  /* film grain */
  content: ""; position: absolute; inset: 0; opacity: 0.05; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
.bg-blobs::before {
  /* vignette */
  content: ""; position: absolute; inset: 0; z-index: 2;
  background: radial-gradient(ellipse 90% 75% at 50% 42%, transparent 55%, rgba(0, 0, 0, 0.5) 100%);
}
.blob { position: absolute; border-radius: 50%; filter: blur(110px); }
.blob-1 {
  width: 480px; height: 480px; top: -140px; left: -120px; opacity: 0.5;
  background: radial-gradient(circle, #2b3f7d 0%, transparent 70%);
}
.blob-2 {
  width: 420px; height: 420px; bottom: -160px; right: -120px; opacity: 0.42;
  background: radial-gradient(circle, #17456b 0%, transparent 70%);
}
.blob-3 {
  width: 340px; height: 340px; top: 38%; left: 58%; opacity: 0.3;
  background: radial-gradient(circle, #4a5fd0 0%, transparent 70%);
}
/* PERF (Oct 21, 2026, Yeinel's sitting): the drift animations are REMOVED on
   purpose. Three 110px-blurred blobs animating forever under backdrop-blur
   glass forced full-screen re-blurs every frame and dragged the whole PC
   (YouTube included) to a crawl. The aurora is now STATIC: same look, the
   browser paints it once and caches it. Do not re-add infinite animation to
   .blob or any full-screen fixed layer. */
@keyframes drift1 { to { transform: translate(70px, 50px) scale(1.12); } }
@keyframes drift2 { to { transform: translate(-60px, -45px) scale(1.08); } }
@keyframes drift3 { to { transform: translate(-50px, 60px) scale(0.92); } }

/* ------- the Apple glass recipe -------
 * deep blur + saturation, 0.5px-feel edge, inner top highlight,
 * soft outer shadow. This is what makes glass read as glass. */
.glass {
  background: var(--glass-bg);
  -webkit-backdrop-filter: blur(32px) saturate(200%) brightness(1.1);
  backdrop-filter: blur(32px) saturate(200%) brightness(1.1);
  border: 1px solid rgba(255, 255, 255, 0.14);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.22),
    inset 0 -1px 0 rgba(255, 255, 255, 0.06),
    inset 1px 0 0 rgba(255, 255, 255, 0.06),
    0 12px 40px rgba(0, 0, 0, 0.45),
    0 2px 8px rgba(0, 0, 0, 0.3);
}

/* Enhanced glassmorphism: floating panels with deeper frost */
.glass-deep {
  background: linear-gradient(135deg, rgba(255,255,255,0.08), rgba(255,255,255,0.02));
  -webkit-backdrop-filter: blur(40px) saturate(220%) brightness(1.15);
  backdrop-filter: blur(40px) saturate(220%) brightness(1.15);
  border: 1px solid rgba(255, 255, 255, 0.18);
  box-shadow:
    inset 0 2px 0 rgba(255, 255, 255, 0.25),
    inset 0 -1px 0 rgba(255, 255, 255, 0.08),
    0 16px 48px rgba(0, 0, 0, 0.5);
}

/* ------- layout ------- */
.app {
  position: relative; z-index: 1;
  width: 100%; max-width: 700px;
  display: flex; flex-direction: column;
  height: 100vh; height: 100dvh;
  padding: 14px 14px 0;
  gap: 12px;
}

/* ------- floating header pill ------- */
.header {
  display: flex; gap: 14px; align-items: center;
  padding: 12px 18px 12px 12px; border-radius: 24px;
  animation: header-in 0.7s var(--spring) backwards;
}
@keyframes header-in { from { opacity: 0; transform: translateY(-18px) scale(0.97); } }
.logo {
  width: 52px; height: 52px; flex: 0 0 52px;
  overflow: hidden;
  display: flex; align-items: center; justify-content: center;
  border-radius: 16px;
  /* Glassmorphism tile — frosted glass, metallic letters float on top */
  background: linear-gradient(135deg, rgba(255,255,255,0.12), rgba(255,255,255,0.03));
  -webkit-backdrop-filter: blur(20px) saturate(180%);
  backdrop-filter: blur(20px) saturate(180%);
  border: 1px solid rgba(255, 255, 255, 0.18);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.25),
    inset 0 -1px 0 rgba(255, 255, 255, 0.08),
    0 8px 24px rgba(0, 0, 0, 0.35);
  transition: transform 0.35s var(--spring-bounce);
}
.logo svg { display: block; filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.3)); }
.logo img { display: block; width: 100%; height: 100%; object-fit: cover; }
.logo:hover { transform: scale(1.06) rotate(-4deg); }
.header-text { flex: 1 1 auto; min-width: 0; }
.header h1 {
  margin: 0; font-size: 19px; font-weight: 700; letter-spacing: -0.02em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  background: linear-gradient(180deg, #fff 30%, #b9c6e2 100%);
  -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent;
}
.subtitle { margin: 3px 0 0; font-size: 12.5px; color: var(--ink-dim); font-weight: 500; }
.subtitle a { transition: color 0.2s; }
.subtitle a:hover { color: var(--ink); }

/* ------- chat ------- */
.chat {
  flex: 1; overflow-y: auto;
  padding: 8px 6px 12px;
  display: flex; flex-direction: column; gap: 8px;
  scrollbar-width: thin; scrollbar-color: rgba(255, 255, 255, 0.16) transparent;
  mask-image: linear-gradient(180deg, transparent 0, #000 18px, #000 calc(100% - 8px), transparent 100%);
  -webkit-mask-image: linear-gradient(180deg, transparent 0, #000 18px, #000 calc(100% - 8px), transparent 100%);
}
.chat::after { content: ""; display: block; flex: 0 0 44px; }
.chat::-webkit-scrollbar { width: 5px; }
.chat::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.16); border-radius: 3px; }
.chat::-webkit-scrollbar-track { background: transparent; }

.msg {
  max-width: 86%; padding: 10px 14px;
  border-radius: 20px; line-height: 1.45; font-size: 15px;
  -webkit-backdrop-filter: blur(28px) saturate(180%);
  backdrop-filter: blur(28px) saturate(180%);
  animation: msg-in 0.55s var(--spring-bounce) backwards;
  overflow-wrap: break-word;
}
@keyframes msg-in {
  from { opacity: 0; transform: translateY(14px) scale(0.94); filter: blur(4px); }
}
.msg.bot {
  background: rgba(255, 255, 255, 0.075);
  border: 1px solid rgba(255, 255, 255, 0.1);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.12),
    0 6px 24px rgba(0, 0, 0, 0.3);
  align-self: flex-start; border-bottom-left-radius: 7px;
}
.msg.user {
  background: linear-gradient(135deg, #6b9bff 0%, #3b5fe3 100%);
  align-self: flex-end; border-bottom-right-radius: 7px;
  font-weight: 600;
  border: 1px solid rgba(255, 255, 255, 0.22);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.3),
    0 6px 22px var(--accent-glow);
}
.msg img.mockup {
  width: 100%; border-radius: 16px; margin-top: 12px; display: block;
  border: 1px solid rgba(255, 255, 255, 0.18);
  box-shadow: 0 12px 36px rgba(0, 0, 0, 0.5);
  animation: mockup-reveal 0.9s var(--spring) backwards;
  /* Fit, never crop (Oct 28, 2026 — Yeinel's restored-review
   * screenshot: a tall mockup ran past its card and the product
   * was cut off mid-garment). The whole product always fits
   * inside the frame: height is capped to the viewport and the
   * picture is contained, letterboxed — never sliced. Applies
   * to fresh reviews, restored reviews, gallery slides, frozen
   * snapshots and the version-compare card alike (all .mockup). */
  max-height: 62vh; object-fit: contain;
}
@keyframes mockup-reveal {
  from { opacity: 0; transform: scale(0.96); filter: blur(14px) saturate(0.6); }
}

/* Version compare (Oct 28, 2026): the original-vs-cartoon pick after
 * a cartoonize — a small caps label sits over each image in the one
 * bot card. Static styles only (perf rule). */
.compare-label {
  display: block; margin-top: 16px;
  font-size: 12px; font-weight: 700; letter-spacing: 0.09em;
  text-transform: uppercase; opacity: 0.85;
}

/* Swipe gallery: horizontal = similar products, vertical = page scroll */
/* (Oct 22, 2026, Yeinel's ruling) There is NO vertical swipe and NO
 * variation control in the gallery: touch-action: pan-y hands vertical
 * drags back to the page as ordinary scrolls, while horizontal drags
 * reach the carousel handlers (pan-x is not allowed, so the browser
 * never claims them). New takes come only from the Reimagine button;
 * the lone browsing control is the "← Previous design" text tap. */
.design-gallery { touch-action: pan-y; user-select: none; -webkit-user-select: none; }
.design-gallery .gallery-img-wrap { min-height: 200px; }
.design-gallery .mockup { margin-top: 12px; }
.gallery-meta { display: flex; align-items: center; justify-content: center; gap: 12px; margin-top: 8px; }
.gallery-counter { font-size: 13px; opacity: 0.8; }
/* Previous-design tap (Oct 22, 2026): ONE understated text control,
 * shown only when a take was left behind via Reimagine — no box, no
 * counter, no chevron pair. Static styles only (perf rule). */
.prev-design-btn {
  background: none; border: none; padding: 4px 6px; cursor: pointer;
  color: rgba(255,255,255,0.72); font-size: 13px;
}
.prev-design-btn:active { color: rgba(255,255,255,0.95); }
.gallery-dots { display: flex; gap: 8px; padding: 8px; }
.gallery-dot { width: 10px; height: 10px; border-radius: 50%; background: rgba(255,255,255,0.25); cursor: pointer; }
.gallery-dot.active { background: rgba(255,255,255,0.9); }
/* Back-view dot (Oct 22, 2026): a ring, not a filled dot — it turns
 * the SAME garment around instead of selecting another one. */
.gallery-dot.view-dot { background: transparent; border: 2px solid rgba(255,255,255,0.45); width: 8px; height: 8px; align-self: center; }
.gallery-dot.view-dot.active { border-color: rgba(255,255,255,0.95); background: rgba(255,255,255,0.35); }
.gallery-hint { text-align: center; font-size: 12px; opacity: 0.5; margin-top: 4px; }

/* iPhone-style carousel: drag follows finger, snaps with spring */
.carousel-viewport {
  overflow: hidden; border-radius: 16px; margin-top: 12px;
  touch-action: pan-y; cursor: grab;
}
.carousel-viewport:active { cursor: grabbing; }
.carousel-track {
  display: flex; will-change: transform;
  /* Width set inline via JS: n * 100% */
}
.carousel-slide {
  flex: 0 0 100%; /* Each slide = 100% of viewport */
  width: 100%; min-width: 100%;
  max-width: 100%;
  position: relative; /* anchors the in-slide wait chip (below) */
}
.carousel-slide .mockup { margin-top: 0; }
/* Garment swipe (2026-10-19, W9): every stop is labeled with its
   garment name + price; a stop whose mockup is still being prepared
   shows the artwork itself on a dashed glass tile. */
.garment-stop-label {
  display: table; margin: 8px auto 2px; padding: 4px 12px;
  border-radius: 999px; font-size: 13px; font-weight: 600;
  background: rgba(255,255,255,0.08); border: 1px solid rgba(255,255,255,0.14);
}
.gallery-stop-name { font-size: 13px; font-weight: 600; opacity: 0.9; }
.carousel-slide.artwork-only .mockup {
  background: rgba(255,255,255,0.04);
  border: 1px dashed rgba(255,255,255,0.18); border-radius: 12px;
}
/* Garment-swipe placeholder (2026-10-19 fix pass): a stop whose garment
   mockup is still rendering shows an honest "preparing" tile in the
   mockup's place — never the bare artwork. */
.carousel-slide.garment-pending .garment-pending-box {
  width: 100%; aspect-ratio: 1 / 1; margin-top: 0;
  display: flex; flex-direction: column; gap: 12px;
  align-items: center; justify-content: center;
  text-align: center; padding: 20px; box-sizing: border-box;
  font-size: 14px; font-weight: 600; opacity: 0.75;
  background: rgba(255,255,255,0.04);
  border: 1px dashed rgba(255,255,255,0.18); border-radius: 16px;
  animation: garment-pending-pulse 1.6s ease-in-out infinite;
}
@keyframes garment-pending-pulse {
  0%, 100% { opacity: 0.55; }
  50% { opacity: 0.9; }
}
/* Pinch zoom (2026-10-19): the rendered image zooms inside its card. */
.design-gallery .carousel-slide img { will-change: transform; }
.design-gallery[data-zoomed="1"] .carousel-viewport { cursor: move; }
.carousel-slide .composite-wrap { margin-top: 0; }

/* Instant composite mockups: design overlaid on blank template */
/* Positioning is set inline per-angle (see renderGallery). */
.composite-wrap { position: relative; }
.composite-design {
  position: absolute;
  transform: translate(-50%, -50%);
  max-height: 32%;
  object-fit: contain;
  pointer-events: none;
}

/* iMessage-style typing indicator */
.typing-dots { display: inline-flex; gap: 5px; padding: 4px 2px; align-items: center; }
.typing-dots span {
  width: 8px; height: 8px; border-radius: 50%;
  background: var(--ink-dim);
  animation: typing-bounce 1.3s ease-in-out infinite;
}
.typing-dots span:nth-child(2) { animation-delay: 0.15s; }
.typing-dots span:nth-child(3) { animation-delay: 0.3s; }
@keyframes typing-bounce {
  0%, 60%, 100% { transform: translateY(0); opacity: 0.45; }
  30% { transform: translateY(-6px); opacity: 1; }
}

/* ------- quick replies: staggered spring chips ------- */
.quick-replies { display: flex; flex-wrap: wrap; gap: 9px; padding: 2px 6px; }
.quick-replies:empty { display: none; }
.quick-replies button.small-reply {
  font-size: 13.5px; padding: 8px 14px; min-height: 38px;
}

/* Category grid (welcome + product picker): an even 3 x 2 instead of
 * ragged content-sized rows with a lonely chip on the last row. */
.quick-replies.qr-compact { gap: 8px; }
.quick-replies button.qr-swatch {
  width: 32px; height: 32px; min-width: 32px; min-height: 32px;
  flex: 0 0 auto;
  border-radius: 50%; padding: 0;
  border: 2px solid rgba(255, 255, 255, 0.35);
  align-self: center;
}
.quick-replies button.qr-swatch.current {
  border-color: #ffffff;
  box-shadow: 0 0 0 2px var(--accent), 0 0 10px rgba(91, 140, 255, 0.55);
}
.quick-replies.qr-grid button {
  flex: 1 1 30%; max-width: calc((100% - 18px) / 3);
  text-align: center; padding-left: 6px; padding-right: 6px;
  font-size: 13px;
}
.quick-replies button {
  background: rgba(255, 255, 255, 0.08);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  backdrop-filter: blur(20px) saturate(160%);
  color: var(--ink);
  border: 1px solid rgba(255, 255, 255, 0.14);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12);
  border-radius: 999px; padding: 11px 20px; cursor: pointer;
  font-size: 14.5px; font-weight: 600; letter-spacing: -0.01em; min-height: 44px;
  transition: transform 0.3s var(--spring), background 0.25s, box-shadow 0.25s, border-color 0.25s;
  animation: chip-in 0.5s var(--spring-bounce) backwards;
}
.quick-replies button:nth-child(1) { animation-delay: 0.03s; }
.quick-replies button:nth-child(2) { animation-delay: 0.09s; }
.quick-replies button:nth-child(3) { animation-delay: 0.15s; }
.quick-replies button:nth-child(4) { animation-delay: 0.21s; }
.quick-replies button:nth-child(5) { animation-delay: 0.27s; }
@keyframes chip-in { from { opacity: 0; transform: translateY(10px) scale(0.9); } }
.quick-replies button:hover {
  background: rgba(255, 255, 255, 0.14);
  transform: translateY(-2px);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.16), 0 8px 22px rgba(0, 0, 0, 0.35);
  border-color: rgba(255, 255, 255, 0.25);
}
.quick-replies button:active { transform: scale(0.94); transition-duration: 0.1s; }
/* Hero actions (Reimagine / Buy now): bigger and bolder than the edit chips. */
.quick-replies button.big-reply {
  flex: 1 1 44%;
  font-size: 17px;
  font-weight: 700;
  padding: 15px 24px;
  min-height: 56px;
  border-radius: 18px;
  background: linear-gradient(135deg, rgba(79, 124, 255, 0.35), rgba(47, 95, 224, 0.35));
  border: 1px solid rgba(120, 160, 255, 0.45);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.18), 0 6px 18px rgba(47, 95, 224, 0.25);
}
.quick-replies button.big-reply:hover {
  background: linear-gradient(135deg, rgba(79, 124, 255, 0.5), rgba(47, 95, 224, 0.5));
  border-color: rgba(140, 175, 255, 0.6);
}
/* Primary reply (Oct 22, 2026, Yeinel's sitting): the ONE action the eye
 * lands on in a reply row — the vision step's "Looks good — make it" and
 * every Create/Go chip. Same brand gradient as the composer send button
 * and the user's own bubbles, white bold text, soft blue glow, slightly
 * larger padding. Placed after .big-reply so a chip carrying both
 * classes still ends up primary. Secondary chips are untouched. */
.quick-replies button.reply-primary {
  background: linear-gradient(135deg, #6b9bff 0%, #3b5fe3 100%);
  color: #fff;
  font-weight: 700;
  padding: 13px 24px;
  border: 1px solid rgba(255, 255, 255, 0.28);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.3),
    0 6px 22px var(--accent-glow);
}
.quick-replies button.reply-primary:hover {
  background: linear-gradient(135deg, #6b9bff 0%, #3b5fe3 100%);
  filter: brightness(1.08);
  border-color: rgba(255, 255, 255, 0.42);
}

/* Reply rows (Oct 28, 2026 — review action cleanup): setReplies
 * groups row-tagged options into .qr-row lines so the review
 * actions read as a hierarchy — Buy now full-width on top, edit
 * actions under it, feedback + Start over under those, swatches
 * in their own labeled row. Static layout only (perf rule). */
.qr-row {
  display: flex; flex-wrap: wrap; gap: 9px;
  flex: 1 1 100%; align-items: center;
}
.qr-row > button:nth-child(2) { animation-delay: 0.09s; }
.qr-row > button:nth-child(3) { animation-delay: 0.15s; }
.qr-row > button:nth-child(4) { animation-delay: 0.21s; }
.quick-replies button.qr-full { flex: 1 1 100%; }
.qr-row-label {
  font-size: 12px; font-weight: 700; letter-spacing: 0.08em;
  text-transform: uppercase; opacity: 0.65; align-self: center;
}

/* ------- product bar: one scrollable row above the composer -------
 * The 13 product types in a single horizontal strip (Yeinel,
 * 2026-10-19) instead of the welcome grid that filled the screen.
 * Same glass pills as the quick replies, slimmer; the strip scrolls
 * sideways, never wraps, and the composer stays pinned below it. */
.product-bar {
  display: flex; flex-wrap: nowrap; gap: 8px;
  overflow-x: auto; overflow-y: hidden;
  padding: 4px 6px;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}
.product-bar[hidden] { display: none; }
/* Horizontal rows (Nov 2, 2026): bindHorizontalScroll in app.js
 * scrolls them by mouse wheel and by hover-edge auto-scroll. There
 * is deliberately no CSS here — the drag this briefly replaced is
 * gone, so no grab cursors and no click-suppression rules remain. */
.product-bar::-webkit-scrollbar { display: none; }
.product-bar button {
  flex: 0 0 auto; white-space: nowrap;
  display: flex; align-items: center;
  background: rgba(255, 255, 255, 0.08);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  backdrop-filter: blur(20px) saturate(160%);
  color: var(--ink);
  border: 1px solid rgba(255, 255, 255, 0.14);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12);
  border-radius: 999px; padding: 8px 15px; cursor: pointer;
  font-size: 13.5px; font-weight: 600; letter-spacing: -0.01em; min-height: 38px;
  transition: transform 0.3s var(--spring), background 0.25s, box-shadow 0.25s, border-color 0.25s;
}
.product-bar button:hover {
  background: rgba(255, 255, 255, 0.14);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.16), 0 8px 22px rgba(0, 0, 0, 0.35);
  border-color: rgba(255, 255, 255, 0.25);
}
.product-bar button:active { transform: scale(0.94); transition-duration: 0.1s; }
.product-bar button.current {
  border-color: #ffffff;
  background: rgba(91, 140, 255, 0.22);
  box-shadow: 0 0 0 2px var(--accent), 0 0 10px rgba(91, 140, 255, 0.55);
}

/* ------- progress card with shimmer ------- */
.progress-card {
  /* Oct 21, 2026 (Yeinel's screenshot): this card is position:fixed over
   * the chat — with a 7% translucent background the bubble behind it
   * bled through and the two texts garbled. Near-opaque base layer so
   * nothing behind it can show through; the glass tint stays on top. */
  background: linear-gradient(rgba(23, 26, 38, 0.96), rgba(23, 26, 38, 0.96)), rgba(255, 255, 255, 0.07);
  -webkit-backdrop-filter: blur(28px) saturate(180%);
  backdrop-filter: blur(28px) saturate(180%);
  border: 1px solid rgba(255, 255, 255, 0.1);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12), 0 8px 30px rgba(0, 0, 0, 0.35);
  align-self: stretch; max-width: 100%;
  border-radius: 22px; padding: 18px 22px;
  font-size: 15.5px; position: relative; overflow: hidden;
}
.progress-card::before {
  /* traveling shimmer */
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(105deg, transparent 40%, rgba(255, 255, 255, 0.07) 50%, transparent 60%);
  animation: shimmer 2.4s linear infinite;
}
@keyframes shimmer { from { transform: translateX(-100%); } to { transform: translateX(100%); } }
.progress-card {
  position: fixed; left: 0; right: 0; margin: 0 auto;
  width: min(656px, calc(100% - 24px));
  bottom: calc(96px + env(safe-area-inset-bottom, 0px));
  z-index: 60;
  animation: none;
}
.progress-top {
  display: flex; justify-content: space-between; align-items: baseline;
  font-size: 13.5px; font-weight: 600; margin-bottom: 9px;
}
.progress-pct { color: var(--accent); font-variant-numeric: tabular-nums; }
.progress-track {
  height: 6px; border-radius: 999px;
  background: rgba(255, 255, 255, 0.12); overflow: hidden;
}
.progress-fill {
  height: 100%; border-radius: 999px;
  background: linear-gradient(90deg, var(--accent), #8ab4ff);
  transition: width 0.3s ease;
}
.progress-card .step-row { padding: 7px 0; color: var(--ink-dim); font-weight: 500; transition: color 0.3s; display: flex; align-items: center; gap: 10px; }
.progress-card .step-row.done { color: var(--good); font-weight: 700; }
.progress-card .step-row.working { color: var(--ink); font-weight: 600; }
.step-dot {
  width: 8px; height: 8px; border-radius: 50%; flex: 0 0 8px;
  background: var(--ink-faint); transition: background 0.3s, box-shadow 0.3s;
}
.step-row.done .step-dot { background: var(--good); box-shadow: 0 0 8px rgba(52, 211, 153, 0.6); }
.step-row.working .step-dot { background: var(--accent1); box-shadow: 0 0 8px var(--accent-glow); animation: dot-pulse 1.2s ease-in-out infinite; }
@keyframes dot-pulse { 0%, 100% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.35); opacity: 0.7; } }
.progress-card .step-row.working::after {
  content: "…";
  display: inline-block; width: 1.2em; text-align: left;
  animation: dots 1.2s steps(4) infinite;
}
@keyframes dots { 0% { content: ""; } 25% { content: "."; } 50% { content: ".."; } 75% { content: "..."; } }

/* ------- working progress: the Di fill (Oct 21, 2026) -------
 * One small bubble per user-waited operation: the Di lettering as a
 * ghost outline, filled by a brand-gradient copy clipped to the
 * progress width, % counter beside it. PERF: the only animated
 * properties are a clip-rect width on this ~62px SVG and a text node —
 * no backdrop-filter additions, no full-screen layers, no will-change.
 * (The Oct 21 PC-crawl lesson: never animate big blurred surfaces.) */
.di-working {
  display: flex; align-items: center; gap: 12px;
  padding: 8px 16px 8px 12px;
  transition: opacity 0.35s var(--spring), transform 0.35s var(--spring);
}
.di-working.di-done { opacity: 0; transform: scale(0.96); }
.di-mark { display: block; flex: 0 0 auto; }
.di-text {
  font-family: -apple-system, BlinkMacSystemFont, "SF Pro Display", "Segoe UI", Roboto, sans-serif;
  font-size: 44px; font-weight: 700; letter-spacing: -0.02em;
}
/* The takeover wordmark's lettering (Nov 2, 2026): Manrope 800 —
 * the same face and weight as the takeover's big numeral, so the
 * word reads as its peer. font-size is in SVG user units (the
 * wordmark's viewBox is 510 wide at font-size 100); the rendered
 * size comes from the .di-wordmark width rule under .di-takeover. */
.di-word-text {
  font-family: 'Manrope', ui-rounded, system-ui, -apple-system, 'Segoe UI', sans-serif;
  font-size: 100px; font-weight: 800; letter-spacing: -0.02em;
}
.di-ghost { fill: rgba(255, 255, 255, 0.07); stroke: rgba(255, 255, 255, 0.38); stroke-width: 0.8; }
.di-pct {
  font-size: 17px; font-weight: 700; color: var(--accent1);
  font-variant-numeric: tabular-nums; min-width: 3.2ch;
}
.progress-di { display: flex; align-items: center; }

/* ------- in-slide Di progress (Oct 22, 2026) -------
 * The same Di fill, inside a gallery slide, for a garment wait the
 * customer is actually looking at: mounted in a pending slide's
 * "Preparing…" box (stacked under the label by the column layout
 * above), or pinned as a chip over an imaged slide while its take
 * re-renders (stale garment/color). Same perf discipline: only the
 * ~46px mark's clip width and a text node ever animate. */
.slide-wait {
  display: flex; align-items: center; gap: 10px;
  transition: opacity 0.35s var(--spring), transform 0.35s var(--spring);
}
.slide-wait.di-done { opacity: 0; transform: scale(0.96); }
.slide-wait .di-mark { width: 46px; height: 33px; }
.slide-wait-overlay {
  position: absolute; left: 50%; bottom: 44px; z-index: 3;
  transform: translateX(-50%);
  background: rgba(10, 13, 22, 0.78);
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 999px; padding: 6px 14px 6px 10px;
}
.slide-wait-overlay.di-done { transform: translateX(-50%) scale(0.96); }

/* ------- product page render progress (Oct 22, 2026) -------
 * The same Di fill on the shop product page: while a picked
 * variant color's photo renders (first-time renders take real
 * seconds server-side), the mark + % sit under the photo with
 * the "Preparing the <Color> photo…" caption instead of a
 * frozen-looking page. Reuses .di-mark/.di-text/.di-ghost/
 * .di-pct above; only this small row is new. Same perf
 * discipline: no backdrop-filter, no full-screen animation —
 * a ~46px clip width and a text node are all that move. */
.render-wait {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  margin-top: 10px;
  transition: opacity 0.35s var(--spring), transform 0.35s var(--spring);
}
.render-wait.di-done { opacity: 0; transform: scale(0.96); }
.render-wait .di-mark { width: 46px; height: 33px; }

/* ------- buy button ------- */
.buy-link {
  display: block; text-align: center;
  margin-top: 14px; padding: 16px 20px; border-radius: 18px;
  background: linear-gradient(135deg, #2fe38a 0%, #34d399 50%, #22c55e 100%);
  background-size: 200% 200%;
  color: #03240f; font-weight: 800; font-size: 17px; letter-spacing: -0.01em; text-decoration: none;
  border: 1px solid rgba(255, 255, 255, 0.25);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.4), 0 8px 28px rgba(52, 211, 153, 0.35);
  transition: transform 0.3s var(--spring), box-shadow 0.3s, background-position 0.6s;
  min-height: 56px;
}
.buy-link:hover {
  transform: translateY(-2px) scale(1.015);
  background-position: 100% 50%;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.4), 0 12px 36px rgba(52, 211, 153, 0.5);
}
.buy-link:active { transform: scale(0.97); transition-duration: 0.1s; }

/* ------- composer: the hero element ------- */
.composer {
  display: flex; gap: 10px; padding: 10px;
  border-radius: 28px; margin-bottom: 14px;
  transition: box-shadow 0.35s, border-color 0.35s;
}
.composer:focus-within {
  border-color: rgba(91, 140, 255, 0.45);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.14),
    0 0 0 4px rgba(91, 140, 255, 0.14),
    0 12px 40px rgba(0, 0, 0, 0.4),
    0 0 32px rgba(91, 140, 255, 0.12);
}
.composer input {
  flex: 1; padding: 13px 20px; border-radius: 999px;
  border: 1px solid transparent;
  background: rgba(0, 0, 0, 0.32); color: var(--ink);
  font-size: 16px; outline: none; min-height: 50px;
  font-family: inherit; letter-spacing: -0.011em;
  transition: background 0.25s;
}
.composer input::placeholder { color: var(--ink-faint); }
.composer input:focus { background: rgba(0, 0, 0, 0.45); }
.composer button {
  width: 52px; height: 50px; flex: 0 0 52px;
  border-radius: 50%; border: none; cursor: pointer;
  background: linear-gradient(135deg, #6b9bff 0%, #3b5fe3 100%);
  color: #fff; font-size: 20px; font-weight: 800;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.35),
    0 4px 18px var(--accent-glow);
  transition: transform 0.3s var(--spring-bounce), box-shadow 0.25s, filter 0.25s;
  display: flex; align-items: center; justify-content: center;
}
.composer button:hover { transform: scale(1.1) rotate(-8deg); filter: brightness(1.1); }
.composer button:active { transform: scale(0.88); transition-duration: 0.08s; }
.composer button:disabled { opacity: 0.35; cursor: default; transform: none; filter: grayscale(0.4); }

.error { color: #ff9d9d; font-size: 14.5px; }
.demo-note { display: block; margin-top: 8px; font-size: 12.5px; color: var(--ink-dim); }

/* ------- confetti ------- */
.confetti { position: fixed; inset: 0; pointer-events: none; z-index: 50; overflow: hidden; }
.confetti-piece {
  position: absolute; top: -20px; width: 10px; height: 14px; border-radius: 3px;
  animation: fall linear forwards;
}
@keyframes fall {
  to { transform: translateY(110vh) rotate(720deg); opacity: 0.8; }
}

/* ------- product cards (legacy) ------- */
.cards { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; width: 100%; }
.card {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 18px 10px; border-radius: 22px; cursor: pointer;
  background: rgba(255, 255, 255, 0.07);
  -webkit-backdrop-filter: blur(28px) saturate(180%);
  backdrop-filter: blur(28px) saturate(180%);
  border: 1px solid rgba(255, 255, 255, 0.1);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12);
  color: var(--ink); font-size: 15px; font-weight: 700;
  transition: transform 0.3s var(--spring), box-shadow 0.3s, border-color 0.3s;
  min-height: 110px; justify-content: center;
  animation: chip-in 0.5s var(--spring-bounce) backwards;
}
.card:nth-child(2) { animation-delay: 0.06s; }
.card:nth-child(3) { animation-delay: 0.12s; }
.card:nth-child(4) { animation-delay: 0.18s; }
.card:hover {
  transform: translateY(-4px) scale(1.02);
  border-color: rgba(91, 140, 255, 0.5);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.16), 0 12px 32px rgba(91, 140, 255, 0.25);
}
.card:active { transform: scale(0.96); transition-duration: 0.1s; }
.card .card-emoji { font-size: 44px; filter: drop-shadow(0 4px 10px rgba(0, 0, 0, 0.4)); }
.card .card-hint { font-size: 12px; font-weight: 500; color: var(--ink-dim); }

/* ------- storefront ------- */
.shop-wrap { max-width: 560px; margin: 0 auto; padding: 16px 16px 120px; position: relative; z-index: 1; }
.shop-card { border-radius: 24px; padding: 22px; margin-bottom: 16px; animation: msg-in 0.6s var(--spring) backwards; }
.product-img { width: 100%; border-radius: 16px; display: block; background: #141821; box-shadow: 0 12px 36px rgba(0,0,0,0.45); }
.product-title { font-size: 25px; margin: 16px 0 4px; letter-spacing: -0.02em; font-weight: 700; }
.product-price { font-size: 22px; font-weight: 800; color: var(--good); margin: 6px 0 12px; letter-spacing: -0.01em; }
.field label { display: block; font-size: 12px; font-weight: 700; color: var(--ink-dim); margin: 14px 0 7px; text-transform: uppercase; letter-spacing: 0.06em; }
.field select, .field input { width: 100%; padding: 13px 15px; border-radius: 14px; border: 1px solid rgba(255,255,255,0.1); background: rgba(0,0,0,0.35); color: var(--ink); font-size: 16px; font-family: inherit; transition: border-color 0.25s, box-shadow 0.25s; }
.field select:focus, .field input:focus { outline: none; border-color: rgba(91,140,255,0.5); box-shadow: 0 0 0 3px rgba(91,140,255,0.15); }
.field select option { background: #141821; }
.btn-primary { display: block; width: 100%; text-align: center; padding: 16px; border: none; border-radius: 16px; font-size: 17px; font-weight: 800; letter-spacing: -0.01em; color: #fff; background: linear-gradient(135deg, #6b9bff, #3b5fe3); cursor: pointer; margin-top: 16px; text-decoration: none; box-shadow: inset 0 1px 0 rgba(255,255,255,0.3), 0 6px 24px var(--accent-glow); transition: transform 0.3s var(--spring), filter 0.25s; }
.btn-primary:hover { transform: translateY(-2px); filter: brightness(1.08); }
.btn-primary:active { transform: scale(0.98); }
.btn-primary:disabled { opacity: 0.55; cursor: wait; transform: none; }
.btn-ghost { display: block; width: 100%; text-align: center; padding: 14px; border-radius: 16px; font-size: 15px; font-weight: 700; color: var(--ink); background: rgba(255,255,255,0.07); border: 1px solid rgba(255,255,255,0.1); cursor: pointer; margin-top: 10px; text-decoration: none; transition: transform 0.3s var(--spring), background 0.25s; }
.btn-ghost:hover { background: rgba(255,255,255,0.12); transform: translateY(-1px); }
.btn-ghost:active { transform: scale(0.98); }
.qty-row { display: flex; align-items: center; gap: 14px; }
.qty-row button { width: 42px; height: 42px; border-radius: 14px; border: 1px solid rgba(255,255,255,0.12); background: rgba(255,255,255,0.07); color: var(--ink); font-size: 20px; cursor: pointer; transition: transform 0.2s var(--spring), background 0.2s; }
.qty-row button:hover { background: rgba(255,255,255,0.14); }
.qty-row button:active { transform: scale(0.9); }
.qty-row span { font-size: 18px; font-weight: 800; min-width: 30px; text-align: center; }
.back-link { display: inline-block; color: var(--ink-dim); text-decoration: none; margin-bottom: 12px; font-size: 14px; font-weight: 600; transition: color 0.2s; }
.back-link:hover { color: var(--ink); }

/* cart drawer */
.cart-fab { position: fixed; right: 18px; bottom: 18px; width: 62px; height: 62px; border-radius: 50%; font-size: 26px; cursor: pointer; z-index: 60; transition: transform 0.3s var(--spring-bounce); }
.cart-fab:hover { transform: scale(1.08); }
.cart-fab:active { transform: scale(0.92); }
.cart-count { position: absolute; top: -4px; right: -4px; background: linear-gradient(135deg, #6b9bff, #3b5fe3); color: #fff; font-size: 12px; font-weight: 800; min-width: 22px; height: 22px; border-radius: 11px; display: flex; align-items: center; justify-content: center; box-shadow: 0 2px 10px var(--accent-glow); }
.cart-overlay { position: fixed; inset: 0; background: rgba(0,0,0,0.55); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); opacity: 0; pointer-events: none; transition: opacity 0.3s; z-index: 70; }
.cart-overlay.show { opacity: 1; pointer-events: auto; }
.cart-drawer { position: fixed; top: 0; right: 0; bottom: 0; width: min(400px, 92vw); z-index: 71; transform: translateX(105%); transition: transform 0.45s var(--spring); display: flex; flex-direction: column; padding: 20px; border-radius: 24px 0 0 24px; }
.cart-drawer.show { transform: none; }
.cart-head { display: flex; justify-content: space-between; align-items: center; }
.cart-head h2 { margin: 0; font-size: 20px; letter-spacing: -0.02em; }
.cart-close { background: rgba(255,255,255,0.08); border: 1px solid rgba(255,255,255,0.1); color: var(--ink-dim); font-size: 16px; cursor: pointer; width: 34px; height: 34px; border-radius: 50%; transition: transform 0.25s var(--spring), background 0.2s; }
.cart-close:hover { background: rgba(255,255,255,0.15); transform: rotate(90deg); }
.cart-items { flex: 1; overflow-y: auto; margin: 12px 0; }
.cart-item { display: flex; gap: 12px; padding: 12px 0; border-bottom: 1px solid rgba(255,255,255,0.08); animation: msg-in 0.4s var(--spring) backwards; }
.cart-item img { width: 64px; height: 64px; object-fit: cover; border-radius: 12px; background: #141821; }
.cart-item-info { flex: 1; }
.cart-item-title { font-weight: 700; font-size: 14px; letter-spacing: -0.01em; }
.cart-item-variant { color: var(--ink-dim); font-size: 12px; margin: 2px 0 6px; }
.cart-item-row { display: flex; align-items: center; gap: 10px; }
.cart-item-row button { width: 28px; height: 28px; border-radius: 9px; border: 1px solid rgba(255,255,255,0.12); background: rgba(255,255,255,0.07); color: var(--ink); cursor: pointer; transition: transform 0.2s var(--spring); }
.cart-item-row button:active { transform: scale(0.88); }
.cart-item-right { text-align: right; font-weight: 700; font-size: 14px; }
.cart-rm { background: none; border: none; color: var(--ink-dim); font-size: 12px; cursor: pointer; text-decoration: underline; margin-top: 6px; }
.cart-empty { color: var(--ink-dim); text-align: center; margin-top: 40px; }
.cart-foot { border-top: 1px solid rgba(255,255,255,0.08); padding-top: 14px; }
.cart-total { display: flex; justify-content: space-between; font-size: 17px; margin-bottom: 4px; font-weight: 700; }

/* checkout */
.order-line { display: flex; justify-content: space-between; flex-wrap: wrap; gap: 4px 12px; padding: 9px 0; border-bottom: 1px solid rgba(255,255,255,0.08); font-size: 14px; }
.order-line .dim { color: var(--ink-dim); font-size: 12px; }
.totals { margin-top: 10px; }
.totals .order-line { border: none; padding: 5px 0; }
.totals .grand { font-size: 19px; font-weight: 800; letter-spacing: -0.01em; }
.demo-banner { background: rgba(255, 190, 60, 0.1); border: 1px solid rgba(255,190,60,0.35); border-radius: 14px; padding: 13px 15px; font-size: 13px; color: #ffd98a; margin-bottom: 14px; }
.secure-note { font-size: 12px; color: var(--ink-dim); text-align: center; margin-top: 10px; }
.error-box { background: rgba(255,90,90,0.1); border: 1px solid rgba(255,90,90,0.4); color: #ff9d9d; border-radius: 14px; padding: 13px 15px; font-size: 14px; margin-top: 12px; display: none; animation: msg-in 0.4s var(--spring) backwards; }
.checkmark { font-size: 64px; text-align: center; animation: chip-in 0.7s var(--spring-bounce) backwards; }
.success-title { text-align: center; font-size: 25px; margin: 14px 0 4px; letter-spacing: -0.02em; font-weight: 700; }
.order-id { text-align: center; color: var(--ink-dim); font-size: 14px; }

@media (prefers-reduced-motion: reduce) {
  .blob, .bg-blobs::after { display: none; }
  .progress-card .step-row.working::after, .progress-card::before { animation: none; }
  .msg, .quick-replies button, .card, .header { animation: none; }
  * { transition-duration: 0.01ms !important; }
}

@media (max-width: 560px) {
  .header { flex-wrap: nowrap; gap: 8px; padding: 10px 12px; border-radius: 20px; }
  .header h1 { font-size: 17px; }
  .logo { width: 40px; height: 40px; flex-basis: 40px; border-radius: 13px; }
  .subtitle { font-size: 0; margin: 2px 0 0; }
  .subtitle a { font-size: 12px; }
  .header .auth-btn { font-size: 12.5px; padding: 7px 11px; }
}

@media (max-width: 420px) {
  .header h1 { font-size: 17px; }
  .logo { width: 40px; height: 40px; flex-basis: 40px; font-size: 26px; border-radius: 13px; }
  .msg { font-size: 15px; max-width: 90%; }
  .app { padding: 10px 10px 0; gap: 10px; }
}

/* ------- auth (Supabase login) ------- */
.auth-btn {
  margin-left: auto; flex: 0 0 auto;
  font: inherit; font-size: 13px; font-weight: 600;
  color: var(--ink);
  background: var(--glass-bright);
  border: 1px solid rgba(255, 255, 255, 0.16);
  border-radius: 999px;
  padding: 8px 14px;
  cursor: pointer;
  max-width: 45%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  transition: transform 0.15s var(--spring), background 0.2s, box-shadow 0.2s;
}
.auth-btn:hover { background: rgba(255, 255, 255, 0.16); box-shadow: 0 0 0 4px rgba(91, 140, 255, 0.12); }
.auth-btn:active { transform: scale(0.96); }
.auth-btn.signed-in { color: var(--ink); font-weight: 600; }

/* D-05: Privacy/Terms reachable from the app itself (under the
   composer) — the legal pages existed but nothing linked to them. */
.legal-line { text-align: center; font-size: 12px; color: var(--ink-dim); padding: 8px 0 14px; }
.legal-line a { color: var(--ink-dim); text-decoration: underline; text-underline-offset: 2px; }
/* D-15: the signed-in account card (packs + two code rows + sign
   out) can exceed a small phone's height — cap it and scroll the
   card, never the page behind it. */
.auth-modal { overflow-y: auto; }
.auth-card { max-height: calc(100dvh - 40px); overflow-y: auto; }
.auth-modal {
  position: fixed; inset: 0; z-index: 60;
  display: flex; align-items: center; justify-content: center;
  padding: 20px;
  background: rgba(3, 5, 10, 0.55);
  -webkit-backdrop-filter: blur(6px);
  backdrop-filter: blur(6px);
  opacity: 0; transition: opacity 0.18s ease;
}
.auth-modal[hidden] { display: none; }
/* The JS drives modal sub-views with the hidden attribute; no display
 * rule inside a card (.auth-card form flex, .auth-toggle block, …) may
 * ever force a hidden element back on screen. Systemic guard — the
 * sign-in form leaking into the signed-in view was this exact bug. */
.auth-card [hidden] { display: none !important; }
.auth-modal.open { opacity: 1; }

/* My Creations log */
.creations-list {
  display: flex; flex-direction: column; gap: 10px;
  max-height: 60vh; overflow-y: auto;
}
.creation-card {
  display: flex; gap: 12px; align-items: center;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: 16px; padding: 10px;
}
.creation-card img {
  width: 56px; height: 56px; border-radius: 10px;
  object-fit: cover; flex: none; background: rgba(255, 255, 255, 0.08);
}
.creation-meta { min-width: 0; }
.creation-title { font-weight: 600; font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.creation-sub { color: var(--ink-dim); font-size: 12.5px; margin-top: 2px; }
.creation-link { color: var(--accent, #7db3ff); font-size: 12.5px; font-weight: 600; text-decoration: none; }
.creation-link:hover { text-decoration: underline; }
.auth-card {
  position: relative;
  width: 100%; max-width: 360px;
  border-radius: 24px;
  padding: 26px 24px 22px;
  transform: translateY(10px) scale(0.98);
  transition: transform 0.22s var(--spring);
}
.auth-modal.open .auth-card { transform: none; }
.auth-card h2 { margin: 0 0 16px; font-size: 20px; font-weight: 700; letter-spacing: -0.02em; }
.auth-close {
  position: absolute; top: 10px; right: 12px;
  font: inherit; font-size: 22px; line-height: 1;
  color: var(--ink-dim);
  background: none; border: none; cursor: pointer;
  padding: 6px 8px; border-radius: 10px;
}
.auth-close:hover { color: var(--ink); background: rgba(255, 255, 255, 0.08); }
.auth-card form { display: flex; flex-direction: column; gap: 10px; }
.auth-card input {
  font: inherit; font-size: 15px;
  color: var(--ink);
  background: rgba(255, 255, 255, 0.06);
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 14px;
  padding: 12px 14px;
  outline: none;
  transition: border-color 0.2s, box-shadow 0.2s;
}
.auth-card input::placeholder { color: var(--ink-faint); }
.auth-card input:focus { border-color: var(--accent1); box-shadow: 0 0 0 4px rgba(91, 140, 255, 0.18); }
.auth-hint { margin: 0 0 14px; font-size: 14px; color: var(--ink-dim); word-break: break-word; }
.auth-msg { margin: 2px 0 0; font-size: 13.5px; color: var(--ink-dim); }
.auth-field { position: relative; display: flex; }
.auth-field[hidden] { display: none; }
.auth-field input { flex: 1; min-width: 0; padding-right: 46px; }
.auth-eye {
  position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
  display: flex; align-items: center; justify-content: center;
  color: var(--ink-dim);
  background: none; border: none; cursor: pointer;
  padding: 7px; border-radius: 10px;
}
.auth-eye:hover { color: var(--ink); background: rgba(255, 255, 255, 0.08); }
.auth-eye .eye-closed { display: none; }
.auth-eye[aria-pressed="true"] .eye-open { display: none; }
.auth-eye[aria-pressed="true"] .eye-closed { display: block; }
.auth-pw-hint { margin: -4px 2px 0; font-size: 12.5px; color: var(--ink-faint); }
.auth-divider {
  display: flex; align-items: center; gap: 12px;
  margin: 16px 0 12px;
  font-size: 12px; color: var(--ink-faint);
}
.auth-divider::before, .auth-divider::after {
  content: ""; flex: 1; height: 1px; background: rgba(255, 255, 255, 0.14);
}
.auth-google {
  font: inherit; font-size: 15px; font-weight: 600;
  color: #1f2430;
  background: rgba(255, 255, 255, 0.94);
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 14px;
  padding: 11px 14px; width: 100%;
  cursor: pointer;
  display: flex; align-items: center; justify-content: center; gap: 10px;
  transition: transform 0.15s var(--spring), opacity 0.2s;
}
.auth-google:hover { opacity: 0.92; }
.auth-google:active { transform: scale(0.98); }
.auth-submit {
  font: inherit; font-size: 15px; font-weight: 600;
  color: #fff;
  background: linear-gradient(180deg, var(--accent1), var(--accent2));
  border: none; border-radius: 14px;
  padding: 12px 14px; width: 100%;
  cursor: pointer;
  box-shadow: 0 6px 20px var(--accent-glow);
  transition: transform 0.15s var(--spring), opacity 0.2s;
}
.auth-submit:hover { opacity: 0.94; }
.auth-submit:active { transform: scale(0.98); }
.auth-submit:disabled { opacity: 0.55; cursor: default; }
.auth-buy { margin: 10px 0 4px; }
#packList { display: grid; gap: 8px; }
.pack-btn.selected { box-shadow: 0 0 0 2px #ffffff inset; filter: brightness(1.18); }
.buy-card-el { margin: 10px 0; padding: 12px; border-radius: 12px; background: rgba(255,255,255,0.08); border: 1px solid rgba(255,255,255,0.18); }
.auth-redeem { display: flex; gap: 8px; margin: 10px 0 4px; }
.auth-redeem .auth-input { flex: 1; min-width: 0; }
.auth-redeem .auth-submit { width: auto; padding-left: 16px; padding-right: 16px; white-space: nowrap; }
.auth-toggle {
  font: inherit; font-size: 13.5px; font-weight: 500;
  color: var(--accent1);
  background: none; border: none; cursor: pointer;
  display: block; margin: 14px auto 0; padding: 4px 6px;
}
.auth-toggle:hover { text-decoration: underline; }
.auth-balance { margin: -8px 0 4px; font-size: 14px; font-weight: 600; color: var(--ink-dim); }
.auth-section-title {
  margin: 18px 0 2px; font-size: 12px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.06em; color: var(--ink-dim);
}
.auth-signout {
  font: inherit; font-size: 14px; font-weight: 500;
  color: var(--ink-dim);
  background: none; border: none; cursor: pointer;
  display: block; margin: 18px auto 0; padding: 4px 6px;
}
.auth-signout:hover { color: var(--ink); text-decoration: underline; }

/* ================= UX REBUILD (Oct 30, 2026) =================
 * The approved preview's look, layered over the existing sheet.
 * Append-only: every rule above stays in force; this section
 * re-skins the canvas/palette and styles the new home/studio
 * chrome. Palette: soft-dark, easy on the eyes — canvas #1D1E23
 * on a #101114 sheet, ink #ECECEA, muted indigo accent, coral
 * secondary. No infinite animations on fixed layers (perf law). */

:root {
  --bg: #101114;
  --bg-soft: #1d1e23;
  --card: rgba(255, 255, 255, 0.055);
  --card-border: rgba(255, 255, 255, 0.13);
  --ink: #ececea;
  --ink-dim: #a7a8ad;
  --accent: #7c86d8;
  --accent-strong: #6670c4;
  --accent-soft: rgba(124, 134, 216, 0.16);
  --mint: #7fd1ae;
  --rose: #f08a76;
}

html, body { background: var(--bg); }
body { font-family: 'Manrope', ui-rounded, system-ui, -apple-system, 'Segoe UI', sans-serif; }

.app {
  max-width: 480px;
  background: var(--bg-soft);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.05), 0 24px 70px rgba(0, 0, 0, 0.5);
  padding-top: env(safe-area-inset-top);
}

/* The aurora blobs stay but go static and muted (perf law). */
.blob { opacity: 0.13; animation: none; }

/* ---- header: two tidy rows, everything reachable ---- */
.topbar {
  position: sticky; top: 0; z-index: 40;
  flex-direction: column; align-items: stretch; gap: 7px;
  padding: 10px 12px 9px;
  background: rgba(29, 30, 35, 0.86);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  border-bottom: 1px solid rgba(255, 255, 255, 0.07);
}
.brand-row, .ctrl-row { display: flex; align-items: center; gap: 8px; }
.brand-row .brand { font-size: 17px; }
.brand-row .steps { margin-left: auto; }
.ctrl-row { flex-wrap: wrap; }
.glass {
  background: var(--card);
  border: 1px solid var(--card-border);
  border-radius: 18px;
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
}
.icon-btn, .lang-toggle, .credits-chip {
  font: inherit; font-size: 12.5px; font-weight: 700; color: var(--ink);
  background: rgba(255, 255, 255, 0.07);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 999px; padding: 7px 12px; cursor: pointer;
  transition: transform 0.15s ease, background 0.2s ease;
}
.icon-btn:active, .lang-toggle:active, .credits-chip:active { transform: scale(0.96); }
.lang-toggle { display: inline-flex; align-items: center; gap: 5px; padding: 5px 9px; }
.lang-toggle .opt { padding: 2px 7px; border-radius: 999px; color: var(--ink-dim); font-weight: 800; }
.lang-toggle .opt.on { background: rgba(255, 255, 255, 0.16); color: var(--ink); }
.lang-toggle .sep { color: var(--ink-dim); opacity: 0.6; }
.credits-chip { color: #ffd9a8; border-color: rgba(255, 217, 168, 0.35); }
.ctrl-row .auth-btn { margin-left: auto; }

/* ---- scrolling stage ---- */
.stage-scroll {
  flex: 1 1 auto; overflow-y: auto; overflow-x: hidden;
  -webkit-overflow-scrolling: touch;
  display: flex; flex-direction: column;
}
.chat { flex: 0 0 auto; overflow: visible; padding-bottom: 8px; }
.home-sections { padding: 4px 14px 26px; }

/* ---- headline + starter chips ---- */
.home-headline { padding: 20px 18px 6px; }
.home-headline h1 {
  margin: 0 0 8px; font-size: 27px; line-height: 1.16; letter-spacing: -0.02em; font-weight: 800;
}
.home-headline p { margin: 0; color: var(--ink-dim); font-size: 14.5px; line-height: 1.5; }
.starter-chips { display: flex; flex-wrap: nowrap; gap: 8px; margin-top: 14px; overflow-x: auto; }
.starter-chip {
  font: inherit; font-size: 13px; font-weight: 700; color: var(--ink);
  background: rgba(255, 255, 255, 0.07); border: 1px solid rgba(255, 255, 255, 0.13);
  border-radius: 999px; padding: 8px 13px; cursor: pointer;
  transition: transform 0.15s ease, background 0.2s ease;
}
.starter-chip:hover { background: rgba(255, 255, 255, 0.12); }
.starter-chip:active { transform: scale(0.96); }

/* ---- home sections ---- */
.sect { margin-top: 26px; }
.sect-head { display: flex; align-items: baseline; justify-content: space-between; margin: 0 2px 10px; }
.sect-head h2, .sect-label {
  margin: 0; font-size: 12px; font-weight: 800; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--ink-dim);
}
.fresh-card {
  position: relative; display: flex; gap: 12px; align-items: center;
  padding: 10px; margin-bottom: 10px; cursor: pointer; text-align: left; width: 100%;
  transition: transform 0.18s ease, background 0.2s ease;
}
.fresh-card:active { transform: scale(0.985); }
.fresh-img { width: 74px; height: 74px; border-radius: 13px; overflow: hidden; flex: 0 0 auto; background: #26272d; }
.fresh-img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.fresh-meta { display: flex; flex-direction: column; gap: 2px; min-width: 0; padding-right: 34px; }
.fresh-meta b { font-size: 14.5px; }
.fresh-meta span { font-size: 12.5px; color: var(--ink-dim); line-height: 1.4; }
.fresh-meta .fresh-go { color: var(--accent); font-weight: 700; font-size: 12.5px; margin-top: 3px; }
.heart-btn {
  position: absolute; top: 10px; right: 10px;
  width: 32px; height: 32px; border-radius: 50%;
  background: rgba(255, 255, 255, 0.08); border: 1px solid rgba(255, 255, 255, 0.12);
  color: var(--ink-dim); font-size: 16px; line-height: 1; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: transform 0.15s ease, color 0.2s ease;
}
.heart-btn.loved { color: var(--rose); border-color: rgba(240, 138, 118, 0.5); }
.heart-btn:active { transform: scale(0.88); }
.your-teaser {
  width: 100%; display: flex; align-items: center; justify-content: space-between;
  padding: 14px 16px; font: inherit; font-size: 13.5px; color: var(--ink-dim); cursor: pointer;
}
.your-teaser b { color: var(--accent); font-size: 13.5px; }
.your-empty { color: var(--ink-dim); font-size: 13.5px; margin: 2px; }
.your-row { display: flex; gap: 10px; overflow-x: auto; padding-bottom: 6px; scrollbar-width: none; }
.your-row::-webkit-scrollbar { display: none; }
.your-card {
  flex: 0 0 108px; font: inherit; text-align: left; cursor: pointer;
  background: var(--card); border: 1px solid var(--card-border); border-radius: 14px;
  padding: 8px; display: flex; flex-direction: column; gap: 3px;
}
.your-card img { width: 100%; height: 84px; object-fit: cover; border-radius: 9px; background: #26272d; }
.your-card b { font-size: 12px; color: var(--ink); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.your-card span { font-size: 11px; color: var(--ink-dim); }
.how-steps { display: flex; flex-direction: column; gap: 9px; }
.how-step { display: flex; gap: 12px; align-items: flex-start; padding: 13px 14px; }
.how-num {
  flex: 0 0 auto; width: 26px; height: 26px; border-radius: 50%;
  background: var(--accent-soft); color: var(--accent);
  display: flex; align-items: center; justify-content: center;
  font-size: 13px; font-weight: 800;
}
.how-step b { display: block; font-size: 14px; margin-bottom: 2px; }
.how-step p { margin: 0; font-size: 13px; color: var(--ink-dim); line-height: 1.45; }
.popular-wrap { padding: 0 14px; margin-top: 4px; }
.popular-wrap .sect-label { display: block; margin: 0 2px 8px; }
body[data-stage="studio"] .popular-wrap { display: none; }

/* ---- studio chrome ---- */
.studio-chrome { padding: 4px 14px 10px; display: flex; flex-direction: column; gap: 12px; }
.price-unit { display: flex; align-items: flex-start; justify-content: space-between; gap: 12px; padding: 13px 15px; }
.price-unit .pu-main { min-width: 0; }
.price-unit b { display: block; font-size: 15.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.price-unit span { font-size: 12.5px; color: var(--ink-dim); }
.price-unit .pu-price { font-size: 19px; font-weight: 800; white-space: nowrap; }
.price-unit .bnpl-line { font-size: 12px; color: var(--ink-dim); margin-top: 3px; text-align: right; }
.price-unit .bnpl-line b { display: inline; font-size: 12px; color: var(--ink); }
.takes-label { font-size: 12px; font-weight: 800; letter-spacing: 0.07em; text-transform: uppercase; color: var(--ink-dim); margin: 0 2px 8px; }
.takes-thumbs { display: flex; gap: 9px; overflow-x: auto; padding-bottom: 4px; scrollbar-width: none; }
.takes-thumbs::-webkit-scrollbar { display: none; }
.take-thumb {
  flex: 0 0 62px; width: 62px; height: 62px; border-radius: 13px; overflow: hidden;
  border: 2px solid rgba(255, 255, 255, 0.12); background: #26272d; cursor: pointer; padding: 0;
}
.take-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.take-thumb.current { border-color: var(--accent); }
.everything-block h3 { font-size: 14.5px; margin: 0 2px 9px; }
.eg-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 10px; }
.eg-cell {
  font: inherit; text-align: left; cursor: pointer; padding: 0 0 9px; overflow: hidden;
  background: var(--card); border: 1px solid var(--card-border); border-radius: 15px; color: var(--ink);
  display: flex; flex-direction: column;
}
.eg-cell img { width: 100%; height: 118px; object-fit: cover; background: #26272d; display: block; }
.eg-cell .eg-name { font-size: 13px; font-weight: 700; padding: 8px 11px 0; }
.eg-cell .eg-price { font-size: 12px; color: var(--ink-dim); padding: 1px 11px 0; }
.buy-card { padding: 15px; }
.buy-head { display: flex; gap: 12px; align-items: center; margin-bottom: 12px; }
.buy-head img { width: 56px; height: 56px; border-radius: 12px; object-fit: cover; background: #26272d; }
.buy-head b { display: block; font-size: 14.5px; }
.buy-head span { font-size: 12.5px; color: var(--ink-dim); }
.receipt .rrow { display: flex; justify-content: space-between; font-size: 13.5px; color: var(--ink-dim); padding: 4px 0; }
.receipt .rrow.total { color: var(--ink); font-weight: 800; font-size: 15px; border-top: 1px solid rgba(255, 255, 255, 0.1); margin-top: 6px; padding-top: 10px; }
.ship-meter { margin: 12px 0 4px; }
.ship-track { height: 7px; border-radius: 99px; background: rgba(255, 255, 255, 0.1); overflow: hidden; }
.ship-fill { height: 100%; border-radius: 99px; background: linear-gradient(90deg, var(--accent-strong), var(--accent)); transition: width 0.5s ease; }
.ship-text { font-size: 12.5px; color: var(--ink-dim); margin-top: 7px; }
.buy-now {
  width: 100%; margin-top: 12px; font: inherit; font-size: 15.5px; font-weight: 800;
  color: #fff; background: linear-gradient(180deg, var(--accent), var(--accent-strong));
  border: none; border-radius: 14px; padding: 14px; cursor: pointer;
  transition: transform 0.15s ease, filter 0.2s ease;
}
.buy-now:active { transform: scale(0.98); }
.buy-card .bnpl-line { font-size: 12.5px; color: var(--ink-dim); text-align: center; margin-top: 10px; }
.buy-card .bnpl-line b { color: var(--ink); }

/* ---- sticky price bar ---- */
.sticky-bar {
  position: sticky; top: 0; z-index: 30;
  display: flex; align-items: center; gap: 10px;
  margin: 0 10px; padding: 9px 12px;
  background: rgba(38, 39, 46, 0.92);
  border: 1px solid rgba(255, 255, 255, 0.12); border-radius: 15px;
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
  box-shadow: 0 10px 26px rgba(0, 0, 0, 0.35);
}
.sticky-bar[hidden] { display: none; }
.sticky-bar .sb-main { flex: 1 1 auto; min-width: 0; }
.sticky-bar b { display: block; font-size: 13.5px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sticky-bar span { font-size: 11.5px; color: var(--ink-dim); }
.sticky-bar .sb-price { font-size: 15.5px; font-weight: 800; white-space: nowrap; }
.sticky-bar .sb-buy {
  font: inherit; font-size: 13.5px; font-weight: 800; color: #fff;
  background: linear-gradient(180deg, var(--accent), var(--accent-strong));
  border: none; border-radius: 11px; padding: 9px 15px; cursor: pointer;
}

/* ---- undo toast ---- */
.undo-toast {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(14px + env(safe-area-inset-bottom)); z-index: 90;
  display: flex; align-items: center; gap: 14px;
  background: rgba(38, 39, 46, 0.96); border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 999px; padding: 10px 16px; font-size: 13.5px; color: var(--ink);
  box-shadow: 0 14px 34px rgba(0, 0, 0, 0.45);
}
.undo-toast[hidden] { display: none; }
.undo-toast button {
  font: inherit; font-weight: 800; color: var(--accent);
  background: none; border: none; cursor: pointer; padding: 0;
}

/* ---- dark re-skin of the pre-rebuild surfaces ---- */
.msg.bot .bubble { background: rgba(255, 255, 255, 0.06); border-color: rgba(255, 255, 255, 0.1); color: var(--ink); }
.msg.user .bubble { background: linear-gradient(180deg, var(--accent), var(--accent-strong)); }
.composer { background: rgba(29, 30, 35, 0.9); border-top-color: rgba(255, 255, 255, 0.07); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px); }
.composer input { background: rgba(255, 255, 255, 0.07); border-color: rgba(255, 255, 255, 0.12); color: var(--ink); }
.quick-replies button { background: rgba(255, 255, 255, 0.07); border-color: rgba(255, 255, 255, 0.13); color: var(--ink); }
.quick-replies button.reply-primary { background: linear-gradient(180deg, var(--accent), var(--accent-strong)); border-color: transparent; color: #fff; }
.product-bar { background: transparent; }
.legal { color: var(--ink-dim); }
.legal a { color: var(--ink-dim); }

/* ================= VISUAL PARITY (Oct 30, 2026) =================
 * Token-by-token port of the approved preview's stylesheet
 * (~/workspace/designeri-ux-preview/preview.html — glass pass).
 * Supersedes the UX-rebuild section above wherever they conflict.
 * Fixes, per Yeinel's two phone screenshots: two-row frosted chrome
 * (no header overflow in either sign-in state), home resting at the
 * top with only its designed sections, preview composer card on
 * home + slim edit bar in the studio, photo-card product strip,
 * un-collapsed home media rows, full-viewport column, and the
 * preview's ambient canvas + anchored-frost glass. Backgrounds are
 * STATIC — no animation on any fixed layer (perf law, Oct 21 2026).
 * Anchored frost: every glass surface carries a near-opaque dark
 * base under its sheen, so small text keeps >= ~4.5:1 contrast no
 * matter what scrolls behind it. */

:root {
  --paper: rgba(255, 255, 255, 0.055);
  --line: rgba(255, 255, 255, 0.12);
  --line-soft: rgba(255, 255, 255, 0.085);
  --faint: #92939a;
  --well: #fcfbf8;
  --peri: #7c86d8;
  --peri2: #98a1e4;
  --peri-deep: #9aa3e2;
  --peri-grad: linear-gradient(180deg, rgba(255, 255, 255, 0.22), rgba(255, 255, 255, 0) 46%, rgba(0, 0, 0, 0.05)),
    linear-gradient(135deg, rgba(102, 112, 196, 0.92), rgba(124, 134, 216, 0.82));
  --glass-edge: rgba(255, 255, 255, 0.09);
  --glass-hi: rgba(255, 255, 255, 0.16);
  --glass-shadow: 0 24px 48px rgba(5, 6, 10, 0.42);
  --anchored: linear-gradient(rgba(22, 23, 29, 0.80), rgba(22, 23, 29, 0.80)),
    linear-gradient(180deg, rgba(255, 255, 255, 0.085), rgba(255, 255, 255, 0.028));
}

html, body { background: #0e0f12; overflow-x: clip; }
body { font-weight: 450; line-height: 1.5; }

/* Ambient canvas (preview): static muted indigo glow top-right,
 * faint coral low-left, deep indigo settle at the bottom. Painted
 * on the fixed layer's own background; the blob spans are retired
 * so nothing on this layer can ever animate. */
.bg-blobs {
  background:
    radial-gradient(760px 420px at 85% -60px, rgba(124, 134, 216, 0.16), rgba(124, 134, 216, 0) 62%),
    radial-gradient(620px 380px at -120px 78%, rgba(240, 138, 118, 0.10), rgba(240, 138, 118, 0) 60%),
    radial-gradient(900px 620px at 50% 115%, rgba(70, 80, 160, 0.10), rgba(70, 80, 160, 0) 65%),
    #0e0f12;
}
.bg-blobs::after { display: none; }
.blob { display: none; }

/* Column: fluid full-viewport on phones (the preview's 430px was a
 * device frame, not a production layout); a cap only on big screens. */
.app {
  width: 100%; max-width: 100%;
  background: transparent; box-shadow: none;
  padding: 12px 16px 0; gap: 10px;
}
@media (min-width: 768px) { .app { max-width: 700px; } }

/* Glass, preview recipe: anchored base + sheen + blur + hairline. */
.glass {
  background: var(--anchored);
  border: 1px solid var(--glass-edge);
  box-shadow: inset 0 1px 0 var(--glass-hi), var(--glass-shadow);
  -webkit-backdrop-filter: blur(22px) saturate(1.4);
  backdrop-filter: blur(22px) saturate(1.4);
}

/* Hidden means hidden, even where a component sets display:flex. */
.studio-chrome[hidden], .price-unit[hidden], .buy-card[hidden],
.takes-row[hidden], .everything-block[hidden], .home-sections[hidden],
.home-headline[hidden] { display: none !important; }

/* ---- chrome: the preview's two-row frosted header ---- */
.header {
  flex-direction: column; align-items: stretch; gap: 10px;
  padding: 14px 16px 12px; border-radius: 26px;
}
.brand-row { display: flex; align-items: center; gap: 12px; min-width: 0; }
.header .logo { width: 48px; height: 48px; flex: 0 0 48px; border-radius: 16px; }
.header .logo img { width: 100%; height: 100%; object-fit: cover; border-radius: inherit; display: block; }
.header-text { flex: 1 1 auto; min-width: 0; }
.header h1 { font-size: 20px; font-weight: 750; letter-spacing: -0.03em; }
.header .subtitle {
  font-size: 12px; color: var(--ink-dim); margin-top: 1px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.header .subtitle a { font-size: 12px; }
.ctrl-row { display: flex; flex-wrap: wrap; justify-content: flex-end; align-items: center; gap: 8px; }
.ctrl-row > * { flex: 0 0 auto; min-width: 0; }
.header .lang-toggle, .header .credits-chip, .header .auth-btn {
  min-height: 40px; padding: 7px 12px; border-radius: 999px;
  font-size: 12.5px; font-weight: 700; white-space: nowrap;
}
.lang-toggle {
  display: inline-flex; align-items: center; gap: 6px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.09), rgba(255, 255, 255, 0.04));
  border: 1px solid var(--line-soft); color: var(--ink);
}
.lang-toggle span { opacity: 0.48; font-weight: 750; }
.lang-toggle span.on { opacity: 1; color: #c9cff7; background: none; }
.lang-toggle .lang-sep { opacity: 0.35; }
.header .auth-btn {
  margin-left: 0; max-width: none;
  background: rgba(124, 134, 216, 0.15);
  border: 1px solid rgba(170, 178, 240, 0.36); color: #aab2ea;
}
.header .auth-btn:hover { background: rgba(124, 134, 216, 0.22); box-shadow: none; }
.header #headerStartOver, .header #creationsBtn {
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0.03));
  border: 1px solid var(--line-soft); color: var(--ink);
}
.header .credits-chip {
  background: rgba(124, 134, 216, 0.15);
  border: 1px solid rgba(170, 178, 240, 0.30); color: #c9cff7;
  font-variant-numeric: tabular-nums;
}

/* ---- stage: children never compress (flex-column shrink fix) ---- */
.stage-scroll > * { flex: 0 0 auto; }
.chat.chat-welcome-hidden { display: none; }
.home-sections { padding: 6px 2px 30px; width: 100%; }
.home-sect { margin-top: 30px; }
.home-sect:first-child { margin-top: 20px; }
.popular-wrap { padding: 0; margin-top: 30px; }
.sect-title, .sect-label {
  font-size: 11px; font-weight: 650; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--peri-deep); margin: 0 2px 14px;
}

/* ---- headline + starter chips ---- */
.home-headline { padding: 24px 2px 2px; }
.home-headline h2 {
  font-size: 32px; font-weight: 750; letter-spacing: -0.03em;
  line-height: 1.14; margin: 0 0 12px;
}
.home-headline p { font-size: 15px; line-height: 1.6; color: var(--ink-dim); margin: 0; }
.starter-chips { gap: 8px; margin-top: 20px; }
.starter-chip {
  padding: 11px 17px; font-size: 14px; font-weight: 600;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0.03));
  border: 1px solid var(--line-soft); color: var(--ink);
}
.starter-chip[data-chip="memorial"] { background: rgba(216, 188, 148, 0.10); color: #dec69e; border-color: rgba(216, 188, 148, 0.26); }
.starter-chip[data-chip="funny"] { background: rgba(240, 138, 118, 0.10); color: #f2ac97; border-color: rgba(240, 138, 118, 0.26); }
.starter-chip[data-chip="pet"] { background: rgba(124, 134, 216, 0.13); color: #acb4e9; border-color: rgba(124, 134, 216, 0.30); }
.starter-chip[data-chip="kid"] { background: rgba(150, 196, 158, 0.10); color: #abcdaf; border-color: rgba(150, 196, 158, 0.26); }

/* ---- Fresh ideas: preview photo cards ---- */
.fresh-feed { display: flex; flex-direction: column; gap: 16px; }
.fresh-card {
  flex-direction: column; align-items: stretch; gap: 0;
  padding: 12px; margin-bottom: 0; border-radius: 24px; width: 100%;
}
.fresh-img {
  width: 100%; height: 224px; flex: none;
  background: var(--well); border-radius: 18px; padding: 8px; box-sizing: border-box;
}
.fresh-img img { width: 100%; height: 100%; object-fit: contain; border-radius: 12px; display: block; }
.fresh-meta { padding: 14px 6px 4px; gap: 3px; }
.fresh-meta b { font-size: 17px; font-weight: 700; }
.fresh-meta span { font-size: 13.5px; line-height: 1.5; }
.fresh-meta .fresh-go { color: var(--peri-deep); font-size: 13px; font-weight: 650; margin-top: 10px; }
.heart-btn {
  width: 44px; height: 44px; top: 16px; right: 16px; font-size: 19px;
  background: linear-gradient(rgba(20, 21, 27, 0.72), rgba(20, 21, 27, 0.72)), rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.14); color: var(--ink-dim);
  -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
}
.heart-btn.loved { color: var(--rose); border-color: rgba(240, 138, 118, 0.5); }

/* ---- Your designs ---- */
.your-teaser { border-radius: 20px; padding: 16px; font-size: 14px; }
.your-teaser b {
  color: #aab2ea; background: rgba(124, 134, 216, 0.15);
  border: 1px solid rgba(170, 178, 240, 0.32); border-radius: 999px;
  padding: 8px 14px; font-size: 13px; white-space: nowrap;
}
.your-row { gap: 12px; padding-bottom: 4px; }
.your-card {
  flex: 0 0 128px; width: 128px; border-radius: 20px; padding: 8px; gap: 0;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0.03));
  border: 1px solid var(--glass-edge);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.10);
}
.your-card img { height: 104px; object-fit: contain; background: var(--well); border-radius: 12px; }
.your-card b { font-size: 13.5px; font-weight: 650; padding: 10px 4px 0; }
.your-card span { font-size: 12.5px; padding: 2px 4px 6px; }

/* ---- Popular products: preview .pcard strip ---- */
.product-bar { gap: 12px; padding: 2px 2px 8px; background: transparent; }
.product-bar button {
  flex-direction: column; align-items: stretch; text-align: left;
  width: 128px; min-height: 0; padding: 0 0 12px; border-radius: 20px; overflow: hidden;
  background: var(--anchored); border: 1px solid var(--glass-edge);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12);
  -webkit-backdrop-filter: blur(18px) saturate(1.4);
  backdrop-filter: blur(18px) saturate(1.4);
}
.product-bar button:hover { background: var(--anchored); border-color: rgba(255, 255, 255, 0.22); }
.product-bar button.current {
  border-color: rgba(190, 198, 255, 0.82);
  box-shadow: 0 0 0 4px rgba(124, 134, 216, 0.22);
  background: var(--anchored);
}
.pcard-well { display: block; height: 104px; background: var(--well); padding: 8px; box-sizing: border-box; }
.pcard-well img { width: 100%; height: 100%; object-fit: contain; border-radius: 12px; display: block; }
.pcard-name {
  display: block; padding: 12px 12px 0; font-size: 13.5px; font-weight: 650;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.pcard-price {
  display: block; padding: 4px 12px 0; font-size: 13px; font-weight: 650;
  color: var(--peri-deep); font-variant-numeric: tabular-nums;
}

/* ---- How it works ---- */
.how-list { display: flex; flex-direction: column; gap: 8px; }
.how-step {
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.06), rgba(255, 255, 255, 0.03));
  border: 1px solid var(--glass-edge); border-radius: 20px;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.10);
  padding: 16px; gap: 16px;
}
.how-num {
  width: 32px; height: 32px; flex: 0 0 32px;
  background: rgba(124, 134, 216, 0.15); color: #c9cff7;
  font-size: 14px; font-weight: 700;
}
.how-step b { font-size: 15px; font-weight: 700; }
.how-step p { font-size: 13.5px; line-height: 1.5; }

/* ---- composer: preview card at home, slim edit bar in studio ---- */
.composer {
  border-radius: 24px; margin-bottom: 8px;
  background: linear-gradient(rgba(22, 23, 29, 0.88), rgba(22, 23, 29, 0.88)),
    linear-gradient(180deg, rgba(255, 255, 255, 0.09), rgba(255, 255, 255, 0.03));
  border: 1px solid var(--glass-edge);
  box-shadow: inset 0 1px 0 var(--glass-hi), 0 18px 40px rgba(5, 6, 10, 0.38);
  -webkit-backdrop-filter: blur(24px) saturate(1.5);
  backdrop-filter: blur(24px) saturate(1.5);
}
.composer:focus-within {
  border-color: rgba(124, 134, 216, 0.5);
  box-shadow: inset 0 1px 0 var(--glass-hi), 0 0 0 4px rgba(124, 134, 216, 0.16), 0 18px 40px rgba(5, 6, 10, 0.38);
}
.composer button {
  background: var(--peri-grad); color: #fff;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.28), inset 0 -1px 0 rgba(20, 22, 40, 0.18), 0 10px 24px rgba(38, 44, 92, 0.35);
}
.composer button:hover { transform: none; filter: brightness(1.05); }
.composer button:disabled {
  background: rgba(255, 255, 255, 0.10); color: var(--faint);
  box-shadow: none; opacity: 1; filter: none; transform: none;
}
.up-label, .send-label { display: none; }
.home-headline .composer { margin-top: 20px; margin-bottom: 0; }
/* home stage (and first paint): the glass idea card */
body:not([data-stage="studio"]) .composer { flex-wrap: wrap; padding: 16px; gap: 12px; }
body:not([data-stage="studio"]) .composer input {
  order: 1; flex: 1 1 100%; min-height: 58px; border-radius: 16px;
  background: linear-gradient(rgba(26, 27, 34, 0.92), rgba(26, 27, 34, 0.92)), rgba(255, 255, 255, 0.04);
  border: 1px solid var(--line-soft); padding: 15px 16px; font-size: 16px;
}
body:not([data-stage="studio"]) .composer input:focus { background: linear-gradient(rgba(26, 27, 34, 0.96), rgba(26, 27, 34, 0.96)), rgba(255, 255, 255, 0.04); }
body:not([data-stage="studio"]) #uploadBtn {
  order: 2; flex: 1 1 100%; width: 100%; height: 50px; border-radius: 999px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.055), rgba(255, 255, 255, 0.025));
  border: 1px solid var(--line-soft); box-shadow: none; color: var(--rose);
  display: flex; align-items: center; justify-content: center; gap: 9px;
  font-size: 14.5px; font-weight: 600;
}
body:not([data-stage="studio"]) #uploadBtn .up-label { display: inline; color: var(--ink-dim); }
body:not([data-stage="studio"]) .composer button[type="submit"] {
  order: 3; flex: 1 1 100%; width: 100%; height: 56px; border-radius: 999px;
  font-size: 16px; font-weight: 700; gap: 8px;
}
body:not([data-stage="studio"]) .composer button[type="submit"] svg { display: none; }
body:not([data-stage="studio"]) .composer button[type="submit"] .send-label { display: inline; }
/* studio stage: the slim capsule edit bar */
body[data-stage="studio"] .composer { flex-wrap: nowrap; border-radius: 999px; padding: 8px; gap: 8px; align-items: center; }
body[data-stage="studio"] .composer input {
  background: transparent; border-color: transparent;
  min-height: 44px; padding: 10px 14px; font-size: 15px; border-radius: 999px;
}
body[data-stage="studio"] .composer input:focus { background: transparent; }
body[data-stage="studio"] #uploadBtn {
  width: 40px; height: 40px; flex: 0 0 40px; border-radius: 50%;
  background: rgba(255, 255, 255, 0.06); border: 1px solid var(--line-soft);
  box-shadow: none; color: var(--ink-dim);
}
body[data-stage="studio"] .composer button[type="submit"] {
  width: 40px; height: 40px; flex: 0 0 40px; border-radius: 50%;
}

/* ---- studio surfaces ---- */
.msg.bot {
  background: linear-gradient(rgba(24, 25, 31, 0.85), rgba(24, 25, 31, 0.85)),
    linear-gradient(180deg, rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0.03));
}
.msg.user {
  background: var(--peri-grad);
  border-color: rgba(196, 203, 255, 0.30);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 8px 22px rgba(38, 44, 92, 0.30);
}
.msg img.mockup { background: var(--well); border-radius: 20px; }
.quick-replies button.reply-primary {
  background: var(--peri-grad); border-color: rgba(196, 203, 255, 0.34); color: #fff;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.28), 0 10px 24px rgba(38, 44, 92, 0.35);
}
.quick-replies button.reply-primary:hover { background: var(--peri-grad); filter: brightness(1.06); }
.quick-replies button.big-reply {
  background: rgba(124, 134, 216, 0.16); border-color: rgba(170, 178, 240, 0.38);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.14);
}
.quick-replies button.big-reply:hover { background: rgba(124, 134, 216, 0.24); }
.quick-replies button.qr-swatch.current {
  border-color: #ffffff;
  box-shadow: 0 0 0 2px #1b1c21, 0 0 0 5px rgba(124, 134, 216, 0.75);
}
.studio-chrome { padding: 6px 2px 14px; gap: 14px; }
.price-unit {
  flex-direction: column; align-items: stretch; gap: 10px;
  border-radius: 24px; padding: 18px 16px;
}
.price-unit .price-main { display: flex; flex-direction: column; align-items: center; gap: 8px; }
.price-unit .price-txt { text-align: center; min-width: 0; }
.price-unit .price-txt b { display: block; font-size: 16px; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.price-unit .price-txt span { display: block; font-size: 13px; color: var(--ink-dim); margin-top: 2px; }
.price-unit .price-value {
  font-size: 24px; font-weight: 750; font-variant-numeric: tabular-nums;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.09), rgba(255, 255, 255, 0.04));
  border: 1px solid var(--line-soft); border-radius: 999px; padding: 7px 15px;
}
.price-unit .bnpl-line { text-align: center; font-size: 13.5px; color: var(--ink-dim); margin: 2px 0 0; }
.price-unit .bnpl-line b { display: inline; font-size: 13.5px; color: var(--peri-deep); }
.takes-thumbs { gap: 10px; }
.take-thumb {
  flex: 0 0 64px; width: 64px; height: 64px; border-radius: 16px;
  background: var(--well); border: 1px solid var(--glass-edge); padding: 4px;
}
.take-thumb img { object-fit: contain; border-radius: 11px; }
.take-thumb.current { border-color: rgba(124, 134, 216, 0.75); box-shadow: 0 0 0 4px rgba(124, 134, 216, 0.22); }
.everything-block { margin-top: 12px; }
.everything-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-top: 12px; }
.everything-block .ghost-btn {
  width: 100%; min-height: 50px; border-radius: 999px; cursor: pointer;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.04));
  border: 1px solid var(--line-soft); color: var(--ink);
  font: inherit; font-size: 14.5px; font-weight: 650;
}
.eg-cell { border-radius: 20px; padding: 8px; gap: 0; }
.eg-cell img { height: auto; aspect-ratio: 4 / 3; object-fit: contain; background: var(--well); border-radius: 12px; }
.eg-cell .eg-name { font-size: 13.5px; font-weight: 650; padding: 10px 4px 0; }
.eg-cell .eg-price { font-size: 13px; font-weight: 650; color: var(--peri-deep); padding: 2px 4px 4px; }

/* ---- sticky price bar: preview pill ---- */
.sticky-bar {
  border-radius: 999px; padding: 8px 8px 8px 20px; margin: 2px 2px 0;
  background: linear-gradient(rgba(20, 21, 27, 0.86), rgba(20, 21, 27, 0.86)),
    linear-gradient(180deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.03));
  border: 1px solid var(--glass-edge);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12), 0 14px 30px rgba(5, 6, 10, 0.40);
  -webkit-backdrop-filter: blur(24px) saturate(1.5);
  backdrop-filter: blur(24px) saturate(1.5);
}
.sticky-txt { flex: 1 1 auto; min-width: 0; }
.sticky-txt b { display: block; font-size: 13.5px; font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sticky-txt span { display: block; font-size: 12px; color: var(--ink-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sticky-price { font-size: 15px; font-weight: 750; font-variant-numeric: tabular-nums; white-space: nowrap; }
.sticky-buy {
  font: inherit; font-size: 14px; font-weight: 700; color: #fff; cursor: pointer;
  background: var(--peri-grad); border: 1px solid rgba(196, 203, 255, 0.30);
  border-radius: 999px; min-height: 44px; padding: 10px 18px; white-space: nowrap;
}

/* ---- buy card ---- */
.buy-card { border-radius: 24px; padding: 20px; }
.buy-head { display: flex; gap: 16px; align-items: center; margin-bottom: 6px; }
.buy-img {
  width: 96px; height: 96px; flex: 0 0 96px; border-radius: 20px;
  background: linear-gradient(180deg, #ffffff, var(--well));
  padding: 8px; box-sizing: border-box;
}
.buy-img img { width: 100%; height: 100%; object-fit: contain; border-radius: 12px; display: block; background: transparent; }
.buy-txt { min-width: 0; }
.buy-txt b { display: block; font-size: 19px; font-weight: 750; letter-spacing: -0.02em; }
.buy-txt span { display: block; font-size: 13.5px; color: var(--ink-dim); margin-top: 3px; }
.receipt { margin-top: 14px; }
.receipt .trow {
  display: flex; justify-content: space-between; align-items: center;
  min-height: 48px; padding: 12px 0;
  border-bottom: 1px solid var(--line-soft); font-size: 14.5px;
}
.receipt .trow span { color: var(--ink-dim); }
.receipt .trow b { font-weight: 600; font-variant-numeric: tabular-nums; }
.receipt .trow.total { border-bottom: none; }
.receipt .trow.total span { color: var(--ink); font-weight: 650; }
.receipt .trow.total b { font-size: 24px; font-weight: 750; color: var(--ink); }
.shipmeter { margin-top: 16px; }
.ship-track { height: 6px; background: rgba(255, 255, 255, 0.08); box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.35); }
.ship-fill { background: linear-gradient(90deg, #6670c4, #7c86d8); }
.ship-text { font-size: 13px; margin-top: 8px; font-variant-numeric: tabular-nums; }
.buy-card .bnpl-line {
  background: rgba(124, 134, 216, 0.13); border: 1px solid rgba(170, 178, 240, 0.26);
  border-radius: 999px; padding: 12px 16px; font-size: 13.5px;
  text-align: center; margin-top: 18px; color: var(--ink-dim);
}
.buy-card .bnpl-line b { color: var(--peri-deep); }
.buy-now-btn {
  width: 100%; margin-top: 16px; min-height: 56px; border-radius: 999px;
  border: 1px solid rgba(196, 203, 255, 0.34); cursor: pointer;
  background: var(--peri-grad); color: #fff;
  font: inherit; font-size: 16px; font-weight: 700;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.28), inset 0 -1px 0 rgba(20, 22, 40, 0.18), 0 14px 30px rgba(38, 44, 92, 0.38);
  transition: transform 0.15s ease, filter 0.2s ease;
}
.buy-now-btn:active { transform: scale(0.985); }

/* ---- undo toast: preview's top-center toast ---- */
.undo-toast {
  top: calc(10px + env(safe-area-inset-top)); bottom: auto;
  border-radius: 20px; padding: 13px 20px; font-size: 13.5px;
  max-width: calc(100vw - 32px);
  background: linear-gradient(rgba(20, 21, 27, 0.88), rgba(20, 21, 27, 0.88)),
    linear-gradient(180deg, rgba(255, 255, 255, 0.09), rgba(255, 255, 255, 0.03));
  border: 1px solid var(--glass-edge);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.14), 0 18px 40px rgba(5, 6, 10, 0.45);
  -webkit-backdrop-filter: blur(28px) saturate(1.5);
  backdrop-filter: blur(28px) saturate(1.5);
}
.undo-toast .undo-btn { color: #aab2ea; font-weight: 750; }

/* ---- neon purge on the remaining app surfaces ----
 * Legacy rules above still reference the old electric blue; every
 * app surface that can show it gets the muted periwinkle here.
 * (The separate shop pages keep their own skin — out of scope.) */
.auth-btn:hover { box-shadow: 0 0 0 4px rgba(124, 134, 216, 0.14); }
.auth-card input:focus { border-color: rgba(124, 134, 216, 0.6); box-shadow: 0 0 0 4px rgba(124, 134, 216, 0.16); }
.auth-submit {
  background: var(--peri-grad);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 10px 24px rgba(38, 44, 92, 0.32);
}
.auth-toggle { color: #aab2ea; }
.creation-link { color: var(--peri-deep); }
::selection { background: rgba(124, 134, 216, 0.35); }
.composer input::placeholder { color: var(--faint); }
.legal-line { color: var(--faint); }
.legal-line a { color: var(--faint); }

/* ================= EXACT MATCH (Oct 30, 2026) =================
 * Yeinel's bar: "exactly like the preview." This section closes
 * the parity pass's three admitted residuals and every remaining
 * token delta found by re-diffing preview.html (glass pass)
 * against the live DOM screen by screen. It supersedes the
 * VISUAL PARITY section wherever they conflict. Values are copied
 * from the preview's stylesheet, never approximated. Static
 * backgrounds only — the perf law stands. */

/* ---- tokens the parity pass never re-pointed ---- */
:root {
  --ink: #ececea;
  --ink-dim: #a7a8ad;
  --ink-faint: #92939a;
  --peri-grad: linear-gradient(180deg, rgba(255, 255, 255, 0.22), rgba(255, 255, 255, 0.045) 46%, rgba(0, 0, 0, 0.05) 100%),
    linear-gradient(135deg, rgba(102, 112, 196, 0.92), rgba(124, 134, 216, 0.82));
}

/* ---- canvas: the preview's five static pools over #1B1C21 ---- */
.bg-blobs {
  background:
    radial-gradient(760px 420px at 88% -80px, rgba(124, 134, 216, 0.16), rgba(124, 134, 216, 0) 62%),
    radial-gradient(540px 380px at -12% 16%, rgba(124, 134, 216, 0.07), rgba(124, 134, 216, 0) 66%),
    radial-gradient(700px 560px at 8% 108%, rgba(240, 138, 118, 0.10), rgba(240, 138, 118, 0) 64%),
    radial-gradient(480px 320px at 82% 58%, rgba(240, 138, 118, 0.045), rgba(240, 138, 118, 0) 66%),
    radial-gradient(480px 340px at 50% 42%, rgba(124, 134, 216, 0.05), rgba(124, 134, 216, 0) 68%),
    #1b1c21;
}

/* ---- column inset: the preview's 24px ---- */
.app { padding: 12px 24px 0; }

/* ---- header: logo tile, solid brand, preview control metrics ---- */
.header { padding: 16px; gap: 12px; }
.header .logo {
  background: var(--peri-grad);
  border: 1px solid rgba(196, 203, 255, 0.30);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.30), inset 0 -10px 18px rgba(38, 44, 96, 0.18), 0 10px 22px rgba(5, 6, 10, 0.42);
  color: #f4f4f0; font-size: 19px; font-weight: 750; letter-spacing: -0.03em;
  -webkit-backdrop-filter: none; backdrop-filter: none;
}
.header .logo:hover { transform: none; }
.header h1 {
  font-size: 20px; font-weight: 750; letter-spacing: -0.03em; line-height: 1.15;
  background: none; -webkit-background-clip: initial; background-clip: initial;
  -webkit-text-fill-color: currentColor; color: var(--ink);
}
.header .subtitle { line-height: 1.35; margin-top: 2px; }
.header .lang-toggle {
  min-height: 44px; padding: 9px 12px; font-size: 12px; font-weight: 750; letter-spacing: 0.06em;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.075), rgba(255, 255, 255, 0.04));
  border: 1px solid rgba(255, 255, 255, 0.11); color: var(--ink-dim);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12), 0 8px 18px rgba(5, 6, 10, 0.18);
}
.lang-toggle .lang-sep { opacity: 0.28; }
.header #headerStartOver {
  min-height: 44px; padding: 10px 15px; font-size: 13px; font-weight: 600;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.075), rgba(255, 255, 255, 0.04));
  border: 1px solid rgba(255, 255, 255, 0.10); color: var(--ink);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12), 0 8px 18px rgba(5, 6, 10, 0.22);
}
.header #headerStartOver .so-ico { color: var(--peri2); font-weight: 700; }
.header #creationsBtn {
  min-height: 44px; padding: 10px 15px; font-size: 13px; font-weight: 600;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.075), rgba(255, 255, 255, 0.04));
  border: 1px solid rgba(255, 255, 255, 0.10); color: var(--ink);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12), 0 8px 18px rgba(5, 6, 10, 0.22);
}
.header .auth-btn {
  min-height: 44px; padding: 9px 13px; font-size: 13px; font-weight: 700;
  background: linear-gradient(180deg, rgba(154, 163, 226, 0.20), rgba(124, 134, 216, 0.12));
  border: 1px solid rgba(170, 178, 240, 0.36); color: #aab2ea;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.16), 0 8px 18px rgba(5, 6, 10, 0.20);
}
.header .credits-chip {
  min-height: 0; padding: 6px 10px; font-size: 12px; font-weight: 700;
  background: linear-gradient(180deg, rgba(154, 163, 226, 0.16), rgba(124, 134, 216, 0.11));
  border: 1px solid rgba(170, 178, 240, 0.32); color: #aab2ea;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.13);
}

/* ---- headline + chips: preview rhythm ---- */
.home-headline { padding: 6px 2px 2px; }
.home-headline h2 { line-height: 1.18; margin: 32px 0 16px; }
.home-headline .composer { margin-top: 24px; }
.starter-chips { margin-top: 24px; }
.starter-chip {
  border-color: rgba(255, 255, 255, 0.10);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.10), 0 8px 18px rgba(5, 6, 10, 0.18);
}
.starter-chip[data-chip="memorial"] { background-color: rgba(216, 188, 148, 0.11); background-image: linear-gradient(180deg, rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0)); border-color: rgba(255, 255, 255, 0.10); }
.starter-chip[data-chip="funny"] { background-color: rgba(240, 138, 118, 0.11); background-image: linear-gradient(180deg, rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0)); border-color: rgba(255, 255, 255, 0.10); }
.starter-chip[data-chip="pet"] { background-color: rgba(124, 134, 216, 0.14); background-image: linear-gradient(180deg, rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0)); border-color: rgba(255, 255, 255, 0.10); }
.starter-chip[data-chip="kid"] { background-color: rgba(150, 196, 158, 0.11); background-image: linear-gradient(180deg, rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0)); border-color: rgba(255, 255, 255, 0.10); }
.starter-chip.sel {
  border-color: rgba(240, 138, 118, 0.6); color: #f5ac99;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.14), 0 0 0 2px rgba(240, 138, 118, 0.16), 0 8px 18px rgba(5, 6, 10, 0.18);
}

/* ---- section labels: preview spacing ---- */
.home-sect { margin-top: 32px; }
.home-sect:first-child { margin-top: 32px; }
.popular-wrap { margin-top: 32px; }
.sect-title, .sect-label { margin: 0 2px 16px; }

/* ---- RESIDUAL 1: the composer is the preview's idea card ----
 * One form, two faces. Home: the form itself goes transparent and
 * .idea-card carries the glass; Create sits in its wrap under the
 * chips (the chips ride inside the form on home — see
 * syncStudioChrome) and the free note closes the stack. Studio:
 * the wrappers dissolve (display:contents) and the same nodes —
 * upload circle, one-line textarea, send circle — form the edit
 * bar. The upload button and the field are the SAME elements in
 * both stages; nothing is ever duplicated or rebound. */
body:not([data-stage="studio"]) .composer {
  display: block; padding: 0; margin-bottom: 0;
  background: none; border: none; border-radius: 0; box-shadow: none;
  -webkit-backdrop-filter: none; backdrop-filter: none;
}
body:not([data-stage="studio"]) .composer:focus-within { border-color: transparent; box-shadow: none; }
.idea-card {
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.06), rgba(255, 255, 255, 0.028) 52%, rgba(255, 255, 255, 0.02)),
    linear-gradient(rgba(22, 23, 29, 0.82), rgba(22, 23, 29, 0.82));
  border: 1px solid var(--glass-edge); border-radius: 24px; padding: 24px;
  -webkit-backdrop-filter: blur(22px) saturate(1.4); backdrop-filter: blur(22px) saturate(1.4);
  box-shadow: inset 0 1px 0 var(--glass-hi), inset 1px 0 0 rgba(255, 255, 255, 0.04), var(--glass-shadow);
}
body:not([data-stage="studio"]) .composer textarea {
  display: block; width: 100%; min-height: 92px; resize: vertical;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.045), rgba(255, 255, 255, 0.03)),
    linear-gradient(rgba(19, 20, 26, 0.72), rgba(19, 20, 26, 0.72));
  border: 1px solid rgba(255, 255, 255, 0.09); border-radius: 16px; padding: 16px;
  color: var(--ink); font-size: 16px; font-weight: 450; font-family: inherit; line-height: 1.5;
  outline: none; box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.07), inset 0 10px 24px rgba(5, 6, 10, 0.10);
  transition: border-color 0.25s cubic-bezier(0.22, 0.61, 0.36, 1), box-shadow 0.25s cubic-bezier(0.22, 0.61, 0.36, 1);
}
body:not([data-stage="studio"]) .composer textarea:focus {
  border-color: rgba(124, 134, 216, 0.55);
  box-shadow: 0 0 0 4px rgba(124, 134, 216, 0.16), inset 0 1px 0 rgba(255, 255, 255, 0.07);
}
body:not([data-stage="studio"]) .composer textarea::placeholder { color: var(--faint); font-size: 16px; font-weight: 450; }
body:not([data-stage="studio"]) #uploadBtn {
  width: 100%; height: auto; min-height: 56px; margin-top: 16px; padding: 16px 20px;
  display: flex; align-items: center; justify-content: center; gap: 8px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.055), rgba(255, 255, 255, 0.028));
  border: 1px solid rgba(255, 255, 255, 0.09); border-radius: 999px;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.09);
  color: var(--ink-dim); font-size: 16px; font-weight: 600;
}
body:not([data-stage="studio"]) #uploadBtn .up-ico { color: var(--rose); font-weight: 700; }
body:not([data-stage="studio"]) #uploadBtn .up-label { display: inline; }
body:not([data-stage="studio"]) #uploadBtn:active { transform: scale(0.97); }
.create-wrap { margin-top: 24px; }
body:not([data-stage="studio"]) .create-btn {
  width: 100%; height: auto; min-height: 56px; padding: 16px 20px; border-radius: 999px;
  display: flex; align-items: center; justify-content: center; gap: 8px;
  background: var(--peri-grad); border: 1px solid rgba(196, 203, 255, 0.34); color: #f4f4f0;
  font-size: 16px; font-weight: 650;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.30), inset 0 -12px 22px rgba(35, 40, 88, 0.20), 0 16px 32px rgba(5, 6, 10, 0.46), 0 6px 18px rgba(102, 112, 196, 0.16);
}
body:not([data-stage="studio"]) .create-btn .send-ico { display: none; }
body:not([data-stage="studio"]) .create-btn .send-label { display: inline; }
body:not([data-stage="studio"]) .create-btn:active { filter: brightness(1.1); transform: scale(0.97); }
.free-note { text-align: center; color: var(--ink-dim); font-size: 14px; font-weight: 500; margin: 16px 0 0; }

/* studio: the same form as the slim edit bar */
body[data-stage="studio"] .idea-card, body[data-stage="studio"] .create-wrap { display: contents; }
body[data-stage="studio"] .free-note { display: none; }
body[data-stage="studio"] .composer {
  display: flex; flex-wrap: nowrap; align-items: center; gap: 8px;
  border-radius: 999px; padding: 8px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0.03)),
    linear-gradient(rgba(20, 21, 27, 0.80), rgba(20, 21, 27, 0.80));
  border: 1px solid rgba(255, 255, 255, 0.10);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 18px 36px rgba(5, 6, 10, 0.42);
  -webkit-backdrop-filter: blur(26px) saturate(1.5); backdrop-filter: blur(26px) saturate(1.5);
}
body[data-stage="studio"] .composer:focus-within {
  border-color: rgba(255, 255, 255, 0.10);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 18px 36px rgba(5, 6, 10, 0.42);
}
body[data-stage="studio"] .composer textarea {
  flex: 1; min-width: 0; width: auto; min-height: 0; height: auto; resize: none; overflow: hidden;
  background: transparent; border: none; border-radius: 0; padding: 8px 0 8px 6px;
  color: var(--ink); font-size: 15px; font-weight: 450; font-family: inherit; line-height: 1.45;
  outline: none; box-shadow: none;
}
body[data-stage="studio"] .composer textarea::placeholder { color: var(--faint); }
body[data-stage="studio"] #uploadBtn {
  order: -1; flex: 0 0 40px; width: 40px; height: 40px; min-height: 0; margin: 0; padding: 0;
  border-radius: 50%; display: flex; align-items: center; justify-content: center;
  background: rgba(255, 255, 255, 0.06); border: 1px solid var(--line-soft); box-shadow: none;
  color: var(--ink-dim); font-size: 17px;
}
body[data-stage="studio"] #uploadBtn .up-label { display: none; }
body[data-stage="studio"] .create-btn {
  flex: 0 0 40px; width: 40px; height: 40px; min-height: 0; padding: 0; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--peri-grad); border: 1px solid rgba(196, 203, 255, 0.28); color: #f4f4f0;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.26), 0 8px 18px rgba(5, 6, 10, 0.32);
}
body[data-stage="studio"] .create-btn .send-label { display: none; }
body[data-stage="studio"] .create-btn .send-ico { display: block; }
body[data-stage="studio"] .create-btn:disabled {
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0.035));
  border-color: rgba(255, 255, 255, 0.07);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.07); color: var(--faint);
}

/* F4: the pinned file input — visually hidden, never display:none */
.visually-hidden {
  position: absolute !important; width: 1px; height: 1px; margin: -1px; padding: 0;
  border: 0; opacity: 0; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
  white-space: nowrap;
}

/* ---- Fresh ideas: the preview's flush photo cards ---- */
.fresh-card {
  padding: 0; overflow: hidden;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0.04));
  border: 1px solid var(--glass-edge);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.13), 0 14px 28px rgba(5, 6, 10, 0.26);
  -webkit-backdrop-filter: blur(18px) saturate(1.35); backdrop-filter: blur(18px) saturate(1.35);
}
.fresh-img {
  height: auto; padding: 8px; border-radius: 0;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.28);
}
.fresh-img img { height: 208px; border-radius: 16px; }
.fresh-meta { padding: 16px; gap: 0; }
.fresh-meta b { letter-spacing: -0.02em; line-height: 1.3; }
.fresh-meta span { line-height: 1.45; margin-top: 4px; }
.fresh-meta .fresh-go { margin-top: 12px; }
.heart-btn {
  background: linear-gradient(180deg, rgba(38, 39, 46, 0.82), rgba(28, 29, 36, 0.78));
  border: 1px solid rgba(255, 255, 255, 0.16); color: #f4f4f0;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.16), 0 10px 20px rgba(5, 6, 10, 0.32);
  -webkit-backdrop-filter: blur(14px) saturate(1.4); backdrop-filter: blur(14px) saturate(1.4);
}
.heart-btn.loved, .heart-btn.saved {
  color: var(--rose); border-color: rgba(240, 138, 118, 0.55);
  background: linear-gradient(180deg, rgba(240, 138, 118, 0.24), rgba(240, 138, 118, 0.14));
}

/* ---- Your designs: teaser pill + pcard-shaped row cards ---- */
.your-teaser {
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.055), rgba(255, 255, 255, 0.03));
  border: 1px solid var(--glass-edge);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.10);
}
.your-teaser span { font-weight: 550; line-height: 1.45; }
.your-teaser b {
  background: linear-gradient(180deg, rgba(154, 163, 226, 0.20), rgba(124, 134, 216, 0.12));
  border: 1px solid rgba(170, 178, 240, 0.36); color: #aab2ea;
  padding: 9px 13px; font-size: 13px; font-weight: 700;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.16), 0 8px 18px rgba(5, 6, 10, 0.20);
}
.your-card {
  padding: 0; overflow: hidden;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0.04));
  border: 1px solid var(--glass-edge);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.13), 0 14px 28px rgba(5, 6, 10, 0.26);
  -webkit-backdrop-filter: blur(18px) saturate(1.35); backdrop-filter: blur(18px) saturate(1.35);
}
.your-card img {
  width: 100%; height: 104px; padding: 8px; box-sizing: border-box;
  background: var(--well); border-radius: 0; object-fit: contain;
}
.your-card b { padding: 12px 12px 0; line-height: 1.3; }
.your-card span { font-size: 13px; font-weight: 550; color: var(--ink-dim); padding: 4px 12px 12px; line-height: 1.3; }

/* ---- Popular products: preview .pcard glass + selection ring ---- */
.product-bar {
  scroll-snap-type: x mandatory;
  -webkit-mask-image: linear-gradient(90deg, #111 90%, transparent);
  mask-image: linear-gradient(90deg, #111 90%, transparent);
}
.product-bar button {
  scroll-snap-align: start;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0.04));
  border: 1px solid var(--glass-edge);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.13), 0 14px 28px rgba(5, 6, 10, 0.26);
  -webkit-backdrop-filter: blur(18px) saturate(1.35); backdrop-filter: blur(18px) saturate(1.35);
}
.product-bar button.current {
  border-color: rgba(190, 198, 255, 0.82);
  box-shadow: 0 0 0 2px rgba(154, 163, 226, 0.24), inset 0 1px 0 rgba(255, 255, 255, 0.16), 0 14px 28px rgba(5, 6, 10, 0.26);
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0.04));
}
.pcard-well { box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.28), inset 0 -12px 22px rgba(93, 84, 70, 0.05); }
/* F2: in the studio the bar lives outside the home sections — it
 * keeps a little air of its own there. */
body[data-stage="studio"] .product-bar { margin: 12px 2px 4px; }

/* ---- How it works: preview step numbers ---- */
.how-step {
  align-items: flex-start;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.055), rgba(255, 255, 255, 0.03));
}
.how-num {
  background: linear-gradient(180deg, rgba(154, 163, 226, 0.20), rgba(124, 134, 216, 0.12));
  border: 1px solid rgba(170, 178, 240, 0.32); color: #c9cff7;
  font-variant-numeric: tabular-nums;
}
.how-step b { line-height: 1.35; }
.how-step p { margin-top: 2px; }

/* ---- RESIDUAL 3: the studio hero — warm pool + specular sweep --
 * The preview's .hero, ported onto the live gallery frame: the
 * carousel viewport carries the pool and the frame; the slide's
 * 8px border-box inset is the hero's padding rim (outer slide
 * geometry is untouched, so the swipe math never notices); the
 * sweep is a static ::before — no animation (perf law). */
.design-gallery .carousel-viewport {
  position: relative; border-radius: 28px;
  background: radial-gradient(85% 72% at 50% 38%, rgba(252, 240, 218, 0.10), rgba(252, 240, 218, 0) 62%),
    linear-gradient(180deg, rgba(255, 255, 255, 0.075), rgba(255, 255, 255, 0.035));
  border: 1px solid rgba(255, 255, 255, 0.095);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.17), inset 0 -1px 0 rgba(255, 255, 255, 0.03), 0 28px 54px rgba(5, 6, 10, 0.46);
  -webkit-backdrop-filter: blur(24px) saturate(1.45); backdrop-filter: blur(24px) saturate(1.45);
}
.design-gallery .carousel-viewport::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 72px; z-index: 2;
  pointer-events: none; opacity: 0.55;
  background: linear-gradient(105deg, rgba(255, 255, 255, 0) 5%, rgba(255, 255, 255, 0.13) 38%, rgba(255, 255, 255, 0.03) 58%, rgba(255, 255, 255, 0) 78%);
}
.design-gallery .carousel-slide { box-sizing: border-box; padding: 8px; }
.design-gallery .carousel-slide .mockup {
  border-radius: 20px; margin-top: 0; border: none;
  box-shadow: 0 10px 26px rgba(5, 6, 10, 0.20);
}

/* ---- Price unit: titleblock + pill, preview values ---- */
.price-unit {
  padding: 16px; gap: 0;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.055), rgba(255, 255, 255, 0.03)),
    linear-gradient(rgba(23, 24, 30, 0.78), rgba(23, 24, 30, 0.78));
  border: 1px solid rgba(255, 255, 255, 0.09);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 14px 28px rgba(5, 6, 10, 0.32);
  -webkit-backdrop-filter: blur(20px) saturate(1.4); backdrop-filter: blur(20px) saturate(1.4);
}
.price-unit .price-main { align-items: stretch; gap: 0; }
.price-unit .price-txt { text-align: left; }
.price-unit .price-txt b {
  font-size: 28px; font-weight: 750; letter-spacing: -0.03em; line-height: 1.18;
  white-space: normal; overflow: visible; text-overflow: clip;
}
.price-unit .price-txt span { font-size: 14px; line-height: 1.45; margin-top: 8px; }
.price-unit .price-value {
  align-self: center; margin-top: 24px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.09), rgba(255, 255, 255, 0.045));
  border: 1px solid rgba(255, 255, 255, 0.10);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.14);
  letter-spacing: -0.02em; line-height: 1.2; color: var(--ink);
}
.price-unit .bnpl-line { margin: 8px 0 0; }
.price-unit .bnpl-line b { font-weight: 700; }

/* ---- Takes thumbs: preview .thumb ---- */
.takes-thumbs {
  padding: 4px 2px 8px; scroll-snap-type: x mandatory;
  -webkit-mask-image: linear-gradient(90deg, #111 90%, transparent);
  mask-image: linear-gradient(90deg, #111 90%, transparent);
}
.take-thumb {
  scroll-snap-align: start; padding: 0; overflow: hidden;
  background: #efece5; border: 1px solid rgba(255, 255, 255, 0.10);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.10), 0 8px 16px rgba(5, 6, 10, 0.18);
}
.take-thumb img { width: 100%; height: 100%; object-fit: contain; border-radius: 0; display: block; }
.take-thumb.current {
  border-color: rgba(190, 198, 255, 0.88);
  box-shadow: 0 0 0 2px rgba(154, 163, 226, 0.26), inset 0 1px 0 rgba(255, 255, 255, 0.16);
}

/* ---- Color row: preview dot ring on the live swatches ---- */
.quick-replies button.qr-swatch {
  border: 1px solid rgba(255, 255, 255, 0.32);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.28), 0 5px 12px rgba(5, 6, 10, 0.22);
}
.quick-replies button.qr-swatch.current {
  border-color: rgba(255, 255, 255, 0.32);
  box-shadow: 0 0 0 2px #1b1c21, 0 0 0 5px rgba(170, 179, 240, 0.88), 0 0 18px rgba(124, 134, 216, 0.20);
}
.qr-row-label {
  font-size: 11px; font-weight: 650; letter-spacing: 0.18em;
  text-transform: uppercase; color: var(--peri-deep);
}

/* ---- Everything grid: preview .ecard + secondary button ---- */
.everything-block { margin-top: 32px; }
.everything-grid { gap: 8px; padding: 4px 2px 8px; margin-top: 0; }
.eg-cell {
  padding: 0; overflow: hidden; text-align: left;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0.04));
  border: 1px solid var(--glass-edge);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.13), 0 14px 28px rgba(5, 6, 10, 0.26);
  -webkit-backdrop-filter: blur(18px) saturate(1.35); backdrop-filter: blur(18px) saturate(1.35);
}
.eg-cell img {
  width: 100%; height: 128px; aspect-ratio: auto; padding: 8px; box-sizing: border-box;
  background: var(--well); border-radius: 0; object-fit: contain;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.28);
}
.eg-cell .eg-name { padding: 12px 12px 0; line-height: 1.3; }
.eg-cell .eg-price { padding: 4px 12px 12px; }
.everything-block .ghost-btn {
  min-height: 56px; margin-top: 12px; font-size: 16px; font-weight: 650;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.10), rgba(255, 255, 255, 0.055));
  border: 1px solid rgba(255, 255, 255, 0.11);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.14), 0 14px 28px rgba(5, 6, 10, 0.30);
  -webkit-backdrop-filter: blur(18px) saturate(1.35); backdrop-filter: blur(18px) saturate(1.35);
}

/* ---- Sticky price bar: preview pill values ---- */
.sticky-bar {
  gap: 12px; padding: 10px 10px 10px 16px; margin-top: 8px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.075), rgba(255, 255, 255, 0.035)),
    linear-gradient(rgba(20, 21, 27, 0.86), rgba(20, 21, 27, 0.86));
  border: 1px solid rgba(255, 255, 255, 0.11);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 16px 32px rgba(5, 6, 10, 0.40);
}
.sticky-txt b { line-height: 1.25; }
.sticky-txt span { line-height: 1.3; }
.sticky-price { color: var(--ink); }
.sticky-buy {
  padding: 10px 16px; font-size: 13.5px;
  border: 1px solid rgba(196, 203, 255, 0.34);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.28), 0 8px 16px rgba(5, 6, 10, 0.30);
}

/* ---- Buy card internals: preview receipt / meter / BNPL ---- */
.buy-img {
  border: 1px solid rgba(255, 255, 255, 0.12);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.50), 0 10px 22px rgba(5, 6, 10, 0.20);
}
.buy-txt b { line-height: 1.35; }
.buy-txt span { margin-top: 4px; line-height: 1.45; }
.receipt { margin-top: 24px; }
.receipt .trow { font-size: 15px; }
.receipt .trow b { min-width: 96px; text-align: right; margin-left: auto; }
.receipt .trow.total { padding: 16px 0 0; }
.receipt .trow.total b { letter-spacing: -0.025em; }
.shipmeter { margin-top: 20px; }
.ship-track { border-radius: 999px; box-shadow: inset 0 1px 3px rgba(5, 5, 9, 0.45); }
.ship-fill { transition: width 0.45s cubic-bezier(0.32, 0.72, 0, 1); }
.ship-text { line-height: 1.45; color: var(--ink-dim); }
.buy-card .bnpl-line {
  background: linear-gradient(180deg, rgba(154, 163, 226, 0.13), rgba(124, 134, 216, 0.09));
  border: 1px solid rgba(154, 163, 226, 0.30);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.10);
  padding: 16px; margin: 24px 0 0; color: var(--ink); font-weight: 500;
}
.buy-card .bnpl-line b { font-weight: 650; }
.buy-now-btn {
  margin-top: 24px;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.30), inset 0 -12px 22px rgba(35, 40, 88, 0.20), 0 16px 32px rgba(5, 6, 10, 0.46), 0 6px 18px rgba(102, 112, 196, 0.16);
}

/* ---- Toast: preview glass banner values ---- */
.undo-toast {
  background: linear-gradient(180deg, rgba(54, 55, 66, 0.78), rgba(38, 39, 46, 0.72));
  border: 1px solid rgba(255, 255, 255, 0.12);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.16), 0 20px 44px rgba(5, 5, 9, 0.52);
  -webkit-backdrop-filter: blur(28px) saturate(1.55); backdrop-filter: blur(28px) saturate(1.55);
  font-weight: 500;
}
.undo-toast .undo-btn { padding: 6px 2px; font-size: 13.5px; }

/* ---- Focus + press: preview global states ---- */
button:focus-visible, input:focus-visible, textarea:focus-visible {
  outline: 2px solid rgba(154, 163, 226, 0.82); outline-offset: 3px;
}
textarea:focus-visible { outline: none; }
::selection { background: rgba(124, 134, 216, 0.32); }
.starter-chip:active, .product-bar button:active, .fresh-card:active,
.eg-cell:active, .take-thumb:active, .your-card:active,
.heart-btn:active { transform: scale(0.97); }
.heart-btn:active { transform: scale(0.92); }

@media (prefers-reduced-motion: reduce) {
  .sticky-bar, .fresh-card, .eg-cell, .take-thumb, .product-bar button { transition: none !important; }
}

/* ================= POLISH PASS (Oct 30, 2026) =================
 * Yeinel, comparing his signed-in phone screenshot against the
 * preview: "make it better." Every value below is quoted from
 * preview.html's final stylesheet (glass pass + six-features
 * pass), applied over the exact-match state. Presentation only —
 * the single structural change is the header account control's
 * avatar presentation (app.js updateAuthUI: same button, same
 * click handler, same ids/hooks). */

/* ---- P3: ctrl rows flow from the panel's left edge ----
 * The parity section right-aligned them (justify-content:flex-end),
 * which left dead space at the left of every wrapped row — the
 * screenshot's second row started mid-panel. Gap rhythm is the
 * preview header's: 8px (header-actions gap, six-features pass). */
.ctrl-row { justify-content: flex-start; }

/* ---- P6: panel finish — the preview's hairline + radius ----
 * Preview header border: 1px solid rgba(255,255,255,.09) (glass
 * pass). Preview panel radius: --radius = 24px (.card). The parity
 * shell carried 26px; the border color/width are re-asserted
 * explicitly so the panel's finish is the preview's, not the
 * generic .glass token's. */
.header { border: 1px solid rgba(255, 255, 255, 0.09); border-radius: 24px; }

/* ---- P5: ambient canvas — the preview's pools, unobstructed ----
 * The exact-match stack below is the preview's, value for value
 * (.col, glass pass). Two things were muting it in the screenshot:
 * (1) the legacy vignette (.bg-blobs::before, radial black up to
 * 50% at the edges) — the preview has no vignette; retired.
 * (2) the header's anchored frost (.80 dark) sits over pool 1;
 * the chrome therefore carries its own echo of that pool — same
 * size, position and alpha as the canvas pool — layered OVER the
 * anchored base, exactly as the preview's pools read through its
 * chrome gradient (rgba(13,14,18,.88→.68) + header sheen). The
 * dark anchor underneath is untouched, so the anchored-frost
 * contrast the small header text relies on is unchanged. Static:
 * no animation on this layer, per the standing perf law. */
.bg-blobs::before { display: none; }
.bg-blobs {
  background:
    radial-gradient(760px 420px at 88% -80px, rgba(124, 134, 216, 0.16), rgba(124, 134, 216, 0) 62%),
    radial-gradient(540px 380px at -12% 16%, rgba(124, 134, 216, 0.07), rgba(124, 134, 216, 0) 66%),
    radial-gradient(700px 560px at 8% 108%, rgba(240, 138, 118, 0.10), rgba(240, 138, 118, 0) 64%),
    radial-gradient(480px 320px at 82% 58%, rgba(240, 138, 118, 0.045), rgba(240, 138, 118, 0) 66%),
    radial-gradient(480px 340px at 50% 42%, rgba(124, 134, 216, 0.05), rgba(124, 134, 216, 0) 68%),
    #1b1c21;
}
.header {
  background:
    radial-gradient(760px 420px at 88% -80px, rgba(124, 134, 216, 0.16), rgba(124, 134, 216, 0) 62%),
    var(--anchored);
}

/* ---- P2: signed-in account control = the preview's avatar ----
 * Preview .signedin .avatar (glass pass): 34×34 circle on
 * --peri-grad, initial at 14px/700 in #F4F4F0, border 1px solid
 * rgba(196,203,255,.30), shadows inset 0 1px 0 rgba(255,255,255,.30),
 * inset 0 -10px 18px rgba(38,44,96,.18), 0 10px 22px rgba(5,6,10,.42).
 * The button IS the avatar (the preview wraps it with the chip in
 * one button; live keeps the chip as its own control beside it —
 * same DOM order the preview's signed-in state shows: credits chip,
 * then avatar). Signed out, #authBtn keeps the preview .signin pill
 * from the exact-match section untouched. */
.header #authBtn.avatar {
  width: 34px; height: 34px; min-height: 34px; flex: 0 0 34px;
  padding: 0; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--peri-grad);
  border: 1px solid rgba(196, 203, 255, 0.30);
  color: #f4f4f0; font-size: 14px; font-weight: 700; letter-spacing: 0;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.30), inset 0 -10px 18px rgba(38, 44, 96, 0.18), 0 10px 22px rgba(5, 6, 10, 0.42);
}
.header #authBtn.avatar:hover { background: var(--peri-grad); filter: brightness(1.08); }

/* ---- P4: the home idea box is a real three-line field ----
 * Preview textarea: min-height 92px, padding 16px, 16px font at
 * line-height 1.5. With rows=3 (set by syncStudioChrome on the
 * home stage) and border-box sizing, the rendered box is 3 lines
 * (72px) + padding (32px) + border (2px) = 106px. The min-height
 * is re-asserted explicitly here — not left to the rows attribute
 * surviving resets — and the placeholder may wrap instead of
 * clipping mid-word. The placeholder TEXT is the dictionary's
 * static preview string in both languages (EN "Describe your
 * idea… e.g. a memorial shirt for my grandma" / ES "Describe tu
 * idea… por ejemplo, una camiseta conmemorativa para mi abuela");
 * applyStaticStrings is its only writer — grep confirms no
 * rotation exists in this build to kill. */
body:not([data-stage="studio"]) .composer textarea {
  height: auto; min-height: 92px; white-space: pre-wrap;
}
body:not([data-stage="studio"]) .composer textarea::placeholder { white-space: pre-wrap; }

/* ================================================================
 * CHIP FIX (Oct 30, 2026) — starter chips rendered as CIRCLES.
 *
 * Root cause: syncStudioChrome (app.js) moves #starterChips INSIDE
 * <form id="composer"> on the home stage, so the chips become
 * descendants of .composer and the LEGACY generic rule
 * `.composer button` (styles.css ~line 642: width:52px; height:50px;
 * flex:0 0 52px; border-radius:50%; border:none; font-size:20px;
 * font-weight:800) lands on them. Its specificity (0,1,1) BEATS
 * `.starter-chip` (0,1,0) wherever both declare (border, radius,
 * font-size), and the chip rules never declared width/height/flex/
 * white-space at all — so the fixed 52x50 round box applied
 * unopposed, the label (no nowrap) wrapped and spilled out of the
 * disc, and only the per-chip tints (0,2,0) survived on top, which
 * is why the discs showed the right colors at the wrong shape.
 * The parity pass repainted `.composer button` (background/color/
 * shadow) but never reset its geometry, so the trap stayed armed.
 *
 * Fix: re-state the PREVIEW chip spec (designeri-ux-preview/
 * preview.html .chips/.chip + glass pass) under the two-class
 * selector `.starter-chips .starter-chip` (0,2,0), which outranks
 * `.composer button` (0,1,1) in EVERY layout context — inside the
 * form on home, back in the headline, or anywhere else the chips
 * are ever moved. Geometry is declared explicitly (width/height
 * auto, flex-basis auto, pill radius, nowrap) so no generic button
 * rule can silently re-box the chips again. Guarded by
 * tests/chip-geometry.harness.js.
 * ================================================================ */
/* SCROLL ROW (Nov 2, 2026 — Yeinel): the chips grew from four to
 * eight (Dad joke / Inside joke / Handwriting / Small business
 * joined Memorial / Funny gift / My pet / Kid's drawing) and the
 * row must stay ONE row on every viewport — on mobile the wrapped
 * second row ate the space he wants for the idea card. So the
 * container is a horizontal scroller in the house pattern (same
 * contract as .product-bar / .your-row: nowrap + overflow-x auto +
 * hidden scrollbar + touch momentum), and the chips' flex flips
 * from 0 1 auto to 0 0 auto: with shrink allowed, a nowrap row
 * would compress the pills and clip their labels instead of ever
 * overflowing — flex-shrink 0 is what makes the row scroll. The
 * container rule below is the last .starter-chips word in the
 * cascade; the base rule up top declares the same nowrap/overflow
 * so no stale wrap survives anywhere. Guarded by
 * tests/chip-geometry.harness.js (row contract) and
 * tests/starter-chips-8.harness.js (the eight chips). */
.starter-chips {
  display: flex; flex-wrap: nowrap; gap: 8px; margin-top: 24px;
  overflow-x: auto; overflow-y: hidden;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
  padding-bottom: 8px;
}
.starter-chips::-webkit-scrollbar { display: none; }
.starter-chips .starter-chip {
  width: auto; height: auto; min-width: 0; min-height: 0;
  flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  white-space: nowrap;
  font-family: inherit; font-size: 14px; font-weight: 600; line-height: 1.2;
  color: var(--ink);
  background: var(--paper);
  border: 1px solid rgba(255, 255, 255, 0.10);
  border-radius: 999px;
  padding: 11px 17px;
  cursor: pointer;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.10), 0 8px 18px rgba(5, 6, 10, 0.18);
  transition: border-color 0.25s cubic-bezier(.22,.61,.36,1), color 0.25s cubic-bezier(.22,.61,.36,1), background-color 0.25s cubic-bezier(.22,.61,.36,1), transform 0.3s cubic-bezier(.34,1.56,.64,1);
}
.starter-chips .starter-chip[data-chip="memorial"] { background-color: rgba(216, 188, 148, 0.11); background-image: linear-gradient(180deg, rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0)); color: #dec69e; }
.starter-chips .starter-chip[data-chip="funny"] { background-color: rgba(240, 138, 118, 0.11); background-image: linear-gradient(180deg, rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0)); color: #f2ac97; }
.starter-chips .starter-chip[data-chip="pet"] { background-color: rgba(124, 134, 216, 0.14); background-image: linear-gradient(180deg, rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0)); color: #acb4e9; }
.starter-chips .starter-chip[data-chip="kid"] { background-color: rgba(150, 196, 158, 0.11); background-image: linear-gradient(180deg, rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0)); color: #abcdaf; }
.starter-chips .starter-chip[data-chip="dad"] { background-color: rgba(238, 164, 88, 0.11); background-image: linear-gradient(180deg, rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0)); color: #f0bc8a; }
.starter-chips .starter-chip[data-chip="inside"] { background-color: rgba(178, 132, 216, 0.12); background-image: linear-gradient(180deg, rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0)); color: #cfb0ec; }
.starter-chips .starter-chip[data-chip="handwriting"] { background-color: rgba(110, 196, 188, 0.11); background-image: linear-gradient(180deg, rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0)); color: #a5dcd6; }
.starter-chips .starter-chip[data-chip="business"] { background-color: rgba(110, 168, 224, 0.12); background-image: linear-gradient(180deg, rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0)); color: #a9cbf0; }
.starter-chips .starter-chip:hover { transform: none; filter: none; }
.starter-chips .starter-chip:active { transform: scale(0.97); }
.starter-chips .starter-chip.sel {
  border-color: rgba(240, 138, 118, 0.6);
  color: #f5ac99;
  background: rgba(240, 138, 118, 0.14);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.14), 0 0 0 2px rgba(240, 138, 118, 0.16), 0 8px 18px rgba(5, 6, 10, 0.18);
}

/* ================================================================
 * TOP BANNER FIX (Oct 30, 2026) — Yeinel, on the polish build:
 * "Fix the top banner." The panel still read as a big loose card.
 *
 * MEASURED on his screenshot (1179×2556 = 393×852pt @3x, signed
 * out, HEAD 6adc528; grounding + a 2× crop of the header):
 *   panel ≈ 190pt tall (22% of the screen; ≈202 with the app's
 *   12px top inset) — the polish pass's own 190 arithmetic held.
 *   Its parts: padding 16+16 · tile 48 · header gap 12 · ctrl rows
 *   44+8+44 · border 2. The PILLS WERE ALREADY 44 (Start over
 *   ≈42–44pt, My Creations ≈44pt measured) — not the ~54 the
 *   brief feared: min-height:44 + border-box (the global * rule)
 *   already sums 10+10 padding around a 19.5px line box = 41.5,
 *   floored to 44. The air was AROUND them: 44px of panel padding
 *   + gaps wrapped around 96px of rows. The subtitle does NOT
 *   wrap on device (crop-verified, one line, "· Shop" included) —
 *   it is re-asserted nowrap/ellipsis below so it stays that way.
 *
 * THE COMPACTION (preview metrics; preview header = padding 16,
 * tile 48, gap 12, one 44 row → 137, full-bleed, no My Creations;
 * live keeps 4–5 real controls in a floating panel → two rows):
 *   border 2 + padding 12+12 + brand row 44 (tile 44; text block
 *   23 title + 2 + 16.2 subtitle = 41.2 rides inside it) + gap 10
 *   + ctrl rows 44+8+44 = 176 TOTAL, both sign-in states (the
 *   signed-in row 2 — chip ≈32 + avatar 34 — rides the same 44
 *   row height). Target was ≤185.
 *
 * Pill heights are now PINNED with height:44px (border-box), not
 * just floored with min-height, so no future font/padding drift
 * can re-inflate them. The signed-in avatar keeps its 34px: the
 * polish rule .header #authBtn.avatar (1,2,0) outranks the
 * .header .auth-btn pin below (0,2,0) on height — intended.
 * The credits chip is deliberately NOT pinned: the preview's
 * chip is a ~32px pill riding the 44 row (exact-match section).
 *
 * Sticky-bar alignment: nothing to fix — the live bar derives NO
 * offset from the header (app.js initStickyBar: IntersectionObserver
 * with root = the stage scroller, threshold 0, no rootMargin; the
 * bar is position:sticky top:0 inside that scroller and its
 * show/hide is purely the buy card's visibility). Compacting the
 * header cannot misalign it; the header itself is a flex child of
 * the 100dvh .app column and the stage scrolls beneath it.
 * ================================================================ */
.header {
  padding: 12px 16px; gap: 10px;
  border: 1px solid rgba(255, 255, 255, 0.09); border-radius: 24px;
}
.header .logo { width: 44px; height: 44px; flex: 0 0 44px; border-radius: 15px; }
.header h1 { font-size: 20px; line-height: 1.15; }
.header .subtitle {
  font-size: 12px; line-height: 1.35; margin-top: 2px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ctrl-row { gap: 8px; }
.header .lang-toggle, .header #headerStartOver, .header #creationsBtn, .header .auth-btn {
  height: 44px; min-height: 44px;
}

/* ================= UPLOAD STUDIO (Oct 30, 2026) =================
 * The upload journey's studio panel: the uploaded image as the
 * persistent hero (the .design-gallery frame above supplies the
 * warm pool + specular sweep) and ONE glass action card under it
 * carrying the current step — the cartoonize ask, a working line,
 * or the product pick strip. Static styles only (perf rule): no
 * animation on any of these surfaces. */
.upload-studio { display: flex; flex-direction: column; gap: 12px; }
.upload-studio[hidden] { display: none; }
/* The hero holds the RAW artwork (not a garment render): contain
 * it, height-capped, never cropped — the same fit law as .mockup. */
.upload-hero .carousel-slide img.mockup {
  width: 100%; max-height: 52vh; object-fit: contain;
}
.upload-card {
  padding: 16px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.055), rgba(255, 255, 255, 0.03)),
    linear-gradient(rgba(23, 24, 30, 0.78), rgba(23, 24, 30, 0.78));
  border: 1px solid rgba(255, 255, 255, 0.09);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 14px 28px rgba(5, 6, 10, 0.32);
  -webkit-backdrop-filter: blur(20px) saturate(1.4); backdrop-filter: blur(20px) saturate(1.4);
  border-radius: 24px;
}
.upload-card[hidden] { display: none; }
.upload-receipt { margin: 0; font-size: 17px; font-weight: 700; letter-spacing: -0.01em; color: var(--ink); }
.upload-ask { margin: 8px 0 0; font-size: 15px; line-height: 1.5; color: var(--ink); }
.upload-receipt + .upload-ask { margin-top: 6px; }
/* The upload's quality warnings ride as small captions, never as
 * stacked chat bubbles. */
.upload-note { margin: 10px 0 0; font-size: 12.5px; line-height: 1.45; color: var(--ink-dim); }
/* A panel wait that ended badly says so on the card itself
 * (Oct 31, 2026) — warm, readable, never alarm-red neon. */
.upload-note.upload-error { color: #f0a8a0; font-weight: 600; }
/* The upload card's Di % mount (Oct 31, 2026): the standard
 * working indicator, hosted by the card under its status line —
 * centered, card-width, same fade-out contract as the chat form.
 * Perf discipline unchanged: only the clip width and the % text
 * ever move. An empty slot takes no space. */
.upload-work-slot:empty { display: none; }
.di-working-panel {
  display: flex; align-items: center; justify-content: center; gap: 12px;
  padding: 12px 16px 2px;
  transition: opacity 0.35s var(--spring), transform 0.35s var(--spring);
}
.di-working-panel.di-done { opacity: 0; transform: scale(0.96); }
.upload-actions { display: flex; flex-direction: column; gap: 10px; margin-top: 14px; }
.upload-act {
  min-height: 50px; border-radius: 999px; cursor: pointer;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.04));
  border: 1px solid var(--line-soft); color: var(--ink);
  font: inherit; font-size: 15px; font-weight: 700;
}
.upload-act.primary {
  background: linear-gradient(180deg, var(--accent), var(--accent-strong));
  border-color: transparent; color: #fff;
}
.upload-act:active { transform: scale(0.98); }
.upload-pick-grid { margin-top: 12px; }

/* Version compare — aligned to the studio card family (Oct 30,
 * 2026): the compare itself stays in the chat exactly as proven,
 * but its labels now sit as glass pills over the same well +
 * radius treatment the studio cards use, instead of bare caps
 * text floating over the bubble. */
.compare-label {
  display: inline-block; margin-top: 16px; padding: 5px 12px;
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 999px;
  font-size: 11.5px; font-weight: 700; letter-spacing: 0.09em;
  text-transform: uppercase; opacity: 1; color: var(--ink);
}

/* ================= PREVIEW MATCH (Oct 30, 2026) =================
 * The journey is the studio now: the transcript is hidden in the
 * studio stage and on the home welcome/chat steps (the error
 * surface on the initial step still shows), the generation wait is
 * a full-screen Di % takeover, and the review controls live in the
 * studio scroll. Static styles only (perf rule). */

/* --- transcript visibility --- */
.chat.chat-studio-hidden { display: none; }

/* --- the Di % takeover (preview progress view) --- */
.di-takeover {
  padding: 56px 8px 40px; text-align: center;
  display: flex; flex-direction: column; align-items: center;
}
.di-takeover[hidden] { display: none; }
.di-takeover .pct {
  font-size: clamp(96px, 30vw, 150px); line-height: 0.95;
  font-weight: 800; letter-spacing: -0.05em; color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.di-takeover .pct small { font-size: 0.42em; font-weight: 700; color: var(--ink-dim); margin-left: 2px; }
/* SIGNATURE PROGRESS (Nov 1, 2026): the mark under the numeral is
 * the shared Di fill (diMarkSvg, injected by ensureTakeoverDi),
 * scaled up to carry takeover presence — clamp(170px, 46vw, 220px)
 * wide with the viewBox ratio kept (height auto). At a 390px phone
 * the Di letters render ≈114px wide / ≈79px tall against the
 * numeral's ≈105px font; on desktop the 220px cap keeps the mark
 * just under the 150px numeral. The ONLY thing that ever changes
 * is the SVG clip rect's width attribute (showTakeover's render)
 * — no transition, no animation, no will-change, no
 * backdrop-filter (Oct 21 perf law). The plain .pbar/.pfill bar
 * that lived here is retired.
 * WORDMARK (Nov 2, 2026 — Yeinel, from his screenshot of this
 * screen: the progress for "this big ol percentage should match
 * the bigness. Designer-i instead of DI for this page
 * specifically so it matches" + "make sure it will fit on mobile
 * as well"): the takeover's mark is now the full "Designer-i"
 * wordmark (diWordmarkSvg, Manrope 800 — the numeral's own face
 * and weight), and THIS rule replaces the Di sizing above for it.
 * Fit math (harness: tests/takeover-signature.harness.js): the
 * glyph run is DI_WORD_EXTENT/viewBox = 504/510 ≈ 0.988 of the
 * SVG's CSS width, and the takeover column offers viewport − 64px
 * at phone widths (.app padding 24×2 + this section's 8×2;
 * ≥768px the column caps at 700px). The rule below —
 * width min(74vw, 520px) — is the ONLY sizing, on every screen
 * (FIT ALWAYS, Nov 2, 2026: it began as the touch/no-hover
 * sizing; a same-day desktop refinement blew the word up to the
 * numeral's full scale, overflowed the column by 129px and
 * edge-panned the excess, and Yeinel rejected it from his own
 * screenshot — "this is too big and doesnt show the whole
 * thing" — so the pan and its hover media block are REMOVED
 * and this fit rule now governs hover and touch alike: the
 * whole word on screen at once, at every viewport, as large
 * as it can be while still fitting whole):
 *   320px → word ≈234px in a 256px column (22px spare)
 *   360px → word ≈263px in a 296px column (33px spare)
 *   390px → word ≈285px in a 326px column (41px spare)
 *   desktop → capped: word ≈514px in the 636px column (122px
 *   spare), letters at ≈102px. No overflow, no clipped final
 *   "i", no horizontal scroll, no pan at any width. The ONLY
 *   thing that ever changes is still the clip rect's width
 *   attribute. */
.di-takeover .takeover-di { margin-top: 30px; }
.di-takeover .di-wordmark { width: min(74vw, 520px); height: auto; }
.di-takeover .takeover-status { margin: 18px 0 0; font-size: 15.5px; color: var(--ink-dim); font-weight: 600; }
/* While the takeover is up, NOTHING else is on screen but the
 * header — no stage, no composer, no replies, no sticky bar. */
body.takeover-on #stageScroll,
body.takeover-on #composer,
body.takeover-on #quickReplies,
body.takeover-on .legal-line,
body.takeover-on #stickyBar { display: none !important; }

/* --- home hint line (guidance without a bubble) --- */
.home-hint { margin: 10px 2px 0; font-size: 14px; line-height: 1.5; color: var(--ink-dim); }
.home-hint[hidden] { display: none; }
body[data-stage="studio"] .home-hint { display: none; }

/* STAND OUT (Nov 2, 2026 — Yeinel, from his screenshot: the picked-
 * product line rendered in the same dim gray as the subtext and
 * "blends into" it): when the hint announces the picked product,
 * setHomeHint adds .home-hint--picked and the line becomes a
 * highlighted glass pill — the product's own blank-template photo
 * on the left, the sentence in full-bright ink, and the product
 * NAME (the productChosen template's <b>) in the brand gradient
 * at 800 weight, so the visitor instantly sees exactly what
 * they're printing on. The glass recipe matches .brief-panel /
 * .review-note (layered gradient over the dark tint, 1px edge,
 * inner top highlight, soft shadow, backdrop blur) — a small
 * element, not a full-screen layer, so the Oct 21 perf law is
 * untouched. Contrast on the pill's dark glass: the sentence in
 * --ink (#f2f5fa) sits ≈13:1; the name's gradient runs
 * #9dbcff → #5b8cff, ≈9:1 → ≈5.9:1 — both ends clear the 4.5:1
 * small-text rule, with plain #9dbcff as the no-gradient-clip
 * fallback. The appearance is ONE 0.32s rise (the msg-in/chip-in
 * family), never a loop, and reduced-motion visitors skip it. On
 * a phone the pill caps at the headline's width and the sentence
 * wraps inside it; the photo stays pinned at text height ×2. */
@keyframes hint-in { from { opacity: 0; transform: translateY(6px) scale(0.98); } }
.home-hint--picked {
  display: inline-flex; align-items: center; gap: 10px;
  max-width: 100%; margin: 12px 2px 0; padding: 7px 16px 7px 8px;
  border-radius: 999px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.075), rgba(255, 255, 255, 0.04)),
    linear-gradient(rgba(23, 24, 30, 0.78), rgba(23, 24, 30, 0.78));
  border: 1px solid rgba(255, 255, 255, 0.14);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.16), 0 12px 26px rgba(5, 6, 10, 0.32);
  -webkit-backdrop-filter: blur(20px) saturate(1.4); backdrop-filter: blur(20px) saturate(1.4);
  color: var(--ink); font-weight: 500;
  animation: hint-in 0.32s var(--spring) backwards;
}
.home-hint--picked .home-hint-thumb {
  flex: 0 0 auto; width: 30px; height: 30px; border-radius: 9px;
  object-fit: cover; background: #fff;
  border: 1px solid rgba(255, 255, 255, 0.18);
}
.home-hint--picked .home-hint-text { min-width: 0; }
.home-hint--picked b { font-weight: 800; color: #9dbcff; }
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .home-hint--picked b {
    background: linear-gradient(92deg, #9dbcff, #5b8cff);
    -webkit-background-clip: text; background-clip: text;
    -webkit-text-fill-color: transparent; color: transparent;
  }
}
@media (prefers-reduced-motion: reduce) {
  .home-hint--picked { animation: none; }
}

/* --- studio gallery host --- */
.studio-gallery-host[hidden] { display: none; }

/* --- the studio note line --- */
.review-note {
  margin: 0; padding: 12px 16px; border-radius: 18px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.05), rgba(255, 255, 255, 0.028)),
    linear-gradient(rgba(23, 24, 30, 0.78), rgba(23, 24, 30, 0.78));
  border: 1px solid rgba(255, 255, 255, 0.09);
  font-size: 14.5px; line-height: 1.55; color: var(--ink);
}
.review-note[hidden] { display: none; }

/* --- the structured design brief --- */
.brief-panel {
  padding: 14px 16px; border-radius: 24px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.055), rgba(255, 255, 255, 0.03)),
    linear-gradient(rgba(23, 24, 30, 0.78), rgba(23, 24, 30, 0.78));
  border: 1px solid rgba(255, 255, 255, 0.09);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 14px 28px rgba(5, 6, 10, 0.32);
  -webkit-backdrop-filter: blur(20px) saturate(1.4); backdrop-filter: blur(20px) saturate(1.4);
}
.brief-panel[hidden] { display: none; }
.brief-attrs { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.brief-attr {
  display: inline-flex; align-items: center; gap: 7px; max-width: 100%;
  padding: 8px 8px 8px 13px; border-radius: 999px; cursor: pointer;
  background: rgba(255, 255, 255, 0.06); border: 1px solid rgba(255, 255, 255, 0.10);
  color: var(--ink); font: inherit; text-align: left;
}
.brief-attr .ba-label {
  font-size: 10.5px; font-weight: 800; letter-spacing: 0.09em;
  text-transform: uppercase; color: var(--peri2); flex: 0 0 auto;
}
.brief-attr .ba-value { font-size: 14px; font-weight: 600; overflow-wrap: anywhere; }
.brief-attr.targeted {
  border-color: rgba(190, 198, 255, 0.82);
  box-shadow: 0 0 0 4px rgba(124, 134, 216, 0.22);
}
.brief-attr .ba-x {
  flex: 0 0 auto; width: 22px; height: 22px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: rgba(255, 255, 255, 0.10); color: var(--ink-dim);
  font-size: 13px; line-height: 1;
}
/* Inline brief editing (Nov 2, 2026): the editing chip is the
   same pill (with the targeted ring) and its value swapped for an
   input. The input is 16px — the size this site's form inputs
   use — so iOS Safari does not auto-zoom when it takes focus. */
.brief-attr.editing {
  border-color: rgba(190, 198, 255, 0.82);
  box-shadow: 0 0 0 4px rgba(124, 134, 216, 0.22);
  cursor: text;
}
.brief-attr .ba-input {
  flex: 1 1 auto; min-width: 0; max-width: 100%;
  background: transparent; border: none; outline: none; padding: 0;
  color: var(--ink); font: inherit; font-size: 16px; font-weight: 600;
}
.brief-attr .ba-ok {
  flex: 0 0 auto; width: 22px; height: 22px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: rgba(124, 134, 216, 0.35); color: var(--ink);
  font-size: 13px; line-height: 1; cursor: pointer;
}
.brief-hint { margin: 10px 0 0; font-size: 13px; line-height: 1.5; color: var(--ink-dim); }
.brief-note { margin: 10px 0 0; font-size: 12.5px; line-height: 1.5; color: var(--ink-dim); }
/* Credit disclaimer (Nov 1, 2026): the shared cost line under the
   studio edit row — same quiet note voice as .brief-note. */
.credit-cost-note { margin: 2px 2px 0; font-size: 12.5px; line-height: 1.5; color: var(--ink-dim); }

/* --- CHOOSE YOUR PRODUCT snap-row --- */
.pstrip-block[hidden] { display: none; }
.product-strip {
  display: flex; gap: 12px; overflow-x: auto; padding: 2px 2px 10px;
  scroll-snap-type: x mandatory; scrollbar-width: none;
}
.product-strip::-webkit-scrollbar { display: none; }
.product-strip .pstrip-card {
  scroll-snap-align: start; flex: 0 0 128px; width: 128px;
  display: flex; flex-direction: column; align-items: stretch; text-align: left;
  padding: 0 0 12px; border-radius: 20px; overflow: hidden; cursor: pointer;
  background: var(--anchored); border: 1px solid var(--glass-edge);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12);
  color: var(--ink); font: inherit;
}
.product-strip .pstrip-card.current {
  border-color: rgba(190, 198, 255, 0.82);
  box-shadow: 0 0 0 4px rgba(124, 134, 216, 0.22);
}
.product-strip .pstrip-well { display: block; height: 104px; background: var(--well); padding: 8px; box-sizing: border-box; }
.product-strip .pstrip-well img { width: 100%; height: 100%; object-fit: contain; border-radius: 12px; display: block; }
.product-strip .pstrip-name { display: block; padding: 12px 12px 0; font-size: 13.5px; font-weight: 650; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.product-strip .pstrip-price { display: block; padding: 4px 12px 0; font-size: 13px; font-weight: 650; color: var(--peri-deep); font-variant-numeric: tabular-nums; }

/* --- transfer picker panel --- */
.transfer-panel {
  padding: 14px 16px; border-radius: 24px;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.055), rgba(255, 255, 255, 0.03)),
    linear-gradient(rgba(23, 24, 30, 0.78), rgba(23, 24, 30, 0.78));
  border: 1px solid rgba(255, 255, 255, 0.09);
}
.transfer-panel[hidden] { display: none; }
.transfer-panel .tp-grid { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.transfer-panel .tp-btn {
  padding: 10px 15px; border-radius: 999px; cursor: pointer;
  background: rgba(255, 255, 255, 0.07); border: 1px solid rgba(255, 255, 255, 0.11);
  color: var(--ink); font: inherit; font-size: 14px; font-weight: 650;
}
.transfer-panel .tp-btn:active { transform: scale(0.97); }

/* --- COLOR row: dots + selected name --- */
.color-row[hidden] { display: none; }
.color-row .field-head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.color-row .selected-value { font-size: 14px; font-weight: 650; color: var(--ink-dim); }
.color-row .dots { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 10px; }
.color-row .dot {
  width: 34px; height: 34px; border-radius: 50%; cursor: pointer; padding: 0;
  border: 2px solid rgba(255, 255, 255, 0.28);
  box-shadow: inset 0 0 0 2px rgba(0, 0, 0, 0.18);
}
.color-row .dot.current { border-color: var(--peri2); box-shadow: 0 0 0 4px rgba(124, 134, 216, 0.30); }

/* --- studio actions --- */
.studio-actions[hidden] { display: none; }
.studio-actions { display: flex; flex-direction: column; gap: 10px; }
.studio-actions .sa-row { display: flex; gap: 10px; }
.studio-actions button {
  min-height: 50px; border-radius: 999px; cursor: pointer; flex: 1 1 0;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.08), rgba(255, 255, 255, 0.04));
  border: 1px solid var(--line-soft); color: var(--ink);
  font: inherit; font-size: 15px; font-weight: 700;
}
.studio-actions button.primary {
  background: linear-gradient(180deg, var(--accent), var(--accent-strong));
  border-color: transparent; color: #fff; width: 100%;
}
.studio-actions button:active { transform: scale(0.98); }

/* --- Continue --- */
.continue-btn {
  width: 100%; min-height: 54px; border-radius: 999px; cursor: pointer;
  background: linear-gradient(180deg, var(--accent), var(--accent-strong));
  border: none; color: #fff; font: inherit; font-size: 16px; font-weight: 750;
}
.continue-btn[hidden] { display: none; }
.continue-btn:active { transform: scale(0.99); }

/* --- studio replies mirror (buy-time asks) --- */
.studio-replies[hidden] { display: none; }

/* --- store link row in the buy card --- */
.store-link-row { margin-top: 12px; text-align: center; }
.store-link-row[hidden] { display: none; }
.store-link-row a { color: var(--peri2); font-size: 15px; font-weight: 700; text-decoration: none; }

/* --- upload pick cells: the customer's OWN art stands in until
 * the real product mockup lands, so a cell never reads as a bare
 * product name. --- */
.eg-cell .eg-art-thumb {
  width: 100%; height: 118px; object-fit: contain; display: block;
  background: #26272d; padding: 10px; box-sizing: border-box;
}

/* --- in-panel version compare (upload studio) --- */
.upload-compare { margin-top: 4px; }
.upload-compare .uc-imgs { display: flex; flex-direction: column; }
.upload-compare img.mockup { width: 100%; border-radius: 16px; display: block; }

/* ================= PAGE SCROLL + TAKEOVER FIT (Oct 31, 2026) =================
 * Yeinel's phone verdict on the preview-match build (his
 * screenshots, Oct 31 ~00:02–00:04 ET):
 *  (1) "I wanted a page scroll not a little box scroll" — the
 *      studio was trapped inside #stageScroll, a fixed-height
 *      region with its OWN vertical scrollbar, wedged between the
 *      header and the composer; the page itself never scrolled.
 *      The preview's studio is ONE long page. So: the DOCUMENT is
 *      now the journey's only vertical scroller. .app grows with
 *      its content, #stageScroll is a plain flow wrapper with no
 *      overflow of its own, the header panel sticks to the top of
 *      the page, the studio edit bar sticks to the bottom (the
 *      preview's .chrome / .editbar pattern), and the sticky price
 *      bar anchors under the header via the --chrome-h measurement
 *      app.js publishes. Horizontal snap strips keep their own
 *      horizontal scrolling, exactly as in the preview.
 *  (2) The hero inside that box rendered cropped/zoomed: slide
 *      images in the studio host had NO sizing rule of their own
 *      (the contain/width law lived on .msg img.mockup, and the
 *      studio gallery is not inside a .msg), so a Printful mockup
 *      painted at natural size and the carousel viewport clipped
 *      it. The preview's hero geometry now applies to every
 *      gallery slide: full column width, square frame, contain —
 *      never cropped.
 *  (3) The takeover numeral ran off both edges of his phone: the
 *      JS wrote the raw float (see app.js INTEGER LAW); these
 *      values keep the preview's scale while guaranteeing the
 *      integer + % fit the column at any viewport (nowrap, and a
 *      clamp whose worst case — "100%" at 800 weight — measures
 *      ≈2.15× the font size, inside the column from 320px up). */

/* (1) the page scrolls; the column grows with its content */
.app { height: auto; min-height: 100vh; min-height: 100dvh; }
.stage-scroll {
  flex: none; height: auto;
  overflow: visible;
  -webkit-overflow-scrolling: auto;
}

/* the header panel stays pinned while the page scrolls under it */
.header { position: sticky; top: 10px; z-index: 40; }

/* the sticky price bar anchors just under the header panel
 * (--chrome-h is the header's measured height, set by app.js;
 * the fallback keeps the bar below a typical two-row header) */
.sticky-bar { top: calc(var(--chrome-h, 168px) + 18px); z-index: 35; }

/* the studio edit bar rides the bottom of the viewport while the
 * studio page scrolls (preview .editbar: sticky, safe-area aware).
 * On home the composer is the in-flow idea card — no sticking. */
body[data-stage="studio"] .composer {
  position: sticky; bottom: calc(8px + env(safe-area-inset-bottom)); z-index: 35;
}

/* (2) the preview's hero geometry on every gallery slide */
.design-gallery .carousel-slide .mockup {
  width: 100%; aspect-ratio: 1 / 1; object-fit: contain; max-height: none;
}
.upload-hero .carousel-slide img.mockup {
  aspect-ratio: 1 / 1; max-height: none;
}

/* (3) the takeover numeral always fits the column */
.di-takeover .pct {
  font-size: clamp(84px, 27vw, 150px);
  white-space: nowrap; max-width: 100%;
}

/* ================================================================
 * BANNER CLEANUP (Nov 1, 2026) — Yeinel's phone screenshot: the
 * header panel ate ~a quarter of the screen and its tagline line
 * ("Turn any idea into a real product · Shop") duplicated the
 * home headline directly below it. Approved cleanup:
 *   - the tagline line is REMOVED from the DOM (index.html); the
 *     Shop link it carried rides the controls row as #shopLink —
 *     same /shop.html destination, no navigation left behind;
 *   - the account cluster (credits chip + Sign in/avatar) moves
 *     from the controls row to the BRAND row's right side — same
 *     elements, ids and bindings, relocated not rebuilt;
 *   - ONE tight controls row under it: EN|ES · Start over ·
 *     My Creations · Shop, 36px pills at 12px, 5px gaps.
 * Geometry (box model over the final cascade + Manrope text
 * widths measured from the real variable font; harness:
 * tests/banner-cleanup.harness.js):
 *   before: 176px at phone widths —
 *     padding 24 + border 2 + brand row 44 (48->44 logo beside
 *     h1+subtitle) + gap 10 + TWO wrapped 44px ctrl rows + gap 8.
 *     (Signed-in EN at 430px models to 166px: there the wrapped
 *     second row carries only the ~31px chip + the 34px avatar.)
 *   after, EN: 104px, both states, 390px and 430px —
 *     padding 20 + border 2 + brand row 40 + gap 6 + one 36 row.
 *     That is 40.9% smaller — the approved ~40%.
 *   after, ES: the same single row at desktop widths, but at
 *     390/430px the controls row WRAPS to two tight rows (145px
 *     total): the Spanish labels are measured 30–65% wider
 *     ("Empezar de nuevo" alone is ~119px of text at 12px; the
 *     four ES pills need ~375px against ~320px available), so a
 *     single ES row at phone width is arithmetically impossible
 *     without shrinking text or renaming labels — a copy call
 *     left for Yeinel, NOT taken here. Nothing clips or hides:
 *     the row wraps exactly as it did before this cleanup.
 * Sticky geometry: --chrome-h is MEASURED from .header at
 * runtime (syncStudioChrome), so the sticky price bar and the
 * studio chrome track the new height automatically; only the
 * pre-JS fallback constant changes below (168 -> 104).
 * The old .subtitle rules above are now dead (no element carries
 * the class) and are left in place deliberately — removing them
 * is a separate no-behavior-change sweep.
 * ================================================================ */
.header { padding: 10px; gap: 6px; }
.header .logo { width: 40px; height: 40px; flex: 0 0 40px; border-radius: 14px; font-size: 17px; }
.brand-row { gap: 10px; }
.brand-side {
  margin-left: auto; flex: 0 0 auto; min-width: 0;
  display: flex; align-items: center; gap: 8px;
}
.ctrl-row { gap: 5px; }
.header .lang-toggle, .header #headerStartOver, .header #creationsBtn {
  height: 36px; min-height: 36px; padding: 0 8px; font-size: 12px;
}
.header .lang-toggle { gap: 4px; letter-spacing: 0.02em; }
.header .auth-btn { height: 36px; min-height: 36px; }
.header .credits-chip { height: 36px; min-height: 36px; padding: 0 10px; }
.header .shop-link {
  display: inline-flex; align-items: center; justify-content: center;
  height: 36px; padding: 0 8px; border-radius: 999px;
  font-size: 12px; font-weight: 700; white-space: nowrap; text-decoration: none;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.075), rgba(255, 255, 255, 0.04));
  border: 1px solid rgba(255, 255, 255, 0.10); color: var(--ink);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.12), 0 8px 18px rgba(5, 6, 10, 0.22);
}
.header .shop-link:hover { color: var(--ink); border-color: rgba(255, 255, 255, 0.18); }
.sticky-bar { top: calc(var(--chrome-h, 104px) + 18px); }

/* ================= FRESH IDEAS ROTATION (Nov 1, 2026) =================
 * The silent timer crossfades ONE card at a time: a small local
 * fade + settle on the swapping card only. The perf rule bans
 * animation on full-screen / fixed layers — this is neither: it
 * is one card, opacity + transform, 340ms, and the JS never
 * starts it for prefers-reduced-motion visitors (the media rule
 * below also kills the transition itself for them). */
.fresh-card { transition: opacity 0.34s ease, transform 0.34s ease; }
.fresh-card.fresh-fading { opacity: 0; transform: scale(0.985); }
@media (prefers-reduced-motion: reduce) {
  .fresh-card { transition: none !important; }
}

/* ================= BRAND HOME (Nov 1, 2026) =================
 * The Di tile + "Designer-i" wordmark are one button (#brandHome,
 * goBrandHome in app.js): a tap lands on the main page WITHOUT
 * discarding the in-progress design (it is parked in the session
 * snapshot — see app.js). Layout law: the slim banner's geometry
 * is pinned by tests/banner-cleanup.harness.js (EN 104px), so
 * this button contributes ZERO box of its own — no padding, no
 * border, no background, no margin — and internally reproduces
 * the exact spacing it replaced: the row's 10px gap between tile
 * and wordmark, the wordmark's old flex role in the row taken
 * over by the button itself (the account cluster is pushed by
 * its own margin-left:auto, unchanged). Static styles only
 * (perf rule): the only state style is a focus ring. */
.brand-home {
  display: flex; align-items: center; gap: 10px;
  flex: 1 1 auto; min-width: 0;
  margin: 0; padding: 0; border: 0; background: none;
  font: inherit; color: inherit; text-align: left;
  cursor: pointer; appearance: none; -webkit-appearance: none;
  -webkit-tap-highlight-color: transparent;
}
.brand-home .header-text { flex: 0 1 auto; }
.brand-home:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 16px;
}
