/* ───────────────────────────── Tunables ───────────────────────────── */
:root {
  /* Type (032c-style): a cold neo-grotesque for the name, a mono in all caps for
     labels such as the links. Loaded in index.html from Google Fonts; to try
     alternatives (Albert Sans, Inter Black / Space Mono) change both places.
     When there is body copy, add a serif here (e.g. EB Garamond) and load it. */
  --font-display: 'Hanken Grotesk', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  --font-body: 'Roboto Mono', ui-monospace, Menlo, monospace;

  /* Photo and color */
  --hero-focus: 75% center;  /* focal point of the photo: the part kept when the viewport is
                                narrower than the photo (e.g. phones); wide screens are unaffected */
  --bg: #413931;             /* background that scrolls over the image: the darker rock */
  --h-gradient: 50vh;        /* height of the transparent → opaque gradient band   */

  /* Layout */
  --pad: 0.75rem;            /* inner padding: around each link, and between the name and its guides */
  --links-size: 0.875rem;    /* link label font-size; the links band is this + 2 × --pad */
  /* Page margin (the outer guide lines sit here). On larger screens it equals the
     height of the links band, so the outer frame and the band share one measure;
     below ~950px it compresses on 4vw down to 1rem. */
  --edge: clamp(1rem, 4vw, calc(var(--links-size) + 2 * var(--pad)));

  /* Name */
  --name-size: clamp(2.5rem, 11vw, 6rem);           /* at the top of the page (main.js
                                                       shrinks it further if the name
                                                       would not fit between the margins) */
  --name-size-end: clamp(1.75rem, 2.5vw, 2.25rem);  /* fully scrolled (top-left)  */
  --name-tracking: -0.03em;  /* letter-spacing of the name */
  --name-color-start: #000;  /* name color over the bare image                      */
  --name-color-end: #fff;    /* name color over the opaque background               */

  /* Links */
  --links-color: #fff;
  /* Link-cell hover fills, sampled from the photo (median of each region). */
  --link-hover-1: #d0a82d;   /* GitHub: the flowers                               */
  --link-hover-1-text: var(--bg);   /* white fails on yellow, so the dark rock    */
  --link-hover-2: #666b6e;   /* LinkedIn: the lighter rock (distant cliffs)       */
  --link-hover-2-text: #fff;
  --link-hover-3: #a2815d;   /* Email: the foreground dirt                        */
  --link-hover-3-text: #fff;

  /* Guides */
  --guides-fade-start: 0.75; /* scroll progress (0–1) at which the guides begin to fade in */
  --guide-color: rgb(255 255 255 / 0.4);
  --guide-width: 1px;        /* 1 device pixel: overridden to 0.5px on 2× screens below */

  /* Auto-scroll: after the page loads (at the top) and this pause, it scrolls itself
     to the bottom over the duration. Any scroll, touch, click or key press stops it;
     it is skipped for prefers-reduced-motion. A duration of 0 disables it. */
  --autoscroll-delay: 2s;
  --autoscroll-duration: 2.25s;
}
@media (min-resolution: 2dppx), (-webkit-min-device-pixel-ratio: 2) {
  :root { --guide-width: 0.5px; }
}

/* ───────────────────────────── Base ───────────────────────────────── */
* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--bg);
  font-family: var(--font-body);
}

/* Layer 0: the image, pinned to the viewport and cropped to fill it exactly */
.hero-image {
  position: fixed;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--hero-focus);
}

/* The scroll range: one viewport of image, then one viewport + gradient band
   of color. The layers below are all fixed and driven from scroll progress. */
.spacer { height: calc(200dvh + var(--h-gradient)); }

/* Layer 1: the colored background. Total height = viewport + gradient band,
   so at max scroll the viewport is filled with the solid color. main.js sets
   --overlay-y: the top edge travels from the bottom of the viewport (scroll 0)
   to -h_gradient (fully scrolled) on an eased curve. */
.overlay {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 1;
  height: calc(100dvh + var(--h-gradient));
  transform: translate3d(0, var(--overlay-y, 100dvh), 0);   /* parked below the viewport until main.js runs */
  will-change: transform;
  /* Fallback for browsers without relative color syntax */
  background: linear-gradient(to bottom, transparent 0, var(--bg) var(--h-gradient));
  /* Eased (smoothstep) ramp: a plain linear gradient has a kink in its rate of
     change where it starts and where it reaches full opacity, which the eye
     reads as a horizontal line (Mach band). Zero slope at both ends removes it. */
  background: linear-gradient(to bottom,
    rgb(from var(--bg) r g b / 0) 0,
    rgb(from var(--bg) r g b / 0.007) calc(var(--h-gradient) * 0.05),
    rgb(from var(--bg) r g b / 0.028) calc(var(--h-gradient) * 0.10),
    rgb(from var(--bg) r g b / 0.061) calc(var(--h-gradient) * 0.15),
    rgb(from var(--bg) r g b / 0.104) calc(var(--h-gradient) * 0.20),
    rgb(from var(--bg) r g b / 0.156) calc(var(--h-gradient) * 0.25),
    rgb(from var(--bg) r g b / 0.216) calc(var(--h-gradient) * 0.30),
    rgb(from var(--bg) r g b / 0.282) calc(var(--h-gradient) * 0.35),
    rgb(from var(--bg) r g b / 0.352) calc(var(--h-gradient) * 0.40),
    rgb(from var(--bg) r g b / 0.425) calc(var(--h-gradient) * 0.45),
    rgb(from var(--bg) r g b / 0.500) calc(var(--h-gradient) * 0.50),
    rgb(from var(--bg) r g b / 0.575) calc(var(--h-gradient) * 0.55),
    rgb(from var(--bg) r g b / 0.648) calc(var(--h-gradient) * 0.60),
    rgb(from var(--bg) r g b / 0.718) calc(var(--h-gradient) * 0.65),
    rgb(from var(--bg) r g b / 0.784) calc(var(--h-gradient) * 0.70),
    rgb(from var(--bg) r g b / 0.844) calc(var(--h-gradient) * 0.75),
    rgb(from var(--bg) r g b / 0.896) calc(var(--h-gradient) * 0.80),
    rgb(from var(--bg) r g b / 0.939) calc(var(--h-gradient) * 0.85),
    rgb(from var(--bg) r g b / 0.972) calc(var(--h-gradient) * 0.90),
    rgb(from var(--bg) r g b / 0.993) calc(var(--h-gradient) * 0.95),
    var(--bg) var(--h-gradient)
  );
}

/* Layer 4: layout guides — thin lines above the name, framing the links row, and at the page
   margins. main.js positions them from measured geometry and fades them in
   from --guides-fade-start to the bottom of the page (--guides-opacity).
   <body data-guides="…"> picks the mode (main.js sets --guides-y accordingly):
     fixed  → pinned to the viewport the whole time
     scroll → offset to the bottom viewport-sized slice of the overlay, so the
              lines ride in with the background and land in place at max scroll */
.guides {
  position: fixed;
  inset: 0;
  z-index: 4;                      /* above everything, so hairlines stay visible over hovered cells */
  transform: translate3d(0, var(--guides-y, 0px), 0);
  opacity: var(--guides-opacity, 0);
  pointer-events: none;
}
body[data-guides="off"] .guides { display: none; }
/* main.js snaps each line's leading edge to the device-pixel grid so hairlines
   stay crisp instead of blurring across two pixels. */
.guide { position: absolute; background: var(--guide-color); }
.guide-h { left: 0; width: 100%; height: var(--guide-width); }
.guide-v { top: 0; height: 100%; width: var(--guide-width); }

/* Layer 3: the name. main.js drives --name-y / --name-scale and --name-mix
   (0 → 1, start → end color, by the opacity of the colored background behind
   the name); the fallbacks place it bottom-left in the start color without JS. */
.name {
  position: fixed;
  top: 0;
  left: calc(var(--edge) + var(--pad));   /* --pad inside the left guide */
  z-index: 3;
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--name-size);
  font-weight: 800;
  line-height: 1;
  letter-spacing: var(--name-tracking);
  white-space: nowrap;
  transform-origin: 0 0;
  transform: translate3d(0, var(--name-y, calc(100dvh - var(--edge) - var(--pad) - 1em)), 0)
             scale(var(--name-scale, 1));
  color: color-mix(in srgb, var(--name-color-end) calc(var(--name-mix, 0) * 100%), var(--name-color-start));
  will-change: transform;
}
/* Layer 2: centered links. main.js drives --links-opacity: they stay
   transparent until the name has scrolled past them, then fade in. */
.links {
  position: fixed;
  inset: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: var(--links-opacity, 0);
  pointer-events: none;            /* the full-screen box itself shouldn't catch clicks */
}
.links.is-hidden { visibility: hidden; }
.links-row { display: flex; }
/* Each link is a "cell" padded by --pad on all sides: the cells abut, so the
   guide separators fall exactly mid-gap and the band is text + 2 × --pad tall. */
.links a {
  pointer-events: auto;
  padding: var(--pad);
  color: var(--links-color);
  font-size: var(--links-size);    /* label tags: small, caps, tracked out */
  font-weight: 500;
  line-height: 1;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-decoration: none;
  transition: background-color 120ms ease, color 120ms ease;
}
/* Hover: each cell fills with its own color and text color (see --link-hover-N). */
.links a:nth-child(1) { --hover-bg: var(--link-hover-1); --hover-fg: var(--link-hover-1-text); }
.links a:nth-child(2) { --hover-bg: var(--link-hover-2); --hover-fg: var(--link-hover-2-text); }
.links a:nth-child(3) { --hover-bg: var(--link-hover-3); --hover-fg: var(--link-hover-3-text); }
.links a:hover,
.links a:focus-visible { background-color: var(--hover-bg); color: var(--hover-fg); }
