/* =============================================================================
   f(x) · styles — im Geiste von LoveFrom: klassische Serife, warmes Papier,
   nahezu monochrom, sehr still. Hell & Dunkel.
   ============================================================================= */
:root {
  --serif: "Hoefler Text", "Iowan Old Style", "Palatino Linotype",
           "Book Antiqua", Palatino, Georgia, Cambria, "Times New Roman", serif;

  --bg: #F1F1F0;             /* neutrales Papier, kein Gelbstich */
  --panel: rgba(250, 250, 249, 0.86);
  --panel-solid: #FBFBFA;
  --panel-border: rgba(28, 28, 32, 0.12);
  --shadow: 0 10px 44px rgba(18, 18, 22, 0.12), 0 1px 2px rgba(18, 18, 22, 0.06);
  --shadow-soft: 0 6px 26px rgba(18, 18, 22, 0.10);
  --ink: #242427;
  --text: #242427;
  --text-2: #646469;
  --text-3: #97979D;
  --hair: rgba(28, 28, 32, 0.10);
  --fill: rgba(20, 20, 24, 0.045);
  --fill-hover: rgba(20, 20, 24, 0.075);
  --accent: #6E88A6;         /* Schiefer, sehr sparsam */
  --danger: #A24A3A;
  --radius-lg: 18px;
  --radius: 12px;
  --radius-sm: 9px;
  /* Luft am Rand der wischbaren Leisten (Dock, Spiegel-Achse): so viel Raum
     bleibt am Scroll-Anschlag neben dem äußersten Segment stehen — zugleich
     der Raum, in dem Kapsel und Unterstreichung stehen dürfen, ohne vom
     Scroll-Rand abgeschnitten zu werden. Zusammen mit der Polsterung der
     Leiste ergibt sich seitlich derselbe Abstand wie unten. */
  --seg-edge: 4px;
  /* Die Auswahlkapsel hat einen feinen Schatten. Dieser Sicherheitsabstand
     hält auch dessen Außenkante innerhalb der sichtbaren Leiste. */
  --seg-pill-safe: 4px;
  --ease: cubic-bezier(0.32, 0.72, 0, 1);
}
:root[data-theme="dark"] {
  --bg: #161617;             /* neutrale Kohle, kein Braunstich */
  --panel: rgba(32, 32, 34, 0.82);
  --panel-solid: #202022;
  --panel-border: rgba(236, 236, 240, 0.13);
  --shadow: 0 10px 44px rgba(0, 0, 0, 0.5), 0 1px 2px rgba(0, 0, 0, 0.4);
  --shadow-soft: 0 6px 26px rgba(0, 0, 0, 0.42);
  --ink: #ECECEE;
  --text: #ECECEE;
  --text-2: #9A9AA0;
  --text-3: #66666C;
  --hair: rgba(236, 236, 240, 0.11);
  --fill: rgba(236, 236, 240, 0.06);
  --fill-hover: rgba(236, 236, 240, 0.11);
  --accent: #7FA0B8;
  --danger: #C56E5C;
}
@media (prefers-color-scheme: dark) {
  :root[data-theme="auto"] {
    --bg: #161617;
    --panel: rgba(32, 32, 34, 0.82);
    --panel-solid: #202022;
    --panel-border: rgba(236, 236, 240, 0.13);
    --shadow: 0 10px 44px rgba(0, 0, 0, 0.5), 0 1px 2px rgba(0, 0, 0, 0.4);
    --shadow-soft: 0 6px 26px rgba(0, 0, 0, 0.42);
    --ink: #ECECEE;
    --text: #ECECEE;
    --text-2: #9A9AA0;
    --text-3: #66666C;
    --hair: rgba(236, 236, 240, 0.11);
    --fill: rgba(236, 236, 240, 0.06);
    --fill-hover: rgba(236, 236, 240, 0.11);
    --accent: #7FA0B8;
    --danger: #C56E5C;
  }
}

* {
  margin: 0; padding: 0; box-sizing: border-box;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
}
html, body { height: 100%; overflow: hidden; }
button:focus, button:focus-visible { outline: none; }
body {
  font-family: var(--serif);
  font-feature-settings: "onum" 1, "liga" 1, "kern" 1;
  background: var(--bg);
  color: var(--text);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  user-select: none;
  -webkit-user-select: none;
}

#app { position: fixed; inset: 0; }
canvas {
  position: absolute; inset: 0; width: 100%; height: 100%; display: block;
  /* Ohne dies deutet der Browser Wischen als Scrollen/Zoomen, bricht den
     laufenden Zeiger mit `pointercancel` ab — und man müsste absetzen. */
  touch-action: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
}
#base { z-index: 1; }
#overlay { z-index: 2; pointer-events: none; }
#base { cursor: crosshair; }
#base.grabbing { cursor: grabbing; }
#base.reading { cursor: crosshair; }

/* ---------------------------------------------------------------------------
   Panel (Funktionen) — wie eine Karte aus feinem Papier
   --------------------------------------------------------------------------- */
.panel {
  position: absolute;
  top: 20px; left: 20px;
  width: 300px;
  /* Untere Grenze ist stets der Dock — nie der bloße Fensterrand — damit
     .panel den Dock unter keinen Umständen berührt. --pill-bottom (app.js,
     updateDockGapVar) ist bereits "Dock-Abstand + Dock-Höhe + 12px" und
     wird beim Resize aktuell gehalten, ganz gleich, wie schmal das Fenster
     wird. */
  max-height: calc(100vh - 20px - var(--pill-bottom, 95px));
  z-index: 5;
  background: var(--panel);
  -webkit-backdrop-filter: saturate(140%) blur(16px);
  backdrop-filter: saturate(140%) blur(16px);
  border: 1px solid var(--panel-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  padding: 14px;
  display: flex;
  flex-direction: column;
  transition: transform 0.5s var(--ease), opacity 0.35s var(--ease);
  overflow: hidden;
}
.panel.collapsed { transform: translateX(-120%); opacity: 0; pointer-events: none; }

/* Untere Einblendung im Weg (Tastatur, Objekt-Eingabe, Spiegel-Achse,
   Hinweis): Position/Größe von .panel bleiben unverändert, solange über dem
   Dock genug Platz für beides bleibt UND sie sich horizontal gar nicht in die
   Quere kommen (stehen sie nebeneinander, ist die Fensterhöhe allein kein
   Grund zu schrumpfen). Ob eine echte Bounding-Box-Überschneidung droht,
   ermittelt keyboard.js geometrisch und setzt dafür body.panel-collide — und
   zwar nur bei einer tatsächlichen Änderung dieses Zustands (nicht bei jedem
   Resize-Tick oder bloßem Fokuswechsel zwischen Eingabefeldern), wodurch kein
   Flackern entsteht.

   --panel-avail-h ist die dabei gemessene Resthöhe bis zur obersten
   überschneidenden Einblendung, bereits ab der Oberkante von .panel gerechnet
   (deshalb hier ohne top-Abzug — in jedem Breakpoint dieselbe Zeile). */
body.panel-collide .panel {
  max-height: min(
    calc(100vh - 20px - var(--pill-bottom, 95px)),
    var(--panel-avail-h, 100vh)
  );
}

/* .panel-h-anim wird von keyboard.js exakt für die Dauer einer echten
   Höhenänderung gesetzt (siehe syncPanel) — max-height bleibt daher
   standardmäßig ohne transition (kein Flackern bei normalem Resize) und
   animiert nur dann, wirklich weich, in derselben Dauer/Kurve wie math-kb
   (siehe .math-kb weiter unten).

   Animiert wird dabei eine von keyboard.js gesetzte Inline-max-height in
   Pixeln, nicht der obige calc()-Wert: .panel ist inhaltsgesteuert hoch und
   die calc()-Grenze liegt weit über der echten Höhe — von dort aus zu
   animieren ließe das Panel erst auf seine natürliche Höhe wachsen und
   danach sichtbar zusammenfahren. */
.panel.panel-h-anim {
  transition: transform 0.5s var(--ease), opacity 0.35s var(--ease), max-height 0.32s var(--ease);
}

.panel-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 2px 4px 14px 6px;
}
.wordmark {
  font-family: var(--serif);
  font-style: italic;
  font-size: 25px; font-weight: 500; letter-spacing: 0.01em;
  color: var(--ink);
}
.wordmark .paren { color: var(--text-3); font-style: italic; }

.panel-scroll {
  flex: 1 1 auto; min-height: 0;
  display: flex; flex-direction: column;
  overflow-y: auto;
}
.panel-scroll::-webkit-scrollbar { width: 0; }
.fn-list { display: flex; flex-direction: column; }

/* Gruppe pro Funktion: Kopfzeile + aufklappbare Objektliste */
.fn-group + .fn-group { border-top: 1px solid var(--hair); }

.fn-row {
  display: flex; align-items: center; gap: 9px;
  border-radius: var(--radius);
  padding: 10px 8px 10px 2px;
  transition: background 0.2s var(--ease);
  position: relative;
}
.fn-row:hover { background: var(--fill); }
.fn-row.invalid .fn-label { color: var(--danger); }

.fn-chevron {
  width: 22px; height: 22px; flex-shrink: 0;
  border: none; background: transparent; padding: 0;
  display: grid; place-items: center;
  color: var(--text-3); cursor: pointer;
  transition: transform 0.4s var(--ease), opacity 0.25s var(--ease), color 0.2s;
}
.fn-chevron:hover { color: var(--ink); }
.fn-group.open > .fn-row .fn-chevron { transform: rotate(90deg); }
.fn-chevron.none { opacity: 0; pointer-events: none; }

.fn-objects {
  display: grid; grid-template-rows: 0fr;
  transition: grid-template-rows 0.45s var(--ease), opacity 0.35s var(--ease);
  opacity: 0;
}
.fn-group.open .fn-objects { grid-template-rows: 1fr; opacity: 1; }
.fn-objects > div { overflow: hidden; }
.fn-objects .obj-inner { padding: 0 4px 10px 30px; }

.obj-label {
  font-style: italic; font-size: 12px; color: var(--text-3);
  padding: 7px 10px 3px 8px;
}

.fn-dot {
  width: 12px; height: 12px; border-radius: 50%;
  flex-shrink: 0; cursor: pointer;
  transition: transform 0.18s var(--ease);
}
.fn-dot:hover { transform: scale(1.18); }
.fn-dot.off { background: transparent !important; box-shadow: inset 0 0 0 1.5px var(--text-3); }

.fn-body { flex: 1; min-width: 0; display: flex; align-items: baseline; gap: 6px; }
.fn-label {
  font-family: var(--serif); font-style: italic;
  font-size: 16px; color: var(--text-2); flex-shrink: 0;
}

/* Term-Feld: gesetzte Anzeige (fn-pretty) und Eingabe (fn-input) teilen sich den Platz. */
.fn-field { flex: 1; min-width: 0; }

.fn-input {
  width: 100%; min-width: 0;
  border: none; outline: none; background: transparent;
  font-family: var(--serif);
  font-size: 16px; color: var(--text);
  letter-spacing: 0.01em;
  font-feature-settings: "onum" 1;
  caret-color: var(--accent);
  display: none;
}
.fn-input::placeholder { color: var(--text-3); font-style: italic; }

/* Gesetzter, nur lesbarer Term — echte Hochzahlen, gut zu markieren & kopieren. */
.fn-pretty {
  display: none;
  min-width: 0; cursor: text;
  font-family: var(--serif);
  font-size: 16px; color: var(--text);
  letter-spacing: 0.01em;
  font-feature-settings: "onum" 1;
  line-height: 1.35;
  white-space: nowrap; overflow-x: auto; overflow-y: hidden;
  scrollbar-width: none;
  border-radius: 5px;
  outline: none;
}
.fn-pretty::-webkit-scrollbar { height: 0; }
.fn-pretty::selection { background: color-mix(in srgb, var(--accent, #b8860b) 26%, transparent); }
.fn-pretty:focus-visible { box-shadow: 0 0 0 2px color-mix(in srgb, var(--text-3) 55%, transparent); }

/* ---------------------------------------------------------------------------
   Zweidimensional gesetzte Terme (Schulbuch- / GeoGebra-Stil).
   Erzeugt von FX.termToRichHtml. Erscheint überall, wo ein Funktionsterm steht
   (gesetzter Term, Ableitungen, Spiegelungen). Maße in em, damit es sich der
   jeweiligen Schriftgröße (Panel-Term wie Objektzeile) anpasst.
   --------------------------------------------------------------------------- */
sup { font-size: 0.72em; line-height: 0; }

/* Bruch — Zähler über Nenner, dünner Bruchstrich. */
.fx-frac {
  display: inline-flex; flex-direction: column;
  vertical-align: middle; text-align: center;
  margin: 0 0.16em;
}
.fx-num { padding: 0 0.34em 0.08em; border-bottom: 1.1px solid currentColor; }
.fx-den { padding: 0.06em 0.34em 0; }
.fx-num, .fx-den { display: block; line-height: 1.18; }

/* Wurzel — Radikalzeichen + Radikand mit Überstrich (Vinkulum). */
.fx-root { display: inline-flex; align-items: stretch; white-space: nowrap; }
.fx-radsign {
  display: inline-flex; align-items: flex-end;
  font-size: 1.02em; line-height: 1;
  transform: scaleY(1.12); transform-origin: bottom;
  margin-right: 0.02em;
}
.fx-radicand {
  border-top: 1.1px solid currentColor;
  padding: 0.12em 0.24em 0 0.14em;
}
.fx-rootidx {
  font-size: 0.62em; align-self: flex-start;
  margin-right: -0.32em; transform: translateY(-0.15em);
}

/* Betrag — senkrechte Balken, die mit dem Inhalt mitwachsen. */
.fx-abs {
  display: inline-flex;
  border-left: 1.1px solid currentColor; border-right: 1.1px solid currentColor;
  padding: 0 0.24em; margin: 0 0.1em;
}

/* Operatorwort (mod) tritt leicht zurück. */
.fx-op { font-style: italic; color: var(--text-2); padding: 0 0.1em; }

/* Sichtbarkeit: gesetzter Term im Ruhezustand, Eingabefeld beim Bearbeiten/leer. */
.fn-field.has-pretty:not(.editing) .fn-pretty { display: block; }
.fn-field.editing .fn-input,
.fn-field:not(.has-pretty) .fn-input { display: block; }

.fn-copy, .fn-remove {
  opacity: 0; width: 20px; height: 20px; flex-shrink: 0;
  border: none; background: transparent; color: var(--text-3);
  cursor: pointer; border-radius: 50%; display: grid; place-items: center;
  transition: opacity 0.18s, color 0.18s;
}
.fn-remove { opacity: 1; }
.fn-copy { margin-left: 2px; }
.fn-row:hover .fn-copy.avail { opacity: 1; }
.fn-copy:hover { color: var(--ink); }
.fn-remove:hover { color: var(--danger); }

.fn-error {
  font-family: var(--serif); font-style: italic;
  font-size: 13px; color: var(--danger);
  padding: 2px 12px 4px; line-height: 1.4;
}

/* Steht außerhalb von .panel-scroll (siehe index.html) — dadurch fest am
   unteren Rand von .panel angepinnt, nie mit wegscrollbar, immer klickbar. */
.add-fn {
  flex-shrink: 0;
  margin-top: 8px; align-self: flex-start;
  display: flex; align-items: center; gap: 7px;
  border: none; background: transparent;
  color: var(--text-2); font-family: var(--serif); font-style: italic;
  font-size: 15px;
  cursor: pointer; padding: 8px 8px; border-radius: var(--radius);
  transition: color 0.2s var(--ease);
}
.add-fn svg { opacity: 0.7; }
.add-fn:hover { color: var(--ink); }

/* Objektzeilen innerhalb einer Gruppe */
.measure {
  display: flex; align-items: center; gap: 10px;
  padding: 6px 8px; border-radius: var(--radius-sm);
  font-size: 13.5px;
  transition: background 0.18s;
}
.measure:hover { background: var(--fill); cursor: pointer; }
.measure.sel { background: var(--fill); }
.measure .m-swatch {
  width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0;
  cursor: pointer;
  transition: transform 0.18s var(--ease);
}
.measure .m-swatch:hover { transform: scale(1.35); }
.measure .m-swatch.off { background: transparent !important; box-shadow: inset 0 0 0 1.5px var(--text-3); }
.measure.hidden .m-text { opacity: 0.45; }
.measure .m-text { flex: 1; min-width: 0; color: var(--text); }
.measure .m-text b { font-weight: 600; font-feature-settings: "onum" 1; }
/* „keine Tangente“ (Knick/Sprung/senkrecht): eine Aussage, kein Wert —
   deshalb zurückgenommen gesetzt statt wie eine Gleichung ausgezeichnet. */
.measure .m-text b.m-none { font-weight: 500; color: var(--text-2); }
.measure .m-text .m-kind {
  color: var(--text-2); font-size: 12.5px; font-style: italic; display: block; margin-top: 1px;
}
.measure .m-copy {
  opacity: 0; width: 18px; height: 18px; flex-shrink: 0;
  border: none; background: transparent; color: var(--text-3);
  cursor: pointer; border-radius: 50%; display: grid; place-items: center;
  transition: opacity 0.18s, color 0.18s;
}
.measure:hover .m-copy { opacity: 1; }
.measure .m-copy:hover { color: var(--ink); }
.measure .m-remove {
  border: none; background: transparent; color: var(--text-3);
  cursor: pointer; font-size: 17px; line-height: 1; padding: 2px;
  transition: color 0.15s;
}
.measure .m-remove:hover { color: var(--danger); }

/* ---------------------------------------------------------------------------
   Bedienelemente — zurückhaltend, typografisch
   --------------------------------------------------------------------------- */
.icon-btn {
  width: 40px; height: 40px;
  display: grid; place-items: center;
  margin: 2px;
  border: none;
  background: transparent;
  color: var(--text-2);
  border-radius: 50%;
  cursor: pointer;
  transition: color 0.2s var(--ease), background 0.2s var(--ease), transform 0.15s var(--ease);

  /* BUTTON PANEL */
  background: var(--panel);
  -webkit-backdrop-filter: blur(16px); backdrop-filter: blur(16px);
  box-shadow: var(--shadow-soft);
  /*  */
}
.icon-btn.ghost { width: 30px; height: 30px; }
/*.icon-btn:hover { color: var(--ink); background: var(--fill); }*/
.icon-btn:active { transform: scale(0.92); }
.icon-btn.active { color: var(--ink); }

.top-right {
  position: absolute; top: 22px; right: 22px; z-index: 5;
  display: flex; gap: 6px;
}

.panel-reveal {
  position: absolute; top: 22px; left: 22px; z-index: 5;
  opacity: 0; transform: translateX(-8px); pointer-events: none;
  transition: opacity 0.35s var(--ease), transform 0.35s var(--ease);
  background: var(--panel);
  -webkit-backdrop-filter: blur(16px); backdrop-filter: blur(16px);
  box-shadow: var(--shadow-soft);
}
.panel-reveal.show { opacity: 1; transform: none; pointer-events: auto; }

.dock {
  position: absolute; bottom: 24px; left: 50%; transform: translateX(-50%);
  z-index: 5;
  display: flex; align-items: stretch; gap: 0; padding: 7px 10px 8px;
  background: var(--panel);
  -webkit-backdrop-filter: saturate(140%) blur(16px);
  backdrop-filter: saturate(140%) blur(16px);
  border: 1px solid var(--panel-border);
  border-radius: 16px;
  box-shadow: var(--shadow);
}
/* Jede Absicht ist eine kleine Spalte: leise Überschrift + ihre Werkzeuge */
.dock-group {
  display: flex; flex-direction: column; align-items: center;
  gap: 3px; padding: 0;
}
.dock-cap {
  font-family: var(--serif); font-style: italic;
  font-size: 11px; letter-spacing: 0.03em; line-height: 1;
  color: var(--text-3);
}
.dock-tools { display: flex; gap: 2px; }
.seg-pill { display: none; }   /* nur auf Smartphones aktiviert, siehe unten */
.dock button {
  position: relative;
  border: none; background: transparent;
  color: var(--text-2);
  font-family: var(--serif); font-size: 15.5px; letter-spacing: 0.01em;
  padding: 6px 9px 8px; border-radius: 9px;
  cursor: pointer;
  transition: color 0.22s var(--ease);
}
.dock button:hover { color: var(--ink); }         /* text-forward, keine Pille */
.dock button.active { color: var(--ink); }
.dock button.active::after {
  content: ''; position: absolute; left: 14px; right: 14px; bottom: 3px;
  height: 1.5px; background: var(--ink); border-radius: 1px;
}
.dock-sep {
  width: 1px; align-self: stretch; flex-shrink: 0;
  margin: 2px 3px; background: var(--hair);
}

@media (max-width: 760px) {
  .dock { padding: 6px 6px 7px; }
  .dock-group { padding: 0 3px; }
  .dock button { padding: 6px 9px 8px; }
  .dock button.active::after { left: 9px; right: 9px; }
  .dock-cap { font-size: 10px; }
  .dock-sep { margin: 2px 2px; }
}

/* Berührung statt Maus: Kopieren/Entfernen können nicht erst beim Hover
   erscheinen, sonst bleiben sie auf Touch-Geräten unerreichbar. */
@media (hover: none) and (pointer: coarse) {
  .fn-copy.avail, .fn-remove, .measure .m-copy { opacity: 1; }
}

/* ---------------------------------------------------------------------------
   Smartphone — schmale Bildschirme (Hochformat wie Querformat).
   Kopfzeile (Panel) und Steuerung (oben rechts) stehen übereinander statt
   nebeneinander, das Dock wird bei Bedarf horizontal wischbar statt zu quetschen.
   --------------------------------------------------------------------------- */
@media (max-width: 640px) {
  .top-right { top: 14px; right: 14px; }
  .panel, .panel-reveal { top: 66px; left: 14px; }
  .panel {
    right: 14px; width: auto; bottom: auto; margin: 0;
    max-height: calc(100vh - 66px - var(--pill-bottom, 95px));
  }
  .panel-reveal.show { top: 14px; }

  /* Untere Einblendung im Weg: Position bleibt (top: 66px), die
     Höhenbegrenzung weicht nur zusätzlich zurück, falls die Einblendung mehr
     Raum braucht als der Dock ohnehin schon reserviert — und nur, wenn sich
     beide laut keyboard.js tatsächlich geometrisch überschneiden würden (auf
     dem Smartphone ist .panel nahezu bildschirmbreit, das ist praktisch fast
     immer der Fall). */
  body.panel-collide .panel {
    max-height: min(
      calc(100vh - 66px - var(--pill-bottom, 95px)),
      var(--panel-avail-h, 100vh)
    );
  }

  /* Die schmale Fassung der Spiegel-Achse steht bei ihren Grundregeln weiter
     unten – sie überschreibt deren Polsterung und muss deshalb danach kommen. */
}

/* Ein echtes Telefon kann – etwa bei aktivierter Desktop-Darstellung oder in
   manchen eingebetteten Browsern – eine Viewportbreite über 640 CSS-Pixel
   melden. Die Größe des Funktions-Panels darf deshalb nicht ausschließlich an
   diesem Breiten-Breakpoint hängen. Für reine Touch-Geräte reservieren wir
   stets die Bildschirmränder; das Panel füllt nur den wirklich verfügbaren
   Bereich und bleibt auch bei dynamischer Browserleiste innerhalb des
   sichtbaren Viewports. */
@media (hover: none) and (pointer: coarse) {
  .top-right { top: 14px; right: 14px; }
  .panel, .panel-reveal { top: 66px; left: 14px; }
  .panel {
    right: 14px;
    width: auto;
    bottom: auto;
    margin: 0;
    max-height: calc(100vh - 66px - var(--pill-bottom, 95px));
    max-height: calc(100dvh - 66px - var(--pill-bottom, 95px));
  }
  .panel-reveal.show { top: 14px; }

  body.panel-collide .panel {
    max-height: min(
      calc(100vh - 66px - var(--pill-bottom, 95px)),
      var(--panel-avail-h, 100vh)
    );
    max-height: min(
      calc(100dvh - 66px - var(--pill-bottom, 95px)),
      var(--panel-avail-h, 100dvh)
    );
  }
}

/* Dock passt nicht mehr verzerrungsfrei in die verfügbare Breite – egal ob
   Smartphone oder ein schmales Desktop-Fenster: app.js misst die tatsächlich
   benötigte Breite gegen die verfügbare (siehe updateDockCompact) und setzt
   dafür ausschließlich diese Klasse, nie eine Geräte-Abfrage. Dieselben
   Regeln wie zuvor unter @media (max-width: 640px), jetzt an den echten
   Platzbedarf gekoppelt statt an eine feste Fensterbreite. */
.dock.dock-compact {
  max-width: calc(100vw - 20px);
  /* var(--seg-edge) + 3px Polsterung der .dock-group = 7px seitlich,
     genau der untere Innenabstand — wie bei der Spiegel-Achse. */
  padding-left: var(--seg-edge); padding-right: 0;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  justify-content: flex-start;
}
.dock.dock-compact::-webkit-scrollbar { display: none; }
.dock.dock-compact::after { content: ''; flex: 0 0 var(--seg-edge); }   /* siehe .ma-seg::after */
.dock.dock-compact .dock-group { flex-shrink: 0; }

/* Nur auf echten Smartphones (schmal + grobes Zeigegerät): die Auswahl folgt
   dem iOS-Kamera-Wähler — eine Kapsel, die beim Wischen über die GESAMTE
   Leiste (gruppenübergreifend) gleitet, statt der textbetonten
   Unterstreichung für Maus/Trackpad. Gewählt wird per Wischen ODER Antippen;
   beides führt die Leiste, eine eigene Tap-Rückmeldung gibt es nicht — die
   Kapsel wandert an die neue Auswahl. Die Trennlinien zwischen den Absichten (Ansicht · Funktion ·
   Messen) bleiben rein optisch. */
@media (max-width: 640px) and (pointer: coarse) {
  /* Horizontales Scrollen gehört uns (Wisch-Wähler), nicht dem Browser.
     Kein grauer Tap-Blitz, keine Textauswahl beim Ziehen. Die Spiegel-Achse
     bekommt exakt dieselbe Behandlung wie das Dock (siehe unten). */
  .dock, .mirror-axis .ma-seg {
    touch-action: pan-y;
    -webkit-tap-highlight-color: transparent;
    -webkit-user-select: none; user-select: none;
  }
  .seg-pill {
    display: block;
    position: absolute; left: 0; top: 0;
    width: 0; height: 0; border-radius: 8px;
    background: var(--panel-solid);
    box-shadow: 0 1px 3px rgba(18, 18, 22, 0.16), 0 0 0 0.5px var(--panel-border);
    /* Kurz gehalten: die Kapsel folgt einem direkt geführten Finger — eine
       längere Kurve würde ihm sichtbar hinterherhinken. */
    transition: transform 0.16s var(--ease), width 0.16s var(--ease), height 0.16s var(--ease), opacity 0.18s var(--ease);
    opacity: 0; pointer-events: none; z-index: 0;
  }
  .seg-pill.seg-ready { opacity: 1; }
  /* Antippen statt Wischen: die Leiste nimmt sich hier mehr Zeit (siehe
     revealScrollTo, `gentle`), also darf die Kapsel ihr nicht davoneilen. */
  .dock.seg-gentle .seg-pill,
  .mirror-axis .ma-seg.seg-gentle .seg-pill {
    transition: transform 0.34s var(--ease), width 0.34s var(--ease), height 0.34s var(--ease), opacity 0.18s var(--ease);
  }
  /* Die Buttons sind reine Beschriftung: Wisch UND Antippen werden vom Dock
     selbst behandelt (siehe initSwipeSeg), die Knöpfe nehmen keine
     Zeigereignisse an. Damit gibt es beim Antippen weder Hover-/Aktiv-Farbe
     noch Hinterlegung noch Fokusring — einzig „.active“ (die Auswahl) färbt
     den Text. */
  .dock button,
  .mirror-axis .ma-seg button {
    position: relative; z-index: 1;
    pointer-events: none;
    cursor: default;
    -webkit-tap-highlight-color: transparent;
  }
  .dock button:hover,
  .dock button:active,
  .dock button:focus,
  .dock button:focus-visible,
  .mirror-axis .ma-seg button:hover,
  .mirror-axis .ma-seg button:active,
  .mirror-axis .ma-seg button:focus,
  .mirror-axis .ma-seg button:focus-visible {
    color: var(--text-2);            /* unverändert — nur .active hebt sich ab */
    background: transparent;
    outline: none; box-shadow: none;
  }
  .dock button.active,
  .dock button.active:hover,
  .dock button.active:active,
  .mirror-axis .ma-seg button.active,
  .mirror-axis .ma-seg button.active:hover,
  .mirror-axis .ma-seg button.active:active { color: var(--ink); background: transparent; }
  .dock button.active::after,
  .mirror-axis .ma-seg button.active::after { display: none; }   /* Kapsel ersetzt die Linie */
}

/* ---------------------------------------------------------------------------
   Objekt-Eingabe (Punkt / Tangente) — Pille über dem Dock
   --------------------------------------------------------------------------- */
.tool-input {
  position: absolute; bottom: var(--pill-bottom, 95px); left: 50%;
  transform: translateX(-50%) translateY(8px);
  z-index: 5;
  display: flex; align-items: center; gap: 8px;
  padding: 6px 6px 6px 14px;
  background: var(--panel);
  -webkit-backdrop-filter: saturate(140%) blur(16px);
  backdrop-filter: saturate(140%) blur(16px);
  border: 1px solid var(--panel-border);
  border-radius: 12px;
  box-shadow: var(--shadow-soft);
  opacity: 0; pointer-events: none;
  transition: opacity 0.3s var(--ease), transform 0.3s var(--ease), bottom 0.3s var(--ease);
}
.tool-input.show { opacity: 1; pointer-events: auto; transform: translateX(-50%) translateY(0); }
body.kb-open .tool-input { bottom: calc(var(--kb-h, 0px) + 12px); }
.tool-input .ti-label {
  font-family: var(--serif); font-style: italic;
  font-size: 15px; color: var(--text-2); flex-shrink: 0;
}
.tool-input input {
  width: 168px; border: none; outline: none; background: transparent;
  font-family: var(--serif); font-size: 15.5px; color: var(--text);
  letter-spacing: 0.01em; font-feature-settings: "onum" 1;
  caret-color: var(--accent);
}
.tool-input input::placeholder { color: var(--text-3); font-style: italic; }
.tool-input.invalid input, .tool-input.invalid input::placeholder { color: var(--danger); }
.tool-input .ti-add {
  width: 30px; height: 30px; flex-shrink: 0;
  border: none; background: var(--fill); color: var(--text-2);
  border-radius: 8px; display: grid; place-items: center; cursor: pointer;
  transition: color 0.2s var(--ease), background 0.2s var(--ease);
}
.tool-input .ti-add:hover { color: var(--ink); background: var(--fill-hover); }
.tool-input .ti-add:active { transform: scale(0.94); }

/* ---------------------------------------------------------------------------
   Spiegel-Achse — Segment-Wähler über dem Dock (nur im Spiegeln-Werkzeug)
   --------------------------------------------------------------------------- */
.mirror-axis {
  position: absolute; bottom: var(--pill-bottom, 95px); left: 50%;
  transform: translateX(-50%) translateY(8px);
  z-index: 5;
  display: flex; align-items: stretch; gap: 0; padding: 7px 10px 8px;
  background: var(--panel);
  -webkit-backdrop-filter: saturate(140%) blur(16px);
  backdrop-filter: saturate(140%) blur(16px);
  border: 1px solid var(--panel-border);
  border-radius: 16px;
  box-shadow: var(--shadow);
  opacity: 0; pointer-events: none;
  /* bottom mitanimieren wie bei .tool-input: klappt die Tastatur auf, wandert
     die Leiste sonst ohne Übergang nach oben. */
  transition: opacity 0.3s var(--ease), transform 0.3s var(--ease), bottom 0.3s var(--ease);
}
.mirror-axis.show { opacity: 1; pointer-events: auto; transform: translateX(-50%) translateY(0); }
.mirror-axis .ma-label {
  display: flex; align-items: center;
  font-family: var(--serif); font-style: italic;
  font-size: 15px; color: var(--text-2); flex-shrink: 0;
  padding: 0 10px;
}
/* Trennlinie wie .dock-sep — nur auf schmalen Bildschirmen sichtbar, wo das
   Label vom wischbaren Teil abgesetzt wird. */
.mirror-axis .ma-sep {
  display: none;
  width: 1px; align-self: stretch; flex-shrink: 0;
  margin: 2px var(--seg-edge); background: var(--hair);
}
.mirror-axis .ma-seg { position: relative; display: flex; gap: 2px; }
.mirror-axis .ma-seg button {
  position: relative;
  /* „x-Achse“ bleibt einzeilig: der Bindestrich wäre sonst eine erlaubte
     Umbruchstelle, sobald die Leiste schmal wird. Umbrochen wird nicht —
     zu schmal wird gewischt (die Leiste scrollt). */
  white-space: nowrap; flex-shrink: 0;
  border: none; background: transparent;
  color: var(--text-2);
  font-family: var(--serif); font-size: 15.5px; letter-spacing: 0.01em;
  padding: 6px 9px 8px; border-radius: 9px; cursor: pointer;
  transition: color 0.22s var(--ease);
}
.mirror-axis .ma-seg button:hover { color: var(--ink); }         /* text-forward, keine Pille — wie beim Dock */
.mirror-axis .ma-seg button.active { color: var(--ink); }
.mirror-axis .ma-seg button.active::after {
  content: ''; position: absolute; left: 14px; right: 14px; bottom: 3px;
  height: 1.5px; background: var(--ink); border-radius: 1px;
}

/* Smartphone — nur die Achsen-Auswahl wird wischbar, „Spiegeln an“ bleibt fix
   links stehen, abgetrennt durch .ma-sep (eigenes Element wie .dock-sep).
   Der rechte Außenabstand wandert von der Leiste in den Scroll-Container:
   dessen Innenabstand ist zugleich der Raum, in dem Kapsel und Unterstreichung
   des Randsegments stehen dürfen, ohne vom Scroll-Rand abgeschnitten zu werden
   (der negative senkrechte Rand hält die Leiste dabei genau so hoch wie zuvor). */
@media (max-width: 640px) {
  .mirror-axis { max-width: calc(100vw - 20px); padding: 7px 0px 8px 10px; }
  .mirror-axis .ma-label { flex-shrink: 0; padding: 0 10px 0 0; }
  .mirror-axis .ma-sep { display: block; }
  .mirror-axis .ma-seg {
    min-width: 0;
    /* var(--seg-edge) hier + var(--seg-edge) an der Leiste = 8px seitlich,
       genau der untere Innenabstand. */
    padding: var(--seg-edge);
    margin: calc(-1 * var(--seg-edge)) 0;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    justify-content: flex-start;
  }
  .mirror-axis .ma-seg::-webkit-scrollbar { display: none; }
  /* Rechts kein Polster, sondern ein Abstandhalter: Safari und Firefox zählen
     die rechte Polsterung eines Flex-Containers nicht zum Scroll-Bereich —
     das letzte Segment stünde am Anschlag genau um diese Breite über der
     Clip-Kante und würde angeschnitten. Ein echtes Flex-Element wird überall
     mitgescrollt. Die 2px Flex-Lücke davor zählen bereits mit. */
  .mirror-axis .ma-seg::after { content: ''; flex: 0 0 calc(var(--seg-edge) - 2px); }
}

/* Spiegeln: Funktions-Eingabe über der Achsenwahl stapeln */
body.tool-entry:has(.mirror-axis.show) .tool-input.show {
  bottom: calc(var(--pill-bottom, 95px) + var(--ma-h, 44px) + 12px);
}
body.tool-entry.kb-open:has(.mirror-axis.show) .mirror-axis.show {
  bottom: calc(var(--kb-h, 0px) + 12px);
}
body.tool-entry.kb-open:has(.mirror-axis.show) .tool-input.show {
  bottom: calc(var(--kb-h, 0px) + 12px + var(--ma-h, 44px) + 12px);
}

/* Hinweis weicht der Eingabeleiste (oder der Spiegel-Achse) nach oben aus —
   --visible-h ist die Höhe der jeweils sichtbaren Pille (per JS gesetzt).
   Ohne Werkzeug-Eingabe steht er unmittelbar über Dock bzw. Tastatur; die
   erste Regel verhindert, dass er sonst hinter der Tastatur verschwände. */
body.kb-open .hint { bottom: calc(var(--kb-h, 0px) + 12px); }
body.tool-entry .hint { bottom: calc(var(--pill-bottom, 95px) + var(--visible-h, 44px) + 12px); }
body.tool-entry.kb-open .hint { bottom: calc(var(--kb-h, 0px) + 12px + var(--visible-h, 44px) + 12px); }

/* Onboarding-Hinweis */
.hint {
  position: absolute; bottom: var(--pill-bottom, 95px); left: 50%;
  transform: translateX(-50%) translateY(6px);
  z-index: 5;
  width: fit-content;
  max-width: calc(100vw - max(18px, env(safe-area-inset-left, 0px)) - max(18px, env(safe-area-inset-right, 0px)));
  font-family: var(--serif); font-style: italic;
  font-size: 14.5px; color: var(--text-2);
  background: var(--panel);
  -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  border: 1px solid var(--panel-border);
  padding: 8px 18px; border-radius: 11px;
  box-shadow: var(--shadow-soft);
  opacity: 0; pointer-events: none;
  transition: opacity 0.5s var(--ease), transform 0.5s var(--ease), bottom 0.3s var(--ease);
  white-space: normal;
  text-align: center;
}
.hint.show { opacity: 1; pointer-events: auto; transform: translateX(-50%) translateY(0); }

/* Werkzeugwechsel: die Karte steht schon da und bekommt nur neuen Text. Ein
   harter Wechsel ließe sie (und mit ihr das ausweichende Panel) springen,
   denn die Hinweise sind unterschiedlich lang.

   Gewechselt wird deshalb wie beim Umblättern: der alte Text bleibt als
   absolut gesetztes Doppel (.hint-ghost) mittig stehen und geht zügig, der
   neue kommt kurz danach nach. Der kleine Versatz ist Absicht — blendete man
   beide gleichzeitig, lägen sie einen Moment lang halbdurchsichtig
   übereinander und die Karte sähe verschmiert aus. Da beide mittig liegen,
   löst sich der eine Satz im anderen auf, statt zu verrutschen.

   Ist die Karte für den neuen Text gleich groß — was bei den meisten
   Hinweisen zutrifft —, bleibt sie einfach stehen: dann wechselt nur der
   Text, ohne jede Bewegung. Erst ein echter Größenunterschied schaltet
   .morphing frei (siehe setHintText in app.js, das Breite und Höhe dafür in
   Pixeln setzt — fit-content allein ist nicht animierbar). Die Größen-
   Übergänge hängen bewusst an dieser Klasse und nicht an .hint: sonst würde
   schon das Messen der Zielgröße eine Animation auslösen. */
.hint .hint-text { display: block; transition: opacity 0.2s var(--ease) 0.09s; }
.hint.swap-start .hint-text { opacity: 0; transition: none; }
.hint .hint-ghost {
  position: absolute; left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  pointer-events: none;
  transition: opacity 0.13s var(--ease);
}
.hint.morphing {
  overflow: hidden;
  transition: opacity 0.5s var(--ease), transform 0.5s var(--ease),
              bottom 0.3s var(--ease), width 0.28s var(--ease), height 0.28s var(--ease);
}

/* ---------------------------------------------------------------------------
   Parameter-Regler (Slider) — GeoGebra-artig, im selben stillen Duktus:
   Serifen-Buchstabe, Haarlinien-Bahn, kleiner Knopf, ▷ zum Animieren.
   --------------------------------------------------------------------------- */
.slider-section {
  display: none;
  border-top: 1px solid var(--hair);
  margin-top: 8px; padding-top: 2px;
}
.slider-section.show { display: block; }
.slider-cap {
  font-family: var(--serif); font-style: italic;
  font-size: 12px; color: var(--text-3);
  padding: 9px 8px 4px 8px;
}
.slider-list { display: flex; flex-direction: column; }

.slider {
  padding: 7px 8px 9px;
  border-radius: var(--radius-sm);
  transition: background 0.2s var(--ease);
}
.slider + .slider { border-top: 1px solid var(--hair); }
.slider:hover { background: var(--fill); }

.sl-head { display: flex; align-items: center; gap: 6px; }
.sl-name {
  font-family: var(--serif); font-style: italic;
  font-size: 16px; color: var(--text); line-height: 1;
}
.sl-eq { color: var(--text-3); font-size: 15px; }
.sl-val {
  width: 60px; border: none; outline: none; background: transparent;
  font-family: var(--serif); font-size: 15.5px; color: var(--text);
  font-feature-settings: "onum" 1;
  caret-color: var(--accent);
  border-bottom: 1px solid transparent; padding-bottom: 1px;
  transition: border-color 0.2s;
}
.sl-val:hover { border-bottom-color: var(--hair); }
.sl-val:focus { border-bottom-color: var(--text-3); }
.sl-spacer { flex: 1; }

.sl-btn {
  width: 27px; height: 27px; flex-shrink: 0;
  border: none; background: transparent; color: var(--text-2);
  border-radius: 50%; display: grid; place-items: center; cursor: pointer;
  transition: color 0.18s, background 0.18s, transform 0.12s;
}
.sl-btn:hover { color: var(--ink); background: var(--fill-hover); }
.sl-btn:active { transform: scale(0.9); }
.slider.playing .sl-play { color: var(--ink); }

.sl-track { display: flex; align-items: center; gap: 9px; margin-top: 6px; }
.sl-end {
  font-family: var(--serif); font-size: 11.5px; color: var(--text-3);
  font-feature-settings: "onum" 1; flex-shrink: 0; min-width: 22px;
}
.sl-end.max { text-align: right; }

.sl-range {
  -webkit-appearance: none; appearance: none;
  flex: 1; min-width: 0; height: 16px; background: transparent; cursor: pointer;
}
.sl-range:focus { outline: none; }
.sl-range::-webkit-slider-runnable-track { height: 2px; border-radius: 2px; background: var(--hair); }
.sl-range::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 13px; height: 13px; margin-top: -5.5px; border-radius: 50%;
  background: var(--panel-solid); border: 1.5px solid var(--ink);
  box-shadow: var(--shadow-soft);
  transition: transform 0.14s var(--ease);
}
.sl-range:hover::-webkit-slider-thumb { transform: scale(1.08); }
.sl-range:active::-webkit-slider-thumb { transform: scale(1.18); }
.sl-range::-moz-range-track { height: 2px; border-radius: 2px; background: var(--hair); }
.sl-range::-moz-range-thumb {
  width: 12px; height: 12px; border-radius: 50%;
  background: var(--panel-solid); border: 1.5px solid var(--ink);
}

.sl-adv {
  display: none; flex-wrap: wrap; align-items: center; gap: 9px 13px;
  padding: 11px 2px 3px;
}
.slider.expanded .sl-adv { display: flex; }
.sl-adv-field { display: flex; align-items: center; gap: 6px; }
.sl-adv-field > span {
  font-family: var(--serif); font-style: italic; font-size: 12px; color: var(--text-3);
}
.sl-adv-field input {
  width: 48px; border: none; outline: none; background: var(--fill);
  border-radius: 6px; padding: 3px 7px;
  font-family: var(--serif); font-size: 13px; color: var(--text);
  font-feature-settings: "onum" 1;
}
.sl-adv-field input:focus { background: var(--fill-hover); }
.sl-mode {
  border: none; background: var(--fill); color: var(--text-2);
  border-radius: 6px; padding: 4px 11px; cursor: pointer;
  font-size: 14px; line-height: 1;
  transition: color 0.18s, background 0.18s;
}
.sl-mode:hover { color: var(--ink); background: var(--fill-hover); }

/* ---------------------------------------------------------------------------
   Mathe-Tastatur — GeoGebra-artig, aber anders geordnet: f(x) zuerst (dies ist
   ein reiner Funktionsplotter), Klammern/Pfeile/Löschen/Enter bleiben fest
   sichtbar rechts, nur die mittlere Seite wechselt (f(x) · 123 · abc · Symbole).
   --------------------------------------------------------------------------- */
.math-kb {
  position: absolute; left: 50%; bottom: 0;
  transform: translateX(-50%) translateY(100%);
  z-index: 8;
  width: min(640px, calc(100vw - 24px));
  display: flex; flex-direction: column; gap: 8px;
  padding: 10px 12px calc(12px + env(safe-area-inset-bottom, 0px));
  background: var(--panel-solid);
  -webkit-backdrop-filter: saturate(140%) blur(16px);
  backdrop-filter: saturate(140%) blur(16px);
  border: 1px solid var(--panel-border);
  border-top-left-radius: var(--radius-lg); border-top-right-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  opacity: 0; pointer-events: none;
  transition: transform 0.32s var(--ease), opacity 0.32s var(--ease);
}
.math-kb.show { opacity: 1; pointer-events: auto; transform: translateX(-50%) translateY(0); }

.mkb-tabs { display: flex; gap: 2px; }
.mkb-tabs button {
  position: relative;
  border: none; background: transparent;
  color: var(--text-2);
  font-family: var(--serif); font-style: italic; font-size: 13.5px;
  padding: 6px 12px 8px; border-radius: 8px;
  cursor: pointer;
  transition: color 0.2s var(--ease);
}
.mkb-tabs button:hover { color: var(--ink); }
.mkb-tabs button.active { color: var(--ink); }
.mkb-tabs button.active::after {
  content: ''; position: absolute; left: 10px; right: 10px; bottom: 3px;
  height: 1.5px; background: var(--ink); border-radius: 1px;
}

.mkb-pages { position: relative; }
.mkb-page {
  display: none;
  grid-template-columns: repeat(6, 1fr);
  gap: 6px;
}
.mkb-page.active { display: grid; }

.mkb-page button, .mkb-nav button {
  border: none; background: var(--fill); color: var(--text);
  font-family: var(--serif); font-size: 15px; letter-spacing: 0.01em;
  padding: 9px 4px; border-radius: var(--radius-sm);
  cursor: pointer;
  transition: background 0.15s var(--ease), color 0.15s var(--ease), transform 0.1s var(--ease);
}
.mkb-page button:hover, .mkb-nav button:hover { background: var(--fill-hover); color: var(--ink); }
.mkb-page button:active, .mkb-nav button:active { transform: scale(0.94); }
.mkb-page button.mkb-var { font-style: italic; color: var(--accent); }

.mkb-nav {
  display: grid; grid-template-columns: repeat(6, 1fr);
  gap: 6px;
}
.mkb-nav .mkb-back { color: var(--danger); }
.mkb-nav .mkb-close {
  color: var(--text-2); font-size: 17px;
  display: grid; place-items: center; padding: 0;
}
.mkb-nav .mkb-close:hover { color: var(--ink); }

@media (max-width: 520px) {
  .math-kb { width: 100vw; border-radius: 0; }
  .mkb-page button, .mkb-nav button { padding: 11px 3px; font-size: 14px; }
}
