/* ==========================================================================
   Page layout — index.html (home), imprint/, privacy/
   Earlier home versions live frozen in archive/ with their own copy of the
   styles; nothing here needs to keep them working.
   ========================================================================== */

/* Full-bleed like the artboard: content always spans the viewport minus the
   20px gutter. Above 1440px all sizes scale via --px (see tokens.css). */
.wrap {
  width: 100%;
  padding-inline: var(--page-gutter);
}

/* ---- Hero ----------------------------------------------------------------
   Figma: Layouts › Variation G ("C reduziert 1"): header, a masthead row,
   one staggered XXL headline, intro + a single button; the services slider
   follows below the fold, on the black → bg fade.
   The hero is as tall as its content: --hero-chrome (header + masthead above,
   intro + bottom padding below — 136 + 57 + 40 at 1440) plus the headline and
   the space around it. That space grows with the screen up to --hero-gap-max,
   so on a laptop the hero fills the first screen, and on taller screens it
   stops there and the services slider peeks in below. */
.hero {
  --hero-chrome: calc(233 * var(--px));
  --hero-gap-min: var(--space-12);
  --hero-gap-max: var(--space-26); /* Figma: 816 on a 900 screen */
  padding-bottom: var(--space-5);
  background: linear-gradient(to bottom, var(--color-black) 70%, var(--color-bg));
}
.hero > .wrap {
  display: flex;
  flex-direction: column;
  padding-bottom: var(--space-10);
}

.site-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-4);
  padding-top: var(--space-10);
}
/* Header buttons, slider arrows and the footer button: white label, accent
   outline; the hover fill still turns it dark. */
.site-header .button,
.slider__controls .button,
.site-footer .button { color: var(--color-text); }

/* Masthead: a plain row of four labels (no rules, like the footer row),
   equal gaps between them (a column grid lines up their starts, but the
   labels differ in width, so the gaps look uneven). */
.masthead {
  display: flex;
  justify-content: space-between;
  gap: var(--space-5);
  margin-top: var(--space-12);
}

/* Headline: a staggered block centred on the page — "Building digital"
   flush left, "experiences" indented (Figma: 440 at 126px), "that click."
   ending under the first line. Column 1 is as wide as line 1, so line 3
   right-aligned in it ends where line 1 does; column 2 takes what line 2
   sticks out beyond that. */
.hero__title {
  display: grid;
  grid-template-columns: max-content 1fr;
  align-self: center;
  /* Equal space above and below (3em = the three lines), within min/max. */
  padding-block: clamp(var(--hero-gap-min), calc((100svh - var(--hero-chrome) - 3em) / 2), var(--hero-gap-max));
  /* 126 @ 1440, smaller on short screens so at least 64 of space stays
     around it and the intro + button still fit on the first screen. */
  font-size: max(48px, min(calc(100vw * 126 / var(--artboard)), calc((100svh - var(--hero-chrome) - 2 * var(--space-16)) / 3)));
}
.hero__line { white-space: nowrap; }
.hero__line:nth-child(1) { grid-column: 1; justify-self: start; }
.hero__line:nth-child(2) { grid-column: 1 / -1; justify-self: end; margin-left: calc(440em / 126); }
.hero__line:nth-child(3) { grid-column: 1; justify-self: end; }

/* Intro + button on the bottom edge. */
.hero__foot {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: var(--space-5);
}
.hero__intro { max-width: calc(404 * var(--px)); }

/* ---- Services slider ------------------------------------------------------
   Room above the cards for the absolutely placed "Services" label + arrows;
   #services jumps land with that header still in view. */
.hero .slider {
  margin-top: calc(var(--space-32) + var(--space-6));
  scroll-margin-top: var(--space-26);
}
/* Header sits in the gap above the cards so the cards keep their artboard position. */
.hero .slider__header {
  position: absolute;
  inset-inline: var(--page-gutter);
  bottom: calc(100% + var(--space-4));
}
.hero .slider__track > * {
  flex-basis: min(calc(927 * var(--px)), calc(100vw - 2 * var(--page-gutter) - var(--space-8)));
}

/* ---- About ----------------------------------------------------------------
   A pinned scene first: while it passes, the statement is written letter by
   letter (letter wave, TextFX) and three tags pop in on top of it
   (js/letter-scrub.js, after two26.studio "A bit about us"). Then portrait |
   heading, story and fact rows (Figma: Layouts › Variation H). */
.about {
  display: flex;
  flex-direction: column;
  padding-bottom: var(--space-32);
  background: var(--color-black);
}

/* The scene's stage sticks for --scrub-distance of scroll when the script
   will run (html.js-scrub, set in the <head>: the page has its full height
   from the first frame, so nothing shifts when the script arrives); without
   it (reduced motion, no JS) the stage is a plain block, the statement
   white, the tags in place. */
.about__scene { --scrub-distance: 1800px; }
.js-scrub .about__scene { height: calc(100svh + var(--scrub-distance)); }
.js-scrub .about__scene > .about__stage {
  position: sticky;
  top: 0;
  height: 100svh;
}

/* The stage is a full screen with the statement centred, so its own air is
   the section's top spacing and the gap down to the portrait. Full bleed, so
   tilted letters and tags are only clipped at the screen edge and never
   widen the page. */
.about__stage {
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-8);
  margin-inline: calc(-1 * var(--page-gutter));
  padding-inline: var(--page-gutter);
  overflow: clip;
  text-align: center;
}
/* text-box trims the line boxes to cap height and baseline, so gaps are
   exactly the visible space (browsers without support keep a bit more air). */
.about__stage > .t-label,
.about__heading { text-box: trim-both cap alphabetic; }

/* The tags are placed on this box, i.e. on the statement itself. */
.about__copy { position: relative; }
.about__statement {
  max-width: 12em;
  text-wrap: balance;
}

/* Tags on top of the statement: bigger than list tags, a little askew. */
.about__pill {
  position: absolute;
  padding: var(--space-2) var(--space-4);
  font-size: calc(18 * var(--px));
}
.about__pill:nth-of-type(1) { top: 8%;     right: -1%; rotate: -4deg; }
.about__pill:nth-of-type(2) { top: 52%;    left: -8%;  rotate: 5deg; }
.about__pill:nth-of-type(3) { bottom: -7%; right: 8%;  rotate: -4.5deg; }

/* Portrait left, the text column on the right half. */
.about__split {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: var(--space-5);
}
.about__media {
  position: relative;
  flex: none;
  overflow: hidden; /* the portrait drifts inside its frame (parallax) */
}
.about__portrait {
  display: block;
  width: calc(228 * var(--px));
  height: auto; /* the width/height attributes only reserve the 4:5 space */
  aspect-ratio: 4 / 5;
  object-fit: cover;
}
/* .about__drift moves (parallax, transform), the image only zooms (reveal,
   scale): one moving property per element, or Safari briefly drops the
   zoom while both animate and the image flashes at its plain size. */
@media (prefers-reduced-motion: no-preference) {
  .about__portrait { scale: 1.2; } /* headroom for the in-frame parallax */
}

.about__text {
  display: flex;
  flex-direction: column;
  gap: var(--space-8);
  width: calc(690 * var(--px));
}
.about__story { max-width: calc(560 * var(--px)); }
.about__story > p + p { margin-top: 1lh; } /* an empty line between paragraphs */

/* Skills / Off screen: label | tags, rows between hairlines. */
.about__facts {
  margin: var(--space-8) 0 0;
  border-bottom: var(--border-width) solid rgb(255 255 255 / 0.12);
}
.about__row {
  display: flex;
  align-items: flex-start;
  gap: var(--space-5);
  padding-block: var(--space-4);
  border-top: var(--border-width) solid rgb(255 255 255 / 0.12);
}
.about__row > dt { flex: none; width: calc(160 * var(--px)); opacity: 0.6; }
.about__row > dd { flex: 1; margin: 0; }
.about__facts .tag-list { justify-content: flex-start; }

/* ---- Footer -------------------------------------------------------------- */
.site-footer {
  padding-top: var(--space-28);
  padding-bottom: var(--space-16);
}
.site-footer__row {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--space-5);
}
.site-footer__row > :last-child { justify-self: end; }

/* Clock colon (time[data-local-time], js/contact.js): on and off every half
   second like a digital clock; opacity, so the time never changes width. */
@media (prefers-reduced-motion: no-preference) {
  .clock-colon { animation: clock-blink 1s steps(1, end) infinite; }
}
@keyframes clock-blink {
  50% { opacity: 0; }
}

.site-footer__claim {
  margin-bottom: var(--space-16);
  text-align: center;
  text-wrap: balance;
}

/* Imprint · privacy: quiet links at the very bottom, on every page. */
.site-footer__legal {
  display: flex;
  justify-content: center;
  gap: var(--space-6);
  margin-top: var(--space-12);
}
.site-footer__legal a {
  opacity: 0.6;
  transition: opacity var(--duration-hover) var(--ease-out), color var(--duration-hover) var(--ease-out);
}
.site-footer__legal a[aria-current="page"] { opacity: 1; }
@media (hover: hover) {
  .site-footer__legal a:hover { opacity: 1; color: var(--color-accent); }
}

/* Reveal footer: it sits stuck to the bottom *behind* the page; the sections
   above (opaque backgrounds) scroll away and uncover it. js/footer-reveal.js
   feeds --reveal (0 → 1) for a slight parallax of the footer content. */
.site-footer--reveal {
  position: sticky;
  bottom: 0;
  z-index: 0;
  background: var(--color-bg);
}
/* A quiet echo of the hero's ASCII field behind the footer. */
.site-footer .ascii-field { opacity: 0.35; }

body:has(.site-footer--reveal) > main {
  position: relative;
  z-index: 1;
}
/* The content drifts down into place and brightens while it is uncovered
   (the ASCII field behind stays put). Scroll-driven where supported, over
   the last --footer-h of the page scroll; otherwise --reveal from the script. */
@media (prefers-reduced-motion: no-preference) {
  .site-footer--reveal > :not(.ascii-field) {
    opacity: calc(0.2 + 0.8 * var(--reveal, 1));
    translate: 0 calc((1 - var(--reveal, 1)) * -48 * var(--px));
  }
  @supports (animation-timeline: scroll()) {
    .site-footer--reveal > :not(.ascii-field) {
      animation: footer-drift linear both;
      animation-timeline: scroll(root);
      animation-range: calc(100% - var(--footer-h, 100vh)) 100%;
    }
  }
}
@keyframes footer-drift {
  from { opacity: 0.2; translate: 0 calc(-48 * var(--px)); }
  to   { opacity: 1; translate: 0 0; }
}

/* Accent footer (every page): accent ground, black type; the elements on it
   flip to black (button outline + fill, legal links), the ASCII field draws
   in black with white sparks (palette hooks in js/ascii-field.js). Comes
   after the rules above, which it overrides at equal specificity. */
.site-footer--accent {
  --ascii-ink: var(--color-black);
  --ascii-trail: var(--color-black);
  --ascii-hot: var(--color-white);
  background: var(--color-accent);
  color: var(--color-text-inverse);
}
.site-footer--accent .ascii-field { opacity: 0.25; } /* black on the light ground reads strong: keep it a texture */
.site-footer--accent .button {
  --roll-color: var(--color-accent); /* hover: accent label on the black fill */
  --line: var(--color-text-inverse);
  color: var(--color-text-inverse);
}
.site-footer--accent .button::before { background: var(--color-text-inverse); }
.site-footer--accent :focus-visible { outline-color: var(--color-text-inverse); }
@media (hover: hover) {
  .site-footer--accent .site-footer__legal a:hover { color: inherit; }
}

/* ---- Legal pages (imprint/, privacy/) -------------------------------------
   Plain reading pages: eyebrow + title, then a narrow column of running text. */
.legal { background: var(--color-black); } /* dark like hero/about, so the footer stands apart; opaque: it sits behind */
.legal__content {
  padding-block: var(--space-26) var(--space-32);
}
/* Eyebrow, title and text share one centred column; the text stays left-aligned. */
.legal__content > * {
  max-width: calc(640 * var(--px));
  margin-inline: auto;
}
.legal__title { margin-top: var(--space-4); }
.legal__body {
  margin-top: var(--space-16);
  font-size: max(15px, var(--text-base)); /* long legal text: never below 15px */
}
.legal__body > * + * { margin-top: var(--space-4); }
.legal__body h2 {
  margin-top: var(--space-16);
  font-family: var(--font-display);
  font-size: var(--text-display-m);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-display);
  text-transform: uppercase;
}
.legal__body h3 { margin-top: var(--space-8); color: var(--color-accent); } /* only the regular weight is loaded, so no bold */
.legal__body h4 { margin-top: var(--space-6); font-family: var(--font-mono); }
.legal__body h2 + *,
.legal__body h3 + *,
.legal__body h4 + * { margin-top: var(--space-3); }
.legal__body h2 + h3 { margin-top: var(--space-6); }
.legal__body > :first-child { margin-top: 0; }
/* Postal address and phone live only here, not in the HTML: out of reach of
   simple scrapers, and the number is not a tap-to-call link. Still visible
   (and read by screen readers), as the imprint requires. */
.legal-address::before {
  content: "Wulfener Str. 12a\A 46286 Dorsten\A Germany";
  white-space: pre-line;
}
.legal-phone::before { content: "+49 1520 2687860"; }
.legal__body ul { padding-left: 1.2em; list-style: disc; }
.legal__body li + li { margin-top: var(--space-1); }
.legal__body a {
  text-decoration: underline;
  text-decoration-color: var(--color-accent);
  text-underline-offset: 3px;
  overflow-wrap: anywhere; /* long URLs and addresses on small screens */
}
@media (hover: hover) {
  .legal__body a:hover { color: var(--color-accent); }
}

/* ---- Responsive ---------------------------------------------------------- */
@media (max-width: 900px) {
  .about__split { flex-direction: column; gap: var(--space-12); }
  .about__media { width: min(100%, 228px); }
  .about__portrait { width: 100%; }
  .about__text { width: auto; }
  .about__heading { font-size: 40px; } /* the desktop size (display-m bottoms out at 28px); about as wide as the portrait */

  /* The statement is at its 48px minimum here, so the tags shrink with it;
     the first and last move to its top and bottom edge, only the middle one
     still sits on the text. */
  .about__scene { --scrub-distance: 1400px; }
  .about__pill { font-size: 14px; }
  .about__pill:nth-of-type(1) { top: -12%;    right: -8%; }
  .about__pill:nth-of-type(2) { top: 50%;     left: -14%; }
  .about__pill:nth-of-type(3) { bottom: -14%; right: 4%; }
}

@media (max-width: 700px) {
  /* Masthead: name and local time only. */
  .masthead > :nth-child(2),
  .masthead > :nth-child(3) { display: none; }

  /* Phones: the headline lines stack flush left and may wrap (4–5 lines
     instead of 3; "EXPERIENCES" ≈ 4.9em still fits), so the hero simply
     fills the screen and the headline is centred in what's left. */
  .hero > .wrap { min-height: calc(100svh - var(--space-20)); }
  .hero__title {
    display: block;
    align-self: stretch;
    margin-block: auto;
    padding-block: var(--space-8);
    font-size: calc((100vw - 2 * var(--page-gutter)) / 6);
  }
  .hero__line { display: block; white-space: normal; }
  .hero__line:nth-child(n) { justify-self: start; margin-left: 0; } /* block layout honours justify-self too */

  .hero__foot { flex-direction: column; align-items: flex-start; gap: var(--space-6); }
}

@media (max-width: 600px) {
  /* Button on top; place/time and © share the line below (each unbroken),
     and stack only if the screen is too narrow for both. */
  .site-footer__row { display: flex; flex-wrap: wrap; justify-content: space-between; }
  .site-footer__row > .t-label { white-space: nowrap; }
  .site-footer__row > .button { order: -2; margin-inline: auto; }
  .site-footer__row::before { content: ""; order: -1; flex-basis: 100%; } /* line break after the button */
  .site-footer__claim { font-size: var(--text-display-xl); } /* 48px here, like the About statement (display-l bottoms out at 34px) */

  .about__row { flex-direction: column; gap: var(--space-3); }
  .about__row > dt { width: auto; }

  /* The first and last tag straddle the statement's top and bottom edge
     (fixed offsets: the line count varies with the screen width). */
  .about__scene { --scrub-distance: 1100px; }
  .about__pill { font-size: 13px; padding: var(--space-1-5) var(--space-3); }
  .about__pill:nth-of-type(1) { top: calc(-1 * var(--space-2));    right: 2%; } /* a little deeper into the first line */
  .about__pill:nth-of-type(2) { top: 50%;                          left: -1%; }
  .about__pill:nth-of-type(3) { bottom: calc(-1 * var(--space-4)); right: 6%; }
}
