/* Harris Flight Pack
   ---------------------------------------------------------------------------
   The page is a relay chase. A single pursuit line runs through the whole
   composition; every piece of content sits at a handoff waypoint on it, and
   three raptors fly the line in sequence. Each leg is shorter than the last —
   a fresh bird covers ground faster than the one it relieved — and within a leg
   the easing bursts then decays, which is the bird tiring. That velocity change
   is what makes a handoff read as a handoff rather than as a colour swap.

   Exactly one thing on screen is ever the bright thing. It starts as the lead
   bird and is handed forward down the line; at rest it is the last hawk, still
   pressing at the edge of the frame. (The bird itself is dark everywhere except
   the cere — that law is palette-independent and the only thing worth keeping
   from the old theme.)

   The other half is acuity. A raptor's fovea is razor-sharp and its periphery
   soft, so the page has ONE dense, high-detail region — the readout — inside an
   otherwise vast and sparse field. Density is the acuity gradient, not blur;
   blur would just make the page unreadable.

   Ultraviolet is a mechanic, not a tint. You cannot show a human a colour they
   cannot see, only that a channel exists which they were missing. So violet
   appears nowhere until the 4th-channel switch is thrown — and then it explains
   the geometry: the quarry trail the pack was following all along.
   --------------------------------------------------------------------------- */

@font-face{
  font-family:'Exo 2';
  src:url('../fonts/exo-2-variable.woff2') format('woff2');
  font-weight:100 900;
  font-style:normal;
  font-display:swap;
}

:root{
  color-scheme:dark;

  /* ground — near-black with a faint cool cast: space, not desert */
  --void:#05060A;

  /* ink */
  --bone:#E9E6DF;          /* the white tail band — ~17:1 on void */
  --dim:#828994;           /* secondary — ~5.9:1 on void */
  --faint:#464F5F;         /* the pursuit line and hairlines; never text */

  /* the one bright thing */
  --signal:#FFC61A;

  /* the channel you cannot see, until you can */
  --uv:#B026FF;
  --uv-soft:rgba(176,38,255,.30);

  --mono:ui-monospace,"Cascadia Code","Cascadia Mono",Consolas,monospace;
  --display:'Exo 2',system-ui,-apple-system,"Segoe UI",sans-serif;

  /* burst, then decay: a bird leaving a handoff and tiring across its leg */
  --press:cubic-bezier(0,.62,.36,1);
  /* settle: an entrance arriving */
  --glide:cubic-bezier(.22,.61,.36,1);
}

*,*::before,*::after{box-sizing:border-box}

html{height:100%}
body{
  position:relative;
  min-height:100%;
  margin:0;
  background:var(--void);
  color:var(--bone);
  font-family:var(--display);
  overflow-x:hidden;
  -webkit-font-smoothing:antialiased;
  text-rendering:optimizeLegibility;
}

:focus-visible{
  outline:2px solid var(--signal);
  outline-offset:4px;
  border-radius:2px;
}
::selection{background:var(--signal);color:var(--void)}

/* ── deep field ──────────────────────────────────────────────────────────── */

.field{position:fixed;inset:0;overflow:hidden;pointer-events:none;z-index:0}

/* one element per layer: the whole starfield is box-shadow on a single 1px dot,
   so drift is one compositor transform per layer rather than 700 nodes */
.stars{
  position:absolute;top:0;left:0;width:1px;height:1px;border-radius:50%;
  will-change:transform;animation:drift linear infinite;
}
.s-far {background:#4A505C;animation-duration:300s}
.s-mid {background:#868D99;animation-duration:200s}
.s-near{background:#D2D6DD;animation-duration:130s}
@keyframes drift{
  from{transform:translate3d(0,0,0)}
  to  {transform:translate3d(-160px,110px,0)}
}

/* a single faint arc — the kettle, seen from a very long way out */
.orbit{
  position:absolute;left:50%;top:50%;
  width:min(190vw,1900px);aspect-ratio:1;
  border:1px solid rgba(233,230,223,.045);
  border-radius:50%;
  transform:translate(-50%,-50%);
  animation:kettle 280s linear infinite;
  will-change:transform;
}
.orbit::after{
  content:"";position:absolute;inset:14%;
  border:1px solid rgba(233,230,223,.026);border-radius:50%;
}
@keyframes kettle{
  from{transform:translate(-50%,-50%) rotate(0deg)}
  to  {transform:translate(-50%,-50%) rotate(360deg)}
}

/* a planet limb below the frame — gives the void a floor and a sense of scale */
.limb{
  position:absolute;left:50%;bottom:-142vw;
  width:206vw;aspect-ratio:1;border-radius:50%;
  transform:translateX(-50%);
  border:1px solid rgba(233,230,223,.075);
  background:radial-gradient(circle at 50% 0%,
    rgba(150,170,205,.045) 0%, rgba(150,170,205,.012) 34%, transparent 55%);
}

/* ── the chase ───────────────────────────────────────────────────────────── */
/* width/height/viewBox are set by js/site.js to match the document */

.chase{position:absolute;top:0;left:0;pointer-events:none;z-index:1}

/* Nothing animates until .is-ready. The centred column settles a little after
   first layout, and a path fitted before that lands ~48px off its own content —
   so js/site.js measures until the geometry stops moving and only then arms the
   sequence. Without JS there is no .is-armed either, and the page is simply
   static and fully legible. */
.pursuit .leg{
  fill:none;
  stroke:var(--faint);
  stroke-width:1.6;
  stroke-linecap:butt;
  stroke-linejoin:miter;
  stroke-miterlimit:2;
}
.is-ready .pursuit .leg{animation:draw var(--dur) var(--press) var(--in) both}
/* a wider, dimmer copy under the line: gives the pursuit weight without
   turning the stroke itself into a highlighter */
.pursuit .leg-halo{
  stroke:rgba(255,198,26,.055);
  stroke-width:7;
  filter:blur(3px);
}
@keyframes draw{
  from{stroke-dashoffset:var(--len)}
  to  {stroke-dashoffset:0}
}

/* the quarry's trail — evasive, ahead of the pack, and outside human channels */
.quarry path{
  fill:none;
  stroke:var(--uv);
  stroke-width:1;
  stroke-dasharray:1 7;
  stroke-linecap:round;
  opacity:0;
  transition:opacity .55s var(--glide);
}
.quarry .quarry-glow{
  stroke:var(--uv-soft);
  stroke-width:6;
  stroke-dasharray:none;
  filter:blur(4px);
}

.handoffs g{opacity:0;transition:opacity .5s var(--glide)}
.handoffs circle{fill:none;stroke:var(--uv);stroke-width:1}
.handoffs line{stroke:var(--uv);stroke-width:1}
.handoffs text{
  font-family:var(--mono);font-size:8px;letter-spacing:.14em;
  fill:var(--uv);
}

.birds .bird{
  fill:var(--signal);
  offset-rotate:auto;
  offset-distance:var(--end,100%);
  /* without transform-box, an SVG transform scales about the viewport origin,
     not the glyph — which threw the bird ~30px off its landing point */
  transform-box:fill-box;transform-origin:center;
  transform:scale(1.3);
  opacity:.24;
}
.is-ready .birds .bird{
  animation:
    fly   var(--dur)              var(--press) var(--in) both,
    spark calc(var(--dur) + .55s) linear       var(--in) both;
}
@keyframes fly{
  from{offset-distance:0%}
  to  {offset-distance:var(--end,100%)}
}
/* the bright thing hands off: each bird is lit only for its own leg */
@keyframes spark{
  0%  {opacity:0}
  7%  {opacity:1}
  62% {opacity:1}
  100%{opacity:.24}
}
/* except the last, which is still lit when the page comes to rest — mantled on
   the kill, which is the enlist button */
.is-ready .birds .bird-last{
  animation:
    fly        var(--dur)             var(--press) var(--in) both,
    spark-last calc(var(--dur) + .3s) linear       var(--in) both;
}
@keyframes spark-last{
  0%  {opacity:0}
  7%  {opacity:1}
  100%{opacity:1}
}

/* ── stage ───────────────────────────────────────────────────────────────── */

/* Asymmetric on purpose. A centred column leaves the pursuit line nowhere to go
   except through the type; offsetting the content opens a field on the right
   wide enough for the chase to be violent in. */
.stage{
  position:relative;z-index:2;
  min-height:100vh;
  display:flex;flex-direction:column;
  /* Top-anchored, not centred. Centring makes every element's position a
     function of the viewport height, and that resolves late enough that a path
     fitted to the content lands ~48px off it. Anchoring to the top makes the
     layout deterministic on the first pass. */
  align-items:flex-start;justify-content:flex-start;
  gap:clamp(18px,3.4vh,34px);
  padding:clamp(96px,17vh,188px) clamp(24px,6vw,104px) clamp(84px,12vh,116px);
  text-align:left;
}
/* align-items:flex-start sizes children to max-content, so without this the
   headline refuses to wrap and runs straight off a phone screen */
.stage > *{max-width:100%}

/* every waypoint arrives as the line reaches it. Hidden only once JS has armed
   the sequence, so a JS failure leaves a readable page rather than a blank one. */
.is-armed .wp{opacity:0;transform:translateY(14px)}
.is-ready .wp{animation:arrive .5s var(--glide) both}
@keyframes arrive{to{opacity:1;transform:translateY(0)}}
.wp-mark{animation-delay:.15s}
.title  {animation-delay:.80s}
.readout{animation-delay:1.50s}
.act    {animation-delay:2.05s}

/* mark — sits top-left like a letterhead, and is the first waypoint --------- */
.wp-mark{
  position:absolute;
  top:clamp(26px,5vh,54px);
  left:clamp(24px,6vw,104px);
  width:clamp(54px,6.4vw,74px);aspect-ratio:1;
}
.mark{width:100%;height:100%;overflow:visible}
.mark-ring{
  fill:none;stroke:var(--faint);stroke-width:1;
  stroke-dasharray:2 9;stroke-linecap:round;
  transform-origin:50% 50%;
  animation:spin 76s linear infinite;
}
@keyframes spin{from{transform:rotate(0)}to{transform:rotate(360deg)}}
.mark-birds use{fill:var(--bone)}
.mark-birds .mark-wing{fill:var(--dim)}

/* title ------------------------------------------------------------------ */
/* monumental: the name should own the frame, not sit politely inside it */
.title{
  margin:0;
  font-size:clamp(2.6rem,13vw,10.5rem);
  font-weight:150;
  line-height:.86;
  letter-spacing:-.005em;
  text-transform:uppercase;
  color:var(--bone);
  text-wrap:balance;
}
.title-2{display:block;font-weight:250;letter-spacing:.008em}

/* readout — the fovea. The only dense region on the page. ---------------- */
.readout{width:100%;max-width:428px}
.readout dl{
  margin:0;
  border-top:1px solid var(--faint);
  border-bottom:1px solid var(--faint);
  padding:11px 0;
  font-family:var(--mono);
  font-size:.6875rem;
  line-height:1.85;
  letter-spacing:.07em;
  font-variant-numeric:tabular-nums;
  text-align:left;
}
.readout .row{display:flex;gap:14px;align-items:baseline}
.readout dt{
  flex:0 0 68px;color:var(--dim);
  font-size:.625rem;letter-spacing:.16em;
}
.readout dd{margin:0;color:var(--dim);min-width:0;overflow-wrap:anywhere}
.readout .hot{color:var(--bone);font-weight:600;letter-spacing:.12em}

.uv-note{
  margin:9px 0 0;
  font-family:var(--mono);font-size:.5625rem;letter-spacing:.2em;
  color:var(--uv);text-align:left;
  opacity:0;transition:opacity .45s var(--glide);
}

/* act -------------------------------------------------------------------- */
.act{display:flex;flex-flow:row wrap;align-items:center;gap:14px 20px}

.enlist{
  display:inline-flex;align-items:center;gap:12px;
  padding:13px 26px;
  border:1px solid var(--faint);
  border-radius:999px;
  color:var(--bone);text-decoration:none;
  font-size:.9375rem;font-weight:400;letter-spacing:.05em;
  background:rgba(11,13,20,.55);
  transition:border-color .16s var(--glide),color .16s var(--glide),
             background-color .16s var(--glide);
}
.enlist-arrow{
  width:22px;height:11px;fill:none;stroke:currentColor;stroke-width:1.4;
  transition:transform .22s var(--glide);
}
.enlist:hover,.enlist:focus-visible{
  border-color:var(--cere-hover,var(--signal));color:var(--signal);
  background:rgba(255,198,26,.11);
}
.enlist:hover .enlist-arrow{transform:translateX(4px)}

/* the kill lands here and stays lit: after the stoop the enlist button is the
   one bright thing on the page, with the last hawk mantled over it */
.is-struck .enlist{
  border-color:var(--signal);color:var(--signal);background:rgba(255,198,26,.07);
}

/* one 1px ring, expanding once. vector-effect keeps the stroke hairline while
   the shape scales, which is what stops it reading as a bloom. */
.impact .strike{
  fill:none;stroke:var(--signal);stroke-width:1.4;
  vector-effect:non-scaling-stroke;
  transform-box:fill-box;transform-origin:center;
  opacity:0;
}
.is-ready .impact .strike{animation:impact .42s var(--press) 2.06s both}
@keyframes impact{
  0%  {transform:scale(1);opacity:0}
  10% {opacity:.85}
  100%{transform:scale(34);opacity:0}
}

/* the 4th-channel switch: an instrument toggle, not a button */
.uv{
  position:fixed;z-index:3;
  right:clamp(18px,3.4vw,40px);
  bottom:clamp(14px,2.6vh,28px);
  display:inline-flex;align-items:center;gap:9px;
  padding:7px 14px 7px 11px;
  background:none;border:1px solid transparent;border-radius:999px;
  font-family:var(--mono);font-size:.5625rem;letter-spacing:.22em;
  text-transform:uppercase;color:var(--dim);
  cursor:pointer;
  transition:color .16s var(--glide),border-color .16s var(--glide);
}
.uv:hover{color:var(--bone);border-color:var(--faint)}
.uv-lamp{
  width:6px;height:6px;border-radius:50%;
  background:var(--faint);
  transition:background-color .3s var(--glide),box-shadow .3s var(--glide);
  animation:standby 5.2s ease-in-out 3.6s infinite;
}
/* enough to be found, not enough to nag */
@keyframes standby{
  0%,88%,100%{box-shadow:0 0 0 0 rgba(176,38,255,0)}
  94%{box-shadow:0 0 0 4px rgba(176,38,255,.15)}
}

/* ── ultraviolet ─────────────────────────────────────────────────────────── */

.uv-on .quarry path{opacity:1}
.uv-on .handoffs g{opacity:1}
.uv-on .uv-note{opacity:1}
.uv-on .uv{color:var(--uv);border-color:var(--uv-soft)}
.uv-on .uv-lamp{
  background:var(--uv);
  box-shadow:0 0 0 3px rgba(176,38,255,.20),0 0 12px 1px rgba(176,38,255,.45);
  animation:none;
}
/* the pursuit line lifts a little: now you can see what it was chasing.
   :not(.leg-halo) matters — without it this also repaints the 7px blurred
   under-copy, which turns the whole line into a grey floodlight. */
.uv-on .pursuit .leg:not(.leg-halo){stroke:#5A6472}
.uv-on .pursuit .leg-halo{stroke:rgba(255,198,26,.085)}

/* ── footer ──────────────────────────────────────────────────────────────── */

.foot{
  position:fixed;left:0;right:0;bottom:clamp(16px,2.8vh,28px);
  z-index:2;text-align:left;padding:0 clamp(24px,6vw,104px);
  font-family:var(--mono);font-size:.5625rem;letter-spacing:.2em;
  text-transform:uppercase;color:#5A616E;
}
.is-armed .foot{opacity:0;transform:translateY(14px)}
.is-ready .foot{animation:arrive .5s var(--glide) 2.45s both}

/* ── rest state ──────────────────────────────────────────────────────────── */
/* Applied once the chase resolves, so a resize recomputes geometry without
   replaying the whole intro. */

.is-settled .leg{animation:none;stroke-dashoffset:0}
.is-settled .bird{animation:none;offset-distance:var(--end,100%);opacity:.24}
.is-settled .bird-last{opacity:1}
.is-settled .wp,.is-settled .foot{animation:none;opacity:1;transform:none}

/* ── narrow and short viewports ──────────────────────────────────────────── */

@media (max-width:560px){
  .title{font-size:clamp(1.85rem,9.4vw,3rem);line-height:.98}
  .readout dl{font-size:.5625rem;letter-spacing:.04em;line-height:1.95}
  .readout dt{flex-basis:52px;font-size:.5rem;letter-spacing:.1em}
  .readout .row{gap:10px}
  .stage{gap:20px}
  .orbit{width:240vw}
  .enlist{padding:12px 20px;font-size:.875rem}
  .foot{font-size:.5rem;letter-spacing:.14em;line-height:1.5}
  /* bottom-right collides with the footer on a phone; the top corner is free
     and balances the mark on the left */
  .uv{top:clamp(12px,2.2vh,22px);bottom:auto;letter-spacing:.15em;padding:6px 11px 6px 9px}
}
@media (max-height:640px){
  .stage{gap:15px;padding-top:44px;padding-bottom:74px}
  .title{font-size:clamp(1.9rem,6.4vw,3.2rem)}
  .wp-mark{width:clamp(40px,5vw,50px)}
}

/* ── reduced motion ──────────────────────────────────────────────────────── */
/* The resting composition is the point: line fully drawn, birds parked at their
   handoff points, everything legible. Only the performance of it is lost. */

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.01ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.01ms !important;
  }
  .wp,.foot{opacity:1;transform:none}
  .pursuit .leg{stroke-dashoffset:0 !important}
  .birds .bird{opacity:.3}
  .birds .bird-last{opacity:1}
  .impact .strike{display:none}
}
