/* ===================================================================
   PIXELDIENST - base.css
   Reset, Grundtypografie, Chrome: Preloader, Cursor, Header,
   linke Fixleiste, Footer-Leiste, Hilfsklassen.
   =================================================================== */

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

html {
  background: var(--black);
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

body {
  background: var(--black);
  color: var(--fg);
  font-family: var(--ff-display);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  font-weight: 400;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img, svg, canvas, video { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
ul, ol { list-style: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
::selection { background: var(--violet); color: #15121f; }

/* Fokus ist sichtbar, immer, ueberall, auch auf dunklem Grund. */
:focus-visible {
  outline: 2px solid var(--violet-text);
  outline-offset: 3px;
  border-radius: 2px;
}

/* ===== Hilfsklassen ============================================== */

.u-visually-hidden {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

.skip-link {
  position: fixed; top: 8px; left: 8px;
  z-index: calc(var(--z-cursor) + 1);
  padding: .7rem 1.1rem; border-radius: 8px;
  background: var(--violet); color: #15121f;
  font-weight: 600; transform: translateY(-160%);
  transition: transform var(--dur) var(--ease);
}
.skip-link:focus-visible { transform: translateY(0); }

.label {
  font-family: var(--ff-mono);
  font-size: var(--fs-label);
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
  color: var(--fg-dim);
}
.is-light .label,
.section--light .label { color: var(--fg-on-light-dim); }

/* ===== Preloader ================================================= */

.preloader {
  position: fixed; inset: 0; z-index: var(--z-preload);
  background: var(--black);
  display: grid; place-items: center;
  transition: opacity .7s var(--ease), visibility .7s;
}
.preloader.is-done { opacity: 0; visibility: hidden; }

.preloader__inner { text-align: center; }
.preloader__brand {
  font-size: clamp(1.4rem, 4vw, 2.4rem);
  font-weight: 300; letter-spacing: .3em;
  text-transform: uppercase; color: var(--fg);
}
.preloader__brand b { font-weight: 700; color: var(--violet-text); }
.preloader__count {
  margin-top: 1.1rem;
  font-family: var(--ff-mono); font-size: var(--fs-small);
  color: var(--fg-dim); letter-spacing: .12em;
}
.preloader__bar {
  position: absolute; left: 0; bottom: 0; height: 2px;
  width: 100%; background: var(--line-dark);
}
.preloader__bar span {
  display: block; height: 100%; width: 0;
  background: var(--violet);
  transition: width .2s linear;
}

/* ===== Eigener Cursor ============================================ */

.cursor, .cursor-dot {
  position: fixed; top: 0; left: 0; z-index: var(--z-cursor);
  pointer-events: none; border-radius: 50%;
  transform: translate(-50%, -50%);
  will-change: transform;
}
.cursor {
  width: 38px; height: 38px;
  border: 1px solid rgba(244, 243, 239, .55);
  mix-blend-mode: difference;
  transition: width var(--dur) var(--ease), height var(--dur) var(--ease),
              background var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.cursor-dot {
  width: 5px; height: 5px; background: var(--fg);
  mix-blend-mode: difference;
}
/* Schwarz, ohne Differenz-Mischung: die bliebe auf dunklem Grund unsichtbar. */
.cursor.is-hover { width: 32px; height: 32px; background: rgba(13, 13, 16, .55); border-color: transparent; mix-blend-mode: normal; }
.cursor.is-drag  { width: 44px; height: 44px; background: rgba(13, 13, 16, .55); border-color: transparent; mix-blend-mode: normal; }
.cursor.is-drag::after {
  content: attr(data-label);
  font-family: var(--ff-mono); font-size: 9px;
  letter-spacing: .14em; color: #15121f;
}
/* Touch-Geraete und Reduced Motion bekommen den Systemcursor. */
@media (hover: none), (pointer: coarse) {
  .cursor, .cursor-dot { display: none; }
}

/* ===== Header ==================================================== */

.header {
  position: fixed; top: 0; left: 0; right: 0; z-index: var(--z-header);
  height: var(--header-h);
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 var(--pad-x);
}

/* Durchscheinendes Schwarz statt Differenz-Blendung: die Leiste traegt
   ihren eigenen Grund, deshalb bleibt die Schrift ueber jeder Sektion
   hell, auch ueber Lavendel und Creme.

   Der Grund liegt bewusst auf ::before und nicht auf .header selbst:
   ein backdrop-filter macht das Element zum Bezugsrahmen fuer alle
   position:fixed-Nachfahren, und das Vollbildmenue (.nav, inset: 0)
   wuerde dann auf Kopfzeilenhoehe zusammenschrumpfen.
   Absolut positioniert ist das Pseudo-Element ausserdem kein Flex-Item. */
.header::before {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background: var(--bar-bg);
  -webkit-backdrop-filter: blur(16px) saturate(140%);
  backdrop-filter: blur(16px) saturate(140%);
  border-bottom: 1px solid var(--bar-line);
}

/* Offenes Menue: der Grund der Leiste wuerde sonst als hellerer Streifen
   ueber dem schwarzen Vollbildmenue stehen. */
.header.is-menu-open::before { background: var(--black); backdrop-filter: none; -webkit-backdrop-filter: none; border-bottom-color: transparent; }

.brand {
  display: flex; align-items: baseline; gap: .55rem;
  font-size: 1.35rem; font-weight: 300; letter-spacing: -.02em;
  color: #fff;
}
/* Die Wortmarke ist EIN Flex-Item. Lagen „PIXEL", „DIENST" und der Punkt
   einzeln im Flex-Container, setzte das gap von .55rem zwischen jeden
   von ihnen eine Luecke, der Abstand gehoert aber nur zwischen Marke
   und Koordinatenanzeige. */
.brand__mark { white-space: nowrap; }
/* --violet-text und nicht --violet: auf dem Leistengrund kaeme das
   kraeftigere #b18cff nur auf 3,2:1, die hellere Variante auf 4,4:1. */
.brand b { font-weight: 700; color: var(--violet-text); }
.brand .brand__dot { color: var(--violet); }
.brand__coords {
  font-family: var(--ff-mono); font-size: 9px;
  letter-spacing: .06em; color: rgba(255, 255, 255, .72);
  white-space: nowrap;
  /* Reserve fuer die 17 Zeichen, die main.js schreibt. Haelt die
     Navigation auch dann ruhig, wenn ein Bildschirm fuenfstellige
     Koordinaten liefert. */
  min-width: 17ch;
}
@media (max-width: 640px) { .brand__coords { display: none; } }

.nav { display: flex; align-items: center; gap: 1.6rem; }
/* padding-block haelt die Klickflaeche bei mindestens 24 px
   (WCAG 2.5.8), ohne den Abstand im Header zu veraendern. */
.nav__link {
  position: relative; font-size: var(--fs-small);
  color: #fff; letter-spacing: -.005em;
  padding-block: .35rem;
}
.nav__link::after {
  content: ''; position: absolute; left: 0; bottom: .15rem;
  width: 100%; height: 1px; background: currentColor;
  transform: scaleX(0); transform-origin: right;
  transition: transform var(--dur) var(--ease);
}
.nav__link:hover::after, .nav__link:focus-visible::after { transform: scaleX(1); transform-origin: left; }

/* Ueber dem Vollbildmenue, damit der Sprachumschalter erreichbar
   bleibt, solange es offen ist. */
.header__right { display: flex; align-items: center; gap: 1.1rem; position: relative; z-index: 1; }

.lang {
  display: flex; align-items: center; gap: .3rem;
  font-family: var(--ff-mono); font-size: var(--fs-label);
  letter-spacing: .1em; color: rgba(255, 255, 255, .55);
  padding: .5rem .2rem;           /* Touch-Target */
}
.lang__opt { padding: .35rem .4rem; transition: color var(--dur-fast) var(--ease); }
.lang__opt.is-active { color: #fff; }
.lang__opt:hover { color: #fff; }

.burger {
  display: none; width: 44px; height: 44px;
  align-items: center; justify-content: center; flex-direction: column; gap: 5px;
}
.burger span {
  display: block; width: 22px; height: 1.5px; background: #fff;
  transition: transform var(--dur) var(--ease), opacity var(--dur) var(--ease);
}
.burger.is-open span:nth-child(1) { transform: translateY(3.25px) rotate(45deg); }
.burger.is-open span:nth-child(2) { transform: translateY(-3.25px) rotate(-45deg); }

@media (max-width: 860px) {
  .burger { display: flex; }
  .nav {
    position: fixed; inset: 0;
    flex-direction: column; justify-content: center; gap: 1.8rem;
    background: var(--black);
    mix-blend-mode: normal;
    opacity: 0; visibility: hidden;
    transition: opacity var(--dur) var(--ease), visibility var(--dur);
  }
  .nav.is-open { opacity: 1; visibility: visible; }
  .nav__link { font-size: 1.6rem; }
}

/* ===== Leisten ueber hellen Sektionen ============================
   Der Leistengrund ist mit 20% Deckkraft nur ein Schleier, die
   Sektion darunter bestimmt die Helligkeit. Ueber Creme und Lavendel
   muss die Schrift deshalb dunkel werden. main.js prueft dafuer, was
   gerade am oberen und am unteren Rand liegt, und setzt
   .on-light-top beziehungsweise .on-light-bottom auf <html>.
   Zwei Klassen, weil oben und unten verschiedene Sektionen stehen
   koennen. */

.on-light-top .header,
.on-light-top .brand,
.on-light-top .nav__link    { color: var(--fg-on-light); }
.on-light-top .brand b      { color: var(--violet-on-light); }
.on-light-top .brand__dot   { color: var(--violet-on-light); }
.on-light-top .brand__coords{ color: rgba(20, 20, 26, .62); }
.on-light-top .lang         { color: rgba(20, 20, 26, .62); }
.on-light-top .lang__opt.is-active,
.on-light-top .lang__opt:hover { color: var(--fg-on-light); }
.on-light-top .burger span  { background: var(--fg-on-light); }

/* Voll deckend, nicht .78: ueber der Lavendel-Flaeche kaeme die
   11px-Schrift sonst nur auf 3,65:1. */
.on-light-bottom .footerbar { color: var(--fg-on-light); }
.on-light-bottom .footerbar a:hover { color: var(--fg-on-light); }

/* Bei offenem Vollbildmenue ist der Grund schwarz, unabhaengig davon,
   ueber welcher Sektion die Leiste gerade steht. */
.header.is-menu-open,
.header.is-menu-open .brand,
.header.is-menu-open .nav__link    { color: #fff; }
.header.is-menu-open .brand b      { color: var(--violet-text); }
.header.is-menu-open .brand__dot   { color: var(--violet); }
.header.is-menu-open .brand__coords{ color: rgba(255, 255, 255, .72); }
.header.is-menu-open .lang         { color: rgba(255, 255, 255, .55); }
.header.is-menu-open .burger span  { background: #fff; }

/* ===== Linke Fixleiste =========================================== */

.rail {
  position: fixed; left: 0; top: 50%; transform: translateY(-50%);
  z-index: var(--z-rail);
  display: flex; flex-direction: column; gap: 3px;
}
.rail__tab {
  display: grid; place-items: center;
  width: var(--rail-w); min-height: 44px; padding: .7rem 0;
  background: var(--cream); color: var(--fg-on-light);
  font-family: var(--ff-mono); font-size: 10px;
  letter-spacing: .1em; text-transform: uppercase;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.rail__tab:hover { background: var(--violet); }
.rail__tab--vertical { writing-mode: vertical-rl; min-height: 86px; }
@media (max-width: 860px) { .rail { display: none; } }

/* ===== Footer-Leiste ============================================= */

.footerbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: var(--z-footer);
  height: var(--footer-h);
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; padding: 0 var(--pad-x);
  font-family: var(--ff-mono); font-size: var(--fs-label);
  letter-spacing: .08em;
  /* .88 statt der frueheren .62: auf dem neuen Grund ueber der
     Creme-Flaeche kaeme Weiss mit .62 nur auf 3,4:1, zu wenig fuer
     11px-Schrift. Mit .88 sind es 5,0:1. */
  color: rgba(255, 255, 255, .88);
}

/* Derselbe Grund wie im Header, und aus demselben Grund auf ::before
   statt auf dem Element: ein backdrop-filter macht das Element zum
   Bezugsrahmen fuer position:fixed-Nachfahren. Absolut positioniert
   ist das Pseudo-Element ausserdem kein Flex-Item. */
.footerbar::before {
  content: ''; position: absolute; inset: 0; z-index: -1;
  background: var(--bar-bg);
  -webkit-backdrop-filter: blur(16px) saturate(140%);
  backdrop-filter: blur(16px) saturate(140%);
  border-top: 1px solid var(--bar-line);
}
.footerbar a:hover { color: #fff; }
.footerbar__legal { display: flex; gap: 1.1rem; }
.footerbar__social { display: flex; gap: 1rem; }
/* 24 px Mindesthoehe fuer jede Klickflaeche in der Leiste (WCAG 2.5.8). */
.footerbar__legal a,
.footerbar__social a {
  display: inline-flex; align-items: center;
  min-width: 24px; min-height: 24px;
}
/* Auf dem Telefon passen Copyright, zwei Rechtslinks und drei Profile
   nicht nebeneinander, sie wuerden umbrechen und aus der Leiste
   laufen. Dort bleibt nur das Noetigste stehen. */
@media (max-width: 640px) {
  .footerbar { font-size: 10px; letter-spacing: .05em; gap: .75rem; }
  .footerbar > span { white-space: nowrap; }
  .footerbar__legal a:nth-child(n + 2) { display: none; }
  .footerbar__social a:not(#lnkYoutube) { display: none; }
}

/* ===== Sektionsgrundform ========================================= */

.section {
  position: relative;
  padding: var(--sec-y) var(--pad-x);
  padding-left: calc(var(--pad-x) + var(--rail-w));
}
.section--light { background: var(--cream); color: var(--fg-on-light); }
.section--violet { background: var(--violet); color: var(--fg-on-light); }
.section--dark { background: var(--black); color: var(--fg); }

.section__head {
  display: flex; align-items: baseline; gap: 1.2rem;
  margin-bottom: clamp(2rem, 5vw, 4.5rem);
}

/* Zweispaltiger Standard: Headline links, Fliesstext rechts. */
.split {
  display: grid; gap: clamp(2rem, 5vw, 5rem);
  grid-template-columns: minmax(0, 1.15fr) minmax(0, .85fr);
  align-items: start;
}
@media (max-width: 900px) { .split { grid-template-columns: 1fr; } }

.prose p + p { margin-top: 1.1em; }
.prose { max-width: 46ch; color: var(--fg-dim); }
.section--light .prose, .section--violet .prose { color: var(--fg-on-light-dim); }
.section--violet .prose { color: #2a2238; }

/* ===== Reveal ====================================================
   Grundzustand fuer alle von scroll.js animierten Elemente.
   Ohne JS oder bei Reduced Motion bleibt alles sichtbar. */
.js .reveal { opacity: 0; transform: translateY(26px); }
.no-motion .reveal { opacity: 1 !important; transform: none !important; }
@media (prefers-reduced-motion: reduce) {
  .reveal { opacity: 1 !important; transform: none !important; }
}
