/* Infinity Catalogue -- ink and brass, carried over from Infinity Closet's design language,
   adapted from mobile screens to a desktop B2B dashboard. */
:root {
  color-scheme: dark;
  --ink: #14110F; --panel: #1F1A16; --raised: #292220; --raised-2: #332B27;
  --line: rgba(201,162,39,.22); --line-soft: rgba(201,162,39,.14);
  --brass: #C9A227; --brass-dim: #8A7327; --brass-bright: #E4BE4A;
  --ivory: #F3ECE0; --taupe: #A09383; --sage: #7FA294; --danger: #D9925A;
  /* dark text that stays dark on a bright brass/ivory surface regardless of
     theme -- decoupled from --ink so --ink is free to flip light/dark. */
  --on-brass: #1A1407;
  /* Vivid gold constants for PAINTED surfaces (button fills, the logo
     chip, spinner strokes, active dots) that always sit on their own
     fixed dark backing -- these stay the same bright gold in both themes.
     Separate from --brass/--brass-dim/--brass-bright below, which are
     reused as TEXT color on the page/card background and need to darken
     in light theme to stay legible (see the light-theme override). */
  --brass-surface: #C9A227; --brass-surface-bright: #E4BE4A;
  /* subtle lighten-on-hover tints for dark surfaces; light theme below
     swaps these to darken-on-hover instead. */
  --hover-tint: rgba(243,236,224,.06); --hover-tint-strong: rgba(243,236,224,.1); --hover-tint-soft: rgba(243,236,224,.05);
  /* letterboxing/mat color behind contain-fit photos */
  --mat: #0c0a09;
  /* The landing page's "editorial band" (steps + stats) is always dark --
     the original ink+brass look this app shipped with -- regardless of
     which theme is active. In dark theme the page is already this color,
     so the band just blends in; in light theme it's the one deliberately
     dark section breaking up an otherwise all-cream page. Not themed. */
  --band-bg: #1F1A16; --band-text: #F3ECE0; --band-muted: #A09383;
  --display: "Fraunces", Georgia, serif; --body: "Inter", -apple-system, "Segoe UI", Roboto, sans-serif;
  --spring: cubic-bezier(.34, 1.56, .64, 1); --soft: cubic-bezier(.22, 1, .36, 1);
  --radius: 14px;
}

/* Light theme: same brand palette (brass accent, sage, danger unchanged),
   ink/panel/raised/ivory/taupe swapped for light surfaces + dark text.
   Applied via data-theme="light" on <html>, toggled in app.js and persisted
   to localStorage; defaults to dark (the :root above) when absent. */
[data-theme="light"] {
  color-scheme: light;
  --ink: #FBF1EC; --panel: #FFFFFF; --raised: #F3E2D9; --raised-2: #ECD3C5;
  --ivory: #2B1D18; --taupe: #7D6459;
  /* Brass/sage/danger are tuned bright for text on a near-black page in
     dark theme (e.g. brass-bright on ink is a 1.6:1 contrast ratio --
     unreadable), so they're overridden for light theme anyway. Brass
     shifts from gold to the same terracotta family as --brass-surface
     below (not just darkened) -- links, numbers, and active states read
     as the same accent as the buttons, both clearing ~4.5:1 on this page. */
  --brass: #7A3B24; --brass-dim: #5C2C1C; --brass-bright: #9E4C2E;
  --sage: #466D60; --danger: #A5551A;
  /* Buttons/dots/spinner/toggle (anything painted with --brass-surface*)
     swap gold for a deepened, darker shade of the Blush Ivory page color
     itself -- a bright yellow-gold button read as off-brand/out of place
     against the rose-cream page, where an antique-terracotta from the same
     hue family reads as an intentional deep accent instead. --on-brass
     (the text/icon color painted on top) flips to a light cream to match. */
  --brass-surface: #6D321D; --brass-surface-bright: #9E4C2E;
  --on-brass: #FDF6F1;
  --hover-tint: rgba(20,17,15,.05); --hover-tint-strong: rgba(20,17,15,.08); --hover-tint-soft: rgba(20,17,15,.04);
  --mat: #F3DED3;
}
/* .btn-outline defaults to plain --ivory text (shared by several outline
   buttons with no particular accent meaning); the landing page's contact
   CTA is the one outline button meant to read as an accent action, so it
   gets the terracotta treatment explicitly rather than changing the
   shared class. */
[data-theme="light"] #openContactFormBtn { color: var(--brass-bright); border-color: rgba(158,76,46,.35); }
[data-theme="light"] #openContactFormBtn:hover { background: rgba(158,76,46,.06); }
/* Lighter than --brass-bright (the links/numbers terracotta) on purpose --
   this is a quiet footer credential, not a primary accent, so it sits one
   step softer; background/border retint to the same terracotta family
   instead of the gold wash used in dark theme. */
[data-theme="light"] .footer-highlight span {
  background: linear-gradient(90deg, rgba(158,76,46,.1), rgba(158,76,46,.16), rgba(158,76,46,.1));
  border-color: rgba(158,76,46,.3); color: #A8552F;
}
* { box-sizing: border-box; }
html, body { height: 100%; margin: 0; background: var(--ink); color: var(--ivory); font-family: var(--body);
  font-size: 15px; line-height: 1.5; -webkit-font-smoothing: antialiased; }
button, input, select, textarea { font: inherit; color: inherit; }
button { cursor: pointer; border: 0; background: none; padding: 0; touch-action: manipulation; }
button:focus-visible, input:focus-visible, a:focus-visible { outline: 2px solid var(--brass); outline-offset: 2px; }
img { max-width: 100%; display: block; }
h1, h2, h3, p { margin: 0; }
a { color: var(--brass); text-decoration: none; }
[hidden] { display: none !important; }

body { background-image:
  radial-gradient(circle at 15% 0%, rgba(201,162,39,.07), transparent 45%),
  radial-gradient(circle at 85% 100%, rgba(127,162,148,.05), transparent 45%); background-attachment: fixed; }

/* ---------- shared bits ---------- */
.eyebrow { font-size: 12px; letter-spacing: .16em; text-transform: uppercase; color: var(--taupe); }
.btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px; min-height: 46px;
  padding: 0 22px; border-radius: 999px; font-weight: 600; font-size: 14.5px; white-space: nowrap;
  transition: transform .25s var(--spring), opacity .2s; }
.btn:active { transform: scale(.97); }
.btn-brass { background: linear-gradient(180deg, var(--brass-surface-bright), var(--brass-surface)); color: var(--on-brass); }
.btn-brass:hover { filter: brightness(1.06); }
.btn-ghost { background: var(--hover-tint); border: 1px solid var(--line); color: var(--ivory); }
.btn-ghost:hover { background: var(--hover-tint-strong); }
.btn-outline { background: transparent; border: 1px solid var(--line); color: var(--ivory); }
.btn[disabled] { opacity: .45; pointer-events: none; }
.btn-block { width: 100%; }
.card { background: var(--panel); border: 1px solid var(--line-soft); border-radius: var(--radius); padding: 22px; }
.pill { display: inline-flex; align-items: center; gap: 6px; padding: 5px 12px; border-radius: 999px;
  background: rgba(201,162,39,.12); border: 1px solid var(--line); font-size: 12.5px; font-weight: 600; color: var(--brass-bright); }
.spinner { width: 20px; height: 20px; border-radius: 50%; border: 2.5px solid rgba(201,162,39,.25); border-top-color: var(--brass-surface); animation: spin .8s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
.toast { position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%); background: var(--raised-2);
  border: 1px solid var(--line); padding: 12px 20px; border-radius: 999px; font-size: 13.5px; z-index: 300;
  animation: toast-rise .3s var(--soft) both; box-shadow: 0 12px 30px rgba(0,0,0,.4); }
.toast.error { border-color: rgba(217,146,90,.5); color: var(--danger); }
@keyframes toast-rise { from { opacity: 0; transform: translate(-50%, 10px); } to { opacity: 1; transform: translate(-50%, 0); } }
@keyframes rise { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }

/* ---------- landing ---------- */
.landing-nav { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; max-width: 1180px; margin: 0 auto;
  padding: 26px 28px; gap: 20px; }
.brand { display: flex; align-items: center; gap: 12px; font-family: var(--display); font-weight: 600; font-size: 19px; }
.brand-link { text-align: left; transition: opacity .2s; }
.brand-link:hover { opacity: .8; }
.brand .mark { width: 32px; height: 32px; border-radius: 9px; flex: none;
  background: linear-gradient(155deg, #241d16, #100d0a 70%); border: 1px solid rgba(201,162,39,.35);
  display: grid; place-items: center; color: #E4BE4A; }
.brand .mark svg { width: 17px; height: 10px; }
.brand .mark.lg { width: 52px; height: 52px; border-radius: 14px; }
.brand .mark.lg svg { width: 28px; height: 17px; }
.brand-text { display: flex; flex-direction: column; line-height: 1.1; justify-content: center; }
.brand-text-full { display: flex; flex-direction: column; }
.brand-text-mobile { display: none; }
.brand-text small { font-family: var(--body); font-size: 10px; font-weight: 600; letter-spacing: .12em;
  text-transform: uppercase; color: var(--taupe); margin-top: 3px; }

/* Brand mark scaled down from an earlier 56px/25px treatment -- at that
   size it visually outweighed everything else in the nav (14px links,
   14.5px sign-in button), making the header feel top-heavy. Still the
   largest element in the bar, just not shouting over its neighbors. */
/* Explicit grid-column on all three children -- without it, hiding .links
   at the 860px breakpoint below removes it from grid auto-placement
   entirely, which shifts .brand into column 1 (so the logo hugs the left
   edge instead of staying centered) and crowds Sign in right next to it
   instead of the right edge. Pinning columns keeps the layout intact
   regardless of which children are hidden. */
.landing-nav .links { grid-column: 1; display: flex; align-items: center; gap: 28px; font-size: 14px; color: var(--taupe); justify-self: start; }
.landing-nav .links a:hover { color: var(--ivory); }
.landing-nav .brand { grid-column: 2; gap: 12px; justify-self: center; }
.landing-nav .brand .mark { width: 42px; height: 42px; border-radius: 12px; box-shadow: 0 6px 18px rgba(201,162,39,.18); }
.landing-nav .brand .mark svg { width: 22px; height: 14px; }
.landing-nav .brand-text { font-size: 19px; }
.landing-nav .nav-actions { grid-column: 3; justify-self: end; display: flex; align-items: center; gap: 10px; }

.theme-toggle { display: inline-flex; align-items: center; justify-content: center; width: 34px; height: 34px;
  border-radius: 50%; flex: none; background: var(--hover-tint); border: 1px solid var(--line); color: var(--taupe);
  transition: background .2s, color .2s, border-color .2s; }
.theme-toggle:hover { background: var(--hover-tint-strong); color: var(--brass-bright); border-color: var(--brass); }
.theme-toggle svg { width: 17px; height: 17px; }
.sidebar-user .theme-toggle { width: 30px; height: 30px; }
.sidebar-user .theme-toggle svg { width: 15px; height: 15px; }

.hero { max-width: 1180px; margin: 0 auto; padding: 56px 28px 36px; display: flex; flex-direction: column; align-items: center; }
.hero-head { text-align: center; max-width: 680px; margin: 0 auto; }
.hero-head .eyebrow { display: flex; align-items: center; justify-content: center; gap: 10px; }
.hero h1 { font-family: var(--display); font-weight: 400; font-size: 50px; line-height: 1.12; letter-spacing: -.01em; margin: 20px 0 22px; text-wrap: balance; }
.hero h1 em { font-style: italic; color: var(--brass-bright); }
.hero-ctas { display: flex; gap: 22px; flex-wrap: wrap; justify-content: center; align-items: center; }
/* Editorial restraint for the marketing page specifically: the primary CTA
   reads as a quiet ink pill rather than the vivid accent-colored buttons
   used everywhere else in the product -- a deliberate top-of-funnel choice,
   not a reversal of the in-app terracotta buttons (Studio/Ads Studio/plan
   cards keep those, scoped to #heroStartBtn only). Only worth doing in
   light theme -- in dark theme the page is already ink-colored, so an
   "ink pill" would vanish against its own background; dark theme keeps
   the original vivid .btn-brass look. */
[data-theme="light"] #heroStartBtn { background: var(--ivory); color: var(--ink); }
[data-theme="light"] #heroStartBtn:hover { filter: brightness(1.2); }
.btn-text-accent { background: none; border: 0; border-radius: 0; min-height: 0; padding: 0 0 3px;
  color: var(--ivory); border-bottom: 1px solid var(--line); font-weight: 600; }
.btn-text-accent:hover { color: var(--brass-bright); border-color: var(--brass-bright); }
.hero-note { margin-top: 16px; color: var(--taupe); font-size: 13px; }

/* hero visual: real garment -> catalogue-photo crossfade loop, the main event */
.hero-visual { position: relative; width: 100%; display: flex; flex-direction: column; align-items: center; gap: 14px; margin-top: 40px; }

/* Before/after reveal: a single "before" panel covers the frame, then
   swipes off to the left to reveal the Infinity Catalogue "after" result
   underneath -- replaces the earlier closet-doors hinge-opening effect. */
/* Instagram-style blurred backdrop: a heavily blurred, darkened copy of the
   CURRENT garment/result photo bleeds out from behind the frame and fades
   to transparent at the edges (the radial-gradient mask), same technique
   Instagram uses to fill letterbox space around a photo/story. This is a
   different effect from the earlier flat-color .result-glow bloom below
   (that one's modeled on sliderrevolution.com's product-slider glow, which
   has no blurred-photo layer at all) -- an EARLIER attempt at a blurred
   backdrop here read as a muddy smear and was rejected ("not good") because
   it had no fade mask and wasn't tied to the frame's rounded-rect shape; the
   mask + tighter blur radius here is what makes this version read as a soft
   photographic bleed instead. Also doubles as JS's color-sampling source
   (sampleGlowColor() in app.js reads this image's pixels to drive
   .result-glow's hue) -- no longer hidden, now rendered for both jobs. */
.result-ambient { position: absolute; inset: -26%; z-index: -3; border-radius: 54px; overflow: hidden; pointer-events: none;
  -webkit-mask-image: radial-gradient(ellipse at center, #000 42%, transparent 76%);
  mask-image: radial-gradient(ellipse at center, #000 42%, transparent 76%); }
.result-ambient img { width: 100%; height: 100%; object-fit: cover;
  filter: blur(46px) brightness(.8) saturate(1.35); transform: scale(1.15); transition: opacity .6s ease; }

/* Colored ambient bloom behind the frame (reference: sliderrevolution.com's
   product-slider glow -- a bold, flat, saturated color field bleeding from
   behind the hero product, not a soft blurred echo of the photo). Color
   comes from --glow-h/--glow-s, sampled off the current garment photo by
   sampleGlowColor() in app.js. Rounded-rect to match the frame's own
   silhouette, not an oval. */
.result-glow { position: absolute; inset: -17%; z-index: -2; border-radius: 46px;
  background: radial-gradient(ellipse at center,
    hsla(var(--glow-h, 42), var(--glow-s, 75%), 58%, .85) 0%,
    hsla(var(--glow-h, 42), var(--glow-s, 75%), 48%, .55) 38%,
    hsla(var(--glow-h, 42), var(--glow-s, 75%), 40%, .18) 62%,
    transparent 78%);
  filter: blur(6px); pointer-events: none;
  transition: background .7s ease;
  animation: glowPulse 4.5s ease-in-out infinite; }
@keyframes glowPulse { 0%, 100% { opacity: .85; transform: scale(1); } 50% { opacity: 1; transform: scale(1.035); } }
/* Borderless by design -- the frame reads as a photo floating on its own
   blurred shadow (.result-ambient below), not a bordered/framed card. No
   border, no inset hairline, no rotating shimmer arc (previously here) --
   the soft drop shadow + ambient photo-bleed carry all the visual weight. */
.result-frame { position: relative; z-index: 1; width: 100%; max-width: 440px; aspect-ratio: 3/4; border-radius: 24px;
  box-shadow:
    0 50px 90px -12px rgba(0,0,0,.65),
    0 18px 40px rgba(0,0,0,.45);
  background: var(--panel); overflow: hidden; }
.result-interior { position: absolute; inset: 0; border-radius: 24px; overflow: hidden; background: var(--mat); }
.result-interior img { width: 100%; height: 100%; object-fit: cover; }
.result-interior::after { content: ""; position: absolute; inset: 0;
  background: radial-gradient(ellipse at 50% 15%, rgba(243,236,224,.14), transparent 60%); pointer-events: none; }

/* Drag-to-compare: .result-interior (the "before" photo) sits as the base
   layer, full-frame; .result-after-clip stacks on top clipped to the
   right of --split (a 0-100% CSS var app.js updates on drag), so dragging
   reveals more or less of the Infinity Catalogue "after" result against
   the untouched upload underneath. Replaces the old timed swipe-reveal --
   letting the visitor control the compare point is a stronger "try the
   product before signing up" moment than a passive auto-swipe. */
.result-frame { cursor: ew-resize; touch-action: none; }
/* will-change promotes this to its own compositing layer so a clip-path
   change on drag is a GPU-only composite, not a repaint that has to run
   back through the blurred .result-ambient/.result-glow layers underneath
   (46px and 6px blur radii -- expensive, and desktop's 440px frame is ~3x
   the pixel area of mobile's 320px cap, which is why the same unpromoted
   repaint read as janky on desktop but not on mobile). */
.result-after-clip { position: absolute; inset: 0; z-index: 2; border-radius: 24px; overflow: hidden;
  clip-path: inset(0 0 0 var(--split, 50%)); will-change: clip-path; }
.result-after-clip img { width: 100%; height: 100%; object-fit: cover; }
.compare-handle { position: absolute; top: 0; bottom: 0; left: var(--split, 50%); z-index: 3; width: 2px;
  background: rgba(255,255,255,.85); transform: translateX(-1px); pointer-events: none; }
.compare-knob { position: absolute; top: 50%; left: 50%; width: 42px; height: 42px; border-radius: 50%; background: #fff;
  transform: translate(-50%,-50%); display: grid; place-items: center; box-shadow: 0 8px 24px rgba(0,0,0,.4); }
.compare-knob svg { width: 17px; height: 17px; color: #2B1D18; }

.hv-badge { position: absolute; top: 18px; z-index: 5; padding: 8px 18px; border-radius: 999px; font-size: 13px;
  font-weight: 700; letter-spacing: .07em; text-transform: uppercase; backdrop-filter: blur(8px);
  box-shadow: 0 8px 20px rgba(0,0,0,.35); pointer-events: none; }
.hv-badge.upload { background: rgba(20,17,15,.65); border: 1.5px solid rgba(243,236,224,.4); color: #F3ECE0; }
.hv-badge.output { background: rgba(201,162,39,.95); border: 1.5px solid var(--brass-bright); color: #1A1407; }
.hv-tag-before { left: 18px; } .hv-tag-after { right: 18px; }

/* Floating fidelity callouts, Kumo-reference-inspired (dribbble.com/shots/26971799):
   small cards drifting around the hero product instead of sitting flat on
   it. Outer element bobs continuously (animation); inner element handles
   the show/hide fade so the two don't fight over the transform property. */
.float-badge { position: absolute; z-index: 4; pointer-events: none; animation: floatBob 3.4s ease-in-out infinite; }
.float-badge-inner { display: flex; align-items: center; gap: 9px; padding: 10px 18px 10px 10px; border-radius: 999px;
  background: var(--raised); border: 1.5px solid rgba(201,162,39,.3); font-size: 14px; font-weight: 700; color: var(--ivory);
  letter-spacing: .01em; box-shadow: 0 16px 36px rgba(0,0,0,.5), inset 0 1px 0 rgba(255,255,255,.06);
  opacity: 0; transform: scale(.82) translateY(10px);
  transition: opacity .5s ease, transform .5s cubic-bezier(.34,1.56,.64,1); white-space: nowrap; }
.float-badge-inner svg { width: 13px; height: 13px; color: var(--sage); flex: none; }
.float-badge-inner span.check-dot { display: grid; place-items: center; width: 22px; height: 22px; border-radius: 50%;
  background: rgba(127,162,148,.18); flex: none; }
.float-badge.show .float-badge-inner { opacity: 1; transform: scale(1) translateY(0); }
.float-badge-1 { top: 10%; left: -9%; animation-delay: .15s; }
.float-badge-2 { top: 46%; right: -11%; animation-delay: .65s; }
.float-badge-3 { bottom: 12%; left: -7%; animation-delay: .35s; }
@keyframes floatBob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-9px); } }
@media (max-width: 680px) { .float-badge { display: none; } }

/* Thumbnail rail under the compare frame -- lets a visitor jump straight
   to the garment type closest to their own catalogue instead of only
   seeing whichever example the page happened to load with. */
.hero-rail { display: flex; gap: 10px; margin-top: 4px; }
.hero-thumb { width: 52px; height: 68px; border-radius: 10px; overflow: hidden; flex: none;
  border: 2px solid transparent; opacity: .5; transition: opacity .25s, border-color .25s; }
.hero-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.hero-thumb.active { opacity: 1; border-color: var(--brass-surface); }
.hero-thumb:hover { opacity: .85; }
.hero-rail-hint { color: var(--taupe); font-size: 12px; text-align: center; }

.hero-scroll { display: flex; flex-direction: column; align-items: center; gap: 6px; margin-top: 36px;
  color: var(--taupe); font-size: 12.5px; letter-spacing: .08em; text-transform: uppercase; font-weight: 600; }
.hero-scroll:hover { color: var(--brass-bright); }
.hero-scroll svg { animation: scrollBounce 1.8s ease-in-out infinite; }
@keyframes scrollBounce { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(6px); } }

.mark-draw { stroke-dasharray: 480; stroke-dashoffset: 480; animation: drawMark 1.4s ease forwards; }
@keyframes drawMark { to { stroke-dashoffset: 0; } }

/* Editorial band: wraps the steps + stats sections in a deliberately dark
   ink section -- see --band-bg's comment above for why this reads the
   same in dark theme and only creates contrast in light theme. */
.editorial-band { background: var(--band-bg); padding: 88px 28px; }
.workflow { max-width: 1180px; margin: 0 auto; padding: 0; }
.workflow h2 { font-family: var(--display); font-weight: 400; font-size: 32px; text-align: center; margin-bottom: 10px; color: var(--band-text); }
.workflow .sub { text-align: center; color: var(--band-muted); margin-bottom: 48px; }
.workflow-steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: 48px;
  border-top: 1px solid rgba(243,236,224,.14); padding-top: 44px; }
.wstep { position: relative; }
.wstep .num { font-family: var(--display); font-style: italic; font-weight: 300; font-size: 42px; line-height: 1;
  color: var(--brass-surface-bright); margin-bottom: 16px; }
.wstep h3 { font-family: var(--display); font-weight: 500; font-size: 19px; margin-bottom: 8px; color: var(--band-text); }
.wstep p { color: var(--band-muted); font-size: 13.8px; line-height: 1.7; }

.features { max-width: 1180px; margin: 64px auto 0; padding: 0; display: grid; grid-template-columns: repeat(4, 1fr); }
.feature { padding: 0 20px; text-align: center; border-left: 1px solid rgba(243,236,224,.14); }
.feature:first-child { border-left: 0; }
.feature .fnum { font-family: var(--display); font-weight: 400; font-size: 32px; color: var(--band-text); }
.feature .flabel { font-size: 11.5px; letter-spacing: .04em; color: var(--band-muted); margin-top: 6px; }

.pricing-preview { max-width: 1180px; margin: 70px auto; padding: 0 28px; text-align: center; }
.pricing-preview h2, .contact-preview h2 { font-family: var(--display); font-weight: 500; font-size: 32px; margin-bottom: 10px; }
.pricing-preview .sub, .contact-preview .sub { color: var(--taupe); margin-bottom: 36px; }
.pricing-preview .plans-grid { text-align: left; }

.contact-preview { max-width: 640px; margin: 70px auto; padding: 0 28px; text-align: center; }
.contact-info { display: flex; align-items: center; justify-content: center; gap: 12px; margin-bottom: 24px; font-size: 15px; }
.contact-info a { color: var(--ivory); font-weight: 600; }
.contact-info a:hover { color: var(--brass-bright); }
.contact-info span { color: var(--taupe); }

.landing-footer { text-align: center; color: var(--taupe); font-size: 12.5px; padding: 40px 28px 50px; }
.footer-highlight { display: flex; justify-content: center; margin-top: 16px; }
.footer-highlight span { display: inline-block; padding: 9px 20px; border-radius: 999px;
  background: linear-gradient(90deg, rgba(201,162,39,.16), rgba(240,203,90,.22), rgba(201,162,39,.16));
  border: 1px solid rgba(201,162,39,.35); color: var(--brass-bright); font-weight: 700; letter-spacing: .02em; font-size: 12.5px; }

/* ---------- bug report ---------- */
.bug-fab { position: fixed; right: 22px; bottom: 22px; z-index: 150; width: 50px; height: 50px; border-radius: 50%;
  background: var(--panel); border: 1.5px solid var(--line-soft); color: var(--brass-bright);
  display: grid; place-items: center; box-shadow: 0 10px 28px rgba(0,0,0,.45); transition: transform .2s, border-color .2s; }
.bug-fab:hover { transform: translateY(-2px); border-color: var(--brass); }
.bug-fab svg { width: 22px; height: 22px; }
#bugReportModal h1 { font-family: var(--display); font-weight: 500; font-size: 22px; margin-bottom: 8px; }
#bugReportModal .sub { color: var(--taupe); font-size: 13.5px; margin-bottom: 20px; }

/* ---------- contact modal ---------- */
.modal-overlay { position: fixed; inset: 0; background: rgba(12,10,8,.72); backdrop-filter: blur(3px);
  display: grid; place-items: center; z-index: 200; padding: 24px; animation: fade-in .25s ease both; }
.modal-card { width: 100%; max-width: 420px; position: relative; animation: rise .35s var(--soft) both; }
.modal-close { position: absolute; top: 14px; right: 14px; width: 32px; height: 32px; border-radius: 50%;
  background: var(--hover-tint); border: 1px solid var(--line-soft); display: grid; place-items: center; color: var(--taupe); }
.modal-close:hover { color: var(--ivory); }
.step-dots { display: flex; justify-content: center; gap: 8px; margin-bottom: 22px; }
.step-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--line); transition: background .25s, width .25s; }
.step-dot.active { background: var(--brass-surface); width: 20px; border-radius: 4px; }
.step-dot.done { background: var(--brass-dim); }
.contact-step h1 { font-family: var(--display); font-weight: 500; font-size: 22px; text-align: center; margin-bottom: 18px; }
.contact-step textarea { width: 100%; min-height: 110px; padding: 12px 14px; border-radius: 10px; background: var(--raised);
  border: 1px solid var(--line-soft); color: var(--ivory); resize: vertical; font-family: inherit; }
.contact-step textarea:focus { border-color: var(--brass); outline: none; }
.contact-nav { display: flex; gap: 10px; margin-top: 4px; }
.contact-nav .btn { flex: 1; }

@media (max-width: 860px) {
  .hero h1 { font-size: 32px; }
  .editorial-band { padding: 56px 24px; }
  .workflow-steps { grid-template-columns: 1fr; border-top: 0; padding-top: 0; gap: 32px; }
  .wstep { border-top: 1px solid rgba(243,236,224,.14); padding-top: 28px; }
  .wstep:first-child { border-top: 0; padding-top: 0; }
  .features { grid-template-columns: repeat(2,1fr); gap: 28px 0; }
  .feature:nth-child(2n+1) { border-left: 0; }
  .feature:nth-child(n+3) { border-top: 1px solid rgba(243,236,224,.14); padding-top: 20px; }
  .landing-nav .links { display: none; }
  /* With .links hidden, its 1fr track still reserved equal width against
     .nav-actions' 1fr track -- squeezing "Sign in" into a column narrower
     than its own content, which wrapped the label onto two lines. auto
     lets the empty first column collapse and nav-actions size to content. */
  .landing-nav { grid-template-columns: auto 1fr auto; }
  /* "Infinity Catalogue" + "by Infinity Closet" stacked under the mark
     read as crowded at this width -- one line, brand name only. */
  .landing-nav .brand-text-full { display: none; }
  .landing-nav .brand-text-mobile { display: block; font-family: var(--display); font-weight: 600; }
  .result-frame { max-width: 320px; }
}

/* ---------- auth ---------- */
.auth-wrap { min-height: 100vh; display: grid; place-items: center; padding: 24px; }
.auth-card { width: 100%; max-width: 400px; position: relative; animation: rise .4s var(--soft) both; }
.auth-card h1 { font-family: var(--display); font-weight: 500; font-size: 26px; text-align: center; margin-bottom: 6px; }
.auth-card .sub { text-align: center; color: var(--taupe); font-size: 14px; margin-bottom: 26px; }
.field { margin-bottom: 14px; }
.field label { display: block; font-size: 12.5px; color: var(--taupe); margin-bottom: 6px; }
.field input { width: 100%; min-height: 46px; padding: 0 14px; border-radius: 10px; background: var(--raised);
  border: 1px solid var(--line-soft); color: var(--ivory); }
.field input:focus { border-color: var(--brass); outline: none; }
.field textarea { width: 100%; min-height: 110px; padding: 12px 14px; border-radius: 10px; background: var(--raised);
  border: 1px solid var(--line-soft); color: var(--ivory); resize: vertical; }
.field textarea:focus { border-color: var(--brass); outline: none; }
.field input[type="file"] { min-height: unset; padding: 10px 14px; }
.auth-divider { display: flex; align-items: center; gap: 12px; margin: 18px 0; color: var(--taupe); font-size: 12.5px; }
.auth-divider::before, .auth-divider::after { content: ""; flex: 1; height: 1px; background: var(--line-soft); }
.google-btn { display: flex; align-items: center; justify-content: center; gap: 10px; width: 100%; min-height: 46px;
  background: #F3ECE0; color: #1A1407; border-radius: 10px; font-weight: 600; font-size: 14px; }
.auth-switch { text-align: center; margin-top: 18px; font-size: 13.5px; color: var(--taupe); }
.auth-switch button { color: var(--brass); font-weight: 600; }

/* ---------- app shell ---------- */
.shell { display: grid; grid-template-columns: 240px 1fr; min-height: 100vh; }
.sidebar { background: var(--panel); border-right: 1px solid var(--line-soft); padding: 22px 16px; display: flex; flex-direction: column; }
.sidebar .brand { padding: 6px 8px 24px; }
.navlist { display: grid; align-content: start; gap: 2px; flex: 1; }
.navitem { display: flex; align-items: center; gap: 12px; padding: 11px 14px; border-radius: 10px; font-size: 14px; font-weight: 500;
  color: var(--taupe); transition: background .2s, color .2s; }
.navitem svg { width: 18px; height: 18px; flex: none; }
.navitem:hover { background: var(--hover-tint-soft); color: var(--ivory); }
.navitem.active { background: rgba(201,162,39,.12); color: var(--brass-bright); }
.sidebar-credits { margin-top: auto; padding: 14px; border-radius: 12px; background: var(--raised); border: 1px solid var(--line-soft); }
.sidebar-credits .n { font-family: var(--display); font-size: 24px; color: var(--brass-bright); }
.sidebar-credits .l { font-size: 11.5px; color: var(--taupe); text-transform: uppercase; letter-spacing: .1em; margin-bottom: 2px; }
.sidebar-user { display: flex; align-items: center; gap: 10px; padding: 10px 8px; margin-top: 10px; font-size: 13px; }
.avatar { width: 30px; height: 30px; border-radius: 50%; background: var(--raised-2); display: grid; place-items: center;
  font-weight: 700; font-size: 12px; color: var(--brass-bright); flex: none; }
.sidebar-user .logout { margin-left: auto; color: var(--taupe); font-size: 12px; }

.main { padding: 32px 40px 60px; max-width: 1100px; }
.page-head { margin-bottom: 26px; }
.page-head h1 { font-family: var(--display); font-weight: 500; font-size: 28px; }
.page-head .sub { color: var(--taupe); font-size: 14.5px; margin-top: 4px; }

/* ---------- upload / new shoot ---------- */
.upload-grid { display: grid; grid-template-columns: 1.6fr 1fr; gap: 24px; align-items: start; }
.model-type-row { display: flex; gap: 10px; margin-bottom: 16px; align-items: flex-start; }
.model-type-option { flex: 1; display: flex; flex-direction: column; gap: 6px; }
.model-type-btn { width: 100%; }
.model-type-btn.selected { background: var(--brass-surface); color: var(--on-brass); border-color: var(--brass-surface); }
.model-type-hint { font-size: 12px; line-height: 1.3; color: var(--taupe); text-align: center; padding: 0 4px; }
.dropzone.is-locked { opacity: .45; pointer-events: none; }
.dropzone { border: 1.5px dashed var(--line); border-radius: var(--radius); padding: 40px 24px; text-align: center;
  background: var(--panel); cursor: pointer; transition: border-color .2s, background .2s; }
.dropzone:hover, .dropzone.drag { border-color: var(--brass); background: rgba(201,162,39,.05); }
.dropzone svg { width: 36px; height: 36px; color: var(--brass); margin: 0 auto 12px; }
.dropzone h3 { font-family: var(--display); font-weight: 500; font-size: 18px; margin-bottom: 6px; }
.dropzone p { color: var(--taupe); font-size: 13.5px; }
.dropzone input[type=file] { display: none; }
.preview-wrap { margin-top: 18px; position: relative; }
.preview-wrap img { width: 100%; border-radius: 12px; border: 1px solid var(--line-soft); max-height: 420px; object-fit: contain; background: var(--mat); }
.preview-wrap .remove { position: absolute; top: 10px; right: 10px; width: 32px; height: 32px; border-radius: 50%;
  background: rgba(20,17,15,.8); border: 1px solid var(--line); display: grid; place-items: center; }

.examples h3 { font-family: var(--display); font-weight: 500; font-size: 16px; margin-bottom: 12px; }
/* Teaching carousel: one card visible at a time instead of every card
   stacked at once competing with the actual upload action for attention.
   All cards occupy the same grid cell (grid-row/column: 1) -- a well-known
   CSS stacking trick where the shared track auto-sizes to the TALLEST
   card's natural height, so swapping between an image card, a short
   text-only card, and a longer-wrapping one (different viewport widths
   wrap differently) never clips or jumps -- no fixed pixel height to
   guess, unlike an earlier version of this that used position:absolute
   and clipped longer cards at some widths. */
.example-carousel { display: grid; margin-bottom: 14px; }
.example-card { display: flex; gap: 12px; padding: 12px; border-radius: 12px; background: var(--panel); border: 1px solid var(--line-soft);
  grid-row: 1; grid-column: 1; opacity: 0; pointer-events: none; transition: opacity .5s var(--soft); }
.example-card.is-active { opacity: 1; pointer-events: auto; }
.example-card .tag { flex: none; width: 26px; height: 26px; border-radius: 50%; display: grid; place-items: center; font-size: 14px; font-weight: 700; }
.example-card.good .tag { background: rgba(127,162,148,.18); color: var(--sage); }
.example-card.bad .tag { background: rgba(217,146,90,.18); color: var(--danger); }
.example-card b { font-size: 13.5px; display: block; margin-bottom: 2px; }
.example-card span { font-size: 12.5px; color: var(--taupe); line-height: 1.5; }
.example-card.with-image img { flex: none; width: 56px; height: 110px; object-fit: contain; border-radius: 8px; border: 1px solid var(--line-soft); background: #fff; }
.example-dots { display: flex; justify-content: center; gap: 8px; }
.example-dots .dot { width: 7px; height: 7px; border-radius: 50%; background: var(--line); transition: background .25s, width .25s; }
.example-dots .dot.is-active { background: var(--brass-surface); width: 20px; border-radius: 4px; }

/* Ads Studio -- scoped to this view only so Studio's shared .dropzone /
   .examples styling is untouched. Dropzone gets more visual weight (it's
   the primary action), and "What you'll get" reads as a distinct card on
   the right rather than a loose list continuing the page. */
#view-ads-new .upload-grid { grid-template-columns: 1.6fr 1fr; }
#view-ads-new .dropzone { padding: 56px 28px; border-width: 2px; }
#view-ads-new .dropzone svg { width: 44px; height: 44px; margin-bottom: 14px; }
#view-ads-new .dropzone h3 { font-size: 21px; }
#view-ads-new .dropzone p { font-size: 14px; }
#view-ads-new .dropzone.is-locked { opacity: .72; }
#view-ads-new .examples { background: var(--panel); border: 1px solid var(--line-soft);
  border-radius: var(--radius); padding: 20px; }

.generate-bar { margin-top: 22px; display: flex; align-items: center; gap: 16px; }
.generate-bar .cost { font-size: 13px; color: var(--taupe); }
.training-consent-row { display: flex; align-items: flex-start; gap: 9px; margin-top: 16px; font-size: 13px; color: var(--taupe); cursor: pointer; line-height: 1.5; }
.training-consent-row input { margin-top: 2px; accent-color: var(--brass); flex: none; }
.training-consent-row a { color: var(--brass-bright); text-decoration: underline; }

/* ---------- processing ---------- */
.processing { display: grid; place-items: center; min-height: 420px; text-align: center; gap: 24px; }
/* Infinity-loop spinner: a dim full track plus a bright "chasing light"
   segment that travels the loop, instead of a generic ring -- reinforces
   the brand mark even in a loading state. 480 is this path's approximate
   total length (same figure used for the draw-on animation elsewhere). */
.infinity-spinner { filter: drop-shadow(0 0 18px rgba(201,162,39,.5)); }
.infinity-spinner .is-track { stroke: rgba(201,162,39,.22); }
.infinity-spinner .is-sweep { stroke: var(--brass-surface-bright); stroke-dasharray: 90 390; animation: infinitySweep 1.6s linear infinite; }
@keyframes infinitySweep { to { stroke-dashoffset: -480; } }
.processing h3 { font-family: var(--display); font-weight: 500; font-size: 23px; }
.processing p { color: var(--taupe); font-size: 14px; max-width: 360px; line-height: 1.6; }
.processing-timer { font-family: var(--display); font-weight: 500; font-size: 20px; color: var(--brass-bright); font-variant-numeric: tabular-nums; }

/* ---------- result ---------- */
.result-grid { display: grid; grid-template-columns: 1fr .9fr; gap: 28px; align-items: start; }
.result-img-wrap { border-radius: var(--radius); overflow: hidden; border: 1px solid var(--line-soft); background: var(--mat); }
.result-img-wrap img { width: 100%; }
.result-disclaimer { margin-top: 12px; font-size: 13px; line-height: 1.5; color: var(--taupe); }
.result-disclaimer a { color: var(--brass-bright); text-decoration: underline; }
.ratio-list { display: grid; gap: 8px; margin: 14px 0 20px; }
.ratio-opt { display: flex; align-items: center; justify-content: space-between; padding: 12px 14px; border-radius: 10px;
  border: 1px solid var(--line-soft); background: var(--panel); font-size: 13.5px; }
.ratio-opt input { accent-color: var(--brass); }
.ratio-opt .dims { color: var(--taupe); font-size: 12px; }
.result-actions { display: grid; gap: 10px; }

/* ---------- artifacts ---------- */
.artifacts-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 20px; }
.gallery { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 16px; }
.gcard { border-radius: 12px; overflow: hidden; border: 1px solid var(--line-soft); background: var(--panel); position: relative; }
.gcard img { width: 100%; aspect-ratio: 3/4; object-fit: cover; }
.gcard .gmeta { padding: 10px 12px; }
.gcard .gmeta b { font-size: 12.5px; text-transform: capitalize; }
.gcard .gmeta span { display: block; font-size: 11px; color: var(--taupe); margin-top: 2px; }
.gcard .gdl { position: absolute; top: 8px; right: 8px; width: 32px; height: 32px; border-radius: 50%; background: rgba(20,17,15,.75);
  border: 1px solid var(--line); display: grid; place-items: center; }
.gcard .gsel { position: absolute; top: 8px; left: 8px; width: 24px; height: 24px; border-radius: 6px;
  background: rgba(20,17,15,.75); border: 1.5px solid rgba(243,236,224,.7); cursor: pointer; z-index: 2; }
.gcard .gsel svg { display: none; width: 16px; height: 16px; margin: 3px; color: var(--ivory); }
.gcard.is-selected { outline: 2px solid var(--brass); outline-offset: -2px; }
.gcard.is-selected .gsel { background: var(--brass); border-color: var(--brass); }
.gcard.is-selected .gsel svg { display: block; }
.motion-preset-card { max-width: 480px; }
.motion-preset-grid { display: grid; grid-template-columns: 1fr; gap: 10px; margin-top: 18px; }
.motion-preset-btn { width: 100%; display: flex; align-items: center; gap: 14px; text-align: left;
  padding: 12px 14px; border-radius: 10px; background: transparent; border: 1px solid var(--line);
  color: var(--ivory); cursor: pointer; font-family: inherit; transition: background .15s, border-color .15s; }
.motion-preset-btn:hover { background: var(--hover-tint); border-color: var(--brass-dim); }
.motion-preset-btn .mp-icon { flex: 0 0 auto; width: 38px; height: 38px; border-radius: 50%; background: var(--raised);
  display: grid; place-items: center; color: var(--brass); }
.motion-preset-btn .mp-icon svg { width: 19px; height: 19px; }
.motion-preset-btn .mp-text { display: flex; flex-direction: column; gap: 3px; }
.motion-preset-btn .mp-text b { font-size: 13.5px; }
.motion-preset-btn .mp-text span { font-size: 12px; color: var(--taupe); line-height: 1.4; }

/* ---------- videos (history) ---------- */
.video-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 16px; }
.video-card { border-radius: 12px; overflow: hidden; border: 1px solid var(--line-soft); background: var(--panel); }
.video-card-head { padding: 10px 12px; display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.video-card-head b { font-size: 12.5px; }
.video-card-head span { font-size: 11px; color: var(--taupe); white-space: nowrap; }
.video-card-body { padding: 0 12px 12px; display: flex; flex-direction: column; gap: 10px; align-items: center; }
.video-card-body video { width: 100%; aspect-ratio: 9/16; max-height: 420px; border-radius: 8px; background: #000; }
.video-card-body .btn { width: 100%; }
.video-status { width: 100%; padding: 30px 10px; text-align: center; font-size: 13px; color: var(--taupe);
  background: var(--raised); border-radius: 8px; }
.video-status-error { color: var(--danger); }

.empty-state { text-align: center; padding: 70px 20px; color: var(--taupe); }
.empty-state svg { width: 44px; height: 44px; margin: 0 auto 14px; color: var(--brass-dim); }

/* ---------- creative engine for meta ads ---------- */
.ad-pack-credits-bar { display: flex; align-items: center; gap: 14px; padding: 14px 16px; margin-bottom: 20px;
  border-radius: 12px; background: var(--raised); border: 1px solid var(--line-soft); }
.ad-pack-credits-bar .l { font-size: 11.5px; color: var(--taupe); text-transform: uppercase; letter-spacing: .1em; }
.ad-pack-credits-bar .n { font-family: var(--display); font-size: 24px; color: var(--brass-bright); }
.ad-pack-credits-bar .btn { margin-left: auto; }
.ad-pack-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 18px; }
.ad-pack-card { border-radius: var(--radius); overflow: hidden; border: 1px solid var(--line-soft); background: var(--panel); }
.ad-pack-card img { width: 100%; aspect-ratio: 4/5; object-fit: cover; display: block; }
.ad-pack-card .apc-meta { padding: 12px 14px; }
.ad-pack-card .apc-meta b { font-size: 13.5px; display: block; margin-bottom: 8px; }
.ad-pack-card .apc-ratios { display: flex; gap: 6px; flex-wrap: wrap; }
.ad-pack-card .apc-ratios button { display: inline-flex; align-items: center; gap: 6px;
  font-size: 11.5px; padding: 5px 10px; border-radius: 8px; border: 1px solid var(--line-soft);
  background: var(--raised); color: var(--ivory); cursor: pointer; }
.ad-pack-card .apc-ratios button svg { width: 13px; height: 13px; flex: none; color: var(--brass-bright); }
.ad-pack-card .apc-ratios button:hover { border-color: var(--brass); color: var(--brass-bright); }

/* ---------- pricing ---------- */
.plans-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; margin-top: 10px; }
.plan-card { border-radius: var(--radius); border: 1px solid var(--line-soft); background: var(--panel); padding: 24px; display: flex; flex-direction: column; }
.plan-card.featured { border-color: var(--brass); box-shadow: 0 0 0 1px var(--brass), 0 20px 40px rgba(201,162,39,.08); }
.plan-card .pname { font-family: var(--display); font-weight: 500; font-size: 19px; margin-bottom: 4px; }
.plan-card .pprice { font-family: var(--display); font-size: 32px; margin: 10px 0 4px; }
.plan-card .pprice span { font-size: 13px; color: var(--taupe); font-family: var(--body); }
.plan-card .pcredits { color: var(--brass-bright); font-size: 13.5px; font-weight: 600; margin-bottom: 16px; }
.plan-card ul { list-style: none; padding: 0; margin: 0 0 20px; display: grid; gap: 9px; font-size: 13px; color: var(--taupe); }
.plan-card li::before { content: "✓ "; color: var(--sage); }

/* ---------- privacy / consent ---------- */
.consent-grid { display: grid; gap: 16px; max-width: 720px; margin-top: 10px; }
.consent-card h3 { font-family: var(--display); font-weight: 500; font-size: 16px; margin-bottom: 6px; }
.consent-card p { color: var(--taupe); font-size: 13.5px; line-height: 1.6; margin: 0; }
.consent-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 20px; }
.toggle { position: relative; display: inline-block; width: 44px; height: 26px; flex: none; cursor: pointer; }
.toggle input { position: absolute; opacity: 0; width: 100%; height: 100%; margin: 0; cursor: pointer; z-index: 1; }
.toggle-track { position: absolute; inset: 0; border-radius: 999px; background: var(--raised); border: 1.5px solid var(--line-soft); transition: background .2s, border-color .2s; }
.toggle-track::after { content: ""; position: absolute; top: 2px; left: 2px; width: 19px; height: 19px; border-radius: 50%; background: var(--taupe); transition: transform .2s, background .2s; }
.toggle input:checked + .toggle-track { background: rgba(201,162,39,.22); border-color: var(--brass); }
.toggle input:checked + .toggle-track::after { transform: translateX(18px); background: var(--brass-surface-bright); }

@media (max-width: 920px) {
  /* Sidebar becomes a horizontal top bar instead of vanishing -- it held
     the ONLY way to reach Studio/Artifacts/Plans & Billing/Privacy, so
     hiding it with nothing in its place (the previous rule) made the whole
     app unnavigable below this width, not just Privacy specifically. */
  .shell { grid-template-columns: 1fr; grid-template-rows: auto 1fr; }
  .sidebar { flex-direction: row; flex-wrap: nowrap; align-items: center; gap: 10px;
    padding: 10px 12px; overflow-x: auto; border-right: none; border-bottom: 1px solid var(--line-soft); }
  .sidebar .brand { padding: 0; flex: none; }
  .sidebar .brand-label { display: none; } /* keep the mark as a compact home link, drop the label to save width */
  .navlist { display: flex; flex-direction: row; flex-wrap: nowrap; flex: none; gap: 4px; }
  .navitem { flex: none; white-space: nowrap; padding: 8px 12px; font-size: 13px; }
  .sidebar-credits { flex: none; margin-top: 0; padding: 8px 12px; white-space: nowrap; }
  .sidebar-credits .l { display: none; }
  .sidebar-credits .n { font-size: 16px; }
  .sidebar-user { flex: none; margin-top: 0; padding: 0; }
  .sidebar-user span { display: none; } /* name dropped to save width; avatar + sign out stay */
  .upload-grid, .result-grid { grid-template-columns: 1fr; }
  .plans-grid { grid-template-columns: 1fr; }
  /* Ads Studio keeps its 2-column layout (dropzone left, "What you'll
     get" right) through this narrower top-bar layout -- only true
     phone widths (see the 640px query below) force it to stack. */
  #view-ads-new .upload-grid { grid-template-columns: 1.6fr 1fr; }
}

@media (max-width: 640px) {
  #view-ads-new .upload-grid { grid-template-columns: 1fr; }
}
