/* ============================================================
   LernPy — editorial-technical UI
   Headings: Fraunces (serif display) · UI: IBM Plex Sans · Code: IBM Plex Mono
   ============================================================ */

/* ---- Reset & base ---- */
* { box-sizing: border-box; }
/* `hidden` muss IMMER verstecken. Die Regel dafür steht im Stylesheet des Browsers und
   verliert gegen JEDE eigene display-Angabe — `.btn { display: inline-flex }` ließ so
   „In Moodle abgeben“ trotz `hidden: true` in der Werkzeugleiste stehen, auch in einer
   Aufgabe, wo es diese Funktion gar nicht gibt. Weiter unten standen deshalb bereits
   fünf Einzelfall-Reparaturen (.search-clear[hidden] usw.); eine sechste hätte wieder
   nur die Stelle behandelt statt der Ursache. */
[hidden] { display: none !important; }
html, body { height: 100%; }
html { background: var(--bg); }
/* Wenn #app im Vollbild ist: Bildschirm mit App-Hintergrund füllen, bei Bedarf scrollen. */
#app:fullscreen { background: var(--bg); overflow-y: auto; }
#app:-webkit-full-screen { background: var(--bg); overflow-y: auto; }
body {
  margin: 0;
  font-family: var(--font-sans);
  background: transparent;
  color: var(--text);
  line-height: 1.6;
  font-size: 15px;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
/* Faint technical grid for atmosphere (never reduces text contrast). */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    linear-gradient(var(--grid-line) 1px, transparent 1px),
    linear-gradient(90deg, var(--grid-line) 1px, transparent 1px);
  background-size: 34px 34px;
}
h1, h2, h3, h4 { margin: 0; line-height: 1.18; font-weight: 600; }
p { margin: 0; }
a { color: var(--primary); }
button { font-family: inherit; }
::selection { background: var(--primary-weak); color: var(--text); }

/* ---- Themed scrollbars (match the design system instead of OS chrome) ---- */
::-webkit-scrollbar { width: 10px; height: 10px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background-color: var(--border-strong);
  border-radius: 999px;
  /* transparent border + padding-box clip = slim pill floating in the gutter */
  border: 2px solid transparent;
  background-clip: padding-box;
}
::-webkit-scrollbar-thumb:hover { background-color: var(--text-muted); }
::-webkit-scrollbar-corner { background: transparent; }
/* Firefox only — gated so Chromium keeps the richer -webkit styling above
   (Chrome 121+ would otherwise let scrollbar-width/color win and drop it). */
@supports (-moz-appearance: none) {
  * { scrollbar-width: thin; scrollbar-color: var(--border-strong) transparent; }
}

.container { max-width: var(--maxw); margin: 0 auto; padding: var(--sp-6) var(--sp-5) var(--sp-10); }

/* Inline SVG icons inherit text color and align with type. */
.icon { width: 18px; height: 18px; flex: 0 0 auto; display: inline-block; vertical-align: -0.18em; }

/* ---- Focus ring (keyboard accessibility) ---- */
:focus-visible { outline: none; box-shadow: var(--ring); border-radius: var(--radius-sm); }

/* ---- Buttons ---- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
  border: 1px solid transparent; border-radius: var(--radius);
  padding: 10px 17px; font-size: 14px; font-weight: 600; letter-spacing: -0.005em;
  cursor: pointer; white-space: nowrap;
  transition: background var(--transition), border-color var(--transition),
    color var(--transition), transform var(--transition), box-shadow var(--transition);
}
.btn .icon { width: 16px; height: 16px; }
.btn:active { transform: translateY(1px); }
.btn:disabled { opacity: 0.55; cursor: default; }
.btn-primary { background: var(--grad); color: var(--on-grad); box-shadow: var(--shadow-sm); }
.btn-primary:hover:not(:disabled) { filter: brightness(1.07); }
.btn-secondary { background: var(--surface); color: var(--text); border-color: var(--border-strong); }
.btn-secondary:hover:not(:disabled) { border-color: var(--primary); color: var(--primary); }
.btn-ghost { background: transparent; color: var(--text-muted); }
.btn-ghost:hover:not(:disabled) { color: var(--text); background: var(--surface-2); }
/* The confirm button of a destructive dialog. Solid red rather than the brand gradient:
   it has to be distinguishable from the primary button at a glance, because that is the
   one thing telling you this dialog is not the usual "OK". Flat colour, no glow — the
   emphasis comes from the hue, not from decoration. */
.btn-danger { background: var(--danger); color: #fff; border-color: var(--danger); }
.btn-danger:hover:not(:disabled) { filter: brightness(1.08); }
.btn-icon { padding: 9px; }
.btn-block { width: 100%; }
.btn-sm { padding: 6px 11px; font-size: 13px; }
.btn-back {
  align-self: flex-start; padding: 6px 12px 6px 8px; margin-bottom: var(--sp-2);
  font-size: 13px; color: var(--text-muted); background: transparent;
}
.btn-back:hover:not(:disabled) { color: var(--primary); background: var(--surface-2); }

/* ---- Card / panel ---- */
.card, .panel {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
}
.panel { padding: var(--sp-5); }

/* ---- Brand ---- */
.brand { display: inline-flex; align-items: center; gap: 10px; cursor: default; }
.brand-logo { width: 30px; height: 30px; flex: 0 0 auto; }
.brand-logo .bl-bg { fill: url(#lpLogoGrad); }
.brand-logo .bl-fg { fill: none; stroke: var(--on-grad); stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; }
.brand-name { font-weight: 700; letter-spacing: -0.025em; font-size: 19px; color: var(--text); }

/* Page titles that lead with an icon (Rangliste, Spiele, Feedback, Verwaltung). */
.page-title { display: flex; align-items: center; gap: 12px; }
.page-title .icon { color: var(--primary); }

/* ============================================================
   Login — asymmetric editorial split
   ============================================================ */
.login-wrap { min-height: 100vh; display: grid; place-items: center; padding: var(--sp-5); }
.login-split {
  width: 100%; max-width: 860px; overflow: hidden;
  display: grid; grid-template-columns: 1.05fr 1fr;
  box-shadow: var(--shadow-lg);
}
.login-aside {
  position: relative; padding: var(--sp-8) var(--sp-6);
  background: var(--grad); color: var(--on-grad);
  display: flex; flex-direction: column; gap: var(--sp-5);
  overflow: hidden;
}
.login-aside::after {
  content: ""; position: absolute; inset: 0; opacity: 0.5; pointer-events: none;
  background-image:
    linear-gradient(rgba(255, 255, 255, 0.07) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, 0.07) 1px, transparent 1px);
  background-size: 28px 28px;
  -webkit-mask-image: radial-gradient(120% 80% at 80% 0%, #000, transparent 75%);
  mask-image: radial-gradient(120% 80% at 80% 0%, #000, transparent 75%);
}
.login-aside .brand-name { color: inherit; }
.login-aside-headline {
  font-family: var(--font-display); font-weight: 700; font-size: clamp(30px, 4vw, 42px);
  line-height: 1.05; letter-spacing: -0.02em; position: relative;
}
.login-aside-sub { font-size: 15px; opacity: 0.92; max-width: 34ch; position: relative; }
.login-aside-meta {
  margin-top: auto; position: relative;
  font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.02em;
  opacity: 0.85; display: flex; align-items: center; gap: var(--sp-2);
}
.login-aside-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--accent); box-shadow: 0 0 0 3px rgba(255,255,255,0.15); }
.login-main { padding: var(--sp-8) var(--sp-6); background: var(--surface); display: flex; flex-direction: column; justify-content: center; }
.login-title { font-family: var(--font-display); margin: 0 0 var(--sp-1); font-size: 27px; font-weight: 600; letter-spacing: -0.01em; }
.login-sub { margin: 0 0 var(--sp-5); color: var(--text-muted); font-size: 14px; }
.login-form { display: flex; flex-direction: column; }

/* ---- Forms ---- */
.label { font-size: 13px; font-weight: 600; color: var(--text-muted); margin-top: var(--sp-3); margin-bottom: var(--sp-1); }
.input {
  width: 100%; padding: 11px 13px; border: 1px solid var(--border-strong); border-radius: var(--radius);
  background: var(--surface); color: var(--text); font-size: 15px; font-family: inherit;
  transition: border-color var(--transition), box-shadow var(--transition);
}
.input::placeholder { color: var(--text-muted); opacity: 0.7; }
.input:focus { outline: none; border-color: var(--primary); box-shadow: var(--ring); }
/* Textareas grow DOWNWARDS only. A textarea defaults to `resize: both`, and dragging it
   sideways breaks out of the form column — wider than its own label, overlapping whatever
   sits beside it, and narrower than the field above if you drag the other way. Height is
   the axis anybody actually wants on a task description or a block of starter code. */
textarea.input { resize: vertical; }
.login-form .btn { margin-top: var(--sp-5); }
.form-error { color: var(--danger); font-size: 14px; min-height: 20px; margin: var(--sp-2) 0 0; }

/* ============================================================
   Topbar
   ============================================================ */
.topbar {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; justify-content: space-between;
  flex-wrap: wrap; row-gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-5);
  background: color-mix(in srgb, var(--surface) 88%, transparent);
  border-bottom: 1px solid var(--border);
  backdrop-filter: blur(10px) saturate(1.2);
}
.topbar .brand { cursor: pointer; }
.topbar-right { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; justify-content: flex-end; min-width: 0; }
.coin-chip, .progress-chip, .user-chip {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 6px 11px; border-radius: var(--radius-sm); font-size: 13px; font-weight: 600;
  background: var(--surface-2); border: 1px solid var(--border);
}
.coin-chip { font-variant-numeric: tabular-nums; }
.coin-chip .icon, .coin-icon { color: var(--coin); width: 15px; height: 15px; }
.progress-chip { color: var(--text-muted); font-weight: 500; }
.user-chip { color: var(--text-muted); background: transparent; border-color: transparent; font-weight: 600; }

/* ============================================================
   Hero + progress
   ============================================================ */
.hero { margin-bottom: var(--sp-6); }
.hero-title { font-family: var(--font-display); font-size: clamp(28px, 4vw, 38px); font-weight: 600; letter-spacing: -0.02em; }
.hero-sub { color: var(--text-muted); margin: var(--sp-2) 0 var(--sp-4); font-size: 15px; }
.progressbar {
  height: 9px; background: var(--surface-2); border-radius: 999px; overflow: hidden;
  border: 1px solid var(--border); position: relative;
}
.progressbar-fill {
  height: 100%; background: var(--grad);
  border-radius: 999px; transition: width 0.7s cubic-bezier(0.4, 0, 0.2, 1);
}
.hero-meta { font-size: 13px; color: var(--text-muted); margin-top: var(--sp-2); font-variant-numeric: tabular-nums; }
.hero-actions { display: flex; gap: var(--sp-2); margin-top: var(--sp-5); flex-wrap: wrap; }

/* ============================================================
   Course sections + lesson cards
   ============================================================ */
.kurs { margin-top: var(--sp-8); }
.kurs-title {
  display: flex; align-items: center; gap: var(--sp-3);
  font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.14em;
  color: var(--text-muted); margin-bottom: var(--sp-4);
}
.kurs-title::after { content: ""; flex: 1; height: 1px; background: var(--border); }

.lesson-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(264px, 1fr)); gap: var(--sp-4); }
.lesson-card {
  position: relative; text-align: left; cursor: pointer; padding: var(--sp-4) var(--sp-4) var(--sp-5);
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  display: flex; flex-direction: column; gap: var(--sp-2); overflow: hidden;
  transition: transform var(--transition), box-shadow var(--transition), border-color var(--transition);
}
/* Left accent rail that grows on hover / completion. */
.lesson-card::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  background: var(--grad); transform: scaleY(0); transform-origin: top;
  transition: transform var(--transition);
}
.lesson-card:hover { transform: translateY(-3px); box-shadow: var(--shadow); border-color: var(--border-strong); }
.lesson-card:hover::before { transform: scaleY(1); }
.lesson-card.is-done::before { background: var(--success); transform: scaleY(1); }
.lesson-card-top { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); }
.lesson-badge {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--text-muted);
}
.is-done .lesson-badge { color: var(--success); }
.lesson-opt {
  font-size: 10px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--warning); background: var(--warning-weak); padding: 3px 8px; border-radius: 999px;
}
.lesson-card-title { font-size: 16.5px; font-weight: 600; letter-spacing: -0.01em; }
.lesson-card-desc {
  font-size: 13.5px; color: var(--text-muted); margin: 0; line-height: 1.5;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
.empty {
  text-align: center; color: var(--text-muted); padding: var(--sp-10) var(--sp-5);
  border: 1px dashed var(--border-strong); border-radius: var(--radius-lg);
}

/* ============================================================
   Lesson view
   ============================================================ */
.lesson-layout { display: grid; grid-template-columns: minmax(280px, 37%) 1fr; gap: var(--sp-5); align-items: start; }
.instructions { position: sticky; top: 84px; }
.lesson-title { font-family: var(--font-display); font-size: 25px; font-weight: 600; letter-spacing: -0.015em; margin: var(--sp-1) 0 var(--sp-3); }
.lesson-desc { color: var(--text); white-space: pre-wrap; line-height: 1.65; }
.tipp { margin-top: var(--sp-5); background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius); padding: var(--sp-2) var(--sp-3); }
.tipp summary { cursor: pointer; font-weight: 600; color: var(--primary); list-style: none; }
.tipp summary::-webkit-details-marker { display: none; }
.tipp summary::before { content: "▸ "; }
.tipp[open] summary::before { content: "▾ "; }
.tipp p { color: var(--text-muted); margin: var(--sp-2) 0 0; }
/* Schema hint for SQL lessons (walkthrough K3 Ü19). Always visible — a
   pupil should never have to click to reveal the table name their task
   refers to. Restrained + monospaced, matches the tipp block visually. */
.sql-schema { margin-top: var(--sp-4); background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius); padding: var(--sp-2) var(--sp-3); }
.sql-schema-label { font-weight: 600; color: var(--text); font-size: 13px; margin-bottom: var(--sp-1); }
.sql-schema-body { font-family: var(--font-mono); color: var(--text-muted); font-size: 13px; line-height: 1.5; margin: 0; white-space: pre-wrap; overflow-x: auto; }

/* ---- Editor ---- */
.editor-panel, .choice-panel { padding: 0; overflow: hidden; }
.editor-toolbar {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: var(--sp-2) var(--sp-3) var(--sp-2) var(--sp-4); border-bottom: 1px solid var(--border);
  background: var(--surface-2);
}
.editor-label { font-family: var(--font-mono); font-weight: 600; font-size: 12px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-muted); }
.spacer { flex: 1; }
.editor { display: flex; font-family: var(--font-mono); font-size: 13.5px; background: var(--surface); min-height: 340px; max-height: 54vh; }
.gutter {
  flex: 0 0 auto; padding: var(--sp-3) 10px; text-align: right; user-select: none;
  color: var(--text-muted); background: var(--surface-2); border-right: 1px solid var(--border);
  overflow: hidden; min-width: 46px; font-variant-numeric: tabular-nums;
}
.gutter-line { line-height: 1.7; opacity: 0.55; }
.code-input {
  flex: 1; resize: none; border: 0; outline: none; padding: var(--sp-3) var(--sp-4);
  font-family: var(--font-mono); font-size: 13.5px; line-height: 1.7; tab-size: 4;
  /* transparent text so the coloured highlight layer shows through; caret stays visible */
  background: transparent; color: transparent; white-space: pre; overflow: auto;
  caret-color: var(--primary); position: relative; z-index: 1;
}
.code-input:focus { box-shadow: none; }

/* ---- Syntax highlighting (VS Code-style, shared by both editors) ---- */
.tok-kw { color: var(--tok-kw); }
.tok-kwc { color: var(--tok-kwc); }
.tok-str { color: var(--tok-str); }
.tok-num { color: var(--tok-num); }
.tok-com { color: var(--tok-com); font-style: italic; }
.tok-fn { color: var(--tok-fn); }
.tok-type, .tok-builtin { color: var(--tok-type); }
.tok-self { color: var(--tok-self); }
.tok-const { color: var(--tok-const); }
.tok-dec { color: var(--tok-dec); }
.hl-layer {
  margin: 0; overflow: hidden; pointer-events: none; box-sizing: border-box;
  font-family: var(--font-mono); white-space: pre; tab-size: 4; color: var(--text);
}
.hl-layer code { font: inherit; color: inherit; background: none; }
/* Keep selected code transparent (the colour layer provides the glyphs) with a
   translucent highlight — otherwise the global ::selection makes it opaque and the
   syntax colours vanish inside a selection. */
.code-input::selection, .ide-code::selection { background: var(--editor-sel); color: transparent; }
.code-input::-moz-selection, .ide-code::-moz-selection { background: var(--editor-sel); color: transparent; }
/* lesson editor: layer sits behind the transparent textarea, same metrics */
.code-area { position: relative; flex: 1; min-width: 0; display: flex; }
.code-area .hl-layer {
  position: absolute; inset: 0; z-index: 0;
  padding: var(--sp-3) var(--sp-4); font-size: 13.5px; line-height: 1.7;
}

/* ---- Output / feedback boxes ---- */
.output { padding: var(--sp-4); border-top: 1px solid var(--border); display: flex; flex-direction: column; gap: var(--sp-3); }
.output-empty { color: var(--text-muted); font-size: 14px; }
.out-box { border-radius: var(--radius); border: 1px solid var(--border); overflow: hidden; }
.out-title { display: flex; align-items: center; gap: 7px; font-size: 11px; font-weight: 700; padding: 8px 12px; text-transform: uppercase; letter-spacing: 0.07em; }
.out-body { margin: 0; padding: 12px; font-family: var(--font-mono); font-size: 13px; line-height: 1.6; white-space: pre-wrap; word-break: break-word; background: var(--surface); color: var(--text); max-height: 240px; overflow: auto; }
.out-success { border-color: var(--success); }
.out-success .out-title { background: var(--success-weak); color: var(--success); }
.out-err { border-color: var(--danger); }
.out-err .out-title { background: var(--danger-weak); color: var(--danger); }
.out-warn .out-title { background: var(--warning-weak); color: var(--warning); }
.out-out .out-title { background: var(--surface-2); color: var(--text-muted); }
/* turtle drawing */
.out-drawing { display: block; max-width: 100%; height: auto; background: #fff; padding: 8px; }
/* "run locally" prompt for desktop-GUI code */
.out-local { padding: 12px; background: var(--surface); display: flex; flex-direction: column; gap: var(--sp-2); align-items: flex-start; }
.out-local p { margin: 0; font-size: 13px; color: var(--text-muted); }

/* ---- Multiple-choice ---- */
.mc-options { display: flex; flex-direction: column; gap: var(--sp-2); padding: var(--sp-4); }
.mc-option {
  display: flex; align-items: center; gap: var(--sp-3); text-align: left;
  padding: var(--sp-3) var(--sp-4); background: var(--surface);
  border: 1px solid var(--border-strong); border-radius: var(--radius);
  cursor: pointer; color: var(--text); font-size: 15px;
  transition: border-color var(--transition), background var(--transition), box-shadow var(--transition);
}
.mc-option:hover { border-color: var(--primary); }
.mc-option.selected { border-color: var(--primary); background: var(--primary-weak); box-shadow: var(--ring); }
.mc-key {
  font-family: var(--font-mono); font-weight: 700; color: var(--primary); flex: 0 0 auto;
  width: 30px; height: 30px; display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--border-strong); border-radius: var(--radius-sm); background: var(--surface-2);
}
.mc-option.selected .mc-key { border-color: var(--primary); background: var(--surface); }
.mc-text { flex: 1; }

/* ============================================================
   Leaderboard
   ============================================================ */
/* Rangliste tabs (overall + per game) */
.rl-tabs {
  display: flex; gap: var(--sp-1); margin-bottom: var(--sp-5);
  border-bottom: 1px solid var(--border); overflow-x: auto; overflow-y: hidden;
}
.rl-tab {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 10px 15px; border: 0; background: transparent; cursor: pointer;
  font-size: 14px; font-weight: 600; color: var(--text-muted); white-space: nowrap;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
  transition: color var(--transition), border-color var(--transition), background var(--transition);
}
.rl-tab .icon { width: 15px; height: 15px; }
.rl-tab:hover:not(.is-active) { color: var(--text); background: var(--surface-2); }
.rl-tab.is-active { color: var(--primary); border-bottom-color: var(--primary); }
.rl-filter { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-bottom: var(--sp-4); }
.rl-search { max-width: 320px; }
/* Class accordion: click a class header to slide its students open */
.rl-class {
  display: flex; align-items: center; gap: var(--sp-2);
  padding: 11px 14px; cursor: pointer;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  transition: border-color var(--transition), background var(--transition),
    border-radius var(--transition);
}
.rl-class:hover { border-color: var(--border-strong); }
.rl-class.is-open {
  border-color: var(--primary);
  border-bottom-left-radius: 0; border-bottom-right-radius: 0;
}
.rl-class-chevron { color: var(--text-muted); width: 14px; flex: 0 0 auto; transition: transform var(--transition); }
.rl-class.is-open .rl-class-chevron { color: var(--primary); }
.rl-class-name { font-weight: 600; font-size: 15px; }
.rl-class-count { color: var(--text-muted); font-size: 13px; margin-left: auto; white-space: nowrap; }
/* max-height is driven in JS (set to the measured content height) so the body
   slides open AND closed reliably — grid-template-rows: 1fr/0fr animates open but
   sticks on close in Chromium. overflow:hidden clips the body while it slides. */
.rl-class-collapse {
  overflow: hidden; max-height: 0; margin-bottom: var(--sp-1);
  transition: max-height 0.26s cubic-bezier(0.4, 0, 0.2, 1);
}
.rl-class-body {
  background: var(--surface-2); padding: 0 var(--sp-3);
  border: 1px solid var(--primary); border-top: 0;
  border-radius: 0 0 var(--radius) var(--radius);
}

.leaderboard { width: 100%; border-collapse: collapse; }
.leaderboard th, .leaderboard td { text-align: left; padding: 11px 12px; border-bottom: 1px solid var(--border); }
.leaderboard tr:last-child td { border-bottom: 0; }
.leaderboard th { font-size: 11px; text-transform: uppercase; letter-spacing: 0.09em; color: var(--text-muted); font-weight: 600; }
.lb-rank { font-weight: 700; width: 56px; font-variant-numeric: tabular-nums; }
.lb-coins { color: var(--coin); font-weight: 600; white-space: nowrap; font-variant-numeric: tabular-nums; }
.lb-coins .icon { color: var(--coin); width: 14px; height: 14px; }

/* ============================================================
   Admin
   ============================================================ */
/* Abstand für ein Panel unter der Reiterleiste. Hieß bis 2026-08-07 `admin-fb-panel`,
   nach dem Feedback-Reiter, den es zuerst gebraucht hat — den gibt es nicht mehr, die
   vier anderen Panels brauchen den Abstand weiterhin. */
.admin-subpanel { margin-top: var(--sp-5); }
.admin-create { display: flex; gap: var(--sp-2); flex-wrap: wrap; align-items: center; margin-bottom: var(--sp-4); }
.admin-create .input { width: auto; flex: 1 1 150px; }
.admin-create select.input { flex: 0 0 auto; }
.admin-table { width: 100%; border-collapse: collapse; }
.admin-table th, .admin-table td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--border); font-size: 14px; }
.admin-table tr:last-child td { border-bottom: 0; }
.admin-table th { font-size: 11px; text-transform: uppercase; letter-spacing: 0.08em; color: var(--text-muted); font-weight: 600; }
.cell-center { text-align: center; }
.is-inactive { opacity: 0.5; }
.row-actions { display: flex; gap: var(--sp-2); }
.role-badge {
  font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em;
  padding: 3px 9px; border-radius: 999px; background: var(--surface-2); border: 1px solid var(--border); color: var(--text-muted);
}
.role-teacher { color: var(--primary); border-color: var(--primary); }
.role-admin { color: var(--danger); border-color: var(--danger); }
.role-select { width: auto; padding: 5px 9px; font-size: 13px; }
.admin-filter { display: flex; align-items: center; gap: var(--sp-2); margin-bottom: var(--sp-3); }
.klasse-label { font-size: 13px; color: var(--text-muted); }
.klassen-list { display: flex; flex-direction: column; gap: var(--sp-2); }
.klasse-item {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-3); background: var(--surface-2);
  border: 1px solid var(--border); border-radius: var(--radius);
}
.klasse-name { font-weight: 600; }
.klasse-count { font-size: 13px; color: var(--text-muted); flex: 1; }
.tag { font-size: 12px; padding: 2px 9px; border-radius: 999px; background: var(--surface); border: 1px solid var(--border); color: var(--text-muted); }
.tag-anon { color: var(--warning); border-color: var(--warning); }

/* ============================================================
   Games
   ============================================================ */
/* Shared Game-Over card (2026-08-12) — used by Tower, Flappy and Block
   Blast to replace the small "tap for restart" hint at the bottom with a
   real centered GUI. Snake / Doodle / Klick-Jagd already have their own
   themed cards; those keep their identity. This one is deliberately
   restrained (dark glass, no glow, no neon) per the "professional, not
   gaming-RGB" rule. */
.game-over-card {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  z-index: 100;
  min-width: 280px; max-width: min(92vw, 420px);
  padding: 28px 36px 22px;
  border-radius: 16px;
  background: rgba(20, 22, 32, 0.94);
  color: #f4f7ff;
  border: 1px solid rgba(255, 255, 255, 0.14);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.55);
  display: flex; flex-direction: column; align-items: stretch; gap: 12px;
  text-align: center;
  font-family: "IBM Plex Sans", system-ui, sans-serif;
  pointer-events: auto;
}
.game-over-title {
  margin: 0; font-family: "Fraunces", Georgia, serif;
  font-size: 30px; font-weight: 700; letter-spacing: 0.01em;
}
.game-over-score-label {
  font-size: 12px; letter-spacing: 0.08em; text-transform: uppercase;
  color: rgba(226, 232, 255, 0.7); margin-bottom: -4px;
}
.game-over-score {
  font-size: 54px; font-weight: 700; line-height: 1;
  font-variant-numeric: tabular-nums; color: #ffd23f;
  margin: 2px 0 6px;
}
.game-over-record {
  font-size: 14px; font-weight: 600; color: #ffd23f;
  margin-top: -4px;
}
.game-over-btn {
  font: inherit; font-size: 15px; font-weight: 600;
  padding: 11px 20px; border-radius: 10px; cursor: pointer;
  border: 1px solid transparent; transition: background 0.12s ease;
}
.game-over-btn-primary { background: #74c83f; color: #fff; border-color: #5aa233; }
.game-over-btn-primary:hover { background: #85d84a; }
.game-over-btn-ghost { background: transparent; color: #f4f7ff; border-color: rgba(255, 255, 255, 0.24); }
.game-over-btn-ghost:hover { background: rgba(255, 255, 255, 0.08); }

/* Per-game skins (2026-08-12) — Ayden asked for each Game-Over card to
   match its game's look ("das dashboard soll aber zum spiel passen"). Same
   structure, per-game palette. */

/* Tower Builder: dark starry sky, block-colour accents. Tower's background
   sweeps through the whole colour wheel with the tower's height (blockHue
   starts at 18° and climbs 9° per floor); the game passes the CURRENT hue
   at death via ``--card-hue`` on the card element, so the card genuinely
   matches the sky the pupil just died against instead of always being
   orange-and-brown. Fallback 18° for the very first floor. */
.game-over-card--tower {
  --card-hue: 18;
  background: linear-gradient(
    180deg,
    hsl(var(--card-hue), 40%, 22%) 0%,
    hsl(var(--card-hue), 30%, 8%) 100%
  );
  border: 1px solid hsla(var(--card-hue), 60%, 60%, 0.4);
  color: #ffe9d1;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.7);
}
.game-over-card--tower .game-over-title { color: #ffe9d1; }
.game-over-card--tower .game-over-score-label { color: rgba(255, 224, 190, 0.65); }
.game-over-card--tower .game-over-score { color: hsl(var(--card-hue), 90%, 68%); }
.game-over-card--tower .game-over-record { color: hsl(var(--card-hue), 90%, 68%); }
.game-over-card--tower .game-over-btn-primary {
  background: hsl(var(--card-hue), 80%, 55%);
  border-color: hsl(var(--card-hue), 70%, 40%);
  color: #fff;
}
.game-over-card--tower .game-over-btn-primary:hover { background: hsl(var(--card-hue), 88%, 62%); }
.game-over-card--tower .game-over-btn-ghost { color: #ffe9d1; border-color: rgba(255, 224, 190, 0.28); }
.game-over-card--tower .game-over-btn-ghost:hover { background: rgba(255, 224, 190, 0.08); }

/* Block Blast: the card IS a Block Blast block. Same chunky visual
   language as ``bevelBlock`` in the game — a saturated face with a
   4-sided bevel (top+left light, right+bottom dark), a dark inner seam
   and a subtle radial highlight on the top face. The Nochmal button
   itself is drawn as a smaller sibling block. Color chosen from the
   game's own piece palette (a teal/gem shade so the card reads as ONE of
   the blocks, not the board background). */
.game-over-card--blockblast {
  --bb-face: #2fb6b9;
  --bb-light: rgba(255, 255, 255, 0.5);
  --bb-mid-light: rgba(255, 255, 255, 0.26);
  --bb-dark: rgba(0, 0, 0, 0.28);
  --bb-mid-dark: rgba(0, 0, 0, 0.42);
  background:
    /* soft top-face highlight */
    radial-gradient(ellipse at 30% 20%, rgba(255, 255, 255, 0.14) 0%, transparent 55%),
    linear-gradient(180deg, #38c9cc 0%, var(--bb-face) 55%, #248c8f 100%);
  color: #ffffff;
  border-radius: 4px;
  /* 4-sided bevel via bordered box-shadows, mirroring bevelBlock's four
     trapezoid faces (see blockblast.js). Order: outer drop, inner top
     highlight, inner left highlight, inner right shadow, inner bottom
     shadow, thin dark seam. */
  box-shadow:
    0 22px 60px rgba(0, 0, 0, 0.55),
    inset 0 10px 0 var(--bb-light),
    inset 10px 0 0 var(--bb-mid-light),
    inset -10px 0 0 var(--bb-dark),
    inset 0 -10px 0 var(--bb-mid-dark),
    inset 0 0 0 2px rgba(0, 0, 0, 0.28);
  padding: 34px 42px 28px;
}
.game-over-card--blockblast .game-over-title {
  color: #ffcf33;
  text-shadow: 0 2px 0 rgba(0, 0, 0, 0.35);
  letter-spacing: 0.02em;
}
.game-over-card--blockblast .game-over-score-label {
  color: rgba(255, 255, 255, 0.82);
  text-shadow: 0 1px 0 rgba(0, 0, 0, 0.35);
}
.game-over-card--blockblast .game-over-score {
  color: #ffcf33;
  text-shadow: 0 3px 0 rgba(0, 0, 0, 0.4);
}
.game-over-card--blockblast .game-over-record { color: #ffcf33; }
/* The Nochmal button is itself a small block in the piece palette (a
   distinct gem colour so it reads as a separate block sitting on the big
   one). Same 4-sided bevel via box-shadow, in gold to draw the eye. */
.game-over-card--blockblast .game-over-btn-primary {
  background: linear-gradient(180deg, #ffdb5a 0%, #f5b41c 100%);
  color: #3a2308;
  border: 0; border-radius: 3px;
  font-weight: 800;
  box-shadow:
    inset 0 4px 0 rgba(255, 255, 255, 0.5),
    inset 4px 0 0 rgba(255, 255, 255, 0.28),
    inset -4px 0 0 rgba(0, 0, 0, 0.22),
    inset 0 -5px 0 rgba(0, 0, 0, 0.4),
    inset 0 0 0 1px rgba(0, 0, 0, 0.3);
}
.game-over-card--blockblast .game-over-btn-primary:hover {
  background: linear-gradient(180deg, #ffe273 0%, #ffbe28 100%);
}
/* The Auswahl button is a smaller mid-tone block — same bevel shape but
   with a purple face (from another piece in the game's palette) so the
   two buttons together read like two blocks stacked. */
.game-over-card--blockblast .game-over-btn-ghost {
  background: linear-gradient(180deg, #8f61e8 0%, #6a3fcd 100%);
  color: #ffffff;
  border: 0; border-radius: 3px;
  font-weight: 700;
  box-shadow:
    inset 0 4px 0 rgba(255, 255, 255, 0.32),
    inset 4px 0 0 rgba(255, 255, 255, 0.18),
    inset -4px 0 0 rgba(0, 0, 0, 0.22),
    inset 0 -5px 0 rgba(0, 0, 0, 0.4),
    inset 0 0 0 1px rgba(0, 0, 0, 0.28);
}
.game-over-card--blockblast .game-over-btn-ghost:hover {
  background: linear-gradient(180deg, #a077f0 0%, #7c53d8 100%);
}

.game-card { align-items: center; text-align: center; padding: var(--sp-5); position: relative; }
.game-emoji { font-size: 42px; }
.game-stage { margin-top: var(--sp-5); display: flex; flex-direction: column; align-items: center; gap: var(--sp-3); }
/* Price chip on each game card — coin icon + "N Münzen". Turns red when the
   pupil is short; the card itself also greys and refuses clicks. */
.game-price {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 8px; border-radius: 999px;
  background: var(--surface); border: 1px solid var(--border);
  color: var(--text-muted); font-size: 12px; font-weight: 600;
  margin-top: 6px;
}
.game-price-short { color: var(--danger); border-color: var(--danger); }
.game-card.is-locked { opacity: 0.55; cursor: not-allowed; }
.game-card.is-locked:hover { transform: none; }
.game-info { display: flex; gap: var(--sp-5); align-items: baseline; flex-wrap: wrap; justify-content: center; }
.game-score { font-weight: 700; font-size: 16px; font-variant-numeric: tabular-nums; }
.game-hint { font-size: 13px; color: var(--text-muted); }
.game-canvas { border: 1px solid var(--border-strong); border-radius: var(--radius); background: var(--surface-2); outline: none; touch-action: none; box-shadow: var(--shadow-sm); }

/* ===== Snake — full-screen Google-style game ===== */
.snake-overlay {
  position: fixed; inset: 0; z-index: 1000;
  background: #578a34; overflow: hidden;
  font-family: var(--font-sans, system-ui, -apple-system, "Segoe UI", sans-serif);
  touch-action: none; user-select: none; -webkit-user-select: none;
}
.snake-canvas { position: absolute; inset: 0; z-index: 1; display: block; }
.snake-bar {
  position: absolute; top: 0; left: 0; right: 0; z-index: 3;
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 18px; pointer-events: none;
}
.snake-score {
  display: flex; align-items: center; gap: 8px;
  color: #fff; font-weight: 800; font-size: 26px;
  font-variant-numeric: tabular-nums; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
}
.snake-actions { display: flex; gap: 8px; pointer-events: auto; }
.snake-iconbtn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; border: none; border-radius: 10px;
  background: rgba(255, 255, 255, 0.16); color: #fff; cursor: pointer;
  transition: background 0.15s ease;
}
.snake-iconbtn:hover { background: rgba(255, 255, 255, 0.3); }
.snake-icon-slot { display: inline-flex; }

.snake-modal-layer {
  position: absolute; inset: 0; z-index: 2; display: none;
  align-items: center; justify-content: center;
  background: rgba(0, 0, 0, 0.28); padding: 20px;
}
.snake-modal-layer.is-open { display: flex; }
.snake-card {
  width: min(360px, 92vw); box-sizing: border-box;
  background: #4bb4e6; border-radius: 18px; padding: 22px;
  box-shadow: 0 18px 50px rgba(0, 0, 0, 0.35);
  display: flex; flex-direction: column; gap: 12px;
  color: #fff; text-align: center;
}
.snake-card-top { display: flex; justify-content: space-around; align-items: center; padding: 4px 0; }
.snake-stat { display: flex; flex-direction: column; align-items: center; gap: 6px; }
/* Override the global 18px .icon cap — the start-screen stats use large icons. */
.snake-stat .icon { width: 46px; height: 46px; vertical-align: middle; }
.snake-score .icon { width: 26px; height: 26px; vertical-align: -0.22em; }
.snake-stat-val { font-size: 26px; font-weight: 800; font-variant-numeric: tabular-nums; }
.snake-trophy { color: #ffd23f; display: inline-flex; }
.snake-art { display: block; width: 100%; height: auto; }
.snake-card-title { margin: 2px 0; font-size: 22px; font-weight: 800; }
/* Menu card: full-bleed start scene (sky = card blue + grass strip) on top, padded
   button body below — like the original Snake start screen. */
.snake-card-menu { padding: 0; overflow: hidden; gap: 0; }
.snake-scene { position: relative; background: #4bb4e6; }
.snake-scene > .snake-art { display: block; }
.snake-scene-stats {
  position: absolute; top: 14px; left: 0; right: 0;
  display: flex; justify-content: space-around; align-items: flex-start;
}
.snake-scene-stats .snake-stat { gap: 2px; }
.snake-scene-stats .snake-stat-val { font-size: 30px; text-shadow: 0 1px 3px rgba(0, 0, 0, 0.28); }
.snake-card-body { padding: 16px 18px 18px; display: flex; flex-direction: column; gap: 12px; }
.snake-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  width: 100%; box-sizing: border-box; padding: 13px 16px;
  border: none; border-radius: 12px; background: #2f7ec4; color: #fff;
  font-size: 16px; font-weight: 700; cursor: pointer; transition: filter 0.15s ease;
}
.snake-btn:hover { filter: brightness(1.08); }
.snake-btn-primary { background: #2766a8; }
.snake-setrow { display: flex; flex-direction: column; gap: 6px; text-align: left; }
.snake-setlabel { font-size: 13px; font-weight: 700; opacity: 0.9; }
.snake-seg-group { display: flex; gap: 6px; }
.snake-seg {
  flex: 1; padding: 9px 8px; border: 2px solid rgba(255, 255, 255, 0.5);
  background: transparent; color: #fff; border-radius: 10px;
  font-size: 14px; font-weight: 700; cursor: pointer;
}
.snake-seg.is-active { background: #fff; color: #2766a8; border-color: #fff; }
.snake-hint { font-size: 12px; opacity: 0.85; margin: 2px 0 0; }
@media (max-width: 360px) {
  .snake-card { width: 96vw; padding: 16px; }
  .snake-seg { padding: 9px 4px; font-size: 13px; }
  .snake-btn { font-size: 15px; padding: 12px; }
}
@media (prefers-reduced-motion: reduce) {
  .snake-iconbtn, .snake-btn { transition: none; }
}

/* Doodle Jump full-screen overlay (hand-drawn graph-paper look, theme-independent) */
.doodle-overlay { position: fixed; inset: 0; z-index: 1000; background: #f7efda; overflow: hidden; touch-action: none; user-select: none; -webkit-user-select: none; }
.doodle-canvas { position: absolute; inset: 0; display: block; width: 100%; height: 100%; }
.doodle-controls { position: absolute; top: 9px; right: 12px; display: flex; gap: 8px; z-index: 2; }
.doodle-btn { width: 40px; height: 40px; display: inline-flex; align-items: center; justify-content: center; border: none; border-radius: 10px; background: rgba(0,0,0,0.06); color: #444; cursor: pointer; }
.doodle-btn:hover { background: rgba(0,0,0,0.12); }
.doodle-banner { position: absolute; left: 50%; top: 52%; transform: translate(-50%,-50%); z-index: 2; }
.doodle-banner.is-hidden { display: none; }
.doodle-card { background: rgba(255,255,255,0.93); border: 2px solid #2c2c2c; border-radius: 16px; padding: 22px 26px; text-align: center; box-shadow: 0 6px 0 rgba(0,0,0,0.12); min-width: 240px; }
.doodle-card-title { font-family: 'Fraunces', Georgia, serif; font-weight: 700; font-size: 26px; color: #2c2c2c; margin-bottom: 8px; }
.doodle-card-text { font-size: 14px; color: #555; margin-top: 4px; }
.doodle-card-score { font-size: 18px; font-weight: 700; color: #3a3a3a; margin-top: 4px; font-variant-numeric: tabular-nums; }
.doodle-card-best { display: flex; align-items: center; justify-content: center; gap: 6px; width: fit-content; margin: 10px auto 2px; padding: 4px 14px; font-weight: 700; font-size: 15px; color: #3f8a2e; background: rgba(143,206,74,0.16); border-radius: 999px; }
.doodle-card-btn { margin-top: 14px; padding: 9px 22px; border: 2px solid #2c2c2c; border-radius: 10px; background: #8fce4a; color: #1f3a10; font-weight: 700; font-size: 15px; cursor: pointer; }
.doodle-card-btn:hover { background: #7ac043; }
.doodle-card-btn.doodle-card-btn-ghost { background: transparent; color: #2c2c2c; margin-top: 10px; }
.doodle-card-btn.doodle-card-btn-ghost:hover { background: rgba(0, 0, 0, 0.06); }

/* Tower Builder full-screen overlay (its own dark look, independent of theme) */
.tower-fs { position: fixed; inset: 0; z-index: 1000; background: #140d08; overflow: hidden; touch-action: none; user-select: none; -webkit-user-select: none; }
.tower-fs-canvas { display: block; width: 100%; height: 100%; }
.tower-fs-score { position: absolute; top: max(18px, env(safe-area-inset-top)); left: 0; right: 0; text-align: center; font-size: clamp(40px, 9vw, 84px); font-weight: 700; color: #f2f5ff; font-variant-numeric: tabular-nums; text-shadow: 0 2px 14px rgba(0,0,0,0.45); pointer-events: none; }
.tower-fs-hint { position: absolute; bottom: max(20px, env(safe-area-inset-bottom)); left: 0; right: 0; text-align: center; font-size: 14px; color: rgba(226,232,255,0.7); pointer-events: none; }
.tower-fs-bar { position: absolute; top: max(14px, env(safe-area-inset-top)); right: 14px; display: flex; gap: 8px; }
.tower-fs-btn { font: inherit; font-size: 14px; padding: 8px 12px; border-radius: 10px; border: 1px solid rgba(255,255,255,0.18); background: rgba(255,255,255,0.08); color: #f2f5ff; cursor: pointer; line-height: 1; }
.tower-fs-btn:hover { background: rgba(255,255,255,0.16); }
.tower-fs-close { font-size: 16px; padding: 8px 11px; }

/* Block Blast full-screen overlay (own blue look, independent of theme) */
.bb-fs { position: fixed; inset: 0; z-index: 1000; background: #2b3a85; overflow: hidden; touch-action: none; user-select: none; -webkit-user-select: none; }
.bb-fs-canvas { display: block; width: 100%; height: 100%; }
.bb-fs-hint { position: absolute; bottom: max(16px, env(safe-area-inset-bottom)); left: 0; right: 0; text-align: center; font-size: 13px; color: rgba(226,232,255,0.75); pointer-events: none; padding: 0 12px; }
.bb-fs-bar { position: absolute; top: max(14px, env(safe-area-inset-top)); right: 14px; display: flex; gap: 8px; }
.bb-fs-btn { font: inherit; font-size: 14px; padding: 8px 12px; border-radius: 10px; border: 1px solid rgba(255,255,255,0.2); background: rgba(255,255,255,0.1); color: #f2f5ff; cursor: pointer; line-height: 1; }
.bb-fs-btn:hover { background: rgba(255,255,255,0.18); }
.bb-fs-close { font-size: 16px; padding: 8px 11px; }

/* Klick-Jagd arcade full-screen overlay (own dark look, independent of theme) */
.kj-fs { position: fixed; inset: 0; z-index: 1000; background: #07080f; overflow: hidden; touch-action: none; user-select: none; -webkit-user-select: none; cursor: crosshair; }
.kj-canvas { display: block; width: 100%; height: 100%; }
/* v2: big centred count-up score over the board (replaces the old top-left HUD) */
.kj-scorewrap { position: absolute; top: max(10px, env(safe-area-inset-top)); left: 0; right: 0; text-align: center; pointer-events: none; z-index: 1; min-height: 108px; }
.kj-scorewrap::after { content: ""; position: absolute; inset: 0; pointer-events: none; background: repeating-linear-gradient(0deg, rgba(0,0,0,0.18) 0 1px, transparent 1px 3px); mix-blend-mode: multiply; opacity: 0.5; }
.kj-score { display: inline-block; font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-weight: 600; line-height: 1; font-size: clamp(40px, 11vw, 88px); letter-spacing: 0.02em; color: #eafff0; text-shadow: 0 0 10px rgba(125,255,142,0.9), 0 0 34px rgba(80,230,120,0.6); transform-origin: 50% 50%; will-change: transform; }
.kj-level { margin-top: 6px; text-align: center; font-size: 14px; font-weight: 600; color: rgba(226,232,255,0.72); letter-spacing: 0.03em; }
.kj-combo { position: static; margin-top: 4px; text-align: center; font-size: clamp(18px, 4vw, 30px); font-weight: 700; color: #ffd23f; text-shadow: 0 2px 12px rgba(0,0,0,0.5); pointer-events: none; min-height: 1.2em; }
.kj-score-punch { animation: kjScorePunch 0.22s cubic-bezier(.2,.9,.25,1); }
@keyframes kjScorePunch { 0% { transform: scale(var(--kj-punch, 1.14)); } 60% { transform: scale(0.97); } 100% { transform: scale(1); } }
.kj-score-rainbow {
  background: linear-gradient(95deg, hsl(var(--kj-hue,140) 95% 62%), hsl(calc(var(--kj-hue,140) + 80) 95% 62%), hsl(calc(var(--kj-hue,140) + 170) 95% 62%), hsl(calc(var(--kj-hue,140) + 260) 95% 62%));
  -webkit-background-clip: text; background-clip: text; color: transparent; -webkit-text-fill-color: transparent;
  text-shadow: none; /* a text-shadow cannot show through the transparent fill — use drop-shadow */
  filter: drop-shadow(0 0 14px hsla(var(--kj-hue,140) 95% 60% / 0.55));
}
@media (max-height: 520px) { .kj-score { font-size: clamp(32px, 8vh, 56px); } .kj-scorewrap { min-height: 84px; } }
.kj-combo-pulse { animation: kjPulse 0.28s ease-out; }
@keyframes kjPulse { 0% { transform: scale(1.32); } 100% { transform: scale(1); } }
.kj-bar { position: absolute; top: max(12px, env(safe-area-inset-top)); right: 14px; display: flex; align-items: center; gap: 8px; z-index: 4; }
.kj-lives { display: flex; gap: 3px; margin-right: 4px; font-size: 22px; line-height: 1; }
.kj-heart { color: #ff5b6e; text-shadow: 0 1px 4px rgba(0,0,0,0.5); }
.kj-heart-off { color: rgba(255,255,255,0.18); text-shadow: none; }
.kj-btn { font: inherit; font-size: 14px; padding: 8px 12px; border-radius: 10px; border: 1px solid rgba(255,255,255,0.18); background: rgba(255,255,255,0.08); color: #f2f5ff; cursor: pointer; line-height: 1; display: inline-flex; align-items: center; }
.kj-btn:hover { background: rgba(255,255,255,0.16); }
.kj-btn-close { padding: 8px 10px; }
.kj-hint { position: absolute; bottom: max(16px, env(safe-area-inset-bottom)); left: 0; right: 0; text-align: center; font-size: 13px; color: rgba(226,232,255,0.6); pointer-events: none; padding: 0 12px; }
.kj-levelup { position: absolute; top: 38%; left: 0; right: 0; text-align: center; font-family: var(--font-display); font-size: clamp(34px, 8vw, 70px); font-weight: 700; color: #fff; text-shadow: 0 4px 24px rgba(0,0,0,0.55); pointer-events: none; animation: kjLevelUp 1.1s ease-out forwards; }
@keyframes kjLevelUp { 0% { opacity: 0; transform: scale(0.6); } 20% { opacity: 1; transform: scale(1.08); } 70% { opacity: 1; transform: scale(1); } 100% { opacity: 0; transform: scale(1); } }
.kj-panel { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; background: rgba(4, 6, 14, 0.7); backdrop-filter: blur(2px); padding: 20px; z-index: 2; }
.kj-panel-card { text-align: center; display: flex; flex-direction: column; align-items: center; gap: 10px; max-width: 460px; }
.kj-panel-title { font-family: var(--font-display); font-size: clamp(34px, 9vw, 64px); font-weight: 700; color: #f2f5ff; }
.kj-panel-score { font-size: clamp(26px, 6vw, 40px); font-weight: 700; color: #ffd23f; font-variant-numeric: tabular-nums; }
.kj-panel-sub { font-size: 15px; color: rgba(226,232,255,0.78); line-height: 1.5; }
.kj-panel-record { font-size: 18px; font-weight: 700; color: #37d67a; }
.kj-cta { margin-top: 8px; font: inherit; font-size: 18px; font-weight: 600; padding: 12px 34px; border-radius: 12px; border: 0; background: linear-gradient(135deg, #2f9e57, #37d67a); color: #06210f; cursor: pointer; box-shadow: 0 6px 20px rgba(0,0,0,0.4); }
.kj-cta:hover { filter: brightness(1.06); }
.kj-panel-hint { font-size: 13px; color: rgba(226,232,255,0.5); }
@media (prefers-reduced-motion: reduce) {
  .kj-combo-pulse { animation: none; }
  .kj-levelup { animation: kjLevelUpReduced 1.1s linear forwards; }
  .kj-score-punch { animation: none; }
  .kj-score-rainbow { background: none; color: inherit; -webkit-text-fill-color: currentColor; filter: none; }
}
@keyframes kjLevelUpReduced { 0% { opacity: 0; } 15% { opacity: 1; } 75% { opacity: 1; } 100% { opacity: 0; } }

/* ---- Klick-Jagd v2: CRT arcade-cabinet panels + slider settings ----
   One dominant accent (acid CRT-green), IBM Plex Mono, scanlines + bezel + vignette.
   Deliberately NOT a multi-stop neon gradient (that reads as generic). */
.kj-fs { --crt: #7dff8e; --crt-dim: rgba(150,255,170,0.55); }
.kj-panel { background: radial-gradient(120% 90% at 50% 20%, rgba(40,120,70,0.16), rgba(2,8,5,0.82) 62%); }
.kj-panel-card {
  position: relative; overflow: hidden; gap: 10px; padding: 34px 38px; border-radius: 14px; max-width: 460px;
  background: radial-gradient(120% 120% at 50% 0%, rgba(40,120,70,0.18), transparent 60%), #05140d;
  border: 1px solid rgba(125,255,142,0.30);
  box-shadow:
    0 0 0 6px rgba(2,8,5,0.92),
    0 0 0 7px rgba(125,255,142,0.18),
    0 24px 70px rgba(0,0,0,0.6),
    inset 0 0 70px rgba(0,0,0,0.7),
    inset 0 0 18px rgba(125,255,142,0.10);
  animation: kjCardIn 0.3s cubic-bezier(.2,.9,.25,1) both;
}
.kj-panel-card::after {
  content: ""; position: absolute; inset: 0; pointer-events: none; border-radius: 14px;
  background: repeating-linear-gradient(0deg, rgba(0,0,0,0.22) 0 1px, transparent 1px 3px);
  mix-blend-mode: multiply; opacity: 0.6;
}
@keyframes kjCardIn { from { opacity: 0; transform: translateY(14px) scale(0.97); } to { opacity: 1; transform: none; } }
.kj-panel-kicker {
  font-family: var(--font-mono); font-size: 12px; font-weight: 600; letter-spacing: 0.42em;
  text-transform: uppercase; color: var(--crt-dim);
}
.kj-panel-title {
  font-family: var(--font-mono); font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em;
  font-size: clamp(24px, 6.5vw, 48px); line-height: 1.05; color: var(--crt); white-space: nowrap;
  text-shadow: 0 0 6px rgba(125,255,142,0.9), 0 0 22px rgba(80,230,120,0.55), 0 0 46px rgba(40,180,90,0.4);
  animation: kjFlicker 4.2s steps(60) infinite;
}
@keyframes kjFlicker { 0%,7%,9%,100% { opacity: 1; } 8% { opacity: 0.72; } 53% { opacity: 0.85; } 54% { opacity: 1; } }
.kj-panel-score {
  font-family: var(--font-mono); font-size: clamp(48px, 13vw, 88px); font-weight: 600; line-height: 1;
  color: #eafff0; font-variant-numeric: tabular-nums; letter-spacing: 0.02em;
  text-shadow: 0 0 10px rgba(125,255,142,0.9), 0 0 34px rgba(80,230,120,0.6);
}
.kj-panel-sub { font-family: var(--font-mono); font-size: 13.5px; color: rgba(190,230,200,0.7); line-height: 1.6; max-width: 34ch; }
.kj-panel-stats { font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.12em; text-transform: uppercase; color: rgba(150,210,165,0.6); }
.kj-panel-record {
  font-family: var(--font-mono); font-size: 14px; font-weight: 600; letter-spacing: 0.18em; text-transform: uppercase;
  color: #ffe14d; text-shadow: 0 0 10px rgba(255,210,60,0.8); animation: kjBlink 0.9s steps(2) infinite;
}
@keyframes kjBlink { 50% { opacity: 0.25; } }
.kj-cta {
  margin-top: 10px; font-family: var(--font-mono); font-size: 17px; font-weight: 600; letter-spacing: 0.12em;
  text-transform: uppercase; padding: 13px 38px; border-radius: 6px; border: 0; cursor: pointer;
  color: #04140a; background: var(--crt);
  box-shadow: 0 4px 0 #2f9e57, 0 0 24px rgba(125,255,142,0.5); transition: transform 0.08s ease, box-shadow 0.08s ease, filter 0.08s ease;
}
.kj-cta:hover { filter: brightness(1.08); }
.kj-cta:active { transform: translateY(3px); box-shadow: 0 1px 0 #2f9e57, 0 0 18px rgba(125,255,142,0.5); }
.kj-link {
  font-family: var(--font-mono); font-size: 13px; letter-spacing: 0.08em; text-transform: uppercase;
  background: transparent; border: 0; color: rgba(150,210,165,0.7); cursor: pointer; padding: 4px 8px;
  text-decoration: underline; text-underline-offset: 3px;
}
.kj-link:hover { color: var(--crt); }
/* settings sliders (CRT) */
.kj-settings-card { gap: 6px; }
.kj-settings-title { font-size: clamp(22px, 6vw, 38px); white-space: normal; }
.kj-set-row { width: 100%; max-width: 360px; margin-top: 14px; text-align: left; }
.kj-set-head { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 7px; }
.kj-set-label { font-family: var(--font-mono); font-size: 12px; letter-spacing: 0.1em; text-transform: uppercase; color: rgba(190,230,200,0.85); }
.kj-set-val { font-family: var(--font-mono); font-size: 13px; font-weight: 600; color: var(--crt); font-variant-numeric: tabular-nums; }
.kj-range { -webkit-appearance: none; appearance: none; width: 100%; height: 8px; border-radius: 2px; outline: none; cursor: pointer;
  background: linear-gradient(90deg, #1c5c34, var(--crt)); box-shadow: inset 0 0 10px rgba(0,0,0,0.6); }
.kj-range::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 16px; height: 24px; border-radius: 3px;
  background: #eafff0; border: 1px solid #2f9e57; box-shadow: 0 0 12px rgba(125,255,142,0.8); cursor: pointer; }
.kj-range::-moz-range-thumb { width: 16px; height: 24px; border-radius: 3px; background: #eafff0; border: 1px solid #2f9e57;
  box-shadow: 0 0 12px rgba(125,255,142,0.8); cursor: pointer; }
.kj-range:focus-visible { box-shadow: inset 0 0 10px rgba(0,0,0,0.6), 0 0 0 3px rgba(125,255,142,0.4); }
@media (prefers-reduced-motion: reduce) {
  .kj-panel-card, .kj-panel-title, .kj-panel-record { animation: none; }
  .kj-cta { transition: none; }
}

/* Flappy Bird full-screen overlay (covers the viewport; on launch it also
   requests OS fullscreen). Sky-coloured background so it never flashes black. */
.flappy-overlay { position: fixed; inset: 0; z-index: 1000; background: #5ec6d6; overflow: hidden; touch-action: none; user-select: none; -webkit-user-select: none; }
.flappy-canvas { display: block; width: 100%; height: 100%; }
.flappy-bar { position: absolute; top: max(14px, env(safe-area-inset-top)); right: 14px; display: flex; gap: 8px; }
.flappy-btn { font: inherit; font-size: 14px; padding: 8px 12px; border-radius: 10px; border: 1px solid rgba(0,0,0,0.18); background: rgba(255,255,255,0.78); color: #1c2b22; cursor: pointer; line-height: 1; }
.flappy-btn:hover { background: rgba(255,255,255,0.95); }
.flappy-exit { font-size: 16px; padding: 8px 11px; }

/* ============================================================
   Modal
   ============================================================ */
.modal-overlay {
  position: fixed; inset: 0; z-index: 100;
  display: flex; align-items: center; justify-content: center;
  background: rgba(20, 16, 8, 0.55); padding: var(--sp-4); backdrop-filter: blur(3px);
  animation: fade 0.18s ease both;
}
.modal-card {
  background: var(--surface); border: 1px solid var(--border-strong); border-radius: var(--radius-lg);
  padding: var(--sp-5); width: 100%; max-width: 400px; box-shadow: var(--shadow-lg);
  display: flex; flex-direction: column; gap: var(--sp-3); animation: pop 0.2s ease both;
}
.modal-title { font-family: var(--font-display); font-size: 19px; font-weight: 600; margin: 0; }
.modal-msg { color: var(--text-muted); margin: 0; }
.modal-actions { display: flex; justify-content: flex-end; gap: var(--sp-2); margin-top: var(--sp-2); }

/* ============================================================
   Motion
   ============================================================ */
@keyframes rise { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }
@keyframes pop { from { opacity: 0; transform: scale(0.96) translateY(6px); } to { opacity: 1; transform: none; } }
.hero { animation: rise 0.5s ease both; }
.kurs { animation: rise 0.5s ease both; animation-delay: 0.06s; }
.panel { animation: rise 0.4s ease both; }
.login-split { animation: pop 0.45s cubic-bezier(0.2, 0.7, 0.2, 1) both; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.001ms !important; transition-duration: 0.001ms !important; }
}

/* ============================================================
   Responsive
   ============================================================ */
@media (max-width: 880px) {
  .lesson-layout { grid-template-columns: 1fr; }
  .instructions { position: static; }
  .editor { max-height: none; }
  .login-split { grid-template-columns: 1fr; max-width: 440px; }
  .login-aside { display: none; }
  .admin-create { flex-direction: column; align-items: stretch; }
}
@media (max-width: 600px) {
  .container { padding: var(--sp-5) var(--sp-4) var(--sp-8); }
  .topbar { padding: var(--sp-3) var(--sp-4); }
  .topbar-right { gap: var(--sp-1); }
  /* Hide the least essential chips so the bar never overflows. */
  .progress-chip, .user-chip { display: none; }
  .admin-table { display: block; overflow-x: auto; }
}

/* ============================================================
   IDE (VS-Code-style: explorer, tabs, editor, panels, statusbar)
   ============================================================ */
.ide-page { display: flex; flex-direction: column; height: calc(100dvh - 58px); min-height: 420px; }
/* Code-UI exakt fensterhoch halten: die Seite selbst scrollt NICHT (kein Höhen-
   Rechenfehler mit der Topbar mehr), nur die Panels innen scrollen. Greift nur,
   wenn die IDE angezeigt wird. */
.app:has(.ide-page) { height: 100dvh; display: flex; flex-direction: column; overflow: hidden; }
.app:has(.ide-page) .ide-page { flex: 1 1 auto; height: auto; min-height: 0; }
.ide-shell { flex: 1; display: grid; grid-template-columns: 230px 1fr; min-height: 0; }

.ide-sidebar { display: flex; flex-direction: column; min-height: 0; border-right: 1px solid var(--border); background: var(--surface); }
.ide-sidebar-head {
  display: flex; align-items: center; gap: var(--sp-2); padding: 8px 10px 8px 14px;
  font-family: var(--font-mono); font-size: 11px; font-weight: 600; letter-spacing: 0.1em;
  text-transform: uppercase; color: var(--text-muted); border-bottom: 1px solid var(--border);
}
.ide-tree { flex: 1; overflow: auto; padding: 6px 0; }
.ide-item {
  display: flex; align-items: center; gap: 7px; padding: 4px 8px; cursor: pointer;
  font-size: 13.5px; color: var(--text); border-left: 2px solid transparent;
}
.ide-item .icon { color: var(--text-muted); flex: 0 0 auto; }
.ide-item:hover { background: var(--surface-2); }
.ide-item.is-active { background: var(--primary-weak); border-left-color: var(--primary); }
.ide-item-name { flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ide-dir { cursor: default; color: var(--text-muted); font-weight: 600; }
.ide-item-action {
  border: 0; background: transparent; color: var(--text-muted); cursor: pointer;
  font-size: 12px; padding: 0 3px; border-radius: var(--radius-sm); visibility: hidden;
}
.ide-item:hover .ide-item-action { visibility: visible; }
.ide-item-action:hover { color: var(--text); background: var(--surface); }

/* Inline "New File"/"New Folder" name input in the tree (VS-Code style) */
.ide-new-row { cursor: default; }
.ide-new-input {
  flex: 1; min-width: 0; padding: 2px 6px; font-size: 13px; font-family: var(--font-sans);
  color: var(--text); background: var(--bg); outline: none;
  border: 1px solid var(--primary); border-radius: var(--radius-sm); box-shadow: var(--ring);
}

/* Live GUI (tkinter im Browser via Pyodide) — eigenes, verschiebbares Fenster */
.ide-gui-window {
  position: fixed; z-index: 80; top: 110px; left: 34%;
  display: flex; flex-direction: column; overflow: hidden;
  min-width: 160px; max-width: 94vw; max-height: 88vh;
  background: var(--surface-2); border: 1px solid var(--border-strong);
  border-radius: 6px; box-shadow: 0 12px 34px rgba(0, 0, 0, 0.45);
}
/* display:flex oben würde das hidden-Attribut aushebeln -> explizit ausblenden */
.ide-gui-window[hidden] { display: none; }
.ide-gui-titlebar {
  display: flex; align-items: center; gap: 8px; cursor: move; user-select: none;
  padding: 5px 8px; background: var(--surface); border-bottom: 1px solid var(--border);
}
.ide-gui-wtitle {
  flex: 1; font-size: 13px; font-weight: 600; color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ide-gui-wclose {
  border: 0; background: transparent; color: var(--text-muted); cursor: pointer;
  font-size: 17px; line-height: 1; padding: 0 5px; border-radius: 3px;
}
.ide-gui-wclose:hover { background: var(--danger); color: #fff; }
.ide-gui-wbody { position: relative; width: 320px; height: 360px; background: #f3f3f3; resize: both; overflow: hidden; }
/* A turtle drawing in the same floating window a tkinter program gets (2026-08-07). It
   used to render inside the terminal panel, where a picture sits among lines of text and
   pushes the output it belongs to off screen. */
.ide-gui-bild { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; background: #fff; overflow: auto; }
.ide-gui-bild[hidden] { display: none; }
.ide-gui-zeichnung { max-width: 100%; max-height: 100%; }
.ide-gui-frame { width: 100%; height: 100%; border: 0; display: block; background: #f3f3f3; }
.ide-gui-boot {
  position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
  padding: 12px; text-align: center; color: #555; font-size: 13px; background: #f3f3f3;
}
/* display:flex würde das hidden-Attribut aushebeln -> Lade-Overlay sonst nie weg */
.ide-gui-boot[hidden] { display: none; }
.ide-gui-wfoot { max-height: 120px; overflow: auto; padding: 4px 8px; border-top: 1px solid var(--border); }
.ide-gui-out { margin: 0; font-size: 12px; }
.ide-gui-out.has-error { color: var(--danger); }

/* Explorer right-click context menu */
.ide-ctx {
  position: fixed; z-index: 60; min-width: 172px; padding: 4px;
  background: var(--surface-2); border: 1px solid var(--border-strong);
  border-radius: var(--radius); box-shadow: var(--shadow);
}
.ide-ctx-item {
  padding: 7px 12px; font-size: 13px; color: var(--text); white-space: nowrap;
  border-radius: var(--radius-sm); cursor: pointer;
}
.ide-ctx-item:hover { background: var(--primary); color: var(--primary-contrast); }
.ide-ctx-sep { height: 1px; background: var(--border); margin: 4px 6px; }

.ide-main { display: flex; flex-direction: column; min-width: 0; min-height: 0; }
.ide-toolbar { position: relative; display: flex; align-items: center; gap: var(--sp-2); border-bottom: 1px solid var(--border); background: var(--surface); padding: 6px var(--sp-2) 6px 0; min-height: 44px; }

/* Editor settings popover — removed 2026-08-11 with the gear icon. */

/* Saved/unsaved indicator in the toolbar */
.ide-saved-state {
  display: inline-flex; align-items: center; gap: 6px; flex: 0 0 auto;
  font-size: 12px; font-weight: 600; padding: 3px 10px; border-radius: 999px;
  border: 1px solid transparent; white-space: nowrap;
}
.ide-saved-dot { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; }
.ide-saved-state.is-clean { color: var(--success); background: var(--success-weak); }
.ide-saved-state.is-clean .ide-saved-dot { background: var(--success); }
.ide-saved-state.is-dirty { color: var(--warning); background: var(--warning-weak); border-color: var(--warning); }
.ide-saved-state.is-dirty .ide-saved-dot { background: var(--warning); }

.ide-tabs { display: flex; align-items: stretch; overflow-x: auto; min-width: 0; }
.ide-tab {
  display: flex; align-items: center; gap: 7px; padding: 9px 10px 9px 14px; cursor: pointer;
  font-size: 13px; color: var(--text-muted); border-right: 1px solid var(--border);
  border-top: 2px solid transparent; white-space: nowrap;
}
.ide-tab.is-active { color: var(--text); background: var(--bg); border-top-color: var(--primary); }
.ide-dirty { color: var(--accent); font-size: 10px; }
.ide-tab-close { border: 0; background: transparent; color: var(--text-muted); cursor: pointer; font-size: 15px; line-height: 1; padding: 0 2px; border-radius: var(--radius-sm); }
.ide-tab-close:hover { color: var(--danger); background: var(--surface-2); }

.ide-editor { flex: 1; display: flex; min-height: 0; background: var(--surface); position: relative; }
.ide-gutter {
  flex: 0 0 auto; min-width: 56px; overflow: hidden; padding: var(--sp-3) 0; text-align: right;
  font-family: var(--font-mono); font-size: 13.5px; line-height: 1.7; user-select: none;
  color: var(--text-muted); background: var(--surface-2); border-right: 1px solid var(--border);
}
.ide-gutter-line { display: flex; align-items: center; justify-content: flex-end; gap: 5px; padding: 0 8px 0 4px; cursor: pointer; opacity: 0.65; }
.ide-gutter-line:hover { opacity: 1; background: var(--surface); }
.ide-bp-dot { width: 9px; height: 9px; border-radius: 50%; background: transparent; flex: 0 0 auto; }
.ide-gutter-line:hover .ide-bp-dot { background: var(--danger-weak); }
.ide-gutter-line.has-bp { opacity: 1; }
.ide-gutter-line.has-bp .ide-bp-dot { background: var(--danger); }
.ide-gutter-line.is-exec { opacity: 1; background: var(--warning-weak); color: var(--warning); font-weight: 700; }
.ide-gutter-line.is-exec .ide-gutter-num::after { content: "\25B6"; margin-left: 4px; font-size: 9px; }
.ide-exec-overlay {
  position: absolute; pointer-events: none; z-index: 0;
  background: var(--warning-weak); border-left: 2px solid var(--warning);
}
.ide-gutter-line.is-error { opacity: 1; background: var(--danger-weak); color: var(--danger); font-weight: 700; }
.ide-gutter-line.is-error .ide-gutter-num::after { content: "\26A0"; margin-left: 4px; font-size: 9px; }
/* ---- the teacher's remarks, in the pupil's own gutter ----
   A marker beside the line number rather than a card wedged between the lines: the
   editor is a textarea with an overlay, so anything inserted between two lines would
   break the alignment of every line under it. Clicking the marker opens the note. */
.ide-gutter-line.has-anm { opacity: 1; }
.ide-anm-marke {
  flex: 0 0 auto; width: 15px; height: 15px; padding: 0; margin-left: 2px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 0; border-radius: 4px; cursor: pointer;
  background: var(--primary-weak); color: var(--primary);
  font-family: var(--font-mono); font-size: 10px; font-weight: 700; line-height: 1;
}
.ide-anm-marke:hover { background: var(--primary); color: var(--on-grad); }
.ide-anm-marke:focus-visible { outline: 2px solid var(--primary); outline-offset: 1px; }
.ide-anm-karte {
  position: absolute; z-index: 6; max-width: min(520px, 70%);
  background: var(--surface); border: 1px solid var(--primary);
  border-radius: var(--radius); box-shadow: var(--shadow-sm);
  padding: var(--sp-2); display: flex; flex-direction: column; gap: var(--sp-2);
}
.ide-anm-eintrag { display: flex; flex-direction: column; gap: 3px; }
.ide-anm-eintrag + .ide-anm-eintrag { border-top: 1px solid var(--border); padding-top: var(--sp-2); }
/* Stacked, not side by side: "show hidden again" and "hide all" are opposites, and a
   row of two ghost buttons reads as one control with two halves. */
.ide-anm-aktionen { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; }
.ide-anm-weg {
  margin-left: auto; width: 20px; height: 20px; padding: 0; flex: 0 0 auto;
  background: transparent; border: 0; border-radius: 4px; cursor: pointer;
  color: var(--text-muted); font-size: 15px; line-height: 1;
}
.ide-anm-weg:hover { background: var(--surface-2); color: var(--text); }

.ide-error-overlay {
  position: absolute; pointer-events: none; z-index: 0;
  background: var(--danger-weak); border-left: 2px solid var(--danger);
}
/* Live-collaboration: remote cursors float above the text, click-through. */
.ide-cursors { position: absolute; inset: 0; pointer-events: none; z-index: 4; overflow: hidden; }
.ide-rcursor { position: absolute; width: 2px; }
.ide-rcursor-label {
  position: absolute; top: -15px; left: -1px; white-space: nowrap;
  font: 600 10px/1.4 var(--font-sans); color: #fff; padding: 0 4px; border-radius: 3px 3px 3px 0;
  pointer-events: none; opacity: 0.92;
}
/* Presence strip in the toolbar (who's editing live). */
.ide-collab-bar { display: flex; align-items: center; gap: 8px; font-size: 12px; color: var(--text-muted); }
.ide-collab-live { color: var(--primary); font-weight: 600; }
/* The same strip once collaboration has stopped for good. Muted rather than red:
   it is a state, not an error, and the title attribute carries what to do next. */
.ide-collab-tot { color: var(--text-muted); font-weight: 600; cursor: help; }
.ide-collab-peer { display: inline-flex; align-items: center; gap: 4px; }
.ide-collab-dot { width: 9px; height: 9px; border-radius: 50%; display: inline-block; }
.ide-code {
  flex: 1; resize: none; border: 0; outline: none; padding: var(--sp-3) var(--sp-4);
  font-family: var(--font-mono); font-size: 13.5px; line-height: 1.7; tab-size: 4;
  /* transparent text so the exec-line overlay AND the coloured highlight layer
     show through behind the caret; the wrapper (.ide-editor) provides the surface. */
  background: transparent; position: relative; z-index: 1;
  color: transparent; white-space: pre; overflow: auto;
  caret-color: var(--primary);
}
.ide-code:focus { box-shadow: none; }
/* IDE highlight layer: above the exec/error tints (z 0, later in DOM), below the
   textarea (z 1). Position/size are set in JS to match the textarea box. */
.ide-hl { position: absolute; z-index: 0; padding: var(--sp-3) var(--sp-4); font-size: 13.5px; line-height: 1.7; }
.ide-empty { flex: 1; display: flex; align-items: center; justify-content: center; color: var(--text-muted); }

/* min-height 130 -> 160 (2026-08-07): the panel holds the output AND, while a program is
   running, the line you type into. The separate Eingabe box that briefly pushed this to
   190px is gone again — the terminal took over its job. */
.ide-panel { flex: 0 0 32%; display: flex; flex-direction: column; min-height: 160px; border-top: 1px solid var(--border); background: var(--surface); }
.ide-panel-head { display: flex; align-items: center; gap: var(--sp-2); border-bottom: 1px solid var(--border); background: var(--surface-2); padding-right: var(--sp-2); }
.ide-panel-tabs { display: flex; }
.ide-panel-tab {
  border: 0; background: transparent; cursor: pointer; padding: 7px 12px;
  font-family: var(--font-mono); font-size: 11px; font-weight: 600; letter-spacing: 0.08em;
  text-transform: uppercase; color: var(--text-muted); border-bottom: 2px solid transparent;
}
.ide-panel-tab.is-active { color: var(--text); border-bottom-color: var(--primary); }
.ide-panel-body { flex: 1; overflow: auto; padding: var(--sp-2) var(--sp-3); }

/* Shown above the traceback when a run died on EOFError. Since „Ausführen" became live
   that only happens while DEBUGGING, which replays a recording and cannot ask anyone.
   A left rule instead of a coloured box — this is a hint, not an alarm. */
.ide-eingabe-hinweis {
  display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap;
  margin: 0 0 var(--sp-2); padding: var(--sp-2) var(--sp-3);
  border-left: 2px solid var(--warning); background: var(--surface-2);
  font-size: 13px; line-height: 1.5;
}
.ide-eingabe-hinweis > span { flex: 1; min-width: 220px; }

/* The line you type into while a program is running — the terminal half of `input()`.
   Deliberately not a boxed form field: it should read as the next line of the terminal,
   which is why it has no border and inherits the output's monospace. */
.ide-tin-zeile { display: flex; align-items: center; gap: var(--sp-2); padding: 2px 0 4px; }
.ide-tin-pfeil { font-family: var(--font-mono); font-size: 12px; color: var(--primary); }
.ide-tin {
  flex: 1; min-width: 0; border: 0; background: transparent; outline: none;
  font-family: var(--font-mono); font-size: 12px; color: var(--text); padding: 2px 0;
}
.ide-tin::placeholder { color: var(--text-muted); opacity: 0.7; }
/* The whole transcript is one <pre>; the pieces inside are spans, so a prompt without a
   trailing newline keeps the answer on its own line. */
.ide-term { white-space: pre-wrap; }
.ide-term > span { white-space: pre-wrap; }
/* What the pupil typed, echoed back. Coloured, so a transcript reads back as a
   conversation: their lines and the program's lines are told apart at a glance. */
.ide-out-in { color: var(--primary); }
.ide-panel-hint { color: var(--text-muted); font-size: 13px; padding: var(--sp-2); }
.ide-out { margin: 0 0 4px; font-family: var(--font-mono); font-size: 13px; line-height: 1.6; white-space: pre-wrap; word-break: break-word; color: var(--text); }
.ide-out-err { color: var(--danger); }
.ide-out-dim { color: var(--text-muted); }
.ide-local-run { margin-top: var(--sp-2); padding: var(--sp-3); border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface-2); }
.ide-local-run-text { margin: 0 0 var(--sp-2); font-size: 13px; color: var(--text-muted); line-height: 1.5; }
.ide-local-run-btns { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-3); }
.ide-local-pylink { background: none; border: none; padding: 0; font-size: 12px; color: var(--text-muted); text-decoration: underline; cursor: pointer; }
.ide-local-pylink:hover { color: var(--text); }

.ide-debug-snap { border: 1px solid var(--border); border-radius: var(--radius); margin-bottom: var(--sp-2); overflow: hidden; }
.ide-debug-head { display: flex; align-items: center; gap: var(--sp-3); padding: 5px 10px; background: var(--surface-2); font-family: var(--font-mono); font-size: 12px; border-radius: var(--radius); margin-bottom: var(--sp-2); }
.ide-debug-hit { font-weight: 700; color: var(--danger); }
.ide-debug-loc { font-weight: 600; }
.ide-debug-func { color: var(--text-muted); }
.ide-debug-nav { display: flex; align-items: center; gap: 6px; margin-bottom: var(--sp-2); flex-wrap: wrap; }
.ide-step-btn { font-family: var(--font-mono); min-width: 34px; padding: 4px 8px; }
.ide-debug-pos { font-family: var(--font-mono); font-size: 12px; color: var(--text-muted); margin: 0 6px; white-space: nowrap; }
.ide-debug-vars { display: flex; flex-wrap: wrap; gap: 6px; padding: 8px 10px; }
.ide-var.is-changed { border-color: var(--primary); background: var(--primary-weak); }
.ide-var.is-changed .ide-var-value { color: var(--primary); font-weight: 700; }
.ide-debug-stack {
  display: flex; flex-wrap: wrap; align-items: center; gap: 2px;
  padding: 4px 10px; font-family: var(--font-mono); font-size: 12px; color: var(--text-muted);
}
.ide-stack-sep { color: var(--text-muted); opacity: 0.6; }
.ide-stack-frame.is-current { color: var(--text); font-weight: 700; }
.ide-debug-output { margin-top: var(--sp-2); }
.ide-debug-output-label {
  font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--text-muted); padding: 0 2px var(--sp-1);
}
.ide-debug-output pre {
  margin: 0; padding: 8px 10px; background: var(--surface-2);
  border: 1px solid var(--border); border-radius: var(--radius);
}
.ide-debug-error {
  margin-top: var(--sp-2); border: 1px solid var(--danger); border-radius: var(--radius);
  background: var(--danger-weak); overflow: hidden;
}
.ide-debug-error-title { padding: 7px 10px; font-size: 12.5px; font-weight: 600; color: var(--danger); }
.ide-debug-error pre { margin: 0; padding: 8px 10px; border-top: 1px solid var(--danger); }
.ide-var { font-family: var(--font-mono); font-size: 12.5px; background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius-sm); padding: 2px 8px; }
.ide-var-name { color: var(--primary); }
.ide-var-value { color: var(--text); }

.ide-statusbar {
  display: flex; align-items: center; gap: var(--sp-4); padding: 4px 12px;
  background: var(--primary); color: var(--on-grad); font-family: var(--font-mono); font-size: 12px;
}
.ide-statusbar .spacer { flex: 1; }
.ide-status-brand { display: inline-flex; align-items: center; gap: 6px; font-weight: 600; }

@media (max-width: 880px) {
  .ide-shell { grid-template-columns: 170px 1fr; }
}

/* ============================================================
   KI-Tutor page — shortcut + setup (the chat lives in the editor)
   ============================================================ */
.tutor-wrap { display: flex; flex-direction: column; }

/* The shortcut, printed large because it IS the feature: this page tells you how to
   reach the assistant, it is not a place to talk to it. Keycap look (mono, thicker
   bottom edge) rather than anything glowing — the convention every dev tool uses. */
.ki-kuerzel-karte { padding: var(--sp-4) var(--sp-5); margin-bottom: var(--sp-4); }
.ki-kuerzel-titel { margin: 0 0 var(--sp-2); font-size: 16px; }
.ki-kuerzel-schritte {
  margin: 0; padding-left: var(--sp-4); display: flex; flex-direction: column; gap: 6px;
  font-size: 14px; color: var(--text);
}
/* Taste und Meldung nebeneinander: eine Absage erklärt genau die Taste, die eben nicht
   angenommen wurde — als Fußnote unter den Knöpfen wird sie nicht gelesen. */
.ki-kuerzel-zeile {
  display: flex; align-items: center; gap: var(--sp-4); flex-wrap: wrap;
  margin: var(--sp-4) 0 var(--sp-3);
}
.ki-kuerzel-gross {
  display: inline-block; flex: 0 0 auto;
  font-family: var(--font-mono); font-size: 34px; font-weight: 600; line-height: 1.1;
  color: var(--text); background: var(--surface-2);
  border: 1px solid var(--border-strong); border-bottom-width: 3px;
  border-radius: var(--radius); padding: 10px 22px;
}
.ki-kuerzel-gross.is-fangen {
  color: var(--text-muted); border-style: dashed; border-bottom-width: 1px; font-size: 26px;
}
.ki-kuerzel-aktionen { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.ki-kuerzel-aktionen .icon { width: 15px; height: 15px; }
.ki-kuerzel-hinweis {
  margin: 0; flex: 1 1 260px; min-width: 0;
  font-size: 13px; line-height: 1.5; color: var(--text-muted);
}
.ki-kuerzel-hinweis.is-fehler {
  display: flex; align-items: flex-start; gap: 10px;
  font-size: 17px; font-weight: 600; line-height: 1.4; color: var(--danger);
}
.ki-kuerzel-hinweis.is-fehler .icon { width: 18px; height: 18px; flex: 0 0 auto; margin-top: 3px; }
@media (max-width: 600px) {
  .ki-kuerzel-gross { font-size: 26px; padding: 8px 16px; }
  .ki-kuerzel-hinweis.is-fehler { font-size: 15px; }
}

/* Leftovers of the removed chat — only rendered when there is something to remove. */
.ki-alte-chats {
  display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap;
  margin-top: var(--sp-4); font-size: 13px; color: var(--text-muted);
}
.ki-alte-chats .icon { width: 14px; height: 14px; }

/* Eingerichtet = ein großer grüner Haken, sonst nichts. Kein Leuchten, kein Rahmen um
   den Haken — die Größe trägt die Aussage. */
.tutor-bereit {
  display: flex; align-items: center; gap: var(--sp-4);
  padding: var(--sp-5); margin-bottom: var(--sp-4);
}
.tutor-haken { flex: 0 0 auto; display: inline-flex; color: var(--success); }
.tutor-haken .icon { width: 44px; height: 44px; stroke-width: 2.5; }
.tutor-bereit-titel { font-size: 19px; }
.tutor-bereit-text { margin: 4px 0 0; font-size: 13.5px; color: var(--text-muted); }

/* One-time setup card with the launcher download button */
.tutor-setup { margin-bottom: var(--sp-4); padding: var(--sp-4) var(--sp-5); }
.tutor-setup-title { margin: 0 0 var(--sp-2); font-size: 16px; }
.tutor-setup-steps { margin: 0 0 var(--sp-3); padding-left: var(--sp-4); display: flex; flex-direction: column; gap: 6px; font-size: 14px; color: var(--text); }
.tutor-setup-actions { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.tutor-setup-actions .icon { width: 15px; height: 15px; }
.tutor-setup-status { font-size: 13px; color: var(--text-muted); }
.tutor-setup-hint { margin: var(--sp-3) 0 0; font-size: 12.5px; color: var(--text-muted); }
.tutor-prog { margin-top: var(--sp-3); display: flex; align-items: center; gap: var(--sp-2); }
.tutor-prog-track { flex: 1; height: 8px; background: var(--surface-2); border: 1px solid var(--border); border-radius: 999px; overflow: hidden; }
.tutor-prog-fill { height: 100%; width: 0; background: var(--success); transition: width 0.2s ease; }
.tutor-prog-label { font-size: 12.5px; color: var(--text-muted); white-space: nowrap; min-width: 110px; }
.tutor-waiting { display: flex; align-items: center; gap: 8px; margin-top: var(--sp-3); font-size: 13px; color: var(--text-muted); }
.tutor-ready { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; margin-top: var(--sp-3); font-size: 13px; color: var(--success); }
.tutor-ready .icon { width: 15px; height: 15px; }
.tutor-spin {
  width: 14px; height: 14px; flex: 0 0 auto; border-radius: 50%;
  border: 2px solid var(--border-strong); border-top-color: var(--success);
  animation: tutor-spin 0.8s linear infinite;
}
@keyframes tutor-spin { to { transform: rotate(1turn); } }
@media (prefers-reduced-motion: reduce) { .tutor-spin { animation-duration: 2s; } }

/* Kopfbereich mit großem Maskottchen auf seiner dunklen Bühne. */
.tutor-hero { display: flex; align-items: center; gap: var(--sp-4); margin: var(--sp-2) 0 var(--sp-4); }
.tutor-hero-text { min-width: 0; }
.tutor-hero .page-title { margin: 0; }
.tutor-hero .hero-sub { margin: 4px 0 0; }
.tutor-mascot {
  flex: 0 0 auto; width: 150px; border-radius: var(--radius-lg); overflow: hidden;
  border: 1px solid var(--border);
}
.tutor-mascot .mascot { width: 100%; height: auto; }
@media (max-width: 600px) {
  .tutor-mascot { width: 104px; }
}

/* Text, der die Seite nicht verlassen soll (Ayden, 2026-08-08): der Aufgabentext,
   damit er nicht in einem Chatfenster landet, und die KI-Antwort, damit ihr Code nicht
   als „eigene Kopie" in die Übung zurückwandert. Das ist eine Hürde, keine Sperre: wer
   die Entwicklerwerkzeuge öffnet, liest beides trotzdem. Screenreader sind NICHT
   betroffen, `user-select` gilt nur für die Maus-/Tastaturauswahl. */
.kein-kopieren { user-select: none; -webkit-user-select: none; }

/* Hinweis, wenn ein Einfügen von außerhalb abgelehnt wurde. Sitzt oben mittig im
   Editor, verschwindet von selbst — zurückhaltend, kein Alarm. */
.ide-paste-hinweis {
  position: absolute; top: 8px; left: 50%; transform: translateX(-50%); z-index: 4;
  display: flex; align-items: center; gap: 8px; max-width: min(560px, 92%);
  padding: 8px 12px; font-size: 12.5px; line-height: 1.45;
  color: var(--text); background: var(--surface-2);
  border: 1px solid var(--border-strong); border-left: 3px solid var(--danger);
  border-radius: var(--radius-sm); box-shadow: var(--shadow-lg);
}
.ide-paste-hinweis .icon { width: 14px; height: 14px; flex: 0 0 auto; color: var(--danger); }

/* ---- IDE: lesson task panel + local folder ---- */
.ide-shell.ide-with-task { grid-template-columns: 210px 1fr 320px; }
.ide-task {
  position: relative; /* Bezug für das aufsitzende Maskottchen */
  display: flex; flex-direction: column; gap: var(--sp-3); min-height: 0; overflow-y: auto;
  border-left: 1px solid var(--border); background: var(--surface); padding: var(--sp-4);
}
.ide-task-title { font-family: var(--font-display); font-size: 20px; font-weight: 600; letter-spacing: -0.01em; }

/* Maskottchen sitzt oben rechts auf der Aufgabe — transparenter Sprite, klick-durchlässig. */
.task-mascot { position: absolute; top: 4px; right: 8px; width: 56px; z-index: 3; }
.instr-mascot { position: absolute; top: 6px; right: 6px; width: 56px; z-index: 3; }

/* ---- Hilfe-Center (Modal mit Rundgang-Liste) ---- */
/* Bei vielen Rundgängen (Admin sieht zusätzlich die 6 Verwaltungs-Reiter) wird die
   Liste höher als der Bildschirm. Deshalb scrollt der Inhalt IM Fenster statt im
   Hintergrund. `overscroll-behavior: contain` verhindert, dass die Scroll-Geste am
   Listenende auf die Seite dahinter durchschlägt. */
.help-card {
  width: min(460px, calc(100vw - 32px));
  max-height: calc(100dvh - 2 * var(--sp-4));
  overflow-y: auto;
  overscroll-behavior: contain;
}
.help-head { font-family: var(--font-pixel); font-size: 12px; color: var(--text-muted); letter-spacing: 0.04em; margin: var(--sp-4) 0 var(--sp-2); }
.help-list { display: flex; flex-direction: column; gap: var(--sp-2); }
.help-item {
  display: flex; align-items: center; gap: var(--sp-3); width: 100%; text-align: left;
  padding: 10px 12px; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface-2); color: var(--text); cursor: pointer; font: inherit;
}
.help-item:hover { border-color: var(--primary); background: var(--surface); }
.help-item .icon { color: var(--accent); flex: 0 0 auto; }
.help-item-label { flex: 1; min-width: 0; }
.help-item-go { flex: 0 0 auto; font-size: 12.5px; font-weight: 600; color: var(--accent); }

/* ---- Interaktiver Rundgang (Coach-Marks) ---- */
.tour-overlay { position: fixed; inset: 0; z-index: 2000; pointer-events: auto; }
/* Scheinwerfer: transparentes Rechteck, drumherum dunkel (per box-shadow). */
.tour-spot {
  position: fixed; pointer-events: none; border-radius: var(--radius-sm);
  border: 2px solid var(--primary);
  box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.62);
  transition: left 0.22s ease, top 0.22s ease, width 0.22s ease, height 0.22s ease;
}
.tour-pop {
  position: fixed; pointer-events: auto; width: min(360px, calc(100vw - 24px));
  background: var(--surface); border: 1px solid var(--border-strong);
  border-radius: var(--radius); box-shadow: var(--shadow-lg);
  padding: var(--sp-4); z-index: 1;
  transition: left 0.22s ease, top 0.22s ease;
}
.tour-titel { font-family: var(--font-pixel); font-size: 15px; color: var(--accent); margin: 0 0 6px; letter-spacing: 0.02em; }
.tour-text { font-size: 14px; line-height: 1.55; color: var(--text); margin: 0; }
.tour-foot { display: flex; align-items: center; gap: var(--sp-2); margin-top: var(--sp-3); flex-wrap: nowrap; }
.tour-foot .spacer { flex: 1; }
.tour-foot .btn { white-space: nowrap; }
.tour-zaehler { font-family: var(--font-pixel); font-size: 11px; color: var(--text-muted); white-space: nowrap; flex: 0 0 auto; }
.tour-zurueck[disabled] { opacity: 0.4; pointer-events: none; }
/* Pfeil, der von der Sprechblase zum Ziel zeigt (Farbe = Blasenhintergrund). */
.tour-pfeil { position: absolute; width: 0; height: 0; }
.tour-pfeil-oben { top: -9px; transform: translateX(-50%); border-left: 9px solid transparent; border-right: 9px solid transparent; border-bottom: 9px solid var(--surface); }
.tour-pfeil-unten { bottom: -9px; transform: translateX(-50%); border-left: 9px solid transparent; border-right: 9px solid transparent; border-top: 9px solid var(--surface); }
.tour-pfeil-links { left: -9px; transform: translateY(-50%); border-top: 9px solid transparent; border-bottom: 9px solid transparent; border-right: 9px solid var(--surface); }
.tour-pfeil-rechts { right: -9px; transform: translateY(-50%); border-top: 9px solid transparent; border-bottom: 9px solid transparent; border-left: 9px solid var(--surface); }
.tour-ohne-animation .tour-spot, .tour-ohne-animation .tour-pop { transition: none; }
.ide-task-desc { font-size: 14px; line-height: 1.6; white-space: pre-wrap; }
/* Submit, plus the "Nächste Lektion" button that joins it after a correct submission. */
.ide-task-actions { margin-top: var(--sp-2); display: flex; flex-direction: column; gap: var(--sp-2); }
.ide-next-hint { font-size: 12px; color: var(--text-muted); text-align: center; margin-top: calc(var(--sp-2) * -1); }
.ide-task-result { display: flex; flex-direction: column; gap: var(--sp-2); }
.ide-task-result .out-body { max-height: 150px; }

/* ---- Aufgaben (teacher-graded assignments) ------------------------------
   Flat status pills and plain cards, in the dev-tool register the rest of the app
   uses — no glow, no animated borders; the state is the only colour. */
/* align-items: center, because a flex item defaults to STRETCH: any taller sibling
   (a paragraph-styled label with margins, say) makes the pill-shaped badge grow to
   the full line height, and with border-radius 999px that turns it into a bubble.
   Measured: badge 48px next to a 24px label with 8/16 margins, 24px once centred. */
.ide-task-meta {
  display: flex; flex-wrap: wrap; align-items: center;
  gap: var(--sp-1); margin-bottom: var(--sp-2);
}
.ide-badge {
  display: inline-flex; align-items: center; gap: 4px;
  font-size: 11.5px; font-weight: 600; padding: 2px 8px; border-radius: 999px;
  border: 1px solid var(--border); color: var(--text-muted); background: var(--surface-2);
}
.ide-badge-ok { color: var(--success); background: var(--success-weak); border-color: var(--success); }
.ide-badge-warn { color: var(--warning); background: var(--warning-weak); border-color: var(--warning); }
.ide-badge-info { color: var(--text); background: var(--surface-2); border-color: var(--border-strong); }
.ide-badge-dim { opacity: 0.75; }
.ide-frist { display: inline-flex; align-items: center; gap: 4px; font-size: 11.5px; color: var(--text-muted); padding: 2px 4px; }
.ide-frist-warn { color: var(--warning); }
.ide-task-hint { font-size: 11.5px; color: var(--text-muted); line-height: 1.5; margin: 0; }
.ide-abgabe-info { font-size: 12px; color: var(--text-muted); display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
.ide-remarks-title { font-size: 13px; margin: var(--sp-2) 0 0; }
.ide-remark { border: 1px solid var(--border); border-radius: var(--radius); padding: var(--sp-2); background: var(--surface); }
.ide-remark-head { display: flex; gap: var(--sp-1); font-size: 11px; color: var(--text-muted); margin-bottom: 4px; }
.ide-remark-where { font-family: var(--font-mono); }
.ide-remark-who { margin-left: auto; }
.ide-remark-text { margin: 0; font-size: 13px; line-height: 1.55; white-space: pre-wrap; }

/* Dashboard section „Deine Aufgaben" */
.aufgaben-card { border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface); overflow: hidden; }
.aufgaben-head { display: flex; align-items: center; gap: var(--sp-1); padding: var(--sp-2) var(--sp-3); border-bottom: 1px solid var(--border); }
.aufgaben-head h2 { font-size: 15px; margin: 0; }
.aufgaben-count { margin-left: auto; font-size: 12px; color: var(--text-muted); }
.aufgaben-body { display: flex; flex-direction: column; }
.aufgabe-row {
  display: flex; align-items: center; gap: var(--sp-2); width: 100%;
  padding: var(--sp-2) var(--sp-3); background: none; border: 0; border-top: 1px solid var(--border);
  color: inherit; text-align: left; cursor: pointer; font: inherit;
}
.aufgabe-row:first-child { border-top: 0; }
.aufgabe-row:hover { background: var(--surface-2); }
.aufgabe-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.aufgabe-title { font-weight: 600; font-size: 14px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.aufgabe-sub { font-size: 11.5px; color: var(--text-muted); }
/* Group work and solo work as two labelled blocks in one card. A quiet section label,
   not a second card: the split exists to order the list, not to add furniture. */
.aufgaben-gruppe-titel {
  display: flex; align-items: center; gap: var(--sp-1);
  margin: 0; padding: var(--sp-2) var(--sp-3) 4px;
  font-size: 11px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase;
  color: var(--text-muted); border-top: 1px solid var(--border);
}
.aufgaben-gruppe-titel:first-child { border-top: 0; }
/* The heading already draws the separator; the row under it must not draw a second. */
.aufgaben-gruppe-titel + .aufgabe-row { border-top: 0; }

/* ---- Verwaltung → Aufgaben ---- */
.auf-ziele { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3); }
/* Group targets are one full-width column of checkboxes grouped by Themenbereich —
   there is no second picker beside them, so the two-column grid above does not apply. */
.auf-ziele:has(.auf-ziel-spalte--gruppen) { grid-template-columns: 1fr; }
/* One embedded picker: a bordered, tinted control whose list scrolls internally, so a
   school with thirty classes or groups cannot push the deadline and the "austeilen"
   button off the screen. Used by the class picker and the group picker alike. */
.auf-auswahl-box {
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface-2);
  max-height: 260px; overflow-y: auto;
}
/* The search rides along at the top of the scroll area instead of sitting above the box:
   scrolled content passes UNDER it, so it is still there at entry 40. It needs its own
   opaque background for that — a transparent sticky header shows the rows through it. */
.auf-auswahl-kopf {
  position: sticky; top: 0; z-index: 1;
  display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap;
  padding: var(--sp-2) var(--sp-3);
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
}
.auf-auswahl-kopf .input {
  flex: 1 1 200px; min-width: 0; padding: 6px 10px; font-size: 13px;
}
.auf-auswahl-liste { padding: var(--sp-2) var(--sp-3); }
.auf-gruppen-thema + .auf-gruppen-thema { margin-top: var(--sp-3); }
.auf-gruppen-thema-name {
  margin: 0 0 2px; font-size: 11px; font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; color: var(--text-muted);
}
.auf-gruppe-leer { margin-left: var(--sp-1); }
.auf-ziel-spalte h4 { font-size: 12px; margin: 0 0 4px; color: var(--text-muted); }
/* NO scrolling on the column itself. Each of its three variants holds a control that
   scrolls internally (the class box, the group box, the pupil result list), and a
   scrolling column around a scrolling box gives you two bars side by side — the outer
   one moving barely 18px, which is what Ayden pointed at. The wheel would also
   stop in whichever one the pointer happened to be over. */
.auf-ziel-spalte { padding-right: var(--sp-1); }
.auf-ziel { height: auto; padding: 3px 0; }
.auf-klassen-liste { display: flex; flex-direction: column; gap: 2px; }

/* Individual pupils: search → results → chips. Only the result list scrolls, so the
   chosen names stay visible while searching — otherwise you lose sight of who you
   already picked. (The column-level cap this used to undo is gone; see above.) */
.auf-treffer {
  display: flex; flex-direction: column; gap: 1px;
  margin-top: 4px; max-height: 168px; overflow-y: auto;
}
.auf-treffer-zeile {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-2);
  width: 100%; padding: 5px 8px; text-align: left;
  background: var(--surface-2); border: 1px solid transparent; border-radius: var(--radius);
  color: inherit; font: inherit; cursor: pointer;
}
.auf-treffer-zeile:hover { background: var(--border); border-color: var(--border-strong); }
.auf-chips { display: flex; flex-wrap: wrap; gap: 4px; margin-top: var(--sp-2); }
.auf-chip {
  display: inline-flex; align-items: center; gap: 5px; padding: 3px 6px 3px 9px;
  background: var(--surface-2); border: 1px solid var(--border-strong);
  border-radius: 999px; font-size: 12px;
}
.auf-chip-klasse { color: var(--text-muted); }

/* Deadline. Two plain fields plus quick buttons; no calendar widget of our own —
   the browser's is better than anything we would draw, the problem was only that a
   datetime-local starts empty and needs five segments typed. */
.auf-frist { display: flex; flex-direction: column; gap: 6px; }
.auf-frist-schnell { display: flex; flex-wrap: wrap; gap: 4px; }
.auf-frist-felder { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.auf-frist-datum { max-width: 190px; }
.auf-frist-zeit { max-width: 120px; }
.auf-frist-text { margin: 0; }
.auf-frist-warn { color: var(--warning); }

/* Retention panel. Restrained on purpose: it is an operational setting, not an alarm —
   the warning box only appears when something is actually about to be deleted. */
.auf-aufbewahrung { margin-top: var(--sp-5); display: flex; flex-direction: column; gap: var(--sp-2); }
.auf-aufbewahrung h3 { margin: 0; font-size: 15px; }
.auf-aufb-form { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.auf-aufb-feld { max-width: 110px; }
.auf-aufb-liste { padding: var(--sp-2); display: flex; flex-direction: column; gap: 3px; }
.auf-aufb-zeile { display: flex; gap: var(--sp-2); align-items: baseline; font-size: 13px; }
.auf-aufb-zeile > span:first-child { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.auf-liste-head {
  display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap;
  margin: var(--sp-5) 0 var(--sp-2);
}
.auf-liste-head h3 { font-size: 15px; margin: 0; }
/* `.input` is width:100%, which in this flex row would push the Archiv button off the
   end. Sized for inline use instead, and allowed to shrink on a narrow screen. */
.auf-listen-suche {
  width: auto; flex: 0 1 260px; min-width: 0;
  padding: 6px 10px; font-size: 13px;
}
.auf-liste { display: flex; flex-direction: column; gap: var(--sp-2); }
.auf-row {
  display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap;
  padding: var(--sp-2) var(--sp-3); background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--radius);
}
.auf-row-main { flex: 1; min-width: 220px; display: flex; flex-direction: column; gap: 3px; }
.auf-row-top { display: flex; align-items: center; gap: var(--sp-1); flex-wrap: wrap; }
.auf-row-title { font-weight: 600; font-size: 14px; }
.auf-row-sub { font-size: 11.5px; color: var(--text-muted); }
.auf-row-actions { display: flex; gap: var(--sp-1); flex-wrap: wrap; }

.auf-review-head { display: flex; flex-direction: column; gap: var(--sp-2); }
.auf-kollegen { border-top: 1px solid var(--border); padding-top: var(--sp-2); }
.auf-kollegen h4 { font-size: 12px; margin: 0 0 6px; color: var(--text-muted); }
.auf-kollegen-liste { display: flex; flex-wrap: wrap; gap: var(--sp-1); margin-bottom: var(--sp-2); }
.auf-kollege {
  display: inline-flex; align-items: center; gap: 4px; font-size: 12px;
  padding: 3px 6px 3px 10px; border-radius: 999px;
  background: var(--surface-2); border: 1px solid var(--border);
}
/* Search-and-chips picker, shared by the pupil targets and the co-reviewer box. */
.auf-picker { display: flex; flex-direction: column; gap: 4px; }

/* One compact row per submission; the code itself is read on its own page. */
.auf-abgabe-zeile {
  display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap;
  padding: 9px 12px; background: var(--surface); cursor: pointer;
  border: 1px solid var(--border); border-radius: var(--radius);
}
.auf-abgabe-zeile:hover { border-color: var(--border-strong); background: var(--surface-2); }
.auf-abgabe-wer { display: flex; align-items: baseline; gap: 6px; min-width: 150px; }
.auf-abgabe-name { font-weight: 600; }

/* ---- full-page review: the IDE shell, read-only ---- */
.ab-page .ide-sidebar { background: var(--surface); }
.ab-page .cb-explorer {
  background: transparent; border-right: 0; max-height: none; flex: 1; overflow-y: auto;
}
.ab-page .cb-pane { flex: 1; min-height: 0; }
.ab-page .cb-pane-kopf { border-bottom: 1px solid var(--border); }
.ab-page .cb-pane .auf-datei { flex: 1; min-height: 0; display: flex; flex-direction: column; }
/* The code fills what is left of the window instead of a fixed box — the whole point
   of leaving the list was to make this big. */
.ab-page .cb-pane .cr-scroll { flex: 1; max-height: none; overflow: auto; }
.ab-toolbar { padding: 5px var(--sp-2); gap: var(--sp-2); min-height: 40px; }
.ab-panel { overflow-y: auto; display: flex; flex-direction: column; gap: var(--sp-2); }
.ab-panel-kopf { display: flex; flex-direction: column; gap: 6px; }
.ab-panel-titel { margin: var(--sp-2) 0 0; font-size: 14px; color: var(--text-muted); }
.ab-aufgabentext { max-height: 30vh; overflow-y: auto; }

.auf-abgaben { display: flex; flex-direction: column; gap: var(--sp-2); margin-top: var(--sp-3); }
.auf-abgabe-head { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; margin-bottom: var(--sp-2); }
.auf-abgabe-head h3 { font-size: 15px; margin: 0; }
.auf-abgabe-status { display: flex; align-items: center; gap: var(--sp-1); flex-wrap: wrap; }
.auf-abgabe-meta { font-size: 11.5px; color: var(--text-muted); }
.auf-abgabe-body { display: flex; flex-direction: column; gap: var(--sp-2); }
.auf-versionen { display: flex; gap: 4px; }
.auf-versionen .btn.is-active { background: var(--surface-2); border-color: var(--border-strong); color: var(--text); }
.auf-datei { border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
.auf-datei-head {
  display: flex; align-items: center; gap: 5px; padding: 5px 10px;
  background: var(--surface-2); border-bottom: 1px solid var(--border);
  font-family: var(--font-mono); font-size: 11.5px; color: var(--text-muted);
}
/* ---- code browser: explorer left, the open file right ----
   The shape of the IDE the pupil wrote in. Before this every file of a hand-in was
   stacked in one column, so five files meant scrolling past four of them to reach the
   line you wanted to comment on — and nothing said which files existed at all. */
.cb-wrap {
  display: grid; grid-template-columns: 190px 1fr;
  border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden;
}
.cb-explorer {
  background: var(--surface-2); border-right: 1px solid var(--border);
  padding: 6px; display: flex; flex-direction: column; gap: 1px;
  max-height: 460px; overflow-y: auto;
}
.cb-explorer-kopf {
  font-size: 11px; text-transform: uppercase; letter-spacing: 0.04em;
  color: var(--text-muted); padding: 2px 6px 6px;
}
.cb-datei {
  display: flex; align-items: center; gap: 6px; width: 100%; padding: 5px 7px;
  background: transparent; border: 1px solid transparent; border-radius: var(--radius);
  color: inherit; font: inherit; font-size: 12.5px; text-align: left; cursor: pointer;
}
.cb-datei:hover { background: var(--border); }
.cb-datei.is-active { background: var(--bg); border-color: var(--border-strong); }
.cb-datei-name {
  flex: 1; font-family: var(--font-mono); font-size: 11.5px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* The remark count is the reason to open a file again, so it is the one thing that
   gets colour here; the line count is context and stays muted. */
.cb-datei-zahl {
  min-width: 17px; text-align: center; font-size: 11px; padding: 0 4px;
  border-radius: 999px; background: var(--warning-weak); color: var(--warning);
}
.cb-datei-zeilen { font-size: 11px; color: var(--text-muted); }
.cb-pane { display: flex; flex-direction: column; min-width: 0; }
.cb-pane-kopf {
  display: flex; align-items: center; gap: 5px; padding: 5px 10px;
  background: var(--surface-2); border-bottom: 1px solid var(--border);
  font-family: var(--font-mono); font-size: 11.5px; color: var(--text-muted);
}
.cb-pfad { color: var(--text); }
.cb-pane .auf-datei { border: 0; border-radius: 0; }
.cb-pane .cr-scroll { max-height: 420px; overflow-y: auto; }

/* ---- code review: one row per line, remarks sitting under their line ----
   Scrolled inside its own box; a long line must never widen the page. */
.cr-scroll { overflow-x: auto; background: var(--bg); padding: 6px 0; }
.cr-lines { display: flex; flex-direction: column; min-width: max-content; }
.cr-line {
  display: flex; align-items: baseline; gap: 10px; width: 100%;
  padding: 0 12px 0 0; background: none; border: 0; color: inherit;
  font-family: var(--font-mono); font-size: 12.5px; line-height: 1.6;
  text-align: left; white-space: pre;
}
.cr-num {
  flex: 0 0 auto; min-width: 30px; padding-right: 8px; text-align: right;
  user-select: none; color: var(--text-muted); border-right: 1px solid var(--border);
}
.cr-code { flex: 1; }
.cr-add { flex: 0 0 auto; opacity: 0; color: var(--text-muted); padding-left: 8px; }
.cr-line.is-klickbar { cursor: pointer; }
.cr-line.is-klickbar:hover { background: var(--surface-2); }
.cr-line.is-klickbar:hover .cr-add { opacity: 1; }
.cr-line.is-klickbar:focus-visible { outline: 2px solid var(--primary); outline-offset: -2px; }
/* Remarks break out of the monospace column and read as prose. */
.cr-remark { margin: 4px 12px 6px 40px; max-width: 620px; white-space: normal; }
.cr-remark.is-entwurf { border-style: dashed; border-color: var(--border-strong); }
.cr-entwurf { margin: 4px 12px 8px 40px; max-width: 620px; display: flex; flex-direction: column; gap: 6px; }
.cr-entwurf-feld { font-size: 13px; }
.cr-entwurf-btns { display: flex; align-items: center; gap: var(--sp-1); flex-wrap: wrap; }
.auf-bewerten { display: flex; flex-direction: column; gap: var(--sp-2); margin-top: var(--sp-1); }
.auf-bewerten-btns { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }

@media (max-width: 720px) {
  .auf-ziele { grid-template-columns: 1fr; }
  /* The explorer becomes a row of files above the code: at this width a 190px column
     would leave the code about twenty characters wide, which is worse than scrolling. */
  .cb-wrap { grid-template-columns: 1fr; }
  .cb-explorer {
    flex-direction: row; flex-wrap: wrap; max-height: none;
    border-right: 0; border-bottom: 1px solid var(--border);
  }
  .cb-explorer-kopf { display: none; }
  .cb-datei { width: auto; }
  .cb-datei-name { flex: 0 1 auto; }
}

/* The explorer's footer box (open/close a local folder) went with the free workspace
   on 2026-08-08 — .ide-sidebar-foot / .ide-folder-* had no markup left. */
.ide-status-folder { opacity: 0.85; }
/* .ide-status-autosave removed 2026-08-11 with the settings toggle. */

@media (max-width: 1100px) {
  .ide-shell.ide-with-task { grid-template-columns: 170px 1fr 260px; }
}
/* At Chromebook / school-tablet widths (walker Run 3 found the overlap at
   929x861, Playwright's default), the 3-column grid crushes the middle
   editor pane and the task aside overlaps the editor toolbar. Collapse to a
   single column so the task panel stacks BELOW the editor — nothing can
   overlap horizontally. Sidebar hidden too because the file explorer is not
   the primary surface for a pupil on a small screen. Threshold 1024 covers
   1024x768 (classic classroom projector), 1280x800 stays 3-column. */
@media (max-width: 1024px) {
  .ide-shell.ide-with-task { grid-template-columns: 1fr; }
  .ide-shell.ide-with-task .ide-sidebar { display: none; }
  .ide-shell.ide-with-task .ide-task {
    border-left: 0;
    border-top: 1px solid var(--border);
    max-height: none;
  }
}

/* ---- IDE: Datenbank-Panel (Python+SQL bridge lessons, 2026-08-22) ---- */
/* Sidebar-tab-strip: Explorer ↔ Datenbank. Only rendered on Python+SQL
   lessons — for every other lesson the sidebar is Explorer-only and this
   selector is unused. Border on the bottom to visually separate the tabs
   from the tree/table content, same as the panel-head divider. */
.ide-sidebar-tabs {
  display: flex; gap: 2px;
  padding: 6px 8px 0 8px;
  border-bottom: 1px solid var(--border);
}
.ide-sidebar-tab {
  flex: 1; padding: 6px 10px; font-size: 12.5px; font-weight: 600;
  color: var(--text-muted); background: transparent; border: 0;
  border-bottom: 2px solid transparent; cursor: pointer;
  transition: color var(--transition), border-color var(--transition);
}
.ide-sidebar-tab:hover { color: var(--text); }
.ide-sidebar-tab.is-active {
  color: var(--text);
  border-bottom-color: var(--primary);
}
.db-viewer {
  padding: 8px; overflow-y: auto; overflow-x: hidden;
  font-size: 12.5px; color: var(--text);
}
.db-empty {
  padding: 16px 8px; color: var(--text-muted); line-height: 1.5;
}
.db-empty p { margin: 0 0 8px 0; }
.db-empty-hint { font-size: 12px; color: var(--text-muted); opacity: 0.8; }
.db-connection { margin-bottom: 12px; }
.db-conn-head {
  font-family: var(--font-mono, monospace); font-size: 12px; font-weight: 600;
  color: var(--text); padding: 6px 4px 4px 4px;
  display: flex; gap: 8px; align-items: baseline;
}
.db-conn-note {
  font-family: var(--font-body, inherit); font-size: 11px; font-weight: 400;
  color: var(--text-muted);
}
.db-conn-error {
  padding: 6px 8px; margin: 4px 4px 8px 4px;
  border-radius: var(--radius-sm); background: var(--surface-2);
  color: var(--danger); font-size: 12px; font-family: var(--font-mono, monospace);
}
.db-table { margin: 4px 0 10px 0; }
.db-table-meta {
  display: flex; gap: 8px; align-items: baseline;
  padding: 4px 4px 6px 4px;
  font-size: 12px;
}
.db-table-name {
  font-family: var(--font-mono, monospace); font-weight: 600; color: var(--text);
}
.db-row-count, .db-row-truncated {
  color: var(--text-muted); font-size: 11.5px;
}
.db-table-scroll {
  border: 1px solid var(--border); border-radius: var(--radius-sm);
  overflow-x: auto; background: var(--surface);
}
.db-empty-table { padding: 8px; color: var(--text-muted); font-style: italic; font-size: 12px; }
.db-grid {
  width: 100%; border-collapse: collapse; font-size: 12px;
  font-family: var(--font-mono, monospace);
}
.db-grid th, .db-grid td {
  padding: 4px 8px; text-align: left; border-bottom: 1px solid var(--border);
  white-space: nowrap; vertical-align: top;
}
.db-grid th {
  position: sticky; top: 0; background: var(--surface-2);
  font-weight: 600; color: var(--text);
}
.db-grid tbody tr:last-child td { border-bottom: 0; }
.db-grid tbody tr:hover { background: var(--surface-2); }
.db-col-name { color: var(--text); }
.db-col-type {
  margin-left: 6px; color: var(--text-muted); font-weight: 400; font-size: 10.5px;
  text-transform: uppercase; letter-spacing: 0.02em;
}
.db-cell-null {
  color: var(--text-muted); font-style: italic; opacity: 0.7;
}
/* Table-tab strip (≥4 tables per connection, walker feature-request 2026-08-22).
   Same MySQL Workbench pattern: horizontal tabs, one per table, first row of
   the connection body, current tab highlighted. Horizontal scroll on overflow
   so a 20-table schema still fits in the ~340 px sidebar. */
.db-connection-tabbed .db-conn-head { margin-bottom: 4px; }
.db-table-tabs {
  display: flex; gap: 2px; overflow-x: auto; overflow-y: hidden;
  padding: 4px 4px 0 4px; margin: 0 0 4px 0;
  border-bottom: 1px solid var(--border);
  scrollbar-width: thin;
}
.db-table-tab {
  padding: 4px 10px; font-size: 12px; font-weight: 600;
  color: var(--text-muted); background: transparent; border: 0;
  border-bottom: 2px solid transparent; cursor: pointer;
  white-space: nowrap; flex: 0 0 auto;
  font-family: var(--font-mono, monospace);
  transition: color var(--transition), border-color var(--transition), background var(--transition);
}
.db-table-tab:hover { color: var(--text); background: var(--surface-2); }
.db-table-tab.is-active {
  color: var(--text);
  border-bottom-color: var(--primary);
}
.db-tab-body { padding: 0 4px; }

/* ---- IDE: collapsible folders ---- */
.ide-chevron { width: 12px; flex: 0 0 auto; font-size: 10px; color: var(--text-muted); }
.ide-dir { cursor: pointer; }

/* ---- IDE: prevent long folder names from pushing the sidebar header apart ---- */
.ide-sidebar-head { overflow: hidden; }
.ide-explorer-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; flex: 0 1 auto; }

/* ---- „Frag die KI zu dieser Stelle" ----
   Restrained on purpose: a thin chip and a plain card, dev-tool aesthetic, no glow and
   no coloured halo — the chip floats over code a pupil is reading. */
.ide-ki-chip {
  position: absolute; right: 16px; z-index: 4; display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 8px; border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface-2); color: var(--text-muted); font-size: 11px; line-height: 18px;
  cursor: pointer; box-shadow: var(--shadow-sm);
}
.ide-ki-chip:hover { color: var(--text); border-color: var(--border-strong); }
.ide-ki-chip[hidden] { display: none; }
/* Persistent toolbar hint that names the shortcut before any selection has
   been made. Walkthrough P9: a first-timer must be able to LEARN about
   Strg+K without having to guess selecting code to see the floating chip. */
.ide-ki-hint {
  display: inline-flex; align-items: center; gap: 5px; padding: 2px 8px;
  color: var(--text-muted); font-size: 11px; line-height: 18px; cursor: help;
  border-right: 1px solid var(--border); margin-right: var(--sp-1);
}
@media (max-width: 720px) { .ide-ki-hint { display: none; } }

.ki-pop-wrap { position: fixed; inset: 0; z-index: 60; pointer-events: none; }
.ki-pop {
  position: fixed; width: min(420px, calc(100vw - 24px)); pointer-events: auto;
  display: flex; flex-direction: column; gap: var(--sp-2); padding: var(--sp-3);
  box-shadow: var(--shadow-lg);
}
/* The header is the drag handle: grab cursor, and no text selection while dragging so a
   pull across the card does not highlight the quoted code instead of moving the window. */
.ki-pop-kopf { display: flex; align-items: center; gap: 6px; cursor: grab; touch-action: none; }
.ki-pop.is-ziehend { user-select: none; }
.ki-pop.is-ziehend .ki-pop-kopf { cursor: grabbing; }
.ki-pop-titel { font-size: 12px; font-weight: 600; color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; user-select: none; }
.ki-pop-zu { background: none; border: 0; cursor: pointer; color: var(--text-muted); font-size: 17px; line-height: 1; padding: 0 4px; }
.ki-pop.is-ziehend .ki-pop-zu { cursor: grabbing; }
.ki-pop-zu:hover { color: var(--text); }
.ki-pop-code {
  margin: 0; max-height: 132px; overflow: auto; background: var(--bg); border: 1px solid var(--border);
  border-radius: var(--radius-sm); padding: 6px 8px; font-family: var(--font-mono); font-size: 12px; line-height: 1.5;
}
.ki-pop-code-zeile { display: flex; gap: 10px; white-space: pre; }
.ki-pop-code-nr { color: var(--text-muted); user-select: none; text-align: right; min-width: 2ch; flex: 0 0 auto; }
.ki-pop-antwort { font-size: 13px; line-height: 1.6; white-space: pre-wrap; max-height: 42vh; overflow-y: auto; }
.ki-pop-antwort:empty { display: none; }
.ki-pop-status { font-size: 12px; color: var(--text-muted); display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.ki-pop-status:empty { display: none; }
.ki-pop-fuss { display: flex; gap: var(--sp-2); align-items: flex-end; }
.ki-pop-frage { flex: 1; min-width: 0; resize: vertical; font-size: 13px; }

/* ---- Admin: user search + class member progress ---- */
.admin-search { max-width: 300px; }
/* search input with a leading magnifier icon (consistent with the app's icon set) */
.search-field { position: relative; display: inline-flex; align-items: center; width: min(440px, 100%); }
.search-field > .icon {
  position: absolute; left: 12px; top: 50%; transform: translateY(-50%);
  width: 16px; height: 16px; color: var(--text-muted); pointer-events: none;
}
.search-field > .admin-search { width: 100%; max-width: none; padding-left: 36px; padding-right: 36px; }
.search-field:focus-within > .icon { color: var(--text); }
/* replace the browser's native search-clear (the stray ×) with our own pictogram */
.search-field > .admin-search::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }
.search-field > .admin-search::-ms-clear { display: none; }
.search-clear {
  position: absolute; right: 7px; top: 50%; transform: translateY(-50%);
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px; padding: 0; border: 0; border-radius: 6px;
  background: transparent; color: var(--text-muted); cursor: pointer;
}
.search-clear:hover { color: var(--text); background: var(--surface-2); }
.search-clear > .icon { width: 15px; height: 15px; }
.search-clear[hidden] { display: none; } /* .search-clear sets display, so [hidden] needs higher specificity */
.member-head { margin-bottom: var(--sp-2); }
.member-progress { display: flex; align-items: center; gap: 8px; }
.mini-progress {
  width: 110px; height: 7px; background: var(--surface-2);
  border: 1px solid var(--border); border-radius: 999px; overflow: hidden;
}
.mini-progress-fill {
  height: 100%; background: var(--grad); border-radius: 999px;
  transition: width 0.5s cubic-bezier(0.4, 0, 0.2, 1);
}
.member-progress-text { font-size: 12px; color: var(--text-muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
/* No top border or margin any more: it sits inside its own table row now, which brings
   its own separation — the old rule was drawing a second line right under the table's. */
.member-detail { max-height: 38vh; overflow-y: auto; }
/* The breakdown opens directly under its pupil. Tinted and marked down the left edge so
   it reads as belonging to the row above rather than as the next pupil in the list —
   across 28 members an untinted full-width row is easy to mistake for one. */
.member-detail-row > td {
  background: var(--surface-2);
  padding: var(--sp-3) var(--sp-4);
  border-left: 2px solid var(--primary);
}
.member-detail-title { font-size: 15px; }
.member-kurs-title {
  margin: var(--sp-3) 0 var(--sp-1); font-size: 11px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.07em; color: var(--text-muted);
}
.member-lektionen { display: flex; flex-direction: column; gap: 4px; }
.member-lektion {
  display: flex; align-items: center; gap: 9px; font-size: 13.5px;
  padding: 5px 10px; border-radius: var(--radius-sm); background: var(--surface-2);
  color: var(--text-muted);
}
.member-lektion.is-done { color: var(--text); }
.member-lektion-mark { flex: 0 0 auto; }
.member-lektion.is-done .member-lektion-mark { color: var(--success); font-weight: 700; }

/* ---- Admin: section tabs ---- */
.admin-tabs {
  display: flex; gap: var(--sp-1); margin-bottom: var(--sp-5);
  border-bottom: 1px solid var(--border); overflow-x: auto; overflow-y: hidden;
}
.admin-tab {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 10px 15px; border: 0; background: transparent; cursor: pointer;
  font-size: 14px; font-weight: 600; color: var(--text-muted); white-space: nowrap;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
  transition: color var(--transition), border-color var(--transition), background var(--transition);
}
.admin-tab .icon { width: 15px; height: 15px; }
.admin-tab:hover:not(.is-active) { color: var(--text); background: var(--surface-2); }
.admin-tab.is-active { color: var(--primary); border-bottom-color: var(--primary); }

/* ---- Admin: sandbox module policy ---- */
.module-list {
  display: flex; flex-direction: column; gap: var(--sp-1);
  /* fill the space below the panel header so the page itself never scrolls */
  max-height: max(260px, calc(100vh - 480px)); overflow-y: auto; padding-right: 4px;
}
.module-group {
  font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--text-muted); margin: var(--sp-4) 0 var(--sp-1);
}
.module-group-gefahr { color: var(--danger); }
.module-group-vorsicht { color: var(--warning); }
.module-group-block { display: flex; flex-direction: column; gap: var(--sp-1); }
/* search filter hides rows/blocks via [hidden]; these set display, so make the
   attribute authoritative (higher specificity than the bare class display rule) */
.module-row[hidden], .module-group-block[hidden] { display: none; }
.module-group-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--sp-2); flex-wrap: wrap; margin: var(--sp-3) 0 0;
  position: sticky; top: 0; z-index: 3;
  background: var(--surface); padding: var(--sp-1) 0;
}
.module-group-row .module-group { margin: 0; }
.module-group-actions { display: flex; gap: var(--sp-2); flex-shrink: 0; }
.module-bulk {
  gap: 6px; padding: 5px 12px; font-size: 12px; font-weight: 600;
  border-radius: 999px;
  border: 1px solid var(--border-strong);
  background: var(--surface-2); color: var(--text-muted);
}
.module-bulk .icon { width: 14px; height: 14px; }
.module-bulk:hover:not(:disabled) { transform: translateY(-1px); box-shadow: var(--shadow-sm); }
.module-bulk:active:not(:disabled) { transform: translateY(0); box-shadow: none; }
/* affirmative — enable all */
.module-bulk-on { color: var(--success); border-color: color-mix(in srgb, var(--success) 40%, var(--border-strong)); }
.module-bulk-on:hover:not(:disabled) {
  background: var(--success-weak); border-color: var(--success); color: var(--success);
}
/* neutral — block all */
.module-bulk-off:hover:not(:disabled) {
  background: var(--surface); border-color: var(--text-muted); color: var(--text);
}
.module-bulk:disabled { opacity: 0.45; }
.module-group-paket { color: var(--accent); }
.module-row {
  position: relative;
  display: flex; flex-direction: column;
  padding: 8px 12px; background: var(--surface-2);
  border: 1px solid var(--border); border-left: 3px solid var(--border); border-radius: var(--radius);
}
.module-row.module-vorsicht { border-left-color: var(--warning); }
.module-row.module-paket { border-left-color: var(--accent); }
.module-row.module-gefahr { border-left-color: var(--danger); }
/* NOTE: row content stays at the default stacking level (no z-index). The busy
   ring is masked to a 2px edge so it never covers content — lifting content with
   z-index would make it paint over the sticky group header while scrolling. */
.module-top { display: flex; align-items: center; gap: var(--sp-3); }
.module-meta { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.module-name { font-family: var(--font-mono); font-weight: 600; font-size: 14px; }
.module-pip { font-weight: 400; font-size: 11px; color: var(--text-muted); }
.module-desc { font-size: 12.5px; color: var(--text-muted); }
.module-state { font-size: 12px; white-space: nowrap; flex: 0 0 auto; color: var(--text-muted); }
.module-state.is-on { color: var(--success); }
.module-state.is-off { color: var(--text-muted); }
.module-actions { display: flex; align-items: center; gap: var(--sp-2); flex: 0 0 auto; }
.module-install { min-width: 116px; justify-content: center; }
.module-toggle { min-width: 92px; justify-content: center; }
.module-toggle.is-on { background: var(--success-weak); color: var(--success); border-color: var(--success); }
.module-toggle.is-off { background: var(--surface); color: var(--text-muted); border-color: var(--border-strong); }
.module-toggle:disabled, .module-install:disabled { opacity: 0.5; cursor: not-allowed; }

/* Live pip terminal inside a library row */
.module-term {
  margin: 8px 0 2px; padding: 8px 10px; border-radius: var(--radius-sm);
  font-family: var(--font-mono); font-size: 11.5px; line-height: 1.5;
  background: #0c0f16; color: #d6deeb; border: 1px solid #1d2433;
  max-height: 200px; overflow: auto; white-space: pre-wrap; word-break: break-word;
}

/* "Installing" state: a thin border-light that travels once around the whole card.
   Perimeter motion (as the user wanted) but professional — a single MUTED green
   segment, crisp and flat, with NO glow halo and NO bright highlight (that was the
   "glossy" look). The mask carves the conic gradient down to a ~1.5px border that
   follows the rounded corners; a faint static outline keeps the ring readable across
   the gap. z-index stays below the sticky group header (3) so it never bleeds over it. */
@property --lib-angle { syntax: "<angle>"; inherits: false; initial-value: 0deg; }
.module-row.is-busy::after {
  content: "";
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  border-radius: var(--radius);
  padding: 1.5px; /* travelling-border thickness */
  background:
    conic-gradient(from var(--lib-angle),
      transparent 0deg 8deg,
      var(--success) 20deg 60deg,
      transparent 72deg 360deg),
    color-mix(in srgb, var(--success) 12%, transparent); /* faint steady outline */
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
  animation: lib-run 1.9s linear infinite;
}
@keyframes lib-run { to { --lib-angle: 360deg; } }
@media (prefers-reduced-motion: reduce) {
  /* no rotation — a steady, evenly muted outline; liveness comes from the terminal */
  .module-row.is-busy::after {
    animation: none;
    background: color-mix(in srgb, var(--success) 32%, transparent);
  }
}

/* ---- Admin: lesson editor ---- */
.lk-form { margin-top: var(--sp-5); display: flex; flex-direction: column; gap: var(--sp-2); }
.lk-form-head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); }
.lk-form-title { font-size: 16px; margin: 0; }
.lk-label {
  display: block; margin: var(--sp-2) 0 4px; font-size: 11px; font-weight: 600;
  text-transform: uppercase; letter-spacing: 0.05em; color: var(--text-muted);
}
.lk-mono { font-family: var(--font-mono); font-size: 13px; line-height: 1.5; }
.lk-grid2 { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-3); }
.lk-checkbox { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--text-muted); height: 38px; }
.lk-checkbox input { width: 16px; height: 16px; accent-color: var(--primary); }
.lk-note { display: flex; align-items: center; gap: 5px; font-size: 12px; color: var(--text-muted); margin: 6px 0 0; }
.lk-note .icon { color: var(--primary); flex: 0 0 auto; }

/* task-type cards */
.lk-types { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-2); margin-bottom: var(--sp-1); }
.lk-type {
  display: flex; flex-direction: column; align-items: flex-start; gap: 3px;
  padding: 10px 12px; text-align: left; cursor: pointer;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius);
  color: var(--text); transition: border-color var(--transition), background var(--transition);
}
.lk-type:hover { border-color: var(--border-strong); }
.lk-type.is-active { border-color: var(--primary); background: var(--primary-weak); }
.lk-type .icon { color: var(--text-muted); }
.lk-type.is-active .icon { color: var(--primary); }
.lk-type b { font-size: 13.5px; font-weight: 600; }
.lk-type span { font-size: 11.5px; color: var(--text-muted); line-height: 1.35; }

/* what varies between the cases — a choice WITHIN the task type, so deliberately
   flatter than .lk-type: no fill, no icon, a thin active marker only */
.lk-modes {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 1px;
  background: var(--border); border: 1px solid var(--border); border-radius: var(--radius);
  overflow: hidden; margin-bottom: var(--sp-2);
}
.lk-mode {
  display: flex; flex-direction: column; align-items: flex-start; gap: 2px;
  padding: 8px 10px; text-align: left; cursor: pointer;
  background: var(--surface); border: 0; border-top: 2px solid transparent;
  color: var(--text-muted); transition: background var(--transition), color var(--transition);
}
.lk-mode:hover { background: var(--surface-2); }
.lk-mode.is-active { background: var(--surface-2); color: var(--text); border-top-color: var(--primary); }
.lk-mode b { font-size: 12.5px; font-weight: 600; }
.lk-mode span { font-size: 11px; line-height: 1.3; color: var(--text-muted); }

.lk-payload { display: flex; flex-direction: column; }

/* multiple-choice options */
.lk-opt { display: flex; align-items: center; gap: 9px; margin-bottom: 7px; }
.lk-opt input[type="radio"] { width: 16px; height: 16px; flex: 0 0 auto; accent-color: var(--primary); }
.lk-opt .input { flex: 1; }
.lk-key {
  width: 24px; height: 24px; flex: 0 0 auto; display: flex; align-items: center; justify-content: center;
  font-family: var(--font-mono); font-size: 12px; color: var(--text-muted);
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius-sm);
}

/* test cases — the teacher fills in inputs only, never an expected output */
.lk-cases { display: flex; flex-direction: column; gap: var(--sp-2); margin-bottom: var(--sp-2); }
.lk-case { border: 1px solid var(--border); border-radius: var(--radius); padding: 9px 10px; }
.lk-case-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 6px; }
.lk-case-label { display: flex; align-items: center; gap: 7px; font-size: 12px; color: var(--text-muted); }
.lk-case-tag {
  padding: 1px 6px; border-radius: var(--radius-sm); font-size: 11px;
  background: var(--surface-2); border: 1px solid var(--border);
}

/* the derived answer key, shown back for confirmation */
.lk-derived {
  margin-top: var(--sp-2); padding: 10px 12px;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius);
}
.lk-derived-title { font-size: 12px; color: var(--text-muted); margin-bottom: 7px; }
.lk-derived-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 12px; margin-bottom: 4px; }
.lk-derived-row code {
  font-family: var(--font-mono); padding: 1px 6px; border-radius: var(--radius-sm);
  background: var(--surface); border: 1px solid var(--border); word-break: break-all;
}
.lk-arrow { color: var(--text-muted); }
.lk-gate-fix { margin-top: var(--sp-2); }

.lk-actions { display: flex; align-items: center; gap: var(--sp-2); margin-top: var(--sp-3); flex-wrap: wrap; }
.lk-result {
  display: flex; align-items: center; gap: 8px; margin-top: var(--sp-3);
  padding: 9px 12px; border-radius: var(--radius); font-size: 13px;
}
.lk-result.is-pass { background: var(--success-weak); color: var(--success); border: 1px solid var(--success); }
.lk-result.is-fail { background: var(--danger-weak); color: var(--danger); border: 1px solid var(--danger); }
.lk-result .icon { flex: 0 0 auto; }
.lk-diff {
  margin: var(--sp-1) 0 0; padding: 10px 12px; font-family: var(--font-mono); font-size: 12px;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius);
  white-space: pre-wrap; word-break: break-word; color: var(--text-muted);
}

/* existing-lessons list */
.lk-list-title { font-size: 15px; margin: 0 0 var(--sp-2); }
.lk-kurs-block { margin-bottom: var(--sp-2); }
.lk-li {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  padding: 9px 12px; margin-bottom: 6px;
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius);
}
.lk-li-meta { display: flex; align-items: center; gap: 9px; min-width: 0; flex-wrap: wrap; }
.lk-li-meta b { font-size: 14px; font-weight: 600; }

@media (max-width: 640px) {
  .lk-grid2, .lk-types, .lk-modes { grid-template-columns: 1fr; }
}

/* Gruppenarbeit (admin tab) */
.gruppen-box { margin-top: var(--sp-3); display: flex; flex-direction: column; gap: var(--sp-2); }
.gruppe-lbl { margin-right: 6px; color: var(--text-muted); font-size: 14px; }
.gruppe-create { display: flex; gap: var(--sp-2); align-items: center; flex-wrap: wrap; }
.gruppe-name-input { max-width: 280px; }
.gruppe-card {
  border: 1px solid var(--border); border-radius: var(--radius);
  padding: var(--sp-2) var(--sp-3); background: var(--surface-2);
  cursor: grab;
}
.gruppe-card:active { cursor: grabbing; }
/* The card being dragged stays visible but recedes, so the drop target reads as the
   thing that matters. Deliberately no transform — moving it would fight the browser's
   own drag image. */
.gruppe-card.is-dragging { opacity: 0.45; }
/* The section under the pointer. A border and a tint, no glow and no bounce: this is a
   filing cabinet, not a game (see Feedback_UI_Zurueckhaltend_Professionell). */
.gruppe-thema-section.is-drop-target {
  border-color: var(--primary);
  background: var(--surface-2);
}
/* Buttons inside a draggable card must not start their own drag on mousedown, or the
   pointer lands on "Löschen" and the card comes with it. */
.gruppe-card button { cursor: pointer; }
.gruppe-head { display: flex; align-items: center; gap: var(--sp-2); }
.gruppe-name { font-weight: 600; }
.gruppe-members { margin-top: var(--sp-2); padding-top: var(--sp-2); border-top: 1px solid var(--border); }
.gruppe-memrow { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); }
.gruppe-memlist { display: flex; flex-wrap: wrap; gap: 6px; }
.member-chip { display: inline-flex; align-items: center; gap: 2px; padding: 2px 2px 2px 10px; background: var(--surface); border: 1px solid var(--border); border-radius: 999px; font-size: 13px; }
.chip-x { border: 0; background: transparent; color: var(--text-muted); cursor: pointer; font-size: 15px; line-height: 1; padding: 0 5px; border-radius: 50%; }
.chip-x:hover { background: var(--danger); color: #fff; }
.gruppe-add { max-width: 240px; }
.gruppe-search-wrap { margin-top: var(--sp-2); display: flex; flex-direction: column; gap: 6px; }
.gruppe-search { max-width: 320px; }
.gruppe-results { display: flex; flex-direction: column; gap: 4px; max-height: 240px; overflow-y: auto; }
.gruppe-result { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); width: 100%; max-width: 420px; text-align: left; padding: 6px 10px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); cursor: pointer; color: var(--text); }
.gruppe-result:hover { border-color: var(--accent); background: var(--surface-2); }
.gruppe-result-name { font-size: 14px; }
.gruppe-result-meta { font-size: 12px; color: var(--text-muted); white-space: nowrap; }
.gruppe-thema-input { max-width: 340px; }
.gruppe-thema-section { border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
/* The Gruppenarbeit tab is two stacked halves and the lower one is a bare div, so its
   heading sat flush against the panel above it (measured: 0px of clearance, against 26px
   for the upper half, which gets it from its own panel padding). The upper half is a
   card with a background; this one is not, so its heading needs more air than a
   card-to-card gap would, or it reads as belonging to the card above. */
.gruppen-aufgaben-teil { margin-top: var(--sp-8); }
.gruppe-thema-head { display: flex; align-items: center; gap: 6px; padding: 4px 8px; background: var(--surface-2); }
.gruppe-thema-toggle { display: flex; align-items: center; gap: 8px; background: transparent; border: 0; cursor: pointer; color: var(--text); font: inherit; text-align: left; padding: 6px 8px; border-radius: var(--radius); }
.gruppe-thema-toggle:hover { background: var(--surface); }
.gruppe-thema-caret { width: 1em; color: var(--text-muted); }
.gruppe-thema-name { font-weight: 600; }
.gruppe-thema-count { color: var(--text-muted); font-size: 13px; }
.gruppe-thema-body { display: flex; flex-direction: column; gap: var(--sp-2); padding: var(--sp-2); }
.gruppe-thema-body[hidden] { display: none; }
.gruppe-add-group { display: flex; align-items: center; gap: 6px; width: 100%; text-align: left; background: transparent; border: 1px dashed var(--border); border-radius: var(--radius); padding: 8px 10px; color: var(--text-muted); cursor: pointer; font: inherit; font-size: 14px; }
.gruppe-add-group:hover { background: var(--surface-2); color: var(--text); }
/* The one destructive control in this tab. Muted until hovered so it never competes
   with Archivieren, which is what a teacher almost always actually wants. */
.auf-gefahr { color: var(--danger); }
.auf-gefahr:hover { background: var(--danger-weak); border-color: var(--danger); }

/* -------- Klassen-Zettel (Phase 5, printable class-credentials sheet) --------
   Renders one card per pupil on screen (dark theme), and rearranges to a black-
   on-white sheet with cutting lines for the print media. `@media print` also
   hides every part of the app chrome that would waste paper (topbar/sidebar/
   navigate-away buttons). Rationale for browser-print instead of a server PDF
   is in views/klassen_zettel.js and in the plan note. */
.zettel-titel { max-width: 960px; margin: 24px auto 12px; padding: 0 20px; }
.zettel-titel h1 { margin: 0 0 6px; font-size: 22px; }
.zettel-druckkopf { display: none; }

/* Two-column grid of dashed tear-off cards. ANTON-style: Ayden's reference
   photo (2026-08-10) has ~14 cards per A4 page, cut apart with scissors and
   handed to each pupil. On screen the grid is a normal dark-theme design; the
   print stylesheet at the bottom of this file tightens padding + font so a
   normal class (25-30 pupils) fits on one A4 sheet. */
.zettel-liste {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px 12px;
  max-width: 960px;
  margin: 12px auto 40px;
  padding: 0 20px;
}
.zettel-karte {
  border: 1px dashed var(--border);
  border-radius: var(--radius);
  padding: 12px 14px;
  background: var(--surface);
  color: var(--text);
  page-break-inside: avoid;
  break-inside: avoid;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.zettel-zeile {
  display: flex;
  align-items: baseline;
  gap: 8px;
}
.zettel-etikett {
  min-width: 78px;
  color: var(--text-muted);
  font-size: 12px;
}
.zettel-wert {
  font-family: "IBM Plex Mono", ui-monospace, Menlo, Consolas, monospace;
  font-size: 15px;
  padding: 2px 6px;
  border-radius: 4px;
  background: var(--surface-2);
  color: var(--text);
  user-select: text; /* opposite of .kein-kopieren; explicit because .card resets */
}
.zettel-hinweis {
  margin: 4px 0 0;
  color: var(--text-muted);
  font-size: 11px;
  line-height: 1.35;
}
.zettel-aktion {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-top: 6px;
}
.zettel-status { color: var(--text-muted); font-size: 12px; }
.zettel-leer {
  max-width: 640px;
  margin: 80px auto;
  padding: 32px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}
.zettel-leer h1 { margin: 0 0 8px; font-size: 20px; }

/* Klartext-Passwort im Reset-Modal (admin.js zeigeStartdaten). */
.startdaten-passwort {
  display: block;
  font-family: "IBM Plex Mono", ui-monospace, Menlo, Consolas, monospace;
  font-size: 22px;
  padding: 12px 16px;
  border-radius: var(--radius);
  background: var(--surface-2);
  color: var(--text);
  text-align: center;
  user-select: all;
  margin: 8px 0 12px;
}

/* Passwort-aendern form hint under the username input. */
.form-hint { margin: -4px 0 12px; color: var(--text-muted); font-size: 12px; }

/* Discreet badge next to a pupil's display_name in the admin tables when they
   still hold an admin-issued temp password. Deliberately understated (muted
   colour, small caps) so it does not compete with the name itself — the point
   is at-a-glance recognition, not a warning label. */
.pw-start-badge {
  color: var(--text-muted);
  font-size: 12px;
  font-variant: small-caps;
  letter-spacing: 0.02em;
}

/* Whole-row dim for a pupil whose must_change_password is still set. Applied
   in both admin tables. Communicates "they are on the list but haven't
   arrived yet" without hiding them. .is-inactive already dims deactivated
   accounts more aggressively; a pupil can be BOTH pre-rotation AND inactive,
   in which case is-inactive wins (also dimmed, but styled as "off"). */
.admin-table tr.is-pre-rotation td {
  opacity: 0.55;
}
.admin-table tr.is-pre-rotation td .row-actions,
.admin-table tr.is-pre-rotation td .pw-start-badge {
  opacity: 1; /* keep the actionable controls + the reason-badge legible */
}

/* Even more pronounced dim for provisional rows — a Verwerfen would delete
   them without warning, so the visual distance from a real class member is
   what makes the risk legible. */
.admin-table tr.is-provisional td {
  opacity: 0.4;
  font-style: italic;
}
.admin-table tr.is-provisional td .row-actions,
.admin-table tr.is-provisional td .pw-start-badge {
  opacity: 1;
  font-style: normal;
}

/* Second sub-count for open provisional batches, colored with the danger
   accent (not red-loud) so the teacher's eye is drawn to the class that
   has something to resolve. Muted enough not to compete with the real
   "N Mitglieder" number. */
.klasse-provisorisch {
  color: var(--danger, #d97706);
  font-size: 12px;
  margin-left: 4px;
}

/* Vorläufiger-Stapel-Panel above the members table. Contained in a soft
   accent so it reads as "here is something to do" but doesn't scream. */
.offene-batches-panel {
  margin: 12px 0 20px;
  padding: 14px 16px;
  border: 1px solid var(--border);
  border-left: 3px solid var(--danger, #d97706);
  border-radius: var(--radius);
  background: var(--surface-2, rgba(255, 255, 255, 0.03));
}
.offene-batches-titel {
  margin: 0 0 4px;
  font-size: 15px;
  color: var(--text);
}
.offene-batches-hinweis {
  margin: 0 0 12px;
  color: var(--text-muted);
  font-size: 13px;
  line-height: 1.4;
}
.offener-batch {
  padding: 10px 0;
  border-top: 1px solid var(--border);
}
.offener-batch:first-of-type {
  border-top: 0;
}
.offener-batch-kopf {
  display: flex;
  align-items: center;
  gap: 12px;
  justify-content: space-between;
  flex-wrap: wrap;
}
.offener-batch-info {
  color: var(--text);
  font-size: 13px;
}
.offener-batch-aktionen {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
}

/* Sub-count next to the "N Mitglieder" line for pupils still on a temp
   password. Muted so it reads as secondary info, not a warning. */
.klasse-unrotated {
  color: var(--text-muted);
  font-size: 12px;
  margin-left: 4px;
}

/* "Vorläufig" warning box on the print-tab. Explains why the two big buttons
   are there and what happens if you close the tab without pressing either.
   Uses the danger-weak background token to communicate "action required"
   without being alarming. */
.zettel-warnung {
  padding: 10px 14px;
  border-left: 3px solid var(--danger, #d97706);
  background: var(--danger-weak, rgba(217, 119, 6, 0.08));
  color: var(--text);
  font-size: 13px;
  line-height: 1.5;
  border-radius: 4px;
  margin: 6px 0 10px;
}

/* One-line status feedback under the action row while a commit/discard is
   in flight. Screen-reader announced via role=status on the element. */
.zettel-status-zeile {
  min-height: 1em;
  margin: 6px 0 0;
  color: var(--text-muted);
  font-size: 13px;
}

.print-only { display: none; }

@media print {
  /* Take everything that is not the sheet off the page. */
  .topbar, .sidebar, .noprint,
  [role="navigation"], .modal-overlay {
    display: none !important;
  }
  body, html {
    background: white !important;
    color: black !important;
    margin: 0;
  }
  #app { background: white !important; }
  /* Whitening EVERY ancestor container. Without this, an ancestor whose
     background comes from the dark-theme CSS variables (``main.container``,
     any wrapping section/div) stayed dark on paper and the whole page
     printed with a black frame around the cards. Ayden 2026-08-11:
     "jetzt ist das außen schwarz das soll weiß bleiben". Deliberately does
     NOT set ``color`` on ``*`` — leaving that to the specific rules below
     so a future non-``.zettel-*`` element on this page keeps whatever color
     it needs. Same idea for backgrounds would be too aggressive (would
     also blank a coloured badge/box), but the print variant of this route
     has none of those, and blanking is what we want here. */
  main, .container, body > *, section, article, aside, div, header, footer {
    background: white !important;
  }
  .zettel-titel { display: none !important; }
  .zettel-druckkopf, .print-only { display: block !important; }
  .zettel-druckkopf { margin: 0 0 5mm; font-size: 11pt; color: black; font-weight: 700; }
  /* Two-column grid stays; tighten paddings + font so a normal class fits on
     one A4 page. Each card is a physical tear-off — the dashed border serves
     as the cutting line, and page-break-inside: avoid stops a card from being
     split by a page break if the batch overflows. Card layout target:
     ~85mm × ~30mm → 2 cols × ~9 rows = 18 cards per A4 page.

     ``min-width: 0`` on ``.zettel-karte`` is load-bearing: the default
     ``min-width: auto`` on grid items expands the track to fit the item's
     min-content, which for a monospace ``.zettel-wert`` with a long username
     is wider than the ``1fr`` share of the page. Without this line the right
     column pushes past the printable area and the right border disappears
     under the printer's non-printable margin (Ayden 2026-08-11 screenshot).
     ``box-sizing: border-box`` is the other half — grid tracks size against
     border-box, so any card padding/border under ``content-box`` widens the
     tracks a second time. Together they pin the layout to the visible page. */
  .zettel-liste {
    display: grid !important;
    grid-template-columns: repeat(2, 1fr);
    gap: 3mm 4mm;
    max-width: none;
    margin: 0;
    padding: 0;
    /* Extra safety: constrain the whole grid to the printable area's width
       regardless of what ancestor styles do — an ancestor at ``width: 100vw``
       (from another feature's overlay CSS) would otherwise overflow. */
    width: 100%;
    box-sizing: border-box;
  }
  .zettel-karte {
    background: white !important;
    color: black !important;
    /* Border is a physical cutting line — must be black, not dark-gray.
       Ayden 2026-08-11: "die gestrichelte line nicht schwarz". Bumped
       to 0.8pt so the dashes are visible on inkjets too (0.6pt disappears
       into small ink dots on many home printers). ``print-color-adjust:
       exact`` is scoped here (not on ``*``) so Chrome's economy mode won't
       fade the dash color; wildcarding it caused the OPPOSITE problem —
       every ancestor's dark-theme background then survived to paper. */
    border: 0.8pt dashed black !important;
    border-radius: 1mm;
    padding: 3mm 4mm;
    gap: 1.5mm;
    min-width: 0;
    box-sizing: border-box;
    -webkit-print-color-adjust: exact;
    print-color-adjust: exact;
  }
  .zettel-zeile {
    /* A ``.zettel-zeile`` is a flex row (baseline-aligned). Same trap as
       above: without min-width:0, the flex item ``.zettel-wert`` grows past
       the card's inner width when the monospace content is long. */
    min-width: 0;
  }
  .zettel-etikett {
    /* Screen shows the "Benutzer:" / "Passwort:" labels in muted gray to
       de-emphasize them against the value. On paper the same gray reads
       "faint / faded" and the pupil can miss the label entirely, so print
       forces black. Ayden 2026-08-11: "da sind immer noch sachen grau". */
    color: black !important;
    font-size: 8pt;
    min-width: 18mm;
  }
  .zettel-wert {
    background: transparent !important;
    color: black !important;
    font-size: 10pt;
    padding: 0;
    border-radius: 0;
    /* Break on any character rather than let a long monospace username push
       the card past the page edge — a wrapped credential still tears off
       fine, an overflowed one gets guillotined by the printer. */
    overflow-wrap: anywhere;
    word-break: break-all;
    min-width: 0;
  }
  .zettel-hinweis {
    /* Same reasoning as the label: gray on paper reads as "washed out".
       The one-line "LernPy → Anmelden. Beim ersten Login …" hint is the
       instruction the pupil actually needs, so it goes black. */
    color: black !important;
    font-size: 7pt;
    line-height: 1.3;
  }
  /* Page margin. The 10mm we had before was inside the "no home printer can
     render inside this" band (most consumer printers have a 5–7mm hardware
     margin plus the browser's own header/footer bleed). Bumping to 14mm
     top / 12mm sides keeps the sheet inside what a normal HP/Canon can
     actually print AND leaves headroom for the browser-drawn "date / page
     title" header that eats into the top margin. Ayden 2026-08-11:
     "wenn man die drucken will sieht man den rand rechts fast garnicht" —
     that was the right side kissing the non-printable band. */
  @page { margin: 14mm 12mm 12mm 12mm; }
}

/* ============================================================
   SQL DB Explorer IDE (2026-08-15)
   Ayden: SQL lessons deserve the same IDE shell as Python —
   task on the right, DB Explorer sidebar on the left, result
   grid + status line at the bottom. Restrained per
   Feedback_UI_Zurueckhaltend_Professionell — VS-Code-like,
   no glow, no accent bars, tokens only.
   ============================================================ */

/* Shell — reuses .ide-shell.ide-with-task's 210/1fr/320 grid without
   overriding the column widths; only the semantics of the columns change. */
.sql-ide-shell { /* nothing to override — inherits from .ide-shell */ }

/* ---- DB Explorer sidebar (LEFT) ---- */
.sql-db-sidebar { min-height: 0; }
.sql-db-list { display: flex; flex-direction: column; gap: var(--sp-2); padding: 6px 0; overflow-y: auto; min-height: 0; }
.sql-db-empty { padding: var(--sp-3); color: var(--text-muted); font-size: 12.5px; margin: 0; }

.sql-db-table {
  border-top: 1px solid var(--border);
  padding: 4px 0 6px;
}
.sql-db-table:first-child { border-top: 0; }
.sql-db-table-name {
  display: flex; align-items: center; gap: 6px;
  width: 100%;
  border: 0; background: transparent; color: var(--text);
  font: inherit; font-weight: 600;
  padding: 4px 10px;
  cursor: pointer; text-align: left;
}
.sql-db-table-name:hover { background: var(--surface-2); }
.sql-db-table-name .icon { color: var(--text-muted); flex: 0 0 auto; }

.sql-db-cols { list-style: none; margin: 0; padding: 0; }
.sql-db-col {
  display: flex; align-items: baseline; justify-content: space-between; gap: 8px;
  width: 100%;
  padding: 3px 10px 3px 26px;
  border: 0; background: transparent; color: var(--text);
  font: inherit; font-size: 12.5px;
  cursor: pointer; text-align: left;
}
.sql-db-col:hover { background: var(--surface-2); }
.sql-db-col-name { font-family: var(--font-mono); color: var(--text); }
.sql-db-col-type { font-family: var(--font-mono); font-size: 11.5px; color: var(--text-muted); }

/* ---- SQL toolbar (CENTER top) ---- */
.sql-ide-main { min-height: 0; }
.sql-ide-toolbar { padding-left: var(--sp-3); }
.sql-ide-toolbar .ide-explorer-label { font-size: 12.5px; color: var(--text-muted); }

/* The editor takes the whole space between the toolbar and the result panel.
   `makeEditor` returns `.editor > .gutter + .code-area > .hl-layer + textarea`,
   sized by their own rules. Wrap gives it a min-height:0 so the flex parent
   collapses correctly on narrow viewports. */
.sql-editor-wrap { flex: 1; min-height: 120px; display: flex; }
.sql-editor-wrap .editor { flex: 1; min-height: 0; }

/* ---- Result panel (CENTER bottom) ---- */
.sql-result-panel { flex: 0 0 40%; }
.sql-result-body {
  padding: 0;
  overflow: auto;
  background: var(--surface);
}
.sql-grid-status {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--text-muted);
  padding: 0 var(--sp-2);
}
.sql-grid-status.has-error { color: var(--danger); }

/* Wide grids scroll INSIDE their container — the vault's rule is that the
   page body never scrolls horizontally. */
.sql-grid-scroll { overflow-x: auto; max-width: 100%; }
.sql-grid {
  border-collapse: collapse;
  width: 100%;
  min-width: max-content; /* let the grid define its own width, then let the
                             scroll container clip it if the row is very wide */
  font-family: var(--font-mono);
  font-size: 12.5px;
}
.sql-grid-head th {
  position: sticky; top: 0;
  background: var(--surface-2);
  color: var(--text);
  font-weight: 600;
  text-align: left;
  padding: 5px 10px;
  border-bottom: 1px solid var(--border-strong, var(--border));
  border-right: 1px solid var(--border);
  white-space: nowrap;
}
.sql-grid-head th:last-child { border-right: 0; }

.sql-grid-row td {
  padding: 4px 10px;
  border-bottom: 1px solid var(--border);
  border-right: 1px solid var(--border);
  color: var(--text);
  vertical-align: top;
  white-space: pre-wrap;
  word-break: break-word;
}
.sql-grid-row td:last-child { border-right: 0; }
.sql-grid-row:nth-child(even) td { background: var(--surface-2); }
.sql-grid-cell.is-null { color: var(--text-muted); font-style: italic; }

/* An empty result (0 rows) still draws the header — a friendly caption
   underneath it says "0 Zeilen — deine Abfrage hat kein Ergebnis geliefert." */
.sql-grid-empty {
  padding: var(--sp-3);
  color: var(--text-muted);
  font-size: 13px;
  text-align: center;
}

/* Error strip — replaces the grid entirely on failure. Monospaced so the
   raw SQLite message reads like a proper error line, not marketing copy. */
.sql-status-error {
  padding: var(--sp-3);
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--danger);
  background: var(--danger-weak, var(--surface-2));
  border-left: 3px solid var(--danger);
  white-space: pre-wrap;
  word-break: break-word;
}

/* ---- Responsive: match the Python IDE's breakpoints ---- */
@media (max-width: 1080px) {
  .sql-ide-shell.ide-with-task { grid-template-columns: 170px 1fr 260px; }
}
@media (max-width: 820px) {
  .sql-ide-shell.ide-with-task { grid-template-columns: 1fr 260px; }
  .sql-ide-shell .sql-db-sidebar { display: none; }
}

/* ---- Zertifikatsanzeige (Verwaltung → System) --------------------------------
   Zurückhaltend gehalten: dünne Linien, ruhige Flächen, kein Leuchten und keine
   Animation. Vorbild sind Entwicklerwerkzeuge, nicht Warnschilder — ein Kasten,
   der schreit, wird nach der zweiten Woche weggeklickt.
   Es werden ausschließlich Variablen benutzt, die es in tokens.css wirklich gibt;
   ein erfundener Name mit hellem Fallback wäre im dunklen Theme sofort sichtbar. */

.zert-hinweis {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin: 0 0 16px;
  padding: 10px 14px;
  border: 1px solid var(--border-strong);
  border-left: 3px solid var(--warning);
  border-radius: var(--radius-sm);
  background: var(--warning-weak);
  color: var(--text);
  font-size: 0.92rem;
  line-height: 1.45;
}

.zert-hinweis.ist-dringend {
  border-left-color: var(--danger);
  background: var(--danger-weak);
}

.zert-hinweis svg {
  flex: 0 0 auto;
  margin-top: 2px;
  color: var(--warning);
}

.zert-hinweis.ist-dringend svg { color: var(--danger); }

.zert-karte {
  max-width: 620px;
  padding: 4px 0 0;
}

.zert-kopf {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 14px;
}

.zert-kopf h3 { margin: 0; font-size: 1.05rem; }

.zert-marke {
  padding: 2px 9px;
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  font-size: 0.78rem;
  color: var(--text-muted);
}

.zert-marke[data-stufe="gut"] { color: var(--success); border-color: var(--success); }
.zert-marke[data-stufe="warnung"] { color: var(--warning); border-color: var(--warning); }
.zert-marke[data-stufe="abgelaufen"] { color: var(--danger); border-color: var(--danger); }

.zert-zeile {
  display: flex;
  gap: 16px;
  padding: 7px 0;
  border-bottom: 1px solid var(--border);
  font-size: 0.93rem;
}

.zert-zeile:last-of-type { border-bottom: none; }

.zert-label { flex: 0 0 130px; color: var(--text-muted); }

/* Namen und Adressen können lang werden (mehrere IPs) — umbrechen statt die
   Karte breit zu ziehen. */
.zert-wert { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }

.zert-meldung { margin: 14px 0 0; font-size: 0.92rem; line-height: 1.5; }
.zert-meldung.ist-warnung { color: var(--warning); }

/* Der Befehl zum Erneuern: als Fließtext lesbar, aber monospace, damit klar ist,
   dass er so eingetippt wird. */
.zert-hilfe {
  margin: 10px 0 0;
  padding: 9px 11px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--text-muted);
  font-family: var(--font-mono, monospace);
  font-size: 0.82rem;
  line-height: 1.55;
  overflow-wrap: anywhere;
}

.zert-laedt { color: var(--text-muted); font-size: 0.92rem; }

/* Urheberangabe im System-Bereich. Zurückhaltend: eine gedämpfte Zeile mit
   dünner Trennlinie darüber, kein Kasten, keine Auszeichnung. Sie soll auffindbar
   sein, nicht auffallen. */
.zert-urheber {
  max-width: 620px;
  margin: 26px 0 0;
  padding-top: 14px;
  border-top: 1px solid var(--border);
  color: var(--text-muted);
  font-size: 0.82rem;
  line-height: 1.6;
}

.zert-urheber-hinweis {
  display: block;
  margin-top: 2px;
  opacity: 0.8;
}
