/* Values come from design.pen. Mobile is the 390 frame, tablet is the 834
   frame, desktop is the 1440 x 900 frame. Mobile and tablet scale with the
   viewport width, so 1 design px = 1 --u. */

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

html,
body,
h1,
p,
ul {
  margin: 0;
  padding: 0;
}

:root {
  --ink: #2b2a2b;
  --ink-role: #282828;
  --ink-muted: #646464;
  --ink-label: #292929;
  --paper: #ffffff;
  --serif: "Newsreader", Georgia, serif;
  --sans: "Spline Sans", system-ui, sans-serif;

  --u: calc(100vw / 390);
  --gutter: 26px;
  --bio-bottom: 44px;
  --bio-gap: 20px;
  --prior-line: 20px;
  --img-filter: none;
  color-scheme: light;
}

/* Dark theme. theme.js sets data-theme. Light is the default. */
:root[data-theme="dark"] {
  --ink: #ecebe8;
  --ink-role: #d9d8d5;
  --ink-muted: #8e8e8e;
  --ink-label: #e6e5e2;
  --paper: #141414;
  /* The images have light backgrounds. Invert them and turn the hue back,
     so they have dark backgrounds with the same colors. prism.js copies
     this filter into the shader backdrop. */
  --img-filter: invert(1) hue-rotate(180deg);
  color-scheme: dark;
}

body {
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  -webkit-font-smoothing: antialiased;
}

a {
  color: inherit;
  text-decoration: none;
}

a:focus-visible {
  outline: 1px solid var(--ink);
  outline-offset: 3px;
}

/* Theme toggle: one quiet icon in the top-right corner. */

.theme-toggle {
  position: absolute;
  top: 16px;
  right: 16px;
  z-index: 20;
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--ink-muted);
  opacity: 0.5;
  cursor: pointer;
  transition: opacity 200ms ease-out;
}

.theme-toggle:hover,
.theme-toggle:focus-visible {
  opacity: 1;
}

.theme-toggle:focus-visible {
  outline: 1px solid var(--ink);
  outline-offset: 0;
}

/* Bio: always visible in the bottom-left corner. */

.bio {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 10;
  padding: 24px var(--gutter) var(--bio-bottom);
  background: var(--paper);
}

.bio__name {
  font: 300 37px/1 var(--serif);
  letter-spacing: -0.6px;
  color: var(--ink);
  margin-bottom: var(--bio-gap);
}

.bio__role {
  font: 400 12px/14px var(--sans);
  color: var(--ink-role);
  margin-bottom: 8px;
}

.bio__prior {
  font: 400 11.5px/var(--prior-line) var(--sans);
  color: var(--ink-muted);
}

/* Home tiles */

.tiles {
  position: relative;
  height: calc(645 * var(--u));
  margin-bottom: 199px;
  list-style: none;
}

.tile {
  position: absolute;
  display: block;
  overflow: hidden;
  left: calc(var(--x) * var(--u));
  top: calc(var(--y) * var(--u));
  width: calc(var(--w) * var(--u));
  height: calc(var(--h) * var(--u));
  --ph: 38;
  --pt: 6;
  --pl: 10;
}

.tile__img,
.tile__prism {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}

.tile__img {
  object-fit: cover;
  filter: var(--img-filter);
}

.tile__prism {
  display: none;
}

.tile__plate {
  position: absolute;
  left: 0;
  bottom: 0;
  z-index: 2;
  width: calc(var(--pw) * var(--u));
  height: calc(var(--ph) * var(--u));
  padding: calc(var(--pt) * var(--u)) 0 0 calc(var(--pl) * var(--u));
  background: var(--paper);
  color: var(--ink-label);
  font: 300 calc(var(--fs) * var(--u)) / 1 var(--serif);
  letter-spacing: -0.3px;
  white-space: nowrap;
}

.tile--resume      { --x: 24;  --y: 68;  --w: 150; --h: 186; --pw: 112; --fs: 20; }
.tile--portfolio   { --x: 194; --y: 68;  --w: 172; --h: 243; --pw: 132; --fs: 20; }
.tile--blog        { --x: 24;  --y: 274; --w: 150; --h: 184; --pw: 76;  --fs: 20; }
.tile--photography { --x: 194; --y: 331; --w: 172; --h: 210; --pw: 165; --fs: 17; }
.tile--contact     { --x: 24;  --y: 478; --w: 150; --h: 167; --pw: 115; --fs: 20; }

/* Tablet */

@media (min-width: 700px) {
  :root {
    --u: min(calc(100vw / 834), 1.25px);
    --gutter: 48px;
    --bio-bottom: 28px;
    --prior-line: 14px;
  }

  .tiles {
    width: calc(834 * var(--u));
    height: calc(868 * var(--u));
    margin: 0 auto 326px;
  }

  .tile {
    --ph: 43;
    --pt: 8;
    --pl: 13;
  }

  .tile--resume      { --x: 64;  --y: 228; --w: 210; --h: 226; --pw: 116; --fs: 22; }
  .tile--portfolio   { --x: 298; --y: 134; --w: 306; --h: 382; --pw: 137; --fs: 25; }
  .tile--blog        { --x: 634; --y: 92;  --w: 146; --h: 183; --pw: 81;  --fs: 20; }
  .tile--photography { --x: 94;  --y: 574; --w: 284; --h: 260; --pw: 177; --fs: 23; }
  .tile--contact     { --x: 492; --y: 650; --w: 260; --h: 218; --pw: 123; --fs: 22; }
}

/* Desktop (mouse or trackpad): the tablet tiles, set loose on a 1440 x 900
   stage. Each tile is a dotted frame until the pointer reveals it. */

@media (min-width: 700px) and (hover: hover) and (pointer: fine) {
  :root {
    /* The third term keeps the tiles (x 430 to 1300) to the
       right of the 380px bio column in narrow windows. */
    --u: min(calc(100vw / 1440), calc(100vh / 900), calc((100vw - 396px) / 870), 1.25px);
    --bio-bottom: 52px;
    --bio-gap: 24px;
  }

  .home {
    overflow: hidden;
  }

  .bio {
    right: auto;
  }

  .tiles {
    position: fixed;
    left: max(calc((100vw - 1440 * var(--u)) / 2), calc(380px - 430 * var(--u)));
    top: calc((100vh - 900 * var(--u)) / 2);
    width: calc(1440 * var(--u));
    height: calc(900 * var(--u));
    margin: 0;
  }

  .tile {
    overflow: visible;
  }

  /* Ghost: a faint copy of each image shows where a tile is. ghost.js
     raises --ghost as the pointer comes near. On hover, the image, the
     shader, the label and the inner stroke fade in over the ghost. */
  .tile__img {
    opacity: var(--ghost, 0.06);
  }

  .tile__img,
  .tile__prism,
  .tile__plate,
  .tile::after {
    transition: opacity 450ms ease-out; /* FADE_MS in prism.js */
  }

  .tile__prism,
  .tile__plate,
  .tile::after {
    opacity: 0;
  }

  .tile__prism {
    display: block;
    z-index: 3;
  }

  .tile::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 4;
    box-shadow: inset 0 0 0 2px var(--paper);
    pointer-events: none;
  }

  .tile:hover > *,
  .tile:focus-visible > *,
  .tile:hover::after,
  .tile:focus-visible::after {
    opacity: 1;
  }

  .tile:focus-visible {
    outline: none;
  }

  .tile--resume      { --x: 430;  --y: 250; }
  .tile--portfolio   { --x: 670;  --y: 120; }
  .tile--blog        { --x: 1010; --y: 96;  }
  .tile--photography { --x: 460;  --y: 560; }
  .tile--contact     { --x: 1040; --y: 470; }
}

/* Inner pages */

.page {
  padding: 40px var(--gutter) 200px;
}

.page__back {
  display: inline-block;
  margin-bottom: 40px;
  font: 400 12px/14px var(--sans);
  color: var(--ink-muted);
}

.page__title {
  font: 300 37px/1 var(--serif);
  letter-spacing: -0.6px;
  color: var(--ink);
  margin-bottom: 32px;
}

.page__list {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.page__list a,
.page__note {
  font: 300 25px/1.2 var(--serif);
  letter-spacing: -0.3px;
  color: var(--ink-label);
}

.page__list a:hover {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 4px;
}

.page__meta {
  display: block;
  margin-top: 4px;
  font: 400 12px/14px var(--sans);
  color: var(--ink-muted);
}
