/* flatlink – schlichtes Standard-Theme.
   Bewusst zurückhaltend gehalten: Wer die Software betreibt, soll hier
   die eigenen Farben eintragen. Alle Farben hängen an den Variablen unten,
   ein Austausch der beiden :root-Blöcke reicht für ein komplettes Redesign. */

:root {
    color-scheme: light dark;
    --paper: #FBFBFC;        /* Seitengrund */
    --surface: #F3F4F6;      /* Karten, Flächen */
    --ink: #16181D;          /* Text, Ränder */
    --muted: #5C6270;        /* Sekundärtext */
    --line: #DFE1E6;         /* Trennlinien */
    --accent: #3B6EA8;       /* Signal: Primär-Aktion, Erfolg */
    --accent-deep: #2C5480;  /* Akzent als Text auf hellen Flächen (kontrastsicher) */
    --accent-tint: #E8EFF7;  /* Hover, markierte Zeilen */
    --on-accent: #FFFFFF;    /* Text auf gefüllter Akzentfläche */
    --radius: 6px;
    --mono: ui-monospace, "SF Mono", "Cascadia Code", Menlo, Consolas, monospace;
}
@media (prefers-color-scheme: dark) {
    :root {
        --paper: #101216;
        --surface: #191C22;
        --ink: #E7E9EE;
        --muted: #949AA6;
        --line: #2A2E37;
        --accent: #5B9BD8;
        --accent-deep: #8CBCE8;
        --accent-tint: #1A222C;
        --on-accent: #101216;
    }
}

* { box-sizing: border-box; }

body {
    margin: 0;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    background: var(--paper);
    color: var(--ink);
    line-height: 1.6;
}

/* Die Hülle ist mindestens bildschirmhoch und verteilt in der Senkrechten:
   <main> nimmt den Rest, dadurch sitzt die Fußzeile auf kurzen Seiten unten am
   Bildschirmrand statt frei in der Mitte zu schweben. 'dvh' berücksichtigt die
   ein- und ausfahrenden Leisten mobiler Browser; 'vh' bleibt als Rückfall für
   ältere Browser darüber stehen. */
.wrap {
    max-width: 960px;
    margin: 0 auto;
    padding: 0 1rem 3rem;
    min-height: 100vh;
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
}
main { flex: 1 0 auto; }

a { color: var(--accent-deep); text-decoration: none; }
a:hover { text-decoration: underline; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

code, .prefix { font-family: var(--mono); }

/* Kopf & Fuß */
.site-head {
    display: flex; align-items: center; justify-content: space-between;
    padding: 1.2rem 0; gap: 1rem; flex-wrap: wrap;
    border-bottom: 1px solid var(--line);
    margin-bottom: 1.5rem;
}
.brand {
    display: inline-flex; align-items: center; gap: 0.6rem;
    font-family: var(--mono);
    font-size: 1.35rem; font-weight: 700; color: var(--ink);
    letter-spacing: -0.02em;
}
.brand svg, .brand img { display: block; }
.brand:hover { text-decoration: none; }
/* Eigenes Logo aus der Konfiguration – die Höhe bestimmt die Größe,
   die Breite ergibt sich aus dem Seitenverhältnis */
.brand-logo { height: 1.7em; width: auto; max-width: 12rem; }
.site-head nav { display: flex; align-items: center; gap: 0.9rem; flex-wrap: wrap; }
.site-head nav a { color: var(--ink); }
.who, .site-head nav a.who { color: var(--muted); font-family: var(--mono); font-size: 0.85rem; }
/* Verwaltungsklappe in der Kopfzeile. <details> statt eines eigenen Menüs:
   funktioniert ohne JavaScript, und die Content-Security-Policy braucht keine
   Ausnahme. Das Skript schließt sie nur zusätzlich beim Klick daneben. */
.nav-more { position: relative; display: inline-block; }
.nav-more > summary {
    list-style: none; cursor: pointer; color: var(--ink);
    display: inline-flex; align-items: center; gap: 0.3rem;
}
.nav-more > summary::-webkit-details-marker { display: none; }
.nav-more > summary::after { content: "▾"; color: var(--muted); font-size: 0.85em; }
.nav-more > summary:hover { text-decoration: underline; }
.nav-more > summary.here { font-weight: 600; }
.nav-panel {
    position: absolute; right: 0; top: calc(100% + 0.5rem); z-index: 20;
    display: grid; min-width: 11rem;
    background: var(--paper); border: 1px solid var(--line); border-radius: var(--radius);
    box-shadow: 0 6px 20px rgb(0 0 0 / 0.12);
    padding: 0.3rem;
}
.nav-panel a { padding: 0.45rem 0.7rem; border-radius: 4px; white-space: nowrap; }
.nav-panel a:hover { background: var(--accent-tint); text-decoration: none; }
.nav-panel a.here { background: var(--accent-tint); font-weight: 600; }

/* Auf schmalen Schirmen kein schwebendes Panel: Es hängt an der Klappe, und
   sobald die nach dem Umbruch links steht, ragt es aus dem Bild. Dort klappt es
   stattdessen in der Zeile auf – kann nicht überlaufen und ist mit dem Daumen
   leichter zu treffen. */
@media (max-width: 560px) {
    .nav-more[open] { flex-basis: 100%; }
    .nav-panel {
        position: static; box-shadow: none; min-width: 0;
        margin-top: 0.4rem; width: 100%;
    }
    .nav-panel a { padding: 0.6rem 0.7rem; }
}

.site-foot {
    margin-top: 3rem; padding-top: 1.2rem; border-top: 1px solid var(--line);
    color: var(--muted); font-size: 0.8rem; text-align: center;
    font-family: var(--mono);
}
.site-foot a { color: var(--muted); }
.site-foot p { margin: 0.25rem 0; }

/* Herkunftszeile: kleines Kiwi-Zeichen neben dem Hinweis aufs Ursprungsprojekt */
.origin {
    display: flex; align-items: center; justify-content: center;
    gap: 0.45rem; opacity: 0.8;
}
/* Der Vogel ist deutlich breiter als hoch (Seitenverhältnis 3:2) – eine
   quadratische Box würde ihn auf Punktgröße schrumpfen */
.origin-mark { width: 2.1em; height: 1.4em; flex: none; }

/* Hero (öffentliche Seite) */
.hero { text-align: center; margin: 2.5rem 0 2rem; }
.hero h1 { font-size: 2.1rem; font-weight: 700; letter-spacing: -0.02em; margin: 0 0 0.4rem; text-wrap: balance; }
.accent { color: var(--accent-deep); }
.sub { color: var(--muted); margin: 0; }

/* Karten — flach, kleiner Radius, kein Schatten */
.card {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    padding: 1.4rem;
    margin-bottom: 1.2rem;
}
.card h1 { margin-top: 0; }
.card h2, .card h3 { margin: 0 0 0.8rem; }
.card.narrow { max-width: 420px; margin: 3rem auto; }
.card.narrow-wide { max-width: 720px; margin: 2rem auto; }
.card.narrow-wide h2 { margin-top: 1.4rem; font-size: 1.1rem; }

/* Seiten, die aus der 420er-Spalte herausgewachsen sind.
   .narrow ist für das gemacht, was schmal bleiben soll: Anmeldung,
   Registrierung, Passwortabfrage – ein Formular, das breit gezogen nur
   schlechter zu lesen wäre. Profil und Erweiterung/API sind daraus
   herausgewachsen (gemessen 420 × 1218 px in einem 1440er Fenster) und
   sahen auf dem Desktop aus wie am Handy, nur mit viel Weiß daneben. */
.card.weit { max-width: 960px; margin: 2rem auto; }

/* Zwei Spalten, sobald der Schirm sie trägt – darunter bleibt es eine.
   Grid und nicht `columns`: Beim Aufklappen eines Abschnitts soll kein
   Nachbar in die andere Spalte rutschen. align-items:start hält die
   Abschnitte oben, statt sie auf Zeilenhöhe zu strecken. */
.spalten { display: grid; gap: 0 2.2rem; }
@media (min-width: 860px) {
    .spalten { grid-template-columns: 1fr 1fr; align-items: start; }
    /* Was über beide Spalten gehört – etwa das Löschen des Kontos, das
       unten und für sich stehen soll. */
    .spalten > .voll { grid-column: 1 / -1; }

    /* Der aufgeklappte Abschnitt nimmt die ganze Breite. Das folgt der
       Idee, die dem Profil ohnehin zugrunde liegt: zugeklappt ein
       Inhaltsverzeichnis, offen genau der eine Abschnitt, in dem gerade
       etwas passiert. Ohne diese Zeile wüchse er in seiner halben Spalte
       in die Länge, während die andere leer danebensteht. */
    .spalten > details[open] { grid-column: 1 / -1; }
}

/* Profil: einklappbare Abschnitte.
   Acht offene Formulare untereinander waren zu viel Seite – zugeklappt ist
   das Profil ein Inhaltsverzeichnis, und offen ist genau der Abschnitt, in
   dem gerade etwas passiert (?zeige= vom Server, sonst der Klick). */
details.abschnitt { border-top: 1px solid var(--line); }
details.abschnitt summary {
    cursor: pointer; list-style: none;
    display: flex; align-items: center; gap: 0.55rem;
    padding: 0.75rem 0;
}
details.abschnitt summary::-webkit-details-marker { display: none; }
details.abschnitt summary::before {
    content: ""; flex: none;
    width: 0.45em; height: 0.45em;
    border-right: 2px solid var(--muted); border-bottom: 2px solid var(--muted);
    transform: rotate(-45deg);           /* zu: Pfeil zeigt nach rechts */
    transition: transform 0.12s;
}
details.abschnitt[open] > summary::before { transform: rotate(45deg); }   /* offen: nach unten */
details.abschnitt summary h2 { margin: 0; font-size: 1.02rem; }
details.abschnitt summary:hover h2 { color: var(--accent-deep); }
details.abschnitt .abschnitt-inhalt { padding: 0.1rem 0 1.1rem; }
details.abschnitt .abschnitt-inhalt > :first-child { margin-top: 0; }

/* Zweistufige Anmeldung: die Kennung aus Schritt 1 links, der Weg zurück
   rechts, darunter ein Strich. Die Zeile ist ein Flex-Container, weil der
   Rückweg in einem eigenen <form> steckt — ein Formular ist Blockinhalt und
   würde ein <p> sprengen. */
.konto-zeile {
    display: flex; align-items: baseline; justify-content: space-between;
    flex-wrap: wrap; gap: 0.6rem 1rem;
    padding-bottom: 0.9rem; margin: 0 0 1.3rem;
    border-bottom: 1px solid var(--line);
}
.konto-zeile strong {
    font-family: var(--mono); font-size: 0.95rem;
    overflow-wrap: anywhere; min-width: 0;
}
.konto-zeile form { margin: 0; }

/* Zwei gleichwertige Wege, getrennt durch ein Wort in der Linie. Kein
   Umschalter: Beide stehen da, und man nimmt den, der einem liegt. Der Strich
   entsteht aus den beiden Pseudoelementen, die sich den Platz teilen — so
   sitzt das Wort immer mittig, egal wie breit die Karte ist. */
.oder {
    display: flex; align-items: center; gap: 0.8rem;
    margin: 1.5rem 0 1.2rem;
    font-family: var(--mono); font-size: 0.72rem; font-weight: 600;
    text-transform: uppercase; letter-spacing: 0.1em;
    color: var(--muted);
}
.oder::before, .oder::after {
    content: ""; flex: 1; height: 1px; background: var(--line);
}

/* Die Zeile unter einer Anmeldemaske: Nebenwege, mittig, klein. */
.form-foot { text-align: center; margin-top: 1.2rem; }

/* Sprungmarken der Abschnittsüberschriften: Nach dem Absenden eines Formulars
   führt die Umleitung zurück zu dem Abschnitt, aus dem es kam. Ohne diesen
   Abstand klebte die Überschrift am oberen Fensterrand, und was darüber steht
   – die Rückmeldung zur eben gemachten Sache – wäre außer Sicht. */
h2[id] { scroll-margin-top: 5rem; }
.card.highlight { border-color: var(--accent); border-left-width: 3px; }
.card.center { text-align: center; margin: 3rem auto; max-width: 420px; }

/* Formulare */
label {
    display: block; font-weight: 500; font-size: 0.78rem;
    font-family: var(--mono); text-transform: uppercase; letter-spacing: 0.06em;
    color: var(--muted); margin: 0.7rem 0 0.3rem;
}
input[type="text"], input[type="password"], input[type="search"], input[type="url"],
input[type="date"], input[type="number"], select {
    width: 100%;
    padding: 0.6rem 0.75rem;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    font-family: var(--mono);
    font-size: 0.95rem;
    background: var(--paper);
    color: var(--ink);
}
input:focus, select:focus { outline: 2px solid var(--accent); outline-offset: -1px; border-color: var(--accent); }

/* Tastaturbedienung: Wer mit Tab durch die Seite geht, muss sehen, wo er ist.
   Bis hierher hatten nur Eingabefelder einen sichtbaren Fokus – Links, Knöpfe
   und Klappen nicht, was WCAG 2.4.7 verletzt. `:focus-visible` statt `:focus`,
   damit ein Mausklick keinen Rahmen hinterlässt. */
a:focus-visible, button:focus-visible, summary:focus-visible,
.btn:focus-visible, [tabindex]:focus-visible, label:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    border-radius: 3px;
}
/* Auf dunklen Bändern reicht der Akzent nicht immer – dort heller umranden */
.band-dark a:focus-visible, .band-dark button:focus-visible, .band-dark .btn:focus-visible {
    outline-color: var(--paper);
}

/* Sprunglink: erste Station beim Tabben, sonst unsichtbar. Ohne ihn muss
   sich jede Tastaturbedienung erst durch die Kopfzeile arbeiten. */
.skip {
    position: absolute; left: -9999px; top: 0; z-index: 100;
    /* Tinte auf Papier, nicht Akzent auf Papier: Der Akzent ist eine
       Signalfarbe und in hellen Themes zu hell für Text darauf – nachgemessen
       kam er auf 2,29:1, gefordert sind 4,5:1. Tinte und Papier haben den
       Kontrast per Definition, sonst wäre der Fließtext unlesbar. */
    padding: 0.6rem 1rem; background: var(--ink); color: var(--paper);
    font-family: var(--mono); text-decoration: none; border-radius: 0 0 var(--radius) 0;
}
.skip:focus { left: 0; }
/* Datumsfelder: iOS/Safari erzwingt sonst eine intrinsische Breite und
   sprengt schmale Layouts nach rechts */
input[type="date"] {
    min-width: 0;
    display: block;
    -webkit-appearance: none;
    appearance: none;
}
/* Flex-Kinder dürfen schrumpfen (sonst schieben intrinsische Breiten die Zeile auf) */
.short-row > *, .actions > *, .actions form.inline > * { min-width: 0; }
/* Kompakte Datumsfelder in Tabellen-Aktionen */
.actions input[type="date"] { width: auto; padding: 0.3rem 0.5rem; font-size: 0.85rem; }

/* Leere Vorschau (noch keine Eingabe) nicht als kaputtes Bild anzeigen */
.preview img:not([src]) { display: none; }

input[type="color"] { width: 100%; height: 2.4rem; padding: 0.15rem; border: 1px solid var(--line); border-radius: var(--radius); background: var(--paper); }
input[type="range"] { width: 100%; accent-color: var(--accent); }
.hp { position: absolute; left: -9999px; }

.short-row { display: flex; gap: 0.5rem; align-items: center; }
.short-row input[type="text"], .short-row input[type="search"], .short-row select { flex: 1; }
.prefix { color: var(--muted); white-space: nowrap; }
.grid-form { display: grid; gap: 0.4rem; }
.grid-form button { justify-self: start; margin-top: 0.6rem; }
.two-col { display: grid; grid-template-columns: 1fr 1fr; gap: 0.8rem; }

/* Buttons — sprechen Mono, sie sind Kommandos.
   Primär ist die einzige gefüllte Akzentfläche im Sichtfeld. */
.btn {
    display: inline-block;
    padding: 0.5rem 1.1rem;
    border: 1px solid var(--ink);
    border-radius: 5px;
    background: transparent;
    color: var(--ink);
    font-family: var(--mono);
    font-size: 0.9rem;
    font-weight: 600;
    cursor: pointer;
    text-decoration: none;
    white-space: nowrap;
}
.btn:hover { background: var(--accent-tint); text-decoration: none; }
.btn-primary { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.btn-primary:hover { background: var(--accent); filter: brightness(0.93); }
/* Mehrere Schaltflächen nebeneinander.
 *
 * Ohne diese Klasse landen sie in einem nackten <p>, und dort trennt sie nur
 * das Leerzeichen aus dem Zeilenumbruch – vier Pixel. Erzwingt die
 * Fensterbreite dann einen Umbruch, stehen sie fast bündig übereinander, weil
 * inline-block keinen vertikalen Abstand kennt. Genau das ist im Betrieb
 * aufgefallen.
 *
 * `gap` wirkt in beide Richtungen und löst damit beide Fälle auf einmal. */
.cta { display: flex; flex-wrap: wrap; gap: 0.7rem; align-items: center; }

/* Notnagel für den Fall, dass jemand .cta vergisst: Zwei Schaltflächen in
 * einem klassenlosen Absatz kleben sonst wieder aneinander. Richtig ist
 * .cta – das hier verhindert nur den auffälligsten Schaden. */
p:not([class]) > .btn + .btn { margin-left: 0.5rem; }

.btn-small { padding: 0.28rem 0.7rem; font-size: 0.8rem; }

/* Über die volle Breite – für Masken, in denen es genau einen Weg vorwärts
   gibt. Bisher stand dafür style="width:100%" an einzelnen Knöpfen. */
.btn-block { display: block; width: 100%; text-align: center; }

/* Ein Knopf, der wie ein Link aussieht. Für Wege, die technisch ein Formular
   brauchen (weil sie etwas ändern und deshalb einen CSRF-Nachweis tragen), im
   Text aber ein Link sein wollen: „Nicht du?" neben der Kennung. Ein <a> wäre
   hier falsch – es würde die Änderung per GET auslösen. */
.btn-link {
    border: 0; background: none; padding: 0; margin: 0;
    font: inherit; color: var(--accent-deep); cursor: pointer;
}
.btn-link:hover { text-decoration: underline; }
.btn-danger { border-color: var(--line); color: var(--muted); }
.btn-danger:hover { border-color: var(--ink); color: var(--ink); background: transparent; }

/* Meldungen — Erfolg trägt den Akzent; Fehler brauchen kein Rot,
   ihnen fehlt einfach der Akzent. */
.flash {
    padding: 0.7rem 1rem;
    border-radius: var(--radius);
    margin-bottom: 1rem;
    border: 1px solid;
    font-family: var(--mono);
    font-size: 0.9rem;
}
.flash-ok { background: var(--accent-tint); border-color: var(--accent); color: var(--accent-deep); }
.flash-err { background: var(--surface); border-color: var(--ink); color: var(--ink); }

/* Ergebnis + QR */
.result { text-align: center; }
.result .short-row { max-width: 480px; margin: 0 auto 1rem; }
.result input { font-weight: 700; text-align: center; color: var(--accent-deep); }
.qr-preview { display: flex; flex-direction: column; align-items: center; gap: 0.6rem; }
.qr-preview img { border: 1px solid var(--line); border-radius: var(--radius); background: #fff; }
.qr-links { display: flex; gap: 0.5rem; flex-wrap: wrap; justify-content: center; }

/* Tabellen — Kurz-Codes und Zahlen in Mono, Kopfzeile wie ein Terminal-Label */
.table-scroll { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; font-size: 0.92rem; font-variant-numeric: tabular-nums; }
th {
    text-align: left; color: var(--muted); font-weight: 500;
    font-family: var(--mono); font-size: 0.72rem;
    text-transform: uppercase; letter-spacing: 0.07em;
}
th, td { padding: 0.55rem 0.6rem; border-bottom: 1px solid var(--line); vertical-align: middle; }
tr:last-child td { border-bottom: 0; }
td a { font-family: var(--mono); }
.row-hl td { background: var(--accent-tint); }
/* Der selbstvergebene Name steht unter dem Code: Er hilft beim Wiederfinden,
   ist aber nicht die Kennung – deshalb kleiner und zurückgenommen. */
.link-title { display: block; color: var(--muted); font-size: 0.82rem; max-width: 22rem;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.url-cell { max-width: 320px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--muted); }
.actions { display: flex; gap: 0.35rem; align-items: center; flex-wrap: wrap; }
.actions form.inline { display: flex; gap: 0.35rem; margin: 0; }
.actions input[type="password"] { width: 150px; padding: 0.3rem 0.5rem; font-size: 0.85rem; }
.list-head { display: flex; justify-content: space-between; align-items: center; gap: 1rem; flex-wrap: wrap; }
.list-head form { margin: 0; }

/* Nutzerliste: eine Zeile je Konto zum Überfliegen, die Formulare erst beim
   Aufklappen. In einer Tabellenzelle standen sie zuvor nebeneinander und
   sprengten die Breite – vier Formulare passen dort schlicht nicht hinein. */
.user-list { display: grid; }
.user { border-bottom: 1px solid var(--line); }
.user:last-child { border-bottom: 0; }
.user > summary {
    display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.5rem 1rem;
    padding: 0.7rem 0.2rem; cursor: pointer; list-style: none;
}
.user > summary::-webkit-details-marker { display: none; }
/* Eigener Pfeil, damit er links steht und sich mitdreht */
.user > summary::before {
    content: "▸"; color: var(--muted); flex: none;
    transition: transform 0.12s ease; display: inline-block;
}
.user[open] > summary::before { transform: rotate(90deg); }
.user > summary:hover { background: var(--accent-tint); }
.user-name { flex: 1 1 14rem; min-width: 0; }
.user-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 0.35rem 0.7rem; }

.user-forms {
    display: grid; gap: 1.1rem;
    padding: 0.4rem 0 1.2rem 1.3rem;
    border-left: 2px solid var(--line);
    margin-left: 0.35rem;
}
.user-forms form { margin: 0; }
.user-forms label { margin-top: 0; }
.user-danger { display: flex; flex-wrap: wrap; gap: 0.5rem; padding-top: 0.4rem; border-top: 1px dashed var(--line); }
/* Auf schmalen Schirmen rutscht der Knopf unter das Feld, statt rechts aus dem
   Bild zu laufen – Datumsfelder bringen eine feste Mindestbreite mit, gegen die
   ein einzeiliges Layout nicht ankommt. */
.user-forms .short-row { flex-wrap: wrap; }
.user-forms .short-row > input { flex: 1 1 12rem; }

@media (prefers-reduced-motion: reduce) {
    .user > summary::before { transition: none; }
}

/* Badges */
.badge {
    display: inline-block; padding: 0.1rem 0.5rem; border-radius: 4px;
    font-family: var(--mono); font-size: 0.72rem; font-weight: 600;
    text-transform: uppercase; letter-spacing: 0.05em;
}
.badge-expired { background: transparent; color: var(--muted); border: 1px solid var(--line); }
.badge-quiet { background: transparent; color: var(--muted); border: 1px solid var(--line); }

/* Einstellungen */
.radio-group { display: grid; gap: 0.7rem; margin-bottom: 1rem; }
.radio {
    display: flex; gap: 0.7rem; align-items: flex-start;
    padding: 0.8rem; border: 1px solid var(--line); border-radius: var(--radius);
    font-family: inherit; font-weight: 400; font-size: 0.95rem;
    text-transform: none; letter-spacing: 0; color: var(--ink);
    cursor: pointer; margin: 0;
}
.radio:has(input:checked) { border-color: var(--accent); background: var(--accent-tint); }
.radio input { margin-top: 0.25rem; accent-color: var(--accent-deep); }

/* Statistik — Zahlen sind Inhalt: Mono, tabellarisch */
.stat-row { display: flex; gap: 1.5rem; flex-wrap: wrap; margin: 1rem 0 1.5rem; }
.stat { display: flex; flex-direction: column; }
.stat strong { font-family: var(--mono); font-size: 1.5rem; font-variant-numeric: tabular-nums; }
.stat span { color: var(--muted); font-family: var(--mono); font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.06em; }
.bars { display: block; }
.bar { fill: var(--accent); }
.bar-zero { fill: var(--line); }
.chart-label { fill: var(--muted); font-family: var(--mono); }

/* QR-Designer */
.designer { display: grid; grid-template-columns: 1fr 1fr; gap: 1.2rem; align-items: start; }
.designer .preview { text-align: center; position: sticky; top: 1rem; }
.designer .preview img { border: 1px solid var(--line); border-radius: var(--radius); background: #fff; max-width: 100%; height: auto; margin-bottom: 0.8rem; }
/* Auf der Untergrund-Bühne bringt das Bild keinen eigenen Grund mit –
   transparente Rahmen-Ecken liegen direkt auf Hell/Dunkel auf */
#preview-stage { line-height: 0; max-width: 100%; }
#preview-stage img { background: transparent; border: 0; border-radius: 0; margin-bottom: 0; }
.controls form { margin-top: 0.8rem; }
.muted { color: var(--muted); font-weight: 400; }
.small { font-size: 0.85rem; }

/* Ankreuzfelder (Rechte, Gruppenzuordnung) – normale Schreibweise statt
   des Versalien-Labels, das für Eingabefelder gilt */
.check {
    display: flex; align-items: center; gap: 0.45rem;
    font-family: inherit; text-transform: none; letter-spacing: 0;
    font-size: 0.9rem; color: var(--ink); font-weight: 400;
    margin: 0.15rem 0;
}
.check input { width: auto; margin: 0; accent-color: var(--accent); }
.check-row { display: flex; flex-wrap: wrap; gap: 0.15rem 1.1rem; }

/* Umschalter zwischen den QR-Typen */
.type-nav { display: flex; gap: 0.5rem; flex-wrap: wrap; justify-content: center; margin: 0 0 1.4rem; }
.type-nav .active { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.type-nav .active:hover { background: var(--accent); }

/* Rechte kommen in zwei Sorten: was ein Konto selbst darf (auf einer Instanz
   mit Tarifen ist das der Tarif) und was jemand für andere darf. Die
   Überschrift dazwischen soll auffallen, bevor jemand hakt. */
.perm-titel {
    width: 100%;
    margin: 0 0 0.1rem;
    font-size: 0.82rem;
    font-weight: 600;
}
.perm-hinweis { width: 100%; margin: 0 0 0.35rem; }
.perm-trenner {
    width: 100%;
    border: 0;
    border-top: 1px solid var(--line);
    margin: 0.9rem 0 0.7rem;
}
.tag {
    display: inline-block; font-family: var(--mono); font-size: 0.75rem;
    padding: 0.1rem 0.45rem; border: 1px solid var(--line);
    border-radius: 999px; color: var(--muted); background: var(--paper);
    white-space: nowrap;
}
.tag-on { border-color: var(--accent); color: var(--accent-deep); background: var(--accent-tint); }
/* Gesperrt: sichtbar, aber nicht alarmrot – eine Sperre ist ein Zustand,
   kein Fehler, und sie ist umkehrbar. */
.tag-off { border-style: dashed; color: var(--muted); }
/* Schlagworte sind anklickbar – als Filter unter dem Link und als Wolke über
   der Liste. Der Unterstrich bliebe sonst der einzige Hinweis darauf. */
.tag-row { display: flex; flex-wrap: wrap; gap: 0.25rem; margin: 0.25rem 0 0; }
a.tag { text-decoration: none; }
a.tag:hover { border-color: var(--accent); color: var(--accent-deep); text-decoration: none; }

/* Wiederholbare Feldzeilen (Ziele einer Link-in-Bio-Seite): Anzeigename,
   Adresse und ein Knopf zum Entfernen nebeneinander. */
.pair-rows { display: grid; gap: 0.4rem; }
.pair-row { display: grid; grid-template-columns: 1fr 1.6fr auto; gap: 0.4rem; align-items: center; }
.pair-row input { margin: 0; }
.row-tools { display: flex; gap: 0.2rem; }
.row-tools .btn { padding: 0.28rem 0.5rem; line-height: 1; }
@media (max-width: 560px) {
    .pair-row { grid-template-columns: 1fr auto; }
    .pair-row input:first-child { grid-column: 1 / -1; }
}

/* Link-in-Bio-Seite: eine Spalte, große Ziele, nichts sonst. Sie wird meist
   vom Handy aus einem QR-Code heraus geöffnet – der Daumen entscheidet. */
.bio { text-align: center; }
.bio-title { margin: 0 0 0.4rem; font-size: 1.5rem; }
.bio-text { color: var(--muted); margin: 0 0 1.4rem; }
.bio-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 0.6rem; }
.bio-link { display: block; width: 100%; padding: 0.8rem 1rem; white-space: normal; }

@media (max-width: 720px) {
    .designer { grid-template-columns: 1fr; }
    .designer .preview { position: static; }
    .hero h1 { font-size: 1.55rem; }
}

@media (prefers-reduced-motion: reduce) {
    * { transition: none !important; animation: none !important; }
}

/* Hinterlegte Passkeys: Name links, Entfernen rechts. Dieselbe Form wie die
   Liste der Zugangsschlüssel darunter. */
.key-list { list-style: none; margin: 0 0 0.8rem; padding: 0; display: flex; flex-direction: column; gap: 0.4rem; }
.key-list li {
    display: flex; align-items: center; justify-content: space-between; gap: 0.8rem;
    flex-wrap: wrap; padding: 0.55rem 0.7rem;
    border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface);
}
.key-list li > div { min-width: 0; }

/* Kampagnen-Baukasten: zugeklappt ein Einzeiler, aufgeklappt ein Feldblock.
   Abgesetzt, damit er nicht wie ein Pflichtfeld des Formulars aussieht. */
/* „Mehr Optionen"-Klappe im Anlege-Formular: dieselbe Zurückhaltung wie die
   Kampagnen-Klappe – der Hauptweg ist ein Feld und ein Knopf. */
details.mehr { margin-top: 0.7rem; }
details.mehr > summary { cursor: pointer; color: var(--muted); font-size: 0.92rem; }
details.mehr[open] > summary { margin-bottom: 0.4rem; color: var(--ink); }
details.mehr label { margin-top: 0.5rem; }

details.utm {
    margin: 0.2rem 0 0.4rem; padding: 0.55rem 0.7rem;
    border: 1px dashed var(--line); border-radius: var(--radius);
}
details.utm > summary { cursor: pointer; color: var(--muted); font-size: 0.92rem; }
details.utm[open] > summary { margin-bottom: 0.4rem; color: var(--ink); }
details.utm label { margin-top: 0.5rem; }

/* Auswahlliste der QR-Serie: eine Zeile je Link, ruhig und scrollbar, damit
   auch zweihundert Einträge die Seite nicht sprengen. */
.check-list {
    max-height: 26rem; overflow-y: auto; margin: 0.6rem 0 1rem;
    border: 1px solid var(--line); border-radius: var(--radius); background: var(--paper);
}
.check-list .check {
    display: flex; gap: 0.6rem; align-items: flex-start;
    padding: 0.45rem 0.7rem; border-bottom: 1px solid var(--line); margin: 0;
}
.check-list .check:last-child { border-bottom: 0; }
.check-list .check:hover { background: var(--accent-tint); }
.check-list .check > span { min-width: 0; }

/* Umschaltung zwischen Kurzlink und statischem Code. Zwei Schaltflächen statt
   Reitern: Der Wechsel lädt die Seite neu, weil sich beide Wege in mehr als
   nur einem Feld unterscheiden. */
.modus-wahl { display: flex; gap: 0.4rem; margin: 0 0 0.9rem; flex-wrap: wrap; }

/* Druckfarben: vier schmale Zahlenfelder nebeneinander */
details.druckfarben { margin: 0.4rem 0 0.8rem; padding: 0.55rem 0.7rem;
    border: 1px dashed var(--line); border-radius: var(--radius); }
details.druckfarben > summary { cursor: pointer; color: var(--muted); font-size: 0.92rem; }
details.druckfarben[open] > summary { margin-bottom: 0.4rem; color: var(--ink); }
.cmyk-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.4rem; margin-bottom: 0.5rem; }
.cmyk-row input { text-align: center; }

/* Verlaufszeile: Auswahl nimmt den Platz, der Farbwähler bleibt schmal.
   Ohne diese Regel drückt der Farbwähler die Auswahl auf Pfeilbreite. */
.grad-row select { flex: 1 1 auto; min-width: 0; }
.grad-row input[type="color"] { flex: 0 0 3.2rem; width: 3.2rem; }

/* Hinweise zur Lesbarkeit neben der Vorschau. Warnungen tragen einen kräftigen
   Balken, Anmerkungen einen ruhigen – wer nur hinschaut, soll den Unterschied
   sehen, ohne zu lesen. */
.lesbarkeit { margin: 0.8rem 0 0; text-align: left; }
.pruef {
    margin: 0 0 0.5rem; padding: 0.5rem 0.7rem; font-size: 0.88rem; line-height: 1.5;
    border-left: 3px solid var(--line); border-radius: 0 var(--radius) var(--radius) 0;
    background: var(--surface); color: var(--ink);
}
.pruef-warn { border-left-color: #B4571F; }
.pruef-info { border-left-color: var(--muted); color: var(--muted); }

/* Linkliste — eine Karte je Link statt einer Tabellenzeile. Links liest man
   nicht als Datensatz, sondern als Ding: vorn der Kurz-Code als Anfasser,
   darunter Ziel und Schlagworte, rechts die Klickzahl und die Werkzeuge. */
.link-list { display: grid; }
.link-row {
    display: flex; align-items: center; gap: 0.6rem 1.2rem; flex-wrap: wrap;
    padding: 0.85rem 0.6rem;
    border-bottom: 1px solid var(--line);
}
.link-row:last-child { border-bottom: 0; }
.link-row:hover { background: var(--accent-tint); }
.link-row.row-hl { background: var(--accent-tint); box-shadow: inset 3px 0 0 var(--accent); }
.link-main { flex: 1 1 14rem; min-width: 0; display: grid; gap: 0.15rem; }
.link-line { display: flex; align-items: center; gap: 0.45rem; flex-wrap: wrap; }
.link-code {
    font-family: var(--mono); font-weight: 700; font-size: 1.02rem;
    color: var(--accent-deep); text-decoration: none;
}
.link-code:hover { text-decoration: underline; }
/* Der Kopieren-Knopf drängt sich nicht vor – er erscheint mit der Zeile */
.btn-copy { opacity: 0; transition: opacity 0.1s ease; }
.link-row:hover .btn-copy, .btn-copy:focus-visible { opacity: 1; }
@media (hover: none) { .btn-copy { opacity: 1; } }
.link-ziel {
    color: var(--muted); font-size: 0.88rem;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.link-unter { display: flex; align-items: center; gap: 0.3rem 0.6rem; flex-wrap: wrap; margin-top: 0.1rem; }
.link-klicks {
    flex: none; text-align: center; text-decoration: none;
    min-width: 4.2rem; padding: 0.35rem 0.6rem;
    border: 1px solid var(--line); border-radius: var(--radius);
    background: var(--paper);
}
.link-klicks strong {
    display: block; font-family: var(--mono); font-size: 1.05rem;
    color: var(--ink); font-variant-numeric: tabular-nums;
}
.link-klicks span {
    display: block; color: var(--muted); font-size: 0.68rem;
    font-family: var(--mono); text-transform: uppercase; letter-spacing: 0.06em;
}
.link-klicks:hover { border-color: var(--accent); text-decoration: none; }
.link-klicks:hover strong { color: var(--accent-deep); }
.link-actions { flex: none; }
/* Schmale Sicht: Klicks und Werkzeuge rutschen unter den Linkblock */
@media (max-width: 640px) {
    .link-row { align-items: flex-start; }
    .link-main { flex-basis: 100%; }
}

/* Blättern unter der Linkliste: schlicht, mittig, mit den Filtern im Gepäck */
.blaettern { display: flex; gap: 0.8rem; align-items: center; justify-content: center; margin-top: 1rem; }

/* Woher die Klicks kamen: drei Merkmalslisten nebeneinander, auf schmalen
   Geräten untereinander. Die Balken sind Anteile, keine absoluten Breiten –
   sonst würde ein Link mit 10.000 Klicks anders aussehen als einer mit 10. */
.dim-grid { display: grid; gap: 1.4rem; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }
.dim-block h3 { margin: 0 0 0.5rem; font-size: 0.95rem; }
.dim-table { width: 100%; border-collapse: collapse; }
.dim-table td { padding: 0.18rem 0; border: 0; vertical-align: middle; }
.dim-name {
    font-size: 0.82rem; color: var(--ink); max-width: 8.5rem;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding-right: 0.5rem;
}
.dim-bar { width: 100%; }
.dim-bar span {
    display: block; height: 0.55rem; min-width: 2px; border-radius: 3px;
    background: var(--accent);
}
.dim-n {
    text-align: right; padding-left: 0.5rem; font-family: var(--mono);
    font-size: 0.8rem; color: var(--muted); font-variant-numeric: tabular-nums;
}

/* ---- Touch-Geräte: kein ungewolltes Hineinzoomen ----
   iOS Safari zoomt beim Antippen eines Eingabefelds automatisch hinein, wenn
   dessen Schrift kleiner als 16px ist – und bleibt danach gezoomt, womit die
   Seite plötzlich quer scrollt. Das sieht aus wie ein Layoutfehler, ist aber
   eine Schutzmaßnahme des Systems gegen zu kleine Schrift. Die richtige
   Antwort ist deshalb nicht, das Zoomen zu verbieten (das wäre ein
   Barrierefreiheitsverstoß, und Safari ignoriert es seit iOS 10 ohnehin),
   sondern die Felder groß genug zu machen.

   Nur auf grobem Zeigegerät: Auf dem Rechner bleiben die kompakten Größen. */
@media (pointer: coarse) {
    input[type="text"], input[type="password"], input[type="search"],
    input[type="url"], input[type="date"], input[type="number"],
    input[type="email"], input[type="tel"], select, textarea,
    .actions input[type="date"], .actions input[type="password"] {
        font-size: 16px;
    }
}

/* Doppeltipp auf Knöpfe und Links soll auslösen, nicht zoomen. Der
   Pinch-Zoom mit zwei Fingern bleibt davon unberührt. */
button, .btn, a, summary, label, input, select, textarea {
    touch-action: manipulation;
}

/* Weichen im Bearbeiten-Formular: Merkmal, Wert und Ziel in einer Zeile,
   auf schmalen Geräten untereinander. Das Ziel bekommt den Rest der Breite –
   es ist das Feld, das man lesen können muss. */
.weiche { display: flex; gap: 0.5rem; align-items: center; margin-bottom: 0.45rem; }
.weiche select { width: auto; flex: none; }
.weiche input[type="text"]:first-of-type { flex: none; width: 6.5rem; }
.weiche input[type="text"]:last-of-type { flex: 1 1 auto; min-width: 0; }
.weiche-n { flex: none; min-width: 2.5rem; text-align: right; font-family: var(--mono); }
@media (max-width: 560px) {
    .weiche { flex-wrap: wrap; }
    .weiche input[type="text"]:last-of-type { flex-basis: 100%; }
}

.ziel-sprache { margin: 0.5rem 0 0.3rem; }
.ziel-sprache input { width: 4.5rem; }
.ziel-sprache p { margin: 0.25rem 0 0; }

/* Das Demo-Band: unübersehbar, aber nicht schrill – es soll erklären, nicht warnen */
.demo-band {
    background: #FFF3D6; color: #5C4A12; border-bottom: 1px solid #E8D49A;
    padding: 0.55rem 1rem; text-align: center; font-size: 0.9rem;
}

/* Hilfe zu den Weichen: drei Spalten – Merkmal, erlaubte Werte, Erläuterung.
   Als Tabelle statt Fließtext, weil man hier nachschlägt und nicht liest. */
.weichen-hilfe { border-collapse: collapse; margin: 0.6rem 0 0.4rem; font-size: 0.85rem; }
.weichen-hilfe th,
.weichen-hilfe td { text-align: left; vertical-align: top; padding: 0.15rem 0.8rem 0.15rem 0; font-weight: normal; }
.weichen-hilfe th { white-space: nowrap; font-weight: 600; }
.weichen-hilfe code { font-size: 0.95em; }

@media (max-width: 560px) {
    /* Auf schmalen Schirmen ergibt die dritte Spalte zwei Buchstaben je Zeile */
    .weichen-hilfe, .weichen-hilfe tr, .weichen-hilfe th, .weichen-hilfe td { display: block; }
    .weichen-hilfe tr { margin-bottom: 0.5rem; }
    .weichen-hilfe th { margin-bottom: 0.1rem; }
}

/* Die Logo-Bibliothek: eine Karte je Logo, Bild links, Verwaltung rechts.
   Auf schmalen Schirmen untereinander – ein Logo neben einer Checkbox-Liste
   ergibt bei 380 Pixeln zwei unlesbare Spalten. */
.logo-liste { display: grid; gap: 1rem; }
.logo-karte { display: flex; gap: 1.2rem; align-items: flex-start; }
.logo-bild {
    flex: 0 0 120px;
    display: grid; place-items: center;
    min-height: 120px; padding: 0.6rem;
    /* Karomuster: Zeigt bei freigestellten Logos, wo die Transparenz sitzt */
    background-color: #fff;
    background-image:
        linear-gradient(45deg, rgb(0 0 0 / 0.06) 25%, transparent 25%, transparent 75%, rgb(0 0 0 / 0.06) 75%),
        linear-gradient(45deg, rgb(0 0 0 / 0.06) 25%, transparent 25%, transparent 75%, rgb(0 0 0 / 0.06) 75%);
    background-size: 16px 16px;
    background-position: 0 0, 8px 8px;
    border-radius: var(--radius, 6px);
}
.logo-bild img { max-width: 100%; max-height: 108px; height: auto; display: block; }
.logo-text { flex: 1 1 auto; min-width: 0; }
.logo-text h3 { margin: 0 0 0.2rem; overflow-wrap: anywhere; }
.logo-text details { margin: 0.6rem 0; }
.logo-text summary { cursor: pointer; font-size: 0.9rem; }
.logo-upload { margin-top: 1rem; }

@media (max-width: 560px) {
    .logo-karte { flex-direction: column; }
    .logo-bild { flex-basis: auto; align-self: flex-start; }
}

