/* ==========================================================================
   PartyTracks - design system
   Mobiel eerst. Alle maten schalen mee met de viewport; tikdoelen zijn
   minimaal 44px zodat de stemknoppen ook met een biertje in de hand werken.
   ========================================================================== */

/*
   De letter van de koppen.

   De site stond op de systeemletter. Dat kost niets en leest prima, maar het
   betekent ook dat de voorpagina op een Mac als een Mac leest en op Windows
   als Windows: er is geen gezicht, alleen tekst in de letter van het
   apparaat. Voor een feest is dat te braaf.

   Unbounded. Breed, hoekig en zwaar, met rechte stukken waar je ronde
   verwacht. Het is de letter van een clubflyer en niet van een nieuwsbrief,
   en dat is precies waar deze site over gaat. Hij staat een tel in de weg op
   een lange kop, want hij is breed, maar onze koppen zijn kort.

   Zelf meegeleverd en niet van Google. Dat moet ook: de CSP laat voor letters
   alleen 'self' toe, zie View::securityHeaders. De licentie (SIL OFL) staat
   ernaast in de map.

   Eén dikte in het bestand en niet de hele as. Unbounded loopt van 400 tot
   900 en dat hele bestand is 51 kB; alleen de 700 is er 21. We gebruiken
   nergens iets anders dan 700, dus de rest is gewicht waar niemand iets aan
   heeft. Zet je hieronder ooit een kop op 800, zet dan ook de hele as terug,
   anders maakt de browser er zelf iets dikkers van en dat wordt een veeg.

   De lopende tekst blijft de systeemletter. Die is op elk apparaat thuis,
   kost niets, en Unbounded is te zwaar om een alinea in te lezen.

   font-display: swap, dus de kop staat er meteen in de systeemletter en
   verspringt zodra de echte binnen is. Daarom staat er ook een preload op in
   Layout: dan is hij er voor de eerste weergave en verspringt er niets.
*/
@font-face {
  font-family: "Unbounded";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(/assets/fonts/unbounded-latin.woff2) format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
  /* Kleur */
  --bg:          #0b0d0f;
  --bg-elevated: #101315;
  --surface:     #16191d;
  --surface-2:   #1e2329;
  --surface-3:   #272d34;
  --line:        #2b3138;
  --line-strong: #3a424b;

  --text:        #f3f6f8;
  --text-muted:  #98a4b1;
  --text-faint:  #6b7681;

  --brand:       #1ed760;
  --brand-dim:   #17b34f;
  --brand-ink:   #04170b;

  --up:          #34d17a;
  --down:        #f4536b;
  --amber:       #ffcb47;
  --danger:      #ff5f6d;

  /* Vorm */
  --r-sm: 8px;
  --r-md: 12px;
  --r-lg: 18px;
  --r-xl: 26px;
  --r-pill: 999px;

  /* Ruimte */
  --s-1: 4px;
  --s-2: 8px;
  --s-3: 12px;
  --s-4: 16px;
  --s-5: 24px;
  --s-6: 32px;
  --s-7: 48px;

  /* Diepte */
  --shadow-1: 0 1px 2px rgba(0,0,0,.4);
  --shadow-2: 0 6px 24px rgba(0,0,0,.45);
  --shadow-3: 0 18px 48px rgba(0,0,0,.55);

  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  /* De koppen in de eigen letter, de rest in die van het apparaat. De
     systeemletter staat er ook achter: tot het bestand binnen is staat de
     kop daarin, en op een apparaat dat de letter niet haalt blijft het
     gewoon leesbaar. */
  --font-kop: "Unbounded", var(--font);
  --tap: 44px;

  color-scheme: dark;
}

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

/* Losse links in tekst: groen in plaats van het blauw en paars van de
   browser, en bezocht ziet er hetzelfde uit als onbezocht. Knoppen, chips en
   menubalken zetten hun eigen kleur en trekken zich hier niets van aan. */
/* :where() houdt de specificiteit op nul, zodat elke klasse (knop, chip,
   menubalk) er zonder gedoe overheen gaat; a:visited won anders van .pt-btn
   en kleurde de tekst op een groene knop groen. */
:where(a) { color: var(--brand); text-decoration: underline; text-decoration-color: rgba(30, 215, 96, .35); text-underline-offset: 2px; }
:where(a:hover) { text-decoration-color: currentColor; }
:where(a:visited) { color: var(--brand); }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  min-height: 100dvh;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  overscroll-behavior-y: none;
}

img { max-width: 100%; display: block; }
button, input, select, textarea { font: inherit; color: inherit; }

:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
  border-radius: var(--r-sm);
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ------------------------------------------------------------- structuur */

.pt-shell {
  width: 100%;
  max-width: 760px;
  margin: 0 auto;
  padding: 0 var(--s-4);
  padding-left: max(var(--s-4), env(safe-area-inset-left));
  padding-right: max(var(--s-4), env(safe-area-inset-right));
}

.pt-shell--wide { max-width: 1180px; }


.pt-centered {
  display: grid;
  place-items: center;
  min-height: 100dvh;
  padding: var(--s-4);
}

.pt-stack > * + * { margin-top: var(--s-4); }
.pt-stack-sm > * + * { margin-top: var(--s-2); }

/* ---------------------------------------------------------------- header */

.pt-topbar {
  position: sticky;
  top: 0;
  z-index: 40;
  background: rgba(11,13,15,.86);
  backdrop-filter: saturate(150%) blur(12px);
  -webkit-backdrop-filter: saturate(150%) blur(12px);
  border-bottom: 1px solid var(--line);
  padding-top: env(safe-area-inset-top);
}

.pt-topbar__inner {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  min-height: 56px;
  padding: var(--s-2) 0;
}

.pt-brand {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  font-family: var(--font-kop);
  font-weight: 700;
  letter-spacing: -.015em;
  text-decoration: none;
  color: var(--text);
  white-space: nowrap;
}

.pt-brand__dot {
  width: 10px; height: 10px;
  border-radius: 50%;
  background: var(--brand);
  box-shadow: 0 0 12px var(--brand);
  flex: 0 0 auto;
}

.pt-topbar__spacer { flex: 1 1 auto; min-width: 0; }

/* Op een smal scherm is er geen ruimte voor de merknaam naast de knoppen. */
@media (max-width: 520px) {
  .pt-brand { font-size: 0; gap: 0; }
  .pt-brand__dot { width: 12px; height: 12px; }
  .pt-topbar__inner { gap: var(--s-2); }
  .pt-topbar__inner .pt-btn { padding: 0 var(--s-3); }
  .pt-code-pill { font-size: .9rem; letter-spacing: .12em; padding: 5px 9px; }
}

/* --------------------------------------------------------------- tekst */

/*
   Alle koppen in de eigen letter, ook de kale h2 van een pagina die geen
   pt-klasse gebruikt. Eén regel, want een kop die hier niet langs komt staat
   straks in de systeemletter naast een kop die dat niet doet, en dat ziet
   eruit als een fout.

   De dikte gaat van 800 naar 700. Niet uit smaak: de as van deze letter
   stopt bij 700, en een browser die om 800 wordt gevraagd mag daar zelf iets
   dikkers van maken. Dat levert een vette veeg op in plaats van een vette
   letter. 700 is in deze letter al zwaarder dan 800 in de systeemletter.

   En de letters staan iets minder op elkaar gedrukt dan eerst. Unbounded is
   van zichzelf breed en zwaar; met -.03em erbovenop liepen de rondingen in
   elkaar over.
*/
h1, h2, h3, h4, .pt-h1, .pt-h2, .pt-h3 { font-family: var(--font-kop); }

.pt-h1 { font-size: clamp(1.6rem, 5vw, 2.35rem); line-height: 1.12; letter-spacing: -.02em; font-weight: 700; margin: 0; }
.pt-h2 { font-size: clamp(1.25rem, 3.6vw, 1.6rem); line-height: 1.2; letter-spacing: -.015em; font-weight: 700; margin: 0; }
.pt-h3 { font-size: 1.05rem; font-weight: 700; margin: 0; letter-spacing: -.005em; }

.pt-muted { color: var(--text-muted); margin: 0; }
.pt-faint { color: var(--text-faint); }
.pt-small { font-size: .875rem; }
.pt-tabular { font-variant-numeric: tabular-nums; }

.pt-section-title {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-3);
  margin: var(--s-5) 0 var(--s-3);
  /* Mag omlopen. Boven de wachtrij staan hier de tabs en de knoppen ernaast,
     en samen hadden die op een scherm van 320 drieënveertig pixels te weinig.
     Zonder dit schuift de hele console zijwaarts. */
  flex-wrap: wrap;
}

/* ---------------------------------------------------------------- kaart */

.pt-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-1);
  overflow: hidden;
}

.pt-card--narrow { max-width: 420px; padding: var(--s-5); text-align: center; }
.pt-card__body { padding: var(--s-4); }
.pt-card__head {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-3);
  padding: var(--s-4);
  border-bottom: 1px solid var(--line);
}

/* --------------------------------------------------------------- knoppen */

.pt-btn {
  --btn-bg: var(--surface-2);
  --btn-fg: var(--text);
  --btn-bd: var(--line-strong);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  min-height: var(--tap);
  padding: 0 var(--s-4);
  border: 1px solid var(--btn-bd);
  border-radius: var(--r-pill);
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-weight: 650;
  text-decoration: none;
  cursor: pointer;
  transition: transform .08s ease, background-color .15s ease, border-color .15s ease, opacity .15s ease;
  -webkit-tap-highlight-color: transparent;
  user-select: none;
}

.pt-btn:hover:not(:disabled) { background: var(--surface-3); }
.pt-btn:active:not(:disabled) { transform: scale(.97); }
.pt-btn:disabled { opacity: .45; cursor: not-allowed; }

.pt-btn--primary { --btn-bg: var(--brand); --btn-fg: var(--brand-ink); --btn-bd: transparent; }
.pt-btn--primary:hover:not(:disabled) { background: var(--brand-dim); }

.pt-btn--ghost { --btn-bg: transparent; --btn-bd: var(--line); }
/* Wit op zwart, net zo luid als de groene ernaast. Voor een keuze tussen twee
   dingen die allebei een eerste keus kunnen zijn, zoals account aanmaken en
   inloggen: dan mag geen van beide wegvallen. */
.pt-btn--wit { --btn-bg: #fff; --btn-fg: #0b0d0f; --btn-bd: transparent; }
.pt-btn--wit:hover:not(:disabled) { background: #e6e9ec; }
.pt-btn--danger { --btn-bg: transparent; --btn-fg: var(--danger); --btn-bd: rgba(255,95,109,.4); }
.pt-btn--danger:hover:not(:disabled) { background: rgba(255,95,109,.12); }

/* Iconen in knoppen hebben een eigen maat nodig; een SVG zonder afmeting
   rekt anders op tot de knop. */
.pt-btn svg { width: 20px; height: 20px; flex: 0 0 auto; }
.pt-btn--sm svg { width: 17px; height: 17px; }

.pt-btn--sm { min-height: 36px; padding: 0 var(--s-3); font-size: .875rem; }
.pt-btn--block { width: 100%; }
.pt-btn--icon { padding: 0; width: var(--tap); flex: 0 0 auto; }
.pt-btn--sm.pt-btn--icon { width: 36px; }

/* Rij met bedieningsknoppen die op mobiel netjes doorloopt */
.pt-btnrow { display: flex; flex-wrap: wrap; gap: var(--s-2); }
.pt-btn__icoon { width: 16px; height: 16px; flex: 0 0 auto; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }

/* ----------------------------------------------------------------- input */

.pt-field { display: flex; flex-direction: column; gap: var(--s-2); }
.pt-label { font-size: .875rem; font-weight: 600; color: var(--text-muted); }

.pt-input {
  width: 100%;
  min-height: var(--tap);
  padding: var(--s-3);
  /* background-color en niet de korte schrijfwijze: die zou het eigen
     pijltje van een keuzelijst (hieronder) weer weggummen. */
  background-color: var(--bg-elevated);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-md);
  transition: border-color .15s ease, background-color .15s ease;
  /* 16px voorkomt dat iOS bij focus inzoomt */
  font-size: 16px;
}

.pt-input::placeholder { color: var(--text-faint); }
.pt-input:focus { border-color: var(--brand); outline: none; background-color: var(--surface); }

/*
   Elke keuzelijst hetzelfde pijltje.

   De browser tekent er zelf een, pal tegen de rand aan, en hoe krapper de
   binnenruimte hoe magerder dat eruitziet. Naast elkaar in een paneel zag je
   zo drie verschillende pijltjes, en bij de compacte lijsten leek het pijltje
   rechts tegen de rand geduwd. Nu tekenen we er zelf een: altijd dezelfde
   afstand tot de rand, met ruimte ernaast gereserveerd zodat een lange keuze
   er niet onderdoor loopt.

   Het pijltje is een plaatje in de stijl zelf (een data-adres). Dat mag van
   de csp: img-src laat 'data:' toe, zie View::headers.
*/
select.pt-input {
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1.2 1.6 6 6.4l4.8-4.8' fill='none' stroke='%2398a4b1' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right var(--s-3) center;
  background-size: 12px 8px;
  padding-right: calc(var(--s-3) * 2 + 12px);
}
select.pt-input:focus { border-color: var(--brand); }
select.pt-input:disabled { opacity: .6; }

.pt-searchbar { display: flex; gap: var(--s-2); }
.pt-searchbar .pt-input { flex: 1 1 auto; min-width: 0; }

.pt-code-input {
  text-align: center;
  font-size: clamp(1.3rem, 6vw, 1.8rem);
  font-weight: 800;
  letter-spacing: .2em;
  text-transform: uppercase;
  padding-left: .3em; /* compenseert de letter-spacing rechts */
}

/* ----------------------------------------------------------------- chips */

.pt-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px;
  border-radius: var(--r-pill);
  background: var(--surface-2);
  border: 1px solid var(--line);
  font-size: .75rem;
  font-weight: 650;
  color: var(--text-muted);
  white-space: nowrap;
}

/*
 * Het merkteken zonder tekst, voor in een lijst met nummers.
 *
 * Met de naam erbij liep een lange titel over drie regels; het logo alleen
 * zegt genoeg en kost geen regel.
 */
.pt-bronteken {
  display: inline-flex;
  width: 1.05em;
  height: 1.05em;
  margin-right: .4em;
  vertical-align: -.17em;
  flex: 0 0 auto;
}
.pt-bronteken svg,
.pt-bronteken img { width: 100%; height: 100%; display: block; border-radius: 50%; }

/* Een merkteken in een chip: klein, en het houdt zijn eigen kleur. */
.pt-chip--bron { padding-left: 7px; gap: 5px; }
.pt-chip--bron svg { width: 14px; height: 14px; flex: 0 0 auto; display: block; }

.pt-chip--brand { background: rgba(30,215,96,.14); border-color: rgba(30,215,96,.35); color: var(--brand); }
.pt-chip--amber { background: rgba(255,203,71,.14); border-color: rgba(255,203,71,.35); color: var(--amber); }
.pt-chip--live  { background: rgba(244,83,107,.14); border-color: rgba(244,83,107,.35); color: var(--down); }
.pt-chip--mine  { background: rgba(255,203,71,.16); border-color: rgba(255,203,71,.4); color: var(--amber); }

/* Een code lees je in een keer of niet. Hij breekt dus nooit af, ook niet
   als de kolom waar hij in staat krap wordt. */
.pt-code-pill {
  display: inline-block;
  white-space: nowrap;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 1rem;
  font-weight: 700;
  letter-spacing: .18em;
  padding: 6px 12px;
  border-radius: var(--r-sm);
  background: var(--surface-2);
  border: 1px solid var(--line-strong);
}

/* ---------------------------------------------------------------- tracks */

.pt-tracks { list-style: none; margin: 0; padding: 0; }

.pt-track {
  display: grid;
  grid-template-columns: 48px minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--s-2);
  padding: var(--s-3) var(--s-3);
  border-bottom: 1px solid var(--line);
}

.pt-track:last-child { border-bottom: 0; }
.pt-track--played { opacity: .45; }

.pt-track__cover {
  width: 48px; height: 48px;
  border-radius: var(--r-sm);
  object-fit: cover;
  background: var(--surface-3);
  flex: 0 0 auto;
}

.pt-track__meta { min-width: 0; }

.pt-track__title {
  font-weight: 650;
  overflow: hidden;
  /* Twee regels is genoeg voor vrijwel elke titel; daarna afkappen. */
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  line-height: 1.25;
}

.pt-track__sub {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  flex-wrap: wrap;
  color: var(--text-muted);
  font-size: .85rem;
  margin-top: 2px;
}

.pt-track__artist {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}

.pt-track__actions { display: flex; align-items: center; gap: var(--s-2); }

/* Stemblok: twee knoppen met het saldo ertussen */
.pt-vote {
  display: grid;
  grid-template-columns: var(--vote-btn) auto var(--vote-btn);
  align-items: center;
  gap: 1px;
  --vote-btn: 40px;
}

@media (min-width: 400px) { .pt-vote { --vote-btn: var(--tap); } }

.pt-vote__btn {
  width: var(--vote-btn);
  height: 44px;
  display: grid;
  place-items: center;
  border: 1px solid var(--line);
  background: var(--surface-2);
  border-radius: var(--r-md);
  cursor: pointer;
  transition: transform .1s ease, background-color .15s ease, border-color .15s ease, color .15s ease;
  -webkit-tap-highlight-color: transparent;
}

.pt-vote__btn svg { width: 20px; height: 20px; }
.pt-vote__btn:active { transform: scale(.9); }

.pt-vote__btn[aria-pressed="true"].is-up {
  background: rgba(52,209,122,.18);
  border-color: var(--up);
  color: var(--up);
}

.pt-vote__btn[aria-pressed="true"].is-down {
  background: rgba(244,83,107,.18);
  border-color: var(--down);
  color: var(--down);
}

.pt-vote__score {
  min-width: 2.2ch;
  text-align: center;
  font-weight: 750;
  font-variant-numeric: tabular-nums;
  font-size: 1.05rem;
}

.pt-vote__score.is-positive { color: var(--up); }
.pt-vote__score.is-negative { color: var(--down); }

/* Kort oplichten als het saldo verandert */

/*
 * Een invulvak met een knop ernaast, zoals bij het label en de
 * quizbibliotheek.
 *
 * Los opgemaakt kreeg elk vakje zijn eigen breedte en stond het rommelig
 * onder elkaar. Zo liggen de vakjes en de knoppen op één lijn, ook als de
 * teksten op de knoppen verschillen. Op een telefoon komt de knop eronder
 * en loopt hij over de volle breedte.
 */
.pt-veldrij {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 11em;
  gap: var(--s-2);
  align-items: end;
}
.pt-veldrij--smal { grid-template-columns: minmax(0, 18em) 11em; }
.pt-veldrij .pt-btn { width: 100%; justify-content: center; }
@media (max-width: 560px) {
  .pt-veldrij, .pt-veldrij--smal { grid-template-columns: minmax(0, 1fr); }
}

/* Het logo van een label in de bovenbalk, op de plek van ons eigen stipje. */
.pt-brand__logo { height: 22px; width: auto; max-width: 120px; object-fit: contain; display: block; }

/* De kleine afzender onderaan de gastpagina en op het tv-scherm. */
.pt-merkregel {
  margin: var(--s-5) 0 0;
  text-align: center;
  font-size: .75rem;
  line-height: 1.6;
  color: var(--text-faint);
}
.pt-merkregel strong { color: var(--text-muted); }
.pt-tv__merkregel {
  display: block;
  font-size: .62em;
  font-weight: 500;
  opacity: .7;
  letter-spacing: .02em;
}

.pt-rank {
  display: grid;
  place-items: center;
  width: 26px; height: 26px;
  border-radius: 50%;
  background: var(--surface-3);
  font-size: .8rem;
  font-weight: 750;
  color: var(--text-muted);
  flex: 0 0 auto;
}

.pt-rank--1 { background: var(--amber); color: #2a1d00; }

/* Op smalle schermen is er geen ruimte voor het rangnummer. */
@media (max-width: 719px) {
  .pt-rank { display: none; }

  /*
   * Een eigen nummer: de knoppen op een eigen regel.
   *
   * Opdragen en weghalen staan naast de stemknoppen, en met z'n drieën namen
   * ze zoveel breedte dat er voor de titel een kolom van een paar letters
   * overbleef. Dan breekt "Billie Jean" in tweeën en staat de hoes op een
   * andere hoogte dan bij de regels eromheen. Zo houdt de titel de hele
   * breedte en zakken de knoppen eronder.
   */
  .pt-track--knoppen {
    grid-template-columns: 40px minmax(0, 1fr);
    grid-template-areas: "hoes titel" "hoes onder" "acties acties";
    align-items: center;
  }
  .pt-track--knoppen > .pt-track__cover { grid-area: hoes; }
  .pt-track--knoppen > .pt-track__actions {
    grid-area: acties;
    justify-content: flex-end;
    /* De ruimte tussen de regels komt al van de gap van het raster; een
       marge erbovenop maakte van elke rij een blok van een halve duim. */
    margin-top: 0;
  }

  /*
     De wachtrij op een telefoon.

     Een rij was honderdtwintig pixels hoog en dan zie je er zes, terwijl je
     tijdens een feest juist wilt zien wat eraan komt. De titel op een regel
     met puntjes, een kleinere hoes, krappere randen en knoppen van
     vierendertig in plaats van vierenveertig schelen samen een kwart. De
     knoppen blijven groot genoeg om in het donker te raken; het zijn er
     zeven op een rij, en dat is de grens.
  */
  /*
     De titel krijgt de volle breedte, de knoppen zakken naar de tweede regel.

     Op een telefoon stonden de stemknoppen naast de titel, en dan hield een
     titel als "Mi Rowsu (Tuintje In Mijn Hart)" een kolom van een paar
     letters over en viel hij af met puntjes. In liggende stand paste hij wel,
     en dat maakte het extra vervelend: dezelfde rij, twee keer iets anders.
     Nu staat de titel over de hele breedte en staan de knoppen op dezelfde
     hoogte als de artiest, rechts naast de regel eronder.

     De tekstkolom gebruikt display:contents, zodat de titel en de regel
     eronder zelf plekken in het raster kunnen innemen. Daarom krijgen ze hun
     eigen min-width: die stond eerst op het vakje eromheen.
  */
  .pt-track {
    grid-template-columns: 40px minmax(0, 1fr) auto;
    grid-template-areas:
      "hoes titel titel"
      "hoes onder acties";
    gap: 2px 6px;
    padding: var(--s-2) var(--s-3);
  }
  .pt-track > .pt-track__cover,
  .pt-track > .pt-rank,
  .pt-track > .pt-move { grid-area: hoes; }
  .pt-track__meta { display: contents; }
  .pt-track__title { grid-area: titel; min-width: 0; }

  /*
     De regel onder de titel mag afbreken.

     Eerst probeerde ik hem op één regel te houden door de artiest met
     puntjes te laten wijken, maar dan stond er "Dam..." naast een heel
     merkje, en de artiest zegt meer dan het merkje. Dus breekt hij af: een
     rij met merkjes is dan drie regels hoog en dat leest nog steeds rustig.
  */
  .pt-track__sub { grid-area: onder; min-width: 0; gap: 6px var(--s-2); }
  .pt-track > .pt-track__actions {
    grid-area: acties;
    align-self: center;
    justify-content: flex-end;
  }

  /*
     De hoes bovenaan uitlijnen, niet in het midden.

     Een rij is een raster met align-items: center. Bij een nummer met een
     merkje extra (van jou, een opdracht aan iemand, anoniem) loopt de regel
     eronder door en wordt de tekstkolom drie regels hoog. De hoes is maar
     veertig pixels en zakte dan naar het midden van die kolom, waardoor de
     titel boven de hoes leek te zweven en de rij scheef stond ten opzichte
     van de rijen erboven en eronder. Zo staat de hoes altijd naast de titel.
  */
  .pt-track > .pt-track__cover,
  .pt-track > .pt-rank,
  .pt-track > .pt-move { align-self: start; }
  .pt-track__cover { width: 40px; height: 40px; }
  .pt-track__title {
    -webkit-line-clamp: 1;
    white-space: nowrap;
    text-overflow: ellipsis;
  }
  .pt-track__actions { gap: 4px; }
  .pt-track__actions .pt-btn--sm { min-height: 34px; }
  .pt-track__actions .pt-btn--sm.pt-btn--icon { width: 34px; }
}

/* --------------------------------------------------------- nu aan het spelen */

.pt-now {
  display: grid;
  grid-template-columns: 72px minmax(0, 1fr);
  gap: var(--s-4);
  align-items: center;
  padding: var(--s-4);
  background: linear-gradient(140deg, rgba(30,215,96,.13), rgba(30,215,96,0) 62%), var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
}

.pt-now__cover {
  width: 72px; height: 72px;
  border-radius: var(--r-md);
  object-fit: cover;
  background: var(--surface-3);
  box-shadow: var(--shadow-2);
}

.pt-now__label {
  display: flex; align-items: center; gap: 6px;
  font-size: .72rem;
  font-weight: 750;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--brand);
}

/*
   De prullenbak op de draaitafel.

   Helemaal rechts in het regeltje, los van het bolletje en het merkje, zodat
   hij niet pal naast 'Nu' staat. Hij is klein en grijs tot je eroverheen
   gaat: dit is een knop die je hoogstens een keer per avond nodig hebt.
*/
.pt-now__weg {
  margin-left: auto;
  color: var(--text-faint);
}
.pt-now__weg:hover { color: var(--down); }

.pt-now__title { font-size: 1.05rem; font-weight: 750; margin-top: 2px; }
.pt-now__title, .pt-now__artist { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pt-now__artist { color: var(--text-muted); font-size: .9rem; }

/* Pulserend bolletje als er iets speelt */
.pt-pulse {
  width: 7px; height: 7px; border-radius: 50%;
  background: var(--brand);
  animation: pt-pulse 1.8s ease-in-out infinite;
}
@keyframes pt-pulse {
  0%, 100% { opacity: 1; box-shadow: 0 0 0 0 rgba(30,215,96,.6); }
  50%      { opacity: .65; box-shadow: 0 0 0 6px rgba(30,215,96,0); }
}

.pt-progress {
  height: 4px;
  border-radius: var(--r-pill);
  background: var(--surface-3);
  overflow: hidden;
  margin-top: var(--s-3);
}

.pt-progress__bar {
  height: 100%;
  background: var(--brand);
  border-radius: inherit;
  transition: width 1s linear;
}

/* Bijna op: dan hoort de balk dat te zeggen voordat je het merkt doordat het
   zoeken stopt. Dezelfde amber als de andere waarschuwingen. */
.pt-progress__bar--warm { background: var(--amber); }

/* Zoeken, filteren en sorteren boven de wachtrij.

   Op een telefoon vielen deze drie over twee regels, elk met een andere
   breedte en hoogte, omdat ze alle drie hun eigen flexmaat hadden. Nu is het
   een raster: het zoekveld over de volle breedte, de twee keuzelijsten
   daaronder samen op een regel. Vanaf een tablet staan ze weer op een rij. */
.pt-zoekrij {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--s-2);
  margin-bottom: var(--s-2);
}
.pt-zoekrij__zoek { grid-column: 1 / -1; }
.pt-zoekrij .pt-input { width: 100%; min-width: 0; min-height: 40px; }

@media (min-width: 560px) {
  .pt-zoekrij { grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr) minmax(0, 1fr); }
  .pt-zoekrij__zoek { grid-column: auto; }
}

/* Een zoekveld boven een lijst: op een telefoon over de volle breedte, op een
   groter scherm hoogstens een stuk of 280 pixels. */
.pt-zoekveld { flex: 1 1 100%; min-width: 0; }
@media (min-width: 560px) { .pt-zoekveld { flex: 1 1 160px; max-width: 280px; } }

/* De lijstjes met spellen en superkrachten op de startpagina: leesbaar op
   een telefoon, en op een breed scherm in twee kolommen zodat je het in een
   oogopslag overziet. */
/* Lopende tekst in een brede sectie: een leesbare regellengte, gecentreerd. */
.pt-lees { max-width: 640px; margin-left: auto; margin-right: auto; }

.pt-spellijst {
  list-style: none;
  margin: var(--s-4) 0 0;
  padding: 0;
  display: grid;
  gap: var(--s-3);
}
.pt-spellijst li {
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--text-muted);
  line-height: 1.5;
}
.pt-spellijst strong { color: var(--text); }

/*
   Op een telefoon de naam van het spel op een eigen regel.

   Tien spellen met hun uitleg achter de naam aan is een lap tekst waar je
   met je ogen niet doorheen komt. Met de naam erboven loop je de lijst langs
   en lees je alleen het stukje dat je aanstaat. Op een breed scherm blijft
   het op een regel: daar lees je toch een hele kolom in een oogopslag.
*/
@media (max-width: 599px) {
  .pt-spellijst--kaarten strong { display: block; margin-bottom: 2px; }
}
/* De kaartjes krijgen hun eigen teken ervoor, net als op de telefoon van een
   gast. De tekst staat in een eigen kolom, zodat een tweede regel netjes
   onder de eerste begint en niet onder het icoontje door loopt. */
.pt-spellijst--kaarten li {
  display: grid;
  grid-template-columns: 1.8rem minmax(0, 1fr);
  gap: var(--s-3);
  align-items: start;
}
.pt-spellijst__icoon { font-size: 1.3rem; line-height: 1.35; }

/*
   De tekeningen bij de kaartjes.

   Hier stonden emoji, en die kwamen elk uit een andere hand: andere stijl,
   andere kleuren, andere dikte. Nu zijn het lijntekeningen van één familie,
   in dezelfde maat en dikte als de menubalk onderaan, en ze nemen de kleur
   aan van waar ze staan. Zie View::icoon.
*/
.pt-icoon { width: 1.35rem; height: 1.35rem; display: block; }
.pt-home__icoon, .pt-spellijst__icoon { color: var(--brand); }
.pt-spellijst__icoon { line-height: 0; padding-top: .15rem; }
@media (min-width: 720px) { .pt-spellijst { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
/* Op een breed scherm drie kolommen: anders staan er twee lange kaarten in
   het midden met aan weerszijden een halve meter niets. */
@media (min-width: 1000px) { .pt-spellijst { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

/* De schuifbalk onder de plaat op de draaitafel.

   De balk zelf blijft net zo dun als eerst, maar eromheen zit lucht zodat je
   hem met een vinger kunt raken. Het knopje staat er alleen als er iets
   speelt, anders lijkt het alsof je ergens aan kunt trekken terwijl er niets
   te schuiven valt. */
.pt-sleep {
  position: relative;
  padding: 9px 0;
  margin-top: calc(var(--s-3) - 9px);
  cursor: pointer;
  touch-action: none;
}
.pt-sleep .pt-progress { margin-top: 0; overflow: visible; }
.pt-sleep:focus-visible { outline: 2px solid var(--brand); outline-offset: 4px; border-radius: var(--r-pill); }

.pt-sleep__knop {
  position: absolute;
  top: 50%;
  left: 0;
  width: 14px;
  height: 14px;
  margin-left: -7px;
  border-radius: 50%;
  background: var(--brand);
  box-shadow: 0 2px 8px rgba(0, 0, 0, .5);
  transform: translateY(-50%) scale(0);
  transition: transform .15s ease, left 1s linear;
  pointer-events: none;
}
.pt-sleep:hover .pt-sleep__knop,
.pt-sleep:focus-visible .pt-sleep__knop,
.pt-sleep.is-sleep .pt-sleep__knop { transform: translateY(-50%) scale(1); }

/* Tijdens het slepen loopt de balk met de vinger mee, zonder na-ijlen. */
.pt-sleep.is-sleep .pt-progress__bar,
.pt-sleep.is-sleep .pt-sleep__knop { transition: none; }

/* Op een aanraakscherm is er geen zweven, dus staat het knopje er altijd. */
@media (pointer: coarse) {
  .pt-sleep__knop { transform: translateY(-50%) scale(1); }
  .pt-sleep { padding: 12px 0; margin-top: calc(var(--s-3) - 12px); }
}

/* De bulkbalk boven de wachtrij, tijdens het selecteren. */
.pt-kiesbalk {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-2);
  padding: var(--s-2) var(--s-3);
  margin-bottom: var(--s-2);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-md);
  background: var(--surface-2);
}
.pt-track__kies {
  width: 22px; height: 22px;
  margin: 0 auto;
  accent-color: var(--brand);
  cursor: pointer;
}
.pt-track.is-gekozen { background: rgba(29, 185, 84, .08); }

/* ------------------------------------------------------- zoekresultaten */

.pt-results { list-style: none; margin: 0; padding: 0; max-height: 46vh; overflow-y: auto; -webkit-overflow-scrolling: touch; }

.pt-result {
  display: grid;
  grid-template-columns: 44px minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-2) var(--s-3);
  border-radius: var(--r-md);
}

.pt-result + .pt-result { margin-top: var(--s-1); }
/* De sponsorregel op de tv: klein, onder de uitslag. */
.pt-tv__sponsor {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin-top: calc(clamp(8px, 1.2vh, 16px) * var(--maat, 1));
  font-size: calc(clamp(.8rem, 1.1vw, 1.1rem) * var(--maat, 1));
  color: var(--text-muted);
}
.pt-tv__sponsor img { height: calc(clamp(22px, 3vh, 44px) * var(--maat, 1)); border-radius: 6px; }

/* De balk bovenaan bij onderhoud of op de testomgeving. */
.pt-omgevingsbalk {
  padding: 6px 14px;
  text-align: center;
  font-size: .85rem;
  font-weight: 650;
  background: rgba(255, 193, 7, .16);
  color: var(--amber);
  border-bottom: 1px solid rgba(255, 193, 7, .3);
}
.pt-omgevingsbalk--test { background: rgba(88, 101, 242, .18); color: #aab6ff; border-bottom-color: rgba(88,101,242,.35); }

/* Muziekroulette: de vakjes waar je fiches op zet. */
.pt-roulette__rij { display: grid; grid-template-columns: repeat(auto-fit, minmax(110px, 1fr)); gap: var(--s-2); margin-top: var(--s-2); }
.pt-roulette__vak {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 10px 8px;
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--text);
  font: inherit;
  cursor: pointer;
  text-align: center;
}
.pt-roulette__vak.is-gezet { border-color: var(--brand); background: rgba(29,185,84,.14); position: relative; }
.pt-roulette__label { font-weight: 650; }
.pt-roulette__inzet { font-size: .75rem; color: var(--text-muted); }
/* Kruisje om je fiches hier weg te halen zolang het bord open is. */
.pt-roulette__terug {
  position: absolute; top: 4px; right: 6px;
  width: 22px; height: 22px;
  display: grid; place-items: center;
  border-radius: 50%;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--text-muted);
  font-size: .85rem; line-height: 1;
}
.pt-roulette__terug:hover, .pt-roulette__terug:focus-visible { color: var(--down); border-color: var(--down); }

/* Het bord op de tv. */
.pt-tv__roulette { display: grid; gap: calc(clamp(6px, .8vh, 12px) * var(--maat, 1)); }
.pt-tv__roul-rij { display: grid; grid-template-columns: repeat(auto-fit, minmax(90px, 1fr)); gap: calc(clamp(6px, .8vw, 12px) * var(--maat, 1)); }
.pt-tv__roul-vak {
  padding: calc(clamp(6px, .9vh, 14px) * var(--maat, 1));
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background: var(--surface-2);
  text-align: center;
  font-size: calc(clamp(.8rem, 1.1vw, 1.2rem) * var(--maat, 1));
}
.pt-tv__roul-vak.is-winnend { border-color: var(--brand); background: rgba(29,185,84,.2); }
.pt-tv__roul-vak b { display: block; font-size: calc(clamp(.9rem, 1.3vw, 1.5rem) * var(--maat, 1)); }

/* Een ingesproken felicitatie op de tv. */
.pt-roep--fel .pt-roep__kop { font-size: calc(clamp(1.4rem, 3vw, 3rem) * var(--maat, 1)); }
.pt-fel__foto { width: calc(clamp(80px, 12vw, 200px) * var(--maat, 1)); height: calc(clamp(80px, 12vw, 200px) * var(--maat, 1)); border-radius: 50%; object-fit: cover; margin: 0 auto var(--s-3); display: block; }

/* De fotomuur op de telefoon: je eigen foto's als kleine tegels. */
.pt-fotos { display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: var(--s-2); }
.pt-foto { position: relative; aspect-ratio: 1 / 1; border-radius: var(--r-md); overflow: hidden; background: var(--surface-2); }
.pt-foto img { width: 100%; height: 100%; object-fit: cover; display: block; }
.pt-foto--wacht img { opacity: .55; }
.pt-foto__stand { position: absolute; left: 0; right: 0; bottom: 0; padding: 3px 6px; font-size: .68rem; background: rgba(0,0,0,.6); color: #fff; }
/*
 * De muur zoals de DJ hem beheert: een regel per foto, op volgorde.
 *
 * Met alleen tegels kon je keuren en weggooien, en verder deed de muur zijn
 * eigen ding. Hier staat per foto wat ermee gebeurt: naar voren, nu in beeld,
 * langer laten staan, of pas later op de avond mee laten doen.
 */
.pt-fotorijen { display: flex; flex-direction: column; }
/* De opnamen worden net zo beheerd als de foto's: zelfde regel, maar met een
   microfoon in plaats van een plaatje en met de speler eronder. */
.pt-opnamerij__icoon {
  width: 44px;
  height: 44px;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--r-sm);
  background: var(--surface-2);
  font-size: 1.2rem;
}
.pt-opnamerij__speler { width: 100%; flex: 1 0 100%; height: 32px; margin-top: 2px; }
.pt-opnamerij { padding-bottom: 6px; }
.pt-fotorij {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  padding: 4px var(--s-2);
  border-radius: var(--r-md);
  border-bottom: 1px solid var(--line);
  flex-wrap: wrap;
}
.pt-fotorij:hover { background: var(--surface-2); }
.pt-fotorij__beeld {
  width: 44px;
  height: 44px;
  flex: 0 0 auto;
  object-fit: cover;
  border-radius: var(--r-sm);
  background: var(--surface-2);
}
.pt-fotorij__tekst { flex: 1 1 7em; min-width: 0; }
.pt-fotorij__naam { font-weight: 650; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pt-fotorij__stand { font-size: .75rem; color: var(--text-faint); }
.pt-fotorij__knoppen { display: flex; gap: 4px; align-items: center; flex-wrap: wrap; margin-left: auto; }
/* Een keuzelijst en een klokje krijgen hun eigen breedte van de browser mee;
   zonder deze regels duwen ze de knoppen van de regel af. */
.pt-fotorij__duur { width: 7.5em; min-width: 0; flex: 0 0 auto; box-sizing: border-box; }
.pt-fotorij__tijd { width: 7em; min-width: 0; flex: 0 0 auto; box-sizing: border-box; }

/* Het tijdveld met het woord 'vanaf' ervoor, als een geheel. */
.pt-vanaf {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  flex: 0 0 auto;
  font-size: .78rem;
  color: var(--text-faint);
}
.pt-vanaf .pt-fotorij__tijd { width: 6.4em; }

/* Op een telefoon staan deze knoppen op twee regels; dan iets kleiner, en
   weghalen helemaal rechts zodat het niet tegen 'Nu' aan komt te staan. */
@media (max-width: 599px) {
  .pt-fotorij__knoppen .pt-btn--sm { min-height: 38px; }
  .pt-fotorij__knoppen .pt-btn--sm.pt-btn--icon { width: 38px; }
  .pt-fotorij__knoppen .pt-input--sm { min-height: 38px; }
  .pt-fotorij__knoppen > .pt-btn--icon:last-child { margin-left: auto; }
}

.pt-foto__weg { position: absolute; top: 4px; right: 4px; width: 24px; height: 24px; border-radius: 50%; border: 0; background: rgba(0,0,0,.6); color: #fff; font-size: 16px; line-height: 24px; cursor: pointer; }

/* De knop waarmee je een ingestuurde foto goedkeurt, over de foto heen. */
.pt-foto__ok { position: absolute; left: 4px; top: 4px; padding: 2px 8px; font-size: .7rem; min-height: 0; }

/*
   Keuren op een telefoon.

   Een tegel van honderdtwaalf pixels met een knop en een kruisje eroverheen:
   dan beoordeel je een foto die je nauwelijks ziet. Een foto die nog gekeurd
   moet worden krijgt daarom twee kolommen, en de twee knoppen worden groter
   zodat je ze met een duim raakt. De goedgekeurde foto's blijven klein, want
   daar staan er op een feest al gauw dertig van.
*/
@media (max-width: 599px) {
  .pt-foto--wacht { grid-column: span 2; }
  .pt-foto--wacht .pt-foto__ok { left: 6px; top: 6px; padding: 6px 12px; font-size: .8rem; min-height: 36px; }
  .pt-foto--wacht .pt-foto__weg { width: 34px; height: 34px; font-size: 20px; line-height: 34px; top: 6px; right: 6px; }
  .pt-foto--wacht .pt-foto__stand { font-size: .78rem; padding: 5px 8px; }
}
.pt-btn--uit { opacity: .5; pointer-events: none; }

/* De fotomuur op de tv: een polaroid die af en toe over de plaat schuift. */
/* De plaatjesbibliotheek in de console, en het voorbeeldje naast een
   keuzelijst. */
.pt-beelden { display: flex; flex-direction: column; gap: var(--s-2); }
.pt-beeld {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-2);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface-2);
}
.pt-beeld img { width: 54px; height: 54px; object-fit: contain; border-radius: 8px; background: var(--surface); }
.pt-beeldvoor {
  flex: 0 0 auto;
  display: grid; place-items: center;
  width: 44px; height: 44px;
  border-radius: 8px;
  border: 1px dashed var(--line);
  /* Een lang gifje moet in het vakje blijven en niet over de rij heen
     hangen; anders staat er een dansend mannetje door je knoppen. */
  overflow: hidden;
}
/* Vaste maten en geen percentages. Het vakje eromheen is een raster dat zich
   naar zijn inhoud voegt, en dan heeft een hoogte van 100% niets om zich aan
   vast te houden: een hoog gifje hing daardoor over de knoppen heen. */
/* Een voorbeeldvakje zonder plaatje erin is een lege stippellijn die om
   aandacht vraagt zonder iets te zeggen; dan laten we hem weg. Bij de
   effectknoppen juist niet: daar houdt de lege kolom de keuzelijsten van
   alle regels op een lijn, en dat staat zo in het raster hieronder. */
.pt-kracht__opties .pt-beeldvoor:empty { display: none; }
.pt-beeldvoor img {
  max-width: 38px;
  max-height: 38px;
  object-fit: contain;
  border-radius: 6px;
}

/* Het plaatje van de effectknop: groot, midden, zonder kader. Een gifje met
   een doorzichtige rand hoort vrij over het scherm te staan. */
.pt-tv__effect {
  position: fixed;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  z-index: 60;
  pointer-events: none;
  animation: pt-effect-in .35s ease-out;
}
.pt-tv__effect img {
  display: block;
  /* Meeschalen met het scherm, ook omhoog: een gifje van 300 pixels is op een
     tv aan de andere kant van de zaal niet te zien. Niet verder dan nodig,
     anders wordt het te zacht. */
  height: clamp(200px, 36vh, 560px);
  width: auto;
  max-width: min(46vw, 620px);
  object-fit: contain;
  filter: drop-shadow(0 12px 40px rgba(0, 0, 0, .65));
}
@keyframes pt-effect-in {
  from { opacity: 0; transform: translate(-50%, -46%) scale(.86); }
  to   { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}
@media (prefers-reduced-motion: reduce) { .pt-tv__effect { animation: none; } }

.pt-tv__foto {
  position: fixed;
  left: 50%;
  top: 50%;
  /* --hoek zet het tv-scherm per foto: de hoek die de DJ koos, of anders een
     die bij die foto hoort. Kent een browser dat niet, dan hangt hij scheef
     zoals hij altijd hing. */
  transform: translate(-50%, -50%) rotate(var(--hoek, -2deg));
  z-index: 40;
  width: min(60vw, calc(70vh * 1.2));
  padding: 14px 14px 44px;
  background: #fff;
  border-radius: 6px;
  box-shadow: 0 30px 80px rgba(0,0,0,.6);
  animation: pt-foto-in .5s ease-out;
}
.pt-tv__foto img { width: 100%; max-height: 60vh; object-fit: contain; display: block; background: #111; }
.pt-tv__foto-naam { position: absolute; left: 14px; right: 14px; bottom: 12px; text-align: center; color: #222; font-weight: 700; font-size: calc(clamp(.9rem, 1.4vw, 1.3rem) * var(--maat, 1)); font-family: "Marker Felt", "Comic Sans MS", cursive; }
@keyframes pt-foto-in {
  from { opacity: 0; transform: translate(-50%, -40%) rotate(calc(var(--hoek, -2deg) + 6deg)) scale(.9); }
  to   { opacity: 1; transform: translate(-50%, -50%) rotate(var(--hoek, -2deg)) scale(1); }
}
/* In een fotomoment komen de foto's achter elkaar voorbij. Dan mogen ze
   groter, want de hele zaal kijkt ernaar, en ze wisselen met een klein
   zwiepje zodat je ziet dat er een nieuwe ligt. */
.pt-tv__foto.is-moment {
  width: min(72vw, calc(78vh * 1.2));
  animation: pt-foto-moment .45s ease-out;
}
@keyframes pt-foto-moment {
  from { opacity: 0; transform: translate(-46%, -50%) rotate(calc(var(--hoek, -2deg) + 5deg)) scale(.94); }
  to   { opacity: 1; transform: translate(-50%, -50%) rotate(var(--hoek, -2deg)) scale(1); }
}

/* Het duwtje: een kaartje dat vraagt om foto's zolang er bijna geen zijn.
   Rechtsonder, want daar zit de QR-code waar ze naartoe moeten. */
.pt-tv__duwtje {
  position: fixed;
  right: clamp(16px, 3vw, 48px);
  bottom: clamp(16px, 3vh, 48px);
  z-index: 40;
  max-width: min(360px, 34vw);
  padding: calc(clamp(12px, 1.6vh, 20px) * var(--maat, 1));
  border-radius: var(--r-lg);
  border: 1px solid var(--line-strong);
  background: var(--bg-elevated);
  box-shadow: 0 20px 50px rgba(0, 0, 0, .55);
  text-align: center;
  animation: pt-fade-in .4s ease both;
}
.pt-tv__duwtje-icoon {
  font-size: calc(clamp(1.6rem, 3vw, 2.6rem) * var(--maat, 1));
  line-height: 1;
  /* Een tekening in plaats van een fototoestel-emoji. De maat komt nog steeds
     van de letter erboven, dus hij schaalt mee met de tv. */
  color: var(--brand);
}
.pt-tv__duwtje-icoon svg { width: 1em; height: 1em; margin: 0 auto; }
.pt-tv__duwtje-kop {
  margin-top: 6px;
  font-size: calc(clamp(1rem, 1.6vw, 1.5rem) * var(--maat, 1));
  font-weight: 800;
}
.pt-tv__duwtje-tekst {
  margin-top: 4px;
  font-size: calc(clamp(.8rem, 1.1vw, 1.05rem) * var(--maat, 1));
  color: var(--text-muted);
}

/* De collage aan het eind. */
.pt-tv__collage { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 8px; margin-top: 12px; max-height: 40vh; overflow: hidden; }
.pt-tv__collage img { width: 100%; aspect-ratio: 1 / 1; object-fit: cover; border-radius: 6px; }

/* Nazorg: de lijsten met de nummers van de avond. */
/* Ruimte voor drie cijfers: deze lijsten lopen tot honderd (de Feest Top 100)
   en bij een lange avond ook de lijst met wat er gedraaid is. Met de oude
   anderhalve em staken 100 en hoger links uit en stond de rand rafelig. */
.pt-nazorg__lijst { margin: var(--s-2) 0 0; padding-left: 2.6em; line-height: 1.7; }
.pt-nazorg__lijst li { padding: 2px 0; }

/* De regel bovenin een paneel dat bij Plus hoort. */
.pt-plus-note { margin: var(--s-2) 0 var(--s-3); }
/* Een clip van het quizblok die al geweest is. */
.pt-result.is-gespeeld { opacity: .55; }
.pt-result:hover { background: var(--surface-2); }
.pt-result__cover { width: 44px; height: 44px; border-radius: 6px; object-fit: cover; background: var(--surface-3); }

/* Een clip van YouTube is geen vierkante hoes maar een beeld. Breder tonen,
   in de verhouding van de video, zodat je ziet wat je toevoegt. */
.pt-result--clip { grid-template-columns: 80px minmax(0, 1fr) auto; }
.pt-result__cover--clip { width: 80px; height: 45px; border-radius: 6px; }

/* ------------------------------------------------------------ meldingen */

.pt-empty {
  padding: var(--s-6) var(--s-4);
  text-align: center;
  color: var(--text-muted);
}

.pt-empty__icon { font-size: 2rem; margin-bottom: var(--s-2); }

.pt-note {
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background: var(--surface-2);
  font-size: .9rem;
}

.pt-note--warn  { border-color: rgba(255,203,71,.4); background: rgba(255,203,71,.1); color: #ffe6a8; }

/*
   Een regel die niet meer grijs mag zijn.

   Soms is een toelichting ineens een waarschuwing, zoals de stand van de
   muziekmap als het scherm bij de speakers de bestanden niet open heeft.
   Een heel vak eromheen is te veel voor een zin; de kleur is genoeg.
*/
.pt-faint.is-letop { color: var(--amber); }
.pt-note--error { border-color: rgba(255,95,109,.4); background: rgba(255,95,109,.1); color: #ffc2c8; }
.pt-note--ok    { border-color: rgba(30,215,96,.4);  background: rgba(30,215,96,.1);  color: #b9f5cf; }

/* Toast: zweeft boven alles, ook op mobiel binnen de veilige zone */
.pt-toasts {
  position: fixed;
  left: 50%;
  bottom: calc(var(--s-4) + env(safe-area-inset-bottom));
  transform: translateX(-50%);
  z-index: 90;
  display: flex;
  flex-direction: column;
  gap: var(--s-2);
  width: min(92vw, 420px);
  pointer-events: none;
}

.pt-toast {
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-md);
  background: var(--surface-3);
  border: 1px solid var(--line-strong);
  box-shadow: var(--shadow-3);
  font-size: .9rem;
  animation: pt-toast-in .22s ease;
}

.pt-toast--error { border-color: rgba(255,95,109,.5); background: #2a1417; color: #ffc2c8; }
.pt-toast--ok    { border-color: rgba(30,215,96,.5);  background: #0e2417; color: #b9f5cf; }

@keyframes pt-toast-in {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* --------------------------------------------------------------- laden */

.pt-skeleton {
  background: linear-gradient(90deg, var(--surface-2) 25%, var(--surface-3) 37%, var(--surface-2) 63%);
  background-size: 400% 100%;
  animation: pt-shimmer 1.3s ease infinite;
  border-radius: var(--r-sm);
}

@keyframes pt-shimmer {
  from { background-position: 100% 50%; }
  to   { background-position: 0 50%; }
}

.pt-spinner {
  width: 18px; height: 18px;
  border: 2px solid rgba(255,255,255,.25);
  border-top-color: currentColor;
  border-radius: 50%;
  animation: pt-spin .7s linear infinite;
}

@keyframes pt-spin { to { transform: rotate(360deg); } }

/* ------------------------------------------------------------ hulpklassen */

.pt-hidden { display: none !important; }
.pt-sr {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.pt-row { display: flex; align-items: center; gap: var(--s-3); }
.pt-row--between { justify-content: space-between; }
.pt-wrap { flex-wrap: wrap; }
.pt-grow { flex: 1 1 auto; min-width: 0; }

/* Ruimte onderaan zodat de laatste rij niet onder een vaste balk valt */
.pt-bottom-space { height: calc(var(--s-7) + env(safe-area-inset-bottom)); }

/* Als de Hitster-vraag onderaan plakt, moet de laatste rij eronderuit kunnen. */
body.pt-has-hitster .pt-bottom-space { height: calc(260px + env(safe-area-inset-bottom)); }

/* ============================ Grotere schermen ============================ */

@media (min-width: 720px) {
  .pt-track { grid-template-columns: 26px 56px minmax(0, 1fr) auto; gap: var(--s-3); padding: var(--s-3) var(--s-5); }
  .pt-track__cover { width: 56px; height: 56px; }
  .pt-track__title { -webkit-line-clamp: 1; white-space: nowrap; text-overflow: ellipsis; }
  .pt-now { grid-template-columns: 96px minmax(0, 1fr); padding: var(--s-5); }
  .pt-now__cover { width: 96px; height: 96px; }
  .pt-now__title { font-size: 1.25rem; }
  .pt-card__body { padding: var(--s-5); }
  .pt-card__head { padding: var(--s-4) var(--s-5); }
}

/* Twee kolommen voor het DJ-scherm */
@media (min-width: 1000px) {
  .pt-split {
    display: grid;
    grid-template-columns: minmax(0, 1.65fr) minmax(300px, 1fr);
    gap: var(--s-5);
    align-items: start;
  }
  .pt-split__side { position: sticky; top: 84px; }
}

/* Kaartraster voor het dashboard */
.pt-grid {
  display: grid;
  gap: var(--s-4);
  grid-template-columns: 1fr;
}

@media (min-width: 640px) { .pt-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px) { .pt-grid { grid-template-columns: repeat(3, 1fr); } }

/* ======================= DJ-console ======================= */

/* Bedieningsbalk: op mobiel vast onderaan, op desktop gewoon in de kaart. */
.pt-transport {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  justify-content: center;
  flex-wrap: wrap;
}

@media (max-width: 999px) {
  .pt-transport--docked {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 70;
    background: rgba(16,19,21,.96);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    border-top: 1px solid var(--line);
    padding: var(--s-3) var(--s-4);
    padding-bottom: calc(var(--s-3) + env(safe-area-inset-bottom));
    box-shadow: 0 -8px 24px rgba(0,0,0,.4);
    flex-wrap: nowrap;
  }
  .pt-transport--docked .pt-transport__meta { display: none; }
}

.pt-transport__btn {
  width: 48px; height: 48px;
  display: grid; place-items: center;
  border-radius: 50%;
  border: 1px solid var(--line-strong);
  background: var(--surface-2);
  cursor: pointer;
  flex: 0 0 auto;
  transition: transform .08s ease, background-color .15s ease;
}

.pt-transport__btn:active:not(:disabled) { transform: scale(.92); }
.pt-transport__btn:disabled { opacity: .4; cursor: not-allowed; }
.pt-transport__btn svg { width: 22px; height: 22px; }

.pt-transport__btn--main {
  width: 60px; height: 60px;
  background: var(--brand);
  color: var(--brand-ink);
  border-color: transparent;
}
.pt-transport__btn--main svg { width: 26px; height: 26px; }
.pt-transport__btn--main:hover:not(:disabled) { background: var(--brand-dim); }

/* Instellingen */
.pt-switch {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  padding: var(--s-3) 0;
  border-bottom: 1px solid var(--line);
  cursor: pointer;
}

.pt-switch:last-child { border-bottom: 0; }
/* Het laatste zichtbare vakje in de spelinstellingen trekt geen lijn meer:
   'Punten en straf' eronder begint er zelf met een, en dan zie je er twee.
   Welk vakje dat is wisselt per spel, dus de console zet dit merkje; zie
   laatsteStreep in admin.js. */
#quiz-instellingen > .is-laatste { border-bottom: 0; }
/* Een vakje waar de uitleg of de schakelaar direct bij hoort wat eronder
   staat: dan geen scheidslijn ertussen. Zie geen-streep in admin.js. */
.geen-streep { border-bottom: 0 !important; }
/* De uitklapbare uitleg wordt pas na het laden onder een schakelaar gezet.
   Stond de schakelaar al op 'geen streep', dan geldt dat ook voor die uitleg;
   anders verschuift de lijn gewoon een regel naar beneden. */
.geen-streep + .pt-uitlegvouw { border-bottom: 0 !important; }
/*
   Een uitklapbare uitleg hoort bij het vakje erboven.

   De console verbergt vakjes die bij het gekozen spel niet horen. Die uitleg
   is een eigen element dat pas ná het laden naast dat vakje wordt gezet, dus
   verbergen in de code haalde hem lang niet altijd mee: je hield een losse
   'Hoe werkt dit?' over, en bij twee verborgen vakjes stonden er zelfs twee
   onder elkaar. Dit volgt de structuur en heeft geen timing nodig.
*/
.pt-module [hidden] + .pt-uitlegvouw { display: none; }
.pt-switch__label { font-size: .95rem; }
.pt-switch__hint { display: block; font-size: .8rem; color: var(--text-faint); margin-top: 2px; }

.pt-switch__track {
  position: relative;
  width: 46px; height: 28px;
  border-radius: var(--r-pill);
  background: var(--surface-3);
  border: 1px solid var(--line-strong);
  flex: 0 0 auto;
  transition: background-color .18s ease, border-color .18s ease;
}

.pt-switch__track::after {
  content: '';
  position: absolute;
  top: 3px; left: 3px;
  width: 20px; height: 20px;
  border-radius: 50%;
  background: var(--text-muted);
  transition: transform .18s ease, background-color .18s ease;
}

.pt-switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.pt-switch input:checked + .pt-switch__track { background: rgba(30,215,96,.28); border-color: var(--brand); }
.pt-switch input:checked + .pt-switch__track::after { transform: translateX(18px); background: var(--brand); }
.pt-switch input:focus-visible + .pt-switch__track { outline: 2px solid var(--brand); outline-offset: 2px; }

.pt-range { width: 100%; accent-color: var(--brand); height: var(--tap); }

/* Genre-keuze */
.pt-genres {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  max-height: 190px;
  overflow-y: auto;
  padding: var(--s-2);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--bg-elevated);
}

.pt-genre {
  padding: 6px 12px;
  border-radius: var(--r-pill);
  border: 1px solid var(--line-strong);
  background: var(--surface-2);
  font-size: .8rem;
  cursor: pointer;
  transition: background-color .15s ease, border-color .15s ease, color .15s ease;
}

.pt-genre[aria-pressed="true"] {
  background: rgba(244,83,107,.18);
  border-color: var(--down);
  color: var(--down);
  text-decoration: line-through;
}

/* Uitklapbaar blok */
.pt-details summary {
  cursor: pointer;
  padding: var(--s-3) var(--s-4);
  font-weight: 650;
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: var(--tap);
}

.pt-details summary::-webkit-details-marker { display: none; }
.pt-details summary::after { content: '⌄'; color: var(--text-faint); font-size: 1.2rem; line-height: 1; }
.pt-details[open] summary::after { content: '⌃'; }

/* ======================= TV-scherm ======================= */

.pt-tv {
  /* Een tv scrollt niet: alles moet binnen het scherm passen. */
  height: 100dvh;
  overflow: hidden;
  display: grid;
  /* Kop, inhoud, en onderaan de lichtkrant. Die laatste rij is nul hoog
     zolang er niets te melden valt. */
  grid-template-rows: auto minmax(0, 1fr) auto;
  gap: calc(clamp(12px, 2.4vh, 32px) * var(--maat, 1));
  /* De rand staat apart zodat de lichtkrant hem kan opheffen en van hoek
     tot hoek kan lopen.

     Boven en onder heeft hij een eigen maat. Bij een party met beeld wordt
     die kleiner om ruimte voor de clip te maken, en de lichtkrant moet dan
     precies even ver naar beneden steken als er padding onder zit. Stond die
     maat maar op een plek, dan hing de lichtkrant een centimeter onder het
     scherm en zag je de helft van de tekst niet. */
  --tv-rand: calc(clamp(16px, 2.4vw, 44px) * var(--maat, 1));
  --tv-rand-y: var(--tv-rand);
  padding: var(--tv-rand-y) var(--tv-rand);
  background:
    radial-gradient(1100px 700px at 15% -10%, rgba(30,215,96,.16), transparent 60%),
    radial-gradient(900px 600px at 110% 110%, rgba(88,101,242,.14), transparent 60%),
    var(--bg);
}

.pt-tv__head { display: flex; align-items: center; justify-content: space-between; gap: var(--s-5); }

/* De linkerkant (titel, koplopers) mag krimpen en de koplopers mogen
   omvallen; de kaart met de code blijft altijd rechts staan. Anders duwt een
   rij lange namen de kaart onder de titel en zakt de hele tv een verdieping. */
.pt-tv__head > div:first-child { flex: 1 1 0; min-width: 0; }
.pt-tv__join { flex: 0 0 auto; }
.pt-tv__title { font-size: calc(clamp(1.4rem, 2.6vw, 2.4rem) * var(--maat, 1)); font-weight: 800; letter-spacing: -.02em; }

.pt-tv__join {
  display: flex;
  align-items: center;
  gap: calc(clamp(12px, 1.5vw, 24px) * var(--maat, 1));
  padding: calc(clamp(10px, 1.2vw, 18px) * var(--maat, 1)) calc(clamp(14px, 1.6vw, 26px) * var(--maat, 1));
  border-radius: var(--r-lg);
  background: var(--surface);
  border: 1px solid var(--line);
  /* Nooit breder dan de helft van de kop, anders drukt een lang eigen adres
     de kaart onder de titel en zakt de hele tv een verdieping. */
  max-width: min(52vw, 640px);
  min-width: 0;
}

.pt-tv__join > div:last-child { min-width: 0; }

.pt-tv__code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: calc(clamp(1.6rem, 3.4vw, 3rem) * var(--maat, 1));
  font-weight: 800;
  letter-spacing: .12em;
  color: var(--brand);
  line-height: 1;
}

.pt-tv__body {
  display: grid;
  grid-template-columns: 1fr;
  gap: calc(clamp(16px, 2.6vw, 44px) * var(--maat, 1));
  align-items: stretch;
  min-height: 0;
  overflow: hidden;
}

/* De hoes krimpt mee zodat titel en artiest altijd zichtbaar blijven. */
.pt-tv__now {
  display: flex;
  flex-direction: column;
  min-height: 0;
  /* Groeit mee met de beschikbare hoogte, zodat de hoes ruimte krijgt. */
  flex: 1 1 auto;
}

@media (min-width: 900px) and (orientation: landscape) {
  .pt-tv__body { grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr); }
}

.pt-tv__cover {
  flex: 1 1 auto;
  min-height: 0;
  width: auto;
  max-width: 100%;
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-3);
  background: var(--surface-2);
  align-self: center;
}

/* Een staand scherm (tablet rechtop): alles onder elkaar, en de plaat
   krijgt een vaste maat in plaats van de hele hoogte, anders rekt hij uit
   tot een ei en blijft de rest van het scherm leeg. */
@media (orientation: portrait) {
  .pt-tv__body { grid-template-columns: 1fr; grid-template-rows: auto minmax(0, 1fr); }
  .pt-tv__now { flex: 0 0 auto; }
  .pt-tv__cover { flex: 0 0 auto; width: min(100%, 26vh); height: auto; }
}

/* YouTube: de speler op de tv. Neemt de plek van de plaat; de titel en de
   voortgang staan eronder zoals altijd. Zichtbaar, want dat eist YouTube. */
.pt-tv__video {
  position: relative;
  /* Het beeld houdt zijn verhouding en pakt de ruimte die er is: is de kolom
     laag, dan wordt hij smaller in plaats van platgedrukt. Eerst stond hier
     alleen een maximumhoogte, en dan werd het een brede streep. */
  flex: 1 1 auto;
  min-height: 0;
  width: auto;
  max-width: 100%;
  height: auto;
  max-height: 100%;
  aspect-ratio: 16 / 9;
  align-self: center;
  border-radius: var(--r-xl);
  overflow: hidden;
  background: #000;
  box-shadow: var(--shadow-3);
}
.pt-tv__video > div:first-child,
.pt-tv__video iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

/* Overvloeien: twee lagen over elkaar, de actieve is zichtbaar. De tijd zet
   het script erin, zodat hij gelijk loopt met het geluid. */
.pt-tv__laag { position: absolute; inset: 0; opacity: 0; transition: opacity .8s ease; pointer-events: none; }
.pt-tv__laag.is-actief { opacity: 1; }

/*
 * De muis houdt de knoppen van YouTube in beeld.
 *
 * Zweef je met de muis over de speler, dan zet YouTube zijn eigen balk
 * eroverheen: titel, pauzeknop en 'Meer video's'. Op een tv-scherm wil je
 * dat niet zien, en er valt ook niets te bedienen: dat doet de DJ in de
 * console. Daarom vangt de speler geen muis, behalve als hij juist om een
 * tik vraagt (een telefoon start een clip niet zonder).
 */
.pt-tv__video iframe { pointer-events: none; }
.pt-tv--tik .pt-tv__video iframe { pointer-events: auto; }

/* Bij een YouTube-party krijgt het beeld de ruimte: de wachtrij ernaast mag
   smaller, en de plaat eronder is toch al verborgen.

   Alleen op een breed liggend scherm. Zonder die grens won deze regel het ook
   op een telefoon rechtop van de algemene regel, en kwam de clip in een kolom
   van nog geen tweehonderd pixels terecht terwijl het scherm er ruim
   driehonderd had. */
@media (min-width: 900px) and (orientation: landscape) and (min-height: 561px) {
  .pt-tv--video .pt-tv__body { grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr); }
}
/* Staat er beeld, dan mag de kop ook kleiner: de code blijft groot genoeg om
   te scannen, maar de kaart eromheen hoeft geen dertig procent van het scherm
   te pakken. Alles wat de kop niet gebruikt gaat naar de clip. */
.pt-tv--video .pt-tv__join { padding: calc(clamp(6px, .7vw, 12px) * var(--maat, 1)) calc(clamp(10px, 1vw, 18px) * var(--maat, 1)); }
.pt-tv--video .pt-tv__join > div:first-child svg { width: calc(clamp(84px, 8vw, 150px) * var(--maat, 1)); height: auto; }
.pt-tv--video .pt-tv__title { font-size: calc(clamp(1.1rem, 2vw, 1.9rem) * var(--maat, 1)); }
.pt-tv--video .pt-tv__dj-foto { width: calc(clamp(34px, 3vw, 54px) * var(--maat, 1)); height: calc(clamp(34px, 3vw, 54px) * var(--maat, 1)); }

/* Staat er beeld, dan houden we de regels eronder klein: elke pixel die de
   titel niet gebruikt, gaat naar de clip. */
.pt-tv--video #tv-now { gap: 2px; flex: 0 0 auto; }
.pt-tv--video .pt-tv__now-title { font-size: calc(clamp(1.2rem, 2.6vw, 2.6rem) * var(--maat, 1)); line-height: 1.1; }
.pt-tv--video .pt-tv__now-artist { font-size: calc(clamp(.9rem, 1.5vw, 1.5rem) * var(--maat, 1)); }
.pt-tv--video .pt-weetje { padding: 8px 12px; font-size: calc(clamp(.75rem, 1vw, 1rem) * var(--maat, 1)); }
.pt-tv--video .pt-tv__balk { margin-top: 6px; }

/* 'Speler zo groot mogelijk': de wachtrij gaat weg en het beeld vult alles
   wat er onder de kop over is. */
.pt-tv__spel { margin-top: clamp(16px, 2.4vh, 32px); }

/*
 * Speler zo groot mogelijk: de wachtrij gaat van de tv af en het beeld pakt
 * alles. Maar niet als er een spel loopt.
 *
 * De vraag van de tijdlijn, de meerkeuze of de bingo staat in diezelfde
 * kolom. Die weghalen betekende dat de zaal bij een spel naar een clip zat
 * te kijken zonder te zien wat er gevraagd werd. Dus tijdens een ronde komt
 * de kolom terug, met alleen het spel erin: de wachtrij hoort er op dat
 * moment niet bij.
 */
.pt-tv--videogroot .pt-tv__side { display: none; }
.pt-tv--videogroot.pt-tv--spel .pt-tv__side { display: block; }
.pt-tv--videogroot.pt-tv--spel .pt-tv__body { grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); }
.pt-tv--videogroot.pt-tv--spel #tv-queue,
.pt-tv--videogroot.pt-tv--spel #tv-side-kop { display: none; }
.pt-tv--videogroot.pt-tv--spel .pt-tv__spel { margin-top: 0; }
.pt-tv--videogroot .pt-tv__body { grid-template-columns: 1fr; }

/*
 * Ombouw en 'zo groot mogelijk' tegelijk: dan blijft de wachtrij gewoon staan.
 *
 * Zo groot mogelijk haalt de wachtrij van de tv om het beeld de volle breedte
 * te geven. Met een toestel eromheen gaat dat niet op: de kast bepaalt de
 * maat van het beeld, dus die breedte wordt toch niet gebruikt en lever je de
 * wachtrij in voor niets. Daarom hier terug naar de gewone indeling.
 */
.pt-tv--kast.pt-tv--videogroot .pt-tv__body { grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr); }
.pt-tv--kast.pt-tv--videogroot .pt-tv__side { display: flex; }
.pt-tv--kast.pt-tv--videogroot.pt-tv--spel #tv-queue { display: block; }
.pt-tv--kast.pt-tv--videogroot.pt-tv--spel #tv-side-kop { display: block; }
.pt-tv--videogroot .pt-tv__video { width: 100%; height: 100%; max-height: 100%; aspect-ratio: auto; }
.pt-tv--videogroot #tv-now { gap: 2px; }
.pt-tv--videogroot .pt-tv__now-title { font-size: calc(clamp(1.1rem, 2.2vw, 2rem) * var(--maat, 1)); }
.pt-tv--videogroot .pt-tv__now-artist { font-size: calc(clamp(.9rem, 1.4vw, 1.3rem) * var(--maat, 1)); }
/* De twee regels onder de code in de kop. Stonden eerst als losse stijl in
   het bestand zelf; nu staan ze hier, zodat een party met beeld ze kleiner
   kan zetten en de clip die ruimte krijgt. */
.pt-tv__join-sub   { font-size: calc(clamp(.8rem, 1vw, 1rem) * var(--maat, 1)); margin-top: 4px; }
.pt-tv__join-groei { font-size: calc(clamp(.7rem, .85vw, .85rem) * var(--maat, 1)); margin-top: 6px; }

/*
 * Beeld is koning.
 *
 * Draait er een clip, dan is elke pixel die de kop niet gebruikt winst voor
 * het beeld. De clip houdt zijn verhouding van 16 bij 9 en is daardoor zo
 * hoog als er plek is; wordt die ruimte groter, dan wordt hij ook breder.
 * Op een scherm van 1600 bij 900 scheelde dit 702 bij 395 tegenover 830 bij
 * 467, dus veertig procent meer beeld. De code blijft groot genoeg om te
 * scannen en de regels eronder blijven leesbaar.
 */
@media (min-width: 900px) and (orientation: landscape) and (min-height: 561px) {
  .pt-tv--video .pt-tv {
    /* De padding volgt deze maat; zie --tv-rand-y hierboven. */
    --tv-rand-y: calc(clamp(10px, 1.4vh, 20px) * var(--maat, 1));
    gap: calc(clamp(8px, 1.2vh, 16px) * var(--maat, 1));
  }
  .pt-tv--video .pt-tv__code { font-size: calc(clamp(1.4rem, 2.2vw, 2.2rem) * var(--maat, 1)); line-height: 1.1; }
  /* De code blijft op zijn volle maat: die moet vanaf de andere kant van de
     zaal te scannen zijn. Hij kostte ook geen hoogte, want het tekstblok
     ernaast is hoger. */
  .pt-tv--video .pt-tv__join > div:last-child { line-height: 1.25; }
  .pt-tv--video .pt-tv__join-sub   { margin-top: 2px; }
  .pt-tv--video .pt-tv__join-groei { margin-top: 2px; }
  .pt-tv--video .pt-bron--tv { margin-top: 4px; }
}

/*
 * De ombouw om het beeld.
 *
 * Zonder keuze is dit niets: display:contents laat de kast verdwijnen en de
 * speler hangt precies zoals eerst in de draaitafel. Dat scheelt een aparte
 * opmaak voor het gewone geval.
 *
 * Met de jaren 80 tv komt er een houten toestel omheen: een rand om het
 * beeld, een luidspreker ernaast en twee knoppen. Alles staat ernaast en
 * eromheen, nooit eroverheen: YouTube eist dat de speler helemaal vrij in
 * beeld staat.
 */
.pt-kast { display: contents; }

/* De kast hoort alleen om een speler die ook echt in beeld staat. Speelt er
   eigen muziek of staat het blok stil, dan zet de tv de speler weg; zonder
   pt-tv--video blijft het hier display:contents en valt de kast mee weg. */

/*
 * De kast krimpt om het beeld heen, met overal even veel hout.
 *
 * Dat is lastiger dan het klinkt. Liet ik de kast zich om het beeld vormen,
 * dan kon de browser de maat niet meer uitrekenen: de breedte hing aan de
 * hoogte van het beeld en die hing weer aan de kast. Dan bleef er een
 * streepje hout over en was het beeld weg. Stond de kast op de volle breedte,
 * dan kwam er links en rechts drie keer zo veel hout als boven en onder: een
 * dienblad in plaats van een toestel.
 *
 * De oplossing: de kast krijgt zelf een vaste verhouding en de rand en de
 * luidsprekerbalk staan in procenten van de breedte. Dan schaalt alles mee en
 * komt het beeld precies op 16 bij 9 uit, met rondom dezelfde rand. De
 * verhouding hieronder is die rekensom: rand 2,2 procent rondom, balk 5
 * procent met 1,8 procent ruimte erboven.
 */
.pt-tv--video.pt-tv--kast .pt-kast {
  display: flex;
  flex-direction: column;
  position: relative;
  flex: 1 1 0;
  min-height: 0;
  min-width: 0;
  align-self: center;
  width: auto;
  max-width: 100%;
  aspect-ratio: 1.539;
  padding: 2.2%;
  border-radius: 1.9%;
}
.pt-tv--video.pt-tv--kast .pt-kast .pt-tv__video {
  width: 100%;
  height: auto;
  max-height: none;
  flex: 0 0 auto;
  /*
   * De verhouding staat hier opnieuw, en dat is geen herhaling.
   *
   * Bij 'speler zo groot mogelijk' zet een andere regel hem op auto, omdat
   * het beeld dan het hele vak moet vullen. In de kast klopt dat niet: daar
   * is de maat van de kast al zo gekozen dat er precies een 16 bij 9 in past.
   * Zonder deze regel werd het beeld nul hoog en stond er alleen een lege
   * houten kast op de tv, met geluid maar zonder clip.
   */
  aspect-ratio: 16 / 9;
  border-radius: calc(clamp(6px, .7vw, 14px) * var(--maat, 1));
}

/* Het toestel zelf: hout met een donkere rand om het beeld. */
.pt-tv--video.pt-tv--kast-jaren80 .pt-kast {
  /*
   * Hout, en geen golfkarton.
   *
   * De eerste versie had strepen van twee pixels met veel contrast, en dat
   * zag eruit als ribbels. Echte fineer is onrustig maar flauw: twee lagen
   * nerf met een andere maat en nauwelijks kleurverschil, over een warme
   * verloop met een lichte bovenkant en een donkere onderkant.
   */
  background:
    repeating-linear-gradient(92deg, rgba(0, 0, 0, .03) 0 1px, rgba(255, 235, 200, .012) 1px 9px),
    repeating-linear-gradient(87deg, rgba(0, 0, 0, .022) 0 2px, rgba(255, 225, 180, .012) 2px 23px),
    linear-gradient(168deg, #8a5c33 0%, #6d4524 38%, #4a2d18 78%, #3a2211 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 235, 200, .22),
    inset 0 -2px 6px rgba(0, 0, 0, .5),
    0 22px 48px rgba(0, 0, 0, .5);
  border: 1px solid rgba(0, 0, 0, .55);
}

/* De beeldbuis: een zwarte rand om het glas, met een randje licht erbuiten. */
.pt-tv--video.pt-tv--kast-jaren80 .pt-kast .pt-tv__video {
  border: calc(clamp(3px, .45vw, 9px) * var(--maat, 1)) solid #0c0c0c;
  border-radius: calc(clamp(8px, .9vw, 16px) * var(--maat, 1));
  box-shadow:
    0 0 0 1px rgba(255, 255, 255, .07),
    0 6px 18px rgba(0, 0, 0, .55);
}

/*
 * Het bedieningspaneel onder het beeld.
 *
 * Luidsprekerrooster, een pitje dat brandt zolang er muziek speelt, en twee
 * knoppen. De linker knop draait mee met het nummer, net als de arm op de
 * plaat in de gewone weergave: aan het begin staat hij links, aan het eind
 * rechts. Alles staat in procenten van de kast, zodat het meeschaalt.
 */
.pt-kast__paneel { display: none; }

.pt-tv--video.pt-tv--kast-jaren80 .pt-kast__paneel {
  display: flex;
  align-items: center;
  gap: 1.4%;
  flex: 0 0 auto;
  height: 5%;
  margin-top: 1.8%;
}

.pt-kast__lamp {
  flex: 0 0 auto;
  width: 1.6%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: #4a1510;
  box-shadow: inset 0 1px 1px rgba(0, 0, 0, .6);
  transition: background .4s ease, box-shadow .4s ease;
}
.pt-kast.is-aan .pt-kast__lamp {
  background: #ff3b24;
  box-shadow: 0 0 6px rgba(255, 59, 36, .85), inset 0 1px 1px rgba(0, 0, 0, .35);
}

.pt-kast__rooster {
  flex: 1 1 auto;
  align-self: stretch;
  border-radius: calc(3px * var(--maat, 1));
  background:
    repeating-linear-gradient(90deg, rgba(0, 0, 0, .5) 0 2px, rgba(255, 235, 200, .07) 2px 5px),
    linear-gradient(180deg, #6a4527, #3c2412);
  box-shadow: inset 0 1px 0 rgba(255, 235, 200, .18), inset 0 -2px 5px rgba(0, 0, 0, .5);
}

.pt-kast__knop {
  position: relative;
  flex: 0 0 auto;
  width: 3.4%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: radial-gradient(circle at 38% 32%, #f6eedd 0 38%, #d9c9a8 60%, #a8977b 100%);
  box-shadow: 0 1px 2px rgba(0, 0, 0, .55), inset 0 -1px 2px rgba(0, 0, 0, .35);
}

/* Het streepje op de knop: dat is wat je ziet draaien. */
.pt-kast__knop i {
  position: absolute;
  left: 50%;
  top: 14%;
  width: 7%;
  height: 36%;
  border-radius: 999px;
  background: rgba(0, 0, 0, .62);
  transform: translateX(-50%) rotate(var(--draai, -140deg));
  transform-origin: 50% 100%;
  transition: transform .9s linear;
}
.pt-kast__knop--tijd i { transition: transform .9s linear; }

/*
 * Een staand scherm heeft geen vaste hoogte: de pagina mag daar scrollen.
 * Dan kan de kast zijn breedte niet uit zijn hoogte halen en moet hij het
 * omgekeerd doen: de volle breedte, en de hoogte volgt uit het beeld. De rand
 * blijft rondom even dik, want die staat in procenten van de breedte.
 */
@media (orientation: portrait), (max-width: 700px) {
  .pt-tv--video.pt-tv--kast .pt-kast {
    flex: 0 0 auto;
    align-self: stretch;
    width: 100%;
    aspect-ratio: auto;
  }
}

/* Op een klein scherm gaat elke pixel naar het beeld: de luidspreker valt
   weg en de rand wordt dun. */
@media (max-width: 700px), (max-height: 480px) {
  /* Zonder de luidsprekerbalk is de kast platter; de verhouding hoort
     daarmee mee te veranderen, anders komt het hout er weer bij. */
  .pt-tv--video.pt-tv--kast .pt-kast { padding: 1.7%; aspect-ratio: 1.723; }
  .pt-tv--video.pt-tv--kast-jaren80 .pt-kast__paneel { display: none; }
}

.pt-tv__video-wacht {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: var(--s-4);
  background: rgba(0, 0, 0, .62);
}
.pt-tv__video-fout {
  position: absolute;
  left: 50%;
  bottom: 8%;
  transform: translateX(-50%);
  z-index: 3;
  max-width: 90%;
  padding: 10px 18px;
  border-radius: 999px;
  background: rgba(0, 0, 0, .75);
  border: 1px solid rgba(255, 255, 255, .2);
  font-size: calc(clamp(.85rem, 1.2vw, 1.1rem) * var(--maat, 1));
}
.pt-tv--video .pt-tv__now .pt-tv__cover,
.pt-tv--video .pt-tv__now .pt-tv__wachtplaat { display: none; }
.pt-tv--video #tv-now { flex: 0 0 auto; }
@media (orientation: portrait) {
  .pt-tv__video { flex: 0 0 auto; width: 100%; }
}

/* Eigen muziek: de mapkeuze boven de plaat. Klein zodra de map gekozen is. */
.pt-tv__map {
  flex: 0 0 auto;
  text-align: center;
  padding: calc(clamp(12px, 1.6vw, 24px) * var(--maat, 1));
  border-radius: var(--r-lg);
  background: var(--surface);
  border: 1px solid var(--line);
  margin-bottom: calc(clamp(10px, 1.4vh, 18px) * var(--maat, 1));
}
.pt-tv__map.is-klaar { padding: 6px 12px; background: transparent; border-color: transparent; }
/* In een mix of bij een blok is eigen muziek maar een van de bronnen. Dan is
   de mapkeuze een instelling, en die staat in het optiepaneel in plaats van
   op het scherm zelf: dit scherm hangt in de zaal en daar horen geen
   instellingen op te staan. Zie de tak in tv.php. */
.pt-tv__map--optie {
  padding: var(--s-3) 0 0;
  background: transparent;
  border: 0;
  border-top: 1px solid var(--line);
  margin: var(--s-2) 0 0;
  text-align: left;
}
.pt-tv__map--optie .pt-tv__map-regel { justify-content: flex-start; }
.pt-tv__map-regel { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: var(--s-2); }

/* Nog niets aan het draaien: een stilstaande plaat met ons label erop. */
.pt-tv__wacht { display: flex; flex-direction: column; align-items: center; gap: var(--s-2); }
.pt-tv__wachtplaat {
  width: min(34vh, 34vw, 320px);
  margin: 0 auto var(--s-4);
  transform: translateX(-6%);
}

.pt-tv__now-title {
  flex: 0 0 auto;
  font-size: calc(clamp(1.5rem, 3.4vw, 3.2rem) * var(--maat, 1));
  font-weight: 800;
  letter-spacing: -.03em;
  line-height: 1.05;
  margin-top: calc(clamp(10px, 1.6vh, 24px) * var(--maat, 1));
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
}

.pt-tv__now-artist {
  flex: 0 0 auto;
  font-size: calc(clamp(1rem, 1.9vw, 1.7rem) * var(--maat, 1));
  color: var(--text-muted);
  margin-top: .25em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* De lijst mag afgekapt worden; de Hitster-vraag eronder nooit. */
.pt-tv__list {
  list-style: none; margin: 0; padding: 0;
  flex: 1 1 0; min-height: 0; overflow: hidden;
  /* Laat een afgekapte regel uitvloeien in plaats van hem doormidden te snijden. */
  -webkit-mask-image: linear-gradient(to bottom, #000 calc(100% - 36px), transparent 100%);
  mask-image: linear-gradient(to bottom, #000 calc(100% - 36px), transparent 100%);
}
/* Compacte variant van een invoerveld, voor krappe rijen. */
.pt-input--sm {
  padding: 6px 10px;
  font-size: .9rem;
  min-height: 34px;
}
/* Ook de compacte maat houdt het pijltje op dezelfde afstand van de rand:
   staan ze onder elkaar, dan hoort het op één lijn te staan. */
select.pt-input--sm { padding-right: calc(var(--s-3) * 2 + 12px); }

/*
   Op een aanraakscherm zijn kleine knoppen groter.

   Zesendertig pixels is prima met een muis, maar een DJ die in het donker
   met zijn duim op zijn telefoon mikt heeft meer nodig. Vierenveertig is de
   maat die de toegankelijkheidsrichtlijnen aanhouden. We hangen dit aan
   'pointer: coarse' en niet aan de schermbreedte: een laptop met een smal
   venster houdt zijn compacte knoppen, een telefoon krijgt ruimte.
*/
@media (pointer: coarse) {
  .pt-btn--sm { min-height: var(--tap); }
  .pt-btn--sm.pt-btn--icon { width: var(--tap); }
  .pt-input--sm { min-height: var(--tap); }
}

/* Jouw eigen cijfers, bovenaan het scorebord. */
.pt-mijncijfers {
  padding: var(--s-4);
  border-bottom: 1px solid var(--line);
}

.pt-mijncijfers__kop {
  font-size: .7rem;
  font-weight: 800;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin-bottom: var(--s-3);
}

.pt-cijfers {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--s-2);
}

/*
   Op een telefoon twee cijfers naast elkaar in plaats van drie.

   Bij drie is een vakje honderdnegen pixels breed en breken labels als
   'verzoekjes van gasten' en 'superkrachten ingezet' over twee regels, met
   een laatste vakje dat in zijn eentje op een rij staat. Bij twee passen de
   labels op een regel, en blijft er een vakje over, dan maakt die de rij af.
*/
@media (max-width: 599px) {
  .pt-cijfers { grid-template-columns: repeat(2, 1fr); }
  .pt-cijfer:last-child:nth-child(odd) { grid-column: span 2; }
}

.pt-cijfer {
  text-align: center;
  padding: var(--s-3) 6px;
  border-radius: var(--r-md);
  background: var(--surface-2);
  border: 1px solid var(--line);
}

.pt-cijfer__getal {
  font-size: 1.35rem;
  font-weight: 800;
  letter-spacing: -.02em;
  line-height: 1.1;
}

.pt-cijfer__label {
  margin-top: 2px;
  font-size: .7rem;
  color: var(--text-muted);
  line-height: 1.25;
}

/* Antwoordknoppen bij een meerkeuzevraag. Elk vlak zijn eigen kleur en
   vorm, zodat je ze van een afstand uit elkaar houdt. */
.pt-keuzes {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--s-2);
  margin-top: var(--s-3);
}
.pt-keuzes--twee { grid-template-columns: 1fr; }

.pt-keuze {
  display: flex;
  align-items: center;
  /* Krap gehouden: op een telefoon staan er twee naast elkaar, en een titel
     als 'Superstition' moet op een regel passen zonder afgebroken te worden. */
  gap: .4em;
  min-height: 60px;
  padding: var(--s-3) 10px;
  border-radius: var(--r-lg);
  border: 1px solid rgba(255, 255, 255, .16);
  color: #fff;
  font: inherit;
  font-weight: 700;
  text-align: left;
  cursor: pointer;
  transition: transform .1s ease, filter .15s ease;
}

.pt-keuze:active:not(:disabled) { transform: scale(.97); }
.pt-keuze:disabled { cursor: default; }

.pt-keuze--0 { background: linear-gradient(160deg, #d94a4a, #a92f2f); }
.pt-keuze--1 { background: linear-gradient(160deg, #3a7bd5, #2a5aa0); }
.pt-keuze--2 { background: linear-gradient(160deg, #d9a13a, #a97a20); }
.pt-keuze--3 { background: linear-gradient(160deg, #3fae5a, #2b8040); }

.pt-keuze__vorm { font-size: .9em; line-height: 1; flex: 0 0 auto; opacity: .9; }
/* break-word in plaats van anywhere: een woord dat op zijn eigen regel past
   blijft heel. Met 'anywhere' werd 'Superstition' vrolijk 'Superstiti-on'. */
.pt-keuze__tekst {
  min-width: 0;
  overflow-wrap: break-word;
  hyphens: auto;
  line-height: 1.2;
}

@media (max-width: 420px) {
  .pt-keuze { font-size: .92rem; }
}

/* Jouw keuze krijgt een rand, zodat je hem terugvindt. */
.pt-keuze.is-gekozen { outline: 3px solid #fff; outline-offset: -3px; }

/* Na afloop: het goede antwoord blijft, de rest dooft. */
.pt-keuze.is-fout { filter: grayscale(.85) brightness(.6); }
.pt-keuze.is-goed { filter: none; box-shadow: 0 0 0 3px rgba(30, 215, 96, .8); }

/* Op tv alleen tonen, niet aanraken: groter en zonder knopgevoel. */
.pt-tv .pt-keuzes { gap: calc(clamp(8px, 1.2vw, 16px) * var(--maat, 1)); margin-top: calc(clamp(10px, 1.6vh, 20px) * var(--maat, 1)); }
.pt-tv .pt-keuze {
  min-height: calc(clamp(40px, 5vh, 70px) * var(--maat, 1));
  font-size: calc(clamp(.9rem, 1.3vw, 1.35rem) * var(--maat, 1));
  padding: calc(clamp(6px, .9vh, 12px) * var(--maat, 1)) calc(clamp(8px, .8vw, 14px) * var(--maat, 1));
}

/* Een titel als '4 Minutes (feat. Justin Timberlake & Timbaland)' mag hoogstens
   drie regels beslaan; anders duwt hij de hele kaart van het scherm. */
.pt-tv .pt-keuze__tekst {
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Lijsten die lang kunnen worden krijgen hun eigen schuifbalk, zodat de
   module niet eindeloos uitrekt. */
.pt-scrollvak {
  max-height: 320px;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}

/* De superkrachten als kaarten: icoon, naam, uitleg en de schuif; wie aan
   staat licht groen op, wie uit staat is gedimd. De instellingen (geluid,
   tekst, gewicht) zitten in de kaart zelf. */
.pt-krachten { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: var(--s-3); margin-top: var(--s-3); }
.pt-kracht {
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-lg);
  border: 1px solid var(--line);
  background: var(--surface-2);
  transition: border-color .15s ease, background-color .15s ease, opacity .15s ease;
}
.pt-kracht:not(.is-aan) { opacity: .7; }
.pt-kracht.is-aan { border-color: rgba(30, 215, 96, .5); background: linear-gradient(180deg, rgba(30, 215, 96, .08), transparent 60%), var(--surface-2); }
.pt-kracht__kop { border-bottom: 0; padding: 0; gap: var(--s-3); }
.pt-kracht__kop .pt-switch__label { flex: 1 1 auto; min-width: 0; }
.pt-kracht__icoon {
  display: grid; place-items: center; flex: 0 0 auto;
  width: 44px; height: 44px; border-radius: 12px;
  background: rgba(255, 255, 255, .06);
  font-size: 1.5rem; line-height: 1;
}
.pt-kracht.is-aan .pt-kracht__icoon { background: rgba(30, 215, 96, .16); }
.pt-kracht__opties {
  margin: var(--s-3) 0 0;
  padding-top: var(--s-3);
  border-top: 1px solid var(--line);
}
.pt-kracht__opties .pt-label { margin-top: var(--s-2); }

/*
   Op een telefoon zitten de instellingen van een kracht achter een regeltje.
   Op een breed scherm staat die knop er niet en staat alles gewoon open.
*/
.pt-kracht__meer { display: none; }
@media (max-width: 599px) {
  .pt-kracht.is-aan .pt-kracht__meer {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-height: 36px;
    margin-top: var(--s-2);
    padding: 0;
    border: 0;
    background: none;
    color: var(--text-faint);
    font: inherit;
    font-size: .8rem;
    cursor: pointer;
  }
  .pt-kracht.is-aan .pt-kracht__meer:hover { color: var(--text-muted); }
  .pt-kracht__opties { display: none; }
  .pt-kracht.toont-opties .pt-kracht__opties { display: block; }
  .pt-kracht.toont-opties .pt-kracht__meer .pt-uitlegvouw__pijl { transform: rotate(90deg); }
}

/* Een bestandskiezer die eruitziet als een knop. */
.pt-upload { cursor: pointer; display: inline-flex; align-items: center; }

/* Zolang de foto onderweg is: het voorbeeld dooft en er draait een molentje
   overheen, zodat duidelijk is dat er iets gebeurt. */
.pt-avatar-bezig { position: relative; display: inline-block; }
.pt-avatar-bezig > * { opacity: .35; filter: grayscale(1); }

.pt-avatar-bezig::after {
  content: '';
  position: absolute;
  top: 50%; left: 50%;
  width: 26px; height: 26px;
  margin: -13px 0 0 -13px;
  border: 3px solid rgba(255,255,255,.25);
  border-top-color: var(--brand);
  border-radius: 50%;
  animation: pt-spin .7s linear infinite;
}

/* De balk onderin bij de gast: vijf onderdelen, altijd bereikbaar.
   De pagina was een lange rol geworden; zo hoef je nergens naartoe te
   scrollen om bij je krachten of het scorebord te komen. */
.pt-tabbar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 80;
  /* Flex en geen raster met een vast aantal kolommen: het bingotabblad komt
     erbij en gaat weer weg, en de rest schuift dan gewoon mee. */
  display: flex;
  background: rgba(11, 13, 15, .94);
  backdrop-filter: saturate(150%) blur(14px);
  -webkit-backdrop-filter: saturate(150%) blur(14px);
  border-top: 1px solid var(--line);
  padding-bottom: env(safe-area-inset-bottom);
  box-shadow: 0 -6px 20px rgba(0, 0, 0, .35);
}

.pt-tabbar__knop {
  position: relative;
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  min-height: 54px;
  padding: 10px 2px;
  border: 0;
  background: none;
  color: var(--text-muted);
  cursor: pointer;
  font: inherit;
}

.pt-tabbar__knop[aria-current="true"] { color: var(--brand); }

/* Het quiztabblad heeft twee icoontjes in een svg, waarvan er een aanstaat.
   Het hidden-attribuut doet op svg-elementen niets uit zichzelf; vandaar. */
.pt-tabbar__icon g[hidden] { display: none; }

/* Wat 'hidden' heeft is weg, ook als het element zelf display: flex of grid
   heeft. Zonder dit wint die eigen regel van de browserstandaard en blijft
   bijvoorbeeld een uitgeschakelde schakelaar gewoon staan. */
[hidden] { display: none !important; }
.pt-tabbar__knop[aria-current="true"] .pt-tabbar__icon { transform: scale(1.12); stroke-width: 2.2; }

/* Een getekend icoontje met het woord eronder. De hele zin blijft in
   aria-label en title staan; het woord is de korte versie. */
.pt-tabbar__icon {
  width: 23px; height: 23px;
  transition: transform .15s ease;
}

.pt-tabbar__woord {
  font-size: .62rem;
  letter-spacing: .01em;
  line-height: 1.1;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pt-tabbar__teller {
  position: absolute;
  top: 6px;
  left: 50%;
  margin-left: 5px;
  min-width: 17px;
  padding: 1px 4px;
  border-radius: 999px;
  background: var(--brand);
  color: var(--brand-ink);
  font-size: .65rem;
  font-weight: 800;
  line-height: 1.3;
  text-align: center;
}

/* Ruimte onder de inhoud, zodat de balk nooit iets afdekt. Het
   Hitster-paneel plakt daar net boven. */
.pt-page-vote .pt-bottom-space { height: calc(72px + env(safe-area-inset-bottom)); }
/* Meldingen boven de balk, anders dekken ze hem af. */
/*
   Een melding hoort boven de balk onderin, niet eroverheen.

   Dit stond alleen voor de gastenpagina ingesteld, maar elke pagina met zo'n
   balk heeft het: op het aanmeldformulier viel de foutmelding precies over de
   knoppen heen. Met :has() geldt het overal waar werkelijk een balk staat, en
   nergens anders.
*/
body:has(.pt-tabbar, .pt-menubalk, .pt-djbar) .pt-toasts {
  /* De balken zijn tussen de zevenenvijftig en tweeenzestig hoog; met deze
     marge staat de melding er net boven in plaats van er net overheen. */
  bottom: calc(78px + env(safe-area-inset-bottom));
}
.pt-page-vote .pt-toasts { bottom: calc(68px + env(safe-area-inset-bottom)); }
/* Het quizpaneel hangt net boven de balk, nooit erachter.
   Bewust vast en niet plakkend: bij de uitslag staat er ook een podium in,
   en dan is het paneel hoger dan de ruimte eronder. Een plakkend blok kan
   dat niet vasthouden en schuift dan half achter de balk. Wordt het te
   hoog, dan krijgt het paneel zijn eigen schuifbalk. */
.pt-hitster-dok {
  position: fixed;
  left: 0;
  right: 0;
  bottom: calc(54px + env(safe-area-inset-bottom));
  z-index: 60;
  max-height: calc(100dvh - 150px - env(safe-area-inset-bottom));
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  padding-bottom: var(--s-3);
}

/* Teller in de balk bovenaan: als een postvakje met een aantal erbij. */
.pt-krachtbel {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 5px 10px 5px 8px;
  border-radius: 999px;
  border: 1px solid rgba(255, 203, 71, .45);
  background: rgba(255, 203, 71, .14);
  color: #ffe6a8;
  font-weight: 800;
  cursor: pointer;
  animation: pt-krachtbel-pop .35s ease;
}
.pt-krachtbel.is-open { background: rgba(255, 203, 71, .3); }
.pt-krachtbel__bliksem { font-size: 1.05rem; line-height: 1; }
.pt-krachtbel__aantal {
  min-width: 1.35em;
  text-align: center;
  font-variant-numeric: tabular-nums;
  margin-top: 3px;
}

@keyframes pt-krachtbel-pop {
  from { transform: scale(.6); opacity: 0; }
  to   { transform: scale(1); opacity: 1; }
}

/* Het moment dat je er een krijgt: even alles opzij. */
.pt-krachtlaag {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: grid;
  place-items: center;
  padding: var(--s-4);
  background: rgba(6, 8, 10, .72);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  animation: pt-fade-in .2s ease;
}

.pt-krachtmelding {
  width: min(24rem, 100%);
  text-align: center;
  padding: var(--s-5) var(--s-4);
  border-radius: var(--r-xl);
  border: 1px solid rgba(255, 203, 71, .5);
  background: linear-gradient(180deg, rgba(255, 203, 71, .16), rgba(255, 203, 71, .05)), var(--surface);
  box-shadow: var(--shadow-3);
  animation: pt-krachtmelding-in .35s cubic-bezier(.2, .9, .3, 1.2);
}

.pt-krachtmelding__icon { font-size: 3.2rem; line-height: 1; }
.pt-krachtmelding__kop {
  margin-top: var(--s-3);
  font-size: 1.3rem; font-weight: 800; letter-spacing: -.02em;
}
.pt-krachtmelding__naam {
  margin-top: 4px;
  font-size: 1.05rem; font-weight: 700; color: #ffe6a8;
}
.pt-krachtmelding__hint { margin-top: 6px; color: var(--text-muted); font-size: .92rem; }

@keyframes pt-krachtmelding-in {
  from { transform: translateY(14px) scale(.94); opacity: 0; }
  to   { transform: none; opacity: 1; }
}

@keyframes pt-fade-in { from { opacity: 0; } to { opacity: 1; } }

@media (prefers-reduced-motion: reduce) {
  .pt-krachtbel, .pt-krachtmelding, .pt-krachtlaag { animation: none; }
}

/* Superkrachten per soort, bij de gast. */
.pt-power__soort {
  margin-top: var(--s-3);
  padding-top: var(--s-3);
  border-top: 1px solid var(--line);
}
.pt-power__soort-kop { display: flex; align-items: flex-start; gap: var(--s-3); }
.pt-power__soort-icon { font-size: 1.5rem; line-height: 1; flex: 0 0 auto; }
.pt-power__soort-naam { font-weight: 700; }

/* Wat een gast bezit, in de DJ-console. */
.pt-gastrij { padding: var(--s-3) 0; border-bottom: 1px solid var(--line); }
.pt-krachtjes { display: flex; gap: 3px; flex: 0 0 auto; }
.pt-krachtje {
  font-size: 1.05rem; line-height: 1;
  padding: 3px 5px;
  border-radius: var(--r-sm);
  background: rgba(255, 203, 71, .12);
  border: 1px solid rgba(255, 203, 71, .35);
}
.pt-krachtkeuze { flex: 1 1 auto; min-width: 0; }

/* ======================= De DJ-tafel =======================
   De bediening zat eerst in één hoge kolom rechts. Nu ligt hij als
   losse modules over de breedte, zoals de vlakken op een echte tafel. */

.pt-desk__head {
  display: flex; align-items: center; justify-content: space-between;
  gap: var(--s-4); padding-top: var(--s-4);
}

.pt-led {
  width: 12px; height: 12px; border-radius: 50%;
  flex: 0 0 auto;
  background: var(--surface-2);
  border: 1px solid var(--line-strong);
  box-shadow: inset 0 1px 2px rgba(0,0,0,.6);
}
.pt-led--aan {
  background: var(--brand);
  border-color: transparent;
  box-shadow: 0 0 10px rgba(30,215,96,.75);
}

.pt-deck {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--s-4);
  margin-top: var(--s-4);
}

@media (min-width: 1000px) {
  .pt-deck { grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr); align-items: stretch; }
}

/* Het paneelvlak: donker, met een lichte rand bovenaan alsof het licht
   erop valt. Gebruikt voor zowel het deck als de modules eronder. */
.pt-deck__panel,
.pt-module {
  position: relative;
  border-radius: var(--r-lg);
  border: 1px solid var(--line-strong);
  background: linear-gradient(180deg, rgba(255,255,255,.035), rgba(255,255,255,0) 42%), var(--surface);
  box-shadow: var(--shadow-2), inset 0 1px 0 rgba(255,255,255,.06);
  padding: var(--s-4);
  min-width: 0;
}

/*
   Een onderdeel in het menu van Beheer brengt zijn eigen kaart mee.

   Het paneel eromheen gaf er nog een rand, een achtergrond en een marge
   bovenop: twee kaders in elkaar, en op een telefoon kostte dat ruim dertig
   pixels van je breedte. Dit paneel is dus alleen een omhulsel.

   Dit staat na .pt-module en niet ervoor: even zwaar betekent dat de laatste
   wint, en andersom gebeurde er niets.
*/
.pt-module--hub {
  padding: 0;
  border: 0;
  background: none;
  box-shadow: none;
}

.pt-deck__panel { display: flex; flex-direction: column; gap: var(--s-3); }

.pt-deck__legend,
.pt-module__kop {
  font-size: .7rem;
  font-weight: 800;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.pt-deck__transport { justify-content: center; align-items: center; }
.pt-deck__transport .pt-transport { margin: auto 0; }
.pt-transport--deck { gap: var(--s-3); }

.pt-deck__device { display: flex; gap: var(--s-2); align-items: center; }
.pt-deck__device .pt-input { flex: 1 1 auto; min-width: 0; }

/*
   Een veld met een knop erachter, zoals 'Bewaren als quiz'.

   Met een vrije breedte neemt het veld zijn hele tekst als uitgangspunt; op
   een telefoon wordt de knop dan naar de volgende regel geduwd en kost zo'n
   rij twee regels. Een basis van tien em laat het veld meekrimpen, dus veld
   en knop blijven naast elkaar.
*/
.pt-veldknop { display: flex; flex-wrap: wrap; gap: var(--s-2); align-items: center; }
/* Een naam van zestig tekens heeft geen zevenhonderd pixels nodig; op een
   breed scherm houdt het veld het bij achtentwintig em. */
.pt-veldknop > .pt-input { flex: 1 1 10em; min-width: 0; max-width: 28em; }
.pt-veldknop > .pt-btn { flex: 0 0 auto; }

/* Op een telefoon de uitgang over de volle breedte: anders houdt 'Ververs'
   er negentig pixels van af en past de naam van een apparaat er niet in. */
@media (max-width: 599px) {
  .pt-deck__device { flex-wrap: wrap; }
  .pt-deck__device .pt-input { flex: 1 1 100%; }
}

/*
   De knoppenrij onder de apparatenlijst: ververs, het tv-scherm openen en
   alles stilzetten.

   Die drie horen bij elkaar, dus ze blijven op een rij in plaats van onder
   elkaar te vallen. Dat kan omdat ververs een icoontje is; de twee
   tekstknoppen krimpen mee en hun label valt desnoods binnen de knop om.
*/
.pt-btnrow--schermen { flex-wrap: nowrap; align-items: stretch; }
.pt-btnrow--schermen > .pt-btn:not(.pt-btn--icon) {
  /* Krimpen mag, uitrekken niet: op een breed scherm houden de twee knoppen
     hun eigen breedte in plaats van de hele rij op te vullen. */
  flex: 0 1 auto;
  min-width: 0;
  padding: 0 var(--s-3);
  text-align: center;
  line-height: 1.15;
}

/*
   Uitleg die je kan wegklikken.

   Dit werkte eerst alleen op een telefoon; op een breed scherm stond alle
   tekst er gewoon. Dat maakte het paneel Spellen een muur: bij elke
   keuzelijst vier regels uitleg, en daartussen moest je de instelling zoeken
   die je zocht. Nu geldt het overal. Je ziet de instellingen onder elkaar,
   en 'Hoe werkt dit?' zet de uitleg erbij zodra je hem nodig hebt.

   Wat er altijd blijft staan: korte regels (onder de honderdveertig tekens),
   waarschuwingen in een pt-note, en alinea's die zelf al verschijnen of
   verdwijnen. Zie vouwAlineas in pt.js.
*/
/*
   Het vraagtekentje achter de naam van een instelling.

   Rond, klein en stil: het hoort bij de naam en mag die niet overstemmen.
   Open is het groen, zodat je ziet welke uitleg eronder hoort. Het tikdoel is
   kleiner dan de vierenveertig pixels die we elders aanhouden; dat is hier
   een bewuste keuze, want ernaast mis tikken opent hoogstens niets en de
   uitleg staat ook in de handleiding.
*/
.pt-uitlegknop {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  margin-left: 6px;
  padding: 0;
  border: 1px solid var(--line-strong);
  border-radius: 50%;
  /* Een eigen vlakje eronder: zonder achtergrond viel het dunne rondje weg
     tegen het paneel en zag je het vraagteken pas als je ernaar zocht. */
  background: var(--surface-2);
  color: var(--text-muted);
  font: inherit;
  font-size: .68rem;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  vertical-align: middle;
  flex: 0 0 auto;
  transition: color .15s ease, border-color .15s ease, background-color .15s ease;
}
/* background-color en niet de korte schrijfwijze: die zou het driehoekje van
   een waarschuwing (een achtergrondplaatje) wegvegen zodra je erover gaat of
   hem openklapt. */
.pt-uitlegknop:hover { color: var(--text); background-color: var(--surface-3); border-color: var(--text-faint); }
.pt-uitlegknop.is-open {
  color: var(--brand);
  border-color: var(--brand);
  background-color: rgba(30, 215, 96, .12);
}

/*
   Een uitleg die een waarschuwing is krijgt een driehoekje.

   Bij 'Alle spellen toestaan, ook op Spotify' staat er geen uitleg over hoe
   iets werkt, maar waar je zelf voor tekent. Een vraagteken nodigt uit om
   het over te slaan; een gevarendriehoekje niet. Het teken zit in het
   plaatje, dus de tekst van de knop zetten we weg (de voorlezer leest het
   aria-label).
*/
.pt-uitlegknop--letop {
  border-color: rgba(255, 203, 71, .45);
  background-color: rgba(255, 203, 71, .14);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 3.6 22 20.4H2L12 3.6Z' fill='none' stroke='%23ffcb47' stroke-width='2' stroke-linejoin='round'/%3E%3Cpath d='M12 10v4.4' fill='none' stroke='%23ffcb47' stroke-width='2' stroke-linecap='round'/%3E%3Ccircle cx='12' cy='17.6' r='1.15' fill='%23ffcb47'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 12px 12px;
  color: transparent;
  font-size: 0;
}
.pt-uitlegknop--letop:hover {
  background-color: rgba(255, 203, 71, .24);
  border-color: rgba(255, 203, 71, .7);
  color: transparent;
}
.pt-uitlegknop--letop.is-open {
  color: transparent;
  border-color: var(--amber);
  background-color: rgba(255, 203, 71, .24);
}

/* De naam en het vraagteken staan op één regel. Ook in een samenvouwkop
   (Punten en straf, Meldingen en reacties), waar het pijltje van de kop
   links staat en het vraagteken achter de tekst. */
.pt-label.heeft-uitleg { display: flex; align-items: center; gap: 0; flex-wrap: wrap; }
summary.heeft-uitleg .pt-uitlegknop { margin-left: 8px; }

/*
   In een samenvouwkop staat het vraagteken achter de naam, niet in het
   midden.

   Zo'n kop verdeelt zijn inhoud over de volle breedte (de naam links, het
   pijltje rechts). Zodra het vraagteken erbij kwam waren het er drie en
   kreeg het middelste de ruimte: het vraagteken bungelde ergens halverwege
   de regel. Nu schuiven naam en vraagteken naar links en wordt alleen het
   pijltje naar rechts geduwd.
*/
.pt-details > summary.heeft-uitleg { justify-content: flex-start; }
.pt-details > summary.heeft-uitleg::after { margin-left: auto; }

/*
   Een instelling op één regel: naam links, keuze rechts.

   Alleen op een scherm dat er breed genoeg voor is, en alleen bij vakken die
   admin.js daarvoor geschikt vindt (zie naamEnKeuzeOpEenRegel). Alles wat
   geen naam of keuze is, zoals een stand of een opengeklapte uitleg, gaat
   over de volle breedte op de regel eronder.
*/
@media (min-width: 720px) {
  .pt-field.is-rij {
    display: grid;
    /* Een vaste kolom voor de naam, geen minmax: die laat de kolom met de
       inhoud meegroeien, en dan begint elke keuzelijst op een andere plek.
       Nu staan ze allemaal op dezelfde lijn onder elkaar. De keuze loopt door
       tot de rand van het paneel, net als een schuifje, zodat de rechterkant
       van alle regels onder elkaar staat. */
    grid-template-columns: 22em minmax(0, 1fr);
    align-items: center;
    /* Geen ruimte tussen de regels: wat onder de keuze hangt zet zijn eigen
       marge, en een dichtgeklapte uitleg mag geen hoogte kosten. */
    gap: 0 var(--s-3);
    /* De hoogte van de bediening. Zo hoog als een schuifje met zijn ruimte
       eromheen, zodat elke regel even hoog is. Op een aanraakscherm groeit
       hij mee naar vierenveertig; daar telt het tikdoel zwaarder. */
    --rij-hoog: 36px;
    /*
       Dezelfde maatvoering als een schakelaar.

       Een instelling met een keuzelijst stond los tussen de schuifjes: geen
       lijn eronder, meer lucht eromheen en een naam in een andere kleur en
       dikte. Daardoor leek het een blok dat ergens anders bij hoorde. Nu
       heeft elke regel dezelfde hoogte, dezelfde lijn en dezelfde naam.
    */
    padding: var(--s-2) 0;
    border-bottom: 1px solid var(--line);
  }
  .pt-field.is-rij:last-child { border-bottom: 0; }
  /* Een regel brengt zijn eigen ruimte mee, dus de extra marge onder een
     uitgeklapte uitleg hoeft er niet nog eens bij. */
  .pt-uitlegvouw + .pt-field.is-rij { margin-top: 0; }
  /* Een regel heeft nu zelf een lijn onder zich, en een vouwblok (Punten en
     straf) trekt er zelf een boven zich. Onder elkaar werden dat er twee met
     een kier ertussen. De bovenste is genoeg. */
  .pt-field.is-rij + .pt-details--vlak { border-top: 0; }
  /* Alles wat niet op de eerste regel staat krijgt zelf wat lucht. */
  .pt-field.is-rij > * { margin-top: var(--s-2); }
  .pt-field.is-rij > .pt-uitlegvouw { margin-top: 0; margin-bottom: 0; }
  .pt-field.is-rij > .pt-uitlegvouw.is-open { margin-top: var(--s-2); margin-bottom: var(--s-1); }
  .pt-field.is-rij > .pt-label {
    font-size: .95rem;
    font-weight: 400;
    color: var(--text);
  }
  .pt-field.is-rij > * { grid-column: 1 / -1; }
  /* Allebei op regel 1, wat er in de opbouw ook tussen staat: anders zakt de
     keuzelijst naar de regel eronder zodra er een uitleg tussen zit. */
  .pt-field.is-rij > .pt-label { grid-column: 1; grid-row: 1; margin: 0; }
  .pt-field.is-rij > .js-rijveld { grid-column: 2; grid-row: 1; margin: 0; }
  /* Allemaal even breed, en breed genoeg voor de langste keuze die erin kan
     staan ('Gewoon: een punt per goed antwoord, sets van een vast aantal
     vragen'). Een rij met vinkjes mag over de hele regel doorlopen, anders
     vallen vier vinkjes op twee regels. */
  .pt-field.is-rij > .js-rijveld:is(select, input) { width: 100%; max-width: none; }
  .pt-field.is-rij > .js-rijveld.pt-vinkjes { grid-column: 2 / -1; }
  .pt-field.is-rij:has(> .pt-vinkjes) { grid-template-columns: 22em minmax(0, 1fr); }

  /*
     Allemaal even hoog.

     Sommige keuzelijsten staan in de compacte maat en andere in de gewone;
     onder elkaar in dezelfde kolom zag je dat meteen, want dan springt de ene
     rij hoger dan de andere. In deze opstelling krijgen ze allemaal dezelfde
     hoogte en dezelfde letter. De binnenruimte rechts laten we met rust: daar
     staat het pijltje van de keuzelijst.

     Ook wat naast zo'n lijst staat (de knop 'Hoor' bij het belletje) doet
     mee, anders staat de knop een paar pixels lager dan de lijst ernaast.
  */
  .pt-field.is-rij > .js-rijveld:is(select, input, textarea),
  .pt-field.is-rij > .js-rijveld > :is(select, input, textarea, .pt-btn) {
    min-height: var(--rij-hoog);
    font-size: 16px;
    padding-block: 6px;
    padding-left: var(--s-3);
  }
  .pt-field.is-rij > .js-rijveld > .pt-btn:not(.pt-btn--icon) { padding-inline: var(--s-4); }

  /*
     Een rij met een luisterknopje erachter.

     Dat knopje hoort op dezelfde plek te staan als een schuifje een paar
     regels hoger, dus helemaal rechts tegen de rand van het paneel. De rij
     loopt daarom door tot die rand en het knopje wordt naar rechts geduwd.
     De keuzelijst ervoor houdt de maat van de kolom aan, zodat hij even
     breed blijft als de lijsten erboven en eronder.
  */
  .pt-field.is-rij > .js-rijveld:has(> .pt-btn--icon) {
    grid-column: 2 / -1;
    display: flex;
    align-items: center;
    gap: var(--s-2);
  }
  .pt-field.is-rij > .js-rijveld:has(> .pt-btn--icon) > :is(select, input) {
    flex: 1 1 auto;
    min-width: 0;
    width: auto;
  }
  .pt-field.is-rij > .js-rijveld:has(> .pt-btn--icon) > .pt-btn--icon {
    margin-left: auto;
    width: var(--rij-hoog);
  }

  /* Op een aanraakscherm is een tikdoel van zesendertig pixels te klein. */
  @media (pointer: coarse) {
    .pt-field.is-rij { --rij-hoog: var(--tap); }
  }
}

.pt-uitlegvouw { margin: var(--s-1) 0 var(--s-2); }
.pt-uitlegvouw__knop {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 32px;
  padding: 2px 2px;
  border: 0;
  background: none;
  color: var(--text-faint);
  font: inherit;
  font-size: .8rem;
  cursor: pointer;
}
.pt-uitlegvouw__knop:hover { color: var(--text-muted); }
.pt-uitlegvouw__pijl {
  display: inline-block;
  font-size: 1.1rem;
  line-height: 1;
  transition: transform .15s ease;
}
.pt-uitlegvouw.is-open .pt-uitlegvouw__pijl { transform: rotate(90deg); }
.pt-uitlegvouw__tekst { display: none; }
.pt-uitlegvouw.is-open .pt-uitlegvouw__tekst { display: block; }
.pt-uitlegvouw__tekst > p { margin-top: 0; }

/* Een uitleg die onder een schakelaar hoort neemt diens onderstreping over,
   anders lijkt hij bij de schakelaar eronder te horen. */
.pt-switch.heeft-vouw { border-bottom: 0; padding-bottom: 0; }
.pt-uitlegvouw--schuif { border-bottom: 1px solid var(--line); padding-bottom: var(--s-2); margin-top: 0; }
.pt-uitlegvouw--schuif:last-child { border-bottom: 0; }
.pt-uitlegvouw--schuif .pt-switch__hint { margin-top: 0; }

@media (max-width: 599px) {

  /* De knoppenrij van het blok: de tussenruimte eruit, zodat 'Blok starten'
     niet alleen rechts komt te hangen maar de regel vult. */
  .pt-blokrij > .pt-grow { display: none; }
  .pt-blokrij > .pt-btn { flex: 1 1 9em; }

  /* Twee knoppen met een lang opschrift passen niet naast elkaar; dan liever
     allebei over de volle breedte dan twee rafelige regels. */
  .pt-btnrow--breed > .pt-btn { flex: 1 1 100%; justify-content: flex-start; }

  /* Een regel met een knop die op een breed scherm rechts hoort te staan:
     op een telefoon valt de tussenruimte weg en vult de knop de regel. */
  .pt-actierij > .pt-grow { display: none; }
  .pt-actierij > .pt-btn { flex: 1 1 100%; }
}

/* Volume als schuif met een grijpbare knop, niet als dun streepje. */
.pt-fader { margin-top: var(--s-2); }
.pt-fader__label {
  display: block;
  font-size: .7rem; font-weight: 800; letter-spacing: .14em;
  text-transform: uppercase; color: var(--text-muted);
  margin-bottom: 2px;
}

.pt-range--fader { -webkit-appearance: none; appearance: none; background: transparent; }
.pt-range--fader::-webkit-slider-runnable-track {
  height: 8px; border-radius: 999px;
  background: var(--surface-2);
  border: 1px solid var(--line);
}
.pt-range--fader::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 20px; height: 30px; margin-top: -12px;
  border-radius: 5px;
  background: linear-gradient(180deg, #f2f4f5, #b9c0c4);
  border: 1px solid rgba(0,0,0,.5);
  box-shadow: 0 2px 5px rgba(0,0,0,.5);
  cursor: grab;
}
.pt-range--fader::-moz-range-track {
  height: 8px; border-radius: 999px;
  background: var(--surface-2); border: 1px solid var(--line);
}
.pt-range--fader::-moz-range-thumb {
  width: 20px; height: 30px; border-radius: 5px;
  background: linear-gradient(180deg, #f2f4f5, #b9c0c4);
  border: 1px solid rgba(0,0,0,.5);
  box-shadow: 0 2px 5px rgba(0,0,0,.5);
  cursor: grab;
}

/* ===========================================================================
   De knoppenbank onder in beeld

   Een DJ kijkt naar de draaitafel en de wachtrij; al het andere hoort onder
   handbereik maar niet in beeld. Alles zit daarom in een lade achter een
   balk die eruitziet als het front van een echt paneel: geborsteld metaal,
   een groef eronder en per knop een lampje dat aangaat als die lade openstaat.
   =========================================================================== */

:root { --djbar-h: 62px; }

.pt-djbar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 80;
  background: rgba(14, 16, 19, .88);
  -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  border-top: 1px solid var(--line);
  padding-bottom: env(safe-area-inset-bottom);
}

.pt-djbar__rek {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  max-width: 720px;
  margin: 0 auto;
  padding: 6px var(--s-3);
}

.pt-djbar__knop {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  padding: 6px 2px 4px;
  border: 0;
  border-radius: 12px;
  background: none;
  color: var(--text-faint);
  font: inherit;
  cursor: pointer;
  transition: color .15s ease, background-color .15s ease;
}

.pt-djbar__knop:hover { color: var(--text); }
.pt-djbar__knop:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.pt-djbar__knop.is-aan { color: var(--brand); }

.pt-djbar__icoon {
  width: 24px; height: 24px;
  fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round;
}

/*
   Wie aan de deur staat: een rood rondje met het aantal, bij het icoontje.

   Het hing eerst in de rechterbovenhoek van de hele knop. Zo'n knop is op een
   breed scherm een paar honderd pixels breed, dus stond het rondje ver van
   het icoontje af en leek het bij niets te horen. Nu hangt het aan het
   icoontje zelf: dat staat altijd in het midden, dus rekenen we vanaf het
   midden een halve icoonbreedte naar rechts.
*/
.pt-djbar__knop { position: relative; }
.pt-djbar__teller {
  position: absolute;
  top: 0;
  left: 50%;
  margin-left: 6px;
  min-width: 18px; height: 18px;
  padding: 0 5px;
  border-radius: 999px;
  background: #e5484d;
  color: #fff;
  font-size: .68rem;
  font-weight: 800;
  line-height: 18px;
  text-align: center;
  box-shadow: 0 1px 3px rgba(0,0,0,.6);
}

/* De deur in het Deelnemers-paneel. */
.pt-deur {
  border: 1px solid rgba(255, 203, 71, .35);
  background: rgba(255, 203, 71, .06);
  border-radius: var(--r-md);
  padding: var(--s-3);
}
.pt-deur__rij { display: flex; align-items: center; gap: var(--s-3); padding: var(--s-2) 0; }
.pt-deur__rij + .pt-deur__rij { border-top: 1px solid var(--line); }
/* Weigeren is de zware keuze van de twee; die kleurt rood zodra je erheen gaat. */
.pt-deur__weg:hover { color: var(--down); border-color: var(--down); }
.pt-gastrij.is-buiten .pt-avatar,
.pt-gastrij.is-buiten .pt-grow { opacity: .4; }

.pt-djbar__naam {
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .01em;
  white-space: nowrap;
}

/* Het Meer-menu: een lijst met icoon, naam, een regel uitleg en een pijl. */
/* Het menu Meer.
 *
 * Zestien rijen onder elkaar is bijna anderhalf scherm scrollen voordat je
 * ziet wat er allemaal in staat. Op een breed scherm staat er ruimte genoeg
 * naast elke rij, dus leggen we ze in kolommen: de kopjes lopen over de hele
 * breedte, de rijen eronder vullen zich op. Op een telefoon blijft het een
 * gewone lijst, want daar past maar een rij naast elkaar. */
.pt-menu {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--s-2);
  align-items: start;
}
@media (min-width: 760px) {
  .pt-menu { grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); }
}
.pt-menu__groep {
  grid-column: 1 / -1;
  margin: var(--s-3) 0 0;
  font-size: .72rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--text-faint);
}
.pt-menu__groep:first-child { margin-top: 0; }
.pt-menu__rij {
  display: flex; align-items: center; gap: var(--s-3);
  width: 100%;
  padding: var(--s-3);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface-2);
  color: var(--text); font: inherit; text-align: left;
  cursor: pointer;
  transition: border-color .15s ease, background-color .15s ease, box-shadow .15s ease, transform .15s ease;
}
/* De rijen staan nu in een raster met een eigen tussenruimte; de oude marge
   tussen twee rijen zou daar bovenop komen. */
.pt-menu__rij { height: 100%; }
a.pt-menu__rij, a.pt-menu__rij:visited { color: var(--text); text-decoration: none; }
/* De hover staat verderop bij de gloed van de console, zodat de spelkaartjes
   en deze rijen hun stand op een plek hebben staan. */
.pt-menu__icoon {
  display: grid; place-items: center; flex: 0 0 auto;
  width: 40px; height: 40px; border-radius: 12px;
  background: rgba(30, 215, 96, .12);
  transition: background-color .15s ease, box-shadow .15s ease;
}
.pt-menu__icoon svg { transition: filter .15s ease; }
.pt-menu__icoon svg { width: 20px; height: 20px; fill: none; stroke: var(--brand); stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.pt-menu__tekst { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 auto; }
.pt-menu__tekst strong { font-size: .95rem; }
.pt-menu__tekst span { font-size: .82rem; color: var(--text-muted); }
.pt-menu__pijl { width: 20px; height: 20px; flex: 0 0 auto; fill: none; stroke: var(--text-faint); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }

/* Teller op een rij in het menu: die staat gewoon in de rij, voor de pijl.
   De teller op de balk hangt in een hoekje en is daarom absoluut geplaatst;
   hier zou dat hem uit de rij trekken. */
/* Een origineel in de bloklijst: hij hoort bij de cover erboven, dus hij
   staat een stukje ingesprongen en wat rustiger. */
.pt-blok__clip--origineel { margin-left: var(--s-4); opacity: .85; }
.pt-blok__clip--origineel .pt-blok__pijlen { justify-content: center; color: var(--text-faint); font-size: 1.2rem; }

.pt-menu__teller {
  flex: 0 0 auto;
  min-width: 20px; height: 20px;
  padding: 0 6px;
  border-radius: 999px;
  background: #e5484d;
  color: #fff;
  font-size: .7rem; font-weight: 800; line-height: 20px; text-align: center;
}

.pt-lade__terug {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  height: 32px;
  padding: 0 12px 0 8px;
  border-radius: var(--r-pill);
  border: 1px solid var(--line-strong);
  background: var(--surface-2);
  color: var(--text-muted);
  font: inherit;
  font-size: .85rem;
  font-weight: 650;
  cursor: pointer;
}
.pt-lade__terug:hover, .pt-lade__terug:focus-visible { color: var(--text); border-color: var(--brand); }
/* Dezelfde knop als link, op een pagina die onder het menu hangt. Zonder dit
   krijgt hij de streep en de kleur van een gewone link. */
a.pt-lade__terug, a.pt-lade__terug:visited { color: var(--text-muted); text-decoration: none; }
a.pt-lade__terug:hover { color: var(--text); text-decoration: none; }
.pt-lade__terug svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.pt-lade__terug:hover { color: var(--text); }

/* Wachtrij en Al gedraaid: twee tabbladen boven dezelfde lijst. Ze staan in
   de titelregel, dus ze mogen groter zijn dan de tabjes in een paneel. */
.pt-rijtabs { display: flex; gap: var(--s-4); align-items: baseline; }

.pt-rijtab {
  border: 0;
  background: none;
  padding: 2px 0 6px;
  border-bottom: 2px solid transparent;
  color: var(--text-muted);
  font: inherit;
  font-size: 1.05rem;
  font-weight: 750;
  cursor: pointer;
}
.pt-rijtab:hover { color: var(--text); }
.pt-rijtab.is-aan { color: var(--text); border-bottom-color: var(--brand); }
.pt-rijtab .pt-small { font-weight: 400; margin-left: 4px; }

/* Op een telefoon moeten de twee tabbladen en de knop Selecteren samen op een
   regel passen. Zonder dit viel 'Wachtrij 35 te gaan' over twee regels. */
.pt-rijtab { white-space: nowrap; }
@media (max-width: 559px) {
  .pt-rijtabs { gap: var(--s-3); }
  .pt-rijtab { font-size: .95rem; }
  .pt-rijtab .pt-small { font-size: .7rem; }
}

/* De twee tabbladen in het paneel Bibliotheken. */
.pt-bibtabs {
  display: flex;
  gap: var(--s-2);
  margin-bottom: var(--s-3);
  border-bottom: 1px solid var(--line);
}

.pt-bibtab {
  border: 0;
  background: none;
  padding: 8px 4px;
  margin-bottom: -1px;
  border-bottom: 2px solid transparent;
  color: var(--text-muted);
  font: inherit;
  font-weight: 650;
  cursor: pointer;
}
.pt-bibtab:hover { color: var(--text); }
.pt-bibtab.is-aan { color: var(--text); border-bottom-color: var(--brand); }

/* ------------------------------------------------------------------ de lade */

.pt-lade {
  position: fixed;
  left: 0; right: 0;
  bottom: var(--djbar-h);
  z-index: 78;
  max-height: min(60vh, 560px);
  overflow-y: auto;
  overscroll-behavior: contain;
  background: linear-gradient(180deg, rgba(255,255,255,.04), rgba(255,255,255,0) 90px), var(--surface);
  border-top: 1px solid var(--line-strong);
  box-shadow: 0 -18px 44px rgba(0,0,0,.6);
  animation: pt-lade-op .18s ease-out;
}

@keyframes pt-lade-op {
  from { transform: translateY(14px); opacity: 0; }
  to   { transform: translateY(0);    opacity: 1; }
}

.pt-lade__kop {
  position: sticky;
  top: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  background: rgba(20,23,25,.96);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--line);
}

/* De weg naar de handleiding in de kop van een paneel: rustig, naast de
   titel, en met het woord erbij zodat het geen raadsel-icoontje is. */
.pt-lade__uitleg {
  display: inline-flex; align-items: center; gap: 6px;
  margin-left: auto; margin-right: var(--s-2);
  padding: 4px 10px;
  border-radius: var(--r-pill);
  border: 1px solid var(--line);
  color: var(--text-muted); text-decoration: none;
  font-size: .8rem; white-space: nowrap;
}
.pt-lade__uitleg:hover { color: var(--text); border-color: var(--line-strong); text-decoration: none; }
.pt-lade__uitleg svg { width: 15px; height: 15px; flex: 0 0 auto; }
@media (max-width: 560px) { .pt-lade__uitleg span { display: none; } }

.pt-lade__titel {
  flex: 1 1 auto;
  font-size: .72rem;
  font-weight: 800;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--text);
}

.pt-lade__dicht {
  flex: 0 0 auto;
  width: 30px; height: 30px;
  border-radius: 50%;
  border: 1px solid var(--line-strong);
  background: var(--surface-2);
  color: var(--text-muted);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
}

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

.pt-lade__vak {
  max-width: 900px;
  margin: 0 auto;
  padding: var(--s-4) var(--s-4) var(--s-5);
}

/* In de lade is het paneel geen kaartje meer; de lade zelf is het vlak. */
.pt-lade .pt-module {
  border: 0;
  background: none;
  box-shadow: none;
  padding: 0;
}

/* De titel staat al in de kop van de lade. */
.pt-lade .pt-module > .pt-module__kop { display: none; }

/* Ruimte onder de pagina, zodat de laatste regel niet onder de balk valt. */
.pt-page-admin main { padding-bottom: calc(var(--djbar-h) + var(--s-5)); }

@media (max-width: 999px) {
  :root { --djbar-h: 62px; }

  /* De transportbalk schuift een etage omhoog en staat op de knoppenbank. */
  .pt-transport--docked { bottom: var(--djbar-h); }
  .pt-page-admin main { padding-bottom: calc(var(--djbar-h) + 96px); }

  .pt-lade { max-height: 74vh; }
  .pt-lade__vak { padding: var(--s-4) var(--s-3) var(--s-5); }
}

@media (prefers-reduced-motion: reduce) {
  .pt-lade { animation: none; }
}

.pt-module > .pt-field,
.pt-module > .pt-switch { margin-top: var(--s-3); }

/* Een veld dat op een uitleg volgt plakte tegen de streep eronder.
   De regel hierboven geldt alleen voor een veld dat rechtstreeks in het
   paneel hangt, en 'Hoe lang speelt elk nummer' zit een laag dieper: dan
   stond de kop vlak tegen de lijn van de schakelaar erboven. Deze regel
   staat er met opzet onder, want hij moet die algemene winnen. */
.pt-uitlegvouw + .pt-field,
.pt-uitlegvouw + .pt-switch,
.pt-uitlegvouw + .pt-label { margin-top: var(--s-3); }
.pt-module > .pt-module__kop + * { margin-top: var(--s-3); }

@media (max-width: 999px) {
  /* Op mobiel blijft de transportbalk onderaan het scherm plakken; het
     paneel eromheen moet dan geen leeg vlak achterlaten. */
  .pt-deck__transport {
    background: none; border: 0; box-shadow: none; padding: 0;
  }
  .pt-deck__transport .pt-deck__legend,
  .pt-deck__transport .pt-transport__meta { display: none; }
}

/* Een deelnemer die iets niet meer mag. Niet doorstrepen: hij doet nog steeds
   mee, alleen niet met alles. Een gedempte naam zegt dat genoeg. */
.pt-gastrij.is-stil .pt-avatar,
.pt-gastrij.is-stil .pt-grow { opacity: .55; }

/* Wat een deelnemer mag: vijf schakelaartjes op een rij. Aan is de rustige
   toestand en dus onopvallend; uit is rood, want dat is wat je wilt zien als
   je de lijst langsloopt. */
.pt-rechten {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: var(--s-2);
}

.pt-recht {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 4px 9px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--text-muted);
  font: inherit;
  font-size: .72rem;
  font-weight: 650;
  line-height: 1.4;
  cursor: pointer;
  transition: border-color .15s ease, color .15s ease, background-color .15s ease;
}

.pt-recht:hover { border-color: var(--line-strong); color: var(--text); }
.pt-recht:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }

.pt-recht__icoon { font-size: .85em; line-height: 1; }

/* Een tune die uit de keuzelijsten gehaald is: nog zichtbaar, maar gedoofd. */
.pt-bericht.is-uit { opacity: .5; }
.pt-bericht.is-uit .pt-bericht__tekst { text-decoration: line-through; }

.pt-recht.is-uit {
  border-color: rgba(255, 95, 109, .55);
  background: rgba(255, 95, 109, .12);
  color: var(--danger);
}

/* Doorgestreept: dan hoef je de kleur niet te kennen om het te zien. */
.pt-recht.is-uit .pt-recht__naam { text-decoration: line-through; }

/* Een gekleurde emoji blijft anders vrolijk staan naast een rood vakje. */
.pt-recht.is-uit .pt-recht__icoon { filter: grayscale(1) opacity(.6); }

/* Een aanmelding die al is afgehandeld blijft staan, maar hoeft niet meer op
   te vallen: je zoekt in die lijst naar wie nog wacht. */
.pt-aanmelding.is-af { opacity: .6; }
.pt-aanmelding.is-af:hover { opacity: 1; }

/* De stappen om een eigen Spotify-app aan te maken. */
.pt-stappen {
  margin: var(--s-3) 0 0;
  padding-left: 20px;
  color: var(--text);
}

.pt-stappen li { margin-bottom: var(--s-3); }
.pt-stappen ul { margin: var(--s-2) 0; padding-left: 18px; }
.pt-stappen ul li { margin-bottom: var(--s-1); }

/* Een adres dat letterlijk overgenomen moet worden, met een knop ernaast.
   Overtypen gaat een keer mis en dan is de foutmelding van Spotify niet te
   plaatsen. */
.pt-kopieerbaar {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  flex-wrap: wrap;
  margin: var(--s-2) 0 4px;
}

.pt-kopieerbaar code {
  flex: 1 1 240px;
  min-width: 0;
  padding: 8px 10px;
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background: var(--surface-2);
  font-size: .85rem;
  word-break: break-all;
}

/* Een inklapbaar blok binnen een paneel: geen eigen kaart, alleen een lijn
   erboven en een kopje dat je kunt openklappen. */
.pt-details--vlak {
  border: 0;
  border-top: 1px solid var(--line);
  border-radius: 0;
  background: none;
  box-shadow: none;
  padding: 0;
}

/*
 * Een schuifje dat uit staat, met een dichtgeklapt blok eronder.
 *
 * Het schuifje heeft een streep onder zich en het kopje eronder een streep
 * boven zich. Zolang er instellingen tussen staan zie je dat niet, maar zet
 * je het spel uit, dan valt dat blok weg en stonden er ineens twee strepen
 * met een kier ertussen. Dan is een streep genoeg.
 */
#punten-vouw { margin-top: var(--s-4); }
.pt-switch + [hidden] + .pt-details--vlak { border-top: 0; }
/*
 * Hetzelfde met het vouwregeltje 'Hoe werkt dit?' ertussen.
 *
 * Dat regeltje wordt door het script tussengeschoven, dus de twee staan dan
 * niet meer naast elkaar en de regel hierboven greep niet meer. Je zag twee
 * strepen met de uitlegknop ertussen.
 */
.pt-switch + .pt-uitlegvouw + .pt-details--vlak,
.pt-switch + [hidden] + .pt-uitlegvouw + .pt-details--vlak { border-top: 0; }

.pt-details--vlak > summary {
  padding: var(--s-3) 0;
  font-size: .72rem;
  font-weight: 800;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--text-muted);
  cursor: pointer;
}

/*
   Wat er in een dichtgeklapt blok zit, in de kop zelf.

   De kop zei alleen 'Meldingen en reacties' en stond dicht, dus wie het
   belletje zocht zag alleen een kopje en zocht verder. Nu staat erachter wat
   erin zit. Op een smal scherm laten we het weg; daar is de regel al vol.
*/
.pt-vouwhint {
  margin-left: auto;
  padding-left: var(--s-3);
  font-size: .72rem;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--text-faint);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
.pt-details[open] > summary > .pt-vouwhint { display: none; }
@media (max-width: 599px) {
  .pt-vouwhint { display: none; }
}

/*
   Het regeltje begint waar de keuzes beginnen.

   Rechts uitlijnen leek netjes, maar dan begint elk regeltje op een andere
   plek: het ene kopje zei vier woorden en het andere zeven. Nu staan ze
   onder elkaar in dezelfde kolom als de keuzelijsten eronder. Los van de
   tekststroom, want de kop heeft zijn eigen letterhoogte en het pijltje
   rechts moet zijn plek houden. De maat is dezelfde 22rem als de naamkolom
   van een instelling (zie .pt-field.is-rij), maar in rem: een kop rekent in
   zijn eigen kleine letter, en dan zou em een andere afstand opleveren.
*/
@media (min-width: 720px) {
  .pt-details--vlak > summary { position: relative; }
  .pt-details--vlak > summary > .pt-vouwhint {
    position: absolute;
    left: calc(22rem + var(--s-3));
    right: 1.6rem;
    margin-left: 0;
    padding-left: 0;
    text-align: left;
  }
}

.pt-details--vlak > summary:hover { color: var(--text); }
.pt-details--vlak[open] > summary { color: var(--text); }

/*
 * De uitleg als laagje over de console.
 *
 * Eerst opende de knop Uitleg de handleiding in een nieuw tabblad. Dan ben je
 * de console kwijt terwijl er muziek draait, en moet je terugzoeken waar je
 * was. Nu komt het stukje dat bij dit paneel hoort gewoon over de console
 * heen, met een kruisje. De tekst komt uit de handleiding zelf, dus hij staat
 * maar op een plek.
 */
.pt-uitleglaag {
  position: fixed;
  inset: 0;
  z-index: 90;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--s-4);
  background: rgba(0,0,0,.62);
  animation: pt-uitleg-op .16s ease-out;
}
@keyframes pt-uitleg-op { from { opacity: 0; } to { opacity: 1; } }

.pt-uitleglaag__vak {
  display: flex;
  flex-direction: column;
  width: min(720px, 100%);
  max-height: min(82vh, 760px);
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-lg);
  box-shadow: 0 24px 60px rgba(0,0,0,.6);
  overflow: hidden;
}

.pt-uitleglaag__kop {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  flex: 0 0 auto;
  padding: var(--s-3) var(--s-4);
  border-bottom: 1px solid var(--line);
  background: rgba(20,23,25,.96);
}

.pt-uitleglaag__inhoud {
  flex: 1 1 auto;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 0 var(--s-4) var(--s-4);
}

/* Het eerste kopje staat al in de balk erboven; in de tekst hoeft hij niet
   nog een keer met een streep erboven te beginnen. */
.pt-uitleglaag__inhoud > h2:first-child,
.pt-uitleglaag__inhoud > h3:first-child {
  margin-top: var(--s-4);
  padding-top: 0;
  border-top: 0;
}

/* De weg naar de hele handleiding houdt hier wel zijn woord: in de balk van
   de lade valt hij weg op een smal scherm, maar een knop zonder tekst zegt
   hier niets. */
.pt-uitleglaag__alles { margin-left: auto; margin-right: 0; }

@media (max-width: 560px) {
  .pt-uitleglaag { padding: 0; align-items: flex-end; }
  .pt-uitleglaag__vak { max-height: 88vh; border-radius: var(--r-lg) var(--r-lg) 0 0; border-bottom: 0; }
  .pt-uitleglaag__alles span { display: inline; }
  .pt-uitleglaag__kop .pt-lade__titel { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
}

/* Het pijltje bij een regel in het tv-menu die iets opent in plaats van
   iets aan of uit te zetten. */
.pt-tvoptie__pijl { margin-left: auto; color: var(--text-faint); font-size: 1.2rem; line-height: 1; }
/* Het uitklaplijstje eronder, met de speakers van dit apparaat. */
.pt-tvopties__sublijst { display: flex; flex-direction: column; gap: 2px; padding: 4px 0 8px 12px; }
.pt-tvopties__sub {
  text-align: left;
  background: none;
  border: 0;
  color: var(--text-muted);
  font: inherit;
  font-size: .9rem;
  padding: 7px 10px;
  border-radius: var(--r-md);
  cursor: pointer;
}
.pt-tvopties__sub:hover { background: var(--surface-2); color: var(--text); }
/* Uitleg onder de speakerlijst: waarom een AirPlay-speaker er niet bij staat. */
.pt-tvopties__wenk {
  margin: 8px 10px 0;
  font-size: .8rem;
  line-height: 1.45;
  color: var(--text-faint);
}
.pt-tvopties__sub.is-aan { color: var(--brand); font-weight: 700; }

/*
 * Een plaatje bij een eigen quizvraag.
 *
 * Op de tv krimpt het mee met de hoogte: de antwoorden moeten in beeld
 * blijven, want daar gaat het om. Op de telefoon is de breedte de grens.
 */
.pt-vraagtv__beeld { display: flex; justify-content: center; margin: clamp(6px, 1.2vh, 16px) 0; }
.pt-vraagtv__beeld img {
  max-height: 30vh;
  max-width: 100%;
  border-radius: var(--r-md);
  object-fit: contain;
}
.pt-vraagbeeld { display: flex; justify-content: center; margin-top: var(--s-2); }
.pt-vraagbeeld img { max-width: 100%; max-height: 32vh; border-radius: var(--r-md); object-fit: contain; }

/* De handleiding: gewone leestekst met wat lucht, en kopjes die je van een
   afstand terugvindt. */
.pt-uitleg p, .pt-uitleg li, .pt-uitleg dd { line-height: 1.6; }
.pt-uitleg p { margin: var(--s-3) 0 0; }
.pt-uitleg h2 { margin: var(--s-6) 0 var(--s-2); padding-top: var(--s-3); border-top: 1px solid var(--line); }
.pt-uitleg h3.pt-uitleg__sub { margin: var(--s-5) 0 var(--s-2); font-size: 1rem; }
.pt-uitleg ul, .pt-uitleg ol { margin: var(--s-3) 0 0; padding-left: 22px; }
.pt-uitleg li { margin-bottom: var(--s-2); }
.pt-uitleg li ul { margin-top: var(--s-2); }
.pt-uitleg .pt-note { margin-top: var(--s-4); }
.pt-uitleg__stappen > li { margin-bottom: var(--s-4); }
.pt-uitleg__stappen strong { color: var(--text); }

.pt-uitleg__inhoud { display: flex; flex-direction: column; gap: 6px; }

.pt-uitleg__inhoud a { color: var(--text); text-decoration: none; }
.pt-uitleg__inhoud a:hover { color: var(--brand); }
.pt-uitleg__inhoud-sub { padding-left: 18px; color: var(--text-muted) !important; font-size: .9em; }

/* Een inhoudsopgave met korte kopjes mag in twee kolommen: acht regels onder
   elkaar is op een telefoon een kwart scherm voor niets. */
.pt-uitleg__inhoud--kort {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(10em, 1fr));
  gap: 8px var(--s-3);
}

.pt-uitleg__vragen dt { margin-top: var(--s-4); font-weight: 700; }
.pt-uitleg__vragen dd { margin: var(--s-1) 0 0; color: var(--text-muted); }

/* Het eigen adres van een DJ op de tv, op de plek van de code. Iets kleiner
   dan de code, want het is langer, maar wel in dezelfde toon. */
.pt-tv__adres {
  font-size: calc(clamp(1rem, 1.9vw, 1.8rem) * var(--maat, 1));
  line-height: 1.15;
  font-weight: 800;
  letter-spacing: .02em;
  color: var(--brand);
  /* Afbreekpunten staan in de html (na punt en streepje); daarbuiten heel laten. */
  word-break: normal;
  overflow-wrap: normal;
}

/* ====================================================== Muziekbingo */

.pt-bingo {
  display: grid;
  gap: 6px;
  margin-top: var(--s-3);
}

.pt-bingo--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.pt-bingo--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

/* Een vakje: vierkant, met titel en artiest erin. Klein lettertype, want er
   moeten er negen of zestien naast elkaar op een telefoon. */
.pt-bingo__vak {
  aspect-ratio: 1 / 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 2px;
  padding: 6px 5px;
  border-radius: var(--r-md);
  border: 1px solid var(--line-strong);
  background: var(--surface-2);
  color: var(--text);
  font: inherit;
  text-align: center;
  cursor: pointer;
  transition: transform .08s ease, background-color .15s ease;
  overflow: hidden;
}

.pt-bingo__vak:active:not(:disabled) { transform: scale(.95); }

.pt-bingo__titel {
  font-size: .72rem;
  font-weight: 700;
  line-height: 1.15;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.pt-bingo--4 .pt-bingo__titel { font-size: .62rem; -webkit-line-clamp: 2; }

.pt-bingo__artiest {
  font-size: .62rem;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.pt-bingo--4 .pt-bingo__artiest { font-size: .55rem; }

/* Afgestreept: groen, met een vinkje eroverheen. */
.pt-bingo__vak.is-af {
  background: rgba(29, 185, 84, .22);
  border-color: var(--brand);
  color: var(--text);
  position: relative;
}

.pt-bingo__vak.is-af::after {
  content: '\2713';
  position: absolute;
  right: 4px; top: 2px;
  font-size: .9rem;
  color: var(--brand);
}

/* Geschrapt door een veto en niets om mee te vervangen. Dat vakje kan nooit
   meer vallen, dus het telt vanzelf mee: afgestreept, maar met een streep
   door de titel zodat je ziet dat je er zelf niets voor hoefde te doen. */
.pt-bingo__vak.is-vrij {
  cursor: default;
}

.pt-bingo__vak.is-vrij .pt-bingo__titel,
.pt-bingo__vak.is-vrij .pt-bingo__artiest {
  opacity: .5;
  text-decoration: line-through;
}

/* De bingo-roep over het hele scherm, op telefoon en tv. */
.pt-roep {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--s-5);
  background: rgba(8, 10, 12, .92);
  text-align: center;
  animation: pt-fade-in .25s ease both;
}
.pt-roep__vak { max-width: 560px; }
.pt-roep__icoon { font-size: clamp(3rem, 12vw, 6rem); line-height: 1; }
.pt-roep__kop { font-size: clamp(1.8rem, 7vw, 3.6rem); font-weight: 900; letter-spacing: -.02em; margin-top: var(--s-3); }
.pt-roep__naam { font-size: clamp(1.1rem, 4vw, 1.8rem); color: var(--text-muted); margin-top: var(--s-2); }
.pt-roep--ok .pt-roep__kop { color: var(--brand); }
/* Kaping: de tekst zelf is de kop, dus wat kleiner en met afbreken. */
.pt-roep--kaping .pt-kaping__tekst { font-size: calc(clamp(1.6rem, 4vw, 4rem) * var(--maat, 1)); line-height: 1.2; overflow-wrap: anywhere; }
.pt-tv__opdracht {
  margin-top: calc(clamp(8px, 1.2vh, 16px) * var(--maat, 1));
  font-size: calc(clamp(1rem, 1.6vw, 1.5rem) * var(--maat, 1));
  color: var(--brand);
  font-weight: 700;
}
.pt-roep--vals .pt-roep__kop { color: var(--down); }
.pt-roep--roep .pt-roep__icoon { animation: pt-roep-bel .6s ease-in-out infinite alternate; }
@keyframes pt-roep-bel { from { transform: rotate(-12deg); } to { transform: rotate(12deg); } }
.pt-roep--vals .pt-roep__icoon { animation: pt-roep-schud .5s ease both; }
.pt-roep--jury .pt-roep__icoon { animation: pt-roep-kijk 1.2s ease-in-out infinite; }
@keyframes pt-roep-kijk { 0%, 100% { transform: translateX(-8px) rotate(-4deg); } 50% { transform: translateX(8px) rotate(4deg); } }
.pt-roep__puntjes::after { content: ''; animation: pt-roep-puntjes 1.2s steps(4, end) infinite; }
@keyframes pt-roep-puntjes { 0% { content: ''; } 25% { content: '.'; } 50% { content: '..'; } 75% { content: '...'; } }
.pt-roep__balk {
  width: min(320px, 70vw);
  height: 8px;
  margin: var(--s-4) auto 0;
  border-radius: 999px;
  background: var(--surface-3);
  overflow: hidden;
}
.pt-roep__balk-vul { height: 100%; width: 0; background: var(--amber); animation: pt-roep-vul linear forwards; }
@keyframes pt-roep-vul { from { width: 0; } to { width: 100%; } }
.pt-roep__beeld img {
  display: block;
  margin: 0 auto;
  max-width: min(90vw, 560px);
  max-height: 38vh;
  border-radius: 14px;
  object-fit: contain;
}
.pt-roep__straf {
  display: inline-block;
  margin-top: var(--s-4);
  padding: 8px 16px;
  border-radius: var(--r-pill);
  background: rgba(255, 203, 71, .16);
  border: 1px solid rgba(255, 203, 71, .5);
  color: var(--amber);
  font-weight: 700;
  font-size: clamp(1rem, 3.5vw, 1.4rem);
}
@keyframes pt-roep-schud {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-10px); }
  75% { transform: translateX(10px); }
}

/* Dubbel of niets bij strafpunten. */
.pt-inzet {
  display: flex; align-items: center; gap: 10px;
  margin-top: var(--s-2);
  padding: 8px 12px;
  border-radius: var(--r-md);
  border: 1px dashed rgba(255, 203, 71, .5);
  color: var(--amber);
  font-weight: 650;
  cursor: pointer;
}
.pt-inzet__vink { width: 20px; height: 20px; accent-color: var(--amber); }

/* Geheime DJ: de deelnemerslijst om uit te kiezen. De lijst scrollt in
   zichzelf; de knop Inzenden blijft eronder staan. */
.pt-spelers {
  max-height: min(42vh, 360px);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  margin-top: var(--s-2);
}
.pt-speler {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  width: 100%;
  padding: 10px var(--s-3);
  border: 0;
  border-bottom: 1px solid var(--line);
  background: transparent;
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.pt-speler:last-child { border-bottom: 0; }
.pt-speler__naam { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pt-speler__vink { color: var(--brand); font-weight: 800; opacity: 0; }
.pt-speler.is-gekozen { background: rgba(29, 185, 84, .14); }
.pt-speler.is-gekozen .pt-speler__vink { opacity: 1; }
.pt-spelerkeuze__voet { padding-top: var(--s-3); }

/* De onthulling: de inzender met foto en toelichting. */
.pt-onthulling {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  margin-top: var(--s-3);
  padding: var(--s-3);
  border-radius: var(--r-md);
  background: rgba(29, 185, 84, .1);
  border: 1px solid rgba(29, 185, 84, .35);
}

/* Op de tv: de deelnemers als rij gezichten, en de onthulling groot. */
.pt-tv__spelers { display: flex; flex-wrap: wrap; gap: 8px 12px; margin-top: calc(clamp(8px, 1.2vh, 16px) * var(--maat, 1)); }
.pt-tv__speler {
  display: flex; align-items: center; gap: 8px;
  padding: 4px 12px 4px 4px;
  border-radius: var(--r-pill);
  border: 1px solid var(--line);
  background: var(--surface);
  font-size: calc(clamp(.8rem, 1.2vw, 1.05rem) * var(--maat, 1));
}
.pt-tv__speler.is-klaar { border-color: var(--brand); background: rgba(29, 185, 84, .12); }
.pt-tv__speler.is-uit { opacity: .45; text-decoration: line-through; }
.pt-tv__gedraaid { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; margin-top: 6px; }
.pt-tv__prijs {
  display: flex; align-items: center; gap: calc(clamp(10px, 1.4vw, 20px) * var(--maat, 1));
  margin-top: calc(clamp(8px, 1.2vh, 16px) * var(--maat, 1));
  padding: calc(clamp(8px, 1vh, 14px) * var(--maat, 1));
  border-radius: var(--r-md);
  border: 1px solid rgba(255, 203, 71, .4);
  background: rgba(255, 203, 71, .08);
}
.pt-tv__prijs-foto { height: calc(clamp(48px, 9vh, 110px) * var(--maat, 1)); max-width: 40%; border-radius: 8px; object-fit: cover; }
.pt-onthulling--tv { margin-top: clamp(8px, 1.2vh, 16px); padding: clamp(10px, 1.4vh, 18px); gap: clamp(12px, 1.6vw, 24px); }

/* Geen stemmen (Geheime DJ): de pijltjes gaan weg, de lijst blijft. */
body.pt-geen-stemmen .pt-vote { display: none !important; }

/* Een verborgen nummer bij echte bingo: alleen een draaiende plaat. */
.pt-geheim__nu { display: flex; align-items: center; gap: var(--s-3); }
.pt-geheim__plaat { width: 72px; flex: 0 0 auto; }
.pt-bingo__knop { margin-top: var(--s-3); font-size: 1.15rem; font-weight: 900; letter-spacing: .06em; }
.pt-bingo--uit .pt-bingo__vak { opacity: .45; }

.pt-bingo__splash {
  text-align: center;
  padding: var(--s-3) 0 var(--s-4);
  border-bottom: 1px solid var(--line);
  margin-bottom: var(--s-3);
}

.pt-bingo__roep {
  font-size: 2.4rem;
  font-weight: 900;
  letter-spacing: .06em;
  color: var(--amber);
  animation: pt-bingo-pop .5s cubic-bezier(.2, 1.4, .4, 1);
}

@keyframes pt-bingo-pop {
  from { transform: scale(.4); opacity: 0; }
  to   { transform: scale(1);  opacity: 1; }
}

/* Op de tv: groot en midden in beeld, kort. */
.pt-tv .pt-bingo__splash {
  border: 0;
  padding: calc(clamp(10px, 2vh, 24px) * var(--maat, 1)) 0;
}

.pt-tv .pt-bingo__roep { font-size: calc(clamp(2.4rem, 6vw, 5.5rem) * var(--maat, 1)); }

/* De stapel met grote knoppen onderin het tv-scherm.
   Ze kunnen tegelijk nodig zijn (geluid aanzetten, hier afspelen, het blok
   laten starten). Los van elkaar stonden ze alle drie op dezelfde plek en
   las je twee teksten door elkaar heen. Hier staan ze onder elkaar, midden
   in beeld, met de nieuwste onderaan. */
.pt-tv__knoppen {
  position: fixed;
  left: 0;
  right: 0;
  bottom: calc(clamp(60px, 10vh, 120px) * var(--maat, 1));
  z-index: 50;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(10px * var(--maat, 1));
  padding: 0 calc(clamp(16px, 2vw, 32px) * var(--maat, 1));
  /* De stapel loopt over de hele breedte, maar alleen de knoppen zelf vangen
     een klik. Anders ligt er een onzichtbare balk over het scherm en komt een
     tik op het beeld (waarmee je geluid vrijgeeft) nergens aan. */
  pointer-events: none;
}
.pt-tv__knoppen > * { pointer-events: auto; }

/* In de stapel bepaalt de stapel de plek, niet de knop zelf. Zo kan geen
   enkele knop meer over een andere heen vallen. */
.pt-tv__knoppen .pt-tv__geluid {
  position: static;
  transform: none;
  max-width: 100%;
  text-align: center;
}

/* ------------------------------------------- instellingen van dit scherm

   Een tandwiel in de hoek met wat dit ene scherm zelf doet: geluid aanzetten,
   meebewegen op de maat, en voor de DJ ook welk scherm de speler is. Ze
   stonden eerder los over het beeld, en dan vallen ze bij elkaar over elkaar
   heen. Hier staan ze onder elkaar in een kaartje dat alleen opengaat als je
   erom vraagt, zodat de zaal naar de muziek kijkt en niet naar knoppen.
   Onderin rechts, want daar zit je duim op een telefoon en een iPad. */
/* Het kaartje zelf zweeft linksboven, net onder de kop. De knop staat in de
   kop zelf (zie hieronder), zodat daar niets voor hoeft op te schuiven. */
.pt-tvopties {
  position: fixed;
  left: calc(clamp(10px, 1.2vw, 22px) * var(--maat, 1));
  top: calc(clamp(56px, 8vh, 96px) * var(--maat, 1));
  padding-left: env(safe-area-inset-left);
  z-index: 60;
}

.pt-tvopties__lijst {
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 10px;
  border-radius: 14px;
  border: 1px solid var(--line-strong);
  background: rgba(12, 14, 16, .94);
  box-shadow: 0 12px 40px rgba(0, 0, 0, .55);
  min-width: min(74vw, 260px);
  /* Nooit tegen de rand van het scherm aan, en nooit breder dan een kolom die
     prettig leest: een regel met een stukje uitleg erin trok het kaartje
     anders over het halve scherm. */
  max-width: min(calc(100vw - 24px), 420px);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
}

.pt-tvopties__kop {
  font-size: .68rem;
  font-weight: 800;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--text-faint);
  padding: 2px 6px 4px;
}

/* Een regel in het kaartje: naam en uitleg links, een schakelaar rechts.
   Dezelfde schakelaar als in de console, zodat het een familie blijft. */
.pt-tvoptie {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  width: 100%;
  min-height: 52px;
  padding: 10px 12px;
  border-radius: 12px;
  border: 1px solid transparent;
  background: none;
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.pt-tvoptie + .pt-tvoptie { border-top: 1px solid var(--line); border-radius: 12px; }
.pt-tvoptie:hover:not(:disabled),
.pt-tvoptie:focus-visible { background: var(--surface-2); }
.pt-tvoptie:disabled { opacity: .55; cursor: default; }

.pt-tvoptie__tekst { min-width: 0; }
.pt-tvoptie__naam { display: block; font-size: .95rem; font-weight: 650; }
.pt-tvoptie__hint {
  display: block;
  margin-top: 2px;
  font-size: .78rem;
  font-weight: 400;
  line-height: 1.35;
  color: var(--text-faint);
}

/* De schakelaar zelf: dezelfde vorm als .pt-switch, maar gestuurd door
   aria-pressed in plaats van een verborgen vinkje. */
.pt-tvoptie .pt-switch__track { transition: background-color .18s ease, border-color .18s ease; }
.pt-tvoptie[aria-pressed="true"] .pt-switch__track {
  background: rgba(30, 215, 96, .28);
  border-color: var(--brand);
}
.pt-tvoptie[aria-pressed="true"] .pt-switch__track::after {
  transform: translateX(18px);
  background: var(--brand);
}

/* Het startvlak op een aanraakscherm, in twee stappen.

   Stap een gaat over ons eigen scherm: de geluidsmotor van de browser en de
   speler van Spotify. Dat vlak ligt over het hele scherm, want op een iPad
   stond je anders te zoeken naar welk van de knopjes je nu moest hebben, en
   het vangt de tik zelf op zodat er geen twijfel over is waar hij heen gaat.

   Stap twee hieronder gaat over het venster van YouTube, en dat hoort bij
   youtube.com. Een tik ernaast telt daar niet mee en een tik erin komt
   omgekeerd nooit bij ons aan, dus die twee zijn niet samen te voegen. Wat we
   wel doen is ze meteen achter elkaar vragen. */
.pt-tvstart {
  position: fixed;
  inset: 0;
  z-index: 70;
  display: grid;
  place-items: center;
  padding: 24px;
  border: 0;
  background: rgba(8, 10, 14, .88);
  color: var(--text);
  font: inherit;
  text-align: center;
  -webkit-tap-highlight-color: transparent;
}
.pt-tvstart__kaart {
  display: grid;
  justify-items: center;
  gap: calc(14px * var(--maat, 1));
  max-width: 22em;
}
/* De ring ademt, zodat je hem in een donkere zaal ziet staan. */
.pt-tvstart__ring {
  display: grid;
  place-items: center;
  width: calc(clamp(72px, 14vh, 140px) * var(--maat, 1));
  height: calc(clamp(72px, 14vh, 140px) * var(--maat, 1));
  border-radius: 50%;
  border: 2px solid rgba(29, 185, 84, .7);
  background: rgba(29, 185, 84, .16);
  animation: pt-tvstart-adem 2.6s ease-in-out infinite;
}
.pt-tvstart__ring svg {
  width: 45%;
  height: 45%;
  color: var(--brand);
}
@keyframes pt-tvstart-adem {
  0%, 100% { box-shadow: 0 0 0 0 rgba(29, 185, 84, .35); }
  50%      { box-shadow: 0 0 0 calc(18px * var(--maat, 1)) rgba(29, 185, 84, 0); }
}
.pt-tvstart__kop {
  font-family: var(--font-kop);
  font-weight: 700;
  font-size: calc(clamp(1.3rem, 3.4vh, 2.4rem) * var(--maat, 1));
  line-height: 1.15;
}
.pt-tvstart__uit {
  color: var(--text-muted);
  font-size: calc(clamp(.9rem, 1.9vh, 1.2rem) * var(--maat, 1));
  line-height: 1.4;
}
/* Nog aan het klaarzetten: wel in beeld, maar tikken doet nog niets. */
.pt-tvstart.is-wacht .pt-tvstart__ring { animation: none; opacity: .5; }

/* Stap twee: de tik moet juist naar het venster van YouTube.

   Daarom vangt dit vlak zelf geen vinger meer en blijft het beeld vrij. Je
   moet kunnen zien waar je tikt, dus geen sluier over de clip; alleen een
   kaartje onderin dat zegt wat er nog moet gebeuren. */
.pt-tvstart--video {
  background: none;
  place-items: end center;
  padding-bottom: calc(clamp(24px, 6vh, 72px) * var(--maat, 1));
  pointer-events: none;
}
.pt-tvstart--video .pt-tvstart__kaart {
  max-width: 26em;
  gap: calc(10px * var(--maat, 1));
  padding: calc(16px * var(--maat, 1)) calc(26px * var(--maat, 1));
  border: 1px solid rgba(29, 185, 84, .55);
  border-radius: var(--r-lg);
  background: rgba(8, 10, 14, .92);
  box-shadow: 0 10px 40px rgba(0, 0, 0, .6);
}
.pt-tvstart--video .pt-tvstart__ring {
  width: calc(clamp(44px, 7vh, 72px) * var(--maat, 1));
  height: calc(clamp(44px, 7vh, 72px) * var(--maat, 1));
}
.pt-tvstart--video .pt-tvstart__kop {
  font-size: calc(clamp(1.1rem, 2.4vh, 1.6rem) * var(--maat, 1));
}
@media (prefers-reduced-motion: reduce) {
  .pt-tvstart__ring { animation: none; }
}

/* De knop om geluid op de tv aan te zetten: groot genoeg om met een muis of
   afstandsbediening te raken, en weg zodra erop geklikt is. */
.pt-tv__geluid {
  position: fixed;
  left: 50%;
  bottom: calc(clamp(60px, 10vh, 120px) * var(--maat, 1));
  transform: translateX(-50%);
  z-index: 50;
  padding: 14px 26px;
  border-radius: 999px;
  border: 1px solid rgba(29, 185, 84, .6);
  background: rgba(29, 185, 84, .18);
  color: var(--text);
  font: inherit;
  font-size: calc(clamp(1rem, 1.6vw, 1.5rem) * var(--maat, 1));
  font-weight: 700;
  cursor: pointer;
  box-shadow: 0 8px 30px rgba(0, 0, 0, .5);
  /* De tekening en het tekstje naast elkaar op een regel. Hier stond een
     sprekertje als emoji in de tekst; dat kwam uit een andere hand dan de
     rest van het scherm. */
  display: inline-flex;
  align-items: center;
  gap: .5em;
}
/* De tekening schaalt mee met de letter van de knop, en die schaalt al mee
   met de tv. Een vaste maat in pixels zou op een groot scherm een speldje
   worden. */
.pt-tv__geluid svg { width: 1.15em; height: 1.15em; flex: 0 0 auto; }

/* Het blok kan vanzelf beginnen; deze knop is alleen nog een vangnet voor een
   browser die geen geluid toelaat. Klein in de hoek tot hij echt nodig is. */
.pt-tv__geluid--klein {
  left: auto;
  right: calc(clamp(16px, 2vw, 32px) * var(--maat, 1));
  bottom: calc(clamp(16px, 2.5vh, 32px) * var(--maat, 1));
  transform: none;
  padding: 7px 14px;
  font-size: calc(clamp(.8rem, .9vw, 1rem) * var(--maat, 1));
  font-weight: 600;
  opacity: .7;
  box-shadow: none;
}
.pt-tv__geluid--klein:hover, .pt-tv__geluid--klein:focus-visible { opacity: 1; }
/* De andere hoek, zodat twee kleine knoppen elkaar niet in de weg zitten. */
.pt-tv__geluid--links { right: auto; left: calc(clamp(16px, 2vw, 32px) * var(--maat, 1)); }
/* Zolang er nog niet op geklikt is, ademt hij rustig: anders zie je hem niet
   staan in een donkere zaal. Na de klik is hij weg. */
.pt-tv__geluid--wenkt { animation: pt-wenk 2.6s ease-in-out infinite; }
@keyframes pt-wenk {
  0%, 100% { opacity: .55; }
  50%      { opacity: 1; box-shadow: 0 0 0 4px rgba(29, 185, 84, .18); }
}
@media (prefers-reduced-motion: reduce) { .pt-tv__geluid--wenkt { animation: none; opacity: .9; } }

/* Bronvermelding bij Spotify-content: waar titels, artiesten en hoezen staan,
   hoort te staan waar ze vandaan komen. Ingetogen, maar wel leesbaar en
   aanklikbaar. Het merkteken houdt zijn eigen kleur. */
.pt-bron {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-top: var(--s-2);
  margin-right: var(--s-3);
  color: var(--text-muted);
  font-size: .75rem;
  text-decoration: none;
}

.pt-bron:hover { color: var(--text); }
.pt-bron__merk { flex: 0 0 auto; }

/* De weg terug naar het nummer op Spotify, bij wat er nu draait. */
.pt-now__spotify {
  display: inline-block;
  margin-top: 4px;
  color: var(--brand);
  font-size: .78rem;
  text-decoration: none;
}

.pt-now__spotify:hover { text-decoration: underline; }

/*
 * Twee merken naast elkaar, zonder tekst.
 *
 * Alleen in een party waar alles door elkaar staat: daar zijn het er twee en
 * werden het anders twee regels. Het teken is 21 pixels, de kleinste maat die
 * Spotify voor zijn eigen teken noemt.
 */
.pt-bronnen-rij { display: inline-flex; align-items: center; gap: var(--s-3); flex-wrap: wrap; width: fit-content; max-width: 100%; align-self: flex-start; }
.pt-bron--kaal { gap: 0; margin-right: 0; }
/* Het regeltje bij de twee tekens: "Muziek via [teken] Spotify en [teken] YouTube". */
.pt-bronnen-rij { gap: var(--s-2); }
.pt-bron--lead { margin-right: 0; cursor: default; }
.pt-bron__naam { margin-left: 6px; }
.pt-bron--kaal .pt-bron__merk { width: 21px; height: 21px; }

/* Op de tv leest niemand kleine letters, maar hij moet er wel staan. */
.pt-bron--tv {
  margin-top: clamp(6px, 1vh, 12px);
  font-size: clamp(.7rem, .85vw, .95rem);
}

.pt-bron--tv .pt-bron__merk { width: 16px; height: 16px; }

/*
 * In de kop blijven ze klein.
 *
 * Spotify en YouTube willen allebei genoemd worden bij de muziek die van hen
 * komt, dus in een party waar alles door elkaar staat zijn het er twee. Samen
 * kostten ze bijna de helft van het kaartje met de code, en die hoogte gaat
 * liever naar het beeld en de plaat. Ze staan er dus wel, maar bescheiden.
 */
/* Op de tv onder elkaar: naast elkaar maakt het kaartje met de code breed,
   en die breedte gaat ten koste van het beeld ernaast. Twee kale merktekens
   passen wel naast elkaar, die zijn maar een paar pixels breed. */
.pt-tv__join .pt-bron--tv { display: flex; margin-top: 4px; margin-right: 0; font-size: clamp(.6rem, .68vw, .78rem); }
.pt-tv__join .pt-bron--kaal { display: inline-flex; }
.pt-tv__join .pt-bron--tv .pt-bron__merk { width: 14px; height: 14px; }
/* Zonder tekst blijft alleen het merkteken over, en dat mag van Spotify niet
   kleiner dan 21 pixels. Ook niet op een smal scherm, dus deze regel staat
   expres scherper dan de maten verderop. */
.pt-tv__join .pt-bron--tv.pt-bron--kaal .pt-bron__merk { width: 21px; height: 21px; }

/* De melding dat een party op slot staat. Amber en niet rood: er is niets
   stuk, er moet alleen iets geregeld worden.

   Niet pt-slot noemen: die naam is al van de vakjes op de quiztijdlijn, en
   dat vocht om dezelfde regels. */
.pt-vergrendeld {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  flex-wrap: wrap;
  margin-bottom: var(--s-4);
  padding: var(--s-4);
  border-radius: var(--r-lg);
  border: 1px solid rgba(255, 203, 71, .45);
  background: rgba(255, 203, 71, .10);
}

.pt-vergrendeld > div { flex: 1 1 260px; min-width: 0; }

.pt-vergrendeld__kop { color: var(--amber); }

/* De vraag die bij het antwoord in beeld blijft. Bewust bescheiden: het
   antwoord is de kop, de vraag geeft er alleen de context bij. Hij mag ook
   nooit meer dan twee regels worden, want op de tv gaat elke extra regel af
   van de ruimte voor de wachtrij. */
.pt-vraagterug {
  margin-bottom: var(--s-2);
  color: var(--text-muted);
  font-size: .9rem;
  line-height: 1.35;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Op de telefoon staat het kruisje om de kaart weg te klikken rechtsboven;
   een lange vraag mag daar niet onderdoor lopen. */
.pt-hitster-dok .pt-vraagterug { padding-right: 34px; }

.pt-tv .pt-vraagterug {
  margin-bottom: calc(clamp(4px, .8vh, 10px) * var(--maat, 1));
  font-size: calc(clamp(.9rem, 1.4vw, 1.5rem) * var(--maat, 1));
}

/* Weetje bij het nummer, onder de titel op de tv. */
.pt-weetje {
  margin-top: clamp(10px, 1.6vh, 20px);
  padding: clamp(8px, 1.2vh, 14px) clamp(10px, 1.2vw, 18px);
  border-left: 3px solid var(--brand);
  background: rgba(255, 255, 255, .04);
  border-radius: 0 var(--r-md) var(--r-md) 0;
  font-size: clamp(.85rem, 1.25vw, 1.15rem);
  line-height: 1.4;
  color: var(--text);
  /* Hoeveel regels erin passen rekent tv.js uit; drie was een gok en liep bij
     een lange titel onder de onderrand door. Dit is de terugval voor het geval
     javascript er nog niet aan toe is. */
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.pt-weetje__kop {
  display: block;
  font-size: .72em;
  font-weight: 800;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--brand);
  margin-bottom: 2px;
}

.pt-weetje__bron {
  font-size: .78em;
  color: var(--text-muted);
  margin-left: .5em;
}

/* De lichtkrant onderaan de tv. Twee keer dezelfde inhoud achter elkaar,
   zodat het schuiven naadloos rond kan lopen. */
.pt-ticker {
  overflow: hidden;
  /* Buiten de rand van de tv om: een lichtkrant hoort van hoek tot hoek te
     lopen, niet als een regeltje binnen de marge te blijven staan. */
  margin: 0 calc(-1 * var(--tv-rand)) calc(-1 * var(--tv-rand-y));
  padding: clamp(8px, 1.2vh, 16px) 0;
  border-top: 1px solid var(--line);
  background: rgba(0, 0, 0, .38);
  mask-image: linear-gradient(to right, transparent, #000 3%, #000 97%, transparent);
  -webkit-mask-image: linear-gradient(to right, transparent, #000 3%, #000 97%, transparent);
}

.pt-ticker__spoor {
  display: flex;
  white-space: nowrap;
  /* Zo breed als de inhoud, niet als het scherm: de animatie schuift -50%,
     en dat moet precies een van de twee blokken zijn. Anders sluit de
     herhaling niet aan en verspringt de regel. */
  width: max-content;
  will-change: transform;
  /* Duur staat hier expliciet: de verkorte schrijfwijze zet hem anders op 0s,
     en dan is een ronde meteen 'voorbij' voordat javascript de echte duur
     heeft berekend. De tv zet hem daarna op maat. */
  animation: pt-ticker-loop 40s linear infinite;
}

.pt-ticker__blok { display: flex; flex: 0 0 auto; }

/* Lege ruimte achter de reeks, zodat de balk gevuld blijft zonder dat een
   bericht twee keer in beeld staat. */
.pt-ticker__ruimte { flex: 0 0 auto; }

.pt-ticker__item {
  display: inline-flex;
  align-items: baseline;
  gap: .5em;
  padding: 0 clamp(18px, 2.4vw, 40px);
  font-size: clamp(1rem, 1.7vw, 1.7rem);
  line-height: 1.3;
}

.pt-ticker__naam { color: var(--brand); font-weight: 800; }
.pt-ticker__tekst { color: var(--text); }

/* Een draaiend plaatje tussen twee berichten, in plaats van een streepje.
   Alles met verlopen: dat is een element per scheiding in plaats van vijf,
   en er staan er zomaar tachtig in de balk.

   De glans is een kegelverloop en dus niet rondsymmetrisch; zonder dat zou
   je van het draaien niets zien. */
.pt-ticker__plaat {
  flex: 0 0 auto;
  align-self: center;
  width: clamp(16px, 1.5vw, 26px);
  height: clamp(16px, 1.5vw, 26px);
  border-radius: 50%;
  background:
    radial-gradient(circle, var(--brand) 0 16%, transparent 17%),
    conic-gradient(from 0deg,
      rgba(255,255,255,.18) 0 9%,
      transparent 9% 46%,
      rgba(255,255,255,.11) 46% 55%,
      transparent 55%),
    repeating-radial-gradient(circle, #2c2f32 0 2px, #16181a 2px 4px);
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .09);
  animation: pt-spin 2.6s linear infinite;
}

@media (prefers-reduced-motion: reduce) {
  .pt-ticker__plaat { animation: none; }
}

@keyframes pt-ticker-loop {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

@media (prefers-reduced-motion: reduce) {
  .pt-ticker__spoor { animation: none; }
}

/* Berichtje sturen, bij de gast. */
.pt-zeg { display: flex; flex-direction: column; gap: var(--s-2); }
.pt-zeg .pt-input { min-width: 0; }
.pt-zeg__veld { resize: vertical; min-height: 84px; line-height: 1.4; font-size: 1.05rem; }
#zeg-teller.is-vol { color: var(--amber); }

/* Berichtenbeheer in de console. */
.pt-bericht {
  display: flex; align-items: flex-start; gap: var(--s-2);
  padding: var(--s-2) 0;
  border-bottom: 1px solid var(--line);
}
.pt-bericht--weg { opacity: .45; }

/*
   Een kaping die op goedkeuring wacht.

   Op een breed scherm staat de tekst links en staan 'Op de tv' en 'Weigeren'
   ernaast. Op een telefoon is daar geen ruimte voor: de twee knoppen gingen
   boven elkaar staan en knepen de boodschap in een kolom van vier regels,
   terwijl je juist die boodschap moet lezen voordat je hem goedkeurt. Daar
   krijgt de tekst de hele breedte en staan de knoppen eronder.
*/
/* Ook op een breed scherm: de tekst krimpt mee en de twee knoppen blijven
   naast elkaar. Zonder dit nam de boodschap zijn hele lengte als uitgangspunt
   en viel 'Weigeren' onder 'Op de tv'. */
.pt-kaping-keur > span:first-child { flex: 1 1 auto; min-width: 0; }
.pt-kaping-keur > .pt-btnrow { flex: 0 0 auto; flex-wrap: nowrap; }

@media (max-width: 599px) {
  .pt-kaping-keur { flex-wrap: wrap; }
  .pt-kaping-keur > span:first-child { flex: 1 1 100%; }
  .pt-kaping-keur > .pt-btnrow { flex: 1 1 100%; }
  .pt-kaping-keur > .pt-btnrow > .pt-btn { flex: 1 1 8em; }
}
.pt-bericht__wie { font-weight: 700; font-size: .85rem; }
.pt-bericht__tekst { font-size: .9rem; overflow-wrap: anywhere; }

/* Tussenstand tussen twee sets: podium plus de superkracht. */
.pt-tussen { text-align: center; }

.pt-tussen__kop {
  display: flex; align-items: center; justify-content: center; gap: .5em;
  font-size: 1.15rem; font-weight: 800; letter-spacing: -.02em;
}
.pt-tussen__trofee { font-size: 1.4em; }

.pt-tussen__podium {
  display: flex; justify-content: center; align-items: flex-end;
  gap: clamp(10px, 3vw, 28px);
  margin-top: var(--s-4);
}

.pt-tussen__speler { display: flex; flex-direction: column; align-items: center; gap: 4px; min-width: 0; }
.pt-tussen__plek { font-size: 1.5em; line-height: 1; }
.pt-tussen__avatar { width: 54px; height: 54px; }
.pt-tussen__naam {
  font-weight: 700; font-size: .95rem; max-width: 8em;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.pt-tussen__score { font-size: .8rem; color: var(--text-muted); }

.pt-tussen__kracht {
  display: inline-flex; align-items: center; gap: .55em;
  margin-top: var(--s-4);
  padding: .5em .95em;
  border-radius: 999px;
  background: rgba(255, 203, 71, .12);
  border: 1px solid rgba(255, 203, 71, .4);
  color: #ffe6a8;
  font-weight: 700;
}
.pt-tussen__bliksem { font-size: 1.2em; }
.pt-tussen__kracht-avatar { width: 26px; height: 26px; }

.pt-tussen__voet { margin-top: var(--s-4); font-size: .85rem; color: var(--text-muted); }

.pt-tussen__balk {
  height: 4px; border-radius: 999px; overflow: hidden;
  background: var(--surface-2); margin-top: 6px;
}
.pt-tussen__balk-vul {
  height: 100%; width: 100%; background: var(--brand);
  animation-name: pt-tussen-krimp;
  animation-timing-function: linear;
  animation-fill-mode: forwards;
}
@keyframes pt-tussen-krimp { from { width: 100%; } to { width: 0%; } }

/* Op tv mag het allemaal wat groter. */
.pt-tussen--groot .pt-tussen__kop { font-size: clamp(1.4rem, 2.6vw, 2.4rem); }
.pt-tussen--groot .pt-tussen__avatar { width: clamp(64px, 7vw, 108px); height: clamp(64px, 7vw, 108px); }
.pt-tussen--groot .pt-tussen__naam { font-size: clamp(1rem, 1.6vw, 1.5rem); max-width: 10em; }
.pt-tussen--groot .pt-tussen__score { font-size: clamp(.85rem, 1.2vw, 1.15rem); }
.pt-tussen--groot .pt-tussen__kracht { font-size: clamp(1rem, 1.6vw, 1.5rem); }
.pt-tussen--groot .pt-tussen__kracht-avatar { width: clamp(30px, 2.6vw, 44px); height: clamp(30px, 2.6vw, 44px); }
.pt-tussen--groot .pt-tussen__voet { font-size: clamp(.9rem, 1.3vw, 1.2rem); }

@media (prefers-reduced-motion: reduce) {
  .pt-tussen__balk-vul { animation: none; width: 100%; }
}

/* Aftelklok bij een stilgevallen party. */
.pt-idle {
  margin-top: .9em;
  padding: .55em .9em;
  border-radius: var(--r-md);
  background: rgba(255, 203, 71, .1);
  border: 1px solid rgba(255, 203, 71, .4);
  color: #ffe6a8;
  font-size: .95em;
  font-weight: 600;
  line-height: 1.35;
  max-width: 34em;
  margin-left: auto;
  margin-right: auto;
}

/* Blijft er nauwelijks hoogte over, dan liever smalle regels dan geen
   regels: hoes kleiner, artiest weg, minder lucht eromheen. */
.pt-tv__list--compact .pt-tv__item {
  grid-template-columns: auto calc(clamp(28px, 2.2vw, 38px) * var(--maat, 1)) minmax(0, 1fr) auto;
  gap: calc(clamp(6px, .8vw, 12px) * var(--maat, 1));
  padding: calc(clamp(3px, .4vh, 6px) * var(--maat, 1)) 0;
  font-size: calc(clamp(.85rem, 1.2vw, 1.15rem) * var(--maat, 1));
}
.pt-tv__list--compact .pt-tv__a { display: none; }

/* Staat er een samenvattingsregel, dan mag die niet zelf wegvagen. */
.pt-tv__list--meer {
  -webkit-mask-image: none;
  mask-image: none;
}

.pt-tv__meer {
  list-style: none;
  padding: calc(clamp(6px, .8vh, 10px) * var(--maat, 1)) 0 0;
  font-size: calc(clamp(.9rem, 1.3vw, 1.15rem) * var(--maat, 1));
  font-weight: 600;
  color: var(--text-muted);
}

.pt-tv__side { display: flex; flex-direction: column; min-height: 0; overflow: hidden; }
.pt-tv__side > h2 { flex: 0 0 auto; }
/* De vraagkaart mag krimpen als het moet; wat niet past wordt afgesneden en
   dat is op een tv niet terug te scrollen. De wachtlijst erboven geeft eerst
   ruimte op, daarna pas deze. */
#tv-hitster { flex: 0 1 auto; min-height: 0; overflow: hidden; }

.pt-tv__item {
  display: grid;
  grid-template-columns: auto calc(clamp(48px, 4vw, 68px) * var(--maat, 1)) minmax(0, 1fr) auto;
  align-items: center;
  gap: calc(clamp(10px, 1.2vw, 20px) * var(--maat, 1));
  padding: calc(clamp(8px, 1vh, 14px) * var(--maat, 1)) 0;
  border-bottom: 1px solid var(--line);
  font-size: calc(clamp(1rem, 1.6vw, 1.5rem) * var(--maat, 1));
}

.pt-tv__item img { width: 100%; aspect-ratio: 1; border-radius: 10px; object-fit: cover; background: var(--surface-2); }
.pt-tv__item .pt-tv__t { font-weight: 700; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pt-tv__item .pt-tv__a { color: var(--text-muted); font-size: .78em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* Het merkteken van de bron voor de artiestnaam, in een party waar alles door
   elkaar staat. Alleen het logo: op een tv is er geen plek voor tekst erbij,
   en de kleur zegt het al. */
.pt-tv__bron {
  display: inline-block;
  width: 1.05em;
  height: 1.05em;
  margin-right: .45em;
  vertical-align: -.17em;
}
.pt-tv__bron svg { width: 100%; height: 100%; display: block; }
.pt-tv__votes { font-weight: 800; font-variant-numeric: tabular-nums; color: var(--brand); }

.pt-tv__rank {
  display: grid; place-items: center;
  width: calc(clamp(30px, 2.6vw, 44px) * var(--maat, 1)); height: calc(clamp(30px, 2.6vw, 44px) * var(--maat, 1));
  border-radius: 50%;
  background: var(--surface-2);
  font-size: .72em; font-weight: 800; color: var(--text-muted);
}

.pt-tv__rank--1 { background: var(--amber); color: #2a1d00; }

/* Aan de deur: de rest van de pagina blijft dicht tot de DJ je binnenlaat. */
body.pt-buiten .pt-tab,
body.pt-buiten .pt-tabbar,
body.pt-buiten #hitster,
body.pt-buiten .pt-krachtbel { display: none !important; }

.pt-deur__wacht {
  display: inline-block;
  width: 14px; height: 14px;
  border: 2px solid var(--brand);
  border-right-color: transparent;
  border-radius: 50%;
  vertical-align: -2px;
  margin-right: 6px;
  animation: pt-spin-disc 1s linear infinite;
}

/*
   De plaat als cover boven een kaartje.

   Hier stonden eerst de regels voor de foto's en daarna voor lijntekeningen.
   De reden dat ze allebei weg zijn staat bij View::plaat.

   Let op de oude fout die hier zat: .pt-beeld bestaat al ergens anders in dit
   bestand, voor de plaatjesbibliotheek in de console en in beheer. Dat is een
   rijtje met een duimnagel van 54 pixels. De fotoregels stonden lager en wonnen
   dus, waardoor die duimnagels volle grijze banners werden. Vandaar een eigen
   naam voor dit blok.

   De plaat is breder dan het kader hoog is, dus hij loopt boven en onder door.
   Dat is met opzet. Een plaat die netjes binnen het kader past leest als een
   plaatje van een plaat; een plaat die er niet in past leest als een plaat die
   er ligt.
*/
.pt-plaatcover {
  margin: var(--s-5) 0 0;
  position: relative;
  overflow: hidden;
  border-radius: var(--r-lg);
  border: 1px solid var(--line);
  /* Drie bij twee en niet zestien bij negen. De plaat moet er helemaal in
     passen, en in een breed kader past alleen een kleine plaat. Hier is er
     boven en onder nog een marge van een procent of vijf. */
  aspect-ratio: 3 / 2;
  background:
    radial-gradient(80% 110% at 50% 6%, rgba(30, 215, 96, .13), rgba(30, 215, 96, 0) 64%),
    linear-gradient(180deg, var(--surface-2), var(--surface));
}

/* In het midden. De arm steekt naar rechts uit en vraagt er dus om de plaat
   naar links te schuiven, zoals op de voorpagina gebeurt, maar in een kaartje
   ziet dat er scheef uit en niet gewogen. De arm mag over het midden heen. */
.pt-plaatcover__plaat {
  position: absolute;
  /* Boven het waaslaagje hieronder, anders ligt dat over de plaat heen. */
  z-index: 1;
  left: 50%;
  top: 50%;
  /* Zesenvijftig procent van de breedte is op een kaartje van drie bij twee
     net iets minder dan de hoogte, dus de plaat raakt de rand niet. */
  width: 56%;
  transform: translate(-50%, -50%);
}

/* Iets groter dan bij een echte single, maar niet veel. Het is hier een foto
   en geen titel, dus hij mag te zien zijn; op de helft van de plaat werd het
   een foto met een rand eromheen in plaats van een plaat met een label. */
.pt-plaatcover .pt-vinyl__label { width: 42%; height: 42%; }

/* Het waas achter de plaat, nog een keer maar sterker, op doorzichtig nul.
   Bij hover gaat het aan. Een tweede laagje en niet het verloop zelf, want
   een verloop rekent een browser niet door en dat zou omklappen in plaats van
   opkomen. */
.pt-plaatcover::before {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(80% 110% at 50% 6%, rgba(30, 215, 96, .30), rgba(30, 215, 96, 0) 64%);
  opacity: 0;
  transition: opacity .25s ease;
  pointer-events: none;
}

/* De arm ligt hier platter dan op de voorpagina. Die plaat staat helemaal in
   beeld, deze loopt boven en onder door het kader, en met de hoek van de
   voorpagina steekt de kop van de arm er bovenuit. Op dertig graden ligt de
   naald in de groef net buiten het label en past de hele arm in het kader. */
.pt-plaatcover .pt-vinyl__arm { --arm-angle: 30deg; }

/*
   De plaat staat stil en gaat pas draaien als je hem aanwijst.

   Drie kaartjes die uit zichzelf staan rond te tollen trekken de aandacht
   weg van waar het over gaat, en de plaat bovenaan de voorpagina draait al.
   Zo staat er een stilstaande plaat op het kaartje, en zodra je erover gaat
   begint hij te lopen. Dat is meteen het antwoord op de vraag of je met dat
   kaartje iets kunt.

   Met animation-play-state en niet door de animatie aan en uit te zetten: zo
   blijft hij staan waar hij was toen je wegging en loopt hij daarvandaan
   verder, in plaats van terug te springen naar het begin.

   Rustiger dan de plaat op de voorpagina, maar wel sneller dan hij eerst
   stond: je moet kunnen zien dat hij op je muis reageert.

   De tweede regel is voor de plaat op een pagina zonder kaartjes, zoals op
   bruiloft.php. Daar is de plaat zelf wat je aanwijst.
*/
.pt-plaatcover .pt-vinyl__disc {
  animation-duration: 6s;
  animation-play-state: paused;
}
@media (hover: hover) {
  .pt-home__kaart:hover .pt-plaatcover .pt-vinyl__disc,
  .pt-plaatcover:hover .pt-vinyl__disc { animation-play-state: running; }
}

/* Een plaat die niet in een kaartje staat: over de volle leesbreedte van 720
   wordt het een poster waar je langs moet scrollen voordat je verder leest. */
.pt-plaatcover--hero { max-width: 520px; margin-left: auto; margin-right: auto; }

/* In een kaart: tot de rand, want een kader binnen een kader met een randje
   ertussen ziet er slordig uit. */
.pt-home__kaart .pt-plaatcover {
  grid-column: 1 / -1;
  grid-row: 1;
  margin: calc(var(--s-4) * -1) calc(var(--s-4) * -1) var(--s-2);
  border: 0;
  border-bottom: 1px solid var(--line);
  border-radius: var(--r-lg) var(--r-lg) 0 0;
}
.pt-home__kaart:has(.pt-plaatcover) strong { grid-row: 2; grid-column: 1 / -1; }
.pt-home__kaart:has(.pt-plaatcover) > span:last-child { grid-row: 3; }

/* ======================= Draaitafel ======================= */

/* De plaat op de voorpagina: het beeldmerk als label, draait vanzelf. Iets
   naar links, zodat de arm die rechts uitsteekt het geheel niet scheef trekt. */
.pt-home-plaat {
  width: min(58vw, 230px);
  margin: var(--s-5) auto 0;
  transform: translateX(-6%);
}
/* Het label mag hier wat groter: het is het beeldmerk, niet een hoes. */
.pt-home-plaat .pt-vinyl__label { width: 46%; height: 46%; }

/* De plaat zelf is geen knop: de knop ligt erop. */
.pt-plaat { position: relative; }

/*
   Het luidsprekertje op het label.

   Dit is het hele raakvlak voor de jingle. Vroeger was de plaat de knop en
   begon het geluid ook vanzelf, en daar schrok iedereen van. Nu moet je dit
   sprekertje aanraken en niets anders.

   Eronder een zacht waas in plaats van een dichte schijf. Een dichte cirkel
   dekt het beeldmerk af en dan kijk je naar een knop met een plaat eromheen,
   in plaats van naar je plaat. Dit loopt naar de rand weg, dus het teken
   blijft leesbaar en het embleem blijft het embleem.

   Het staat bewust naast de draaiende plaat in plaats van erin, want alles
   binnen de plaat draait mee en een rondtollend sprekertje is onleesbaar.
*/
.pt-plaatknop {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);
  width: 34%;
  aspect-ratio: 1 / 1;
  padding: 0;
  border: 0;
  border-radius: 50%;
  display: grid;
  place-items: center;
  cursor: pointer;
  background: radial-gradient(circle,
    rgba(0, 0, 0, .58) 0%,
    rgba(0, 0, 0, .46) 42%,
    rgba(0, 0, 0, 0) 72%);
  color: #fff;
  transition: transform .15s ease-out;
}
.pt-plaatknop:hover { transform: translate(-50%, -50%) scale(1.06); }
.pt-plaatknop:active { transform: translate(-50%, -50%) scale(.97); }
.pt-plaatknop:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 3px;
}

.pt-plaatknop svg {
  width: 48%;
  height: 48%;
  fill: currentColor;
  filter: drop-shadow(0 1px 3px rgba(0, 0, 0, .7));
}

/*
   Het teken zegt wat de klik doet, niet wat er aan staat.

   Stil staat er een sprekertje met golfjes: klik en je hoort het. Loopt de
   jingle, dan staat er een streep door het sprekertje: klik en het is weer
   stil. Andersom werkt niet, want een kruisje op een pagina waar toch niets
   te horen is leest als kapot en nodigt nergens toe uit.
*/
.pt-plaatknop__demp { display: none; }
.pt-plaatknop.is-speelt .pt-plaatknop__hoor { display: none; }
.pt-plaatknop.is-speelt .pt-plaatknop__demp { display: block; }

/* Het geluid zelf hoort nergens ruimte in te nemen. */
.pt-home-plaat audio { display: none; }

.pt-vinyl {
  position: relative;
  aspect-ratio: 1 / 1;
  background: none;
  box-shadow: none;
  border-radius: 50%;
}

/* De plaat zelf.
   Drie lagen over elkaar: de fijne groeven, een paar bredere scheidingen
   tussen de nummers, en een gladde rand aan de buitenkant met een gladde ring
   rond het label. Een enkele streeppatroon leest als stof; echt vinyl heeft
   juist die overgangen. */
.pt-vinyl__disc {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background:
    /* Gladde buitenrand en de vlakke ring rond het label. */
    radial-gradient(circle at 50% 50%,
      transparent 0 36%,
      rgba(0,0,0,.55) 36% 37.5%,
      transparent 37.5% 95%,
      rgba(255,255,255,.05) 95% 96%,
      transparent 96%),
    /* Bredere scheidingen: waar het ene nummer overgaat in het volgende. */
    repeating-radial-gradient(circle at 50% 50%,
      rgba(255,255,255,.05) 0 1px,
      transparent 1px 26px),
    /* De groeven zelf: fijn en met weinig contrast, anders wordt het corduroy. */
    repeating-radial-gradient(circle at 50% 50%,
      #101013 0 1px,
      #191920 1px 2.2px),
    #0b0b0d;
  box-shadow:
    0 16px 44px rgba(0, 0, 0, .55),
    /* Dikke rand: de zijkant van de plaat vangt licht. */
    inset 0 0 0 1px rgba(255, 255, 255, .10),
    inset 0 0 22px rgba(0, 0, 0, .8);
  animation: pt-spin-disc 3.4s linear infinite;
}

/* Glans over de plaat, staat stil terwijl de plaat draait.
   Twee tegenoverliggende vegen in plaats van een egale ring: zo ziet vinyl
   eruit onder een lamp, en je ziet er ook de draaiing beter door. */
.pt-vinyl::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  pointer-events: none;
  background:
    conic-gradient(from 200deg,
      rgba(255,255,255,.13), rgba(255,255,255,0) 14%,
      rgba(255,255,255,0) 36%, rgba(255,255,255,.07) 50%,
      rgba(255,255,255,0) 64%, rgba(255,255,255,0) 86%,
      rgba(255,255,255,.13)),
    /* Licht van linksboven op de bolling van de plaat. */
    radial-gradient(circle at 32% 26%, rgba(255,255,255,.07), transparent 55%);
}

.pt-vinyl[data-paused="true"] .pt-vinyl__disc { animation-play-state: paused; }

.pt-vinyl__label {
  position: absolute;
  left: 50%; top: 50%;
  width: 38%; height: 38%;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  object-fit: cover;
  background: var(--surface-3);
  box-shadow:
    0 0 0 1px rgba(0, 0, 0, .7),
    0 0 14px rgba(0, 0, 0, .5),
    /* Het papieren label ligt iets verzonken in het vinyl. */
    inset 0 0 10px rgba(0, 0, 0, .35);
}

.pt-vinyl__hole {
  position: absolute;
  left: 50%; top: 50%;
  width: 3.4%; height: 3.4%;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: var(--bg);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, .3),
    inset 0 2px 3px rgba(0, 0, 0, .9);
}

@keyframes pt-spin-disc { to { transform: rotate(360deg); } }

/* ------------------------------------------------------------- de toonarm

   Draaipunt rechtsboven buiten de plaat, naald op de groef. De arm bestaat
   uit een buis, een draaipunt met tegengewicht, een kop die schuin staat en
   een naald die de plaat raakt. */
.pt-vinyl__arm {
  position: absolute;
  /* Draaipunt rechts, ongeveer op de hoogte van het midden - zoals bij een
     echte pick-up. De naald staat daardoor tussen 1 en 3 uur op de plaat. */
  top: 44%;
  right: -14%;
  width: 48%;
  height: 2.4%;
  min-height: 5px;
  transform-origin: 96% center;
  /* Negatief kantelt de arm naar beneden, de plaat op. De hoek loopt mee met
     de voortgang: hoe verder in het nummer, hoe dichter bij het midden. */
  transform: rotate(var(--arm-angle, 42deg));
  transition: transform 1.1s linear;
  filter: drop-shadow(0 5px 9px rgba(0, 0, 0, .6));
}

/* De buis. Rond gepolijst metaal: fel randje bovenaan, donkere onderkant,
   en naar de kop toe iets smaller. */
.pt-vinyl__arm-bar {
  position: absolute;
  inset: 0;
  border-radius: 999px;
  background: linear-gradient(180deg,
    #f4f7fa 0%, #dfe5ea 16%, #b3bbc3 44%, #7c848c 74%, #4e555c 100%);
  box-shadow: inset 0 0 0 .5px rgba(255,255,255,.35);
}

.pt-vinyl__arm::before {           /* draaipunt met tegengewicht */
  content: '';
  position: absolute;
  right: -16%;
  top: 50%;
  width: 30%;
  aspect-ratio: 1;
  transform: translateY(-50%);
  border-radius: 50%;
  background:
    radial-gradient(circle at 34% 28%, #79828c 0 18%, #3a4046 62%, #1b1f23 100%);
  box-shadow:
    0 4px 12px rgba(0, 0, 0, .65),
    inset 0 0 0 1px rgba(255, 255, 255, .14),
    inset 0 -2px 4px rgba(0, 0, 0, .6);
}

/* Het ronde blokje op het draaipunt: de as waar de arm omheen draait. */
.pt-vinyl__arm::after {
  content: '';
  position: absolute;
  right: -2%;
  top: 50%;
  width: 11%;
  aspect-ratio: 1;
  transform: translateY(-50%);
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #cfd6dd, #6d757d 70%, #3b4147);
  box-shadow: 0 1px 3px rgba(0, 0, 0, .6);
}

/* De kop staat altijd schuin op de arm; dat is precies wat een pick-up
   herkenbaar maakt. Smal en langwerpig, niet vierkant: een blokje leest als
   een blokje en niet als een houder waar een element in zit. */
.pt-vinyl__arm-kop {
  position: absolute;
  /* Breedte telt van de armlengte, hoogte van de armdikte: vandaar de
     ogenschijnlijk vreemde verhouding. Uitgerekend wordt het een smal,
     langwerpig kopje. */
  left: -5%;
  top: 50%;
  width: 4.5%;
  height: 260%;
  transform: translateY(-34%) rotate(-22deg);
  transform-origin: 60% 20%;
  border-radius: 2px 2px 1px 1px;
  background: linear-gradient(150deg, #f4f7fa 0%, #cfd6dd 45%, #8b939b 100%);
  box-shadow: 0 2px 5px rgba(0, 0, 0, .5), inset 0 0 0 .5px rgba(255,255,255,.45);
}

/* Het element: het zwarte blokje onder de kop waar de naald in zit. Steekt
   bewust aan weerszijden een beetje uit, zoals een echte cartridge. */
.pt-vinyl__arm-element {
  position: absolute;
  left: -22%;
  bottom: -34%;
  width: 144%;
  height: 40%;
  border-radius: 1px;
  background: linear-gradient(180deg, #3a4046 0 38%, #191d21 100%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.22),
    0 2px 4px rgba(0, 0, 0, .6);
}

/* De naald: een haartje dat de groef raakt, met een lichtpuntje op het
   contact. Zonder dat puntje zweeft de arm boven de plaat. */
.pt-vinyl__arm-naald {
  position: absolute;
  left: 42%;
  bottom: -58%;
  width: 16%;
  min-width: 1px;
  height: 26%;
  background: linear-gradient(180deg, #eef2f6, #8d959d);
}

.pt-vinyl__arm-naald::after {
  content: '';
  position: absolute;
  left: 50%;
  bottom: -2px;
  width: 5px; height: 5px;
  margin-left: -2.5px;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(255,255,255,.55), rgba(255,255,255,0) 70%);
}

/* Op kleine formaten (DJ-console) laten we de arm weg. */
.pt-vinyl--small .pt-vinyl__arm { display: none; }
.pt-vinyl--small .pt-vinyl__label { width: 42%; height: 42%; }

/* Plaatwissel: de oude plaat schuift van de draaitafel, de nieuwe zakt erop. */
.pt-vinyl--out {
  animation: pt-vinyl-out .42s cubic-bezier(.4, 0, .8, .4) forwards;
  pointer-events: none;
}

.pt-vinyl--in {
  animation: pt-vinyl-in .62s cubic-bezier(.2, .8, .3, 1) both;
}

/* Tijdens de wissel vervaagt de arm even; de hoek zelf blijft van de
   voortgang, anders bleef hij na een trackwissel op één plek hangen. */
.pt-vinyl--out .pt-vinyl__arm { opacity: .35; transition: opacity .3s ease; }

@keyframes pt-vinyl-out {
  from { transform: translate(0, 0) scale(1) rotate(0); opacity: 1; }
  to   { transform: translate(16%, 16%) scale(.8) rotate(-9deg); opacity: 0; }
}

@keyframes pt-vinyl-in {
  from { transform: translate(-12%, -24%) scale(.85) rotate(7deg); opacity: 0; }
  60%  { opacity: 1; }
  to   { transform: translate(0, 0) scale(1) rotate(0); opacity: 1; }
}

/* De titel komt mee met de nieuwe plaat. */
.pt-fade-in { animation: pt-fade-in .5s ease .12s both; }

@keyframes pt-fade-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Het nummer dat als volgende klaarstaat, springt eruit. */
.pt-track--next {
  background: linear-gradient(90deg, rgba(30, 215, 96, .10), rgba(30, 215, 96, 0) 55%);
  box-shadow: inset 3px 0 0 var(--brand);
}

/* Stemknoppen die op slot zitten. */
.pt-vote--locked {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  color: var(--text-faint);
}

.pt-vote--locked svg { width: 16px; height: 16px; }

/* ======================= Profiel en scorebord ======================= */

.pt-avatar {
  width: 34px; height: 34px;
  border-radius: 50%;
  object-fit: cover;
  background: var(--surface-3);
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  font-size: .75rem;
  font-weight: 750;
  color: var(--text-muted);
  overflow: hidden;
}

.pt-avatar--lg { width: 56px; height: 56px; font-size: 1rem; }
.pt-avatar--xl { width: clamp(64px, 9vh, 110px); height: clamp(64px, 9vh, 110px); font-size: 1.6rem; }
.pt-avatar--sm { width: 26px; height: 26px; font-size: .65rem; }

.pt-profile-bar {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  width: 100%;
  padding: var(--s-3);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  cursor: pointer;
  text-align: left;
  color: inherit;
}

.pt-profile-bar:hover { background: var(--surface-2); }

/* Een flexrij en geen raster: de naam moet alle ruimte krijgen die overblijft,
   en met vaste kolommen kreeg de puntenkolom er veel te veel. */
.pt-score {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  padding: var(--s-2) var(--s-4);
  border-bottom: 1px solid var(--line);
}

.pt-score > .pt-rank { flex: 0 0 26px; }
.pt-score > .pt-avatar { flex: 0 0 auto; }
.pt-score > .pt-grow { flex: 1 1 auto; min-width: 0; }
/* De punten nemen alleen de ruimte die ze nodig hebben. */
.pt-score > :last-child { flex: 0 0 auto; }

.pt-score:last-child { border-bottom: 0; }
.pt-score--me { background: rgba(255, 203, 71, .10); box-shadow: inset 3px 0 0 var(--amber); }
.pt-score__name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-weight: 600; }
.pt-score__pts { font-weight: 800; font-variant-numeric: tabular-nums; color: var(--brand); }

/* ======================= Uitslagmoment ======================= */

.pt-moment {
  display: grid;
  place-items: center;
  gap: var(--s-2);
  padding: var(--s-4) 0 var(--s-2);
  text-align: center;
}

.pt-moment__icon { font-size: 2.6rem; line-height: 1; }
.pt-moment__title { font-size: 1.3rem; font-weight: 800; letter-spacing: -.02em; }
.pt-moment__sub { color: var(--text-muted); font-size: .9rem; }

.pt-moment--good .pt-moment__icon { animation: pt-cheer .7s cubic-bezier(.2, 1.4, .4, 1) both; }
.pt-moment--good .pt-moment__title { color: var(--brand); }

.pt-moment--bad .pt-moment__icon { animation: pt-shake .55s ease both; }
.pt-moment--bad .pt-moment__title { color: var(--amber); }

@keyframes pt-cheer {
  0%   { transform: scale(.4) rotate(-18deg); opacity: 0; }
  60%  { transform: scale(1.25) rotate(6deg); opacity: 1; }
  100% { transform: scale(1) rotate(0); opacity: 1; }
}

@keyframes pt-shake {
  0%, 100% { transform: translateX(0) rotate(0); }
  20% { transform: translateX(-7px) rotate(-7deg); }
  45% { transform: translateX(6px) rotate(6deg); }
  70% { transform: translateX(-4px) rotate(-4deg); }
}

/* Confetti: losse deeltjes, geen bibliotheek. */
.pt-confetti {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 95;
  overflow: hidden;
}

.pt-confetti i {
  position: absolute;
  top: -12px;
  width: 9px;
  height: 14px;
  border-radius: 2px;
  opacity: 0;
  animation: pt-fall var(--dur, 1.8s) linear var(--delay, 0s) forwards;
}

@keyframes pt-fall {
  0%   { opacity: 1; transform: translateY(0) rotate(0); }
  100% { opacity: 0; transform: translateY(105vh) rotate(720deg); }
}

/* ======================= Koploper op tv ======================= */

.pt-tv__leaders {
  display: flex;
  align-items: center;
  gap: calc(clamp(10px, 1.4vw, 20px) * var(--maat, 1));
  flex-wrap: wrap;
  margin-top: calc(clamp(8px, 1.2vh, 16px) * var(--maat, 1));
  font-size: calc(clamp(.85rem, 1.3vw, 1.15rem) * var(--maat, 1));
}

.pt-tv__leader {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px 6px 6px;
  border-radius: var(--r-pill);
  background: var(--surface);
  border: 1px solid var(--line);
  max-width: 100%;
}

/* Een lange naam wordt afgekapt; de score blijft altijd leesbaar. */
.pt-tv__leader > span {
  max-width: 14ch;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.pt-tv__leader--1 { border-color: var(--amber); background: rgba(255, 203, 71, .12); }
.pt-tv__leader b { font-variant-numeric: tabular-nums; color: var(--brand); }

/* ======================= Aftelklokje ======================= */

.pt-ring {
  width: 68px;
  height: 68px;
  flex: 0 0 auto;
  transform: rotate(-90deg);   /* begin bovenaan */
}

.pt-ring__track {
  fill: none;
  stroke: var(--surface-3);
  stroke-width: 9;
}

.pt-ring__bar {
  fill: none;
  stroke: var(--brand);
  stroke-width: 9;
  stroke-linecap: round;
  transition: stroke-dashoffset .16s linear, stroke .4s ease;
}

.pt-ring--warn   .pt-ring__bar { stroke: var(--amber); }
.pt-ring--danger .pt-ring__bar { stroke: var(--down); }

.pt-ring__label {
  fill: var(--text);
  font-size: 34px;
  font-weight: 800;
  font-family: var(--font);
  transform: rotate(90deg);    /* tekst weer rechtop */
  transform-origin: 50px 50px;
}

.pt-ring--warn   .pt-ring__label { fill: var(--amber); }
.pt-ring--danger .pt-ring__label { fill: var(--down); }

/* De laatste seconden tikt het klokje mee. */
.pt-ring--danger .pt-ring__label { animation: pt-tick 1s ease-in-out infinite; }

@keyframes pt-tick {
  0%, 100% { opacity: 1; }
  50%      { opacity: .55; }
}

/* Tijd om: trillen als een wekker, met een flits over het hele paneel. */
.pt-ring--alarm { animation: pt-alarm 1.1s ease-in-out; }

.pt-alarm-flash {
  animation: pt-alarm-flash 1.1s ease-in-out;
}

@keyframes pt-alarm-flash {
  0%, 100% { border-color: var(--line-strong); box-shadow: var(--shadow-3); }
  15%, 45% {
    border-color: var(--down);
    box-shadow: 0 0 0 3px rgba(244, 83, 107, .25), var(--shadow-3);
  }
  30%, 60% { border-color: var(--line-strong); box-shadow: var(--shadow-3); }
}

@keyframes pt-alarm {
  0%, 100% { transform: rotate(-90deg) scale(1); }
  8%  { transform: rotate(-78deg) scale(1.14); }
  16% { transform: rotate(-102deg) scale(1.14); }
  24% { transform: rotate(-80deg) scale(1.11); }
  32% { transform: rotate(-100deg) scale(1.11); }
  40% { transform: rotate(-82deg) scale(1.08); }
  48% { transform: rotate(-98deg) scale(1.08); }
  56% { transform: rotate(-85deg) scale(1.05); }
  64% { transform: rotate(-95deg) scale(1.05); }
  74% { transform: rotate(-88deg) scale(1.02); }
  84% { transform: rotate(-92deg) scale(1.02); }
}

/* ======================= Podium ======================= */

.pt-podium {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: var(--s-2);
  padding: var(--s-4) var(--s-2) 0;
}

.pt-podium__spot {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--s-2);
  flex: 1 1 0;
  min-width: 0;
  max-width: 140px;
}

.pt-podium__who {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  min-width: 0;
  width: 100%;
}

.pt-podium__name {
  font-size: .82rem;
  font-weight: 650;
  text-align: center;
  max-width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.pt-podium__block {
  width: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  border-radius: var(--r-md) var(--r-md) 0 0;
  background: var(--surface-2);
  border: 1px solid var(--line-strong);
  border-bottom: 0;
}

.pt-podium__rank { font-size: 1.5rem; font-weight: 800; line-height: 1; }
.pt-podium__score { font-size: .75rem; color: var(--text-muted); font-variant-numeric: tabular-nums; }

/* Hoogte en kleur per plek: goud, zilver, brons. */
.pt-podium__spot--1 .pt-podium__block {
  height: 92px;
  background: linear-gradient(180deg, rgba(255,203,71,.30), rgba(255,203,71,.10));
  border-color: var(--amber);
}
.pt-podium__spot--1 .pt-podium__rank { color: var(--amber); }
.pt-podium__spot--1 .pt-avatar { box-shadow: 0 0 0 3px var(--amber); }

.pt-podium__spot--2 .pt-podium__block {
  height: 68px;
  background: linear-gradient(180deg, rgba(206,214,222,.24), rgba(206,214,222,.08));
  border-color: #ced6de;
}
.pt-podium__spot--2 .pt-podium__rank { color: #ced6de; }
.pt-podium__spot--2 .pt-avatar { box-shadow: 0 0 0 3px #ced6de; }

.pt-podium__spot--3 .pt-podium__block {
  height: 50px;
  background: linear-gradient(180deg, rgba(205,127,80,.26), rgba(205,127,80,.08));
  border-color: #cd7f50;
}
.pt-podium__spot--3 .pt-podium__rank { color: #cd7f50; }
.pt-podium__spot--3 .pt-avatar { box-shadow: 0 0 0 3px #cd7f50; }

/* Op tv schaalt het podium mee met de schermhoogte: groot op een echte tv,
   maar het moet ook op een kort venster binnen beeld blijven. */
.pt-tv .pt-podium { padding-top: var(--s-2); }
.pt-tv .pt-podium__spot { max-width: 190px; }
.pt-tv .pt-podium__name { font-size: calc(clamp(.75rem, 1.2vw, 1.1rem) * var(--maat, 1)); }
.pt-tv .pt-avatar--lg { width: calc(clamp(32px, 5vh, 56px) * var(--maat, 1)); height: calc(clamp(32px, 5vh, 56px) * var(--maat, 1)); }
.pt-tv .pt-podium__rank { font-size: calc(clamp(1rem, 2.4vh, 1.6rem) * var(--maat, 1)); }
.pt-tv .pt-podium__spot--1 .pt-podium__block { height: calc(clamp(44px, 10vh, 120px) * var(--maat, 1)); }
.pt-tv .pt-podium__spot--2 .pt-podium__block { height: calc(clamp(32px, 7.5vh, 90px) * var(--maat, 1)); }
.pt-tv .pt-podium__spot--3 .pt-podium__block { height: calc(clamp(24px, 5.5vh, 68px) * var(--maat, 1)); }

/* ======================= Volgorde aanpassen (DJ) ======================= */

/* De twee pijltjes vullen samen de hele hoogte van de rij: het bovenste lijnt
   uit met de bovenkant van het blokje, het onderste met de onderkant. Dat
   oogt als een kolom in plaats van twee zwevende knopjes, en het levert
   meteen vlakken op die groot genoeg zijn om met een vinger te raken. Het
   rangnummer ertussen houdt zijn eigen hoogte, de pijltjes verdelen de rest. */
.pt-move {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  align-self: stretch;
  justify-content: space-between;
  gap: 2px;
  width: 100%;
  min-height: 48px;
}

.pt-move__btn {
  flex: 1 1 0;
  /* Nooit kleiner dan dit, ook niet in een lage rij, en nooit groter dan
     een vingerdruk: in een hoge rij zou een pijl anders een lange sliert
     worden. Hij blijft wel aan de boven- of onderkant hangen. */
  min-height: 22px;
  max-height: 44px;
  width: 100%;
  display: grid;
  place-items: center;
  border: 1px solid var(--line);
  background: var(--surface-2);
  border-radius: 6px;
  cursor: pointer;
  color: var(--text-muted);
  line-height: 1;
  font-size: .8rem;
  padding: 0;
}

.pt-move__btn:hover:not(:disabled) { background: var(--surface-3); color: var(--text); }
.pt-move__btn:disabled { opacity: .3; cursor: not-allowed; }

.pt-move__rank {
  flex: 0 0 auto;
  text-align: center;
  /* Zo strak als het cijfer zelf, want elke pixel die hier weggaat komt bij
     de pijltjes erboven en eronder. */
  line-height: 1;
  font-size: .72rem;
  font-weight: 750;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}

/* De DJ-wachtrij heeft een eigen kolom voor de verplaatsknoppen. */
.pt-page-admin .pt-track { grid-template-columns: 32px 48px minmax(0, 1fr) auto; }

/* Op een smal scherm is de hoes kleiner; dan hoort de kolom dat ook te zijn. */
@media (max-width: 719px) {
  .pt-page-admin .pt-track { grid-template-columns: 32px 40px minmax(0, 1fr) auto; }
  /*
     Tot hier staat het rangnummer uit. In de lijst Gedraaid staan ook geen
     verplaatspijltjes, dus daar blijft die eerste kolom leeg; die laten we
     weg. Deze regel hoort na de regel hierboven, anders wint die.
  */
  .pt-page-admin .pt-track--played { grid-template-columns: 40px minmax(0, 1fr) auto; }
}

@media (min-width: 720px) {
  .pt-page-admin .pt-track { grid-template-columns: 34px 56px minmax(0, 1fr) auto; }
}

/* Op een telefoon is er naast alle knoppen geen ruimte voor de titel. Dan
   staan titel en artiest bovenaan over de hele breedte, met de hoes ervoor,
   en komen de knoppen op een tweede regel eronder. */
@media (max-width: 599px) {
  .pt-page-admin .pt-track {
    grid-template-columns: 34px 40px minmax(0, 1fr);
    grid-template-areas:
      "rang hoes meta"
      "rang acties acties";
    row-gap: 6px;
  }
  .pt-page-admin .pt-track > .pt-rank,
  .pt-page-admin .pt-track > .pt-track__kies { grid-area: rang; align-self: center; }
  .pt-page-admin .pt-track > .pt-move { grid-area: rang; align-self: stretch; }
  .pt-page-admin .pt-track > .pt-track__cover { grid-area: hoes; width: 40px; height: 40px; }
  /*
     In de console blijft de tekstkolom een vakje.

     Op de telefoon van een gast lost `.pt-track__meta` op in het raster
     (display:contents), zodat titel en artiest er zelf een plek in krijgen.
     De console heeft daar een eigen indeling omheen, met een kolom voor het
     rangnummer, en daarin bestaan die plekken niet. Zonder deze regel zochten
     titel en artiest zelf maar een plek en kwamen ze over elkaar heen te
     staan.
  */
  .pt-page-admin .pt-track > .pt-track__meta {
    display: flex;
    flex-direction: column;
    justify-content: center;
    grid-area: meta;
    min-width: 0;
  }
  .pt-page-admin .pt-track > .pt-track__actions { grid-area: acties; justify-content: flex-start; flex-wrap: wrap; }
  /*
     Een titel op een regel, met puntjes als hij niet past.

     Hij stond op twee regels zodat je een lange clipnaam helemaal kon lezen,
     maar in de wachtrij staan er tien onder elkaar en dan kost elke tweede
     regel je het overzicht. De artiest, het jaar en de bron staan er gewoon
     onder, en voor een clip is er het kijkknopje.
  */
  .pt-page-admin .pt-track__title {
    -webkit-line-clamp: 1;
    white-space: nowrap;
    text-overflow: ellipsis;
  }
  /* De verplaatspijltjes hoeven niet zo hoog als de hele rij. */
  .pt-page-admin .pt-move__btn { min-height: 28px; }
  /*
     Weggooien helemaal naar rechts.

     Op de tweede regel blijft rechts toch ruimte over, en de prullenbak stond
     tegen 'Nu' aan. In een donkere zaal met een duim is dat het verschil
     tussen het nummer nu draaien en het nummer kwijt zijn.
  */
  .pt-page-admin .pt-track > .pt-track__actions > .pt-btn--danger { margin-left: auto; }
  /*
     De lijst Gedraaid heeft geen rangnummer en geen verplaatspijltjes, dus
     daar hoeft de kolom links niet leeg te blijven staan. Dit moet na de
     algemene regel hierboven staan, anders wint die.
  */
  .pt-page-admin .pt-track--played {
    grid-template-columns: 40px minmax(0, 1fr);
    grid-template-areas:
      "hoes meta"
      "acties acties";
  }
}

/* Het rangnummer blijft in de DJ-console ook op mobiel zichtbaar. */
.pt-page-admin .pt-move { display: flex; }

/* Sluitknop op het quizpaneel, zodat de gast zijn stemlijst weer ziet. */
.pt-hitster { position: relative; }

.pt-hitster__close {
  position: absolute;
  top: 6px;
  right: 6px;
  width: 34px;
  height: 34px;
  display: grid;
  place-items: center;
  border: 0;
  background: transparent;
  color: var(--text-faint);
  font-size: 1.5rem;
  line-height: 1;
  border-radius: 50%;
  cursor: pointer;
  z-index: 1;
}

.pt-hitster__close:hover { background: var(--surface-3); color: var(--text); }

/* Ruimte houden zodat de tekst niet onder de knop loopt. */
.pt-hitster .pt-card__body { padding-right: 44px; }

/* Onderregel op het podium met de ruwe score. */
.pt-podium__sub { font-size: .68rem; color: var(--text-faint); font-variant-numeric: tabular-nums; }

/* Getekende avatar: figuurtje op een gekleurde bol. */
.pt-avatar--drawn {
  font-size: 1.05rem;
  line-height: 1;
  color: #06140b;
  text-shadow: 0 1px 0 rgba(255, 255, 255, .35);
}

.pt-avatar--drawn.pt-avatar--sm { font-size: .8rem; }
.pt-avatar--drawn.pt-avatar--lg { font-size: 1.7rem; }

/* Fotokiezer met een voorbeeld van je huidige avatar ernaast. */
.pt-avatar-picker {
  display: flex;
  align-items: center;
  gap: var(--s-3);
}

.pt-avatar-picker .pt-avatar { width: 56px; height: 56px; }
.pt-avatar-picker .pt-avatar--drawn { font-size: 1.7rem; }

/* ======================= Superkracht ======================= */

.pt-power {
  border: 1px solid var(--amber);
  border-radius: var(--r-lg);
  background: linear-gradient(135deg, rgba(255, 203, 71, .16), rgba(255, 203, 71, .04));
  padding: var(--s-4);
  box-shadow: 0 0 0 1px rgba(255, 203, 71, .15), var(--shadow-2);
}

.pt-power__title {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  font-weight: 800;
  color: var(--amber);
}

.pt-power__title span:first-child { font-size: 1.35rem; }

.pt-power--armed {
  border-color: var(--brand);
  background: linear-gradient(135deg, rgba(30, 215, 96, .16), rgba(30, 215, 96, .04));
}

.pt-power--armed .pt-power__title { color: var(--brand); }

/* De stemknoppen springen eruit zodra een superstem klaarstaat. */
/* Een kracht staat scherp: laat zien waar je moet tikken.
   Bij een superstem zijn dat de pijltjes, want daar kies je ook een richting. */
body.pt-super-armed .pt-vote__btn {
  border-color: var(--brand);
  box-shadow: 0 0 0 2px rgba(30, 215, 96, .3);
  animation: pt-wijs 1.4s ease-in-out infinite;
}

@keyframes pt-wijs {
  0%, 100% { box-shadow: 0 0 0 2px rgba(30, 215, 96, .3); }
  50%      { box-shadow: 0 0 0 5px rgba(30, 215, 96, .12); }
}

/* Bij voorkruiper en veto wijs je een heel nummer aan; dan is de hele regel
   de knop. */
.pt-track--kiesbaar {
  cursor: pointer;
  outline: 2px dashed rgba(30, 215, 96, .55);
  outline-offset: -4px;
  border-radius: var(--r-md);
}

.pt-track--kiesbaar:active { transform: scale(.99); }

@media (prefers-reduced-motion: reduce) {
  body.pt-super-armed .pt-vote__btn { animation: none; }
}

/* Crashmelding op tv. */
.pt-crash {
  display: flex;
  align-items: center;
  gap: clamp(10px, 1.4vw, 20px);
  padding: clamp(10px, 1.4vh, 18px) clamp(14px, 1.6vw, 24px);
  border-radius: var(--r-lg);
  border: 1px solid var(--down);
  background: rgba(244, 83, 107, .16);
  animation: pt-crash-in .4s ease both;
}

.pt-crash__icon { font-size: clamp(1.6rem, 3vw, 2.6rem); }
.pt-crash__text { font-weight: 800; font-size: clamp(1rem, 1.8vw, 1.6rem); }

@keyframes pt-crash-in {
  from { opacity: 0; transform: translateY(-12px) scale(.96); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

/* Op tv mogen de podiumavatars flink groter; dat leest van een afstand
   beter en is bovendien leuker om naar te kijken. */
.pt-tv .pt-avatar--lg {
  width: calc(clamp(52px, 9vh, 104px) * var(--maat, 1));
  height: calc(clamp(52px, 9vh, 104px) * var(--maat, 1));
}

.pt-tv .pt-avatar--drawn.pt-avatar--lg { font-size: calc(clamp(1.8rem, 4.6vh, 3.4rem) * var(--maat, 1)); }
.pt-tv .pt-podium__spot { max-width: 230px; }

/* Teller op de superkrachtkaart: het aantal moet meteen opvallen. */
.pt-power__head {
  display: flex;
  align-items: center;
  gap: var(--s-3);
}

.pt-power__badge {
  position: relative;
  width: 54px;
  height: 54px;
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #ffe28a, #ffb524);
  box-shadow: 0 0 0 3px rgba(255, 203, 71, .28), 0 6px 16px rgba(0, 0, 0, .45);
}

.pt-power__count {
  font-size: 1.6rem;
  font-weight: 800;
  color: #3a2500;
  line-height: 1;
}

.pt-power__bolt {
  position: absolute;
  right: -4px;
  bottom: -4px;
  font-size: 1.05rem;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .5));
}

/* Stemknoppen voor de DJ in de wachtrij. */
.pt-djvote {
  display: flex;
  align-items: center;
  gap: 2px;
}

.pt-djvote__btn {
  width: 28px;
  height: 28px;
  display: grid;
  place-items: center;
  border: 1px solid var(--line);
  background: var(--surface-2);
  border-radius: var(--r-sm);
  color: var(--text-muted);
  font-size: 1rem;
  font-weight: 700;
  line-height: 1;
  padding: 0;
  cursor: pointer;
  transition: background-color .15s ease, color .15s ease, transform .08s ease;
}

.pt-djvote__btn:hover { background: var(--surface-3); color: var(--text); }
.pt-djvote__btn:active { transform: scale(.9); }
.pt-djvote .pt-vote__score { min-width: 2.4ch; font-size: .95rem; }

/* ======================= Tijdlijn (Hitster) ======================= */

.pt-timeline {
  display: flex;
  align-items: stretch;
  gap: 4px;
  overflow-x: auto;
  padding: var(--s-2) 2px var(--s-3);
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
  /* Rechterrand vervaagt, zodat zichtbaar is dat er meer kaarten staan. */
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent 100%);
  mask-image: linear-gradient(to right, #000 calc(100% - 24px), transparent 100%);
}

/* Past alles binnen het scherm, dan is de vervaging onnodig. */
.pt-timeline--past {
  -webkit-mask-image: none;
  mask-image: none;
  justify-content: center;
}

.pt-tl-card {
  flex: 0 0 auto;
  min-width: 64px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  padding: var(--s-2) var(--s-3);
  border-radius: var(--r-md);
  background: var(--surface-2);
  border: 1px solid var(--line-strong);
  text-align: center;
}

.pt-tl-card__year {
  font-size: 1.05rem;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--text);
  line-height: 1;
}

.pt-tl-card__who {
  font-size: .65rem;
  color: var(--text-faint);
  max-width: 92px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* De plekken ertussen: smal, maar met een fatsoenlijk tikdoel. */
.pt-slot {
  flex: 0 0 auto;
  width: 34px;
  min-height: 58px;
  display: grid;
  place-items: center;
  border: 1px dashed var(--line-strong);
  border-radius: var(--r-md);
  background: transparent;
  color: var(--text-faint);
  font-size: 1.1rem;
  cursor: pointer;
  transition: background-color .15s ease, border-color .15s ease, color .15s ease, transform .08s ease;
  -webkit-tap-highlight-color: transparent;
}

/* Zolang je nog kunt kiezen: breder, groen gestippeld en zachtjes ademend,
   met een woordje eronder. Dit zijn de knoppen; de kaarten niet. */
.pt-slot--kies {
  width: 58px;
  min-height: 64px;
  border: 1.5px dashed rgba(30, 215, 96, .7);
  color: var(--brand);
  background: rgba(30, 215, 96, .07);
  animation: pt-slot-adem 1.6s ease-in-out infinite;
}
.pt-slot__teken { font-size: 1.25rem; line-height: 1; font-weight: 700; }
/* Het woordje blijft binnen zijn vakje, wat er ook gerekend wordt: anders
   loopt EERDER over de kaart ernaast. pasTijdlijnIn kiest de lettergrootte
   zo dat het past; dit is het slot erachter. */
.pt-slot__woord {
  font-size: .55rem; letter-spacing: .02em; text-transform: uppercase; opacity: .85;
  max-width: 100%; overflow: hidden; text-overflow: clip; white-space: nowrap;
}
.pt-slot { overflow: hidden; }
.pt-slot--kies.pt-slot--gekozen { animation: none; background: rgba(30, 215, 96, .2); border-style: solid; }
@keyframes pt-slot-adem {
  0%, 100% { box-shadow: 0 0 0 0 rgba(30, 215, 96, 0); }
  50%      { box-shadow: 0 0 0 4px rgba(30, 215, 96, .18); }
}
@media (prefers-reduced-motion: reduce) { .pt-slot--kies { animation: none; } }

/* De zoekregel bij een lijst: waar je zoekt, waarnaar, en de knop. Op een
   breed scherm één regel, op een telefoon valt het zoekveld over de hele
   breedte en komen bron en knop eronder.

   Eigen naam en niet .pt-zoekrij: die bestaat al voor de wachtrij in de
   console, en dat is een raster met andere regels. */
.pt-lijstzoek {
  display: flex;
  gap: var(--s-2);
  align-items: center;
  flex-wrap: wrap;
}
.pt-lijstzoek .pt-input { width: auto; }
.pt-lijstzoek__bron { flex: 0 0 auto; }
.pt-lijstzoek__veld { flex: 1 1 14em; min-width: 10em; }
@media (max-width: 520px) {
  .pt-lijstzoek__veld { flex: 1 1 100%; order: -1; }
}

/* Het regeltje onder een tijdlijn die niet in beeld past. */
.pt-timeline__hint {
  text-align: center;
  font-size: .72rem;
  color: var(--text-faint);
  margin-top: -6px;
  transition: opacity .3s ease;
}
.pt-timeline__hint::before { content: '\2190\00a0'; }
.pt-timeline__hint::after  { content: '\00a0\2192'; }
.pt-timeline__hint--weg { opacity: 0; }

.pt-slot:hover:not(:disabled) {
  background: rgba(30, 215, 96, .12);
  border-color: var(--brand);
  color: var(--brand);
}

.pt-slot:active:not(:disabled) { transform: scale(.94); }
.pt-slot:disabled { opacity: .35; cursor: not-allowed; }

.pt-slot--gekozen {
  background: rgba(30, 215, 96, .2);
  border-style: solid;
  border-color: var(--brand);
  color: var(--brand);
}

/* Het antwoord van deze ronde: schuift van boven op zijn plek en licht op. */
.pt-tl-card--antwoord {
  border: 1.5px solid var(--brand);
  background: rgba(30, 215, 96, .16);
  box-shadow: 0 0 0 3px rgba(30, 215, 96, .18), 0 8px 20px rgba(0, 0, 0, .35);
  animation: pt-tl-schuif .7s cubic-bezier(.2, .9, .3, 1.15) both;
}
.pt-tl-card--antwoord .pt-tl-card__year { color: var(--brand); }
@keyframes pt-tl-schuif {
  from { transform: translateY(-140%) scale(.9); opacity: 0; }
  60%  { opacity: 1; }
  to   { transform: none; opacity: 1; }
}

/* De kaart die zojuist geplaatst is, licht op. */
.pt-tl-card--nieuw {
  border-color: var(--brand);
  background: rgba(30, 215, 96, .14);
  animation: pt-cheer .5s ease both;
}

.pt-tl-card--fout {
  border-color: var(--down);
  background: rgba(244, 83, 107, .14);
}

/* Op tv mag alles ruimer. */
.pt-tv .pt-tl-card { min-width: calc(clamp(84px, 8vw, 130px) * var(--maat, 1)); }
.pt-tv .pt-tl-card__year { font-size: calc(clamp(1.1rem, 1.9vw, 1.7rem) * var(--maat, 1)); }
.pt-tv .pt-tl-card__who { font-size: calc(clamp(.6rem, .9vw, .8rem) * var(--maat, 1)); max-width: 120px; }
.pt-tv .pt-slot { width: calc(clamp(28px, 3vw, 48px) * var(--maat, 1)); min-height: calc(clamp(52px, 6vw, 78px) * var(--maat, 1)); }

/* Tijdlijn die zich naar de beschikbare ruimte voegt (tv-scherm). */
.pt-timeline--fit {
  overflow: hidden;
  justify-content: center;
  flex-wrap: nowrap;
  -webkit-mask-image: none;
  mask-image: none;
}

.pt-timeline--fit .pt-tl-card {
  min-width: 0;
  width: var(--tl-card, 96px);
  padding-left: 4px;
  padding-right: 4px;
}

.pt-timeline--fit .pt-slot {
  /* De terugval is breed genoeg voor het langste woord (EERDER). Stond hier
     34px, en dan liep dat woord uit het vakje zolang pasTijdlijnIn nog geen
     maat had kunnen nemen. */
  width: var(--tl-slot, 46px);
  min-height: 0;
}
.pt-timeline--fit .pt-slot__teken { font-size: var(--tl-font, 19px); }
/* De terugval staat in pixels en niet in rem: op een tv kan de basisletter
   groot staan, en dan werd .6rem een woord dat twee keer zo breed was als
   zijn vakje. Normaal rekent pasTijdlijnIn deze maat zelf uit. */
.pt-timeline--fit .pt-slot__woord { font-size: var(--tl-sub, 10px); }
.pt-timeline--zonderwoord .pt-slot__woord { display: none; }

.pt-timeline--fit .pt-tl-card__year {
  font-size: var(--tl-font, 1.2rem);
}

.pt-timeline--fit .pt-tl-card__who {
  font-size: var(--tl-sub, .6rem);
  max-width: 100%;
}

/* Past de tijdlijn niet op één rij, dan mag hij omvallen. */
.pt-timeline--fit.pt-timeline--wrap {
  flex-wrap: wrap;
  row-gap: 6px;
}

/* ------------------------------------------------------ party crashers */

.pt-chip--uit { opacity: .5; text-decoration: line-through; }

.pt-crash-rol {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-3);
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background: var(--surface);
}
.pt-crash-rol__icoon { font-size: 2.4rem; line-height: 1; }
.pt-crash-rol--crasher { border-color: rgba(244, 83, 107, .5); background: rgba(244, 83, 107, .1); }
.pt-crash-rol--shazam  { border-color: rgba(255, 203, 71, .5); background: rgba(255, 203, 71, .1); }
.pt-crash-rol--feest   { border-color: rgba(30, 215, 96, .4); background: rgba(30, 215, 96, .08); }

.pt-crash-lijst { display: grid; gap: var(--s-1); }
.pt-crash-item {
  display: grid;
  grid-template-columns: 44px minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--s-3);
  width: 100%;
  padding: var(--s-2) var(--s-3);
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background: var(--surface);
  color: inherit;
  text-align: left;
  font: inherit;
  cursor: pointer;
}
.pt-crash-item:disabled { cursor: default; opacity: .7; }
.pt-crash-item.is-mijn { border-color: var(--down); background: rgba(244, 83, 107, .12); }
.pt-crash-item .pt-chip { justify-self: end; }
.pt-crash-item .pt-chip + .pt-chip { margin-left: 4px; }

.pt-crash-spelers { display: flex; flex-wrap: wrap; gap: 8px; }
.pt-crash-speler {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 6px 14px 6px 6px;
  border-radius: var(--r-pill);
  border: 1px solid var(--line);
  background: var(--surface);
  color: inherit;
  font: inherit;
  cursor: pointer;
}
.pt-crash-speler.is-mijn { border-color: var(--down); background: rgba(244, 83, 107, .14); }

.pt-crash-nacht {
  margin-top: var(--s-4);
  padding: var(--s-5) var(--s-3);
  border-radius: var(--r-md);
  background: #0b0d14;
  border: 1px solid #1c2033;
  text-align: center;
}
.pt-crash-nacht__maan { font-size: 3rem; line-height: 1; margin-bottom: var(--s-2); }

.pt-crash-weg .pt-track__title { text-decoration: line-through; text-decoration-thickness: 3px; text-decoration-color: var(--down); }
.pt-crash-weg { opacity: .8; }

/* De tv: de playlist als rij chips, zodat hij ook met twaalf nummers in de dok past. */
.pt-tv__crash-lijst {
  display: flex; flex-wrap: wrap;
  gap: calc(clamp(4px, .5vw, 8px) * var(--maat, 1));
  margin-top: calc(clamp(6px, 1vh, 12px) * var(--maat, 1));
}
.pt-tv__crash-item {
  display: inline-flex; align-items: center; gap: 6px;
  max-width: calc(clamp(220px, 24vw, 420px) * var(--maat, 1));
  padding: 3px 8px 3px 3px;
  border-radius: var(--r-pill);
  border: 1px solid var(--line);
  background: var(--surface);
  min-width: 0;
  font-size: calc(clamp(.7rem, .95vw, .95rem) * var(--maat, 1));
}
.pt-tv__crash-item img, .pt-tv__crash-item .pt-tv__crash-hoes { width: calc(clamp(20px, 1.8vw, 30px) * var(--maat, 1)); height: calc(clamp(20px, 1.8vw, 30px) * var(--maat, 1)); border-radius: 50%; flex: none; background: var(--surface-2, #222); object-fit: cover; }
.pt-tv__crash-item .pt-tv__crash-tekst { min-width: 0; display: flex; gap: 4px; white-space: nowrap; overflow: hidden; }
.pt-tv__crash-item .pt-tv__crash-titel { font-weight: 650; overflow: hidden; text-overflow: ellipsis; }
.pt-tv__crash-item .pt-tv__crash-artiest { color: var(--text-muted); overflow: hidden; text-overflow: ellipsis; flex: none; max-width: 12ch; }
.pt-tv__crash-item .pt-tv__crash-artiest::before { content: '· '; }
.pt-tv__crash-item.is-uit { opacity: .4; }
.pt-tv__crash-item.is-uit .pt-tv__crash-titel { text-decoration: line-through; }
.pt-tv__crash-item.is-crasher { border-color: var(--down); }
.pt-tv__crash-stem {
  margin-left: auto; flex: none;
  min-width: 1.8em; padding: 0 8px;
  border-radius: var(--r-pill);
  background: var(--down); color: #fff;
  font-weight: 800; text-align: center;
}
.pt-tv__speler .pt-tv__crash-stem { margin-left: 4px; }
.pt-tv__speler.is-crasher { border-color: var(--down); }

.pt-roep--nacht { background: radial-gradient(ellipse at 50% 30%, #101528 0%, #05060b 70%); }
.pt-roep--nacht .pt-roep__icoon { animation: pt-crash-zweef 3s ease-in-out infinite alternate; }
@keyframes pt-crash-zweef { from { transform: translateY(0); } to { transform: translateY(-12px); } }
.pt-roep__weg {
  display: inline-block; margin-top: var(--s-3);
  font-size: clamp(1.2rem, 4vw, 2.2rem); font-weight: 800;
  text-decoration: line-through; text-decoration-thickness: 4px; text-decoration-color: var(--down);
}
.pt-roep__rollen { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; margin-top: var(--s-4); }

.pt-crash-regels { display: grid; gap: var(--s-3); padding: 0 var(--s-4) var(--s-4); }
.pt-crash-regel { display: flex; gap: var(--s-3); align-items: flex-start; }
.pt-crash-regel__icoon { font-size: 1.4rem; line-height: 1.2; flex: none; width: 1.6em; text-align: center; }
.pt-crash-regel__kop { font-weight: 650; margin-bottom: 2px; }
.pt-tv__crash-regels { display: grid; gap: calc(clamp(2px, .5vh, 6px) * var(--maat, 1)); margin-top: calc(clamp(6px, 1vh, 12px) * var(--maat, 1)); color: var(--text-muted); font-size: calc(clamp(.8rem, 1.15vw, 1.05rem) * var(--maat, 1)); }
.pt-tv__crash-regel { display: flex; gap: 8px; align-items: baseline; }
.pt-gastrij.is-weg { opacity: .6; }

/* Geheime DJ: het gezicht van de inzender op het label, ook zonder foto. */
.pt-vinyl__label--gezicht.pt-avatar { flex: none; display: grid; place-items: center; width: 38%; height: 38%; }
.pt-vinyl--small .pt-vinyl__label--gezicht.pt-avatar { width: 42%; height: 42%; }
.pt-vinyl__label--gezicht.pt-avatar--drawn { font-size: clamp(1.6rem, 7vh, 4.5rem); }
.pt-vinyl--small .pt-vinyl__label--gezicht.pt-avatar--drawn { font-size: 1.6rem; }

/* De DJ linksboven op de tv, naast de partynaam. */
.pt-tv__links { display: flex; align-items: center; gap: calc(clamp(12px, 1.6vw, 26px) * var(--maat, 1)); min-width: 0; }
/* De foto van de DJ is ook de knop naar de instellingen van dit scherm.
   Hij ziet er hetzelfde uit als eerst; alleen de muisaanwijzer en een lichte
   glans bij zweven verraden dat er iets achter zit. */
.pt-tv__dj {
  flex: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  border: 0;
  padding: 0;
  /* Safari tekent anders zijn eigen grijze knop om de foto heen, ook met
     background: none. Met appearance: none blijft de achtergrond echt weg. */
  -webkit-appearance: none;
  appearance: none;
  background: transparent;
  box-shadow: none;
  font: inherit;
  color: inherit;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.pt-tv__dj:hover .pt-tv__dj-foto,
.pt-tv__dj:focus-visible .pt-tv__dj-foto,
.pt-tv__dj[aria-expanded="true"] .pt-tv__dj-foto {
  box-shadow: 0 6px 24px rgba(0, 0, 0, .45), 0 0 0 4px rgba(30, 215, 96, .25);
}
.pt-tv__dj:focus-visible { outline: none; }

/* Geen foto ingesteld: dan staat het logo er, met wat lucht eromheen zodat
   het niet tegen de rand van de cirkel aan plakt. */
.pt-tv__dj-foto--merk { object-fit: contain; padding: 14%; background: var(--surface-2); }
.pt-tv__dj-foto {
  width: calc(clamp(64px, 9vh, 110px) * var(--maat, 1)); height: calc(clamp(64px, 9vh, 110px) * var(--maat, 1));
  border-radius: 50%; object-fit: cover;
  border: 3px solid var(--brand);
  box-shadow: 0 6px 24px rgba(0, 0, 0, .45);
  background: var(--surface-2);
}
.pt-tv__dj-foto--leeg { display: grid; place-items: center; font-size: calc(clamp(1.6rem, 4vh, 3rem) * var(--maat, 1)); }
.pt-tv__dj-naam { font-size: calc(clamp(.7rem, 1vw, .95rem) * var(--maat, 1)); font-weight: 700; color: var(--brand); letter-spacing: .04em; text-transform: uppercase; white-space: nowrap; max-width: calc(clamp(80px, 11vh, 140px) * var(--maat, 1)); overflow: hidden; text-overflow: ellipsis; }
.pt-tv__leader--rest { padding: 6px 12px; color: var(--text-muted); font-weight: 600; }

/* Grote groepen op de tv: kleinere chips, anders past de dok niet. */
.pt-tv__spelers--compact { gap: 4px 6px; }
.pt-tv__spelers--compact .pt-tv__speler { font-size: calc(clamp(.65rem, .9vw, .85rem) * var(--maat, 1)); padding: 2px 8px 2px 2px; gap: 5px; }
.pt-tv__spelers--compact .pt-avatar--sm { width: 20px; height: 20px; font-size: .55rem; }
/* Het telletje aan het eind van de namenlijst: wie er niet meer bij pastte. */
.pt-tv__speler--meer { font-weight: 700; color: var(--text-muted); padding-left: 10px; }
.pt-tv__crash-lijst--compact { gap: 3px 4px; }
.pt-tv__crash-lijst--compact .pt-tv__crash-item { font-size: calc(clamp(.6rem, .8vw, .8rem) * var(--maat, 1)); padding: 2px 6px 2px 2px; max-width: calc(clamp(160px, 18vw, 300px) * var(--maat, 1)); }
.pt-tv__crash-lijst--compact .pt-tv__crash-item img, .pt-tv__crash-lijst--compact .pt-tv__crash-hoes { width: 18px; height: 18px; }

/* Deelnemers in de console: compact, twee regels per persoon. */
.pt-gastrij { padding: var(--s-2) 0; }
.pt-gastrij__onder { display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); margin-top: 6px; flex-wrap: wrap; }
.pt-gastrij__onder .pt-rechten { margin-top: 0; gap: 4px; flex: 1 1 auto; }
.pt-gastrij__onder .pt-recht { padding: 2px 7px; font-size: .72rem; gap: 4px; }
.pt-gastrij__geef { display: flex; align-items: center; gap: 4px; flex: 0 0 auto; }
.pt-gastrij__geef .pt-krachtkeuze { flex: 0 1 auto; width: auto; max-width: 150px; padding-top: 4px; padding-bottom: 4px; font-size: .8rem; }
.pt-gastrij__geef .pt-btn--icon { min-width: 30px; height: 30px; padding: 0; }

/* ------------------------------------------------------------- beheertabel */

.pt-tabel { width: 100%; border-collapse: collapse; font-size: .95rem; }
.pt-tabel th, .pt-tabel td { padding: 10px var(--s-3); text-align: left; vertical-align: top; border-bottom: 1px solid var(--line); }
.pt-tabel th { font-size: .72rem; letter-spacing: .08em; text-transform: uppercase; color: var(--text-faint); font-weight: 700; white-space: nowrap; }
.pt-tabel__num { text-align: right !important; font-variant-numeric: tabular-nums; }

/*
   De partylijst: zes kolommen en een rij knoppen in een leeskolom van 1180px.

   Hij paste er net niet in, en dan sta je op elk scherm naar rechts te
   schuiven voor knoppen die er gewoon zijn. De kaart breder maken dan de rest
   loste dat op, maar dan steekt er een kaart uit tussen de andere en dat
   staat niet. Dus halen we de ruimte uit de kolommen zelf: een getal heeft
   geen tien tekens nodig en een datum staat prima zonder lucht eromheen, dus
   die krimpen tot hun inhoud. Dit staat hier en niet bovenaan bij de andere
   breedtes, want anders wint de algemene padding hieronder ervan.
*/
.pt-tabel--partys th,
.pt-tabel--partys td { padding-left: var(--s-2); padding-right: var(--s-2); }

.pt-tabel--partys .pt-tabel__num,
.pt-tabel--partys .pt-tabel__datum { width: 1%; white-space: nowrap; }
.pt-tabel__pijl { color: var(--text-faint); text-align: right !important; width: 1%; }
.pt-tabel__rij { cursor: pointer; }
.pt-tabel__rij:hover { background: var(--surface-2); }
.pt-tabel__rij.is-open { background: var(--surface-2); }
.pt-tabel__rij.is-open td { border-bottom-color: transparent; }
.pt-tabel__detail td { background: var(--surface-2); padding: var(--s-2) var(--s-4) var(--s-4); }
.pt-tabel tbody tr:last-child td { border-bottom: 0; }
.pt-tabel__rij--stil { cursor: default; }
.pt-tabel__rij--stil:hover { background: transparent; }
.pt-tabel__sort {
  background: none; border: 0; padding: 0; cursor: pointer;
  font: inherit; color: inherit; letter-spacing: inherit; text-transform: inherit;
}
.pt-tabel__sort:hover { color: var(--text); }
.pt-tabel__sort.is-op::after { content: ' \2191'; color: var(--brand); }
.pt-tabel__sort.is-af::after { content: ' \2193'; color: var(--brand); }
.pt-tabel__voet {
  display: flex; align-items: center; justify-content: space-between; gap: var(--s-3);
  padding: var(--s-3) var(--s-3);
  border-top: 1px solid var(--line);
}

/* ------------------------------------------------------------- dj-login */

.pt-login { width: min(100%, 440px); display: flex; flex-direction: column; gap: var(--s-4); text-align: center; }
.pt-login__kop { display: flex; flex-direction: column; align-items: center; gap: var(--s-3); margin-top: var(--s-2); }
.pt-login__kop .pt-muted { max-width: 30ch; }
.pt-login__icoon {
  display: grid; place-items: center;
  width: 72px; height: 72px; border-radius: 50%;
  background: radial-gradient(circle at 30% 30%, rgba(30, 215, 96, .35), rgba(30, 215, 96, .08) 70%);
  border: 1px solid rgba(30, 215, 96, .35);
  box-shadow: 0 0 40px rgba(30, 215, 96, .18);
}
.pt-login__icoon svg { width: 34px; height: 34px; fill: none; stroke: var(--brand); stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }

/*
 * De gloed ademt.
 *
 * Langzaam en klein: vier en een halve seconde heen en terug, en het verschil
 * tussen laag en hoog is net genoeg om te zien dat er iets leeft. Sneller of
 * sterker wordt het een knipperlicht, en dit is een inlogscherm en geen
 * nooduitgang.
 *
 * De ruststand staat op 0% en 100%. Dat is met opzet: wie in zijn systeem
 * heeft staan dat hij geen bewegende beelden wil, krijgt van de regel
 * bovenin dit bestand een animatie van een honderdste milliseconde die één
 * keer loopt, en komt dus precies op die ruststand uit.
 */
.pt-login__icoon { animation: pt-gloed-adem 3.6s ease-in-out infinite; }

/*
 * Twee schaduwlagen in allebei de standen: een strakke om de cirkel en een
 * wijde eromheen. Die tweede doet het meeste werk, want een grote zachte
 * gloed valt eerder op dan een felle rand. Het moeten er in beide
 * sleutelstanden evenveel zijn, anders springt het in plaats van te vloeien.
 *
 * De vulling van de cirkel ademt mee. Alleen een halo eromheen bleef te
 * braaf; nu wordt het schijfje zelf ook groener. Het verloop heeft in beide
 * standen dezelfde vorm, anders kan de browser er niet tussenin rekenen en
 * klapt hij halverwege om in plaats van te vloeien.
 */
@keyframes pt-gloed-adem {
  0%, 100% {
    box-shadow: 0 0 22px rgba(30, 215, 96, .14), 0 0 46px rgba(30, 215, 96, .06);
    border-color: rgba(30, 215, 96, .28);
  }
  50% {
    box-shadow: 0 0 62px rgba(30, 215, 96, .70), 0 0 120px rgba(30, 215, 96, .34);
    border-color: rgba(30, 215, 96, 1);
  }
}

/*
 * De vulling ademt mee, maar via een laagje eroverheen en niet via het
 * verloop zelf. Een radial-gradient laat zich niet altijd doorrekenen: in de
 * proef stond hij op een kwart van de cyclus al op de eindwaarde en klapte
 * hij dus om in plaats van te vloeien. Doorzichtigheid rekent wel netjes door.
 *
 * Het laagje ligt over de cirkel maar onder het pictogram, anders ademt het
 * koptelefoontje mee de mist in.
 */
.pt-login__icoon { position: relative; }
.pt-login__icoon > svg { position: relative; z-index: 1; }
.pt-login__icoon::after {
  content: '';
  position: absolute;
  inset: -1px;
  border-radius: 50%;
  background: radial-gradient(circle at 30% 30%, rgba(30, 215, 96, .45), rgba(30, 215, 96, .14) 70%);
  opacity: 0;
  pointer-events: none;
  animation: pt-gloed-vulling 3.6s ease-in-out infinite;
}

@keyframes pt-gloed-vulling {
  0%, 100% { opacity: 0; }
  50%      { opacity: 1; }
}

.pt-btn--lg { min-height: 56px; font-size: 1.05rem; gap: 10px; }
/* Een lijn-icoontje in een knop, in de kleur van de tekst. De Spotify-glyph
   hieronder is gevuld, want zo hoort die van Spotify; dit is de tegenhanger
   voor al het andere. */
.pt-btn__ikoon {
  /* Maat komt van `.pt-btn svg` hierboven, die is specifieker; hier een
     eigen width zetten doet niets en liegt alleen in de code. */
  fill: none; stroke: currentColor; stroke-width: 1.8;
  stroke-linecap: round; stroke-linejoin: round;
}
.pt-btn__spotify { width: 22px; height: 22px; fill: #0b1210; }
.pt-btn__spotify circle { fill: #0b1210; }
.pt-btn__spotify path { stroke: var(--brand); }

.pt-login__form { text-align: left; margin-top: var(--s-2); }
.pt-login__form .pt-field { text-align: left; }

/* Koppelen: dezelfde kop als de login, daaronder genummerde stappen. */
.pt-koppel { padding-top: var(--s-6); }
/* De inleiding onder de kop mag hier breder dan op de inlogpagina. Daar is
   het een halve zin en past 30ch prima; hier is het een hele en werden het
   drie opgepropte regeltjes midden op een breed scherm. */
.pt-koppel .pt-login__kop .pt-muted { max-width: 46ch; }
.pt-koppel__stap { display: flex; align-items: center; gap: var(--s-3); margin: var(--s-6) 0 var(--s-3); }
.pt-koppel__nr {
  display: grid; place-items: center; flex: 0 0 auto;
  width: 30px; height: 30px; border-radius: 50%;
  background: var(--brand); color: #0b1210; font-weight: 800; font-size: .9rem;
}
.pt-login__voetnoot { text-align: center; margin: var(--s-2) 0 0; font-size: .64rem; line-height: 1.4; color: var(--text-faint); opacity: .8; }
.pt-login__voetnoot a, .pt-login__voetnoot a:visited { white-space: nowrap; color: var(--text-faint); text-decoration-color: rgba(255,255,255,.25); }
/*
 * Het vinkje in een eigen vakje, even breed als de knop eronder.
 *
 * Los boven de knop leek het scheef te staan: een vierkant vinkje tegen de
 * ronde zijkant van een pilknop. In een vakje met dezelfde hoeken en dezelfde
 * breedte staan ze op één lijn, en het leest als iets wat bij de knop hoort.
 */
.pt-login__akkoord {
  display: flex; align-items: flex-start; gap: 10px;
  margin: 0 0 var(--s-3);
  padding: var(--s-3);
  border-radius: var(--r-lg);
  border: 1px solid var(--line);
  background: var(--surface);
  font-size: .82rem; color: var(--text-muted); line-height: 1.4; text-align: left;
  cursor: pointer;
}
.pt-login__akkoord:hover { border-color: var(--line-strong); }
.pt-login__akkoord input { width: 18px; height: 18px; margin: 1px 0 0; accent-color: var(--brand); flex: 0 0 auto; }
.pt-login__akkoord a { color: var(--text); }

/*
 * De merkjes onder de knop in een raster.
 *
 * Gewoon gecentreerd zwierven ze per regel alle kanten op, en dan oogt het
 * rommelig onder een knop die netjes de hele breedte vult. Nu vullen ze twee
 * kolommen die precies tussen dezelfde randen staan.
 */
.pt-login__chips {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: var(--s-2);
  margin-top: calc(-1 * var(--s-2));
}
.pt-login__chips .pt-chip {
  justify-content: center;
  text-align: center;
  white-space: normal;
  padding: 6px 10px;
}

/* Er staan er twee naast elkaar, ook op een laptop, want de inlogkaart is
   altijd smal. Blijft er een over, dan maakt die de rij af in plaats van
   halfbreed links te blijven hangen. */
.pt-login__chips > :last-child:nth-child(odd) { grid-column: 1 / -1; }

/*
 * De scheiding naar het koppelen.
 *
 * Dit werd over het hoofd gezien, en dat kost een nieuwe DJ een foutmelding
 * van Spotify die hij niet begrijpt. Dus geen grijs regeltje meer tussen twee
 * streepjes, maar een kopje in de merkkleur dat je ziet staan.
 */
.pt-login__scheiding {
  display: flex; align-items: center; gap: var(--s-3);
  margin-top: var(--s-5);
  color: var(--brand); font-size: .82rem; font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase; white-space: nowrap;
}
.pt-login__scheiding::before, .pt-login__scheiding::after {
  content: ''; flex: 1; height: 1px;
  background: linear-gradient(90deg, transparent, var(--brand-dim));
}
.pt-login__scheiding::after { background: linear-gradient(90deg, var(--brand-dim), transparent); }

.pt-wegen { display: grid; gap: var(--s-2); }
.pt-weg {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-3) var(--s-4);
  border-radius: var(--r-lg);
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--text); text-decoration: none; text-align: left;
  transition: border-color .15s ease, background .15s ease, transform .1s ease;
}
.pt-weg:hover { border-color: rgba(30, 215, 96, .5); background: var(--surface-2); text-decoration: none; }
/* De weg die een nieuwe DJ moet nemen: die mag opvallen. */
.pt-weg--eerst { border-color: rgba(30, 215, 96, .45); background: rgba(30, 215, 96, .06); }
.pt-weg--eerst .pt-weg__icoon { background: rgba(30, 215, 96, .16); }
.pt-weg:active { transform: scale(.985); }
.pt-weg__icoon {
  display: grid; place-items: center;
  width: 44px; height: 44px; flex: 0 0 auto; border-radius: 12px;
  background: rgba(30, 215, 96, .12);
}
.pt-weg__icoon svg { width: 22px; height: 22px; fill: none; stroke: var(--brand); stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.pt-weg__tekst { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 auto; }
.pt-weg__tekst strong { font-size: .98rem; }
.pt-weg__tekst span { font-size: .84rem; color: var(--text-muted); line-height: 1.35; }
.pt-weg__pijl { flex: 0 0 auto; }
.pt-weg__pijl svg { width: 20px; height: 20px; fill: none; stroke: var(--text-faint); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.pt-weg:hover .pt-weg__pijl svg { stroke: var(--brand); }

/* ------------------------------------------------------------- startpagina */

/* Ruimte onderaan voor de menubalk, ook op een telefoon met een rand. */
.pt-met-tabbar { padding-bottom: calc(64px + env(safe-area-inset-bottom)); }
/* De login staat in het midden van het scherm; zonder dit zakt hij achter de balk. */
.pt-met-tabbar .pt-centered { min-height: calc(100dvh - 64px - env(safe-area-inset-bottom)); }
.pt-home__top { min-height: calc(100dvh - 64px - env(safe-area-inset-bottom)); padding-bottom: var(--s-5); }
/* Op een telefoon moet de teaser boven de balk uitkomen: de plaat en de
   tussenruimtes wat kleiner, zodat alles in een scherm past. */
@media (max-height: 820px) {
  .pt-home__top .pt-home-plaat { width: min(46vw, 190px); margin-top: var(--s-3); }
  .pt-home__top .pt-stack > * + * { margin-top: var(--s-3); }
  .pt-home__top .pt-h1 { margin-top: var(--s-3) !important; }
}
@media (max-height: 700px) {
  .pt-home__top .pt-home-plaat { width: min(36vw, 150px); }
}
.pt-home__meer {
  display: inline-flex; flex-direction: column; align-items: center; gap: 8px;
  margin-top: var(--s-2);
  font-size: .85rem; color: var(--text-muted); text-decoration: none;
}
.pt-home__meer:hover { color: var(--text); text-decoration: none; }
.pt-home__meer-knop {
  display: grid; place-items: center;
  width: 36px; height: 36px; border-radius: 50%;
  border: 1px solid var(--line-strong);
  background: var(--surface-2);
  animation: pt-home-wenk 1.8s ease-in-out infinite;
}
.pt-home__meer-knop svg { width: 18px; height: 18px; fill: none; stroke: var(--brand); stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.pt-home__meer:hover .pt-home__meer-knop { border-color: var(--brand); }
@keyframes pt-home-wenk { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(5px); } }

/*
   Een stuk van de voorpagina, met een waas boven de kop.

   De pagina is bijna zwart en elk stuk begint met een streepje en dan tekst.
   Dat leest als een lijst en niet als een pagina. Een zacht groen waas dat
   vanaf de bovenrand wegloopt zet een lamp boven de kop: je ziet waar een
   stuk begint, en het is dezelfde gloed als achter de platen op de kaartjes
   en om het icoontje op het inlogscherm.

   Breder dan de tekst en veel hoger dan de kop, want een waas dat je kunt
   aanwijzen is geen waas meer maar een vlek. Hij loopt op zeventig procent
   van zijn hoogte al naar niets toe.

   Het waas staat onder de tekst. Vandaar de relatieve stand op de sectie en
   op wat erin staat; zonder dat laatste ligt het laagje over de kop heen en
   kleurt de tekst mee.
*/
.pt-home__promo {
  position: relative;
  padding: var(--s-6) var(--s-4) var(--s-7);
  border-top: 1px solid var(--line);
}
.pt-home__promo::before {
  content: '';
  position: absolute;
  /* Links en rechts op nul met automatische marges: zo staat het laagje in
     het midden en kan het nooit breder worden dan de sectie. Met een breedte
     plus translateX van een halve stak het op een telefoon aan weerszijden
     uit, en dan schuift de hele pagina zijwaarts. Een overflow:hidden op de
     sectie zou dat ook oplossen, maar die knipt meteen de gloed af van een
     kaartje dat tegen de rand aan ligt. */
  left: 0;
  right: 0;
  top: 0;
  max-width: 980px;
  margin-left: auto;
  margin-right: auto;
  height: 440px;
  background: radial-gradient(58% 100% at 50% 0%, rgba(30, 215, 96, .13), rgba(30, 215, 96, 0) 70%);
  pointer-events: none;
}
.pt-home__promo > * { position: relative; }
.pt-home__kaarten {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--s-3);
  margin-top: var(--s-5);
}
/* De prijspagina: gratis en Plus naast elkaar, daaronder de drie manieren om
   Plus te nemen. Op een telefoon onder elkaar, want vergelijken in twee smalle
   kolommen leest niet. */
.pt-prijs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--s-3);
  margin-top: var(--s-4);
}
.pt-prijs__kaart {
  display: flex; flex-direction: column;
  padding: var(--s-4);
  border-radius: var(--r-lg);
  border: 1px solid var(--line);
  background: var(--surface);
}
.pt-prijs__kaart--plus { border-color: rgba(29, 185, 84, .45); background: var(--surface-2); }
.pt-prijs__naam { font-weight: 700; letter-spacing: .1em; text-transform: uppercase; font-size: .8rem; color: var(--text-muted); }
.pt-prijs__bedrag { font-size: 1.9rem; font-weight: 800; line-height: 1.2; margin-top: 4px; }
.pt-prijs__onder { font-size: .85rem; color: var(--text-faint); }
.pt-prijs__lijst { list-style: none; padding: 0; margin: var(--s-3) 0 0; display: flex; flex-direction: column; gap: 8px; }
.pt-prijs__lijst li { position: relative; padding-left: 22px; font-size: .92rem; line-height: 1.45; color: var(--text-muted); }
.pt-prijs__lijst li::before {
  content: '';
  position: absolute; left: 2px; top: .45em;
  width: 10px; height: 5px;
  border-left: 2px solid var(--brand); border-bottom: 2px solid var(--brand);
  transform: rotate(-45deg);
}
.pt-prijs__plannen {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: var(--s-3);
  margin-top: var(--s-4);
}
.pt-prijs__plan {
  display: flex; flex-direction: column; gap: 2px;
  padding: var(--s-3);
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background: var(--surface);
  text-align: center;
}
.pt-prijs__plannaam { font-size: .85rem; color: var(--text-muted); }
.pt-prijs__planbedrag { font-size: 1.4rem; font-weight: 800; }
.pt-prijs__planregel { font-size: .8rem; color: var(--text-faint); line-height: 1.4; }

/*
 * Een kaartje op de startpagina: het icoontje naast de kop, de tekst eronder.
 *
 * Het icoontje stond eerst bovenop, met de kop eronder; dan is het een los
 * plaatje dat boven de tekst zweeft. Naast elkaar horen ze bij elkaar, en
 * omdat de rij in het midden uitlijnt blijft dat kloppen als de kop over
 * twee regels loopt.
 */
.pt-home__kaart {
  display: grid;
  grid-template-columns: 40px minmax(0, 1fr);
  column-gap: var(--s-3);
  row-gap: var(--s-2);
  align-items: center;
  /* De kaartjes in een rij zijn even hoog, en de rijen binnen een kaartje
     rekken standaard mee om die hoogte op te vullen. Daardoor stond er bij
     een kaartje met weinig tekst een gat van veertig pixels tussen de kop en
     de tekst, precies bij de kaartjes die je het snelst wilt lezen. Met start
     blijven de rijen zo hoog als hun inhoud en zakt de overgebleven ruimte
     naar de onderkant, waar niemand hem ziet. */
  align-content: start;
  padding: var(--s-4);
  border-radius: var(--r-lg);
  border: 1px solid var(--line);
  background: var(--surface);
}
/* De kop van een kaartje is een strong en geen h, dus hij liep de regel bij
   de koppen mis en bleef in de systeemletter staan naast koppen die dat niet
   deden. Dat zag je meteen. */
.pt-home__kaart strong { grid-column: 2; grid-row: 1; font-family: var(--font-kop); font-size: 1rem; line-height: 1.3; }
.pt-home__kaart > span:last-child {
  grid-column: 1 / -1;
  grid-row: 2;
  font-size: .9rem; color: var(--text-muted); line-height: 1.5;
}
.pt-home__icoon {
  grid-column: 1; grid-row: 1;
  display: grid; place-items: center;
  width: 40px; height: 40px; border-radius: 12px;
  background: rgba(30, 215, 96, .14);
  font-size: 1.3rem; line-height: 1;
}

/*
   De kaartjes reageren op de muis.

   Een rij kaartjes op een donkere pagina is een rij vlakken die allemaal
   hetzelfde zijn. Met een randje en een gloed onder de muis weet je welke je
   aanwijst, en in de kaartjes waar een link in zit zie je dat er iets te
   klikken valt.

   Het is dezelfde gloed als op het inlogscherm: een randje in het groen en
   twee schaduwlagen, een strakke en een wijde. Die tweede doet het meeste
   werk, want een grote zachte gloed valt eerder op dan een felle rand. Daar
   ademt hij vanzelf, hier komt hij op bij de muis, met dezelfde kleuren zodat
   het één ding blijft.

   Alles staat in een hover-media-query. Op een telefoon blijft een
   hover-stand hangen na een tik, en dan licht er een kaartje op dat niemand
   meer aanwijst.

   De achtergrond van het vakje om een icoontje is met opzet een vlakke kleur
   en geen verloop. Een verloop rekent een browser niet door, dus dat klapt om
   in plaats van op te komen. Zie ook de notitie bij het inlogscherm.
*/
.pt-home__kaart,
.pt-spellijst li,
.pt-prijs__kaart,
.pt-prijs__plan {
  transition: border-color .2s ease, box-shadow .2s ease, transform .2s ease;
}
.pt-home__icoon { transition: background-color .2s ease, box-shadow .2s ease; }
.pt-home__icoon svg,
.pt-spellijst__icoon svg { transition: filter .2s ease; }

@media (hover: hover) {
  .pt-home__kaart:hover,
  .pt-spellijst li:hover,
  .pt-prijs__kaart:hover,
  .pt-prijs__plan:hover {
    border-color: rgba(30, 215, 96, .55);
    box-shadow: 0 0 22px rgba(30, 215, 96, .15), 0 0 54px rgba(30, 215, 96, .07);
    transform: translateY(-2px);
  }

  /* Het vakje om het icoontje wordt groener en krijgt een halo. */
  .pt-home__kaart:hover .pt-home__icoon {
    background-color: rgba(30, 215, 96, .30);
    box-shadow: 0 0 20px rgba(30, 215, 96, .45), 0 0 42px rgba(30, 215, 96, .20);
  }

  /* De tekening zelf gloeit op. Een drop-shadow en geen box-shadow: die
     laatste zet een gloed om het vierkante vak van de svg, en dan zie je een
     groen blokje in plaats van een oplichtend tekeningetje. */
  .pt-home__kaart:hover .pt-home__icoon svg,
  .pt-spellijst li:hover .pt-spellijst__icoon svg {
    filter: drop-shadow(0 0 7px rgba(30, 215, 96, .85));
  }

  /* De drie kaartjes met een plaat hebben geen icoontje. Daar wordt het waas
     achter de plaat sterker, zodat ook die kaartjes meedoen. */
  .pt-home__kaart:hover .pt-plaatcover::before { opacity: 1; }
}

/*
   De spellen krijgen een draai.

   De twee lijstjes onder elkaar zien er hetzelfde uit, en het zijn twee heel
   verschillende dingen: een spel kies je vooraf, een kracht zet je in tijdens
   het spel. Daarom krijgt elk zijn eigen beweging. Hier draait het teken één
   keer om zijn as, bij de krachten hieronder slaat het aan als een vonk.

   Alleen het tekeningetje draait en niet het kaartje. Een kaartje dat
   omklapt verbergt zijn eigen tekst, en juist die tekst is waarmee deze
   pagina gevonden wordt. Zie het gesprek erover.

   De perspective staat op het vakje eromheen en niet op de tekening zelf,
   anders draait hij plat rond in plaats van weg van je af.
*/
.pt-spellijst__icoon { perspective: 320px; }

@media (hover: hover) {
  .pt-spellijst--kaarten:not(.pt-spellijst--krachten) li:hover .pt-spellijst__icoon svg {
    animation: pt-spel-draai .6s ease;
  }
}

@keyframes pt-spel-draai {
  from { transform: rotateY(0); }
  to   { transform: rotateY(360deg); }
}

/*
   De superkrachten krijgen een vonk.

   De spellen zijn een opsomming, de superkrachten zijn iets dat je inzet. Dat
   verschil mag je zien: ga je over zo'n kaartje, dan slaat het teken aan als
   een lamp die onder stroom komt en gaat er een veeg licht overheen.

   Het aanslaan is met opzet geen nette opkomende gloed maar een flikkering:
   fel, even bijna uit, weer fel, en dan blijft hij staan. Dat laatste is
   precies dezelfde stand als de gewone hover hierboven, zodat er niets
   terugspringt op het moment dat het vonkje klaar is.

   De veeg loopt in een schuine baan over het kaartje. Hij staat over de
   tekst heen en niet eronder, want dat is wat een lichtveeg doet.

   Eén keer per keer dat je erover gaat, en niet herhalend: een kaartje dat
   blijft flikkeren is een storing en geen kracht.
*/
.pt-spellijst--krachten li {
  position: relative;
  /* De veeg moet binnen de afgeronde hoeken blijven. Dit knipt alleen wat
     erin staat; de gloed van de hover ligt erbuiten en blijft dus heel. */
  overflow: hidden;
}
.pt-spellijst--krachten li::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(105deg,
    rgba(30, 215, 96, 0) 38%,
    rgba(30, 215, 96, .14) 47%,
    rgba(198, 255, 222, .30) 50%,
    rgba(30, 215, 96, .14) 53%,
    rgba(30, 215, 96, 0) 62%);
  transform: translateX(-130%);
  pointer-events: none;
}

@media (hover: hover) {
  .pt-spellijst--krachten li:hover::after { animation: pt-kracht-veeg .7s ease-out; }
  .pt-spellijst--krachten li:hover .pt-spellijst__icoon svg { animation: pt-kracht-vonk .55s ease-out; }
}

@keyframes pt-kracht-veeg {
  from { transform: translateX(-130%); }
  to   { transform: translateX(130%); }
}

/*
 * De flikkering. De eindstand is gelijk aan de hover-stand van een gewoon
 * icoontje, dus als de animatie afloopt blijft het teken staan waar het al
 * stond. Zet je die hover-stand hierboven om, zet dan ook deze laatste
 * sleutelstand om, anders knipt het terug.
 */
@keyframes pt-kracht-vonk {
  0%   { transform: scale(1);    filter: drop-shadow(0 0 0 rgba(30, 215, 96, 0)); }
  16%  { transform: scale(1.24); filter: drop-shadow(0 0 15px rgba(205, 255, 226, 1)); }
  30%  { transform: scale(.96);  filter: drop-shadow(0 0 2px rgba(30, 215, 96, .35)); }
  46%  { transform: scale(1.12); filter: drop-shadow(0 0 13px rgba(140, 255, 196, .95)); }
  62%  { transform: scale(1);    filter: drop-shadow(0 0 4px rgba(30, 215, 96, .5)); }
  100% { transform: scale(1);    filter: drop-shadow(0 0 7px rgba(30, 215, 96, .85)); }
}


/*
   Dezelfde gloed in de console.

   De kaartjes op de voorpagina lichten op onder de muis, en de dingen in de
   console waar je op klikt deden dat nog met een grijs randje. Nu is het
   dezelfde gloed met dezelfde kleuren, zodat het een geheel is.

   Alleen wat je aanklikt: de spelkaartjes en de rijen in het menu. De panelen
   eromheen niet, want daar werk je in, die klik je niet aan. Een console waar
   bij elke muisbeweging iets staat op te lichten werkt niet prettig als je er
   een avond achter zit.

   Het optillen is hier een pixel en op de voorpagina twee. Daar bekijk je een
   rij kaartjes, hier sta je te werken tussen de knoppen.
*/
@media (hover: hover) {
  .pt-spelkaart:hover,
  .pt-menu__rij:hover {
    border-color: rgba(30, 215, 96, .55);
    background: var(--surface-3);
    box-shadow: 0 0 18px rgba(30, 215, 96, .13), 0 0 40px rgba(30, 215, 96, .06);
    transform: translateY(-1px);
  }

  .pt-menu__rij:hover .pt-menu__icoon,
  .pt-spelkaart:hover .pt-spelkaart__icoon {
    background-color: rgba(30, 215, 96, .28);
    box-shadow: 0 0 18px rgba(30, 215, 96, .4), 0 0 36px rgba(30, 215, 96, .18);
  }

  .pt-menu__rij:hover .pt-menu__icoon svg,
  .pt-spelkaart:hover .pt-spelkaart__icoon svg {
    filter: drop-shadow(0 0 6px rgba(30, 215, 96, .8));
  }

  /* Een spel dat niet kan doet ook niet alsof. Deze regel staat na de regels
     hierboven en is zwaarder, dus hij wint van allebei. */
  .pt-spelkaart.is-uit:hover {
    border-color: var(--line);
    background: var(--surface-2);
    box-shadow: none;
    transform: none;
  }
}

/*
   De grote teksten op de tv en in de console.

   De regel bij de koppen bovenin pakt h1 tot en met h4 en de pt-h-klassen.
   Op de tv en in de console zijn de grootste teksten geen koppen maar divs
   met een eigen klasse, en die bleven dus in de systeemletter staan. Op de
   tv zag je dat meteen: de naam van de party stond naast het woord
   PartyTracks, en die twee kwamen uit twee verschillende letters.

   De dikte gaat overal naar 700. Het bestand heeft alleen die ene dikte, en
   een browser die om 800 of 900 wordt gevraagd mag daar zelf iets dikkers
   van maken. Dat levert een veeg op in plaats van een letter.

   Wat hier bewust niet bij staat: de partycode op de tv, want die staat in
   een vaste-breedteletter zodat hij over te tikken is, en alles wat een
   getal toont. Unbounded heeft brede cijfers, en een scorebord dat breder
   wordt duwt het tv-scherm uit zijn hoogte. Zie [[partytracks-tv-geen-scroll]].
*/
.pt-tv__title,
.pt-tv__duwtje-kop,
.pt-roep__kop,
.pt-moment__title,
.pt-crash__text,
.pt-now__title {
  font-family: var(--font-kop);
  font-weight: 700;
}

/*
   Dezelfde effecten op een telefoon.

   Alles hierboven hangt aan hover, en op een telefoon bestaat dat niet. Daar
   komt het moment waarop je een kaartje tegenkomt met scrollen in de plaats.
   Een scriptje zet de klasse is-zicht op een kaartje dat goed in beeld staat
   en haalt hem er weer af als je verder scrolt; zie inBeeld in home.js.

   De regels zijn een kopie van die hierboven met is-zicht in plaats van
   hover. Dat kan niet in één blok, want de twee staan in een media-query die
   elkaar uitsluit. Pas je boven iets aan, pas het dan hier ook aan.
*/
@media (hover: none) {
  .pt-home__kaart.is-zicht,
  .pt-spellijst li.is-zicht {
    border-color: rgba(30, 215, 96, .55);
    box-shadow: 0 0 22px rgba(30, 215, 96, .15), 0 0 54px rgba(30, 215, 96, .07);
    transform: translateY(-2px);
  }

  .pt-home__kaart.is-zicht .pt-home__icoon {
    background-color: rgba(30, 215, 96, .30);
    box-shadow: 0 0 20px rgba(30, 215, 96, .45), 0 0 42px rgba(30, 215, 96, .20);
  }

  .pt-home__kaart.is-zicht .pt-home__icoon svg,
  .pt-spellijst li.is-zicht .pt-spellijst__icoon svg {
    filter: drop-shadow(0 0 7px rgba(30, 215, 96, .85));
  }

  .pt-home__kaart.is-zicht .pt-plaatcover::before { opacity: 1; }

  /* De plaat draait zolang het kaartje in beeld staat en staat stil zodra je
     hem voorbij bent. */
  .pt-home__kaart.is-zicht .pt-plaatcover .pt-vinyl__disc { animation-play-state: running; }

  /*
     De plaat bovenaan een gelegenheidspagina draait gewoon.

     Daar is maar één plaat en die is waar je naar kijkt als de pagina opent.
     Daar een scriptje voor laden dat bijhoudt of hij in beeld staat is meer
     werk dan het waard is.
  */
  .pt-plaatcover--hero .pt-vinyl__disc { animation-play-state: running; }

  /* De draai en de vonk, één keer als het kaartje in beeld komt. Omdat de
     klasse er bij het wegscrollen weer af gaat, loopt het opnieuw als je
     terugscrolt. */
  .pt-spellijst--kaarten:not(.pt-spellijst--krachten) li.is-zicht .pt-spellijst__icoon svg {
    animation: pt-spel-draai .6s ease;
  }
  .pt-spellijst--krachten li.is-zicht::after { animation: pt-kracht-veeg .7s ease-out; }
  .pt-spellijst--krachten li.is-zicht .pt-spellijst__icoon svg { animation: pt-kracht-vonk .55s ease-out; }
}

/* Rustige menubalk onderaan: vier icoontjes met een woord eronder. */
.pt-menubalk {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 20;
  display: grid; grid-template-columns: repeat(4, 1fr);
  padding: 6px 0 calc(6px + env(safe-area-inset-bottom));
  background: rgba(14, 16, 19, .86);
  -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  border-top: 1px solid var(--line);
}
.pt-menubalk__item {
  display: flex; flex-direction: column; align-items: center; gap: 3px;
  padding: 4px 2px;
  color: var(--text-faint); text-decoration: none;
  font-size: .68rem; letter-spacing: .01em;
}
.pt-menubalk__item svg { width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.pt-menubalk__item:hover, .pt-menubalk__item:focus-visible { color: var(--text); text-decoration: none; }
.pt-menubalk__item.is-actief { color: var(--brand); }
.pt-menubalk { grid-template-columns: repeat(5, 1fr); }

/* --------------------------------------------- deelnemerstabel in de console */

.pt-tabel--gasten th, .pt-tabel--gasten td { padding: 8px var(--s-2); vertical-align: middle; }
.pt-tabel--gasten td:first-child { max-width: 220px; }
.pt-rechten--tabel { margin-top: 0; flex-wrap: nowrap; gap: 4px; }
.pt-rechten--tabel .pt-recht { padding: 3px 7px; }
.pt-tabel__rij.is-weg td:first-child, .pt-tabel__rij.is-buiten td:first-child { opacity: .6; }
/*
   Een tabel die breder is dan zijn kaart schuift zijwaarts; op een telefoon
   worden die tabellen kaartjes en hoeft dat niet meer.

   Let op: een kaart knipt zijn inhoud af (overflow: hidden, voor de ronde
   hoeken). Zet je dan alleen overflow-x op visible, dan maakt de browser daar
   weer auto van, want visible en hidden kunnen niet naast elkaar. Daarom
   allebei de kanten in een keer.
*/
.pt-tabelvak { overflow-x: auto; }
@media (max-width: 719px) { .pt-tabelvak { overflow: visible; } }

/*
   De tabellen op de beheerpagina op een telefoon: kaartjes.

   Zes kolommen zijn vijfhonderdzeventig pixels breed in een vakje van
   driehonderdvijftig, dus je schoof zijwaarts om bij de stand of het pijltje
   te komen. Nu staat de naam op een eigen regel en staan de gegevens eronder
   op een rij, met het pijltje rechts. Openklappen werkt hetzelfde: de rij met
   details hangt er gewoon onder.
*/
@media (max-width: 719px) {
  #dj-tabel, #dj-tabel tbody, #dj-tabel tr, #dj-tabel td,
  #aanmeld-tabel, #aanmeld-tabel tbody, #aanmeld-tabel tr, #aanmeld-tabel td { display: block; }
  #dj-tabel thead, #aanmeld-tabel thead { display: none; }

  #dj-tabel tbody tr.pt-tabel__rij,
  #aanmeld-tabel tbody tr.pt-tabel__rij {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 10px;
    padding: 10px 2px;
    border-bottom: 1px solid var(--line);
  }
  #dj-tabel td, #aanmeld-tabel td { padding: 0; border: 0; }

  /* De naam over de volle breedte, de rest als regel eronder. */
  #dj-tabel tbody td:first-child,
  #aanmeld-tabel tbody td:first-child { flex: 1 1 100%; }
  #dj-tabel tbody td:not(:first-child),
  #aanmeld-tabel tbody td:not(:first-child) {
    flex: 0 1 auto; font-size: .8rem;
    /* Zonder dit liepen "7 party's", "3 dagen geleden" en "deze app" samen
       de rechterrand uit: een vakje dat niet mag krimpen blijft breed, ook
       als er geen plek meer is. */
    min-width: 0; max-width: 100%;
  }
  /* De regel met de cijfers onder een opengeklapte DJ breekt waar het moet. */
  #dj-tabel tr.pt-tabel__detail { overflow-wrap: anywhere; }
  /* Een los getal zegt niets zonder zijn kolomkop. */
  #dj-tabel tbody td:nth-child(3)::after { content: attr(data-eenheid); color: var(--text-faint); }
  #dj-tabel tbody td.pt-tabel__pijl { margin-left: auto; }
  /*
     De knoppen bij een aanmelding op een eigen regel, links.

     Ze werden naar rechts geduwd en vulden de regel waar ze toevallig
     terechtkwamen, dus begon elke rij knoppen op een andere plek. Onder
     elkaar op dezelfde linkerkant leest dat als een kaartje in plaats van
     als losse stukjes.
  */
  #aanmeld-tabel tbody td:last-child { flex: 1 1 100%; margin-top: 4px; }
  #aanmeld-tabel tbody td:last-child .pt-btnrow { justify-content: flex-start; flex-wrap: wrap; }

  /* De opengeklapte regel blijft gewoon een blok onder zijn eigen rij. */
  #dj-tabel tr.pt-tabel__detail td { display: block; padding: var(--s-2) 0 var(--s-3); }
}

/* De lade met de deelnemers mag breder zijn dan de andere panelen. */
.pt-lade--breed .pt-lade__vak { max-width: 1400px; }

/* Onder een breed scherm laten we het woord bij een recht weg; het plaatje
   met de rode streep zegt dan genoeg, en de tabel blijft in beeld. Op een
   telefoon schuift hij zijwaarts. */
@media (max-width: 1499px) {
  .pt-rechten--tabel .pt-recht__naam { display: none; }
  .pt-rechten--tabel .pt-recht { padding: 4px 7px; }
  .pt-rechten--tabel .pt-recht.is-uit { background: rgba(229, 72, 77, .18); border-color: rgba(229, 72, 77, .6); }
}
.pt-tabel--gasten .pt-krachtkeuze { width: 118px; }
.pt-tabel--gasten td:first-child { max-width: 200px; }

/*
   De deelnemers op een telefoon: kaartjes in plaats van een tabel.

   De tabel is negenhonderd pixels breed en stond in een vakje van
   driehonderdvijftig, dus je schoof zijwaarts om bij de knoppen te komen en
   zag de naam niet meer waar ze bij hoorden. Nu wordt elke deelnemer een
   kaartje van drie regels: wie het is met zijn stand, wat hij mag met de
   deurknop erachter, en onderaan het geven en afnemen van een superkracht.

   De kolomkoppen vallen weg en daarmee het sorteren; daarvoor staat boven de
   lijst een keuzelijst, net als bij de bibliotheken op het dashboard.
*/
@media (max-width: 719px) {
  .pt-tabel--gasten,
  .pt-tabel--gasten tbody,
  .pt-tabel--gasten tr,
  .pt-tabel--gasten td { display: block; }
  .pt-tabel--gasten thead { display: none; }
  .pt-tabel--gasten tr {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
    padding: 8px 2px;
    border-bottom: 1px solid var(--line);
  }
  .pt-tabel--gasten tbody tr:last-child { border-bottom: 0; }
  .pt-tabel--gasten td { padding: 0; border: 0; max-width: none; }

  /* Regel 1: wie het is, hoe hij erbij staat, wanneer hij voor het laatst keek. */
  .pt-tabel--gasten td:nth-child(1) { flex: 1 1 7em; min-width: 0; }
  .pt-tabel--gasten td:nth-child(2),
  .pt-tabel--gasten td:nth-child(3) { flex: 0 0 auto; }
  /* Iemand met veel superkrachten mag ze over twee regels zetten in plaats
     van de naam van de regel te duwen. */
  .pt-tabel--gasten td:nth-child(4) { flex: 0 1 auto; min-width: 0; }
  .pt-tabel--gasten .pt-krachtjes { flex-wrap: wrap; }

  /* Regel 2: wat hij mag. Regel 3: een superkracht geven of afnemen. */
  .pt-tabel--gasten td:nth-child(5) { flex: 1 1 100%; }
  .pt-tabel--gasten td:nth-child(6) { flex: 1 1 100%; }
  .pt-tabel--gasten .pt-rechten--tabel { flex-wrap: wrap; }
  .pt-tabel--gasten .pt-gastrij__geef { flex-wrap: wrap; }
  .pt-tabel--gasten .pt-krachtkeuze { width: auto; flex: 1 1 8em; min-width: 0; }
  .pt-gastrij__geenkracht { display: none; }

  /* De deur hoort niet tussen de plusjes; die zet iemand buiten. */
  .pt-tabel--gasten .pt-gastrij__geef .pt-btn--deur { margin-left: auto; }
}

/* ---------------------------------------------------------------------------
   Een laag scherm: de telefoon in liggende stand.

   Dat is 812 bij 375, dus extreem breed en extreem laag. De kop is gemaakt
   voor een echte tv en groeit mee met de breedte: de QR-code werd daardoor
   bijna de hele hoogte en van de draaitafel en de wachtrij bleef niets over.
   Op zo'n scherm laten we alles met de hoogte meeschalen in plaats van met
   de breedte. Scrollen doet een tv niet, dus het moet er gewoon in passen.
--------------------------------------------------------------------------- */
@media (min-width: 701px) and (max-height: 560px) {
  .pt-tv {
    gap: calc(8px * var(--maat, 1));
    --tv-rand: calc(clamp(10px, 2.4vh, 20px) * var(--maat, 1));
  }

  .pt-tv__head { gap: calc(12px * var(--maat, 1)); }
  .pt-tv__join {
    padding: calc(6px * var(--maat, 1)) calc(12px * var(--maat, 1));
    gap: calc(12px * var(--maat, 1));
  }
  .pt-tv__join > div:first-child svg { width: calc(min(21vh, 100px) * var(--maat, 1)); height: auto; }
  .pt-tv__code { font-size: calc(min(5.4vh, 1.8rem) * var(--maat, 1)); line-height: 1.1; }
  .pt-tv__join .pt-small { font-size: calc(min(2.8vh, .8rem) * var(--maat, 1)); line-height: 1.25; }
  .pt-tv__join-sub,
  .pt-tv__join-groei { margin-top: 1px; line-height: 1.2; }

  /*
   * De bronvermelding klein houden.
   *
   * In een party waar alles door elkaar staat zijn het er twee, en samen
   * vulden ze bijna de helft van het kaartje. Op een liggende telefoon is dat
   * de ruimte die het beeld nodig heeft. Ze blijven staan, want ze horen bij
   * de voorwaarden van Spotify en YouTube, maar dan klein.
   */
  .pt-tv__join .pt-bron--tv {
    padding: 2px 7px;
    margin-top: 3px;
    font-size: calc(min(2.3vh, .7rem) * var(--maat, 1));
    gap: 5px;
  }
  .pt-tv__join .pt-bron--tv .pt-bron__merk { width: 13px; height: 13px; }

  .pt-tv__dj-foto { width: calc(min(14vh, 62px) * var(--maat, 1)); height: calc(min(14vh, 62px) * var(--maat, 1)); }
  .pt-tv__dj-naam { font-size: calc(min(2.6vh, .8rem) * var(--maat, 1)); }
  .pt-tv__title { font-size: calc(min(7vh, 1.8rem) * var(--maat, 1)); }

  /* Alles wat hoogte vraagt, mag hier bescheiden zijn. */
  .pt-tv__now-title { font-size: calc(min(7vh, 1.7rem) * var(--maat, 1)); margin-top: calc(4px * var(--maat, 1)); }
  .pt-tv__now-artist { font-size: calc(min(4.4vh, 1.1rem) * var(--maat, 1)); }
  .pt-tv__item {
    padding: calc(3px * var(--maat, 1)) 0;
    font-size: calc(min(4vh, 1rem) * var(--maat, 1));
    grid-template-columns: auto calc(min(7vh, 42px) * var(--maat, 1)) minmax(0, 1fr) auto;
  }

  /*
   * De ruimte zit hier in de breedte, niet in de hoogte.
   *
   * Onder elkaar paste de draaitafel en de wachtrij niet meer: de plaat werd
   * afgesneden en het kopje STRAKS schoof over de titel heen. Naast elkaar
   * heeft allebei de volle hoogte. Dat gold al vanaf 900 pixels breed, maar
   * juist op een telefoon in liggende stand (die is smaller) was het nodig.
   */
  .pt-tv__body {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: calc(16px * var(--maat, 1));
  }

  /*
   * De knop die om een tik vraagt, dichter naar de onderrand.
   *
   * Hij staat vast onderin beeld en zweefde op een liggende telefoon midden
   * over de wachtrij. Lager en kleiner houdt hem zichtbaar zonder dat hij de
   * lijst afdekt.
   */
  .pt-tv__knoppen { bottom: calc(10px * var(--maat, 1)); gap: calc(6px * var(--maat, 1)); }
  .pt-tv__geluid { padding: calc(8px * var(--maat, 1)) calc(16px * var(--maat, 1)); font-size: calc(min(3.4vh, .95rem) * var(--maat, 1)); }

  /* En in de draaitafel de plaat naast de titel in plaats van erboven. */
  .pt-tv__now { flex-direction: row; align-items: center; gap: calc(12px * var(--maat, 1)); }
  /*
   * Behalve als er beeld is: een speler in een rij heeft geen eigen breedte
   * en kromp tot nul, waardoor er op een telefoon in liggende stand alleen
   * nog een titel stond. Met beeld blijft de clip dus boven de titel.
   */
  .pt-tv--video .pt-tv__now { flex-direction: column; align-items: stretch; }
  .pt-tv__now > div { min-width: 0; }
  .pt-tv__cover,
  .pt-tv__wachtplaat { flex: 0 0 auto; width: auto; height: 100%; max-height: min(26vh, 150px); aspect-ratio: 1 / 1; }
  .pt-tv__now-title { margin-top: 0; }
}

/*
 * Een heel laag liggend scherm: een telefoon in de breedte, met de balken van
 * de browser erbij. Dan blijft er nog geen 350 pixels hoogte over.
 *
 * Daar passen de kop, het beeld, de titel en de wachtrij niet meer naast en
 * onder elkaar zonder dat er iets overheen valt. Dus gaat eraf wat niet nodig
 * is om mee te doen: het weetje, het duwtje over foto's en de regel onder de
 * code. De kop krimpt verder, zodat het beeld de ruimte krijgt die overblijft.
 */
@media (min-width: 701px) and (max-height: 460px) {
  .pt-tv .pt-weetje,
  .pt-tv__duwtje,
  .pt-tv__join-groei,
  .pt-tv__join-sub { display: none; }
  /* "Scan of ga naar ..." staat ook al boven de code; op dit formaat is de
     code zelf genoeg. */
  .pt-tv__join > div:last-child > .pt-muted:first-child { display: none; }

  .pt-tv__join > div:first-child svg { width: calc(min(24vh, 76px) * var(--maat, 1)); height: auto; }
  .pt-tv__code { font-size: calc(min(6vh, 1.5rem) * var(--maat, 1)); }
  .pt-tv__join { padding: calc(5px * var(--maat, 1)) calc(10px * var(--maat, 1)); gap: calc(10px * var(--maat, 1)); }
  .pt-tv__join .pt-bron--tv { font-size: calc(min(2.6vh, .62rem) * var(--maat, 1)); padding: 1px 6px; }
  .pt-tv__join .pt-bron--tv .pt-bron__merk { width: 11px; height: 11px; }
  .pt-tv__title { font-size: calc(min(7vh, 1.4rem) * var(--maat, 1)); }
  .pt-tv__now-title { font-size: calc(min(7vh, 1.3rem) * var(--maat, 1)); }
  .pt-tv__now-artist { font-size: calc(min(4.4vh, .9rem) * var(--maat, 1)); }

  /* De wachtstand is een hele alinea; op dit formaat houden we er een regel
     van over, anders duwt hij het beeld van het scherm. */
  .pt-tv__wacht { font-size: calc(min(3.4vh, .8rem) * var(--maat, 1)); }
  .pt-tv__wacht .pt-empty__icon,
  .pt-tv__wacht .pt-tv__wachtplaat { display: none; }

  /*
   * En wat er onder het beeld staat mag hoogstens de helft pakken.
   *
   * Zonder die grens duwde een lange titel of de wachtstand het beeld tot een
   * postzegel van achttien bij tien pixels. Nu houdt de clip altijd de helft.
   */
  .pt-tv--video #tv-now { max-height: 48%; overflow: hidden; }
}

/* ------------------------------------------------------- tv op een telefoon */

/* Een tv-pagina op een telefoon (de DJ die even meekijkt, of een gast die
   het scherm niet kan zien): dan mag hij wel scrollen. Alles onder elkaar,
   de kop compact, de QR kleiner, en de lijsten helemaal in plaats van
   afgesneden op schermhoogte. */
@media (max-width: 700px) {
  .pt-tv { height: auto; min-height: 100dvh; overflow: visible; grid-template-rows: auto auto auto; gap: var(--s-4); }
  .pt-tv__head { flex-direction: column; align-items: stretch; gap: var(--s-3); }
  .pt-tv__head > div:first-child { flex: none; }
  .pt-tv__links { gap: var(--s-3); }
  .pt-tv__dj-foto { width: 56px; height: 56px; }
  .pt-tv__title { font-size: 1.35rem; }
  .pt-tv__join { max-width: none; width: 100%; padding: var(--s-3); gap: var(--s-3); }
  .pt-tv__join > div:first-child svg { width: 88px; height: 88px; }
  .pt-tv__code { font-size: 1.6rem; letter-spacing: .1em; }
  .pt-tv__body { grid-template-columns: 1fr; grid-template-rows: auto auto; overflow: visible; }
  .pt-tv__now { flex: none; }
  .pt-tv__cover { flex: none; width: min(100%, 220px); height: auto; }
  .pt-tv__now-title { font-size: 1.4rem; }
  .pt-tv__now-artist { font-size: 1rem; }
  .pt-tv__side { overflow: visible; }
  .pt-tv__list { flex: none; overflow: visible; -webkit-mask-image: none; mask-image: none; }
  .pt-tv__item { font-size: 1rem; grid-template-columns: auto 44px minmax(0, 1fr) auto; }
  #tv-hitster { flex: none; overflow: visible; }
}

/* ------------------------------------------------- snelstart in de console */

.pt-snelstart {
  margin-bottom: var(--s-4);
  padding: var(--s-3) var(--s-4) var(--s-4);
  border-radius: var(--r-lg);
  border: 1px solid rgba(30, 215, 96, .35);
  background: linear-gradient(180deg, rgba(30, 215, 96, .10), rgba(30, 215, 96, .03));
}
.pt-snelstart__kop { display: flex; align-items: center; justify-content: space-between; gap: var(--s-3); }
.pt-snelstart__stappen { display: grid; gap: var(--s-2); margin-top: var(--s-3); }
@media (min-width: 900px) { .pt-snelstart__stappen { grid-template-columns: repeat(3, 1fr); } }
.pt-snelstart__stap {
  display: flex; align-items: flex-start; gap: var(--s-3);
  padding: var(--s-3);
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--text); font: inherit; text-align: left; text-decoration: none;
  cursor: pointer;
  transition: border-color .15s ease, background-color .15s ease;
}
.pt-snelstart__stap:hover { border-color: var(--brand); background: var(--surface-2); text-decoration: none; }
.pt-snelstart__stap > span:last-child { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.pt-snelstart__stap > span:last-child > span { font-size: .82rem; color: var(--text-muted); line-height: 1.4; }
.pt-snelstart__stap a { color: var(--brand); }
.pt-snelstart__nr {
  display: grid; place-items: center; flex: 0 0 auto;
  width: 26px; height: 26px; border-radius: 50%;
  background: var(--brand); color: #0b1210; font-weight: 800; font-size: .85rem;
}

/* ------------------------------------------------ spelkeuze als kaarten */

.pt-spelkaarten { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: var(--s-2); }
.pt-spelkaart {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-3);
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background: var(--surface-2);
  color: var(--text); font: inherit; text-align: left;
  cursor: pointer;
  /* transform staat erbij voor het optillen onder de muis; zonder die naam
     in de rij springt het in plaats van te vloeien. */
  transition: border-color .15s ease, background-color .15s ease, box-shadow .15s ease, transform .15s ease;
}
.pt-spelkaart.is-uit { opacity: .45; cursor: not-allowed; }
.pt-spelkaart.is-uit:hover { border-color: var(--line); background: var(--surface-2); }
.pt-spelkaart.is-gekozen {
  border-color: var(--brand);
  background: rgba(30, 215, 96, .10);
  box-shadow: inset 0 0 0 1px var(--brand);
}
.pt-spelkaart__icoon {
  display: grid; place-items: center; flex: 0 0 auto;
  width: 40px; height: 40px; border-radius: 12px;
  background: rgba(255, 255, 255, .06);
  font-size: 1.3rem; line-height: 1;
  /* De tekening erin erft deze kleur; zie View::icoon. */
  color: var(--text-muted);
}
.pt-spelkaart__icoon svg { width: 1.35rem; height: 1.35rem; transition: filter .15s ease; }
.pt-spelkaart.is-gekozen .pt-spelkaart__icoon { background: rgba(30, 215, 96, .18); color: var(--brand); }
/* Gekozen, maar op deze bron niet mogelijk: oranje in plaats van groen, zodat
   niemand denkt dat dit spel straks draait. */
.pt-spelkaart.is-onmogelijk {
  opacity: 1;
  border-color: rgba(255, 203, 71, .55);
  background: rgba(255, 203, 71, .08);
  cursor: not-allowed;
}
.pt-spelkaart.is-onmogelijk .pt-spelkaart__icoon { background: rgba(255, 203, 71, .16); }
.pt-spelkaart.is-onmogelijk .pt-spelkaart__tekst span { color: var(--amber); }
.pt-spelkaart__tekst { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.pt-spelkaart__tekst strong { font-size: .95rem; }
.pt-spelkaart__tekst span { font-size: .8rem; color: var(--text-muted); line-height: 1.35; }

/*
   Een rij vinkjes, bijvoorbeeld welke superkrachten te winnen zijn.

   Dit waren losse labels met het vinkje van de browser ernaast: op een
   telefoon een doel van een paar millimeter, tussen tekst die net zo groot
   is. Nu is elk vinkje een vakje waar je met je duim in kan tikken, en het
   vinkje zelf is groter.
*/
/*
   Opschonen: drie groepjes knoppen met een kopje.

   Op een telefoon staat elke knop over de volle breedte onder elkaar. Als
   mozaiek van negen verschillend brede knoppen zag je niet welke er een
   streep door je avond haalt; nu staan ze op een rij en de rode onderaan,
   achter een lijn.
*/
/*
   Het sfeerlicht: zes kleuren en een flits.

   De kleuren zijn een keuze uit zes en horen dus als gelijke vakjes bij
   elkaar; als losse knoppen van elk hun eigen breedte vielen ze rafelig over
   twee regels en stond de flits er als zevende tussen alsof dat ook een
   kleur was. Nu een raster, met de flits ernaast en op een telefoon eronder.
*/
.pt-lichtvak { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); margin-top: var(--s-2); }
.pt-kleurgrid {
  flex: 1 1 16em;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(7.5em, 1fr));
  gap: 6px;
}
@media (max-width: 599px) {
  .pt-lichtvak__flits { flex: 1 1 100%; justify-content: center; }
}

.pt-opschoon { display: flex; flex-direction: column; gap: var(--s-4); }
.pt-opschoon__kop {
  display: block;
  font-size: .7rem;
  font-weight: 800;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: var(--s-2);
}
.pt-opschoon__groep--gevaar { border-top: 1px solid var(--line); padding-top: var(--s-3); }
.pt-opschoon__groep--gevaar .pt-opschoon__kop { color: var(--danger); }

@media (max-width: 599px) {
  .pt-btnrow--stapel { flex-direction: column; align-items: stretch; }
  .pt-btnrow--stapel > .pt-btn { width: 100%; justify-content: flex-start; }
}

.pt-vinkjes { display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-4); }
.pt-vinkje { display: inline-flex; align-items: center; gap: 6px; }
@media (max-width: 599px) {
  .pt-vinkjes { gap: 6px; }
  .pt-vinkje {
    flex: 1 1 calc(50% - 6px);
    min-height: 38px;
    padding: 4px 8px;
    border: 1px solid var(--line);
    border-radius: var(--r-md);
    background: var(--surface-2);
  }
  .pt-vinkje input[type="checkbox"] { width: 18px; height: 18px; flex: 0 0 auto; }
}

/*
   De spelkaarten op een telefoon: twee naast elkaar.

   Met een minimum van tweehonderd pixels past er op een telefoon maar een
   kaart naast elkaar, en negen spellen onder elkaar zijn zevenhonderd pixels
   scrollen om er een te kiezen. Twee kolommen met alleen het plaatje en de
   naam maken er driehonderd van. Wat een spel doet staat er zodra je kiest,
   in de regel onder 'Spel aan'.
*/
@media (max-width: 599px) {
  .pt-spelkaarten { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 6px; }
  .pt-spelkaart { gap: 8px; padding: 8px; }
  .pt-spelkaart__icoon { width: 32px; height: 32px; border-radius: 10px; font-size: 1.1rem; }
  .pt-spelkaart__tekst strong { font-size: .85rem; line-height: 1.2; }
  .pt-spelkaart__regel { display: none; }
  .pt-spelkaart__reden { font-size: .72rem; }
}

/* --------------------------------------------------- partytabel dashboard */

.pt-tabel--partys td { vertical-align: middle; }
.pt-tabel__naam { color: var(--text); font-weight: 700; text-decoration: none; }
.pt-tabel__naam:hover { color: var(--brand); text-decoration: none; }
.pt-code-pill--klein { font-size: .85rem; padding: 4px 8px; letter-spacing: .12em; }
/* De kolom krijgt de breedte die de code nodig heeft, niet andersom. */
.pt-tabel__codecel { white-space: nowrap; width: 1%; }
.pt-tabel__mobiel { display: none; }
@media (max-width: 700px) {
  /* Op een telefoon: naam met de cijfers eronder, status, en de knoppen; de
     losse kolommen vallen weg zodat de console-knop in beeld blijft. */
  .pt-tabel--partys th:nth-child(2), .pt-tabel--partys td:nth-child(2),
  .pt-tabel--partys th:nth-child(4), .pt-tabel--partys td:nth-child(4),
  .pt-tabel--partys th:nth-child(5), .pt-tabel--partys td:nth-child(5),
  .pt-tabel--partys th:nth-child(6), .pt-tabel--partys td:nth-child(6) { display: none; }
  .pt-tabel__mobiel { display: block; margin-top: 2px; }
  /* Elke rij wordt een kaartje: naam en status op de eerste regel, de
     knoppen eronder over de volle breedte. */
  .pt-tabel--partys thead { display: none; }
  .pt-tabel--partys tr { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); padding: var(--s-3); border-bottom: 1px solid var(--line); }
  .pt-tabel--partys td { display: block; padding: 0; border: 0; }
  .pt-tabel--partys td:first-child { flex: 1 1 0; min-width: 0; }
  .pt-tabel--partys td:nth-child(3) { flex: 0 0 auto; }
  .pt-tabel--partys td:last-child { flex: 0 0 100%; text-align: left !important; white-space: normal !important; }
  .pt-tabel--partys td:last-child .pt-btnrow { flex-wrap: wrap; justify-content: flex-start !important; }

}

/*
   De kolom met de knoppen krijgt precies de breedte die hij nodig heeft.

   Op een liggend scherm (een iPad, of een telefoon in de breedte) ging alle
   overgebleven ruimte naar de kolom 'waar gaat hij over', en viel de
   prullenbak onder de andere twee knoppen. Met width: 1% en nowrap neemt de
   tabel eerst de knoppen en de datum, en krijgt de omschrijving de rest.
*/
.pt-tabel__acties { width: 1%; white-space: nowrap; }
.pt-tabel__acties .pt-btnrow { flex-wrap: nowrap; }
.pt-tabel--quiz td:nth-child(5) { white-space: nowrap; }

/* De quizbibliotheek: zelfde tabel, zelfde gedrag op een telefoon. De
   cijfers en de datum vallen weg en staan in de regel onder de naam. */
@media (max-width: 700px) {
  .pt-tabel--quiz th:nth-child(2), .pt-tabel--quiz td:nth-child(2),
  .pt-tabel--quiz th:nth-child(3), .pt-tabel--quiz td:nth-child(3),
  .pt-tabel--quiz th:nth-child(4), .pt-tabel--quiz td:nth-child(4),
  .pt-tabel--quiz th:nth-child(5), .pt-tabel--quiz td:nth-child(5) { display: none; }
  .pt-tabel--quiz thead { display: none; }
  .pt-tabel--quiz tr { display: flex; flex-wrap: wrap; align-items: center; gap: var(--s-2); padding: var(--s-3); border-bottom: 1px solid var(--line); }
  .pt-tabel--quiz td { display: block; padding: 0; border: 0; }
  .pt-tabel--quiz td:first-child { flex: 1 1 0; min-width: 0; }
  /* De knoppen stonden op een eigen regel omdat ze met hun woorden erin de
     naam tot drie letters per regel knepen. Als pictogram passen ze ernaast
     en scheelt dat per rij een halve kaart. */
  .pt-tabel--quiz td:last-child { flex: 0 0 auto; text-align: right !important; }
  .pt-tabel--quiz td:last-child .pt-btnrow { flex-wrap: nowrap; gap: 4px; justify-content: flex-end !important; }
  /*
     De naam en de regel eronder blijven binnen hun eigen vak.

     Zonder dit liep een lange omschrijving ("57 nummers, Oktoberfest
     liedjes") gewoon door onder de drie knoppen heen. Het vak krimpt al mee,
     maar wat er niet in past moet ook echt worden afgeknipt.
  */
  .pt-tabel--quiz td:first-child { overflow: hidden; }
  .pt-tabel--quiz td:first-child > * { min-width: 0; max-width: 100%; }
  /*
     En het vak met de knoppen krijgt zijn eigen breedte terug.

     In de tabel staat er width: 1% op, zodat de kolom niet breder wordt dan
     de knoppen. In deze kaartweergave is de rij geen tabelrij meer maar een
     flexrij, en daar betekent 1% ook echt een procent: een vakje van drie
     pixels waar drie knoppen uit staken, boven op de tekst ernaast.
  */
  .pt-tabel--quiz td.pt-tabel__acties { width: auto; }
}

/* Een pictogram in een knop: even groot als de letters ernaast. */
.pt-btn__ico { width: 18px; height: 18px; flex: 0 0 auto; }
.pt-btn--kort { gap: 6px; }

/*
   Knoppen die inkrimpen tot hun pictogram.

   Op een breed scherm staat het woord erbij, want dat leest het snelst. Is
   er minder ruimte, dan blijft alleen het plaatje over. Dat gebeurt eerder
   dan bij de kaartweergave van de tabel: de rij knoppen staat in de laatste
   kolom, en met de woorden erin schoof die op een kleiner laptopscherm al
   voorbij de rand. Als plaatje passen ze altijd, en op een telefoon staan ze
   als vijf ronde knoppen netjes op een regel.
*/
@media (max-width: 1140px) {
  .pt-btn--kort .pt-btn__woord { display: none; }
  .pt-btn--kort { width: var(--tap); padding: 0; justify-content: center; }
}

/* ------------------------------------------------- bronkeuze bij nieuwe party */

/* De keuze 'waar komt de muziek vandaan' bij het aanmaken van een party.
   Heette eerst ook .pt-bron, net als de bronvermelding onder de speler, en
   die kaartopmaak won het daar: twee dikke blokken in plaats van twee
   regeltjes. Vandaar een eigen naam. */
.pt-bronnen { display: grid; gap: var(--s-2); }
.pt-bronkeuze {
  display: flex; align-items: flex-start; gap: var(--s-3);
  padding: var(--s-3);
  border-radius: var(--r-md);
  border: 1px solid var(--line);
  background: var(--surface-2);
  cursor: pointer;
}
.pt-bronkeuze:has(input:checked) { border-color: var(--brand); background: rgba(30, 215, 96, .08); }
.pt-bronkeuze.is-uit { opacity: .5; cursor: not-allowed; }
.pt-bronkeuze input { margin-top: 3px; accent-color: var(--brand); }
.pt-bronkeuze__tekst { display: flex; flex-direction: column; gap: 2px; }
.pt-bronkeuze__tekst span { font-size: .82rem; color: var(--text-muted); line-height: 1.4; }

/* --------------------------------------------------------------- het blok
   De lijst van het blok: pijlen om de volgorde te schuiven, en een jaartal
   dat je kunt aanklikken om het zelf in te vullen. */
.pt-blok__vak {
  margin-top: var(--s-3);
  padding: var(--s-3);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface-2);
}
.pt-blok__vak + .pt-blok__vak { margin-top: var(--s-2); }
/* Dezelfde regel als elders, maar met een kolom voor de pijltjes ervoor.
   Net als in de wachtrij lopen die pijltjes van de bovenkant tot de
   onderkant van de regel, zodat de kolom uitlijnt met het blokje ernaast. */
.pt-blok__clip { grid-template-columns: 34px 44px minmax(0, 1fr) auto; gap: var(--s-2); }
.pt-blok__pijlen {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  align-self: stretch;
  justify-content: space-between;
  gap: 2px;
  min-height: 44px;
}
.pt-blok__pijlen .pt-btn { width: 100%; flex: 1 1 0; min-height: 22px; max-height: 44px; padding: 0; }
.pt-blok__pijlen .pt-btn svg { width: 14px; height: 14px; }
.pt-blok__pijlen .pt-btn[disabled] { opacity: .25; cursor: default; }
/* Bij een origineel staat er geen knop maar een pijltje naar het nummer
   erboven. Dat hoort in het midden te blijven staan. */
.pt-blok__clip--origineel .pt-blok__pijlen { justify-content: center; align-items: center; }

/* Op een telefoon viel een clipregel uiteen over drie regels: artiest, het
   jaartal en het merkje kwamen dan allemaal onder elkaar. Dat maakte de
   lijst onnodig lang om doorheen te scrollen. Hier houden we alles op een
   regel: de artiest krijgt de ruimte die overblijft en kapt af met puntjes,
   de merkjes blijven heel, want die moet je kunnen lezen en aanklikken. */
@media (max-width: 599px) {
  .pt-blok__clip {
    grid-template-columns: 30px 36px minmax(0, 1fr) auto;
    gap: var(--s-2);
    padding: var(--s-1) var(--s-2);
  }
  .pt-blok__clip .pt-result__cover { width: 36px; height: 36px; }
  .pt-blok__pijlen { min-height: 36px; }
  .pt-blok__clip .pt-track__title {
    font-size: .95rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .pt-blok__clip .pt-track__sub {
    flex-wrap: nowrap;
    gap: var(--s-1);
    min-width: 0;
    font-size: .8rem;
  }
  .pt-blok__clip .pt-track__artist {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .pt-blok__clip .pt-chip { flex: 0 0 auto; padding: 2px 7px; font-size: .68rem; }
  /* Het merkje 'geweest' mag hier weg: een gespeelde regel is op de telefoon
     al te zien aan de gedempte kleur, en zo houdt de artiest zijn ruimte. */
  .pt-blok__clip.is-gespeeld .pt-chip:not(.pt-chip--knop):not(.pt-chip--brand) { display: none; }
  /* De artiest mag afkappen, maar niet helemaal verdwijnen. */
  .pt-blok__clip .pt-track__artist { flex: 0 1 auto; min-width: 5.5em; }
}
.pt-chip--knop { cursor: pointer; font-family: inherit; }
.pt-chip--knop:hover, .pt-chip--knop:focus-visible { border-color: var(--brand); color: var(--text); }
.pt-blok__jaar { width: 96px; }
/* Hetzelfde knopje in de wachtrij: het jaartal van een nummer rechtzetten. */
.pt-jaarknop { padding: 0 7px; font-size: .72rem; line-height: 1.5; }
.pt-jaarveld { width: 84px; }
.pt-mapkeuze { margin-top: var(--s-2); padding-top: var(--s-2); border-top: 1px solid var(--line); }
/*
 * De knop en "Ingesteld: ..." op dezelfde regel, netjes op het midden.
 * Zonder dit rekt de tekst over de hele hoogte van de knop uit en hangt hij
 * met zijn eerste regel bovenaan.
 */
.pt-mapkeuze .pt-btnrow,
#blok-map .pt-btnrow { align-items: center; }
.pt-mapkeuze .js-mapstand,
#blok-map .js-mapstand { align-self: center; }

/* ------------------------------------------------------------- de oproep
   Een spel dat nog moet beginnen vraagt iets van de zaal. Dat mag groot en
   vrolijk in beeld: een badge, een regel waar je meteen naar handelt, en een
   balk die vult naarmate er meer mensen klaar zijn. */
.pt-oproep {
  border-color: rgba(29, 185, 84, .45);
  background:
    radial-gradient(120% 140% at 0% 0%, rgba(29, 185, 84, .18), transparent 60%),
    var(--surface);
}
.pt-oproep.is-klaar { border-color: var(--brand); box-shadow: 0 0 0 1px rgba(29,185,84,.35), 0 10px 40px rgba(29,185,84,.15); }
.pt-oproep__kop { display: flex; align-items: center; gap: calc(clamp(10px, 1.2vw, 18px) * var(--maat, 1)); }
.pt-oproep__badge {
  flex: 0 0 auto;
  display: grid; place-items: center;
  width: calc(clamp(44px, 4.4vw, 74px) * var(--maat, 1));
  height: calc(clamp(44px, 4.4vw, 74px) * var(--maat, 1));
  border-radius: 50%;
  background: rgba(29, 185, 84, .16);
  border: 1px solid rgba(29, 185, 84, .4);
  font-size: calc(clamp(1.3rem, 2.2vw, 2.2rem) * var(--maat, 1));
  line-height: 1;
}
.pt-oproep__titel {
  font-size: calc(clamp(1.3rem, 2.4vw, 2.4rem) * var(--maat, 1));
  font-weight: 800; letter-spacing: -.01em; line-height: 1.1;
}
.pt-oproep__actie {
  margin-top: 2px;
  font-size: calc(clamp(.95rem, 1.5vw, 1.5rem) * var(--maat, 1));
  font-weight: 700; color: var(--brand);
}
.pt-oproep__tekst {
  margin-top: calc(clamp(6px, 1vh, 14px) * var(--maat, 1));
  color: var(--text-muted);
  font-size: calc(clamp(.85rem, 1.25vw, 1.25rem) * var(--maat, 1));
  line-height: 1.45;
}
.pt-oproep__tekst--klein { font-size: calc(clamp(.72rem, 1vw, 1rem) * var(--maat, 1)); color: var(--text-faint); }
.pt-oproep__stand { margin-top: calc(clamp(8px, 1.2vh, 16px) * var(--maat, 1)); }
.pt-oproep__cijfer {
  display: inline-block;
  font-size: calc(clamp(1rem, 1.6vw, 1.6rem) * var(--maat, 1));
  font-weight: 800;
}
.pt-oproep.is-klaar .pt-oproep__cijfer { color: var(--brand); }
.pt-oproep__balk {
  margin-top: 6px; height: calc(8px * var(--maat, 1));
  border-radius: 999px; background: var(--surface-2); overflow: hidden;
}
.pt-oproep__balk span {
  display: block; height: 100%; border-radius: 999px;
  background: linear-gradient(90deg, rgba(29,185,84,.7), var(--brand));
  transition: width .6s ease;
}

/* Dezelfde oproep op de telefoon, maar dan op telefoonmaat: het scherm is
   klein en de kaart staat naast knoppen en fiches. */
.pt-page-vote .pt-oproep__badge { width: 38px; height: 38px; font-size: 1.15rem; }
.pt-page-vote .pt-oproep__titel { font-size: 1.1rem; }
.pt-page-vote .pt-oproep__actie { font-size: .92rem; }
.pt-page-vote .pt-oproep__tekst { font-size: .88rem; margin-top: var(--s-2); }
.pt-page-vote .pt-oproep__tekst--klein { font-size: .8rem; }
.pt-page-vote .pt-oproep__kop { gap: var(--s-2); }
.pt-roulette__mijn { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin-top: var(--s-2); }
.pt-roulette__weg { cursor: pointer; opacity: .7; padding: 0 2px; }
.pt-roulette__weg:hover, .pt-roulette__weg:focus-visible { opacity: 1; color: var(--down); }

/* De balk boven de wachtrij: het blok loopt, of begint zo. Hier kijkt de DJ
   de hele avond naar, dus stoppen kan hier ook. */
.pt-blokbalk {
  display: flex; align-items: center; gap: var(--s-3);
  flex-wrap: wrap;
  margin-top: var(--s-4);
  padding: var(--s-3);
  border-radius: var(--r-md);
  border: 1px solid rgba(255, 203, 71, .45);
  background: rgba(255, 203, 71, .08);
}
.pt-blokbalk.is-loopt { border-color: rgba(29, 185, 84, .5); background: rgba(29, 185, 84, .1); }
/* Niets aan de hand: dan is het gewoon een regel, geen waarschuwing. */
.pt-blokbalk.is-rust { border-color: var(--line); background: var(--surface-2); }
.pt-blokbalk.is-rust /* Bolletje en titel op een regel, en de ondertitel netjes eronder. */
.pt-blokbalk__kop { display: flex; align-items: center; gap: var(--s-2); }
.pt-blokbalk__punt { background: var(--text-faint); }
.pt-blokbalk__punt {
  width: 10px; height: 10px; border-radius: 50%;
  background: var(--amber); flex: 0 0 auto;
}
.pt-blokbalk.is-loopt .pt-blokbalk__punt { background: var(--brand); animation: pt-pulse 1.8s ease-in-out infinite; }

#motor-acties { white-space: pre-line; }

/* ------------------------------------------------------------ sfeerlicht
   De schermen in de zaal doen mee: het tv-scherm en de telefoons kleuren een
   paar tellen mee met wat er gebeurt. Bewust rustig: geen snelle flikkering,
   dat is naar voor de ogen en kost batterij. */
.pt-licht {
  position: fixed;
  inset: 0;
  z-index: 9000;
  pointer-events: none;
  opacity: 0;
  transition: opacity .5s ease, background-color .5s ease;
  mix-blend-mode: screen;
}
/* De DJ kiest hoe hard het licht meedoet; die sterkte staat in een variabele
   en rekent door in alles wat hieronder zichtbaar wordt. */
.pt-licht { --licht-sterkte: .75; }
.pt-licht.is-aan { opacity: var(--licht-sterkte); }
.pt-licht[data-kleur="groen"]     { background: radial-gradient(circle at 50% 50%, rgba(29,185,84,.55), rgba(29,185,84,.12) 70%); }
.pt-licht[data-kleur="rood"]      { background: radial-gradient(circle at 50% 50%, rgba(244,83,107,.55), rgba(244,83,107,.12) 70%); }
.pt-licht[data-kleur="warm"]      { background: radial-gradient(circle at 50% 50%, rgba(255,170,64,.5), rgba(255,120,32,.12) 70%); }
.pt-licht[data-kleur="koel"]      { background: radial-gradient(circle at 50% 50%, rgba(80,160,255,.5), rgba(40,90,255,.12) 70%); }
.pt-licht[data-kleur="roze"]      { background: radial-gradient(circle at 50% 50%, rgba(255,105,180,.5), rgba(200,60,180,.12) 70%); }
/* Blauw-wit, de kleuren van Beieren. Geen harde ruit maar twee banen die
   langzaam over elkaar schuiven: op een telefoon op tafel is dat een lamp, op
   de tv een gordijn. */
.pt-licht[data-kleur="beiers"] {
  background: linear-gradient(115deg, rgba(60, 130, 235, .55), rgba(255, 255, 255, .5) 38%, rgba(60, 130, 235, .55) 62%, rgba(255, 255, 255, .5));
  background-size: 260% 260%;
  animation: pt-licht-schuif 9s ease-in-out infinite;
}
/* Rood, geel en groen: de kleuren van carnaval. Drie banen die over elkaar
   schuiven, wat sneller dan de Beierse, want hier mag het druk zijn. */
.pt-licht[data-kleur="carnaval"] {
  background: linear-gradient(115deg, rgba(235, 60, 60, .55), rgba(255, 210, 50, .55) 33%, rgba(60, 190, 90, .55) 66%, rgba(235, 60, 60, .55));
  background-size: 300% 300%;
  animation: pt-licht-schuif 7s ease-in-out infinite;
}
.pt-licht[data-kleur="regenboog"] {
  background: linear-gradient(120deg, rgba(255,80,80,.45), rgba(255,200,60,.45), rgba(60,220,120,.45), rgba(80,160,255,.45), rgba(200,100,255,.45));
  background-size: 300% 300%;
  animation: pt-licht-schuif 6s ease-in-out infinite;
}
@keyframes pt-licht-schuif {
  0%, 100% { background-position: 0% 50%; }
  50%      { background-position: 100% 50%; }
}
/* De flits is een korte, zachte opdoffer: twee keer aan en weer weg. */
.pt-licht[data-kleur="flits"] {
  background: rgba(255, 255, 255, .75);
  animation: pt-licht-flits 1.4s ease-in-out 2;
}
@keyframes pt-licht-flits {
  0%, 100% { opacity: 0; }
  20%      { opacity: var(--licht-sterkte); }
  60%      { opacity: calc(var(--licht-sterkte) * .25); }
}
/* Feeststand: tussen de pulsen door ademt het scherm zachtjes mee. */
/* Tussen de pulsen door ademt het scherm zachtjes mee, een slag rustiger dan
   een puls zelf. */
.pt-licht.is-adem { animation: pt-licht-adem 7s ease-in-out infinite; }
@keyframes pt-licht-adem {
  0%, 100% { opacity: calc(var(--licht-sterkte) * .16); }
  50%      { opacity: calc(var(--licht-sterkte) * .38); }
}
/* Meebewegen op de maat: aan het begin van elke maat zwelt de gloed op en
   zakt daarna langzaam weg. Een hele maat lang, niet een tel: op elke tel
   werd het een knipperlicht. De duur zet het script.

   'both' houdt de eindstand vast, zodat het er tussendoor niet even
   uitspringt naar volle sterkte als de klok iets uitloopt. */
.pt-licht.is-tel { animation: pt-licht-tel var(--licht-tel, 2s) ease-out 1 both; }
@keyframes pt-licht-tel {
  0%   { opacity: calc(var(--licht-sterkte) * .42); }
  35%  { opacity: calc(var(--licht-sterkte) * .22); }
  100% { opacity: calc(var(--licht-sterkte) * .13); }
}

/* ---------------------------------------------------------- aanstekers

   Vroeger ging bij een langzaam nummer de aansteker de lucht in. Tegenwoordig
   is dat de zaklamp van de telefoon, maar dat licht is wit en hard. Dit is
   het warme licht van toen: een vlam die staat te wiegen en onregelmatig
   flakkert, want een echte vlam brandt nooit gelijkmatig.

   Twee lagen over elkaar: een brede warme gloed die het scherm vult, en een
   kern die feller is. Die laatste beweegt, zodat het niet als een plaatje
   voelt maar als vuur. */
.pt-licht.is-aansteker {
  opacity: 1;
  mix-blend-mode: normal;
  /* Drie lagen: de hete kern, de gloed eromheen, en een donkere warme
     bodem. Die bodem dempt de app eronder, zodat het scherm van een afstand
     een vlam is en geen webpagina met een oranje vlek. */
  background:
    radial-gradient(ellipse 34% 26% at 50% 60%, rgba(255, 240, 200, .98), rgba(255, 180, 70, .85) 40%, rgba(255, 120, 20, .45) 66%, rgba(0, 0, 0, 0) 82%),
    radial-gradient(ellipse 62% 48% at 50% 66%, rgba(255, 140, 30, .5), rgba(140, 50, 0, .28) 55%, rgba(0, 0, 0, 0) 80%),
    linear-gradient(rgba(14, 7, 2, .72), rgba(14, 7, 2, .72));
  animation: pt-vlam 2.6s ease-in-out infinite;
  transform-origin: 50% 85%;
}

/* Het flakkeren. Onregelmatige stappen, anders wordt het een metronoom. */
@keyframes pt-vlam {
  0%   { opacity: .92; transform: scale(1) skewX(0deg); }
  12%  { opacity: 1;   transform: scale(1.04) skewX(-1.2deg); }
  26%  { opacity: .84; transform: scale(.98) skewX(.8deg); }
  41%  { opacity: .97; transform: scale(1.03) skewX(1.4deg); }
  58%  { opacity: .88; transform: scale(1) skewX(-.6deg); }
  73%  { opacity: 1;   transform: scale(1.05) skewX(-1.6deg); }
  88%  { opacity: .86; transform: scale(.99) skewX(1deg); }
  100% { opacity: .92; transform: scale(1) skewX(0deg); }
}

/* Op de maat gaat de vlam even hoger op, zoals een arm die meedeint. */
.pt-licht.is-aansteker.is-wieg { animation: pt-vlam 2.6s ease-in-out infinite, pt-vlam-op var(--licht-tel, 2s) ease-out 1 both; }
@keyframes pt-vlam-op {
  0%   { filter: brightness(1.35); }
  100% { filter: brightness(1); }
}

/* Beweging beperken: dan staat de vlam stil, maar hij blijft wel warm. */
@media (prefers-reduced-motion: reduce) {
  .pt-licht.is-aansteker, .pt-licht.is-aansteker.is-wieg { animation: none; }
}

/* ------------------------------------------------------- kleurenslinger

   Elke telefoon licht om de beurt kort op in zijn eigen kleur. Van een
   afstand loopt er dan een slinger door de zaal. Tussen de beurten door is
   het scherm donker; dat hoort erbij, want anders zie je de slinger niet. */
.pt-licht.is-slinger {
  mix-blend-mode: normal;
  opacity: 0;
  transition: opacity .18s ease-out, background-color .18s ease-out;
  background: radial-gradient(circle at 50% 50%, var(--slinger-kleur, #ff5ea8), rgba(0, 0, 0, 0) 78%);
}
.pt-licht.is-slinger.is-beurt {
  opacity: 1;
  transition: opacity .09s ease-out;
}

/* De klok op de draaitafel: hoever de plaat is, hoe lang hij duurt en
   hoeveel er nog rest. Cijfers met een vaste breedte, anders staat de regel
   bij elke tel te dansen. */
.pt-now__tijd {
  margin-top: var(--s-2);
  font-size: .82rem;
  color: var(--text-muted);
  font-variant-numeric: tabular-nums;
}
/* De laatste tien tellen: dan wil je weten dat je moet opletten. */
.pt-now__tijd.is-bijna { color: var(--amber); }

/* ----------------------------------------------------- het toostmoment

   Aftellen en dan één woord over het hele scherm. Zo groot als het scherm
   toelaat, want dit is het moment waarop iedereen opkijkt. */
/* Boven de lichtlaag. Die ligt over alles heen en mengt mee, en daardoor
   stond dit hele scherm grijs weg te spoelen met een bleekgroen woord erop.
   Dit moment mag scherp zijn, dus gaat hij erboven. */
.pt-roep--prost {
  z-index: 9200;
  background: rgba(8, 10, 12, .97);
}
.pt-roep--prost .pt-roep__vak { max-width: min(1500px, 94vw); }

.pt-prost__tel {
  font-size: calc(clamp(5rem, 28vw, 18rem) * var(--maat, 1));
  font-weight: 900;
  line-height: 1;
  color: var(--amber);
  animation: pt-prost-tel 1s ease-out both;
}
@keyframes pt-prost-tel {
  0%   { opacity: 0; transform: scale(1.5); }
  30%  { opacity: 1; transform: scale(1); }
  100% { opacity: .85; transform: scale(.96); }
}

.pt-prost__woord {
  font-size: calc(clamp(2.5rem, 13vw, 10rem) * var(--maat, 1));
  font-weight: 900;
  line-height: 1.05;
  letter-spacing: -.02em;
  /* Nooit midden in een woord afbreken. PROST! hoort niet als PROS en T!
     onder elkaar te staan. Past het niet, dan krimpt het script hem. */
  overflow-wrap: normal;
  word-break: keep-all;
  hyphens: none;
  white-space: nowrap;
}
/* Het plaatje bij de toost: boven het woord, en niet groter dan wat er over
   is. Een gifje van een bierpul hoort het woord te versieren, niet te
   verdringen. */
.pt-prost__beeld {
  display: block;
  margin: 0 auto calc(clamp(8px, 1.6vh, 20px) * var(--maat, 1));
  height: calc(clamp(90px, 26vh, 420px) * var(--maat, 1));
  width: auto;
  max-width: min(60vw, 520px);
  object-fit: contain;
}

.pt-prost__woord.is-nu {
  color: var(--brand);
  animation: pt-prost-woord .6s ease-out both;
}
@keyframes pt-prost-woord {
  0%   { opacity: 0; transform: scale(.7) rotate(-2deg); }
  60%  { opacity: 1; transform: scale(1.08) rotate(1deg); }
  100% { opacity: 1; transform: scale(1) rotate(0); }
}

@media (prefers-reduced-motion: reduce) {
  .pt-prost__tel, .pt-prost__woord.is-nu { animation: none; }
}

/* --------------------------------------------------------------- Plus

   Wat in Plus zit blijft zichtbaar in de console, maar doet niets tot Plus
   loopt. Niet weggehaald en niet met een slot erop: gedempt, met een merkje
   erbij. Zo zie je wat er te halen valt zonder dat het in de weg zit. */
.pt-plusmerk {
  display: inline-flex;
  align-items: center;
  padding: 1px 8px;
  border-radius: 999px;
  border: 1px solid rgba(255, 203, 71, .5);
  background: rgba(255, 203, 71, .12);
  color: var(--amber);
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
  flex: 0 0 auto;
}

.is-plusuit { position: relative; }

/* De inhoud gedempt, het merkje niet: dat moet juist opvallen. */
.pt-module.is-plusuit > *:not(.pt-plusmerk):not(.pt-module__kop),
.pt-field.is-plusuit > *:not(.pt-plusmerk) {
  opacity: .5;
}

.pt-module.is-plusuit > .pt-plusmerk,
.pt-field.is-plusuit > .pt-plusmerk { margin-bottom: var(--s-2); }

/* Een vak dat uitstaat vangt de klik op; het venster legt het dan uit. */
.is-plusuit, .is-plusuit * { cursor: pointer; }
.is-plusuit input, .is-plusuit select, .is-plusuit textarea, .is-plusuit button { pointer-events: none; }

/* In het menu en op de balk: alleen het merkje, verder niets veranderen. */
.pt-menu__rij.is-plusuit .pt-menu__tekst, .pt-djbar__knop.is-plusuit { opacity: .75; }
.pt-menu__rij.is-plusuit .pt-plusmerk { margin-left: auto; }
.pt-djbar__knop.is-plusuit { position: relative; }
.pt-djbar__knop.is-plusuit .pt-plusmerk {
  position: absolute;
  top: 2px;
  right: 2px;
  padding: 0 4px;
  font-size: .55rem;
}

/* Het venster: klein, midden in beeld, en weg met een klik ernaast. */
.pt-plusvenster {
  position: fixed;
  inset: 0;
  /* Boven de lade en de balk van de console; die zitten op 78 en 80. */
  z-index: 120;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--s-4);
  background: rgba(8, 10, 12, .72);
  animation: pt-fade-in .18s ease both;
}
.pt-plusvenster__kaart {
  width: min(460px, 100%);
  padding: var(--s-4);
  border-radius: var(--r-lg);
  border: 1px solid var(--line-strong);
  background: var(--bg-elevated);
  box-shadow: 0 18px 50px rgba(0, 0, 0, .5);
}
.pt-plusvenster__kaart p { margin: var(--s-2) 0 0; }

/* ------------------------------------------------------- eigen vragen

   De quiz die de DJ zelf schrijft. Drie plekken: de lijst in de console, de
   knoppen op de telefoon en de vraag groot op de tv. */

/* In de console: een regel per vraag met zijn antwoorden eronder. */
/*
 * De lijst met eigen vragen: een regel per vraag.
 *
 * Met drie regels tekst en vijf knoppen met woorden erop paste er op een
 * laptop maar een handvol vragen op het scherm, en tijdens een feest wil je
 * er juist snel een uitpikken. Nu staat alles op een regel met de antwoorden
 * eronder, en op een breed scherm blijft de tekst bij de knoppen in de buurt
 * in plaats van dat er een meter ruimte tussen valt.
 */
.pt-vraagrij {
  display: flex;
  gap: var(--s-2);
  /* Bovenaan uitlijnen: op een telefoon loopt de vraag over twee regels en
     dan hoort het nummertje bij de eerste regel te staan, niet ergens in het
     midden te zweven. */
  align-items: flex-start;
  padding: 6px var(--s-2);
  border-radius: var(--r-md);
  border-bottom: 1px solid var(--line);
  flex-wrap: wrap;
}
.pt-vraagrij:hover { background: var(--surface-2); }
/*
 * Al gesteld: hij mag nog een keer, maar je moet in een oogopslag zien welke
 * je gehad hebt. Een streep in de kantlijn en een merkje naast de vraag; de
 * regel dooft maar blijft leesbaar, want halfdoorzichtig lezen slecht in een
 * donkere zaal.
 */
.pt-vraagrij.is-gesteld {
  opacity: .78;
  border-left: 3px solid var(--brand);
  padding-left: calc(var(--s-2) - 3px);
  background: var(--surface-2);
}
.pt-vraagrij.is-gesteld:hover { opacity: 1; }
.pt-vraagrij.is-gesteld .pt-vraagrij__vraag { font-weight: 600; }
.pt-vraagrij__gesteld {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  margin-left: 8px;
  padding: 1px 8px;
  border: 1px solid var(--brand);
  border-radius: 999px;
  color: var(--brand);
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .01em;
  vertical-align: middle;
  white-space: nowrap;
}

/* Het nummertje ervoor: zo verwijs je naar "die derde" zonder te tellen. */
.pt-vraagrij__nr {
  flex: 0 0 auto;
  width: 1.6em;
  text-align: right;
  font-size: .8rem;
  font-weight: 700;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}
.pt-vraagrij__tekst { flex: 1 1 18em; min-width: 0; max-width: 60em; }
.pt-vraagrij__vraag { font-weight: 650; line-height: 1.3; }
.pt-vraagrij__onder { display: flex; flex-wrap: wrap; gap: 4px; align-items: center; margin-top: 3px; }
.pt-vraagrij__meta { font-size: .75rem; color: var(--text-faint); white-space: nowrap; }
.pt-chip--mini { padding: 1px 8px; font-size: .7rem; font-weight: 600; }

/*
   De knop met de opdracht erin: '🎁 voor Lulu'.

   Hij staat tussen de andere knoppen van je eigen nummer, zodat zo'n regel
   er hetzelfde uitziet als een regel zonder opdracht. Een lange naam wordt
   afgekapt met puntjes; de hele naam staat in de tip en in het label.
*/
.pt-opdracht { max-width: 11em; padding-left: var(--s-2); padding-right: var(--s-2); }
.pt-opdracht__naam {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.pt-vraagrij__onder .pt-chip.is-goed { border-color: var(--brand); color: var(--brand); }
/* De stand onder de vragen: smal, met de cijfers recht onder elkaar. */
.pt-standrij {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  padding: 2px var(--s-2);
  border-radius: var(--r-sm);
}
.pt-standrij:hover { background: var(--surface-2); }
.pt-standrij__nr {
  flex: 0 0 auto;
  width: 1.8em;
  text-align: right;
  font-size: .8rem;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}
.pt-standrij__naam { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pt-standrij__goed { flex: 0 0 auto; font-size: .75rem; color: var(--text-faint); font-variant-numeric: tabular-nums; }
.pt-standrij__punten { flex: 0 0 auto; min-width: 3.2em; text-align: right; font-variant-numeric: tabular-nums; }
/* De koploper mag opvallen, verder geen kleur: het blijft een lijstje. */
.pt-standrij:first-child .pt-standrij__punten { color: var(--amber); }

.pt-vraagrij__knoppen { display: flex; gap: 4px; flex-wrap: wrap; align-items: center; align-self: center; margin-left: auto; }

/*
   Het plaatje bij een vraag.

   De keuzelijst en de knop staan naast elkaar zolang dat past; op een
   telefoon gaat de lijst over de volle breedte en komt de knop eronder. Het
   voorbeeldvakje staat ernaast en is er alleen als er ook werkelijk een
   plaatje gekozen is: een leeg vakje met een stippellijn vraagt de aandacht
   voor niets en kost op een klein scherm een halve regel.
*/
.pt-beeldkies { display: flex; flex-wrap: wrap; gap: var(--s-2); align-items: center; }
.pt-beeldkies > select { flex: 1 1 12em; min-width: 0; }
.pt-beeldkies__uitleg { margin: 6px 0 0; }

/* De regel met de tijd en de knoppen onder een vraag. */
.pt-vraagactie {
  display: flex;
  gap: var(--s-2);
  align-items: flex-end;
  flex-wrap: wrap;
  margin-top: var(--s-3);
}

@media (max-width: 560px) {
  .pt-beeldkies > select { flex: 1 1 100%; }
  /* De tijd over de volle breedte, de knoppen daaronder samen op een regel.
     Zonder dit kruipt 'Nieuwe vraag' naast het keuzelijstje en valt de groene
     knop er los onder. */
  .pt-vraagactie { align-items: stretch; }
  .pt-vraagactie > .pt-field { flex: 1 1 100%; }
  .pt-vraagactie > .pt-grow { display: none; }
  .pt-vraagactie > .pt-btn { flex: 1 1 9em; }
}

/*
   Een rij in een lijst op een telefoon: alles op een regel.

   Met de tekst op 18em als basis past er naast de hoes niets meer bij en
   viel elk nummer uiteen over drie regels: hoes, titel, knoppen. Dan zie je
   er nog twee op een scherm. Hier krimpt de tekst mee, blijven de knoppen
   ernaast staan en houd je overzicht.
*/
/* Staat er alleen op een telefoon; zie de mediaquery hieronder. */
.pt-vraagrij__alleenmobiel { display: none; }

@media (max-width: 700px) {
  .pt-vraagrij { gap: 8px; padding: 6px 4px; align-items: center; }
  .pt-vraagrij__nr { width: 1.3em; font-size: .75rem; }
  /* Acht em als basis in plaats van achttien: dan deelt de tekst de regel
     met de hoes en de knoppen in plaats van ze naar beneden te duwen. */
  .pt-vraagrij__tekst { flex: 1 1 8em; min-width: 0; }
  .pt-vraagrij__vraag { font-size: .92rem; }
  .pt-vraagrij > .pt-track__cover { width: 40px; height: 40px; }
  /* De knoppen blijven bij elkaar; past de hele groep niet, dan gaat hij als
     geheel naar de volgende regel en niet knop voor knop. */
  .pt-vraagrij__knoppen { flex-wrap: nowrap; gap: 2px; margin-left: auto; }
  /* Iets kleiner dan de 44 van een speelknop: dit is voorbereiden, niet
     bedienen in het donker, en met drie knoppen naast elkaar is dat het
     verschil tussen een regel en drie regels. */
  .pt-vraagrij__knoppen .pt-btn--sm.pt-btn--icon { width: 38px; min-height: 38px; }
  /*
     Bij een vraag staan alle antwoorden als merkjes onder elkaar; dat is op
     een telefoon een halve kolom per vraag. Alleen het goede antwoord blijft
     staan, met erachter hoeveel er in totaal zijn. De rest zie je zodra je
     de vraag openklapt om hem aan te passen.
  */
  /* Alleen de antwoorden van een vraag; een merkje dat de bron noemt
     ('Spotify', 'Je eigen muziek') hoort juist wel te blijven staan. */
  .pt-vraagrij__optie:not(.is-goed) { display: none; }
  .pt-vraagrij__alleenmobiel { display: inline; }
}

/* Sorteren op een telefoon: de kolomkoppen zijn daar weg, dus een lijstje. */
.pt-tabel__mobielsort { display: none; }
@media (max-width: 700px) {
  .pt-tabel__mobielsort { display: flex; align-items: center; gap: var(--s-2); margin-top: var(--s-2); }
  .pt-tabel__mobielsort select { flex: 1 1 auto; min-width: 0; }
}

/*
   De kop boven een bibliotheeklijst: zoeken links, iets nieuws maken rechts.

   Op een telefoon stond het zoekveld over de volle breedte en werd het
   naamveld door de tussenruimte tegen de rechterrand geduwd, met de knop er
   los onder. Hier valt die tussenruimte weg en staan het naamveld en de knop
   samen op de tweede regel.
*/
@media (max-width: 700px) {
  /*
     Alles onder elkaar, en even breed.

     Als flexrij kreeg elk vakje zijn eigen maat: het zoekveld bijna de volle
     breedte, het naamveld acht pixels verder naar rechts omdat er een
     opvuller voor stond, en de knop weer ergens anders. Drie verschillende
     linkerkanten onder elkaar, en dat ziet er scheef uit. Als raster van een
     kolom beginnen ze allemaal op dezelfde plek.
  */
  .pt-lijstkop {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--s-2);
  }
  .pt-lijstkop > * { width: 100%; min-width: 0; flex: none !important; }
  .pt-lijstkop > .pt-grow { display: none; }
  /* Twee vakjes die bij elkaar horen mogen wel naast elkaar: de soort van
     een nieuwe lijst en de knop die hem maakt. */
  .pt-lijstkop > select + .pt-btn { grid-column: 2; }
  .pt-lijstkop:has(> select) { grid-template-columns: minmax(0, 1fr) auto; }
  .pt-lijstkop:has(> select) > *:not(select):not(select + .pt-btn) { grid-column: 1 / -1; }
  /* De regel onder de naam mag twee regels worden, niet vier: met een lange
     omschrijving werd elke rij anders een kaartje van een halve duim hoog. */
  .pt-tabel__mobiel {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }
}

/* Op de telefoon: knoppen waar je met een duim op kunt mikken. */
.pt-vraagknoppen { display: flex; flex-direction: column; gap: var(--s-2); margin-top: var(--s-3); }
.pt-vraagknop {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  width: 100%;
  min-height: calc(var(--tap) + 8px);
  padding: var(--s-2) var(--s-3);
  text-align: left;
  border-radius: var(--r-md);
}
.pt-vraagknop.is-stil {
  border: 1px solid var(--line);
  background: var(--surface-2);
  opacity: .7;
}
.pt-vraagknop.is-goed { border-color: var(--brand); color: var(--brand); opacity: 1; }
.pt-vraagknop.is-fout { border-color: var(--rood, #f4536b); color: var(--rood, #f4536b); opacity: 1; }
.pt-vraagknop__letter {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.9em;
  height: 1.9em;
  border-radius: 50%;
  background: var(--surface-3, rgba(255,255,255,.08));
  font-weight: 700;
  flex: 0 0 auto;
}
.pt-vraaguitslag { margin-top: var(--s-2); font-weight: 600; }
.pt-vraaguitslag.is-goed { color: var(--brand); }
.pt-vraaguitslag.is-fout { color: var(--rood, #f4536b); }

/* Op de tv: groot genoeg om vanaf de andere kant van de zaal te lezen. */
.pt-roep--vraag { background: rgba(8, 10, 12, .95); }
.pt-vraagtv { max-width: min(1100px, 88vw); }
.pt-vraagtv__kop {
  font-size: calc(clamp(.9rem, 1.5vw, 1.3rem) * var(--maat, 1));
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.pt-vraagtv__tekst {
  font-size: calc(clamp(1.6rem, 4.4vw, 4rem) * var(--maat, 1));
  font-weight: 800;
  line-height: 1.15;
  margin-top: calc(clamp(6px, 1vh, 14px) * var(--maat, 1));
  overflow-wrap: anywhere;
}
.pt-vraagtv__opties {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: calc(clamp(8px, 1.2vh, 18px) * var(--maat, 1));
  margin-top: calc(clamp(12px, 2vh, 28px) * var(--maat, 1));
}
/* Twee antwoorden naast elkaar leest prettiger dan twee onder elkaar. */
.pt-vraagtv__opties:has(> :nth-child(3)) { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.pt-vraagtv__optie {
  display: flex;
  align-items: center;
  gap: calc(clamp(8px, 1vw, 16px) * var(--maat, 1));
  padding: calc(clamp(10px, 1.4vh, 20px) * var(--maat, 1)) calc(clamp(12px, 1.4vw, 24px) * var(--maat, 1));
  border: 2px solid var(--line-strong);
  border-radius: var(--r-lg, 16px);
  font-size: calc(clamp(1rem, 2.2vw, 2.1rem) * var(--maat, 1));
  text-align: left;
  background: var(--surface-2);
}
.pt-vraagtv__optie.is-goed { border-color: var(--brand); color: var(--brand); background: rgba(29,185,84,.12); }
.pt-vraagtv__optie.is-stil { opacity: .45; }
.pt-vraagtv__letter {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.7em;
  height: 1.7em;
  border-radius: 50%;
  background: rgba(255,255,255,.1);
  font-weight: 800;
  flex: 0 0 auto;
}
.pt-vraagtv__aantal { font-variant-numeric: tabular-nums; color: var(--text-muted); }
.pt-vraagtv__onder {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: calc(clamp(10px, 1.6vw, 24px) * var(--maat, 1));
  margin-top: calc(clamp(12px, 2vh, 28px) * var(--maat, 1));
  flex-wrap: wrap;
}
.pt-vraagtv__actie {
  font-size: calc(clamp(1rem, 1.8vw, 1.6rem) * var(--maat, 1));
  color: var(--text-muted);
  margin-top: calc(clamp(8px, 1.2vh, 16px) * var(--maat, 1));
}
.pt-vraagtv__binnen { font-size: calc(clamp(.85rem, 1.2vw, 1.2rem) * var(--maat, 1)); color: var(--text-muted); }

/* Op een telefoon in de hoogte passen er geen twee antwoorden naast elkaar. */
@media (max-width: 700px) {
  .pt-vraagtv__opties { grid-template-columns: minmax(0, 1fr); }
}

/* De effectrij onder het transport: een blokje dat erbij hoort maar het
   transport niet in de weg zit. */
.pt-effecten {
  margin-top: var(--s-3);
  padding-top: var(--s-3);
  border-top: 1px solid var(--line);
}

/* Het kopje is tegelijk de knop om in en uit te klappen. */
.pt-effecten__kop {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-2);
  cursor: pointer;
  list-style: none;
  font-size: .7rem;
  font-weight: 800;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--text-muted);
  padding: 2px 0;
}
.pt-effecten__kop::-webkit-details-marker { display: none; }
.pt-effecten__kop::after { content: '\2304'; font-size: 1.1rem; line-height: 1; letter-spacing: 0; }
.pt-effecten[open] .pt-effecten__kop::after { content: '\2303'; }
.pt-effecten__kop:hover { color: var(--text); }

/* Elke effectknop staat op een regel met het geluid of het plaatje dat hij
   gebruikt. Zo hoeft niemand te raden welke keuzelijst bij welke knop hoort.
   De knoppen krijgen dezelfde breedte, dan lopen de lijsten ernaast gelijk. */
/*
   Elke regel hetzelfde raster: knop, voorbeeldje, keuzelijst.

   Met losse rijen naast elkaar begon elke keuzelijst op een andere plek,
   want de ene regel had wel een voorbeeldje en de andere niet. Nu staan de
   kolommen vast en blijft de kolom van het voorbeeldje gewoon leeg als er
   geen plaatje bij hoort. Alles staat daardoor onder elkaar uitgelijnd.
*/
.pt-effect {
  display: grid;
  grid-template-columns: 7.5em minmax(0, 1fr);
  align-items: center;
  gap: var(--s-2);
  margin-top: var(--s-2);
}

/* Alles wat links staat deelt dezelfde kolom en dezelfde middenlijn: de
   knoppen, en het voorbeeldje van het plaatje. Daardoor loopt er een rechte
   lijn door de rij en beginnen alle keuzelijsten op dezelfde plek. */
.pt-effect__knop { grid-column: 1; justify-content: center; }

/* Een knop die wel iets doet maar waarvan de zaal niets zal horen: amber, met
   de reden in de tip. Niet uitzetten, want de DJ mag het gewoon proberen. */
.pt-effect__knop.is-stil {
  border-color: rgba(255, 203, 71, .55);
  color: var(--amber);
}
.pt-effect .pt-beeldvoor { grid-column: 1; justify-self: center; }
.pt-effect .pt-input { grid-column: 2; width: 100%; }

/* Uitgezet zolang er geen plaatje klaarstaat. */
.pt-effect__knop[disabled] { opacity: .45; cursor: not-allowed; }

/* De stroboscoop van de effectknop: drie flitsen per seconde, niet meer.
   Sneller knipperen kan mensen met lichtgevoelige epilepsie ziek maken; drie
   per seconde is de grens die de toegankelijkheidsrichtlijnen aanhouden. Op
   een dansvloer is dat nog steeds een stroboscoop. */
/* Let op de is-puls ervoor. Zonder die eis hangt het knipperen aan de kleur
   alleen, en dan blijft het scherm knipperen zodra die kleur om wat voor
   reden dan ook blijft staan. Dat gebeurde: de stroboscoop ging niet meer
   uit. Nu stopt hij hoe dan ook zodra de puls voorbij is. */
.pt-licht.is-puls[data-kleur="strobo"] {
  background: rgba(255, 255, 255, .8);
  animation: pt-licht-strobo 333ms steps(2, end) infinite;
}
@keyframes pt-licht-strobo {
  0%   { opacity: var(--licht-sterkte); }
  100% { opacity: 0; }
}

/* Een uitschieter: een klap die er echt bovenuit komt. Korter en feller dan
   de maat, en alleen op het scherm dat de muziek zelf hoort. */
.pt-licht.is-accent { animation: pt-licht-accent 900ms ease-out 1 both; }
@keyframes pt-licht-accent {
  0%   { opacity: calc(var(--licht-sterkte) * .8); }
  100% { opacity: calc(var(--licht-sterkte) * .13); }
}
@media (prefers-reduced-motion: reduce) {
  .pt-licht { transition: none; animation: none !important; }
}

/* Een uitlegvakje met een informatierondje ervoor: dit is geen waarschuwing,
   het legt alleen iets uit. */
.pt-note--info { display: flex; gap: var(--s-3); align-items: flex-start; }
.pt-note__icoon { width: 20px; height: 20px; flex: 0 0 auto; margin-top: 1px; color: var(--brand); }

/* ==========================================================================
   Affiche: een poster van je party

   De poster is in millimeters gemaakt, want hij komt uit een printer. Alles
   erbinnen staat in em, met de lettermaat van het vel als maatstaf. Een ander
   formaat kiezen verandert dus alleen de maat van het vel en de basisletter,
   en de hele poster schaalt mee. Op het scherm wordt hij met transform
   teruggeschaald tot hij in de kolom past; bij het printen gaat dat eraf.
   ========================================================================== */

.pt-affiche-lay { display: grid; gap: var(--s-5); grid-template-columns: minmax(0, 1fr); align-items: start; }
@media (min-width: 980px) {
  .pt-affiche-lay { grid-template-columns: minmax(300px, 400px) minmax(0, 1fr); }
}
/* Op een telefoon staat de poster boven het formulier: anders scrol je eerst
   langs alles heen voordat je ziet wat je aan het maken bent. */
@media (max-width: 979px) {
  .pt-affiche__voorbeeld { order: -1; }
}

.pt-affiche__doos { width: 100%; overflow: hidden; }
.pt-affiche__schaal { transform-origin: top left; }

/* De keuzevakjes voor thema en formaat. */
.pt-affiche__themas { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: var(--s-2); }
.pt-affiche__thema {
  display: block;
  padding: var(--s-2);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  cursor: pointer;
}
.pt-affiche__thema input { position: absolute; opacity: 0; width: 0; height: 0; }
.pt-affiche__thema:has(input:checked),
.pt-affiche__thema.is-gekozen { border-color: var(--brand); background: rgba(30,215,96,.08); }
.pt-affiche__thema:has(input:focus-visible) { outline: 2px solid var(--brand); outline-offset: 2px; }
.pt-affiche__proef {
  position: relative;
  display: block;
  height: 56px;
  border-radius: var(--r-sm);
  overflow: hidden;
  background: var(--aff-papier);
  border: 1px solid var(--line);
}
.pt-affiche__proef .pt-affiche__sier { position: absolute; inset: 0; }
.pt-affiche__themanaam { display: block; margin-top: var(--s-2); font-size: .9rem; font-weight: 600; }
.pt-affiche__themauitleg { display: block; font-size: .78rem; color: var(--text-faint); line-height: 1.35; }

/*
   Op een telefoon het kleurvlak en de naam, zonder het zinnetje erbij.

   Zes thema's met elk drie regels uitleg zijn vijfhonderdvijftig pixels
   scrollen voor een keuze die je met je ogen maakt: het vlakje laat zien hoe
   hij eruitziet, en de poster erboven verandert zodra je kiest. De uitleg
   blijft in de tip staan, en op een breed scherm staat hij er gewoon bij.
*/
@media (max-width: 599px) {
  .pt-affiche__themauitleg { display: none; }
  .pt-affiche__themas { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.pt-affiche__formaten { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: var(--s-2); }
.pt-affiche__formaat {
  display: block;
  padding: var(--s-2) var(--s-3);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  cursor: pointer;
}
.pt-affiche__formaat input { position: absolute; opacity: 0; width: 0; height: 0; }
.pt-affiche__formaat:has(input:checked),
.pt-affiche__formaat.is-gekozen { border-color: var(--brand); background: rgba(30,215,96,.08); }
.pt-affiche__formaatnaam { display: block; font-size: .9rem; font-weight: 600; }
.pt-affiche__formaatuitleg { display: block; font-size: .78rem; color: var(--text-faint); line-height: 1.35; }

/* Twee velden naast elkaar zolang er ruimte is. */
.pt-affiche__paar { display: grid; gap: var(--s-3); grid-template-columns: minmax(0, 1fr); }
@media (min-width: 560px) { .pt-affiche__paar { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); } }

/* Een datumveld houdt vast aan zijn eigen minimumbreedte en duwt zich anders
   uit de kolom; vandaar de losse maatvoering. */
.pt-affiche__kies { display: block; margin-top: var(--s-2); }
.pt-affiche__datumveld { display: block; width: 100%; max-width: 100%; min-width: 0; margin-top: 4px; }

/* -------------------------------------------------------------- het vel zelf */

.pt-affiche {
  position: relative;
  overflow: hidden;
  width: var(--aff-b);
  height: var(--aff-h);
  font-size: var(--aff-basis);
  font-family: var(--font);
  color: var(--aff-inkt);
  background: var(--aff-papier);
  box-shadow: var(--shadow-3);
  /* Zonder dit laat de printer de achtergrond weg en komt er een wit vel uit. */
  -webkit-print-color-adjust: exact;
  print-color-adjust: exact;
}

.pt-affiche[data-formaat="a4"]       { --aff-b: 210mm; --aff-h: 297mm; --aff-basis: 4.4mm; }
.pt-affiche[data-formaat="a3"]       { --aff-b: 297mm; --aff-h: 420mm; --aff-basis: 6.2mm; }
.pt-affiche[data-formaat="vierkant"] { --aff-b: 210mm; --aff-h: 210mm; --aff-basis: 4.1mm; }

.pt-affiche__sier { position: absolute; inset: 0; z-index: 0; }

/* De eigen foto van de DJ.
 *
 * Hij ligt onder de versiering en onder de tekst, met een waas in de kleur
 * van het thema eroverheen. Zonder die waas is een foto met een lichte lucht
 * erin genoeg om een witte kop onleesbaar te maken, en dat merk je pas als
 * het affiche aan de muur hangt. */
.pt-affiche__foto { position: absolute; inset: 0; z-index: 0; overflow: hidden; }
.pt-affiche__foto img { width: 100%; height: 100%; object-fit: cover; display: block; }
.pt-affiche__waas { position: absolute; inset: 0; }

/* Over het hele vel: de kleur van het thema ligt eroverheen. Onderaan loopt
   hij dichter, want daar staat het blok met de QR-code en het adres, en dat
   moet leesbaar blijven ook als de foto daar net licht is. */
.pt-affiche[data-foto="achter"] .pt-affiche__waas { background: var(--aff-papier); opacity: .66; }
.pt-affiche[data-foto="achter"] .pt-affiche__foto::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, transparent 58%, var(--aff-vloei) 100%);
  opacity: .72;
}

/* Een band bovenin. De hoogte staat in em, net als de rest van het affiche,
   dus hij schaalt mee met het formaat. Onderaan vloeit hij over in de kleur
   van het vel, zodat er geen harde rand door de poster loopt. */
.pt-affiche[data-foto="boven"] .pt-affiche__foto { inset: 0 0 auto 0; height: 24em; }
.pt-affiche[data-foto="boven"] .pt-affiche__waas {
  background: linear-gradient(180deg, rgba(0,0,0,.18) 0%, rgba(0,0,0,0) 40%, var(--aff-vloei) 100%);
}
.pt-affiche[data-foto="boven"] .pt-affiche__binnen { padding-top: 25.6em; }
.pt-affiche[data-formaat="vierkant"][data-foto="boven"] .pt-affiche__foto { height: 15em; }
.pt-affiche[data-formaat="vierkant"][data-foto="boven"] .pt-affiche__binnen { padding-top: 16.2em; }

/* Het voorbeeldje bij de knop om een foto te kiezen. */
.pt-affiche__fotovoor {
  display: inline-flex;
  width: 64px;
  height: 44px;
  border-radius: var(--r-sm);
  overflow: hidden;
  background: var(--surface-2);
  border: 1px solid var(--line);
  flex: 0 0 auto;
}
.pt-affiche__fotovoor img { width: 100%; height: 100%; object-fit: cover; display: block; }

.pt-affiche__binnen {
  position: relative;
  z-index: 1;
  height: 100%;
  display: flex;
  flex-direction: column;
  gap: 1.1em;
  padding: 2.2em;
}

.pt-affiche__top { display: flex; align-items: center; justify-content: space-between; gap: 1em; }
.pt-affiche__dj { display: flex; align-items: center; gap: .6em; min-width: 0; }
.pt-affiche__djfoto { width: 2.8em; height: 2.8em; border-radius: 50%; object-fit: cover; border: .12em solid var(--aff-accent); }
.pt-affiche__djnaam { font-size: .82em; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; }
.pt-affiche__merk { font-size: .7em; font-weight: 700; letter-spacing: .24em; text-transform: uppercase; color: var(--aff-zacht); white-space: nowrap; }

.pt-affiche__midden { flex: 1 1 auto; display: flex; flex-direction: column; justify-content: center; gap: .9em; min-height: 0; }

.pt-affiche__kop {
  margin: 0;
  font-weight: 800;
  line-height: 1.02;
  letter-spacing: -.015em;
  overflow-wrap: break-word;
  text-wrap: balance;
}
.pt-affiche[data-kop="xl"]      .pt-affiche__kop { font-size: 5.2em; }
.pt-affiche[data-kop="groot"]   .pt-affiche__kop { font-size: 4em; }
.pt-affiche[data-kop="normaal"] .pt-affiche__kop { font-size: 2.9em; }
.pt-affiche[data-kop="klein"]   .pt-affiche__kop { font-size: 2.2em; }

.pt-affiche__regel { margin: 0; font-size: 1.25em; line-height: 1.3; color: var(--aff-zacht); }

.pt-affiche__feiten { margin: .6em 0 0; display: flex; flex-direction: column; gap: .5em; }
.pt-affiche__feit {
  display: flex;
  align-items: baseline;
  gap: .8em;
  padding-top: .5em;
  border-top: .035em solid var(--aff-lijn);
}
.pt-affiche__feit dt {
  /* Breed genoeg voor "Hoe laat" met deze letterafstand; krapper en dat
     kopje valt over twee regels. */
  flex: 0 0 7.2em;
  margin: 0;
  font-size: .74em;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--aff-zacht);
}
.pt-affiche__feit dd { margin: 0; font-size: 1.3em; font-weight: 700; line-height: 1.2; overflow-wrap: break-word; min-width: 0; }

.pt-affiche__slot { margin: .4em 0 0; font-size: 1.05em; font-style: italic; color: var(--aff-accent); }

.pt-affiche__onder {
  display: flex;
  align-items: center;
  gap: 1.2em;
  padding: 1em;
  border-radius: .7em;
  background: var(--aff-vlak);
}
.pt-affiche__onder--geenqr { justify-content: center; text-align: center; }
/* De maat van de QR-code. Normaal is 9,2em, wat op A4 eenenveertig millimeter
   is; een code werkt tot ongeveer tien keer zijn eigen breedte, dus dat leest
   van een meter of veertig. Klein en groot zijn daar een factor op, zodat het
   vierkante vel hieronder zijn eigen maat houdt en toch meeschaalt. */
.pt-affiche[data-qrmaat="klein"] { --qr-schaal: .75; }
.pt-affiche[data-qrmaat="groot"] { --qr-schaal: 1.5; }
.pt-affiche__qr { flex: 0 0 auto; width: calc(9.2em * var(--qr-schaal, 1)); padding: .5em; background: #fff; border-radius: .4em; }
.pt-affiche__qr svg { display: block; width: 100%; height: auto; }
.pt-affiche__meedoen { min-width: 0; }
.pt-affiche__scan { margin: 0; font-size: 1.25em; font-weight: 800; line-height: 1.15; }
.pt-affiche__uitleg { margin: .3em 0 0; font-size: .82em; line-height: 1.35; color: var(--aff-zacht); }
.pt-affiche__adres { margin: .55em 0 0; font-size: 1em; font-weight: 700; color: var(--aff-accent); overflow-wrap: break-word; }
.pt-affiche__code { margin: .1em 0 0; font-size: 1.6em; font-weight: 800; letter-spacing: .12em; }

/* Een leeg veld staat wel in de HTML (dan kan het verschijnen terwijl je
   typt) maar niet in beeld. Deze regel komt na alle andere, zodat hij van
   display:flex en display:block wint. */
.pt-affiche .is-leeg { display: none; }

/* Op een vierkant vel is het krap: daar mag de kop een maat kleiner en gaat
   de laatste regel eruit. */
.pt-affiche[data-formaat="vierkant"] .pt-affiche__binnen { padding: 1.8em; gap: .9em; }
.pt-affiche[data-formaat="vierkant"][data-kop="xl"]    .pt-affiche__kop { font-size: 4.2em; }
.pt-affiche[data-formaat="vierkant"][data-kop="groot"] .pt-affiche__kop { font-size: 3.2em; }
.pt-affiche[data-formaat="vierkant"] .pt-affiche__qr { width: calc(7.4em * var(--qr-schaal, 1)); }
.pt-affiche[data-formaat="vierkant"] .pt-affiche__uitleg { display: none; }

/* ------------------------------------------------------------------ thema's

   Elk thema zet dezelfde handvol kleuren, en daarnaast een versiering op de
   laag eronder. De kleine voorbeeldjes bij de themakeuze dragen dezelfde
   klasse, dus die kleuren vanzelf mee.
*/

/* Neon: jaren 80, met een raster dat onderin de diepte in loopt. */
.pt-aff-thema[data-thema="neon"] {
  --aff-papier: linear-gradient(170deg, #150a26 0%, #0a0612 55%, #140a1f 100%);
  --aff-inkt: #ffffff;
  --aff-zacht: #cdb7ef;
  --aff-accent: #ff3ea5;
  --aff-vlak: rgba(255,255,255,.08);
  --aff-lijn: rgba(255,255,255,.24);  --aff-vloei: #0a0612;
}
.pt-aff-thema[data-thema="neon"] .pt-affiche__sier {
  background-image:
    repeating-linear-gradient(90deg, rgba(45,226,230,.30) 0 .05em, transparent .05em 2.4em),
    repeating-linear-gradient(0deg,  rgba(45,226,230,.30) 0 .05em, transparent .05em 2.4em),
    radial-gradient(60% 38% at 50% 0%,   rgba(255,62,165,.45), transparent 72%),
    radial-gradient(75% 42% at 50% 100%, rgba(45,226,230,.35), transparent 72%);
  background-size: 100% 34%, 100% 34%, 100% 100%, 100% 100%;
  background-position: bottom, bottom, top, bottom;
  background-repeat: no-repeat;
}
.pt-aff-thema[data-thema="neon"][data-licht="ja"] {
  --aff-papier: #fdf7ff;
  --aff-inkt: #1a0b2b;
  --aff-zacht: #6b4b8f;
  --aff-accent: #d4147a;
  --aff-vlak: rgba(212,20,122,.08);
  --aff-lijn: rgba(26,11,43,.2);  --aff-vloei: #fdf7ff;
}
.pt-aff-thema[data-thema="neon"][data-licht="ja"] .pt-affiche__sier {
  background-image:
    repeating-linear-gradient(90deg, rgba(0,160,170,.28) 0 .05em, transparent .05em 2.4em),
    repeating-linear-gradient(0deg,  rgba(0,160,170,.28) 0 .05em, transparent .05em 2.4em);
  background-size: 100% 28%, 100% 28%;
  background-position: bottom, bottom;
  background-repeat: no-repeat;
}

/* Disco: goud op zwart, met stralen die uit een spiegelbol komen. */
.pt-aff-thema[data-thema="disco"] {
  --aff-papier: #08070a;
  --aff-inkt: #fdf7e6;
  --aff-zacht: #c9b98a;
  --aff-accent: #e8c76a;
  --aff-vlak: rgba(232,199,106,.12);
  --aff-lijn: rgba(232,199,106,.35);  --aff-vloei: #08070a;
}
.pt-aff-thema[data-thema="disco"] .pt-affiche__sier {
  background-image:
    repeating-conic-gradient(from 0deg at 50% 12%, rgba(232,199,106,.16) 0deg 4deg, transparent 4deg 14deg),
    radial-gradient(circle at 50% 12%, rgba(232,199,106,.35), transparent 38%);
}
.pt-aff-thema[data-thema="disco"][data-licht="ja"] {
  --aff-papier: #fffaf0;
  --aff-inkt: #241c08;
  --aff-zacht: #7a6734;
  --aff-accent: #a8822a;
  --aff-vlak: rgba(168,130,42,.1);
  --aff-lijn: rgba(36,28,8,.22);  --aff-vloei: #fffaf0;
}
.pt-aff-thema[data-thema="disco"][data-licht="ja"] .pt-affiche__sier {
  background-image:
    repeating-conic-gradient(from 0deg at 50% 12%, rgba(168,130,42,.12) 0deg 4deg, transparent 4deg 14deg);
}

/* Strak: één accentbalk, verder niets. Leest van ver en kost geen inkt. */
.pt-aff-thema[data-thema="strak"] {
  --aff-papier: #0b0d0f;
  --aff-inkt: #ffffff;
  --aff-zacht: #9aa5b0;
  --aff-accent: #1ed760;
  --aff-vlak: rgba(255,255,255,.07);
  --aff-lijn: rgba(255,255,255,.22);  --aff-vloei: #0b0d0f;
}
.pt-aff-thema[data-thema="strak"] .pt-affiche__sier {
  background-image: linear-gradient(var(--aff-accent), var(--aff-accent));
  background-size: 100% 1.1em;
  background-position: top;
  background-repeat: no-repeat;
}
.pt-aff-thema[data-thema="strak"][data-licht="ja"] {
  --aff-papier: #ffffff;
  --aff-inkt: #0b0d0f;
  --aff-zacht: #566069;
  --aff-accent: #0f9d4a;
  --aff-vlak: #f1f3f5;
  --aff-lijn: rgba(11,13,15,.18);  --aff-vloei: #ffffff;
}

/* Zomer: zonsondergang. */
.pt-aff-thema[data-thema="zomer"] {
  --aff-papier: linear-gradient(180deg, #f3a74b 0%, #e2622f 16%, #a43a62 38%, #4a1a5e 70%, #2b1055 100%);
  --aff-inkt: #fff6ec;
  --aff-zacht: #ffd9b8;
  --aff-accent: #ffd166;
  --aff-vlak: rgba(0,0,0,.22);
  --aff-lijn: rgba(255,255,255,.3);  --aff-vloei: #a43a62;
}
.pt-aff-thema[data-thema="zomer"] .pt-affiche__sier {
  background-image: radial-gradient(circle at 50% 8%, rgba(255,209,102,.6), transparent 38%);
}
.pt-aff-thema[data-thema="zomer"][data-licht="ja"] {
  --aff-papier: #fff8ef;
  --aff-inkt: #3a1d12;
  --aff-zacht: #8a5a3a;
  --aff-accent: #e2622f;
  --aff-vlak: rgba(226,98,47,.1);
  --aff-lijn: rgba(58,29,18,.2);  --aff-vloei: #fff8ef;
}
.pt-aff-thema[data-thema="zomer"][data-licht="ja"] .pt-affiche__sier {
  background-image: radial-gradient(circle at 50% 10%, rgba(255,183,77,.45), transparent 40%);
}

/* Oktoberfest: de ruiten van de Beierse vlag. */
.pt-aff-thema[data-thema="oktoberfest"] {
  --aff-papier: #0b3268;
  --aff-inkt: #ffffff;
  --aff-zacht: #bcd3f2;
  --aff-accent: #ffd166;
  --aff-vlak: rgba(255,255,255,.12);
  --aff-lijn: rgba(255,255,255,.32);
  --aff-ruit: rgba(255,255,255,.085);
  --aff-vloei: #0b3268;
}
.pt-aff-thema[data-thema="oktoberfest"] .pt-affiche__sier,
.pt-aff-thema[data-thema="oktoberfest"][data-licht="ja"] .pt-affiche__sier {
  background-image:
    linear-gradient(45deg, var(--aff-ruit) 25%, transparent 25% 75%, var(--aff-ruit) 75%),
    linear-gradient(45deg, var(--aff-ruit) 25%, transparent 25% 75%, var(--aff-ruit) 75%);
  background-size: 2.6em 2.6em;
  background-position: 0 0, 1.3em 1.3em;
}
.pt-aff-thema[data-thema="oktoberfest"][data-licht="ja"] {
  --aff-papier: #ffffff;
  --aff-inkt: #0d3b7a;
  --aff-zacht: #4a6b9c;
  --aff-accent: #c8891a;
  --aff-vlak: rgba(13,59,122,.08);
  --aff-lijn: rgba(13,59,122,.25);
  --aff-ruit: rgba(13,59,122,.085);
  --aff-vloei: #ffffff;
}

/* Feestdagen: donkergroen met rood en sneeuw. */
.pt-aff-thema[data-thema="kerst"] {
  --aff-papier: linear-gradient(175deg, #0c2f20 0%, #072116 100%);
  --aff-inkt: #f6fff8;
  --aff-zacht: #a9ccb6;
  --aff-accent: #e0474c;
  --aff-vlak: rgba(255,255,255,.08);
  --aff-lijn: rgba(255,255,255,.24);
  --aff-sneeuw: rgba(255,255,255,.55);
  --aff-vloei: #0a2819;
}
.pt-aff-thema[data-thema="kerst"] .pt-affiche__sier,
.pt-aff-thema[data-thema="kerst"][data-licht="ja"] .pt-affiche__sier {
  background-image:
    radial-gradient(circle, var(--aff-sneeuw) .085em, transparent .1em),
    radial-gradient(circle, var(--aff-sneeuw) .05em,  transparent .06em);
  background-size: 3.2em 3.2em, 1.9em 1.9em;
  background-position: 0 0, .9em 1.1em;
}
.pt-aff-thema[data-thema="kerst"][data-licht="ja"] {
  --aff-papier: #f6fbf7;
  --aff-inkt: #0c2f20;
  --aff-zacht: #4d7360;
  --aff-accent: #c0292e;
  --aff-vlak: rgba(12,47,32,.08);
  --aff-lijn: rgba(12,47,32,.2);
  --aff-sneeuw: rgba(12,47,32,.18);
  --aff-vloei: #f6fbf7;
}

/* ------------------------------------------------------------------ printen

   Op papier hoort alleen de poster. De schaal die hem op het scherm passend
   maakt gaat eraf, want het vel is al precies zo groot als de pagina.
*/
@media print {
  .pt-topbar,
  .pt-menubalk,
  .pt-omgevingsbalk,
  .pt-affiche__balk,
  .pt-affiche__werk { display: none !important; }

  html, body { margin: 0; padding: 0; background: #fff; }
  body.pt-affiche-body { padding-bottom: 0 !important; }

  .pt-affiche-pagina { max-width: none !important; width: auto !important; margin: 0 !important; padding: 0 !important; }
  .pt-affiche-lay { display: block; gap: 0; }
  .pt-affiche__doos { height: auto !important; overflow: visible; }
  /* De schaal en de marge die hem op het scherm in het midden zetten, zijn
     door JavaScript op het element zelf gezet. Op papier moeten ze eraf,
     anders staat het vel scheef op de pagina. */
  .pt-affiche__schaal { transform: none !important; margin-left: 0 !important; }
  .pt-affiche { box-shadow: none; break-inside: avoid; }
}

/* Het merkje bij het nummer dat draait: aan de rechterkant van het regeltje
   boven de titel. Het staat in een kopregel die alles in hoofdletters zet met
   een ruime letterafstand; een merknaam schrijf je gewoon, dus hier gaat dat
   er weer af. */
.pt-now__label .pt-chip--bron {
  margin-left: auto;
  text-transform: none;
  letter-spacing: normal;
  font-weight: 650;
}

/* De regel met het opschrift van de draaitafel, met de bronvermelding er
   direct naast. Op een smal scherm valt de vermelding netjes onder het
   opschrift in plaats van de tekst plat te drukken. */
.pt-deck__kopregel {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--s-2) var(--s-3);
  min-width: 0;
}
/* De marges die de vermelding elders van de tekst eromheen houden, moeten er
   hier af: op deze regel staat hij naast het woord en niet eronder. Zonder
   dit duwt de bovenmarge hem een stukje omlaag en staat hij scheef. */
.pt-deck__kopregel .pt-bron { margin-top: 0; margin-right: 0; }
/* De rij met de twee merken lijnt elders bovenaan uit, omdat hij daar onder
   een blok tekst hangt. Hier hoort hij midden op de regel, op dezelfde hoogte
   als het woord ernaast. */
.pt-deck__kopregel .pt-bronnen-rij { align-self: center; }

/* De knop om iemand eruit te zetten: vierkant met alleen de deur erin, ook op
   een breed scherm. Rood pas als je erover gaat, want het is geen knop waar je
   per ongeluk op moet drukken, maar ook geen knop die de hele rij rood maakt. */
.pt-btn--deur { width: var(--tap); padding: 0; justify-content: center; }
.pt-btn--deur.is-eruit:hover { color: var(--danger); border-color: rgba(255,95,109,.5); }

/* Een regel in het schermmenu die niets kan omzetten, alleen uitleggen. Geen
   schuifje erachter, en hij voelt niet aan als een knop die niet reageert. */
.pt-tvoptie--uitleg:disabled { cursor: default; opacity: 1; }
.pt-tvoptie--uitleg .pt-switch__track { display: none; }
.pt-tvoptie--uitleg .pt-tvoptie__hint { white-space: normal; }
.pt-tvoptie--uitleg:hover { background: none; }

/* De castknop in de console als de browser het niet zelf kan. Dan is er geen
   knop meer nodig: de regel eronder zegt hoe je het via je Mac of via het
   menu van Chrome wel doet, en een knop die niet reageert helpt niemand. */
.pt-btn--uitleg { display: none; }

/* De regel onder de effectknoppen die zegt waar ze klinken. Hij staat in
   hetzelfde raster als de knoppen erboven, maar de linkerkolom is hier een
   opschrift en geen knop, dus wat rustiger en rechts uitgelijnd tegen het
   keuzevak aan. */
.pt-effect--uitgang { margin-top: var(--s-3); border-top: 1px solid var(--line); padding-top: var(--s-3); }
.pt-label--klein {
  font-size: .72rem;
  font-weight: 800;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin: 0;
}

/* Een regeltje dat je ergens op wijst zonder dat er iets mis is: amber, maar
   zonder kader eromheen. Staat onder de keuze waar de effecten uit klinken. */
.pt-note--wenk { color: var(--amber); }

/* Wat er voor de deur staat, op de beheerpagina. Een definitielijst in twee
   kolommen; op een telefoon past dat niet, daar komt de waarde onder de naam. */
.pt-schild { display: grid; grid-template-columns: max-content 1fr; gap: var(--s-2) var(--s-4); align-items: baseline; margin: 0; }
.pt-schild dt { margin: 0; }
.pt-schild dd { margin: 0; min-width: 0; word-break: break-word; }
.pt-schild code { font-size: .8rem; }
@media (max-width: 599px) {
  .pt-schild { grid-template-columns: 1fr; gap: 2px; }
  .pt-schild dd + dt { margin-top: var(--s-3); }
}

/* De keuze bovenaan de DJ-login: een account aanmaken of inloggen. Twee
   knoppen naast elkaar, allebei even breed, want de vraag is binair. De
   tekst mag binnen een knop afbreken; op een telefoon past "Account
   aanmaken" niet op een regel en dat hoeft ook niet. */
.pt-login__keuze {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: var(--s-3); margin: var(--s-2) 0 var(--s-2);
  align-items: stretch;
}
/* Breekt "Account aanmaken" af, dan groeit die knop. De ander groeit mee,
   anders staan er twee knoppen van verschillende hoogte naast elkaar. */
.pt-login__keuze .pt-btn { height: 100%; padding: var(--s-2) var(--s-3); text-align: center; line-height: 1.25; }
.pt-login__keuze + .pt-login__akkoord { margin-top: var(--s-3); }
/* Onder de 340 pixels wordt naast elkaar onleesbaar smal. */
@media (max-width: 339px) { .pt-login__keuze { grid-template-columns: 1fr; } }

/* Onze eigen foutmelding onder een veld, in plaats van het oranje ballonnetje
   van de browser. Zie assets/js/velden.js. */
.pt-veldfout {
  margin: 6px 0 0;
  font-size: .82rem;
  line-height: 1.4;
  color: #ffc2c8;
  text-align: left;
}
.pt-field.is-fout .pt-input,
.pt-login__akkoord.is-fout { border-color: rgba(255, 95, 109, .55); }
.pt-login__akkoord.is-fout input[type="checkbox"] { outline: 2px solid rgba(255, 95, 109, .55); outline-offset: 2px; }

/* De drie wegen naar een uitgang, in het hulpblok van het paneel Party.
   Genummerd omdat de volgorde het halve antwoord is: het tv-scherm staat bij
   de speakers, de webspeler speelt af op de laptop van de DJ. */
.pt-uitgangwegen { margin: var(--s-3) 0; padding-left: 1.3em; display: grid; gap: var(--s-2); }
.pt-uitgangwegen li { line-height: 1.45; }
.pt-uitgangwegen strong { color: var(--text); }

/* Waarom het nummer kort klinkt, onder de klok op de draaitafel. Stond eerst
   alleen in een muis-tip, en die bestaat op een telefoon niet. */
.pt-now__stukreden {
  margin-top: 4px;
  font-size: .78rem;
  line-height: 1.4;
  color: var(--amber);
}

/* Geen dubbele streep in het zoekblok van de console.
   De tabbalk (Spotify / YouTube / Van de DJ) heeft een lijn onder zich en de
   playlistlade een lijn boven zich. Zolang er geen zoekresultaten tussen
   staan, en dat is het grootste deel van de avond, liggen die twee pal op
   elkaar. Dan is een lijn genoeg. */
#dj-search-results:empty + #playlist-lade { border-top: 0; }

/*
   Een zoekbalk met twee knoppen erachter op een telefoon.

   Het veld hield over wat de knoppen lieten liggen, en bij "Opslaan" en
   "Wissen" was dat zo weinig dat er van "AIza..." nog "Alza" overbleef. Het
   veld gaat nu over de volle breedte en de knoppen staan eronder.
*/
@media (max-width: 599px) {
  .pt-searchbar { flex-wrap: wrap; }
  .pt-searchbar > .pt-input { flex: 1 1 100%; min-width: 0; }
  .pt-searchbar > .pt-btn { flex: 1 1 auto; }
}

/*
   Een rij met een vinkje, twee knoppen en een standregel.

   Als flexrij viel die op een telefoon uiteen: het vinkje links, de ene knop
   ernaast, de andere eronder op een nieuwe plek, en de standregel ergens
   ertussendoor. Als raster staat het vinkje op zijn eigen regel, staan de
   twee knoppen naast elkaar even breed, en komt de stand eronder.
*/
@media (max-width: 599px) {
  .pt-knoprij {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--s-2);
    align-items: center;
  }
  .pt-knoprij > label,
  .pt-knoprij > span { grid-column: 1 / -1; }
  .pt-knoprij > .pt-btn { width: 100%; }
}

/* --------------------------------------------- tikdoelen op een aanraakscherm

   Nagemeten op 14-10-2026, op 320, 390, 768 en 1280 breed. Drie dingen die je
   met je duim moet kunnen raken bleven onder de vierenveertig pixels die de
   richtlijnen aanhouden.

   Dit blok staat achteraan en niet bij het blok 'pointer: coarse' hierboven,
   want .pt-tabel__sort zet zelf padding op 0 en .pt-bron zet zijn marges, en
   die regels staan verderop in dit bestand. Een media query wint niet van een
   gewone regel die later komt.

   Wat met opzet klein blijft staat in een rij van de wachtrij of een lijst.
   Daar is 34 of 38 de maat, want een rij van 120 pixels betekent dat je er zes
   ziet terwijl je tijdens een feest juist wilt zien wat eraan komt. Die
   afweging staat bij .pt-track en .pt-vraagrij__knoppen uitgeschreven. Het
   gaat om .pt-track__actions (34), .pt-move__btn (33), .pt-djvote__btn (28),
   .pt-jaarknop (19) en .pt-vraagrij__knoppen (38). Die laten we dus staan; een
   meting die ze noemt is geen fout maar een keuze. */
@media (pointer: coarse) {
  /* Een kolomkop waarop je sorteert was zeventien pixels hoog in een cel van
     achtendertig. De knop vult nu de hele cel, dus je raakt wat je ziet. */
  .pt-tabel__sort {
    display: block;
    width: 100%;
    text-align: inherit;
    padding-block: 14px;
    margin-block: -10px;
  }

  /* Een uitklapper ('Uit een playlist van Spotify') was eenentwintig pixels
     en is op die pagina's wel de knop waar je op drukt. */
  .pt-vouw > summary { padding-block: 12px; }

  /* Hetzelfde voor de uitklapper Effecten in de console. */
  .pt-effecten__kop { padding-block: 14px; }

  /* De tabs boven de wachtrij (Wachtrij, Al gedraaid) waren drieendertig. De
     streep onder de actieve tab blijft onderaan staan, want die hangt aan de
     onderrand van de knop. */
  .pt-rijtab {
    display: inline-flex;
    align-items: center;
    min-height: var(--tap);
  }

  /* Het kruisje waarmee je een lade dichtdoet was dertig. */
  .pt-lade__dicht { width: var(--tap); height: var(--tap); }

  /* De velden in de zoekrij boven de wachtrij bleven op veertig staan. Niet
     omdat iemand dat wilde, maar omdat `.pt-zoekrij .pt-input` specifieker is
     dan de regel `.pt-input--sm` die hierboven in dit bestand al vierenveertig
     vraagt. Specificiteit wint van volgorde, dus die regel kwam er nooit
     doorheen. */
  .pt-zoekrij .pt-input { min-height: var(--tap); }

  /* De bronvermelding onderaan een pagina. Ruimte eromheen in plaats van een
     hogere regel, zodat er niets verschuift. De marges nemen precies terug wat
     de ruimte erbij zet, boven en onder, dus de tekst staat op dezelfde plek
     en de pagina wordt geen pixel langer. Nagemeten. */
  .pt-bron {
    /* Blok in plaats van inline, anders bepaalt de regelhoogte mee wat dit
       wordt en schuift de tekst alsnog een paar pixels. Breed is hij alleen
       zover als zijn inhoud, dus het tikvlak loopt niet door over de hele
       regel. */
    display: flex;
    width: fit-content;
    padding-block: 13px;
    /* Dertien eraf voor de ruimte die erbij komt, en nog vier omdat een blok
       niet de regelafstand van de alinea meekrijgt die een inline-link wel
       had. Nagemeten op /uitleg.php: de tekst staat op dezelfde pixel als met
       een muis en de hele pagina scheelt er twee op bijna vijftigduizend. */
    margin-block: calc(var(--s-2) - 17px) -9px;
  }
}

