/* ============================================================
   MOTION
   One idea throughout: the site is built on a grid, and motion shows it.

     grid       one unit (--grid, below) and a heavy line every six units,
                always behind the content, never over it,
                from the content column's left edge and the header's bottom.
                The same on every page, so it can stay put while one page
                gives way to the next. The hero is seated on it exactly.
     boot       homepage first visit: the page fades in over the grid
                behind a sweeping guide line; the grid grows out from it
                with the page appearing inside it, and once the page is all
                there and usable the grid fades out slowly.
     pages      leaving: the grid spreads from where you clicked while the
                content fades. Entering: the page renders on it, it fades.
     blueprint  an open inspector lays the hero on graph paper measured from
                the headline. Closed, a grey lens under the cursor shows the
                same paper underneath the page.
     grounds    backgrounds behind the cut-out portrait
     role       the role's blue hover

   js/motion.js drives it. Options are data attributes on <html>
   (motion-lab.html sets them from the query string).
   ============================================================ */

:root{
  --sg-minor:rgba(63,63,70,.03);
  --sg-major:rgba(63,63,70,.07);
  --bp-minor:rgba(63,63,70,.03);
  --bp-major:rgba(63,63,70,.07);
  --bp-lens-minor:rgba(63,63,70,.055);
  --bp-lens-major:rgba(63,63,70,.12);
}
:root[data-theme="dark"]{
  --sg-minor:rgba(159,159,169,.035);
  --sg-major:rgba(159,159,169,.07);
  --bp-minor:rgba(159,159,169,.035);
  --bp-major:rgba(159,159,169,.065);
  --bp-lens-minor:rgba(159,159,169,.05);
  --bp-lens-major:rgba(159,159,169,.11);
}

/* ---------- the unit ----------
   A sixth of the hero headline's line height, in whole pixels: between the
   quarter this started at and the eighth that followed, with the heavy line
   still one headline line. The
   headline's size formula is css/hero.css's; it depends on the viewport only,
   so every page gets the same unit. 1.2 is the leading the headline was
   tuned at; rounding moves it by at most two pixels. Registered, so scripts
   read it back resolved. */
@property --grid{syntax:'<length>';inherits:true;initial-value:24px;}
:root{
  --hero-fs:clamp(2rem,min(calc((100vw - 2 * var(--gutter)) / 8.3),calc(22.4px + 5.11vw),11vh),6rem);
  --grid:round(calc(var(--hero-fs) * 1.2 / 6),1px);
}
@supports (height:1svh){
  :root{--hero-fs:clamp(2rem,min(calc((100vw - 2 * var(--gutter)) / 8.3),calc(22.4px + 5.11vw),11svh),6rem);}
}

/* ---------- the hero, seated on the grid ----------
   Line height: six units. The portrait: seven units by five, so both its top
   and its foot sit on a line (it used to be three quarters of a line, which
   fell between two). Merriweather's baseline sits 3 units + 0.354em below
   the top of a line (ascent .979, descent .271), so raising the image's
   bottom by 0.354em - 2 units puts its top on the line.
   The role's tint fills its line exactly: the roles element's padding (.12em top, .2em
   bottom) is outside the line box, so the tint starts and stops there. The
   clip runs a hair past it so descenders are not shaved.
   js/motion.js moves the headline, buttons, portrait and role onto grid lines. */
.hero h1{line-height:calc(var(--grid) * 6);}
.hero .face{width:calc(var(--grid) * 7);height:calc(var(--grid) * 5);vertical-align:calc(.354em - var(--grid) * 2);}
.hero .roles{
  --tint-top:.12em;--tint-bottom:.2em;
  clip-path:inset(calc(var(--tint-top) - .05em) 0 calc(var(--tint-bottom) - .06em) 0 round .1em);
}
.hero .cta{margin-top:round(clamp(28px,3.4vw,44px),var(--grid));}
.hero .cta a{min-height:round(up,52px,var(--grid));}
@media (max-width:767px){ .hero .cta{margin-top:0;} }

/* the hero is its own stacking context, so the blueprint can sit at
   z-index -1: behind the sentence, above the page. The header and the page
   paint above the site grid as well, so every grid -- the lens, the
   blueprint and the one the boot and the page transitions draw -- passes
   under the words, never over them. */
.hero{isolation:isolate;}
.rd-top{position:relative;z-index:2;}
main,footer.rd-foot{position:relative;z-index:1;}
/* main carries its own paper (css/site.css, css/color.css), which would hide
   a grid lying under it; while one is on, the page background shows instead.
   It is the same colour, so nothing else changes. */
.grid-live main{background:transparent;}

@property --grid-r{syntax:'<length>';inherits:false;initial-value:1px;}


/* ---------- the site grid (boot and pages) ----------
   Two layers, vertical and horizontal lines, so the boot can draw them in
   separate directions. Pages spread both from the click (the mask on the
   container); the boot draws them (the masks on the layers). */
@property --draw-v{syntax:'<length-percentage>';inherits:false;initial-value:0%;}
@property --draw-h{syntax:'<length-percentage>';inherits:false;initial-value:0%;}
.site-grid{
  position:fixed;inset:0;z-index:0;pointer-events:none;
  -webkit-mask-image:radial-gradient(circle var(--grid-r) at var(--sg-ox,50%) var(--sg-oy,50%),#000 calc(100% - 240px),transparent);
          mask-image:radial-gradient(circle var(--grid-r) at var(--sg-ox,50%) var(--sg-oy,50%),#000 calc(100% - 240px),transparent);
  opacity:0;visibility:hidden;
}
.site-grid b{position:absolute;inset:0;background-position:var(--sg-x,0) var(--sg-y,0);}
.site-grid .sg-v{
  background-image:linear-gradient(to right,var(--sg-major) 1px,transparent 1px),linear-gradient(to right,var(--sg-minor) 1px,transparent 1px);
  background-size:calc(var(--grid) * 6) 100%,var(--grid) 100%;
}
.site-grid .sg-h{
  background-image:linear-gradient(to bottom,var(--sg-major) 1px,transparent 1px),linear-gradient(to bottom,var(--sg-minor) 1px,transparent 1px);
  background-size:100% calc(var(--grid) * 6),100% var(--grid);
}
/* drawn: no spread, the lines grow instead */
.site-grid.is-draw{-webkit-mask-image:none;mask-image:none;}
.site-grid.is-draw .sg-v{
  -webkit-mask-image:linear-gradient(to bottom,#000 calc(var(--draw-v) - 120px),transparent var(--draw-v));
          mask-image:linear-gradient(to bottom,#000 calc(var(--draw-v) - 120px),transparent var(--draw-v));
}
.site-grid.is-draw .sg-h{
  -webkit-mask-image:linear-gradient(to right,#000 calc(var(--draw-h) - 160px),transparent var(--draw-h));
          mask-image:linear-gradient(to right,#000 calc(var(--draw-h) - 160px),transparent var(--draw-h));
}
.site-grid.is-draw.is-on{transition:opacity .15s ease;}
.site-grid.is-draw.is-on .sg-v{--draw-v:calc(100% + 120px);transition:--draw-v 1.1s cubic-bezier(.45,0,.25,1);}
.site-grid.is-draw.is-on .sg-h{--draw-h:calc(100% + 160px);transition:--draw-h 1.1s cubic-bezier(.45,0,.25,1) .12s;}
.boot .site-grid{position:absolute;z-index:auto;}
.site-grid.is-on{
  --grid-r:var(--sg-max);opacity:1;visibility:visible;
  transition:--grid-r .9s cubic-bezier(.3,.6,.25,1),opacity .15s ease;
}
.site-grid.is-out{opacity:0;visibility:hidden;transition:opacity .6s ease,visibility 0s linear .6s;}
.site-grid.no-anim{transition:none;}
@media (prefers-reduced-motion:reduce){ .site-grid{display:none;} }


/* ---------- boot ----------
   The grid is up (js/motion.js), the page fades in over it, the grid fades
   out. Opacity only: nothing moves while the hero is seated on the grid. */
.is-booting .rd-top,.is-booting main,.is-booting .rd-foot{
  opacity:0;
  /* if the script never runs, the page fades in by itself */
  animation:boot-fade .7s ease 3s forwards;
}
.is-booting.boot-in .rd-top,.is-booting.boot-in main,.is-booting.boot-in .rd-foot{
  opacity:1;transition:opacity .7s ease;
}
/* the script is running: it fades the page in itself */
.boot-live.is-booting .rd-top,.boot-live.is-booting main,.boot-live.is-booting .rd-foot{animation:none;}
@keyframes boot-show{to{opacity:1;}}
@keyframes boot-fade{from{opacity:0;}to{opacity:1;}}
/* the boot's grid covers the hero only and scrolls with it, softening out at
   its foot */
.site-grid.is-hero{
  position:absolute;bottom:auto;height:var(--sg-hh,100vh);
  -webkit-mask-image:linear-gradient(to bottom,#000 calc(100% - 160px),transparent);
          mask-image:linear-gradient(to bottom,#000 calc(100% - 160px),transparent);
}
.site-grid.is-hero.is-on{transition:opacity .3s ease;}


/* ---------- pages ---------- */
.is-leaving main,.is-leaving .rd-foot{opacity:0;transition:opacity .3s ease;}
.is-entering:not(.is-entered) main,
.is-entering:not(.is-entered) .rd-foot{opacity:0;
  /* if the script never runs, the page shows itself anyway */
  animation:boot-show 0s linear 3s forwards;}
.is-entered main,.is-entered .rd-foot{transition:opacity .5s ease .08s;}


/* ---------- blueprint ---------- */
/* the stage covers the first screen edge to edge (js/motion.js sizes it) and
   clips what it holds, so the lens never widens the page */
.bp-stage{position:absolute;z-index:-1;pointer-events:none;overflow:hidden;}
.bp-grid{
  position:absolute;inset:0;pointer-events:none;
  background-image:
    linear-gradient(to right,var(--bp-a) 1px,transparent 1px),
    linear-gradient(to bottom,var(--bp-a) 1px,transparent 1px),
    linear-gradient(to right,var(--bp-b) 1px,transparent 1px),
    linear-gradient(to bottom,var(--bp-b) 1px,transparent 1px);
  background-size:
    var(--bp-line) var(--bp-line),var(--bp-line) var(--bp-line),
    var(--bp-cell) var(--bp-cell),var(--bp-cell) var(--bp-cell);
  background-position:var(--bp-x) var(--bp-y);
  opacity:0;visibility:hidden;
}
/* open: the whole hero, spreading out from the element that was opened */
.bp-grid.is-base{
  --bp-a:var(--bp-major);--bp-b:var(--bp-minor);
  -webkit-mask-image:radial-gradient(circle var(--grid-r) at var(--bp-ox) var(--bp-oy),#000 calc(100% - 200px),transparent);
          mask-image:radial-gradient(circle var(--grid-r) at var(--bp-ox) var(--bp-oy),#000 calc(100% - 200px),transparent);
  transition:opacity .25s ease,visibility 0s linear .25s,--grid-r 0s linear .25s;
}
.bp-on .bp-grid.is-base{
  --grid-r:var(--bp-max);opacity:1;visibility:visible;
  transition:opacity .15s ease,--grid-r 1.1s cubic-bezier(.3,.6,.25,1);
}
/* closed: a grey lens under the cursor, onto the same paper.
   The paper is a layer of its own, the size of the stage, drawn once; the
   lens is a window that slides over it and the paper slides back by the same
   amount. Both are transforms, so moving the lens repaints nothing -- with a
   background-position instead, every frame redraws the whole tile. */
.bp-grid.is-lens{
  --bp-a:var(--bp-lens-major);--bp-b:var(--bp-lens-minor);
  inset:auto;left:0;top:0;overflow:hidden;background:none;will-change:transform;
  -webkit-mask-image:radial-gradient(circle closest-side,#000 30%,transparent);
          mask-image:radial-gradient(circle closest-side,#000 30%,transparent);
  transition:opacity .25s ease,visibility 0s linear .25s;
}
.bp-paper{
  position:absolute;left:0;top:0;pointer-events:none;will-change:transform;
  background-image:
    linear-gradient(to right,var(--bp-a) 1px,transparent 1px),
    linear-gradient(to bottom,var(--bp-a) 1px,transparent 1px),
    linear-gradient(to right,var(--bp-b) 1px,transparent 1px),
    linear-gradient(to bottom,var(--bp-b) 1px,transparent 1px);
  background-size:
    var(--bp-line) var(--bp-line),var(--bp-line) var(--bp-line),
    var(--bp-cell) var(--bp-cell),var(--bp-cell) var(--bp-cell);
  background-position:var(--bp-x) var(--bp-y);
}
.bp-in:not(.bp-on) .bp-grid.is-lens{opacity:1;visibility:visible;transition:opacity .25s ease;}

/* the floating panel sits on the grid: give it the page behind it, bled past
   its edges so its alignment to the content edge does not move */
.bp-on .insp.is-float{background:var(--paper);box-shadow:0 0 0 14px var(--paper);border-radius:2px;}

@media (prefers-reduced-motion:reduce){
  .bp-on .bp-grid.is-base{transition:opacity .2s ease;}
}


/* ---------- phones: the headline at the top ---------- */
@media (max-width:767px){
  .hero h1{margin-block:0 auto;}
}


/* ---------- role hover: blue text ---------- */
.hero .roles > span{transition:transform calc(.62s / var(--roll-speed, 1)) cubic-bezier(.65,0,.35,1),color var(--hover-t) ease;}
[data-hero][data-hover="roles"] .roles > span{color:var(--accent-text);}
@media (prefers-reduced-motion:reduce){ .hero .roles > span{transition:color var(--hover-t) ease;} }


/* ---------- portrait grounds ----------
   The photo is a cut-out, so the inspector changes what is behind it rather
   than the photo itself. While a ground is showing the hover blue stays off. */
[data-hero][data-open="avatar"] .face:hover:not([data-ground]){background:var(--portrait-ground);}
.hero .face[data-ground]{transition:none;}

/* a literal blueprint: blue paper, a line every 0.4em and a fine one every 0.1em */
.hero .face[data-ground="blueprint"]{
  background-color:#155dfc;
  background-image:
    linear-gradient(rgba(255,255,255,.32) 1px,transparent 1px),
    linear-gradient(90deg,rgba(255,255,255,.32) 1px,transparent 1px),
    linear-gradient(rgba(255,255,255,.12) 1px,transparent 1px),
    linear-gradient(90deg,rgba(255,255,255,.12) 1px,transparent 1px);
  background-size:.4em .4em,.4em .4em,.1em .1em,.1em .1em;
  background-position:-1px -1px;
  animation:ground-drift 8s linear infinite;
}
@keyframes ground-drift{to{background-position:calc(.4em - 1px) calc(.4em - 1px);}}

@property --au-1{syntax:'<percentage>';inherits:false;initial-value:20%;}
@property --au-2{syntax:'<percentage>';inherits:false;initial-value:20%;}
@property --au-3{syntax:'<percentage>';inherits:false;initial-value:80%;}
.hero .face[data-ground="aurora"]{
  background-color:#172554;
  background-image:
    radial-gradient(circle at var(--au-1) 25%,#2b7fff 0,transparent 58%),
    radial-gradient(circle at 85% var(--au-2),#a855f7 0,transparent 52%),
    radial-gradient(circle at var(--au-3) 95%,#22d3ee 0,transparent 56%);
  animation:ground-aurora 9s ease-in-out infinite alternate;
}
@keyframes ground-aurora{
  0%{--au-1:10%;--au-2:10%;--au-3:85%;}
  50%{--au-1:70%;--au-2:70%;--au-3:25%;}
  100%{--au-1:30%;--au-2:100%;--au-3:60%;}
}

@media (prefers-reduced-motion:reduce){
  .hero .face[data-ground]{animation:none;}
}
