/* gabrielw.de – "Signal Grid": neo-brutalist frame, minimalist density. No framework. */

/* ---------- Fonts (war assets/fonts/fonts.css; gemerged 2026-09-13, spart
   einen blockierenden Request im kritischen Pfad - auf mobil 150-450ms fuer
   687 Byte gzip). Die woff2 selbst liegen weiter in assets/fonts/. ---------- */
/* Space Grotesk 400/500/700 + Space Mono 400/700, self-hosted (fetched from Google Fonts 2026-09-10, OFL) */
/* vietnamese */
@font-face {
  font-family: 'Space Grotesk';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(../fonts/V8mDoQDjQSkFtoMM3T6r8E7mPb54C_k3HqUtEw.woff2) format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'Space Grotesk';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(../fonts/V8mDoQDjQSkFtoMM3T6r8E7mPb94C_k3HqUtEw.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Space Grotesk';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(../fonts/V8mDoQDjQSkFtoMM3T6r8E7mPbF4C_k3HqU.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* vietnamese */
@font-face {
  font-family: 'Space Grotesk';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(../fonts/V8mDoQDjQSkFtoMM3T6r8E7mPb54C_k3HqUtEw.woff2) format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'Space Grotesk';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(../fonts/V8mDoQDjQSkFtoMM3T6r8E7mPb94C_k3HqUtEw.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Space Grotesk';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(../fonts/V8mDoQDjQSkFtoMM3T6r8E7mPbF4C_k3HqU.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* vietnamese */
@font-face {
  font-family: 'Space Grotesk';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(../fonts/V8mDoQDjQSkFtoMM3T6r8E7mPb54C_k3HqUtEw.woff2) format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'Space Grotesk';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(../fonts/V8mDoQDjQSkFtoMM3T6r8E7mPb94C_k3HqUtEw.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Space Grotesk';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(../fonts/V8mDoQDjQSkFtoMM3T6r8E7mPbF4C_k3HqU.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* vietnamese */
@font-face {
  font-family: 'Space Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(../fonts/i7dPIFZifjKcF5UAWdDRYE58RXi4EwSsbg.woff2) format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'Space Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(../fonts/i7dPIFZifjKcF5UAWdDRYE98RXi4EwSsbg.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Space Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(../fonts/i7dPIFZifjKcF5UAWdDRYEF8RXi4EwQ.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* vietnamese */
@font-face {
  font-family: 'Space Mono';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(../fonts/i7dMIFZifjKcF5UAWdDRaPpZUFqaHi6WZ3S_Yg.woff2) format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* latin-ext */
@font-face {
  font-family: 'Space Mono';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(../fonts/i7dMIFZifjKcF5UAWdDRaPpZUFuaHi6WZ3S_Yg.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Space Mono';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(../fonts/i7dMIFZifjKcF5UAWdDRaPpZUFWaHi6WZ3Q.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  --bg: #FFFFFF; --grid: #E4E4E4; --ink: #0A0A0A; --accent: #FFE500; --muted: #5F5F5F; --soft: #F4F4F4; --text-2: #333333;
  --bw: 2px; --shadow: 5px 5px 0 var(--ink); --shadow-sm: 3px 3px 0 var(--ink); --shadow-lg: 8px 8px 0 var(--ink);
  --display: "Space Grotesk", system-ui, sans-serif; --mono: "Space Mono", ui-monospace, "SF Mono", Menlo, monospace;
  --max: 1200px; --pad: clamp(1.25rem, 4vw, 3rem); --section-y: clamp(3rem, 6vw, 5rem);
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; scroll-padding-top: 5rem; }
body {
  margin: 0; color: var(--ink); font: 16px/1.6 var(--display); background-color: var(--bg);
  background-image: linear-gradient(var(--grid) 1px, transparent 1px), linear-gradient(90deg, var(--grid) 1px, transparent 1px);
  background-size: 28px 28px;
}
img, canvas, svg { display: block; }
canvas.px { image-rendering: pixelated; }
a { color: inherit; }
:focus-visible { outline: 3px solid var(--ink); outline-offset: 3px; }
/* ---------- Textauswahl ----------
   Ohne eigene Regel nimmt der Browser sein Blau - das passt nirgends ins Raster.
   Auf hellem wie auf dunklem Grund funktioniert Gelb/Ink; nur auf den gelben
   Flaechen selbst (Kontaktblock, Callout, Tape, mark, Buttons) waere Gelb auf Gelb
   unsichtbar, dort wird die Auswahl invertiert. Der Kontrast bleibt dabei exakt
   gleich, weil es dieselben zwei Farben sind, nur getauscht: 15,52:1 in beide
   Richtungen (AAA ab 7:1). */
::selection { background: var(--accent); color: var(--ink); text-shadow: none; }

.contact::selection, .contact ::selection,
.callout::selection, .callout ::selection,
.tape::selection, .tape ::selection,
.todo::selection, .todo ::selection,
.btn::selection, .btn ::selection,
mark::selection, mark ::selection {
  background: var(--ink); color: var(--accent); text-shadow: none;
}

/* .btn.dark and .card:hover are dark - the default rule applies again there. */
.btn.dark::selection, .btn.dark ::selection { background: var(--accent); color: var(--ink); }

mark { background: var(--accent); color: inherit; padding: 0 .1em; -webkit-box-decoration-break: clone; box-decoration-break: clone; mix-blend-mode: multiply; }
.skip { position: absolute; left: -999px; top: 0; background: var(--accent); padding: .5rem 1rem; font: 700 13px var(--mono); border: var(--bw) solid var(--ink); z-index: 100; }
.skip:focus { left: 1rem; top: 1rem; }

/* ---------- frame ---------- */
.sheet { max-width: var(--max); margin: 2.5rem auto 3rem; background: var(--bg); border: var(--bw) solid var(--ink); box-shadow: var(--shadow-lg); }
@media (max-width: 1300px) { .sheet { margin: 2rem 2.5rem 3rem; } }
@media (max-width: 760px) { .sheet { margin: 0; border-left: 0; border-right: 0; box-shadow: none; } }

/* ---------- header ---------- */
.site-header { position: sticky; top: 0; z-index: 20; display: flex; align-items: center; justify-content: space-between; gap: 1.5rem; padding: .8rem var(--pad); background: var(--bg); border-bottom: var(--bw) solid var(--ink); }
.brand { display: flex; align-items: center; gap: .75rem; text-decoration: none; font: 700 13px/1.25 var(--mono); text-transform: uppercase; letter-spacing: .02em; }
.brand small { display: block; font-weight: 400; color: var(--muted); }
.nav { display: flex; gap: 1.5rem; font: 400 13px var(--mono); text-transform: uppercase; }
.nav a { text-decoration: none; padding: .15rem .15rem; }
.nav a:hover { background: var(--accent); }
.menu-btn { display: none; align-items: center; gap: .5rem; border: var(--bw) solid var(--ink); background: var(--bg); font: 700 12px var(--mono); text-transform: uppercase; padding: .55rem .8rem; box-shadow: var(--shadow-sm); cursor: pointer; }
.menu-btn:hover { transform: translate(1px, 1px); box-shadow: 2px 2px 0 var(--ink); }
@media (max-width: 900px) {
  .site-header { flex-wrap: wrap; }
  .menu-btn { display: inline-flex; }
  .site-header .header-cta { display: none; }
  .nav { display: none; flex-direction: column; gap: 0; flex-basis: 100%; margin: .8rem calc(-1 * var(--pad)) calc(-.8rem - var(--bw)); border-top: var(--bw) solid var(--ink); }
  .nav a { padding: 1rem var(--pad); border-bottom: var(--bw) solid var(--ink); }
  .nav a:last-child { border-bottom: 0; }
  .site-header.open .nav { display: flex; }
}

/* ---------- buttons, labels, tags ---------- */
.btn { display: inline-flex; align-items: center; gap: .6rem; padding: .85rem 1.25rem; border: var(--bw) solid var(--ink); background: var(--accent); color: var(--ink); font: 700 14px/1 var(--mono); text-transform: uppercase; letter-spacing: .02em; text-decoration: none; box-shadow: var(--shadow); transition: transform .1s, box-shadow .1s; cursor: pointer; }
.btn:hover { transform: translate(2px, 2px); box-shadow: var(--shadow-sm); }
.btn:active { transform: translate(5px, 5px); box-shadow: none; }
.btn.ghost { background: var(--bg); }
.btn.dark { background: var(--ink); color: var(--bg); }
.btn.sm { padding: .65rem .9rem; font-size: 12px; box-shadow: var(--shadow-sm); }
.btn.sm:hover { box-shadow: 1px 1px 0 var(--ink); }
.label { font: 400 12px/1.2 var(--mono); letter-spacing: .04em; text-transform: uppercase; color: var(--muted); margin: 0 0 .6rem; }
.label::before { content: "// "; }
.tags { display: flex; flex-wrap: wrap; gap: .5rem; }
.tag { font: 400 11px/1 var(--mono); text-transform: uppercase; border: var(--bw) solid currentColor; padding: .35rem .5rem; white-space: nowrap; }
.tag::before { content: "[ "; } .tag::after { content: " ]"; }

/* ---------- tape (marquee) ---------- */
.tape { background: var(--accent); border-bottom: var(--bw) solid var(--ink); overflow: hidden; font: 700 12px/1 var(--mono); text-transform: uppercase; }
.tape .track { display: flex; width: max-content; animation: marq 28s linear infinite; padding: .6rem 0; }
.tape span { padding-right: 1.5rem; }
.tape span::after { content: "///"; margin-left: 1.5rem; }
@keyframes marq { to { transform: translateX(-50%); } }

/* ---------- hero ---------- */
.hero { display: grid; grid-template-columns: 1.25fr 1fr; gap: 3rem; align-items: center; padding: var(--section-y) var(--pad); border-bottom: var(--bw) solid var(--ink); }
.hero h1 { font: 700 clamp(2.5rem, 5.4vw, 4.4rem)/1 var(--display); letter-spacing: -.04em; margin: .5rem 0 1.25rem; text-wrap: balance; }
/* The yellow highlight must never be torn across two lines - it moves to the
   next line as a whole instead. Older browsers ignore text-wrap and break as
   before; nowrap still applies there. */
.hero h1 mark { white-space: nowrap; }
.lead { font-size: clamp(1.05rem, 1.4vw, 1.2rem); max-width: 50ch; margin: 0 0 2rem; color: var(--text-2); }
.cta { display: flex; flex-wrap: wrap; gap: 1.25rem; }
.hero-art { display: grid; gap: 1.25rem; }
.art { border: var(--bw) solid var(--ink); display: grid; place-items: center; padding: 1.5rem; background: repeating-linear-gradient(45deg, transparent 0 12px, var(--ink) 12px 13px); }
.art canvas { background: var(--bg); border: var(--bw) solid var(--ink); padding: 10px; max-width: 100%; height: auto; }
/* A <dl>: term -> value is exactly what this is, and unlike a plain <div> it
   carries aria-label validly. The rows stay <div> because dt/dd cannot be
   wrapped in anything else. */
.spec { margin: 0; border: var(--bw) solid var(--ink); background: var(--bg); font: 13px/1.3 var(--mono); }
.spec div { display: flex; justify-content: space-between; gap: 1rem; padding: .7rem 1rem; border-bottom: var(--bw) solid var(--ink); }
.spec div:last-child { border-bottom: 0; }
.spec dt { color: var(--muted); text-transform: uppercase; }
.spec dd { margin: 0; font-weight: 700; text-align: right; }
@media (max-width: 900px) { .hero { grid-template-columns: 1fr; } }

/* ---------- sections ---------- */
.section { padding: var(--section-y) var(--pad); border-bottom: var(--bw) solid var(--ink); }
.section h2 { font: 700 clamp(1.9rem, 3.6vw, 2.8rem)/1.05 var(--display); letter-spacing: -.03em; margin: 0 0 1rem; }
.intro { max-width: 60ch; font-size: 1.1rem; margin: 0 0 2.5rem; color: var(--text-2); }
.fineprint { margin: 1.5rem 0 0; font: 13px/1.5 var(--mono); color: var(--muted); }

/* services */
.cards { display: grid; grid-template-columns: repeat(2, 1fr); border: var(--bw) solid var(--ink); background: var(--bg); }
.card { padding: 1.75rem; border-bottom: var(--bw) solid var(--ink); transition: background .15s, color .15s; }
.card:nth-child(odd) { border-right: var(--bw) solid var(--ink); }
.card:nth-last-child(-n+2) { border-bottom: 0; }
.card:hover { background: var(--ink); color: var(--bg); }
.card .num { font: 400 12px/1 var(--mono); color: var(--muted); }
.card:hover .num { color: var(--accent); }
.card h3 { font: 700 1.45rem/1.1 var(--display); letter-spacing: -.02em; margin: .75rem 0 .6rem; hyphens: auto; }
.card p { margin: 0 0 1.1rem; }
@media (max-width: 900px) {
  .cards { grid-template-columns: 1fr; }
  .card:nth-child(odd) { border-right: 0; }
  .card:nth-last-child(-n+2) { border-bottom: var(--bw) solid var(--ink); }
  .card:last-child { border-bottom: 0; }
}

/* process */
.steps { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.25rem; }
.step { border: var(--bw) solid var(--ink); background: var(--bg); padding: 1.5rem; box-shadow: var(--shadow-sm); }
.step .num { font: 700 2rem/1 var(--mono); color: var(--muted); }
.step h3 { font: 700 1.25rem/1.15 var(--display); margin: .75rem 0 .5rem; letter-spacing: -.02em; }
.step p { margin: 0; font-size: .95rem; }
.callout { margin-top: 2.25rem; border: var(--bw) solid var(--ink); background: var(--accent); padding: 1.5rem 1.75rem; box-shadow: var(--shadow); display: grid; grid-template-columns: auto 1fr; gap: 1.25rem; align-items: start; }
.callout .num { font: 700 2rem/1 var(--mono); }
.callout p { margin: 0; font-size: 1.05rem; font-weight: 500; max-width: 70ch; }
@media (max-width: 900px) { .steps { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 600px) { .steps { grid-template-columns: 1fr; } .callout { grid-template-columns: 1fr; } }

/* about */
.about { display: grid; grid-template-columns: minmax(220px, 320px) 1fr; gap: 3rem; align-items: start; }
.portrait { margin: 0; border: var(--bw) solid var(--ink); background: var(--accent); padding: 12px; box-shadow: var(--shadow); }
/* Not pointer: the portrait is not a link. The crosshair is the only hint that
   something happens if you stay on it. */
.portrait { cursor: crosshair; }
.portrait-stack { position: relative; display: grid; }
.portrait-stack > * { grid-area: 1 / 1; width: 100%; height: auto; }
.portrait-stack picture { display: block; }
/* The photo is the resting state (yellow/black duotone via multiply over the
   yellow frame). On top of it sits the print layer from site.js, which charges
   as long as the pointer stays on the image.
   That layer is opaque, so *no* multiply - and that is exactly why the <canvas>
   comes after the <picture> in the markup: in the grid the later element paints
   on top. site.js sets the opacity per frame, hence no transition either, which
   would otherwise fight the charge curve. */
.portrait-stack img { display: block; width: 100%; height: auto; filter: grayscale(1) contrast(1.15) brightness(1.05); mix-blend-mode: multiply; }
.portrait-stack canvas { opacity: 0; image-rendering: pixelated; }
.portrait figcaption { font: 11px/1.3 var(--mono); text-transform: uppercase; margin-top: .75rem; }
.about p { max-width: 60ch; margin: 0 0 1rem; }
.stack { margin: 1.5rem 0; }
.nope { list-style: none; padding: 0; margin: 2rem 0 0; border-top: var(--bw) solid var(--ink); max-width: 60ch; }
.nope li { padding: .7rem 0; border-bottom: var(--bw) solid var(--ink); font-size: .95rem; }
.nope li::before { content: "[ ✕ ]"; font: 700 12px var(--mono); margin-right: .75rem; }
.nope-title { font: 700 12px/1.2 var(--mono); text-transform: uppercase; margin: 2rem 0 .5rem; }
.stats { display: grid; grid-template-columns: repeat(3, 1fr); border: var(--bw) solid var(--ink); margin-top: 2rem; background: var(--bg); }
.stat { padding: 1rem 1.1rem; border-right: var(--bw) solid var(--ink); }
.stat:last-child { border-right: 0; }
.stat b { display: block; font: 700 2rem/1 var(--display); letter-spacing: -.03em; }
.stat > span { font: 400 11px/1.3 var(--mono); text-transform: uppercase; color: var(--muted); }
@media (max-width: 900px) { .about { grid-template-columns: 1fr; } }

/* contact */
.contact { background: var(--accent); }
.contact h2 { font-size: clamp(2.4rem, 6vw, 4.4rem); }
.contact .intro, .contact .label { color: var(--ink); }
.contact-actions { display: flex; flex-wrap: wrap; gap: 1.25rem; margin-bottom: 1.75rem; }
.contact .fineprint { color: var(--ink); }

/* footer */
.site-footer { display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: 1.25rem 2rem; padding: 1.75rem var(--pad); font: 12px/1.6 var(--mono); text-transform: uppercase; }
.site-footer a { text-decoration: none; }
.site-footer a:hover { background: var(--accent); }
.foot-links { display: flex; gap: 1.5rem; flex-wrap: wrap; }
.foot-meta { color: var(--muted); }
.foot-meta .ver { color: var(--ink); text-decoration: underline dotted; text-underline-offset: 3px; }

/* legal pages + 404 */
.legal { padding: var(--section-y) var(--pad); max-width: 76ch; }
.legal h1 { font: 700 clamp(2rem, 4vw, 3rem)/1.05 var(--display); letter-spacing: -.03em; margin: .5rem 0 1.5rem; }
.legal h2 { font: 700 1.35rem/1.2 var(--display); letter-spacing: -.02em; margin: 2.5rem 0 .75rem; }
.legal p, .legal li { margin: 0 0 .75rem; }
.legal address { font-style: normal; }
.legal h3 { font: 700 1rem/1.3 var(--display); margin: 1.75rem 0 .5rem; }
.legal ul { padding-left: 1.15rem; }
.legal .lead { border: var(--bw) solid var(--ink); border-left-width: 8px; padding: 1rem 1.15rem; margin: 0 0 2.5rem; }
.legal .toc { margin: 0 0 3rem; padding: 0; list-style: none; font: 400 13px/2 var(--mono); columns: 2; column-gap: 2rem; }
.legal .toc a { text-decoration: underline dotted; text-underline-offset: 3px; }
.legal .toc a:hover { background: var(--accent); }
@media (max-width: 620px) { .legal .toc { columns: 1; } }
.todo { background: var(--accent); border: 1px dashed var(--ink); padding: 0 .3em; font: .85em var(--mono); }
/* error pages (403, 404, 405, 500, 502, 503): a yellow tile with the code or an animation, text beside it */
.err { min-height: 60vh; display: grid; grid-template-columns: 220px minmax(0, 48ch); justify-content: center; align-items: center; gap: clamp(2rem, 5vw, 4rem); padding: var(--section-y) var(--pad); }
.err h1 { font: 700 clamp(2.2rem, 5vw, 3.6rem)/1.04 var(--display); letter-spacing: -.035em; margin: 0 0 1rem; text-wrap: balance; }
.err p { margin: 0 0 2rem; color: var(--text-2); font-size: 1.08rem; }
.err .label { margin: 0 0 .6rem; color: var(--muted); font-size: 12px; }
.btn[hidden] { display: none; }
.vis { position: relative; margin: 0; width: 220px; aspect-ratio: 1; border: var(--bw) solid var(--ink); background: var(--accent); box-shadow: var(--shadow); display: grid; place-items: center; }
.vis .code { font: 700 4.8rem/1 var(--display); letter-spacing: -.06em; }
.vis figcaption { position: absolute; top: calc(100% + 14px); left: 0; right: 0; text-align: center; font: 400 11px/1.3 var(--mono); text-transform: uppercase; color: var(--muted); }
@media (max-width: 700px) {
  .err { grid-template-columns: 1fr; align-content: center; }
  .vis { width: 170px; }
  .vis .code { font-size: 3.6rem; }
  .vis.locked { margin-bottom: 1.5rem; }
}
/* 404: the pupils follow the pointer (site.js) */
.eyes { width: 82%; height: auto; overflow: visible; }
.eyes .eye { transform-box: fill-box; transform-origin: center; transition: transform .07s ease-in; }
.eyes.blink .eye { transform: scaleY(.08); }
/* 403: a padlock behind crossed barrier tape; rattling it gets an answer, never access */
.vis.locked { --sway: 0deg; }
.tapes { position: absolute; inset: 0; overflow: hidden; }
.tapes div { position: absolute; left: -40%; width: 180%; top: 50%; background: var(--ink); color: var(--accent); font: 700 10px/1 var(--mono); text-transform: uppercase; letter-spacing: .06em; white-space: nowrap; padding: .45rem 0; transition: transform .3s ease-out; }
.tapes div:first-child { transform: translateY(-50%) rotate(calc(-32deg + var(--sway))); }
.tapes div:last-child { transform: translateY(-50%) rotate(calc(32deg - var(--sway))); }
.tapes span { display: inline-block; animation: tapes 9s linear infinite; }
.tapes div:last-child span { animation-direction: reverse; }
@keyframes tapes { to { transform: translateX(-50%); } }
.lock { position: relative; z-index: 1; width: 100px; padding: 0; border: 0; background: none; color: var(--ink); cursor: pointer; transform-origin: 50% 10%; }
.lock svg { width: 100%; height: auto; overflow: visible; }
.lock .shackle { transition: transform .08s; }
.lock.rattle { animation: rattle .5s ease-in-out; }
.lock.rattle .shackle { transform: translateY(-5px); }
@keyframes rattle { 0%, 100% { transform: rotate(0); } 15% { transform: rotate(-14deg); } 35% { transform: rotate(11deg); } 55% { transform: rotate(-8deg); } 75% { transform: rotate(5deg); } }
.say { position: absolute; z-index: 2; top: -18px; left: 50%; transform: translateX(-50%); width: max-content; max-width: 200px; margin: 0; padding: .35rem .6rem; background: var(--bg); border: var(--bw) solid var(--ink); box-shadow: var(--shadow-sm); font: 700 12px/1.3 var(--mono); text-align: center; }
.say:empty { display: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .tape .track, .tapes span, .lock.rattle { animation: none; }
  .btn, .card, .menu-btn, .tapes div, .eyes .eye { transition: none; }
}

/* ---------- Dark Reader ----------
   The extension recomputes every colour itself - including those in rules that
   try to argue with it; tested with `!important`, no effect, and
   `data-darkreader-ignore` does not help either. The only thing you can steer is
   what is not a colour. Exactly one such property breaks under Dark Reader:
   `mix-blend-mode: multiply` turns black on a dark background, which makes the
   yellow highlight and the portrait disappear entirely. Without
   Dark Reader this block does nothing - it hangs off the extension's attribute. */
html[data-darkreader-scheme="dark"] mark,
html[data-darkreader-scheme="dark"] .portrait-stack img { mix-blend-mode: normal; }
