/* Vemido Schriftbibliothek — Specimen-Page-Styling.
 * Kompakt, professionell, typografisch versiert.
 * Off-white BG, dunkelgrauer Text, einzelne dezente Akzentfarbe.
 * Keine Schatten, keine Rundungen ausser am Input — Fokus auf Type.
 */

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

/* CSS-Variablen fuer die zwei Color-Picker oben rechts + zwei abgeleitete
 * Werte fuer "Chrome"-Elemente (Trennlinien, Sekundaer-Text), die JS bei
 * BG-Aenderung passend zu der wahrgenommenen Helligkeit umschaltet:
 *   --tt-line-color      → Trennlinien (z.B. .tt-family-header border-bottom)
 *   --tt-secondary-text  → graue Texte (z.B. .tt-family-count)
 * Damit bleiben Linien + Sekundaer-Texte auf einem dunklen BG sichtbar
 * (hell), und auf einem hellen BG kontrastreich (dunkel). Defaults =
 * Off-white BG + dunkler Text wie vorher. */
:root {
    /* --tt-page-bg: #f7f7f5; */
    --tt-page-bg: #f9f8f5;
    --tt-specimen-fg: #1a1a1a;
    --tt-line-color: #1a1a1a;
    --tt-secondary-text: #333;
}
html {
    /* --tt-sticky-top: 215px; */
    --tt-sticky-top: 213px;
    font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
    color: #1a1a1a;
    background: var(--tt-page-bg);
    /* overflow-x: clip auf html (nicht hidden — sonst Sticky-Bruch).
     * Das Browser-Document-Scrollelement ist html, nicht body — wenn
     * wir nur body clippen, kann das html trotzdem eine horizontale
     * Scrollbar zeigen. Clip auf html schneidet die horizontale
     * Scrollbar im Document-Root sauber ab. */
    overflow-x: clip;
    /* Font-Smoothing per Default GARANTIERT AUS. Wir setzen die
     * Off-Werte explizit (statt nur den Default zu lassen) — sonst
     * koennte irgendein vererbtes/uebergeordnetes CSS oder ein
     * Browser-Style-Reset versehentlich Greyscale-AA aktivieren.
     * Resultat: System-Rendering, auf macOS subpixel-antialiased
     * (= LCD-Subpixel-AA, native OS-Defaults). */
    -webkit-font-smoothing: auto;
    -moz-osx-font-smoothing: auto;
    text-rendering: auto;
    font-feature-settings: normal;
}
/* Smoothing-Set per CSS-Klasse aktivierbar. Aktivieren via:
 *   - <html class="smooth"> im Quelltext / DevTools, oder
 *   - document.documentElement.classList.add('smooth') in JS, oder
 *   - Checkbox "Font-Smoothing" im Live-Tester-Controls.
 * Wirkung: Greyscale-AA + optimizeLegibility + explizite kern/liga. */
html.smooth {
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
    font-feature-settings: "kern", "liga";
}
body {
    font-size: 14px;
    line-height: 1.5;
    /* overflow-x: clip statt hidden — clip ist subtil anders:
     *   - hidden erzeugt einen NEUEN Formatting Context
     *     → bricht position: sticky auf descendant-Elementen
     *   - clip clippt visuell, behaelt aber den ursprünglichen
     *     Scroll-Container → Sticky bleibt funktional
     * Faengt horizontale Sub-Pixel-Ueberlaeufe von Sticky-Headern,
     * negativen Margins (.tt-family-header margin-left:-5px) etc.
     * ab — sonst zeigt Body manchmal eine 1-px-Scrollbar unten. */
    overflow-x: clip;
}

/* ── Page-Header (sticky) ────────────────────────────────────── */
.tt-page-header {
    /* padding: 24px 32px 16px; */
    /* padding: 12px 32px 16px; */
    /* padding: 12px 14px 16px; */
    padding: 14px 14px 15px;
    border-bottom: 1px solid #e5e5e5;
    position: sticky;
    top: 0;
    /* background: #f7f7f5; */
    background: #f9f8f5;
    z-index: 10;
    /* Flex-Layout: Titel-Block links, Sprachschalter rechts. */
    display: flex;
    align-items: center;
    gap: 16px;
}
.tt-page-header-text {
    flex: 1;
    min-width: 0;
    /* Logo links, Titel-Block (h1 + meta-Counter) rechts. Logo spannt
     * vertikal beide Titel-Zeilen, weil align-items:center die ganze
     * .tt-page-header-titles als Geschwister vertikal mittig zum Logo
     * setzt. */
    display: flex;
    align-items: center;
    gap: 14px;
}
.tt-page-header-titles {
    flex: 1;
    min-width: 0;
}
/* TUXS-Logo: 48x48, klickbarer Outlink zur Designer-Site.
 * flex-shrink:0 damit es bei wenig Platz nicht zerquetscht wird.
 * Link-Wrapper hat keinen Border/Outline. Hover-Effekt: 3D-Card-Flip
 * um die Y-Achse. Frueher war perspective:600px — bei dem kurzen
 * Abstand entsteht zur Halbrotation eine starke perspektivische
 * Verkuerzung ("Kaugummi"-Effekt). Mit 2000px ist die Perspektive
 * fast orthografisch: 3D-Tiefe bleibt, aber das SVG wird nicht mehr
 * sichtbar gequetscht. */
.tt-logo-link {
    display: inline-flex;
    flex-shrink: 0;
    line-height: 0;
    cursor: pointer;
    text-decoration: none;
    border: none;
    outline: none;
    perspective: 2000px;
}
.tt-logo-link:hover,
.tt-logo-link:focus,
.tt-logo-link:focus-visible,
.tt-logo-link:active {
    outline: none;
    border: none;
    text-decoration: none;
}
.tt-logo {
    width: 48px;
    height: 48px;
    display: block;
    transition: transform 0.55s cubic-bezier(0.4, 0.0, 0.2, 1);
    transform-style: preserve-3d;
}
.tt-logo-link:hover .tt-logo {
    transform: rotateY(180deg);
}
.tt-page-header h1 {
    font-size: 20px;
    font-weight: 600;
    letter-spacing: -0.01em;
    color: #1a1a1a;
}
.tt-meta {
    font-size: 12px;
    color: #666;
    /* margin-top: 2px; */
    margin-top: 0px;
    margin-bottom: 0px;
    font-variant-numeric: tabular-nums;
}
/* Auf sehr schmalen Viewports (< 480 px) den Familien/Schnitt-Counter
 * ausblenden — der schmale Header-Bereich hat sonst nicht genug Platz
 * fuer Logo + Titel + Counter + Sprachschalter. */
@media (max-width: 480px) {
    .tt-meta { display: none; }
    /* Engere line-height fuer den Page-Titel auf sehr schmalen Viewports —
     * verhindert grosse Lufthoehe wenn der Titel auf zwei Zeilen umbricht. */
    .tt-page-header h1 { line-height: 1.18; }
}

/* ── Sprach-Auswahl (Vemido-Frontend-Stil) ───────────────────────
 * 1:1 portiert von der Root-Directory-Variante in /css/styles.css
 * (Selektoren #lang-nav .form-select-sm). Pill-rund, hellgrau-
 * transparenter Hintergrund, KEIN Border, Globus-SVG als Caret rechts.
 * Funktional aktuell ohne Effekt — keine onchange-Logik. */
.tt-language-select {
    appearance: none;
    -webkit-appearance: none;
    flex-shrink: 0;
    /* Explizit rechtsbuendig — auch wenn .tt-page-header-text bereits
     * flex:1 ist und die Selectbox automatisch ans rechte Ende drueckt,
     * kommt margin-left:auto als zweiter Riegel: greift selbst wenn der
     * flex-Container-Modus durch eine spaetere Aenderung wegbrechen sollte. */
    margin-left: auto;
    padding: 0.35rem 2.5rem 0.38rem 1.2rem;
    border: none;
    border-radius: 999999px;
    background-color: rgba(229, 229, 229, 0.68);
    color: #111827;
    font: inherit;
    font-size: 14px;
    line-height: 1.4;
    cursor: pointer;
    box-shadow: none;
    /* Vemido-Globe-SVG (1:1 aus /css/styles.css Zeile 1029) — als
     * Dropdown-Caret rechts positioniert. */
    background-image: url("data:image/svg+xml,%3Csvg width='14' viewBox='0 0 20 20' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M1.66663 10.0001C1.66663 5.39771 5.39759 1.66675 9.99996 1.66675C14.6023 1.66675 18.3333 5.39771 18.3333 10.0001C18.3333 14.6025 14.6023 18.3334 9.99996 18.3334C5.39759 18.3334 1.66663 14.6025 1.66663 10.0001ZM9.99996 3.33341L9.99104 3.33342L9.99139 3.33479C9.95963 3.34286 9.80535 3.40924 9.58085 3.74399C9.36709 4.06271 9.15088 4.53605 8.95932 5.15837C8.63433 6.21414 8.40896 7.60422 8.34913 9.16675H11.6508C11.591 7.60422 11.3656 6.21414 11.0406 5.15837C10.849 4.53605 10.6328 4.06271 10.4191 3.74399C10.1946 3.40924 10.0403 3.34286 10.0085 3.33479L10.0089 3.33342L9.99996 3.33341ZM11.6508 10.8334H8.34913C8.41119 12.4543 8.65137 13.8887 8.99546 14.9565C9.19753 15.5837 9.42283 16.0447 9.63919 16.3394C9.74591 16.4848 9.83696 16.5711 9.90386 16.6188C9.93619 16.6418 9.96 16.6537 9.97486 16.6598C9.98916 16.6656 9.99635 16.6665 9.99788 16.6666L9.99996 16.6667H10.0021C10.0036 16.6666 10.0108 16.6656 10.0251 16.6598C10.0399 16.6537 10.0637 16.6418 10.0961 16.6188C10.163 16.5711 10.254 16.4848 10.3607 16.3394C10.5771 16.0447 10.8024 15.5837 11.0045 14.9565C11.3485 13.8887 11.5887 12.4543 11.6508 10.8334ZM6.68134 9.16675C6.74185 7.46317 6.98634 5.90276 7.36641 4.66805C7.46726 4.34041 7.57976 4.02878 7.70432 3.7392C5.40381 4.58296 3.69765 6.65849 3.38487 9.16675H6.68134ZM3.38487 10.8334H6.68134C6.74405 12.5989 7.00439 14.2116 7.40911 15.4677C7.49847 15.745 7.59673 16.0109 7.70431 16.261C5.40381 15.4172 3.69765 13.3417 3.38487 10.8334ZM13.3186 10.8334H16.615C16.3023 13.3417 14.5961 15.4172 12.2956 16.261C12.4032 16.0109 12.5015 15.745 12.5908 15.4677C12.9955 14.2116 13.2559 12.5989 13.3186 10.8334ZM16.615 9.16675H13.3186C13.2581 7.46317 13.0136 5.90276 12.6335 4.66805C12.5327 4.34041 12.4202 4.02878 12.2956 3.7392C14.5961 4.58296 16.3023 6.65849 16.615 9.16675Z' fill='%23111827'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 1rem center;
    background-size: 16px;
}
.tt-language-select:focus,
.tt-language-select:focus-visible {
    outline: none;
    border: none;
    box-shadow: none;
}

/* ── Live-Tester (sticky direkt unter Page-Header) ───────────── */
/* Die `top`-Werte fuer .tt-live-tester und .tt-sidebar werden von JS
 * dynamisch gesetzt, weil sie sich aus der GEMESSENEN Hoehe von
 * .tt-page-header bzw. .tt-live-tester ergeben — sonst desynchronisieren
 * sie sich bei Padding-Aenderungen und es entsteht ein scrollender
 * Mini-Spalt. Siehe specimen.js → updateStickyTops().
 * Fallback (CSS-Default) ist nur ein Anfangswert vor dem ersten JS-Run. */
.tt-live-tester {
    /* padding: 16px 32px 14px; */
    padding: 14px;
    border-bottom: 1px solid #e5e5e5;
    background: #fff;
    position: sticky;
    top: 76px; /* Fallback — JS misst echte Page-Header-Hoehe */
    z-index: 9;
    /* Verhindert dass die Section horizontal/vertikal scrollbar wird,
     * wenn z. B. der Live-Text zu lang ist oder die Slider-Row auf
     * schmalem Viewport breiter als der Container wird. */
    overflow: hidden;
}

/* Farb-Gruppe (BG + FG + Invert) — wird in .tt-controls als EIN Flex-Item
 * behandelt, sodass die drei Elemente bei Flex-Wrap immer als Einheit
 * gemeinsam in die naechste Zeile rutschen statt einzeln umzubrechen.
 * margin-left: auto schiebt die ganze Gruppe ans rechte Ende der Row. */
.tt-color-group {
    display: inline-flex;
    align-items: center;
    align-self: center;
    flex-shrink: 0;
    gap: 6px;
    margin-left: auto;
}
/* Innerhalb der Gruppe regelt der eigene gap: 6px die Abstaende —
 * die alten negativen margin-left-Workarounds (die den 32 px gap der
 * Eltern-Row kompensiert haben) werden hier explizit zurueckgesetzt. */
.tt-color-group .tt-color-swatch:has(#ttBgColor),
.tt-color-group .tt-color-swatch + .tt-color-swatch,
.tt-color-group .tt-color-invert {
    margin-left: 0;
}

/* Color-Swatches in der Controls-Row (BG + FG) — rechtsbuendig
 * mit margin-left: auto auf der ERSTEN Swatch (BG): das schiebt BG +
 * alles danach (FG) ans rechte Ende der Flex-Row.
 * 28x18 px kompakt, native color-input ueberlappt das Swatch-Rechteck
 * komplett (Click-Target = ganze Flaeche, gewaehlte Farbe = sichtbarer
 * Hintergrund). */
.tt-color-swatch {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* width: 28px; */
    width: 32px;
    height: 18px;
    border: 1px solid #d4d4d4;
    border-radius: 3px;
    cursor: pointer;
    overflow: hidden;
    flex-shrink: 0;
    align-self: center;
}
/* Bug-Fix: `:first-of-type` matchte den ersten <label> (= "Grösse"-Slider),
 * nicht den ersten .tt-color-swatch — weil :first-of-type tag-basiert ist,
 * nicht class-basiert. Stattdessen via :has() den BG-Swatch eindeutig
 * targeten (er enthaelt #ttBgColor). margin-left:auto schiebt ihn + den
 * danach folgenden FG-Swatch ans rechte Ende der Flex-Row. */
.tt-color-swatch:has(#ttBgColor) {
    margin-left: auto;
}
/* Engerer Abstand zwischen BG und FG (1/4 vom Parent gap:24px = 6 px).
 * Adjacent-sibling-Selector matcht das zweite .tt-color-swatch (FG),
 * negativer margin-left zieht es naeher an BG heran:
 *   gap(24) + margin-left(-18) = 6 px effektiver Abstand */
.tt-color-swatch + .tt-color-swatch {
    margin-left: -18px;
}
/* Invert-Button direkt nach den beiden Swatches — tauscht BG ↔ FG.
 * Gleiche Dimensionen wie die Swatches (32×18 px), gleicher Border-Stil.
 * Icon: zwei entgegengesetzte Pfeile, schwarz, currentColor-stroke. */
.tt-color-invert {
    appearance: none;
    flex-shrink: 0;
    width: 32px;
    height: 18px;
    /* Gleicher Engabstand wie zwischen BG und FG */
    margin-left: -18px;
    padding: 0;
    border: 1px solid #d4d4d4;
    border-radius: 3px;
    background: #fff;
    color: #1a1a1a;
    cursor: pointer;
    align-self: center;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: border-color 0.1s, background 0.1s;
}
.tt-color-invert svg {
    display: block;
    transition: transform 0.2s ease;
}
.tt-color-invert:hover {
    border-color: #1a1a1a;
    background: #f5f5f5;
}
.tt-color-invert:hover svg {
    transform: rotate(180deg); /* leichte Animation als Hover-Affordance */
}
.tt-color-invert:focus-visible {
    outline: 2px solid #1d4ed8;
    outline-offset: 1px;
}
.tt-color-swatch input[type="color"] {
    position: absolute;
    inset: -3px;
    width: calc(100% + 6px);
    height: calc(100% + 6px);
    padding: 0;
    border: 0;
    background: transparent;
    cursor: pointer;
}
.tt-color-label {
    position: relative;
    z-index: 1;
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    /* font-size: 8px; */
    /* color: rgba(255, 255, 255, 0.95); */
    /* text-shadow: 0 0 2px rgba(0, 0, 0, 0.6); */
    font-size: 10px;
    font-weight: 700;
    color: #000;
    text-shadow: none;
    letter-spacing: 0.05em;
    pointer-events: none;
}
/* Auf der FG-Swatch (dunkler Default) bleibt das Label weiss damit es
 * gegen den schwarzen Default-Wert lesbar ist. */
#ttFgColor + .tt-color-label {
    color: #fff;
}

/* Input + Reset-Button in einer Flex-Row — Button gleiche Hoehe wie Input.
 * flex-wrap fuer Mobile-Viewports: wenn die Row zu breit wird (Input +
 * Length-Select + ggf. Trigger + Counter + Reset), umbrechen statt
 * horizontal aus dem Viewport rauszuwachsen. */
.tt-input-row {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: stretch;
    /* margin-top: 20px; */
    margin-top: 0;
}
.tt-reset-all {
    appearance: none;
    flex-shrink: 0;
    height: 40px;
    padding: 0 14px;
    border: 1px solid #d4d4d4;
    border-radius: 4px;
    background: #fff;
    color: #1a1a1a;
    font: inherit;
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    transition: background 0.1s, border-color 0.1s, color 0.1s;
}

/* Specimen-Laenge-Auswahl (lang/mittel/kurz). Funktionalitaet kommt
 * spaeter — aktuell nur UI. Selbe Hoehe wie Input + Reset-Button damit
 * die Input-Row sauber fluchtet. */
.tt-sample-length {
    appearance: none;
    -webkit-appearance: none;
    flex-shrink: 0;
    height: 40px;
    padding: 0 28px 0 12px;
    border: 1px solid #d4d4d4;
    border-radius: 4px;
    background: #fff;
    color: #1a1a1a;
    font: inherit;
    font-size: 13px;
    cursor: pointer;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'><path fill='none' stroke='%23666' stroke-width='1.5' d='M1 1l4 4 4-4'/></svg>");
    background-repeat: no-repeat;
    background-position: right 10px center;
}
.tt-sample-length:focus {
    outline: 2px solid rgba(29, 78, 216, 0.3);
    outline-offset: 1px;
    border-color: #1d4ed8;
}
.tt-reset-all:hover {
    background: #1a1a1a;
    border-color: #1a1a1a;
    color: #fff;
}
.tt-reset-all:active {
    background: #000;
}

/* Counter-Button "X markiert" — erscheint nur wenn ≥1 Cut-Checkbox
 * angehakt ist. Klick → smooth-scroll zum ersten markierten Schnitt.
 * Brand-blau, damit der User die Auswahl sofort visuell wahrnimmt. */
.tt-scroll-selected {
    appearance: none;
    flex-shrink: 0;
    height: 40px;
    padding: 0 14px;
    border: 1px solid #1d4ed8;
    border-radius: 4px;
    background: #1d4ed8;
    color: #fff;
    font: inherit;
    font-size: 13px;
    font-weight: 600;
    cursor: pointer;
    transition: background 0.1s;
    font-variant-numeric: tabular-nums;
}
.tt-scroll-selected:hover {
    background: #1e40af;
    border-color: #1e40af;
}
.tt-scroll-selected #ttSelectedCount {
    margin-right: 4px;
}
#ttLiveText {
    flex: 1;
    min-width: 0;
    width: 100%;
    height: 40px;
    margin-top: 0;
    font-family: inherit;
    font-size: 18px;
    padding: 8px 12px;
    border: 1px solid #d4d4d4;
    border-radius: 4px;
    background: #fff;
    color: #1a1a1a;
}
#ttLiveText:focus {
    outline: none;
    border-color: #1d4ed8;
}
.tt-controls {
    display: flex;
    flex-wrap: wrap;
    /* row-gap kleiner als column-gap, damit auf umgebrochenen Zeilen
     * die Controls nicht unnoetig weit auseinander stehen. */
    gap: 16px 32px;
    margin-top: 12px;
}
.tt-controls label {
    display: inline-flex;
    align-items: center;
    /* gap: 8px; */
    /* color: #666; */
    gap: 10px;
    /* font-size: 12px; */
    font-size: 11px;
    color: #000;
    cursor: pointer;
}
.tt-ctrl-label {
    /* min-width: 100px; */
    min-width: auto;
    color: #1a1a1a;
    font-weight: 500;
}
/* Font-Smoothing-Checkbox in der Live-Tester-Controls-Reihe.
 * Base-Styling kommt von .tt-controls label (inline-flex, gap:10px,
 * font-size:12px). Hier nur die Checkbox-Groesse + Akzentfarbe
 * anpassen, damit sie nicht zu klein neben den Slidern wirkt. */
.tt-smoothing-toggle input[type="checkbox"] {
    width: 14px;
    height: 14px;
    margin: 0;
    accent-color: #1d4ed8;
    cursor: pointer;
}
.tt-controls input[type="range"] {
    /* width: 100px; */
    width: 80px;
    vertical-align: middle;
    accent-color: #1d4ed8;
}
/* Line-Height-Slider ausgeblendet — :has() erlaubt es das ganze
 * <label>-Wrapper-Element zu treffen ohne HTML-Aenderung. JS setzt
 * weiterhin line-height-Werte (default bleibt aktiv), nur die UI ist
 * versteckt. */
.tt-controls label:has(#ttLH) {
    display: none;
}
.tt-ctrl-out {
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 11px;
    /* color: #888; */
    color: #555;
    /* min-width: 48px; */
    /* width: 56px; */
    min-width: auto;
    width: auto;
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* ── Layout — Sidebar + Main ─────────────────────────────────── */
.tt-layout {
    display: grid;
    grid-template-columns: 240px 1fr;
}
.tt-sidebar {
    /* Frueher position: sticky — hat die Sidebar erst ab Scroll-Position
     * ~10 px ans top: 172 geklebt; davor scrollte sie sichtbar mit dem
     * Layout mit, was die ersten Eintraege schwer erreichbar machte.
     * Jetzt position: fixed → bleibt absolut an Ort und Stelle, unabhaengig
     * vom Scroll-State. Die Grid-Spalte (.tt-layout columns 240px 1fr)
     * bleibt in der Layout-Reservation — die fixed Sidebar overlayt dort.
     *
     * KEIN Padding mehr direkt — wird vom Inner-Wrapper getragen, damit
     * smooth-scrollbar einen sauberen Scroll-Host hat. Sonst rechnet die
     * Library Inner-Hoehe falsch und der Inhalt rutscht nach unten.
     */
    position: fixed;
    top: 172px;
    left: 0;
    width: 240px;
    height: calc(100vh - 172px);
    /* overflow-y wird vom Inner-Wrapper / smooth-scrollbar geregelt;
     * .tt-sidebar selbst muss hidden bleiben, damit nichts ueberschiesst. */
    overflow: hidden;
    /* border-right: 1px solid #e5e5e5; */
    /* background: #f7f7f5; */
    border-right: none;
    background: #f9f8f5;
    z-index: 5; /* unter Page-Header (10) und Live-Tester (9) */
    /* Flex-Column: Filter-Block (auto-Hoehe) sitzt fix oben, Scroll-Host
     * (.tt-sidebar-inner mit flex:1) nimmt den Rest. Damit beginnt der
     * Scrollbalken erst unterhalb der Filter und gehoert nur zur
     * Familien-Liste. */
    display: flex;
    flex-direction: column;
}
/* Inner-Wrapper — wird von smooth-scrollbar als Scroll-Host benutzt
 * (data-scrollbar="true"). Traegt die Padding, fuellt die Sidebar
 * komplett aus. box-sizing: border-box damit das Padding NICHT die
 * Breite addiert. */
.tt-sidebar-inner {
    /* Flex-Kind: nimmt den Platz unterhalb des Filter-Blocks. min-height:0
     * ist Pflicht, sonst waechst der Inner-Container am Inhalt entlang
     * statt zu scrollen. */
    flex: 1;
    min-height: 0;
    width: 100%;
    /* padding-top entfaellt — der Filter-Block oberhalb traegt jetzt
     * sein eigenes oberes Padding. Hier nur noch horizontal + bottom. */
    padding: 0 20px 20px 14px;
    box-sizing: border-box;
    border-right: 1px solid #cecece;
}
/* Sidebar-Footer: dritter Flex-Child unter .tt-sidebar-filters (oben)
 * und .tt-sidebar-inner (flex:1, scrollt). Hoehe 24px, fix am unteren
 * Sidebar-Rand, scrollt nicht mit der Family-Liste. Linksbuendig der
 * Impressum-Link, rechtsbuendig das rote Upload-Icon. */
.tt-sidebar-footer {
    flex: 0 0 36px;
    height: 36px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    /* padding: 0 20px 0 14px; */
    padding: 0 18px 0 14px;
    border-top: 1px solid #e5e5e5;
    /* Rechte Trennlinie identisch zu .tt-sidebar-inner — dadurch zieht
     * sich die vertikale Sidebar-Kante ueber die volle Hoehe durch. */
    border-right: 1px solid #cecece;
    background: inherit;
    box-sizing: border-box;
}
/* Wrapper fuer Impressum + @ + Hilfe — eine inline-Einheit, damit die
 * Links und das @-Zeichen sauber zentriert in der gleichen Linie sitzen. */
.tt-footer-links {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 11px;
    line-height: 1;
}
.tt-footer-sep {
    color: #999;
    font-size: 11px;
    line-height: 1;
}
.tt-imprint-link {
    font-size: 11px;
    color: #666;
    text-decoration: none;
    line-height: 1;
    /* Button-Reset — die Links sind jetzt <button>-Elemente */
    appearance: none;
    background: none;
    border: 0;
    padding: 0;
    cursor: pointer;
    font-family: inherit;
}
.tt-imprint-link:hover,
.tt-imprint-link:focus {
    color: #1a1a1a;
    text-decoration: underline;
}
body[data-tt-bg-dark="1"] .tt-imprint-link {
    color: #cecece;
}
body[data-tt-bg-dark="1"] .tt-imprint-link:hover,
body[data-tt-bg-dark="1"] .tt-imprint-link:focus {
    color: #cecece;
}

/* ================================================================
   INFO-MODAL (Impressum + Hilfe)
   Brutalbox-Stil — gleiche Schicht wie Glyphen-Vergleich-Modal.
   ================================================================ */
.tt-info-modal[hidden] { display: none; }
.tt-info-modal {
    position: fixed;
    inset: 0;
    z-index: 9999;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
}
.tt-info-modal-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.55);
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
    cursor: pointer;
    z-index: 0;
}
.tt-info-modal-content {
    position: relative;
    z-index: 1;
    background: #fff;
    border-radius: 12px;
    box-shadow: 0 24px 60px -12px rgba(0, 0, 0, 0.4);
    width: min(92vw, 720px);
    max-height: min(92vh, 680px);
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
/* Header: gleiches hellgraues Band wie im Glyphen-Vergleich */
.tt-info-modal-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 12px 20px;
    background: #f9f8f5;
    border-bottom: 1px solid #e5e5e5;
    flex-shrink: 0;
}
.tt-info-modal-title {
    font-size: 15px;
    font-weight: 600;
    color: #1a1a1a;
    margin: 0;
    line-height: 1.2;
}
/* Close-Button: gleicher Pill-Stil wie im Overlay-Modal */
.tt-info-modal-close {
    appearance: none;
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: #ebebeb;
    color: #1a1a1a;
    line-height: 0;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background 0.1s, color 0.1s;
}
.tt-info-modal-close:hover {
    background: #1a1a1a;
    color: #fff;
}
.tt-info-modal-close:focus-visible {
    outline: 2px solid #1d4ed8;
    outline-offset: 2px;
}
/* Scrollbarer Inhaltsbereich */
.tt-info-modal-body {
    flex: 1;
    overflow-y: auto;
    padding: 28px 32px;
    font-size: 14px;
    line-height: 1.65;
    color: #1a1a1a;
}
/* Impressum-spezifische Typografie */
.tt-imprint-body h3 {
    font-size: 14px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.03em;
    color: #777;
    margin: 20px 0 6px;
}
.tt-imprint-body h3:first-of-type { margin-top: 0; }
.tt-imprint-body p { margin: 0 0 4px; }
.tt-imprint-lead {
    font-size: 13px;
    color: #555;
    border-left: 3px solid #e5e5e5;
    padding-left: 12px;
    margin-bottom: 24px !important;
    line-height: 1.6;
}
.tt-imprint-footer {
    margin-top: 28px !important;
    font-size: 11px;
    color: #aaa;
}
.tt-imprint-link-inline {
    color: #1d4ed8;
    text-decoration: none;
}
.tt-imprint-link-inline:hover {
    text-decoration: underline;
}
/* Hilfe-Modal: mehr Luft vor den Abschnitts-Headlines */
.tt-help-body h3 { margin-top: 36px; }
.tt-help-body h3:first-of-type { margin-top: 0; }

/* Hilfe-Modal Bild-Placeholder (16:9, 240px breit) */
.tt-help-img {
    display: block;
    max-width: 480px;
    width: 100%;
    height: auto;
    border-radius: 4px;
    border: 1px solid #e5e5e5;
    margin: 10px 0 16px;
}
/* Upload-Icon-Button: roter Akzent (Customer-Webfont-Uploads sind im
 * UI generell rot markiert — Konsistenz mit der spaeter folgenden
 * Family-Markierung). 14x14 Icon, kein Padding, hover dunkler. */
.tt-upload-icon-btn {
    width: 14px;
    height: 14px;
    padding: 0;
    background: transparent;
    border: 0;
    color: #c00;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.tt-upload-icon-btn:hover,
.tt-upload-icon-btn:focus {
    /* Hover-Farbe: gleiches Blau wie Sidebar-Links (.tt-sidebar a:hover)
     * — visueller Konsistenz-Anker fuer interaktive Elemente. */
    color: #1d4ed8;
}
body[data-tt-bg-dark="1"] .tt-upload-icon-btn {
    color: #fefefe;
}

/* ── Upload-Modal ──────────────────────────────────────────────
 * Kompakte Lightbox vom Sidebar-Footer-Upload-Icon getriggert.
 * Layout-Patterns angelehnt an .tt-overlay-modal (Glyphen-Vergleich),
 * aber bewusst kleiner + simpler: Header + Info-Liste + Upload-Button.
 * Backdrop-Click und ESC schliessen analog. */
.tt-upload-modal[hidden] { display: none; }
.tt-upload-modal {
    position: fixed;
    inset: 0;
    z-index: 100; /* ueber Page-Header (10), Live-Tester (9), Sidebar (5) */
    display: flex;
    align-items: center;
    justify-content: center;
}
.tt-upload-modal-backdrop {
    position: absolute;
    inset: 0;
    background: rgba(20, 20, 20, 0.45);
    backdrop-filter: blur(2px);
    -webkit-backdrop-filter: blur(2px);
}
.tt-upload-modal-content {
    position: relative;
    background: #fff;
    border-radius: 8px;
    box-shadow: 0 12px 48px rgba(0, 0, 0, 0.25);
    width: min(90vw, 360px);
    padding: 20px 24px 24px;
    box-sizing: border-box;
    color: #1a1a1a;
}
.tt-upload-modal-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 14px;
}
.tt-upload-modal-title {
    font-size: 15px;
    font-weight: 600;
    margin: 0;
    color: #1a1a1a;
}
.tt-upload-modal-close {
    width: 22px;
    height: 22px;
    padding: 0;
    background: transparent;
    border: 0;
    color: #666;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}
.tt-upload-modal-close:hover,
.tt-upload-modal-close:focus {
    color: #1a1a1a;
}
.tt-upload-info-list {
    list-style: disc;
    padding: 0 0 0 20px;
    margin: 0 0 18px;
    font-size: 12px;
    line-height: 1.5;
    color: #333;
}
.tt-upload-info-list li {
    margin-bottom: 4px;
}
.tt-upload-info-list li:last-child {
    margin-bottom: 0;
}
/* Quota-/Timer-Anzeige wurde in die Bullet-Liste (Count + TTL) und
 * den Action-Button (Inline-Timer + Progress-Fill) verlegt. Das
 * .tt-upload-stats-Div traegt nur noch data-Attribute fuer JS und ist
 * via [hidden]-Attribut komplett unsichtbar. */
.tt-upload-stats[hidden] { display: none; }

/* Limit-erreicht-Highlight in der Bullet-Liste: fett, um die Aufmerk-
 * samkeit auf "kein weiterer Upload moeglich" zu lenken. */
.tt-upload-info-list li.is-limit-full {
    font-weight: 600;
    color: #1a1a1a;
}

/* Primaer-Aktion = Upload-Button + Progress-Bar in einem.
 * Layout: <label> ist Position-Container; der Fill (.tt-upload-quota-fill)
 * sitzt absolut darunter und wird via JS auf (used/limit)*100% gesetzt;
 * Icon + Label bilden den Vordergrund (.tt-upload-action-content) und
 * sitzen z-index 1 ueber dem Fill. */
.tt-upload-action-btn {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 40px;
    padding: 0 16px;
    background: #c00;
    color: #fff;
    border: 0;
    border-radius: 6px;
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    transition: background 0.1s;
    box-sizing: border-box;
    overflow: hidden;
}
.tt-upload-action-btn:hover,
.tt-upload-action-btn:focus-within {
    background: #900;
}
.tt-upload-action-content {
    position: relative;
    z-index: 1;
    display: inline-flex;
    align-items: center;
    gap: 8px;
}
/* Progress-Fill: anthrazitfarbene Layer, wandert von links nach rechts.
 * Bei 10/10 deckt er den ganzen Button ab → Button wirkt deaktiviert. */
.tt-upload-quota-fill {
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
    width: 0%;
    background: #2e2e30; /* anthrazit */
    transition: width 0.25s ease;
    z-index: 0;
}
/* Voll-Zustand: Button-Background komplett anthrazit, Hover-Effekt aus,
 * Klick deaktiviert (pointer-events: none auf dem Label-Wrapper, file-
 * Input bleibt im DOM aber unzugaenglich da der Klick nicht durchkommt). */
.tt-upload-action-btn[aria-disabled="true"] {
    background: #2e2e30;
    cursor: not-allowed;
    pointer-events: none;
}
.tt-upload-action-btn[aria-disabled="true"]:hover,
.tt-upload-action-btn[aria-disabled="true"]:focus-within {
    background: #2e2e30;
}
.tt-upload-action-btn[aria-busy="true"] {
    cursor: wait;
}
/* Sichtbarer Focus-Ring am Action-Button: das Label umschliesst den
 * visually-hidden file-input, der Tab-Focus landet auf dem Input —
 * via :focus-within projizieren wir den Ring auf das visuelle Label. */
.tt-upload-action-btn:focus-within {
    outline: 2px solid #1d4ed8;
    outline-offset: 2px;
}

/* Ghost-Button "Uploads loeschen" — sekundaere Aktion unter dem
 * primaeren Action-Button. Transparent mit Border, hover wechselt zu
 * roter Akzentfarbe (Konsistenz mit dem Upload-Trigger-Icon und der
 * Family-Markierung in der Sidebar). Nur sichtbar wenn aktuell Files
 * auf Disk liegen — sonst via [hidden] verborgen. */
.tt-upload-reset-btn[hidden] { display: none; }
.tt-upload-reset-btn {
    margin-top: 8px;
    width: 100%;
    height: 32px;
    padding: 0 16px;
    background: transparent;
    color: #666;
    border: 1px solid #d4d4d4;
    border-radius: 6px;
    font-size: 12px;
    font-weight: 400;
    cursor: pointer;
    transition: background 0.1s, color 0.1s, border-color 0.1s;
    box-sizing: border-box;
}
.tt-upload-reset-btn:hover,
.tt-upload-reset-btn:focus-visible {
    background: #fff5f5;
    color: #c00;
    border-color: #c00;
}
.tt-upload-reset-btn:focus-visible {
    outline: 2px solid #1d4ed8;
    outline-offset: 2px;
}
/* sr-only / visually-hidden: aus dem visuellen Layout raus, aber im
 * Tab-Order + Screen-Reader-zugaenglich. Wird vom File-Input innerhalb
 * der Action-Btn-Label-Wrapper genutzt. */
.tt-visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
}
/* (Inline-Timer im Action-Button entfernt — redundant zur TTL-Bullet
 * in der Liste, die ohnehin "Automatische Loeschung in Xh Ymin" zeigt.) */

/* Status-Bereich nach dem Upload-Button: Erfolgs- und Fehler-Listen. */
.tt-upload-status {
    margin-top: 12px;
    font-size: 11px;
    line-height: 1.5;
}
.tt-upload-status:empty { display: none; }
.tt-upload-status .tt-upload-success {
    color: #060;
    margin-bottom: 4px;
}
.tt-upload-status .tt-upload-error-list {
    list-style: disc;
    padding-left: 18px;
    margin: 0;
    color: #b00020;
}
.tt-upload-status .tt-upload-error-list li {
    margin-bottom: 2px;
}
.tt-upload-status .tt-upload-error-name {
    color: #333;
}

.tt-sidebar nav ol {
    list-style: none;
    counter-reset: fam;
    font-size: 13px;
}
.tt-sidebar li {
    counter-increment: fam;
    padding: 4px 0;
    /* line-height: 1.3; */
    line-height: 1.25;
    display: flex;
    align-items: baseline;
    gap: 8px;
}
.tt-sidebar li::before {
    content: counter(fam, decimal-leading-zero);
    font-variant-numeric: tabular-nums;
    /* color: #aaa; */
    color: #777;
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 11px;
    flex-shrink: 0;
}
.tt-sidebar a {
    /* color: #1a1a1a; */
    color: #111;
    text-decoration: none;
    flex: 1;
    transition: color 0.1s;
    min-width: 0;
    overflow: hidden;
    /* text-overflow: ellipsis; */
    white-space: nowrap;
}
.tt-sidebar a:hover,
.tt-sidebar a:focus {
    color: #1d4ed8;
}
.tt-cut-count {
    /* color: #aaa; */
    color: #777;
    font-size: 11px;
    font-variant-numeric: tabular-nums;
    flex-shrink: 0;
}

/* ── Dark-BG-Mode fuer die Sidebar ──────────────────────────────
 * Wenn die gewaehlte Hintergrundfarbe eine Luminanz < 128 (CCIR 601) hat,
 * setzt JS body[data-tt-bg-dark="1"] und CSS schaltet die Sidebar plus
 * ihre Bestandteile auf einen dunklen Look um, damit alles lesbar bleibt.
 * Threshold + Mechanik identisch zur --tt-line-color / --tt-secondary-
 * text-Logik (siehe applyBg in specimen.js). */
body[data-tt-bg-dark="1"] .tt-sidebar,
body[data-tt-bg-dark="1"] .tt-page-header {
    background: #444;
}
body[data-tt-bg-dark="1"] .tt-sidebar {
    /* border-right: 1px solid #e5e5e5;  → im Dark-Mode dunkler */
    border-right: 1px solid #444;
}
/* Im Dark-Mode die rechten Trennlinien an Filter-Block + Scroll-Host
 * ausblenden — auf dunklem Hintergrund wirken die hellen #cecece-Linien
 * zu kontrastreich/stoerend. */
body[data-tt-bg-dark="1"] .tt-sidebar-filters,
body[data-tt-bg-dark="1"] .tt-sidebar-inner,
body[data-tt-bg-dark="1"] .tt-sidebar-footer {
    border-right: none;
}
body[data-tt-bg-dark="1"] .tt-sidebar-footer {
    border-top: none;
}
body[data-tt-bg-dark="1"] .tt-sidebar a {
    color: #fefefe;
}
body[data-tt-bg-dark="1"] .tt-open-source-toggle,
body[data-tt-bg-dark="1"] .tt-licensable-toggle,
body[data-tt-bg-dark="1"] .tt-brand-toggle,
body[data-tt-bg-dark="1"] .tt-italic-toggle {
    color: #fefefe;
}
/* "Weitere Filter"-Accordion im Dark-Mode — bleibt durchgehend dunkel:
 *   - Summary-Text + Chevron immer hell, sowohl zu als auch offen
 *   - Im offenen Zustand: leicht aufgehellter Hintergrund (subtil
 *     dunkler als reines #444, aber heller als das Surrounding) statt
 *     weisser Block, der auf dunkler Sidebar zu krass raussticht
 *   - Toggle-Texte bleiben hell (greifen aus der dark-mode-Regel oben) */
body[data-tt-bg-dark="1"] .tt-more-filters > summary {
    color: #fefefe;
}
body[data-tt-bg-dark="1"] .tt-more-filters > summary::after {
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'><path fill='none' stroke='%23cecece' stroke-width='1.5' d='M1 1l4 4 4-4'/></svg>");
}
body[data-tt-bg-dark="1"] .tt-more-filters[open] {
    /* Subtile Aufhellung gegen Sidebar-#444, ohne Helligkeits-Sprung */
    background-color: #555;
}
body[data-tt-bg-dark="1"] .tt-cut-count {
    color: #cecece;
}
body[data-tt-bg-dark="1"] .tt-sidebar li::before {
    color: #cecece;
}
body[data-tt-bg-dark="1"] .tt-filter-select {
    /* background-color statt background-shorthand — sonst wischt der
     * Shorthand auch die background-image (Chevron-SVG) weg. */
    background-color: #cecece;
}
/* Family-Action-Buttons (z.B. "+" / Edit-Toggle in der Familien-Header-
 * Row): im Dark-Mode auf hellgrauen Hintergrund/Border umstellen, damit
 * sie auf dunkler Page-BG ueberhaupt sichtbar bleiben. */
body[data-tt-bg-dark="1"] .tt-family-action-btn {
    border-color: #ccc;
    background: #ccc;
}
/* Family-Info-Panel (aufklappbarer Block unter dem Family-Header): im
 * Dark-Mode hellerer Hintergrund + passender Border, damit das Panel
 * sich gegen die dunkle Page-BG abhebt. */
body[data-tt-bg-dark="1"] .tt-family-info-panel {
    background: #eee;
    border-color: #eee;
}
/* Page-Header + Live-Tester + deren Inhalte */
body[data-tt-bg-dark="1"] .tt-page-header {
    border-bottom: 1px solid #444;
}
body[data-tt-bg-dark="1"] .tt-page-header h1 {
    color: #fefefe;
}
body[data-tt-bg-dark="1"] .tt-meta {
    color: #cecece;
}
body[data-tt-bg-dark="1"] .tt-edit-mode-toggle {
    color: #cecece;
}
body[data-tt-bg-dark="1"] .tt-live-tester {
    border-bottom: 1px solid #565656;
    background: #444;
}
body[data-tt-bg-dark="1"] .tt-ctrl-label,
body[data-tt-bg-dark="1"] .tt-ctrl-out {
    color: #cecece;
}
body[data-tt-bg-dark="1"] #ttLiveText,
body[data-tt-bg-dark="1"] .tt-sample-length,
body[data-tt-bg-dark="1"] .tt-reset-all {
    border: 1px solid #cecece;
    /* background-color statt background-shorthand — wichtig fuer
     * .tt-sample-length, das eine Chevron-SVG als background-image
     * fuehrt; der Shorthand wuerde die wegwischen. */
    background-color: #cecece;
}

/* Per-Cut-Checkbox sitzt LINKS am Anfang der .tt-cut-header (vor dem
 * Filename) — kein margin-left:auto noetig, sie erbt einfach ihren
 * Platz aus der Flex-Reihenfolge. Wenn 1+ Cuts angehakt sind und der
 * Counter-Button "X anzeigen" gedrueckt wird: nur diese werden gezeigt,
 * alle anderen Cuts ausgeblendet. Familien ohne markierten Cut werden
 * ebenfalls versteckt (Klasse `.has-visible-cut` wird vom JS gesetzt). */
.tt-cut-check {
    flex-shrink: 0;
    width: 16px;
    height: 16px;
    cursor: pointer;
    accent-color: #1d4ed8;
    align-self: center;
    /* Rechtsbuendig: order:1 schiebt die Checkbox visuell ans Ende
     * des Flex-Containers (DOM-Order bleibt unveraendert — wichtig
     * fuer Tastatur-Navigation und Screenreader, die DOM-Order
     * folgen). margin-left:auto fuellt den Raum davor, sodass
     * Filename / Cut-Name / Italic-Pill linksbuendig stehen. */
    order: 1;
    margin-left: auto;
    margin-right: 6px;
}
/* Auf grossen Viewports (>1440px) wandert die Checkbox nach links
 * (vor den Cut-Namen) — auf breiten Layouts ist das natuerlicher,
 * weil rechts ohnehin viel leerer Raum bleibt. DOM-Order ist davon
 * unbetroffen (Tastatur-Tab/Screenreader). */
@media (min-width: 1441px) {
    .tt-cut-check {
        order: 0;
        margin-left: 0;
        margin-right: 0;
    }
}
/* Keine Hintergrund-Hinterlegung fuer markierte Cuts — die Checkbox
 * selbst (Haeckchen) ist visuelle Markierung genug. Der Filter-Counter-
 * Button "X anzeigen" zeigt zudem global wie viele markiert sind. */

/* Filter-Mode: wird NUR durch Klick auf den Counter-Button aktiviert
 * (nicht automatisch beim Ankreuzen — sonst verschwinden waehrend des
 * Sammelns die noch nicht markierten Cuts). Wenn body[data-tt-filter-
 * active="1"]:
 *   - Cuts ohne :checked-Box → ausblenden
 *   - Familien ohne mindestens einen markierten Cut → ausblenden */
body[data-tt-filter-active="1"] .tt-cut:not(:has(.tt-cut-check:checked)) {
    display: none;
}
body[data-tt-filter-active="1"] .tt-family:not(.has-visible-cut) {
    display: none;
}

/* Counter-Button im Filter-Mode visuell anders, damit der User sieht
 * "Aha, der Filter ist aktiv, klick mich um ihn aufzuheben". */
body[data-tt-filter-active="1"] .tt-scroll-selected {
    background: #fff;
    color: #1d4ed8;
}
body[data-tt-filter-active="1"] .tt-scroll-selected:hover {
    background: #1d4ed8;
    color: #fff;
}

.tt-main {
    /* Explizite Grid-Column-Zuweisung: weil .tt-sidebar position: fixed
     * ist, faellt sie aus dem Grid-Flow raus — ohne diese Zeile wuerde
     * .tt-main automatisch in die erste Spalte rutschen (240px breit) und
     * der Content stark gequetscht werden. */
    grid-column: 2;
    padding: 32px;
    /* max-width: 1200px; */
    max-width: 1380px;
    min-width: 0;
    /* Clip statt hidden: verhindert dass zu lange Display-Headlines (z.B.
     * "Boxkämpfer" bei 96px / 64px Mobile) die Spalte und damit den Body
     * horizontal aufblasen — ohne einen Scroll-Kontext aufzumachen, der
     * position: sticky von .tt-live-tester / .tt-page-header brechen
     * wuerde. So bleibt der Live-Tester immer in voller Viewport-Breite
     * sichtbar und das Eingabefeld wird nicht angeschnitten. */
    overflow-x: clip;
}

/* ── Family-Section ──────────────────────────────────────────── */
.tt-family {
    margin-bottom: 80px;
    scroll-margin-top: 200px; /* Sticky-Header-Offset bei Anchor-Jump */
}
.tt-family-header {
    display: flex;
    align-items: baseline;
    gap: 16px;
    padding-top: 10px;
    padding-bottom: 10px;
    /* margin-bottom: 28px; */
    margin-bottom: 6px;
    /* Trennlinie via Pseudo-Element 12px ueber der Headerunterkante.
     * Ehemaliger border-bottom: 2px solid <line-color> hing direkt
     * unten am Header — beim Sticky-Scrollen klebte die Linie an dem
     * darunter durchziehenden Text. Mit absolutem Bottom:12px liegt
     * die Linie innerhalb des Headers, mit 12px Abstand zur unteren
     * Kante (= sichtbarer Atemraum unter der Linie, gefuellt vom
     * Header-Background, wenn Cuts darunter durchscrollen). */
    position: relative;  /* Containing-Block fuer ::after-Linie. Wird
                            auf >=768px durch position:sticky in der
                            Media-Query ueberschrieben — sticky liefert
                            ebenfalls einen Positioning-Context. */
}
.tt-family-header::after {
    content: "";
    position: absolute;
    left: 3px;
    right: -1px;
    bottom: 0;
    height: 2px;
    background: var(--tt-line-color, #1a1a1a);
    pointer-events: none;
}
/* Sticky Family-Header — nur ab 768px Viewport. Bleibt am oberen
 * Specimen-Rand kleben (16px unter dem Live-Tester, Wert wird in JS
 * via --tt-sticky-top gesetzt) bis die eigene .tt-family-Section
 * unten endet — dann scrollt der Header mit raus, der naechste
 * Family-Header ruckt sticky an seinen Platz. Background nicht-
 * transparent, damit Cuts darunter nicht durchscheinen.
 * z-index: 8 < 9 (live-tester) < 10 (page-header). Auf Mobile
 * (<768px) bleibt der Header position: static (Default), kein
 * Sticky-Verhalten — Mobile braucht den Platz fuer den Inhalt. */
@media (min-width: 768px) {
    .tt-family-header {
        position: sticky;
        top: var(--tt-sticky-top, 200px);
        background: #f9f8f5ee;
        z-index: 8;
        /* Header zieht 5px nach links und kompensiert per padding —
         * deckt damit das negative margin-left:-0.05em am .tt-display
         * im Sticky-Modus mit Header-BG ab (sonst wuerde der Display-
         * Glyph beim Vorbeiscrollen unter dem Header an dessen linker
         * Kante hervorlugen). */
        margin-left: -6px;
        padding-left: 6px;
        backdrop-filter: blur(4px);
    }
    /* Release-Klasse: wird via IntersectionObserver in specimen.js
     * gesetzt, sobald die naechste Family-Header ~100px in den
     * Viewport eintritt. Der vorherige Header verliert seine Sticky-
     * Anker und scrollt natuerlich mit dem Fluss raus — die neue
     * Family-Header rueckt sticky an seinen Platz.
     * WICHTIG: position: relative (NICHT static), damit das absolut
     * positionierte ::after-Element (Trennlinie am Header-Bottom)
     * weiterhin den Family-Header als Containing-Block nutzt. Bei
     * static wuerde die Linie auf den naechsten positionierten
     * Vorfahren fallen — ggf. den Initial-Containing-Block, wo sie
     * als geisterhafte horizontale Linie irgendwo mitten im Viewport
     * stehen bleibt. */
    .tt-family.is-header-released .tt-family-header {
        position: relative;
        /* WICHTIG: top: auto resetten — der sticky-Default `top: var(--tt-sticky-top)`
         * wuerde bei position: relative als positiver Offset ALSO der Header
         * nach unten verschieben (~500px). Bei static wird `top` ignoriert,
         * bei relative greift es. Deshalb explizit auf auto/0 setzen. */
        top: auto;
    }
    /* Dark-Mode: sticky Background = Seitenhintergrund (vom Color-Picker
     * via --tt-page-bg gesetzt), volldeckend ohne Alpha. backdrop-filter
     * entfaellt — auf dunklem Hintergrund kein Sinn fuer halbtransparenten
     * Blur, und der User-Farbwunsch soll exakt getroffen werden. */
    body[data-tt-bg-dark="1"] .tt-family-header {
        background: var(--tt-page-bg);
        backdrop-filter: none;
    }
}
.tt-family-header h2 {
    font-size: 36px;
    font-weight: 700;
    line-height: 1.1;
    letter-spacing: -0.02em;
    color: var(--tt-specimen-fg, #1a1a1a);
}
.tt-family-count {
    font-size: 12px;
    /* color: #666; */
    color: var(--tt-secondary-text, #333);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* ── Family-Action-Button (Platzhalter) ────────────────────────
 * Kreisrunder Mini-Button rechts in der .tt-family-header. Aktuell ohne
 * Funktion — Hook fuer eine kuenftige Aktion (z.B. Family-Detail-View,
 * Source-Picker, etc.). 16x16 px, weiss, dezenter 1-px-Border, Hover-
 * State leicht abgesetzt. */
.tt-family-action-btn {
    appearance: none;
    margin-left: auto;
    margin-right: -1px;
    margin-top: 3px;
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    padding: 0;
    border: 1px solid #d4d4d4;
    border-radius: 50%;
    background: #fff;
    color: #1a1a1a; /* SVG erbt currentColor */
    cursor: pointer;
    align-self: center;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: border-color 0.1s, background 0.1s;
}
.tt-family-action-btn svg {
    display: block;
    transition: transform 0.2s ease;
}
.tt-family-action-btn:hover {
    border-color: #1a1a1a;
    background: #f5f5f5;
}
.tt-family-action-btn:hover svg {
    transform: rotate(-90deg); /* 90° gegen Uhrzeigersinn */
}
.tt-family-action-btn[aria-expanded="true"] svg {
    transform: rotate(45deg); /* + wird zu × */
}
.tt-family-action-btn[aria-expanded="true"]:hover svg {
    transform: rotate(45deg); /* offen-State gewinnt vor Hover */
}
.tt-family-action-btn:focus-visible {
    outline: 2px solid #1d4ed8;
    outline-offset: 2px;
}
/* Empty-State im Read-Mode: Button verstecken. Im Edit-Mode bleibt er
 * sichtbar damit der User Inhalt anlegen kann. */
body:not([data-tt-edit-mode="1"]) .tt-family-action-btn.is-empty {
    display: none;
}

/* ── Family-Info-Panel ──────────────────────────────────────────
 * Klappt unter dem Family-Header auf. hidden-Attribut wird vom JS
 * getoggled. Inhalt: Info-Text + URL-Buttons + Edit-Toolbar (nur DE+Edit-Mode). */
.tt-family-info-panel {
    padding: 14px 16px;
    background: #fafaf8;
    border: 1px solid #e5e5e5;
    border-radius: 4px;
    font-family: system-ui, -apple-system, sans-serif;
    font-size: 14px;
    line-height: 1.55;
    color: #1a1a1a;
    /* Im Flex-Wrapper nimmt das Panel den verfuegbaren Platz; max-width
     * begrenzt es auf praktikable Lese-Breite. Frueher 720px fix —
     * jetzt 720px Cap aber flex-shrink/grow-faehig. min-width 280px
     * verhindert dass das Panel auf engem Viewport zu schmal wird. */
    max-width: 720px;
    min-width: 280px;
    flex: 1 1 auto;
    position: relative;
}
/* Wrapper wird via [hidden] auf dem Container ein-/ausgeblendet
 * (gemeinsam mit der Gallery) — siehe .tt-family-info-row-wrapper. */
.tt-family-info-row-wrapper {
    margin-top: 12px;
    display: flex;
    gap: 16px;
    align-items: stretch;   /* Gallery streckt sich auf Panel-Hoehe */
}
.tt-family-info-row-wrapper[hidden] {
    display: none;
}
/* Wenn der Wrapper per JS geoeffnet wird, scrollt specimen.js ihn
 * mit scrollIntoView in den sichtbaren Bereich. scroll-margin-top
 * sorgt dafuer dass er UNTERHALB des sticky Family-Headers landet,
 * nicht VON ihm verdeckt. Wert = sticky-Top (Live-Tester-Bottom) +
 * Header-Hoehe (ca. 90px) + 8px Atemraum. */
.tt-family-info-row-wrapper {
    scroll-margin-top: calc(var(--tt-sticky-top, 200px) + 98px);
}
@media (max-width: 767px) {
    .tt-family-info-row-wrapper {
        display: block;
    }
    .tt-family-info-row-wrapper[hidden] {
        display: none;
    }
}
/* Edit-Hint (nur in EN-Mode sichtbar — DE editiert direkt) */
.tt-family-info-edit-hint {
    margin: 0 0 10px 0;
    padding: 8px 10px;
    font-size: 12px;
    color: #92400e;
    background: #fff7ed;
    border-left: 3px solid #fdba74;
    border-radius: 2px;
}
body:not([data-tt-edit-mode="1"]) .tt-family-info-edit-hint {
    /* Hint ist nur im Edit-Mode relevant */
    display: none;
}

/* Strukturierte Rows (year, designer) — Skalar-Felder im Panel.
 * Sprach-unabhaengig, NICHT an DeepL geschickt. Im Read-Mode wird
 * eine leere Row (label + value) komplett verborgen, sodass der
 * Panel-Inhalt sauber bleibt. */
.tt-family-info-rows {
    display: flex;
    flex-direction: column;
    /* gap: 4px; */
    gap: 0;
    margin-bottom: 10px;
    font-size: 13px;
    line-height: 1.5;
}
.tt-family-info-row {
    display: flex;
    align-items: baseline;
    gap: 8px;
}
.tt-family-info-row-label {
    /* color: #666; */
    color: #555;
    font-weight: 500;
    /* min-width: 130px; */
    min-width: 7rem;
    flex-shrink: 0;
}
.tt-family-info-row-value {
    color: #1a1a1a;
    flex: 1;
    min-width: 0;
    /* padding: 1px 4px; */
    padding: 0;
    border: 1px solid transparent;
    border-radius: 3px;
    font-weight: 700;
}
/* Edit-Mode + DE: Value contenteditable mit dezentem Border + Focus.
 * Typografie auf Eingabe-Style normalisiert (kein Inheritance vom
 * grossen specimen-Text), damit das Eingabefeld nicht mit Display-
 * Schrift gerendert wird. */
body[data-tt-edit-mode="1"] .tt-family-info-row-value[contenteditable="true"] {
    border-color: #d4d4d4;
    background: #fff;
    cursor: text;
    padding: 0 4px;
    font-weight: normal;
    letter-spacing: normal;
    font-size: 13px;
}
body[data-tt-edit-mode="1"] .tt-family-info-row-value[contenteditable="true"]:focus {
    outline: none;
    border-color: #1d4ed8;
}
/* Empty-Placeholder im Edit-Mode (data-placeholder via CSS) */
body[data-tt-edit-mode="1"] .tt-family-info-row-value[contenteditable="true"]:empty::before {
    content: attr(data-placeholder);
    color: #bbb;
    font-style: italic;
    pointer-events: none;
}
/* Read-Mode + leere Row → ganze Reihe (Label + Value) verstecken */
body:not([data-tt-edit-mode="1"]) .tt-family-info-row.is-empty {
    display: none;
}

/* Edit-Mode-only Rows (Hersteller, Version, Trademark):
 * im Read-Mode immer ausblenden, im Edit-Mode immer zeigen (auch leer). */
body:not([data-tt-edit-mode="1"]) .tt-family-info-row--edit-only {
    display: none;
}
body[data-tt-edit-mode="1"] .tt-family-info-row--edit-only {
    display: flex;
}

/* Toolbar mit Translate-Button und Read-from-Font-Button */
.tt-family-info-toolbar {
    display: flex;
    justify-content: flex-end;
    gap: 6px;
    margin-bottom: 8px;
}
body:not([data-tt-edit-mode="1"]) .tt-family-info-toolbar {
    display: none;
}
.tt-family-info-translate-btn,
.tt-family-info-readfont-btn {
    appearance: none;
    padding: 4px 10px;
    border: 1px solid #d4d4d4;
    border-radius: 3px;
    background: #fff;
    color: #1a1a1a;
    font: inherit;
    font-size: 12px;
    cursor: pointer;
    transition: background 0.1s, border-color 0.1s;
}
.tt-family-info-translate-btn:hover,
.tt-family-info-readfont-btn:hover {
    background: #1a1a1a;
    color: #fff;
    border-color: #1a1a1a;
}
.tt-family-info-translate-btn[disabled],
.tt-family-info-readfont-btn[disabled] {
    opacity: 0.5;
    cursor: wait;
}

/* Info-Content: HTML-Inhalt mit <strong>/<br>. Im Edit-Mode +
 * contenteditable bekommt er einen subtilen Focus-State. */
.tt-family-info-content {
    margin: 0;
    /* padding: 6px 4px; */
    /* border: 1px solid transparent; */
    padding: 0;
    border: none;
    border-radius: 3px;
}
.tt-family-info-content strong {
    font-weight: 600;
}
/* Inline-Links im Info-Text — gleiche Farbsprache wie die dedizierten
 * URL-Felder unten (.tt-family-info-link-url), aber etwas dezenter
 * (kein Border-Bottom als Default; nur bei :hover unterstrichen). Im
 * Edit-Mode (contenteditable) sind Klicks default cursor-positioning;
 * Cmd-/Ctrl-Klick oeffnet den Link. Im Read-Mode normaler Klick. */
.tt-family-info-content a {
    color: #1d4ed8;
    text-decoration: underline;
    text-decoration-color: rgba(29, 78, 216, 0.4);
    text-underline-offset: 2px;
}
.tt-family-info-content a:hover {
    text-decoration-color: #1d4ed8;
}
body[data-tt-edit-mode="1"] .tt-family-info-content[contenteditable="true"] {
    border-color: #d4d4d4;
    background: #fff;
    cursor: text;
    /* Default-Hoehe etwa doppelt so gross wie der Read-Mode-Inhalt
     * typischerweise ist — gibt dem User Platz zum Tippen ohne dass
     * die Box bei kurzem Inhalt komisch klein wirkt. */
    /* min-height: 160px; */
    min-height: 100px;
}
body[data-tt-edit-mode="1"] .tt-family-info-content[contenteditable="true"]:focus {
    outline: none;
    border-color: #1d4ed8;
    background: #fff;
}
/* Empty-Placeholder im Edit-Mode (data-placeholder via CSS) */
body[data-tt-edit-mode="1"] .tt-family-info-content.is-empty:empty::before {
    content: attr(data-placeholder);
    color: #999;
    font-style: italic;
    pointer-events: none;
}

/* EN-Preview unter der DE-Textarea — nur im Edit-Mode sichtbar.
 * Zeigt die bestehende DeepL-Uebersetzung damit der User beim Editieren
 * weiss was die EN-Variante derzeit ist. Nach erfolgreichem Translate-
 * Klick wird der Inhalt via JS aktualisiert. */
.tt-family-info-en-preview {
    margin-top: 6px;
    padding: 6px 8px;
    background: #f5f5f3;
    border-left: 2px solid #d4d4d4;
    border-radius: 0 3px 3px 0;
    font-size: 11px;
    line-height: 1.5;
    color: #666;
}
.tt-family-info-en-preview-label {
    display: inline-block;
    margin-right: 6px;
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-weight: 600;
    color: #999;
    font-size: 10px;
    letter-spacing: 0.05em;
    text-transform: uppercase;
}
.tt-family-info-en-preview-text strong {
    font-weight: 600;
    color: #333;
}
/* Empty-State: Hinweis-Text statt leerer Box */
.tt-family-info-en-preview-text[data-empty="1"]::before {
    content: "—";
    color: #bbb;
    font-style: italic;
}
/* Nur im Edit-Mode sichtbar */
body:not([data-tt-edit-mode="1"]) .tt-family-info-en-preview {
    display: none;
}

/* URL-Footer */
.tt-family-info-links {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    margin-top: 12px;
    padding-top: 10px;
    /* border-top: 1px dashed #e5e5e5; */
    border-top: 1px dashed #ccc;
    font-size: 12px;
}
.tt-family-info-link {
    display: inline-flex;
    align-items: baseline;
    gap: 6px;
}
.tt-family-info-link-label {
    /* color: #666; */
    color: #555;
    font-weight: 500;
}
.tt-family-info-link-url {
    color: #1d4ed8;
    text-decoration: none;
    word-break: break-all;
    line-height: 1.2;
    border-bottom: 1px solid transparent;
    transition: border-color 0.1s;
}
.tt-family-info-link-url:hover {
    border-bottom-color: #1d4ed8;
}
/* Read-Mode + leere URL → Link komplett verstecken */
body:not([data-tt-edit-mode="1"]) .tt-family-info-link.is-empty {
    display: none;
}
/* Edit-Mode + DE: URL contenteditable */
body[data-tt-edit-mode="1"] .tt-family-info-link-url[contenteditable="true"] {
    display: inline-block;
    min-width: 200px;
    padding: 1px 4px;
    border: 1px solid #d4d4d4;
    border-radius: 3px;
    background: #fff;
    color: #1a1a1a;
    cursor: text;
}
body[data-tt-edit-mode="1"] .tt-family-info-link-url[contenteditable="true"]:focus {
    outline: none;
    border-color: #1d4ed8;
}
body[data-tt-edit-mode="1"] .tt-family-info-link.is-empty .tt-family-info-link-url:empty::before {
    content: attr(data-placeholder);
    color: #999;
    font-style: italic;
}

/* Open-Source-Pill oben rechts im Info-Panel — nur im Read-Mode
 * sichtbar. Im Edit-Mode ist die OS-Pill ohnehin in der
 * .tt-family-tags-Container im Family-Header sichtbar (Edit-Mode-CSS
 * macht sie dort sichtbar via :not-Regel im Tag-Block). Damit haben
 * wir keine doppelte Anzeige. */
.tt-family-info-os-pill {
    position: absolute;
    top: 10px;
    right: 12px;
    display: inline-flex;
    align-items: center;
    height: 22px;
    padding: 0 10px;
    font-family: system-ui, -apple-system, sans-serif;
    font-size: 11px;
    font-weight: 500;
    color: #1a1a1a;
    background: #e0e7ff;
    border: 1px solid #c7d2fe;
    border-radius: 11px;
    user-select: none;
    pointer-events: none; /* nicht klickbar — rein dekorativer Indikator */
}
/* Im Edit-Mode wuerde die Lizenz-Pill (oben rechts im Info-Panel) das
 * Erscheinungsjahr-Eingabefeld ueberlagern. Daher dort verbergen —
 * die Lizenz-Info ist im Edit-Mode ohnehin als Tag-Pill am Family-
 * Header sichtbar und damit nicht doppelt noetig. */
body[data-tt-edit-mode="1"] .tt-family-info-os-pill {
    display: none;
}

/* Status-Pill rechts unten im Panel */
.tt-family-info-status {
    position: absolute;
    bottom: 8px;
    right: 14px;
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 11px;
    color: #16a34a;
    font-style: italic;
    transition: opacity 0.3s;
    pointer-events: none;
}
.tt-family-info-status.is-error {
    color: #dc2626;
}
/* Wenn das Panel selbst ".is-empty" hat (alle 3 Felder leer), keine
 * dauerhafte Visual-Markierung — Empty wird durch Action-Button-Hide
 * im Read-Mode kommuniziert. */

/* ── Cut-Article (pro Schriftschnitt) ─────────────────────────── */
.tt-cut {
    padding: 24px 0;
    border-bottom: 1px solid #dedede;
    /* Anchor-Sprung (#cut-<id> aus Sidebar-Sub-Liste der Upload-Family
     * bzw. allg. von externen Links) muss beachten dass darueber das
     * Page-Header + Live-Tester + Family-Header sticky stehen. Identisch
     * zu .tt-family-info-row-wrapper: --tt-sticky-top (= Page-Header +
     * Live-Tester) plus ~98px Family-Header-Hoehe + Atemraum, sodass
     * der Cut SICHTBAR unterhalb des sticky Family-Headers landet. */
    scroll-margin-top: calc(var(--tt-sticky-top, 200px) + 98px);
}
.tt-cut:last-child {
    border-bottom: none;
}
.tt-cut-header {
    display: flex;
    align-items: end;
    flex-wrap: wrap;
    gap: 12px;
    margin-bottom: 16px;
    /* Family-Specimen erbt font-family auf .tt-cut → Header bewusst auf
     * system-ui zurueckholen, damit Cut-Name + Filename neutral lesbar
     * bleiben (sonst wuerde z. B. ein Display-Font wie CursorGothic den
     * Header unleserlich machen). */
    font-family: system-ui, -apple-system, sans-serif;
}
.tt-cut-name {
    font-size: 16px;
    font-weight: 600;
    /* Erbt die Specimen-Foreground-Farbe (vom FG-Color-Picker bzw.
     * BG-abgeleitetem Kontrast). Auf dunklem BG damit hell, auf
     * hellem dunkel — analog zum Family-Header-h2. */
    color: var(--tt-specimen-fg, #1a1a1a);
    letter-spacing: -0.005em;
    font-variant-numeric: tabular-nums;
    /* Klickbarkeit nur im Edit-Mode — Cursor + Hover-Affordanz
     * dementsprechend gegated, damit normale Besucher gar nicht erst
     * den Eindruck bekommen, dass sie was bearbeiten koennten. */
    cursor: default;
    padding: 0 6px 0;
    margin: -2px -5px;
    border-radius: 3px;
    transition: background 0.1s;
    user-select: none;
}
body[data-tt-edit-mode="1"] .tt-cut-name {
    cursor: pointer;
}
body[data-tt-edit-mode="1"] .tt-cut-name:hover {
    background: #ececea;
}
/* Im Dark-Mode (dunkler Specimen-BG) das Hover-Light-Grey gegen einen
 * subtilen halbtransparenten Tint austauschen — ein heller Block
 * waere auf schwarzem Specimen zu kontrastreich. Nur im Edit-Mode
 * aktiv (sonst kein Hover-Feedback ausserhalb der Bearbeitbarkeit). */
body[data-tt-bg-dark="1"][data-tt-edit-mode="1"] .tt-cut-name:hover {
    background: rgba(255, 255, 255, 0.12);
}
/* Wenn die Weight-Heuristik den Filename nicht aufloesen konnte, zeigen
 * wir den Fallback-Cut-Namen orange-eingefaerbt — damit du auf den ersten
 * Blick siehst wo Phase 2 (Manual-Override) noetig wird. */
.tt-cut-name[data-tt-weight-missing="1"] {
    color: #ea580c;
    font-weight: 500;
}
/* Manueller Override aktiv — kleiner blauer Punkt links, signalisiert
 * "von der Heuristik abweichend manuell gesetzt". Nur im Edit-Mode
 * sichtbar — fuer normale Besucher ist diese interne Markierung
 * irrelevant und nur Visual-Noise. */
body[data-tt-edit-mode="1"] .tt-cut-name[data-tt-weight-override="1"]::before {
    content: "";
    display: inline-block;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: #1d4ed8;
    margin-right: 6px;
    vertical-align: middle;
    transform: translateY(-1px);
}

/* Inline-Select beim Klick auf den Weight-Wert — kompakter Pickup-Editor.
 * Ersetzt den Text-Inhalt der h3 fuer die Dauer der Auswahl. */
.tt-weight-select {
    appearance: none;
    -webkit-appearance: none;
    font: inherit;
    font-weight: 600;
    font-size: 14px;
    font-variant-numeric: tabular-nums;
    color: #1a1a1a;
    background: #fff;
    border: 1px solid #1d4ed8;
    border-radius: 3px;
    padding: 2px 18px 2px 6px;
    cursor: pointer;
    /* Eigener Caret-Down-Indicator (kein Browser-Default-Chrome) */
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'><path fill='none' stroke='%231d4ed8' stroke-width='1.5' d='M1 1l4 4 4-4'/></svg>");
    background-repeat: no-repeat;
    background-position: right 5px center;
}
.tt-weight-select:focus {
    outline: 2px solid rgba(29, 78, 216, 0.3);
    outline-offset: 1px;
}
.tt-cut-file {
    /* Per Default ausgeblendet — wird via GET-Param ?show_file=1
     * eingeblendet. Dev-Tool fuer den Type-Tester selbst, nicht fuer
     * Endkunden. */
    display: none;
    font-family: ui-monospace, "SF Mono", Menlo, "Courier New", monospace;
    font-size: 11px;
    color: #000;
    background: #ccc9;
    padding: 2px 9px;
    border-radius: 3px;
    word-break: break-all;
}
body[data-tt-show-file="1"] .tt-cut-file,
body[data-tt-edit-mode="1"] .tt-cut-file {
    /* Edit-Mode zeigt den Font-File-Namen IMMER an (unabhaengig vom
     * ?show_file=1-Param) — weil im Edit-Mode der File-Name eine
     * primaere Information ist (z.B. fuer Weight-Override-Mapping). */
    display: inline;
}

/* ── Sidebar-Filter (Weight + Tag) ─────────────────────────────
 * Frueher in einer eigenen Filter-Row unter den Slidern im Live-Tester.
 * Jetzt oben in der Sidebar, beide Selects volle Spaltenbreite, gleich
 * breit. Container-Stack mit gap, leichte Trennlinie zur Familien-Liste
 * darunter. */
.tt-sidebar-filters {
    /* Sitzt jetzt AUSSERHALB des Scroll-Hosts als erstes Flex-Kind der
     * .tt-sidebar — bleibt damit permanent oben sichtbar, der Scrollbalken
     * (smooth-scrollbar auf .tt-sidebar-inner) beginnt erst unterhalb der
     * border-bottom-Trennlinie. Padding wird hier selbst getragen, weil
     * das oberste Padding aus .tt-sidebar-inner entfernt wurde. */
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 16px 20px 16px 14px;
    /* border-bottom: 1px solid #e5e5e5; */
    border-bottom: none;
    border-right: 1px solid #cecece;
}

/* Open-Source- und Italic-Checkbox unterhalb der beiden Filter-Selects.
 * Reduziert: keine Hinterlegung / kein Border bei aktivem Filter, das
 * native Checkbox-Haeckchen genuegt als Indikator. Vertikal eng aneinander
 * — die zweite Checkbox kompensiert per negativem margin-top den parent
 * gap:8px, sodass die beiden Toggles dicht beieinander sitzen. */
.tt-open-source-toggle,
.tt-licensable-toggle,
.tt-brand-toggle,
.tt-italic-toggle {
    /* display: flex (NICHT inline-flex), damit jede Checkbox eine
     * eigene Zeile einnimmt — sonst stellen sich die Labels neben-
     * einander, sobald der Parent kein column-Flex ist (z.B. innerhalb
     * <details>, das auf manchen Browsern den Content-Bereich nicht
     * als Flex-Kontext durchreicht). */
    display: flex;
    align-items: center;
    gap: 8px;
    /* padding: 5px 0 0 10px; */
    padding: 5px 0 1px 10px;
    /* Homogen mit den Family-Namen in der Sidebar darunter:
     *   .tt-sidebar nav ol  → font-size: 13px
     *   .tt-sidebar li      → line-height: 1.3, padding: 4px 0,
     *                         display: flex, align-items: baseline, gap: 8px
     *   .tt-sidebar a       → color: #111
     * Damit die Toggles als visuelle Fortsetzung der Family-Liste
     * wirken statt als separater Bedienblock. */
    font-size: 13px;
    /* line-height: 1.3; */
    line-height: 1.25;
    color: #111;
    cursor: pointer;
    user-select: none;
}
.tt-open-source-toggle input[type="checkbox"],
.tt-licensable-toggle input[type="checkbox"],
.tt-brand-toggle input[type="checkbox"],
.tt-italic-toggle input[type="checkbox"] {
    width: 14px;
    height: 14px;
    margin: 0;
    accent-color: #1d4ed8;
    cursor: pointer;
}
/* Folge-Checkboxen ruecken naeher an die vorhergehende — Parent
 * gap:8px wird per negativem margin-top auf effektive 2px reduziert,
 * sodass die vier Toggles als visuelle Gruppe wirken. Wird im
 * Accordion-Container (.tt-more-filters) ueberschrieben — dort
 * regelt details selbst per gap das Spacing. */
.tt-licensable-toggle,
.tt-brand-toggle,
.tt-italic-toggle {
    margin-top: -6px;
}

/* Accordion fuer "Weitere Filter" — nimmt die vier Boolean-Toggles
 * (Open Source, Licensable, Brand, Italic) auf. Default eingeklappt.
 * Verwendet den exakt selben Chevron-SVG wie die .tt-filter-select-
 * Dropdowns oberhalb (Datei-URI weiter oben), inkl. 180°-Rotation
 * beim Aufklappen. Visuell minimalistisch — nur Text + Chevron, kein
 * Border/Hintergrund, damit der Block sich in den Filter-Stack
 * einfuegt ohne als eigene "Karte" zu wirken. */
.tt-more-filters {
    display: flex;
    flex-direction: column;
    gap: 2px;            /* tight cluster zwischen Toggles */
}
/* Im geoeffneten Zustand bekommt der Block einen ruhigen weissen
 * Hintergrund + extra Bottom-Padding, damit die Toggle-Liste sich
 * visuell als zusammengehoerige Karte vom uebrigen Sidebar-
 * Hintergrund absetzt. */
.tt-more-filters[open] {
    background-color: #fff;
    padding-bottom: 12px;
}
.tt-more-filters > summary {
    list-style: none;    /* Firefox-Default-Marker weg */
    cursor: pointer;
    user-select: none;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 0 4px 10px;
    font-size: 13px;
    line-height: 1.3;
    color: #111;
}
/* WebKit/Blink-Default-Marker weg */
.tt-more-filters > summary::-webkit-details-marker { display: none; }
.tt-more-filters > summary::after {
    content: '';
    width: 10px;
    height: 6px;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'><path fill='none' stroke='%23666' stroke-width='1.5' d='M1 1l4 4 4-4'/></svg>");
    background-repeat: no-repeat;
    transition: transform 0.15s ease;
}
/* Chevron-Rotation (positive = im Uhrzeigersinn):
 *   default (zu)    →    0° (V nach unten)
 *   hover (zu)      →  -90° (V nach rechts — subtile Hint-Animation,
 *                           signalisiert "hier klicken zum Aufklappen")
 *   open            →  180° (V nach oben — gewinnt ueber Hover, weil
 *                           die [open]-Regel spaeter im Quelltext liegt
 *                           und gleiche Spezifitaet hat) */
.tt-more-filters > summary:hover::after {
    transform: rotate(-90deg);
}
.tt-more-filters[open] > summary::after {
    transform: rotate(180deg);
}
/* Im Accordion verschwindet der negative margin-top der Folge-Toggles
 * (siehe oben) — details regelt das Spacing per eigenem gap:2px,
 * sonst wuerden die Toggles uebereinanderliegen. */
.tt-more-filters > .tt-licensable-toggle,
.tt-more-filters > .tt-brand-toggle,
.tt-more-filters > .tt-italic-toggle {
    margin-top: 0;
}
.tt-filter-select {
    appearance: none;
    -webkit-appearance: none;
    font: inherit;
    font-size: 13px;
    font-variant-numeric: tabular-nums;
    color: #1a1a1a;
    background: #fff;
    border: 1px solid #d4d4d4;
    border-radius: 4px;
    /* padding: 6px 26px 6px 10px; */
    padding: 4px 24px 4px 8px;
    width: 100%;
    cursor: pointer;
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'><path fill='none' stroke='%23666' stroke-width='1.5' d='M1 1l4 4 4-4'/></svg>");
    background-repeat: no-repeat;
    background-position: right 10px center;
}
.tt-filter-select:focus {
    outline: 2px solid rgba(29, 78, 216, 0.3);
    outline-offset: 1px;
    border-color: #1d4ed8;
}
/* Aktiver Filter (nicht "alle") → Border in Akzent-Farbe als visuelles
 * Feedback. `:has()` checked das aktuell selected option und prueft ob
 * es einen non-empty value hat. */
.tt-filter-select:has(option:checked:not([value=""])) {
    border-color: #1d4ed8;
    background-color: #eff6ff;
}

/* ── Tag-UI pro Schriftfamilie ─────────────────────────────────
 * Tags wurden vom Cut-Header in den Family-Header verschoben — eine
 * Schrift-Klassifizierung gehoert zur ganzen Familie, nicht zum
 * einzelnen Schnitt. Pills sitzen rechts neben "X Schnitte", VOR dem
 * Action-Button. Im Edit-Mode erscheinen × auf den Pills + das
 * +Tag-Input (CSS-Gating via body[data-tt-edit-mode="1"]). */
.tt-family-tags {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 4px;
    margin-left: 8px;
    /* Optische 1-px-Korrektur: bringt die Pills visuell auf die
     * Baseline des H2-Family-Namens (sonst sitzen sie minimal tiefer
     * weil ihre Pill-Box-Mitte vs h2-Baseline 1px versetzt ist). */
    position: relative;
    top: -1px;
}
/* Legacy-Klasse — die alte Cut-Tag-Container existieren nicht mehr im
 * DOM. Style bleibt zur Kompatibilitaet falls externe Snippets darauf
 * verweisen sollten; an der Page wirkt sie nicht mehr. */
.tt-cut-tags {
    display: none;
}
.tt-tag-pill {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    height: 22px;
    padding: 0 6px 0 10px;
    white-space: nowrap;
    font-family: system-ui, -apple-system, sans-serif;
    font-size: 11px;
    font-weight: 500;
    color: #1a1a1a;
    background: #e0e7ff;
    border: 1px solid #c7d2fe;
    border-radius: 11px;
    user-select: none;
}
.tt-tag-remove {
    /* Reset: nichts vom System / Browser-Default uebernehmen — alle
     * relevanten Properties explizit setzen. */
    appearance: none;
    margin: 0;
    padding: 0;
    border: 0;
    background: transparent;
    box-shadow: none;
    outline: none;
    box-sizing: border-box;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    color: #1d4ed8;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* Kein font-size / line-height noetig — Inhalt ist ein SVG, kein
     * Text-Glyph. Damit wegfallend auch die Browser-/Font-Variabilitaet
     * der ×-Glyph-Position. */
}
/* Beim Tab-Fokus subtile Outline-Variante (statt nativer Browser-Ring) */
.tt-tag-remove:focus-visible {
    outline: 2px solid rgba(29, 78, 216, 0.4);
    outline-offset: 1px;
}
.tt-tag-remove-icon {
    display: block;
    width: 8px;
    height: 8px;
    flex-shrink: 0;
}
.tt-tag-remove:hover {
    background: #1d4ed8;
    color: #fff;
}
.tt-tag-input {
    appearance: none;
    height: 22px;
    width: 70px;
    padding: 0 6px;
    font-family: system-ui, -apple-system, sans-serif;
    font-size: 11px;
    color: #1a1a1a;
    background: transparent;
    border: 1px dashed #d4d4d4;
    border-radius: 11px;
    outline: none;
}
.tt-tag-input:focus {
    border-style: solid;
    border-color: #1d4ed8;
    background: #fff;
    width: 110px;
}

/* ── Edit-Mode-Toggle ──────────────────────────────────────────
 * Default: × auf Pills + "+Tag"-Input + per-Cut-CSS-Editor sind
 * versteckt. Erst wenn der User den Toggle "Edit-Mode" einschaltet
 * → body[data-tt-edit-mode="1"] → alle Edit-Controls werden
 * eingeblendet.
 *
 * Damit bleiben die Pills selbst (Tag-Anzeige) IMMER sichtbar — nur
 * die Edit-Affordances (Loesch-X + Hinzufuegen-Input + CSS-Override-
 * Editor) sind gegated.
 */
body:not([data-tt-edit-mode="1"]) .tt-tag-remove,
body:not([data-tt-edit-mode="1"]) .tt-tag-input,
body:not([data-tt-edit-mode="1"]) .tt-cut-css-editor {
    display: none;
}
/* "Open Source" ist eine Lizenz-Eigenschaft, keine sichtbar relevante
 * Klassifizierung im Read-Mode → Pill nur im Edit-Mode anzeigen, damit
 * sie nicht visuell mit den typografischen Kategorie-Tags konkurriert.
 * Im Edit-Mode bleibt sie sichtbar (mit ×-Button) damit der User sie
 * pflegen kann. */
body:not([data-tt-edit-mode="1"]) .tt-tag-pill[data-tag="Open Source"],
body:not([data-tt-edit-mode="1"]) .tt-tag-pill[data-tag="OS"],
body:not([data-tt-edit-mode="1"]) .tt-tag-pill[data-tag="CL"],
body:not([data-tt-edit-mode="1"]) .tt-tag-pill[data-tag="BT"] {
    display: none;
}
.tt-edit-mode-toggle {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    color: #666;
    cursor: pointer;
    user-select: none;
    /* Sitzt jetzt im Page-Header rechts oben, links vom Sprach-Auswahl-
     * Menue. Die Position kommt automatisch durch das Flex-Layout des
     * Page-Headers (header-text = flex:1, dann edit-mode, dann lang-
     * select). Kein margin-left:auto mehr noetig. */
    flex-shrink: 0;
}
.tt-edit-mode-toggle input[type="checkbox"] {
    width: 14px;
    height: 14px;
    margin: 0;
    accent-color: #ea580c;
    cursor: pointer;
}
body[data-tt-edit-mode="1"] .tt-edit-mode-toggle {
    color: #ea580c;
    font-weight: 600;
}

/* Im Edit-Modus zur visuellen Klarheit: Pills bekommen einen kleinen
 * orange-getoenten Rand-Akzent, damit der User sieht "ich bin im
 * editier-modus, achte was du klickst". */
body[data-tt-edit-mode="1"] .tt-tag-pill {
    border-color: #fdba74;
    background: #fff7ed;
}

/* ── Per-Cut CSS-Editor (Edit-Mode) ───────────────────────────
 * <details>-Block am Ende jedes Cut-Articles. Im Edit-Mode sichtbar,
 * default eingeklappt — Klick auf summary blendet Textarea + Hinweise
 * ein. User schreibt rohes CSS (".tt-display { letter-spacing: 0.05em; }"),
 * Speichern auf Blur/Strg+Enter via save-css.php. JS reicht das geupdatete
 * Override an den globalen <style id="tt-cut-css-overrides">-Block weiter.
 *
 * Cuts mit aktivem Override: orange Indicator-Dot links + Article hat
 * data-cut-css-override="1" (rendert zusaetzlich einen dezenten linken
 * Accent-Balken im Edit-Mode). */
.tt-cut-css-editor {
    margin-top: 16px;
    padding: 8px 12px;
    border: 1px dashed #d4d4d4;
    border-radius: 4px;
    background: #fafaf8;
    font-family: system-ui, -apple-system, sans-serif;
}
.tt-cut-css-editor summary {
    cursor: pointer;
    list-style: none;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: 12px;
    color: #666;
    user-select: none;
    padding: 2px 0;
}
.tt-cut-css-editor summary::-webkit-details-marker { display: none; }
.tt-cut-css-summary-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    border-radius: 50%;
    background: #ececea;
    color: #888;
    font-size: 11px;
    line-height: 1;
    transition: background 0.1s, color 0.1s;
}
.tt-cut-css-summary-label {
    font-weight: 500;
    color: #1a1a1a;
}
.tt-cut-css-summary-status {
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 11px;
    color: #888;
    font-style: italic;
    margin-left: auto;
}
.tt-cut-css-editor[data-has-override="1"] {
    border-color: #fdba74;
    border-style: solid;
    background: #fff7ed;
}
.tt-cut-css-editor[data-has-override="1"] .tt-cut-css-summary-icon {
    background: #ea580c;
    color: #fff;
}
.tt-cut-css-body {
    margin-top: 8px;
}
.tt-cut-css-input {
    width: 100%;
    min-height: 72px;
    padding: 8px 10px;
    border: 1px solid #d4d4d4;
    border-radius: 4px;
    background: #fff;
    color: #1a1a1a;
    font-family: ui-monospace, "SF Mono", Menlo, "Courier New", monospace;
    font-size: 12px;
    line-height: 1.5;
    resize: vertical;
    tab-size: 2;
}
.tt-cut-css-input:focus {
    outline: 2px solid rgba(29, 78, 216, 0.25);
    outline-offset: 1px;
    border-color: #1d4ed8;
}
.tt-cut-css-input.tt-cut-css-error {
    border-color: #dc2626;
    background: #fef2f2;
}
.tt-cut-css-actions {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-top: 6px;
    font-size: 11px;
    color: #888;
}
.tt-cut-css-hint {
    flex: 1;
    line-height: 1.45;
}
.tt-cut-css-hint code {
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 11px;
    background: #ececea;
    color: #1a1a1a;
    padding: 1px 4px;
    border-radius: 2px;
}
.tt-cut-css-clear {
    appearance: none;
    flex-shrink: 0;
    padding: 4px 10px;
    border: 1px solid #d4d4d4;
    border-radius: 3px;
    background: #fff;
    color: #666;
    font: inherit;
    font-size: 11px;
    cursor: pointer;
    transition: background 0.1s, color 0.1s, border-color 0.1s;
}
.tt-cut-css-clear:hover {
    background: #dc2626;
    border-color: #dc2626;
    color: #fff;
}

/* Article-Indicator: Cuts mit aktivem CSS-Override bekommen im Edit-Mode
 * einen dezenten orange Akzent-Balken links — schnelle visuelle
 * Identifikation welche Schnitte manuell gestylt sind. */
body[data-tt-edit-mode="1"] .tt-cut[data-cut-css-override="1"] {
    box-shadow: inset 3px 0 0 0 #ea580c;
    padding-left: 12px;
}

/* Italic-Pill rechts neben dem Weight-Wert. Separate Anzeige, weil
 * Italic eine eigene Achse ist (nicht Teil des font-weight). Klein,
 * dezent, in Italic gerendert um den Sinn auch typografisch zu
 * untermauern. */
/* Font-Name aus der OpenType-name-Tabelle — wird client-seitig fuer
 * Upload-Familien gefuellt (specimen.js → loadUploadFontNames). Leerer
 * Span ist via :empty unsichtbar.
 *
 * Visuell spiegelt der Span die .tt-cut-name (Weight-Label links daneben):
 * gleiche Groesse + Weight + letter-spacing + tabular-nums. Damit beide
 * Eintraege in der Flex-Row baseline-buendig stehen, MUSS auch die
 * negative Bottom-Margin von .tt-cut-name (-2px) reproduziert werden —
 * sonst aligned `align-items: end` die Margin-Edges 2px versetzt und der
 * Span sitzt sichtbar unter dem Weight-Label.
 *
 * Farbe: dunkelgrau (#444). Rot wirkte als Sekundaer-Akzent zu aggressiv;
 * wir wollen ihn als ruhige Zusatz-Info, nicht als Eyecatcher. */
.tt-cut-fontname {
    font-size: 16px;
    font-weight: 600;
    color: #444;
    font-family: system-ui, -apple-system, sans-serif;
    letter-spacing: -0.005em;
    font-variant-numeric: tabular-nums;
    margin-left: 4px;
    margin-bottom: -2px;
    user-select: text;
}
.tt-cut-fontname:empty { display: none; }

.tt-cut-italic-pill {
    display: inline-flex;
    align-items: center;
    height: 18px;
    padding: 0 8px;
    /* Optische Korrektur: bei align-items:end im .tt-cut-header sitzt
     * die Pill sonst exakt auf der Baseline der Cut-Name-h3 — 1px
     * margin-bottom hebt sie minimal an, damit Pill und Cut-Name
     * optisch buendig schliessen. */
    margin-bottom: 1px;
    font-family: system-ui, -apple-system, sans-serif;
    font-size: 11px;
    font-weight: 500;
    font-style: italic;
    color: #1a1a1a;
    background: #f1ecff;
    border: 1px solid #d8cfff;
    border-radius: 9px;
    letter-spacing: 0.02em;
    user-select: none;
}

/* ── Specimens (in der Schriftart des Schnitts) ──────────────── */
/* Alle Specimen-Texte erben var(--tt-specimen-fg) → der FG-Color-Picker
 * im Live-Tester aendert sie alle gleichzeitig live. Family-Heading
 * ebenfalls (siehe oben). Cut-Name + Cut-Filename bleiben neutral, weil
 * sie zur Page-Chrome zaehlen und immer lesbar bleiben muessen. */
.tt-display {
    font-size: 78px;
    line-height: 1.09;
    letter-spacing: 0;
    /* margin-bottom: 16px; */
    /* margin-bottom: 0; */
    margin-bottom: 10px;
    /* Optische Korrektur: bei Display-Schriften sitzt der erste Glyph
     * meist mit Side-Bearing rechts der visuellen Kante — minimaler
     * negativer Margin schiebt den Absatz nach links auf die
     * Spalten-Kante. */
    margin-left: -0.05em;
    color: var(--tt-specimen-fg, #1a1a1a);
}
/* Sekundaer-Headline — nur im "lang"-Modus sichtbar (CSS-Gating unten).
 * 48 px, ueberhalb des Pangrams, eigene Sample-Sentence. */
.tt-headline {
    font-size: 48px;
    line-height: 1.15;
    /* margin-bottom: 8px; */
    margin-bottom: 10px;
    color: var(--tt-specimen-fg, #1a1a1a);
}
.tt-pangram {
    font-size: 36px;
    line-height: 1.25;
    /* margin-bottom: 12px; */
    /* margin-bottom: 8px; */
    margin-bottom: 16px;
    color: var(--tt-specimen-fg, #1a1a1a);
}
/* Eigene Zeile fuer kritische Zeichenpaare — kleiner als der
 * Hauptpangram, sitzt direkt darunter, gleicher FG-Color. */
.tt-pangram-critical-pairs {
    font-size: 24px;
    line-height: 1.25;
    margin-bottom: 16px;
    color: var(--tt-specimen-fg, #1a1a1a);
}
.tt-body {
    font-size: 18px;
    /* line-height: 1.55;
       JS staffelt line-height abhaengig vom Body-Slider:
       >19px=1.5, >17px=1.525, sonst 1.55. Default-Slider=18px → 1.525. */
    line-height: 1.525;
    /* max-width: 760px;
       JS staffelt max-width abhaengig von der Body-Slider-Groesse:
       >19px=1000, >17px=920, >15px=840, sonst 760.
       Default-Slider=18px → JS setzt 920px direkt nach Init. */
    max-width: 920px;
    margin-top: 20px;
    margin-bottom: 12px;
    color: var(--tt-specimen-fg, #1a1a1a);
}
/* Zusaetzlicher Body-Block — nur im "lang"-Modus sichtbar. Dadurch
 * verdoppelt sich die Fliesstext-Menge. */
.tt-body-extra {
    font-size: 18px;
    /* line-height: 1.55;
       max-width: 720px;
       Beide Werte werden vom Body-Slider (applySizeBody in specimen.js)
       je nach Schriftgroesse gestaffelt — selbe Logik wie .tt-body.
       Defaults hier passen zum Slider-Default 18px. */
    line-height: 1.525;
    max-width: 920px;
    margin-bottom: 24px;
    color: var(--tt-specimen-fg, #1a1a1a);
}
/* Zwei aufeinanderfolgende body-extra-Absaetze: Gap zwischen ihnen
 * auf 12px reduzieren, damit sie buendig zum 12px-Gap zwischen
 * .tt-body und dem ersten .tt-body-extra sind. Der bottom-Margin
 * vom letzten .tt-body-extra bleibt 24px (Abstand zum naechsten
 * Block, z.B. .tt-glyphs). */
.tt-body-extra + .tt-body-extra {
    margin-top: -12px;
}
/* Glyph-Zeile: Numerals + Diakritika + Punctuation in einem Block.
 * Keine Leerzeichen zwischen den Zeichen — stattdessen letter-spacing
 * 0.1em fuer dezente optische Trennung. Tabular-Nums damit Ziffern in
 * gleicher Breite stehen. */
.tt-glyphs {
    /* font-size: 18px; */
    font-size: 24px;
    line-height: 1.4;
    letter-spacing: 0.1em;
    margin: 12px 0 12px;
    font-variant-numeric: tabular-nums;
    color: var(--tt-specimen-fg, #1a1a1a);
    word-break: break-all;
}

/* Microtext — nur im "lang"-Modus, ~80 Zeichen in 12 px unter den
 * Glyphen. Zeigt Lesbarkeit der Font in sehr kleiner Groesse (Captions,
 * Footnotes etc.). */
.tt-microtext {
    font-size: 12px;
    line-height: 1.5;
    letter-spacing: 0.01em;
    margin-top: 8px;
    margin-bottom: 24px;
    max-width: 640px;
    color: var(--tt-specimen-fg, #1a1a1a);
}

/* ── Sample-Length-Modi ───────────────────────────────────────
 * `body[data-tt-length]` steuert welche Specimen-Zeilen sichtbar sind.
 *   "medium" (Default): tt-display + tt-pangram + tt-body + tt-glyphs
 *   "short":            nur tt-display + tt-body
 *   "long":             alle inkl. tt-headline (48px) + tt-body-extra
 *                       (verdoppelter Fliesstext) + tt-microtext (12px)
 * Implementierung via :not()-Selektoren — Default-Anzeige bleibt
 * unangetastet wenn kein data-tt-length gesetzt ist. */

/* Im Default + "medium" + "short": die "lang"-Extras NICHT zeigen.
 * .tt-microtext zaehlt jetzt nicht mehr zu den "lang"-Extras —
 * erscheint auch im Medium-Modus. */
body:not([data-tt-length="long"]) .tt-headline,
body:not([data-tt-length="long"]) .tt-body-extra {
    display: none;
}
/* Im "short"-Modus zusaetzlich pangram + critical-pairs + glyphs +
 * microtext verstecken — im Short-Modus bleiben nur Display + Body
 * sichtbar. */
body[data-tt-length="short"] .tt-pangram,
body[data-tt-length="short"] .tt-pangram-critical-pairs,
body[data-tt-length="short"] .tt-glyphs,
body[data-tt-length="short"] .tt-microtext {
    display: none;
}
/* ── Mobile/Tablet (< 768 px) ─────────────────────────────────── */
@media (max-width: 768px) {
    .tt-layout {
        grid-template-columns: 1fr;
    }
    .tt-sidebar {
        /* Auf Mobile: position: fixed wieder neutralisieren — Sidebar
         * wird zur normalen Block-Section ueber dem Main-Content. Auch
         * Flex aufheben, damit Filter + Liste in natuerlicher Hoehe
         * (nicht flex:1-collapsed) untereinander stehen. */
        position: static;
        top: auto;
        left: auto;
        width: auto;
        height: auto;
        max-height: none;
        border-right: 0;
        border-bottom: 1px solid #e5e5e5;
        /* padding: 16px; */
        /* padding: 16px 20px 20px 14px; */
        padding: 16px 14px 20px 14px;
        display: block;
    }
    .tt-sidebar-inner {
        flex: none;
        min-height: 0;
        padding: 0;
        /* Rechte Trennlinie nur auf Desktop — auf Mobile sitzt die Sidebar
         * als Block ueber dem Main-Content, eine vertikale Linie ergibt
         * dort keinen Sinn. */
        border-right: 0;
    }
    .tt-sidebar-filters {
        padding: 0 0 16px 0;
        margin-bottom: 16px;
        /* Rechte Trennlinie nur auf Desktop — siehe .tt-sidebar-inner. */
        border-right: 0;
    }
    .tt-main {
        /* Auf Mobile fluten — Grid hat hier nur 1 Spalte. */
        grid-column: auto;
        padding: 24px 20px;
    }
    /* .tt-page-header { padding: 20px 20px 12px; } */
    /* .tt-live-tester { padding: 12px 20px; top: 60px; } */
    .tt-live-tester { top: 60px; }
    /* Input in der Tester-Row bekommt eine eigene volle Zeile auf Mobile,
     * damit es nicht von Select + Reset-Button rechts angeschnitten wird.
     * flex-basis: 100% zwingt das Input alleine in die erste Flex-Zeile,
     * der Rest (Sample-Length-Select, Reset-Button etc.) wrappt darunter. */
    .tt-input-row #ttLiveText { flex-basis: 100%; }
    .tt-controls input[type="range"] { width: 120px; }
    .tt-family-header h2 { font-size: 28px; }
    .tt-display { font-size: 64px; }
    .tt-pangram { font-size: 24px; }
}

/* ── Jump-to-Top-Button ──────────────────────────────────────────
 * Schwebt unten rechts; erscheint via JS sobald >1000 px gescrollt
 * wurden, verschwindet wieder oben (Class .is-visible toggled). Look:
 * halb-transparentes Grau mit backdrop-filter:blur(7px) — Glassmorphism-
 * Effekt der den darunterliegenden Specimen-Inhalt durchscheinen laesst.
 * Fade-In/Fade-Out via opacity-Transition. */
.tt-jump-top {
    position: fixed;
    /* right: 24px; */
    /* bottom: 24px; */
    right: 16px;
    bottom: 16px;
    z-index: 50;
    width: 48px;
    height: 48px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border: 1px solid rgba(255, 255, 255, 0.25);
    border-radius: 50%;
    background: rgba(120, 120, 120, 0.4);
    color: #fff;
    cursor: pointer;
    backdrop-filter: blur(7px);
    -webkit-backdrop-filter: blur(7px);
    box-shadow: 0 6px 20px -6px rgba(0, 0, 0, 0.25);
    /* Default state vor JS-Aktivierung: per [hidden] komplett weg */
    opacity: 0;
    transform: translateY(8px);
    pointer-events: none;
    transition: opacity 0.22s ease, transform 0.22s ease, background 0.15s ease;
}
.tt-jump-top[hidden] {
    /* HTML5 hidden-Attribut ueberschreiben — wir wollen das per Class steuern,
     * nicht per display:none, damit die opacity-Transition smooth laeuft.
     * Initial-State (vor erstem Scroll) bleibt aber ungesehen via opacity 0. */
    display: inline-flex;
}
.tt-jump-top.is-visible {
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
}
.tt-jump-top:hover {
    background: rgba(80, 80, 80, 0.55);
    border-color: rgba(255, 255, 255, 0.4);
}
.tt-jump-top:focus-visible {
    outline: 2px solid #1d4ed8;
    outline-offset: 2px;
}
.tt-jump-top svg {
    display: block;
}

/* Auf Mobile etwas kleiner + naeher am Rand. */
@media (max-width: 768px) {
    .tt-jump-top {
        width: 42px;
        height: 42px;
        right: 16px;
        bottom: 16px;
    }
}

/* ── smooth-scrollbar (eigene Sidebar-Scrollbar) ────────────────
 * Initialisiert auf .tt-sidebar via specimen.js. Die Library wrappt
 * den Inhalt in .scroll-content und ersetzt den nativen Scrollbar
 * durch eigene Track + Thumb Elemente. Styles direkt aus dem Snippet
 * vom User uebernommen, von Markdown-Auto-Link-Artefakten bereinigt.
 *
 * WICHTIG: das Original-Snippet setzt auf dem Host-Element
 * `position: relative; overflow: scroll;`. Bei uns wuerde das die
 * `.tt-sidebar { position: fixed; overflow-y: auto; }`-Definition
 * ueberschreiben (Sidebar wuerde aus dem Fixed-Layout fallen). Die
 * Library braucht diese Properties auf dem Host gar nicht — sie setzt
 * intern overflow:hidden + verschiebt via translate3d. Daher hier
 * nur `display: block` als unschaedlicher Default behalten. */
scrollbar,
[scrollbar],
[data-scrollbar] {
    display: block;
}
scrollbar .scroll-content,
[scrollbar] .scroll-content,
[data-scrollbar] .scroll-content {
    -webkit-transform: translate3d(0, 0, 0);
    transform: translate3d(0, 0, 0);
    will-change: transform;
}
scrollbar.scrolling .scroll-content,
[scrollbar].scrolling .scroll-content,
[data-scrollbar].scrolling .scroll-content {
    pointer-events: none;
}
scrollbar.scrolling .scroll-content .scroll-content,
[scrollbar].scrolling .scroll-content .scroll-content,
[data-scrollbar].scrolling .scroll-content .scroll-content {
    pointer-events: auto;
}
scrollbar .scrollbar-track,
[scrollbar] .scrollbar-track,
[data-scrollbar] .scrollbar-track {
    position: absolute;
    opacity: 0;
    z-index: 1;
    transition: opacity 0.5s 1s ease-out, background 0.5s ease-out;
    background: transparent;
}
scrollbar .scrollbar-track.show,
[scrollbar] .scrollbar-track.show,
[data-scrollbar] .scrollbar-track.show,
scrollbar .scrollbar-track:hover,
[scrollbar] .scrollbar-track:hover,
[data-scrollbar] .scrollbar-track:hover {
    opacity: 1;
    transition-delay: 0s;
}
scrollbar .scrollbar-track:hover,
[scrollbar] .scrollbar-track:hover,
[data-scrollbar] .scrollbar-track:hover {
    background: rgba(252, 248, 243, 1);
}
scrollbar .scrollbar-track-x,
[scrollbar] .scrollbar-track-x,
[data-scrollbar] .scrollbar-track-x {
    bottom: 0;
    left: 0;
    width: 100%;
    height: 10px;
}
scrollbar .scrollbar-track-y,
[scrollbar] .scrollbar-track-y,
[data-scrollbar] .scrollbar-track-y {
    top: 0;
    right: 0;
    width: 10px;
    height: 100%;
}
.scrollbar-track.scrollbar-track-x.show {
    display: none !important;
}
scrollbar .scrollbar-thumb,
[scrollbar] .scrollbar-thumb,
[data-scrollbar] .scrollbar-thumb {
    position: absolute;
    top: 6px;
    left: 0;
    right: 0;
    width: 5px;
    height: 5px;
    /* background: rgb(224, 220, 212); */
    /* background: rgba(196, 192, 184, 0.44); */
    background: rgba(93, 88, 82, 0.43);
    border-radius: 5px;
}

/* ── Zeichenvergleich-Lightbox ──────────────────────────────────
 * Trigger: Button "Zeichenvergleich" links vom Counter-Button. Wird
 * sichtbar wenn >=1 Cut markiert ist.
 * Lightbox: zeigt bis zu 3 markierte Cuts uebereinandergelegt mit
 * halbtransparenten Default-Farben (Blau/Gruen/Rot), bottom-left-
 * Anchor (gemeinsame Baseline). Visuell angelehnt an Vemido's
 * .booking-modal-Pattern, aber komplett eigene Klassen damit der
 * TypeTester self-contained bleibt. */

.tt-overlay-trigger {
    appearance: none;
    flex-shrink: 0;
    height: 40px;
    padding: 0 14px;
    border: 1px solid #1a1a1a;
    border-radius: 4px;
    background: #1a1a1a;
    color: #fff;
    font: inherit;
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    transition: background 0.1s, border-color 0.1s;
}
.tt-overlay-trigger:hover {
    background: #000;
    border-color: #000;
}
.tt-overlay-trigger:focus-visible {
    outline: 2px solid #1d4ed8;
    outline-offset: 2px;
}

/* Scroll-Lock waehrend ein Modal offen ist. Das Browser-Document-
 * Scroll-Element ist html, nicht body — body.overflow:hidden allein
 * reicht nicht. Mit :has() sperren wir direkt auf html-Ebene.
 * body.tt-modal-open bleibt als Anker; alle Modals setzen diese Klasse. */
html:has(body.tt-modal-open),
body.tt-modal-open {
    overflow: hidden;
}

/* Modal-Huelle */
.tt-overlay-modal {
    position: fixed;
    inset: 0;
    z-index: 9999;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
}
.tt-overlay-modal[hidden] {
    display: none;
}
.tt-overlay-modal-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.65);
    cursor: pointer;
    z-index: 0;
}
.tt-overlay-modal-content {
    position: relative;
    z-index: 1;
    background: #fff;
    border-radius: 12px;
    box-shadow: 0 24px 60px -12px rgba(0, 0, 0, 0.4);
    width: min(92vw, 1100px);
    max-height: min(92vh, 720px);
    display: flex;
    flex-direction: column;
    /* Kein Padding mehr — Header/Footer bringen ihre eigenen Innenabstaende
     * mit, damit die hellgrauen Baender bis an die Modal-Raender stossen. */
    padding: 0;
    overflow: hidden;
}
.tt-overlay-modal-close {
    appearance: none;
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: #f5f5f5;
    color: #1a1a1a;
    line-height: 0;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background 0.1s, color 0.1s;
}
.tt-overlay-close-icon {
    display: block; /* eliminiert Inline-Baseline-Whitespace, X bleibt
                       optisch exakt mittig im Kreis */
}
.tt-overlay-modal-close:hover {
    background: #1a1a1a;
    color: #fff;
}
.tt-overlay-modal-close:focus-visible {
    outline: 2px solid #1d4ed8;
    outline-offset: 2px;
}

/* Header: hellgraues Band, 3-Spalten-Grid (links Fullscreen, Mitte
 * zentriertes Eingabefeld, rechts Side-Toggle + Close). 1fr auto 1fr
 * sorgt fuer echte Mittel-Zentrierung egal wie breit Side-Toggle wird. */
.tt-overlay-header {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: 16px;
    padding: 10px 24px;
    background: #f9f8f5;
    border-bottom: 1px solid #e5e5e5;
}
.tt-overlay-header-left {
    display: inline-flex;
    align-items: center;
    justify-self: start;
}
.tt-overlay-header-center {
    display: inline-flex;
    align-items: center;
    gap: 12px;
    justify-self: center;
}
.tt-overlay-header-right {
    display: inline-flex;
    align-items: center;
    gap: 12px;
    justify-self: end;
}

/* Fullscreen-Button — visuell analog zu Vemido's
 * .style-preview-expand-btn (32x32 rund, weisser Hintergrund, dezenter
 * Border). Toggelt zwischen Expand- und Compress-Icon basierend auf
 * .is-fullscreen-Klasse auf .tt-overlay-modal-content. */
.tt-overlay-fullscreen-btn {
    appearance: none;
    width: 32px;
    height: 32px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: #f5f5f5;
    color: #1a1a1a;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background 0.1s, color 0.1s;
}
.tt-overlay-fullscreen-btn:hover {
    background: #1a1a1a;
    color: #fff;
}
.tt-overlay-fullscreen-btn:focus-visible {
    outline: 2px solid #1d4ed8;
    outline-offset: 2px;
}
.tt-overlay-fullscreen-btn svg {
    width: 18px;
    height: 18px;
    fill: currentColor;
}
/* Icon-Wechsel via Modal-State */
.tt-overlay-fullscreen-btn .tt-overlay-icon-compress {
    display: none;
}
.tt-overlay-modal-content.is-fullscreen .tt-overlay-fullscreen-btn .tt-overlay-icon-expand {
    display: none;
}
.tt-overlay-modal-content.is-fullscreen .tt-overlay-fullscreen-btn .tt-overlay-icon-compress {
    display: block;
}

/* Footer-Toggle direkt neben Fullscreen — nur im Fullscreen-Mode sichtbar.
 * Icon zeigt immer den Zielzustand (was ein Klick erreicht):
 * aria-pressed="true"  = Footer sichtbar → OFF-Icon (Outline, kein Footer) einblenden
 * aria-pressed="false" = Footer versteckt → ON-Icon (gefuellter Streifen) einblenden */
.tt-overlay-footer-toggle-btn {
    appearance: none;
    width: 32px;
    height: 32px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: #f5f5f5;
    color: #1a1a1a;
    cursor: pointer;
    display: none; /* nur im Fullscreen-Mode sichtbar */
    align-items: center;
    justify-content: center;
    margin-left: 6px;
    transition: background 0.1s, color 0.1s;
}
.tt-overlay-modal-content.is-fullscreen .tt-overlay-footer-toggle-btn {
    display: inline-flex;
}
.tt-overlay-footer-toggle-btn:hover {
    background: #1a1a1a;
    color: #fff;
}
.tt-overlay-footer-toggle-btn:focus-visible {
    outline: 2px solid #1d4ed8;
    outline-offset: 2px;
}
.tt-overlay-footer-toggle-btn svg {
    width: 18px;
    height: 18px;
}
/* Default-State (aria-pressed="true" = Footer sichtbar) → OFF-Icon zeigen
 * (zeigt was Klick erreicht: Footer ausblenden = Outline-Rect ohne Streifen).
 * Bei aria-pressed="false" (Footer versteckt) → ON-Icon zeigen. */
.tt-overlay-footer-toggle-btn .tt-overlay-icon-footer-on {
    display: none;
}
.tt-overlay-footer-toggle-btn[aria-pressed="false"] .tt-overlay-icon-footer-off {
    display: none;
}
.tt-overlay-footer-toggle-btn[aria-pressed="false"] .tt-overlay-icon-footer-on {
    display: block;
}

/* Footer ausblenden wenn der Toggle es so will. Da .tt-overlay-footer ein
 * eigener flex:0-Block am Ende des Modal-Contents ist, expandiert der
 * Stack-Scroller (flex:1) automatisch in den freigewordenen Platz. */
.tt-overlay-modal-content.is-footer-hidden .tt-overlay-footer {
    display: none;
}

/* Fullscreen-Mode: Modal-Content fuellt den ganzen Viewport */
.tt-overlay-modal-content.is-fullscreen {
    width: 100vw;
    max-width: none;
    height: 100vh;
    max-height: none;
    border-radius: 0;
}
.tt-overlay-modal:has(.is-fullscreen) {
    /* Padding um die Modal-Box wegnehmen wenn Fullscreen aktiv */
    padding: 0;
}
/* Side-by-Side-Toggle im Header — sichtbar nur wenn <=2 Zeichen im
 * Text-Input. Layout: kleiner inline-flex mit Native-Checkbox + Label. */
.tt-overlay-side-toggle {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    color: #1a1a1a;
    cursor: pointer;
    user-select: none;
}
.tt-overlay-side-toggle[hidden] {
    display: none;
}
.tt-overlay-side-toggle input[type="checkbox"] {
    width: 14px;
    height: 14px;
    margin: 0;
    accent-color: #1d4ed8;
    cursor: pointer;
}
/* Hint sitzt zwischen Header und Stack — eigene Zeile mit Padding. */
.tt-overlay-hint {
    margin: 12px 24px;
}
/* Stack-Wrapper geht ohne Margin/Padding edge-to-edge. Begruendung:
 * Padding innerhalb eines horizontalen Scroll-Containers wird beim
 * Scroll-Ende nicht zuverlaessig sichtbar (Browser-Quirks); Margins
 * sprengen das 100%-breite SVG. Header/Footer haben eigene Innen-
 * abstaende und sind visuell die Begrenzung. */
/* Footer: hellgraues Band, mehrere Reihen Per-Slot-Inputs + globale
 * Opacity-Reihe darunter. */
.tt-overlay-footer {
    padding: 16px 24px;
    background: #f9f8f5;
    border-top: 1px solid #e5e5e5;
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.tt-overlay-footer:empty {
    display: none;
}

/* Per-Slot-Reihe: Cut-Name links, Size + Spacing rechts ausgerichtet.
 * Alle Children inline-zentriert (vertical-mid), spart vertikalen
 * Platz weil Inputs + Labels alle gleich hoch sind. */
/* Grid-Container fuer die Per-Slot-Reihen. Default 1-spaltig; ab 4 Cuts
 * (Klasse `has-many`) 2-spaltig: Slots 1-3 links, 4-6 rechts (column-flow,
 * 3 Zeilen). */
.tt-overlay-rows-grid {
    display: grid;
    grid-template-columns: 1fr;
    row-gap: 12px;
}
.tt-overlay-rows-grid.has-many {
    grid-template-columns: 1fr 1fr;
    grid-template-rows: repeat(3, auto);
    grid-auto-flow: column;
    column-gap: 32px;
}
.tt-overlay-footer-row {
    display: flex;
    align-items: center;
    gap: 20px;
    font-size: 13px;
}
.tt-overlay-row-label {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    flex: 1;
    min-width: 0;
}
/* Runder Color-Picker vor dem Cut-Namen — nativer <input type="color">
 * mit allen Browser-Defaults entfernt; Border-Radius 50% macht ihn zum
 * sauberen Kreis. Klick oeffnet System-Farbwaehler. */
.tt-overlay-row-color {
    appearance: none;
    -webkit-appearance: none;
    width: 16px;
    height: 16px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: transparent;
    cursor: pointer;
    flex-shrink: 0;
    overflow: hidden;
}
.tt-overlay-row-color::-webkit-color-swatch-wrapper { padding: 0; }
.tt-overlay-row-color::-webkit-color-swatch { border: 0; border-radius: 50%; }
.tt-overlay-row-color::-moz-color-swatch { border: 0; border-radius: 50%; }
.tt-overlay-row-name {
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 13px;
    font-weight: 600;
    color: #2b2b2b; /* einheitlich Anthrazit; Slot-Farbe sitzt im Picker-Kreis davor */
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Input-Wrap: Label klein RECHTS neben dem Input (em / px) — spart
 * vertikalen Platz im Footer. */
.tt-overlay-input-wrap {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
}
.tt-overlay-input-label {
    font-size: 11px;
    color: #666;
    font-weight: 500;
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
}
.tt-overlay-size-input,
.tt-overlay-spacing-input {
    width: 64px;
    height: 28px;
    padding: 0 8px;
    border: 1px solid #d4d4d4;
    border-radius: 4px;
    background: #fff;
    color: #1a1a1a;
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 12px;
    text-align: center;
    font-variant-numeric: tabular-nums;
}
.tt-overlay-spacing-input {
    width: 76px; /* etwas breiter wegen Dezimalstellen */
}
.tt-overlay-size-input:focus,
.tt-overlay-spacing-input:focus {
    outline: none;
    border-color: #1d4ed8;
}
/* Browser-Spinner-Pfeile bei Number-Inputs entfernen — sieht
 * unaufgeraeumt aus, User editiert per Tastatur. */
.tt-overlay-size-input::-webkit-inner-spin-button,
.tt-overlay-size-input::-webkit-outer-spin-button,
.tt-overlay-spacing-input::-webkit-inner-spin-button,
.tt-overlay-spacing-input::-webkit-outer-spin-button {
    -webkit-appearance: none;
    margin: 0;
}
.tt-overlay-size-input,
.tt-overlay-spacing-input {
    -moz-appearance: textfield;
    appearance: textfield;
}

/* Globaler Opacity-Slider unter den Per-Slot-Reihen — horizontal mittig */
.tt-overlay-footer-opacity {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 12px;
    padding-top: 10px;
    border-top: 1px dashed #e0ddd5;
    font-size: 12px;
    color: #555;
}
.tt-overlay-footer-opacity .tt-overlay-input-label {
    text-align: left;
}
.tt-overlay-opacity-input,
.tt-overlay-zoom-input {
    /* Beide Slider in einer Reihe — kompakt (120px statt urspruenglich
     * 280px), damit Opacity + Zoom + Guides-Toggles nebeneinander
     * Platz haben und den Footer nicht dominieren. */
    flex: 0 1 120px;
    max-width: 120px;
    accent-color: #1d4ed8;
}
.tt-overlay-opacity-out,
.tt-overlay-zoom-out {
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 11px;
    color: #888;
    /* 40px reicht fuer "100%" und auch "300%" (Zoom-Max). */
    min-width: 40px;
    font-variant-numeric: tabular-nums;
}
/* Hilfslinien werden im SVG immer mitgerendert mit den Klassen
 * `tt-guide-v` (vertikale Cell-Trenner) bzw `tt-guide-h` (horizontale
 * Baseline/Cap/x-Height/Em). Sichtbarkeit toggelt rein per Modal-
 * Klasse `.is-guides-v` / `.is-guides-h` — Checkbox-Klick aendert nur
 * diese Klassen, kein Re-Render noetig. */
.tt-overlay-modal .tt-guide { display: none; }
.tt-overlay-modal.is-guides-v .tt-guide-v { display: inline; }
.tt-overlay-modal.is-guides-h .tt-guide-h { display: inline; }

/* Hilfslinien-Toggle-Gruppe rechts unten im Footer — der Wrap-Container
 * sitzt via `margin-left: auto` ganz rechts, die zwei Checkboxen darin
 * stehen nah beieinander (gap 14px) statt mit dem grossen 12-px-Gap der
 * Opacity-Reihe. */
.tt-overlay-guides-wrap {
    display: inline-flex;
    align-items: center;
    gap: 14px;
    margin-left: auto;
}
.tt-overlay-guides-toggle {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    color: #555;
    cursor: pointer;
    user-select: none;
}
.tt-overlay-guides-toggle input[type="checkbox"] {
    margin: 0;
    cursor: pointer;
}

/* Hinweis (z.B. "3 von 5 markierten Schriften") */
.tt-overlay-hint {
    margin: 0 0 12px;
    padding: 8px 12px;
    font-size: 12px;
    color: #92400e;
    background: #fff7ed;
    border-left: 3px solid #fdba74;
    border-radius: 2px;
}
.tt-overlay-hint[hidden] {
    display: none;
}

/* Stack-Canvas: SVG-Element. <text>-Layer werden per JS eingefuegt
 * mit gemeinsamer y-Koordinate (= Baseline). Damit pixel-genau
 * uebereinandergelegte Glyphen, unabhaengig von Font-Descender etc. */
/* Wrapper um das SVG-Stack-Element — uebernimmt die Flex-Sizing-
 * Verantwortung und stellt horizontale Scrollbalken zur Verfuegung
 * wenn die Glyphen (z.B. 6 Cuts side-by-side) breiter als der Modal
 * sind. Vertikale Overflow bleibt versteckt (Stack-Hoehe ist fix). */
.tt-overlay-stack-scroll {
    flex: 1;
    background: #fff;
    overflow-x: auto;
    overflow-y: hidden;
    display: flex;
    align-items: stretch;
    padding: 0 24px;
}
/* Bei Zoom >= 200% wird in JS .is-zoomed-tall am Modal gesetzt + eine
 * min-height am Stack-SVG. Damit braucht der Stack-Scroller vertikales
 * overflow auto, sonst keine Scrollbar trotz ueberlaufendem Content. */
.tt-overlay-modal.is-zoomed-tall .tt-overlay-stack-scroll {
    overflow-y: auto;
}
.tt-overlay-stack {
    height: 100%;
    flex-shrink: 0;
    background: #fff;
    overflow: visible;
    display: block;
}
/* Layer-Reihenfolge im SVG-DOM bestimmt z-index: spaeter eingefuegt
 * = visuell oben. Slot 2 wird zuletzt gerendert → liegt obenauf. */

/* Header-Text-Input: Eingabe des Vergleichstexts (max 8 Zeichen) */
.tt-overlay-text-label {
    font-size: 12px;
    color: #555;
    font-weight: 500;
}
.tt-overlay-text-input {
    flex: 0 0 180px;
    height: 36px;
    padding: 0 12px;
    border: 1px solid #d4d4d4;
    border-radius: 4px;
    background: #fff;
    color: #1a1a1a;
    font-family: inherit;
    font-size: 14px;
    text-align: center;
    letter-spacing: 0.05em;
}
.tt-overlay-text-input:focus {
    outline: none;
    border-color: #1d4ed8;
}

/* ── Hidden-Fonts-Markierung ─────────────────────────────────────
   Familien aus /_hidden/ werden NUR im 'both'-Mode optisch markiert
   (regulaer + _hidden gemischt) — dashed in der Sidebar, dotted am
   H2 — damit klar ist, welche Schriften extra sind.
   In 'hidden-only' und 'show-dir' kommen ALLE angezeigten Familien
   aus _hidden/ — die Markierung waere redundant und wird per
   body[data-tt-font-mode]-Selektor unterdrueckt. */
body[data-tt-font-mode="both"] .tt-sidebar li.tt-family-hidden a {
    font-style: italic;
    text-decoration: underline;
    text-decoration-style: dashed;
}
body[data-tt-font-mode="both"] .tt-family-header h2.tt-family-hidden-title {
    text-decoration: underline;
    text-decoration-style: dotted;
}

/* User-Upload-Family: NUR in der Sidebar rot — visuelle Klammer mit dem
 * roten Upload-Icon im Sidebar-Footer (.tt-upload-icon-btn). Im Haupt-
 * bereich rechts soll der Section-Block visuell identisch zu einer
 * normalen Familie sein (schwarze Ueberschrift + Trennlinie), damit der
 * Specimen-Vergleich nicht durch Akzentfarbe verzerrt wird. */
.tt-sidebar li.tt-family-upload a,
.tt-sidebar li.tt-family-upload .tt-cut-count {
    color: #c00;
}
.tt-sidebar li.tt-family-upload a:hover,
.tt-sidebar li.tt-family-upload a:focus {
    color: #900;
}

/* Upload-Family-Header in der Sidebar: KEIN Ziffer-Praefix, fette
 * Schrift, dient als Sektions-Ueberschrift fuer die nachfolgende
 * Sub-Liste der einzelnen Cuts. Counter wird absichtlich NICHT
 * inkrementiert, damit die regulaeren Familien danach weiter bei der
 * korrekten Nummer fortlaufen. */
.tt-sidebar li.tt-family-upload-header {
    counter-increment: none;
    font-weight: 600;
    margin-top: 4px;
}
.tt-sidebar li.tt-family-upload-header::before {
    content: '';
    display: none;
}
/* Sub-Liste der einzelnen Upload-Cuts unter dem Header — eigener
 * Counter, leichteres font-weight als die Sub-Header, leichter
 * eingerueckt damit visuell als Sub-Items erkennbar. */
.tt-sidebar .tt-family-upload-cuts-wrap {
    counter-increment: none;
    padding: 0;
    display: block;
}
.tt-sidebar .tt-family-upload-cuts-wrap::before {
    content: '';
    display: none;
}
.tt-sidebar ol.tt-family-upload-cuts {
    list-style: none;
    counter-reset: uploadcut;
    padding: 0;
    margin: 2px 0 6px;
    font-size: 13px;
}
.tt-sidebar ol.tt-family-upload-cuts li {
    counter-increment: uploadcut;
    padding: 2px 0;
    line-height: 1.25;
    display: flex;
    align-items: baseline;
    gap: 8px;
    font-weight: 400;
}
.tt-sidebar ol.tt-family-upload-cuts li::before {
    content: counter(uploadcut, decimal-leading-zero);
    font-variant-numeric: tabular-nums;
    color: #c00;
    font-family: ui-monospace, "SF Mono", Menlo, monospace;
    font-size: 11px;
    flex-shrink: 0;
    font-weight: 400;
}
.tt-sidebar ol.tt-family-upload-cuts a {
    color: #c00;
    font-weight: 400;
    text-decoration: none;
    flex: 1;
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
}
.tt-sidebar ol.tt-family-upload-cuts a:hover,
.tt-sidebar ol.tt-family-upload-cuts a:focus {
    color: #900;
}

/* Filter-Bar via ?hide_filter=1 ausblenden. GET-Parameter wandert mit
   der URL — nuetzlich fuer Kunden-Demo-Links in Kombination mit
   #show-<slug>. */
body[data-tt-hide-filter="1"] .tt-sidebar-filters {
    display: none;
}
/* Wenn der Filter-Block weg ist, hat die Family-Liste oben keine
 * border-bottom-Trennlinie der Filter-Section mehr. Etwas Padding
 * gibt der Liste den noetigen Atemraum zur Sidebar-Header-Linie. */
body[data-tt-hide-filter="1"] .tt-sidebar-inner {
    padding-top: 12px;
}

/* Live-Tester-Controls (Slider, Farb-Picker) via ?hide-controls=1
   ausblenden. Buttons-Row darueber bleibt sichtbar — Kunde kann
   weiterhin Reset/Overlay etc. nutzen, soll aber Slider-Defaults
   nicht verstellen koennen. */
body[data-tt-hide-controls="1"] .tt-controls {
    display: none;
}

/* ── Responsive Sidebar-Header / Tag-Pills ──────────────────────
 * Auf schmalen Viewports den Cut-Counter (".tt-family-count") und
 * darunter auch die typografischen Tag-Pills wegnehmen — die Sidebar
 * ist sonst zu eng und der Family-Header bricht in mehrere Zeilen. */
@media (max-width: 640px) {
    .tt-family-count { display: none; }
}
@media (max-width: 480px) {
    .tt-tag-pill { display: none; }
}

/* ── Family-Image-Gallery ─────────────────────────────────────────
 * Bis zu 2 Referenzbilder pro Familie, sitzt rechts neben dem
 * .tt-family-info-panel im .tt-family-info-row-wrapper. Bilder werden
 * auf Panel-Hoehe gestreckt, Breite ergibt sich aus Aspect-Ratio
 * (proportional) oder ist quadratisch wenn .is-square gesetzt ist
 * (cover-Crop). Konfiguriert via Edit-Mode (URL-Inputs + Square-
 * Checkbox), gespeichert per save-family-info.php. */
.tt-family-images-gallery {
    flex: 0 0 auto;
    display: flex;
    gap: 12px;
    align-items: stretch;
}
.tt-family-image-item {
    margin: 0;
    display: flex;
    flex-direction: column;
    align-self: stretch;     /* zwingt Item auf Gallery-Hoehe */
    min-width: 0;
}
.tt-family-image-clickable {
    appearance: none;
    margin: 0; padding: 0;
    border: none;
    border-radius: 4px;
    background: transparent;
    cursor: zoom-in;
    overflow: hidden;
    /* Vertikal: shrink-to-fit auf das Bild (kein flex:1, kein
     * height:100% — Button waechst nur so hoch wie das Bild ist).
     * Horizontal: nimmt volle verfuegbare Item-Breite. */
    flex: none;
    height: fit-content;
    width: 100%;
    display: block;
}
.tt-family-image {
    display: block;
    height: 100%;
    width: fit-content;
    max-height: 300px;
}

/* Square-Modus: aspect-ratio:1 zwingt den Container in Quadrat,
 * Bild via cover-Crop. Beide Slots der Gallery folgen dem Toggle. */
.tt-family-images-gallery.is-square .tt-family-image-clickable {
    aspect-ratio: 1 / 1;
    max-width: none;
    width: auto;
    height: 100%;
}
.tt-family-images-gallery.is-square .tt-family-image {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* URL-/Caption-Input + Square-Toggle — nur im Edit-Mode sichtbar */
.tt-family-image-url-input,
.tt-family-image-caption-input,
.tt-family-image-square-toggle {
    display: none;
}
body[data-tt-edit-mode="1"] .tt-family-image-url-input,
body[data-tt-edit-mode="1"] .tt-family-image-caption-input {
    display: block;
    margin-top: 4px;
    padding: 0 4px;
    font-family: system-ui, -apple-system, sans-serif;
    font-size: 11px;
    line-height: 1.6;
    border: 1px solid #d4d4d4;
    border-radius: 3px;
    background: #fff;
    width: 100%;
    box-sizing: border-box;
}
body[data-tt-edit-mode="1"] .tt-family-image-url-input:focus,
body[data-tt-edit-mode="1"] .tt-family-image-caption-input:focus {
    outline: none;
    border-color: #1d4ed8;
}
body[data-tt-edit-mode="1"] .tt-family-image-square-toggle {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    align-self: flex-end;
    font-size: 12px;
    color: #1a1a1a;
    cursor: pointer;
    user-select: none;
    white-space: nowrap;
}
body[data-tt-edit-mode="1"] .tt-family-image-square-toggle input[type="checkbox"] {
    width: 14px;
    height: 14px;
    margin: 0;
    accent-color: #1d4ed8;
    cursor: pointer;
}

/* Read-Mode: leere Image-Items komplett verbergen (kein Layout-Loch).
 * :has() prueft ob ein .tt-family-image-clickable im Item existiert —
 * fehlt es, ist das Item leer. Square-Toggle ebenfalls verbergen. */
body:not([data-tt-edit-mode="1"]) .tt-family-image-item:not(:has(.tt-family-image-clickable)) {
    display: none;
}
body:not([data-tt-edit-mode="1"]) .tt-family-image-square-toggle {
    display: none;
}
/* Wenn die Gallery komplett leer ist (Read-Mode + keine Bilder), Gap
 * zwischen Wrapper-Children verstecken indem die Gallery als
 * display:none gesetzt wird via :has-Selector. */
body:not([data-tt-edit-mode="1"]) .tt-family-images-gallery:not(:has(.tt-family-image-clickable)) {
    display: none;
}

/* Mittlere Viewports (768–1200 px): Image-Items begrenzen auf 20vw,
 * damit das Info-Panel nicht zu sehr eingeschnuert wird wenn die
 * Bilder durch ihre Aspect-Ratio breit gerendert werden. Ab 1201px
 * Viewport gibt's genug Platz fuer den Default ohne Cap. */
@media (max-width: 1200px) {
    .tt-family-image-item {
        max-width: 20vw;
    }
}

/* Mobile: Gallery komplett verstecken (User soll sich auf Inhalt
 * konzentrieren, nicht auf Referenzbilder die zu klein wuerden) */
@media (max-width: 767px) {
    .tt-family-images-gallery {
        display: none;
    }
}

/* ── Image-Lightbox ───────────────────────────────────────────────
 * Eigenes Modal (separat vom Glyph-Vergleich-Overlay) fuer Klick auf
 * ein Family-Referenzbild. Bild wird in Natural-Aufloesung gezeigt;
 * bei groesser-als-Viewport via object-fit:contain auf maximale
 * Darstellung gefittet. Schliessen: X-Button, Escape, Klick auf
 * Backdrop ausserhalb des Bildes. */
.tt-image-lightbox {
    position: fixed;
    inset: 0;
    z-index: 1000;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(0, 0, 0, 0.85);
    padding: 24px;
    cursor: zoom-out;
}
.tt-image-lightbox[hidden] {
    display: none;
}
/* Figure umfasst Bild + Caption als Stack. max-width/max-height
 * begrenzen die Gesamtgroesse auf den Lightbox-Innenraum (minus
 * Caption-Hoehe). Bild flext mit max-height: calc(100% - Caption-
 * Reservation), sodass Caption immer sichtbar bleibt. */
.tt-image-lightbox-figure {
    margin: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 16px;
    max-width: 100%;
    max-height: 100%;
    cursor: default;
}
.tt-image-lightbox-img {
    /* Bild nimmt verfuegbaren Platz, Caption darunter bleibt frei.
     * min-height:0 erlaubt Shrinken im Flex-Container. */
    max-width: 100%;
    max-height: 100%;
    min-height: 0;
    width: auto;
    height: auto;
    object-fit: contain;
    display: block;
}
.tt-image-lightbox-caption {
    color: #fff;
    font-family: system-ui, -apple-system, sans-serif;
    font-weight: 400;
    line-height: 1.4;
    text-align: center;
    /* Schriftgroesse responsive: <1200px → 14px, >=1200px → 18px */
    font-size: 14px;
    max-width: 80vw;
    /* Word-wrap fuer lange Captions */
    word-wrap: break-word;
}
@media (min-width: 1200px) {
    .tt-image-lightbox-caption {
        font-size: 18px;
    }
}
.tt-image-lightbox-caption[hidden] {
    display: none;
}
.tt-image-lightbox-close {
    position: absolute;
    top: 16px;
    right: 16px;
    width: 32px;
    height: 32px;
    appearance: none;
    margin: 0; padding: 0;
    border: 0;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.15);
    color: #fff;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.tt-image-lightbox-close:hover {
    background: rgba(255, 255, 255, 0.3);
}
.tt-image-lightbox-close:focus-visible {
    outline: 2px solid rgba(255, 255, 255, 0.5);
    outline-offset: 2px;
}

/* ── Print ───────────────────────────────────────────────────── */
@media print {
    .tt-page-header,
    .tt-live-tester,
    .tt-sidebar { display: none; }
    .tt-layout { grid-template-columns: 1fr; }
    .tt-main { padding: 0; max-width: none; }
    .tt-family { page-break-inside: avoid; margin-bottom: 40px; }
    .tt-cut { page-break-inside: avoid; }
}
