/* ===================================================================
   mahiru — Gestaltungsgrundlage

   Eine Datei, eingebunden vor dem projekteigenen Stylesheet:

       <link rel="stylesheet" href="mahiru.css">
       <link rel="stylesheet" href="app.css">

   Sie bringt Farben, Takt, Grundlayout und die wiederkehrenden
   Bausteine mit. Alles Projektspezifische gehoert in die zweite
   Datei - hier wird nichts geaendert, damit alle Projekte gleich
   aussehen.

   Die Bausteine sind bewusst wenige und einfach. Was hier fehlt, baut
   das Projekt selbst - aber aus diesen Farben, diesen Abstaenden und
   diesem Takt.
   =================================================================== */

/* --- 1. Werte --------------------------------------------------- */

:root {
  /* Farben.

     Die Oberflaeche ist dauerhaft dunkel, auch wenn ein Projekt
     seinen Inhalten einen hellen Modus anbietet. Der Grundton ist
     nicht schwarz, sondern ein sehr dunkles Blaugrau - reines
     Schwarz wirkt auf grossen Flaechen hart und laesst Raender
     verschwinden. */

  /* Grundton der Inhaltsflaeche. */
  --hintergrund: #0a0a0c;

  /* Kaesten: Karten, Felder, Dialoge. Eine Spur DUNKLER als die
     Flaeche dahinter, nicht heller. Das ist ungewoehnlich und
     Absicht: die Kaesten wirken eingelassen statt aufgesetzt. */
  --flaeche: #050507;

  /* Kopf- und Fusszeile. Die einzigen durchgehend schwarzen
     Flaechen; sie setzen die Kanten der Seite. */
  --kopf: #000000;

  --text: #e9e7ee;
  --text-schwach: #8d8b98;
  --rand: #1e1e25;

  /* Der Akzent. Sparsam einsetzen - siehe 03-regeln.md. */
  --akzent: #b490fc;
  /* Derselbe Ton in Einzelwerten, damit sich die Deckkraft rechnen
     laesst: rgb(var(--akzent-rgb) / 0.4). Mit einer Hex-Angabe geht
     das nicht. */
  --akzent-rgb: 180 144 252;
  /* Gedaempft, fuer Flaechen hinter dem Akzent. */
  --akzent-schwach: #2a2136;

  --erfolg: #4c9a68;
  --fehler: #e0616a;

  /* Takt der Bewegung.

     Drei Dauern statt beliebiger Zahlen im ganzen Stylesheet: so
     laeuft alles im selben Rhythmus, und das Tempo laesst sich an
     einer Stelle aendern.

       kurz    Rueckmeldung unter dem Finger (Farbe, Druck)
       mittel  Felder, die auf- und zugehen
       lang    ganze Ansichten und Auftritte

     Die Beschleunigung faellt zum Ende hin steil ab: die Bewegung
     kommt schnell in Gang und legt sich sanft hin. Das wirkt
     schneller, als es ist. */
  --takt-kurz: 130ms;
  --takt: 220ms;
  --takt-lang: 320ms;
  --schwung: cubic-bezier(0.2, 0.85, 0.3, 1);
  --schwung-weich: cubic-bezier(0.4, 0, 0.2, 1);

  /* Abstaende. Eine Reihe, keine krummen Zwischenwerte. */
  --luft-1: 0.25rem;
  --luft-2: 0.5rem;
  --luft-3: 0.75rem;
  --luft-4: 1rem;
  --luft-5: 1.5rem;
  --luft-6: 2rem;

  /* Rundungen. Klein fuer Bedienelemente, groesser fuer Kaesten,
     ganz rund fuer Pillen und Abzeichen. */
  --rund-klein: 0.375rem;
  --rund: 0.5rem;
  --rund-voll: 999px;

  /* Schriften. Systemschriften, nichts Nachgeladenes: die Projekte
     sollen ohne fremde Server auskommen. */
  --schrift: system-ui, -apple-system, sans-serif;
  --schrift-fest: ui-monospace, SFMono-Regular, "SF Mono", Menlo,
    "DejaVu Sans Mono", monospace;
}

/* --- 2. Grundlage ------------------------------------------------ */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html,
body {
  height: 100%;
}

body {
  margin: 0;
  font-family: var(--schrift);
  background: var(--hintergrund);
  color: var(--text);
  line-height: 1.5;
}

/* Damit das hidden-Attribut auch bei Flex- und Grid-Kindern wirkt. */
[hidden] {
  display: none !important;
}

/* Kein Zoomen per Doppeltipp. Ohne das wartet der Browser nach jedem
   Tippen etwa eine drittel Sekunde ab, ob ein zweiter folgt - die
   Bedienung fuehlt sich dadurch traege an. Der Text bleibt ueber die
   Zoomgeste der Seite und die Schriftgroesse des Systems
   vergroesserbar. */
.knopf,
button,
.symbolknopf,
input[type="range"],
label {
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}

:focus-visible {
  outline: 2px solid var(--akzent);
  outline-offset: 2px;
}

a {
  color: var(--akzent);
}

/* --- 3. Geruest --------------------------------------------------- */

/* Kopfzeile. Reicht als Anwendung auf dem Homescreen bis unter die
   Kerbe; env() gibt an, wie viel Platz freibleiben muss. Im
   gewoehnlichen Browserfenster ist der Wert null. */
.kopfzeile {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--luft-4);
  background: var(--kopf);
  border-bottom: 1px solid var(--rand);
  padding: calc(var(--luft-5) + env(safe-area-inset-top)) var(--luft-5)
    var(--luft-5);
  padding-left: calc(var(--luft-5) + env(safe-area-inset-left));
  padding-right: calc(var(--luft-5) + env(safe-area-inset-right));
}

.fusszeile {
  background: var(--kopf);
  border-top: 1px solid var(--rand);
  padding: var(--luft-3) var(--luft-5);
  padding-bottom: calc(var(--luft-3) + env(safe-area-inset-bottom));
  color: var(--text-schwach);
  font-size: 0.85rem;
}

.inhalt {
  padding: var(--luft-5);
  padding-left: calc(var(--luft-5) + env(safe-area-inset-left));
  padding-right: calc(var(--luft-5) + env(safe-area-inset-right));
}

/* --- 4. Logo ------------------------------------------------------ */

/* Markup und Namensregel stehen in logo.md. */

.logo {
  display: flex;
  align-items: center;
  gap: 0.625rem;
  margin: 0;
  min-width: 0;
}

.logo-marke {
  width: 2rem;
  height: 2rem;
  flex-shrink: 0;
}

.logo-flaeche {
  fill: var(--akzent);
}

/* Dieselbe Farbe wie die Kaesten, damit die Marke wirkt, als waere
   sie aus der Flaeche ausgestanzt. */
.logo-seite {
  fill: var(--flaeche);
}

/* Der Name ist als Pfad geschrieben, deshalb dicktengleich - sonst
   sieht "~/" wie ein Versehen aus statt wie eine Absicht. */
.logo-schrift {
  font-family: var(--schrift-fest);
  font-size: 1rem;
  letter-spacing: -0.02em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Das Pfadzeichen tritt zurueck: es gehoert zum Namen, ist aber nicht
   der Name. */
.logo-pfad,
.logo-rest {
  color: var(--text-schwach);
  font-weight: 400;
}

.logo-betont {
  font-weight: 700;
  color: var(--akzent);
}

/* --- 5. Knoepfe --------------------------------------------------- */

.knopf,
button {
  font: inherit;
  padding: var(--luft-2) var(--luft-4);
  border: 1px solid var(--rand);
  border-radius: var(--rund-klein);
  background: var(--flaeche);
  color: var(--text);
  cursor: pointer;
  transition:
    background-color var(--takt-kurz) var(--schwung-weich),
    border-color var(--takt-kurz) var(--schwung-weich),
    color var(--takt-kurz) var(--schwung-weich),
    transform var(--takt-kurz) var(--schwung);
}

/* Die eine hervorgehobene Handlung. Hoechstens eine je Ansicht. */
.knopf.betont {
  background: var(--akzent);
  border-color: var(--akzent);
  color: #fff;
  white-space: nowrap;
}

/* Was sich nicht zurueckholen laesst. */
.knopf.gefahr {
  border-color: var(--fehler);
  color: var(--fehler);
}

button:hover:not(:disabled),
.knopf:hover {
  filter: brightness(0.95);
}

.knopf:active,
button:active:not(:disabled) {
  transform: scale(0.96);
}

button:disabled,
.knopf:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

/* Knopf, der nur ein Symbol traegt. */
.symbolknopf {
  display: grid;
  place-items: center;
  padding: var(--luft-2) var(--luft-3);
  border: 1px solid var(--rand);
  border-radius: var(--rund-klein);
  background: var(--flaeche);
  color: var(--text-schwach);
  cursor: pointer;
  transition:
    color var(--takt-kurz) var(--schwung-weich),
    border-color var(--takt-kurz) var(--schwung-weich),
    transform var(--takt-kurz) var(--schwung);
}

.symbolknopf:hover {
  color: var(--text);
}

.symbolknopf.aktiv {
  color: var(--akzent);
  border-color: var(--akzent-schwach);
}

.symbolknopf svg {
  width: 1.125rem;
  height: 1.125rem;
}

/* --- 6. Kaesten und Karten ---------------------------------------- */

.karte {
  padding: var(--luft-4);
  background: var(--flaeche);
  border: 1px solid var(--rand);
  border-radius: var(--rund);
  transition:
    border-color var(--takt) var(--schwung-weich),
    transform var(--takt-kurz) var(--schwung);
}

/* Anklickbare Karten heben sich beim Darueberfahren leicht an. */
.karte.waehlbar:hover {
  transform: translateY(-2px);
  border-color: var(--akzent-schwach);
}

.karte.gewaehlt {
  border-color: var(--akzent);
}

/* Ein schwebendes Feld: Menue, Einstellungen, Auswahl. Wird ueber das
   hidden-Attribut geschaltet - die Bewegung dazu steht in Abschnitt
   9. Der umgebende Behaelter braucht position: relative. */
.feld {
  position: absolute;
  top: 3.5rem;
  right: var(--luft-4);
  z-index: 10;
  width: min(20rem, calc(100vw - 2rem));
  max-height: 60vh;
  overflow-y: auto;
  padding: var(--luft-4);
  background: var(--flaeche);
  border: 1px solid var(--rand);
  border-radius: var(--rund);
  box-shadow: 0 0.75rem 2rem rgb(0 0 0 / 0.7);
}

.feld h2 {
  margin: 0 0 var(--luft-3);
  font-size: 0.9rem;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-schwach);
}

/* --- 7. Kleinteile ------------------------------------------------ */

/* Hinweis, wenn nichts da ist. Nie eine leere Flaeche stehenlassen. */
.leer {
  color: var(--text-schwach);
  font-size: 0.9rem;
  margin: var(--luft-3) 0;
}

.warnung {
  color: var(--fehler);
  font-size: 0.9rem;
}

.abzeichen {
  display: inline-grid;
  place-items: center;
  min-width: 1.5rem;
  height: 1.5rem;
  padding: 0 0.375rem;
  border-radius: var(--rund-voll);
  background: var(--akzent-schwach);
  color: var(--akzent);
  font-size: 0.8rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* Fortschritt. Der Balken laeuft zum neuen Wert, statt zu springen. */
.balken {
  height: 3px;
  border-radius: var(--rund-voll);
  background: var(--rand);
  overflow: hidden;
}

.balken > * {
  display: block;
  height: 100%;
  background: var(--akzent);
  transition: width var(--takt-lang) var(--schwung);
}

/* Regler. */
input[type="range"] {
  flex: 1;
  min-width: 0;
  accent-color: var(--akzent);
}

.regler-zeile {
  display: flex;
  align-items: center;
  gap: 0.625rem;
}

/* Kopfzeile einer Einstellung: Name links, Wert rechts. */
.einstellung-kopf {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--luft-3);
  margin-bottom: var(--luft-2);
  font-size: 0.9rem;
}

.einstellung-kopf .wert {
  color: var(--akzent);
  font-variant-numeric: tabular-nums;
}

/* Eingabefelder. */
input[type="text"],
input[type="password"],
input[type="search"],
input[type="number"],
select,
textarea {
  font: inherit;
  width: 100%;
  padding: var(--luft-2) var(--luft-3);
  border: 1px solid var(--rand);
  border-radius: var(--rund-klein);
  background: var(--hintergrund);
  color: var(--text);
  transition: border-color var(--takt-kurz) var(--schwung-weich);
}

input:focus,
select:focus,
textarea:focus {
  border-color: var(--akzent);
}

::placeholder {
  color: var(--text-schwach);
}

/* --- 8. Zahlen und Tabellen --------------------------------------- */

/* Ueberall, wo Zahlen untereinanderstehen oder sich aendern:
   gleich breite Ziffern, sonst huepft das Layout. */
.zahl,
td.zahl,
.wert {
  font-variant-numeric: tabular-nums;
}

.vergleich {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.85rem;
}

.vergleich th,
.vergleich td {
  padding: var(--luft-2) var(--luft-1);
  text-align: left;
  border-bottom: 1px solid var(--rand);
  vertical-align: top;
}

.vergleich th {
  color: var(--text-schwach);
  font-weight: 400;
}

/* --- 9. Bewegung -------------------------------------------------- */

/* Felder und Ansichten werden ueber das hidden-Attribut geschaltet,
   also ueber display: none. Daran liess sich frueher nichts
   animieren. Zwei Bausteine loesen das:

     transition-behavior: allow-discrete  laesst display mitlaufen;
         beim Ausblenden bleibt die Darstellung bis zum Ende der
         Bewegung stehen und faellt erst dann weg.

     @starting-style  gibt den Zustand an, aus dem heraus ein gerade
         erst dargestelltes Element hereinkommt.

   Dass [hidden] display mit !important setzt, stoert nicht: laufende
   Uebergaenge stehen in der Rangfolge ueber wichtigen Angaben des
   Stylesheets. */

.feld {
  transition:
    opacity var(--takt) var(--schwung),
    transform var(--takt) var(--schwung),
    display var(--takt) allow-discrete;
}

.feld[hidden] {
  opacity: 0;
  transform: translateY(-0.45rem) scale(0.975);
}

@starting-style {
  .feld:not([hidden]) {
    opacity: 0;
    transform: translateY(-0.45rem) scale(0.975);
  }
}

/* Ganze Ansichten. */
.ansicht {
  transition:
    opacity var(--takt-lang) var(--schwung),
    transform var(--takt-lang) var(--schwung),
    display var(--takt-lang) allow-discrete;
}

.ansicht[hidden] {
  opacity: 0;
  transform: scale(0.985);
}

@starting-style {
  .ansicht:not([hidden]) {
    opacity: 0;
    transform: scale(0.985);
  }
}

/* Waehrend des Ausblendens ist ein Element noch da - unsichtbar, aber
   vorhanden. Ohne diese Zeile finge es in dieser Drittelsekunde noch
   Klicks ab, die dem darunterliegenden gelten. */
.feld[hidden],
.ansicht[hidden] {
  pointer-events: none;
}

/* Listen bauen sich von oben nach unten auf. Die Verzoegerung kommt
   aus --reihe, das beim Erzeugen gesetzt wird:

       el.style.setProperty('--reihe', String(Math.min(i, 12)))

   Der Deckel ist wichtig: bei hundert Eintraegen wartete der letzte
   sonst drei Sekunden.

   backwards und nicht both - bei both bliebe transform nach dem Lauf
   unter der Regie der Animation, und das Anheben beim Darueberfahren
   griffe nicht mehr. */
@keyframes herein {
  from {
    opacity: 0;
    transform: translateY(0.6rem);
  }
}

.gestaffelt {
  animation: herein var(--takt-lang) var(--schwung) backwards;
  animation-delay: calc(var(--reihe, 0) * 30ms);
}

/* Auftritt einer Seite oder eines Dialogs. */
@keyframes auftritt {
  from {
    opacity: 0;
    transform: translateY(0.9rem) scale(0.985);
  }
}

.auftritt {
  animation: auftritt var(--takt-lang) var(--schwung) backwards;
}

/* Wer im System keine Bewegung moechte, bekommt keine. Nicht auf null
   setzen: Uebergaenge, die mit display arbeiten, brauchen ein Ende,
   das ausgeloest wird. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-delay: 0ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0ms !important;
  }
}
