/* AQcredix — the founder hero, full screen.
 *
 * THE STAGE IS THE VIEWPORT. The clips are 16:9 and screens are not, so the
 * video is sized with object-fit:cover and the character — who sits dead centre
 * of the frame — is what the crop is anchored to. On a tall phone the wall is
 * cropped away at the sides; on an ultrawide the ceiling and floor go. He stays
 * the same size relative to the screen either way, which is the only thing that
 * has to hold across aspect ratios.
 *
 * THE BACKGROUND IS NOT REMOVED — IT IS DISSOLVED. He wears a white shirt in
 * front of a near-white wall (sampled: wall 199,194,190 / shirt 168,151,144),
 * so no colour or luma key can separate them; a key that takes the wall takes
 * his shirt with it. Instead the frame is graded down and then masked with a
 * wide elliptical feather centred on him, so the picture fades to the page's
 * own background long before it reaches an edge. There is no rectangle, and
 * what is left is a man at a desk emerging out of the dark.
 *
 * TEXT IS NEVER LEFT TO CHANCE. Copy sits in the left and right thirds, and
 * both are backed by a scrim that is opaque enough to hold contrast over the
 * brightest thing the video can put there. Readability does not depend on which
 * frame is on screen.
 */

/* ============================================================
   THE STAGE
   ============================================================ */
.fpv-hero{
  position:relative;
  /* THE HERO IS ONE SCREEN, MEASURED FROM WHERE IT ACTUALLY STARTS.
     100svh alone is wrong here: the hero begins below the standards notice and
     the site header, so a full-viewport box hangs off the bottom of the screen
     by exactly that much — and everything pinned to the hero's lower edge, the
     sound switch and the scroll cue, goes with it. --fpv-top is that offset,
     measured once by hero-video.js and refreshed on resize, because how tall
     the notice wraps to is a fact about rendered text that CSS cannot ask for.
     The fallback keeps it sane if the script never runs.

     svh, not vh: vh counts the strip behind mobile browser chrome, which shows
     up as a band of dead ground under the hero on a phone. */
  min-height:calc(100svh - var(--fpv-top, 0px));
  display:grid;
  align-items:center;
  overflow:hidden;
  isolation:isolate;
  background:var(--bg);
}

.fpv-stage{
  position:absolute;
  inset:0;
  z-index:0;
  pointer-events:auto;      /* he is clickable */
}

.fpv{
  position:absolute;
  inset:0;
  overflow:hidden;
  background:var(--bg);
}

/* THE CANVAS IS THE ONLY THING ON SCREEN.
   Everything is drawn into it — the typing clip, the head-turn stills, the
   greeting — so there is never more than one element compositing, and never a
   gap between two half-faded layers for the page to show through. That gap was
   the black flash.

   How a 16:9 frame meets a screen that is not 16:9 is decided in the draw call
   now rather than by object-fit, because the fit has to be identical for every
   source or he changes size between the typing clip and the stills. Landscape
   contains (his whole head and the whole desk stay in shot); portrait fills,
   anchored high on him, because containing a wide frame in a tall window
   leaves him a strip across the middle. */
.fpv-canvas{
  position:absolute;
  inset:0;
  width:100%;
  height:100%;
  display:block;
}

/* The source clips are decoded but never shown. Not display:none, which stops
   some browsers decoding them at all — parked off-screen instead. */
.fpv-src{
  position:absolute;
  left:-9999px;
  width:1px; height:1px;
  opacity:0;
  pointer-events:none;
}

/* The poster sits under the canvas, so the stage always has a picture on it —
   including before the first frame is drawn, and anywhere the draw loop cannot
   run. An undrawn canvas is transparent, so what shows is him, not black. */
.fpv{
  background-size:contain;
  background-position:50% 50%;
  background-repeat:no-repeat;
}
@media (max-aspect-ratio: 1/1){
  .fpv{ background-size:cover; background-position:50% 30%; }
}

/* THE DISSOLVE. A single elliptical mask, generously feathered, centred on
   him. Everything past it is the page. Both properties: Safari still wants
   the prefixed one. */
.fpv{
  -webkit-mask-image:radial-gradient(118% 92% at 50% 42%,
      #000 0%, #000 34%, rgba(0,0,0,.92) 50%, rgba(0,0,0,.55) 68%,
      rgba(0,0,0,.18) 84%, transparent 100%);
  mask-image:radial-gradient(118% 92% at 50% 42%,
      #000 0%, #000 34%, rgba(0,0,0,.92) 50%, rgba(0,0,0,.55) 68%,
      rgba(0,0,0,.18) 84%, transparent 100%);
}

/* A wash of the brand indigo over the footage, and a floor gradient that
   carries the bottom of the picture into the page rather than stopping it. */
.fpv-wash{
  position:absolute;
  inset:0;
  z-index:2;
  pointer-events:none;
  background:
    linear-gradient(180deg, transparent 52%, var(--bg) 97%),
    linear-gradient(140deg, color-mix(in srgb, var(--brand-2) 10%, transparent), transparent 55%);
}

/* ============================================================
   THE SCRIMS — what makes the words legible over moving footage
   Two columns of shade, one per text rail, fading to nothing in the middle so
   they never darken him. Strong enough at the edges that body copy clears
   4.5:1 against the brightest frame the video has.
   ============================================================ */
.fpv-scrim{
  position:absolute;
  inset:0;
  z-index:3;
  pointer-events:none;
  background:
    linear-gradient(90deg,
      color-mix(in srgb, var(--bg) 94%, transparent) 0%,
      color-mix(in srgb, var(--bg) 82%, transparent) 20%,
      transparent 42%),
    linear-gradient(270deg,
      color-mix(in srgb, var(--bg) 94%, transparent) 0%,
      color-mix(in srgb, var(--bg) 78%, transparent) 18%,
      transparent 40%);
}

/* ============================================================
   THE CONTENT RAILS
   ============================================================ */
.fpv-copy{
  position:relative;
  z-index:4;
  width:100%;
  max-width:1560px;
  margin:0 auto;
  padding:clamp(80px,9vh,120px) clamp(20px,3.4vw,52px) clamp(56px,7vh,84px);
  display:grid;
  grid-template-columns:minmax(0,1fr) minmax(0,1.15fr) minmax(0,1fr);
  align-items:center;
  gap:clamp(16px,2vw,32px);
  pointer-events:none;        /* the stage underneath stays clickable */
  min-height:calc(100svh - var(--fpv-top, 0px));
  box-sizing:border-box;
}
.fpv-copy > *{ pointer-events:auto; }

/* THE COPY SITS ON GLASS, NOT ON A GUESS.
   A scrim alone means the contrast behind the words depends on which frame is
   playing — and the brightest frame in these clips is a lit white wall. A panel
   fixes it: the text has its own surface, it clears contrast against that
   surface whatever the video does, and it matches the glass the rest of the
   site now uses. */
.fpv-left{
  grid-column:1;
  display:flex; flex-direction:column; gap:12px;
  padding:clamp(20px,1.8vw,28px);
  border-radius:18px;
  background:color-mix(in srgb, var(--bg) 78%, transparent);
  border:1px solid var(--glass-edge, var(--border));
  box-shadow:var(--glass-lift, var(--shadow-2)), inset 0 1px 0 var(--glass-specular, transparent);
  -webkit-backdrop-filter:blur(18px) saturate(112%);
  backdrop-filter:blur(18px) saturate(112%);
}
.fpv-right{
  grid-column:3;
  display:flex; flex-direction:column; gap:14px;
  align-items:flex-end; text-align:right;
}

/* THE NAME, AT A SENSIBLE SIZE. The old hero set it in Anton at up to 180px
   across the whole screen, which is a poster, not a portfolio. This is a name
   on a professional page: large enough to lead, small enough to be read as a
   name rather than as a graphic. */
.fpv-name{
  font-family:var(--font-display);
  font-weight:700;
  font-size:clamp(28px,3.4vw,46px);
  line-height:1.08;
  letter-spacing:-.025em;
  color:var(--fg);
  margin:0;
  text-wrap:balance;
}
.fpv-eyebrow{
  font-family:var(--font-mono);
  font-size:clamp(10.5px,.85vw,12px);
  letter-spacing:1.6px;
  text-transform:uppercase;
  color:var(--accent-text);
  margin:0;
}
.fpv-role{
  font-size:clamp(14px,1.05vw,16.5px);
  line-height:1.55;
  color:var(--fg-muted);
  margin:0;
  max-width:34ch;
}
.fpv-meta{
  font-size:clamp(12.5px,.9vw,14px);
  line-height:1.6;
  color:var(--fg-faint);
  margin:0;
  max-width:36ch;
}
.fpv-actions{ display:flex; gap:10px; flex-wrap:wrap; margin-top:6px; }

/* The right rail: credentials, right-aligned so they hang off the edge the
   scrim covers. */
.fpv-tags{ display:flex; flex-direction:column; gap:7px; align-items:flex-end; }
.fpv-tags .fp-tag{
  font-size:clamp(10.5px,.78vw,12px);
  font-weight:600;
  line-height:1.45;
  padding:7px 13px;
  border-radius:14px;
  background:var(--surface-1);
  border:1px solid var(--border);
  color:var(--fg);
  backdrop-filter:blur(10px);
  -webkit-backdrop-filter:blur(10px);
  max-width:30ch;
  text-align:right;
}

/* THE INVITATION. Nobody discovers a click target on a video by staring at it.
   One quiet line, and the name inside it is the button. */
.fpv-hint{
  display:flex; align-items:center; gap:8px;
  margin:4px 0 0;
  font-size:12.5px;
  color:var(--fg-faint);
}
.fpv-hint svg{ flex:none; opacity:.75; }
.fpv-namehit{
  -webkit-appearance:none; appearance:none;
  background:none; border:0; padding:0; margin:0;
  font:inherit; font-weight:600;
  color:var(--fg-muted);
  text-decoration:underline;
  text-decoration-thickness:1px;
  text-underline-offset:3px;
  text-decoration-color:color-mix(in srgb, var(--brand-2) 45%, transparent);
  cursor:pointer;
  transition:color .25s ease, text-decoration-color .25s ease;
}
.fpv-namehit:hover,
.fpv-namehit:focus-visible{ color:var(--accent-text); text-decoration-color:var(--brand-2); }
.fpv-namehit:focus-visible{ outline:2px solid var(--brand-2); outline-offset:3px; border-radius:4px; }
@media (hover: none), (pointer: coarse){ .fpv-hint{ display:none; } }

/* THE SOUND SWITCH. Sits on the stage, out of the way of both text rails, and
   above the video so it stays clickable — the stage underneath opens the
   greeting on click, which is why this stops the event. */
.fpv-sound{
  position:absolute;
  right:clamp(16px,2.2vw,32px);
  bottom:clamp(16px,3vh,32px);
  z-index:6;
  display:inline-flex; align-items:center; gap:8px;
  padding:9px 15px;
  border-radius:999px;
  cursor:pointer;
  font:inherit;
  font-size:12.5px;
  font-weight:600;
  color:var(--fg-muted);
  background:color-mix(in srgb, var(--bg) 72%, transparent);
  border:1px solid var(--glass-edge, var(--border));
  box-shadow:inset 0 1px 0 var(--glass-specular, transparent);
  -webkit-backdrop-filter:blur(14px) saturate(112%);
  backdrop-filter:blur(14px) saturate(112%);
  transition:color .2s ease, border-color .2s ease;
}
.fpv-sound:hover{ color:var(--fg); border-color:color-mix(in srgb, var(--brand-2) 40%, var(--glass-edge)); }
.fpv-sound:focus-visible{ outline:2px solid var(--brand-2); outline-offset:3px; }
.fpv-sound svg{ flex:none; }
/* No cursor, no clips, nothing to hear. */
@media (hover: none), (pointer: coarse){ .fpv-sound{ display:none; } }
@media (max-width:560px){ .fpv-sound .fpv-sound-label{ display:none; } .fpv-sound{ padding:10px; } }

/* The cue that there is more below. */
.fpv-scroll{
  position:absolute;
  left:50%; bottom:clamp(16px,3vh,32px);
  transform:translateX(-50%);
  z-index:5;
  display:flex; flex-direction:column; align-items:center; gap:7px;
  font-family:var(--font-mono);
  font-size:10.5px; letter-spacing:1.5px; text-transform:uppercase;
  color:var(--fg-faint);
  pointer-events:none;
}
.fpv-scroll i{
  width:1px; height:30px;
  background:linear-gradient(var(--fg-faint), transparent);
  animation:fpv-drop 2.4s ease-in-out infinite;
}
@keyframes fpv-drop{ 0%,100%{ opacity:.25; transform:scaleY(.6); transform-origin:top; }
                     50%{ opacity:.9; transform:scaleY(1); transform-origin:top; } }

/* No pointer / reduced motion: a still, and nothing else changes. */
.fpv-still{ background-size:cover; background-position:50% 38%; }
.fpv-still .fpv-canvas{ display:none; }

/* ============================================================
   ASPECT RATIOS
   ============================================================ */

/* LAPTOPS ARE 16:10 AND THEIR WINDOWS ARE SHORTER STILL.
   A MacBook reports 1440x900 or 1512x982, and once the browser's own chrome,
   the standards notice and the site header are taken off it, the hero gets
   somewhere around 620-790px to live in. The copy has to shrink to fit that,
   not overflow it — an overflowing hero is the one thing the full-screen
   layout must never do, because there is nothing below the fold to scroll to
   except the rest of the page.

   Three tiers, each taking a little more out: padding first, then the type,
   then the credential chips, which are the least load-bearing thing here. */
@media (max-height:820px) and (min-width:901px){
  .fpv-copy{ padding-top:clamp(52px,7vh,76px); padding-bottom:clamp(36px,5vh,56px); gap:14px; }
  .fpv-left{ gap:9px; padding:clamp(16px,1.5vw,22px); }
  .fpv-name{ font-size:clamp(25px,2.7vw,36px); }
  .fpv-role{ font-size:clamp(13px,.95vw,15px); }
  .fpv-tags{ gap:6px; }
  .fpv-tags .fp-tag:nth-child(n+6){ display:none; }
}

@media (max-height:700px) and (min-width:901px){
  .fpv-copy{ padding-top:clamp(44px,6vh,60px); padding-bottom:28px; gap:10px; }
  .fpv-left{ gap:7px; padding:14px 16px; }
  .fpv-name{ font-size:clamp(22px,2.3vw,30px); }
  .fpv-role{ font-size:13px; line-height:1.45; }
  .fpv-meta{ font-size:12px; line-height:1.45; }
  .fpv-hint{ margin-top:2px; }
  .fpv-tags .fp-tag:nth-child(n+5){ display:none; }
  .fpv-scroll{ display:none; }
}

/* Short and wide — a laptop in landscape, or a desktop with a shallow window.
   There is no room for a full-height column of copy, so it tightens rather
   than scrolling the hero. */
@media (max-height:640px) and (min-width:901px){
  .fpv-copy{ padding-top:clamp(64px,10vh,88px); padding-bottom:40px; }
  .fpv-name{ font-size:clamp(24px,2.6vw,34px); }
  .fpv-role{ font-size:14px; }
  .fpv-tags .fp-tag:nth-child(n+5){ display:none; }
  .fpv-scroll{ display:none; }
}

/* Tablet and narrow desktop: the right rail moves under the left one rather
   than squeezing both into unreadable slivers. */
@media (max-width:1100px) and (min-width:901px){
  .fpv-copy{ grid-template-columns:minmax(0,1fr) minmax(0,.9fr); }
  .fpv-left{ grid-column:1; }
  .fpv-right{ grid-column:2; }
  .fpv-tags .fp-tag:nth-child(n+6){ display:none; }
}

/* Phones and small tablets. The character is behind the copy rather than
   beside it, so the scrim becomes a floor-to-ceiling wash and the text sits on
   top of it in one column. Portrait screens crop the 16:9 frame hard, which is
   why the mask is re-centred on him. */
/* PORTRAIT AND NEAR-SQUARE SCREENS — the stage splits instead of fighting.
   Filling a tall screen with a 16:9 frame means cropping away almost the whole
   width, which zooms him until the screen is a face and the desk is gone. So
   on a portrait screen the picture takes the top of the stage at its own shape
   — whole figure, whole desk — and the copy takes the ground beneath it. Two
   bands, no crop, nothing cut off. */
@media (max-aspect-ratio: 1/1){
  .fpv{
    inset:0 0 auto 0;
    height:min(56svh, 62vw * 0.5625 + 22svh);
  }
  .fpv{
    -webkit-mask-image:radial-gradient(96% 88% at 50% 44%,
        #000 0%, #000 44%, rgba(0,0,0,.80) 64%, rgba(0,0,0,.30) 84%, transparent 100%);
    mask-image:radial-gradient(96% 88% at 50% 44%,
        #000 0%, #000 44%, rgba(0,0,0,.80) 64%, rgba(0,0,0,.30) 84%, transparent 100%);
  }
  .fpv-wash{
    inset:0 0 auto 0;
    height:min(56svh, 62vw * 0.5625 + 22svh);
    background:linear-gradient(180deg, transparent 55%, var(--bg) 99%);
  }
  .fpv-scrim{ display:none; }   /* nothing to shade: the copy is on its own ground */
  .fpv-copy{
    grid-template-columns:1fr;
    align-content:end;
    align-items:end;
    padding-top:calc(min(56svh, 62vw * 0.5625 + 22svh) - 12px);
    padding-bottom:clamp(56px,8svh,80px);
    gap:14px;
  }
  .fpv-left{ grid-column:1; }
  .fpv-right{ grid-column:1; align-items:flex-start; text-align:left; }
  .fpv-tags{ flex-direction:row; flex-wrap:wrap; align-items:flex-start; }
  .fpv-tags .fp-tag{ max-width:none; text-align:left; }
}

@media (max-width:900px){
  .fpv-hero{ min-height:calc(100svh - var(--fpv-top, 0px)); }
  .fpv{
    -webkit-mask-image:radial-gradient(135% 68% at 50% 32%,
        #000 0%, #000 38%, rgba(0,0,0,.85) 56%, rgba(0,0,0,.35) 78%, transparent 100%);
    mask-image:radial-gradient(135% 68% at 50% 32%,
        #000 0%, #000 38%, rgba(0,0,0,.85) 56%, rgba(0,0,0,.35) 78%, transparent 100%);
  }
  .fpv-scrim{
    background:linear-gradient(180deg,
      color-mix(in srgb, var(--bg) 55%, transparent) 0%,
      color-mix(in srgb, var(--bg) 20%, transparent) 30%,
      color-mix(in srgb, var(--bg) 82%, transparent) 58%,
      var(--bg) 82%);
  }
  .fpv-copy{
    grid-template-columns:1fr;
    align-items:end;
    padding:clamp(64px,10vh,96px) 20px clamp(64px,9vh,88px);
    gap:14px;
  }
  .fpv-left{ grid-column:1; }
  .fpv-right{
    grid-column:1;
    align-items:flex-start;
    text-align:left;
  }
  .fpv-tags{ flex-direction:row; flex-wrap:wrap; align-items:flex-start; }
  .fpv-tags .fp-tag{ max-width:none; text-align:left; }
  .fpv-tags .fp-tag:nth-child(n+5){ display:none; }
  .fpv-role{ max-width:none; }
  .fpv-meta{ max-width:none; }
}

@media (max-width:560px){
  .fpv-name{ font-size:clamp(24px,7.4vw,32px); }
  .fpv-tags .fp-tag:nth-child(n+4){ display:none; }
}

@media print{
  .fpv-hero{ min-height:0; }
  .fpv-canvas, .fpv-scroll{ display:none; }
  .fpv-scrim, .fpv-wash{ display:none; }
}
