/* ===== SnipIA landing =====
   The product's visual system (black, ivory, gold, Inter Tight, the cut) in a
   build-free stylesheet. Token values are copied from
   frontend/src/styles/tokens.css: keep them in step by hand.
   Sections below the hero are added in page order; each block is headed. */

:root {
  --black: #000000;
  --ivory: #f2efe9;
  --stone: #8f897f;
  --gold: #d9b27a;
  --graphite: #1a1816;
  --line: #2b2722;

  --display-font: 'Inter Tight', 'Inter', system-ui, sans-serif;
  --text-font: 'Inter', system-ui, sans-serif;
  --step-0: 15px;
  --step-1: 18px;
  --step-2: 28px;
  --step-3: 44px;
  --step-4: 72px;

  --ease: cubic-bezier(.2, .9, .2, 1);
  --gutter: clamp(16px, 5vw, 80px);
  --measure: 62ch;
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body { margin: 0; background: var(--black); color: var(--ivory); font-family: var(--text-font); font-size: var(--step-0); line-height: 1.5; -webkit-font-smoothing: antialiased; overflow-x: hidden; }
a { color: inherit; text-decoration: none; }
img, video { display: block; max-width: 100%; }
h1, h2, h3 { margin: 0; font-family: var(--display-font); font-weight: 800; letter-spacing: -.035em; line-height: 1.02; }
:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }

/* ===== wordmark: Snip in ivory, IA in gold ===== */
.wordmark { font-family: var(--display-font); font-weight: 800; font-size: 22px; letter-spacing: -.03em; color: var(--ivory); }
.wordmark span { color: var(--gold); }

/* ===== nav ===== */
.nav { position: fixed; inset: 0 0 auto; z-index: 50; display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 14px var(--gutter); background: linear-gradient(rgba(0,0,0,.9), rgba(0,0,0,0)); }
.nav .wordmark { display: inline-flex; align-items: center; min-height: 44px; }
.nav-links { display: flex; align-items: center; gap: 28px; font-size: 15px; color: var(--stone); }
.nav-links a:not(.btn) { display: inline-flex; align-items: center; min-height: 44px; transition: color .2s; }
.nav-links a:not(.btn):hover { color: var(--ivory); }

/* ===== buttons (as the product's site: gold is the primary action) ===== */
.btn { display: inline-flex; align-items: center; justify-content: center; min-height: 48px; padding: 0 28px; border: 1px solid var(--gold); border-radius: 999px; background: var(--gold); color: var(--black); font: 600 16px/1 var(--text-font); cursor: pointer; transition: transform .2s var(--ease), background .2s, border-color .2s; }
.btn:hover { background: #e6c48f; }
.btn:active { transform: scale(.97); }
.btn-ghost { border-color: var(--line); background: none; color: var(--ivory); font-weight: 500; }
.btn-ghost:hover { border-color: var(--ivory); background: none; }
.btn-small { min-height: 44px; padding: 0 20px; font-size: 14px; }

/* ===== layout ===== */
.section { position: relative; padding: 0 var(--gutter); scroll-margin-top: 72px; }
.section:empty { padding: 0; }

/* ===== 1. hero ===== */
/* clip, not hidden: the brand's off-stage layers must not widen the page, and the hero must not become a scroll container */
.hero { position: relative; overflow-x: clip; display: flex; flex-direction: column; justify-content: center; min-height: 100vh; min-height: 100svh; padding: 120px var(--gutter) 96px; }
.hero-inner { width: 100%; max-width: 1240px; margin: 0 auto; }
.tagline { margin: 0; margin-top: clamp(20px, 3vw, 36px); color: var(--ivory); font-family: var(--display-font); font-weight: 800; font-size: clamp(21px, 4.2vw, 52px); letter-spacing: -.03em; line-height: 1.1; }
.lead { margin: 20px 0 0; max-width: 46ch; color: var(--stone); font-size: clamp(16px, 1.6vw, 20px); line-height: 1.55; }
.cta-row { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 36px; }

/* ===== the brand transformation (js/brand.js sets data-stage) =====
   The h1 says "SnipIA" to everyone; .brand-word is its visual copy. The stem
   (Peluquer/Barber → Snip) and the low part (ía → IA) are stacked in grids;
   the stem is right-aligned and clipped at its right edge, which is the cut,
   so the old stem slides into it and the new one comes out of it. Stage
   'done' is the resting state and the markup's, so without JavaScript or
   with reduced motion it simply reads SnipIA. */
.brand { --glide: cubic-bezier(.5, 0, .15, 1); /* eases in and out, so "Snip" and the "IA" glide instead of jumping */
  font-size: clamp(54px, 17vw, 184px); line-height: .95; letter-spacing: -.045em; white-space: nowrap; }
.brand-word { display: inline-flex; align-items: baseline; }
.brand-stem, .brand-low { position: relative; display: inline-grid; }
.brand-stem { grid-template-columns: minmax(0, 1fr); justify-items: end; clip-path: inset(-.4em 0 -.4em -3em); transition: width .6s var(--glide) .2s; }
.brand-low { justify-items: start; padding-right: .04em; }
.brand-stem > span, .brand-ia-low, .brand-ia { grid-area: 1 / 1; }
.brand-new { color: var(--ivory); }
.brand-ia { color: var(--gold); }
.brand-old, .brand-ia-low { display: none; color: var(--ivory); }
.brand-blade { position: absolute; left: -.03em; top: -.06em; bottom: -.16em; width: max(2px, .035em); background: linear-gradient(180deg, transparent, var(--gold) 14%, #fff3dc 50%, var(--gold) 86%, transparent); box-shadow: 0 0 22px rgba(217, 178, 122, .8); transform: rotate(9deg) scaleY(0); transform-origin: center top; opacity: 0; pointer-events: none; }

/* every stage before 'done' shows the start word's layers */
.brand:not([data-stage="done"]) .brand-old, .brand:not([data-stage="done"]) .brand-ia-low { display: block; }
.brand[data-stage="word"] .brand-new, .brand[data-stage="cut"] .brand-new, .brand[data-stage="lift"] .brand-new { transform: translateX(110%); }
.brand[data-stage="word"] .brand-ia, .brand[data-stage="cut"] .brand-ia { opacity: 0; transform: translateY(.3em); }
/* cut: the blade crosses just before "ía" and leaves the cut open */
.brand[data-stage="cut"] .brand-low { transform: translate(.06em, .03em); transition: transform .45s var(--ease) .15s; }
.brand[data-stage="cut"] .brand-blade, .brand[data-stage="lift"] .brand-blade { animation: brand-blade .7s var(--ease) both; }
/* lift: "ía" rises and turns into a gold "IA" */
.brand[data-stage="lift"] .brand-low { transform: translate(.06em, -.05em); transition: transform .5s var(--ease); }
.brand[data-stage="lift"] .brand-ia-low { opacity: 0; transform: translateY(-.4em); transition: opacity .3s ease, transform .5s var(--ease); }
.brand[data-stage="lift"] .brand-ia { opacity: 1; transform: none; transition: opacity .35s ease .1s, transform .55s var(--ease) .1s; }
/* swap, in two beats so the two words never share the cut: the old stem leaves
   (0 to .3 s); the stem narrows from .2 s while Snip comes out of the cut and the
   cut closes, all on one curve (--glide), ending at .9 s. 'done' waits until 1 s. */
.brand[data-stage="swap"] .brand-ia-low { opacity: 0; }
.brand[data-stage="swap"] .brand-old { transform: translateX(110%); opacity: 0; transition: transform .3s cubic-bezier(.6, 0, .9, .4), opacity 0s linear .3s; }
.brand[data-stage="swap"] .brand-new { transform: none; transition: transform .6s var(--glide) .3s; }
.brand[data-stage="swap"] .brand-low { transform: none; transition: transform .6s var(--glide) .3s; }
@keyframes brand-blade {
  0% { opacity: 1; transform: rotate(9deg) scaleY(0); transform-origin: center top; }
  45% { opacity: 1; transform: rotate(9deg) scaleY(1); transform-origin: center top; }
  46% { transform-origin: center bottom; }
  100% { opacity: 1; transform: rotate(9deg) scaleY(0); transform-origin: center bottom; }
}

/* ===== the cut on headlines (as frontend/src/styles/cut.css) =====
   Markup: <h2 class="cut"><span class="cut-text">Text</span><span class="cut-copy"
   aria-hidden="true" data-text="Text"></span><span class="cut-blade" aria-hidden="true"></span></h2>
   The open cut is the resting state. With JavaScript (html.js) it waits closed
   until its section is in view (.section.in) or js/landing.js says go (.go). */
.cut { --cut-open: translate(.05em, .09em); position: relative; display: block; width: fit-content; max-width: 100%; padding-bottom: .09em; white-space: nowrap; }
/* a sentence, not a display headline: even a small opening reads as a
   strikethrough at this size, so its cut closes again after the blade */
.tagline.cut { --cut-open: translate(0, 0); }
.cut-text { display: block; clip-path: polygon(0 0, 100% 0, 100% 38%, 0 62%); }
.cut-copy { position: absolute; inset: 0 0 .09em; clip-path: polygon(0 62%, 100% 38%, 100% 100%, 0 100%); transform: var(--cut-open); }
.cut-copy::before { content: attr(data-text); content: attr(data-text) / ''; }
.cut-blade { position: absolute; left: -6%; right: -6%; top: 50%; height: 2px; background: linear-gradient(90deg, transparent, var(--gold) 12%, #fff3dc 50%, var(--gold) 88%, transparent); box-shadow: 0 0 22px rgba(217, 178, 122, .8); transform: rotate(-6deg) scaleX(0); transform-origin: left center; opacity: 0; pointer-events: none; }
@media (prefers-reduced-motion: no-preference) {
  .js .cut .cut-copy { transform: none; }
  .js .section.in .cut .cut-copy, .js .cut.go .cut-copy { animation: cut-part 1.1s var(--ease) .15s both; }
  .js .section.in .cut .cut-blade, .js .cut.go .cut-blade { animation: cut-blade 1.1s var(--ease) both; }
}
@keyframes cut-part {
  0%, 22% { transform: none; }
  100% { transform: var(--cut-open); }
}
@keyframes cut-blade {
  0% { opacity: 1; transform: rotate(-6deg) scaleX(0); transform-origin: left center; }
  40% { opacity: 1; transform: rotate(-6deg) scaleX(1); transform-origin: left center; }
  41% { transform-origin: right center; }
  100% { opacity: 1; transform: rotate(-6deg) scaleX(0); transform-origin: right center; }
}

/* ===== kinetic headlines: words rise out of a mask (data-kinetic, js/landing.js) ===== */
.kinetic .line { display: block; }
.kinetic .w { display: inline-block; overflow: hidden; vertical-align: top; padding-bottom: .1em; margin-right: .22em; }
.kinetic .w > span { display: inline-block; transform: translateY(110%); }
.in .kinetic .w > span, .kinetic.in .w > span { transform: none; transition: transform .8s var(--ease) calc(var(--i) * 60ms); }

/* ===== reveal: rises in once it is in view; only with JavaScript ===== */
@media (prefers-reduced-motion: no-preference) {
  .js .reveal { opacity: 0; transform: translateY(18px); }
  .js .in .reveal, .js .reveal.in { opacity: 1; transform: none; transition: opacity .8s var(--ease) var(--d, 0s), transform .8s var(--ease) var(--d, 0s); }
}

/* ===== 2. video ===== */
.video-section { padding-top: clamp(72px, 10vw, 140px); padding-bottom: clamp(56px, 8vw, 120px); }
.video-inner { max-width: 1240px; margin: 0 auto; }
.video-title { font-size: min(var(--step-4), calc(1240px / var(--n) * 2.15), calc((100vw - 2 * var(--gutter)) / var(--n) * 2.15)); } /* one line, sized to fit its --n characters, as the features' */
/* The space is reserved by aspect-ratio, so the page does not jump when the file loads. */
.video-frame { position: relative; width: 100%; max-width: 1100px; margin: clamp(28px, 4vw, 48px) auto 0; aspect-ratio: 16 / 9; overflow: hidden; border: 1px solid var(--line); border-radius: 20px; background: var(--graphite); box-shadow: 0 30px 80px rgba(0, 0, 0, .6); }
.video-frame video { width: 100%; height: 100%; object-fit: cover; background: var(--graphite); }
.video-play { position: absolute; inset: 0; margin: auto; display: grid; place-items: center; width: 76px; height: 76px; padding: 0; border: 1px solid var(--gold); border-radius: 50%; background: rgba(0, 0, 0, .55); color: var(--gold); cursor: pointer; }
.video-play[hidden] { display: none; }
.video-play svg { width: 34px; height: 34px; margin-left: 4px; }
.video-play:hover { background: rgba(0, 0, 0, .75); }
@media (prefers-reduced-motion: no-preference) {
  .video-play { transition: transform .2s var(--ease), background .2s; }
  .video-play:hover { transform: scale(1.06); }
}
/* the controls sit under the frame, at its width, on the left (Snip stands on the right) */
.video-controls { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 12px; width: 100%; max-width: 1100px; margin: 16px auto 0; }
.video-btn { min-height: 44px; padding: 0 20px; border: 1px solid var(--line); border-radius: 999px; background: none; color: var(--ivory); font: 500 14px/1 var(--text-font); cursor: pointer; }
.video-btn[hidden] { display: none; }
.video-btn:hover, .video-btn[aria-pressed="true"] { border-color: var(--gold); }
.video-link { display: inline-flex; align-items: center; min-height: 44px; color: var(--gold); font-weight: 600; text-decoration: underline; text-underline-offset: 4px; }
.video-link[hidden] { display: none; }
@media (max-width: 700px) {
  /* 9:16, centred, never taller than 80% of the screen */
  .video-frame { width: min(100%, calc(80vh * 9 / 16)); width: min(100%, calc(80svh * 9 / 16)); aspect-ratio: 9 / 16; border-radius: 16px; }
  .video-controls { width: min(100%, calc(80vh * 9 / 16)); width: min(100%, calc(80svh * 9 / 16)); }
}

/* ===== 3-9. the product's sections =====
   The headline on one line, sized to fit (--n is its length in characters);
   on a wide screen the body and the picture sit side by side under it, and
   .reverse puts the picture on the left. Snip stands in the body's column,
   under the text (js/landing.js). The shots are the real demo
   (scripts/capture.mjs): panels in a window, the booking page in a phone. */
.feature { padding-top: clamp(64px, 9vw, 128px); padding-bottom: clamp(24px, 4vw, 56px); }
.feature-inner { max-width: 1240px; margin: 0 auto; }
.feature h2 { font-size: min(var(--step-4), calc((100vw - 2 * var(--gutter)) / var(--n) * 2.15)); }
.feature .copy p { max-width: 40ch; margin: 18px 0 0; color: var(--stone); font-size: clamp(16px, 1.5vw, 19px); line-height: 1.55; }
.feature .stage { display: flex; justify-content: center; margin-top: 120px; } /* on a phone, Snip waits in this gap */
@media (min-width: 860px) {
  .feature-inner { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); column-gap: clamp(32px, 5vw, 80px); }
  .feature:has(.frame-window, .pair) .feature-inner { grid-template-columns: minmax(0, 4fr) minmax(0, 8fr); }
  .feature.reverse:has(.frame-window, .pair) .feature-inner { grid-template-columns: minmax(0, 8fr) minmax(0, 4fr); }
  .feature .copy { display: contents; }
  .feature h2 { grid-column: 1 / -1; font-size: min(var(--step-4), calc(1240px / var(--n) * 2.15), calc((100vw - 2 * var(--gutter)) / var(--n) * 2.15)); }
  .feature.reverse h2 { justify-self: end; }
  .feature .copy p { grid-row: 2; grid-column: 1; align-self: start; margin-top: 44px; }
  .feature .stage { grid-row: 2; grid-column: 2; margin-top: 40px; }
  .feature.reverse .copy p { grid-column: 2; }
  .feature.reverse .stage { grid-column: 1; }
  /* a phone shot is tall: keep it inside a laptop's screen */
  .feature .frame-phone { width: 260px; border-radius: 42px; }
  .feature .frame-phone img { border-radius: 33px; }
}

/* the frames, in the product's graphite */
.frame-phone { width: min(300px, 76vw); padding: 9px; border: 1px solid var(--line); border-radius: 46px; background: var(--graphite); box-shadow: 0 30px 80px rgba(0, 0, 0, .6); }
.frame-phone img { width: 100%; height: auto; border-radius: 37px; }
.frame-window { position: relative; width: 100%; padding-top: 26px; overflow: hidden; border: 1px solid var(--line); border-radius: 16px; background: var(--graphite); box-shadow: 0 30px 80px rgba(0, 0, 0, .6); }
.frame-window::before { content: ""; position: absolute; left: 14px; top: 10px; width: 7px; height: 7px; border-radius: 50%; background: var(--line); box-shadow: 12px 0 var(--line), 24px 0 var(--line); }
.frame-window img { width: 100%; height: auto; border-top: 1px solid var(--line); }

/* a panel shot with a phone variant (<picture>): on a phone it is the panel's
   own phone layout, so it sits in a phone frame; the <source>'s width and
   height give the box its shape before it loads */
.frame-window picture { display: block; }
@media (max-width: 700px) {
  .frame-window.has-phone { width: min(300px, 76vw); padding: 9px; border-radius: 46px; }
  .frame-window.has-phone::before { display: none; }
  .frame-window.has-phone img { border: 0; border-radius: 37px; }
}

/* 7. before and after, side by side where they fit */
.pair { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 230px), 1fr)); gap: 16px; width: 100%; max-width: 760px; }
.pair figure { margin: 0; overflow: hidden; border: 1px solid var(--line); border-radius: 18px; background: var(--graphite); box-shadow: 0 24px 60px rgba(0, 0, 0, .5); }
.pair figcaption { padding: 12px 16px; border-bottom: 1px solid var(--line); color: var(--stone); font-size: 14px; }
.pair figcaption b { color: var(--gold); font-weight: 600; }
.pair img { width: 100%; height: auto; }

/* 3. the problem: a drawn phone, said to be one */
.sketch { display: flex; flex-direction: column; align-items: center; gap: 12px; margin: 0; }
.sketch figcaption { color: var(--stone); font-size: 12px; letter-spacing: .12em; text-transform: uppercase; }
.sketch-phone { width: min(290px, 76vw); padding: 28px 14px 22px; border: 1px solid var(--line); border-radius: 44px; background: radial-gradient(120% 60% at 50% 0%, #2b241b, var(--graphite) 65%); box-shadow: 0 30px 80px rgba(0, 0, 0, .6); }
.sketch-clock { text-align: center; }
.sketch-clock span { display: block; color: var(--stone); font-size: 13px; }
.sketch-clock b { display: block; font-family: var(--display-font); font-weight: 600; font-size: 60px; letter-spacing: -.03em; line-height: 1.05; }
.sketch-notes { display: grid; gap: 8px; margin: 22px 0 0; padding: 0; list-style: none; }
.sketch-notes li { display: grid; grid-template-columns: 24px minmax(0, 1fr); column-gap: 10px; padding: 9px 12px; border-radius: 14px; background: rgba(242, 239, 233, .07); font-size: 13px; line-height: 1.3; }
.sketch-notes i { grid-row: span 2; align-self: center; width: 24px; height: 24px; border-radius: 8px; background: var(--gold); }
.sketch-notes .call i { background: #a4574c; }
.sketch-notes b { font-weight: 600; }
.sketch-notes span { overflow: hidden; color: var(--stone); white-space: nowrap; text-overflow: ellipsis; }

/* 8. the emails, as cards (texts from backend/src/shared/email.ts) */
.mails { display: grid; gap: 16px; width: 100%; max-width: 500px; }
.mail { padding: 20px 22px; border: 1px solid var(--line); border-radius: 16px; background: var(--graphite); box-shadow: 0 24px 60px rgba(0, 0, 0, .5); font-size: 14px; }
@media (min-width: 860px) { .mail:first-child { margin-right: 40px; } .mail + .mail { margin-left: 40px; } }
.mail-head { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 4px 12px; color: var(--stone); font-size: 13px; }
.mail-head strong { color: var(--gold); font-weight: 600; }
.mail-subject { margin: 10px 0 0; font-weight: 600; font-size: 15px; }
.mail-body { margin: 10px 0 0; color: #cfc9bf; line-height: 1.5; white-space: pre-line; }

/* ===== Snip, the guide: living scissors. js/landing.js places him every frame
   (a transform on .guide) and sets the classes for his pose. ===== */
.guide { position: fixed; left: 0; top: 0; z-index: 40; width: 112px; pointer-events: none; will-change: transform; }
.guide-body { transform-origin: 50% 98%; filter: drop-shadow(0 16px 22px rgba(0,0,0,.55)); }
.guide svg { display: block; width: 100%; height: auto; }
.guide.left svg { transform: scaleX(-1); }
.guide .blade, .guide .arm, .guide .pupil { transform-box: view-box; transition: transform .25s var(--ease); }
.guide .blade { transform-origin: 100px 148px; }
.guide .arm-l { transform-origin: 76px 118px; }
.guide .arm-r { transform-origin: 124px 118px; }
.guide .pupil { transform-box: fill-box; transform-origin: 50% 50%; }
.guide.hidden { opacity: 0; }
/* resting by a section: points at it */
.guide.pointing .arm-r { transform: rotate(-70deg); }
/* in the air: legs apart, arms up */
.guide.jumping .blade-l { transform: rotate(16deg); }
.guide.jumping .blade-r { transform: rotate(-16deg); }
.guide.jumping .arm-l { transform: rotate(80deg); }
.guide.jumping .arm-r { transform: rotate(-80deg); }
/* on the ladder: legs together, arms swapping rungs (--step flips 0/1) */
.guide.climbing .blade-l { transform: rotate(-8deg); }
.guide.climbing .blade-r { transform: rotate(8deg); }
.guide.climbing .arm-l { transform: rotate(calc(60deg + var(--step, 0) * 50deg)); }
.guide.climbing .arm-r { transform: rotate(calc(-110deg + var(--step, 0) * 50deg)); }
.guide.climbing .blade, .guide.climbing .arm { transition-duration: .12s; }
/* a snip of the legs when he arrives */
.guide.snip .blade-l { animation: snip-l .3s ease 2; }
.guide.snip .blade-r { animation: snip-r .3s ease 2; }
@keyframes snip-l { 50% { transform: rotate(-16deg); } }
@keyframes snip-r { 50% { transform: rotate(16deg); } }
.guide.blink .pupil { transform: scaleY(.12); }

/* his speech bubble: ivory card, black text */
.bubble { position: absolute; bottom: calc(100% + 8px); left: 0; width: max-content; max-width: 300px; margin: 0; padding: 12px 16px; border-radius: 14px; background: var(--ivory); color: var(--black); font-family: var(--text-font); font-weight: 500; font-size: 15px; line-height: 1.35; box-shadow: 0 16px 40px rgba(0,0,0,.45); transform: scale(.6); transform-origin: 15% 120%; opacity: 0; transition: opacity .25s ease, transform .35s var(--ease); }
.bubble::after { content: ""; position: absolute; left: 36px; bottom: -7px; width: 14px; height: 14px; background: var(--ivory); transform: rotate(45deg); border-radius: 3px; }
/* the bubble opens towards what he faces, never over the headline */
.guide.left .bubble { left: auto; right: 0; transform-origin: 85% 120%; }
.guide.left .bubble::after { left: auto; right: 36px; }
.guide.talking .bubble { opacity: 1; transform: scale(1); }
/* beside him rather than above, where he waits in a section's gap on a phone */
.guide.aside .bubble { left: auto; right: calc(100% + 6px); bottom: 14px; transform-origin: 100% 80%; }
.guide.aside .bubble::after { left: auto; right: -6px; bottom: 16px; }

/* his props, positioned by js/landing.js */
.fx { position: fixed; inset: 0; z-index: 39; pointer-events: none; overflow: hidden; }
.ladder { position: absolute; left: 0; top: 0; width: 46px; transform-origin: 50% 0; opacity: 0; border-left: 6px solid #b88746; border-right: 6px solid #b88746; border-radius: 4px; background: repeating-linear-gradient(to bottom, transparent 0 22px, var(--gold) 22px 28px); filter: drop-shadow(0 10px 14px rgba(0,0,0,.5)); }
.portal { position: absolute; left: 0; top: 0; width: 150px; height: 40px; margin: -20px 0 0 -75px; border-radius: 50%; background: radial-gradient(closest-side, #000 55%, #3a2a12 75%, var(--gold) 92%, rgba(217,178,122,0) 100%); box-shadow: 0 0 40px rgba(217,178,122,.55), 0 0 90px rgba(217,178,122,.25); opacity: 0; }
.portal::after { content: ""; position: absolute; inset: 3px; border-radius: 50%; border: 2px dashed rgba(255,236,200,.8); animation: spin 2.5s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

/* ===== 10. the demo (js/demo.js) =====
   Before "Empezar la demo" the stage is empty: no frame, no request to /demo/.
   Wide (data-layout="side-by-side"): the site in a 390-wide phone, the panel in
   a window beside it, both about 700 px tall. Narrow ("tabs"): one frame at a
   time, full width, 80% of the screen. On a phone Snip waits in the gap above
   the stage (js/landing.js). */
.demo-section { padding-top: clamp(72px, 10vw, 140px); padding-bottom: clamp(56px, 8vw, 120px); }
.demo-inner { max-width: 1240px; margin: 0 auto; }
.demo-section h2 { font-size: min(var(--step-4), calc((100vw - 2 * var(--gutter)) / var(--n) * 2.15)); }
.demo-lead { max-width: 46ch; margin: 18px 0 0; color: var(--stone); font-size: clamp(16px, 1.5vw, 19px); line-height: 1.55; }
.demo-note { max-width: 46ch; margin: 12px 0 0; color: var(--gold); font-size: 14px; }
.demo-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 12px 16px; margin-top: 28px; }
.demo-actions .btn[hidden] { display: none; }
.demo-link { display: inline-flex; align-items: center; min-height: 44px; color: var(--gold); font-weight: 600; text-decoration: underline; text-underline-offset: 4px; }
.demo-link[hidden] { display: none; }
.demo-stage { margin-top: 120px; }
.demo-tabs { display: flex; gap: 8px; margin-bottom: 12px; }
.demo-tabs[hidden], .demo-pane[hidden] { display: none; }
.demo-tabs [role="tab"] { flex: 1 1 0; min-height: 44px; padding: 0 16px; border: 1px solid var(--line); border-radius: 999px; background: none; color: var(--stone); font: 500 15px/1 var(--text-font); cursor: pointer; }
.demo-tabs [aria-selected="true"] { border-color: var(--gold); background: rgba(217, 178, 122, .12); color: var(--ivory); }
.demo-caption { display: none; }
.demo-phone, .demo-window { overflow: hidden; border: 1px solid var(--line); border-radius: 16px; background: var(--graphite); box-shadow: 0 30px 80px rgba(0, 0, 0, .6); }
.demo-phone iframe, .demo-window iframe { display: block; width: 100%; height: 80vh; height: 80svh; border: 0; background: var(--black); }
.demo-error { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; margin: 0; padding: 24px; border: 1px solid var(--line); border-radius: 16px; color: var(--ivory); }
.demo-error:focus { outline: none; }
.demo-error:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }
.demo-pane:focus { outline: none; }
.demo-error a { display: inline-flex; align-items: center; min-height: 44px; color: var(--gold); font-weight: 600; text-decoration: underline; text-underline-offset: 4px; }
@media (min-width: 860px) {
  .demo-stage { margin-top: 48px; }
}
.demo-stage[data-layout="side-by-side"] .demo-panes { display: flex; align-items: flex-end; justify-content: center; gap: 32px; }
.demo-stage[data-layout="side-by-side"] .demo-pane:first-child { flex: 0 0 auto; }
.demo-stage[data-layout="side-by-side"] .demo-pane:last-child { flex: 1 1 auto; min-width: 0; max-width: 1000px; }
.demo-stage[data-layout="side-by-side"] .demo-caption { display: block; margin: 0 0 12px; color: var(--stone); font-size: 14px; }
.demo-stage[data-layout="side-by-side"] .demo-phone { width: 412px; padding: 10px; border-radius: 46px; }
.demo-stage[data-layout="side-by-side"] .demo-phone iframe { width: 390px; height: 700px; border-radius: 36px; }
.demo-stage[data-layout="side-by-side"] .demo-window { position: relative; padding-top: 26px; }
.demo-stage[data-layout="side-by-side"] .demo-window::before { content: ""; position: absolute; left: 14px; top: 10px; width: 7px; height: 7px; border-radius: 50%; background: var(--line); box-shadow: 12px 0 var(--line), 24px 0 var(--line); }
/* the panel lays out at 1000 px and is scaled into its window (js/demo.js sets the sizes) */
/* clip, not hidden: a hidden box can still be scrolled, and focus or a click inside the frame would slide the panel sideways */
.demo-stage[data-layout="side-by-side"] .demo-window .demo-scaler { overflow: clip; border-top: 1px solid var(--line); }
.demo-stage[data-layout="side-by-side"] .demo-window iframe { max-width: none; }

/* ===== footer ===== */
.foot { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 8px 24px; padding: 40px var(--gutter); border-top: 1px solid var(--line); color: var(--stone); font-size: 14px; }
.foot p { margin: 0; }

/* ===== small screens ===== */
@media (max-width: 640px) {
  .nav-links a:not(.btn) { display: none; }
  .hero { justify-content: flex-start; padding-top: 22vh; padding-top: 22svh; }
  .cta-row .btn { flex: 1 1 auto; }
  .guide { width: 64px; }
  .bubble { max-width: min(240px, calc(100vw - 32px)); font-size: 13px; }
  .portal { width: 100px; height: 28px; margin: -14px 0 0 -50px; }
  .ladder { width: 32px; }
}

/* ===== people who asked for less motion get the final states ===== */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; animation-delay: 0s !important; transition: none !important; }
  .kinetic .w > span { transform: none; }
  .guide-body { animation: none !important; }
}

/* ===== 11. "Te llamamos": the lead form (js/lead.js) ===== */
.lead-section { padding-top: clamp(72px, 10vw, 140px); padding-bottom: clamp(96px, 12vw, 180px); }
.lead-inner { max-width: 640px; margin: 0 auto; }
.lead-section h2 { font-size: min(var(--step-4), calc((100vw - 2 * var(--gutter)) / var(--n) * 2.15)); }
.lead-lead { max-width: 46ch; margin: 18px 0 0; color: var(--stone); font-size: clamp(16px, 1.5vw, 19px); line-height: 1.55; }
.lead-nojs { margin: 28px 0 0; color: var(--gold); font-weight: 600; }
.lead-form { display: grid; gap: 18px; margin-top: 32px; }
.lead-form[hidden], .lead-nojs[hidden], .lead-thanks[hidden] { display: none; }
.lead-form .field { display: grid; gap: 6px; }
.lead-form label { color: var(--ivory); font-size: 14px; font-weight: 500; }
.lead-form input { width: 100%; min-height: 48px; padding: 0 16px; border: 1px solid var(--line); border-radius: 12px; background: var(--graphite); color: var(--ivory); font: 400 16px/1.2 var(--text-font); }
.lead-form input:hover { border-color: #4a4338; }
.lead-form input:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; border-color: var(--gold); }
.lead-form input[aria-invalid="true"] { border-color: #c9706a; }
/* the honeypot: off-screen, not display:none (bots fill what they can "see") */
.lead-hp { position: absolute; left: -10000px; top: auto; width: 1px; height: 1px; overflow: hidden; }
.lead-error { min-height: 1.5em; margin: 0; color: #e0958f; font-weight: 500; }
.lead-error:empty { min-height: 0; }
.lead-form .btn { justify-self: start; }
.lead-form .btn:disabled { opacity: .55; cursor: progress; transform: none; }
.lead-thanks { margin: 32px 0 0; font-family: var(--display-font); font-weight: 800; font-size: clamp(26px, 4vw, var(--step-3)); letter-spacing: -.03em; line-height: 1.1; color: var(--ivory); }
.lead-thanks:focus { outline: none; }
.lead-thanks:focus-visible { outline: 2px solid var(--gold); outline-offset: 6px; }
@media (max-width: 700px) { .lead-form .btn { justify-self: stretch; } }
