/* ------------------------------------------------------------
   Stefan Bartos, v3 "Werkstück, Atelier"
   Ein Schreibtisch ohne Ränder: Kamera mit Verschieben und Zoom,
   Karten mit Gewicht, ein Licht, das Schatten wirft.
   Geist und Geist Mono. Raster 8px. Petrol als einziger Signaturton.
   ------------------------------------------------------------ */

@font-face {
  font-family: "Geist";
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url("assets/fonts/geist-latin.woff2") format("woff2");
}
@font-face {
  font-family: "Geist Mono";
  font-style: normal;
  font-weight: 400 500;
  font-display: swap;
  src: url("assets/fonts/geist-mono-latin.woff2") format("woff2");
}

/* Schatten-Variablen typisiert, damit sie weich übergehen können */
@property --sx { syntax: "<length>"; inherits: false; initial-value: 0px; }
@property --sy { syntax: "<length>"; inherits: false; initial-value: 0px; }
@property --sa { syntax: "<number>"; inherits: false; initial-value: 0.16; }

:root {
  --surface:   #e4e5e2;
  --surface-2: #d9dbd7;
  --card:      #fbfbfa;
  --card-2:    #f3f4f2;
  --card-edge: rgba(23, 26, 27, 0.08);
  --card-hi:   rgba(255, 255, 255, 0.95);
  --ink:       #17191a;
  --muted:     #686d70;
  --faint:     #9a9ea0;
  --line:      rgba(23, 26, 27, 0.09);
  --accent:    #1c5c69;
  --accent-2:  #174c57;
  --on-accent: #f2f6f6;
  --on-accent-muted: rgba(242, 246, 246, 0.7);
  --term:      #17191a;
  --term-ink:  #e6e8e6;
  --term-muted:#8b9194;
  --scrim:     rgba(228, 229, 226, 0.94);

  --doodle: 0.10;
  --doodle-mobile: 0.15;
  --grain: 0.05;
  --lamp: 0;
  --noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .07 -.0175'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");

  --shadow-hue: 28, 32, 34;
  --shadow-ui:
    0 1px 1px rgba(var(--shadow-hue), 0.04),
    0 4px 10px -2px rgba(var(--shadow-hue), 0.08),
    0 18px 40px -16px rgba(var(--shadow-hue), 0.22);
  --shadow-float:
    0 2px 2px rgba(var(--shadow-hue), 0.05),
    0 12px 24px -6px rgba(var(--shadow-hue), 0.12),
    0 48px 96px -24px rgba(var(--shadow-hue), 0.34);

  --font: "Geist", "Helvetica Neue", Arial, sans-serif;
  --mono: "Geist Mono", ui-monospace, "SF Mono", Menlo, monospace;

  --r-outer: 22px;
  --r-inner: 15px;
  --bezel: 6px;

  --ease-out: cubic-bezier(0.32, 0.72, 0, 1);
  --ease-io: cubic-bezier(0.65, 0, 0.2, 1);
  --ease-spring: cubic-bezier(0.34, 1.4, 0.64, 1);
  --t-layout: 820ms;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --surface:   #121314;
    --surface-2: #0d0e0f;
    --card:      #1e2021;
    --card-2:    #252728;
    --card-edge: rgba(255, 255, 255, 0.07);
    --card-hi:   rgba(255, 255, 255, 0.06);
    --ink:       #ecece9;
    --muted:     #9a9fa2;
    --faint:     #6c7174;
    --line:      rgba(255, 255, 255, 0.09);
    --accent:    #6fb7c4;
    --accent-2:  #5aa5b3;
    --on-accent: #0f1a1c;
    --on-accent-muted: rgba(15, 26, 28, 0.68);
    --term:      #0d0e0f;
    --scrim:     rgba(18, 19, 20, 0.94);
    --shadow-hue: 0, 0, 0;
    --doodle: 0.055;
    --doodle-mobile: 0.09;
    --grain: 0.07;
    --lamp: 1;
  --noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .098 -.0245'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
    --shadow-ui:
      0 1px 0 rgba(255, 255, 255, 0.04) inset,
      0 4px 12px rgba(0, 0, 0, 0.35),
      0 24px 48px -16px rgba(0, 0, 0, 0.6);
    --shadow-float:
      0 1px 0 rgba(255, 255, 255, 0.05) inset,
      0 12px 24px -6px rgba(0, 0, 0, 0.45),
      0 56px 110px -24px rgba(0, 0, 0, 0.8);
  }
}
:root[data-theme="dark"] {
  --surface:   #121314;
  --surface-2: #0d0e0f;
  --card:      #1e2021;
  --card-2:    #252728;
  --card-edge: rgba(255, 255, 255, 0.07);
  --card-hi:   rgba(255, 255, 255, 0.06);
  --ink:       #ecece9;
  --muted:     #9a9fa2;
  --faint:     #6c7174;
  --line:      rgba(255, 255, 255, 0.09);
  --accent:    #6fb7c4;
  --accent-2:  #5aa5b3;
  --on-accent: #0f1a1c;
  --on-accent-muted: rgba(15, 26, 28, 0.68);
  --term:      #0d0e0f;
  --scrim:     rgba(18, 19, 20, 0.94);
  --shadow-hue: 0, 0, 0;
  --doodle: 0.055;
  --doodle-mobile: 0.09;
  --grain: 0.07;
  --lamp: 1;
  --noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .098 -.0245'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  --shadow-ui:
    0 1px 0 rgba(255, 255, 255, 0.04) inset,
    0 4px 12px rgba(0, 0, 0, 0.35),
    0 24px 48px -16px rgba(0, 0, 0, 0.6);
  --shadow-float:
    0 1px 0 rgba(255, 255, 255, 0.05) inset,
    0 12px 24px -6px rgba(0, 0, 0, 0.45),
    0 56px 110px -24px rgba(0, 0, 0, 0.8);
}

/* Basis */

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

html { color-scheme: light dark; -webkit-text-size-adjust: 100%; }
:root[data-theme="light"] { color-scheme: light; }
:root[data-theme="dark"] { color-scheme: dark; }

body {
  margin: 0;
  background: var(--surface);
  color: var(--ink);
  font-family: var(--font);
  font-size: 1rem;
  line-height: 1.55;
  font-feature-settings: "liga" 1, "kern" 1, "ss01" 1;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  min-height: 100dvh;
}

/* Feines Papierkorn über allem, statisch */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 2000;
  pointer-events: none;
  opacity: var(--grain);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1.4 -.35'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

img { display: block; max-width: 100%; height: auto; }
a { color: inherit; text-decoration: none; }
/* Kein grauer Tipp-Kasten am iPhone, Knöpfe geben selbst Rückmeldung */
html { -webkit-tap-highlight-color: transparent; }
h1, h2 { margin: 0; font-weight: 500; text-wrap: balance; letter-spacing: -0.02em; }
p { margin: 0; text-wrap: pretty; }
figure { margin: 0; }
ul { margin: 0; padding: 0; list-style: none; }
button { font: inherit; color: inherit; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 6px;
}

.kbd {
  display: inline-grid;
  place-items: center;
  min-width: 1.6em;
  height: 1.6em;
  padding: 0 0.4em;
  font-family: var(--mono);
  font-size: 0.6875rem;
  font-weight: 500;
  line-height: 1;
  color: var(--muted);
  background: var(--card-2);
  border: 1px solid var(--line);
  border-bottom-width: 2px;
  border-radius: 6px;
}

/* Kopfleiste: schwebend, ohne Fläche */

.bar {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 18px 24px;
  pointer-events: none;
}
.bar > * { pointer-events: auto; }

.bar__name {
  display: inline-flex;
  color: var(--ink);
  /* Langes Drücken am iPhone soll den Namen nicht markieren */
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  align-items: center;
  gap: 10px;
  font-weight: 500;
  font-size: 0.9375rem;
  letter-spacing: -0.01em;
  padding: 8px 0;
}
/* Kleine Marke: zwei gestapelte Karten */
.bar__mark {
  position: relative;
  width: 18px;
  height: 20px;
}
.bar__mark::before,
.bar__mark::after {
  content: "";
  position: absolute;
  inset: 0 2px 2px 0;
  border-radius: 4px;
  transition: transform 500ms var(--ease-spring);
}
.bar__mark::before { background: var(--faint); opacity: 0.55; transform: rotate(-10deg) translate(-1px, 2px); }
.bar__mark::after { background: var(--accent); transform: translate(3px, 0); }
/* Hover nur mit Maus: auf Touch bliebe :hover nach dem Tippen hängen. Dort fächert es nur, solange der Finger drauf ist. */
.bar__name:active .bar__mark::before { transform: rotate(-16deg) translate(-3px, 3px); }
.bar__name:active .bar__mark::after { transform: translate(4px, -2px) rotate(4deg); }
@media (hover: hover) {
  .bar__name:hover .bar__mark::before { transform: rotate(-16deg) translate(-3px, 3px); }
  .bar__name:hover .bar__mark::after { transform: translate(4px, -2px) rotate(4deg); }
}

.bar__actions { display: flex; gap: 8px; align-items: center; }

/* Knöpfe: Pille mit Hairline, physisches Drücken */

.btn,
.pill {
  appearance: none;
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--ink);
  background: var(--card);
  border: 1px solid var(--card-edge);
  border-radius: 999px;
  padding: 8px 16px;
  line-height: 1.2;
  cursor: pointer;
  white-space: nowrap;
  box-shadow: 0 1px 0 var(--card-hi) inset, 0 1px 2px rgba(var(--shadow-hue), 0.06);
  transition:
    transform 260ms var(--ease-spring),
    box-shadow 260ms var(--ease-out),
    border-color 260ms var(--ease-out),
    background-color 260ms var(--ease-out),
    color 260ms var(--ease-out);
}
@media (hover: hover) {
  .btn:hover,
  .pill:hover {
    border-color: rgba(var(--shadow-hue), 0.2);
    box-shadow: 0 1px 0 var(--card-hi) inset, 0 3px 8px rgba(var(--shadow-hue), 0.10);
    transform: translateY(-1px);
  }
  /* Füllt den Spalt unter dem angehobenen Knopf, sonst flackert der Hover an der Unterkante */
  .btn:hover::after,
  .pill:hover::after {
    content: "";
    position: absolute;
    inset: 100% 0 -2px;
  }
}
.btn:active,
.pill:active {
  transform: translateY(0) scale(0.96);
  box-shadow: 0 1px 0 var(--card-hi) inset;
}
.btn { padding: 7px 14px; box-shadow: var(--shadow-ui); }
@media (hover: hover) {
  .btn:hover { box-shadow: var(--shadow-ui); }
}
.btn .kbd { margin-right: -6px; }
.btn--icon { padding: 7px; width: 36px; height: 34px; justify-content: center; }
.btn--icon svg { fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.btn--icon .lamp-cone { fill: currentColor; fill-opacity: 0; transition: fill-opacity 300ms var(--ease-out); }
.btn[aria-pressed="true"] {
  color: var(--accent);
  border-color: color-mix(in srgb, var(--accent) 40%, transparent);
}
/* Lampenknopf hängt direkt am Theme statt an aria-pressed, so ist er schon
   vor dem Script richtig gefärbt und blendet beim Laden nicht um */
:root[data-theme="dark"] .btn--icon .lamp-cone { fill-opacity: 1; }
:root[data-theme="dark"] #theme {
  color: var(--accent);
  border-color: color-mix(in srgb, var(--accent) 40%, transparent);
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .btn--icon .lamp-cone { fill-opacity: 1; }
  :root:not([data-theme="light"]) #theme {
    color: var(--accent);
    border-color: color-mix(in srgb, var(--accent) 40%, transparent);
  }
}

.pill--solid {
  background: var(--ink);
  color: var(--card);
  border-color: var(--ink);
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.12) inset, 0 2px 6px rgba(var(--shadow-hue), 0.18);
}
/* Eigene Lichtkante: Die allgemeine Hover-Regel setzt eine fast weiße, die auf Dunkel als Strich wirkt */
@media (hover: hover) {
  .pill--solid:hover {
    border-color: var(--ink);
    box-shadow: 0 1px 0 rgba(255, 255, 255, 0.12) inset, 0 4px 12px rgba(var(--shadow-hue), 0.22);
  }
}
.pill--solid:active { box-shadow: 0 1px 0 rgba(255, 255, 255, 0.12) inset, 0 1px 3px rgba(var(--shadow-hue), 0.18); }

.pill--on-accent {
  background: color-mix(in srgb, var(--on-accent) 12%, transparent);
  color: var(--on-accent);
  border-color: color-mix(in srgb, var(--on-accent) 22%, transparent);
  box-shadow: none;
}
@media (hover: hover) {
  .pill--on-accent:hover {
    background: color-mix(in srgb, var(--on-accent) 20%, transparent);
    border-color: color-mix(in srgb, var(--on-accent) 36%, transparent);
    box-shadow: none;
  }
}

/* Schreibtisch */

.desk { position: relative; }

/* Kritzeleien auf der Fläche, mit der Schriftfarbe eingefärbt.
   Auf breiten Schirmen wandern sie mit der Kamera (--cx, --cy, --cz). */
.desk::before {
  content: "";
  position: absolute;
  inset: 0;
  background-color: var(--ink);
  opacity: var(--doodle);
  -webkit-mask-image: url("assets/doodle.svg");
  mask-image: url("assets/doodle.svg");
  -webkit-mask-size: calc(440px * var(--cz, 1)) calc(440px * var(--cz, 1));
  mask-size: calc(440px * var(--cz, 1)) calc(440px * var(--cz, 1));
  -webkit-mask-position: var(--cx, 0px) var(--cy, 0px);
  mask-position: var(--cx, 0px) var(--cy, 0px);
  pointer-events: none;
}

/* Dunkel: eine Schreibtischlampe, die dem Zeiger folgt */
.desk::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: var(--lamp);
  background:
    radial-gradient(1100px circle at var(--lx, 30%) var(--ly, 20%), rgba(255, 248, 236, 0.05), transparent 62%),
    radial-gradient(140% 120% at 50% 40%, transparent 55%, rgba(0, 0, 0, 0.35));
  transition: opacity 600ms var(--ease-out);
}

/* Karte: Hülle (Position, Schatten) + Kern (Drehen, Anheben) + Seiten (Material) */

.card {
  position: relative;
  width: 21rem;
  --r-card: var(--r-outer);
  --flip: 0deg;
  --lift-y: 0px;
  perspective: 1800px;
}

/* Der Schatten liegt auf der Hülle und dreht nicht mit beim Umdrehen.
   Versatz und Stärke setzt das Script aus Lichtposition und Höhe. */
.card::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: var(--r-card);
  pointer-events: none;
  box-shadow:
    calc(var(--sx) * 0.12) calc(var(--sy) * 0.12 + 1px) 2px rgba(var(--shadow-hue), 0.06),
    calc(var(--sx) * 0.45) calc(var(--sy) * 0.45 + 4px) 12px -3px rgba(var(--shadow-hue), 0.08),
    var(--sx) calc(var(--sy) + 16px) 40px -12px rgba(var(--shadow-hue), var(--sa));
}

.card__core {
  position: relative;
  display: grid;
  transform-style: preserve-3d;
  /* Anheben getrennt vom Drehen: Hover mitten in der Drehung startet sie sonst neu */
  translate: 0 var(--lift-y);
  transform: rotateY(var(--flip));
  transition: translate 460ms var(--ease-spring), scale 460ms var(--ease-spring), transform 460ms var(--ease-spring);
}

.face {
  grid-area: 1 / 1;
  position: relative;
  min-width: 0;
  background: var(--card);
  border: 1px solid var(--card-edge);
  border-radius: var(--r-card);
  padding: var(--bezel);
  box-shadow: 0 1px 0 var(--card-hi) inset;
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
}
.face--back { transform: rotateY(180deg); }
.card--flip .face { display: flex; flex-direction: column; }
.card--flip .card__body { flex: 1; display: flex; flex-direction: column; }
.card--flip .card__actions { margin-top: auto; padding-top: 16px; }

.card.is-flipped { --flip: 180deg; }
.card.is-flipping .card__core { transition: translate 460ms var(--ease-spring), scale 460ms var(--ease-spring), transform 820ms var(--ease-io); }

/* Innere Flächen mit konzentrischem Radius */

.card__media,
.card__portrait {
  position: relative;
  overflow: hidden;
  border-radius: var(--r-inner);
  background: var(--surface);
}
.card__media img { aspect-ratio: 10 / 7; object-fit: cover; width: 100%; }
.card__portrait img { aspect-ratio: 5 / 4; object-fit: cover; object-position: 50% 30%; width: 100%; }

.card__body { padding: 18px 14px 14px; }

.card__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
}

.card__name { font-size: 1.3125rem; line-height: 1.2; }

/* Texte, die ihre Farbe sonst nur erben, bekommen sie ausdrücklich. Safari blendet geerbte Farbe
   beim weichen Themenwechsel erst um, wenn die Eltern fertig sind, sie springt dann verspätet. */
.card__title,
.card__name,
.ledger li > span:first-child,
.live__score > span:first-child { color: var(--ink); }
.live__note--axis span { color: var(--faint); }
.card--contact .card__name { color: var(--on-accent); }

.card__year,
.card__meta {
  font-family: var(--mono);
  font-size: 0.75rem;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
  color: var(--muted);
}
.card__meta { margin-top: 14px; }
.card__meta--top { margin: 0 0 10px; }

.card__desc,
.card__more,
.card__body > p {
  margin-top: 8px;
  color: var(--muted);
  max-width: 36ch;
  font-size: 0.9375rem;
}
.card__more { margin-top: 0; color: var(--ink); }

.card__actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; }

/* Glanz auf Bildern: ein schwacher Lichtreflex, der dem Licht folgt */
.card__media::after,
.card__photo::after,
.card__portrait::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(var(--gloss, 135deg), rgba(255, 255, 255, 0.16), rgba(255, 255, 255, 0) 42%);
  mix-blend-mode: soft-light;
}

.chip {
  position: absolute;
  left: 10px;
  bottom: 10px;
  display: inline-flex;
  gap: 6px;
  align-items: baseline;
  padding: 5px 10px;
  font-family: var(--mono);
  font-size: 0.6875rem;
  font-weight: 500;
  color: var(--ink);
  background: var(--card);
  border: 1px solid var(--card-edge);
  border-radius: 999px;
  box-shadow: 0 2px 8px rgba(var(--shadow-hue), 0.12);
}
.chip b { font-weight: 500; color: var(--muted); }

/* Vorstellung: nur Typografie, sehr groß */

.card--intro { width: 37rem; }
.card--intro .face { padding: calc(var(--bezel) + 30px) calc(var(--bezel) + 30px) calc(var(--bezel) + 26px); }

.card__title {
  font-size: 2.875rem;
  line-height: 1.04;
  letter-spacing: -0.035em;
  max-width: 15ch;
}
.card__lead {
  margin-top: 18px;
  font-size: 1rem;
  color: var(--muted);
  max-width: 38ch;
}
.card--intro .card__actions { margin-top: 24px; }

/* Projektkarte ohne Bild: Terminal als Anker */

.card--text { width: 21rem; }

.term {
  border-radius: var(--r-inner);
  background: var(--term);
  color: var(--term-ink);
  padding: 16px 16px 18px;
  font-family: var(--mono);
  font-size: 0.75rem;
  line-height: 1.6;
  min-height: 10.5rem;
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.04) inset;
  overflow-wrap: anywhere;
}
.term__line::before { content: "$ "; color: var(--term-muted); }
.term__out { margin-top: 8px; color: var(--term-muted); }
.term.is-typing .term__line::after,
.term.is-done .term__out::after {
  content: "";
  display: inline-block;
  width: 0.55em;
  height: 1.05em;
  margin-left: 2px;
  vertical-align: -0.18em;
  background: var(--term-ink);
  animation: caret 1.05s steps(1) infinite;
}
.term.is-done .term__out::after { animation-iteration-count: 4; animation-fill-mode: forwards; }
@keyframes caret { 50% { opacity: 0; } 100% { opacity: 0; } }

/* Zahlenkolonnen wie auf einem Beleg */
.ledger { margin-top: 14px; font-size: 0.8125rem; }
.ledger li {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  padding: 7px 0;
  border-top: 1px solid var(--line);
}
.ledger li:last-child { border-bottom: 1px solid var(--line); }
.ledger li > span:last-child {
  font-family: var(--mono);
  font-size: 0.75rem;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.ledger--loose li { padding: 9px 0; }

/* Livewerte von Current State of Call of Duty */

.live { margin-bottom: 14px; }
.live__score {
  display: flex;
  align-items: baseline;
  gap: 4px;
  font-size: 3.25rem;
  font-weight: 500;
  line-height: 0.9;
  letter-spacing: -0.05em;
  font-variant-numeric: tabular-nums;
}
.live__of { font-size: 1rem; letter-spacing: 0; color: var(--muted); }
.meter {
  position: relative;
  height: 6px;
  margin-top: 16px;
  border-radius: 999px;
  background: var(--line);
  overflow: hidden;
}
.meter__fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: 100%;
  border-radius: inherit;
  background: var(--ink);
  transform-origin: 0 50%;
  transform: scaleX(var(--v, 0));
  transition: transform 1200ms var(--ease-out) 200ms;
}
.live__note { margin-top: 10px; font-size: 0.8125rem; color: var(--muted); }
.live__note--axis {
  display: flex;
  justify-content: space-between;
  margin-top: 6px;
  font-family: var(--mono);
  font-size: 0.6875rem;
  color: var(--faint);
}
.spark { display: block; width: 100%; height: 44px; margin-top: 14px; overflow: visible; }
.spark .spark__area { fill: var(--ink); opacity: 0.06; }
.spark .spark__line { fill: none; stroke: var(--ink); stroke-width: 1.5; vector-effect: non-scaling-stroke; stroke-linejoin: round; }
.spark .spark__mid { stroke: var(--line); stroke-width: 1; vector-effect: non-scaling-stroke; stroke-dasharray: 2 3; }

/* Über mich */

.card--about { width: 19.5rem; }
.card--about .card__body p { max-width: 31ch; }
.card--about .card__body p + p { margin-top: 10px; }

/* Werkzeug */

.card--stack { width: 21rem; }
.card--stack .card__body { padding: 18px 16px 12px; }

/* Fotokarten: kleine Abzüge ohne Rand */

.card--photo { width: 11rem; --r-card: 10px; }
.card__photo {
  position: relative;
  overflow: hidden;
  border-radius: 4px;
  background: var(--surface);
  /* Sichtbare Kante 1px innerhalb des Bildes: Safari schneidet die Grenze eines gedrehten
     Bildes (bzw. seiner Ebene) ohne Glättung, eine Pfadkante darin wird geglättet */
  clip-path: inset(1px round 4px);
}
/* Schatten deckungsgleich mit dem sichtbaren Foto */
.card--photo::before { inset: 1px; }
.card__photo img { aspect-ratio: 3 / 4; object-fit: cover; width: 100%; }
.card--photo { cursor: zoom-in; }
/* Offenes Foto hat den Tisch verlassen: ganze Karte samt Schatten weg,
   sonst bliebe dort eine leere helle Fläche liegen. Der Schatten blendet beim
   Rückflug schon wieder ein (.is-returning), damit er am Ende nicht aufspringt. */
.card--photo::before { transition: opacity 640ms var(--ease-out); }
.card--photo.is-away .card__core,
.card--photo.is-away:not(.is-returning)::before { opacity: 0; }

/* Kontakt: die einzige farbige Fläche */

.card--contact { width: 21rem; }
.card--contact .face {
  background: var(--accent);
  color: var(--on-accent);
  border-color: color-mix(in srgb, var(--accent) 70%, black);
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.18) inset;
}
.card--contact .card__body { padding: 20px 20px 18px; }
.card--contact .card__body > p { color: var(--on-accent-muted); }
.card--contact :focus-visible { outline-color: var(--on-accent); }

.card__mail {
  display: inline-block;
  margin-top: 26px;
  font-size: 1.5rem;
  font-weight: 500;
  letter-spacing: -0.025em;
  line-height: 1.1;
  background: linear-gradient(currentColor, currentColor) 0 100% / 0% 1px no-repeat,
              linear-gradient(rgba(255, 255, 255, 0.3), rgba(255, 255, 255, 0.3)) 0 100% / 100% 1px no-repeat;
  padding-bottom: 4px;
  overflow-wrap: anywhere;
  color: var(--on-accent);
  transition: background-size 500ms var(--ease-out);
}
@media (hover: hover) {
  .card__mail:hover { background-size: 100% 1px, 100% 1px; }
}
.card--contact .card__actions { margin-top: 22px; }

/* ------------------------------------------------------------
   Breite Schirme: Kamera, Welt, Physik
   ------------------------------------------------------------ */

/* Kamera erst ab genug Breite und Höhe, ein quer gehaltenes Handy bleibt bei der Liste */
@media (min-width: 720px) and (min-height: 540px) {
  html, body { height: 100%; overflow: hidden; overscroll-behavior: none; }

  .desk {
    position: fixed;
    inset: 0;
    overflow: hidden;
    cursor: grab;
    touch-action: none;
    user-select: none;
    -webkit-user-select: none;
  }
  .is-panning .desk, .is-panning .card { cursor: grabbing; }

  .world {
    position: absolute;
    top: 0; left: 0;
    width: 0; height: 0;
    transform-origin: 0 0;
    will-change: transform;
  }
  /* Bis das Script die Karten gelegt hat (wartet auf die Schrift), bleibt der Tisch leer */
  .js .world:not(.is-placed) { visibility: hidden; }
  /* Kritzeleien ebenso, sonst stehen sie kurz an der falschen Stelle und springen */
  .js .desk:not(.is-placed)::before { visibility: hidden; }
  .desk.is-placed::before { animation: doodle-in 600ms var(--ease-out); }
  @keyframes doodle-in { from { opacity: 0; } }

  .card {
    position: absolute;
    top: 0; left: 0;
    will-change: transform;
    transform-origin: 50% 40%;
    transition:
      transform var(--t-layout) var(--ease-out),
      opacity 520ms var(--ease-out);
    cursor: grab;
    -webkit-user-drag: none;
  }
  .card img { -webkit-user-drag: none; pointer-events: none; }
  .card a, .card button { cursor: pointer; }
  .card--photo { cursor: zoom-in; }
  /* Auf dem Tisch hat der Schatten dieselben Ecken wie das Foto, sonst sieht man beim
     Anheben eine runder geschnittene Kante. Mobil bleibt es beim alten Stand (10px),
     der am iPhone saubere Ränder hatte. */
  .card--photo { --r-card: 4px; }

  /* Beim Ziehen und Werfen steuert das Script jedes Bild selbst */
  .card.is-held,
  .card.is-gliding { transition: none; }
  .card.is-held { cursor: grabbing; }
  .card.is-settling { transition: transform 620ms var(--ease-spring); }

  @media (hover: hover) {
    .card:hover { --lift-y: -3px; }
    /* Nicht anheben, solange das Foto unterwegs ist: Die Karte läge sonst beim Landen woanders,
       und das Script hielte den Hover für eine Bewegung und ließe das Foto sofort landen */
    .card--photo.is-away { --lift-y: 0px; }
  }
  .card.is-held { --lift-y: -6px; }
  .card.is-held .card__core { scale: 1.03; }
}

/* Werkzeugleiste unten rechts */

.hud {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 90;
  display: grid;
  gap: 6px;
  padding: 6px;
  background: var(--card);
  border: 1px solid var(--card-edge);
  border-radius: 16px;
  box-shadow: var(--shadow-ui);
  transition: opacity 400ms var(--ease-out), transform 500ms var(--ease-out);
}
.js .hud:not(.is-on) { opacity: 0; transform: translateY(12px); pointer-events: none; }
.minimap {
  display: block;
  width: 200px;
  height: 132px;
  border-radius: 11px;
  background: var(--surface);
  cursor: crosshair;
  touch-action: none;
}
.hud__row { display: flex; gap: 2px; align-items: center; }
.hud__btn {
  appearance: none;
  display: grid;
  place-items: center;
  height: 30px;
  min-width: 30px;
  padding: 0 8px;
  background: transparent;
  border: 0;
  border-radius: 9px;
  color: var(--ink);
  cursor: pointer;
  font-size: 0.75rem;
  font-weight: 500;
  transition: background-color 200ms var(--ease-out);
}
@media (hover: hover) {
  .hud__btn:hover { background: var(--card-2); }
}
.hud__btn svg { fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; }
.hud__btn--value { flex: 1; font-family: var(--mono); font-variant-numeric: tabular-nums; color: var(--muted); }
.hud__btn--text { margin-left: 2px; padding: 0 12px; border-left: 1px solid var(--line); border-radius: 0 9px 9px 0; }

/* Befehlspalette */

/* Der Dialog selbst ist nur Rahmen: Fläche auf .palette__form, Schatten auf .palette__shade,
   damit beim Aufgehen die Fläche aufgezogen und der Schatten getrennt skaliert werden kann. */
.palette {
  width: min(36rem, calc(100vw - 32px));
  max-width: none;
  margin: 16vh auto auto;
  padding: 0;
  color: var(--ink);
  background: transparent;
  border: 0;
  overflow: visible;
}
.palette__shade {
  position: absolute;
  inset: 0;
  border-radius: 20px;
  box-shadow: var(--shadow-float);
  transform-origin: 50% 0;
  pointer-events: none;
}
.palette__form {
  position: relative;
  background: var(--card);
  border: 1px solid var(--card-edge);
  border-radius: 20px;
  overflow: hidden;
}
.palette::backdrop { background: color-mix(in srgb, var(--surface-2) 55%, transparent); }
.palette[open]::backdrop { animation: fade-in 300ms var(--ease-out); }
.palette.is-closing::backdrop { opacity: 0; transition: opacity 400ms var(--ease-out); }
.btn--search.is-away { opacity: 0; }
@keyframes fade-in { from { opacity: 0; } }

.palette__input {
  display: block;
  width: 100%;
  padding: 20px 22px;
  font: inherit;
  font-size: 1.0625rem;
  color: var(--ink);
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--line);
  outline: none;
}
.palette__input::placeholder { color: var(--faint); }
.palette__list { max-height: min(22rem, 50vh); overflow-y: auto; padding: 6px; scroll-padding: 6px; }
.palette__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 10px 14px;
  border-radius: 11px;
  cursor: pointer;
  font-size: 0.9375rem;
}
.palette__item small { font-family: var(--mono); font-size: 0.6875rem; color: var(--faint); }
.palette__item[aria-selected="true"] { background: var(--card-2); }
.palette__item[aria-selected="true"] small { color: var(--muted); }
.palette__item mark { background: none; color: inherit; text-decoration: underline; text-decoration-color: var(--accent); text-underline-offset: 3px; text-decoration-thickness: 1.5px; }
.palette__empty { padding: 18px 14px; color: var(--muted); font-size: 0.9375rem; }
.palette__foot {
  display: flex;
  gap: 18px;
  padding: 10px 18px;
  border-top: 1px solid var(--line);
  font-size: 0.75rem;
  color: var(--muted);
}
.palette__foot span { display: inline-flex; gap: 4px; align-items: center; }
.palette__foot .kbd:last-of-type { margin-right: 2px; }

/* Fotos groß */

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 300;
  cursor: zoom-out;
}
/* Nur der Hintergrund blendet, das Bild bleibt beim Hin- und Rückflug sichtbar */
.lightbox { touch-action: none; }
/* Reicht bis unter Statusleiste und Adressleiste, damit dort nichts durchscheint */
.lightbox::before {
  content: "";
  position: absolute;
  inset: -50vh 0;
  background: var(--scrim);
  opacity: 0;
  transition: opacity 420ms var(--ease-out);
}
.lightbox.is-open::before { opacity: calc(1 - var(--lb-drag, 0)); }
/* Foto nach unten ziehen: Hintergrund folgt dem Finger, Vorschau und Pfeile sind sofort weg */
.lb-drag .lightbox::before { transition: none; }
.lb-drag .lightbox.is-open .lightbox__strip,
.lb-drag .lightbox.is-open .lightbox__nav { opacity: 0; transition: opacity 120ms var(--ease-out); }
.lightbox[hidden] { display: none; }
/* Beim Rückflug gehen Tippen und Scrollen schon an die Seite darunter */
.lightbox:not(.is-open) { pointer-events: none; }
.lightbox__img {
  position: fixed;
  top: 0; left: 0;
  border-radius: 8px;
  transform-origin: 50% 50%;
  /* Kein will-change: Sonst bliebe das Bild in der kleinen Startgröße gezeichnet und wirkte groß unscharf */
  transition: transform 640ms var(--ease-out), opacity 300ms var(--ease-out), border-radius 640ms var(--ease-out);
}
.lightbox__img img {
  position: relative;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Ecken und Rand per Zuschnitt, den setzt das Script passend zur Karte (--clip) */
  clip-path: var(--clip, inset(1px round 8px));
  transition: clip-path 640ms var(--ease-out);
}
/* Große Fassung über der kleinen, blendet erst ein, wenn sie entpackt ist */
.lightbox__img .lightbox__big {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: clip-path 640ms var(--ease-out), opacity 160ms var(--ease-out);
}
.lightbox__img .lightbox__big.is-ready { opacity: 1; }
.lightbox__img.is-instant img { transition: none; }
/* Schatten auf eigener Ebene: läuft beim Rückflug per opacity aus,
   sonst verschwindet er am Ende auf einen Schlag */
.lightbox__img::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: var(--shadow-float);
  transition: opacity 640ms var(--ease-out);
}
.lightbox:not(.is-open) .lightbox__img { border-radius: 4px; }
.lightbox:not(.is-open) .lightbox__img::before { opacity: 0; }
/* Glanz wie auf der Karte, blendet beim Rückflug ein. Sonst käme er beim Landen auf einen Schlag dazu. */
.lightbox__img::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(var(--gloss, 135deg), rgba(255, 255, 255, 0.16), rgba(255, 255, 255, 0) 42%);
  mix-blend-mode: soft-light;
  clip-path: var(--clip, inset(1px round 8px));
  opacity: 0;
  transition: opacity 640ms var(--ease-out), clip-path 640ms var(--ease-out);
}
.lightbox:not(.is-open) .lightbox__img::after { opacity: 1; }
.lightbox__img.is-instant::after { transition: none; }
/* Rückflug in Seitenkoordinaten: Scrollt man dabei, wandert das Foto mit der Seite mit,
   statt einen Moment stehen zu bleiben. Lage und Höhe setzt das Script. */
/* overflow: Bilder neben dem Schirm (Filmstreifen) dürfen die Seite nicht verbreitern,
   sonst zoomt Safari heraus */
.lightbox.is-closing { position: absolute; bottom: auto; overflow: hidden; }
.lightbox.is-closing .lightbox__img { position: absolute; }
/* Am Ende überblenden statt umspringen: Karte und großes Bild zeichnet der Browser verschieden scharf */
.lightbox__img.is-landing { transition: opacity 320ms var(--ease-out); opacity: 0 !important; }
.lightbox__img--side { visibility: hidden; }
.lightbox__img img { -webkit-user-drag: none; user-select: none; -webkit-user-select: none; }
/* Vorschau unter dem Bild wie in der Fotos-App. Lage setzt das Script (--strip-y),
   die Leiste schiebt sich so, dass das aktuelle Bild in der Mitte steht. */
.lightbox__strip {
  position: fixed;
  left: 50%;
  top: var(--strip-y, auto);
  width: 0;
  height: 44px;
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 140ms var(--ease-out), transform 140ms var(--ease-out);
  touch-action: none;
}
.lightbox.is-open .lightbox__strip {
  opacity: 1;
  transform: none;
  transition: opacity 400ms var(--ease-out) 200ms, transform 520ms var(--ease-out) 200ms;
}
.lightbox__track {
  position: absolute;
  top: 0; left: 0;
  display: flex;
  gap: 4px;
  transition: transform 420ms var(--ease-out);
}
.lightbox__thumb {
  flex: none;
  width: 33px;
  height: 44px;
  padding: 0;
  border: 0;
  border-radius: 4px;
  overflow: hidden;
  background: var(--card);
  cursor: pointer;
  opacity: 0.5;
  transform: scale(0.86);
  transition: opacity 300ms var(--ease-out), transform 420ms var(--ease-out);
}
.lightbox__thumb img { width: 100%; height: 100%; object-fit: cover; pointer-events: none; -webkit-user-drag: none; }
/* Nachbarn rücken etwas zur Seite, das aktuelle Bild steht frei und voll */
.lightbox__thumb.is-before { transform: translateX(-5px) scale(0.86); }
.lightbox__thumb.is-after { transform: translateX(5px) scale(0.86); }
.lightbox__thumb[aria-current="true"] { opacity: 1; transform: scale(1.06); }
@media (hover: hover) {
  .lightbox__thumb:not([aria-current="true"]):hover { opacity: 0.8; }
}
.lb-lock, .lb-lock body { overflow: hidden; }
.lightbox__nav {
  position: fixed;
  top: 50%;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  margin-top: -22px;
  background: var(--card);
  color: var(--ink);
  border: 1px solid var(--card-edge);
  border-radius: 999px;
  box-shadow: var(--shadow-ui);
  cursor: pointer;
  opacity: 0;
  transition: opacity 140ms var(--ease-out), transform 260ms var(--ease-spring);
}
.lightbox.is-open .lightbox__nav { opacity: 1; transition: opacity 400ms var(--ease-out) 200ms, transform 260ms var(--ease-spring); }
@media (hover: hover) {
  .lightbox__nav:hover { transform: scale(1.06); }
}
.lightbox__nav svg { fill: none; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.lightbox__nav--prev { left: 24px; }
.lightbox__nav--next { right: 24px; }

/* Rückmeldung unten mittig */

.toast {
  position: fixed;
  left: 50%;
  bottom: 28px;
  z-index: 400;
  padding: 10px 16px;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--card);
  background: var(--ink);
  border-radius: 999px;
  box-shadow: var(--shadow-ui);
  transform: translate(-50%, 16px);
  opacity: 0;
  pointer-events: none;
  transition: transform 420ms var(--ease-spring), opacity 300ms var(--ease-out);
}
.toast.is-on { transform: translate(-50%, 0); opacity: 1; }

/* Themenwechsel: neues Licht breitet sich vom Knopf aus */

/* Während der Aufnahme für den Übergang liegen umgedrehte Karten flach,
   sonst zeichnet Safari ihre Rückseite gespiegelt. Sieht gleich aus.
   Genauso, solange eine Karte ruht (.is-rest), egal welche Seite oben liegt:
   Safaris Bild für die Tab-Übersicht ignoriert backface-visibility und malt
   die Rückseite gespiegelt über die Vorderseite. */
.is-flat .card--flip .card__core,
.card--flip.is-rest .card__core { transform: none !important; transition: none !important; }
.is-flat .card--flip .face,
.card--flip.is-rest .face { -webkit-backface-visibility: visible; backface-visibility: visible; }
.is-flat .card--flip:not(.is-flipped) .face--back,
.is-flat .card--flip.is-flipped .face--front,
.card--flip.is-rest:not(.is-flipped) .face--back,
.card--flip.is-rest.is-flipped .face--front { visibility: hidden; }
.is-flat .card--flip.is-flipped .face--back,
.card--flip.is-rest .face--back { transform: none; }

/* Touch-Geräte: weicher Farbwechsel statt Kreis, damit Safaris Leisten
   oben und unten gleichzeitig mit der Seite umfärben */
.theme-fade,
.theme-fade *,
.theme-fade *::before,
.theme-fade *::after {
  transition:
    background-color 520ms var(--ease-out),
    color 520ms var(--ease-out),
    border-color 520ms var(--ease-out),
    box-shadow 520ms var(--ease-out),
    fill 520ms var(--ease-out),
    stroke 520ms var(--ease-out),
    opacity 520ms var(--ease-out) !important;
}

::view-transition-old(root),
::view-transition-new(root) { animation: none; mix-blend-mode: normal; }
::view-transition-new(root) { animation: reveal 760ms var(--ease-io); }
@keyframes reveal {
  from { clip-path: circle(0 at var(--vt-x, 100%) var(--vt-y, 0%)); }
  to { clip-path: circle(var(--vt-r, 150vmax) at var(--vt-x, 100%) var(--vt-y, 0%)); }
}

/* ------------------------------------------------------------
   Schmale Bildschirme: gestapelte Liste, keine Physik
   ------------------------------------------------------------ */

@media (max-width: 719.98px), (max-height: 539.98px) {
  .bar { position: static; padding: 18px 20px 4px; }
  .btn--search, .btn--wide { display: none; }
  .hud { display: none; }

  .desk { min-height: 100dvh; }
  .desk::before {
    opacity: var(--doodle-mobile);
    -webkit-mask-size: 300px 300px;
    mask-size: 300px 300px;
  }
  .world {
    display: grid;
    grid-template-columns: repeat(6, minmax(0, 1fr));
    gap: 24px 12px;
    padding: 16px 20px 72px;
  }
  .card,
  .card--intro,
  .card--about,
  .card--contact,
  .card--stack,
  .card--text,
  .card--photo { width: 100%; min-width: 0; grid-column: span 6; }
  .card--photo { grid-column: span 2; }
  /* Reihenfolge mobil: Vorstellung, Über mich, Projekte, Werkzeug, Fotos, Kontakt.
     Die vielen Fotos erst nach den Projekten, sonst muss man lange bis dorthin scrollen. */
  .card--about { order: 1; }
  .card--project { order: 2; }
  .card--stack { order: 3; }
  .card--photo { order: 4; }
  .card--contact { order: 5; }
  .card--photo:nth-of-type(odd) { transform: rotate(-1.5deg); }
  .card--photo:nth-of-type(even) { transform: rotate(1.5deg) translateY(6px); }
  .card--intro .face { padding: calc(var(--bezel) + 18px); }
  .card__title { font-size: 1.875rem; max-width: none; }
  .card__mail { font-size: 1.375rem; }
  /* Mobil: deckend */
  .lightbox::before { background: var(--surface); }
  /* Safari zeichnet unter Status- und Adressleiste nur die Seite selbst,
     nichts Fixiertes. Deshalb die Seite ausblenden, solange ein Foto offen ist. */
  .desk, .bar { transition: opacity 420ms var(--ease-out); }
  .lb-cover .desk,
  .lb-cover .bar { opacity: var(--lb-drag, 0); pointer-events: none; }
  .lb-drag .desk, .lb-drag .bar { transition: none; }
  .lb-cover .lightbox::before { opacity: 0; }
  /* Unsichtbar und würde beim Rückflug die Seite unten verlängern */
  .lightbox.is-closing::before { display: none; }
  /* Beim Ziehen und beim Rückflug ist nur das Foto sichtbar, die Bildansicht selbst nicht.
     Solange sie sichtbar über der Seite liegt, auch leer, zeichnet Safari die Seite unter
     seiner unteren Leiste nicht, dort bliebe ein dunkler Streifen. Der Abdunkler fehlt dann,
     fällt mobil aber nicht auf: Er hat dieselbe Farbe wie der Seitenhintergrund. */
  .lb-drag .lightbox,
  .lightbox.is-closing { visibility: hidden; }
  .lb-drag .lightbox__img:not(.lightbox__img--side),
  .lightbox.is-closing .lightbox__img:not(.lightbox__img--side) { visibility: visible; }

  /* Körnung im Seitenhintergrund statt als Ebene darüber. Den Hintergrund
     zeichnet Safari auch unter Status- und Adressleiste, so gibt es dort
     keinen Farbsprung. */
  body::after { display: none; }
  html { background: var(--surface) var(--noise); }
  body { background: transparent; }
  /* Mobil ohne Pfeile: Blättern per Wischen oder Vorschauleiste */
  .lightbox__nav { display: none; }
}

/* Katze: Bleistiftstriche in Schriftfarbe, Fläche in Tischfarbe, damit sie über Karten lesbar bleibt.
   Lage setzt das Script (Weltkoordinaten), mobil sitzt sie auf der Vorstellung. */

.cat {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 100000;
  width: 140px;
  height: 80px;
  pointer-events: none;
  outline-offset: -10px;
  transform-origin: 70px 70px;
}
.cat svg { display: block; overflow: visible; pointer-events: none; }
/* Bis zu ihrem Auftritt ist sie nicht da */
.cat:not(.is-here) { visibility: hidden; }
.cat--perch:not(.is-here) { visibility: visible; opacity: 0; transform: translateY(-24px) scale(0.8); }
.cat--perch.is-here { transition: opacity 300ms var(--ease-out), transform 560ms var(--ease-spring); }
.cat__body { fill: var(--surface); stroke: var(--ink); stroke-width: 2; stroke-linejoin: round; }
.cat__line,
.cat__leg,
.cat__tail { fill: none; stroke: var(--ink); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.cat__tail { stroke-width: 2.4; }
.cat__leg--far { opacity: 0.45; }
.cat__thin { stroke-width: 1; opacity: 0.7; }
.cat__eye { fill: var(--ink); }
.cat__shadow { fill: rgba(var(--shadow-hue), 0.16); }
/* Nur der Körper ist klickbar, nicht das ganze Rechteck */
.cat__awake, .cat__asleep { pointer-events: visiblePainted; cursor: pointer; }
.is-catgame .cat__awake, .is-catgame .cat__asleep { pointer-events: none; }

/* Mobil: sitzt oben rechts auf der Kante der Vorstellung */
.cat--perch { top: -66px; left: auto; right: 6px; z-index: 2; transform: scale(0.8); transform-origin: 50% 100%; }

/* Laserpunkt am Zeiger, sobald die Katze jagt */
.laser {
  position: absolute;
  top: -5px;
  left: -5px;
  z-index: 100001;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 22%, transparent);
  pointer-events: none;
  opacity: 0;
  transition: opacity 300ms var(--ease-out);
}
.laser.is-on { opacity: 1; }
.is-catgame .desk { cursor: none; }

/* Pfotenabdruck: verblasst nach ein paar Sekunden */
.paw {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 3;
  width: 12px;
  height: 12px;
  pointer-events: none;
  background:
    radial-gradient(circle at 50% 70%, var(--ink) 0 2.6px, transparent 3px),
    radial-gradient(circle at 22% 38%, var(--ink) 0 1.3px, transparent 1.6px),
    radial-gradient(circle at 42% 22%, var(--ink) 0 1.3px, transparent 1.6px),
    radial-gradient(circle at 62% 22%, var(--ink) 0 1.3px, transparent 1.6px),
    radial-gradient(circle at 80% 38%, var(--ink) 0 1.3px, transparent 1.6px);
  opacity: 0.22;
  animation: paw-fade 10s var(--ease-io) forwards;
}
@keyframes paw-fade { 0%, 70% { opacity: 0.22; } 100% { opacity: 0; } }

/* Im Spiel: Suche und Aufräumen weg, dafür ein X zum Beenden */
.btn--close { display: none; }
.is-catgame .btn--close { display: inline-flex; }
.is-catgame #open-palette,
.is-catgame #tidy { display: none; }

/* Im Spiel: Karten reagieren nicht auf Klicks, heruntergefallene verschwinden */
.is-catgame .card { pointer-events: none; }
.card.is-fallen { opacity: 0; scale: 0.86; transition: opacity 420ms var(--ease-out), scale 520ms var(--ease-out); }

.card--intro.is-nudged { animation: nudge 520ms var(--ease-spring); }
@keyframes nudge { 30% { rotate: -1.6deg; translate: -3px 0; } 60% { rotate: 0.8deg; } }

.catgame { color: var(--ink); }
.catgame__score,
.catgame__hint,
.catgame__end {
  position: fixed;
  left: 50%;
  z-index: 120;
  opacity: 0;
  transform: translate(-50%, 8px);
  transition: opacity 400ms var(--ease-out), transform 500ms var(--ease-out);
  pointer-events: none;
}
.catgame__score {
  top: 20px;
  display: flex;
  gap: 12px;
  align-items: baseline;
  padding: 6px 16px;
  border-radius: 14px;
  background: var(--card);
  border: 1px solid var(--card-edge);
  box-shadow: var(--shadow-ui);
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
}
.catgame__score b { font-size: 1.5rem; font-weight: 500; color: var(--ink); }
.catgame__score span { font-size: 0.875rem; color: var(--muted); }
.catgame__hint { bottom: 28px; padding: 8px 14px; border-radius: 12px; background: var(--card); box-shadow: var(--shadow-ui); font-size: 0.9375rem; color: var(--muted); white-space: nowrap; }
.catgame.is-on .catgame__score,
.catgame.is-hint .catgame__hint { opacity: 1; transform: translate(-50%, 0); }
.catgame__end {
  top: 50%;
  padding: 24px 24px 20px;
  min-width: 17rem;
  text-align: center;
  background: var(--card);
  border: 1px solid var(--card-edge);
  border-radius: var(--r-outer);
  box-shadow: var(--shadow-float);
  transform: translate(-50%, calc(-50% + 12px));
}
.catgame.is-end .catgame__end { opacity: 1; transform: translate(-50%, -50%); pointer-events: auto; }
.catgame__result { font-size: 1.5rem; font-weight: 500; letter-spacing: -0.02em; }
.catgame__best { margin-top: 6px; font-size: 0.875rem; color: var(--muted); }
.catgame__end .card__actions { justify-content: center; margin-top: 20px; }
.catgame__pop {
  position: fixed;
  z-index: 121;
  font: 500 1.25rem/1 var(--mono);
  color: var(--accent);
  pointer-events: none;
  transform: translate(-50%, -50%);
  animation: pop 900ms var(--ease-out) forwards;
}
@keyframes pop { from { opacity: 1; transform: translate(-50%, -50%) scale(0.8); } to { opacity: 0; transform: translate(-50%, -150%) scale(1.1); } }

/* Bewegung reduzieren */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    transition-duration: 1ms !important;
    transition-delay: 0ms !important;
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
  }
  ::view-transition-new(root) { animation: none; }
  .card { --lift-y: 0px !important; }
}
