/* ============================================================================
   MOTION — every effect from the approved design, mobile-first.

   Ported from final.html and index.html; see DESIGN_MAP.md for the line
   ranges each one came from. Phone is the base. Anything that costs a phone
   more than it gives it is behind a min-width or a hover query.

   Order here follows the map:
     1 nav squiggle · 2 gradient shimmer · 3 typing · 4 aurora · 12 back-to-top
   ============================================================================ */


/* --- 1 · Nav squiggle underline (design: index.html line) ------------------
   The original draws an SVG path and sweeps it in from 390px. Desktop nav
   only — it is a hover effect, so a phone never loads the work. */

@keyframes bm-line { 0% { background-position-x: 390px; } }

@media (hover: hover) and (min-width: 768px) {
  .bm-nav a {
    position: relative;
    background-repeat: no-repeat;
    background-position: bottom center;
    background-size: 100% 12px;
  }
  .bm-nav a:hover {
    background-image: url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJMYXllcl8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCIgd2lkdGg9IjM5MHB4IiBoZWlnaHQ9IjUwcHgiIHZpZXdCb3g9IjAgMCAzOTAgNTAiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDM5MCA1MCIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+CjxwYXRoIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2Q5NGY1YyIgc3Ryb2tlLXdpZHRoPSIxLjUiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgZD0iTTAsNDcuNTg1YzAsMCw5Ny41LDAsMTMwLDAKCWMxMy43NSwwLDI4Ljc0LTM4Ljc3OCw0Ni4xNjgtMTkuNDE2QzE5Mi42NjksNDYuNSwyNDMuNjAzLDQ3LjU4NSwyNjAsNDcuNTg1YzMxLjgyMSwwLDEzMCwwLDEzMCwwIi8+Cjwvc3ZnPgo=");
    animation: bm-line 1s;
  }
  .bm-nav a:hover { color: var(--raw-red-500); }
}


/* --- 2 · Gradient-text shimmer -------------------------------------------
   A moving gradient clipped to the glyphs. Applied to the hero headline and
   the timeline heading — the two largest pieces of type on the page. */

@keyframes bm-shimmer {
  0%   { background-position:   0 50%; }
  100% { background-position: 100% 50%; }
}

.bm-shimmer {
  background: linear-gradient(90deg,
    var(--raw-white) 0%,
    var(--raw-red-500) 35%,
    var(--raw-white) 70%,
    var(--raw-red-500) 100%);
  background-size: 200% auto;
  background-position: 0 50%;
  background-clip: text;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  animation: bm-shimmer 5s infinite alternate linear;
}

/* On light sections the gradient runs navy into crimson instead. */
.bm-shimmer--dark {
  background-image: linear-gradient(90deg,
    var(--raw-navy-900) 0%,
    var(--raw-red-600) 50%,
    var(--raw-navy-900) 100%);
}


/* --- 3 · Typing heading + cursor ------------------------------------------
   The design measures the typed width in pixels and overrides it per
   breakpoint. Measuring in `ch` instead makes one rule work at every width,
   which is what mobile-first asks for: the text is set in a monospace face,
   so `ch` is exactly one character.

   `--bm-chars` is the character count, set inline per element. */

@keyframes bm-typing { 0% { width: 0; } 100% { width: var(--bm-typed, 100%); } }
@keyframes bm-caret  { 50% { border-color: transparent; } 100% { border-color: var(--action); } }

.bm-typed {
  display: block;
  width: 0;
  max-width: 100%;
  overflow: hidden;
  white-space: nowrap;
  border-right: 3px solid var(--action);
  font-family: var(--font-mono);
  --bm-typed: calc(var(--bm-chars, 20) * 1ch + 0.5ch);
  animation:
    bm-typing 2s steps(var(--bm-chars, 20), end) infinite alternate,
    bm-caret 0.7s step-end infinite;
}

/* Without motion the line is simply present, cursor and all. */
@media (prefers-reduced-motion: reduce) {
  .bm-typed { width: auto; animation: none; border-right-color: transparent; }
  .bm-shimmer { animation: none; }
}


/* --- 4 · Aurora --------------------------------------------------------
   Four blurred blobs whose border-radius morphs as they drift. Four large
   blurred layers is real compositing work, so a phone does not get them:
   the section keeps its navy and its copy and loses only the drift. */

@keyframes bm-aurora-border {
  0%   { border-radius: 37% 29% 27% 27% / 28% 25% 41% 37%; }
  25%  { border-radius: 47% 29% 39% 49% / 61% 19% 66% 26%; }
  50%  { border-radius: 57% 23% 47% 72% / 63% 17% 66% 33%; }
  75%  { border-radius: 28% 49% 29% 100% / 93% 20% 64% 25%; }
  100% { border-radius: 37% 29% 27% 27% / 28% 25% 41% 37%; }
}
@keyframes bm-aurora-1 { 0% { top: 0; right: 0; } 50% { top: 100%; right: 75%; } 75% { top: 100%; right: 25%; } 100% { top: 0; right: 0; } }
@keyframes bm-aurora-2 { 0% { top: -50%; left: 0; } 60% { top: 100%; left: 75%; } 85% { top: 100%; left: 25%; } 100% { top: -50%; left: 0; } }
@keyframes bm-aurora-3 { 0% { bottom: 0; left: 0; } 40% { bottom: 100%; left: 75%; } 65% { bottom: 40%; left: 50%; } 100% { bottom: 0; left: 0; } }
@keyframes bm-aurora-4 { 0% { bottom: -50%; right: 0; } 50% { bottom: 0; right: 40%; } 90% { bottom: 50%; right: 25%; } 100% { bottom: -50%; right: 0; } }

.bm-aurora {
  position: absolute;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
  display: none;
}

.bm-aurora__item {
  position: absolute;
  width: 60%;
  height: 60%;
  filter: blur(80px);
  opacity: 0.55;
}

@media (min-width: 768px) {
  .bm-aurora { display: block; }

  .bm-aurora__item:nth-of-type(1) {
    top: -50%;
    background-color: var(--raw-red-600);
    animation: bm-aurora-border 6s ease-in-out infinite, bm-aurora-1 12s ease-in-out infinite alternate;
  }
  .bm-aurora__item:nth-of-type(2) {
    right: 0; top: 0;
    background-color: var(--raw-navy-700);
    animation: bm-aurora-border 6s ease-in-out infinite, bm-aurora-2 12s ease-in-out infinite alternate;
  }
  .bm-aurora__item:nth-of-type(3) {
    left: 0; bottom: 0;
    background-color: var(--raw-red-500);
    animation: bm-aurora-border 6s ease-in-out infinite, bm-aurora-3 8s ease-in-out infinite alternate;
  }
  .bm-aurora__item:nth-of-type(4) {
    right: 0; bottom: -50%;
    background-color: var(--raw-navy-800);
    animation: bm-aurora-border 6s ease-in-out infinite, bm-aurora-4 24s ease-in-out infinite alternate;
  }
}

@media (prefers-reduced-motion: reduce) {
  .bm-aurora { display: none; }
}

/* Anything sitting over the aurora needs its own stacking level. */
.bm-section--aurora { position: relative; isolation: isolate; overflow: hidden; }
.bm-section--aurora > .bm-container { position: relative; z-index: 2; }


/* --- 9 · Reveal base state -------------------------------------------------
   GSAP animates these to their resting values. If GSAP never loads, the
   no-js rule below puts everything back, so nothing is ever invisible. */

[data-reveal] { opacity: 0; transform: translateY(24px); }

html.bm-no-motion [data-reveal],
html.bm-no-motion [data-reveal-group] > * {
  opacity: 1 !important;
  transform: none !important;
}


/* --- 12 · Back to top ------------------------------------------------------
   Sits above the mobile action bar, appears past 600px of scroll. */

.bm-totop {
  position: fixed;
  right: var(--gutter);
  bottom: calc(var(--actionbar-h) + var(--sp-3));
  z-index: 55;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--surface-brand);
  border: 1px solid var(--border-inverse);
  color: var(--text-inverse);
  box-shadow: var(--shadow-2);
  opacity: 0;
  visibility: hidden;
  transform: translateY(8px);
  transition: opacity var(--speed) var(--ease),
              visibility var(--speed) var(--ease),
              transform var(--speed) var(--ease),
              background-color var(--speed) var(--ease);
}
.bm-totop.is-visible { opacity: 1; visibility: visible; transform: translateY(0); }
.bm-totop:hover { background: var(--action); border-color: var(--action); }

@media (min-width: 768px) {
  .bm-totop { bottom: var(--sp-5); }
}
