:root {
  --bg: #07070a;
  --bg-2: #0d0d12;
  --panel: rgba(255, 255, 255, 0.035);
  --panel-strong: rgba(255, 255, 255, 0.07);
  --line: rgba(255, 255, 255, 0.09);
  /* Undurchsichtige Entsprechung dessen, was unter einer Karte liegt. Die
   * Stundenlinien werden hinter die Karten gezeichnet – sieht man sie *durch*
   * eine Karte, liegt das nicht an der Reihenfolge, sondern daran, dass zu
   * wenig Farbe da ist. Karten mischen deshalb gegen dieses Brett statt gegen
   * `transparent`. */
  --board: #0f0e15;
  --text: #ece9f5;
  --muted: #9c96b3;
  --violet: #a855f7;
  --gold: #e0a54a;
  --green: #8fdc4a;
  --red: #f0553d;
  --radius: 12px;
  /* Anzeigehöhe einer Stunde und Breite der Achsenspalte. */
  --hour-h: 46px;
  --axis-col: 52px;

  /* Der Schleier über `raid-calendar-bg.png`. Er ist kein Effekt, sondern die
   * Bedingung dafür, dass Text lesbar bleibt: Das Bild ist ein Raum, in dem
   * der Wochenplan hängt – nicht sein Inhalt. Ohne Schleier liegt Weiß auf
   * dem hellen Violett oben links und im Gold rechts; die Werte sind so
   * gewählt, dass die hellste Stelle des Bildes unter dem Text noch 4,5:1
   * gegen Weiß hergibt. `tools/contrast-check.js` misst das nach. */
  --scrim-top: rgb(13 13 18 / 0.52);
  --scrim-bottom: rgb(7 7 10 / 0.68);
  /* Grundton der großen Flächen, die über dem Bild liegen. */
  --surface: rgb(13 12 19 / 0.82);
  --surface-solid: rgb(10 9 14 / 0.88);
}

* {
  box-sizing: border-box;
}

html,
body {
  margin: 0;
  min-height: 100%;
}

body {
  background-color: var(--bg);
  /* Das Bild liegt unten, alles andere ist der Schleier darüber. Reihenfolge
   * in CSS ist von vorn nach hinten – deshalb steht `url()` zuletzt. */
  background-image:
    radial-gradient(1200px 700px at 15% -10%, rgba(168, 85, 247, 0.16), transparent 60%),
    radial-gradient(900px 600px at 105% 15%, rgba(224, 165, 74, 0.12), transparent 55%),
    linear-gradient(180deg, var(--scrim-top), var(--scrim-bottom) 60%),
    /* Ohne führenden Schrägstrich: Die Seite liegt auf GitHub Pages unter
     * /raid-calendar/, und "/raid-calendar-bg.png" würde dort im Repo-Root
     * landen. Lokal ist "./" genau dasselbe wie "/". */
    url("./raid-calendar-bg.png");
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  background-attachment: fixed;
  color: var(--text);
  font-family: "Segoe UI", Inter, system-ui, -apple-system, "Helvetica Neue", sans-serif;
  font-size: 15px;
  line-height: 1.45;
}

/* ---------- Grundgerüst ---------- */

.shell {
  display: grid;
  grid-template-columns: 250px minmax(0, 1fr);
  gap: 22px;
  max-width: 1680px;
  margin: 0 auto;
  padding: 26px 26px 40px;
  min-height: 100vh;
}

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

/* ---------- Linke Marken-Spalte ---------- */

.brand {
  position: sticky;
  top: 26px;
  align-self: start;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 20px 18px;
  border: 1px solid var(--line);
  border-radius: 16px;
  /* Deckend, weil die Markenspalte über dem hellsten Teil des Bildes steht.
   * Der Schleier allein reicht dort nicht –Violett gegen Weiß ist der
   * schlechteste Fall der ganzen Seite. */
  background: linear-gradient(160deg, rgb(30 22 44 / 0.88), var(--surface-solid));
  backdrop-filter: blur(10px);
}

.brand-crest {
  width: 76px;
  height: 76px;
  border-radius: 22px;
  display: grid;
  place-items: center;
  font-size: 38px;
  margin-bottom: 8px;
  background: linear-gradient(145deg, rgba(168, 85, 247, 0.35), rgba(224, 165, 74, 0.2));
  border: 1px solid rgba(255, 255, 255, 0.14);
  overflow: hidden;
}

.brand-crest img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.brand-name {
  margin: 0;
  font-size: 30px;
  font-weight: 800;
  font-style: italic;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  line-height: 1.05;
  background: linear-gradient(100deg, #c084fc, #f5d0fe 45%, var(--gold));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  overflow-wrap: anywhere;
}

.brand-tagline {
  margin: 0 0 10px;
  font-size: 13px;
  font-weight: 700;
  font-style: italic;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--muted);
}

.brand-meta {
  margin: 0;
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 4px 12px;
  font-size: 12.5px;
  border-top: 1px solid var(--line);
  padding-top: 12px;
}

.brand-meta dt {
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-size: 11px;
}

.brand-meta dd {
  margin: 0;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* ---------- Feste Raids in der Markenspalte ---------- */

.brand-lanes:not(:empty) {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--line);
}

.brand-lanes-title {
  margin: 0 0 9px;
  font-size: 11px;
  font-weight: 800;
  font-style: italic;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
}

.brand-lane {
  position: relative;
  padding: 5px 0 6px 10px;
  border-left: 2px solid color-mix(in srgb, var(--accent) 60%, transparent);
}

.brand-lane-title {
  display: flex;
  align-items: baseline;
  gap: 6px;
  font-size: 13.5px;
  font-weight: 800;
}

.brand-lane-glyph {
  font-size: 12px;
}

.brand-lane-name {
  /* Nicht der reine Spurfarbton: Dunkle Akzente (das Blau der Monatsspur
   * ist #3038a3) kommen auf der schwarzen Markenspalte nicht mehr als 2:1
   * gegen den Text, egal was dahinter liegt. Der Ton wird deshalb für die
   * Schrift aufgehellt – Punkt und Kartenrand behalten die echte Farbe. */
  color: color-mix(in srgb, var(--accent) 62%, var(--text));
}

.brand-lane-detail {
  padding-right: 62px;
  font-size: 11.5px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.brand-lane-link {
  position: absolute;
  right: 0;
  bottom: 6px;
  font-size: 11px;
  font-weight: 700;
  color: var(--muted);
  text-decoration: none;
  opacity: 0.75;
}

.brand-lane-link:hover,
.brand-lane-link:focus-visible {
  color: var(--accent);
  opacity: 1;
}

/* ---------- Kopfleiste ---------- */

.main {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.topbar {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  align-items: center;
  justify-content: space-between;
}

.week-nav {
  display: flex;
  align-items: center;
  gap: 10px;
}

.week-label {
  min-width: 260px;
  text-align: center;
}

.week-range {
  display: block;
  font-size: 21px;
  font-weight: 800;
  font-style: italic;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.week-sub {
  display: block;
  font-size: 12px;
  color: var(--muted);
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.nav-btn {
  min-width: 38px;
  height: 38px;
  padding: 0 12px;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--text);
  font-size: 18px;
  font-weight: 700;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, transform 0.1s;
}

.nav-btn:hover {
  background: var(--panel-strong);
  border-color: rgba(168, 85, 247, 0.5);
}

.nav-btn:active {
  transform: translateY(1px);
}

.nav-btn--wide {
  font-size: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.topbar-right {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
}

.tz-field {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted);
}

select {
  background: var(--panel);
  color: var(--text);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 7px 10px;
  font-size: 13px;
}

.status {
  font-size: 12px;
  color: var(--muted);
  display: flex;
  align-items: center;
  gap: 7px;
}

.status::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--green);
  box-shadow: 0 0 10px var(--green);
}

.status[data-state="error"]::before {
  background: var(--red);
  box-shadow: 0 0 10px var(--red);
}

.status[data-state="loading"]::before {
  background: var(--gold);
  box-shadow: 0 0 10px var(--gold);
}

/* ---------- Brett ---------- */

.board {
  border: 1px solid var(--line);
  border-radius: 16px;
  /* Etwas deckender als vorher: Die leere Fläche zwischen den Karten ist
   * genau die, durch die man sonst das Bild sieht – und genau dort stehen
   * die Stundenlinien, die schwächer sind als jede Textfarbe. */
  background: var(--surface-solid);
  overflow: hidden;
}

/* Derselbe Innenabstand wie `.board-body` – sonst sitzen die sieben Spalten im
   Kopf um 14 px versetzt zu denen darunter. */
.board-head {
  display: grid;
  grid-template-columns: var(--axis-col) repeat(7, minmax(0, 1fr));
  padding: 0 14px;
  border-bottom: 1px solid var(--line);
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.05), transparent);
}

.head-corner {
  border-right: 1px solid var(--line);
}

.day-head {
  padding: 12px 10px 10px;
  text-align: center;
  border-left: 1px solid var(--line);
  position: relative;
}

.day-head:first-of-type {
  border-left: 0;
}

.day-head::after {
  content: "";
  position: absolute;
  left: 18%;
  right: 18%;
  bottom: 0;
  height: 2px;
  background: var(--day-accent, transparent);
  opacity: 0.75;
}

.day-head--weekend {
  background: linear-gradient(180deg, rgba(224, 165, 74, 0.1), transparent);
}

.day-head--today {
  background: linear-gradient(180deg, rgba(168, 85, 247, 0.16), transparent);
}

.day-head--today .day-name {
  color: #fff;
}

.day-head--today::after {
  height: 3px;
  opacity: 1;
  box-shadow: 0 0 12px var(--day-accent);
}

.day-name {
  display: block;
  font-size: 13px;
  font-weight: 800;
  font-style: italic;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: #d8d3e8;
}

.day-date {
  display: block;
  font-size: 11px;
  color: var(--muted);
  letter-spacing: 0.1em;
  font-variant-numeric: tabular-nums;
}

.board-body {
  position: relative;
  padding: 0 14px 14px;
}

/* ---------- Zeitachse ---------- */

.grid {
  display: grid;
  grid-template-columns: var(--axis-col) minmax(0, 1fr);
}

/* Beschriftung sitzt nur an den Kanten der gelaufenen Abschnitte – im
   zusammengedrückten Bereich gäbe es nichts zu beschriften. */
.grid-axis {
  position: relative;
  height: var(--grid-height);
  border-right: 1px solid var(--line);
}

.grid-tick {
  position: absolute;
  right: 8px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.grid-days {
  position: relative;
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  height: var(--grid-height);
}

.grid-lines {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.grid-line {
  position: absolute;
  left: 0;
  right: 0;
  height: 1px;
  background: var(--line);
}

/* Der Tageswechsel ist die einzige Linie, die eine Aussage macht und keine
   volle Stunde markiert. */
.grid-line--day {
  background: rgba(255, 255, 255, 0.2);
}

.grid-day {
  position: relative;
  border-left: 1px solid var(--line);
}

.grid-day:first-child {
  border-left: 0;
}

.grid-day--weekend {
  background: rgba(224, 165, 74, 0.045);
}

.grid-day--today {
  background: rgba(168, 85, 247, 0.07);
  box-shadow: inset 0 0 0 1px rgba(168, 85, 247, 0.28);
}

/* ---------- Gebuchte Slots ---------- */

/* Zwei Kartenformen, zwei Bedeutungen – und die lauter gewinnt:
 *
 *   `.slot`  die gebuchte Grundlinie aus `lanes.json`. Sie läuft jede Woche,
 *            sie ist der Selbstverständliche. Sie tritt deshalb leise auf:
 *            flacher Grund, dünner Rand, gedämpfte Farbe, kleinere Schrift.
 *   `.ev`    ein echter Termin aus Discord. Der ist einmalig, der zählt heute,
 *            und deshalb lauter: heller Rand, kräftiger Balken, größere Schrift.
 *
 * Vorher war es umgekehrt – der Slot brüllte mit 19 px, der Termin flüsterte
 * mit 11 px, und das Besondere verschwand zwischen dem Gewohnten.
 *
 * Der linke Akzentbalken fehlt am Slot absichtlich: Jedes echte Event hat
 * ihn, ein gebuchter Slot nicht – daran unterscheidet das Auge sie auf einen
 * Blick. Verschwindet der Slot, sobald ein echtes Raid ihn fast ganz ersetzt:
 * eine doppelte Ankündigung ist schlimmer als keine. */
/* Ein Grundlinien-Streifen ist nie so breit wie der Termin, den er ergänzt –
 * er zieht über die volle Tagesbreite, aber nur über die Zeit, die kein
 * Termin belegt. Platz und Breite setzt `app.js` deshalb direkt; hier steht
 * nur, wie er aussieht. */
.slot {
  position: absolute;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: flex-start;
  padding: 6px 10px 7px;
  border-radius: var(--radius);
  border: 1px solid color-mix(in srgb, var(--accent) 20%, transparent);
  background: linear-gradient(155deg, color-mix(in srgb, var(--accent) 7%, var(--board)), color-mix(in srgb, var(--board) 60%, #000) 82%);
  color: var(--text);
  font: inherit;
  text-align: left;
  overflow: hidden;
  cursor: pointer;
  transition: transform 0.12s, box-shadow 0.15s, border-color 0.15s;
}

.slot:hover,
.slot:focus-visible {
  z-index: 2;
  transform: translateY(-1px);
  box-shadow: 0 8px 22px rgba(0, 0, 0, 0.5), 0 0 0 1px color-mix(in srgb, var(--accent) 45%, transparent);
  outline: none;
}

/* Ein schmaler Streifen ist die Folge einer echten Überlappung: Er zeigt, dass
 * hier zwei Dinge gleichzeitig laufen. Für mehr als die Uhrzeit ist da kein
 * Raum – und zerbrochene Wörter („19. / 30 / – / 22 / Uhr") sagen weniger als
 * eine ganze, wenn auch kleine Zeile. */
.slot-rhythm {
  display: block;
  font-size: 9px;
  font-weight: 800;
  font-style: italic;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--muted) 82%, transparent);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Gleiche Größe wie die Uhrzeile eines Termins – aber gedämpft. Die Größe
 * allein entscheidet nicht mehr darüber, was wichtig ist, das tut der
 * Kontrast. Umbrochen statt abgeschnitten. */
.slot-time {
  display: block;
  font-size: 13px;
  font-weight: 700;
  font-style: italic;
  line-height: 17px;
  letter-spacing: -0.01em;
  color: color-mix(in srgb, var(--accent) 62%, var(--muted));
  overflow-wrap: break-word;
}

.slot-name {
  display: block;
  font-size: 11.5px;
  font-weight: 600;
  line-height: 15px;
  color: color-mix(in srgb, var(--text) 58%, transparent);
  overflow-wrap: break-word;
}

/* ---------- Terminkarten ---------- */

.ev {
  position: absolute;
  display: flex;
  align-items: flex-start;
  gap: 9px;
  padding: 6px 9px;
  border-radius: 10px;
  border: 1px solid color-mix(in srgb, var(--accent) 55%, transparent);
  border-left: 4px solid var(--accent);
  background: linear-gradient(155deg, color-mix(in srgb, var(--accent) 26%, var(--board)), color-mix(in srgb, var(--board) 50%, #000) 78%);
  color: var(--text);
  font: inherit;
  text-align: left;
  overflow: hidden;
  cursor: pointer;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.45);
  transition: transform 0.12s, box-shadow 0.15s, border-color 0.15s;
}

.ev:hover,
.ev:focus-visible {
  z-index: 2;
  transform: translateY(-1px);
  box-shadow: 0 8px 22px rgba(0, 0, 0, 0.55), 0 0 0 1px color-mix(in srgb, var(--accent) 65%, transparent);
  outline: none;
}

.ev--lane {
  background: linear-gradient(155deg, color-mix(in srgb, var(--accent) 32%, var(--board)), color-mix(in srgb, var(--board) 55%, #000) 82%);
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--accent) 16%, transparent);
}

/* Ein abgesagter Termin bleibt sichtbar, trägt aber nichts mehr bei. */
.ev--dead {
  border-color: rgba(255, 255, 255, 0.13);
  border-left-color: rgba(255, 255, 255, 0.2);
  /* Die Schraffur kommt *über* einer deckenden Grundfarbe: Ein abgesagter
   * Termin behält sein Feld, sonst zöge das Raster auch über den Text. */
  background:
    repeating-linear-gradient(135deg, rgba(255, 255, 255, 0.035) 0 6px, transparent 6px 13px),
    color-mix(in srgb, var(--board) 88%, #000);
  color: var(--muted);
}

.ev--dead .ev-title {
  text-decoration: line-through;
  text-decoration-color: color-mix(in srgb, var(--red) 70%, transparent);
}

.ev--dead .ev-time {
  color: var(--red);
}

.ev--active .ev-time::before {
  content: "";
  display: inline-block;
  width: 7px;
  height: 7px;
  margin-right: 6px;
  border-radius: 50%;
  background: var(--green);
  box-shadow: 0 0 8px color-mix(in srgb, var(--green) 70%, transparent);
  vertical-align: middle;
  animation: pulse 1.9s ease-in-out infinite;
}

@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.35; }
}

.ev--continues {
  mask-image: linear-gradient(180deg, #000 calc(100% - 16px), transparent);
}

.ev-cover {
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  border-radius: 8px;
  object-fit: cover;
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: var(--panel-strong);
}

.ev-text {
  min-width: 0;
  display: flex;
  flex-direction: column;
}

/* Die Zeilenhöhen sind feste Pixelwerte, weil `app.js` daraus die Kartenhöhe
 * rechnet (CARD_CHROME / TITLE_LINE). Verschiebt sich eine Schrift hier, muss
 * die Konstante dort mitgehen – sonst schneidet die Karte den Namen ab. */
.ev-time {
  display: block;
  font-size: 13px;
  font-weight: 800;
  font-style: italic;
  line-height: 17px;
  letter-spacing: 0.02em;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.ev-title {
  display: -webkit-box;
  -webkit-line-clamp: var(--title-lines, 3);
  line-clamp: var(--title-lines, 3);
  -webkit-box-orient: vertical;
  font-size: 13.5px;
  font-weight: 800;
  line-height: 17px;
  letter-spacing: 0.005em;
  overflow: hidden;
  overflow-wrap: anywhere;
}

.ev-rhythm {
  display: block;
  margin-top: 2px;
  font-size: 9.5px;
  font-weight: 700;
  line-height: 12px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Eine zu schmale Karte macht die Uhrzeit kleiner, bevor sie irgendetwas
 * kürzt: Sie ist bei einem Termin das Wichtigste, am Zeitraum darf nichts
 * fehlen. Welche Stufe nötig ist, misst `fitTimeLine` – es liest `scrollWidth`,
 * statt die Kartenbreite hochzurechnen. Grund: Das Coverbild nimmt dem Text ein
 * Drittel, ohne dass man das der Karte von außen ansieht. */
.ev-time--tight {
  font-size: 11.5px;
  letter-spacing: 0;
}

.ev-time--tightest {
  font-size: 10.5px;
  letter-spacing: 0;
}

/* Letzte Stufe: umbrechen statt abschneiden. Eine Zeile mehr, aber der
 * vollständige Zeitraum steht da. */
.ev-time--wrap {
  font-size: 10.5px;
  letter-spacing: 0;
  white-space: normal;
  text-overflow: clip;
}

/* ---------- Leerzustand ---------- */

.board-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 46px 20px;
  text-align: center;
  color: var(--muted);
  font-size: 14px;
}

.board-empty--error {
  border-top: 1px solid color-mix(in srgb, var(--red) 34%, transparent);
  background: color-mix(in srgb, var(--red) 8%, transparent);
}

.board-empty strong {
  font-size: 17px;
  font-weight: 800;
  font-style: italic;
  letter-spacing: 0.03em;
  color: var(--text);
}

.board-empty span {
  max-width: 62ch;
}

.board-empty-note {
  font-size: 12px;
  color: var(--muted);
  font-family: ui-monospace, "Cascadia Mono", Consolas, monospace;
}

.board-empty-link {
  margin-top: 4px;
  padding: 7px 14px;
  border-radius: 8px;
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--text);
  font-size: 12.5px;
  text-decoration: none;
}

.board-empty-link:hover {
  background: var(--panel-strong);
}

/* ---------- Fußzeile ---------- */

.legend {
  display: flex;
  flex-wrap: wrap;
  gap: 10px 26px;
  align-items: center;
  padding: 14px 18px;
  border: 1px solid var(--line);
  border-radius: 14px;
  /* Kleinste Schrift der Seite (12,5 px) – deshalb deckend statt transparent. */
  background: var(--surface-solid);
  font-size: 12.5px;
  color: var(--muted);
}

.legend-item {
  display: flex;
  align-items: center;
  gap: 8px;
}

.legend-dot {
  width: 10px;
  height: 10px;
  border-radius: 3px;
  background: var(--accent, var(--violet));
  flex: 0 0 auto;
  box-shadow: 0 0 10px color-mix(in srgb, var(--accent, var(--violet)) 55%, transparent);
}

.legend strong {
  color: var(--text);
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  font-size: 11.5px;
}

/* ---------- Detailpanel ---------- */

.detail {
  position: fixed;
  top: 0;
  right: 0;
  height: 100%;
  width: min(400px, 92vw);
  padding: 26px 24px;
  background: linear-gradient(180deg, #12101a, #08070c);
  border-left: 1px solid var(--line);
  box-shadow: -24px 0 60px rgba(0, 0, 0, 0.6);
  transform: translateX(102%);
  transition: transform 0.22s ease;
  overflow-y: auto;
  z-index: 20;
}

.detail[data-open="true"] {
  transform: translateX(0);
}

.detail-close {
  position: absolute;
  top: 14px;
  right: 16px;
  width: 32px;
  height: 32px;
  border-radius: 8px;
  border: 1px solid var(--line);
  background: var(--panel);
  color: var(--text);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
}

.detail-cover {
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  border-radius: 12px;
  margin-bottom: 18px;
  background: var(--panel);
}

.detail-kind {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--accent, var(--violet));
}

.detail-title {
  margin: 6px 0 10px;
  font-size: 24px;
  font-weight: 800;
  font-style: italic;
  letter-spacing: 0.02em;
  line-height: 1.15;
}

.detail-lane {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin-bottom: 14px;
  padding: 4px 11px;
  border-radius: 999px;
  border: 1px solid color-mix(in srgb, var(--accent) 45%, transparent);
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  font-size: 11px;
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--accent);
}

.detail-rows {
  display: grid;
  gap: 10px;
  margin: 0 0 18px;
}

.detail-row {
  display: grid;
  grid-template-columns: 96px 1fr;
  gap: 12px;
  font-size: 13.5px;
}

.detail-row dt {
  color: var(--muted);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding-top: 2px;
}

.detail-row dd {
  margin: 0;
  overflow-wrap: anywhere;
}

.detail-description {
  padding-top: 14px;
  border-top: 1px solid var(--line);
  color: #cfc9e2;
  white-space: pre-wrap;
}

.detail-footnote {
  margin: 18px 0 0;
  font-size: 12px;
  color: var(--muted);
}

.detail-actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  margin-top: 20px;
}

.detail-actions a {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 9px 14px;
  border-radius: 9px;
  border: 1px solid color-mix(in srgb, var(--accent, var(--violet)) 45%, transparent);
  background: color-mix(in srgb, var(--accent, var(--violet)) 16%, transparent);
  color: var(--text);
  font-size: 12.5px;
  font-weight: 600;
  text-decoration: none;
}

.detail-actions a:hover {
  background: color-mix(in srgb, var(--accent, var(--violet)) 28%, transparent);
}

/* Früher stand hier ein pauschales `-webkit-line-clamp: 2` für schmale
 * Fenster. Das war eine Schätzung und hat Namen abgeschnitten, die in der
 * Karte Platz hatten. `fitCard` misst den Zeilenbedarf inzwischen selbst und
 * schreibt `--title-lines`; die Schätzung daneben hätte nur dazwischengefunkt.
 * Der Deckel hängt allein noch an der Kartenbreite, nicht am Fenster. */