/* ============================================================
   HERO DEMO — the real Retail+ app, running in the hero
   ============================================================
   Replaces the hand-built Ask-Hank facsimile that used to sit here. That
   markup was a replica of a product screen, so it drifted every time the
   product moved and nobody noticed. This embeds the actual app
   (/app/?demo&tour=hero — the real App.tsx on src/demo/ fixtures, driven by
   the DOM tour in src/demo/tour.ts), so the hero cannot advertise a UI that
   no longer exists.

   Two things this file is careful about:

   1. LCP. The demo bundle is ~363 kB gz. It is NOT part of first paint — the
      stage renders as a pure-CSS poster and the iframe is injected later
      (see hero-demo.js). Nothing here loads a byte of the app.

   2. The morph. Beat 3 switches to a phone, and the switch is a CROSS-FADE,
      not a width animation: resizing the iframe live would fire a resize
      event per frame and each one costs a full re-render inside the app.
      One dimension change, hidden behind a 200ms fade.
   ============================================================ */

/* ---------- where this card lives ----------
   It used to live in the hero, and this file used to carry ~95 lines of hero
   layout to make that work: .hero-grid forced to one column, the stat strip
   grid-placed into the empty right half so the demo wasn't pushed below the
   fold, and a POS-persona exception because that persona swapped the demo for
   an "intelligence layer" panel.

   All of that is gone. The redesign gives the demo its own band
   (section.demo-band#demo) below a two-column hero, the hero's right column is
   now a per-persona photograph with the stat strip beneath it (.hero-visual),
   and the POS panel no longer exists. Those rules were not merely redundant —
   `.hero-grid { grid-template-columns: 1fr; }` would have collapsed the new
   two-column hero, so they had to go rather than be left dormant.

   NOTE for anyone tracing the old contract: the comment that used to sit here
   said the stat strip must stay a DESCENDANT of .hero-copy because
   conversion.js read `heroCopy.querySelector('.hero-stat-strip')`. That is no
   longer true. conversion.js now looks the strip up from the hero SECTION
   (`heroCopy.closest('.hero')`), which is what lets it live in .hero-visual.

   The card is styled to sit inside the demo band's window chrome; the few
   overrides that flatten its own frame in that context are inline in
   index.html next to the markup, not here. */

.hero-demo {
  position: relative;
  /* The selector segment above owns the top spacing; the card centres and
     TRANSITIONS its width — hero-demo.js shrink-wraps it to the frame being
     shown (phone/tablet/desktop), so the whole box resizes per device. The
     iframe inside keeps a fixed viewport + transform scale, so the width
     transition is pure CSS and the app never re-renders during it. */
  margin-top: 0;
  margin-left: auto;
  margin-right: auto;
  transition: width 320ms ease;
  border-radius: 18px;
  border: 1px solid var(--tap-line);
  background:
    radial-gradient(120% 90% at 50% 0%, #FFFFFF 0%, #FBFBF7 55%, #F6F6EE 100%);
  box-shadow: var(--tap-shadow-flyout);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  /* The app inside is orange Retail+ chrome and the site is olive. The frame is
     what makes that read as "a product being shown" rather than a clash. */
  isolation: isolate;
}

/* ---------- stage: holds the scaled iframe ---------- */
/* Height is chosen to fit a 1280x640 viewport exactly at the content width:
   1140/1280 = 0.891, and 640 * 0.891 = 570. Both frames are 640 tall, so the
   scale — and therefore the text size — is identical on every beat and only the
   width changes across the morph.

   NB: no `flex: 1` here. With it, the stage stretched to whatever the flex
   container's own height happened to be (540 - rail = 492) and silently ignored
   this value, costing ~1.5px of app text. The explicit height must win. */
.hero-demo-stage {
  position: relative;
  flex: 0 0 auto;
  height: 570px;
  overflow: hidden;
}

.hero-demo-frame {
  position: absolute;
  top: 50%;
  left: 50%;
  border: 0;
  display: block;
  background: #fff;
  /* Set by JS per beat. The iframe's own width is what the app measures, so
     these are real CSS pixels inside the frame — 1280 renders the desktop
     layout, 390 renders the genuine mobile one. */
  width: var(--demo-w, 1280px);
  height: var(--demo-h, 800px);
  transform: translate(-50%, -50%) scale(var(--demo-s, 0.42));
  transform-origin: center center;
  opacity: 0;
  transition: opacity 200ms ease;
  pointer-events: none;
}
.hero-demo.is-live .hero-demo-frame { opacity: 1; }
/* Mid-morph: faded out while the dimensions swap underneath. */
.hero-demo.is-morphing .hero-demo-frame { opacity: 0; }
/* Once the visitor takes over, the app becomes interactive. */
.hero-demo.is-interactive .hero-demo-frame { pointer-events: auto; }

/* Phone beat gets a bezel so a 390px viewport reads as a handset rather than
   as a broken desktop layout. */
.hero-demo-bezel {
  position: absolute;
  top: 50%;
  left: 50%;
  width: calc(var(--bezel-w, 0px));
  height: calc(var(--bezel-h, 0px));
  transform: translate(-50%, -50%);
  border-radius: 34px;
  border: 1px solid var(--tap-line-strong);
  box-shadow: 0 18px 50px rgba(0,0,0,0.14);
  opacity: 0;
  transition: opacity 260ms ease;
  pointer-events: none;
}
.hero-demo[data-frame="phone"].is-live .hero-demo-bezel,
.hero-demo[data-frame="tablet"].is-live .hero-demo-bezel { opacity: 1; }

/* ---------- poster (pre-load state) ---------- */
/* Deliberately CSS-only. A screenshot poster would go stale exactly the way
   the old facsimile did, and it would cost a request in the LCP window. */
.hero-demo-poster {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 18px;
  text-align: center;
  padding: 32px;
  background:
    radial-gradient(120% 90% at 50% 0%, #FFFFFF 0%, #FBFBF7 60%, #F4F4EA 100%);
  transition: opacity 320ms ease, visibility 320ms;
  z-index: 2;
}
.hero-demo.is-live .hero-demo-poster { opacity: 0; visibility: hidden; }

.hero-demo-play {
  width: 62px; height: 62px;
  border-radius: 50%;
  border: 0;
  background: var(--tap-orange);
  color: #fff;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  box-shadow: 0 8px 28px rgba(242,122,46,0.36);
  transition: transform 160ms ease, box-shadow 160ms ease;
}
.hero-demo-play:hover { transform: scale(1.06); box-shadow: 0 12px 34px rgba(242,122,46,0.44); }
.hero-demo-play:focus-visible { outline: 2px solid var(--tap-orange-deep); outline-offset: 3px; }
.hero-demo-play svg { width: 22px; height: 22px; margin-left: 3px; }

.hero-demo-poster-title {
  font-size: 15px; font-weight: 700; color: var(--tap-ink);
  letter-spacing: -0.01em;
}
.hero-demo-poster-sub {
  font-size: 12.5px; color: var(--tap-ink-2); max-width: 30ch; line-height: 1.5;
}

/* Skeleton shown between the click and the app's first paint. */
.hero-demo-loading {
  position: absolute; inset: 0; z-index: 1;
  display: none;
  align-items: center; justify-content: center;
  color: var(--tap-ink-3); font-size: 12.5px;
}
.hero-demo.is-loading .hero-demo-loading { display: flex; }

/* ---------- device selector ----------
   Mobile · Tablet · Web — a standalone rounded segment floating ABOVE the
   demo card (a sibling, not part of it). The active pill tracks whichever
   frame is on screen — the tour drives it per beat until the visitor picks;
   a pick pins the whole card to that viewport. */
.hero-demo-devices {
  display: flex;
  width: max-content;
  margin: 40px auto 14px;
  gap: 2px;
  padding: 4px;
  border: 1px solid var(--tap-line);
  border-radius: 999px;
  background: rgba(255,255,255,0.85);
  backdrop-filter: saturate(140%) blur(6px);
  box-shadow: 0 2px 10px rgba(17,17,17,0.06);
}
.hero-demo-device {
  border: 0;
  background: transparent;
  border-radius: 999px;
  padding: 7px 18px;
  min-height: 34px;
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--tap-ink-3);
  cursor: pointer;
  transition: color 160ms ease, background 160ms ease, box-shadow 160ms ease;
}
.hero-demo-device:hover { color: var(--tap-ink); }
.hero-demo-device[aria-pressed="true"] {
  color: #fff;
  background: var(--tap-orange-deep);
  box-shadow: 0 1px 4px rgba(194,65,12,0.35);
}
.hero-demo-device:focus-visible { outline: 2px solid var(--tap-orange-deep); outline-offset: 2px; }
@media (max-width: 860px) {
  .hero-demo-devices { margin-top: 28px; }
  .hero-demo-device { min-height: 44px; padding: 10px 18px; }
}

/* ---------- step rail ---------- */
.hero-demo-rail {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  border-top: 1px solid var(--tap-line);
  background: rgba(255,255,255,0.72);
  backdrop-filter: saturate(140%) blur(6px);
  min-height: 46px;
}
.hero-demo-dots { display: flex; gap: 6px; flex-shrink: 0; }
.hero-demo-dot {
  width: 22px; height: 4px; border-radius: 2px;
  border: 0; padding: 0;
  background: var(--tap-line-strong);
  cursor: pointer;
  transition: background 200ms ease, width 200ms ease;
}
.hero-demo-dot[aria-current="true"] { background: var(--tap-orange); width: 30px; }
.hero-demo-dot:focus-visible { outline: 2px solid var(--tap-orange-deep); outline-offset: 3px; }

.hero-demo-caption {
  font-size: 12.5px; font-weight: 600; color: var(--tap-ink);
  letter-spacing: -0.01em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.hero-demo-hint {
  margin-left: auto; flex-shrink: 0;
  font-size: 11px; color: var(--tap-ink-3);
}
/* At phone/tablet card widths the rail is too narrow for the hint. */
.hero-demo[data-frame="phone"] .hero-demo-hint,
.hero-demo[data-frame="tablet"] .hero-demo-hint { display: none; }

/* ---------- reduced motion ---------- */
/* No auto-start and no morph animation. The demo still runs if the visitor
   asks for it — reduced motion is not a reason to withhold the content. */
@media (prefers-reduced-motion: reduce) {
  .hero-demo-frame,
  .hero-demo-bezel,
  .hero-demo-poster { transition: none; }
  .hero-demo-play:hover { transform: none; }
}

/* ---------- mobile ---------- */
/* On a phone the hero stacks; the stage gets shorter and the desktop beats
   scale down further. Handled numerically in JS (it measures the stage), so
   there is only the height to set here. */
/* On a phone the stage is too narrow for a desktop viewport to be legible at
   any scale, so hero-demo.js pins every beat to the phone frame there — a
   mobile visitor sees the mobile app, which is the honest thing to show them.
   Only the box height needs setting here. */
@media (max-width: 860px) {
  .hero-demo { margin-top: 32px; }
  .hero-demo-stage { height: 520px; }
  .hero-demo-caption { font-size: 12px; }
  .hero-demo-hint { display: none; }
}
@media (max-width: 520px) {
  .hero-demo-stage { height: 460px; }
}
