/* SwiftFrame site — brand tokens + custom layers.
   Brand mesh, marquee, and reveal keyframes are added in later tasks. */
:root {
  --sf-bg: #0c0a16;
  --sf-indigo-darkest: #1e1b4b;
  --sf-indigo: #312e81;
  --sf-violet: #4c1d95;
  --sf-purple: #7e22ce;
  --sf-pink: #be185d;
  --sf-text: #f5f3ff;
  --sf-muted: rgba(245, 243, 255, 0.65);
  --sf-border: rgba(255, 255, 255, 0.10);
}

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: 0.001ms !important; animation-iteration-count: 1 !important; }
}

body { -webkit-font-smoothing: antialiased; line-height: 1.5; overflow-x: hidden; }

/* Shared utility for muted text that still passes 4.5:1 on the dark bg */
.text-muted { color: var(--sf-muted); }

/* ---- Brand mesh: animated indigo -> purple -> pink radial blobs + grain ---- */
.sf-mesh {
  position: absolute;
  inset: 0;
  overflow: hidden;
  z-index: 0;
  background: var(--sf-bg);
  pointer-events: none;
}
.sf-mesh::before,
.sf-mesh::after {
  content: "";
  position: absolute;
  inset: -25%;
  background:
    radial-gradient(40% 40% at 25% 30%, var(--sf-pink) 0%, transparent 60%),
    radial-gradient(45% 45% at 75% 25%, var(--sf-purple) 0%, transparent 60%),
    radial-gradient(50% 50% at 60% 75%, var(--sf-indigo) 0%, transparent 60%),
    radial-gradient(45% 45% at 20% 80%, var(--sf-violet) 0%, transparent 60%);
  filter: blur(40px) saturate(1.1);
  will-change: transform;
  animation: sf-mesh-drift 24s ease-in-out infinite alternate;
}
.sf-mesh::after {
  opacity: 0.6;
  animation: sf-mesh-drift 30s ease-in-out infinite alternate-reverse;
  mix-blend-mode: screen;
}
/* grain + dark vignette for text contrast */
.sf-mesh > .sf-mesh-grain {
  position: absolute;
  inset: 0;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.4'/%3E%3C/svg%3E");
  opacity: 0.15;
  mix-blend-mode: overlay;
}
.sf-mesh > .sf-mesh-vignette {
  position: absolute;
  inset: 0;
  background: radial-gradient(120% 120% at 50% 40%, transparent 40%, rgba(12, 10, 22, 0.55) 100%);
}
@keyframes sf-mesh-drift {
  0%   { transform: translate3d(-4%, -2%, 0) scale(1.05) rotate(0deg); }
  50%  { transform: translate3d(3%, 2%, 0) scale(1.12) rotate(4deg); }
  100% { transform: translate3d(-2%, 4%, 0) scale(1.08) rotate(-3deg); }
}
@media (prefers-reduced-motion: reduce) {
  .sf-mesh::before, .sf-mesh::after { animation: none; }
}

/* ---- Animated WebGL mesh gradient: paper-shaders swirl, mounted into the hero ----
   Replaces the CSS radial blobs with a live shader (see assets/js/hero-mesh.js).
   The static radial fallback below shows if the shader can't load (no WebGL / offline). */
.sf-mesh--shader::before,
.sf-mesh--shader::after { content: none; }
.sf-mesh--shader {
  background:
    radial-gradient(60% 60% at 25% 30%, var(--sf-violet) 0%, transparent 70%),
    radial-gradient(55% 55% at 78% 30%, var(--sf-purple) 0%, transparent 70%),
    radial-gradient(65% 65% at 55% 85%, var(--sf-indigo) 0%, transparent 70%),
    radial-gradient(50% 50% at 85% 80%, var(--sf-pink) 0%, transparent 70%),
    var(--sf-bg);
}
.sf-mesh--shader > .sf-shader { position: absolute; inset: 0; }
.sf-mesh--shader > .sf-shader canvas {
  display: block;
  width: 100% !important;
  height: 100% !important;
}

/* ---- Animated shader backdrop for full-bleed sections (see assets/js/flow-shader.js) ----
   Used behind #proces and #pakketten. Kept subtle so the frosted cards stay readable:
   muted opacity, soft edge masks, and a vignette that fades the whole thing into --sf-bg. */
.sf-flow-mesh {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  /* Static radial fallback if WebGL can't load (canvas stays empty). */
  background:
    radial-gradient(70% 60% at 50% 50%, var(--sf-violet) 0%, transparent 70%),
    var(--sf-bg);
}
.sf-flow-mesh > canvas {
  display: block;
  width: 100%;
  height: 100%;
  opacity: 0.55;
  /* Feather all four edges so the animation melts into the page instead of ending hard. */
  -webkit-mask-image:
    linear-gradient(to bottom, transparent 0%, #000 18%, #000 82%, transparent 100%),
    linear-gradient(to right, transparent 0%, #000 12%, #000 88%, transparent 100%);
  mask-image:
    linear-gradient(to bottom, transparent 0%, #000 18%, #000 82%, transparent 100%),
    linear-gradient(to right, transparent 0%, #000 12%, #000 88%, transparent 100%);
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
}
/* Tint + top/bottom blend into the surrounding dark sections. */
.sf-flow-mesh-vignette {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to bottom, var(--sf-bg) 0%, transparent 22%, transparent 78%, var(--sf-bg) 100%),
    rgba(12, 10, 22, 0.32);
}

/* ---- Auto-hide header: slides up out of view once the hero (colour mesh) scrolls past ---- */
.sf-header {
  transition: transform 0.5s cubic-bezier(0.4, 0, 0.2, 1);
  will-change: transform;
}
.sf-header.is-hidden { transform: translateY(-100%); }
@media (prefers-reduced-motion: reduce) {
  .sf-header { transition: none; }
}

/* ---- Platform mockup: scroll-scrubbed zoom-to-fill (desktop, JS-driven) ---- */
[data-platform-zoom] {
  transform-origin: center center;
  will-change: transform;
  backface-visibility: hidden;
}

/* ---- Scroll reveal ---- */
[data-reveal] {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 0.6s cubic-bezier(0.16, 1, 0.3, 1), transform 0.6s cubic-bezier(0.16, 1, 0.3, 1);
  transition-delay: var(--reveal-delay, 0ms);
}
[data-reveal].is-visible { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  [data-reveal] { opacity: 1; transform: none; transition: none; }
}

/* ---- Examples deck marquee ---- */
.sf-deck-track {
  animation: sf-marquee 48s linear infinite;
  /* No compositing hints (will-change / translateZ): forcing a GPU layer while
     the track animates, then losing it on pause, is what re-rounds the position
     and makes it "jump". Staying on the main thread keeps the rounding consistent. */
}
.sf-deck:hover .sf-deck-track,
.sf-deck:focus-within .sf-deck-track { animation-play-state: paused; }
@keyframes sf-marquee {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}
.sf-deck { overflow-x: hidden; }
@media (prefers-reduced-motion: reduce) {
  .sf-deck-track { animation: none; }
  .sf-deck { overflow-x: auto; }
}
.sf-card {
  position: relative;
  aspect-ratio: 9 / 16;
  width: 200px;
  flex: 0 0 auto;
  border-radius: 1rem;
  border: 1px solid var(--sf-border);
  overflow: hidden;
  background: linear-gradient(150deg, var(--sf-indigo) 0%, var(--sf-violet) 50%, var(--sf-pink) 100%);
  box-shadow: 0 20px 40px -24px rgba(0, 0, 0, 0.8);
}
/* Smaller reels on phones so more than one is visible at a time. */
@media (max-width: 640px) { .sf-card { width: 150px; } }
@media (min-width: 768px) { .sf-card { width: 248px; } }
.sf-card video, .sf-card img { width: 100%; height: 100%; object-fit: cover; display: block; }
.sf-card-play {
  position: absolute; inset: 0; display: grid; place-items: center; color: rgba(255,255,255,0.9);
}

/* ---- Hero phone mockup ---- */
.sf-phone { width: 100%; max-width: 430px; }
.sf-phone__frame {
  position: relative;
  /* iPhone-17-like proportions; height-capped so the phone always fits the
     hero viewport and grows a bit wider on tall screens (never past max-width). */
  aspect-ratio: 9 / 19.5;
  height: min(82svh, 880px);
  max-width: 100%;
  margin-inline: auto;
  padding: 0.6rem;
  border-radius: 2.75rem;
  background: #0b0a12;
  border: 1px solid rgba(255, 255, 255, 0.08);
  box-shadow:
    0 0 0 1px rgba(255, 255, 255, 0.04) inset,
    0 30px 80px -24px rgba(190, 24, 93, 0.45),
    0 40px 80px -32px rgba(0, 0, 0, 0.9);
}
/* On phones, cap the mockup height so the hero (heading + phone + buttons)
   lands close to a single screen instead of ~1.7. */
@media (max-width: 640px) {
  .sf-phone__frame { height: min(54svh, 520px); }
}
/* Nudge the phone a little lower than the centered text, and a touch left,
   on desktop. */
@media (min-width: 1024px) {
  .sf-phone { transform: translate(-2.5rem, 2.5rem); }
}
.sf-phone__island {
  position: absolute; top: 1.05rem; left: 50%; transform: translateX(-50%);
  width: 30%; height: 1.05rem; border-radius: 999px; background: #000; z-index: 3;
}
.sf-phone__screen {
  position: relative; height: 100%; width: 100%;
  border-radius: 2.1rem; overflow: hidden; background: #15131c;
}
.sf-phone__iframe {
  position: absolute; inset: 0; height: 100%; width: 100%;
  border: 0; opacity: 0; transition: opacity .5s ease;
}
.sf-phone__iframe.is-loaded { opacity: 1; }
.sf-phone__loader {
  position: absolute; inset: 0; display: grid; place-items: center; gap: .65rem;
  transition: opacity .5s ease;
}
.sf-phone__loader.is-hidden { opacity: 0; }
.sf-phone__spinner {
  height: 2.25rem; width: 2.25rem; border-radius: 999px;
  border: 2px solid rgba(255, 255, 255, 0.2); border-top-color: #be185d;
  animation: sf-phone-spin .8s linear infinite;
}
.sf-phone__loadlabel { font-size: .75rem; color: rgba(245, 243, 255, 0.5); }
@keyframes sf-phone-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .sf-phone__spinner { animation: none; }
}

/* ---- Hero phone coachmarks ---- */
.sf-coach {
  position: absolute; inset: 0; z-index: 4;
  pointer-events: none; /* taps pass through to the iframe */
  transition: opacity .5s ease;
}
.sf-coach.is-dismissed { opacity: 0; }
.sf-coach__chip {
  position: absolute; transform: translate(-50%, -50%);
  display: flex; align-items: center; gap: .5rem;
  opacity: 0; transition: opacity .4s ease;
}
.sf-coach__chip.is-active { opacity: 1; }
.sf-coach__ring {
  position: relative; flex: none; height: 1.4rem; width: 1.4rem;
  border-radius: 999px; background: #be185d;
  box-shadow: 0 0 0 6px rgba(190, 24, 93, 0.25);
}
.sf-coach__ring::after {
  content: ""; position: absolute; inset: 0; border-radius: 999px;
  border: 2px solid #be185d;
  animation: sf-coach-pulse 1.8s ease-out infinite;
}
.sf-coach__label {
  white-space: nowrap; border-radius: 999px;
  background: rgba(12, 10, 22, 0.92); border: 1px solid rgba(255, 255, 255, 0.1);
  padding: .35rem .7rem; font-size: .72rem; color: #f5f3ff;
  backdrop-filter: blur(6px);
}
.sf-coach__label b { color: #f472b6; font-family: "Geist Mono", ui-monospace, monospace; }
.sf-coach__nudge {
  position: absolute; bottom: -1.6rem; left: 50%; transform: translateX(-50%);
  white-space: nowrap; font-size: .75rem; color: rgba(245, 243, 255, 0.65);
}
.sf-coach__close {
  pointer-events: auto; position: absolute; top: .5rem; right: .5rem;
  border-radius: 999px; background: rgba(12, 10, 22, 0.8);
  border: 1px solid rgba(255, 255, 255, 0.12);
  padding: .2rem .6rem; font-size: .68rem; color: rgba(245, 243, 255, 0.7);
}
.sf-coach__close:hover { color: #f5f3ff; }
.sf-coach__close:focus-visible { outline: 2px solid #f472b6; outline-offset: 2px; }
@keyframes sf-coach-pulse {
  0%   { transform: scale(1);   opacity: .8; }
  100% { transform: scale(2.4); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .sf-coach__chip { transition: none; }
  .sf-coach__ring::after { animation: none; }
}
