/* ============================================================================
   Layout.

   Auch diese Datei geht ueber das Kern-Inventar hinaus — das Designsystem liefert die
   Seitenleiste, aber kein Seitengeruest. Bewusst minimal gehalten: Layout ist
   Sache der Screens, hier stehen nur die Traeger, die jeder Screen braucht.
   ========================================================================== */

/* --- Seitengeruest: Kopfleiste, Seitenleiste und Inhalt ------------------- *
 * Drei Traeger. Die Kopfleiste liegt ueber beiden Spalten und traegt, was zur
 * PERSON und zur ganzen Anwendung gehoert: Marke, Suche, eigenes Menue. Die
 * Seitenleiste traegt nur noch die ORTE der Anwendung. Die Trennung ist der
 * Punkt: links die Plattform, oben man selbst.
 *
 * Der Inhalt schliesst links ohne Rand an die Seitenleiste an und nutzt immer
 * die volle Breite — keine Hoechstbreite, keine wachsende Luecke. Unter der
 * Umbruchbreite wird aus der Spalte ein waagerechter Streifen unter der
 * Kopfleiste; dann braucht der Inhalt links wieder seinen Rand.            */
.layout {
  display: grid;
  grid-template-columns: var(--size-sidebar) minmax(0, 1fr);
  grid-template-rows: auto minmax(0, 1fr);

  /* `dvh` statt `vh`: Am Handy waechst und schrumpft die Browserleiste, und
     `vh` rechnet mit der GROESSTEN Hoehe — die Seite waere immer ein Stueck
     zu hoch und schoebe den Fuss unter die Leiste. `vh` bleibt als Rueckfall
     fuer Browser ohne `dvh` davor stehen.                                  */
  min-block-size: 100vh;
  min-block-size: 100dvh;

  /* Wie weit die Kopfleiste gerade ausgewichen ist — siehe unten. */
  --topbar-shift: 0px;
}

/* Ueber beiden Spalten und oben klebend: Suche und eigenes Menue sind von
   jeder Stelle der Seite aus erreichbar, auch weit unten in einer Liste. */
/* Die Kopfleiste weicht beim Blaettern nach unten aus und kommt beim ersten
   Blaettern nach oben zurueck (Issue #66). Wie weit sie verschoben ist, steht
   in EINER Variablen: Die Seitenleiste haengt daran und rutscht mit, sonst
   klaffte oben eine Luecke, sobald die Leiste weg ist. Ohne Skript wird
   data-topbar nie gesetzt, und alles steht wie bisher (NFA-13).            */
.layout[data-topbar="hidden"] {
  --topbar-shift: calc(-1 * var(--size-topbar));
}

.layout__topbar {
  grid-column: 1 / -1;
  position: sticky;
  inset-block-start: 0;
  z-index: var(--layer-topbar);
  transform: translateY(var(--topbar-shift));
  transition: transform var(--motion-fast) var(--motion-ease);
}

.layout__sidebar {
  /* Die Leiste beginnt unter der Kopfleiste und bleibt beim Blaettern stehen:
     100vh minus Kopfleiste, sonst schoebe die eigene Mindesthoehe sie nach
     unten aus dem Bild. Weicht die Kopfleiste aus, rueckt die Leiste nach —
     sie liegt unter ihr, nicht neben ihr. */
  position: sticky;
  inset-block-start: calc(var(--size-topbar) + var(--topbar-shift));
  block-size: calc(100vh - var(--size-topbar) - var(--topbar-shift));
  block-size: calc(100dvh - var(--size-topbar) - var(--topbar-shift));
  min-block-size: 0;
  overflow-y: auto;
  transition: inset-block-start var(--motion-fast) var(--motion-ease);
}

.layout__main {
  min-inline-size: 0;
  padding-inline: 0 var(--space-5);

  /* Luft zwischen Kopfleiste und Inhalt (Issue #66) — vorher sass die erste
     Ueberschrift dicht unter der Leiste. */
  padding-block: var(--space-5) var(--space-6);

  /* clip, nicht hidden: kein Scrollcontainer, nur keine Seitenbreite aus
     Dingen, die rechts hinausragen — etwa unsichtbare, aber gelayoutete
     Tooltips am rechten Rand. Senkrecht bleibt alles sichtbar.             */
  overflow-x: clip;
}

/* --- Tab-Leiste: die Navigation am Handy ---------------------------------- *
 * Fest am unteren Rand, denn dort kommt der Daumen an. Sie liegt ueber dem
 * Inhalt (dieselbe Ebene wie die Kopfleiste) und traegt den unteren
 * Geraeteeinzug selbst — auf einem iPhone laege sie sonst unter dem
 * Home-Indikator. Ueber 60 rem gibt es sie nicht, dort steht die
 * Seitenleiste.                                                             */
.layout__tabbar {
  display: none;
}

@media (width < 60rem) {
  .layout {
    grid-template-columns: minmax(0, 1fr);
  }

  /* Die Seitenleiste verschwindet aus dem Fluss, die Tab-Leiste tritt an ihre
     Stelle. Zwei Klassen, damit die Ausblendung jede Einzelklasse schlaegt,
     die der Leiste sonst ein display gibt (sidebar--flex) — app.css kommt als
     letztes Blatt und gewaenne bei gleicher Spezifitaet. */
  .layout > .layout__sidebar {
    display: none;
  }

  .layout > .layout__tabbar {
    position: fixed;
    inset-inline: 0;
    inset-block-end: 0;
    z-index: var(--layer-topbar);
    display: flex;
    padding-block-end: calc(var(--space-1) + var(--space-safe-bottom));
  }

  .layout__main {
    padding-inline-start: var(--space-5);

    /* Platz fuer die Leiste, sonst verdeckt sie das Ende jeder Seite. */
    padding-block-end: calc(
      var(--size-tabbar) + var(--space-6) + var(--space-safe-bottom)
    );
  }
}

/* --- Stapel: gleichmaessiger Abstand zwischen Geschwistern ---------------- */
.stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

/* Derzeit gleich weit wie der Stapel selbst — die Karten wurden mit 8 px zu
   gedrängt. Die Klasse bleibt, damit die Stufe wieder enger werden kann,
   ohne jedes Markup anzufassen. */
.stack--tight {
  gap: var(--space-4);
}

.stack--loose {
  gap: var(--space-6);
}

/* --- Spalten -------------------------------------------------------------- *
 * Mehrere Listen nebeneinander. Bricht von selbst auf eine Spalte, sobald der
 * Platz nicht mehr reicht — ohne Umbruchpunkt im Stylesheet.                 */
.columns {
  display: grid;

  /* `min(300px, 100%)` statt `300px`: Auf einem 320-px-Geraet ist die Spalte
     schmaler als 300 px, und eine feste Mindestbreite schoebe den Inhalt aus
     der Karte heraus (Issue #14). Mit `min()` gibt die Spalte nach, sobald der
     Platz kleiner ist als der Wunsch.                                       */
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));

  /* Nicht strecken: Sonst zieht der laengste Eintrag alle anderen mit in die
     Hoehe und hinterlaesst leere Flaechen. */
  align-items: start;
  gap: var(--space-4) var(--space-6);
}

/* --- Tabellen ------------------------------------------------------------- *
 * Die Terminfindungs-Matrix ist der wichtigste Screen und im Kern eine
 * Tabelle. Sie gehoert in eine echte <table> — nicht in Div-Raster: nur so
 * lesen Screenreader Zeile und Spalte vor.
 * Der Wrapper ist Pflicht, sonst schiebt die Matrix auf dem Handy die ganze
 * Seite waagerecht.                                                          */
.table-wrap {
  overflow-x: auto;

  /* Anker fuer alles, was darin absolut steht — etwa ein `visually-hidden` in
     einer Kopfzelle weit rechts. Ohne diesen Anker misst es sich am Dokument
     statt am Rahmen, bleibt beim Scrollen der Tabelle zurueck und macht die
     ganze Seite waagerecht verschiebbar (Issue #14).                        */
  position: relative;
}

.table {
  inline-size: 100%;
  border-collapse: collapse;
  color: var(--zone-text-strong);
}

.table th,
.table td {
  padding: var(--table-padding-block) var(--table-padding-inline);
  text-align: start;
  vertical-align: middle;
  font-weight: 700;
  border-block-end: var(--border-hairline) solid var(--zone-border);
}

.table thead th {
  font-size: var(--font-size-small);
  color: var(--zone-text-quiet);
  font-weight: 700;
  white-space: nowrap;
}

/* Senkrechte Linien trennen die Spalten. Die erste Zelle jeder Zeile bekommt
   keine — auch die Zeilenbeschriftung nicht, die ein <th> ist.

   th und td stehen bewusst getrennt und in dieser Reihenfolge: Gruppiert
   fordern ihre Spezifitäten gegenläufige Reihenfolgen (K-24). */
.table--center td {
  text-align: center;
}

.table th:not(:first-child) {
  border-inline-start: var(--border-hairline) solid var(--zone-border);
}

.table td:not(:first-child) {
  border-inline-start: var(--border-hairline) solid var(--zone-border);
}

.table--center th:not(:first-child) {
  text-align: center;
}

.table__highlight {
  background: var(--bg-region);
  color: var(--zone-text-strong);
}

/* Antwortzelle: Das Icon sitzt mittig, egal wie hoch die Zeile wird. Eine
   Zielgröße braucht sie nicht — sie ist Anzeige, kein Bedienelement. */
.table__answer {
  display: flex;
  align-items: center;
  justify-content: center;
}

/* --- Nur fuer Screenreader ------------------------------------------------ */
.visually-hidden {
  position: absolute;

  /* stylelint-disable-next-line declaration-property-value-disallowed-list --
     Die 1-Pixel-Box ist das bekannte Muster, um Inhalt fuer Sehende zu
     verbergen und fuer Screenreader lesbar zu halten. Ein Token waere hier
     sinnlos: der Wert ist keine Gestaltungsentscheidung, sondern Technik. */
  inline-size: 1px;

  /* stylelint-disable-next-line declaration-property-value-disallowed-list -- s. o. */
  block-size: 1px;
  padding: 0;

  /* stylelint-disable-next-line declaration-property-value-disallowed-list -- s. o. */
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* --- Kopfleiste ----------------------------------------------------------- *
 * Marke links, Suche in der Mitte, das Eigene rechts. Sie ist die einzige
 * Flaeche, auf der die PERSON steht — die Seitenleiste daneben fuehrt nur
 * noch zu Orten der Anwendung. Bis hierher war beides gemischt.
 *
 * Ohne JavaScript vollstaendig: Die Suche ist ein GET-Formular, das eigene
 * Menue ein <details> (NFA-13).                                             */
.topbar {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  min-block-size: var(--size-topbar);
  padding-inline: var(--space-edge-left) var(--space-5);

  /* Als WebApp im Vollbild liegt oben die Statusleiste des Geraets. Im
     Browser ist der Einzug 0 und die Regel aendert nichts.                 */
  padding-block-start: var(--space-safe-top);
  border-block-end: var(--border-hairline) solid var(--zone-border);
}

/* Zwei Knoepfe als EIN Stueck: „Meine Spielrunden" und das Plus als Anhang daran.
   Zwei Ziele braucht es (Liste und Anlegen), ein Knopf soll es sein — also
   stossen sie ohne Luecke aneinander, die Rundungen weichen nach aussen und
   eine Haarlinie trennt die Flaechen (Issue #37).                          */
.topbar__pair {
  display: flex;
  align-items: center;
}

/* Der vordere Knopf gibt seine rechte Kante ganz ab — sonst staenden zwei
   Haarlinien aufeinander und die Naht waere doppelt so dick wie jede andere
   Kante der Leiste. */
.topbar__pair > .button:first-child {
  border-inline-end: 0;
  border-start-end-radius: 0;
  border-end-end-radius: 0;
}

/* Das Plus ist quadratisch wie ein Icon-Knopf, traegt aber die Flaeche des
   Knopfs daneben — es ist dessen Ende, kein eigenes Element. Seine linke
   Kante ist die Naht zwischen beiden. */
.topbar__add {
  inline-size: var(--size-target-min);
  padding-inline: 0;
  border-start-start-radius: 0;
  border-end-start-radius: 0;
}

/* Die Marke misst die Breite der Seitenleiste, damit die Suche auf derselben
   Kante beginnt wie der Inhalt darunter. Der Zwischenraum der Leiste gehört
   dabei zur Marke — sonst stünde das Feld genau um ihn zu weit rechts, und
   auf dem Bildschirm sieht man die Kante sofort (Issue #37). */
.topbar__brand {
  flex: none;
  inline-size: calc(
    var(--size-sidebar) - var(--space-edge-left) - var(--space-4)
  );
  padding-inline-start: 0;
  color: inherit;
  text-decoration: none;
}

.topbar__search {
  flex: 1;
  min-inline-size: var(--size-search-min);
  max-inline-size: var(--size-search-max);
}

/* Der Weg zur Suchflaeche, wenn fuer das Feld kein Platz mehr ist. Er steht
   erst unter 24 rem im Bild — siehe die Umbruchbreite weiter unten. */
.topbar__search-link {
  display: none;
}

/* Die Symbole stehen dicht beieinander: Meldungen, Glocke und das eigene
   Menue sind eine Gruppe, kein Nebeneinander einzelner Knoepfe. Kein
   Zwischenraum — die 44-px-Zielflaechen stossen direkt aneinander und bleiben
   dabei unberuehrt (Issue #37). Zwischen den Symbolen selbst liegt damit nur
   noch die Luft, die jeder Knopf um sein Icon traegt. Das Paar davor bekommt
   seinen eigenen Abstand, sonst klebte „Meine Spielrunden" an der Glocke.       */
.topbar__actions {
  margin-inline-start: auto;
  display: flex;
  align-items: center;
  gap: 0;
  flex: none;
}

.topbar__actions > .topbar__pair {
  margin-inline-end: var(--space-3);
}

/* Groesser als im Fliesstext: In der Leiste steht kein Wort daneben, das
   Symbol traegt die Aussage allein. Weil es nach innen in seinen 44-px-Knopf
   hineinwaechst, ruecken die Symbole dabei zusammen, ohne dass eine
   Zielflaeche schrumpft — 24 px statt 20 px lassen 20 px statt 24 px
   dazwischen. Ueber --size-icon wie .icon--nav, nicht ueber die
   Schriftgroesse.                                                         */
.topbar .icon-button > .icon {
  --size-icon: var(--size-icon-topbar);
}

/* Der Ausloeser des eigenen Menues: Avatar, Name, Pfeil. Als <summary> bringt
   er keinen eigenen Stil mit. */
.topbar__user {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-block-size: var(--size-target-min);
  padding-inline: var(--space-2);
  border-radius: var(--radius-control);
  color: var(--zone-text-strong);
}

.topbar__user:hover {
  background: var(--bg-sunken);
}

.topbar[data-zone] .topbar__user > .icon {
  color: var(--zone-text-quiet);
}

.dropdown[open] > .topbar__user > .icon {
  transform: rotate(180deg);
}

/* Unter der Umbruchbreite traegt die Kopfleiste die Marke nicht mehr in
   Seitenleisten-Breite, und der Name neben dem Avatar faellt weg — Platz hat
   dort die Suche noetiger. */
@media (width < 60rem) {
  .topbar {
    padding-inline: var(--space-4);
    gap: var(--space-3);
  }

  .topbar__brand {
    inline-size: auto;
  }

  .topbar__user > .nav__user-name {
    display: none;
  }
}

/* Eng wird zuerst der Text knapp, nicht das Feld: Der Name der Marke und die
   Beschriftung am Knopf verschwinden, Marke, Suche und Menü bleiben. */
@media (width < 48rem) {
  .topbar__brand > span:not(.brand__mark) {
    display: none;
  }

  .topbar__label {
    display: none;
  }

  /* „Meine Spielrunden" und das Plus fallen ganz weg: Zu den Spielrunden führt unten
     die Tab-Leiste, und angelegt wird dort. Was bleibt, ist das, was es sonst
     nirgends gibt — Suche, Meldungen, eigenes Menü. */
  .topbar__pair {
    display: none;
  }
}

/* Zuletzt gibt das Suchfeld selbst nach (Issue #14). Auf 320 px — der Breite,
   gegen die WCAG 1.4.10 prüft — bleiben neben Marke, Meldungen und eigenem
   Menü noch 50 px für das Feld; darin ist nichts mehr zu lesen und die Leiste
   schiebt die ganze Seite nach rechts. Die Grenze liegt deshalb dort, wo das
   Feld seine Mindestbreite gerade noch bekommt: unter 24 rem tritt an seine
   Stelle die Lupe, die auf `/search` führt — dieselbe Suche, dasselbe Feld,
   nur auf der ganzen Breite. */
@media (width < 24rem) {
  .topbar__search {
    display: none;
  }

  .topbar__search-link {
    display: inline-flex;
  }
}

/* Wer Bewegung abbestellt hat, bekommt das Ausweichen der Kopfleiste ohne
   Fahrt — sie ist dann einfach da oder nicht. */
@media (prefers-reduced-motion: reduce) {
  .layout__topbar,
  .layout__sidebar {
    transition: none;
  }
}
