/*
 * home.css: the home page's header extras, hero, section frame and about.
 * Projects and the contact form have their own files (projects.css,
 * contact.css). Tokens come from base.css.
 */

html { scroll-behavior: smooth; }

section { scroll-margin-top: var(--space-6); }

/* ── Header: animated logo and theme toggle ─────────────────────── */
.logo {
  display: inline-flex;
  white-space: pre;
  /* "DR-DEV" + cursor = 7 monospace chars. Reserving that width keeps
     the header from re-flowing while the logo animation types/erases */
  min-width: 7ch;
}

/* Blinks four times (4.8 s), then stays lit: WCAG 2.2.2 allows blinking
   that starts on its own only if it stops within 5 s. */
.cursor { animation: blink 1.2s step-end 4; }
@keyframes blink { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }

.site-nav {
  display: flex;
  gap: var(--space-8);
  align-items: center;
  flex-wrap: wrap;
  font: 500 var(--fs-label) var(--font-mono);
  color: var(--mut);
  margin-left: auto; /* desktop: nav and toggle sit together on the right */
}

/* ── Theme toggle ───────────────────────────────────────────────── */
.theme-toggle {
  display: inline-grid;
  place-items: center;
  width: var(--control-size);
  height: var(--control-size);
  padding: 0;
  cursor: pointer;
  color: var(--fg);
  background: none;
  border: var(--hairline) solid var(--line);
  border-radius: var(--radius-sm);
  /* header gap + this = the nav's own gap, so the spacing reads as one row */
  margin-left: calc(var(--space-8) - var(--space-4));
}
.theme-toggle:hover { border-color: var(--acc); color: var(--acc); }

/* Line icons, drawn in the text colour so hover and themes recolour them.
   Both sit in the same grid cell; the theme decides which one is shown. */
.icon {
  grid-area: 1 / 1;
  width: var(--icon-size);
  height: var(--icon-size);
  fill: none;
  stroke: currentColor;
  stroke-width: 1.75; /* in the icon's 24-unit grid, not px */
  stroke-linecap: round;
  stroke-linejoin: round;
  transition:
    transform var(--dur-icon) var(--ease-spring),
    opacity var(--dur-icon-fade) ease;
}

/* Sun → moon: the sun turns away and shrinks while the moon swings in from
   the other side with a slight overshoot. Moon → sun: the reverse, and the
   rays shoot out one after another once the core is in place. */
.icon-sun  { transform: rotate(0) scale(1); opacity: 1; }
.icon-moon { transform: rotate(-120deg) scale(0.4); opacity: 0; }
:root[data-theme="light"] .icon-sun  { transform: rotate(120deg) scale(0.4); opacity: 0; }
:root[data-theme="light"] .icon-moon { transform: rotate(0) scale(1); opacity: 1; }

.ray {
  transform-box: view-box;
  transform-origin: center;
  transition: transform var(--dur-ray) var(--ease-spring);
  transition-delay: calc(var(--dur-ray-wait) + var(--ray-n) * var(--ray-stagger));
}
:root[data-theme="light"] .ray { transform: scale(0); transition-delay: 0s; }
.ray:nth-child(1) { --ray-n: 0; }
.ray:nth-child(2) { --ray-n: 1; }
.ray:nth-child(3) { --ray-n: 2; }
.ray:nth-child(4) { --ray-n: 3; }
.ray:nth-child(5) { --ray-n: 4; }
.ray:nth-child(6) { --ray-n: 5; }
.ray:nth-child(7) { --ray-n: 6; }
.ray:nth-child(8) { --ray-n: 7; }

/* The new theme opens as a circle from the button (the script drives the
   clip-path); switch off the browser's default cross-fade. Only while the
   theme switches: page-to-page transitions keep their cross-fade. */
:root.theme-switching::view-transition-old(root),
:root.theme-switching::view-transition-new(root) {
  animation: none;
  mix-blend-mode: normal;
}

/* ── Hero ───────────────────────────────────────────────────────── */
.hero {
  position: relative;
  padding: var(--hero-pad-top) 0 var(--hero-pad-bottom);
  /* How far the dot grid runs past the content column, into the gutter */
  --grid-bleed: 40px;
  /* Fade the grid's top and bottom so the dots emerge and recede softly; a
     hard top row would run past the header line and read as misaligned. */
  --grid-fade: linear-gradient(180deg, transparent 0, #000 14%, #000 55%, transparent 100%);
}

/* Ambient: dotted grid behind the hero (static CSS version). */
.hero-grid {
  position: absolute;
  inset: 0 calc(-1 * var(--grid-bleed));
  z-index: 0;
  pointer-events: none;
  background-image: radial-gradient(var(--grid) 1.4px, transparent 1.4px); /* literal: dot radius, matches BASE_R in the canvas script */
  background-size: var(--space-8) var(--space-8);
  background-position: center top;
}

/* Interactive canvas version: the script swaps it in for the CSS grid
   when motion is allowed. Same box and fade, so the two match at rest. */
.hero-grid-canvas {
  position: absolute;
  /* <canvas> is a replaced element: `inset` won't stretch it (width:auto
     resolves to its intrinsic 300x150), so size it explicitly. */
  top: 0;
  left: calc(-1 * var(--grid-bleed));
  width: calc(100% + 2 * var(--grid-bleed));
  height: 100%;
  z-index: 0;
  pointer-events: none;
  display: none;
}

.hero-grid,
.hero-grid-canvas {
  -webkit-mask-image: var(--grid-fade);
          mask-image: var(--grid-fade);
}

/* Ambient: oversized outlined wordmark, parked on the right, drifts on scroll */
.hero-watermark {
  position: absolute;
  inset: 0;
  z-index: 0;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  overflow: hidden;
  pointer-events: none;
  /* keep the last glyph clear of the overflow clip edge (the stroke of
     the final letter was getting shaved off on the right) */
  padding-right: var(--space-3);
}
.watermark-svg {
  /* The generated outline box is this tall per em of the old CSS text
     (printed by tools/watermark.py), so the word keeps its old size. */
  --wm-em-height: 0.754;
  --wm-stroke: 2px;
  --wm-stroke-units: 19; /* fallback until the script measures; about right on a phone */
  --wm-drift: 0.35;      /* parallax: px the word moves down per px scrolled (read by the script) */
  height: calc(var(--fs-watermark) * var(--wm-em-height));
  width: auto;
  overflow: visible;
  will-change: transform;
}
/* Outlines are stroked in the SVG's own units, which scale with the word.
   A script converts --wm-stroke (2px on screen) into those units for the
   current size and sets --wm-stroke-units. vector-effect: non-scaling-stroke
   would do it in CSS, but it makes browsers dash in screen pixels, which
   breaks the pathLength-based trace (it falls apart into 1px dots). */
.watermark-svg use {
  fill: none;
  stroke-width: var(--wm-stroke-units);
  stroke-linejoin: round;
}
.wm-base use { stroke: var(--wm); }

/* The trace: an accent line drawn along each letter's outline. --wm-p is the
   drawn share of a letter (0..1, pathLength="1"); the scroll script sets it
   letter by letter. It starts at 0, and reduced motion shows it finished. */
.wm-trace use {
  --wm-p: 0;
  stroke: var(--wm-trace);
  stroke-dasharray: 1;
  stroke-dashoffset: calc(1 - var(--wm-p));
}

/* Keep hero content above the ambient layers */
.hero-inner { position: relative; z-index: 1; }

/* Ambient: section-number scramble. The digits are tabular so the label
   never changes width while ticking */
.tick { font-variant-numeric: tabular-nums; }

.eyebrow { font: 500 var(--fs-ui) var(--font-mono); color: var(--acc); margin-bottom: var(--space-6); }

.hero h1 {
  margin: 0;
  font: 700 var(--fs-hero)/var(--lh-display) var(--font-sans);
  letter-spacing: -0.03em;
}
.hero h1 .dim { color: var(--mut); }

.hero-actions { display: flex; gap: var(--space-4); margin-top: var(--space-12); flex-wrap: wrap; }

.btn {
  display: inline-block;
  font: 700 var(--fs-ui) var(--font-mono);
  background: var(--acc);
  color: var(--accfg);
  padding: var(--space-4) var(--space-7);
  border-radius: var(--radius-md);
}
/* Opaque on purpose: the watermark drifts behind it while scrolling. It
   keeps full opacity on hover too (no global link dim); the accent border
   is the hover feedback. */
.btn-ghost {
  font-weight: 500;
  background: var(--bg);
  color: var(--fg);
  border: var(--hairline) solid var(--line);
}
.btn-ghost:hover { opacity: 1; border-color: var(--acc); }

/* ── Sections ───────────────────────────────────────────────────── */
.section { padding: var(--section-pad) 0; border-top: var(--hairline) solid var(--line); }

.section-label {
  font: 500 var(--fs-label) var(--font-mono);
  color: var(--mut);
  margin-bottom: var(--space-8);
  width: fit-content; /* so the underline can measure the label's text */
  /* Drawn share of the underline, 0..1. The scroll script overrides it per
     label as the label rises to the upper third of the screen. Without the
     script, and under reduced motion (the script never runs), it stays 1
     and the line is simply drawn in full. */
  --reveal: 1;
}
/* The number in accent, like the numbered headings on the text pages. */
.section-label .tick { color: var(--acc); }
/* Accent underline, a little longer than its label. */
.section-label::after {
  content: '';
  display: block;
  width: calc(100% + var(--underline-overhang));
  height: var(--underline-weight);
  margin-top: var(--space-2);
  background: var(--acc);
  transform: scaleX(var(--reveal));
  transform-origin: left center;
}

/* ── About ──────────────────────────────────────────────────────── */
.about-grid { display: grid; grid-template-columns: var(--about-label-col) 1fr; gap: var(--space-12); }
.about-grid .section-label { margin-bottom: 0; }
.about-grid p { margin: 0; font: 400 var(--fs-lead)/var(--lh-relaxed) var(--font-sans); max-width: var(--measure-wide); }

@media (max-width: 900px) {
  .about-grid { grid-template-columns: 1fr; gap: var(--space-6); }
}

@media (max-width: 600px) {
  /* One row on phones too: tighter gaps, so logo, links and toggle fit with
     the "./" prefixes from 375px (below that the prefixes go, see further
     down). The logo stays left, links and toggle sit together on the right. */
  .site-header { gap: var(--space-2_5); }
  .site-nav { gap: var(--space-2_5); }
  .theme-toggle { margin-left: 0; }

  /* Same free-floating watermark as on desktop, shifted so "dev" shows in
     the free space right of the short name lines ("Dominik", "Röttger.").
     `translate` (not `transform`), because the parallax script owns the
     transform and the two combine. */
  .watermark-svg {
    --wm-shift-x: 50px;
    --wm-shift-y: -90px;
    --wm-drift: 0.45;    /* a little faster on phones, so it travels further down */
    translate: var(--wm-shift-x) var(--wm-shift-y);
  }
}

/* Narrow phones: drop the "./" before the links and tighten the gaps a
   little more, so the header stays one row down to 320px. */
@media (max-width: 374px) {
  .nav-prefix { display: none; }
  .site-header, .site-nav { gap: var(--space-2); }
}

/* ── Reduced motion ─────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .cursor { animation: none; }
  .icon, .ray { transition: none; }
  .wm-trace use { --wm-p: 1; }
}
