/* Archivo (SIL Open Font License) self-hosted: no third-party request,
   so no visitor IP reaches Google and the site is fully self-contained. */
@font-face {
  font-family: Archivo;
  font-style: normal;
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-display: swap;
  src: url(../assets/fonts/archivo-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: Archivo;
  font-style: normal;
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-display: swap;
  src: url(../assets/fonts/archivo-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ---------- tokens ---------- */

:root {
  --abyss: #0D0A1A;
  --deep: #17122E;
  --edge: #2E2450;
  --amber: #FF9C42;
  --amber-lift: #FFB067;
  --ember: #FF4D6D;
  --tide: #3FBEDA;
  --haze: #A79FC4;
  --paper: #F3EFFF;

  --shell: min(1180px, 100%);
  --gutter: clamp(1.25rem, 5vw, 4rem);

  --ease: cubic-bezier(.16, 1, .3, 1);
}

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

body,
h1,
h2,
h3,
p {
  margin: 0;
}

/* ---------- base ---------- */

html {
  scroll-behavior: smooth;
}

body {
  position: relative;

  /* plate hover glows bleed sideways by design; clip (not hidden, which
     would kill the sticky header) so they never add a scrollbar */
  overflow-x: clip;

  min-height: 100vh;

  background: var(--abyss);
  color: var(--paper);

  font-family: Archivo, system-ui, sans-serif;
  font-stretch: 100%;
  font-size: clamp(1rem, .96rem + .2vw, 1.09rem);
  line-height: 1.6;

  -webkit-font-smoothing: antialiased;
}

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

  /* considered defaults for any inline link that does carry an underline */
  text-underline-offset: .18em;
  text-decoration-thickness: 1px;
}

/* ---------- browser surfaces ---------- */
/* The parts not drawn here still ship with defaults belonging to no design
   system. Theme them from the palette. */

::selection {
  color: var(--abyss);
  background: var(--amber);
  text-shadow: none;
}

html {
  /* tells the UA to render its own chrome dark, so form controls and the
     default scrollbar stop arriving as light-mode widgets on a dark page */
  color-scheme: dark;

  scrollbar-width: thin;
  scrollbar-color: var(--edge) transparent;
}

img {
  display: block;
  max-width: 100%;
}

:focus-visible {
  outline: 2px solid var(--amber);
  outline-offset: 4px;
}

/* ---------- ambient hex field ---------- */

.tiles {
  position: absolute;
  inset: 0;

  width: 100%;
  height: 100%;

  opacity: .46;
  pointer-events: none;

  /* centred under the name's baseline so the tiles read as lit by the same
     light, not as a separate texture lower down the section */
  -webkit-mask-image: radial-gradient(78% 52% at 50% 68%, #000 0%, transparent 74%);
  mask-image: radial-gradient(78% 52% at 50% 68%, #000 0%, transparent 74%);
}

/* stroke lives here, not as an SVG attribute, so the tile field is lit by
   the same token as everything else the light touches */
.tiles g {
  stroke: var(--amber);
}

.tiles__fill {
  animation: drift 120s linear infinite;
}

@keyframes drift {
  to {
    transform: translate(-93.53px, -162px);
  }
}

/* ---------- top bar ---------- */

.topbar {
  position: sticky;
  top: 0;
  z-index: 20;

  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 2rem;

  padding: 1.05rem var(--gutter);

  background: rgba(13, 10, 26, .66);
  border-bottom: 1px solid rgba(46, 36, 80, .55);

  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}

/* the wordmark duplicates the hero name while that name fills the viewport;
   it earns its place only once the hero has scrolled away. Default is visible
   so a failed or absent script leaves the identity anchor in place. */
.js .topbar__mark {
  opacity: 0;
  transform: translateY(-4px);
  pointer-events: none;

  transition: opacity .35s ease, transform .35s var(--ease);
}

.js .topbar.is-anchored .topbar__mark {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}

.topbar__mark {
  font-stretch: 118%;
  font-weight: 700;
  font-size: .95rem;
  letter-spacing: -.005em;
}

.topbar__nav {
  display: flex;
  align-items: center;
  gap: clamp(1rem, 2.6vw, 2.1rem);

  font-size: .9rem;
  color: var(--haze);
}

.topbar__nav a {
  transition: color .25s ease;
}

.topbar__nav a:hover {
  color: var(--paper);
}

.topbar__resume {
  padding: .4rem .95rem;

  color: var(--amber);
  border: 1px solid rgba(255, 156, 66, .38);
  border-radius: 2px;

  transition: background-color .25s ease, border-color .25s ease, color .25s ease;
}

.topbar__resume:hover {
  color: var(--abyss);
  background: var(--amber);
  border-color: var(--amber);
}

/* ---------- hero ---------- */

.hero {
  position: relative;
  z-index: 1;

  /* the glow is wider than a phone viewport; clip it rather than
     let it push a horizontal scrollbar onto the page */
  overflow: hidden;

  display: flex;
  align-items: center;

  min-height: min(88svh, 820px);

  padding: clamp(4rem, 11vh, 8rem) var(--gutter) clamp(5rem, 13vh, 9rem);
}

@keyframes breathe {
  from {
    opacity: .72;
    transform: translateX(-50%) scaleY(.94);
  }

  to {
    opacity: 1;
    transform: translateX(-50%) scaleY(1.08);
  }
}

.hero__inner {
  position: relative;
  z-index: 1;

  width: var(--shell);
  margin-inline: auto;
}

.hero__name {
  /* at wdth 125 the letterforms are wide enough that width, not size, carries
     the hierarchy; the long line lands around 85% of the shell, not flush to it */
  position: relative;

  font-size: clamp(2.7rem, 14.9vw, 12.2rem);
  font-weight: 700;
  font-stretch: 125%;
  line-height: .86;
  letter-spacing: -.04em;

  animation: resolve 1.5s var(--ease) both;
}

/* the light is the name's own: anchored to its box so it rim-lights the
   baseline at every breakpoint instead of drifting out of register */
.hero__name::after {
  content: "";
  position: absolute;
  z-index: -1;
  top: 100%;
  left: 50%;

  width: min(1420px, 132vw);
  height: clamp(200px, 30vh, 380px);

  transform: translateX(-50%);
  transform-origin: 50% 0;

  background: radial-gradient(ellipse at 50% 0%,
      rgba(255, 156, 66, .5),
      rgba(255, 77, 109, .2) 38%,
      transparent 72%);

  filter: blur(40px);
  pointer-events: none;

  animation:
    bloom 1.6s var(--ease) .4s both,
    breathe 11s ease-in-out 2s infinite alternate;
}

/* the one authored moment: the name opens from the narrow end of Archivo's
   width axis to its maximum, and the horizon blooms as it settles */
@keyframes resolve {
  from {
    opacity: 0;
    font-stretch: 62%;
    letter-spacing: .06em;
    filter: blur(6px);
  }

  to {
    opacity: 1;
    font-stretch: 125%;
    letter-spacing: -.035em;
    filter: blur(0);
  }
}

@keyframes bloom {
  from {
    opacity: 0;
    transform: translateX(-50%) scaleY(.4);
  }

  to {
    opacity: 1;
    transform: translateX(-50%) scaleY(1);
  }
}

.hero__under {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: clamp(1.4rem, 3.5vw, 3.5rem);

  margin-top: clamp(1.8rem, 4.2vh, 3rem);
}

.hero__say {
  flex: 1 1 26rem;
  max-width: 48ch;
}

.hero__lead {
  font-size: clamp(1rem, .95rem + .3vw, 1.18rem);
  line-height: 1.55;
  color: var(--haze);

  animation: rise .8s var(--ease) .62s both;
}

.hero__where {
  max-width: 54ch;
  margin-top: .9rem;

  font-size: .85rem;
  color: rgba(167, 159, 196, .74);

  animation: rise .8s var(--ease) .74s both;
}

.hero__acts {
  flex: 0 0 auto;

  display: flex;
  flex-wrap: wrap;
  gap: .85rem;

  animation: rise .8s var(--ease) .86s both;
}

@keyframes rise {
  from {
    opacity: 0;
    transform: translateY(14px);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

/* ---------- buttons ---------- */

.btn {
  padding: .78rem 1.5rem;

  font-size: .94rem;
  font-weight: 600;

  border: 1px solid transparent;
  border-radius: 2px;

  transition: background-color .25s ease, border-color .25s ease,
    color .25s ease, transform .25s var(--ease);
}

.btn:hover {
  transform: translateY(-2px);
}

.btn--solid {
  color: var(--abyss);
  background: var(--amber);
}

.btn--solid:hover {
  background: var(--amber-lift);
}

.btn--ghost {
  color: var(--paper);
  border-color: var(--edge);
}

.btn--ghost:hover {
  border-color: var(--haze);
}

/* ---------- work ---------- */

.work,
.about,
.contact {
  position: relative;
  z-index: 1;

  width: var(--shell);
  margin-inline: auto;

  padding-inline: var(--gutter);
}

.work {
  padding-block: clamp(3rem, 8vh, 6rem) clamp(3.5rem, 9vh, 6rem);
}

.about,
.contact {
  padding-block: clamp(2.5rem, 6vh, 4.5rem);
}

.section__title {
  max-width: 20ch;

  font-size: clamp(1.7rem, 1.2rem + 2.1vw, 2.65rem);
  font-weight: 700;
  font-stretch: 108%;
  line-height: 1.1;
  letter-spacing: -.02em;
}

.plates {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: clamp(2.6rem, 5vw, 4.2rem);

  margin-top: clamp(2.5rem, 6vh, 4rem);
}

/* ---------- plate ---------- */

.plate {
  position: relative;
  isolation: isolate;

  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

.plate__open {
  display: block;
  width: 100%;
}

.plate--lead {
  grid-column: 1 / -1;
}

.plate::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: -7% -7% -15%;

  background: radial-gradient(58% 62% at 50% 100%,
      rgba(255, 156, 66, .55),
      rgba(255, 77, 109, .2) 46%,
      transparent 74%);

  filter: blur(42px);
  opacity: 0;

  transition: opacity .55s ease;
}

.plate:hover::before,
.plate:focus-visible::before {
  opacity: 1;
}

.plate__frame {
  display: block;
  position: relative;
  overflow: hidden;

  aspect-ratio: 16 / 9;

  background: var(--deep);
  border: 1px solid var(--edge);
  border-radius: 3px;

  transition: border-color .35s ease, box-shadow .45s ease;
}

.plate:hover .plate__frame {
  border-color: rgba(255, 156, 66, .5);
  box-shadow: 0 20px 62px -22px rgba(255, 156, 66, .5);
}

.plate__frame img {
  width: 100%;
  height: 100%;

  object-fit: cover;

  transition: transform .75s var(--ease);
}

.plate:hover .plate__frame img {
  transform: scale(1.032);
}

.plate__empty {
  position: absolute;
  inset: 0;

  display: grid;
  place-items: center;

  font-size: .85rem;
  color: rgba(167, 159, 196, .64);
}

.plate__meta {
  display: flex;
  flex-direction: column;
  gap: .62rem;

  padding-top: 1.2rem;
}

.plate__head {
  display: flex;
  align-items: baseline;
  gap: .9rem;
}

.plate__title {
  font-size: clamp(1.22rem, 1.05rem + .7vw, 1.62rem);
  font-weight: 700;
  font-stretch: 108%;
  letter-spacing: -.017em;
}

.plate--lead .plate__title {
  font-size: clamp(1.5rem, 1.15rem + 1.5vw, 2.2rem);
}

.plate__year {
  flex: none;

  font-size: .82rem;
  color: rgba(167, 159, 196, .76);
  font-variant-numeric: tabular-nums;
}

.plate__line {
  max-width: 54ch;

  font-size: .97rem;
  line-height: 1.55;
  color: var(--haze);
}

.plate__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .55rem 1.6rem;

  width: 100%;
  margin-top: .9rem;
}

.plate__site {
  margin-top: .85rem;
  padding-bottom: 2px;

  font-size: .85rem;
  color: var(--haze);

  border-bottom: 1px solid var(--edge);

  transition: color .25s ease, border-color .25s ease;
}

.plate__site:hover {
  color: var(--amber);
  border-color: var(--amber);
}

.sig {
  display: inline-flex;
  align-items: center;
  gap: .55rem;

  font-size: .84rem;
  color: var(--haze);
}

.sig::before {
  content: "";

  width: 6px;
  height: 6px;

  border-radius: 50%;
}

.sig--live::before {
  background: var(--tide);
  box-shadow: 0 0 0 3px rgba(63, 190, 218, .15);
}

.sig--warm::before {
  background: var(--amber);
  box-shadow: 0 0 0 3px rgba(255, 156, 66, .15);
}

.plate__stack {
  display: flex;
  flex-wrap: wrap;
  gap: .2rem 1.15rem;

  font-size: .84rem;
  color: rgba(167, 159, 196, .74);
}

/* ---------- narrow ---------- */

@media (max-width: 860px) {

  /* no empty column to fill on a phone — keep the tiles clear of the copy */
  .tiles {
    opacity: .3;

    -webkit-mask-image: radial-gradient(62% 34% at 72% 99%, #000 0%, transparent 72%);
    mask-image: radial-gradient(62% 34% at 72% 99%, #000 0%, transparent 72%);
  }

  .plates {
    grid-template-columns: minmax(0, 1fr);
  }

  .topbar__mark {
    display: none;
  }

  .topbar {
    justify-content: center;
  }
}

/* ---------- motion off ---------- */

@media (prefers-reduced-motion: reduce) {

  html {
    scroll-behavior: auto;
  }

  .tiles__fill,
  .hero__name::after,
  .hero__name,
  .hero__lead,
  .hero__where,
  .hero__acts {
    animation: none;
  }

  .btn:hover,
  .plate:hover .plate__frame img,
  .js .topbar__mark,
  .js .topbar.is-anchored .topbar__mark {
    transform: none;
  }
}


/* ---------- about + contact ---------- */

.prose {
  max-width: 58ch;
  margin-top: clamp(1.5rem, 3vh, 2rem);
}

.prose p {
  margin-bottom: 1rem;
  color: var(--haze);
}

.prose p:last-child {
  margin-bottom: 0;
  color: var(--paper);
}

.links {
  display: flex;
  flex-wrap: wrap;
  gap: .7rem 2.4rem;

  margin: clamp(1.5rem, 3vh, 2rem) 0 0;
  padding: 0;

  list-style: none;
}

.links a {
  padding-bottom: 2px;

  color: var(--paper);
  border-bottom: 1px solid var(--edge);

  transition: color .25s ease, border-color .25s ease;
}

.links a:hover {
  color: var(--amber);
  border-color: var(--amber);
}

.foot {
  position: relative;
  z-index: 1;

  width: var(--shell);
  margin-inline: auto;

  padding: 2rem var(--gutter) 3rem;

  font-size: .84rem;
  color: rgba(167, 159, 196, .74);

  border-top: 1px solid rgba(46, 36, 80, .5);
}

/* ---------- detail sheet ---------- */

/* author styles outrank the UA sheet, so display:flex would otherwise
   beat dialog:not([open]){display:none} and leave the sheet in the page */
.sheet:not([open]) {
  display: none;
}

.sheet {
  position: relative;

  display: flex;
  flex-direction: column;
  overflow: hidden;

  width: min(860px, calc(100vw - 2rem));
  max-height: min(86vh, 880px);
  margin: auto;
  padding: 0;

  color: var(--paper);
  background: var(--deep);
  border: 1px solid var(--edge);
  border-radius: 4px;
}

.sheet::backdrop {
  background: rgba(6, 4, 14, .74);
}

.sheet__body {
  overflow-y: auto;
  overscroll-behavior: contain;
}

.sheet__close {
  position: absolute;
  top: .8rem;
  right: .8rem;
  z-index: 3;

  display: grid;
  place-items: center;

  width: 2.1rem;
  height: 2.1rem;
  padding: 0;

  font-size: 1.2rem;
  line-height: 1;
  color: var(--paper);

  background: rgba(13, 10, 26, .74);
  border: 1px solid var(--edge);
  border-radius: 50%;

  cursor: pointer;

  transition: border-color .25s ease, color .25s ease;
}

.sheet__close:hover {
  color: var(--amber);
  border-color: var(--amber);
}

.sheet__frame {
  display: block;
  position: relative;
  overflow: hidden;

  aspect-ratio: 16 / 9;

  background: var(--abyss);
  border-bottom: 1px solid var(--edge);
}

.sheet__frame img {
  width: 100%;
  height: 100%;

  object-fit: cover;
}

.sheet__text {
  padding: clamp(1.4rem, 3.5vw, 2.4rem);
}

.sheet__title {
  font-size: clamp(1.5rem, 1.15rem + 1.5vw, 2.2rem);
  font-weight: 700;
  font-stretch: 108%;
  letter-spacing: -.02em;
}

.sheet__sig {
  margin-top: .5rem;
}

.sheet__text p {
  max-width: 64ch;
  margin-top: .9rem;

  color: var(--haze);
}

.sheet__stack {
  margin-top: 1.3rem;
}

.sheet__acts {
  display: flex;
  flex-wrap: wrap;
  gap: .8rem;

  margin-top: 1.6rem;
}

/* ---------- card-to-sheet morph ---------- */

::view-transition-group(plate) {
  animation-duration: .5s;
  animation-timing-function: cubic-bezier(.16, 1, .3, 1);
}

::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: .32s;
}
