/* ================================================================
   TARABA Showroom — motion + animated exhibits
   css/showroom-motion.css | Loaded after css/showroom.css, together
   with js/showroom-motion.js. Spec: docs/design-system.md (M1–M10).

   Every rule here shows the FINAL state by default. Start states
   live under html.js-motion, which the script adds only when the
   visitor allows motion.
================================================================ */

/* ─────────────────────────────────────────────
       HERO ROOM — headline left, mascot right,
       the flight line behind (M1)
    ───────────────────────────────────────────── */
.hero-room {
  min-height: 92vh;
  min-height: 92svh;
  display: flex;
  align-items: center;
  padding-top: calc(var(--room-y) + 40px);
}
.hero-room .wrap {
  display: grid;
  grid-template-columns: 7fr 5fr;
  gap: var(--s-7);
  align-items: center;
  width: 100%;
}
.hero-room h1 {
  font-family: var(--f-display);
  font-size: var(--fs-display);
  font-weight: 800;
  line-height: 1.02;
  letter-spacing: -0.025em;
  color: var(--white);
}
.hero-room h1 em {
  font-style: normal;
  color: var(--orange);
}
.hero-room .lead {
  color: rgba(255, 255, 255, 0.78);
}
.hero-room__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-4);
  margin: var(--s-6) 0 var(--s-7);
}
.hero-flight {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  pointer-events: none;
}
.hero-flight__trail {
  fill: none;
  stroke: url(#hero-trail-grad);
  stroke-width: 3;
  stroke-linecap: round;
}
.hero-flight__orbit {
  fill: none;
  stroke: rgba(234, 162, 33, 0.4);
  stroke-width: 1.5;
  stroke-linecap: round;
  transform-box: fill-box;
  transform-origin: center;
}
.hero-flight__glow {
  transform-box: fill-box;
  transform-origin: center;
}
.js-motion .hero-flight__trail {
  stroke-dasharray: var(--len, 2400);
  animation: sr-draw 1.2s cubic-bezier(0.45, 0, 0.25, 1) 0.3s both;
}
.js-motion .hero-flight__orbit {
  animation: sr-spin 60s linear infinite;
}
.js-motion .hero-flight__orbit--rev {
  animation-direction: reverse;
}
.js-motion .hero-flight__glow {
  animation: sr-breathe 10s ease-in-out infinite;
}
@keyframes sr-draw {
  from {
    stroke-dashoffset: var(--len, 2400);
  }
  to {
    stroke-dashoffset: 0;
  }
}
@keyframes sr-spin {
  to {
    transform: rotate(360deg);
  }
}
@keyframes sr-breathe {
  0%,
  100% {
    opacity: 0.65;
    transform: scale(1);
  }
  50% {
    opacity: 1;
    transform: scale(1.06);
  }
}

/* ─────────────────────────────────────────────
       THE EXPLANATION GAP — product, gap, buyer;
       the bridge builds (M4)
    ───────────────────────────────────────────── */
.gap-exhibit {
  width: 100%;
  max-width: 760px;
  margin: var(--s-7) auto 0;
}
.gap-exhibit svg {
  width: 100%;
  height: auto;
  overflow: visible;
}
.gap__label {
  font-family: var(--f-display);
  font-size: 16px;
  font-weight: 700;
  fill: var(--navy);
}
.gap__sub {
  font-family: var(--f-body);
  font-size: 13px;
  fill: var(--text-soft);
}
.gap__plank,
.gap__msg,
.gap__q,
.gap__ok {
  transform-box: fill-box;
  transform-origin: center;
}
/* Final state: bridge built, buyer convinced (the question mark by the
   product has gone; the tick shows, level with where it was) */
.gap__msg,
.gap__q {
  opacity: 0;
}
.gap__ok {
  opacity: 1;
}
/* Start state (motion on, not yet in view) */
.js-motion [data-motion="gap"]:not(.is-in) .gap__plank {
  opacity: 0;
  transform: translateY(-26px);
}
.js-motion [data-motion="gap"]:not(.is-in) .gap__q {
  opacity: 0;
  transform: scale(0.6);
}
.js-motion [data-motion="gap"]:not(.is-in) .gap__ok {
  opacity: 0;
  transform: scale(0.6);
}
/* the delayed transitions run only on the way in, so the start state
   (on load, or a replay) applies at once instead of fading back late */
.js-motion [data-motion="gap"].is-in .gap__plank {
  transition:
    opacity 260ms var(--ease-out),
    transform 380ms cubic-bezier(0.3, 1.4, 0.5, 1);
  /* client, 2026-10-31: first the "?" by the product, then the bridge one
     plank at a time, then the message crosses and the buyer's tick shows */
  transition-delay: calc(450ms + var(--i, 0) * 110ms);
}
/* the "?" pops in at 0.15s and fades as the tick lands at 2.2s */
.js-motion [data-motion="gap"].is-in .gap__q {
  animation: gap-q 2.4s linear both;
}
@keyframes gap-q {
  0%,
  5.5% {
    opacity: 0;
    transform: scale(0.6);
  }
  15% {
    opacity: 1;
    transform: scale(1);
  }
  91.6% {
    opacity: 1;
    transform: scale(1);
  }
  100% {
    opacity: 0;
    transform: scale(0.6);
  }
}
.js-motion [data-motion="gap"].is-in .gap__ok {
  transition:
    opacity 250ms ease-out 2.2s,
    transform 350ms cubic-bezier(0.3, 1.4, 0.5, 1) 2.2s;
}
/* replay (js/pages/index.js): snap back to the start state at once */
.js-motion [data-motion="gap"].is-reset * {
  transition: none !important;
  animation: none !important;
}
.js-motion [data-motion="gap"].is-in .gap__msg {
  animation: sr-message 0.6s cubic-bezier(0.45, 0, 0.25, 1) 1.6s both;
}
@keyframes sr-message {
  0% {
    opacity: 0;
    transform: translate(0, 0);
  }
  15%,
  85% {
    opacity: 1;
  }
  100% {
    opacity: 0;
    transform: translate(var(--travel, 300px), 0);
  }
}

/* ─────────────────────────────────────────────
       M2 — room reveal
    ───────────────────────────────────────────── */
.js-motion [data-reveal] {
  transition:
    opacity var(--dur-reveal) var(--ease-out),
    transform var(--dur-reveal) var(--ease-out);
  transition-delay: calc(var(--i, 0) * 80ms);
}
.js-motion [data-reveal]:not(.is-in) {
  opacity: 0;
  transform: translateY(16px);
}
.js-motion .guide[data-reveal] .guide__bubble {
  transition:
    opacity 300ms var(--ease-out),
    transform 300ms cubic-bezier(0.3, 1.4, 0.5, 1);
  transition-delay: calc(var(--i, 0) * 80ms + 400ms);
}
.js-motion .guide[data-reveal]:not(.is-in) .guide__bubble {
  opacity: 0;
  transform: scale(0.92);
}

/* ─────────────────────────────────────────────
       M5 — steps: the flight line draws, badges pop in
       (the dashed line is revealed through a solid mask path)
    ───────────────────────────────────────────── */
.steps__mask-path {
  fill: none;
  stroke: #fff;
  stroke-width: 14;
}
.js-motion [data-motion="steps"] .steps__mask-path {
  stroke-dasharray: var(--len, 1100);
  transition: stroke-dashoffset 1.2s cubic-bezier(0.45, 0, 0.25, 1) 0.1s;
}
.js-motion [data-motion="steps"]:not(.is-in) .steps__mask-path {
  stroke-dashoffset: var(--len, 1100);
}
.js-motion [data-motion="steps"] .step__badge {
  transition:
    opacity 250ms var(--ease-out),
    transform 350ms cubic-bezier(0.3, 1.4, 0.5, 1),
    background-color var(--dur-micro) var(--ease-out);
  transition-delay: calc(var(--i, 1) * 280ms - 120ms);
}
.js-motion [data-motion="steps"]:not(.is-in) .step__badge {
  opacity: 0;
  transform: scale(0.6);
}

/* ─────────────────────────────────────────────
       M8 — the principle: strike the three T's,
       then light "character"
    ───────────────────────────────────────────── */
.statement em {
  position: relative;
  display: inline-block;
  color: var(--slate-light);
}
.statement em::after {
  content: "";
  position: absolute;
  left: -3%;
  right: -3%;
  top: 54%;
  height: 0.075em;
  border-radius: 1em;
  background: var(--orange);
  transform-origin: 0 50%;
}
.js-motion [data-motion="statement"] em,
.js-motion [data-motion="statement"] em::after {
  transition:
    color 250ms ease-out,
    transform 260ms var(--ease-out);
  transition-delay: calc(300ms + var(--i, 0) * 260ms);
}
.js-motion [data-motion="statement"]:not(.is-in) em {
  color: var(--white);
}
.js-motion [data-motion="statement"]:not(.is-in) em::after {
  transform: scaleX(0);
}
.js-motion [data-motion="statement"] strong {
  transition: color 400ms ease-out 1.25s;
}
.js-motion [data-motion="statement"]:not(.is-in) strong {
  color: var(--white);
}

/* ─────────────────────────────────────────────
       M9 — the guide returns in the CTA band
    ───────────────────────────────────────────── */
.js-motion .cta-band__mascot[data-reveal]:not(.is-in) {
  transform: translateY(24px);
}

/* ─────────────────────────────────────────────
       M7 — logo marquee
       (a static wrapped strip without JS / with reduced motion)
    ───────────────────────────────────────────── */
.marquee {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(
    90deg,
    transparent,
    #000 6%,
    #000 94%,
    transparent
  );
  mask-image: linear-gradient(
    90deg,
    transparent,
    #000 6%,
    #000 94%,
    transparent
  );
}
.marquee__track {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  row-gap: var(--s-4);
  list-style: none;
}
.marquee__track > * {
  padding-right: var(--s-4);
}
.marquee.is-running .marquee__track {
  flex-wrap: nowrap;
  width: max-content;
  animation: sr-marquee 45s linear infinite;
}
.marquee.is-running:hover .marquee__track,
.marquee.is-running:focus-within .marquee__track {
  animation-play-state: paused;
}
@keyframes sr-marquee {
  to {
    transform: translateX(-50%);
  }
}

/* ─────────────────────────────────────────────
       M10 — keyboard focus gets the same lift as hover
    ───────────────────────────────────────────── */
.exhibit:focus-visible,
.industry:focus-visible {
  transform: translateY(-4px);
}

/* ─────────────────────────────────────────────
       RESPONSIVE
    ───────────────────────────────────────────── */
@media (max-width: 1023px) {
  .hero-room .wrap {
    grid-template-columns: 1fr;
  }
  .hero-room__mascot img {
    max-height: 420px;
  }
}
@media (max-width: 639px) {
  .js-motion [data-reveal]:not(.is-in) {
    transform: translateY(12px);
  }
  /* The Gap SVG renders at ~half size on phones: double its label sizes
     (SVG user units) so they stay ≈ 12–14px on screen; drop the sub-lines. */
  .gap__label {
    font-size: 28px;
  }
  .gap__sub {
    display: none;
  }
  .marquee.is-running .marquee__track {
    animation-duration: 60s;
  }
}

@media (prefers-reduced-motion: reduce) {
  .hero-flight__trail,
  .hero-flight__orbit,
  .hero-flight__glow,
  .marquee__track {
    animation: none !important;
  }
}

/* ── Page-to-page transition (CSS only; approved 2026-10-29) ──
   Same-site links cross-fade instead of a hard cut. The nav and the
   WhatsApp button keep their place; only the page body fades and lifts.
   Browsers without cross-document view transitions just load the page. */
@view-transition {
  navigation: auto;
}
.nav {
  view-transition-name: site-nav;
}
.wa {
  view-transition-name: site-wa;
}
::view-transition-old(root) {
  animation: page-out 220ms var(--ease-out, ease-out) both;
}
::view-transition-new(root) {
  animation: page-in 380ms var(--ease-out, ease-out) 80ms both;
}
@keyframes page-out {
  to {
    opacity: 0;
    transform: translateY(-8px);
  }
}
@keyframes page-in {
  from {
    opacity: 0;
    transform: translateY(14px);
  }
}
@media (prefers-reduced-motion: reduce) {
  @view-transition {
    navigation: none;
  }
}
