:root {
  --bg: #f6f6f4;
  --panel: #ffffff;
  --ink: #1a1a18;
  --muted: #6b6b66;
  --line: #dcdcd6;
  --accent: #2f6f4e;
  --computed: #b58a00;
  --error: #b3261e;
  --radius: 5px;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--bg);
  color: var(--ink);
  font: 13px/1.5 ui-sans-serif, system-ui, sans-serif;
}

/* ── Kopfzeile ──────────────────────────────────────────────────────── */

header {
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 7px 14px;
  background: var(--panel);
  border-bottom: 1px solid var(--line);
  /* Eine Zeile, immer: Nichts in der Kopfzeile darf intern umbrechen —
     bei schmalem Fenster weichen stattdessen die entbehrlichen Angaben. */
  flex-wrap: nowrap;
  white-space: nowrap;
}

/* Je schmaler das Fenster, desto weniger Beiwerk: erst die Messwerte,
   dann Projektname und Klarname. Die Handlungen bleiben. */
@media (max-width: 1250px) {
  .stat { display: none; }
}
@media (max-width: 1020px) {
  .project { display: none; }
  .account .who { display: none; }
}

.brand {
  font-weight: 650;
  letter-spacing: -0.01em;
  color: var(--ink);
  text-decoration: none;
}
a.brand:hover { color: var(--accent); }
.project { color: var(--muted); }
/* Der Rückweg auf Nebenseiten. Im Editor gibt es ihn nicht: Dort führt die
   Wortmarke zurück, und ein zweiter Weg daneben ist nur Beiwerk. */
a.nav-back {
  color: var(--muted);
  text-decoration: none;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 3px 9px;
  font-size: 12.5px;
}
a.nav-back:hover { background: var(--panel); color: var(--ink); }
/* Der Weg zur Hilfe: in der Kopfzeile, unaufdringlich. */
.help-link {
  color: var(--muted);
  text-decoration: none;
  font-size: 12.5px;
}
.help-link:hover { color: var(--accent); }
a.help-link.ghost {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 3px 9px;
  line-height: 1.2;
}
.stat { color: var(--muted); font-variant-numeric: tabular-nums; }
.toggle { color: var(--muted); display: flex; gap: 6px; align-items: center; }

button {
  border: 1px solid var(--line);
  background: var(--panel);
  border-radius: var(--radius);
  color: var(--ink);
  cursor: pointer;
  font: inherit;
  padding: 4px 10px;
}
button:hover { background: #f0efec; }
button.ghost { color: var(--muted); }

/* Anwesenheit */

/* Wer da ist: die anderen als Chips, daneben das eigene Konto. Beides
   beantwortet dieselbe Frage und steht deshalb in einer Gruppe, abgesetzt
   von den Handlungen rechts. */
.who-bar {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 10px;
  padding-right: 14px;
  border-right: 1px solid var(--line);
}
.who-bar:has(.peers:empty):has(.account:empty) { display: none; }

.peers {
  display: flex;
  align-items: center;
}
.peers:empty { display: none; }
.peer-chip {
  width: 24px;
  height: 24px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  color: #fff;
  font-size: 11px;
  font-weight: 600;
  border: 2px solid var(--panel);
  margin-left: -6px;
  cursor: default;
}
.peer-chip.commenter::after {
  content: "";
  position: absolute;
  transform: translate(9px, 9px);
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--computed);
  border: 1.5px solid var(--panel);
}

.zoom { display: flex; align-items: center; gap: 2px; color: var(--muted); }
.zoom button { width: 24px; padding: 0; height: 22px; line-height: 1; }
/* Das Label ist zugleich der Schalter zurück auf die automatische Breite. */
#zoom-label {
  min-width: 46px;
  text-align: center;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
}
#zoom-label:hover { color: var(--ink); }

/* ── Layout ─────────────────────────────────────────────────────────── */

main {
  flex: 1;
  display: grid;
  grid-template-columns: 200px minmax(260px, 30%) 1fr;
  min-height: 0;
}

/* Lesemodus: nur die Seiten. Für den geteilten Bildschirm, wenn links
   Claude steht und rechts das Dokument. */
body.reading main { grid-template-columns: 1fr; }
body.reading .files,
body.reading .source { display: none; }
body.reading #diagnostics { display: none; }

.pane { min-height: 0; overflow: auto; }

/* Vortragsmodus: eine Folie, sonst nichts. Der Grund, warum Video in Folium
   überhaupt trägt — im PDF ließe sich beides nicht haben. */
body.presenting header,
body.presenting .files,
body.presenting .source,
body.presenting #diagnostics,
body.presenting .page-margin { display: none; }

body.presenting main { grid-template-columns: 1fr; }

body.presenting .preview {
  background: #000;
  overflow: hidden;
}

body.presenting .pages {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100vh;
  margin: 0;
  padding: 0;
  gap: 0;
}

/* Alle Folien außer der aktuellen bleiben im DOM — sie sind vorgeladen und
   sollen beim Umblättern sofort dastehen —, nehmen aber keinen Platz ein. */
body.presenting .page { display: none; }
body.presenting .page.current {
  display: block;
  box-shadow: none;
  border: none;
}

/* Im Vortrag zeigt der Zeiger nicht auf Bearbeitbares. */
body.presenting .page .selectable { cursor: default; }
body.presenting .page text { user-select: none; }

/* ── Dateiexplorer ──────────────────────────────────────────────────── */

.files {
  background: var(--panel);
  border-right: 1px solid var(--line);
  padding: 8px 0;
}

.files .group {
  padding: 6px 12px 2px;
  color: var(--muted);
  font-size: 11px;
  letter-spacing: .02em;
}

.files .file {
  display: block;
  width: 100%;
  text-align: left;
  border: 0;
  border-radius: 0;
  background: none;
  padding: 3px 12px 3px 20px;
  color: var(--ink);
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.files .file:hover { background: #f0efec; }

/* Zeile aus Datei plus Aktionen: die Knöpfe erscheinen beim Überfahren. */
.file-row { display: flex; align-items: center; }
.file-row .file { flex: 1; min-width: 0; padding-left: 26px; }
.row-action {
  border: 0;
  background: none;
  color: var(--muted);
  padding: 2px 7px;
  opacity: 0;
  flex: none;
  font-size: 13px;
}
.file-row:hover .row-action,
.folder-row:hover .row-action { opacity: 1; }
.row-action:hover { color: var(--ink); background: none; }

/* Ordnerzeilen: Ziel und Gliederung zugleich. Die gewählte trägt die Farbe —
   dorthin geht, was man anlegt oder hochlädt. */
.folder-row {
  display: flex;
  align-items: center;
  gap: 5px;
  padding: 4px 12px 3px;
  margin-top: 4px;
  color: var(--ink);
  font-weight: 550;
  font-size: 12px;
  cursor: pointer;
  border-left: 2px solid transparent;
}
.folder-row:hover { background: #f0efec; }
.folder-row.selected {
  background: #eaf1ed;
  border-left-color: var(--accent);
  color: var(--accent);
}
.folder-row .twist { width: 10px; color: var(--muted); font-size: 10px; }
.folder-row .name {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.folder-row .count {
  color: var(--muted);
  font-weight: 400;
  font-size: 11px;
}
.folder-row.root { margin-top: 0; }

/* Der Schalter für Schriften und Übriges: unten im Baum, unaufdringlich. */
.hidden-toggle {
  display: block;
  width: calc(100% - 20px);
  margin: 10px 10px 4px;
  border: 1px dashed var(--line);
  background: none;
  color: var(--muted);
  font-size: 11.5px;
  padding: 4px 8px;
  text-align: left;
}
.hidden-toggle:hover { color: var(--ink); background: var(--panel); }

/* Bilder tragen ein anderes Zeichen als Quelltext. */
.file.kind-image::before,
.file.kind-font::before,
.file.kind-other::before {
  content: "◇";
  color: var(--muted);
  margin-right: 6px;
  font-size: 10px;
}
.file.kind-image::before { content: "▣"; }

/* Die Bildvorschau im Blatt. */
.image-preview {
  display: block;
  max-width: 100%;
  max-height: 42vh;
  margin: 8px auto;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  /* Karo als Grund: Ein transparentes PNG wäre auf Weiß unsichtbar. */
  background: #fff
    repeating-conic-gradient(#f0efec 0% 25%, #fff 0% 50%) 0 0 / 16px 16px;
}
.file-preview {
  display: block;
  width: 100%;
  height: 38vh;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: #fff;
  margin: 8px 0;
}
.image-path {
  font: 12px/1.5 ui-monospace, monospace;
  color: var(--muted);
  cursor: pointer;
  padding: 4px 0 8px;
}
.image-path:hover { color: var(--accent); }
.folder-row.dropping,
.files.dropping { outline: 2px dashed var(--accent); outline-offset: -2px; }

/* Die Menüs hinter „Herunterladen" und „⋯". */
.more-menu,
.download-menu {
  position: fixed;
  z-index: 60;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 4px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: 0 6px 20px rgba(0, 0, 0, .12);
}
.more-menu button,
.more-menu .toggle,
.more-menu a,
.download-menu button {
  border: 0;
  text-align: left;
  white-space: nowrap;
  padding: 5px 12px;
  color: var(--ink);
  text-decoration: none;
  border-radius: var(--radius);
}
.more-menu .toggle { gap: 8px; }
.more-menu button:hover,
.more-menu .toggle:hover,
.more-menu a:hover,
.download-menu button:hover { background: #f0efec; }
#more { width: 30px; padding: 4px 0; }

/* Die Dokumente des Projekts — nur da, wenn es mehrere sind. */
.document-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 3px;
  padding: 8px 10px;
  border-bottom: 1px solid var(--line);
}
.document-bar .document {
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 3px 10px;
  font-size: 11.5px;
  color: var(--muted);
  background: var(--panel);
}
.document-bar .document.current {
  background: var(--accent);
  border-color: transparent;
  color: #fff;
  font-weight: 550;
}
.document-bar .document.current:hover { background: #275c41; }

/* Die Werkzeugleiste des Explorers. */
.file-tools {
  padding: 4px 10px 6px;
  border-bottom: 1px solid var(--line);
  margin-bottom: 4px;
}
.file-tools .buttons { display: flex; gap: 4px; }
.file-tools .row-action {
  opacity: 1;
  flex: none;
  width: 30px;
  height: 24px;
  display: grid;
  place-items: center;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0;
}
.file-tools .row-action:hover { background: #f0efec; }
.file-tools .slot { display: flex; align-items: center; gap: 3px; }
.file-tools .slot:not(:empty) { margin-top: 6px; }
.file-tools .prefix { color: var(--muted); font-size: 11px; flex: none; }
.path-input {
  width: 100%;
  min-width: 0;
  padding: 3px 8px;
  font: inherit;
  font-size: 12px;
  border: 1px solid var(--accent);
  border-radius: var(--radius);
  background: var(--panel);
  color: var(--ink);
}
.path-input:focus { outline: none; }
.files .file[aria-current="true"] {
  background: #eaf1ed;
  color: var(--accent);
  font-weight: 550;
  box-shadow: inset 2px 0 0 var(--accent);
}
.files .file.readonly { color: var(--muted); }

/* ── Quelltext ──────────────────────────────────────────────────────── */

.source {
  border-right: 1px solid var(--line);
  background: var(--panel);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.filebar {
  padding: 6px 12px;
  border-bottom: 1px solid var(--line);
  color: var(--muted);
  font-size: 12px;
  display: flex;
  align-items: center;
  gap: 8px;
}

.editor { position: relative; flex: 1; min-height: 0; }
.editor[hidden] { display: none; }

/* Der Betrachter steht, wo sonst der Quelltext steht: ein Bild, eine
   Notiz, ein PDF. Eine Datei ist eine Datei — man sieht sie an derselben
   Stelle an, gleich welcher Art sie ist. */
.viewer {
  flex: 1;
  min-height: 0;
  overflow: auto;
  padding: 14px;
}
.viewer[hidden] { display: none; }
.viewer .note-body { max-width: 62ch; }

.image-view {
  display: flex;
  flex-direction: column;
  gap: 10px;
  height: 100%;
}
.image-view .image-preview {
  flex: 1;
  min-height: 0;
  object-fit: contain;
  max-width: 100%;
  cursor: zoom-in;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  /* Karo als Grund: Ein transparentes PNG wäre auf Weiß unsichtbar. */
  background: #fff
    repeating-conic-gradient(#f0efec 0% 25%, #fff 0% 50%) 0 0 / 16px 16px;
}
/* Unter dem Bild: links der Aufruf zum Einfügen, rechts die Handlungen. */
.image-view .image-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex: none;
}
.image-view .image-path {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font: 11.5px/1.6 ui-monospace, "SF Mono", Menlo, monospace;
  color: var(--muted);
  cursor: pointer;
  padding: 4px 8px;
  background: var(--bg);
  border-radius: var(--radius);
}
.image-view .image-path:hover { color: var(--ink); }
.image-view .image-actions button { flex: none; }
.image-view .file-preview { flex: 1; min-height: 300px; }

/* Textfeld und Spiegel müssen zeichengenau übereinanderliegen — jede
   Abweichung in Schrift, Abstand oder Umbruch verschiebt die Auszeichnung. */
#code,
.syntax-layer,
.source-marks {
  width: 100%;
  height: 100%;
  padding: 12px;
  font: 12.5px/1.65 ui-monospace, "SF Mono", Menlo, monospace;
  white-space: pre-wrap;
  word-wrap: break-word;
  overflow-wrap: break-word;
  tab-size: 2;
  border: 0;
}

#code {
  position: relative;
  resize: none;
  /* Durchsichtig, aber mit sichtbarem Cursor: Der Text kommt aus der
     Schicht darunter, die ihn eingefärbt trägt. */
  color: transparent;
  caret-color: var(--ink);
  background: transparent;
}
#code::selection { background: rgba(47, 111, 78, .22); }

/* Die Einfärbung liegt zuunterst: Sie trägt denselben Text in derselben
   Schrift, und das Textfeld darüber ist durchsichtig. */
.syntax-layer {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  color: var(--ink);
}
.syn-comment { color: #8a8a82; font-style: italic; }
.syn-heading { color: var(--ink); font-weight: 650; }
.syn-func { color: var(--accent); }
.syn-string { color: #7d4b12; }
.syn-math { color: #2f5d8c; }
.syn-label { color: var(--computed); }
.syn-ref { color: var(--computed); }
.syn-strong { font-weight: 650; }
.syn-emph { font-style: italic; }

/* Der Spiegel liegt darüber: sein Text ist unsichtbar, nur die
   Auszeichnung ist zu sehen. */
.source-marks {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  color: transparent;
}

.source-marks .removed {
  background: rgba(179, 38, 30, .13);
  text-decoration: line-through;
  text-decoration-color: rgba(179, 38, 30, .75);
  border-radius: 2px;
}
.source-marks .added {
  background: rgba(47, 111, 78, .15);
  border-radius: 2px;
}
.source-marks .commented {
  background: rgba(233, 178, 30, .22);
  border-radius: 2px;
}
#code:focus { outline: none; }
/* Auch schreibgeschützt bleibt der Text durchsichtig — er kommt aus der
   Einfärbung darunter; nur der Cursor verschwindet. */
#code[readonly] { caret-color: transparent; }
.source:has(#code[readonly]) .syntax-layer { color: #3c3c38; }

/* Vorschläge beim Tippen: Befehle, Bildpfade, Literaturschlüssel. */
.completions {
  position: fixed;
  z-index: 50;
  max-height: 220px;
  min-width: 240px;
  max-width: 380px;
  overflow-y: auto;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: 0 6px 20px rgba(0, 0, 0, .12);
  padding: 3px;
}
.completion {
  display: flex;
  align-items: baseline;
  gap: 7px;
  padding: 3px 8px;
  border-radius: 3px;
  cursor: pointer;
  font-size: 12.5px;
  white-space: nowrap;
}
.completion:hover { background: var(--bg); }
.completion.current { background: #eaf1ed; }
.completion .art {
  color: var(--muted);
  width: 12px;
  text-align: center;
  font-size: 11px;
  flex: none;
}
.completion .art.func { color: var(--accent); }
.completion .art.path { color: var(--computed); }
.completion .label { font-family: ui-monospace, monospace; }
.completion .detail {
  color: var(--muted);
  font-size: 11.5px;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Cursor der anderen im Quelltext */
.peer-carets {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
}
.peer-caret {
  position: absolute;
  width: 2px;
  transition: transform .12s ease-out;
}
.peer-caret::after {
  content: attr(data-name);
  position: absolute;
  top: -15px;
  left: 0;
  font: 10px/1.4 ui-sans-serif, system-ui, sans-serif;
  color: #fff;
  background: inherit;
  padding: 0 4px;
  border-radius: 3px;
  white-space: nowrap;
}

/* ── Vorschau ───────────────────────────────────────────────────────── */

.preview {
  position: relative;
  padding: 22px;
  display: flex;
  flex-direction: column;
  align-items: center;
}

/* Sind Kommentare da, rückt die Seite nach links und macht rechts Platz für
   die Karten — sonst steht sie mittig. */
.preview:has(.page-margin) .pages {
  margin-right: 266px;
}

/* Die Seiten und die Kommentarstreifen daneben liegen im selben Container:
   die Streifen sind absolut neben ihrer Seite positioniert, sodass sie
   selbstverständlich mitscrollen. */
.pages {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
}

.page-margin {
  position: absolute;
  width: 250px;
}

.page {
  background: #fff;
  /* Die Auswahl wird selbst gezeichnet; die des Browsers würde nur die
     unsichtbaren Trefferflächen markieren und beim Ziehen flackern. */
  user-select: none;
  box-shadow: 0 1px 3px rgba(0,0,0,.10), 0 8px 24px rgba(0,0,0,.06);
  cursor: text;

  /* Der Flex-Container würde die Seiten sonst in der Höhe zusammenstauchen,
     bis nur graue Streifen übrig bleiben. Die Maße kommen aus dem SVG. */
  flex: 0 0 auto;

  /* Graustufen-Antialiasing statt Subpixel (LCD) — der entscheidende Punkt
     für ein PDF-artiges Schriftbild.

     Chromium färbt Glyphkanten standardmäßig für LCD-Bildschirme ein: links
     orange, rechts blau. Auf einer gesetzten Dokumentseite liest sich das als
     unscharfer Farbstich, denn ein PDF-Betrachter rendert Text in reinen
     Graustufen.

     `will-change: transform` hebt die Seite auf eine eigene Compositing-Ebene.
     Dort kann Chromium kein Subpixel-AA anwenden, weil die Ebene transparent
     zusammengesetzt wird, und fällt auf Graustufen zurück. Nachgemessen an
     dieser Seite: farbige Randpixel 80,6 % → 6,0 %, wobei ein echtes
     PDF-Rendering bei 5,9 % liegt.

     `-webkit-font-smoothing` allein wirkt auf SVG-Text nicht — ebensowenig
     `opacity`, `isolation`, `filter` oder `translateZ`; alle wurden gemessen. */
  will-change: transform;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Glyphen sind unsichtbare Trefferflächen über dem gezeichneten Text. */
.hit { fill: transparent; }
.hit:hover { fill: rgba(47,111,78,.10); }


/* Über der Seite steht der Textcursor: man markiert dort Text, wie man es
   von einem Dokument erwartet — kein Fadenkreuz. */
.page { cursor: text; }

.caret {
  fill: var(--accent);
  animation: blink 1.1s steps(1) infinite;
}
@keyframes blink { 50% { opacity: 0; } }

/* Die laufende Textauswahl in der Seite.
   `pointer-events: none`, damit der Zeiger weiter die Glyphen darunter
   erreicht — sonst bräche das Ziehen ab, sobald die Auswahl darunter liegt. */
.selection rect {
  fill: rgba(47, 111, 78, .22);
  pointer-events: none;
}

/* Kommentar-Markierungen in der Seite. Kräftiger als eine bloße Tönung:
   eine Anmerkung soll man beim Überfliegen finden, ohne sie zu suchen. */
.comment-mark {
  fill: rgba(233, 178, 30, .34);
  cursor: pointer;
  transition: fill .12s;
}
.comment-mark:hover,
.comment-mark.active { fill: rgba(233, 178, 30, .6); }
.comment-mark.resolved { fill: rgba(120,120,110,.10); }

/* Die Unterstreichung macht die Stelle auch dort erkennbar, wo die Tönung
   auf einer Abbildung oder farbigem Grund untergeht. */
.comment-underline {
  stroke: rgba(181, 138, 0, .85);
  stroke-width: .8;
}
.comment-underline.resolved { stroke: rgba(120,120,110,.3); }

/* ── Diagnosen ──────────────────────────────────────────────────────── */

#diagnostics {
  border-top: 1px solid var(--line);
  background: var(--panel);
  max-height: 24vh;
  overflow: auto;
}
#diagnostics:empty { display: none; }

.diag {
  padding: 6px 14px;
  border-bottom: 1px solid var(--line);
  font: 12px/1.5 ui-monospace, monospace;
  cursor: pointer;
}
.diag:hover { background: #faf9f6; }
.diag.error { color: var(--error); }
.diag.warning { color: var(--computed); }

/* ── Dialoge ────────────────────────────────────────────────────────── */

.modal {
  position: fixed;
  inset: 0;
  background: rgba(26,26,24,.34);
  display: grid;
  place-items: center;
  z-index: 10;
}
.modal[hidden] { display: none; }

.card {
  background: var(--panel);
  border-radius: 10px;
  padding: 22px;
  width: min(420px, calc(100vw - 32px));
  box-shadow: 0 10px 40px rgba(0,0,0,.20);
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.card h2 { margin: 0; font-size: 15px; font-weight: 650; }
.card p { margin: 0; color: var(--muted); }
.card label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  color: var(--muted);
  font-size: 12px;
}
.card input, .card textarea {
  font: inherit;
  padding: 7px 9px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  color: var(--ink);
  background: var(--bg);
}
.card textarea { resize: vertical; font-family: inherit; }
.card input:focus, .card textarea:focus {
  outline: 2px solid var(--accent);
  outline-offset: -1px;
}
.card .row { display: flex; gap: 8px; justify-content: flex-end; }
.card .where {
  font-size: 11.5px;
  font-family: ui-monospace, monospace;
}
.card .quote {
  border-left: 2px solid var(--computed);
  padding-left: 10px;
  color: var(--ink);
  font-style: italic;
  max-height: 80px;
  overflow: auto;
}

/* Ein ganzer Gegenstand — Tabelle, Formel, Bildaufruf — steht als
   Quelltext da, nicht als Zitat: Man ersetzt ihn Zeichen für Zeichen. */
.card .quote.code {
  font: 12px/1.5 ui-monospace, "SF Mono", Menlo, monospace;
  font-style: normal;
  white-space: pre-wrap;
  max-height: 220px;
  background: var(--bg);
  border-radius: var(--radius);
  padding: 8px 10px;
}

/* ── Kommentarkarten am Seitenrand ──────────────────────────────────── */

.page-margin .comment {
  position: absolute;
  left: 0;
  width: 100%;
  padding: 9px 11px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-left: 3px solid var(--computed);
  border-radius: var(--radius);
  box-shadow: 0 1px 3px rgba(0,0,0,.07);
  cursor: pointer;
  transition: top .18s ease-out, box-shadow .12s, transform .12s;
}
.page-margin .comment:hover {
  box-shadow: 0 2px 10px rgba(0,0,0,.12);
  transform: translateX(-3px);
}
.page-margin .comment.resolved {
  opacity: .55;
  border-left-color: var(--line);
}
/* Kommentare auf noch nicht geladenen Seiten: sie kennen ihre Höhe nicht. */
.page-margin .comment.offscreen { border-left-style: dotted; }
.comment .who { font-weight: 550; font-size: 12px; }
.comment .what { color: var(--muted); font-size: 12px; }

.comment .reply {
  margin-top: 5px;
  padding-left: 8px;
  border-left: 2px solid var(--line);
  color: var(--muted);
  font-size: 12px;
}
.comment .reply .who { display: inline; margin-right: 3px; }

/* Die Knöpfe erscheinen erst beim Überfahren: die Liste soll ruhig
   aussehen, solange man nur liest. */
.comment .row {
  margin-top: 6px;
  gap: 4px;
  justify-content: flex-start;
  opacity: 0;
  transition: opacity .12s;
}
.comment:hover .row,
.comment:focus-within .row { opacity: 1; }
.comment .row button {
  padding: 1px 7px;
  font-size: 11.5px;
}

/* Die Änderung in der Karte: alt durchgestrichen, neu darunter. Eingerückt,
   damit erkennbar bleibt, was Anmerkung und was Vorschlag ist. */
.comment .edit {
  margin-top: 8px;
  padding: 7px 9px;
  background: var(--bg);
  border-radius: var(--radius);
  border-left: 2px solid var(--accent);
}
.comment .edit.accepted,
.comment .edit.declined,
.comment .edit.stale { opacity: .6; border-left-color: var(--line); }
.comment .edit .what { margin-top: 5px; }
/* Die Warnung des Probe-Kompilats: auffällig, denn Annehmen bleibt möglich. */
.comment .edit .breaks { color: var(--error); font-weight: 550; }
.comment .edit .row { opacity: 1; margin-top: 7px; }

.comment .diff {
  font: 11.5px/1.45 ui-monospace, monospace;
  word-break: break-word;
}
.comment del {
  display: block;
  background: rgba(179,38,30,.10);
  color: #7d1c16;
  text-decoration-color: rgba(179,38,30,.6);
  padding: 1px 4px;
  border-radius: 3px;
}
.comment ins {
  display: block;
  background: rgba(47,111,78,.12);
  color: #1d4a34;
  text-decoration: none;
  padding: 1px 4px;
  border-radius: 3px;
  margin-top: 2px;
}
.comment .edit .row button { padding: 2px 8px; font-size: 12px; }

/* Zwei Bilder nebeneinander: alt links, neu rechts. Der Rand ist schmal,
   deshalb teilen sie sich die Breite gleichmäßig. */
.image-diff {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px;
  margin-bottom: 7px;
}
.image-diff figure { margin: 0; min-width: 0; }
.image-diff img {
  display: block;
  width: 100%;
  height: auto;
  max-height: 140px;
  object-fit: contain;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 3px;
}
/* Die neue Fassung bekommt den grünen Rahmen — dieselbe Farbe wie <ins>. */
.image-diff .after img { border-color: rgba(47,111,78,.5); }
.image-diff .before img { border-color: rgba(179,38,30,.4); opacity: .75; }
.image-diff .missing {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 60px;
  border: 1px dashed var(--line);
  border-radius: 3px;
  color: var(--muted);
  font-size: 11px;
}
.image-diff figcaption {
  margin-top: 3px;
  font: 10.5px/1.3 ui-monospace, monospace;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* ── Projektübersicht ───────────────────────────────────────────────── */

/* Die einzige Seite, die scrollt: `body` ist sonst eine Flex-Spalte über
   die volle Höhe, in der der Editor seine Bereiche verteilt. */
body.overview-page { height: auto; min-height: 100vh; display: block; }

.overview {
  /* `main` ist im Editor ein Raster mit Dateibaum-Spalte — hier ist es eine
     einzelne Spalte, sonst quetscht sich alles in die ersten 200px. */
  display: block;
  max-width: 760px;
  margin: 0 auto;
  padding: 48px 24px 80px;
}

/* Überschriften wie im Dialog: 15px/650. Die Beschriftung darüber wie im
   Dateibaum — 11px, gesperrt, gedämpft. */
.overview h2 {
  font-size: 15px;
  font-weight: 650;
  margin: 0 0 4px;
}
.overview .hint {
  color: var(--muted);
  margin: 0 0 16px;
  max-width: 54ch;
}
.overview h2 + .hint { margin-top: 0; }

/* Jedes Projekt eine Zeile: links der Weg ins Dokument, rechts der ins
   Repository. */
.project-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-bottom: 36px;
}
.project-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 14px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.project-row:hover { border-color: var(--accent); }
.project-row .open {
  flex: 1;
  min-width: 0;
  text-decoration: none;
  color: var(--ink);
}
.project-row .name { font-weight: 550; }
.project-row .meta {
  color: var(--muted);
  margin-top: 1px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.project-row a.ghost {
  flex: none;
  color: var(--muted);
  text-decoration: none;
  padding: 3px 10px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.project-row a.ghost:hover { background: var(--bg); color: var(--ink); }

.new-project {
  border-top: 1px solid var(--line);
  padding-top: 22px;
}

/* Das Formular für ein neues Repository: eine Zeile, wie eine Repo-Zeile. */
.create-repo {
  display: flex;
  gap: 6px;
  align-items: center;
  margin-bottom: 14px;
}
.create-repo input {
  flex: 1;
  min-width: 0;
  padding: 5px 10px;
  font: inherit;
  font-family: ui-monospace, monospace;
  font-size: 12.5px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--panel);
  color: var(--ink);
}
.create-repo input:focus { outline: 2px solid var(--accent); outline-offset: -1px; }
.create-repo .hint { margin: 0; flex-basis: 100%; }
.create-repo { flex-wrap: wrap; }

.repo-list { display: flex; flex-direction: column; gap: 2px; }

/* Das Verwaltungsbrett: eine Zeile je Konto. */
.user-list { display: flex; flex-direction: column; gap: 6px; }
.user-row {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 14px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.user-row.blocked { opacity: .65; }
.user-row .avatar { width: 28px; height: 28px; border-radius: 50%; }
.user-row .wer { flex: 1; min-width: 0; }
.user-row .name { font-weight: 550; }
.user-row .meta {
  color: var(--muted);
  font-size: 12px;
  margin-top: 1px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.blocked-mark {
  margin-left: 8px;
  font-size: 11px;
  font-weight: 400;
  color: var(--error);
  border: 1px solid currentColor;
  border-radius: 999px;
  padding: 0 6px;
}

/* Der MCP-Zugang: Adresse und Token zum Kopieren, mehr nicht. */
.assistant-access {
  border-top: 1px solid var(--line);
  margin-top: 36px;
  padding-top: 22px;
}
.token-row {
  display: flex;
  gap: 8px;
  align-items: center;
  margin-bottom: 6px;
}
.token-label {
  color: var(--muted);
  flex: 0 0 180px;
}
.token-row { align-items: flex-start; }
.token-row .token-label,
.token-row button { padding-top: 5px; }
.assistant-access .hint.trailing { margin-top: 14px; max-width: 64ch; }
/* Die Zwischenzeile, die sagt, für welche Maske die nächste Zeile ist —
   beschriftet wie eine Gruppe im Dateibaum. */
.token-group {
  color: var(--muted);
  font-size: 11px;
  letter-spacing: .02em;
  margin: 14px 0 6px;
}
.token-row code {
  flex: 1;
  min-width: 0;
  /* Lange Werte umbrechen statt abschneiden: Das Claude-Code-Kommando ist
     eine Zeile, die man lesen können muss, bevor man sie ausführt. */
  overflow-wrap: anywhere;
  padding: 5px 10px;
  font-family: ui-monospace, monospace;
  font-size: 12.5px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--panel);
}

/* Wie die Dateien im Explorer: volle Breite, links bündig, ohne Rahmen
   bis zum Überfahren. */
.repo {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  padding: 6px 10px;
  text-align: left;
  background: none;
  border-color: transparent;
}
.repo:hover { background: var(--panel); border-color: var(--line); }
.repo:disabled { cursor: default; opacity: .7; }
.repo .slug { font-family: ui-monospace, monospace; font-size: 12px; }
.repo .tags { display: flex; gap: 4px; flex-shrink: 0; }

.tag {
  font-size: 11px;
  letter-spacing: .02em;
  color: var(--muted);
  border: 1px solid var(--line);
  border-radius: 3px;
  padding: 0 5px;
}

/* Das Blatt von unten: auf dem Telefon der Kommentarverlauf, überall die
   Notizen für Claude. Ohne Inhalt ist es nicht da. */
#thread-sheet {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 40;
  max-height: 55vh;
  overflow-y: auto;
  background: var(--panel);
  border-top: 1px solid var(--line);
  border-radius: 14px 14px 0 0;
  box-shadow: 0 -10px 30px rgba(0, 0, 0, .18);
  padding: 4px 14px 14px;
  transform: translateY(105%);
  transition: transform .25s ease-out;
}
#thread-sheet.open { transform: translateY(0); }
#thread-sheet .grip {
  display: flex;
  justify-content: flex-end;
  padding: 4px 0;
  position: sticky;
  top: 0;
  background: var(--panel);
}
.note-title { font-weight: 650; margin-bottom: 6px; }
/* Gesetztes Markdown im Blatt: eng gesetzt, aber lesbar — eine Notiz ist
   ein Text, kein Quelltext. */
.note-body { font-size: 13px; line-height: 1.6; color: var(--ink); }
.note-body h3 { font-size: 14px; margin: 14px 0 4px; }
.note-body h4,
.note-body h5,
.note-body h6 { font-size: 13px; margin: 12px 0 3px; color: var(--muted); }
.note-body p { margin: 0 0 8px; }
.note-body ul,
.note-body ol { margin: 0 0 8px; padding-left: 20px; }
.note-body li { margin-bottom: 2px; }
.note-body blockquote {
  margin: 0 0 8px;
  padding-left: 10px;
  border-left: 2px solid var(--line);
  color: var(--muted);
}
.note-body code {
  font: 11.5px/1.4 ui-monospace, monospace;
  background: var(--bg);
  border-radius: 3px;
  padding: 0 4px;
}
.note-body pre {
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 8px 10px;
  overflow-x: auto;
  margin: 0 0 10px;
}
.note-body pre code { background: none; padding: 0; }
.note-body table {
  border-collapse: collapse;
  margin: 0 0 10px;
  font-size: 12px;
  width: 100%;
}
.note-body th,
.note-body td {
  border-bottom: 1px solid var(--line);
  padding: 4px 8px 4px 0;
  text-align: left;
  vertical-align: top;
}
.note-body th { font-weight: 650; }
.note-body a { color: var(--accent); }

/* Der Anmeldeknopf: akzentfarben, wo immer er steht. Der große auf der
   Übersicht und der kleine in der Kopfzeile unterscheiden sich nur im Maß. */
a.login {
  display: inline-block;
  color: #fff;
  background: var(--accent);
  border: 1px solid transparent;
  border-radius: var(--radius);
  text-decoration: none;
  padding: 2px 8px;
}
a.login:hover { background: #275c41; color: #fff; }
.login.big { padding: 6px 14px; font-weight: 550; }

/* Wer angemeldet ist, ganz rechts in der Kopfzeile. */
.account {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12.5px;
}
.account:empty { display: none; }
.account .avatar {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  display: block;
}
.account .who { color: var(--ink); font-weight: 550; }
.account a {
  color: var(--muted);
  text-decoration: none;
  padding: 2px 8px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.account a:hover { background: var(--panel); color: var(--ink); }
.account a.login {
  color: #fff;
  background: var(--accent);
  border-color: transparent;
}
.account a.login:hover { background: #275c41; color: #fff; }

/* Ein Zustand, der bestehen bleibt — etwa ein blockierter Push. Oben und
   quer über die Breite, weil man ihn nicht übersehen soll. */
#notices {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 20;
  display: flex;
  flex-direction: column;
}
.notice {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  padding: 9px 16px;
  background: #fdf3e7;
  color: #7a4a18;
  border-bottom: 1px solid rgba(179,110,30,.35);
  font-size: 13px;
  box-shadow: 0 1px 6px rgba(0,0,0,.08);
}
.notice button {
  padding: 2px 10px;
  font-size: 12px;
  border-color: rgba(179,110,30,.4);
  color: #7a4a18;
}

/* Ein Bild, das seinen Quelltext kennt, lässt sich anklicken. Der Zeiger sagt
   das an, ohne dass etwas am Bild selbst zu sehen wäre. */
.page image.selectable { cursor: pointer; }
.page image.selectable:hover { outline: 2px solid var(--accent); }
/* Das gewählte Bild bleibt markiert, solange der Dialog offen ist. */
.page image.chosen { outline: 2px solid var(--accent); }

/* Der Ort einer Tabellenzelle, über dem Diff. */
.cell-place {
  margin-bottom: 5px;
  font-size: 11.5px;
  color: var(--muted);
}

.reply-field { margin-top: 6px; }
.reply-field textarea {
  width: 100%;
  font: 12px/1.45 inherit;
  padding: 5px 7px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg);
  color: var(--ink);
  resize: vertical;
}
.reply-field textarea:focus {
  outline: 2px solid var(--accent);
  outline-offset: -1px;
}

/* Erscheint bei einer Markierung im Quelltext. */
.comment-button {
  position: absolute;
  right: 14px;
  bottom: 14px;
  background: var(--accent);
  color: #fff;
  border-color: transparent;
  box-shadow: 0 2px 8px rgba(0,0,0,.18);
  z-index: 2;
}
.comment-button:hover { background: #275c41; }
.comment-button[hidden] { display: none; }

/* In der Seite sitzt der Knopf an der Auswahl statt in der Ecke. */
/* Der Knopf für einen angeklickten Gegenstand: oben rechts, wo er auch bei
   einer seitenfüllenden Tabelle sichtbar bleibt. */
.comment-button.subject {
  position: absolute;
  top: 12px;
  right: 12px;
  z-index: 5;
}
.comment-button.subject[hidden] { display: none; }

.comment-button.floating {
  position: absolute;
  right: auto;
  bottom: auto;
  padding: 3px 10px;
  font-size: 12px;
  z-index: 3;
}

/* ── Ein- und ausgeklappte Karten ───────────────────────────────────── */

/* Eingeklappt ist die Karte eine Zeile hoch: Name und der Anfang des Textes.
   Bei zehn Anmerkungen auf einer Seite entscheidet das darüber, ob man den
   Rand noch lesen kann. */
.page-margin .comment:not(.open) .what {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.page-margin .comment:not(.open) { padding: 6px 10px; }
.page-margin .comment:not(.open) .row { display: none; }

.page-margin .comment.open {
  box-shadow: 0 3px 14px rgba(0,0,0,.14);
  z-index: 4;
}
.page-margin .comment.open .row { opacity: 1; }

/* Eine wartende Änderung fällt auf — sie will eine Entscheidung. */
.page-margin .comment.proposing { border-left-color: var(--accent); }

.comment .more {
  margin-top: 3px;
  color: var(--muted);
  font-size: 11px;
}

/* Das Zeichen hinter dem Namen sagt eingeklappt, ob eine Änderung drinsteckt
   und wie sie steht. */
.comment .badge {
  margin-left: 5px;
  font-weight: 400;
  color: var(--muted);
}
.comment .badge.open { color: var(--accent); font-weight: 600; }
.comment .badge.declined,
.comment .badge.stale { color: rgba(179,38,30,.7); }

/* ── Änderung im Kommentardialog ────────────────────────────────────── */

.propose {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 8px;
  color: var(--muted);
  font-size: 12.5px;
  cursor: pointer;
}
.propose input { margin: 0; accent-color: var(--accent); }
#comment-edit { margin-top: 6px; }
#comment-edit[hidden] { display: none; }

/* ── Telefon ────────────────────────────────────────────────────────── */

/* Auf einem Telefon ist Folium ein Betrachter: nur die Seiten, passgenau.
   Als Media-Query, nicht als JS-Klasse: Das Aussehen darf nicht davon
   abhängen, dass ein Skript gelaufen ist. app.js setzt zusätzlich die
   Klasse `phone` für das Verhalten (Zoom einpassen, Auswahl aus). */

@media (pointer: coarse) and (max-width: 820px) {
  /* Die Kopfzeile trägt nur die Wortmarke und den Projektnamen. Alles
     andere — Zoom, Lesemodus, Teilen, Statistik, Anwesende, Anmeldung —
     ist Mausbedienung oder Platzverschwendung auf 400 Pixeln. */
  header {
    padding-top: max(7px, env(safe-area-inset-top));
    padding-left: max(14px, env(safe-area-inset-left));
    padding-right: max(14px, env(safe-area-inset-right));
  }
  .zoom,
  #share,
  #more,
  .nav-back,
  .toggle,
  .stat,
  .who-bar { display: none; }

  /* Nur die Seiten — wie der Lesemodus, aber unabhängig von ihm. */
  main { grid-template-columns: 1fr; }
  .files,
  .source,
  #diagnostics { display: none; }

  .preview {
    padding: 8px 8px calc(8px + env(safe-area-inset-bottom));
    /* Ruckfreies Wischen auf iOS. */
    -webkit-overflow-scrolling: touch;
  }
  .pages { gap: 10px; }

  /* Die Kommentarkarten brauchen eine Randspalte, die es hier nicht gibt.
     Die Markierungen im Text bleiben sichtbar. */
  .preview:has(.page-margin) .pages { margin-right: 0; }
  .page-margin { display: none; }

  /* Erkenntnisse aus dem PWA-Versuch (docs/mobile.md): Der lange Druck auf
     Text öffnet sonst Apples Menü, und Textknoten fangen Berührungen ab. */
  .page,
  .page text {
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    user-select: none;
  }
  .page text,
  .page tspan { pointer-events: none; }

  /* Der Kommentierknopf hängt an der Mausauswahl. */
  .comment-button { display: none; }

  /* Der bleibende Hinweis muss unter die Kopfzeile rutschen können. */
  #notices { top: env(safe-area-inset-top); }

  /* Fingerfläche: Der unsichtbare Strich zählt zur Trefffläche der
     Markierung — 14px mehr in jede Richtung, ohne sichtbar zu sein. */
  .comment-mark {
    stroke: transparent;
    stroke-width: 20;
  }

  /* Auf dem Telefon muss das Blatt die Home-Anzeige aussparen. */
  #thread-sheet {
    padding-bottom: calc(12px + env(safe-area-inset-bottom));
  }
  #thread-sheet .comment { border: 0; padding: 4px 0 0; }
  /* Kein Hover auf dem Telefon: Die Bedienzeile blendet am Desktop erst
     beim Überfahren ein — hier muss sie von Anfang an dastehen. */
  #thread-sheet .comment .row { opacity: 1; }
  /* Die Auswahlzeilen, wenn mehrere Anmerkungen auf einer Stelle liegen. */
  .thread-choice {
    display: block;
    width: 100%;
    text-align: left;
    padding: 10px 12px;
    margin-bottom: 6px;
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: var(--bg);
  }
  .thread-choice .who { font-weight: 550; margin-right: 8px; }
  .thread-choice .what {
    color: var(--muted);
    display: block;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  /* Fingerfreundliche Knöpfe: Übernehmen und Ablehnen sind die Handlung,
     derentwegen das Blatt existiert. */
  #thread-sheet .comment .row button {
    padding: 8px 14px;
    font-size: 14px;
  }
  #thread-sheet textarea { font-size: 16px; } /* verhindert iOS-Autozoom */
}
