/* ============================================================
   BIER MET MIJ: donker, minimalistisch designsysteem
   ============================================================ */

:root {
  /* Achtergronden */
  --bg: #0b0b0d;
  --surface: #141418;
  --surface-2: #1c1c22;
  --surface-3: #26262e;
  --border: #2a2a33;
  --border-strong: #3a3a45;

  /* Tekst: alle drie halen ≥4.5:1 op elke achtergrond hierboven.
     --text-faint was #6b6b76 (3,2–3,7:1): te licht om in een donkere kroeg
     te lezen, terwijl het o.a. de tabbalk-labels draagt. */
  --text: #f4f4f5;
  --text-dim: #a1a1aa;
  --text-faint: #8f8f9a;
  /* Puur decoratief grijs (lijnen, uitgegrijsde iconen), nooit voor tekst. */
  --ink-mute: #6b6b76;

  /* Accent (bier-goud), kan door de gebruiker aangepast worden */
  --accent: #f5a524;
  --accent-strong: #e08c0b;
  --accent-soft: rgba(245, 165, 36, 0.14);
  /* Dezelfde accentkleur als losse getallen, voor waar er een
     doorzichtigheid overheen moet. js/app.js zet hem om bij het wisselen
     van thema; deze regel is de stand voor het laden. */
  --accent-rgb: 245, 165, 36;
  --on-accent: #1a1200;
  --accent-hi: #ffc95a;

  /* Status */
  --danger: #ef4444;
  --danger-soft: rgba(239, 68, 68, 0.14);
  --success: #22c55e;
  --live: #34d399;

  /* Vorm & ritme */
  --r-sm: 10px;
  --r-md: 16px;
  --r-lg: 22px;
  --r-full: 999px;
  --gap: 16px;

  /* Zachte waas: de vulling van elk vlak dat geen lijst is (kaarten, tegels,
     badges, uitklappers). Geen rand en geen egale kleur, maar een verloop dat
     naar onderen uitdooft, zodat een vlak niet als hokje aan het scherm
     geplakt zit. Wit is bewust: het werkt op elke achtergrond, ook in een
     sheet, en het blijft kloppen als de gebruiker het accent verandert.
     --waas-goud haalt zijn kleur wél uit het accent, dus die verkleurt mee. */
  --waas: linear-gradient(170deg, rgba(255,255,255,.062), rgba(255,255,255,.014));
  --waas-druk: linear-gradient(170deg, rgba(255,255,255,.10), rgba(255,255,255,.03));
  --waas-goud: linear-gradient(170deg, var(--accent-soft), rgba(255,255,255,.012));

  --shadow: 0 8px 30px rgba(0, 0, 0, 0.45);

  --nav-h: 64px;
  --safe-b: env(safe-area-inset-bottom, 0px);
  --safe-t: env(safe-area-inset-top, 0px);
  /* De hoogte van de statusbalk in de Android-app, gezet door js/native.js.
     In de browser blijft dit nul; daar zit de balk niet over de pagina. */
  --balk: 0px;

  /* Lagen, van onder naar boven. Namen in plaats van losse getallen, zodat
     nieuwe onderdelen niet hoeven te gokken waar ze thuishoren. */
  --z-sticky: 30;
  --z-nav: 40;
  --z-scrim: 60;
  --z-sheet: 61;
  /* Een foto schermvullend bekijken ligt over de vensters heen (die kun je
     eronder openhouden), maar niet over een melding: als het versturen
     misgaat moet je dat kunnen lezen zonder eerst weg te tikken. */
  --z-foto: 70;
  --z-toast: 80;
  /* De intro ligt over alles heen, ook over een toast: hij is het eerste wat
     je van de app ziet en er hoort niets doorheen te schemeren. */
  --z-intro: 90;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

html, body {
  height: 100%;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

body {
  overscroll-behavior-y: none;
  line-height: 1.5;
}

button, input, textarea { font: inherit; color: inherit; }
button { cursor: pointer; border: none; background: none; -webkit-tap-highlight-color: transparent; }
a { color: var(--accent); }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 6px; }

/* ---------- App-frame ---------- */
#app {
  max-width: 480px;
  margin: 0 auto;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  position: relative;
}

.view {
  flex: 1;
  padding: calc(var(--safe-t) + 20px) 20px calc(var(--nav-h) + var(--safe-b) + 24px);
  animation: fadeUp .28s ease-out;
}
.view.no-nav { padding-bottom: calc(var(--safe-b) + 24px); }
.hidden { display: none !important; }

@keyframes fadeUp {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  /* Alles wat beweegt, niet alleen de drie schermen van weleer: de pulserende
     ring om de check-in-knop en de laadspinner draaiden gewoon door. */
  *, *::before, *::after { animation: none !important; transition: none !important; }
  /* De spinner is de uitzondering: zonder beweging is het een stilstaand
     rondje dat niets zegt. Wel rustiger en zonder draaiing. */
  .spinner, .spinner.big { animation: pulse-soft 1.4s ease-in-out infinite !important; }
}
@keyframes pulse-soft { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }

/* ---------- Het woordmerk ----------
   Was een neonbuis als PNG met een gloed uit CSS. Nu tekst, met vier
   bellen die vanaf de punt opstijgen en bovenaan knappen.

   Waarom tekst en geen plaatje: het schaalt scherp mee op elk scherm, het
   volgt de accentkleur vanzelf, en er hoeft geen 60 kB aan afbeelding
   binnen te komen vóór het eerste dat je van de app ziet er staat.

   Alles rekent in cqw, procenten van de breedte van .bord. Dat is hier
   200 px (zie .view-home .bord verderop), maar zet je hem ooit ergens
   groter neer, dan schaalt het logo compleet mee zonder één getal.
   ---------------------------------------------------------- */
.bord {
  display: block;
  width: 100%;
  margin: 2px 0 20px;
  position: relative;
  z-index: 1;               /* vóór het glas, zodat niets erover valt */
  container-type: inline-size;
}
.bm-logo {
  display: block;
  position: relative;
  font-weight: 900;
  /* -.04em is de ondergrens: strakker en de letters raken elkaar. */
  letter-spacing: -.04em;
  font-size: 16cqw;
  line-height: 1.05;
  /* Nooit afbreken. Werd het woord breder dan zijn kader, dan viel de punt
     naar de volgende regel, en de bellen hangen aan die punt: die kwamen dan
     onder het woord uit in plaats van erboven. Met nowrap kan dat niet meer.
     16cqw is gemeten de grootste maat die binnen de 250 px past. */
  white-space: nowrap;
  /* Het kader staat gecentreerd (margin: 0 auto op .bord), maar de tekst
     erbinnen stond links. Het woord is smaller dan zijn kader, dus bleef de
     overgebleven ruimte helemaal rechts staan en hing het logo een paar pixels
     naar links. Dit centreert de tekst in het kader; de punt schuift mee, en
     omdat de bellen aan de punt hangen schuiven die vanzelf mee. */
  text-align: center;
  color: var(--text);
  /* Dit was eerst 27cqw en daarna 15cqw, en allebei lieten ze te veel lucht
     boven het woord staan: het logo zakte naar het midden terwijl het
     bovenaan hoort te hangen.

     Nu 9cqw. De bellen hebben die ruimte niet nodig om te bestaan, want ze
     staan absoluut geplaatst: ze mogen gerust boven dit blok uitkomen, daar
     zit alleen nog de bovenmarge van .view en die is minstens 20 px plus de
     inkeping van het toestel. Dit getal bepaalt dus alleen waar het WOORD
     staat, niet hoe ver de bellen komen. */
  padding-top: 9cqw;
}
/* De punt is het enige gouden ding in het woord, én het vertrekpunt van de
   bellen. inline-block, want een gewoon inline-element geeft absoluut
   geplaatste kinderen geen fatsoenlijk kader om vanaf te rekenen: de bellen
   zouden dan vanaf de regel vertrekken in plaats van vanaf de punt. */
.bm-punt {
  color: var(--accent);
  display: inline-block;
  position: relative;
}

.bm-bel {
  position: absolute;
  left: 0; bottom: .3em;
  border-radius: 50%;
  background: var(--accent);
  pointer-events: none;
  will-change: transform, background-color, box-shadow;
  animation: bel-stijg 3.4s infinite;
}

/* De kleur komt uit --accent-rgb en volgt dus het thema. Stond hier eerst
   als vaste goudwaarde, waardoor de bellen goud bleven terwijl de punt van
   het woord wel meekleurde: de animatie overschrijft de kleur van .bm-bel.

   Let op de animation-timing-function ín de keyframes: die geldt telkens
   voor het stuk dat daar begint. Zo krijgt het stijgen een rustige curve en
   het knappen een snelle, zonder dat het twee animaties hoeven te zijn. */
@keyframes bel-stijg {
  0% {
    transform: translate(0, 0) scale(.35);
    background: rgba(var(--accent-rgb), 0);
    box-shadow: 0 0 0 0 rgba(var(--accent-rgb), 0);
    animation-timing-function: cubic-bezier(.34, .02, .38, 1);
  }
  7%  { background: rgba(var(--accent-rgb), .95); }
  /* Bovenaan: op volle grootte, nog heel. */
  86% {
    transform: translate(var(--dx), var(--dy)) scale(1);
    background: rgba(var(--accent-rgb), .95);
    box-shadow: 0 0 0 0 rgba(var(--accent-rgb), .55);
    animation-timing-function: cubic-bezier(.16, .84, .3, 1);
  }
  /* Knappen: de VULLING valt weg terwijl de ring naar buiten schiet.
     Dit ging eerst met opacity, en dat werkte niet: opacity geldt voor het
     hele element, dus de ring vervaagde mee en je zag een bel die
     wegdoezelde. Vulling en ring hebben nu elk hun eigen doorzichtigheid,
     en dat leest wél als barsten. */
  92% {
    transform: translate(var(--dx), calc(var(--dy) - .8cqw)) scale(1.3);
    background: rgba(var(--accent-rgb), 0);
    box-shadow: 0 0 0 1.1cqw rgba(var(--accent-rgb), .5);
  }
  100% {
    transform: translate(var(--dx), calc(var(--dy) - 1.6cqw)) scale(1.45);
    background: rgba(var(--accent-rgb), 0);
    box-shadow: 0 0 0 2.8cqw rgba(var(--accent-rgb), 0);
  }
}

/* Vier bellen, alle vier naar rechts. Hoe later er een vertrekt, hoe kleiner
   hij begint en hoe verder hij komt: dan waaiert de sliert uit in plaats van
   dat het vier keer hetzelfde bolletje is. */
.bm-b1 { width: 3.4cqw; height: 3.4cqw; --dx: 1.0cqw; --dy: -10.5cqw; animation-delay: 0s;   }
.bm-b2 { width: 2.8cqw; height: 2.8cqw; --dx: 3.6cqw; --dy: -14.0cqw; animation-delay: .7s;  }
.bm-b3 { width: 2.2cqw; height: 2.2cqw; --dx: 6.2cqw; --dy: -17.0cqw; animation-delay: 1.4s; }
.bm-b4 { width: 1.7cqw; height: 1.7cqw; --dx: 8.8cqw; --dy: -18.0cqw; animation-delay: 2.1s; }

/* Minder beweging: dan staan de bellen stil op hun plek en knapt er niets.
   Weghalen zou het logo zijn helft kosten, dus ze blijven staan. */
@media (prefers-reduced-motion: reduce) {
  .bm-bel { animation: none; box-shadow: none; }
  .bm-b1 { transform: translate(1.0cqw,  -4.0cqw); }
  .bm-b2 { transform: translate(3.6cqw,  -8.5cqw); opacity: .75; }
  .bm-b3 { transform: translate(6.2cqw, -13.0cqw); opacity: .55; }
  .bm-b4 { transform: translate(8.8cqw, -17.0cqw); opacity: .35; }
}
.page-title { font-size: 1.625rem; font-weight: 700; letter-spacing: -.02em; margin-bottom: 4px; }
.page-sub { color: var(--text-dim); font-size: 0.875rem; margin-bottom: 22px; }

.icon-btn {
  width: 44px; height: 44px;
  display: grid; place-items: center;
  border-radius: var(--r-full);
  background: var(--surface);
  border: 1px solid var(--border);
  color: var(--text-dim);
  transition: background .18s, color .18s;
}
.icon-btn:active { background: var(--surface-2); color: var(--text); }

/* ---------- Startscherm: alles op één viewport ----------
   Het startscherm vult precies één scherm (100dvh, inclusief de padding die
   ruimte laat voor de tabbalk). Logo, glas en knoppen hebben een vaste,
   compacte hoogte; de vriendenlijst is het enige deel dat meegroeit en
   binnenin scrolt zodra er veel check-ins zijn. Zo hoeft de pagina zelf
   nooit te scrollen, op elk toestel. */
.view-home {
  height: 100dvh; /* vaste hoogte: nodig zodat de lijst binnenin kan scrollen */
  display: flex;
  flex-direction: column;
}
/* Het logo houdt zijn eigen, compacte hoogte. */
.view-home > .bord { flex: 0 0 auto; }
/* Het glasblok en het deel eronder délen de ruimte die overblijft. Op een
   lange telefoon bleef er anders 170 tot 250 px leeg tegen de onderrand
   liggen, en dat leest als een fout; dezelfde ruimte tussen twee elementen
   leest als lucht. Nu zakt het glas naar het optische midden en de strook
   naar beneden. Groeien mag, krimpen niet (1 0 auto): op een korte telefoon
   blijft alles precies zoals het was en vangt het scrollende deel eronder
   het tekort op. */
.view-home > .home { flex: 1 0 auto; }
/* Logo kleiner en gecentreerd, zodat het niet het halve scherm vult. */
/* Het woord vult zijn kader bijna helemaal, dus groter worden gaat via de
   breedte van het kader en niet via de lettergrootte: alles binnen .bord
   rekent in cqw en schaalt dus vanzelf mee, bellen inbegrepen.

   De min() is er voor smalle toestellen. Op een telefoon van 320 px blijft
   er na de zijmarges van .view maar 280 px over, en een vaste 275 px zou het
   woord dan tot tegen de rand duwen. Met 82vw krimpt het kader daar mee. */
.view-home .bord { max-width: min(275px, 82vw); margin: 0 auto 4px; }
/* ============================================================
   DRAAIKNOPPEN VOOR HET GLAS OP START

   Alles wat je met het oog wilt bijstellen staat hier bij elkaar, één regel
   per ding. De rest van de opmaak rekent hieruit, en js/app.js leest ze uit,
   dus je hoeft nergens anders iets te veranderen.

   Verander één getal tegelijk en kijk wat er gebeurt; ze werken op elkaar in.
   ============================================================ */
.view-home .glass-btn {

  /* HOE GROOT. De doorsnede van de ring, en dus van het hele blok.
     Het schaalt mee met de schermhoogte, zodat een korte telefoon de strook
     met gezichten niet kwijtraakt en een lange telefoon geen mini-glas krijgt.
     Wil je het overal groter, verhoog dan het middelste getal (39.6vh).
     Het eerste getal is de ondergrens, het laatste de bovengrens. */
  --ring: clamp(112px, calc(39.6vh - 84px), 262px);

  /* HOE VEEL LUCHT OM HET GLAS. Hoeveel kleiner het glas is dan de ring.
     Hoger getal is een kleiner glas met meer ruimte eromheen.
     Onder de 1.4 gaat het glas de ring raken. */
  --ruim: 1.5;

  /* DE SPIEGELING. Hoe lang het spiegelbeeld onder het glas doorloopt, maal
     de ring. Hij hangt los onder de ring en loopt gerust achter de tekst
     door, dus dit verschuift verder niets. Op 0 is er geen spiegeling meer. */
  --diep: 0.9;

  /* "IK DRINK IETS" HOGER OF LAGER. De ruimte tussen de onderkant van de
     ring en de tekst eronder. Dit is de enige knop die de teller verschuift;
     de andere doen daar niets aan. Negatief mag ook: dan schuift de tekst de
     ring in. Lager getal is hoger. */
  --onder: calc(var(--ring) * .02);

  /* HET GLAS HOGER OF LAGER BINNEN DE RING. Maal de hoogte van het glas.
     Positief is omlaag, negatief is omhoog. Op 0 staat het bierglas precies
     in het midden van de cirkel, maar door de voet en de schuine bovenkant
     oogt dat net iets te hoog. */
  --zak: .05;

  /* HET HELE BLOK HOGER OF LAGER. Negatief is omhoog. Wat je hier weghaalt
     komt ten goede aan de vriendenstrook eronder. */
  --hoger: 6px;

  gap: 0;
  margin-top: var(--hoger);
}
.view-home .home { min-height: 0; gap: 8px; }
/* De strook en de banners zitten samen in dit deel; het neemt de resterende
   ruimte en scrolt binnenin zodra er veel is. De pagina zelf scrolt nooit. */
.view-home .home-scroll {
  flex: 1 1 auto; min-height: 0; overflow-y: auto;
  display: flex; flex-direction: column;
}
.view-home .home-scroll > * { flex: none; }
/* De strook zakt naar de onderkant van dat deel. Is er geen ruimte over, dan
   valt de auto-marge weg en houdt de padding de lucht die er hoort te zijn. */
.view-home #liveBlock { margin-top: auto; padding-top: 16px; }
.view-home .section-label { margin-top: 14px; }

/* ---------- Vaste kop, scrollende inhoud ----------
   Zelfde opzet als Start en Kaart: de pagina zelf scrolt nooit. De kop blijft
   staan en alleen het deel eronder beweegt. Je ziet dus altijd op welk scherm
   je zit, en de knoppen bovenaan zakken niet weg zodra de lijst lang wordt.
   Gebruikt op Chat, Vrienden en Profiel. Wat vast moet staan zet je gewoon
   boven de scrollbak; alles binnen .vast-scroll beweegt mee. */
.view-vast {
  height: 100dvh;
  display: flex;
  flex-direction: column;
}
/* Alles in de kop houdt zijn eigen hoogte. Zonder dit persen lange koppen
   zichzelf plat zodra de scrollbak om ruimte vraagt. */
.view-vast > * { flex: 0 0 auto; }
.view-vast > .vast-scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}
.view-vast .page-sub { margin-bottom: 14px; }

/* De scrollbak loopt door tot onder de tabbalk. Die balk is matglas, dus de
   inhoud schuift er zichtbaar achter langs in plaats van er een stuk boven af
   te breken. Zelfde gedrag als op de gewone pagina's, waar de hele pagina
   scrolt. De ruimte die de balk inneemt zit daarom ín de bak en niet
   eromheen: zo is het laatste item nog vrij onder de balk vandaan te
   scrollen. */
.view-vast { padding-bottom: 0; }
.view-vast > .vast-scroll { padding-bottom: calc(var(--nav-h) + var(--safe-b) + 24px); }

/* Uitzondering: een scherm met een typebalk onderaan. Die moet je zien
   terwijl je typt, dus daar houdt het scherm de ruimte wél vrij. */
.view-vast.met-balk { padding-bottom: calc(var(--nav-h) + var(--safe-b) + 8px); }
.view-vast.met-balk > .vast-scroll { padding-bottom: 8px; }

/* Chat heeft een strakkere kop, want daar staan twee knoppen onder de tekst. */
.view-chat .page-sub { margin-bottom: 4px; }
.view-chat .action-row { margin: 10px 0 4px; }
.view-chat .section-label { margin-top: 16px; }

/* ---------- Oproep-kaart ---------- */
.chips { display: flex; flex-wrap: wrap; gap: 8px; }

.op-kaart { padding: 15px 17px; margin-bottom: 10px; }
.op-kop { display: flex; align-items: flex-start; gap: 10px; }
.op-emoji { font-size: 1.25rem; line-height: 1.3; flex: none; }
.op-tekst { min-width: 0; flex: 1; }
.op-tekst b { display: block; font-size: 0.9375rem; }
.op-wanneer {
  display: block;
  font-size: 0.8125rem;
  color: var(--accent);
  font-weight: 600;
  margin-top: 2px;
}
.op-bericht {
  font-size: 0.875rem;
  color: var(--text-dim);
  margin: 8px 0 0;
  font-style: italic;
}
.op-mee { font-size: 0.8125rem; color: var(--text-dim); margin-top: 10px; }
.op-mee.leeg { opacity: .7; }
.op-knoppen { display: flex; gap: 8px; margin-top: 12px; }
.op-knoppen .btn { flex: 1; }
/* Je eigen antwoord blijft zichtbaar, zodat je niet hoeft te onthouden
   wat je gekozen had. */
.btn.ghost.gekozen {
  background: var(--accent-soft);
  border-color: rgba(var(--accent-rgb), .4);
  color: var(--accent);
}

.home {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  text-align: center;
}
/* De check-in-knop ís een glas bier. Geen cirkel met een icoontje erin:
   hetzelfde glas loopt vol als je incheckt en zakt een half uur lang. */
.glass-btn {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  padding: 4px 12px 0;
  transition: transform .14s cubic-bezier(.22,1,.36,1);
}
.glass-btn:active { transform: scale(.965); }

/* ============================================================
   HET GLAS, DE KLOK EN DE SPIEGELING

   Drie lagen boven elkaar in hetzelfde vierkant:
     de schijf     (achtergrond, geeft de knop een vlak om op te drukken)
     de spiegeling (de animatie op zijn kop, onder de voet van het glas)
     het glas      (de animatie zelf)
     de ring       (de klok, bovenop)

   De maten komen binnen als --ring, --ruim en --diep, uit het blok met
   draaiknoppen hierboven. Alles hier rekent daaruit terug, en js/app.js
   leest --ruim uit om de tekening op de goede maat te zetten. Je verandert
   dus alleen daarboven iets.
   ============================================================ */
.gb-glas {
  /* De maten hieronder komen van de draaiknoppen op .view-home .glass-btn.
     De tweede waarde in elke var() is de terugval, voor het geval deze knop
     ooit buiten het startscherm belandt. Zet die terugval NIET als eigen
     regel hier neer: een waarde die op het element zelf staat wint het van
     een waarde die van boven komt, en dan doet geen enkele draaiknop nog iets. */
  --glas: calc(var(--ring, 220px) / var(--ruim, 1.5));

  position: relative;
  width: var(--ring, 220px);
  /* Het blok is precies zo groot als de ring, en verder niets. De spiegeling
     hangt er los onder en loopt gerust achter de tekst door; die telt niet
     mee. Zo verandert alleen --onder de plek van de teller, en doen de
     andere knoppen daar niets aan. */
  height: var(--ring, 220px);
}

/* Het vierkant waar de ring, de schijf en het glas in zitten. */
.gb-ringvak {
  position: relative;
  z-index: 2;          /* boven de spiegeling, die er deels achter valt */
  flex: none;
  width: var(--ring, 220px);
  height: var(--ring, 220px);
  display: grid;
  place-items: center;
}

/* De schijf erachter. Zonder dit zweeft de tekening op een zwart vlak en is
   er niets dat zegt dat je erop kunt drukken. Hij neemt de accentkleur over,
   dus hij verandert mee met het thema. De eerste regel is er voor browsers
   die color-mix nog niet kennen. */
.gb-gloed {
  position: absolute; inset: 0; border-radius: 50%;
  pointer-events: none; z-index: 0;
  background: var(--accent-soft);
  background: color-mix(in srgb, var(--accent) 8%, transparent);
  border: 1px solid var(--border);
  border: 1px solid color-mix(in srgb, var(--accent) 20%, transparent);
  box-shadow: 0 0 40px color-mix(in srgb, var(--accent) 14%, transparent);
}

/* De klok. Onzichtbaar zolang er niets af te tellen valt. */
.gb-ring {
  position: absolute; inset: 0; width: 100%; height: 100%;
  transform: rotate(-90deg);
  pointer-events: none; z-index: 3; overflow: visible;
}
/* De straal is 49.2 van de 50, en de lijn is 2.4 dik. De band loopt dus van
   48 tot 50.4 en valt daarmee precies over de rand van de schijf. De svg mag
   buiten zijn kader tekenen (overflow: visible hierboven), anders zou die
   laatste 0.4 wegvallen. Verander je dit, verander dan ook RING_STRAAL in
   js/app.js: die rekent de omtrek uit om de klok te laten leeglopen. */
.gb-ring circle { fill: none; stroke-width: 2.4; }
.gb-baan { stroke: rgba(255, 255, 255, .08); }
.gb-wijzer { stroke: var(--accent); stroke-linecap: round; }
.glass-btn.is-leeg .gb-ring { opacity: 0; }
/* De laatste vijf minuten, gelijk met de teller eronder. */
.glass-btn.soon .gb-wijzer { stroke: var(--danger); }

/* De animatie zelf. Maten en uitsnede komen uit js/app.js: die weet waar
   het glas in de tekening zit, en dat is niet in het midden. */
.gb-foto { position: relative; z-index: 2; display: block; }

/* De spiegeling: hetzelfde beeld op zijn kop, vervagend naar onder. */
.gb-spiegelvak {
  /* Los van de opbouw, zodat hij de hoogte van het blok niet beïnvloedt.
     Hij begint op de voet van het glas (een halve glashoogte onder het midden
     van de ring) en loopt door tot de onderkant van het blok. Wordt het glas
     kleiner, dan schuift hij mee omhoog zonder dat de teller verspringt. */
  position: absolute; z-index: 1;
  left: 50%;
  top: calc(var(--ring, 220px) / 2 + var(--glas) / 2);
  height: calc(var(--ring, 220px) * var(--diep, .34));
  transform: translateX(-50%);
  overflow: hidden;
  opacity: .3;
  pointer-events: none;
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, transparent 66%);
  mask-image: linear-gradient(to bottom, #000 0%, transparent 66%);
}
.gb-spiegel { display: block; transform: scaleY(-1); }

/* Leeg glas: de schijf ademt als uitnodiging om te tikken. Vroeger deed het
   glas dat zelf, maar dan beweegt de ring mee en dat leest als een fout. */
.glass-btn.is-leeg .gb-gloed { animation: gloedadem 3.4s ease-in-out infinite; }
@keyframes gloedadem {
  0%, 100% { opacity: .72; transform: scale(.975); }
  50%      { opacity: 1;   transform: scale(1.035); }
}
/* Bij een tik veert het glas op en zet de schijf even uit. */
.gb-foto.bons { animation: glasbons .58s cubic-bezier(.22,1,.36,1); }
@keyframes glasbons {
  0%   { transform: scale(1); }
  20%  { transform: scale(.9); }
  46%  { transform: scale(1.105); }
  68%  { transform: scale(.972); }
  86%  { transform: scale(1.018); }
  100% { transform: scale(1); }
}
.glass-btn.flits .gb-gloed { animation: gloedflits .58s cubic-bezier(.22,1,.36,1); }
@keyframes gloedflits {
  0%   { transform: scale(1); }
  30%  { transform: scale(1.14); }
  100% { transform: scale(1); }
}

/* De getekende glazen vullen hun vak; js/app.js zet de maat van dat vak. */
.gb-foto > svg, .gb-spiegel > svg { display: block; width: 100%; height: 100%; }

/* Het glas ademt. Een tekening die helemaal stilstaat leest als een plaatje,
   en dit is met opzet net te weinig om te zien als je ernaar kijkt en net
   genoeg om te missen als het er niet is. Het draaipunt ligt onderaan, zodat
   het glas op tafel blijft staan en alleen de bovenkant meegeeft. Het glas en
   zijn spiegelbeeld krijgen dezelfde vertraging mee, anders zie je meteen dat
   het twee losse tekeningen zijn. */
.gb-ademt { animation: glasadem 4.2s ease-in-out infinite; transform-origin: 50% 90%; }
@keyframes glasadem {
  0%, 100% { transform: scale(1);     }
  45%      { transform: scale(1.055); }
}

/* Koffie loopt niet leeg: er zit geen laag met inhoud in die tekening, en een
   kop koffie die halverwege blijft steken leest ook nergens naar. Die danst,
   met de kop als draaipunt zodat hij op tafel blijft staan. Ademen hoeft er
   niet meer bij: twee bewegingen op hetzelfde beeld wordt onrustig. */
.gb-danst { animation: koffiedans 2.9s ease-in-out infinite; transform-origin: 50% 86%; }
@keyframes koffiedans {
  0%, 100% { transform: rotate(-3.2deg) translateY(0); }
  22%      { transform: rotate(2.6deg)  translateY(-1.6%); }
  50%      { transform: rotate(-1.2deg) translateY(.4%); }
  74%      { transform: rotate(3.2deg)  translateY(-1.2%); }
}

/* Wie minder beweging wil, krijgt een stilstaand glas. De ring blijft wel
   werken: dat is geen versiering maar de klok, en het niveau in het glas ook:
   dat vertelt hetzelfde als de ring. */
@media (prefers-reduced-motion: reduce) {
  .gb-foto.bons, .gb-gloed, .gb-ademt, .gb-danst { animation: none !important; }
}

.gb-tekst {
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  color: var(--text);
  /* De ruimte boven deze tekst is een draaiknop, zie het blok bovenaan.
     Buiten het startscherm is er geen knop en houden we een gewone marge. */
  margin-top: var(--onder, 8px);
  /* De spiegeling loopt hier achter door, dus de tekst moet erbovenop. */
  position: relative;
  z-index: 2;
}
.gb-cta {
  font-size: 1.25rem; font-weight: 800; letter-spacing: -.01em;
  color: var(--accent);
}
.glass-btn small { font-weight: 600; font-size: 0.8125rem; color: var(--text-dim); }

.home-hint { color: var(--text-dim); font-size: 0.8438rem; max-width: 280px; margin-bottom: 4px; }

/* Oproep/poll-knoppen op de start. Kleiner lettertype zodat "Wie wil
   drinken?" op smalle toestellen op één regel blijft. */
.action-row { display: flex; gap: 10px; margin: 22px 0 4px; }
.action-row .btn {
  flex: 1;
  font-size: 0.875rem;
  padding: 0 12px;
  gap: 6px;
  white-space: nowrap;
}

/* Poll-kaart */
.poll-card { padding: 15px 17px; margin-bottom: 10px; }
.poll-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; }
.poll-head b { font-size: 0.9375rem; }
/* Blijft visueel 32px, maar het raakvlak is 44px: een duim in een kroeg
   mikt niet nauwkeuriger dan dat. */
.icon-btn.sm { width: 32px; height: 32px; flex: none; position: relative; }
.icon-btn.sm::after { content: ""; position: absolute; inset: -6px; border-radius: inherit; }
.poll-by { font-size: 0.75rem; color: var(--text-faint); margin: 2px 0 6px; }
/* Wie deze poll kan zien, met namen, niet alleen een aantal. */
.poll-scope {
  font-size: 0.75rem; color: var(--text-dim);
  background: var(--surface-2);
  border-radius: var(--r-sm);
  padding: 6px 9px;
  margin-bottom: 12px;
  line-height: 1.4;
}
.poll-opts { display: flex; flex-direction: column; gap: 8px; }
.poll-opt {
  position: relative; overflow: hidden;
  display: flex; align-items: center; gap: 8px;
  min-height: 44px; padding: 8px 12px;
  border-radius: var(--r-sm);
  background: var(--surface-2); border: 1px solid var(--border);
  text-align: left;
  transition: border-color .16s, background .16s;
}
.poll-opt:active { background: var(--surface-3); }
/* Bezig met versturen: de stem is al zichtbaar, de bevestiging volgt nog. */
.poll-opt.pending { opacity: .72; }
.poll-opt.chosen { border-color: var(--accent); }
/* De balk schaalt (transform) in plaats van te groeien (width): geen
   herberekening van de layout bij elke stem die binnenkomt. */
.poll-opt .po-fill {
  position: absolute; left: 0; top: 0; bottom: 0; width: 100%;
  background: var(--surface-3); z-index: 0;
  transform: scaleX(0); transform-origin: left;
  transition: transform .5s cubic-bezier(.22,1,.36,1);
}
.poll-opt.chosen .po-fill { background: var(--accent-soft); }
.poll-opt .po-label { position: relative; z-index: 1; flex: 1; font-size: 0.875rem; font-weight: 600; }
.poll-opt .po-pct { position: relative; z-index: 1; font-size: 0.8125rem; font-weight: 700; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.poll-opt.chosen .po-pct { color: var(--accent); }

/* "App installeren"-tip onderaan de startpagina (alleen buiten de PWA).
   Bewust neutraal: accent is op dit scherm gereserveerd voor de check-in-knop. */
.install-banner {
  width: 100%;
  display: flex; align-items: center; gap: 8px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: 10px 12px;
  margin-top: 26px;
  text-align: left;
}
.install-banner .ib-main {
  flex: 1; min-width: 0;
  display: flex; align-items: center; gap: 12px;
  text-align: left;
  padding: 4px 2px;
  transition: opacity .16s;
}
.install-banner .ib-main:active { opacity: .7; }
.install-banner .ib-icon { color: var(--text-dim); flex: none; display: grid; place-items: center; }
.install-banner .ib-text { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.install-banner .ib-text b { font-size: 0.875rem; }
.install-banner .ib-text span { font-size: 0.8125rem; color: var(--text-dim); line-height: 1.4; }
/* Hetzelfde gouden stipje als op de tabbalk, nu vóór de kop van de balk.
   Zonder dat merkje lijkt "Update beschikbaar" op de installatietip die
   soms op dezelfde plek staat, en dan leest niemand het verschil. */
.install-banner .ib-stip {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--accent);
  display: inline-block; margin-right: 7px; vertical-align: middle;
}

/* Klein CSS-glaasje, gebruikt op het welkomstscherm en in de
   eerste-keer-schermen. De grote knop tekent zichzelf op canvas. */
.beer-glass {
  width: 62px; height: 78px;
  border: 3px solid var(--accent);
  border-radius: 6px 6px 13px 13px;
  position: relative;
  overflow: hidden;
  background: rgba(var(--accent-rgb), .06);
}
.beer-liquid {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 100%;
  background: linear-gradient(to bottom, var(--accent-hi), var(--accent));
  will-change: height;
}
.beer-liquid::before {
  content: "";
  position: absolute; top: -5px; left: 0; right: 0; height: 7px;
  background: #fff7e6; opacity: .92;
  border-radius: 50%;
}
.countdown {
  font-size: 1.375rem; font-weight: 800;
  font-variant-numeric: tabular-nums;
  letter-spacing: .01em;
  color: var(--accent);
  transition: color .3s;
}
/* Laatste vijf minuten: alleen de klok verkleurt. Er stond hier ook een
   balkje met "Je sessie loopt bijna af" onder het glas, maar dat duwde de
   rest van het startscherm omlaag. De klok zegt het al. */
.countdown.soon { color: var(--danger); }

/* Terugblik na afloop: wie proostte, wie kwam eraan. */
.summary-list {
  list-style: none;
  margin-top: 16px;
  display: flex; flex-direction: column; gap: 10px;
}
.summary-list li {
  background: var(--waas);
  border: 0;
  border-radius: var(--r-md);
  padding: 13px 15px;
  font-size: 0.9375rem;
  line-height: 1.45;
}

/* Verbinding kwijt. */
.offline-bar {
  position: sticky; top: 0;
  z-index: var(--z-sticky);
  background: var(--danger-soft);
  border-bottom: 1px solid rgba(239, 68, 68, .4);
  color: var(--text);
  font-size: 0.8125rem; font-weight: 600;
  text-align: center;
  padding: 8px 14px;
}
.stop-link {
  color: var(--text-dim); font-size: 0.8125rem; font-weight: 600;
  padding: 8px 14px; border-radius: var(--r-full);
  background: var(--surface); border: 1px solid var(--border);
}
.stop-link:active { background: var(--surface-2); }

/* ---------- Live vrienden lijst ---------- */
.section-label {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--text-faint);
  font-weight: 700;
  margin: 26px 4px 12px;
}
.list { display: flex; flex-direction: column; gap: 0; }

/* ---------- De kaart ----------
   De rand is eraf. Een kaart is nu een zachte waas met rondere hoeken: nog
   steeds een vlak, maar zonder de harde omlijning die op Statistieken en
   Profiel een muur van grijze hokjes opleverde. De padding is 1px omhoog,
   precies de rand die wegviel, zodat de inhoud niet verschuift. */
.card {
  background: var(--waas);
  border: 0;
  border-radius: var(--r-lg);
  padding: 15px 17px;
}

/* ---------- De rij ----------
   Geen vakje meer met een rand eromheen. Er staat toch al één ding per rij,
   dus die rand vertelde je niets wat je niet al zag; acht gesprekken werden
   acht grijze blokken. Nu dragen de gezichten de lijst en licht alleen op
   wat aandacht vraagt. */
.friend-row {
  display: flex;
  align-items: center;
  gap: 14px;
  background: none;
  border: 0;
  border-radius: var(--r-md);
  padding: 12px;
  width: 100%;
  text-align: left;
  position: relative;
  transition: background .16s;
}
.friend-row:active { background: var(--surface-2); }

/* Ongelezen: het enige wat oplicht. Een streep links en een gouden waas,
   zodat het scherm je naar het nieuwe wijst in plaats van alles even hard
   te laten schreeuwen. Wie live is herken je aan het stipje op zijn gezicht
   en niet aan zijn rij; anders vechten twee signalen om dezelfde aandacht. */
.friend-row.nieuw { background: var(--accent-soft); }
.friend-row.nieuw::before {
  content: "";
  position: absolute; left: 0; top: 10px; bottom: 10px;
  width: 3px; border-radius: var(--r-full);
  background: var(--accent);
}
.friend-row.nieuw .meta b { font-weight: 800; }
.friend-row.nieuw .meta span { color: var(--text); }

/* Een haarlijn tússen de rijen, niet eronder: daarom op elke rij behalve de
   eerste. Als pseudo-element en niet als border, want de rij heeft ronde
   hoeken en een border zou die bocht meelopen. Ingesprongen, zodat de lijn
   niet tegen de rand van het scherm aan loopt. */
.friend-row + .friend-row::after,
.hist-row + .hist-row::after {
  content: "";
  position: absolute;
  left: 12px; right: 12px; top: 0;
  height: 1px;
  background: var(--border);
}
/* Rond een oplichtende rij geen lijn: die zou het gouden vlak doorsnijden. */
.friend-row.nieuw::after,
.friend-row.nieuw + .friend-row::after { display: none; }

/* ---------- Uitklapblok ----------
   Native <details>, dus het werkt ook zonder JavaScript en een schermlezer
   weet vanzelf of het open of dicht staat. */
.uitklap { margin-top: 22px; }
.uitklap > summary {
  display: flex; align-items: center; gap: 12px;
  background: var(--waas);
  border: 0;
  border-radius: var(--r-lg);
  padding: 15px;
  cursor: pointer;
  list-style: none;               /* het standaard driehoekje weg */
  transition: background .16s;
}
.uitklap > summary::-webkit-details-marker { display: none; }
.uitklap > summary:active { background: var(--waas-druk); }
.uitklap .uk-tekst { flex: 1; min-width: 0; }
.uitklap .uk-tekst b { display: block; font-size: 0.9375rem; }
.uitklap .uk-tekst span { display: block; font-size: 0.8125rem; color: var(--text-dim); margin-top: 1px; }
.uitklap .uk-pijl { flex: none; color: var(--text-dim); display: grid; place-items: center; }
.uitklap .uk-pijl svg { transition: transform .22s cubic-bezier(.22, 1, .36, 1); }
.uitklap[open] .uk-pijl svg { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) {
  .uitklap .uk-pijl svg { transition: none; }
}

/* ---------- Club van 100 ----------
   Het pleknummer is hier geen versiering maar de kern: de club telt af van
   honderd, dus elk lid heeft een echte plaats in de rij. */
/* Kaal getal, geen bolletje: het nummer is een plaats in de rij en geen
   knop. Zonder die cirkel schuift het icoon er strak tegenaan en houdt de
   naam meer ruimte. `tabular-nums` houdt 1 en 10 even breed, zodat de
   iconen onder elkaar op één lijn blijven staan. */
.club-nr {
  min-width: 20px; flex: none;
  text-align: right;
  color: var(--accent);
  font-size: 0.8125rem; font-weight: 700;
  font-variant-numeric: tabular-nums;
}
/* Het icoon van een clublid. Iets kleiner dan een gewone avatar, want er
   staat al een pleknummer naast en samen moeten ze op een smalle telefoon
   naast de naam passen. `contain` in plaats van `cover`: bij een logo wil je
   het hele merk zien, niet een uitsnede met de letters eraf. Een gewone
   profielfoto is vierkant uitgesneden, dus die valt er precies in. */
.club-av { width: 38px; height: 38px; font-size: 0.875rem; }
.club-av .av-img { object-fit: contain; background: var(--surface-3); }
/* De rij heeft 14px tussenruimte. Tussen nummer en icoon mag dat iets
   krapper, want die twee horen bij elkaar, maar ze moeten elkaar niet
   raken: dan lees je het nummer als onderdeel van het plaatje. */
.club-nr + .club-av { margin-left: -2px; }

/* Lang niet elk clublid gaat ergens heen: sommigen staan er alleen met hun
   naam. Die rijen hebben even in de accentkleur gestaan om te laten zien dat
   je erop kunt drukken, maar in een lijst met tientallen namen werd dat een
   bonte boel: het goud trok de aandacht naar wie toevallig een profiel heeft
   in plaats van naar wie bovenaan staat, en dáár gaat deze lijst over. Terug
   naar wit. Het pijltje rechts blijft het verschil maken. */

.club-teller { margin-bottom: 14px; }
.club-teller span {
  display: block; margin-top: 8px;
  font-size: 0.8125rem; color: var(--text-dim);
}
.club-bar {
  height: 6px; border-radius: var(--r-full);
  background: var(--surface-2); border: 1px solid var(--border);
  overflow: hidden;
}
.club-bar > i {
  display: block; height: 100%;
  background: var(--accent);
  border-radius: inherit;
  transition: width .6s cubic-bezier(.22, 1, .36, 1);
}
@media (prefers-reduced-motion: reduce) {
  .club-bar > i { transition: none; }
}
.avatar {
  width: 46px; height: 46px; flex: none;
  border-radius: var(--r-full);
  background: var(--surface-3);
  display: grid; place-items: center;
  font-weight: 700; font-size: 1.0625rem; color: var(--accent);
  position: relative;
}
/* Losgemaakt uit het raster en over de hele bol gelegd. Dat moet, want een
   rasteronderdeel dat gecentreerd staat (place-items: center) krijgt zijn
   eigen hoogte en niet die van het vak eromheen: height:100% levert dan
   gewoon de volle hoogte van de foto op. Bij een profielfoto viel dat nooit
   op, want die wordt vierkant bijgesneden. Bij een foto van een check-in
   wel: die houdt de vorm waarin je hem maakte, en een staande foto liep
   zonder dit door de halve pagina heen. */
.avatar .av-img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover; border-radius: inherit;
}
/* Het groene stipje van iemand die nu ingecheckt is. Staat overal waar je zijn
   gezicht ziet: de strook op Start, de vriendenlijst, de chat, een stekkie,
   het klassement, je eigen profielkaart. Eén betekenis, dus één vorm.
   Het klopt als een hartslag (sp-klop): twee tikken en dan rust. */
.avatar.live::after {
  content: ""; position: absolute; right: -1px; bottom: -1px;
  width: 13px; height: 13px; border-radius: 50%;
  background: var(--live); border: 2.5px solid var(--surface);
  animation: sp-klop 1.9s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
  .avatar.live::after { animation: none; }
}
/* ---------- Live-strook op Start ----------
   Wie er nu drinkt, in één strook van vaste hoogte: een paar overlappende
   gezichten en de zin ernaast. De volledige lijst staat op Vrienden, want
   die groeit mee en drukte Start vol.

   Dit is waar de app om draait, dus de strook mag opvallen. Dat doet hij
   met de live-kleur die overal al "dit gebeurt nu" betekent (de stip in een
   gesprek, het Live-label), en niet met het goud: goud is van de check-in
   knop, en die mag niets naast zich dulden. Goud = jij, groen = zij.
   De klap zit in het verschil tussen de twee standen: zit er niemand, dan
   is dit een doffe regel; zit er wél iemand, dan licht het hele blok op. */
/* Geen kader en geen kleurvlak: de gezichten mét hun aflopende ringen zijn
   nu zelf het nieuws, en die vertellen ook al dat er iets gaande is. Een
   gekleurd blok eromheen deed daar niets meer bij en vocht met het goud van
   de check-in-knop, die op dit scherm niets naast zich hoort te dulden. */
.live-strip { background: none; border: 0; padding: 0; }
/* ----- Niemand actief -----
   Geen kaart met een zin erin, maar de vórm van de strook die er straks staat:
   drie lege plekken die zachtjes ademen. Zo zie je in één blik wat hier hoort
   te komen, en dat het nu aan jou is. Het ademen is bewust traag en flauw: op
   dit scherm bewegen het glas en de bellen van het logo al, en een derde ding
   dat hard knippert maakt het onrustig in plaats van uitnodigend. */
@keyframes ls-spook-adem {
  0%, 100% { opacity: .55; }
  50%      { opacity: .95; }
}
/* De spookrij schuift niet: er valt niets te bekijken, hij hoort alleen vol
   te ogen. Hij loopt daarom bewust door tot voorbij de rand en vervaagt daar,
   zodat het afsnijden duidelijk bedoeld is en niet op een fout lijkt. */
.ls-rij.spoken {
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to right, #000 62%, transparent 100%);
          mask-image: linear-gradient(to right, #000 62%, transparent 100%);
}
.ls-spook { cursor: default; }
/* Een doorgetrokken lijn in plaats van een stippellijn. Een stippelrand leest
   als "hier hoort iets te komen dat er nog niet is", en dat is precies de
   verkeerde boodschap: deze plekken hóren leeg te zijn zolang er niemand
   drinkt. Een hele lijn is rustiger en oogt af. */
.ls-spook .ls-ring {
  background: none;
  border: 2px solid var(--text-faint);
  animation: ls-spook-adem 2.8s ease-in-out var(--vertraag, 0s) infinite;
}
.ls-naambalk {
  width: 32px; height: 8px;
  border-radius: var(--r-full);
  background: var(--border-strong);
  animation: ls-spook-adem 2.8s ease-in-out var(--vertraag, 0s) infinite;
}
/* De uitnodiging staat rechts in de kop, op de plek waar anders het aantal
   staat. Bij een storing staat hij eronder als hele zin. */
.ls-lok { font-size: 0.8125rem; color: var(--text-dim); }
p.ls-lok { margin-top: 9px; }

/* ----- Kop: waar het over gaat, en hoeveel het er zijn ----- */
.ls-kop {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 10px; margin-bottom: 11px;
}
.ls-titel { font-size: 0.9375rem; font-weight: 700; color: var(--text); letter-spacing: -.01em; }
.ls-alles {
  flex: none;
  display: inline-flex; align-items: baseline; gap: 4px;
  font-size: 0.8125rem; color: var(--text-dim);
}
.ls-alles:active { opacity: .6; }
.ls-getal {
  font-size: 1rem; font-weight: 800;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
  letter-spacing: -.02em;
}
.ls-pijl { font-size: 1rem; line-height: 1; }

/* ----- De rij gezichten -----
   Iedereen die drinkt staat erin. Past de rij niet, dan schuif je hem opzij;
   dat is beter dan "+3" waar je niet op kunt tikken. De rij loopt bewust door
   de padding van de strook heen (negatieve marge), zodat het laatste gezicht
   niet tegen de rand plakt maar netjes onder de rand door schuift. */
.ls-rij {
  display: flex; gap: 13px;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  /* Geen negatieve marge om tot de schermrand te lopen: .home-scroll heeft
     overflow-y: auto, en dan kapt de browser ook horizontaal af. Dan zou het
     laatste gezicht bij het schuiven half wegvallen. */
  margin: 0; padding: 2px 0 0;
}
.ls-rij::-webkit-scrollbar { display: none; }

.ls-av {
  flex: none; width: 62px;
  display: flex; flex-direction: column; align-items: center; gap: 7px;
  /* De stand van de klok hoort HIER thuis en niet op .ls-ring. app.js zet
     hem als inline stijl op .ls-av, en een eigen declaratie op .ls-ring zou
     die overerving overschrijven: dan blijft elke ring op 1 staan en loopt
     er niets af. Inline wint van deze regel, .ls-ring erft wat er staat. */
  --deel: 1;                       /* 1 = net begonnen, 0 = tijd om */
}
.ls-av:active .ls-ring { transform: scale(.94); }
.ls-ring { transition: transform .14s; }

/* ----- De ring is een klok -----
   Twee kleuren, geen verloop: het groene deel is de tijd die nog over is, het
   oranje deel is de tijd die op is. --deel telt van 1 naar 0 en wordt door
   app.js gezet, dus het groen krimpt met de klok mee en het oranje groeit
   erachteraan. De 3 px padding is de ring zelf; het gezicht dekt de rest af.

   De kleuren staan hier vast en volgen bewust NIET het accentthema: dit is
   een aflopende klok. Bij een blauw of paars accent moet groen nog steeds
   "net begonnen" betekenen en oranje "bijna om". */
.ls-ring {
  --ring-groen: var(--live);
  --ring-oranje: #f5a524;
  position: relative;
  width: 60px; height: 60px;
  border-radius: var(--r-full);
  padding: 3px;
  display: grid; place-items: center;
  background: conic-gradient(
    var(--ring-groen) calc(var(--deel) * 360deg),
    var(--ring-oranje) 0
  );
}
.ls-ring .avatar { width: 54px; height: 54px; font-size: 1.125rem; }
/* Het groene stipje zit al op .avatar.live (inclusief de hartslag); zonder
   kader eromheen hoort zijn randje hier de kleur van de pagina zelf te
   hebben in plaats van die van een kaart. */
.live-strip .ls-av .avatar.live::after { border-color: var(--bg); }

.ls-naam {
  max-width: 100%;
  font-size: 0.75rem; font-weight: 600; color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  text-align: center;
}
.ls-em { font-size: 0.8125rem; margin-right: 3px; }

/* ---------- Er schuift iemand aan ----------
   Alleen wanneer er écht iemand bijkomt terwijl je kijkt. Het gezicht komt
   van links binnen (daar groeit de rij), het getal rolt door en het blok
   geeft één gloedpuls die wegebt. Daarna is het weer stil.
   De curve is dezelfde als elders in de app: rustig uitdempend, geen stuiter.
   "Minder beweging" zet dit allemaal uit via de globale regel bovenaan. */
@keyframes ls-gezicht-in {
  from { opacity: 0; transform: translateX(-16px) scale(.72); }
  to   { opacity: 1; transform: none; }
}
.ls-av.nieuw { animation: ls-gezicht-in .46s cubic-bezier(.22, 1, .36, 1) both; }

@keyframes ls-getal-tik {
  from { opacity: 0; transform: translateY(-45%); }
  to   { opacity: 1; transform: none; }
}
.ls-getal.tikt { display: inline-block; animation: ls-getal-tik .34s cubic-bezier(.22, 1, .36, 1) both; }

/* Zonder kader kan de puls geen gloed óm het blok meer zijn: dat zou een
   zwevende lichtrechthoek worden. Nu licht de kop even op, want daar staat
   het getal dat zojuist veranderde. */
@keyframes ls-puls {
  from { color: var(--accent); }
  to   { color: inherit; }
}
.live-strip.puls .ls-titel { animation: ls-puls .9s cubic-bezier(.22, 1, .36, 1) both; }

/* ---------- Het gezicht wordt de popup ----------
   Tik je een gezicht aan, dan groeit precies dát gezicht door naar de kop
   van de popup, in plaats van dat er los iets omhoog schuift. Kan de browser
   het niet, dan gebeurt er niets bijzonders: de popup opent zoals altijd. */
::view-transition-group(sessie-gezicht) {
  animation-duration: .42s;
  animation-timing-function: cubic-bezier(.22, 1, .36, 1);
}
::view-transition-old(sessie-gezicht),
::view-transition-new(sessie-gezicht) {
  animation-duration: .42s;
  animation-timing-function: cubic-bezier(.22, 1, .36, 1);
}
/* De rest van het scherm vloeit er kort achteraan; korter dan het gezicht,
   zodat je oog bij het gezicht blijft. */
::view-transition-old(root),
::view-transition-new(root) { animation-duration: .26s; }
.ls-pijl { font-size: 1.125rem; color: var(--text-faint); flex: none; }

.friend-row .meta { flex: 1; min-width: 0; }
.friend-row .meta b { font-size: 0.9375rem; font-weight: 600; display: block; }
/* Laat doorlopen op een tweede regel in plaats van afkappen: juist de
   staart (📍 locatie, BOB) bepaalt of je erheen loopt. */
.friend-row .meta span { font-size: 0.8125rem; color: var(--text-dim); display: block; line-height: 1.4; }
.friend-row .drink-emoji { font-size: 1.625rem; flex: none; }

/* Het kruisje bij een voorstel: "die ken ik niet, hou maar op". Grijs en
   zonder rand, want het staat naast "Toevoegen" en hoort daar niet mee te
   concurreren. Het aanraakvlak is wél 40 bij 40, anders raak je op een
   telefoon nooit wat je bedoelt. De negatieve marge haalt die ruimte weer
   van de rand af, zodat de rij niet breder wordt dan de andere. */
.weg-knop {
  flex: none;
  width: 40px; height: 40px;
  margin: 0 -8px 0 -6px;
  display: grid; place-items: center;
  background: none; border: 0;
  color: var(--text-faint);
  font-size: 1.375rem; line-height: 1;
  border-radius: var(--r-full);
  transition: background .16s, color .16s;
}
.weg-knop:active { background: var(--surface-2); color: var(--text); }

/* ---------- "Even op gang komen": de stappen in de uitklapbalk ----------
   Elke regel is zelf de knop. Vijf losse knoppen met een eigen tekst
   ("Uitnodigen", "Aanzetten") riepen alle vijf even hard, en ze maakten de
   lijst zo hoog dat hij niet meer onder het glas paste. Nu zegt de regel wat
   er gebeurt en wijst het pijltje dat er iets achter zit.

   Wat af is wordt grijs en doorgestreept en zakt naar de achtergrond, zodat
   je oog vanzelf bij het openstaande blijft hangen. Geen balk die volloopt:
   dat is een spelletje, en dit is geen spelletje. */
.stap {
  display: flex; align-items: center; gap: 12px;
  width: 100%; padding: 6px 2px;
  background: none; border: 0; text-align: left;
  border-radius: var(--r-md);
  transition: background .16s;
}
.stap:not(:disabled):active { background: var(--surface-2); }
.stap .bol {
  width: 22px; height: 22px; flex: none;
  border-radius: 50%;
  border: 1.5px solid var(--border-strong);
  display: grid; place-items: center;
  font-size: 0.8125rem; font-weight: 800;
  color: transparent;              /* het vinkje is er al, maar onzichtbaar */
}
.stap.af .bol { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.stap .naam { flex: 1; min-width: 0; font-size: 0.875rem; color: var(--text); }
.stap.af .naam { color: var(--text-faint); text-decoration: line-through; }
.stap-chev { flex: none; color: var(--text-faint); font-size: 1.25rem; line-height: 1; }

/* Wegklikken kan pas als je de balk hebt opengetikt. Dat is met opzet: je
   verbergt niets wat je nog nooit gezien hebt, en de dichte balk blijft één
   regel zonder kruisje ernaast. */
.stap-weg {
  display: block; width: 100%;
  margin-top: 4px; padding: 10px 2px;
  background: none; border: 0;
  color: var(--text-faint); font-size: 0.8125rem; text-align: center;
}
.stap-weg:active { color: var(--text-dim); }

/* Menurij in het profiel: een icoon voorop en een pijltje dat zegt
   "hier zit nog iets achter". */
.friend-row .menu-emoji { font-size: 1.375rem; flex: none; line-height: 1; }
.chev {
  flex: none;
  font-size: 1.375rem;
  line-height: 1;
  color: var(--text-faint);
  padding-left: 2px;
}

/* ---------- Rechts in een rij ----------
   Er stond overal hetzelfde grijze bolletje, terwijl het drie verschillende
   dingen zei: wat er gebeurt als je tikt, een toestand, en een aantal. Nu
   heeft elk van die drie zijn eigen vorm, zodat je niet meer hoeft te lezen
   om te weten waar je naar kijkt.

   .pill    = een toestand ("Live", "Al vriend", "Aangemeld")
   .chev    = deze rij gaat ergens heen
   .telling = een aantal */
.pill {
  font-size: 0.75rem; font-weight: 600;
  padding: 4px 10px; border-radius: var(--r-full);
  background: var(--surface-2); color: var(--text-dim);
}
.pill.live { background: rgba(52,211,153,.16); color: var(--live); }

.chev {
  flex: none;
  color: var(--ink-mute);
  font-size: 1.375rem; line-height: 1;
  padding-left: 4px;
}
/* Een adres buiten de app: zelfde gewicht, ander teken. Een pijl naar rechts
   belooft een volgend scherm, en dat is dit niet. */
.chev.uit { font-size: 1.0625rem; }
.telling {
  flex: none;
  font-size: 0.875rem; font-weight: 700;
  color: var(--text-dim);
  font-variant-numeric: tabular-nums;
}

/* ---------- Lege staat ---------- */
.empty {
  text-align: center;
  padding: 48px 24px;
  color: var(--text-dim);
}
.empty svg { color: var(--ink-mute); margin-bottom: 14px; }
.empty b { display: block; color: var(--text); font-size: 1rem; margin-bottom: 6px; }
.empty p { font-size: 0.875rem; max-width: 240px; margin: 0 auto; }

/* Lege staat zonder vrienden: geen doodlopende melding maar een uitweg. */
.empty.solo {
  text-align: left;
  background: var(--waas);
  border: 0;
  border-radius: var(--r-lg);
}
.empty.solo p { max-width: none; margin: 0; }

/* Uitleg onder uitgeschakelde oproep-/pollknoppen. */
.action-note {
  font-size: 0.8125rem;
  color: var(--text-dim);
  line-height: 1.5;
  margin: 10px 4px 0;
}

/* ---------- Welkom (eenmalig, na het kiezen van je naam) ---------- */
.welcome { display: flex; flex-direction: column; }
/* Het woordmerk boven het welkomscherm. Hetzelfde als op het startscherm,
   dus ook hier moet .bm-logo een kader hebben om zijn cqw-maten vanaf te
   rekenen: zonder container-type is het logo nul pixels groot. */
.welcome-merk {
  container-type: inline-size;
  width: 100%;
  max-width: min(275px, 82vw);
  margin: 8px auto 22px;
}
.welcome .page-sub { margin-bottom: 28px; text-wrap: pretty; }

.welcome-steps {
  list-style: none;
  display: flex; flex-direction: column; gap: 18px;
  margin-bottom: 30px;
}
.welcome-steps li { display: flex; align-items: flex-start; gap: 14px; }
.welcome-steps b { display: block; font-size: 0.9375rem; margin-bottom: 2px; }
.welcome-steps p { font-size: 0.8438rem; color: var(--text-dim); line-height: 1.5; }
.ws-mark {
  flex: none;
  width: 42px; height: 42px;
  display: grid; place-items: center;
  border-radius: var(--r-full);
  background: var(--accent-soft);
  color: var(--accent);
}
.ws-mark svg { width: 22px; height: 22px; }
.ws-clock {
  font-size: 0.9375rem; font-weight: 800;
  line-height: 1; flex-direction: column;
}
.ws-clock small { font-size: 0.5625rem; font-weight: 700; opacity: .75; letter-spacing: .04em; }

.welcome-cta { margin-top: auto; }
.welcome-alone {
  font-size: 0.875rem; color: var(--text-dim);
  text-align: center; line-height: 1.5;
  margin-bottom: 14px;
}

/* ---------- Eerste-keer-momenten in een sheet ---------- */
.first-run { text-align: center; }
.first-run h2 { text-align: center; margin-bottom: 6px; }
.first-run .sub { text-align: center; text-wrap: pretty; }
.fr-glass { display: flex; justify-content: center; margin: 2px 0 16px; }
.fr-glass .beer-glass { width: 58px; height: 74px; }

.fr-avatars {
  display: flex; align-items: center; justify-content: center;
  gap: 10px; margin: 4px 0 16px;
}
.fr-avatars .avatar { width: 54px; height: 54px; font-size: 1.1875rem; }
.fr-clink { font-size: 1.5rem; }

/* ---------- Knoppen ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 48px; padding: 0 20px;
  border-radius: var(--r-full);
  font-weight: 700; font-size: 0.9375rem;
  background: var(--accent); color: var(--on-accent);
  transition: transform .1s, filter .18s, background .18s;
}
.btn:active { transform: scale(.97); }
/* Uitgeschakeld moet leesbaar blijven. Opacity .5 maakte de tekst onleesbaar
   op donker. Duidelijk gedempt, maar nog boven de contrastgrens. */
.btn:disabled {
  cursor: not-allowed;
  background: var(--surface-2);
  color: var(--text-dim);
  border: 1px solid var(--border);
  box-shadow: none;
}
.btn:disabled:active { transform: none; }
.btn.block { width: 100%; }
/* Tweede en derde knoppen zijn leeg vanbinnen, alleen een randje. Dan blijft
   de hoofdknop de enige met een vlak en dus onmiskenbaar de belangrijkste;
   drie gevulde knoppen onder elkaar vechten om dezelfde aandacht. */
.btn.ghost { background: none; color: var(--text); border: 1px solid var(--border-strong); }
.btn.ghost:active { background: var(--surface-2); }
.btn.danger { background: none; color: var(--danger); border: 1px solid rgba(239, 68, 68, .45); }
.btn.danger:active { background: var(--danger-soft); }
.btn.sm { min-height: 40px; font-size: 0.875rem; padding: 0 16px; }

.chip {
  display: inline-flex; align-items: center; gap: 6px;
  min-height: 40px; padding: 0 16px;
  border-radius: var(--r-full);
  background: var(--surface-2); border: 1px solid var(--border);
  color: var(--text); font-size: 0.875rem; font-weight: 600;
  transition: background .16s, border-color .16s;
}
.chip:active { background: var(--surface-3); }
/* Reageren op een sessie. Zonder rand, want het vlak zegt het al.
   `transparent` in plaats van `border: 0`, zodat de maat gelijk blijft aan
   een gewone chip ernaast. */
.chip.accent { background: var(--accent-soft); border-color: transparent; color: var(--accent); }
/* "Ik kom eraan" gaat over iemand die nu onderweg is, en dat is in deze app
   groen. Proost is een groet, dat blijft goud. Twee verschillende dingen
   horen er niet hetzelfde uit te zien. */
.chip.mee { background: rgba(52,211,153,.15); border-color: transparent; color: var(--live); }
.chip.mee:active { background: rgba(52,211,153,.24); }

/* ---------- Formulieren ---------- */
.field { margin-bottom: 16px; }
.field label { display: block; font-size: 0.8125rem; font-weight: 600; color: var(--text-dim); margin-bottom: 8px; }
.input {
  width: 100%;
  min-height: 50px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: 0 16px;
  font-size: 1rem; /* voorkomt inzoomen op iOS */
  color: var(--text);
  transition: border-color .16s, background .16s;
}
textarea.input { padding: 12px 16px; min-height: 84px; resize: vertical; line-height: 1.45; }
.input::placeholder { color: var(--text-faint); }
.input:focus { border-color: var(--accent); background: var(--surface-2); outline: none; }
.field .hint { font-size: 0.75rem; color: var(--text-faint); margin-top: 6px; }

/* Het oogje in een wachtwoordveld. Zit ín het veld, aan de rechterkant, met
   ruimte ernaast zodat de tekst er niet onder doorloopt. De knop is 42 bij 42
   en dus met een duim te raken, ook al oogt het pictogram klein. */
.pw-veld { position: relative; }
.pw-veld .input { padding-right: 52px; }
.pw-oog {
  position: absolute; right: 4px; top: 50%;
  transform: translateY(-50%);
  width: 42px; height: 42px;
  border-radius: var(--r-full);
  display: grid; place-items: center;
  background: transparent; color: var(--text-faint);
  transition: color .16s, background .16s;
}
.pw-oog:active { background: var(--surface-2); }
.pw-oog svg { width: 20px; height: 20px; }
/* Twee pictogrammen in dezelfde knop; er is er altijd één zichtbaar. Zo
   springt de knop niet als je hem omzet. */
.pw-oog .oog-dicht { display: none; }
.pw-oog.aan { color: var(--accent); }
.pw-oog.aan .oog-open { display: none; }
.pw-oog.aan .oog-dicht { display: block; }
/* Foutmeldingen staan bijna overal náást een .field in plaats van erin, dus
   de regel mag niet van .field afhangen: anders blijft een foutmelding in de
   gewone tekstkleur staan en valt hij niet op. */
.err { font-size: 0.8125rem; color: var(--danger); margin-top: 6px; }

/* Akkoordvinkjes bij het aanmaken van een account. Het hele blok is een
   <label>, dus je hoeft niet precies het vierkantje te raken. De links erin
   openen een pagina zonder het vinkje om te zetten. */
.akkoord {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin-bottom: 14px;
  padding: 12px 14px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  cursor: pointer;
  transition: border-color .16s, background .16s;
}
.akkoord input[type="checkbox"] {
  flex: none;
  width: 22px; height: 22px;
  margin: 0;
  accent-color: var(--accent);
  cursor: pointer;
}
.akkoord span { font-size: 0.875rem; line-height: 1.5; color: var(--text-dim); }
.akkoord b { color: var(--text); font-weight: 600; }
.akkoord:has(input:checked) { border-color: rgba(var(--accent-rgb), .4); background: var(--surface-2); }
.akkoord.mis { border-color: var(--danger); background: var(--danger-soft); }
.akkoord.mis span { color: var(--text); }

/* ---------- Onderste navigatie ---------- */
.tabbar {
  position: fixed;
  bottom: 0; left: 0; right: 0;
  max-width: 480px; margin: 0 auto;
  /* min-height in plaats van height: bij een grote tekstinstelling mag de
     balk meegroeien in plaats van de labels af te knippen. */
  min-height: calc(var(--nav-h) + var(--safe-b));
  padding-bottom: var(--safe-b);
  /* Matglas, zelfde taal als de meldingen. Let op welk getal wat doet:

     De KLEUR bepaalt of je de balk als een ruitje ziet liggen. Hij was
     rgb(15,15,18) en de achtergrond is rgb(11,11,13), dus vrijwel hetzelfde;
     dan valt er niets te zien, hoe je de dekking ook zet. Nu lichter, zodat de
     balk een eigen vlak wordt.

     De DEKKING (het laatste getal) bepaalt hoeveel je van de inhoud eronder
     ziet. Die is alleen zichtbaar op het moment dat er iets achter de balk
     langsschuift; boven een leeg stuk scherm verandert er niets van. */
  background: rgba(20,20,25,.50);
  backdrop-filter: blur(24px) saturate(1.7);
  -webkit-backdrop-filter: blur(24px) saturate(1.7);
  border-top: 1px solid rgba(255,255,255,.11);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.05);
  display: flex;
  z-index: var(--z-nav);
}
/* Kan het toestel niet vervagen (oudere Android), dan wordt de balk gewoon
   dicht. Halfdoorzichtig zonder vervaging betekent dat de labels boven
   langsschuivende gezichten en tekst komen te staan, en dan lees je ze niet. */
@supports not ((backdrop-filter: blur(2px)) or (-webkit-backdrop-filter: blur(2px))) {
  .tabbar { background: rgba(15,15,18,.97); border-top-color: var(--border); }
}
.tabbar button {
  flex: 1;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
  padding: 8px 2px;
  color: var(--text-faint);
  font-size: 0.75rem; font-weight: 600;
  line-height: 1.2;
  transition: color .16s;
}
.tabbar button svg { width: 24px; height: 24px; }
.tabbar button.active { color: var(--accent); }
.tabbar button .tab-badge {
  position: absolute; transform: translate(14px,-14px);
  min-width: 16px; height: 16px; padding: 0 4px;
  background: var(--danger); color: #fff;
  border-radius: var(--r-full);
  font-size: 0.625rem; font-weight: 700;
  display: grid; place-items: center;
}
/* Een stipje zonder getal, voor een mededeling in plaats van een taak.
   Rood is in deze app de kleur van iets dat op je ligt te wachten: een
   vriendverzoek, een ongelezen bericht. Dat er een update klaarstaat is
   geen taak en al helemaal geen probleem, dus dat wordt goud en klein. */
.tabbar button .tab-badge.stil {
  min-width: 9px; width: 9px; height: 9px; padding: 0;
  font-size: 0; background: var(--accent);
  transform: translate(13px,-13px);
}

/* ---------- Bottom sheet ---------- */
.scrim {
  position: fixed; inset: 0;
  background: rgba(0,0,0,.55);
  z-index: var(--z-scrim);
  opacity: 0;
  transition: opacity .22s;
}
.scrim.show { opacity: 1; }
.sheet {
  position: fixed; left: 0; right: 0; bottom: 0;
  max-width: 480px; margin: 0 auto;
  background: var(--surface);
  border-radius: var(--r-lg) var(--r-lg) 0 0;
  border-top: 1px solid var(--border-strong);
  padding: 10px 20px calc(20px + var(--safe-b));
  z-index: var(--z-sheet);
  transform: translateY(100%);
  transition: transform .28s cubic-bezier(.32,.72,0,1);
  max-height: 88dvh; overflow-y: auto;
}
.sheet.show { transform: translateY(0); }
.sheet .grip { width: 40px; height: 4px; border-radius: 2px; background: var(--border-strong); margin: 4px auto 16px; }
.sheet h2 { font-size: 1.25rem; font-weight: 700; margin-bottom: 4px; }
.sheet .sub { color: var(--text-dim); font-size: 0.875rem; margin-bottom: 18px; }

/* ---------- Mijlpaal: het feestje bij je 10e, 25e, 50e, 75e en 100e ----------
   Het getal en de tekst staan bovenop (z-index 2), het feest eronder. De
   feestlaag vangt geen tikken op, dus de knoppen eronder blijven gewoon
   werken terwijl er confetti overheen valt. */
.feestkop { position: relative; text-align: center; padding: 6px 0 2px; }
.feestkop .mijl {
  font-size: 3.25rem; font-weight: 900; letter-spacing: -.04em;
  line-height: 1; color: var(--accent);
  position: relative; z-index: 2; display: inline-block;
}
.feestkop .mijl small { font-size: 1.25rem; font-weight: 800; margin-left: 2px; }
/* Het slotvenster van "Even op gang komen" heeft geen getal maar een woord.
   Kleiner dus, anders valt "Proost!" over de rand. */
.feestkop .mijl.woord { font-size: 2.5rem; }
.feestkop .feest-tekst { position: relative; z-index: 2; margin-top: 10px; }
.feest {
  position: absolute; left: 0; right: 0; top: -80px; bottom: -320px;
  pointer-events: none; overflow: hidden; z-index: 1;
}

/* Confetti: snippers die van boven naar beneden dwarrelen. Elk snippertje
   krijgt zijn eigen drift en draaiing mee; allemaal hetzelfde ziet eruit
   als regen. */
.cf {
  position: absolute; top: -20px; border-radius: 1px;
  animation: cf-val cubic-bezier(.25,.6,.5,1) forwards;
}
@keyframes cf-val {
  0%   { transform: translate(0, 0) rotate(0deg); opacity: 0; }
  8%   { opacity: 1; }
  85%  { opacity: 1; }
  100% { transform: translate(var(--dx), 400px) rotate(var(--rot)); opacity: 0; }
}

/* Vuurwerk: drie korte uitbarstingen achter het getal. Na anderhalve
   seconde is het stil en lees je gewoon wat er staat. */
.vonk {
  position: absolute; width: 5px; height: 5px; border-radius: 50%;
  animation: vonk-uit cubic-bezier(.15,.75,.3,1) forwards;
}
@keyframes vonk-uit {
  0%   { transform: translate(0,0) scale(1); opacity: 1; }
  70%  { opacity: 1; }
  100% { transform: translate(var(--x), var(--y)) scale(.3); opacity: 0; }
}
.knal {
  position: absolute; width: 10px; height: 10px; border-radius: 50%;
  border: 2px solid var(--accent-hi);
  animation: knal-uit .8s ease-out forwards;
}
@keyframes knal-uit {
  0%   { transform: scale(.2); opacity: .9; }
  100% { transform: scale(7); opacity: 0; }
}

/* Minder beweging gevraagd? Dan maakt startFeest() al niets aan. Dit is de
   tweede rem, voor het geval er toch iets getekend is. */
@media (prefers-reduced-motion: reduce) {
  .cf, .vonk, .knal { display: none; }
}

/* Drank-raster */
.drink-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin-bottom: 8px; }
/* Dezelfde behandeling als de tegels op Statistieken: geen rand, maar een
   zachte waas met rondere hoeken. Het drankje dat je koos licht goud op, net
   als een behaalde badge; dat is nu het enige verschil dat je hoeft te zien. */
.drink-opt {
  aspect-ratio: 1;
  background: var(--waas);
  border: 0;
  border-radius: var(--r-lg);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px;
  transition: transform .1s, background .16s;
  position: relative;
}
.drink-opt:active { transform: scale(.95); background: var(--waas-druk); }
.drink-opt.selected { background: var(--waas-goud); }
.drink-opt .em { font-size: 2.125rem; line-height: 1; }
.drink-opt .nm { font-size: 0.7813rem; font-weight: 600; color: var(--text-dim); }
.drink-opt.selected .nm { color: var(--accent); }
/* "Toevoegen" is een lege plek en geen drankje, dus die houdt zijn gestreepte
   rand. Als outline en niet als border: een outline verandert de maat van het
   vakje niet, dus hij blijft precies even groot als de tegels ernaast. */
.drink-opt.add {
  background: none;
  outline: 1.5px dashed var(--border-strong);
  outline-offset: -2px;
}
.drink-opt.add:active { background: var(--waas-druk); }
.drink-opt.add .em { color: var(--ink-mute); }

/* Drankjes beheren: één regel per drankje. Pictogram, naam, animatie, weg.
   Op een smal scherm zakt de animatie naar een eigen regel eronder, want
   drie velden naast elkaar wordt daar onleesbaar smal. */
.beheer-lijst { display: flex; flex-direction: column; gap: 8px; }
.beheer-rij {
  display: grid;
  grid-template-columns: 54px minmax(0, 1fr) minmax(0, 1.2fr) 32px;
  gap: 8px; align-items: center;
}
.beheer-rij .input { padding: 9px 10px; font-size: 0.875rem; }
.beheer-rij .em { text-align: center; font-size: 1.125rem; padding-left: 4px; padding-right: 4px; }
.beheer-rij .weg { color: var(--ink-mute); }
.beheer-rij .weg:active { color: var(--danger); }
@media (max-width: 420px) {
  .beheer-rij {
    grid-template-columns: 54px minmax(0, 1fr) 32px;
    grid-template-areas: "em nm weg" "an an an";
  }
  .beheer-rij .em { grid-area: em; }
  .beheer-rij .nm { grid-area: nm; }
  .beheer-rij .an { grid-area: an; }
  .beheer-rij .weg { grid-area: weg; }
}

/* ---------- Chat ---------- */
.thread {
  display: flex; flex-direction: column; gap: 8px;
  padding: 4px 0 12px;
}
.msg {
  max-width: 80%;
  padding: 9px 13px;
  border-radius: 16px;
  font-size: 0.9063rem;
  line-height: 1.4;
  word-break: break-word;
}
.msg.them { align-self: flex-start; background: var(--surface-2); border-bottom-left-radius: 5px; }
.msg.me   { align-self: flex-end; background: var(--accent); color: var(--on-accent); border-bottom-right-radius: 5px; }
.msg .who { font-size: 0.6875rem; font-weight: 700; color: var(--accent); margin-bottom: 2px; }
.msg.me .who { display: none; }
.msg .time { font-size: 0.625rem; opacity: .6; margin-top: 3px; display: block; }

.reactions-row { display: flex; gap: 8px; flex-wrap: wrap; margin: 4px 0 16px; }
.reaction-log { display: flex; flex-direction: column; gap: 6px; margin-bottom: 8px; }
.reaction-log .r { font-size: 0.8125rem; color: var(--text-dim); }
.reaction-log .r b { color: var(--text); font-weight: 600; }

/* Chat-pagina (1-op-1) */
.chat-head {
  display: flex; align-items: center; gap: 12px;
  margin-bottom: 6px;
}
.chat-head .avatar { flex: none; }
/* Het gesprek is de scrollbak van dit scherm; .vast-scroll regelt de hoogte.
   Hierdoor scrolt de pagina zelf niet meer mee: de kop met het gezicht blijft
   boven staan, de typebalk onder, en alleen de berichten bewegen. Daardoor
   kan de app ook echt naar het laatste bericht springen bij het openen; toen
   de hele pagina nog schoof, kwam je halverwege uit. */
.dm-thread {
  padding: 12px 2px;
  gap: 8px;
  overscroll-behavior: contain;
}
/* Alleen in de chatlijst. Daar hangt de tijd bovenaan, op één lijn met de
   naam, want daaronder staat het bericht zelf. */
.chat-time { font-size: 0.6875rem; color: var(--text-faint); flex: none; white-space: nowrap; align-self: flex-start; margin-top: 4px; }
.msg a { color: inherit; text-decoration: underline; font-weight: 600; }

/* Live-banner bovenaan een gesprek */
.dm-live {
  display: flex; align-items: center; gap: 10px;
  background: var(--accent-soft);
  border: 1px solid rgba(var(--accent-rgb), .35);
  border-radius: var(--r-md);
  padding: 10px 12px;
  margin: 6px 0 4px;
}
.dm-live .dot { width: 9px; height: 9px; border-radius: 50%; background: var(--live); flex: none; box-shadow: 0 0 0 3px rgba(52,211,153,.18); }
.dm-live .meta { flex: 1; min-width: 0; }
.dm-live .meta b { display: block; font-size: 0.875rem; }
.dm-live .meta a, .dm-live .meta span { font-size: 0.7813rem; color: var(--accent); font-weight: 600; }
.dm-live .chip { min-height: 36px; padding: 0 12px; font-size: 0.8125rem; flex: none; }
/* Het losse stipje voor een ongelezen bericht is vervallen: de rij zelf
   licht nu op (.friend-row.nieuw). Zie de rij-sectie hierboven. */

/* De typebalk staat vast onderaan. Vroeger was dit een sticky element dat
   over de berichten heen schoof, met een verloop eronder om die overgang te
   verzachten. Nu heeft het gesprek zijn eigen scrollbak, dus de balk is
   gewoon de onderste rij van een scherm dat precies past: hij overlapt niets
   meer en hoeft dus ook niets meer te verbergen. */
.composer {
  display: flex; gap: 8px; align-items: flex-end;
  flex: none;
  padding-top: 8px;
}
.composer .input { min-height: 46px; }
.composer .send {
  width: 46px; height: 46px; flex: none;
  border-radius: var(--r-full);
  background: var(--accent); color: var(--on-accent);
  display: grid; place-items: center;
}
.composer .send:disabled { opacity: .4; }

/* ---------- Kaart ---------- */
/* Leaflet pant/zoomt met CSS-transforms, die intern een eigen stapel-laag
   optrekken. Zonder een harde begrenzing hier kan die laag op sommige
   mobiele browsers boven een latere fixed-positioned sheet uitkomen, ook
   al is de z-index van die sheet hoger. isolation:isolate + een lage,
   expliciete z-index sluiten de kaart volledig op in haar eigen laag. */
#map {
  width: 100%; height: calc(100dvh - var(--nav-h) - var(--safe-b) - var(--safe-t) - 120px);
  min-height: 320px; border-radius: var(--r-md); overflow: hidden; border: 1px solid var(--border);
  position: relative; z-index: 0; isolation: isolate;
}

/* De Kaart-tab staat vast: precies één scherm hoog, nooit scrollen. Zelfde
   aanpak als het startscherm. De kop is compacter dan elders, zodat de kaart
   wat hoger begint en er meer van te zien is; de kaart neemt daarna alle
   ruimte die overblijft, hoe hoog of laag de telefoon ook is. */
.view-map {
  height: 100dvh;
  display: flex;
  flex-direction: column;
}
.view-map .page-title { font-size: 1.375rem; margin-bottom: 2px; }
.view-map .page-sub { margin-bottom: 10px; }
.view-map .kaart-vlak { flex: 1 1 auto; min-height: 0; }
.view-map #map { height: 100%; min-height: 0; }
/* Harde garantie bovenop isolation: onzichtbaar zolang er een sheet open
   staat (zie openSheet/sluitSheetVisueel), zodat de kaart nooit, ook niet
   door een compositing-eigenaardigheid van de mobiele browser, boven de
   sheet kan uitsteken. visibility i.p.v. display, zodat de kaart zijn
   grootte/positie behoudt en niet opnieuw hoeft te initialiseren. */
#map.map-hidden { visibility: hidden; }
.leaflet-container { background: #e9e9ee !important; font-family: inherit; }

/* Tijdens de openingsvlucht staan de spelden uit. Ze zijn op dat zoomniveau
   toch onleesbaar en ze moeten anders elk beeld opnieuw geplaatst worden, wat
   je als schokken terugziet. Alleen opacity, want dat draait op de
   grafische kaart en kost geen herberekening van de pagina. Bij aankomst
   komen ze in een halve seconde tevoorschijn: dat leest als landen. */
#map .leaflet-marker-pane { transition: opacity .5s ease; }
#map.vliegt .leaflet-marker-pane { opacity: 0; }
@media (prefers-reduced-motion: reduce) {
  #map .leaflet-marker-pane { transition: none; }
}

/* Eigen locatie: blauwe stip met zachte pulserende ring (zoals gebruikelijk). */
.me-dot {
  position: relative;
  width: 18px; height: 18px; border-radius: 50%;
  background: #2f80ff; border: 3px solid #fff;
  box-shadow: 0 0 0 3px rgba(47, 128, 255, .35), 0 1px 4px rgba(0, 0, 0, .4);
}
.me-dot::before {
  content: ""; position: absolute; left: 50%; top: 50%;
  width: 18px; height: 18px; border-radius: 50%;
  background: rgba(47, 128, 255, .35);
  transform: translate(-50%, -50%);
  animation: me-puls 2s ease-out infinite;
}
@keyframes me-puls {
  0%   { transform: translate(-50%, -50%) scale(1);   opacity: .6; }
  100% { transform: translate(-50%, -50%) scale(3.2); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) { .me-dot::before { animation: none; } }

/* Compacte marker: emoji + naam, met pijltje naar de plek */
.bmm-pin { pointer-events: auto; }
/* ---------- Wie er nu drinkt: een gezicht op de kaart ----------
   Zelfde taal als een actief stekkie: rond, groene rand, kloppend bolletje.
   Een naambalkje per persoon werd een muur van tekst zodra er drie mensen
   bij elkaar stonden; een gezicht herken je in één blik en het neemt een
   vaste, kleine ruimte in. Wie het is en wat hij drinkt lees je in de sheet
   die opengaat als je erop tikt. */
.map-av {
  position: relative;
  display: inline-grid; place-items: center;
  /* Zelfde vorm en zelfde ankerpunt als een stekkie: rond met een scherpe
     hoek linksonder die de plek aanwijst, en die hoek staat precies op de
     coördinaat. Zonder dat puntje zweeft een gezicht boven de kaart zonder
     te zeggen wáár het staat. */
  transform: translate(-50%, -100%);
  width: 30px; height: 30px;      /* precies zo groot als een stekkie */
  border-radius: 50% 50% 50% 4px;
  /* De rand is dezelfde aftellende klok als op het startscherm: het groene
     deel is de tijd die deze persoon nog heeft, het oranje deel de tijd die
     op is. --deel wordt door app.js gezet en elke tien seconden bijgewerkt.
     Geen echte border maar padding met een verloop erachter, want een border
     kan geen cirkelverloop dragen. */
  --deel: 1;
  --ring-groen: var(--live);
  --ring-oranje: #f5a524;
  padding: 3px;
  background: conic-gradient(
    var(--ring-groen) calc(var(--deel) * 360deg),
    var(--ring-oranje) 0
  );
  box-shadow: 0 2px 10px rgba(0, 0, 0, .55);
}
/* De foto blijft een cirkel binnen die vorm, zodat het puntje linksonder
   vrij blijft en als punt leesbaar is. */
.map-av .ma-foto {
  width: 100%; height: 100%;
  border-radius: 50%; overflow: hidden;
  display: grid; place-items: center;
  background: var(--surface-3);
  color: var(--accent);
  font-size: 0.625rem; font-weight: 700; letter-spacing: -.02em;
}
/* Zelfde reden als bij .avatar .av-img: uit het raster gelicht, anders
   houdt een staande foto zijn eigen hoogte en puilt de speld uit. */
.map-av .ma-foto { position: relative; }
.map-av .ma-foto .av-img {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover;
}
/* Het drankje als klein plaatje rechtsboven: dat is het onderwerp van een
   check-in, dus dat mag je zien zonder te tikken. */
.map-av .ma-em {
  position: absolute; top: -5px; right: -5px;
  width: 16px; height: 16px;
  border-radius: 50%;
  background: var(--surface);
  border: 1px solid var(--border-strong);
  display: grid; place-items: center;
  font-size: 0.5625rem; line-height: 1;
}
/* Jij bent de uitzondering, maar niet in de ring: die is bij jou net zo goed
   een klok. Jouw speld krijgt er een accentrand omhéén, zodat je jezelf
   terugvindt zonder dat je eigen aftelling onleesbaar wordt. */
.map-av.me { box-shadow: 0 2px 10px rgba(0,0,0,.55), 0 0 0 2px var(--accent); }

/* ---------- Stekkies (vaste plekken) ----------
   Bewust rustiger dan een check-in-speld: mensen zijn het nieuws, plekken
   de achtergrond. Alleen het icoon; de naam zie je als je erop tikt. */
.stek-pin {
  position: relative; /* anker voor het aantal-bolletje */
  display: inline-flex; align-items: center; justify-content: center;
  transform: translate(-50%, -100%);
  width: 30px; height: 30px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 50% 50% 50% 4px;
  box-shadow: 0 2px 6px rgba(0, 0, 0, .45);
  opacity: .7;
}
/* Zit er niemand, dan is het een plek en geen gebeurtenis. Grijs, ook het
   icoon: een gekleurd biertje op een grijze speld trekt evenveel aandacht
   als een actieve. Zo is het verschil met een groene speld meteen duidelijk,
   zonder dat de plek helemaal verdwijnt. */
.stek-pin .pe { font-size: 0.9375rem; line-height: 1; filter: grayscale(1); }
.stek-pin.actief .pe { filter: none; }

/* Zit er nu iemand op dit stekkie, dan mag de plek opvallen: daar gebeurt het.
   Groen en niet de accentkleur, want groen betekent in deze app overal "dit
   gebeurt nu" (de live-stip, de ring om een gezicht). Bij een blauw of paars
   accent moet dat verschil overeind blijven. */
.stek-pin.actief {
  opacity: 1;
  border-color: var(--live);
  background: color-mix(in oklab, var(--live) 14%, var(--surface));
  box-shadow: 0 2px 10px rgba(0, 0, 0, .5), 0 0 0 3px rgba(52, 211, 153, .18);
}
/* Het kloppende bolletje. Geen gelijkmatig ademen maar een échte hartslag:
   twee tikken kort achter elkaar en dan rust. Dat leest als leven, waar een
   sinus als een laadindicator leest. De rust aan het eind is net zo belangrijk
   als de tikken zelf; zonder die pauze wordt het trillen. */
/* Rechtsonder, niet linksonder: de speld heeft linksonder een scherpe punt
   die de plek aanwijst, en daar hoort niets overheen te liggen. */
.sp-live {
  position: absolute; right: -3px; bottom: -1px;
  width: 11px; height: 11px;
  border-radius: 50%;
  background: var(--live);
  border: 2px solid var(--surface);
  animation: sp-klop 1.9s ease-in-out infinite;
}
/* Langzamer gemaakt van 1,2 naar 1,9 seconde. De tikken zelf zijn even kort
   gebleven en alleen de rust erna is langer geworden: de percentages zijn
   daarom meegeschaald. Had ik ze laten staan, dan waren de twee tikken zelf
   trager geworden en dat leest niet als een rustiger hartslag maar als een
   trage. Een hart dat kalmer klopt tikt even hard, alleen minder vaak. */
@keyframes sp-klop {
  0%   { transform: scale(1);    opacity: 1; }
  7.5% { transform: scale(1.34); opacity: .85; }  /* lub */
  15%  { transform: scale(1);    opacity: 1; }
  23%  { transform: scale(1.22); opacity: .9; }   /* dub */
  30%  { transform: scale(1);    opacity: 1; }
  100% { transform: scale(1);    opacity: 1; }    /* rust */
}
@media (prefers-reduced-motion: reduce) {
  .sp-live { animation: none; }
}
/* Op een actieve speld hoort het aantal dezelfde taal te spreken als het
   bolletje; groen naast oranje op één speld van 30 pixels vecht. */
.stek-pin.actief .sp-aantal { background: var(--live); color: #06231a; }
.sp-aantal {
  position: absolute; top: -6px; right: -8px;
  min-width: 18px; height: 18px;
  padding: 0 5px;
  border-radius: var(--r-full);
  background: var(--accent);
  color: var(--on-accent);
  font-size: 0.6875rem; font-weight: 800; line-height: 18px;
  text-align: center;
  font-variant-numeric: tabular-nums;
  box-shadow: 0 1px 4px rgba(0, 0, 0, .5);
}

/* De knoppen over de kaart. Met tekst erbij, want een kaal plusje op een
   kaart zegt niemand iets. Ze liggen óver de kaart en niet eronder, zodat
   de kaart-tab op één scherm past en je niet hoeft te scrollen.
   z-index onder de sheet, boven de tegels. */
.kaart-vlak { position: relative; }
.kaart-knoppen {
  position: absolute; left: 10px; right: 10px; bottom: 10px; z-index: 500;
  display: flex; justify-content: space-between; align-items: flex-end; gap: 8px;
  pointer-events: none; /* de kaart blijft sleepbaar tussen de knoppen door */
}
.kaart-knoppen > * { pointer-events: auto; }
.stek-knop {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--surface);
  color: var(--text);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-full);
  padding: 9px 14px;
  font-size: 0.8125rem; font-weight: 600;
  box-shadow: 0 2px 10px rgba(0, 0, 0, .5);
}
.stek-knop:active { background: var(--surface-2); }
/* Verdwijnen mee met de kaart zodra er een sheet overheen komt. */
#map.map-hidden + .kaart-knoppen { visibility: hidden; }

/* Popup in het donkere thema */
.leaflet-popup-content-wrapper, .leaflet-popup-tip { background: var(--surface-2); color: var(--text); box-shadow: var(--shadow); }
.leaflet-popup-content { font-size: 0.8125rem; margin: 10px 12px; }
.leaflet-popup-content b { color: var(--accent); }
.leaflet-container a.leaflet-popup-close-button { color: var(--text-dim); }

/* ---------- Geschiedenis ---------- */
.stat-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin-bottom: 22px; }
.stat {
  background: var(--waas); border: 0;
  border-radius: var(--r-lg); padding: 17px 13px; text-align: center;
}
.stat .n { font-size: 1.625rem; font-weight: 800; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.stat .l { font-size: 0.75rem; color: var(--text-dim); margin-top: 2px; }
/* Een tegel die ergens heen gaat, hoort daar ook naar te voelen. Alleen de
   tegels met een bestemming krijgen dit; de rest blijft een tegel. Zonder rand
   moet de waas het verschil maken, dus die is hier goud in plaats van grijs. */
.stat.klikbaar { cursor: pointer; background: var(--waas-goud); transition: background .16s; }
.stat.klikbaar:active { background: var(--waas-druk); }
.stat.klikbaar .l { color: var(--accent); }
.stat.klikbaar:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
/* De historie is ook een lijst, dus die volgt dezelfde regels: geen vakje,
   wel een haarlijn ertussen. Bleef hij een kaart, dan stonden er in dezelfde
   app twee soorten lijsten naast elkaar. */
.hist-row {
  display: flex; align-items: center; gap: 14px;
  padding: 12px;
  position: relative;
}
.hist-row .em { font-size: 1.625rem; }
.hist-row .meta b { font-size: 0.9375rem; }
.hist-row .meta span { font-size: 0.8125rem; color: var(--text-dim); display: block; }

/* ---------- Toast ---------- */
.toast-action {
  margin-left: 12px;
  font-size: 0.8125rem; font-weight: 700;
  /* Op glas is het gewone accent net te donker; dit is dezelfde kleur, een
     tint lichter, zodat "Opnieuw" ook boven een druk scherm leesbaar blijft. */
  color: var(--accent-hi);
  padding: 4px 8px; margin: -4px -4px -4px 8px;
  border-radius: var(--r-sm);
  flex: none;
}
.toast-action:active { background: rgba(255,255,255,.08); }

.toast-wrap {
  position: fixed; left: 0; right: 0; top: calc(var(--safe-t) + 10px);
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  z-index: var(--z-toast); pointer-events: none; padding: 0 16px;
}
/* De melding is van glas: half doorzichtig, alles erachter vervaagt, en een
   dun lichtrandje bovenlangs alsof er licht op de rand valt. De kleur zit in
   het glas zelf en niet alleen in de rand, want een rand van één pixel is te
   weinig om "gelukt" of "misgegaan" mee te zeggen.
   De vulling staat bewust in background-color en de kleur in background-image:
   zo kan de fallback onderaan er een dicht vlak van maken zonder de kleur
   kwijt te raken. */
.toast {
  background-color: rgba(38,38,46,.55);
  -webkit-backdrop-filter: blur(18px) saturate(1.6);
  backdrop-filter: blur(18px) saturate(1.6);
  border: 1px solid rgba(255,255,255,.14);
  color: var(--text);
  padding: 12px 18px;
  border-radius: var(--r-full);
  font-size: 0.875rem; font-weight: 600;
  box-shadow: 0 10px 34px rgba(0,0,0,.5), inset 0 1px 0 rgba(255,255,255,.16);
  animation: toastIn .52s cubic-bezier(.21, 1.32, .38, 1);
  max-width: 100%;
  /* De wrapper laat aanrakingen door; de melding zelf vangt ze op, zodat
     "Opnieuw" aantikbaar is en je een fout kunt wegtikken. */
  pointer-events: auto;
  display: flex; align-items: center;
  text-align: left;
}
.toast.good {
  background-image: linear-gradient(150deg, rgba(52,211,153,.26), rgba(52,211,153,.08));
  border-color: rgba(52,211,153,.34);
}
.toast.bad {
  background-image: linear-gradient(150deg, rgba(239,68,68,.26), rgba(239,68,68,.08));
  border-color: rgba(239,68,68,.38);
}
/* Hij valt van boven het scherm naar binnen, schiet iets door en veert terug.
   Dat leest als iets dat neerkomt in plaats van iets dat verschijnt. */
@keyframes toastIn {
  from { opacity: 0; transform: translateY(-140%) scale(.94); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
/* En hij gaat dezelfde weg terug omhoog. */
.toast.weg { animation: toastUit .26s ease-in forwards; }
@keyframes toastUit {
  from { opacity: 1; transform: translateY(0) scale(1); }
  to   { opacity: 0; transform: translateY(-90%) scale(.96); }
}

/* Oudere Android-telefoons kennen geen vervaging en tonen dan alleen de
   halfdoorzichtige vulling. Boven de gele check-in-knop wordt de tekst dan
   onleesbaar, dus daar wordt het glas een dicht vlak. De kleur van "gelukt"
   en "misgegaan" ligt erbovenop en blijft dus gewoon staan. */
@supports not ((backdrop-filter: blur(2px)) or (-webkit-backdrop-filter: blur(2px))) {
  .toast { background-color: var(--surface-3); border-color: var(--border-strong); }
}

/* ---------- Auth / onboarding ---------- */
.auth {
  min-height: 100dvh;
  display: flex; flex-direction: column; justify-content: center;
  padding: 40px 28px calc(40px + var(--safe-b));
  text-align: center;
}
.auth .logo { width: 84px; height: 84px; margin: 0 auto 20px; color: var(--accent); }
.auth h1 { font-size: 1.875rem; font-weight: 800; letter-spacing: -.03em; }
.auth .tag { color: var(--text-dim); margin: 8px 0 34px; font-size: 0.9375rem; }
.auth form { text-align: left; }
.auth .switch { margin-top: 20px; font-size: 0.875rem; color: var(--text-dim); }

.divider { display: flex; align-items: center; gap: 12px; color: var(--text-faint); font-size: 0.75rem; margin: 20px 0; }
.divider::before, .divider::after { content: ""; flex: 1; height: 1px; background: var(--border); }

/* Spinner */
.spinner {
  width: 18px; height: 18px; border-radius: 50%;
  border: 2px solid rgba(0,0,0,.25); border-top-color: currentColor;
  animation: spin .7s linear infinite;
}
.spinner.big { width: 30px; height: 30px; border-width: 3px; border-color: var(--border); border-top-color: var(--accent); }
@keyframes spin { to { transform: rotate(360deg); } }
.center-spin { min-height: 60dvh; display: grid; place-items: center; }

/* ---------- Accentkleur-kiezer ---------- */
.swatch-dot { width: 20px; height: 20px; border-radius: 50%; flex: none; border: 2px solid var(--surface); box-shadow: 0 0 0 1px var(--border-strong); }
.swatch-dot.big { width: 30px; height: 30px; }
.swatch-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.swatch {
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  padding: 14px 8px; border-radius: var(--r-md);
  background: var(--surface-2); border: 2px solid var(--border);
  font-size: 0.7813rem; font-weight: 600; color: var(--text-dim);
  transition: border-color .16s, background .16s;
}
.swatch.on { border-color: var(--accent); background: var(--accent-soft); color: var(--text); }

/* ---------- Balkgrafiek (drankverdeling) ---------- */
.bars { display: flex; flex-direction: column; gap: 9px; }
.bar-row { display: flex; align-items: center; gap: 10px; }
.bar-label { flex: 0 0 40%; font-size: 0.8125rem; font-weight: 600; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bar-track { flex: 1; height: 12px; background: var(--surface-2); border-radius: var(--r-full); overflow: hidden; }
.bar-fill { display: block; height: 100%; width: 100%; background: linear-gradient(90deg, var(--accent), var(--accent-hi)); border-radius: var(--r-full); transform: scaleX(0); transform-origin: left; transition: transform .5s cubic-bezier(.22,1,.36,1); }
.bar-val { flex: none; font-size: 0.8125rem; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--text-dim); min-width: 20px; text-align: right; }

/* ---------- Badges ---------- */
.badge-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.badge {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 15px 7px; border-radius: var(--r-lg); width: 100%;
  background: var(--waas); border: 0;
  text-align: center;
  opacity: .38; filter: grayscale(.7);
  transition: opacity .2s, transform .15s;
}
.badge:active { transform: scale(.95); }
.badge.on { opacity: 1; filter: none; background: var(--waas-goud); }
.badge .be { font-size: 1.875rem; line-height: 1; }
.badge .bn { font-size: 0.7188rem; font-weight: 600; color: var(--text-dim); }
.badge.on .bn { color: var(--text); }

/* ---------- Ranglijst ---------- */
.friend-row .rank { flex: none; width: 26px; text-align: center; font-size: 1.0625rem; font-weight: 800; color: var(--text-dim); font-variant-numeric: tabular-nums; }
.friend-row.me-row { border-color: rgba(var(--accent-rgb), .4); background: var(--accent-soft); }
.fr-main { display: flex; align-items: center; gap: 14px; flex: 1; min-width: 0; cursor: pointer; }
.fr-main:active { opacity: .7; }

/* ============================================================
   DE INTRO: twee figuren die binnenlopen en proosten
   ============================================================
   Speelt één keer, bij de allereerste start, over het inlogscherm heen.
   Als hij klaar is lost hij op en staat het echte inlogscherm er al.

   Drie dingen zijn geen versiering maar noodzaak:
   - je kunt hem altijd wegtikken (je wilt inloggen, niet kijken)
   - hij slaat zichzelf over bij "minder beweging"
   - gaat er iets mis, dan komt het inlogscherm er gewoon
   Inloggen mag nooit van een animatie afhangen. */
.intro-laag {
  position: fixed; inset: 0;
  z-index: var(--z-intro);
  background: var(--bg);
  display: grid; place-items: center;
}
.intro-laag svg { width: 100%; height: 100%; display: block; }

/* De onderdelen van een figuur. Elk krijgt in de code een eigen id, zodat
   armen, benen en glas los van elkaar kunnen bewegen. */
.intro-laag .hoofd { fill: var(--accent-hi); }
.intro-laag .romp  { fill: var(--accent); }
.intro-laag .lid   { stroke: var(--accent-strong); stroke-width: 7; stroke-linecap: round; fill: none; }
.intro-laag .glasje { fill: var(--accent-hi); }
.intro-laag .schuim { fill: #fff7e6; }
.intro-laag .vonk   { stroke: var(--accent-hi); stroke-width: 2.4; stroke-linecap: round; }

/* Groepen die als geheel groter worden, moeten dat om hun eigen midden doen.
   Zonder deze regel rekent de browser vanaf de linkerbovenhoek van het
   tekenvak en schuift het hele tafereel bij het opschalen naar rechtsonder. */
.intro-laag #introFiguren,
.intro-laag #introVonken,
.intro-laag #introGrond { transform-box: fill-box; transform-origin: center; }

.intro-over {
  position: absolute; top: calc(var(--safe-t) + 14px); right: 14px;
  padding: 8px 16px; border-radius: var(--r-full);
  background: rgba(255,255,255,.08);
  color: var(--text-dim); font-size: 0.8125rem; font-weight: 600;
}
.intro-over:active { background: rgba(255,255,255,.16); }

/* ============================================================
   MACHTIGINGEN: het scherm na het aanmelden
   ============================================================
   Eén moment, twee stappen, elk met een eigen knop. Dat laatste is geen
   omslachtigheid: een telefoon toont zijn toestemmingsvraag alleen als die
   rechtstreeks uit een tik voortkomt, en twee vragen achter één knop laat
   de tweede wegvallen. */
.mach-stap { display: flex; flex-direction: column; min-height: 100dvh; padding-bottom: calc(var(--safe-b) + 20px); }
.mach-teller {
  font-size: 0.75rem; font-weight: 700; letter-spacing: .06em;
  color: var(--text-faint); text-transform: uppercase;
  margin-bottom: 10px;
}
.mach-icoon {
  width: 74px; height: 74px; margin: 0 auto 18px;
  border-radius: 50%; display: grid; place-items: center;
  background: var(--waas-goud); color: var(--accent);
}
.mach-icoon svg { width: 38px; height: 38px; }
.mach-kop { text-align: center; }
.mach-kop h1 { font-size: 1.5rem; font-weight: 700; letter-spacing: -.02em; margin-bottom: 8px; }
.mach-kop p { color: var(--text-dim); font-size: 0.9375rem; line-height: 1.6; }
.mach-punten { list-style: none; margin: 22px 0 0; display: flex; flex-direction: column; gap: 12px; }
.mach-punten li {
  display: flex; gap: 12px; align-items: flex-start;
  font-size: 0.9063rem; line-height: 1.5;
}
.mach-punten .vink { flex: none; color: var(--live); font-weight: 800; }
/* De knoppen zakken naar de onderkant: daar staat je duim. */
.mach-voet { margin-top: auto; padding-top: 26px; }
.mach-uitleg { font-size: 0.8125rem; color: var(--text-faint); line-height: 1.55; margin-top: 14px; text-align: center; }
.mach-gelukt { color: var(--live); font-weight: 700; text-align: center; margin-top: 14px; font-size: 0.9063rem; }

/* ---------- Foto's ----------
   Twee soorten, allebei tijdelijk: het kiekje bij een check-in dat een
   halfuur lang je gezicht is, en de foto in een gesprek die na een dag
   weg is. Zie de uitleg boven maakFoto() in js/app.js. */

/* Een gezicht waar nu een check-in-foto in zit, krijgt een klein
   cameraatje in de hoek. Dat doet twee dingen tegelijk: het zegt dat dit
   niet iemands profielfoto is, en het is het enige teken dat erop tikken
   iets doet. Zonder dat merkje zou je het nooit proberen. */
.avatar:has(img.foto-nu)::before {
  content: "📷"; position: absolute; left: -2px; top: -2px;
  width: 17px; height: 17px; border-radius: 50%;
  background: var(--surface); border: 1.5px solid var(--border);
  display: grid; place-items: center; font-size: 8px; line-height: 1;
  z-index: 1;
}
.avatar img.foto-nu, .ma-foto img.foto-nu { cursor: zoom-in; }

/* De fotoregel in het check-invenster. Dicht: één knop over de volle
   breedte, want een halve knop naast niets ziet eruit als een fout. */
.chip.foto-knop { width: 100%; justify-content: center; }
.foto-mee {
  display: flex; align-items: center; gap: 12px;
  padding: 8px; border-radius: var(--r-md);
  background: var(--surface-2); border: 1px solid var(--border);
}
.foto-mee img {
  width: 52px; height: 52px; flex: none;
  border-radius: 10px; object-fit: cover;
}
.foto-mee .fm-tekst { flex: 1; min-width: 0; line-height: 1.35; }
.foto-mee .fm-tekst b { display: block; font-size: 0.875rem; }
.foto-mee .fm-tekst span { font-size: 0.75rem; color: var(--text-dim); }

/* De twee knoppen onder het glas op Start. Naast elkaar, want ze zijn
   even belangrijk en allebei bijzaak. */
.home-acties { display: flex; gap: 8px; flex-wrap: wrap; justify-content: center; }

/* De cameraknop in de chatbalk. Even hoog als het invoervak ernaast,
   maar rustiger dan de verstuurknop: die is goud en heeft voorrang. */
.composer .foto-send {
  width: 46px; height: 46px; flex: none;
  border-radius: var(--r-full);
  background: var(--surface-2); border: 1px solid var(--border);
  display: grid; place-items: center; font-size: 1.125rem;
  transition: background .16s;
}
.composer .foto-send:active { background: var(--surface-3); }
.composer .foto-send:disabled { opacity: .4; }

/* Een foto in een bericht. De bel krimpt tot om de foto heen: een
   gekleurde rand van 13px rondom een plaatje is een lijstje, en dat is
   niet wat een chatbericht hoort te zijn. */
/* De foto krijgt een vaste breedte en niet 100%. Een bel groeit mee met zijn
   inhoud, dus bij een breedte in procenten kijken die twee naar elkaar en
   wordt de bel zo smal als de foto zelf. Bij een staande foto blijft er dan
   een strookje van veertig pixels over. Vaste breedte, hoogte naar rato, en
   pas als het echt te hoog wordt snijden we bij; de hele foto zie je door
   erop te tikken. */
.msg.met-foto { padding: 4px; }
.msg-foto {
  display: block; width: 216px; max-width: 100%;
  height: auto; max-height: 300px; object-fit: cover;
  border-radius: 13px; cursor: zoom-in;
}
.msg.met-foto .time { padding: 0 9px 3px; }
.msg.met-foto > :not(.msg-foto):not(.time) { padding: 6px 9px 0; display: block; }

/* Schermvullend kijken. Tik waar je wilt en hij is weg. */
.fotoscherm {
  position: fixed; inset: 0; z-index: var(--z-foto);
  background: rgba(0,0,0,.92);
  display: grid; place-items: center; padding: 24px;
  opacity: 0; transition: opacity .18s ease-out;
  cursor: zoom-out;
}
.fotoscherm.aan { opacity: 1; }
.fotoscherm img {
  max-width: 100%; max-height: 82vh;
  border-radius: 14px; display: block;
  box-shadow: 0 24px 60px rgba(0,0,0,.6);
}
.fotoscherm .fs-onder {
  position: absolute; left: 24px; right: 24px; bottom: 26px;
  text-align: center; color: rgba(255,255,255,.78);
  font-size: 0.8125rem; font-weight: 600;
}
/* Bovenin, maar onder de statusbalk. In de app tekent de pagina daar
   achter door, en een kruisje onder de klok en het batterijtje is er wel maar
   zie je niet. */
.fotoscherm .fs-dicht {
  position: absolute; top: calc(max(var(--safe-t), var(--balk)) + 18px); right: 18px;
  width: 40px; height: 40px; border-radius: var(--r-full);
  background: rgba(255,255,255,.14); color: #fff;
  display: grid; place-items: center; font-size: 1.0625rem;
}
/* Wat je met een foto kunt doen, staat bij de foto zelf: daar kijk je op dat
   moment naar. Links, ver van de sluitknop, want dit tik je niet per ongeluk
   aan. Ze verschijnen alleen als het jouw foto is. */
.fotoscherm .fs-knop {
  position: absolute; top: calc(max(var(--safe-t), var(--balk)) + 18px);
  width: 40px; height: 40px; border-radius: var(--r-full);
  background: rgba(255,255,255,.14); color: #fff;
  display: grid; place-items: center; font-size: 1.0625rem;
  cursor: pointer;
}
.fotoscherm .fs-weg { left: 18px; }
.fotoscherm .fs-weg:active { background: var(--danger); }
/* Naast de prullenbak, of op die plek als er geen prullenbak is. */
.fotoscherm .fs-vervang { left: 18px; }
.fotoscherm .fs-weg ~ .fs-vervang { left: 66px; }
.fotoscherm .fs-vervang:active { background: var(--accent); color: var(--on-accent); }

/* ---------- Het album van een stekkie ----------
   Foto's die op deze plek gemaakt zijn. Vierkant en klein: het is een
   herinnering aan een avond, geen fotogalerij. Tikken maakt hem groot. */
.album {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
  gap: 8px;
  margin-bottom: 4px;
}
.album-tegel {
  position: relative; aspect-ratio: 1;
  border: 0; padding: 0; overflow: hidden;
  border-radius: var(--r-md);
  background: var(--surface-2);
  cursor: pointer;
}
.album-tegel img { width: 100%; height: 100%; object-fit: cover; display: block; }
.album-tegel:active { transform: scale(.96); }
/* Het bijschrift ligt over de onderkant van de foto. Met een verloop
   erachter, want een lichte foto maakt witte letters onleesbaar. */
.album-tegel .at-tekst {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 14px 6px 5px;
  font-size: 0.6875rem; font-weight: 600; line-height: 1.3;
  color: #fff; text-align: left;
  background: linear-gradient(to top, rgba(0,0,0,.78), transparent);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ---------- "Wat is er nieuw" ----------
   Eén keer na een update. Kop en regels, verder niets: dit is een mededeling
   en geen scherm waar je iets moet doen. */
.nieuws { display: flex; flex-direction: column; gap: 16px; margin-top: 14px; }
.nieuws-punt { display: flex; flex-direction: column; gap: 3px; }
.nieuws-punt b {
  font-size: 0.9375rem; font-weight: 700; color: var(--text);
  letter-spacing: -.005em;
}
.nieuws-punt span {
  font-size: 0.875rem; line-height: 1.5; color: var(--text-dim);
}

/* De zin die iemand bij zijn check-in zette. */
.checkin-bericht {
  margin: 2px 0 10px;
  color: var(--text);
  font-size: 0.9375rem; line-height: 1.5;
}
@media (prefers-reduced-motion: reduce) {
  .fotoscherm { transition: none; }
}
