/* ==========================================================================
   MOTION LAYER · avatar shell, choreographed reveals, scroll depth
   Loaded after bw-editorial.css. Uses the individual `translate` / `scale`
   properties so nothing here fights the existing `transform` declarations
   (reveal, tilt, stagger offsets, hover).
   ========================================================================== */

:root {
  --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-soft: cubic-bezier(0.22, 1, 0.36, 1);
}

/* --------------------------------------------------------------------------
   1. AVATAR · shell for the WebGL memoji (avatar-depth.js does the motion)
   -------------------------------------------------------------------------- */
.avatar-visual-wrap {
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  outline: none;
}

.avatar-visual-wrap:focus-visible {
  outline: 2px solid var(--ice-deep);
  outline-offset: 4px;
  border-radius: 28px;
}

.avatar-rig {
  position: relative;
  z-index: 3;
  width: 100%;
  height: 100%;
}

.avatar-float {
  position: relative;
  width: 100%;
  height: 100%;
  animation: heroBikerFloat 5.4s ease-in-out infinite alternate 1.25s;
}

/* Depth-rigged WebGL memoji (avatar-depth.js). The <img> is the poster until
   the first frame lands, and the fallback without WebGL. */
.avatar-canvas {
  position: absolute;
  inset: 0;
  z-index: 4;
  width: 100%;
  height: 100%;
  display: block;
  pointer-events: none;
}

/* The soft shadow is a static silhouette, painted once: a drop-shadow on the
   live canvas would be re-blurred on every frame. */
.avatar-visual-wrap img.avatar-shadow {
  position: absolute;
  inset: 0;
  z-index: 3;
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: bottom center;
  pointer-events: none;
  filter: brightness(0) blur(21px);
  opacity: 0.22;
  translate: 0 22px;
  will-change: translate;
}

.avatar-visual-wrap.is-3d img:not(.avatar-shadow) {
  visibility: hidden;
}

.avatar-visual-wrap:not(.is-3d) .avatar-shadow {
  display: none;
}

/* breathing and sway now come from the rig, not a CSS bob */
.avatar-visual-wrap.is-3d .avatar-float {
  animation: none;
}

/* --------------------------------------------------------------------------
   1b. SCROLLBAR · a thin slate pill floating on a clear track
   -------------------------------------------------------------------------- */
::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}

::-webkit-scrollbar-track {
  background: transparent;
}

::-webkit-scrollbar-thumb {
  background: rgba(100, 116, 139, 0.42);
  border: 3px solid transparent;
  border-radius: 999px;
  background-clip: padding-box;
}

::-webkit-scrollbar-thumb:hover {
  background-color: rgba(71, 85, 105, 0.68);
}

::-webkit-scrollbar-corner {
  background: transparent;
}

/* The track shows the root background: it follows the plane under the middle
   of the screen (bw-engine.js §3 sets html[data-sb]). */
html { background-color: #F4F7FA; transition: background-color 0.35s ease; }
html[data-sb="black"] { background-color: #07090D; }

html[data-sb="black"]::-webkit-scrollbar-thumb {
  background-color: rgba(194, 214, 232, 0.34);
}

html[data-sb="black"]::-webkit-scrollbar-thumb:hover {
  background-color: rgba(194, 214, 232, 0.6);
}

@supports not selector(::-webkit-scrollbar) {
  html {
    scrollbar-width: thin;
    scrollbar-color: rgba(100, 116, 139, 0.5) transparent;
  }
}

/* --------------------------------------------------------------------------
   1c. SHEETS · each section is a sheet laid over the previous one
   (bw-engine.js §1B moves the sheet being left and dims it via .sheet-veil)
   -------------------------------------------------------------------------- */
main > section.plane-white { background-color: #F4F7FA; }
main > section.plane-black { background-color: #07090D; }

main > section + section {
  border-radius: 30px 30px 0 0;
  box-shadow:
    0 -1px 0 rgba(194, 214, 232, 0.12),
    0 -28px 64px -18px rgba(7, 9, 13, 0.34);
}

.sheet-veil {
  position: absolute;
  inset: 0;
  z-index: 40;
  background: #07090D;
  opacity: 0;
  pointer-events: none;
}

#hero .hero-studio-frame {
  transform-origin: 50% 35%;
}

/* The sheet motion is a scroll-driven animation, so it runs on the
   compositor in lockstep with the native scroll: no JS frame in between,
   nothing trails or wobbles. Range: from the moment the next section's top
   reaches the bottom of the screen (exit 0%) to the moment it reaches the
   top (exit 100%). Outside that range nothing applies, so a sheet is only
   a layer while it is being covered. The sheet slides only with a fine
   pointer; on touch screens it just dims. */
@supports (animation-timeline: view()) {
  main > section > .sheet-veil {
    animation: sheet-dim linear none;
    animation-timeline: view();
    animation-range: exit 0% exit 100%;
  }

  main > section.plane-white > .sheet-veil { --veil-max: 0.36; }

  @media (hover: hover) and (pointer: fine) {
    main > section:has(> .sheet-veil) {
      animation: sheet-recede linear none;
      animation-timeline: view();
      animation-range: exit 0% exit 100%;
    }
  }
}

@keyframes sheet-dim {
  0% { opacity: 0; }
  50% { opacity: calc(var(--veil-max, 0.24) * 0.25); }
  100% { opacity: var(--veil-max, 0.24); }
}

@keyframes sheet-recede {
  from { transform: translate3d(0, 0, 0); }
  to { transform: translate3d(0, calc(100vh * var(--sheet-lag, 0.12)), 0); }
}

@media (max-width: 992px) {
  main > section { --sheet-lag: 0.1; }
}

@media (max-width: 992px) {
  main > section + section {
    border-radius: 22px 22px 0 0;
  }
}

/* --------------------------------------------------------------------------
   1d. ICONS · the site's own set (design canvas). A flat chip with the
   faintest vertical shade, in the same colours as every other chip of its
   plane; on it a solid glyph with one lit node (gradients in the .gi-defs
   block at the top of <body>). Ice glyphs on black, steel glyphs on white.
   -------------------------------------------------------------------------- */
.gico,
.bcell-ico.gico,
.clink .clink-ico.gico {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  box-sizing: border-box;
  background: linear-gradient(180deg, rgba(194, 214, 232, 0.13) 0%, rgba(194, 214, 232, 0.06) 100%);
  border: 1px solid rgba(194, 214, 232, 0.16);
  box-shadow: none;
}

.gico svg {
  display: block;
  overflow: visible;
}

/* white plane: frost chip, steel glyph */
.plane-white .gico,
.clink .clink-ico.gico {
  background: linear-gradient(180deg, #F3F7FB 0%, #E6EDF5 100%);
  border-color: rgba(15, 23, 42, 0.06);
}

.plane-white .gico [fill="url(#gi-ice)"] { fill: url(#gi-steel-ink); }
.plane-white .gico [stroke="url(#gi-ice-s)"] { stroke: url(#gi-steel-ink-s); }
.plane-white .gico [stroke="url(#gi-brawn)"] { stroke: url(#gi-steel-ink-b); }
.plane-white .gico [fill="url(#gi-acc)"] { fill: url(#gi-acc-deep); }

/* dark pills (primary, and any pill on hover) go back to ice */
.clink.clink-primary .clink-ico.gico,
.clink:hover .clink-ico.gico {
  background: linear-gradient(180deg, rgba(194, 214, 232, 0.2) 0%, rgba(194, 214, 232, 0.09) 100%);
  border-color: rgba(194, 214, 232, 0.2);
}

.clink.clink-primary .gico [fill="url(#gi-ice)"],
.clink:hover .gico [fill="url(#gi-ice)"] { fill: url(#gi-ice); }
.clink.clink-primary .gico [fill="url(#gi-acc)"],
.clink:hover .gico [fill="url(#gi-acc)"] { fill: url(#gi-acc); }
.clink:hover .gico [stroke="url(#gi-brawn)"] { stroke: url(#gi-brawn); }

/* specs rows */
.sk-ico.gico { width: 34px; height: 34px; border-radius: 9px; }
.sk-ico.gico svg { width: 21px; height: 21px; }

/* "other hours" cards */
.bcell-ico.gico { width: 48px; height: 48px; border-radius: 13px; }
.bcell-ico.gico svg { width: 30px; height: 30px; }
.bcell:hover .bcell-ico.gico { transform: translateY(-2px); }

/* contact pills */
.clink-ico.gico { width: 30px; height: 30px; border-radius: 50%; }
.clink-ico.gico svg { width: 17px; height: 17px; }

/* interface glyphs */
.nav-cta i svg { width: 14px; height: 14px; }
.modal-close svg { width: 20px; height: 20px; }
.modal-close {
  background: linear-gradient(180deg, #1C2431 0%, #0B0E14 100%);
  border-color: rgba(194, 214, 232, 0.24);
  box-shadow: 0 10px 24px -10px rgba(0, 0, 0, 0.7), inset 0 1px 0 rgba(255, 255, 255, 0.1);
}
.modal-btn svg { width: 13px; height: 13px; }
.c-btn svg { width: 22px; height: 22px; }
.c-btn .gi-line { stroke: url(#gi-ice-s); transition: stroke 0.25s var(--ease); }
.c-btn:hover .gi-line { stroke: #0B0F17; }

/* --------------------------------------------------------------------------
   1e. PROJECT ART · project stages are drawn in the carved-ice language in
   index.html (.stage-art). The four domain cards keep their glass and blur.
   -------------------------------------------------------------------------- */
.stage-art { transition: transform 0.6s var(--ease); }

.pcard-stage {
  background:
    radial-gradient(70% 90% at 55% 78%, rgba(194, 214, 232, 0.1), rgba(194, 214, 232, 0) 70%),
    linear-gradient(145deg, #0D121B 0%, #070A10 100%);
}

/* --------------------------------------------------------------------------
   1f. SIGNATURE · written by the scroll (bw-engine.js §1C sets --sig 0..1)
   -------------------------------------------------------------------------- */
.signature-block { position: relative; }

/* Hurricane's loops reach well outside a 0.9 line box; the mask clips to the
   box, so give the glyphs room and take it back with negative margins. */
.signature-script {
  padding: 0.4em 0.35em;
  margin: -0.4em -0.35em;
}

.signature-script.is-writing {
  -webkit-mask-image: linear-gradient(100deg, #000 0, #000 calc(var(--sig, 0) * 116% - 14%), transparent calc(var(--sig, 0) * 116% - 2%));
          mask-image: linear-gradient(100deg, #000 0, #000 calc(var(--sig, 0) * 116% - 14%), transparent calc(var(--sig, 0) * 116% - 2%));
}

.sig-nib {
  position: absolute;
  left: -4px;
  top: -4px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: radial-gradient(circle, #FFFFFF 0%, #E6EFF7 45%, rgba(194, 214, 232, 0) 72%);
  box-shadow: 0 0 14px 4px rgba(194, 214, 232, 0.45);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.25s ease;
}

/* --------------------------------------------------------------------------
   2. REVEAL · one motion language for every entrance below the hero
      Short rise + fade, one expo-out curve, one duration, 70ms steps. No
      scale: a running `scale` transition re-lays out the text inside on
      every frame. bw-engine.js adds .rv-item, then .is-visible a little
      before the element reaches the viewport, then .rv-done once the
      entrance has finished (which hands `transition` back to each
      component's own hover styles). One-shot: nothing re-animates on the
      way back up.
   -------------------------------------------------------------------------- */
:root {
  --m-ease: cubic-bezier(0.16, 1, 0.3, 1);
  --m-dur: 1.3s;
  --m-fade: 1s;
  --m-step: 90ms;
  --m-rise: 26px;
}

@media (max-width: 760px) {
  :root {
    --m-rise: 16px;
  }
}

.rv-item:not(.rv-done) {
  transition:
    opacity var(--m-fade) var(--m-ease),
    translate var(--m-dur) var(--m-ease);
}

.rv-item:not(.is-visible) {
  opacity: 0;
  translate: 0 var(--m-rise);
}

.rv-item:not(.rv-done) { transition-property: opacity, translate, scale; transition-duration: var(--m-fade), var(--m-dur), var(--m-dur); transition-timing-function: var(--m-ease); }
.pcard.rv-item:not(.is-visible),
.acard.rv-item:not(.is-visible),
.bcell.rv-item:not(.is-visible),
.graph-stage-card.rv-item:not(.is-visible),
.stack-group.rv-item:not(.is-visible),
.polaroid-stage.rv-item:not(.is-visible),
.film.rv-item:not(.is-visible),
.track.rv-item:not(.is-visible) {
  scale: 0.985;
}

/* Headings and the contact card stay put; their parts rise in sequence:
   eyebrow → title → description. */
.sec-head.rv-item,
.contact-box.rv-item {
  opacity: 1;
  translate: none;
}

.sec-head.rv-item .eyebrow,
.sec-head.rv-item .sec-title,
.sec-head.rv-item .sec-desc,
.contact-box.rv-item .eyebrow,
.contact-box.rv-item .big,
.contact-box.rv-item .clinks {
  transition:
    opacity var(--m-fade) var(--m-ease) var(--m-d, 0s),
    translate var(--m-dur) var(--m-ease) var(--m-d, 0s);
}

.sec-head.rv-item .sec-title,
.contact-box.rv-item .big {
  --m-d: var(--m-step);
}

.sec-head.rv-item .sec-desc,
.contact-box.rv-item .clinks {
  --m-d: calc(var(--m-step) * 2);
}

.sec-head.rv-item:not(.is-visible) .eyebrow,
.sec-head.rv-item:not(.is-visible) .sec-title,
.sec-head.rv-item:not(.is-visible) .sec-desc,
.contact-box.rv-item:not(.is-visible) .eyebrow,
.contact-box.rv-item:not(.is-visible) .big,
.contact-box.rv-item:not(.is-visible) .clinks {
  opacity: 0;
  translate: 0 var(--m-rise);
}

.sec-head.rv-item .eyebrow::before,
.contact-box.rv-item .eyebrow::before {
  transition: scale var(--m-dur) var(--m-ease) var(--m-step);
}

.sec-head.rv-item:not(.is-visible) .eyebrow::before,
.contact-box.rv-item:not(.is-visible) .eyebrow::before {
  scale: 0;
}

/* --------------------------------------------------------------------------
   3. PILLAR CARDS · scroll depth (desktop). motion.js eases --par toward the
      scroll position; it rides the same `translate` channel as the reveal.
   -------------------------------------------------------------------------- */
.scard {
  translate: 0 var(--par, 0px);
}

.scard.rv-item:not(.is-visible) {
  translate: 0 calc(var(--m-rise) + var(--par, 0px));
}

.scard.is-drifting {
  will-change: translate;
}

/* Hero stats decode (bw-engine.js §12): characters not yet locked. */
.hr-stat-n .scr,
.hr-stat-l .scr { color: var(--ice-deep, #5B7A96); opacity: 0.55; }

/* The four grounds: dark, dark→light, light→dark, light. The first and last
   carry their own soft streaks in the same blurred light as the middle two,
   quieter, so none of the four is flat. Titles are set larger to hold the
   card. */
.scard:nth-child(1) {
  background:
    radial-gradient(240px 200px at 88% 6%, rgba(148, 180, 206, 0.16) 0%, rgba(148, 180, 206, 0) 70%),
    #10151F;
}

/* 1 · vertical: two shafts of light falling from the top edge */
.scard:nth-child(1)::before {
  content: '';
  position: absolute;
  top: -12%;
  left: 34%;
  width: 62%;
  height: 92%;
  background: linear-gradient(90deg,
    transparent 0%, rgba(230, 239, 247, 0.42) 22%, transparent 40%,
    transparent 56%, rgba(194, 214, 232, 0.26) 70%, transparent 84%);
  -webkit-mask-image: linear-gradient(180deg, #000 0%, rgba(0, 0, 0, 0.55) 45%, transparent 100%);
          mask-image: linear-gradient(180deg, #000 0%, rgba(0, 0, 0, 0.55) 45%, transparent 100%);
  filter: blur(16px);
  transform: rotate(7deg);
  z-index: 1;
  pointer-events: none;
}


/* 4 · curved: one arc of light bending across the top */
.scard:nth-child(4)::before {
  content: '';
  position: absolute;
  top: -66%;
  right: -58%;
  width: 150%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle,
    transparent 50%, rgba(111, 142, 171, 0.2) 55%, rgba(255, 255, 255, 1) 61%,
    rgba(255, 255, 255, 0.85) 65%, rgba(111, 142, 171, 0.42) 71%, transparent 78%);
  filter: blur(11px);
  z-index: 1;
  pointer-events: none;
}

@media (max-width: 720px) {
  .scard:nth-child(4)::before { width: 120%; top: -150%; right: -20%; }
  .scard:nth-child(1)::before { left: 46%; width: 48%; }
}

.scard-bottom h3 {
  font-size: clamp(1.32rem, 1.75vw, 1.62rem);
  line-height: 1.12;
  letter-spacing: -0.032em;
  margin-bottom: 10px;
}

/* Entrance: the cards rise softly in sequence, then a single faint light
   pass crosses the glass. */
.stagger-4-grid { perspective: 1400px; }

.scard { transform-origin: 50% 100%; }

.scard.rv-item:not(.rv-done) {
  transition-property: opacity, translate, scale, rotate;
  transition-duration: var(--m-fade), 1.4s, 1.4s, 1.4s;
  transition-timing-function: var(--m-ease);
}

.scard.rv-item:not(.is-visible) {
  scale: 0.985;
  translate: 0 calc(var(--m-rise) + var(--par, 0px));
}

.scard::after {
  content: '';
  position: absolute;
  inset: -2px;
  z-index: 3;
  pointer-events: none;
  background: linear-gradient(105deg, rgba(255, 255, 255, 0) 36%, rgba(255, 255, 255, 0.12) 50%, rgba(255, 255, 255, 0) 64%);
  translate: -110% 0;
}

.scard.is-visible::after {
  translate: 110% 0;
  transition: translate 1.6s cubic-bezier(0.45, 0, 0.2, 1) calc(0.45s + var(--sc-i, 0) * 0.11s);
}

.scard:nth-child(2) { --sc-i: 1; }
.scard:nth-child(3) { --sc-i: 2; }
.scard:nth-child(4) { --sc-i: 3; }



/* --------------------------------------------------------------------------
   4. INNER PARALLAX · media drifts inside its frame (motion.js writes the
      `translate` of the media itself)
   -------------------------------------------------------------------------- */
.polaroid-photo img,
.film video {
  scale: 1.1;
}

@supports (animation-timeline: view()) {
  .polaroid-photo img,
  .film video {
    animation: inner-drift linear both;
    animation-timeline: view();
    animation-range: cover;
  }
}

@keyframes inner-drift {
  from { translate: 0 4%; }
  to { translate: 0 -4%; }
}

/* --------------------------------------------------------------------------
   5. SPEC CHIPS · the panel arrives, then its rows light up one by one
      (opacity only: the panel already carries the rise)
   -------------------------------------------------------------------------- */
.stack-group.rv-item .sk-v span {
  transition:
    opacity var(--m-fade) var(--m-ease) calc(0.12s + var(--cr, 0) * var(--m-step) + var(--cc, 0) * 18ms),
    border-color 0.3s var(--ease),
    color 0.3s var(--ease);
}

.stack-group.rv-item:not(.is-visible) .sk-v span {
  opacity: 0;
}

/* --------------------------------------------------------------------------
   6. NAVBAR · hairline reading progress
   -------------------------------------------------------------------------- */
.bar-progress {
  position: absolute;
  left: 26px;
  right: 26px;
  bottom: -1px;
  height: 1px;
  border-radius: 1px;
  background: linear-gradient(90deg, transparent, var(--ice) 18%, var(--ice) 82%, transparent);
  transform-origin: 0 50%;
  transform: scaleX(0);
  opacity: 0.75;
  pointer-events: none;
}

#bar[data-plane="white"] .bar-progress {
  background: linear-gradient(90deg, transparent, var(--ice-deep) 18%, var(--ice-deep) 82%, transparent);
  opacity: 0.55;
}

/* --------------------------------------------------------------------------
   7. TOUCH · tactile press feedback instead of hover tilt
   -------------------------------------------------------------------------- */
@media (hover: none) {
  .pcard:active,
  .acard:active,
  .bcell:active,
  .clink:active,
  .c-btn:active {
    scale: 0.985;
  }

  .avatar-visual-wrap:active .avatar-rig {
    filter: brightness(1.03);
  }
}

/* --------------------------------------------------------------------------
   8. WORD-BY-WORD LIGHT-UP · About story (motion.js writes only the words
      whose value changed)
   -------------------------------------------------------------------------- */
.scrub-words .w {
  transition: color 0.12s linear;
}

/* 9. Motion stays on regardless of prefers-reduced-motion (owner's call). */

/* Contact heading: two natural lines, never a lone word. */
.contact-box .big { max-width: 24ch; text-wrap: balance; }
.contact-box .big .big-l { display: block; }

/* Graph HUD: readable on the dark card, and a fixed footprint so tapping a
   node never resizes the card. */
.gh-right { color: rgba(194, 214, 232, 0.62); }

.graph-hud-bottom {
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: center;
  column-gap: 14px;
  row-gap: 8px;
  color: rgba(226, 234, 245, 0.72);
}

.graph-hud-bottom #gi-desc {
  grid-column: 1 / -1;
  line-height: 1.5;
  min-height: 3em;
}

@media (max-width: 720px) {
  .graph-hud-top { padding: 14px 16px; gap: 12px; flex-wrap: nowrap; }
  .gh-left { font-size: 0.6rem; letter-spacing: 0.04em; min-width: 0; }
  .gh-right > span { display: none; }
  .gh-reset { white-space: nowrap; padding: 5px 11px; font-size: 0.62rem; }
  #os-graph-canvas { height: 500px; }
  .graph-hud-bottom { grid-template-columns: 1fr; justify-items: start; padding: 14px 16px; }
  .graph-hud-bottom strong { min-height: 2.7em; line-height: 1.35; }
  .graph-hud-bottom #gi-desc { min-height: 4.5em; }

  /* footer: the bat stays on the line, after "made at night" */
  footer { flex-wrap: nowrap; align-items: center; }
  footer > span:first-child { flex: 1 1 auto; min-width: 0; }
  footer .batsig { flex: none; }
}

.ft-chunk { white-space: nowrap; }
@media (max-width: 720px) {
  .ft-sep { display: none; }
  .ft-chunk { display: block; }
  .ft-sep + .ft-chunk::before {
    content: '';
    display: inline-block;
    width: 5px;
    height: 5px;
    margin: 0 8px 0 1px;
    border-radius: 50%;
    background: var(--ice-deep, #5B7A96);
    vertical-align: 0.18em;
  }
}
