/* ============================================================
   Interloop — shared stylesheet
   Design system: Phase 2 tokens (navy / slate / signal cyan / amber)
   ============================================================ */

html { scroll-behavior: smooth; scroll-padding-top: 90px; }
body { -webkit-font-smoothing: antialiased; }

/* ---------- Type utilities ---------- */
.eyebrow   { font-size:.8125rem; font-weight:600; letter-spacing:.08em; text-transform:uppercase; }
.h-display { font-family:'Manrope',sans-serif; font-weight:800; letter-spacing:-.025em; line-height:1.05; }
.h2        { font-family:'Manrope',sans-serif; font-weight:700;  letter-spacing:-.02em;  line-height:1.14; }
.h3        { font-family:'Manrope',sans-serif; font-weight:600;  letter-spacing:-.015em; line-height:1.25; }
.prose-body p { margin-bottom: 1.15rem; }
.prose-body p:last-child { margin-bottom: 0; }

/* ---------- Scroll reveal ---------- */
.reveal { opacity:0; transform:translateY(16px);
  transition:opacity .55s cubic-bezier(.22,1,.36,1), transform .55s cubic-bezier(.22,1,.36,1); }
.reveal.in { opacity:1; transform:none; }

/* ---------- Nav underline ---------- */
.link-underline { position:relative; }
.link-underline::after {
  content:''; position:absolute; left:0; bottom:-6px; height:2px; width:100%;
  background:#00A8CC; transform:scaleX(0); transform-origin:left;
  transition:transform .2s cubic-bezier(.22,1,.36,1);
}
.link-underline:hover::after,
.link-underline[aria-expanded="true"]::after,
.link-underline.is-active::after { transform:scaleX(1); }
.link-underline.is-active { color:#fff; }

/* ---------- Ambient motion ---------- */
.node-pulse { animation:pulse 2.8s ease-in-out infinite; }
@keyframes pulse { 0%,100%{opacity:.35} 50%{opacity:1} }
.dash-run { stroke-dasharray:4 6; animation:run 3s linear infinite; }
@keyframes run { to { stroke-dashoffset:-40; } }

/* ---------- Focus ---------- */
:focus-visible { outline:2px solid #00A8CC; outline-offset:3px; border-radius:2px; }

/* ---------- Forms (on navy) ---------- */
.form-field {
  background:rgba(255,255,255,.06); border:1px solid rgba(255,255,255,.16);
  color:#fff; border-radius:8px; padding:.7rem .9rem; width:100%; font-size:.9375rem;
  transition:border-color .15s, box-shadow .15s;
}
.form-field::placeholder { color:#8A99A8; }
.form-field:focus { outline:none; border-color:#00A8CC; box-shadow:0 0 0 3px rgba(0,168,204,.22); }
.form-field option { color:#1C2530; }

/* ---------- Image frames ---------- */
.logo-frame {
  background:#fff; border:1px solid #D9E1E8; border-radius:12px;
  display:grid; place-items:center; padding:1.5rem; min-height:120px;
  transition:border-color .2s cubic-bezier(.22,1,.36,1), transform .2s cubic-bezier(.22,1,.36,1);
}
.logo-frame:hover { border-color:#00A8CC; transform:translateY(-2px); }
.logo-frame img { max-height:56px; width:auto; object-fit:contain; }

/* Certificates are documents, not photographs: show the whole page rather
   than cropping into the blank paper at the centre. Portrait and landscape
   scans therefore both sit inside the same 4:3 frame. */
.cert-thumb {
  width:100%; aspect-ratio:4/3; object-fit:contain; object-position:center;
  background:#F4F7F9; border-bottom:1px solid #D9E1E8; padding:.75rem;
}

.product-shot {
  width:100%; aspect-ratio:4/3; object-fit:contain; background:#F4F7F9; padding:1.25rem;
}

/* ---------- Lightbox ---------- */
#lightbox {
  position:fixed; inset:0; z-index:80; background:rgba(8,21,39,.92);
  display:none; align-items:center; justify-content:center; padding:2rem;
}
#lightbox.open { display:flex; }
#lightbox img { max-width:min(900px,92vw); max-height:86vh; border-radius:8px; background:#fff; }

/* ---------- Reduced motion ---------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior:auto; }
  .reveal { opacity:1 !important; transform:none !important; transition:none !important; }
  .node-pulse, .dash-run { animation:none !important; }
  *, *::before, *::after { animation-duration:.001ms !important; transition-duration:.001ms !important; }
}

/* ---------- Product plate (for SKUs without a photograph) ---------- */
.product-plate {
  width:100%; aspect-ratio:4/3; background:#F4F7F9;
  display:grid; place-items:center; position:relative; overflow:hidden;
}
.product-plate::before {
  content:''; position:absolute; inset:0;
  background-image:linear-gradient(#D9E1E8 1px, transparent 1px),
                   linear-gradient(90deg, #D9E1E8 1px, transparent 1px);
  background-size:22px 22px; opacity:.55;
}
.product-plate span {
  position:relative; font-family:'JetBrains Mono', ui-monospace, monospace;
  font-size:.8125rem; letter-spacing:.14em; color:#4A5A6B;
  background:#fff; border:1px solid #D9E1E8; border-radius:6px; padding:.6rem 1.1rem;
}

/* ============================================================
   Hero video (index)
   The master is native 1920x1080 at 24fps, so the footage is shown
   SHARP — no blur, no dimming. The earlier clip was 480x220 and had
   to be defocused to hide the upscaling; that treatment is gone.

   Contrast for the copy is bought entirely by the scrim below,
   which is weighted over the left half where the text sits and
   thins out to almost nothing on the right, so the traffic and the
   lit towers stay plainly visible.
   ============================================================ */
.hero-stage { position:relative; overflow:hidden; isolation:isolate; }

.hero-media {
  position:absolute; inset:0; overflow:hidden; pointer-events:none; z-index:0;
  background:#0D2440 linear-gradient(155deg,#16406B 0%,#0D2440 52%,#081527 100%);
}

/* The still is a frame of the same clip and carries the same treatment,
   so it sits invisibly behind the video. It is what the hero falls back
   to whenever the video cannot run — reduced motion, small screens,
   blocked autoplay, a codec the browser refuses — and it means the city
   is never simply missing. */
.hero-media__still,
.hero-media__video {
  position:absolute; inset:0; width:100%; height:100%; max-width:none;
  -o-object-fit:cover; object-fit:cover; object-position:center 45%;
  /* Only enough overscan to crop the encoder's edge rows. */
  transform:scale(1.04);
  /* Shown straight. The saturation and contrast lift is cosmetic —
     it pushes the sodium street lighting toward the brand amber and
     the tower glow toward the signal cyan; it does not dim anything. */
  filter:saturate(1.18) contrast(1.06);
  opacity:1;
}
.hero-media__still {
  background:url('../img/hero-city-lights.jpg') center 42%/cover no-repeat;
}
/* No JS gate on visibility: the markup autoplays on its own, so a script
   failure costs the motion, never the picture. */

/* Weighted to the left where the copy sits and almost clear by the
   right edge, so the lights stay plainly visible; the top band hides
   the seam under the sticky header and the bottom band fades into
   the navy-700 client bar.

   This is deliberately the LIGHT half of the contrast budget, and it
   is paired with the text-shadow below. A scrim heavy enough to carry
   the copy on its own was measured against this clip at 6.6 mean
   luminance over the right third of the frame, where the lit towers
   are; this one leaves that at 9.0 — 37% brighter — for text contrast
   within 0.4 of the same. The difference is bought by protecting the
   letterforms locally rather than dimming the picture. */
.hero-media__scrim {
  position:absolute; inset:0;
  background:
    linear-gradient(90deg, rgba(13,36,64,.90) 0%, rgba(13,36,64,.82) 42%, rgba(13,36,64,.44) 60%, rgba(13,36,64,.11) 78%, rgba(13,36,64,.03) 100%),
    linear-gradient(180deg, rgba(13,36,64,.38) 0%, rgba(13,36,64,0) 18%, rgba(13,36,64,0) 66%, rgba(13,36,64,.66) 100%);
}

/* text-shadow inherits, so one declaration on the wrapper covers the
   eyebrow, headline, body copy and the stat row.

   This is load-bearing, not decoration. The footage is sharp and
   undimmed now, so a headlight or a lit window can sit directly
   against a letterform. Worst-case contrast over the background ring
   within 2px of the glyph edges, sampled across the whole loop:

                        headline   body copy
     scrim alone          3.53        4.46     <- body misses AA
     scrim + this shadow  4.95        5.04     <- both clear AA

   so the shadow is what carries the body copy over 4.5:1 and lets
   the scrim stay light enough for the city to read. */
.hero-copy { text-shadow:0 1px 2px rgba(8,21,39,.70), 0 2px 16px rgba(8,21,39,.62); }
/* The buttons carry their own solid grounds — a shadow on the amber
   CTA's navy label would only muddy it. */
.hero-cta { text-shadow:none; }

.hero-media__grid { position:absolute; inset:0; opacity:.28; }

/* 768-1023px still plays the video but the copy runs full-bleed
   across it, so the directional scrim gives way to an even one. */
@media (max-width:1023px) {
  /* The copy crosses the whole frame here, so there is no calm side
     left to lean on and the ramp has to be even. It also has to be
     heavier than the desktop one rather than lighter: at this width
     the body copy sits over the CENTRE of the shot, which is its
     brightest part. Measured at 900px, the even ramp the desktop
     numbers would suggest left the body copy at 3.5:1; this is the
     lightest one that clears 4.5 (measured 4.9). */
  .hero-media__scrim {
    background:linear-gradient(180deg, rgba(13,36,64,.72) 0%, rgba(13,36,64,.68) 45%, rgba(13,36,64,.84) 100%);
  }
  .hero-media__still,
  .hero-media__video { opacity:.95; }
}

/* The outline CTA needs a backdrop of its own now that the panel
   behind it is moving footage rather than flat navy. */
.hero-btn-ghost {
  color:#D9E1E8; background:rgba(13,36,64,.45);
  border:1px solid rgba(255,255,255,.28);
  -webkit-backdrop-filter:blur(6px); backdrop-filter:blur(6px);
  transition:color .15s, border-color .15s, background-color .15s;
}
.hero-btn-ghost:hover { color:#fff; border-color:#00A8CC; background:rgba(13,36,64,.62); }

@media (prefers-reduced-motion: reduce) {
  /* Motion goes, the city stays: the still underneath carries the hero. */
  .hero-media__video { display:none; }
}
