:root {
  color-scheme: light dark;
  --bg: #edf2ee;
  --panel: #ffffff;
  --panel-2: #f5f8f6;
  --panel-3: #e8eeea;
  --text: #152019;
  --muted: #66736b;
  --border: #d8e0da;
  --accent: #176b43;
  --accent-strong: #0f5333;
  --accent-soft: #def2e6;
  --fix: #159447;
  --fix-dark: #087a36;
  --fix-soft: #e2f7e9;
  --warn: #b46d12;
  --warn-soft: #fff1d8;
  --danger: #b33a3a;
  --danger-soft: #fbe7e7;
  --perimeter: #167444;
  --exclusion: #c14b4b;
  --dock: #3966a6;
  --robot: #111a14;
  --shadow: 0 10px 32px rgba(18, 52, 32, .08);
  --radius: 18px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --bg: #0d1510;
    --panel: #151f18;
    --panel-2: #1b2820;
    --panel-3: #243229;
    --text: #eff7f1;
    --muted: #a8b6ac;
    --border: #304238;
    --accent: #65bd89;
    --accent-strong: #86d3a4;
    --accent-soft: #1d3c2a;
    --fix: #56ce78;
    --fix-dark: #35ae5a;
    --fix-soft: #173c24;
    --warn: #edb85c;
    --warn-soft: #3c2e17;
    --danger: #ef8585;
    --danger-soft: #422020;
    --perimeter: #63c68d;
    --exclusion: #ed8585;
    --dock: #8db5eb;
    --robot: #ffffff;
    --shadow: none;
  }
}

* { box-sizing: border-box; }
html { background: var(--bg); }
body {
  margin: 0;
  min-width: 320px;
  min-height: 100%;
  font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  background: var(--bg);
  color: var(--text);
  -webkit-tap-highlight-color: transparent;
}
button, input, select { font: inherit; }
button, select, input { min-height: 46px; }
button { cursor: pointer; }
button:disabled { cursor: not-allowed; }
button:focus-visible, input:focus-visible, select:focus-visible, summary:focus-visible {
  outline: 3px solid color-mix(in srgb, var(--accent), transparent 55%);
  outline-offset: 2px;
}

.topbar {
  width: min(1180px, calc(100% - 28px));
  margin: 0 auto;
  padding: 18px 0 12px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
}
.brand { display: flex; align-items: center; gap: 11px; min-width: 0; }
.brand-mark {
  width: 42px;
  height: 42px;
  border-radius: 13px;
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  color: #fff;
  background: linear-gradient(145deg, var(--accent), var(--accent-strong));
  font-weight: 900;
  font-size: 1.2rem;
  box-shadow: 0 6px 18px color-mix(in srgb, var(--accent), transparent 72%);
}
.topbar h1 { margin: 1px 0 0; font-size: clamp(1.15rem, 4vw, 1.65rem); line-height: 1.15; }
.eyebrow, .overline { color: var(--muted); font-size: .68rem; letter-spacing: .12em; font-weight: 800; }

.pill {
  border-radius: 999px;
  padding: 8px 12px;
  white-space: nowrap;
  font-size: .78rem;
  font-weight: 800;
  border: 1px solid var(--border);
  transition: background .2s ease, color .2s ease, border-color .2s ease;
}
.pill.online { background: var(--fix-soft); color: var(--fix-dark); border-color: color-mix(in srgb, var(--fix), transparent 35%); }
.pill.offline { background: var(--panel); color: var(--muted); }

.tabs {
  position: sticky;
  top: 0;
  z-index: 30;
  width: min(1180px, calc(100% - 20px));
  margin: 0 auto 14px;
  padding: 5px;
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 4px;
  background: color-mix(in srgb, var(--panel), transparent 4%);
  border: 1px solid var(--border);
  border-radius: 16px;
  box-shadow: 0 7px 22px rgba(18, 52, 32, .06);
  backdrop-filter: blur(12px);
}
.tab-btn {
  min-width: 0;
  min-height: 50px;
  padding: 7px 10px;
  border: 0;
  border-radius: 12px;
  background: transparent;
  color: var(--muted);
  font-weight: 800;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
}
.tab-btn.active { background: var(--accent-soft); color: var(--accent-strong); }
.tab-icon { font-size: 1.15rem; line-height: 1; }

.app-shell {
  width: min(1180px, calc(100% - 24px));
  margin: 0 auto;
  padding-bottom: 32px;
}
.tab-panel { animation: panel-in .16s ease-out; }
.tab-panel[hidden] { display: none !important; }
@keyframes panel-in { from { opacity: .5; transform: translateY(3px); } to { opacity: 1; transform: none; } }

.page-heading {
  display: flex;
  justify-content: space-between;
  gap: 18px;
  align-items: end;
  margin: 8px 2px 16px;
}
.page-heading h2 { margin: 3px 0 5px; font-size: clamp(1.35rem, 4vw, 2rem); }
p { margin: 0; color: var(--muted); line-height: 1.5; }
h2, h3 { color: var(--text); }
h3 { margin: 0 0 5px; font-size: 1rem; }

.card {
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 18px;
  box-shadow: var(--shadow);
  margin-bottom: 14px;
}

.capture-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 4px 2px 10px;
}
.map-title-block { min-width: 0; display: grid; gap: 2px; }
.map-title-block strong { font-size: 1.08rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gps-badge {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 38px;
  padding: 7px 11px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--panel);
  color: var(--muted);
  font-size: .78rem;
  font-weight: 900;
}
.gps-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--muted); box-shadow: 0 0 0 4px color-mix(in srgb, var(--muted), transparent 85%); }
.gps-badge.fix { background: var(--fix-soft); color: var(--fix-dark); border-color: color-mix(in srgb, var(--fix), transparent 45%); }
.gps-badge.fix .gps-dot { background: var(--fix); box-shadow: 0 0 0 4px color-mix(in srgb, var(--fix), transparent 78%); }
.gps-badge.warning { background: var(--warn-soft); color: var(--warn); border-color: color-mix(in srgb, var(--warn), transparent 48%); }
.gps-badge.warning .gps-dot { background: var(--warn); box-shadow: 0 0 0 4px color-mix(in srgb, var(--warn), transparent 80%); }

.telemetry-strip {
  display: grid;
  grid-template-columns: 1fr 1fr minmax(1.45fr, 2fr) 1.15fr;
  gap: 8px;
  margin-bottom: 10px;
}
.telemetry-item {
  min-width: 0;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 9px 11px;
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: baseline;
  gap: 6px;
}
.telemetry-item > span { color: var(--muted); font-size: .68rem; font-weight: 900; letter-spacing: .05em; text-transform: uppercase; }
.telemetry-item strong { font-size: 1rem; text-align: right; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.telemetry-item small { color: var(--muted); font-size: .68rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.gps-item { grid-template-columns: auto auto 1fr; }
.gps-item strong { text-align: left; }

.mapping-stage {
  position: relative;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 20px;
  overflow: hidden;
  box-shadow: var(--shadow);
}
.map-toolbar {
  padding: 9px;
  border-bottom: 1px solid var(--border);
  background: var(--panel);
}
.mode-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; }
.mode-btn {
  min-height: 43px;
  border: 1px solid transparent;
  border-radius: 11px;
  padding: 8px 12px;
  background: var(--panel-2);
  color: var(--muted);
  font-weight: 850;
}
.mode-btn.active { background: var(--accent-soft); border-color: color-mix(in srgb, var(--accent), transparent 48%); color: var(--accent-strong); }
.exclusion-controls { display: flex; gap: 8px; align-items: end; margin-top: 8px; }

.map-frame {
  position: relative;
  width: 100%;
  height: clamp(370px, 58dvh, 720px);
  min-height: 370px;
  background: var(--panel-2);
  overflow: hidden;
}
#mapSvg { display: block; width: 100%; height: 100%; }
.canvas-bg { fill: var(--panel-2); }
.grid-line { stroke: var(--border); stroke-width: 1; vector-effect: non-scaling-stroke; opacity: .65; }
.perimeter-shape { fill: color-mix(in srgb, var(--perimeter), transparent 90%); stroke: var(--perimeter); stroke-width: 5; vector-effect: non-scaling-stroke; }
.exclusion-shape { fill: color-mix(in srgb, var(--exclusion), transparent 86%); stroke: var(--exclusion); stroke-width: 4; vector-effect: non-scaling-stroke; }
.dock-shape { fill: none; stroke: var(--dock); stroke-width: 5; stroke-dasharray: 12 9; vector-effect: non-scaling-stroke; }
.point-perimeter { fill: var(--panel); stroke: var(--perimeter); stroke-width: 4; vector-effect: non-scaling-stroke; }
.point-exclusion { fill: var(--panel); stroke: var(--exclusion); stroke-width: 4; vector-effect: non-scaling-stroke; }
.point-dock { fill: var(--panel); stroke: var(--dock); stroke-width: 4; vector-effect: non-scaling-stroke; }
.robot-dot { fill: var(--robot); stroke: var(--panel); stroke-width: 5; vector-effect: non-scaling-stroke; }
.robot-ring { fill: none; stroke: var(--robot); stroke-width: 2; vector-effect: non-scaling-stroke; opacity: .45; }
.map-hud {
  position: absolute;
  left: 10px;
  bottom: 10px;
  max-width: calc(100% - 20px);
  padding: 7px 10px;
  border-radius: 10px;
  color: var(--text);
  background: color-mix(in srgb, var(--panel), transparent 8%);
  border: 1px solid color-mix(in srgb, var(--border), transparent 15%);
  backdrop-filter: blur(9px);
  font-size: .72rem;
  box-shadow: 0 4px 18px rgba(20, 43, 28, .08);
}

.capture-dock {
  position: sticky;
  bottom: calc(8px + env(safe-area-inset-bottom));
  z-index: 20;
  margin: 10px 0 0;
  padding: 11px;
  border: 1px solid var(--border);
  border-radius: 20px;
  background: color-mix(in srgb, var(--panel), transparent 4%);
  box-shadow: 0 12px 36px rgba(16, 46, 28, .14);
  backdrop-filter: blur(14px);
}
.capture-meta { display: flex; justify-content: space-between; align-items: center; gap: 10px; margin: 0 2px 9px; }
.fix-switch { display: inline-flex; align-items: center; gap: 8px; color: var(--muted); font-size: .75rem; font-weight: 750; }
.fix-switch input { width: 20px; height: 20px; min-height: 0; margin: 0; accent-color: var(--fix); }
.save-state { color: var(--muted); font-size: .7rem; white-space: nowrap; }
.capture {
  width: 100%;
  min-height: 92px;
  border-radius: 17px;
  padding: 13px 16px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  border: 1px solid var(--border);
  background: var(--panel-3);
  color: var(--muted);
  transition: transform .08s ease, background .18s ease, border-color .18s ease, box-shadow .18s ease;
}
.capture:not(:disabled):active { transform: scale(.992); }
.capture-icon {
  width: 48px;
  height: 48px;
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: color-mix(in srgb, currentColor, transparent 86%);
  font-size: 2rem;
  font-weight: 500;
  line-height: 1;
}
.capture-copy { min-width: 0; display: grid; gap: 3px; text-align: left; }
.capture-copy strong { font-size: clamp(1.1rem, 4vw, 1.45rem); line-height: 1.1; }
.capture-copy small { font-size: .78rem; font-weight: 700; opacity: .9; }
.capture.capture-fix {
  border-color: var(--fix);
  background: linear-gradient(145deg, var(--fix), var(--fix-dark));
  color: #fff;
  box-shadow: 0 9px 24px color-mix(in srgb, var(--fix), transparent 70%);
}
.capture.capture-warning:not(:disabled) {
  border-color: color-mix(in srgb, var(--warn), transparent 20%);
  background: var(--warn-soft);
  color: var(--warn);
}
.capture.capture-blocked {
  border-color: color-mix(in srgb, var(--warn), transparent 45%);
  background: color-mix(in srgb, var(--warn-soft), var(--panel) 48%);
  color: var(--warn);
  opacity: 1;
}
.capture.capture-idle:disabled { opacity: .72; }
.capture-status { min-height: 1.25em; margin: 7px 4px 0; color: var(--muted); font-size: .74rem; text-align: center; }
.capture-actions { display: grid; grid-template-columns: 1fr; gap: 7px; margin-top: 9px; }
.undo-action {
  width: 100%;
  min-height: 62px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 11px;
  padding: 10px 14px;
  border-radius: 15px;
  border: 1px solid color-mix(in srgb, var(--danger), transparent 35%);
  background: color-mix(in srgb, var(--danger), transparent 92%);
  color: var(--danger);
}
.undo-action:not(:disabled):active { transform: scale(.993); }
.undo-action:disabled { opacity: .46; color: var(--muted); border-color: var(--border); background: var(--panel-3); }
.undo-icon { font-size: 1.55rem; line-height: 1; font-weight: 850; }
.undo-copy { display: grid; gap: 1px; text-align: left; min-width: 0; }
.undo-copy strong { font-size: .98rem; line-height: 1.15; }
.undo-copy small { font-size: .7rem; font-weight: 700; opacity: .82; }
.clear-element-action { min-height: 46px; font-size: .78rem; }

.recent-drawer {
  margin-top: 10px;
  padding: 0 4px;
  color: var(--muted);
}
.recent-drawer summary { cursor: pointer; min-height: 44px; display: flex; align-items: center; font-size: .8rem; font-weight: 800; }
.recent-points { display: grid; gap: 5px; padding: 0 0 8px; color: var(--muted); font-size: .8rem; }
.recent-point { display: flex; justify-content: space-between; gap: 10px; border-bottom: 1px solid var(--border); padding: 6px 0; }

.field { display: grid; gap: 6px; min-width: 0; }
.field.grow { flex: 1 1 240px; }
.field > span { font-size: .75rem; color: var(--muted); font-weight: 800; }
.field small { color: var(--muted); line-height: 1.4; }
.field.compact > span { font-size: .68rem; }
input, select {
  width: 100%;
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 10px 12px;
  background: var(--panel-2);
  color: var(--text);
  font-size: 16px;
}
button, .file-button {
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 10px 14px;
  background: var(--panel-2);
  color: var(--text);
  font-weight: 800;
  min-height: 46px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  text-decoration: none;
  user-select: none;
}
.primary { background: var(--accent); color: #fff; border-color: var(--accent); }
.primary:hover:not(:disabled) { background: var(--accent-strong); }
.secondary { background: var(--panel-2); }
.ghost { background: transparent; }
.danger { background: var(--danger-soft); color: var(--danger); border-color: color-mix(in srgb, var(--danger), transparent 55%); }
.compact-btn { min-height: 43px; padding: 8px 12px; }
.big-action { min-height: 58px; font-size: 1.02rem; }
.file-button { cursor: pointer; }

.form-stack { display: grid; gap: 14px; }
.new-map-row { display: flex; gap: 10px; align-items: end; flex-wrap: wrap; }
.action-card { display: grid; grid-template-columns: 1fr minmax(220px, 330px); gap: 24px; align-items: start; }
.stacked-actions { display: grid; gap: 8px; }

.connection-card { max-width: 760px; }
.connection-hero { display: flex; gap: 14px; align-items: center; margin-bottom: 20px; }
.connection-orb {
  width: 58px; height: 58px; border-radius: 18px; display: grid; place-items: center;
  background: var(--accent-soft); color: var(--accent-strong); font-size: 2rem; flex: 0 0 auto;
}
.connection-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 9px; margin-top: 18px; }
.connection-actions .big-action { grid-column: 1 / -1; }
.password-field { max-width: 420px; }
.notice { border-radius: 13px; padding: 12px 14px; margin-bottom: 14px; line-height: 1.45; }
.notice.warning { background: var(--warn-soft); color: var(--warn); border: 1px solid color-mix(in srgb, var(--warn), transparent 55%); }
.hidden { display: none !important; }

.debug-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 12px; }
#debugLog {
  min-height: 260px;
  max-height: 56dvh;
  overflow: auto;
  margin: 0;
  background: #0b110d;
  color: #cde8d5;
  border-radius: 14px;
  padding: 13px;
  font-size: .77rem;
  line-height: 1.45;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

footer {
  width: min(1180px, calc(100% - 24px));
  margin: 0 auto 24px;
  color: var(--muted);
  font-size: .72rem;
  text-align: center;
}

@media (min-width: 900px) {
  #tabCapture { max-width: 1180px; margin: 0 auto; }
  .capture-dock { max-width: 760px; margin-left: auto; margin-right: auto; }
}

@media (max-width: 760px) {
  .topbar { width: calc(100% - 22px); padding-top: 12px; }
  .brand-mark { width: 38px; height: 38px; border-radius: 12px; }
  .eyebrow { display: none; }
  .pill { font-size: .7rem; padding: 7px 10px; }
  .tabs { width: calc(100% - 12px); margin-bottom: 9px; border-radius: 14px; }
  .tab-btn { min-height: 48px; padding: 6px 4px; display: grid; gap: 2px; font-size: .69rem; }
  .tab-icon { font-size: 1.2rem; }
  .app-shell { width: calc(100% - 12px); }
  .capture-header { margin-left: 5px; margin-right: 5px; }
  .telemetry-strip { grid-template-columns: 1fr 1fr; }
  .gps-item { grid-column: 1 / -1; order: 3; }
  .telemetry-item { padding: 8px 10px; }
  .mapping-stage { border-radius: 16px; }
  .map-frame { height: clamp(360px, 55dvh, 600px); }
  .capture-dock { border-radius: 17px; padding: 9px; }
  .capture { min-height: 96px; }
  .capture-meta { align-items: flex-start; }
  .save-state { max-width: 38%; overflow: hidden; text-overflow: ellipsis; }
  .action-card { grid-template-columns: 1fr; }
  .new-map-row, .new-map-row > *, .connection-actions > *, .stacked-actions > * { width: 100%; }
  .connection-card { max-width: none; }
}

@media (max-width: 430px) {
  .topbar h1 { font-size: 1.05rem; }
  .capture-header { align-items: flex-end; }
  .gps-badge { padding: 6px 9px; font-size: .7rem; }
  .telemetry-strip { gap: 6px; }
  .telemetry-item small { font-size: .63rem; }
  .mode-btn { font-size: .76rem; padding-inline: 6px; }
  .exclusion-controls { flex-wrap: wrap; }
  .exclusion-controls .field { flex: 1 1 100%; }
  .capture-actions { grid-template-columns: 1fr; }
  .fix-switch { font-size: .7rem; }
  .map-hud { font-size: .66rem; }
}

/* v4: mapping controls float at the upper-right; bottom is capture-only */
.mapping-stage { overflow: hidden; }
.map-frame {
  height: clamp(430px, 64dvh, 780px);
  min-height: 430px;
}
.map-tools-panel {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 8;
  width: min(330px, calc(100% - 20px));
  padding: 9px;
  display: grid;
  gap: 7px;
  border: 1px solid color-mix(in srgb, var(--border), transparent 8%);
  border-radius: 15px;
  background: color-mix(in srgb, var(--panel), transparent 6%);
  box-shadow: 0 8px 28px rgba(14, 39, 24, .12);
  backdrop-filter: blur(12px);
}
.map-tools-panel .mode-row { gap: 5px; }
.map-tools-panel .mode-btn {
  min-height: 38px;
  padding: 6px 7px;
  border-radius: 9px;
  font-size: .72rem;
}
.map-tools-panel .exclusion-controls {
  display: grid;
  grid-template-columns: 1fr;
  gap: 6px;
  align-items: stretch;
  margin-top: 0;
  padding-top: 6px;
  border-top: 1px solid var(--border);
}
.map-tools-panel .exclusion-controls.hidden { display: none; }
.map-tools-panel .field.compact { gap: 3px; }
.map-tools-panel .field.compact > span { font-size: .64rem; }
.map-tools-panel .field.compact select { min-height: 38px; padding-block: 5px; font-size: .76rem; }
.mini-action-row { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.map-tools-panel .compact-btn { min-height: 38px; padding: 6px 8px; font-size: .72rem; }
.map-tool-action {
  width: 100%;
  min-height: 48px;
  padding: 8px 10px;
  border-radius: 11px;
  display: flex;
  align-items: center;
  gap: 9px;
  text-align: left;
  border: 1px solid var(--border);
  background: var(--panel-2);
  color: var(--text);
}
.map-tool-action strong,
.map-tool-action small { display: block; }
.map-tool-action strong { font-size: .78rem; line-height: 1.15; }
.map-tool-action small { margin-top: 2px; color: var(--muted); font-size: .64rem; line-height: 1.2; }
.map-tool-action > span:first-child { font-size: 1.25rem; line-height: 1; }
.undo-tool { color: var(--danger); border-color: color-mix(in srgb, var(--danger), transparent 55%); background: color-mix(in srgb, var(--danger-soft), transparent 20%); }
.undo-tool:disabled { opacity: .48; color: var(--muted); border-color: var(--border); background: var(--panel-2); }
.clear-tool { min-height: 39px; justify-content: center; color: var(--danger); font-size: .7rem; font-weight: 800; }
.tool-status-block {
  display: grid;
  gap: 4px;
  padding: 7px 2px 1px;
  border-top: 1px solid var(--border);
}
.tool-status-block .fix-switch { font-size: .7rem; }
.tool-status-block .fix-switch input { width: 18px; height: 18px; }
.tool-point-status { color: var(--muted); font-size: .65rem; line-height: 1.25; }
.tool-status-block .save-state { font-size: .62rem; overflow: hidden; text-overflow: ellipsis; }

.capture-dock {
  width: 100%;
  max-width: none;
  position: sticky;
  bottom: calc(6px + env(safe-area-inset-bottom));
  z-index: 20;
  margin: 9px 0 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
  backdrop-filter: none;
}
.capture {
  width: 100%;
  min-height: 104px;
  border-radius: 18px;
}

.export-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.export-hint { display: block; color: var(--muted); font-size: .72rem; line-height: 1.4; }

@media (min-width: 900px) {
  .capture-dock { max-width: none; margin-left: 0; margin-right: 0; }
}

@media (max-width: 760px) {
  .map-frame { height: clamp(440px, 62dvh, 680px); min-height: 440px; }
  .map-tools-panel { width: min(300px, calc(100% - 18px)); top: 9px; right: 9px; padding: 8px; }
  .capture-dock { padding: 0; border-radius: 0; }
  .capture { min-height: 102px; border-radius: 16px; }
}

@media (max-width: 430px) {
  .map-frame { height: clamp(455px, 63dvh, 650px); min-height: 455px; }
  .map-tools-panel { width: min(276px, calc(100% - 18px)); }
  .map-tools-panel .mode-btn { font-size: .67rem; padding-inline: 4px; }
  .map-tool-action { min-height: 45px; }
  .export-grid { grid-template-columns: 1fr; }
}
.recent-tool-drawer {
  border-top: 1px solid var(--border);
  padding-top: 4px;
  color: var(--muted);
}
.recent-tool-drawer summary {
  min-height: 34px;
  display: flex;
  align-items: center;
  cursor: pointer;
  font-size: .68rem;
  font-weight: 850;
}
.recent-tool-drawer .recent-points { max-height: 128px; overflow: auto; }
.recent-tool-drawer .recent-point { padding: 5px 2px; font-size: .64rem; }

/* v5: bilingual header switch */
.topbar-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  flex: 0 0 auto;
}
.language-toggle {
  min-height: 36px;
  height: 36px;
  padding: 3px 5px;
  display: inline-flex;
  align-items: center;
  gap: 3px;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--panel);
  color: var(--muted);
  font-size: .72rem;
  font-weight: 900;
  letter-spacing: .04em;
}
.language-toggle .lang-option {
  min-width: 30px;
  min-height: 28px;
  padding: 0 7px;
  display: inline-grid;
  place-items: center;
  border-radius: 999px;
  transition: background .16s ease, color .16s ease;
}
.language-toggle .lang-divider { opacity: .35; }
.language-toggle[data-language="de"] .lang-de,
.language-toggle[data-language="en"] .lang-en {
  background: var(--accent-soft);
  color: var(--accent-strong);
}

@media (max-width: 430px) {
  .topbar { flex-wrap: wrap; gap: 8px; }
  .brand { flex: 1 1 100%; }
  .topbar-actions { width: 100%; justify-content: space-between; }
  .language-toggle { order: 2; }
  .topbar-actions .pill { order: 1; }
}

/* v6 — technical dark field-console theme */
:root {
  color-scheme: dark;
  --bg: #070b0d;
  --panel: #0e1417;
  --panel-2: #11191d;
  --panel-3: #172126;
  --text: #e8f1f3;
  --muted: #83949b;
  --border: #243238;
  --accent: #38b6c8;
  --accent-strong: #79d8e6;
  --accent-soft: #102a30;
  --fix: #3ed87a;
  --fix-dark: #1aaf58;
  --fix-soft: #0d2a1a;
  --warn: #f0b64a;
  --warn-soft: #30240d;
  --danger: #ff6974;
  --danger-soft: #32151a;
  --perimeter: #46dc86;
  --exclusion: #ff6c78;
  --dock: #5fb3ff;
  --robot: #f2fbff;
  --shadow: 0 18px 50px rgba(0,0,0,.34);
  --radius: 14px;
  --tech-line: rgba(82, 130, 144, .16);
  --tech-glow: rgba(56, 182, 200, .15);
}

html {
  background: #05080a;
}
body {
  background:
    radial-gradient(circle at 50% -120px, rgba(37, 114, 127, .14), transparent 420px),
    linear-gradient(rgba(255,255,255,.012) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,.012) 1px, transparent 1px),
    var(--bg);
  background-size: auto, 28px 28px, 28px 28px, auto;
  letter-spacing: .005em;
}

.topbar {
  padding-top: 16px;
  padding-bottom: 10px;
}
.brand-mark {
  position: relative;
  border-radius: 9px;
  background: #0a1215;
  color: var(--accent-strong);
  border: 1px solid #2f5b65;
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.025), 0 0 24px rgba(56,182,200,.09);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.brand-mark::before,
.brand-mark::after {
  content: "";
  position: absolute;
  width: 7px;
  height: 7px;
  border-color: var(--accent);
  opacity: .8;
}
.brand-mark::before { left: 4px; top: 4px; border-left: 1px solid; border-top: 1px solid; }
.brand-mark::after { right: 4px; bottom: 4px; border-right: 1px solid; border-bottom: 1px solid; }
.topbar h1 {
  font-weight: 740;
  letter-spacing: -.025em;
}
.eyebrow, .overline {
  color: #65808a;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  letter-spacing: .16em;
}
.topbar-actions { gap: 9px; }
.pill,
.language-toggle {
  background: rgba(13, 20, 23, .88);
  border-color: #28383e;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.025);
}
.pill.online {
  background: #0b2617;
  color: #73eba0;
  border-color: #245c38;
  box-shadow: 0 0 18px rgba(62,216,122,.08), inset 0 1px 0 rgba(255,255,255,.025);
}
.language-toggle[data-language="de"] .lang-de,
.language-toggle[data-language="en"] .lang-en {
  background: #17343b;
  color: #8ce6f0;
}

.tabs {
  top: 7px;
  padding: 4px;
  margin-bottom: 12px;
  background: rgba(10, 15, 18, .91);
  border-color: #24343a;
  border-radius: 12px;
  box-shadow: 0 12px 32px rgba(0,0,0,.28), inset 0 1px 0 rgba(255,255,255,.02);
  backdrop-filter: blur(18px);
}
.tab-btn {
  border-radius: 9px;
  color: #71858d;
  text-transform: uppercase;
  letter-spacing: .05em;
  font-size: .75rem;
}
.tab-btn.active {
  background: linear-gradient(180deg, #173038, #10262c);
  color: #89e2ed;
  box-shadow: inset 0 0 0 1px #28525c, inset 0 1px 0 rgba(255,255,255,.035);
}
.tab-icon { color: currentColor; }

.card,
.mapping-stage {
  background: rgba(13, 20, 23, .96);
  border-color: #23343a;
  box-shadow: var(--shadow), inset 0 1px 0 rgba(255,255,255,.018);
}
.card { border-radius: 13px; }
.page-heading h2 { font-weight: 720; letter-spacing: -.025em; }
p { color: #83959c; }

.capture-header {
  padding: 0 2px;
  margin-bottom: 8px;
}
.map-title-block strong {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  letter-spacing: -.01em;
}
.gps-badge {
  border-radius: 8px;
  background: #0d1518;
  border-color: #26373d;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  letter-spacing: .04em;
  text-transform: uppercase;
}
.gps-dot { border-radius: 2px; box-shadow: none; }
.gps-badge.fix {
  background: #0b2516;
  color: #78f1a5;
  border-color: #28643d;
  box-shadow: 0 0 22px rgba(62,216,122,.08);
}
.gps-badge.fix .gps-dot { background: #46e980; box-shadow: 0 0 9px rgba(70,233,128,.55); }
.gps-badge.warning {
  background: #2a200d;
  color: #f5c562;
  border-color: #665126;
}
.gps-badge.warning .gps-dot { background: #f0b64a; box-shadow: 0 0 8px rgba(240,182,74,.38); }

.telemetry-strip { gap: 6px; }
.telemetry-item {
  position: relative;
  overflow: hidden;
  min-height: 58px;
  background: linear-gradient(180deg, #10181c, #0c1316);
  border-color: #223238;
  border-radius: 9px;
  padding: 8px 10px;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.018);
}
.telemetry-item::after {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  width: 2px;
  height: 100%;
  background: #28444d;
}
.telemetry-item > span,
.telemetry-item small {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.telemetry-item > span { color: #66808a; }
.telemetry-item strong {
  color: #eff8fa;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-variant-numeric: tabular-nums;
  letter-spacing: -.035em;
}
.telemetry-item small { color: #657a82; }

.mapping-stage {
  border-radius: 12px;
  border-color: #294047;
}
.map-frame {
  background:
    radial-gradient(circle at 50% 45%, rgba(28, 67, 73, .15), transparent 55%),
    #081013;
}
.canvas-bg { fill: #081013; }
.grid-line {
  stroke: #24434a;
  stroke-width: 1;
  opacity: .42;
}
.perimeter-shape {
  fill: rgba(55, 209, 117, .055);
  stroke: #43df84;
  filter: drop-shadow(0 0 4px rgba(67,223,132,.14));
}
.exclusion-shape {
  fill: rgba(255, 91, 105, .07);
  stroke: #ff6c78;
  filter: drop-shadow(0 0 4px rgba(255,108,120,.12));
}
.dock-shape {
  stroke: #5fb3ff;
  filter: drop-shadow(0 0 4px rgba(95,179,255,.13));
}
.point-perimeter,
.point-exclusion,
.point-dock { fill: #071012; stroke-width: 4; }
.robot-dot {
  fill: #e9fbff;
  stroke: #0a1215;
  filter: drop-shadow(0 0 6px rgba(209,247,255,.4));
}
.robot-ring { stroke: #8fe4ef; opacity: .55; }
.map-hud {
  border-radius: 7px;
  background: rgba(7, 14, 17, .84);
  border-color: #294149;
  color: #a8bec5;
  box-shadow: 0 8px 22px rgba(0,0,0,.28);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  backdrop-filter: blur(12px);
}

.map-tools-panel {
  width: min(338px, calc(100% - 20px));
  border-radius: 10px;
  background: rgba(8, 15, 18, .91);
  border-color: #2a424a;
  box-shadow: 0 12px 34px rgba(0,0,0,.4), inset 0 1px 0 rgba(255,255,255,.02);
  backdrop-filter: blur(18px);
}
.map-tools-panel .mode-btn {
  border-radius: 7px;
  background: #111b1f;
  border-color: #213238;
  color: #83969d;
  text-transform: uppercase;
  letter-spacing: .035em;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.map-tools-panel .mode-btn.active {
  background: #17333a;
  color: #91e8f2;
  border-color: #33616b;
  box-shadow: inset 0 0 16px rgba(56,182,200,.045);
}
.map-tools-panel .exclusion-controls,
.tool-status-block,
.recent-tool-drawer { border-color: #23353b; }
.map-tool-action {
  border-radius: 8px;
  background: #10191d;
  border-color: #273940;
}
.undo-tool {
  color: #ff8a93;
  border-color: #573038;
  background: rgba(50, 21, 26, .72);
}
.clear-tool { color: #d87880; }
.fix-switch input { accent-color: #3ed87a; }
.tool-point-status,
.save-state,
.recent-tool-drawer,
.recent-points { color: #758990; }

.capture-dock {
  bottom: calc(8px + env(safe-area-inset-bottom));
}
.capture {
  min-height: 108px;
  border-radius: 11px;
  border: 1px solid #2b3d43;
  background: linear-gradient(180deg, #151f23, #0f171a);
  box-shadow: 0 12px 34px rgba(0,0,0,.34), inset 0 1px 0 rgba(255,255,255,.025);
}
.capture-icon {
  border-radius: 8px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.capture-copy strong {
  text-transform: uppercase;
  letter-spacing: .035em;
  font-weight: 850;
}
.capture-copy small {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  letter-spacing: .02em;
}
.capture.capture-fix {
  border-color: #35c86f;
  background: linear-gradient(180deg, #26bb63, #118d49);
  color: #f5fff8;
  box-shadow: 0 10px 30px rgba(31, 188, 97, .2), inset 0 1px 0 rgba(255,255,255,.16);
}
.capture.capture-fix .capture-icon {
  background: rgba(0,0,0,.16);
  box-shadow: inset 0 0 0 1px rgba(255,255,255,.13);
}
.capture.capture-warning:not(:disabled) {
  border-color: #806127;
  background: linear-gradient(180deg, #33270f, #271d0b);
  color: #f4c96b;
}
.capture.capture-blocked {
  border-color: #564723;
  background: linear-gradient(180deg, #211b10, #17130c);
  color: #b89955;
}
.capture.capture-idle:disabled {
  background: linear-gradient(180deg, #121a1d, #0d1316);
  color: #62737a;
  opacity: 1;
}

input, select,
button, .file-button {
  border-radius: 8px;
}
input, select {
  background: #0b1215;
  border-color: #2a3b41;
  color: #e6f0f2;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.018);
}
button, .file-button {
  background: #111a1e;
  border-color: #2a3b42;
}
button:hover:not(:disabled), .file-button:hover {
  border-color: #3c5861;
}
.primary {
  background: #156f80;
  border-color: #2f9cad;
  color: #effcff;
}
.primary:hover:not(:disabled) { background: #1a7f91; }
.secondary { background: #111a1e; }
.ghost { background: transparent; }
.danger {
  background: #2c1519;
  color: #ff8a93;
  border-color: #583039;
}

.connection-orb {
  border-radius: 10px;
  background: #102b31;
  color: #7bdce8;
  border: 1px solid #28515b;
  box-shadow: inset 0 0 20px rgba(56,182,200,.045);
}
.notice.warning {
  background: #2a200d;
  color: #f4c665;
  border-color: #5f4a20;
}
#debugLog {
  background: #05090b;
  color: #9de6c1;
  border: 1px solid #23363b;
  border-radius: 8px;
  box-shadow: inset 0 0 22px rgba(0,0,0,.28);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
footer {
  color: #586b72;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

@media (max-width: 760px) {
  .tabs { top: 4px; }
  .mapping-stage { border-radius: 10px; }
  .map-tools-panel { border-radius: 9px; }
  .capture { min-height: 106px; border-radius: 10px; }
}

@media (max-width: 430px) {
  .brand-mark { width: 36px; height: 36px; }
  .topbar h1 { font-size: 1rem; }
  .gps-badge { border-radius: 7px; }
  .telemetry-item { border-radius: 7px; }
  .map-tools-panel { width: min(280px, calc(100% - 16px)); top: 8px; right: 8px; }
}

/* v7: adjustable grid + scale-accurate mower footprint */
.grid-major {
  stroke: #31545d;
  opacity: .62;
}
.grid-axis {
  stroke: #4a7680;
  opacity: .9;
  stroke-width: 1.5;
}

.view-tool-drawer {
  border-top: 1px solid #23353b;
  padding-top: 4px;
  color: #758990;
}
.view-tool-drawer summary {
  min-height: 34px;
  display: flex;
  align-items: center;
  cursor: pointer;
  font-size: .68rem;
  font-weight: 850;
  text-transform: uppercase;
  letter-spacing: .04em;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.view-settings {
  display: grid;
  gap: 7px;
  padding: 4px 1px 2px;
}
.view-settings .view-toggle {
  min-height: 31px;
  font-size: .68rem;
}
.view-settings .field.compact > span {
  color: #71868e;
  text-transform: uppercase;
  letter-spacing: .035em;
}
.view-settings select,
.view-settings input[type="number"] {
  min-height: 38px;
  border-radius: 7px;
  border: 1px solid #263b42;
  background: #0d171a;
  color: #dce9ec;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.view-divider {
  height: 1px;
  background: var(--shell-border);
  margin: 1px 0;
}
.mower-size-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 7px;
}
.unit-input {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 6px;
}
.unit-input input { width: 100%; min-width: 0; }
.unit-input > span {
  color: #789098;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .7rem;
}
.view-note {
  color: #647a82;
  font-size: .62rem;
  line-height: 1.35;
}

.robot-mower {
  pointer-events: none;
}
.robot-body {
  fill: rgba(21, 43, 49, .94);
  stroke: #a9edf4;
  stroke-width: 2;
  vector-effect: non-scaling-stroke;
  filter: drop-shadow(0 0 6px rgba(89, 213, 226, .28));
}
.robot-front {
  fill: #63d9e7;
  stroke: #d2f8fb;
  stroke-width: 1.3;
  vector-effect: non-scaling-stroke;
}
.robot-axle {
  stroke: #6c949d;
  stroke-width: 1.2;
  vector-effect: non-scaling-stroke;
  opacity: .9;
}
.robot-center {
  fill: #ecfbfd;
  stroke: #071012;
  stroke-width: 1.4;
  vector-effect: non-scaling-stroke;
}
.robot-position-marker {
  fill: none;
  stroke: #9cecf4;
  stroke-width: 1.2;
  vector-effect: non-scaling-stroke;
  opacity: .55;
}

@media (max-width: 430px) {
  .view-tool-drawer summary { min-height: 32px; }
  .mower-size-grid { gap: 5px; }
  .view-settings select,
  .view-settings input[type="number"] { min-height: 36px; }
}

/* v8 — point edit / relearn mode */
.edit-tool {
  color: #8ce6f0;
  border-color: #2c5159;
  background: linear-gradient(180deg, #102329, #0c1b20);
}
.edit-tool.active {
  color: #b7f5fc;
  border-color: #4ecbdd;
  background: linear-gradient(180deg, #173b44, #102a31);
  box-shadow: inset 0 0 0 1px rgba(121,216,230,.08), 0 0 18px rgba(56,182,200,.09);
}
.edit-controls {
  display: grid;
  gap: 7px;
  padding: 8px;
  border: 1px solid #31515a;
  border-radius: 9px;
  background: rgba(11, 26, 31, .96);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.02);
}
.edit-controls.hidden { display: none; }
.edit-selection-card {
  min-width: 0;
  padding: 7px 8px;
  border: 1px solid #263d44;
  border-radius: 7px;
  background: #091215;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.edit-selection-card strong,
.edit-selection-card small { display: block; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.edit-selection-card strong { color: #bceff5; font-size: .72rem; }
.edit-selection-card small { margin-top: 3px; color: #789099; font-size: .64rem; white-space: nowrap; }

#mapSvg.edit-mode .map-point {
  cursor: crosshair;
  pointer-events: all;
}
#mapSvg.edit-mode .map-point:hover,
#mapSvg.edit-mode .map-point:focus {
  outline: none;
  filter: drop-shadow(0 0 8px rgba(121,216,230,.65));
}
.selected-map-point {
  fill: #dffbff !important;
  stroke: #59dcea !important;
  stroke-width: 6 !important;
  filter: drop-shadow(0 0 8px rgba(89,220,234,.7));
}
.edit-selected-ring {
  fill: none;
  stroke: #71e7f3;
  stroke-width: 3;
  stroke-dasharray: 7 5;
  vector-effect: non-scaling-stroke;
  pointer-events: none;
  opacity: .92;
}
.edit-distance-line {
  stroke: #79d8e6;
  stroke-width: 2;
  stroke-dasharray: 7 6;
  vector-effect: non-scaling-stroke;
  pointer-events: none;
  opacity: .72;
}

@media (max-width: 430px) {
  .edit-controls { padding: 7px; gap: 6px; }
  .edit-selection-card { padding: 6px 7px; }
}
.map-point-hit {
  fill: rgba(0,0,0,0.001);
  stroke: none;
  cursor: crosshair;
  pointer-events: all;
}
.map-point-hit:focus { outline: none; }


/* v9: mapping workflow tools 1-7 */
.auto-capture-tools,
.validation-tool-drawer {
  border-top: 1px solid #23353b;
  padding-top: 7px;
}
.auto-capture-tools {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 96px;
  gap: 6px 8px;
  align-items: end;
}
.auto-capture-tools .fix-switch { min-height: 38px; }
.auto-distance-field { min-width: 0; }
.auto-capture-state {
  grid-column: 1 / -1;
  color: #6f858d;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .63rem;
}
.edit-action-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 5px;
}
.edit-action-btn {
  min-height: 36px;
  padding: 5px 6px;
  border-radius: 6px;
  color: #82969d;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .64rem;
  text-transform: uppercase;
}
.edit-action-btn.active {
  background: #17343b;
  border-color: #35616b;
  color: #98edf5;
}
.edit-small-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.history-undo-tool { color: #89dce7; border-color: #31515a; background: rgba(16, 40, 46, .72); }
.capture.capture-stop {
  border-color: #b36e32;
  background: linear-gradient(180deg, #653b17, #492a10);
  color: #ffd19c;
}
.validation-tool-drawer summary {
  min-height: 34px;
  display: flex;
  align-items: center;
  cursor: pointer;
  font-size: .68rem;
  font-weight: 850;
  text-transform: uppercase;
  letter-spacing: .04em;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  color: #758990;
}
.validation-controls { display: grid; gap: 6px; padding-bottom: 2px; }
.validation-summary {
  padding: 7px 8px;
  /* Tokens statt fester Dunkelwerte: der Hell-Modus ueberschrieb hier nur die Schriftfarbe,
     der fast schwarze Hintergrund blieb stehen — dunkler Text auf dunklem Kasten. */
  border: 1px solid var(--shell-border);
  border-radius: 7px;
  background: var(--shell-panel-2);
  color: var(--shell-text);
  font-size: .65rem;
  line-height: 1.35;
}
.validation-list { display: grid; gap: 4px; max-height: 160px; overflow: auto; }
.validation-item { border-left: 2px solid #3a5660; padding: 4px 6px; color: #91a4aa; font-size: .63rem; line-height: 1.3; }
.validation-item.error { border-color: #ff6674; color: #ff9da6; }
.validation-item.warning { border-color: #e7ad46; color: #eec675; }
.validation-item.info { border-color: #579fc8; color: #8fcce8; }
.map-hud { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.map-distance-info { color: #75d8e4; }
.movement-trail-shape {
  fill: none;
  stroke: #4f8b94;
  stroke-width: 2;
  stroke-dasharray: 7 7;
  opacity: .55;
  vector-effect: non-scaling-stroke;
}
.segment-recording-shape {
  fill: none;
  stroke: #f2c45b;
  stroke-width: 4;
  stroke-dasharray: 10 6;
  vector-effect: non-scaling-stroke;
  filter: drop-shadow(0 0 4px rgba(242,196,91,.18));
}
.point-segment-recording { fill: #081013; stroke: #f2c45b; stroke-width: 4; }
.range-map-point:not(.selected-map-point) { stroke-width: 6; filter: drop-shadow(0 0 5px rgba(116,221,234,.28)); }
.boundary-distance-line { stroke: #6dd7e2; stroke-width: 1.5; stroke-dasharray: 4 5; opacity: .72; vector-effect: non-scaling-stroke; }
.history-card { margin-top: 14px; }
.history-card-head { display: flex; align-items: start; justify-content: space-between; gap: 14px; flex-wrap: wrap; }
.history-list { display: grid; gap: 6px; margin-top: 12px; color: #788b92; }
.history-entry {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 10px;
  align-items: center;
  padding: 8px 9px;
  border: 1px solid #24363c;
  border-radius: 8px;
  background: #0c1417;
}
.history-entry strong, .history-entry small { display: block; }
.history-entry strong { color: #c5d7db; font-size: .76rem; }
.history-entry small { margin-top: 2px; color: #687c83; font-size: .65rem; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
@media (max-width: 430px) {
  .auto-capture-tools { grid-template-columns: minmax(0, 1fr) 88px; }
  .edit-action-btn { font-size: .59rem; padding-inline: 3px; }
  .edit-small-actions { grid-template-columns: 1fr; }
  .validation-list { max-height: 120px; }
}

/* Keep the increasingly capable map tool console usable on small phones. */
.map-tools-panel {
  max-height: calc(100% - 20px);
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
}
.map-tools-panel::-webkit-scrollbar { width: 5px; }
.map-tools-panel::-webkit-scrollbar-thumb { background: #2c464e; border-radius: 999px; }

.file-button.is-disabled { opacity: .45; cursor: not-allowed; pointer-events: none; }


/* v11: integrated bilingual help & compatibility guide */
.help-system-card,
.help-card { overflow: hidden; }
.help-card-head {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  align-items: flex-start;
  margin-bottom: 14px;
}
.help-status-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
}
.help-status-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  min-width: 0;
  padding: 11px 12px;
  border: 1px solid var(--shell-border);
  border-radius: 9px;
  background: var(--shell-panel-2);
}
.help-status-row > span {
  min-width: 0;
  color: var(--shell-muted);
  font-size: .78rem;
}
.status-value {
  flex: 0 0 auto;
  font: 800 .72rem/1.2 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  text-transform: uppercase;
  letter-spacing: .045em;
}
.status-value.ok { color: #73eba0; }
.status-value.warn { color: #f4c665; }
.status-value.bad { color: #ff8a93; }
.help-source-note {
  display: block;
  margin-top: 10px;
  color: #596c73;
  font: .68rem/1.4 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.help-card h3 { margin-bottom: 13px; }
.help-card h4 {
  margin: 0 0 8px;
  color: #b8c8ce;
  font-size: .82rem;
  text-transform: uppercase;
  letter-spacing: .055em;
}
.help-steps,
.help-list {
  margin: 0;
  padding-left: 1.25rem;
  color: #a2b1b7;
}
.help-steps { display: grid; gap: 10px; }
.help-steps li,
.help-list li { padding-left: 4px; line-height: 1.55; }
.help-list { display: grid; gap: 7px; }
.compat-grid,
.help-feature-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 9px;
}
.compat-item,
.help-feature-grid > div,
.format-card {
  min-width: 0;
  padding: 13px;
  border: 1px solid var(--shell-border);
  border-radius: 10px;
  background: var(--shell-panel-2);
}
.compat-item { border-left-width: 3px; }
.compat-item.good { border-left-color: #3ed87a; }
.compat-item.bad { border-left-color: #ef6670; }
.compat-item.neutral { border-left-color: #4fbccc; }
.compat-item strong,
.help-feature-grid strong,
.format-card strong {
  display: block;
  margin-bottom: 5px;
  color: var(--shell-text);
  font-size: .84rem;
}
.compat-item span,
.help-feature-grid span,
.format-card p {
  display: block;
  color: var(--shell-muted);
  font-size: .79rem;
  line-height: 1.5;
}
.help-two-col {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}
.help-note { margin-top: 12px; }
/* Der PWA-Abschnitt folgt direkt auf das zweispaltige Offline-Raster und braucht Luft. */
.help-card .help-two-col + h4 { margin-top: 16px; }
.notice.info {
  background: #0d2228;
  color: #9dcbd3;
  border-color: #28515b;
}
.faq-list { display: grid; gap: 7px; }
.faq-list details {
  border: 1px solid var(--shell-border);
  border-radius: 9px;
  background: var(--shell-panel-2);
  overflow: hidden;
}
.faq-list summary {
  min-height: 46px;
  padding: 12px 13px;
  cursor: pointer;
  color: #c9d7dc;
  font-weight: 760;
  list-style-position: inside;
}
.faq-list details[open] summary { border-bottom: 1px solid #24363c; }
.faq-list p { padding: 12px 13px 14px; font-size: .8rem; }

@media (max-width: 760px) {
  .tabs { grid-template-columns: repeat(5, minmax(0, 1fr)); }
  .tab-btn { padding-left: 2px; padding-right: 2px; font-size: .64rem; }
  .help-status-grid,
  .compat-grid,
  .help-feature-grid,
  .help-two-col { grid-template-columns: 1fr; }
}

@media (max-width: 390px) {
  .tab-icon { font-size: .95rem; }
  .tab-btn { font-size: .59rem; letter-spacing: .025em; }
}

/* v12 · mapping quality, gallery and manual mower control */
.tabs { grid-template-columns: repeat(6, minmax(0, 1fr)); }

/* Nur die Fuellung zeigt die RTK-Qualitaet. Der Rand bleibt der Elementfarbe vorbehalten
   (Perimeter/Ausschluss/Wegpunkt/Dock) — vorher ueberschrieb die Qualitaet auch den Rand
   mit !important, dadurch sahen Punkte aller Elemente identisch aus. */
.map-point.quality-excellent { fill: #4cf59a !important; }
.map-point.quality-good { fill: #74ddea !important; }
.map-point.quality-warning { fill: #f3c963 !important; }
.map-point.quality-bad { fill: #ef6670 !important; }

.measurement-line {
  stroke: #f3c963;
  stroke-width: 2.5;
  stroke-dasharray: 7 5;
  vector-effect: non-scaling-stroke;
  filter: drop-shadow(0 0 4px rgba(243,201,99,.25));
}
.measurement-point { fill: #f3c963; stroke: #11181b; stroke-width: 2; vector-effect: non-scaling-stroke; }
.measurement-label {
  fill: #f8e4aa;
  font-size: 12px;
  font-weight: 800;
  paint-order: stroke;
  stroke: #080d0f;
  stroke-width: 3px;
  stroke-linejoin: round;
}
#mapSvg.measurement-mode { cursor: crosshair; }

.map-gallery {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 10px;
}
.map-gallery-card {
  position: relative;
  min-width: 0;
  display: grid;
  grid-template-columns: 1fr auto auto;
  overflow: hidden;
  border: 1px solid #27383e;
  border-radius: 12px;
  background: #091013;
}
.map-gallery-card.active { border-color: #4fbccc; box-shadow: inset 0 0 0 1px rgba(79,188,204,.25); }
.map-gallery-card.locked { border-style: dashed; }
.map-card-select {
  min-width: 0;
  display: grid;
  grid-template-columns: 112px minmax(0,1fr);
  align-items: center;
  gap: 10px;
  padding: 9px;
  border: 0;
  background: transparent;
  color: inherit;
  text-align: left;
}
.map-card-thumb { width: 112px; aspect-ratio: 8 / 5; border: 1px solid #203038; border-radius: 8px; background: #050a0c; }
.thumb-perimeter { fill: rgba(62,216,122,.08); stroke: #3ed87a; stroke-width: 2; }
.thumb-exclusion { fill: rgba(239,102,112,.12); stroke: #ef6670; stroke-width: 2; }
.thumb-dock { fill: none; stroke: #4fbccc; stroke-width: 2; }
.map-card-copy { min-width: 0; display: grid; gap: 3px; }
.map-card-copy strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: #dce8eb; }
.map-card-copy small { color: #82949b; font-size: .72rem; }
/* Umbenennen und Duplizieren als schmale Spalte zwischen Karte und Schloss. */
.map-card-tools {
  align-self: stretch;
  display: grid;
  align-content: center;
  gap: 4px;
  padding: 6px 5px;
  border-left: 1px solid var(--shell-border-soft);
  background: var(--shell-panel-2);
}
.map-card-tool {
  display: grid;
  place-items: center;
  width: 36px; height: 36px;
  padding: 0;
  border: 1px solid var(--shell-border);
  border-radius: 9px;
  background: var(--shell-panel);
  color: var(--shell-muted);
}
.map-card-tool svg { width: 17px; height: 17px; fill: none; stroke: currentColor; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }
.map-card-tool:active { background: var(--shell-hover); }

.modal-input {
  width: 100%;
  margin-top: 10px;
  padding: 9px 10px;
  border: 1px solid var(--shell-border);
  border-radius: 9px;
  background: var(--shell-panel-2);
  color: var(--shell-text);
  font: inherit;
}

.map-card-lock {
  align-self: stretch;
  width: 72px;
  min-height: 0;
  padding: 6px 4px;
  display: grid;
  justify-items: center;
  align-content: center;
  gap: 2px;
  border: 0;
  border-left: 1px solid var(--shell-border-soft);
  border-radius: 0;
  background: var(--shell-panel-2);
  color: var(--shell-muted);
}

.control-safety-card { border-color: #4b3539; }
.control-status-row,
.control-section-head {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  align-items: flex-start;
}
.control-status-row { margin-bottom: 12px; color: #83959c; }
#controlConnectionStatus { color: #ef6670; }
#controlConnectionStatus.online { color: #4cf59a; }
.emergency-stop {
  width: 100%;
  min-height: 76px;
  margin-top: 12px;
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-rows: auto auto;
  column-gap: 12px;
  align-items: center;
  text-align: left;
  background: #55151c;
  border-color: #a73a46;
  color: #fff;
}
.emergency-stop > span { grid-row: 1 / 3; font-size: 1.7rem; }
.emergency-stop strong { font-size: 1.05rem; letter-spacing: .08em; }
.emergency-stop small { color: #ffd9dc; }

.speed-readout { flex: 0 0 auto; display: grid; justify-items: end; gap: 2px; color: #81949b; font-size: .72rem; }
.speed-readout strong { color: #74ddea; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: .9rem; }
.drive-pad {
  width: min(360px, 100%);
  margin: 16px auto 10px;
  display: grid;
  grid-template-columns: repeat(3, minmax(70px, 1fr));
  grid-template-areas: ". forward ." "left stop right" ". reverse .";
  gap: 9px;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
}
.drive-forward { grid-area: forward; }
.drive-left { grid-area: left; }
.drive-stop { grid-area: stop; }
.drive-right { grid-area: right; }
.drive-reverse { grid-area: reverse; }
.drive-btn {
  min-height: 78px;
  display: grid;
  place-items: center;
  gap: 2px;
  border: 1px solid #2a4249;
  background: #0a1519;
  color: #b9cbd0;
  touch-action: none;
}
.drive-btn > span { font-size: 1.45rem; line-height: 1; }
.drive-btn small { color: #80939a; }
.drive-btn.pressed { background: #12343c; border-color: #4fbccc; color: #9de9f4; transform: translateY(1px); }
.drive-stop { border-color: #5a3439; color: #ef8a92; }
.control-command-state {
  min-height: 42px;
  display: grid;
  place-items: center;
  padding: 8px 12px;
  border: 1px solid #26373d;
  border-radius: 9px;
  background: #080e11;
  color: #92a7ae;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  text-align: center;
}

.mow-state { min-width: 62px; padding: 7px 10px; border-radius: 999px; text-align: center; font-size: .75rem; font-weight: 900; letter-spacing: .08em; }
.mow-state.off { background: #171d20; color: #819198; border: 1px solid #313f44; }
.mow-state.on { background: #5b171e; color: #ffd9dc; border: 1px solid #aa3c47; box-shadow: 0 0 0 3px rgba(239,102,112,.08); }
.danger-switch { margin: 14px 0 10px; }
.mow-start-button {
  width: 100%;
  min-height: 86px;
  display: grid;
  place-items: center;
  gap: 4px;
  border: 1px solid #784049;
  border-radius: 12px;
  background: #291217;
  color: #ffdce0;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
}
.mow-start-button:disabled { opacity: .42; }
.mow-start-button strong { font-size: 1rem; }
.mow-start-button small { color: #d9a9ae; }
.mow-progress { height: 6px; margin-top: 7px; overflow: hidden; border-radius: 999px; background: #24171a; }
.mow-progress span { display: block; width: 0; height: 100%; background: #ef6670; transition: width .04s linear; }

@media (max-width: 760px) {
  .tabs { display: flex; overflow-x: auto; scrollbar-width: none; }
  .tabs::-webkit-scrollbar { display: none; }
  .tab-btn { flex: 0 0 92px; }
  .map-gallery { grid-template-columns: 1fr; }
  .map-card-select { grid-template-columns: 96px minmax(0,1fr); }
  .map-card-thumb { width: 96px; }
  .control-section-head { align-items: center; }
}

/* v13 · adjustable mowing motor PWM */
.mow-pwm-control {
  margin: 10px 0 14px;
  padding: 12px;
  border: 1px solid #303d42;
  border-radius: 10px;
  background: #090f12;
}
.mow-pwm-head h4 { margin: 0 0 3px; color: #dbe7ea; font-size: .92rem; }
.mow-pwm-head p { margin: 0; color: #82949b; font-size: .78rem; line-height: 1.4; }
.mow-pwm-slider { width: 100%; margin: 12px 0 10px; accent-color: #ef6670; }
.mow-pwm-input-row { display: grid; grid-template-columns: minmax(100px, 150px) minmax(150px, 1fr); gap: 10px; align-items: end; }
.compact-field { margin: 0; }
.compact-field input { min-height: 44px; }
.mow-pwm-apply { min-height: 44px; }
.sr-only { position: absolute !important; width: 1px !important; height: 1px !important; padding: 0 !important; margin: -1px !important; overflow: hidden !important; clip: rect(0,0,0,0) !important; white-space: nowrap !important; border: 0 !important; }
@media (max-width: 420px) { .mow-pwm-input-row { grid-template-columns: 1fr; } }

/* v14 · mobile-first map workspace, slide-in tools and analog joystick */
.tabs { grid-template-columns: repeat(5, minmax(0, 1fr)); }
.telemetry-strip {
  grid-template-columns: minmax(74px,.75fr) minmax(74px,.75fr) minmax(170px,1.8fr);
  gap: 5px;
  margin-bottom: 7px;
}
.telemetry-item {
  min-height: 46px;
  padding: 6px 8px;
  border-radius: 8px;
}
.telemetry-item strong { font-size: .9rem; }
.telemetry-item > span { font-size: .6rem; }
.gps-item {
  grid-template-columns: auto auto minmax(0,1fr);
  grid-template-rows: auto auto;
  column-gap: 7px;
  row-gap: 1px;
}
.gps-item > span:first-child { grid-row: 1 / 3; align-self: center; }
.gps-item > #solutionValue { grid-column: 2; grid-row: 1; }
.gps-meta {
  grid-column: 2 / 4;
  grid-row: 2;
  display: flex;
  min-width: 0;
  gap: 5px;
  align-items: center;
}
.gps-meta #gpsDetail { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gps-meta .battery-inline { color: #b7c9cf; font-size: .69rem; font-weight: 800; text-align: left; }
.telemetry-firmware { grid-column: 3; grid-row: 1; text-align: right; align-self: center; }
.telemetry-dot { color: #36515a; }

.mapping-stage { overflow: hidden; }
.map-frame {
  height: clamp(480px, 68dvh, 860px);
  min-height: 480px;
}

.edge-drawer-toggle {
  position: absolute;
  z-index: 16;
  top: 50%;
  min-width: 38px;
  width: 38px;
  min-height: 104px;
  padding: 8px 4px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  transform: translateY(-50%);
  border: 1px solid #34525b;
  background: rgba(11, 25, 29, .95);
  color: #8de3ed;
  box-shadow: 0 8px 28px rgba(0,0,0,.36);
  backdrop-filter: blur(12px);
  touch-action: manipulation;
}
.edge-drawer-toggle > span { font-size: 1.15rem; line-height: 1; }
.edge-drawer-toggle small {
  writing-mode: vertical-rl;
  text-transform: uppercase;
  letter-spacing: .08em;
  font: 800 .55rem/1 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}
.edge-drawer-toggle.active { background: #15343b; border-color: #4e8794; color: #b2f0f7; }
.control-drawer-toggle { left: 0; border-left: 0; border-radius: 0 9px 9px 0; }
.tools-drawer-toggle { right: 0; border-right: 0; border-radius: 9px 0 0 9px; }

.map-tools-panel,
.map-control-panel {
  transition: transform .22s ease, opacity .18s ease, visibility .18s ease;
  will-change: transform;
}
.map-tools-panel {
  top: 8px;
  right: 8px;
  width: min(330px, calc(100% - 54px));
  max-height: calc(100% - 16px);
  z-index: 15;
}
.map-tools-panel.collapsed {
  transform: translateX(calc(100% + 20px));
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

.map-control-panel {
  position: absolute;
  left: 8px;
  top: 8px;
  z-index: 15;
  width: min(390px, calc(100% - 54px));
  max-height: calc(100% - 16px);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 10px;
  border: 1px solid #2d4850;
  border-radius: 11px;
  background: rgba(7, 15, 18, .95);
  box-shadow: 0 14px 40px rgba(0,0,0,.5), inset 0 1px 0 rgba(255,255,255,.025);
  backdrop-filter: blur(18px);
  scrollbar-width: thin;
}
.map-control-panel.collapsed {
  transform: translateX(calc(-100% - 20px));
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}
.map-control-panel::-webkit-scrollbar { width: 5px; }
.map-control-panel::-webkit-scrollbar-thumb { background: #2c464e; border-radius: 999px; }
.drawer-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  padding: 1px 1px 8px;
  border-bottom: 1px solid #24383f;
}
.drawer-head > div { display: grid; gap: 2px; }
.drawer-head strong { color: #dce9ec; font-size: .92rem; }
.drawer-close {
  width: 42px;
  min-width: 42px;
  min-height: 42px;
  padding: 0;
  border: 1px solid #30464d;
  border-radius: 8px;
  background: #101a1e;
  color: #94aab1;
  font-size: 1.35rem;
}
.compact-status { margin: 8px 2px 7px; font-size: .72rem; }
.compact-emergency {
  min-height: 50px;
  margin: 0 0 8px;
  grid-template-columns: auto 1fr;
  grid-template-rows: 1fr;
  padding: 7px 10px;
}
.compact-emergency > span { grid-row: auto; font-size: 1.1rem; }
.compact-emergency strong { font-size: .85rem; }

.joystick-section { padding: 5px 2px 0; }
.joystick-head { align-items: center; }
.joystick-head h3 { margin: 0 0 2px; font-size: .88rem; }
.joystick-head p { max-width: 230px; font-size: .68rem; line-height: 1.25; }
.drive-speed-field { margin: 7px 0 4px; gap: 3px; }
.drive-speed-field > span { font-size: .64rem; }
.drive-speed-field input[type="range"] { min-height: 34px; width: 100%; accent-color: #62d7e6; }
.joystick-wrap { display: grid; place-items: center; padding: 4px 0 5px; }
.joystick-base {
  position: relative;
  width: min(300px, 76vw);
  aspect-ratio: 1;
  border-radius: 50%;
  overflow: hidden;
  touch-action: none;
  user-select: none;
  -webkit-user-select: none;
  background:
    radial-gradient(circle at center, rgba(72,185,201,.11) 0 23%, transparent 24%),
    radial-gradient(circle at center, transparent 0 47%, rgba(69,128,139,.17) 48% 49%, transparent 50%),
    radial-gradient(circle at 42% 37%, #122328 0, #0b171b 58%, #071014 100%);
  border: 2px solid #365964;
  box-shadow: inset 0 0 40px rgba(58,169,187,.07), 0 8px 24px rgba(0,0,0,.32);
}
.joystick-base.unavailable { opacity: .58; }
.joystick-ring { position: absolute; left: 50%; top: 50%; border: 1px solid rgba(94,175,190,.25); border-radius: 50%; transform: translate(-50%,-50%); pointer-events: none; }
.joystick-ring.ring-a { width: 72%; height: 72%; }
.joystick-ring.ring-b { width: 42%; height: 42%; }
.joystick-axis { position: absolute; pointer-events: none; background: rgba(95,179,191,.2); }
.joystick-axis-x { left: 9%; right: 9%; top: 50%; height: 1px; }
.joystick-axis-y { top: 9%; bottom: 9%; left: 50%; width: 1px; }
.joystick-label { position: absolute; color: #617b84; font: 800 .57rem/1 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; text-transform: uppercase; letter-spacing: .06em; pointer-events: none; }
.joy-forward { top: 8px; left: 50%; transform: translateX(-50%); }
.joy-reverse { bottom: 8px; left: 50%; transform: translateX(-50%); }
.joy-left { left: 8px; top: 50%; transform: translateY(-50%) rotate(-90deg); }
.joy-right { right: 8px; top: 50%; transform: translateY(-50%) rotate(90deg); }
.joystick-knob {
  position: absolute;
  left: 50%; top: 50%;
  width: 76px; height: 76px;
  border-radius: 50%;
  transform: translate(-50%, -50%);
  display: grid;
  place-items: center;
  pointer-events: none;
  background: radial-gradient(circle at 36% 30%, #7fe9f4, #2c8998 45%, #15515c 72%);
  border: 2px solid #a2f0f7;
  box-shadow: 0 8px 22px rgba(0,0,0,.45), 0 0 22px rgba(89,214,230,.18), inset 0 1px 1px rgba(255,255,255,.35);
  transition: transform .07s linear;
}
.joystick-dot { width: 13px; height: 13px; border-radius: 50%; background: #d8fbff; box-shadow: 0 0 13px rgba(216,251,255,.7); }
.drive-stop-wide {
  width: 100%;
  min-height: 44px;
  margin: 1px 0 6px;
  display: inline-flex;
  justify-content: center;
  align-items: center;
  gap: 8px;
  border: 1px solid #654048;
  border-radius: 8px;
  background: #281318;
  color: #ff9aa2;
  font-weight: 850;
  text-transform: uppercase;
  letter-spacing: .06em;
}
.control-command-state { min-height: 34px; padding: 6px 8px; font-size: .68rem; }
.inline-mow-panel { margin-top: 8px; border-top: 1px solid #263a41; }
.inline-mow-panel > summary {
  min-height: 46px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  cursor: pointer;
  color: #c3d3d7;
  font-weight: 800;
  list-style: none;
}
.inline-mow-panel > summary::-webkit-details-marker { display: none; }
.inline-mow-body { padding: 0 1px 4px; }
.compact-mow-pwm { padding: 8px; margin: 7px 0 9px; }
.compact-mow-pwm .mow-pwm-slider { min-height: 36px; margin: 7px 0; }
.compact-mow-pwm .mow-pwm-input-row { grid-template-columns: 92px 1fr; gap: 7px; }
.compact-mow-pwm .compact-field input,
.compact-mow-pwm .mow-pwm-apply { min-height: 40px; }
.map-control-panel .mow-start-button { min-height: 62px; padding: 8px 10px; }
.map-control-panel .mow-start-button strong { font-size: .86rem; }
.map-control-panel .mow-start-button small { font-size: .67rem; }

@media (max-width: 760px) {
  .topbar { width: calc(100% - 16px); padding: 8px 0 6px; }
  .brand-mark { width: 34px; height: 34px; border-radius: 9px; }
  .topbar h1 { font-size: 1rem; }
  .eyebrow { font-size: .54rem; }
  .topbar-actions { gap: 5px; }
  .pill { padding: 6px 8px; font-size: .65rem; }
  .language-toggle { min-height: 36px; padding: 4px 6px; }
  .tabs { width: calc(100% - 12px); margin-bottom: 7px; padding: 3px; }
  .tab-btn { flex: 1 0 76px; min-height: 43px; font-size: .6rem; gap: 4px; }
  .tab-icon { font-size: .9rem; }
  .app-shell { width: calc(100% - 10px); padding-bottom: 20px; }
  .capture-header { margin: 1px 2px 5px; }
  .map-title-block .overline { font-size: .52rem; }
  .map-title-block strong { font-size: .86rem; }
  .gps-badge { min-height: 31px; padding: 5px 8px; font-size: .64rem; }
  .telemetry-strip { grid-template-columns: .7fr .7fr 1.8fr; }
  .telemetry-item { min-height: 42px; padding: 5px 6px; }
  .telemetry-item strong { font-size: .78rem; }
  .telemetry-item > span, .telemetry-item small { font-size: .55rem; }
  .gps-meta { gap: 3px; }
  .gps-meta .battery-inline { font-size: .58rem; }
  .map-frame { height: clamp(470px, 70dvh, 760px); min-height: 470px; }
  .map-tools-panel,
  .map-control-panel { top: 6px; max-height: calc(100% - 12px); }
  .map-tools-panel { right: 6px; width: min(318px, calc(100% - 48px)); }
  .map-control-panel { left: 6px; width: min(380px, calc(100% - 48px)); }
  .edge-drawer-toggle { width: 34px; min-width: 34px; min-height: 94px; }
  .capture { min-height: 82px; }
  .capture-copy strong { font-size: 1rem; }
  .capture-copy small { font-size: .67rem; }
}

@media (max-width: 430px) {
  .brand .eyebrow { display: none; }
  .brand-mark { display: none; }
  .topbar h1 { font-size: .9rem; }
  .pill { max-width: 112px; overflow: hidden; text-overflow: ellipsis; }
  .tabs { border-radius: 9px; }
  .tab-btn { flex-basis: 68px; min-height: 40px; }
  .tab-btn span:last-child { font-size: .55rem; }
  .capture-header { gap: 6px; }
  .gps-badge { max-width: 46%; overflow: hidden; }
  .telemetry-strip { grid-template-columns: 66px 66px minmax(0,1fr); }
  .telemetry-item { border-radius: 7px; }
  .telemetry-item > small:not(.gps-meta):not(.telemetry-firmware) { display: none; }
  .telemetry-firmware { display: none; }
  .gps-item { grid-template-columns: auto auto minmax(0,1fr); }
  .map-frame { height: clamp(500px, 72dvh, 720px); min-height: 500px; }
  .map-tools-panel { width: calc(100% - 44px); padding: 7px; }
  .map-control-panel { width: calc(100% - 44px); padding: 8px; }
  .joystick-base { width: min(280px, 72vw); }
  .joystick-knob { width: 70px; height: 70px; }
  .joystick-head p { font-size: .63rem; }
  .compact-mow-pwm .mow-pwm-input-row { grid-template-columns: 88px 1fr; }
}

@media (prefers-reduced-motion: reduce) {
  .map-tools-panel, .map-control-panel, .joystick-knob { transition: none; }
}


/* ==========================================================================
   v17 · Kartier-Oberflaeche: Kopfzeile, Vollbildkarte, Daumen-Joystick
   Ersetzt Tab-Leiste, Schieber und Maehsteuerung.
   ========================================================================== */

html, body { height: 100%; }
body {
  margin: 0;
  padding: 0;
  overflow: hidden;
  overscroll-behavior: none;
  -webkit-user-select: none;
  user-select: none;
}
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.app-frame {
  /* Bewusst Flex statt Grid: die Update-Leiste ist meistens ausgeblendet. In einem Grid mit
     festen Zeilen rutschten die restlichen Kinder dann eine Zeile hoch — die Karte landete in
     der auto-Zeile und die Fahrzone in der 1fr-Zeile, also genau vertauscht. Bei Flex haben
     die Kinder ihre Rolle selbst, egal wie viele davon gerade ausgeblendet sind. */
  display: flex;
  flex-direction: column;
  height: 100dvh;
}
.app-frame > .update-bar,
.app-frame > .appbar,
.app-frame > .drive-zone { flex: 0 0 auto; }
.app-frame > .map-stage { flex: 1 1 auto; min-height: 0; }
body.menu-open .app-frame { visibility: hidden; }

/* --- Kopfzeile ---------------------------------------------------------- */
.appbar {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: calc(env(safe-area-inset-top, 0px) + 6px) 8px 6px;
  background: var(--shell-bar);
  border-bottom: 1px solid var(--shell-border-soft);
}
.appbar-icon-btn {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 42px; height: 42px;
  padding: 0;
  border: 1px solid var(--shell-border);
  border-radius: 11px;
  background: var(--shell-panel);
  color: var(--shell-text);
}
.appbar-icon-btn svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }
.appbar-icon-btn:active { background: var(--shell-hover); }
.ble-chip.offline { color: var(--shell-danger); border-color: #57302f; }
.ble-chip.online { color: var(--shell-ok); border-color: var(--shell-ok-border); background: var(--shell-ok-bg); }
/* Demo-Marke (Stand v76): solange der Demo laeuft, steht das Wort im Verbindungsknopf statt des
   Bluetooth-Zeichens — es gibt ja keine Funkverbindung. Kein Blinken, nichts liegt ueber der
   Karte, und der Knopf behaelt seine Groesse: die Kopfzeile verschiebt sich beim Umschalten
   nicht, der Modus-Chip verliert keinen Platz (im Browser nachgemessen, 38 und 42 px).
   Die Farben stehen zusaetzlich unter `.appbar`, weil `:root[data-theme="light"] button` und
   seine Media-Query-Fassung mit (0,2,1) sonst jede Statusfarbe des Knopfes ueberschreiben. */
.ble-chip-demo { display: none; }
.ble-chip.demo svg { display: none; }
.ble-chip.demo .ble-chip-demo { display: block; font-size: .62rem; font-weight: 800; letter-spacing: .02em; line-height: 1; }
.appbar .ble-chip.demo { color: var(--shell-warn); border-color: var(--shell-warn-border); background: var(--shell-warn-bg); }

.mode-chip {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 7px;
  height: 42px;
  padding: 0 10px;
  border: 1px solid var(--shell-border);
  border-radius: 11px;
  background: var(--shell-panel);
  color: var(--shell-text);
  font-size: .82rem;
  font-weight: 800;
  letter-spacing: .02em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.mode-chip:active { background: var(--shell-hover); }
.mode-dot { width: 11px; height: 11px; border-radius: 50%; flex: 0 0 auto; background: var(--perimeter); }
.mode-chip[data-mode="exclusion"] .mode-dot { background: var(--exclusion); }
.mode-chip[data-mode="waypoint"] .mode-dot { background: var(--waypoint, #d7a24a); }
.mode-chip[data-mode="dock"] .mode-dot { background: var(--dock); }

.rtk-chip {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 5px;
  height: 42px;
  padding: 0 9px;
  border: 1px solid var(--shell-border);
  border-radius: 11px;
  background: var(--shell-panel);
  font-size: .74rem;
  font-weight: 800;
  white-space: nowrap;
}
/* Seit v68 ist das Abzeichen ein Knopf (Tipp blendet die GPS-Einblendung um). Die globale
   Knopfregel wuerde sonst ihre eigene Mindesthoehe und Schriftfamilie mitbringen. */
.rtk-chip { min-height: 0; color: var(--shell-text); font-family: inherit; cursor: pointer;
  -webkit-appearance: none; appearance: none; }
.rtk-chip strong { font-size: .78rem; }
.rtk-chip svg { width: 15px; height: 15px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; opacity: .85; }
.rtk-chip.fix { color: var(--shell-ok); border-color: var(--shell-ok-border); background: var(--shell-ok-bg); }
.rtk-chip.float { color: var(--shell-warn); border-color: var(--shell-warn-border); background: var(--shell-warn-bg); }
.rtk-chip.nofix { color: var(--shell-danger); border-color: var(--shell-danger-border); background: var(--shell-danger-bg); }
.rtk-chip.no-data { color: var(--shell-muted); }

.battery-chip {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 5px;
  height: 42px;
  padding: 0 8px;
  border: 1px solid var(--shell-border);
  border-radius: 11px;
  background: var(--shell-panel);
  color: var(--shell-text);
  font-size: .72rem;
  font-weight: 800;
  white-space: nowrap;
}
.battery-glyph {
  position: relative;
  width: 24px; height: 12px;
  border: 1.5px solid currentColor;
  border-radius: 3px;
  opacity: .85;
}
.battery-glyph::after {
  content: ""; position: absolute; right: -4px; top: 3px;
  width: 2.5px; height: 6px; border-radius: 0 2px 2px 0; background: currentColor;
}
.battery-glyph i { position: absolute; inset: 1.5px; width: 0; background: currentColor; border-radius: 1px; transition: width .3s ease; }
.battery-chip.low { color: var(--shell-danger); border-color: var(--shell-danger-border); }
.battery-chip.unknown { color: var(--shell-muted); }

/* --- Kartenbuehne ------------------------------------------------------- */
.map-stage {
  position: relative;
  min-height: 0;
  background: var(--shell-bg);
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
/* Eigener Bezugsrahmen fuer die schwebenden Elemente (Hinweiszeile, Aufnahme-Cluster):
   sie sollen sich an der Zeichenflaeche ausrichten, nicht an der Buehne inklusive
   Werkzeugleiste — sonst laege die Hinweiszeile hinter den Werkzeugen. */
.map-canvas-area { position: relative; flex: 1 1 auto; min-height: 0; }
.map-stage #mapSvg {
  display: block;
  width: 100%;
  height: 100%;
  touch-action: none;
  border: 0;
  border-radius: 0;
}
.map-point-hit { fill: transparent; stroke: none; cursor: pointer; }


.map-fab {
  display: grid;
  place-items: center;
  width: 48px; height: 48px;
  padding: 0;
  border: 1px solid var(--shell-border);
  border-radius: 14px;
  background: var(--shell-panel);
  color: var(--shell-text);
  box-shadow: 0 6px 18px rgba(0,0,0,.4);
}
.map-fab svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }
.map-fab:active { background: var(--shell-hover); }
.map-fab[disabled] { opacity: .35; }
.map-fab.danger-fab { color: var(--shell-danger); border-color: var(--shell-danger-border); background: var(--shell-danger-bg); }

.capture-fab {
  position: absolute;
  right: 12px; bottom: 12px;
  display: grid;
  place-items: center;
  width: var(--capture-size); height: var(--capture-size);
  padding: 0;
  border: 2px solid var(--shell-ok-border);
  border-radius: 50%;
  background: var(--shell-ok-bg);
  color: var(--shell-ok);
  box-shadow: 0 10px 28px rgba(0,0,0,.5);
  overflow: hidden;
}
.capture-fab .capture-ring {
  position: absolute;
  inset: -2px;
  border-radius: 50%;
  pointer-events: none;
  background: conic-gradient(var(--shell-ok) calc(var(--capture-progress, 0) * 360deg), transparent 0);
  opacity: .38;
}
.capture-fab .capture-fab-icon { position: relative; display: grid; place-items: center; }
.capture-fab svg { width: 30px; height: 30px; fill: none; stroke: currentColor; stroke-width: 2.1; stroke-linecap: round; stroke-linejoin: round; }
.capture-fab .icon-move { display: none; }
.capture-fab.move-mode .icon-add { display: none; }
.capture-fab.move-mode .icon-move { display: grid; }
.capture-fab.holding { transform: scale(.96); }
.capture-fab[disabled] { opacity: .45; }
.capture-fab.capture-warning { border-color: var(--shell-warn-border); background: var(--shell-warn-bg); color: var(--shell-warn); }
.capture-fab.capture-blocked { border-color: var(--shell-danger-border); background: var(--shell-danger-bg); color: var(--shell-danger); }
.capture-fab.capture-idle { border-color: var(--shell-border); background: var(--shell-panel); color: var(--shell-muted); }
.capture-fab.capture-stop { border-color: var(--shell-danger-border); background: var(--shell-danger-bg); color: var(--shell-danger); }
.capture-fab.move-mode { border-color: var(--shell-info-border); background: var(--shell-info-bg); color: var(--shell-info); }
.capture-fab.move-mode .capture-ring { display: none; }

/* --- Fahrzone ----------------------------------------------------------- */
.drive-zone {
  /* Drei Spalten: der Joystick bleibt mittig, die Statusanzeige belegt eine der
     Aussenspalten — so verdeckt der bedienende Daumen sie nicht. */
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  justify-items: center;
  /* Nicht auseinanderziehen: die Zone soll genau so hoch sein wie ihr Inhalt,
     der ganze Rest gehoert der Karte. */
  align-content: center;
  column-gap: 10px;
  row-gap: 4px;
  /* Seitlicher Innenabstand = --edge-gap: dadurch steht der Umschalter an der Aussenkante
     seiner Spalte genau so weit vom Bildschirmrand entfernt wie der Rueckgaengig-Knopf auf
     der Karte darueber — beide auf einer gemeinsamen senkrechten Linie. */
  padding: 8px var(--edge-gap) calc(env(safe-area-inset-bottom, 0px) + 8px);
  background: var(--shell-bar);
  border-top: 1px solid var(--shell-border-soft);
}
/* Gemeinsames Feld fuer Joystick UND Tastenkreuz. Groesse und Gitterplatzierung stehen nur
   hier, die beiden Steuerungen fuellen es aus — dadurch bleibt der Ecken-Umschalter in beiden
   Modi an derselben Stelle, ohne zweite Positionslogik. */
.drive-zone .drive-control {
  /* Feste Groesse statt height:auto + aspect-ratio: als Grid-Kind wurde der Joystick sonst
     auf die Zeilenhoehe gestreckt, die Zeile wuchs mit — und die Fahrzone nahm den halben
     Bildschirm ein. align-self verhindert das Strecken zusaetzlich. */
  /* Anteilig zur Bildschirmhoehe (Standard rund 30 % der Zone), zusaetzlich skalierbar
     ueber --joystick-scale aus den Einstellungen. Die Obergrenze in dvh sorgt dafuer, dass
     auch die groesste Stufe der Karte genug Platz laesst. */
  /* Daumenziel je Richtungstaste und die Luecke dazwischen — daraus ergibt sich, wie klein
     das Feld hoechstens werden darf, ohne dass das Tastenkreuz unten herauslaeuft. */
  --drive-pad-key-min: 44px;
  --drive-pad-gap: 4px;
  /* Halbe Breite der Zonenstriche auf vorwaerts/rueckwaerts. Sie zeichnet die Striche **und**
     sagt `app.js`, welche Flaeche zum Strich gehoert: dort gilt die langsamere Nachbarzone. */
  --drive-zone-line: 1px;
  /* **Die Einschnuerung der Sanduhr — an genau einer Stelle.** 0 waere das alte X durch die
     Mitte, 1 ein Kreuz aus vier Rechtecken. Der Wert ist der Anteil der halben nutzbaren
     Ausdehnung `H = 50% - Fuge`, den die halbe Taille misst: bei 0,5 laufen die vier
     Trennlinien nicht auf den Mittelpunkt zu, sondern auf die beiden Punkte `50% +- H/2`.
     Vorwaerts und rueckwaerts werden dadurch breite Trapeze, links und rechts schmale Keile —
     bei vor/zurueck schiebt der Daumen ueber die ganze Laenge, links/rechts sind Korrekturen
     auf der Stelle. */
  --drive-pad-waist: 0.5;
  /* Halbe Taillenbreite als Laenge. Steht hier und nicht viermal in den Formen. */
  --drive-pad-waist-half: calc((50% - var(--drive-pad-gap)) * var(--drive-pad-waist));
  /* **Die Fuge zwischen vorwaerts und rueckwaerts.** Bis v63 schrieben beide Trapeze fuer ihre
     Taillenkante denselben Ausdruck — die Flaechen beruehrten sich dort auf ganzer Laenge, der
     Abstand war 0 px, waehrend zu den Keilen und zum Rand 4 px standen. Beim alten X lagen die
     beiden Spitzen sogar 2 * cut = 5,66 px auseinander; die Sanduhr hatte das ersatzlos verloren.
     Jede Taillenkante rueckt deshalb um die halbe Fuge von der Feldmitte weg — und wandert dabei
     **auf ihrer eigenen Schraege** mit: je Pixel senkrecht nach aussen um `1 - Taille` seitlich
     nach aussen. Nur so bleibt die Fuge zu den Keilen unveraendert genau `--drive-pad-gap`; ein
     Versatz um `--drive-pad-cut-y` wuerde die Kante von ihrer Linie herunterziehen. */
  --drive-pad-waist-lift: calc(var(--drive-pad-gap) / 2);
  --drive-pad-waist-slide: calc(var(--drive-pad-gap) / 2 * (1 - var(--drive-pad-waist)));
  /* **Die Chevrons auf den Fahrtasten.** Sie ersetzen die frueheren Mini-Pfeile und sind reine
     Zeichnung — `pointer-events: none`, die Trefferflaeche bleibt die beschnittene Taste.
     Lage und Groesse folgen vollstaendig aus den Zonengrenzen und den Formtoken; die vier Zahlen
     hier sind das einzige Gestalterische daran und stehen deshalb an derselben Stelle wie die
     Taille.
       air    Luft zur Grenzlinie: der Kasten fuellt sein Band bis auf diesen Anteil.
       stroke Strichstaerke je Laengsmass — waechst dadurch nach aussen mit der Breite mit.
       rise-* Anstieg je Zone (Hoehe durch Breite). Nach aussen **flacher**, damit der Chevron
              trotz des kuerzer werdenden Bandes nach aussen **breiter** wird: die drei Baender
              messen laengs der Achse 0,25 F / 0,15 F / 0,1 F - Fuge, die aeussere Zone hat also
              den wenigsten Weg. Ohne das Abflachen wuerde der schnelle Chevron der kleinste.
       turn   Anteil der Keiltiefe, den der Chevron der Drehtasten einnimmt (45-Grad-Form). */
  --drive-chevron-air: 0.2;
  --drive-chevron-stroke: 0.08;
  --drive-chevron-stroke-min: 2px;
  --drive-chevron-rise-slow: 0.55;
  --drive-chevron-rise-normal: 0.26;
  --drive-chevron-rise-fast: 0.075;
  --drive-chevron-rise-turn: 0.5;
  --drive-chevron-turn: 0.67;
  /* Deckkraft je Zone: innen blass, aussen kraeftig. Die Hervorhebung der aktiven Zone macht
     weiterhin **allein** das Band — `data-zone` veraendert an den Chevrons nichts, sonst saehe
     man zwei Aussagen ueber denselben Zustand. */
  --drive-chevron-dim-slow: 0.55;
  --drive-chevron-dim-normal: 0.78;
  --drive-chevron-dim-fast: 0.95;
  /* Die beiden Versaetze, die die Fuge zwischen zwei Tasten auf ihrer ganzen Laenge genau
     `--drive-pad-gap` breit halten — **senkrecht zur Trennlinie gemessen**, nicht waagerecht.
     Seit der Einschnuerung stehen die Linien nicht mehr im 45-Grad-Winkel, und der eine Faktor
     1/sqrt(2) von frueher traegt nicht mehr fuer beide Richtungen:
       Trapez, waagerecht versetzt:  gap/2 * sqrt((1-k)^2 + 1)         -> k=0,5: 0,559017
       Keil,   senkrecht versetzt:   gap/2 * sqrt((1-k)^2 + 1)/(1-k)   -> k=0,5: 1,118034
     Bei k = 0 fallen beide auf das alte 0,7071 zusammen.
     Beide Faktoren sind **ausgerechnet, nicht per `sqrt()` gebildet** — aber nicht, weil CSS die
     Funktion nicht haette: `pow()`, `sqrt()` und `hypot()` gibt es seit **Chrome und Chrome fuer
     Android 120** (https://developer.chrome.com/blog/chrome-120-beta), und Android/Chrome ist die
     Zielplattform. Der Grund ist ein anderer: `tests/layout-test.js` rechnet die vier Formen
     selbst nach und wertet dazu die `clip-path`-Ausdruecke aus. Ein Ausdruck, den ein Browser
     nicht unterstuetzt, macht `clip-path` **still ungueltig** — die Taste waere dann gar nicht
     beschnitten, ohne Fehlermeldung. Ausgerechnete Faktoren sind fuer beide Seiten lesbar; dass
     sie zur Taille passen, rechnet der Test aus `--drive-pad-waist` nach.
 */
  --drive-pad-cut-x: calc(var(--drive-pad-gap) * 0.559017);
  --drive-pad-cut-y: calc(var(--drive-pad-gap) * 1.118034);
  /* **Wie weit die Drehtasten ueber das Feld hinausragen.** Der Keil allein ist ein Dreieck; der
     groesste Kreis darin bleibt bis zu einer Feldgroesse von 203,34 px unter dem Daumenmass (bei
     140 px nur 29 px). Statt das Feld zu vergroessern, wandert nur die Aussenkante der beiden
     Drehtasten nach aussen — Sanduhr, Fugen, Zonen und Hoehe des Feldes bleiben, wie sie sind.
     Gerechnet ist genau so viel, dass der Kreis `--drive-pad-key-min` misst:
       Ueberstand = key-min/2 * (1 + sqrt((1-k)^2 + 1)) - (1-k) * (F/2 - gap - cut-y)
     Die Schraege des Keils haengt nicht von F ab, deshalb ist das linear in F; reicht der Keil von
     selbst, ist der Ueberstand 0. Gemessen von der bisherigen Aussenkante der Taste (eine Fuge im
     Feld) bis zum Aussenrand des Rahmens um den Ueberstand, also ab der Feldkante — genau der
     Platz, den `.drive-control.mode-buttons` daneben freihaelt. Der Faktor ist ausgerechnet wie die
     Fugenfaktoren; `tests/layout-test.js` rechnet ihn aus `--drive-pad-waist` nach. */
  --drive-turn-reach-factor: 2.118034;
  --drive-turn-reach: max(0px, calc(var(--drive-pad-key-min) / 2 * var(--drive-turn-reach-factor)
    - (var(--joystick-size) / 2 - var(--drive-pad-gap) - var(--drive-pad-cut-y)) * (1 - var(--drive-pad-waist))));
  /* Die Rechnung stammt aus dem alten Dreierraster (drei gestapelte Tasten). Seit dem
     diagonalen Schnitt ist sie nicht mehr die Herleitung, aber weiterhin die **schaerfste** der
     Schranken. Die Sanduhr verlangt bei k = 0,5 (44 px Daumenziel, 4 px Fuge): Aussenkante des
     Keils ab 60,9 px Feldgroesse, Trapez an der inneren Zonengrenze ab 70,0 px, Trapez an
     seiner Taille ab 104,9 px. 140 px erfuellt alle drei mit Abstand;
     `tests/layout-test.js` rechnet sie nach, statt es zu unterstellen. */
  --drive-field-min: calc(3 * var(--drive-pad-key-min) + 2 * var(--drive-pad-gap));
  --joystick-size: clamp(var(--drive-field-min), calc(25dvh * var(--joystick-scale, 1)),
    min(calc(240px * var(--joystick-scale, 1)), 38dvh, calc(100vw - var(--drive-side-reserve))));
  /* Platz, den die beiden Seitenspalten zusammen mindestens behalten: je Seite der Umschalter
     (34 px) plus Spaltenabstand (10 px), dazu der Innenabstand der Zone (2 x 8 px). Ohne diese
     Grenze schob die groesste Joystick-Stufe auf schmalen Telefonen Knopf und Anzeige aus dem
     Bild. */
  --drive-side-reserve: 130px;
  grid-column: 2;
  width: var(--joystick-size);
  height: var(--joystick-size);
  /* Beide Kinder ausdruecklich in Zeile 1: sonst wandert die Anzeige in Spalte 1 (links vom
     Joystick) in eine zweite Zeile, weil der Platzierungszeiger nach dem Joystick schon in
     Spalte 3 steht. Genau das war der sichtbare Layout-Sprung bei „Rechtshaender“. */
  grid-row: 1;
  align-self: center;
  justify-self: center;
}
/* Im Tastenmodus haelt das Feld links und rechts den Platz frei, um den die Drehtasten
   hinausragen. Nur so kann der Ueberstand nichts ueberdecken: die Seitenspalten werden um genau
   diesen Betrag schmaler, und zwischen Ueberstand und Fahrtanzeige bleibt der volle
   Spaltenabstand. Die Feldgroesse selbst aendert sich nicht, das Feld bleibt mittig. Im
   Joystick-Modus gibt es keinen Ueberstand. */
.drive-zone .drive-control.mode-buttons { margin-inline: var(--drive-turn-reach); }
.drive-zone .joystick-base {
  width: 100%;
  height: 100%;
  aspect-ratio: auto;
  margin: 0;
  touch-action: none;
}

/* Seitenspalte neben dem Fahrfeld: Umschalter **oben**, Fahrtanzeige **darunter**. Beide
   teilen sich die Aussenspalte und stehen deshalb uebereinander statt um dieselbe Breite zu
   konkurrieren — vorher sass der Knopf absolut neben dem Feld und reservierte sich ueber einen
   Aussenabstand genau den Platz, der der Anzeige dann fehlte („Fahrt gestoppt“ wurde am Rand
   abgeschnitten). Die Seite haengt am selben `data-handed` wie alles Uebrige: Rechtshaender
   links, Linkshaender rechts. Kein position:absolute mehr, der Knopf kann den Kreis nicht
   ueberlappen, weil er in einer eigenen Gitterspalte liegt. */
.drive-side {
  grid-row: 1;
  grid-column: 1;
  /* Die Spalte wird ausgefuellt, damit der Umschalter an der **Aussenkante** sitzen kann und
     die Fahrtanzeige darunter trotzdem die ganze Spaltenbreite nutzt. */
  justify-self: stretch;
  /* Und sie fuellt auch die **Hoehe** der Zeile. Ohne das erbt sie `align-items: center` von
     der Fahrzone: der Stapel aus Umschalter und Fahrtanzeige stand dann mittig, der Umschalter
     also tief unten neben der Anzeige statt oben unter dem Rueckgaengig-Knopf der Karte. Als
     erstes Kind der gefuellten Spalte sitzt der Umschalter jetzt am oberen Rand der Steuerzone
     — senkrecht unter dem Rueckgaengig-Knopf, mit nur der Zonenkante dazwischen. */
  align-self: stretch;
  min-width: 0;
  max-width: 100%;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 6px;
}
:root[data-handed="left"] .drive-side { grid-column: 3; }
/* Aussenkante der Spalte = Bildschirmseite: Rechtshaender links, Linkshaender rechts. Damit
   liegt der Umschalter auf derselben senkrechten Linie wie der Rueckgaengig-Knopf der Karte. */
.drive-mode-side {
  --drive-toggle-size: 34px;
  /* Einrueckung auf die gemeinsame Mittelachse: der Rueckgaengig-Knopf darueber ist
     var(--fab-size) breit, dieser hier nur var(--drive-toggle-size). Ohne die halbe Differenz
     stimmten zwar die Randabstaende, die Knoepfe standen aber sichtbar versetzt. */
  --drive-toggle-inset: calc((var(--fab-size) - var(--drive-toggle-size)) / 2);
  flex: 0 0 auto;
  align-self: flex-start;
  margin-left: var(--drive-toggle-inset);
  display: grid;
  place-items: center;
  width: var(--drive-toggle-size);
  height: var(--drive-toggle-size);
  padding: 0;
  border: 1px solid var(--shell-border);
  border-radius: 10px;
  background: var(--shell-panel);
  color: var(--shell-muted);
}
:root[data-handed="left"] .drive-mode-side { align-self: flex-end; margin-left: 0; margin-right: var(--drive-toggle-inset); }
.drive-mode-side:active { background: var(--shell-hover); }
/* Kugel anteilig zur Basis: skaliert automatisch mit jeder Groessenstufe mit. */
.drive-zone .joystick-knob { width: 41%; height: 41%; }

/* --- Richtungstasten statt Joystick ---------------------------------------
   Das Kreuz sitzt in derselben Gitterspalte und benutzt dieselbe --joystick-size wie der
   Joystick. Dadurch bleibt die Fahrzone gleich hoch, und Groesseneinstellung, Fahrtanzeige und
   Linkshaender-Spiegelung gelten unveraendert fuer beide Steuerungsarten. Bewusst nur vier
   Richtungen und keine Diagonalen — genau darum geht es. */
.drive-zone .drive-pad {
  width: 100%;
  height: 100%;
  /* **Der Grund fuer die abgeschnittene Taste unten.** Eine Altlast aus dem v14-Layer,
     `.drive-pad { margin: 16px auto 10px }` (weiter oben in dieser Datei), traf dieses Element
     weiterhin: das Kreuz ist `height: 100%` des Feldes, wurde durch den oberen Aussenabstand
     aber um 16 px nach unten geschoben. Sein unterer Rand lag damit 16 px unter der
     Feldunterkante, wo die Fahrzone nur 8 px Innenabstand hat — die Taste ragte also ueber den
     Bildschirmrand hinaus und wurde von `body { overflow: hidden }` gekappt. Weil 16 px ein
     fester Wert ist, trat das in **jeder** Groessenstufe auf. Der runde Joystick setzt in
     `.drive-zone .joystick-base` seit jeher `margin: 0` und war deshalb nie betroffen — genau
     diese Asymmetrie hat gefehlt. Beide Steuerungen muessen dieselbe Randbox haben. */
  margin: 0;
  /* Ebenfalls Altlast: die alte Regel benennt Bereiche („forward“, „stop“ …), die es im
     heutigen Markup nicht mehr gibt. Sie ist tote Last und koennte ein kuenftiges
     `grid-area: forward` still ins Leere laufen lassen. */
  grid-template-areas: none;
  grid-template-columns: none;
  grid-template-rows: none;
  /* **Diagonaler Schnitt statt Dreierraster.** Auf einem 3x3-Raster belegten die vier Tasten nur
     die Kantenmitten; Mitte und Ecken lagen brach. Zur Mitte hin verlaengern laesst sich das dort
     nicht, weil alle vier dieselbe Mittelzelle beanspruchen und sich ueberlagern wuerden. Die
     Diagonalen teilen das Quadrat stattdessen ueberschneidungsfrei in vier Keile — jede Taste
     reicht damit von ihrer Aussenkante bis fast an den Mittelpunkt und wird rund die Haelfte
     laenger. Die Tasten liegen uebereinander und werden erst durch `clip-path` getrennt; die
     Trefferpruefung folgt der Beschneidung, es kann also nur eine Taste gemeint sein. */
  position: relative;
  /* Eigene Stapelebene: der Rahmen um den Ueberstand der Drehtasten liegt darin unter den Tasten,
     aber ueber dem Untergrund der Fahrzone. */
  isolation: isolate;
  display: block;
  /* Die Fugen zwischen den Keilen sind der durchscheinende Untergrund der Flaeche. */
  background: var(--shell-border);
  border-radius: 14px;
  touch-action: none;
}
/* Der Rahmen um den Ueberstand der Drehtasten — derselbe Untergrund wie die Fugen, damit die
   Taste nicht ohne Kante aus dem Feld waechst. Er greift eine Fuge weit ins Feld hinein, sonst
   bliebe an der gerundeten Feldecke ueber dem Ueberstand eine Kerbe. Ohne Ueberstand schrumpft er
   samt diesem Eingriff auf null (`min(…, Ueberstand * 1000)`), die Feldecke bleibt dann, wie sie
   war. */
.drive-zone .drive-pad::before,
.drive-zone .drive-pad::after {
  --drive-turn-rim-overlap: min(var(--drive-pad-gap), var(--drive-turn-reach) * 1000);
  content: '';
  position: absolute;
  z-index: -1;
  top: var(--drive-pad-cut-y);
  bottom: var(--drive-pad-cut-y);
  width: calc(var(--drive-turn-reach) + var(--drive-turn-rim-overlap));
  background: inherit;
}
.drive-zone .drive-pad::before {
  right: calc(100% - var(--drive-turn-rim-overlap));
  border-radius: var(--drive-pad-gap) 0 0 var(--drive-pad-gap);
}
.drive-zone .drive-pad::after {
  left: calc(100% - var(--drive-turn-rim-overlap));
  border-radius: 0 var(--drive-pad-gap) var(--drive-pad-gap) 0;
}

.drive-key {
  /* **Der Grund fuer die abgeschnittene Taste unten.** Global gilt `button { min-height: 46px }`.
     Eine Gitterzeile konnte ihr Kind nicht unter dessen Mindesthoehe druecken, das Kreuz
     brauchte damit immer mindestens 3 x 46 + 2 x 4 = 146 px — mehr, als das Feld in kleinen
     Groessenstufen hoch ist. Der Ueberhang lief unten aus der Fahrzone heraus und wurde vom
     Bildschirmrand gekappt; der runde Joystick ist kein Button und hatte dieses Minimum nie,
     deshalb trat es nur im Tastenmodus auf. Seit dem diagonalen Schnitt fuellt jede Taste das
     ganze Feld und wird beschnitten, die Mindesthoehe kann also nichts mehr aufblaehen — die
     Null bleibt trotzdem stehen, damit ein Rueckbau auf ein Raster nicht dieselbe Falle stellt. */
  min-height: 0;
  position: absolute;
  inset: 0;
  display: grid;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: var(--shell-panel);
  color: var(--shell-text);
  touch-action: none;
}
/* **Die Chevrons.** Sie ersetzen die frueheren Mini-Pfeile (ein Symbol je Taste, 15 % gross,
   an den Rand der Taste geschoben). Vorwaerts und rueckwaerts tragen je drei — einen je Zone —,
   die Drehtasten je einen; die Anzahl sagt damit dasselbe wie das Fahrverhalten.
   Rein zeichnend: `pointer-events: none`, jedes SVG ist `aria-hidden`, der zugaengliche Name
   steht unveraendert als `aria-label` am Button. Der Kasten wird ueber seine Mitte gesetzt,
   `overflow: visible` laesst den Strich ueber den Pfad hinausstehen, statt ihn halb wegzuschneiden
   — deshalb ist der umschliessende Kasten `Breite + Strich` mal `Anstieg + Strich`, und genau so
   rechnet `tests/layout-test.js` nach. `non-scaling-stroke` haelt den Strich gleich dick, obwohl
   die viewBox ungleichmaessig gestreckt wird. */
.drive-chevron {
  position: absolute;
  left: var(--chev-x);
  top: var(--chev-y);
  width: var(--chev-box-w);
  height: var(--chev-box-h);
  transform: translate(-50%, -50%);
  overflow: visible;
  fill: none;
  stroke: currentColor;
  /* Absolute Laenge, niemals Prozent — siehe die Begruendung an `.drive-key`. Die Untergrenze
     haelt den Strich auch dann sichtbar, wenn die Breite einmal klein ausfaellt. */
  stroke-width: max(var(--drive-chevron-stroke-min), calc(var(--chev-w) * var(--drive-chevron-stroke)));
  stroke-linecap: round;
  stroke-linejoin: round;
  pointer-events: none;
}
.drive-chevron path { vector-effect: non-scaling-stroke; }
.drive-key:active { background: var(--shell-hover); }

/* Die vier Flaechen der Sanduhr. Aussen um `--drive-pad-gap` eingerueckt, damit der Untergrund
   als Rahmen stehen bleibt; die Trennlinien laufen auf die beiden Taillenpunkte statt auf den
   Mittelpunkt und sind um `--drive-pad-cut-x` (Trapez, waagerecht) bzw. `--drive-pad-cut-y`
   (Keil, senkrecht) versetzt, damit die Fuge dazwischen senkrecht gemessen genauso breit ist
   wie die zum Rand. Vor/zurueck sind Trapeze — aussen ueber die volle Breite, an der Taille
   `2 * waist-half` —, links/rechts Keile mit der Spitze `waist-half + cut-x` vor der Mitte.
   Die beiden Taillenkanten stehen seit dem Nachbau um `--drive-pad-waist-lift` von der Mitte ab
   und um `--drive-pad-waist-slide` seitlich nach aussen: dadurch trennt die volle Fuge auch
   vorwaerts von rueckwaerts, nicht nur die Trapeze von den Keilen.
   Keine der vier Formen schreibt eine eigene Zahl: Fuge, Taille und alle Versaetze sind Token. */
.drive-key.key-up {
  clip-path: polygon(calc(var(--drive-pad-gap) + var(--drive-pad-cut-x)) var(--drive-pad-gap),
    calc(100% - var(--drive-pad-gap) - var(--drive-pad-cut-x)) var(--drive-pad-gap),
    calc(50% + var(--drive-pad-waist-half) - var(--drive-pad-cut-x) + var(--drive-pad-waist-slide))
      calc(50% - var(--drive-pad-waist-lift)),
    calc(50% - var(--drive-pad-waist-half) + var(--drive-pad-cut-x) - var(--drive-pad-waist-slide))
      calc(50% - var(--drive-pad-waist-lift)));
}
.drive-key.key-down {
  clip-path: polygon(calc(var(--drive-pad-gap) + var(--drive-pad-cut-x)) calc(100% - var(--drive-pad-gap)),
    calc(50% - var(--drive-pad-waist-half) + var(--drive-pad-cut-x) - var(--drive-pad-waist-slide))
      calc(50% + var(--drive-pad-waist-lift)),
    calc(50% + var(--drive-pad-waist-half) - var(--drive-pad-cut-x) + var(--drive-pad-waist-slide))
      calc(50% + var(--drive-pad-waist-lift)),
    calc(100% - var(--drive-pad-gap) - var(--drive-pad-cut-x)) calc(100% - var(--drive-pad-gap)));
}
/* Links/rechts: der Keil plus ein Streifen ueber die Feldkante hinaus, `--drive-turn-reach` breit
   (bei grossem Feld 0, dann fallen je zwei Ecken zusammen und es bleibt der reine Keil). Die
   Schraegen zur Sanduhr sind dieselben wie vorher, die Fugen dorthin also auch. */
.drive-key.key-left {
  clip-path: polygon(calc(var(--drive-pad-gap) - var(--drive-turn-reach)) calc(var(--drive-pad-gap) + var(--drive-pad-cut-y)),
    var(--drive-pad-gap) calc(var(--drive-pad-gap) + var(--drive-pad-cut-y)),
    calc(50% - var(--drive-pad-waist-half) - var(--drive-pad-cut-x)) 50%,
    var(--drive-pad-gap) calc(100% - var(--drive-pad-gap) - var(--drive-pad-cut-y)),
    calc(var(--drive-pad-gap) - var(--drive-turn-reach)) calc(100% - var(--drive-pad-gap) - var(--drive-pad-cut-y)));
}
.drive-key.key-right {
  clip-path: polygon(calc(100% - var(--drive-pad-gap) + var(--drive-turn-reach)) calc(var(--drive-pad-gap) + var(--drive-pad-cut-y)),
    calc(100% - var(--drive-pad-gap) + var(--drive-turn-reach)) calc(100% - var(--drive-pad-gap) - var(--drive-pad-cut-y)),
    calc(100% - var(--drive-pad-gap)) calc(100% - var(--drive-pad-gap) - var(--drive-pad-cut-y)),
    calc(50% + var(--drive-pad-waist-half) + var(--drive-pad-cut-x)) 50%,
    calc(100% - var(--drive-pad-gap)) calc(var(--drive-pad-gap) + var(--drive-pad-cut-y)));
}
/* **Der Ueberstand liegt ausserhalb des Tastenkastens.** Der Kasten bleibt das Feld — damit gelten
   alle Prozente, die Fugen und die Lage der Chevrons unveraendert. Gemalt wird der Ueberstand von
   diesem Pseudo-Element; beschnitten wird er wie die ganze Taste vom clip-path oben, das dafuer
   ueber den Kasten hinausreicht. Trefferpruefung und `:active` gehoeren damit zur Taste selbst. */
.drive-key.key-left::before,
.drive-key.key-right::before {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  width: var(--drive-turn-reach);
  background: inherit;
}
.drive-key.key-left::before { right: 100%; }
.drive-key.key-right::before { left: 100%; }

/* **Die Zonen.** Die Achse laeuft von der Mitte des Feldes (50 %) zur Aussenkante der jeweiligen
   Taste (100 %); ein Anteil q der Strecke Mitte->Kante liegt deshalb bei `50% + q/2`. Die
   Grenzen kommen aus `--drive-zone-inner`/`--drive-zone-outer`, die `applyDriveZonePreferences()`
   aus DRIVE_ZONES setzt — im Stylesheet steht keine eigene Prozentzahl, sonst koennten Strich
   und gefahrene Geschwindigkeit auseinanderlaufen. */
.drive-key.key-up { --zone-axis: to top; }
.drive-key.key-down { --zone-axis: to bottom; }
.drive-key.key-left { --zone-axis: to left; }
.drive-key.key-right { --zone-axis: to right; }
/* Die beiden Grenzen in Elementkoordinaten. Sie standen bis v63 unter
   `.drive-pad.zones-on .drive-key` und waren damit nur bei eingeschalteten Zonen definiert —
   der eine Chevron, den vorwaerts und rueckwaerts **ohne** Zonen zeigen, sitzt aber an genau
   derselben Stelle wie der der normalen Zone und braucht sie deshalb auch dann. Sie gehoeren
   zur Taste, nicht zum Schalter, und stehen jetzt hier. */
.drive-key {
  /* **Alle Chevron-Masse stehen in px, nicht in Prozent.** Grund ist nachgemessen, nicht
     vermutet: `stroke-width` loest einen Prozentwert gegen die **viewBox** des SVG auf, nicht
     gegen die Taste. `2.82353%` (= 0,08 * Chevronbreite, gemeint waren 3,95 px bei F = 140)
     kam in Chrome 153 als **0,045 px** an — pixelgleich mit `stroke-width: 0.04464px`, also
     Faktor 88 zu duenn und praktisch unsichtbar. Die Taste liegt `inset: 0` ueber dem Feld,
     ihr Kasten ist damit genau `--joystick-size`; die Breitbild-Fassung setzt das Token an
     `.drive-control` neu, es stimmt also in beiden Layouts. */
  --key-size: var(--joystick-size);
  --key-half: calc(var(--key-size) / 2);
  /* Die halbe Taille als Laenge — dieselbe Rechnung wie `--drive-pad-waist-half`, nur in px
     statt in Prozent. `tests/layout-test.js` rechnet beide Fassungen gegeneinander nach, damit
     sie nicht auseinanderlaufen koennen. */
  --drive-pad-waist-half-len: calc((var(--key-half) - var(--drive-pad-gap)) * var(--drive-pad-waist));
  /* Die Zonengrenzen auf der Achse Mitte -> Aussenkante. `--drive-zone-inner` ist seitdem ein
     **blosser Anteil** (0,5) statt eines Prozentwerts: derselbe Wert traegt so die Grenzstriche
     und die Chevrons, und nur als Zahl laesst er sich mit einer Laenge multiplizieren. */
  --zone-inner: calc(var(--key-half) + var(--drive-zone-inner, 0.5) * var(--key-half));
  --zone-outer: calc(var(--key-half) + var(--drive-zone-outer, 0.8) * var(--key-half));
  /* Tiefe des Drehkeils von der Aussenkante bis zur Spitze — Bezugsmass des Dreh-Chevrons. */
  --drive-turn-depth: calc(var(--key-half) - var(--drive-pad-gap) - var(--drive-pad-waist-half-len) - var(--drive-pad-cut-x));
}
.drive-pad.zones-on .drive-key {
  background-image: linear-gradient(var(--zone-axis),
    transparent calc(var(--zone-inner) - var(--drive-zone-line)), var(--shell-border) calc(var(--zone-inner) - var(--drive-zone-line)),
    var(--shell-border) calc(var(--zone-inner) + var(--drive-zone-line)), transparent calc(var(--zone-inner) + var(--drive-zone-line)),
    transparent calc(var(--zone-outer) - var(--drive-zone-line)), var(--shell-border) calc(var(--zone-outer) - var(--drive-zone-line)),
    var(--shell-border) calc(var(--zone-outer) + var(--drive-zone-line)), transparent calc(var(--zone-outer) + var(--drive-zone-line)));
}
/* Die Zone, in der gerade gefahren wird. `data-zone` setzt `refreshCursorZoneVisual()` an genau
   der gedrueckten Taste; das Band liegt ueber den Grenzstrichen. */
.drive-pad.zones-on .drive-key[data-zone] {
  background-image: linear-gradient(var(--zone-axis),
    transparent var(--zone-from), var(--accent-soft) var(--zone-from),
    var(--accent-soft) var(--zone-to), transparent var(--zone-to)),
    linear-gradient(var(--zone-axis),
    transparent calc(var(--zone-inner) - var(--drive-zone-line)), var(--shell-border) calc(var(--zone-inner) - var(--drive-zone-line)),
    var(--shell-border) calc(var(--zone-inner) + var(--drive-zone-line)), transparent calc(var(--zone-inner) + var(--drive-zone-line)),
    transparent calc(var(--zone-outer) - var(--drive-zone-line)), var(--shell-border) calc(var(--zone-outer) - var(--drive-zone-line)),
    var(--shell-border) calc(var(--zone-outer) + var(--drive-zone-line)), transparent calc(var(--zone-outer) + var(--drive-zone-line)));
}
.drive-key[data-zone="slow"] { --zone-from: 50%; --zone-to: var(--zone-inner); }
.drive-key[data-zone="normal"] { --zone-from: var(--zone-inner); --zone-to: var(--zone-outer); }
.drive-key[data-zone="fast"] { --zone-from: var(--zone-outer); --zone-to: 100%; }

/* Links und rechts tragen keine Grenzen, weil sie keine Zonen mehr haben: das Drehen auf der
   Stelle laeuft mit einer festen Geschwindigkeit. Die `[data-zone]`-Fassungen stehen bewusst
   mit dabei und die Regel bewusst **nach** dem Band oben — sonst zeichnete ein versehentlich
   gesetztes Merkmal ein hervorgehobenes Band ohne zugehoerige Grenzstriche. */
.drive-pad.zones-on .key-left,
.drive-pad.zones-on .key-right,
.drive-pad.zones-on .key-left[data-zone],
.drive-pad.zones-on .key-right[data-zone] { background-image: none; }

/* **Lage und Groesse der Chevrons — ohne eine eigene Zahl.** Die Achse ist dieselbe wie bei den
   Grenzstrichen: von der Feldmitte (50 %) zur Aussenkante der Taste (100 %), ein Anteil q liegt
   bei `50% + q/2`. Jeder Chevron sitzt in der Mitte seines Bandes und fuellt es bis auf die Luft.
   Die Baender sind dabei zur **Taste** hin gekappt, nicht zum Feldrand: innen endet das langsame
   Band an der Taillenkante (`waist-lift`), aussen das schnelle an der Tastenkante (`gap`).
   Ohne diese Kappung ragte der schnelle Chevron ueber den Rand der beschnittenen Taste hinaus. */
.drive-key .chev-slow {
  --chev-rise: var(--drive-chevron-rise-slow);
  --chev-a0: calc(var(--key-half) + var(--drive-pad-waist-lift));
  --chev-a1: var(--zone-inner);
  opacity: var(--drive-chevron-dim-slow);
}
.drive-key .chev-normal {
  --chev-rise: var(--drive-chevron-rise-normal);
  --chev-a0: var(--zone-inner);
  --chev-a1: var(--zone-outer);
  opacity: var(--drive-chevron-dim-normal);
}
.drive-key .chev-fast {
  --chev-rise: var(--drive-chevron-rise-fast);
  --chev-a0: var(--zone-outer);
  --chev-a1: calc(var(--key-size) - var(--drive-pad-gap));
  opacity: var(--drive-chevron-dim-fast);
}
/* Der Dreh-Chevron traegt die Deckkraft der normalen Zone: er ist der einzige auf seiner Taste,
   und die Drehtasten fahren eine feste Geschwindigkeit — es gibt nichts abzustufen. */
.drive-key .chev-turn {
  --chev-rise: var(--drive-chevron-rise-turn);
  opacity: var(--drive-chevron-dim-normal);
}
/* Vor/zurueck: die Breite folgt aus der Bandhoehe und dem Anstieg der Zone. Weil der Anstieg nach
   aussen faellt, waechst die Breite nach aussen — obwohl das Band kuerzer wird. */
.key-up .drive-chevron,
.key-down .drive-chevron {
  --chev-w: calc((var(--chev-a1) - var(--chev-a0)) * (1 - var(--drive-chevron-air))
    / (var(--chev-rise) + var(--drive-chevron-stroke)));
  --chev-box-w: var(--chev-w);
  --chev-box-h: calc(var(--chev-w) * var(--chev-rise));
  /* Mitte des Bandes. Steht nur hier: die Drehtasten haben kein Band, und eine Rechnung mit
     undefinierten Grenzen waere dort eine Aussage ueber nichts. */
  --chev-a: calc((var(--chev-a0) + var(--chev-a1)) / 2);
  --chev-x: 50%;
}
.key-up .drive-chevron { --chev-y: calc(100% - var(--chev-a)); }
.key-down .drive-chevron { --chev-y: var(--chev-a); }
/* Links/rechts: ein Chevron in 45-Grad-Form, so gross wie die Keiltiefe ihn mit Luft zulaesst.
   Die Spitze zeigt nach aussen, die Arme laufen auf die Keilspitze zu. */
.key-left .drive-chevron,
.key-right .drive-chevron {
  --chev-w: calc(var(--drive-turn-depth) * var(--drive-chevron-turn) * (1 - var(--drive-chevron-air))
    / (var(--chev-rise) + var(--drive-chevron-stroke)));
  --chev-box-w: calc(var(--chev-w) * var(--chev-rise));
  --chev-box-h: var(--chev-w);
  --chev-turn-x: calc(var(--drive-pad-gap) + var(--drive-turn-depth) * var(--drive-chevron-air) / 2
    + var(--chev-w) * var(--chev-rise) / 2);
  --chev-y: 50%;
}
.key-left .drive-chevron { --chev-x: var(--chev-turn-x); }
.key-right .drive-chevron { --chev-x: calc(100% - var(--chev-turn-x)); }

/* **Ohne Zonen zeigt jede Taste genau einen Chevron** — den der normalen Zone, an unveraenderter
   Stelle und in unveraenderter Groesse. Ohne Zonen faehrt `cursorDriveVector()` genau
   `speeds.normal`, der sichtbare Chevron ist also buchstaeblich der, dessen Geschwindigkeit gilt;
   beim Einschalten kommen zwei Geschwister dazu, es wandert nichts. Umgeschaltet wird allein
   ueber die Klasse `zones-on` am Feld, damit der Layout-Test die Frage statisch entscheiden kann.
   Ausgeblendet ist der Grundzustand, eingeblendet die Ausnahme: eine Regel, die einen Chevron
   zusaetzlich zeigt, muss `zones-on` nennen. `data-zone` kommt hier bewusst nicht vor. */
.drive-key .chev-slow,
.drive-key .chev-fast { display: none; }
.drive-pad.zones-on .drive-key .chev-slow,
.drive-pad.zones-on .drive-key .chev-fast { display: block; }

/* Das Erweitern-Werkzeug: im laufenden Vorgang („Fertig“) hervorgehoben, damit erkennbar ist,
   dass die Kontur gerade offen ist. */
.map-tool.extend-tool.extend-active {
  color: var(--shell-warn);
  border-color: var(--shell-warn-border);
  background: var(--shell-warn-bg);
}

/* Der Umschalter zeigt das Symbol des Modus, in den er **wechselt** — wie ein Hell/Dunkel-
   Schalter, der im Hellen den Mond zeigt. Die Klasse benennt weiterhin den aktiven Modus,
   nur das gezeigte Symbol ist das jeweils andere. */
.drive-mode-tool .drive-mode-icon { display: none; }
.drive-mode-tool.mode-joystick .icon-pad,
.drive-mode-tool.mode-buttons .icon-joystick { display: grid; }
.drive-mode-icon svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.drive-meta {
  /* Kind der Seitenspalte: kein eigener Gitterplatz mehr. Umbruch an Leerzeichen ist erlaubt
     („Fahrt“ / „gestoppt“), ein Wort, das auch dann nicht passt, endet sichtbar mit „…“ statt
     still am Rand abgeschnitten zu werden. */
  /* Der Umschalter haengt oben; die Anzeige behaelt trotzdem ihre senkrechte Mitte neben dem
     Joystick, statt gleich darunter zu kleben. */
  margin-block: auto;
  min-width: 0;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  overflow-wrap: normal;
  text-align: right;
  font-size: .68rem;
  font-weight: 700;
  line-height: 1.3;
  color: var(--shell-muted);
}
:root[data-handed="left"] .drive-meta {
  /* Exakt gespiegelt zur Rechtshaender-Variante — nur die Ausrichtung dreht sich. */
  text-align: left;
}

/* --- Menueseite --------------------------------------------------------- */
.menu-page {
  position: fixed;
  inset: 0;
  /* inset: 0 misst den Layout-Viewport — auf Android Chrome ist das die Hoehe OHNE
     Adressleiste. Die Seite waere damit hoeher als der sichtbare Bereich: der untere
     Rand liegt hinter der Browserleiste und .menu-scroll bekommt zu viel Hoehe, wodurch
     knapp zu langer Inhalt abgeschnitten wird und gar nicht erst scrollt.
     100dvh misst den tatsaechlich sichtbaren Viewport, wie schon bei .app-frame. */
  height: 100dvh;
  max-height: 100dvh;
  z-index: 60;
  display: flex;
  flex-direction: column;
  background: var(--bg);
}
.menu-page[hidden] { display: none; }
.menu-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: calc(env(safe-area-inset-top, 0px) + 8px) 10px 8px;
  background: var(--shell-bar);
  border-bottom: 1px solid var(--shell-border-soft);
}
/* Der Titel nimmt nur seine eigene Breite, damit die Demo-Marke direkt daneben steht; die
   Sprachumschaltung bleibt ueber margin-left: auto am rechten Rand. */
.menu-bar strong { flex: 0 1 auto; min-width: 0; font-size: 1rem; letter-spacing: .04em; text-transform: uppercase; }
.menu-bar .language-toggle { margin-left: auto; }
.menu-bar .demo-mark {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  height: 26px;
  padding: 0 8px;
  border: 1px solid var(--shell-warn-border);
  border-radius: 999px;
  background: var(--shell-warn-bg);
  color: var(--shell-warn);
  font-size: .72rem;
  font-weight: 800;
  letter-spacing: .06em;
}
.menu-scroll {
  flex: 1 1 auto;
  /* min-height: 0 ist Pflicht: ohne das waechst das Flex-Kind auf Inhaltshoehe. */
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  padding: 10px 10px calc(env(safe-area-inset-bottom, 0px) + 28px);
  /* Gleiche Spaltenbreite auf Handy und Desktop: ohne Begrenzung ziehen sich die
     Einstellungszeilen im breiten Fenster ueber den halben Bildschirm. */
  width: 100%;
  max-width: 760px;
  margin-inline: auto;
  /* Bewusst Blocklayout: ein Grid- oder Flex-Stapel kann seine Kinder auf die
     Containerhoehe zusammenstauchen, ein aufgeklappter Abschnitt wird dann
     abgeschnitten statt den Container zu verlaengern. */
  display: block;
}
.menu-scroll > * + * { margin-top: 8px; }
.menu-section {
  border: 1px solid var(--shell-border-soft);
  border-radius: 12px;
  background: var(--shell-panel-2);
}
.menu-section > summary {
  list-style: none;
  padding: 14px 14px;
  min-height: 52px;
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: .84rem;
  font-weight: 800;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--shell-text);
  cursor: pointer;
}
.menu-section > summary::-webkit-details-marker { display: none; }
.menu-section > summary::after { content: "▾"; margin-left: auto; opacity: .6; }
.menu-section[open] > summary::after { content: "▴"; }
.menu-body { padding: 0 10px 12px; display: block; }
.menu-body > * + * { margin-top: 8px; }
/* Sicherheitsnetz: aufgeklappter Inhalt bestimmt die Hoehe seines Abschnitts, nie umgekehrt. */
.menu-section[open], .menu-subsection[open] { height: auto; min-height: 0; overflow: visible; }
.menu-section[open] > .menu-body, .menu-subsection[open] > .menu-body { height: auto; overflow: visible; }
.menu-body .card { margin: 0; }
.menu-body .page-heading { display: none; }

@media (max-width: 430px) {
  .appbar { gap: 5px; padding-inline: 6px; }
  .appbar-icon-btn { width: 38px; height: 38px; }
  .mode-chip, .rtk-chip, .battery-chip { height: 38px; font-size: .68rem; }
  .mode-chip { padding-inline: 8px; }
  .capture-fab { width: 92px; height: 92px; }

}

@media (prefers-reduced-motion: reduce) {
  .joystick-knob, .battery-glyph i, .capture-fab { transition: none; }
}

/* Wegpunkte: offene Punktfolge, klar von Perimeter/Ausschluss/Dock unterscheidbar. */
:root { --waypoint: #d7a24a; }
.waypoint-shape {
  fill: none;
  stroke: var(--waypoint);
  stroke-width: 4;
  stroke-dasharray: 5 8;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
  filter: drop-shadow(0 0 4px rgba(215,162,74,.14));
}
.point-waypoint { fill: var(--point-fill); stroke: var(--waypoint); stroke-width: 4; vector-effect: non-scaling-stroke; }
.map-point.selected-map-point { stroke: var(--selection); stroke-width: 4; }
/* Erster der beiden Punkte, an denen die Kontur aufgetrennt werden soll. Bewusst eine andere
   Farbe als die Auswahl: es ist keine Auswahl zum Verschieben, sondern eine Kantenwahl. */
.map-point.extend-pick-point { stroke: var(--shell-warn, #e7ad46); stroke-width: 4; }
.extend-pick-ring { fill: none; stroke: var(--shell-warn, #e7ad46); stroke-width: 2; stroke-dasharray: 4 3; }
/* Die beiden gewaehlten Punkte bedeuten Verschiedenes und sehen seit v70 verschieden aus.
   Der **erste** ist zugleich das aktive Ende, an dem weitergebaut wird: eigene Farbe
   (var(--shell-info), die Bearbeitungsfarbe der Karte — die Warnfarbe bleibt dem nur
   vorgemerkten zweiten Punkt) und ein Blinken, das kein anderer Punkt der Karte traegt.
   Welcher Punkt das ist, entscheidet allein extensionEndIndex() in app.js; hier steht nur,
   wie er aussieht. Ausdruecklich keine feste Farbe: beide Fassungen kommen aus den Tokens
   und folgen damit Hell/Dunkel. */
.map-point.extend-pick-active { stroke: var(--shell-info); }
.extend-pick-ring.extend-pick-ring-active { stroke: var(--shell-info); }
.map-point.extend-pick-active, .extend-pick-ring.extend-pick-ring-active {
  animation: extend-pick-blink 1.1s ease-in-out infinite;
}
/* Nur die Deckkraft pulsiert — die Farbe bleibt in jedem Takt dieselbe, damit der Punkt auch
   im dunkelsten Moment noch als der markierte lesbar ist. */
@keyframes extend-pick-blink { 0%, 100% { opacity: 1; } 50% { opacity: .28; } }
/* Wer Bewegung abbestellt hat, bekommt kein Blinken — die Farbe unterscheidet die beiden Punkte
   weiterhin, sie ist die eigentliche Aussage. */
@media (prefers-reduced-motion: reduce) {
  .map-point.extend-pick-active, .extend-pick-ring.extend-pick-ring-active { animation: none; opacity: 1; }
}
/* Vorschau vom aktiven Ende zur Maeherposition: bewusst die Warnfarbe der Markierung, damit
   Linie und markiertes Ende als eine Einheit lesbar sind — die beiden anderen Hilfslinien
   (.edit-distance-line, .boundary-distance-line) liegen farblich ohnehin schon dicht beieinander. */
.extend-guide-line { stroke: var(--shell-warn, #e7ad46); stroke-width: 2; stroke-dasharray: 7 6; vector-effect: non-scaling-stroke; pointer-events: none; opacity: .72; }


/* ==========================================================================
   v18 · Farbtokens, Hell/Dunkel und die Bedienelemente auf der Karte
   Dunkel ist die Vorgabe; die Hell-Palette steht zweimal (Attribut und
   prefers-color-scheme) und muss inhaltlich gleich bleiben.
   ========================================================================== */

:root {
  --shell-bg: #081013;
  --shell-bar: #08151a;
  --shell-panel: #0d1c21;
  --shell-panel-2: #0b171b;
  --shell-border: #2c4b54;
  --shell-border-soft: #22424b;
  --shell-hover: #14313a;
  --shell-text: #d7ecf1;
  --shell-muted: #90a8ae;
  --shell-ok: #6ce0a0; --shell-ok-bg: #0d241a; --shell-ok-border: #2c6a48;
  --shell-warn: #e8c37a; --shell-warn-bg: #241d0d; --shell-warn-border: #6a5726;
  --shell-danger: #ef8f8f; --shell-danger-bg: #240f0f; --shell-danger-border: #5d3130;
  --shell-danger-solid: #c03a32;
  --shell-info: #a9d0f5; --shell-info-bg: #0d1f2f; --shell-info-border: #3a6fa8;
  --shell-hud: rgba(8, 21, 26, .62);
  /* Gemeinsamer Abstand aller randstaendigen Bedienelemente zum Bildschirmrand:
     Aufnahme-Cluster, Rueckgaengig-Knopf, Ansicht-Symbol, Karteninfo und der
     Joystick-Umschalter in der Fahrzone. Ein Wert, damit sie auf einer Linie stehen. */
  --edge-gap: 12px;
  /* Groesse der kleinen runden Randknoepfe (Rueckgaengig auf der Karte, Automatik im
     Aufnahme-Cluster). Sie bestimmt zugleich die **Mittelachse** der Randspalte:
     var(--edge-gap) + var(--fab-size) / 2 vom Bildschirmrand. Der schmalere
     Joystick-Umschalter rueckt genau auf diese Achse ein, statt nur buendig links zu stehen —
     bei gleichem Randabstand, aber verschiedener Breite lagen die beiden sonst sichtbar
     versetzt uebereinander. */
  --fab-size: 48px;
  /* Breite des grossen Aufnahme-Knopfes — die Positionszeile rechnet damit ihren Freiraum. */
  --capture-size: 104px;
  --point-fill: #071012;
  --selection: #7fe4ff;
}

:root[data-theme="light"] {
  --shell-bg: #e8efea;
  --shell-bar: #f5f9f6;
  --shell-panel: #ffffff;
  --shell-panel-2: #f6faf7;
  --shell-border: #ccd8d0;
  --shell-border-soft: #dde6e0;
  --shell-hover: #e6efe9;
  --shell-text: #16241c;
  --shell-muted: #5b6d64;
  --shell-ok: #12703d; --shell-ok-bg: #ddf2e5; --shell-ok-border: #79bd97;
  --shell-warn: #855510; --shell-warn-bg: #fbefd7; --shell-warn-border: #d6ac63;
  --shell-danger: #a52f2f; --shell-danger-bg: #fbe2e2; --shell-danger-border: #d78e8e;
  --shell-danger-solid: #b3352f;
  --shell-info: #21578e; --shell-info-bg: #e2ecf8; --shell-info-border: #8bb1da;
  --shell-hud: rgba(255, 255, 255, .74);
  --point-fill: #ffffff;
  --selection: #0e6f8f;
  --waypoint: #a26c1f;}

@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) {
    --shell-bg: #e8efea;
    --shell-bar: #f5f9f6;
    --shell-panel: #ffffff;
    --shell-panel-2: #f6faf7;
    --shell-border: #ccd8d0;
    --shell-border-soft: #dde6e0;
    --shell-hover: #e6efe9;
    --shell-text: #16241c;
    --shell-muted: #5b6d64;
    --shell-ok: #12703d; --shell-ok-bg: #ddf2e5; --shell-ok-border: #79bd97;
    --shell-warn: #855510; --shell-warn-bg: #fbefd7; --shell-warn-border: #d6ac63;
    --shell-danger: #a52f2f; --shell-danger-bg: #fbe2e2; --shell-danger-border: #d78e8e;
    --shell-danger-solid: #b3352f;
    --shell-info: #21578e; --shell-info-bg: #e2ecf8; --shell-info-border: #8bb1da;
    --shell-hud: rgba(255, 255, 255, .74);
    --point-fill: #ffffff;
    --selection: #0e6f8f;
    --waypoint: #a26c1f;}
}

/* --- Beschriftete Kartenknoepfe ------------------------------------------ */
/* Die Beschriftung steht *neben* dem Knopf, nicht darueber. Oberhalb lag sie auf schmalen
   Telefonen im Weg: mehrzeilige Labels wuchsen nach oben und deckten das Symbol des daruber
   liegenden Knopfes ab. Sie ist deshalb absolut positioniert und traegt nichts zur Hoehe der
   Knopfspalte bei — die gemeinsame senkrechte Mittelachse der Knoepfe bleibt dadurch erhalten. */
.fab-with-label { position: relative; display: grid; justify-items: center; gap: 0; }
.fab-with-label[hidden] { display: none; }
.fab-label {
  position: absolute;
  top: 50%;
  /* Standardseite ist links: beide Knopfspalten kleben am rechten Bildschirmrand,
     rechts daneben ist schlicht kein Platz. */
  right: 100%;
  margin-right: 6px;
  transform: translateY(-50%);
  /* Bewusst eng gehalten, damit die Beschriftung auf einem 360-px-Telefon nicht bis in die
     Hinweiszeile oben links reicht. Laengere Texte brechen um statt abgeschnitten zu werden. */
  max-width: min(112px, 32vw);
  padding: 1px 6px;
  border-radius: 7px;
  background: var(--shell-hud);
  color: var(--shell-muted);
  font-size: .58rem;
  font-weight: 800;
  line-height: 1.3;
  text-align: right;
  white-space: normal;
  /* Niemals `anywhere`: das war die Ursache der Buchstabenkolonnen auf schmalen Geraeten.
     Umbrochen wird hoechstens zwischen Woertern. */
  overflow-wrap: normal;
  word-break: normal;
  hyphens: none;
}
/* --- Haendigkeit ---------------------------------------------------------
   Alles haengt an einem einzigen Attribut am <html> (applyHandedness()). Vorher sass die
   Umschaltung an der Fahrzone und betraf nur deren Anzeige; jede weitere Stelle haette ihre
   eigene Bedingung gebraucht. Rechtshaender ist der unveraenderte Standard, deshalb steht er
   in den Grundregeln und nur die Linkshaender-Seite wird ueberschrieben. */
:root[data-handed="left"] .map-toolbar { flex-direction: row-reverse; }
:root[data-handed="left"] .map-view-reset { right: auto; left: var(--edge-gap); }
:root[data-handed="left"] .map-corner-undo { left: auto; right: var(--edge-gap); }
:root[data-handed="left"] .capture-cluster { left: var(--edge-gap); right: auto; }
/* Wandert der Aufnahme-Knopf an den linken Rand, ist links kein Platz mehr fuer seine
   Beschriftung — sie klappt auf die andere Seite. */
:root[data-handed="left"] .capture-cluster .fab-label {
  right: auto;
  left: 100%;
  margin-right: 0;
  margin-left: 6px;
  text-align: left;
}
.capture-cluster { z-index: 2; }

/* --- Hinweisbereich fuer die Kontur-Erweiterung ---------------------------
   Eigene Zeile zwischen Werkzeugleiste und Zeichenflaeche, bewusst **kein** Overlay: die
   Anweisung hat die volle Breite (in der schmalen Werkzeugleiste wurde sie abgeschnitten) und
   verdeckt die Karte nicht — waehrend der Auswahl muss weiter auf Punkte getippt werden. */
.map-hint {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 7px 10px;
  border-bottom: 1px solid var(--shell-border);
  background: var(--shell-info-bg);
  color: var(--shell-text);
}
.map-hint.is-error { background: var(--shell-warn-bg); }
.map-hint-text {
  min-width: 0;
  margin: 0;
  font-size: .68rem;
  line-height: 1.35;
  color: var(--shell-text);
}
.map-hint-actions { flex: 0 0 auto; display: flex; gap: 6px; }
.map-hint-actions button { min-height: 34px; padding: 4px 12px; font-size: .7rem; }

/* --- Werkzeugleiste oben auf der Karte ------------------------------------
   Loesen loest das eigentliche Problem der frueheren Eckbeschriftungen: dort stand nur die
   Knopfbreite zur Verfuegung, und `overflow-wrap: anywhere` brach den Text notfalls Buchstabe
   fuer Buchstabe untereinander. Hier hat jede Beschriftung die volle Zeilenbreite, laeuft
   ausdruecklich `nowrap`, und passt die Leiste einmal nicht, scrollt sie waagerecht. */
.map-toolbar {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  /* Seit Karteninfo, Rueckgaengig und Ansicht-Symbol wieder auf der Karte liegen, steht hier
     nur noch die Werkzeuggruppe. Sie sammelt sich an der Daumenseite, statt eine leere Haelfte
     stehen zu lassen (`space-between` haette genau das getan). Bei Linkshaendern kehrt
     `row-reverse` weiter unten die Seite um. */
  /* Kartenname links, Werkzeuge rechts (bei Linkshaendern dreht `row-reverse` beides um). */
  justify-content: space-between;
  gap: 10px;
  padding: 3px 6px;
  border-bottom: 1px solid var(--shell-border);
  background: var(--shell-panel);
}
/* --- Karteninfo als zweite Zeile der Werkzeugleiste ----------------------
   Auf kleinen Displays (Xperia XZ1) kostete der Overlay-Streifen oben auf der Karte zu viel
   Flaeche. Punktzahl und Konturzustand stehen jetzt als **zweite Zeile unter dem Kartennamen**
   in der Leiste, die Karte bleibt dort frei. Der Block ist eine Spalte; die Leiste selbst
   bleibt eine Zeile, `row-reverse` bei Linkshaendern dreht ihn samt Werkzeugen auf die andere
   Seite, `align-items` spiegelt zusaetzlich die Ausrichtung im Block. */
.toolbar-info {
  /* Gibt vor den Werkzeugen nach — der Name darf sie nie verdraengen. */
  flex: 0 10 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1px;
  overflow: hidden;
}
:root[data-handed="left"] .toolbar-info { align-items: flex-end; }
.toolbar-map-meta {
  max-width: 100%;
  display: flex;
  align-items: baseline;
  gap: 5px;
  min-width: 0;
  font-size: .55rem;
  line-height: 1.35;
  color: var(--shell-muted);
  white-space: nowrap;
}
.toolbar-map-meta:empty { display: none; }

/* --- Positionsanzeige unten zwischen den beiden Eckknoepfen ---------------
   Sie spannt sich als **Band** genau ueber die Luecke zwischen Rueckgaengig- und
   Aufnahme-Knopf: links wie rechts Randabstand + Knopfbreite + ein kleiner Abstand. Weil beide
   Kanten gesetzt sind, kann sie die Knoepfe auch auf sehr schmalen Displays nicht ueberlappen —
   sie kuerzt vorher per Ellipse. Die beiden Knoepfe sind verschieden breit (48 gegen 104 px),
   deshalb sind die Abzuege seitenverschieden und drehen sich mit der Haendigkeit mit.
   Das Band selbst ist unsichtbar; die halbtransparente Pille traegt der Text darin, damit sie
   sich auf die tatsaechliche Textbreite zusammenzieht und mittig in der Luecke steht. */
.map-position {
  position: absolute;
  z-index: 2;
  bottom: var(--edge-gap);
  left: calc(var(--edge-gap) + var(--fab-size) + 8px);
  right: calc(var(--edge-gap) + var(--capture-size) + 8px);
  display: flex;
  justify-content: center;
  min-width: 0;
  pointer-events: none;
}
:root[data-handed="left"] .map-position {
  left: calc(var(--edge-gap) + var(--capture-size) + 8px);
  right: calc(var(--edge-gap) + var(--fab-size) + 8px);
}
.map-position .info-line {
  padding: 3px 8px;
  border-radius: 8px;
  background: var(--shell-hud);
  color: var(--shell-muted);
  font-size: .6rem;
  line-height: 1.4;
}
.info-line { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Konturfeld: **Name der betroffenen Kontur samt Zustand** („Perimeter · geschlossen“), nie
   der Zustand allein — als freistehendes Wort war nicht erkennbar, welche Kontur gemeint ist.
   Die Pillenform fasst beides sichtbar zu einer Einheit zusammen. Nur im Perimeter- und
   Ausschluss-Modus gefuellt, bei Wegpunkten und Dockpfad leer und damit unsichtbar. Weil hier
   jetzt ein Name steht, muss das Feld schrumpfen koennen und kuerzt per Ellipse. */
.info-chip {
  flex: 0 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--shell-panel-2);
  color: var(--shell-muted);
  font-size: .55rem;
  font-weight: 800;
}
.info-chip:empty { display: none; }
.info-line:empty { display: none; }
.info-dim { color: var(--shell-muted); }
.info-dim:empty { display: none; }
/* `flex: 0 1 auto` + `min-width: 0`: die Werkzeuggruppe **muss** schrumpfen duerfen. Mit
   `flex: 0 0 auto` nahm sie immer ihre volle Inhaltsbreite ein, wuchs ueber die Leiste hinaus
   und wurde von `.map-stage { overflow: hidden }` rechts abgeschnitten — das `overflow-x: auto`
   darunter war wirkungslos, weil der Kasten nie schmaler als sein Inhalt wurde. Zuerst gibt
   die Karteninfo nach (`flex: 1 1 auto`), erst danach scrollt diese Gruppe. */
.map-tools {
  flex: 0 1 auto;
  min-width: 0;
  display: flex;
  align-items: stretch;
  gap: 6px;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: none;
}
.map-tools::-webkit-scrollbar { display: none; }
/* Nur der **Kartenname** steht in der Leiste; Punktzahl, Konturzustand und Positionsmeldung
   bleiben auf der Karte. Schrumpfgewicht 10 gegen 1 bei den Werkzeugen: wird es eng, gibt
   zuerst der Name nach (er kuerzt per Ellipse), erst danach scrollt die Werkzeuggruppe. */
.toolbar-map-name {
  flex: 0 10 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: .68rem;
  font-weight: 800;
  color: var(--shell-text);
}
.map-tool-slot { display: flex; flex: 0 0 auto; }
.map-tool {
  flex: 0 0 auto;
  display: grid;
  justify-items: center;
  align-content: center;
  gap: 2px;
  min-width: 62px;
  min-height: 44px;           /* Daumenziel, auch wenn das Symbol klein ist */
  padding: 3px 8px;
  border: 1px solid var(--shell-border);
  border-radius: 10px;
  background: var(--shell-panel);
  color: var(--shell-text);
  font-family: inherit;
  font-size: .55rem;
  font-weight: 700;
  line-height: 1.15;
}
.map-tool svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
/* Einzelne lange Beschriftung darf die Leiste nicht sprengen: eine Zeile bleibt eine Zeile
   (kein Rueckfall auf Buchstabenkolonnen), zu lang wird gekuerzt statt breiter zu werden. */
.map-tool { max-width: 96px; }
.map-tool-label {
  max-width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Schmale Telefone: die Leiste passt sich der Bildschirmbreite an, statt zu ueberlaufen. */
@media (max-width: 430px) {
  .map-toolbar { gap: 6px; padding: 4px 6px; }
  .map-tools { gap: 4px; }
  .map-tool { min-width: 52px; max-width: 78px; padding: 3px 5px; font-size: .52rem; }
  .map-tool svg { width: 16px; height: 16px; }
}
.map-tool:active { background: var(--shell-hover); }
.map-tool[disabled] { color: var(--shell-muted); border-color: var(--shell-border); background: var(--shell-panel); opacity: .55; }

/* --- „Ansicht zuruecksetzen“: reines Symbol auf der Karte -----------------
   Bewusst ohne Knopfflaeche und Rahmen, wie in Kartenprogrammen ueblich. Der Schlagschatten
   haelt es ueber hellem wie dunklem Kartengrund lesbar; die Trefferflaeche bleibt trotzdem
   44 x 44 px. Sichtbar nur nach eigener Zoom-/Verschiebe-Geste (app.js). */
.map-view-reset {
  position: absolute;
  z-index: 2;
  top: 6px;
  right: var(--edge-gap);
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--shell-text);
  filter: drop-shadow(0 1px 3px rgba(0, 0, 0, .5));
}
.map-view-reset svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.map-view-reset:active { color: var(--shell-info); }

/* --- GPS-Einblendung oben auf der Karte -----------------------------------
   Sie sitzt auf der **Gegenseite** des Ansicht-Symbols: bei Rechtshaendern links, bei
   Linkshaendern rechts. Gleiche Seite hiesse Ueberdeckung, denn beide stehen oben.
   `pointer-events: none` — sie ist Anzeige, kein Ziel, und darf die Karte nicht abfangen. */
.map-gps-panel {
  position: absolute;
  z-index: 2;
  top: 6px;
  left: var(--edge-gap);
  display: flex;
  flex-direction: column;
  gap: 1px;
  max-width: calc(100% - 2 * var(--edge-gap) - 44px);
  padding: 5px 8px;
  border-radius: 10px;
  background: var(--shell-hud);
  color: var(--shell-text);
  font-size: .58rem;
  font-weight: 700;
  line-height: 1.35;
  pointer-events: none;
}
:root[data-handed="left"] .map-gps-panel { left: auto; right: var(--edge-gap); }
.gps-panel-line { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.gps-panel-line:empty { display: none; }

/* --- Rueckgaengig unten an der Kartenecke ---------------------------------
   Spiegelbildlich zum Aufnahme-Cluster: Rechtshaender unten links, Linkshaender unten rechts,
   derselbe Randabstand (--edge-gap) wie Aufnahme-Cluster und Joystick-Umschalter. Groesse wie
   der Automatik-Knopf im **inaktiven** Zustand, nicht wie der grosse Aufnahme-Knopf. */
.map-corner-undo {
  position: absolute;
  z-index: 2;
  left: var(--edge-gap);
  bottom: var(--edge-gap);
}
.undo-fab {
  display: grid;
  place-items: center;
  width: var(--fab-size);
  height: var(--fab-size);
  padding: 0;
  border: 2px solid var(--shell-info-border);
  border-radius: 50%;
  background: var(--shell-info-bg);
  color: var(--shell-info);
  box-shadow: 0 6px 18px rgba(0, 0, 0, .32);
}
.undo-fab svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 2.1; stroke-linecap: round; stroke-linejoin: round; }
.undo-fab:active { background: var(--shell-hover); }
.undo-fab[disabled] { color: var(--shell-muted); border-color: var(--shell-border); background: var(--shell-panel); opacity: .55; }
.map-tool.delete-point { color: var(--shell-info); border-color: var(--shell-info-border); background: var(--shell-info-bg); }
.map-tool.delete-area { color: var(--shell-danger); border-color: var(--shell-danger-border); background: var(--shell-danger-bg); }

/* --- Aufnahme-Cluster: Automatik ersetzt den manuellen Knopf -------------- */
.capture-cluster {
  position: absolute;
  right: var(--edge-gap); bottom: var(--edge-gap);
  width: 96px;
  display: grid;
  justify-items: center;
  gap: 8px;
}
.capture-cluster .capture-fab { position: static; }
.auto-fab {
  display: grid;
  place-items: center;
  width: var(--fab-size); height: var(--fab-size);
  padding: 0;
  border: 2px solid var(--shell-border);
  border-radius: 50%;
  background: var(--shell-panel);
  color: var(--shell-text);
  box-shadow: 0 6px 18px rgba(0,0,0,.32);
}
.auto-fab svg { width: 22px; height: 22px; fill: currentColor; stroke: currentColor; stroke-width: 1.6; stroke-linecap: round; stroke-linejoin: round; }
.auto-fab .icon-pause { display: none; }
.auto-fab[disabled] { opacity: .4; }
/* Der Verschieben-Knopf teilt sich Groesse, Form und Platz mit dem Automatik-Knopf — beide sind
   nie gleichzeitig sichtbar, sie haengen an derselben Bedingung (`selected`). Nur die Fuellung
   muss zurueckgenommen werden: das Pfeilkreuz besteht aus offenen Teilpfaden, `fill: currentColor`
   aus `.auto-fab svg` wuerde sie zuschmieren. */
.move-fab svg { fill: none; stroke-width: 2; }
.capture-cluster.auto-active .auto-fab {
  width: 104px; height: 104px;
  border-color: var(--shell-danger-solid);
  background: var(--shell-danger-solid);
  color: #fff;
}
.capture-cluster.auto-active .auto-fab svg { width: 34px; height: 34px; }
.capture-cluster.auto-active .auto-fab .icon-play { display: none; }
.capture-cluster.auto-active .auto-fab .icon-pause { display: grid; }
.capture-cluster.auto-active .fab-label { color: var(--shell-danger); }

/* --- Dialog -------------------------------------------------------------- */
.modal-backdrop {
  position: fixed;
  inset: 0;
  height: 100dvh;
  z-index: 70;
  display: grid;
  place-items: center;
  padding: 16px;
  background: rgba(0, 0, 0, .55);
}
.modal-backdrop[hidden] { display: none; }
.modal {
  width: min(380px, 100%);
  display: grid;
  gap: 10px;
  padding: 16px;
  border: 1px solid var(--shell-border);
  border-radius: 16px;
  background: var(--shell-panel);
  color: var(--shell-text);
  box-shadow: 0 24px 60px rgba(0,0,0,.45);
}
.modal h2 { margin: 0; font-size: .95rem; letter-spacing: .02em; }
.mode-options { display: grid; gap: 8px; }
.mode-option {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 58px;
  padding: 0 14px;
  border: 1px solid var(--shell-border);
  border-radius: 12px;
  background: var(--shell-panel-2);
  color: var(--shell-text);
  font-size: .86rem;
  font-weight: 700;
  text-align: left;
}
.mode-option .mode-dot { width: 13px; height: 13px; border-radius: 50%; flex: 0 0 auto; background: var(--perimeter); }
.mode-option[data-mode="exclusion"] .mode-dot { background: var(--exclusion); }
.mode-option[data-mode="waypoint"] .mode-dot { background: var(--waypoint); }
.mode-option[data-mode="dock"] .mode-dot { background: var(--dock); }
.mode-option.active { border-color: var(--shell-ok-border); background: var(--shell-ok-bg); color: var(--shell-ok); }

/* --- Menue: Unterabschnitte und Themenwahl ------------------------------- */
.menu-subsections { display: block; }
.menu-subsections > * + * { margin-top: 8px; }
.menu-subsection {
  border: 1px solid var(--shell-border-soft);
  border-radius: 10px;
  background: var(--shell-panel-2);
}
.menu-subsection > summary {
  list-style: none;
  display: flex;
  align-items: center;
  min-height: 46px;
  padding: 10px 12px;
  color: var(--shell-text);
  font-size: .76rem;
  font-weight: 800;
  letter-spacing: .03em;
  cursor: pointer;
}
.menu-subsection > summary::-webkit-details-marker { display: none; }
.menu-subsection > summary::after { content: "▾"; margin-left: auto; opacity: .6; }
.menu-subsection[open] > summary::after { content: "▴"; }
.menu-subsection > .menu-body { padding: 0 8px 10px; }

.theme-setting { display: grid; gap: 7px; }
.theme-segment { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; }
.theme-btn {
  min-height: 44px;
  padding: 6px 8px;
  border: 1px solid var(--shell-border);
  border-radius: 8px;
  background: var(--shell-panel-2);
  color: var(--shell-muted);
  font-size: .72rem;
  font-weight: 800;
}
.theme-btn.active { border-color: var(--shell-ok-border); background: var(--shell-ok-bg); color: var(--shell-ok); }

/* --- Ausgewaehlte Ausschlussflaeche -------------------------------------- */
.exclusion-shape.selected-area {
  stroke: var(--selection);
  stroke-width: 6;
  fill: color-mix(in srgb, var(--selection), transparent 82%);
}

/* --- Hell-Modus: die alten, fest verdrahteten Dunkelwerte ueberschreiben --- */
:root[data-theme="light"] body,
:root:not([data-theme="dark"]) body {
  background: var(--shell-bg);
  color: var(--shell-text);
}

:root[data-theme="light"] .card, :root[data-theme="light"] .mapping-stage { background: var(--shell-panel); border-color: var(--shell-border); box-shadow: 0 8px 24px rgba(20,45,32,.07); }
:root[data-theme="light"] p, :root[data-theme="light"] .view-note, :root[data-theme="light"] .recent-points, :root[data-theme="light"] .history-list, :root[data-theme="light"] .help-list li, :root[data-theme="light"] .auto-capture-state { color: var(--shell-muted); }
:root[data-theme="light"] h2, :root[data-theme="light"] h3, :root[data-theme="light"] h4, :root[data-theme="light"] strong, :root[data-theme="light"] summary { color: var(--shell-text); }
:root[data-theme="light"] input, :root[data-theme="light"] select, :root[data-theme="light"] textarea { background: #fff; border-color: var(--shell-border); color: var(--shell-text); box-shadow: none; }
:root[data-theme="light"] button, :root[data-theme="light"] .file-button { background: var(--shell-panel-2); border-color: var(--shell-border); color: var(--shell-text); }
:root[data-theme="light"] button:hover:not(:disabled), :root[data-theme="light"] .file-button:hover { border-color: var(--shell-muted); }
:root[data-theme="light"] .primary { background: #12703d; border-color: #0d5b31; color: #fff; }
:root[data-theme="light"] .secondary { background: var(--shell-ok-bg); border-color: var(--shell-ok-border); color: var(--shell-ok); }
:root[data-theme="light"] .ghost { background: transparent; border-color: var(--shell-border); color: var(--shell-muted); }
:root[data-theme="light"] .danger { background: var(--shell-danger-bg); border-color: var(--shell-danger-border); color: var(--shell-danger); }
:root[data-theme="light"] .pill { background: var(--shell-panel-2); border-color: var(--shell-border); color: var(--shell-muted); }
:root[data-theme="light"] .pill.online { background: var(--shell-ok-bg); border-color: var(--shell-ok-border); color: var(--shell-ok); }
:root[data-theme="light"] .notice.warning { background: var(--shell-warn-bg); border-color: var(--shell-warn-border); color: var(--shell-warn); }
:root[data-theme="light"] .field > span, :root[data-theme="light"] .field-label, :root[data-theme="light"] .overline, :root[data-theme="light"] .unit-input > span, :root[data-theme="light"] .eyebrow { color: var(--shell-muted); }
:root[data-theme="light"] .validation-item { color: var(--shell-muted); border-color: var(--shell-border); }
:root[data-theme="light"] .validation-item.error { border-color: var(--shell-danger); color: var(--shell-danger); }
:root[data-theme="light"] .validation-item.warning { border-color: var(--shell-warn); color: var(--shell-warn); }
:root[data-theme="light"] .validation-item.info { border-color: var(--shell-info); color: var(--shell-info); }
:root[data-theme="light"] .history-entry { background: var(--shell-panel-2); border-color: var(--shell-border); }
:root[data-theme="light"] .history-entry strong { color: var(--shell-text); }
:root[data-theme="light"] .history-entry small { color: var(--shell-muted); }
:root[data-theme="light"] #debugLog { background: var(--shell-panel-2); border-color: var(--shell-border); color: var(--shell-text); }
:root[data-theme="light"] .map-gallery-card { background: var(--shell-panel-2); border-color: var(--shell-border); }
:root[data-theme="light"] .map-gallery-card.active { border-color: var(--shell-ok-border); box-shadow: inset 0 0 0 1px var(--shell-ok-border); }
:root[data-theme="light"] .help-card, :root[data-theme="light"] .help-system-card, :root[data-theme="light"] .recent-tool-drawer, :root[data-theme="light"] .recent-point { border-color: var(--shell-border); }

/* Joystick */
:root[data-theme="light"] .joystick-base {
  background:
    radial-gradient(circle at center, rgba(18,112,61,.10) 0 23%, transparent 24%),
    radial-gradient(circle at center, transparent 0 47%, rgba(18,112,61,.16) 48% 49%, transparent 50%),
    radial-gradient(circle at 42% 37%, #ffffff 0, #eef4f0 58%, #e2ebe5 100%);
  border-color: var(--shell-border);
  box-shadow: inset 0 0 40px rgba(18,112,61,.05), 0 8px 24px rgba(20,45,32,.12);
}
:root[data-theme="light"] .joystick-ring { border-color: rgba(18,112,61,.20); }
:root[data-theme="light"] .joystick-axis { background: rgba(18,112,61,.16); }
:root[data-theme="light"] .joystick-knob {
  background: radial-gradient(circle at 36% 30%, #3fae74, #15784a 45%, #0d5b31 72%);
  border-color: #0d5b31;
  box-shadow: 0 8px 22px rgba(20,45,32,.28), inset 0 1px 1px rgba(255,255,255,.35);
}
:root[data-theme="light"] .joystick-dot { background: #eafaf0; box-shadow: none; }

/* Kartenzeichnung */
:root[data-theme="light"] .canvas-bg { fill: #f2f6f3; }
:root[data-theme="light"] .grid-line { stroke: #cbd8d0; opacity: .95; }
:root[data-theme="light"] .grid-major { stroke: #aec0b5; opacity: .95; }
:root[data-theme="light"] .grid-axis { stroke: #8ba396; opacity: 1; }
:root[data-theme="light"] .perimeter-shape { stroke: #167444; fill: rgba(22,116,68,.07); filter: none; }
:root[data-theme="light"] .exclusion-shape { stroke: #b13636; fill: rgba(177,54,54,.09); filter: none; }
:root[data-theme="light"] .dock-shape { stroke: #2f5f9e; filter: none; }
:root[data-theme="light"] .waypoint-shape { filter: none; }
:root[data-theme="light"] .movement-trail-shape { stroke: #7a8f84; }
:root[data-theme="light"] .robot-body { fill: rgba(255,255,255,.94); stroke: #16241c; filter: none; }
:root[data-theme="light"] .robot-front { fill: #12703d; stroke: #0d5b31; }
:root[data-theme="light"] .robot-axle { stroke: #6d7f75; }
:root[data-theme="light"] .robot-center { fill: #16241c; stroke: #ffffff; }
:root[data-theme="light"] .robot-position-marker { stroke: #12703d; }
:root[data-theme="light"] .robot-dot { fill: #16241c; stroke: #ffffff; filter: none; }
:root[data-theme="light"] .robot-ring { stroke: #12703d; }
:root[data-theme="light"] .edit-selected-ring { stroke: var(--selection); }
:root[data-theme="light"] .edit-distance-line { stroke: var(--selection); }
:root[data-theme="light"] .boundary-distance-line { stroke: #2f5f9e; }

@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) .card, :root:not([data-theme="dark"]) .mapping-stage { background: var(--shell-panel); border-color: var(--shell-border); box-shadow: 0 8px 24px rgba(20,45,32,.07); }
  :root:not([data-theme="dark"]) p, :root:not([data-theme="dark"]) .view-note, :root:not([data-theme="dark"]) .recent-points, :root:not([data-theme="dark"]) .history-list, :root:not([data-theme="dark"]) .help-list li, :root:not([data-theme="dark"]) .auto-capture-state { color: var(--shell-muted); }
  :root:not([data-theme="dark"]) h2, :root:not([data-theme="dark"]) h3, :root:not([data-theme="dark"]) h4, :root:not([data-theme="dark"]) strong, :root:not([data-theme="dark"]) summary { color: var(--shell-text); }
  :root:not([data-theme="dark"]) input, :root:not([data-theme="dark"]) select, :root:not([data-theme="dark"]) textarea { background: #fff; border-color: var(--shell-border); color: var(--shell-text); box-shadow: none; }
  :root:not([data-theme="dark"]) button, :root:not([data-theme="dark"]) .file-button { background: var(--shell-panel-2); border-color: var(--shell-border); color: var(--shell-text); }
  :root:not([data-theme="dark"]) button:hover:not(:disabled), :root:not([data-theme="dark"]) .file-button:hover { border-color: var(--shell-muted); }
  :root:not([data-theme="dark"]) .primary { background: #12703d; border-color: #0d5b31; color: #fff; }
  :root:not([data-theme="dark"]) .secondary { background: var(--shell-ok-bg); border-color: var(--shell-ok-border); color: var(--shell-ok); }
  :root:not([data-theme="dark"]) .ghost { background: transparent; border-color: var(--shell-border); color: var(--shell-muted); }
  :root:not([data-theme="dark"]) .danger { background: var(--shell-danger-bg); border-color: var(--shell-danger-border); color: var(--shell-danger); }
  :root:not([data-theme="dark"]) .pill { background: var(--shell-panel-2); border-color: var(--shell-border); color: var(--shell-muted); }
  :root:not([data-theme="dark"]) .pill.online { background: var(--shell-ok-bg); border-color: var(--shell-ok-border); color: var(--shell-ok); }
  :root:not([data-theme="dark"]) .notice.warning { background: var(--shell-warn-bg); border-color: var(--shell-warn-border); color: var(--shell-warn); }
  :root:not([data-theme="dark"]) .field > span, :root:not([data-theme="dark"]) .field-label, :root:not([data-theme="dark"]) .overline, :root:not([data-theme="dark"]) .unit-input > span, :root:not([data-theme="dark"]) .eyebrow { color: var(--shell-muted); }
  :root:not([data-theme="dark"]) .validation-item { color: var(--shell-muted); border-color: var(--shell-border); }
  :root:not([data-theme="dark"]) .validation-item.error { border-color: var(--shell-danger); color: var(--shell-danger); }
  :root:not([data-theme="dark"]) .validation-item.warning { border-color: var(--shell-warn); color: var(--shell-warn); }
  :root:not([data-theme="dark"]) .validation-item.info { border-color: var(--shell-info); color: var(--shell-info); }
  :root:not([data-theme="dark"]) .history-entry { background: var(--shell-panel-2); border-color: var(--shell-border); }
  :root:not([data-theme="dark"]) .history-entry strong { color: var(--shell-text); }
  :root:not([data-theme="dark"]) .history-entry small { color: var(--shell-muted); }
  :root:not([data-theme="dark"]) #debugLog { background: var(--shell-panel-2); border-color: var(--shell-border); color: var(--shell-text); }
  :root:not([data-theme="dark"]) .map-gallery-card { background: var(--shell-panel-2); border-color: var(--shell-border); }
  :root:not([data-theme="dark"]) .map-gallery-card.active { border-color: var(--shell-ok-border); box-shadow: inset 0 0 0 1px var(--shell-ok-border); }
  :root:not([data-theme="dark"]) .help-card, :root:not([data-theme="dark"]) .help-system-card, :root:not([data-theme="dark"]) .recent-tool-drawer, :root:not([data-theme="dark"]) .recent-point { border-color: var(--shell-border); }

  /* Joystick */
  :root:not([data-theme="dark"]) .joystick-base {
    background:
      radial-gradient(circle at center, rgba(18,112,61,.10) 0 23%, transparent 24%),
      radial-gradient(circle at center, transparent 0 47%, rgba(18,112,61,.16) 48% 49%, transparent 50%),
      radial-gradient(circle at 42% 37%, #ffffff 0, #eef4f0 58%, #e2ebe5 100%);
    border-color: var(--shell-border);
    box-shadow: inset 0 0 40px rgba(18,112,61,.05), 0 8px 24px rgba(20,45,32,.12);
  }
  :root:not([data-theme="dark"]) .joystick-ring { border-color: rgba(18,112,61,.20); }
  :root:not([data-theme="dark"]) .joystick-axis { background: rgba(18,112,61,.16); }
  :root:not([data-theme="dark"]) .joystick-knob {
    background: radial-gradient(circle at 36% 30%, #3fae74, #15784a 45%, #0d5b31 72%);
    border-color: #0d5b31;
    box-shadow: 0 8px 22px rgba(20,45,32,.28), inset 0 1px 1px rgba(255,255,255,.35);
  }
  :root:not([data-theme="dark"]) .joystick-dot { background: #eafaf0; box-shadow: none; }

  /* Kartenzeichnung */
  :root:not([data-theme="dark"]) .canvas-bg { fill: #f2f6f3; }
  :root:not([data-theme="dark"]) .grid-line { stroke: #cbd8d0; opacity: .95; }
  :root:not([data-theme="dark"]) .grid-major { stroke: #aec0b5; opacity: .95; }
  :root:not([data-theme="dark"]) .grid-axis { stroke: #8ba396; opacity: 1; }
  :root:not([data-theme="dark"]) .perimeter-shape { stroke: #167444; fill: rgba(22,116,68,.07); filter: none; }
  :root:not([data-theme="dark"]) .exclusion-shape { stroke: #b13636; fill: rgba(177,54,54,.09); filter: none; }
  :root:not([data-theme="dark"]) .dock-shape { stroke: #2f5f9e; filter: none; }
  :root:not([data-theme="dark"]) .waypoint-shape { filter: none; }
  :root:not([data-theme="dark"]) .movement-trail-shape { stroke: #7a8f84; }
  :root:not([data-theme="dark"]) .robot-body { fill: rgba(255,255,255,.94); stroke: #16241c; filter: none; }
  :root:not([data-theme="dark"]) .robot-front { fill: #12703d; stroke: #0d5b31; }
  :root:not([data-theme="dark"]) .robot-axle { stroke: #6d7f75; }
  :root:not([data-theme="dark"]) .robot-center { fill: #16241c; stroke: #ffffff; }
  :root:not([data-theme="dark"]) .robot-position-marker { stroke: #12703d; }
  :root:not([data-theme="dark"]) .robot-dot { fill: #16241c; stroke: #ffffff; filter: none; }
  :root:not([data-theme="dark"]) .robot-ring { stroke: #12703d; }
  :root:not([data-theme="dark"]) .edit-selected-ring { stroke: var(--selection); }
  :root:not([data-theme="dark"]) .edit-distance-line { stroke: var(--selection); }
  :root:not([data-theme="dark"]) .boundary-distance-line { stroke: #2f5f9e; }
}

/* Beschriftung und Erklaerung im Menue einheitlich: gleiche Schriftfamilie, klare
   Abstufung nur ueber Groesse und Farbe. Vorher stand ein .75rem-Fettlabel direkt ueber
   einem .62rem-Hinweis in Monospace und einer abweichenden Graustufe. */
.menu-body .fix-switch {
  font-size: .78rem;
  font-weight: 700;
  color: var(--shell-text);
}
.menu-body .view-note,
.menu-body .auto-capture-state,
.menu-body .field small {
  display: block;
  font-family: inherit;
  font-size: .68rem;
  font-weight: 500;
  line-height: 1.45;
  color: var(--shell-muted);
}

/* Absteigende Zonenstaffel: Warnfarbe statt Fehlerfarbe — die Zonen funktionieren weiterhin,
   ueberraschend ist nur ihre Reihenfolge. Die Spezifitaet (0,3,0) muss ueber der Grundregel
   darueber (0,2,0) liegen, sonst faerbt sich nichts. Farbe aus dem Token, damit sie in Hell
   und Dunkel lesbar bleibt. */
.menu-body .view-note.is-warning {
  color: var(--warn);
  border-left: 2px solid color-mix(in srgb, var(--warn), transparent 45%);
  padding-left: 8px;
  margin-block: 6px;
}

/* Die Kartenflaeche kommt aus dem Hintergrund des SVG statt aus einem Rechteck mit fester
   Groesse — der viewBox folgt jetzt der gemessenen Flaeche (siehe updateViewBox in app.js). */
.map-stage #mapSvg { background: var(--map-canvas, var(--shell-bg)); }
:root { --map-canvas: #081013; }
:root[data-theme="light"] { --map-canvas: #f2f6f3; }
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) { --map-canvas: #f2f6f3; }
}

/* Symbole kraeftiger und im gesperrten Zustand noch lesbar — auf der dunklen Karte
   verschwanden duenne Striche bei opacity .4 fast vollstaendig. */
.map-fab svg { stroke-width: 2.1; }
.capture-fab svg { width: 34px; height: 34px; stroke-width: 2.6; }
.auto-fab svg { width: 26px; height: 26px; stroke-width: 2; }
.capture-cluster.auto-active .auto-fab svg { width: 38px; height: 38px; }
.map-fab[disabled], .auto-fab[disabled], .capture-fab[disabled] { opacity: .62; }

/* Rueckfragen im App-Design statt window.confirm(): gleiche Karte wie der Moduswahl-Dialog. */
.modal-text {
  margin: 0;
  color: var(--shell-muted);
  font-size: .8rem;
  line-height: 1.45;
}
.modal-actions {
  /* Untereinander statt nebeneinander: die Beschriftungen sagen, was der Knopf tut
     („Kontur automatisch schließen“), dafuer reicht eine halbe Dialogbreite nicht. */
  display: grid;
  grid-template-columns: 1fr;
  gap: 8px;
}
.modal-actions button { min-height: 48px; font-weight: 800; }
.modal-actions.single { grid-template-columns: 1fr; }

/* Ohne diese Regel greift das hidden-Attribut bei Knoepfen nicht: die Regel
   `button { display: inline-flex }` weiter oben schlaegt das display:none des Browsers.
   Das liess unter anderem den Abbrechen-Knopf in reinen Meldungen stehen und den
   Knopf „Ansicht zuruecksetzen“ dauerhaft sichtbar. */
[hidden] { display: none !important; }

/* Schloss in der Kartenübersicht: offen = gedämpft und dünn, gesperrt = Warnfarbe,
   gefüllter Körper und Wortmarke. Die früheren Emoji waren im Dunkeln nicht zu unterscheiden. */
.lock-icon { width: 22px; height: 22px; }
.lock-icon .lock-body { fill: none; stroke: currentColor; stroke-width: 1.8; }
.lock-icon .lock-shackle { fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; }
.map-card-lock small { font-size: .52rem; font-weight: 800; letter-spacing: .04em; text-transform: uppercase; }
.map-card-lock.active {
  background: var(--shell-warn-bg);
  color: var(--shell-warn);
}
.map-card-lock.active .lock-icon .lock-body { fill: currentColor; stroke: currentColor; }
.map-card-lock.active .lock-icon { width: 24px; height: 24px; }
.map-gallery-card.locked { border-color: var(--shell-warn-border); border-style: solid; }

/* Update-Hinweis ganz oben, über der Kopfzeile: hier schaut der Nutzer ohnehin hin.
   Ausgeblendet nimmt er dank [hidden] keinen Platz in der Grid-Zeile ein. */
.update-bar {
  width: 100%;
  min-height: 40px;
  padding: 8px 12px;
  border: 0;
  border-bottom: 1px solid var(--shell-ok-border);
  border-radius: 0;
  background: var(--shell-ok-bg);
  color: var(--shell-ok);
  font-size: .74rem;
  font-weight: 800;
  text-align: center;
}
.update-bar:active { background: var(--shell-ok-border); }

/* Elementliste im Menü unter „Karten“: alle Bestandteile der Karte mit Punktzahl,
   antippbar zum Aktivieren, einzeln löschbar. */
.element-list-head { margin-top: 4px; font-size: .72rem; font-weight: 800; color: var(--shell-muted); }
.element-list { display: grid; gap: 6px; }
.element-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: stretch;
  gap: 6px;
  border: 1px solid var(--shell-border-soft);
  border-radius: 10px;
  background: var(--shell-panel-2);
  overflow: hidden;
}
.element-row.active { border-color: var(--shell-ok-border); background: var(--shell-ok-bg); }
.element-select {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 8px;
  min-height: 48px;
  padding: 6px 10px;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--shell-text);
  font-size: .78rem;
  font-weight: 700;
  text-align: left;
}
.element-dot { width: 11px; height: 11px; border-radius: 50%; background: var(--perimeter); }
.element-dot[data-mode="exclusion"] { background: var(--exclusion); }
.element-dot[data-mode="waypoint"] { background: var(--waypoint); }
.element-dot[data-mode="dock"] { background: var(--dock); }
.element-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.element-count { color: var(--shell-muted); font-size: .68rem; font-weight: 600; white-space: nowrap; }
.element-delete {
  display: grid;
  place-items: center;
  width: 48px;
  min-height: 48px;
  padding: 0;
  border: 0;
  border-left: 1px solid var(--shell-border-soft);
  border-radius: 0;
  background: transparent;
  color: var(--shell-danger);
}
.element-delete[disabled] { color: var(--shell-muted); opacity: .5; }
.element-trash { width: 20px; height: 20px; fill: none; stroke: currentColor; stroke-width: 1.9; stroke-linecap: round; stroke-linejoin: round; }

/* Sperrzustand auf drei Wegen erkennbar: Form des Bügels, Farbe und Wort — Farbe allein
   war auf dem Gerät nicht zu sehen. */
.lock-icon { width: 30px; height: 30px; }
.lock-icon .lock-body { fill: none; stroke: currentColor; stroke-width: 2; }
.lock-icon .lock-shackle { fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; }
.lock-icon .lock-keyhole { fill: currentColor; stroke: none; }
.map-card-lock.active .lock-icon { width: 32px; height: 32px; }
.map-card-lock.active .lock-icon .lock-body { fill: currentColor; stroke: currentColor; }
.map-card-lock.active .lock-icon .lock-keyhole { fill: var(--shell-warn-bg); }
.map-card-lock small { font-size: .56rem; }
.map-card-locked-note {
  margin-top: 2px;
  color: var(--shell-warn);
  font-size: .7rem;
  font-weight: 800;
}

/* Fahrzone an die Bildschirmhöhe anpassen — sie bleibt trotzdem immer inhaltshoch. */


/* --- Breite Fenster: Fahrzone neben die Karte statt darunter ---------------
   Die Bereiche sind benannt, damit die meist ausgeblendete Update-Leiste die
   übrigen Kinder nicht verschiebt (genau der Fehler, der die Aufteilung im
   Hochformat schon einmal vertauscht hat). */
@media (min-width: 760px) {
  .app-frame {
    display: grid;
    --drive-column: clamp(300px, 30vw, 520px);
    grid-template-columns: minmax(0, 1fr) var(--drive-column);
    grid-template-rows: auto auto minmax(0, 1fr);
    grid-template-areas:
      "update update"
      "bar    bar"
      "map    drive";
  }
  .app-frame > .update-bar { grid-area: update; }
  .app-frame > .appbar { grid-area: bar; }
  .app-frame > .map-stage { grid-area: map; }
  .app-frame > .drive-zone {
    grid-area: drive;
    border-top: 0;
    border-left: 1px solid var(--shell-border-soft);
  }
  /* Die Statusanzeige steht auch hier seitlich — gleiche Anordnung wie am Handy.
     Die Spalte ist dafuer breiter, der Joystick etwas zurueckhaltender. */
  .drive-zone .drive-control {
    --joystick-size: clamp(150px, calc(14vw * var(--joystick-scale, 1)),
      min(calc(260px * var(--joystick-scale, 1)), calc(var(--drive-column) - var(--drive-side-reserve))));
  }
  /* Der Modus-Chip soll auf breiten Schirmen nicht über die halbe Leiste wandern. */
  .mode-chip { flex: 0 1 auto; max-width: 260px; }
  .rtk-chip { margin-left: auto; }
}

/* Schnellzugriff „Fläche schließen & neue“ — steht unter dem Papierkorb und erscheint nur im
   Ausschluss-Modus ab drei Punkten, deshalb in der Farbe der Ausschlussflächen statt neutral. */
.close-new-fab {
  color: var(--exclusion);
  border-color: var(--shell-danger-border);
  background: var(--shell-danger-bg);
}
.close-new-fab svg { stroke-width: 2.2; }

/* Elementfarbe deutlich am Punktrand: kräftigerer Rand und je Art eine eigene Farbe.
   Die Füllung bleibt der RTK-Qualität vorbehalten. */
.map-point { stroke-width: 3.5; }
.point-perimeter { stroke: var(--perimeter); }
.point-exclusion { stroke: var(--exclusion); }
.point-waypoint { stroke: var(--waypoint); }
.point-dock { stroke: var(--dock); }

/* --- Diagnoseprotokoll: Hinweis bei pausiertem Mitlaufen ------------------
   Der Knopf schwebt ueber dem unteren Rand des Protokolls und erscheint nur, solange der
   Nutzer hochgescrollt hat. Er sagt beides: dass neue Zeilen da sind und wie man zurueck ans
   Ende kommt. Farben ueber die --shell-Tokens, damit er in beiden Themes lesbar ist. */
.debug-log-wrap { position: relative; }
.log-jump {
  position: absolute;
  left: 50%;
  bottom: 10px;
  transform: translateX(-50%);
  z-index: 2;
  min-height: 34px;
  max-width: calc(100% - 24px);
  padding: 5px 12px;
  border: 1px solid var(--shell-info-border);
  border-radius: 999px;
  background: var(--shell-info-bg);
  color: var(--shell-info);
  font-size: .7rem;
  font-weight: 800;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  box-shadow: 0 6px 18px rgba(0,0,0,.32);
}
.log-jump:active { background: var(--shell-hover); }

/* ===== v55: CaSSAndRA-Exportgruppe =========================================
   Der Bezugspunkt gehoert sichtbar zum CaSSAndRA-Knopf — nur dieses eine Format braucht ihn.
   Vorher standen die beiden Eingabefelder frei unter der Formatbeschreibung und wirkten wie eine
   allgemeine Einstellung des Kartenabschnitts. Bewusst nur eine Kante und Einzug aus den
   vorhandenen Tokens, keine eigene Flaeche und kein neuer Farbwert: die Gruppe soll zusammen-
   fassen, nicht um Aufmerksamkeit konkurrieren. */
.export-group {
  border-left: 2px solid var(--shell-border);
  padding-left: 10px;
  margin-block: 4px;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
/* Die Trennlinie zwischen den Formatgruppen leistet die Gruppe selbst. */
.export-group + .export-grid { margin-top: 4px; }

/* Verbindungshinweis: rot hervorgehoben, aber weiterhin eine Hinweiszeile und kein Alarm —
   der Zusammenhang ist eine Beobachtung, keine belegte Ursache. Farbe aus den vorhandenen
   Tokens, damit sie in beiden Themes traegt. */
.connect-warning {
  color: var(--danger, #ff6b6b);
  border-left: 2px solid var(--danger, #ff6b6b);
  padding-left: 8px;
  display: block;
  margin-block: 6px;
}
