/* ==========================================================================
   NATHAN CHERRY — PERSONAL SITE

   Standalone. This folder depends on nothing outside itself: no kit, no
   framework, no build step. Copy the folder anywhere and it works.

   The treatment is lifted from Cherrify UI's screen module — a photograph
   that arrives in its own colours and resolves into a wash — but only the
   parts this one page uses. The kit is 98 stylesheets; this is one, because
   a placeholder has no business carrying a component library.

   The only values kept from it are the handful of tokens below, inlined with
   their real numbers rather than imported, so there is nothing to resolve.
   ========================================================================== */

:root {
  /* ---- COLOUR ---- */
  --ink-950: #141414;
  --ink-900: #1d1d1d;
  --ink-700: #3a3a3a;
  --paper:   #ffffff;

  /* ---- TYPE ---- */
  --font: 'IBM Plex Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI',
          Roboto, Helvetica, Arial, sans-serif;

  --fs-2xs: 8px;
  --fs-xs:  11px;
  --fs-sm:  12px;
  --fs-md:  14px;
  --fs-4xl: 40px;

  --fw-light:  300;
  --fw-medium: 500;
  --fw-bold:   600;

  --lh-base: 1.45;
  --tracking-label: 0.04em;
  --tracking-wide:  0.08em;

  /* ---- SPACE ---- */
  --space-2: 4px;
  --space-3: 6px;
  --space-4: 8px;
  --space-5: 10px;
  --space-6: 12px;
  --space-7: 16px;
  --space-8: 20px;
  --space-9: 24px;
  --space-10: 32px;

  /* ---- MOTION ---- */
  --dur-base: 200ms;
  --ease:     cubic-bezier(0.4, 0, 0.2, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);

  --focus: #94ce0c;
}

/* ==========================================================================
   RESET — only what this page needs
   ========================================================================== */

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

html, body { height: 100%; }

body {
  margin: 0;
  background-color: var(--ink-900);
  color: var(--paper);
  font-family: var(--font);
  font-size: var(--fs-md);
  line-height: var(--lh-base);
  -webkit-font-smoothing: antialiased;
}

svg { display: block; fill: currentColor; }

/* Until the opening has run, no transition or animation may fire. Without
   this an animation declared on an element that exists at first paint has
   ALREADY RUN before anything can gate it. */
html:not(.is-ready) *,
html:not(.is-ready) *::before,
html:not(.is-ready) *::after {
  transition: none !important;
  animation-duration: 0s !important;
}

/* ==========================================================================
   THE SCREEN

   Three layers rather than one, because the opening moves the photograph and
   the colour INDEPENDENTLY — and an element's own background cannot be
   animated apart from its pseudo-elements, so three backgrounds means three
   elements.

     __art-photo   the picture, in its own colours      .85 -> 0
     __art-wash    gradient + grain                     .22 -> 1
     __art-tex     the picture again, as luminance      0   -> .18

   The settled state below IS the finished design. The animation only adds an
   arrival — if the script never runs, nothing matches and the page renders
   correctly anyway.
   ========================================================================== */

.screen {
  position: relative;
  min-height: 100vh;
  display: grid;
  place-items: center;
  padding: var(--space-10) var(--space-9);
  overflow: hidden;
  background-color: var(--ink-900);
}

.screen__art {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;

  /* Contains the luminosity blend below. Without a stacking context the
     blend hunts up the tree for its backdrop. */
  isolation: isolate;
}

.screen__art > span {
  position: absolute;
  inset: 0;
  display: block;
}

.screen__art-photo,
.screen__art-tex {
  background-image: url('fields.jpeg');
  background-size: cover;
  background-position: center;
  transform-origin: 50% 45%;
}

/* Settled: gone. This layer exists for the first second and a half. */
.screen__art-photo { opacity: 0; }

/* The picture as texture, not subject — luminance only, so the tone comes
   from the wash underneath. */
.screen__art-tex {
  opacity: 0.18;
  mix-blend-mode: luminosity;
}

.screen__art-wash {
  /* The grain is not decoration. A flat gradient across a whole viewport
     bands into visible stripes on an 8-bit display; noise at a few percent
     is the standard fix, and `overlay` stops it greying the whole thing. */
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='0.4'/%3E%3C/svg%3E"),
    linear-gradient(115deg, var(--ink-700) 0%, var(--ink-900) 55%, var(--ink-950) 100%);
  background-size: 140px 140px, auto;
  background-blend-mode: overlay, normal;
}

/* The content has to be lifted above the art explicitly. The art is
   absolutely positioned with a z-index, so a non-positioned sibling paints
   underneath it — fully opaque, correctly placed, and invisible. */
.screen__body {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 560px;
  display: flex;
  flex-direction: column;
  gap: var(--space-7);
}

/* ==========================================================================
   THE PAGE
   ========================================================================== */

.me-name {
  margin: 0;
  font-size: var(--fs-4xl);
  font-weight: var(--fw-light);
  line-height: 1.1;
  color: var(--paper);
}
.me-name b { font-weight: var(--fw-medium); }

.me-lede {
  margin: var(--space-4) 0 0;
  max-width: 52ch;
  color: rgba(255, 255, 255, 0.78);
  font-size: var(--fs-md);
}

.me-label {
  font-size: var(--fs-2xs);
  font-weight: var(--fw-bold);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.45);
}

.me-list {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin: var(--space-4) 0 0;
  padding: 0;
  list-style: none;
}

/* The whole row is the target, and the rule grows from nothing rather than
   appearing — growing reads as the row being selected, appearing reads as
   something switching on. */
.me-link {
  position: relative;
  display: flex;
  align-items: baseline;
  gap: var(--space-5);
  padding: var(--space-3) 0 var(--space-3) var(--space-5);
  color: rgba(255, 255, 255, 0.86);
  font-size: var(--fs-md);
  text-decoration: none;
  transition: color var(--dur-base) var(--ease),
              padding-left var(--dur-base) var(--ease);
}
.me-link::before {
  content: "";
  position: absolute;
  left: 0; top: 50%;
  width: 0; height: 1px;
  margin-top: -1px;
  background-color: rgba(255, 255, 255, 0.55);
  transition: width var(--dur-base) var(--ease);
}
.me-link:hover,
.me-link:focus-visible {
  color: var(--paper);
  padding-left: var(--space-8);
}
.me-link:hover::before,
.me-link:focus-visible::before { width: var(--space-6); }
.me-link:focus-visible { outline: 2px solid var(--focus); outline-offset: 3px; }

.me-link__note {
  color: rgba(255, 255, 255, 0.45);
  font-size: var(--fs-sm);
}

.me-socials {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-6);
  margin-top: var(--space-4);
}
.me-socials a {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  color: rgba(255, 255, 255, 0.78);
  font-size: var(--fs-sm);
  text-decoration: none;
}
.me-socials a:hover { color: var(--paper); text-decoration: underline; }
.me-socials svg { width: 13px; height: 13px; color: rgba(255, 255, 255, 0.5); }
.me-socials a:focus-visible { outline: 2px solid var(--focus); outline-offset: 3px; }

.me-copy {
  margin-top: var(--space-8);
  padding-top: var(--space-6);
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  color: rgba(255, 255, 255, 0.45);
  font-size: var(--fs-xs);
  letter-spacing: var(--tracking-label);
}
.me-copy b { font-weight: var(--fw-medium); color: rgba(255, 255, 255, 0.7); }

/* ==========================================================================
   MOTION

   The whole block is inside a no-preference query on purpose. Reduced motion
   normally kills animation DURATION but leaves DELAY standing, so a stagger
   written outside such a query would hold every element back for its full
   delay with nothing animating — a page that sits half-empty and then snaps
   together. In here, reduced motion means no rule matches at all, and the
   base state above is already the finished design.
   ========================================================================== */

@media (prefers-reduced-motion: no-preference) {

  html.is-lit .screen__art-photo { animation: s-photo 1500ms var(--ease-out) both; }
  html.is-lit .screen__art-wash  { animation: s-wash 1250ms var(--ease-out) 120ms both; }
  html.is-lit .screen__art-tex   { animation: s-tex 1500ms var(--ease-out) both; }

  /* The handover from real colour to luminance texture is a cross-fade
     between two copies of the same image, because mix-blend-mode cannot be
     animated. Both scale 1.06 -> 1 about the same origin in lockstep, so it
     reads as one image settling back rather than two sliding past. */
  @keyframes s-photo {
    0%   { opacity: 0.85; transform: scale(1.06); }
    50%  { opacity: 0.5; }
    100% { opacity: 0;    transform: scale(1); }
  }
  @keyframes s-wash { from { opacity: 0.22; } to { opacity: 1; } }
  @keyframes s-tex {
    from { opacity: 0;    transform: scale(1.06); }
    to   { opacity: 0.18; transform: scale(1); }
  }

  html.is-lit:not(.is-settled) .screen__body > * {
    animation: s-rise 600ms var(--ease-out) both;
  }
  html.is-lit:not(.is-settled) .screen__body > *:nth-child(1) { animation-delay: 260ms; }
  html.is-lit:not(.is-settled) .screen__body > *:nth-child(2) { animation-delay: 380ms; }
  html.is-lit:not(.is-settled) .screen__body > *:nth-child(3) { animation-delay: 460ms; }
  html.is-lit:not(.is-settled) .screen__body > *:nth-child(4) { animation-delay: 540ms; }

  @keyframes s-rise {
    from { opacity: 0; transform: translateY(12px); }
    to   { opacity: 1; transform: translateY(0); }
  }
}

@media (forced-colors: active) {
  /* None of the art carries meaning — it is texture, and forced colours has
     no palette for it to draw from. */
  .screen__art { display: none; }
}

@media (max-width: 700px) {
  .screen { padding: var(--space-8) var(--space-7); }
  .me-name { font-size: 28px; }
}
