/* pase.gameon.mx — the member passport (layouts/pase).
 *
 * Ported from the prototype (apps/mobile-app/passport/index.html), which is
 * the UX source of truth: one phone column on sand, cards with 2px ink borders
 * and hard offset shadows, an ink tab bar. Its own sheet and not
 * application.css: the passport loads this, the fonts and nothing else, so a
 * phone on a venue's Wi-Fi downloads tens of kilobytes, not the news site's
 * three hundred.
 *
 * Responsiveness rules every rule here keeps:
 *   - Spacing and fixed heights on the 4px grid.
 *   - Every tappable thing is at least 44px tall, and answers the tap at once
 *     with a pressed state (:active) — no 300ms wait, no hover dependence.
 *   - Nothing animates layout properties; motion is transform and opacity,
 *     and none of it under prefers-reduced-motion.
 *   - Images carry width and height in the markup (PaseHelper#pase_image), so
 *     the CSS only ever scales a box that is already reserved. */

:root {
  --sand: #FFFBEF;
  --sand-2: #F1ECDC;
  --sand-3: #E2DAC4;
  --paper: #FFFFFF;
  --cream: #FFFDF5;
  --ink: #17150F;
  --ink-2: #4A463B;
  --muted: #5E5745;
  --subtle: #767162;
  --yellow: #F9C901;
  --yellow-50: #FFFBEB;
  --coral: #FF5C39;
  --green-ink: #0B7239;
  --green-surface: #E4F7EC;
  --font: "Outfit", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
  --shadow: 4px 4px 0 var(--ink);
  --shadow-sm: 4px 4px 0 var(--ink);
  --pressed: 2px 2px 0 var(--ink);
  color-scheme: light;
}

*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }
html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
html, body { min-height: 100%; }
body {
  margin: 0;
  text-wrap: pretty;
  background: var(--sand);
  color: var(--ink);
  font-family: var(--font);
  font-size: 16px;
  line-height: 24px;
  -webkit-tap-highlight-color: transparent;
  /* No double-tap zoom delay on the passport's controls. */
  touch-action: manipulation;
}
a { color: var(--ink); }
:focus-visible { outline: 3px solid var(--ink); outline-offset: 2px; }
button { font: inherit; color: inherit; }
h1, h2, h3, p { margin: 0; }
h1, h2, h3 { text-wrap: balance; }
img, svg { display: block; }
img { max-width: 100%; height: auto; }

/* One phone column. On a wider screen it stays a phone, framed. */
.app {
  max-width: 430px;
  margin: 0 auto;
  min-height: 100vh;
  min-height: 100dvh;
  background: var(--sand);
  overflow-x: clip;
  padding-top: env(safe-area-inset-top, 0px);
  padding-bottom: env(safe-area-inset-bottom, 0px);
}
@media (min-width: 470px) {
  body { background: var(--sand-2); }
  .app { border-inline: 2px solid var(--ink); }
}
.app:has(.tabbar) { padding-bottom: calc(96px + env(safe-area-inset-bottom, 0px)); }

.screen {
  padding: 20px 20px 32px;
  display: flex;
  flex-direction: column;
  gap: 20px;
  animation: screen-in .18s ease-out;
}
@keyframes screen-in { from { opacity: .4; transform: translateY(4px); } }

/* Notes above the screen: test mode and flash. */
.testing, .flash {
  margin: 0;
  padding: 8px 20px;
  font-size: 14px;
  line-height: 20px;
  font-weight: 700;
  border-bottom: 2px solid var(--ink);
}
/* Ink on purpose, not inherited: on the dark hunt screen the page's text is
 * sand, which on yellow cannot be read. */
.testing { background: var(--yellow); color: var(--ink); }
.flash--notice { background: var(--yellow-50); }
.flash--alert { background: #FFE4DC; }

/* Type */
.kicker { display: block; font-size: 12px; line-height: 16px; font-weight: 700; letter-spacing: .12em; color: var(--subtle); text-transform: uppercase; }
.h1 { font-size: 28px; line-height: 32px; font-weight: 900; letter-spacing: -.03em; }
.h2 { font-size: 20px; line-height: 24px; font-weight: 900; letter-spacing: -.02em; }
.mono-k { font-family: var(--mono); font-size: 12px; line-height: 16px; font-weight: 600; letter-spacing: .08em; color: var(--muted); text-transform: uppercase; }
.lbl { display: block; font-family: var(--mono); font-size: 12px; line-height: 16px; font-weight: 500; letter-spacing: .08em; color: var(--muted); text-transform: uppercase; }
.val { display: block; font-size: 16px; line-height: 20px; font-weight: 800; }
.note { font-size: 14px; line-height: 20px; font-weight: 600; color: var(--ink-2); text-align: center; }
.sec-head { display: flex; justify-content: space-between; align-items: center; gap: 12px; min-height: 32px; }
.head-aside { font-size: 14px; line-height: 20px; font-weight: 700; color: var(--ink-2); white-space: nowrap; }
.col-12 { display: flex; flex-direction: column; gap: 12px; }

/* Header: meeple, title, chips */
.hdr { display: flex; align-items: center; gap: 12px; min-height: 48px; }
.hdr-av { width: 56px; height: 52px; flex: none; display: block; }
a.hdr-av:active { transform: scale(.95); }
.hdr-av .pase-av { width: 56px; height: 52px; overflow: visible; }
.hdr-txt { flex: 1; min-width: 0; }
/* «Hola, <name>»: a name is one long word as often as not (an email's local
 * part), so it ends in an ellipsis rather than running under the chips. */
.hdr-txt .kicker { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hdr-txt .h1 { font-size: 24px; line-height: 28px; overflow-wrap: anywhere; }
.hdr-chips { display: flex; gap: 8px; flex: none; }
.hdr-chip {
  display: inline-flex; align-items: center; gap: 4px; height: 32px; padding: 0 8px;
  border-radius: 999px; background: var(--yellow); border: 2px solid var(--ink);
  font-size: 16px; font-weight: 900; font-variant-numeric: tabular-nums;
}
.hdr-chip svg { width: 18px; height: 18px; flex: none; }

/* Cards and buttons */
.card { background: var(--paper); border: 2px solid var(--ink); border-radius: 16px; box-shadow: var(--shadow); }
.empty { padding: 16px; font-size: 16px; line-height: 24px; color: var(--ink-2); box-shadow: none; }

.btn {
  min-height: 48px; border-radius: 999px; border: 2px solid var(--ink); background: var(--ink); color: var(--sand);
  font-size: 16px; line-height: 20px; font-weight: 800; padding: 0 20px;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  cursor: pointer; text-decoration: none; user-select: none; -webkit-user-select: none;
  transition: transform .06s ease-out;
}
.btn:active { transform: translateY(2px); }
.btn--yellow { background: var(--yellow); color: var(--ink); box-shadow: var(--shadow-sm); }
.btn--yellow:active { transform: translate(2px, 2px); box-shadow: var(--pressed); }
.btn--alt { background: var(--paper); color: var(--ink); box-shadow: var(--shadow-sm); }
.btn--block { width: 100%; }
.btn[disabled], .btn[aria-disabled="true"] { background: var(--sand-3); color: var(--muted); border-color: var(--subtle); box-shadow: none; cursor: progress; transform: none; }

.status {
  display: inline-flex; align-items: center; gap: 8px; min-height: 32px;
  border: 2px solid var(--ink); border-radius: 999px; padding: 4px 12px;
  font-size: 14px; line-height: 20px; font-weight: 800; background: var(--paper); white-space: nowrap;
}
.status--next { background: var(--yellow); }
.chips { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; }

.tag {
  display: inline-block; font-family: var(--mono); font-size: 12px; line-height: 16px; font-weight: 600;
  letter-spacing: .1em; text-transform: uppercase; background: var(--ink); color: var(--sand);
  border-radius: 4px; padding: 0 8px;
}

/* The pass for the next meetup */
.ticket { position: relative; background: var(--yellow); border: 2px solid var(--ink); border-radius: 20px; box-shadow: var(--shadow); }
.t-top { padding: 16px; display: flex; flex-direction: column; gap: 12px; }
.t-row { display: flex; justify-content: space-between; gap: 8px; font-family: var(--mono); font-size: 12px; line-height: 16px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; }
.t-title { font-size: 28px; line-height: 32px; font-weight: 900; letter-spacing: -.03em; overflow-wrap: anywhere; color: var(--ink); text-decoration: none;
  /* A link now (to the meetup): a 44px target on one line, paid back by the
   * margin so the ticket keeps its rhythm. */
  display: block; padding-block: 6px; margin-block: -6px; }
.t-fields { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
.t-fields .lbl { color: var(--ink); }
.t-fields .val { overflow-wrap: anywhere; }
/* The tear line, with a notch bitten out of each edge. A notch is a sand disc
 * centred on the card's outer edge — big enough to cover the border and the
 * hard shadow beside it — plus an ink half-ring clipped to the half inside the
 * card. Nothing is rotated, so no box reaches past the phone column. */
.t-div { position: relative; height: 0; border-top: 2px dashed var(--ink); margin: 0 20px; }
.t-notch { position: absolute; top: -17px; width: 32px; height: 32px; }
.t-notch--l { left: -38px; }
.t-notch--r { right: -38px; }
.t-notch::before, .t-notch::after { content: ""; position: absolute; inset: 0; border-radius: 50%; }
.t-notch::before { background: var(--sand); }
.t-notch::after { border: 2px solid var(--ink); }
.t-notch--l::after { clip-path: inset(0 0 0 50%); }
.t-notch--r::after { clip-path: inset(0 50% 0 0); }
.t-bottom { padding: 16px; display: flex; flex-direction: column; gap: 12px; }
.t-scan { display: flex; align-items: center; gap: 16px; }
.scan-ill { width: 76px; height: 76px; flex: none; background: var(--paper); border: 2px solid var(--ink); border-radius: 16px; display: flex; align-items: center; justify-content: center; }
.t-scan p { font-size: 16px; line-height: 20px; font-weight: 700; }
.t-bottom .note { text-align: left; }

/* «Tus stickers»: the passes already used, stacked like tickets in a wallet */
.stack { position: relative; }
.strip, .front {
  position: absolute; display: flex; justify-content: space-between; gap: 12px; color: var(--ink);
  border: 2px solid var(--ink); border-radius: 16px;
}
.strip { height: 112px; padding: 4px 16px; font-size: 14px; line-height: 24px; font-weight: 700; }
.strip-t { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.strip .d { font-family: var(--mono); font-size: 12px; font-weight: 500; text-transform: uppercase; white-space: nowrap; }
.strip--0 { background: #F1ECDC; }
.strip--1 { background: #4B82F0; }
.strip--2 { background: #12B3B1; }
.strip--3 { background: #8B72F0; }
.strip--4 { background: #FF7A5C; }
.strip--5 { background: #FCD84D; }
.front { left: 0; right: 0; height: 116px; background: var(--paper); box-shadow: var(--shadow); padding: 12px 16px; align-items: center; }
.front-txt { flex: 1; display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.front-k { font-family: var(--mono); font-size: 12px; line-height: 16px; font-weight: 500; letter-spacing: .08em; color: var(--ink-2); text-transform: uppercase; }
.front-t { font-size: 20px; line-height: 24px; font-weight: 900; letter-spacing: -.02em; text-wrap: balance; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.front-img { width: 80px; height: auto; max-height: 72px; object-fit: contain; flex: none; transform: rotate(6deg); }

/* Check-in: closed, ready, and the reveal */
/* svh, not dvh: the smallest viewport, so the centred content does not slide
 * when a phone's address bar hides as the page scrolls. */
.checkin {
  min-height: calc(100svh - 64px - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px));
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 16px; text-align: center;
}
/* The picture and the action sit a step further from the words than the
 * words from each other. */
.checkin > :first-child { margin-bottom: 8px; }
.checkin p { font-size: 16px; line-height: 24px; color: var(--ink-2); max-width: 22rem; }
/* A status tile, not a control: border only, since the hard shadow is what
 * marks the things you can press. */
.checkin-ill { width: 96px; height: 96px; display: flex; align-items: center; justify-content: center; background: var(--paper); border: 2px solid var(--ink); border-radius: 24px; }
.checkin .actions, .checkin form.actions, .checkin > .btn { display: flex; flex-direction: column; gap: 12px; width: 100%; margin: 8px 0 0; }
.checkin .btn { width: 100%; }
.checkin-sticker svg { width: 160px; height: auto; }
.entry-logo { width: 96px; height: 83px; }

/* The die-cut sticker casts the system's hard ink shadow, following its
 * outline. */
.reveal-sticker { width: 200px; filter: drop-shadow(4px 4px 0 var(--ink)); }
/* The door's form: an address, or a password. 16px text, so iOS does not zoom
 * the page when the field takes focus. */
.entry { display: flex; flex-direction: column; gap: 8px; width: 100%; text-align: left; margin-top: 8px; }
.entry-label { font-size: 14px; line-height: 20px; font-weight: 700; }
.entry-input {
  height: 48px; width: 100%; padding: 0 16px; border: 2px solid var(--ink); border-radius: 12px;
  background: var(--paper); color: var(--ink); font: inherit; font-size: 16px;
}
/* Focus in the palette: the ink ring, with a yellow halo between field and
 * ring so it reads as a state and not as a second border. */
.entry-input:focus { outline: 3px solid var(--ink); outline-offset: 2px; box-shadow: 0 0 0 2px var(--yellow); }
.entry .btn { margin-top: 8px; }
.text-link {
  min-height: 44px; display: inline-flex; align-items: center; font-size: 16px; font-weight: 800;
  color: var(--ink); text-decoration: underline; text-underline-offset: 3px;
}
/* The same link when it is a form's button (button_to): none of the
 * browser's button. */
button.text-link { background: none; border: 0; padding: 0; font-family: inherit; cursor: pointer; }

.reveal-sticker img, .reveal-sticker svg { width: 200px; height: auto; }
.reveal--fresh:not(.reveal--held) .reveal-sticker { animation: flip-in .9s cubic-bezier(.2, .8, .2, 1.1) both; }
@keyframes flip-in {
  0% { transform: perspective(600px) rotateY(100deg) scale(.5); opacity: 0; }
  60% { transform: perspective(600px) rotateY(-14deg) scale(1.08); opacity: 1; }
  100% { transform: none; }
}
.reveal--fresh:not(.reveal--held) :is(.reveal-h, .chips, .new-medal) { animation: rise-in .35s .45s ease-out both; }
@keyframes rise-in { from { opacity: 0; transform: translateY(8px); } }

/* ── The check-in's stamp (pase/checkins/_stamp, stamp_controller.js) ── The
 * reveal is held, unseen but in its place, while this year's passport page is
 * stamped over it, and flips in as the page turns away. Should the script never
 * run, it shows by itself, unanimated. */
.reveal--held { visibility: hidden; animation: stamp-failsafe 1ms 4s forwards; }
@keyframes stamp-failsafe { to { visibility: visible; } }
/* The page: the whole screen, over the tab bar, its contents in the phone
 * column (a screen wider than the column still sees only paper). Its paper
 * and security print: fine waves, as a passport's page has; an ink edge, so
 * it reads as a sheet while it slides up. */
.stamp-page {
  position: fixed; inset: 0; z-index: 30;
  display: flex; flex-direction: column; gap: 12px; overflow: hidden; backface-visibility: hidden;
  /* It turns on the column's left edge, where a page's spine would be. */
  transform-origin: max(0px, calc((100vw - 430px) / 2)) 50%;
  padding: calc(20px + env(safe-area-inset-top, 0px)) max(20px, calc((100vw - 430px) / 2 + 20px)) calc(16px + env(safe-area-inset-bottom, 0px));
  background: #FBF6E6; color: var(--ink); border-top: 2px solid var(--ink); touch-action: manipulation; cursor: pointer;
}
.stamp-page::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background:
    repeating-radial-gradient(circle at 120% 40%, transparent 0 9px, #D9E3D6 9px 10px),
    repeating-radial-gradient(circle at -20% 70%, transparent 0 13px, #E6DCC0 13px 14px);
  mask-image: linear-gradient(180deg, rgba(0, 0, 0, .55), rgba(0, 0, 0, .25));
}
.stamp-page > * { position: relative; }
.stamp-head {
  display: flex; justify-content: space-between; gap: 12px; padding-bottom: 8px;
  border-bottom: 2px solid var(--ink); color: var(--ink);
}
.stamp-head span { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
/* The boxes and the caption under them, centred together in what the head
 * and the foot leave. */
.stamp-grid { margin-top: auto; display: grid; grid-template-columns: 1fr 1fr; gap: 28px 8px; }
.stamp-cell { display: grid; place-items: center; min-width: 0; }
/* Tonight's box under its ink, one on the other. */
.stamp-cell > * { grid-area: 1 / 1; }
/* An impression: ink laid on paper, multiplied into it. Tonight's waits,
 * unseen, for the stamp to put it there. */
/* Two rows of them fit any screen, a phone on its side included. */
.stamp-imp, .stamp-slot { width: min(100%, 168px, (100dvh - 230px) * .57); mix-blend-mode: multiply; }
.stamp-imp svg, .stamp-slot svg { width: 100%; height: auto; overflow: visible; }
.stamp-imp--new { opacity: 0; }
.stamp-imp--empty { aspect-ratio: 655 / 570; }
.stamp-caption { margin-bottom: auto; text-align: center; color: var(--ink); opacity: 0; }
.stamp-skip {
  align-self: center; min-height: 44px; padding: 0 12px; border: 0; background: none; color: var(--subtle); cursor: pointer;
}
.stamp-foot {
  font-family: var(--mono); font-size: 12px; line-height: 16px; letter-spacing: .06em; color: var(--muted);
  /* Broken anywhere and cut to one line: it ends on a whole character. */
  word-break: break-all; height: 16px; overflow: hidden;
}
.stamp-shade { position: absolute; inset: 0; opacity: 0; pointer-events: none; background: linear-gradient(90deg, rgba(23, 21, 15, 0) 30%, rgba(23, 21, 15, .28)); }
/* The stamp and its hard shadow, laid by the script over tonight's box. */
.stamp-tool, .stamp-shadow { position: absolute; z-index: 2; pointer-events: none; will-change: transform, opacity; }
.stamp-tool { z-index: 3; transform-origin: 50% 67.2%; }
.stamp-tool svg, .stamp-shadow svg { width: 100%; height: auto; overflow: visible; }
.stamp-shadow svg { transform: scaleY(.55); }
/* A phone on its side: the four boxes in one wider row, sized by the height. */
@media (orientation: landscape) and (max-height: 500px) {
  .stamp-page {
    gap: 4px; transform-origin: max(0px, calc((100vw - 760px) / 2)) 50%;
    padding-inline: max(20px, calc((100vw - 760px) / 2 + 20px));
  }
  .stamp-grid { grid-template-columns: repeat(4, 1fr); }
  .stamp-imp, .stamp-slot { width: min(100%, 168px, (100dvh - 150px) * 1.1); }
  .stamp-foot { display: none; }
}

.new-medal {
  display: flex; align-items: center; gap: 12px; text-align: left; width: 100%;
  background: var(--paper); border: 2px solid var(--ink); border-radius: 16px; box-shadow: var(--shadow-sm); padding: 8px 16px 8px 8px;
}
.new-medal svg { width: 56px; height: 48px; flex: none; }
.new-medal > span { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; min-width: 0; }
.new-medal b { font-size: 16px; line-height: 20px; font-weight: 900; }
.new-medal small { font-size: 14px; line-height: 20px; color: var(--ink-2); }
/* «Mi cuenta»: a logro earned by the meeple editor, over the page's foot. */
.medal-toast {
  position: fixed; left: 50%; bottom: calc(16px + env(safe-area-inset-bottom, 0px)); z-index: 20;
  width: min(calc(100% - 32px), 398px); transform: translateX(-50%); pointer-events: none; box-shadow: var(--shadow);
  animation: toast-in .35s ease-out both, toast-out .4s 6s ease-in forwards;
}
@keyframes toast-in { from { opacity: 0; transform: translate(-50%, 16px); } to { transform: translateX(-50%); } }
@keyframes toast-out { to { opacity: 0; transform: translate(-50%, 16px); visibility: hidden; } }

/* Inicio: the member's card, the three counts, the strips. */
.member { padding: 16px; display: flex; align-items: center; gap: 16px; background: var(--cream); }
.member-av { width: 112px; height: 104px; flex: none; }
.member-av .pase-av { width: 112px; height: 104px; overflow: visible; }
.member-fields { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.member-fields .val { overflow-wrap: anywhere; }

.stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 12px; }
.stat {
  min-height: 64px; padding: 8px 12px; display: flex; flex-direction: column; justify-content: center;
  background: var(--paper); border: 2px solid var(--ink); border-radius: 12px; box-shadow: var(--shadow-sm);
  color: var(--ink); text-decoration: none;
}
a.stat:active { transform: translate(2px, 2px); box-shadow: var(--pressed); }
.stat--hl { background: var(--yellow); }
.stat b { display: flex; align-items: center; gap: 4px; font-size: 28px; line-height: 32px; font-weight: 900; font-variant-numeric: tabular-nums; }
.stat b svg { width: 20px; height: 20px; }
.stat small { font-size: 16px; font-weight: 800; color: var(--ink-2); }
.stat span { font-size: 12px; line-height: 16px; font-weight: 700; }

.medal-row { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 4px; }
.medal-mini {
  min-height: 44px; display: flex; flex-direction: column; align-items: center; gap: 4px; text-align: center;
  color: var(--ink); text-decoration: none; min-width: 0;
}
/* The name's type is the name's alone: the sheet a mini opens
 * (pase/attendees/show) is in its DOM and would inherit it. */
.medal-mini > span { font-size: 12px; line-height: 16px; font-weight: 700; text-wrap: balance; hyphens: auto; overflow-wrap: anywhere; }
.medal-mini > svg, .medal-mini .medal-open > svg { width: 56px; height: 48px; }

.sticker-strip { display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 64px; padding: 8px 16px; color: var(--ink); text-decoration: none; }
.sticker-strip:active { transform: translate(2px, 2px); box-shadow: var(--pressed); }
/* Overlapping a quarter, the first one whole: nothing is clipped. */
.sticker-strip-imgs { display: flex; align-items: center; min-width: 0; }
.sticker-strip-imgs > * { width: 48px; height: auto; max-height: 44px; object-fit: contain; flex: none; margin-left: -12px; }
.sticker-strip-imgs > :first-child { margin-left: 0; }
/* Six of them take 228px, which a 360px phone does not give the strip beside
 * «Ver todos» (201px): there they overlap more, never into the link. */
@media (max-width: 389px) { .sticker-strip-imgs > * { margin-left: -18px; } }
.sticker-strip .text-link { white-space: nowrap; }

/* Stickers: the season's progress and the honeycomb. */
.progress { padding: 16px; display: flex; flex-direction: column; gap: 12px; }
.progress-top { display: flex; align-items: flex-end; justify-content: space-between; gap: 8px; }
.progress-count { font-size: 16px; font-weight: 600; }
.big { font-size: 40px; line-height: 40px; font-weight: 900; letter-spacing: -.04em; font-variant-numeric: tabular-nums; }
.streak-pill { display: inline-flex; align-items: center; gap: 4px; min-height: 32px; padding: 4px 12px; background: #FFF3EE; border: 2px solid var(--ink); border-radius: 999px; font-size: 14px; font-weight: 800; white-space: nowrap; }
.segs { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 4px; }
.seg { height: 12px; border-radius: 4px; border: 2px solid var(--ink); background: var(--paper); }
.seg--attended { background: var(--yellow); }
.seg--missed { background: var(--sand-3); border-style: dashed; border-color: var(--subtle); }
.seg--future { border-color: var(--sand-3); }
.guess-line { font-size: 14px; line-height: 20px; font-weight: 600; color: var(--muted); }
.guess-line b { color: var(--ink); }

.hive { position: relative; width: 100%; max-width: 360px; margin: 0 auto; }
.cell { position: absolute; width: 30.725%; display: block; color: var(--ink); text-decoration: none; border-radius: 12px; }
.cell .cell-img { position: absolute; left: 4.7%; top: 4.3%; width: 90.6%; height: 91.3%; object-fit: contain; }
.cell .frame { position: absolute; inset: 0; width: 100%; height: 100%; }
.cell:active .cell-img { transform: scale(.96); }
.pill {
  position: absolute; left: 50%; bottom: -4px; transform: translateX(-50%);
  background: var(--ink); color: var(--sand); border: 2px solid var(--sand); border-radius: 999px;
  font-size: 12px; line-height: 16px; font-weight: 800; padding: 0 8px; white-space: nowrap;
}
.hint { font-size: 14px; line-height: 20px; font-weight: 600; color: var(--muted); text-align: center; }

/* Stickers: the season puzzle (docs/plans/2026-10-07-pase-season-puzzle.md
   §3.1), on the hive's back. «Voltear» turns each cell over (rotateY,
   staggered by slot) and slides it into the assembled hive by the transform
   the server wrote (--slide, Pase::Hive#slide); then the member's tiles fade
   in. Transforms and opacity only: the hive keeps its box, nothing reflows.
   Tiles and slots are hex boxes moved by a translate in their own
   percentages (Pase::Hive#tile_at); their size and a cell's back come from
   Pase::Hive too, through the hive's --tile-* and --back-* variables. */
.hive-wrap { display: flex; flex-direction: column; gap: 12px; }
/* The board takes the column, as the cards around it do: its framed poster
   is as wide as they are. */
.hive.hive--board { max-width: none; }
.puzzle-bar { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 12px 12px 12px 16px; }
.puzzle-count { margin: 0; min-width: 0; }
.puzzle-count b { display: block; font-size: 24px; line-height: 28px; font-weight: 900; letter-spacing: -.02em; font-variant-numeric: tabular-nums; }
.puzzle-count small { display: block; font-size: 14px; line-height: 20px; font-weight: 600; color: var(--ink-2); }
.puzzle-actions { display: flex; align-items: center; gap: 8px; flex: none; }
.btn--icon { width: 48px; padding: 0; flex: none; }
/* As wide as its longer label, so «Ver stickers» moves nothing beside it. */
.puzzle-turn { width: 120px; padding: 0 8px; }
.puzzle-sound .snd-off, .puzzle-sound[aria-pressed="false"] .snd-on { display: none; }
.puzzle-sound[aria-pressed="false"] .snd-off { display: inline; }
/* Two lines' room, so a longer hint never pushes the hive down. */
.puzzle-hint { min-height: 40px; margin: 0; }
.puzzle-other { margin-top: 4px; }
/* The meetup page's «Secretos» card: the piece its secrets give. */
.puzzle-line { margin: 0; font-size: 14px; line-height: 20px; font-weight: 600; color: var(--ink-2); }

.cell-flip, .cell-face { position: absolute; inset: 0; display: block; }
.hive--board .cell {
  perspective: 600px;
  transition: transform 650ms cubic-bezier(.2, .8, .2, 1) var(--d, 0ms), opacity 300ms ease;
}
.hive--board .cell-flip { transform-style: preserve-3d; transition: transform 650ms cubic-bezier(.3, .7, .2, 1) var(--d, 0ms); }
.hive--board .cell-face { backface-visibility: hidden; -webkit-backface-visibility: hidden; }
/* The back: a plain sticker back, the hex's box inside the cell's. */
.cell-back {
  inset: auto; left: var(--back-x); top: var(--back-y); width: var(--back-w); height: var(--back-h);
  transform: rotateY(180deg); background: var(--sand-3);
  clip-path: polygon(25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%, 0 50%);
}
.cell-back::after { content: ""; position: absolute; inset: 2px; clip-path: inherit; background: var(--sand-2); }
.hive.is-flipped .cell { transform: var(--slide); pointer-events: none; }
.hive.is-flipped .cell-flip { transform: rotateY(180deg); }
.hive.is-flipped .cell--off { opacity: 0; }

.board-layer { position: absolute; inset: 0; opacity: 0; visibility: hidden; transition: opacity 260ms ease, visibility 0s linear 260ms; }
.hive.is-settled .board-layer { opacity: 1; visibility: visible; transition: opacity 260ms ease; }
.slot, .tile {
  position: absolute; left: 0; top: 0; width: var(--tile-w); height: var(--tile-h);
  margin: 0; padding: 0; border: 0; background: none; color: inherit;
}
.slot { cursor: pointer; clip-path: polygon(25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%, 0 50%); }
.hive.is-picking .slot--empty { background: rgba(249, 201, 1, .35); }
/* The tile's own box takes no taps: its picture does, inside the hex, so a
   tap on a neighbour's corner is the neighbour's. */
.tile { z-index: 1; pointer-events: none; transition: transform 420ms cubic-bezier(.2, .8, .2, 1); }
.tile img {
  position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: auto; cursor: pointer;
  clip-path: polygon(25% 0, 75% 0, 100% 50%, 75% 100%, 25% 100%, 0 50%); transition: filter 200ms ease;
  -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
}
.tile--fixed img { cursor: default; }
.tile:focus-visible { outline: none; }
.tile.is-lifted { z-index: 3; }
.tile.is-lifted img { filter: brightness(1.08); }
/* The lifted tile's outline: its own element, so the picture's hex clip
   cannot cut it down. The hex of a box 4 units larger all round. */
.tile-ring {
  position: absolute; left: -4.167%; top: -4.878%; width: 108.333%; height: 109.756%; display: none; pointer-events: none;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 104 90' preserveAspectRatio='none'%3E%3Cg fill='none' stroke-linejoin='round'%3E%3Cpolygon points='24,0 72,0 96,41 72,82 24,82 0,41' stroke='%2317150F' stroke-width='7'/%3E%3Cpolygon points='24,0 72,0 96,41 72,82 24,82 0,41' stroke='%23F9C901' stroke-width='4'/%3E%3C/g%3E%3C/svg%3E") 0 0 / 100% 100% no-repeat;
}
.tile.is-lifted .tile-ring, .tile:focus-visible .tile-ring { display: block; }

/* The finale (§3.2): the stage shrinks the hive into a framed print in the
   same box (--solved, --k from Pase::Hive#frame), the poster fades in under
   the tiles, the colour tiles dissolve into it and grey ones stay. The
   frame's lines are divided by the stage's scale so they land at 2px: a
   cream mat, deeper at the foot, the app's ink edge and hard shadow. */
.hive-stage { position: absolute; inset: 0; transform-origin: 0 0; transition: transform 700ms cubic-bezier(.2, .8, .2, 1); }
.hive.is-solved .hive-stage { transform: var(--solved); }
.poster-frame {
  position: absolute; left: 0; top: 0; background: var(--sand); opacity: 0; pointer-events: none;
  border-radius: calc(10px / var(--k, 1));
  box-shadow: inset 0 0 0 calc(2px / var(--k, 1)) var(--ink), calc(4px / var(--k, 1)) calc(4px / var(--k, 1)) 0 var(--ink);
  transition: opacity 200ms ease;
}
.poster-plate {
  position: absolute; left: 50%; bottom: calc(9px / var(--k, 1)); transform: translateX(-50%); white-space: nowrap;
  padding: calc(2px / var(--k, 1)) calc(10px / var(--k, 1)); background: var(--sand-2); border: calc(1.5px / var(--k, 1)) solid var(--ink);
  border-radius: calc(4px / var(--k, 1)); color: var(--ink-2); box-shadow: inset 0 calc(1px / var(--k, 1)) 0 #fff;
  font-size: calc(11px / var(--k, 1)); line-height: 1.45; font-weight: 800; letter-spacing: .12em; text-transform: uppercase;
}
.poster { position: absolute; left: 0; top: 0; opacity: 0; pointer-events: none; border-radius: 2px; overflow: hidden; transition: opacity 200ms ease; }
.poster img { display: block; width: 100%; height: 100%; }
.hive.is-solved .poster-frame { opacity: 1; transition: opacity 700ms ease 150ms; }
.hive.is-solved .poster { opacity: 1; transition: opacity 900ms ease; }
.hive.is-solved .cell { opacity: 0; }
.hive.is-solved .slot { visibility: hidden; }
.hive.is-solved .tile img { cursor: default; }
.hive.is-solved .tile:not(.tile--grey) { opacity: 0; transition: opacity 900ms ease 500ms, transform 420ms cubic-bezier(.2, .8, .2, 1); }
/* Over the whole page and no part of it: it moves nothing and takes no taps. */
.confetti { position: fixed; inset: 0; width: 100vw; height: 100vh; pointer-events: none; z-index: 50; }

/* The card under a board whose pieces are all held: two faces in one cell,
   so the finale turns it over without changing its height. */
.puzzle-card { display: grid; padding: 16px; }
.puzzle-card__face { grid-area: 1 / 1; display: flex; flex-direction: column; gap: 8px; align-items: flex-start; transition: opacity 400ms ease, transform 400ms ease; }
.puzzle-card__face p { margin: 0; font-size: 16px; line-height: 24px; color: var(--ink-2); }
.puzzle-card__done, .puzzle-card.is-done .puzzle-card__pending { opacity: 0; visibility: hidden; transform: translateY(8px); }
.puzzle-card.is-done .puzzle-card__done { opacity: 1; visibility: visible; transform: none; }
.puzzle-medal {
  display: inline-flex; align-items: center; min-height: 44px; padding: 0 16px; border: 2px solid var(--ink); border-radius: 999px;
  background: var(--yellow); color: var(--ink); font-size: 14px; font-weight: 800; text-decoration: none; box-shadow: var(--pressed);
}
/* An operator's try of the puzzle (Pase::PuzzlePreview): marked in coral
   and dashed, like the prototype's own test panel, so nobody mistakes it for
   the member's screen. */
.preview-bar { padding: 12px 16px 16px; border-style: dashed; border-color: var(--coral); box-shadow: none; display: flex; flex-direction: column; gap: 8px; }
.preview-bar__head { margin: 0; font-size: 14px; line-height: 20px; font-weight: 600; color: var(--ink-2); }
.preview-bar__head b { margin-right: 6px; font-size: 12px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--coral); }
.preview-bar__actions { display: flex; flex-wrap: wrap; gap: 8px; }
.preview-bar__form { display: contents; }
.preview-bar__btn { min-height: 44px; padding: 0 12px; font-size: 14px; }
.preview-bar__note { margin: 0; font-size: 14px; line-height: 20px; color: var(--ink-2); }

/* The typed answer (§3.3), under the board from the first piece on. */
.puzzle-answer { padding: 16px; display: flex; flex-direction: column; gap: 8px; align-items: flex-start; }
.puzzle-answer p { margin: 0; font-size: 16px; line-height: 24px; color: var(--ink-2); }
.puzzle-answer__form { display: flex; gap: 8px; width: 100%; margin-top: 4px; }
.puzzle-answer__form .entry-input { flex: 1; min-width: 0; }
.puzzle-answer__form .btn { flex: none; padding: 0 16px; }
.puzzle-answer .puzzle-answer__note, .puzzle-answer .puzzle-answer__no { font-size: 14px; line-height: 20px; font-weight: 600; }
.puzzle-answer .puzzle-answer__no { color: var(--ink); }
.puzzle-answer .puzzle-answer__said { font-weight: 800; color: var(--ink); overflow-wrap: anywhere; }
@media (prefers-reduced-motion: reduce) {
  .hive--board .cell, .hive--board .cell-flip, .board-layer, .hive.is-settled .board-layer, .tile, .hive-stage,
  .poster, .poster-frame, .hive.is-solved .poster, .hive.is-solved .poster-frame, .hive.is-solved .tile:not(.tile--grey), .puzzle-card__face { transition: none; }
}

/* Stickers: «B-sides y Fest», the events beside the season, one row each. */
.events { display: flex; flex-direction: column; gap: 12px; }
.event-list { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 12px; }
.event-row { position: relative; isolation: isolate; overflow: hidden; display: flex; align-items: center; gap: 12px; min-height: 72px; padding: 8px 16px 8px 8px; color: var(--ink); text-decoration: none; }
.event-row:active { transform: translate(2px, 2px); box-shadow: var(--pressed); }
.event-img { width: 56px; height: 48px; flex: none; display: grid; place-items: center; }
.event-img > * { width: 56px; height: 48px; object-fit: contain; }
.event-txt { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.event-txt b { font-size: 16px; line-height: 20px; font-weight: 900; overflow-wrap: anywhere; }
.event-txt small { font-size: 14px; line-height: 20px; color: var(--ink-2); }
/* The event's banner fills the row's right side under the card's own clip
   and fades out toward the text: painted below it (z-index -1 inside the
   row's isolated stack, above the card's white), and a mask, not an overlay,
   so the white it fades into is the card itself. A long title runs over
   it, so the fade stays faint where text can reach and the text carries a
   halo of the card's white. */
.event-banner {
  position: absolute; z-index: -1; top: 0; right: 0; width: 55%; height: 100%; object-fit: cover; pointer-events: none;
  -webkit-mask-image: linear-gradient(to right, transparent, rgb(0 0 0 / .3) 45%, #000 90%);
  mask-image: linear-gradient(to right, transparent, rgb(0 0 0 / .3) 45%, #000 90%);
}
.event-txt:has(~ .event-banner) { text-shadow: 0 0 3px var(--paper), 0 0 6px var(--paper), 0 0 10px var(--paper); }

/* One meetup */
.head { display: flex; align-items: center; gap: 12px; min-height: 48px; }
.back, .help-btn {
  width: 44px; height: 44px; flex: none; border-radius: 50%; border: 2px solid var(--ink); background: var(--paper);
  box-shadow: var(--shadow-sm); display: flex; align-items: center; justify-content: center; color: var(--ink);
}
.back:active, .help-btn:active { transform: translate(2px, 2px); box-shadow: var(--pressed); }
.hero { position: relative; margin-bottom: 52px; }
.banner { display: block; width: 100%; height: auto; aspect-ratio: 16 / 9; object-fit: cover; border: 2px solid var(--ink); border-radius: 16px; box-shadow: var(--shadow); background: var(--sand-2); }
.banner--empty { display: flex; align-items: center; justify-content: center; }
.banner-logo { width: 96px; height: 83px; opacity: .5; }
.hero-sticker { position: absolute; left: 12px; bottom: -52px; width: 124px; transform: rotate(-6deg); filter: drop-shadow(4px 4px 0 var(--ink)); }
.hero-sticker img, .hero-sticker svg { width: 124px; height: auto; }
/* The grey copy is already the «not yours» signal; it stays opaque, so the
 * banner's edge never shows through it. Face down, the dashed hex casts no
 * shadow: a shadow following dashes reads as smudged. */
.hero-sticker--next, .hero-sticker--future, .hero-sticker--open { filter: none; }
.hero-status { position: absolute; right: 12px; bottom: -44px; }
/* A past night's badge leads to its page: the link is a 44px target centred
   on the badge, which sits where it always did and looks the same. */
.hero-status--link { bottom: -50px; display: flex; align-items: center; min-height: 44px; text-decoration: none; }
.status--attended { background: var(--yellow); }
.status--missed { background: var(--sand-2); border-style: dashed; }
.status--open { background: var(--yellow); }
.title-block { display: flex; flex-direction: column; gap: 4px; }
/* «Invitar a alguien» and «Asistiré», side by side under the title. */
.title-links { display: flex; flex-wrap: wrap; column-gap: 24px; }
.title-xl { font-size: 32px; line-height: 36px; font-weight: 900; letter-spacing: -.03em; overflow-wrap: anywhere; }
.date { font-size: 16px; line-height: 20px; font-weight: 600; color: var(--ink-2); }
.tagline { font-size: 16px; line-height: 24px; font-style: italic; color: var(--ink-2); }
.prose { font-size: 16px; line-height: 24px; max-width: 26rem; }
/* «El título», a card dealt face down: a dark card back, framed in yellow,
 * saying it holds spoilers, which a tap turns over to the story
 * (title_card_controller). The controller swaps the faces at half the turn,
 * and the easing is symmetric, so that is the moment the card is edge on:
 * only the face up is in the flow, and the card takes its height there. */
.title-card { --turn: .6s; position: relative; perspective: 1200px; scroll-margin-top: 16px; }
.title-card-turn {
  position: relative; display: grid; transform-style: preserve-3d;
  transition: transform var(--turn) cubic-bezier(.65, 0, .35, 1), translate .06s ease-out;
}
.title-card.is-turned .title-card-turn { transform: rotateY(180deg); }
.title-card-face {
  grid-area: 1 / 1; padding: 16px; display: flex; flex-direction: column; gap: 12px;
  -webkit-backface-visibility: hidden; backface-visibility: hidden; transition: box-shadow .06s ease-out;
}
.title-card-front {
  align-items: center; gap: 4px; padding: 24px 16px; text-align: center; background: var(--ink); color: var(--sand);
  box-shadow: inset 0 0 0 6px var(--ink), inset 0 0 0 8px var(--yellow), var(--shadow);
}
.title-card-note { font-size: 16px; line-height: 20px; font-weight: 600; color: var(--sand-2); }
.title-card-hint { margin-top: 8px; color: var(--yellow); }
.title-card-back { transform: rotateY(180deg); }
.title-card:not(.is-face-up) .title-card-back, .title-card.is-face-up .title-card-front {
  position: absolute; inset: 0 0 auto; visibility: hidden;
}
.title-card-hit {
  position: absolute; inset: 0; z-index: 1; padding: 0; border: 0; border-radius: 16px;
  background: transparent; cursor: pointer; -webkit-tap-highlight-color: transparent;
}
/* Clear of the card's 4px shadow. */
.title-card-hit:focus-visible { outline-offset: 6px; }
/* Pressed like the page's buttons: in by 2px, the shadow halved. */
.title-card:has(.title-card-hit:active) .title-card-turn { translate: 2px 2px; }
.title-card:has(.title-card-hit:active) .title-card-back { box-shadow: var(--pressed); }
.title-card:has(.title-card-hit:active) .title-card-front {
  box-shadow: inset 0 0 0 6px var(--ink), inset 0 0 0 8px var(--yellow), var(--pressed);
}
@media (prefers-reduced-motion: reduce) {
  .title-card { --turn: 0s; }
}
.callout { padding: 16px; }
.callout p { font-size: 16px; line-height: 24px; }
.night-medals { display: flex; flex-wrap: wrap; gap: 8px; }
.medal-chip {
  display: inline-flex; align-items: center; gap: 8px; min-height: 44px; padding: 4px 12px 4px 4px;
  background: var(--paper); border: 2px solid var(--ink); border-radius: 999px; color: var(--ink);
  font-size: 14px; font-weight: 800; text-decoration: none;
}
.medal-chip svg { width: 32px; height: 28px; }
.pager { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.pager-link { display: flex; flex-direction: column; gap: 4px; min-height: 64px; padding: 8px 12px; border: 2px solid var(--ink); border-radius: 16px; background: var(--paper); box-shadow: var(--shadow-sm); color: var(--ink); text-decoration: none; }
.pager-link:active { transform: translate(2px, 2px); box-shadow: var(--pressed); }
.pager-link--next { grid-column: 2; text-align: right; }
.pager-link small { font-size: 14px; line-height: 16px; font-weight: 800; color: var(--ink); }
.pager-link span { font-size: 14px; line-height: 20px; font-weight: 800; text-wrap: balance; overflow-wrap: anywhere; }

/* A panel that folds away: a <details> whose <summary> is its head, all of
 * it the tap target, with a chevron at its end that turns over while open.
 * Native, so it folds with no JavaScript, keeps nothing in the page's height
 * while shut, and a screen reader hears a button that says which way it is.
 * `display: block`, not the panel's own flex: a <details> lays out its body
 * as one box, so the body carries the gap. */
details.fold { display: block; }
.fold-head {
  display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 44px;
  list-style: none; cursor: pointer; touch-action: manipulation; -webkit-tap-highlight-color: transparent;
}
.fold-head::-webkit-details-marker { display: none; }
.fold-head::marker { content: ""; }
.fold-head:focus-visible { outline: 3px solid var(--ink); outline-offset: 4px; border-radius: 8px; }
.fold-aside { display: inline-flex; align-items: center; gap: 8px; flex: none; }
.fold-chev { display: flex; flex: none; transition: transform .15s ease-out; }
.fold[open] > .fold-head .fold-chev { transform: rotate(180deg); }
.fold-body { display: flex; flex-direction: column; gap: 12px; margin-top: 12px; }
@media (prefers-reduced-motion: reduce) {
  .fold-chev { transition: none; }
}
/* The guess, answered and folded: right or wrong in a mark, then the
 * question, the game and (sealed) when they will know, stacked in the middle
 * column — a grid, since a <summary> holds its heading directly. Sealed, there
 * is no mark and no first column. */
.quiz-head { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; column-gap: 12px; row-gap: 4px; }
.quiz-head > :not(.quiz-mark, .fold-chev) { grid-column: 2; display: block; overflow-wrap: anywhere; }
.quiz-head > .quiz-mark, .quiz-head > .fold-chev { grid-row: 1 / span 3; }
.quiz-head > .fold-chev { grid-column: 3; }
.quiz-head:not(:has(.quiz-mark)) { grid-template-columns: minmax(0, 1fr) auto; }
.quiz-head:not(:has(.quiz-mark)) > :not(.fold-chev) { grid-column: 1; }
.quiz-head:not(:has(.quiz-mark)) > .fold-chev { grid-column: 2; }
.quiz-mark {
  width: 32px; height: 32px; flex: none; display: flex; align-items: center; justify-content: center;
  border: 2px solid var(--ink); border-radius: 50%; background: var(--paper);
}
.quiz-mark--right { background: var(--yellow); }
.quiz-mark--wrong { color: var(--ink-2); border-style: dashed; }

/* Logros */
.feature { padding: 16px; display: flex; align-items: center; gap: 16px; background: var(--yellow); }
.feature-flame svg { width: 48px; height: 48px; }
.feature-txt { display: flex; flex-direction: column; gap: 4px; }
.feature-kicker { font-size: 12px; line-height: 16px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; }
.feature p { font-size: 16px; line-height: 20px; font-weight: 700; }
.note--left { text-align: left; }
/* Todos · Ganados · Me faltan: one track, the current filter filled ink. */
.medal-filter {
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 4px; padding: 4px;
  background: var(--paper); border: 2px solid var(--ink); border-radius: 999px;
}
.medal-filter-tab {
  min-height: 44px; display: flex; align-items: center; justify-content: center; gap: 4px; padding: 0 8px; border-radius: 999px;
  color: var(--ink); font-size: 14px; line-height: 20px; font-weight: 800; text-decoration: none; white-space: nowrap;
  touch-action: manipulation; -webkit-tap-highlight-color: transparent;
}
.medal-filter-tab:active { background: var(--sand-2); }
.medal-filter-tab[aria-current="page"] { background: var(--ink); color: var(--sand); }
.medal-filter-tab:focus-visible { outline: 3px solid var(--ink); outline-offset: 2px; }
.medal-filter-n { font-weight: 600; color: var(--subtle); font-variant-numeric: tabular-nums; }
.medal-filter-tab[aria-current="page"] .medal-filter-n { color: var(--sand-3); }
/* «Ganados» lit is an earned medal's own yellow. */
.medal-filter-tab--won[aria-current="page"] { background: var(--yellow); color: var(--ink); }
.medal-filter-tab--won[aria-current="page"] .medal-filter-n { color: var(--ink-2); }
.medal-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); row-gap: 24px; column-gap: 8px; }
/* A «taps» logro's medal (medal_taps_controller): tappable, and saying so in nothing but the nudge. */
.medal-taps { display: block; touch-action: manipulation; -webkit-tap-highlight-color: transparent; user-select: none; -webkit-user-select: none; }
.medal-taps svg { display: block; width: 88px; height: 76px; }
.medal-cell { display: flex; flex-direction: column; align-items: center; gap: 4px; text-align: center; min-width: 0; }
/* The medal itself, not every icon in the sheet the cell holds. */
.medal-cell > svg, .medal-open > svg { width: 88px; height: 76px; }
.medal-name { font-size: 14px; line-height: 20px; font-weight: 800; text-wrap: balance; overflow-wrap: anywhere; }
.medal-sub { font-size: 12px; line-height: 16px; color: var(--subtle); text-wrap: balance; overflow-wrap: anywhere; }
/* A struck medal (PaseHelper#pase_medal): the photographed metal, lifted off
 * the page by a soft shadow, a glint crossing it every few seconds (its SVG
 * animates the gradient, so nothing leaves the medal's box); not won yet,
 * grey and still. Under reduced motion, no glint at all. */
.medal-struck { filter: drop-shadow(0 2px 2px rgb(23 21 15 / .4)); }
.medal-struck.is-locked { filter: grayscale(1) brightness(.72) contrast(.9); opacity: .55; }
.medal-struck g { mix-blend-mode: screen; }
/* In the grid, the struck medal one holds is the button that opens it. */
.medal-open {
  display: block; padding: 0; border: 0; border-radius: 12px; background: none; cursor: pointer;
  touch-action: manipulation; -webkit-tap-highlight-color: transparent;
}
.medal-open svg { display: block; transition: transform .12s ease-out; }
.medal-open:active svg { transform: scale(.94); }
.medal-open:focus-visible { outline: 3px solid var(--ink); outline-offset: 2px; }
/* The whole cell of a won logro opens it: its name and dates too. A mini
 * (another member's, pase/attendees/show) to its own edge, its row's gap
 * too narrow to share. */
.medal-cell--won, .medal-mini--open { position: relative; }
.medal-cell--won .medal-open::after, .medal-mini--open .medal-open::after { content: ""; position: absolute; inset: -4px; border-radius: 12px; }
.medal-mini--open .medal-open::after { inset: 0; }
.medal-cell--won:has(.medal-open:active), .medal-mini--open:has(.medal-open:active) { background: var(--sand-2); border-radius: 12px; }
/* A won logro up close (pase/medals/_sheet): the medal beside its name,
 * then what won it. In the cell's DOM, so it would take the cell's centring. */
.medal-sheet { text-align: left; }
.medal-sheet-head { display: flex; align-items: center; gap: 16px; min-width: 0; }
.medal-sheet-head > svg { width: 104px; height: 90px; flex: none; }
.medal-sheet-name { min-width: 0; display: flex; flex-direction: column; align-items: flex-start; gap: 8px; }
.medal-sheet-name .h2 { overflow-wrap: anywhere; text-wrap: balance; }
.medal-sheet-tags { display: flex; flex-wrap: wrap; gap: 4px; }
/* What won it (pase/medals/_facts), on the sheet and under the coin. */
.medal-facts { margin: 0; display: flex; flex-direction: column; gap: 16px; }
.medal-facts > div { display: flex; flex-direction: column; gap: 4px; }
.medal-facts dd { margin: 0; font-size: 16px; line-height: 24px; overflow-wrap: anywhere; }
.medal-facts small { display: block; font-size: 14px; line-height: 20px; color: var(--ink-2); }
/* A fingertip tall, like every other link in the app. */
.medal-facts-link { display: inline-flex; align-items: center; min-height: 44px; font-weight: 800; color: var(--ink); text-underline-offset: 3px; }
.coin-txt .medal-facts { margin-top: 8px; gap: 8px; }
.coin-txt .medal-facts .mono-k { color: var(--yellow); }
.coin-txt .medal-facts dd { font-size: 14px; line-height: 20px; color: #D9D1BA; }
.coin-txt .medal-facts small { color: #B8AF95; }
.coin-txt .medal-facts-link { color: var(--sand); }
/* Up close (pase/medals/_coin, medal_coin_controller): the medal on a dark
 * sheet, its two faces back to back with its thickness between them — a stack
 * of thin layers cut to its outline, which reads as the rim while it turns.
 * The thickness is a share of the coin's own width (cqw), so it scales with
 * it. A tap anywhere off the coin closes the sheet. */
.coin-sheet {
  width: 100%; max-width: none; height: 100dvh; max-height: none; margin: 0; overflow: hidden;
  padding: calc(24px + env(safe-area-inset-top)) 16px calc(24px + env(safe-area-inset-bottom));
  border: 0; background: transparent; color: var(--sand);
}
.coin-sheet[open] { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 32px; }
.coin-sheet::backdrop { background: radial-gradient(120% 80% at 50% 38%, #3B3427 0%, #17150F 62%); }
.coin-sheet:focus { outline: none; }
/* 16px clear each side: swayed and in perspective, a tip comes nearer and
 * draws up to 8px wider than the stage. Its height leaves 380px for the words
 * under it: the name, what won it (pase/medals/_facts) and «Cerrar». */
.coin-stage { position: relative; width: min(100% - 32px, 340px, (100dvh - 380px) * 1.1); container-type: inline-size; perspective: 1100px; }
.coin {
  position: absolute; inset: 0; display: block; width: 100%; height: 100%; padding: 0; border: 0; background: none;
  transform-style: preserve-3d; cursor: grab; touch-action: none; user-select: none; -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
}
.coin:active { cursor: grabbing; }
.coin:focus-visible { outline: 3px solid var(--yellow); outline-offset: 12px; border-radius: 24px; }
.coin-shadow {
  position: absolute; left: 12%; right: 12%; bottom: -12%; height: 9%; border-radius: 50%;
  background: radial-gradient(closest-side, rgb(0 0 0 / .6), transparent); transform: scaleX(var(--shadow-x, 1)); opacity: var(--shadow-o, 1);
}
.coin-sway, .coin-body, .coin-edge { position: absolute; inset: 0; transform-style: preserve-3d; }
.coin-sway { animation: coin-sway 8s ease-in-out infinite; }
.coin.is-turning .coin-sway { animation-play-state: paused; }
@keyframes coin-sway {
  0%, 100% { transform: rotateX(3deg) rotateY(-8deg); }
  50% { transform: rotateX(-2deg) rotateY(8deg); }
}
.coin-face { position: absolute; inset: 0; backface-visibility: hidden; -webkit-backface-visibility: hidden; }
.coin-face--obverse { transform: translateZ(2.1cqw); }
.coin-face--reverse { transform: rotateY(180deg) translateZ(2.1cqw); }
.coin-face img { display: block; width: 100%; height: 100%; object-fit: contain; pointer-events: none; -webkit-user-drag: none; }
.coin:active .coin-face img { filter: brightness(1.06); }
/* The glint is a band three faces wide slid across the face (transform
 * only), cut to the face's own outline by its mask. --glint runs 1 → 0, off
 * the left edge to off the right; the controller sets it from the angle. */
.coin-glint {
  position: absolute; inset: 0; overflow: hidden; pointer-events: none; mix-blend-mode: screen;
  -webkit-mask: var(--face) center / 100% 100% no-repeat; mask: var(--face) center / 100% 100% no-repeat;
}
.coin-glint::before {
  content: ""; position: absolute; top: 0; bottom: 0; left: 0; width: 300%;
  background: linear-gradient(105deg, transparent 39%, rgb(255 244 214 / .18) 45%, rgb(255 250 235 / .7) 49.5%, rgb(255 255 255 / .85) 50%, rgb(255 250 235 / .7) 50.5%, rgb(255 244 214 / .18) 55%, transparent 61%);
  transform: translateX(calc(var(--glint, 1) * -66.667%));
}
.coin:not(.is-turning) .coin-glint::before { animation: coin-glint 5s ease-in-out 1.6s infinite; }
@keyframes coin-glint {
  0% { transform: translateX(-66.667%); }
  32%, 100% { transform: translateX(0); }
}
.coin-edge i {
  position: absolute; inset: 0; transform: translateZ(calc(var(--z) * 4cqw));
  background: linear-gradient(90deg, #6E5214, #E7C766 28%, #8F6C1E 52%, #F2D98A 74%, #6E5214);
  -webkit-mask: var(--obverse) center / 100% 100% no-repeat; mask: var(--obverse) center / 100% 100% no-repeat;
}
/* Seen edge-on the layers are slivers with gaps between them: the side
 * itself, a band across the coin's middle as thick as the coin, closes them.
 * Inside the coin, so either face hides it until the coin is nearly edge-on. */
.coin-side {
  position: absolute; top: 0; bottom: 0; left: calc(50% - 2cqw); width: 4cqw; transform: rotateY(90deg);
  background: linear-gradient(180deg, #6E5214, #D9B44A 12%, #F2D98A 40%, #A9832A 62%, #E7C766 85%, #6E5214);
}
.coin-txt { display: flex; flex-direction: column; align-items: center; gap: 4px; max-width: 340px; text-align: center; }
.coin-name { font-size: 24px; line-height: 28px; font-weight: 900; color: var(--sand); text-wrap: balance; overflow-wrap: anywhere; }
.coin-hint { margin-top: 8px; font-size: 12px; line-height: 16px; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: var(--yellow); }
.coin-close { min-width: 160px; }
@media (prefers-reduced-motion: reduce) {
  .coin:not(.is-turning) .coin-glint::before, .coin-sway { animation: none; }
  .medal-struck g { display: none; }
  .medal-open svg { transition: none; }
}
/* Who else was at a meetup, and the logros one gives another. */
.people { margin: 0; padding: 0; list-style: none; display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); row-gap: 12px; column-gap: 8px; }
.person {
  min-height: 44px; display: flex; flex-direction: column; align-items: center; gap: 4px; padding: 4px 0; border-radius: 12px;
  color: var(--ink); text-decoration: none; min-width: 0;
}
.person:active { background: var(--sand-2); }
.person-av { width: 64px; height: 58px; flex: none; }
.person-av .pase-av { width: 64px; height: 58px; overflow: visible; }
/* Two lines, so a first name and a surname both show; a longer one ends in «…». */
.person-name {
  max-width: 100%; font-size: 12px; line-height: 16px; font-weight: 800; text-align: center; text-wrap: balance; overflow-wrap: anywhere;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden;
}
/* The medal beside the words, and the button under them: the words get the
   card's width, not what a button beside them would leave. */
.gift { padding: 16px; display: grid; grid-template-columns: 56px minmax(0, 1fr); column-gap: 12px; row-gap: 12px; align-items: start; }
.gift--given { background: var(--yellow-50); }
.gift > svg { width: 56px; height: 48px; }
.gift-txt { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.gift-txt b { font-size: 16px; line-height: 20px; font-weight: 900; overflow-wrap: anywhere; }
.gift-txt small { font-size: 14px; line-height: 20px; color: var(--ink-2); overflow-wrap: anywhere; }
.gift-txt .gift-by { font-weight: 700; color: var(--ink); }
.gift-form { grid-column: 2; }
.gift-btn { min-width: 120px; }

.bar { width: 72px; height: 8px; border: 2px solid var(--ink); border-radius: 999px; background: var(--paper); overflow: hidden; display: flex; }
.bar i { display: block; background: var(--yellow); }

/* Play: the one guess at the sticker's game. */
.quiz { padding: 16px; display: flex; flex-direction: column; gap: 12px; scroll-margin-top: 16px; }
.quiz--right { background: var(--yellow-50); }
.quiz-sub { font-size: 16px; line-height: 20px; color: var(--ink-2); }
.quiz-verdict { font-size: 16px; line-height: 20px; font-weight: 800; }
.quiz-opts { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.opt-form { display: contents; }
.opt {
  min-height: 56px; padding: 8px 12px; display: flex; align-items: center; justify-content: center; text-align: center;
  border: 2px solid var(--ink); border-radius: 12px; background: var(--paper); box-shadow: var(--shadow-sm);
  font-size: 16px; line-height: 20px; font-weight: 800; color: var(--ink); text-wrap: balance; overflow-wrap: anywhere; cursor: pointer;
}
button.opt:active { transform: translate(2px, 2px); box-shadow: var(--pressed); }
button.opt[disabled] { cursor: progress; color: var(--muted); }
span.opt { box-shadow: none; color: var(--muted); border-color: var(--sand-3); }
span.opt--right { color: var(--ink); border-color: var(--ink); background: var(--yellow); }
span.opt--wrong { color: var(--ink-2); border-color: var(--ink-2); border-style: dashed; text-decoration: line-through; }

/* Play: the secrets of a night. */
.secrets { padding: 16px; display: flex; flex-direction: column; gap: 12px; background: var(--yellow-50); }
.secrets-top { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.secret-count {
  display: inline-flex; align-items: center; min-height: 32px; padding: 0 12px; border: 2px solid var(--ink); border-radius: 999px;
  background: var(--paper); font-size: 16px; font-weight: 900; font-variant-numeric: tabular-nums; white-space: nowrap;
}
.secret-list { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 8px; }
.secret-list li { font-size: 16px; line-height: 24px; }
/* The secrets counted in meeples (PaseHelper#pase_meeple_mark): yellow once
 * found, an outline while hidden — the prototype's pips. */
.mm { display: block; flex: none; width: 16px; height: 16px; }
.mm path { fill: var(--paper); stroke: var(--ink); stroke-width: 26; stroke-linejoin: round; }
.mm.on path { fill: var(--yellow); }
.secret-count { gap: 6px; }
.secret-list__item { display: flex; align-items: flex-start; gap: 12px; min-width: 0; }
.secret-list__item > span { min-width: 0; overflow-wrap: anywhere; }
.secret-list__item .mm { width: 22px; height: 24px; margin-top: 0; }
.secret-list__item:not(.secret-list__item--found) { color: var(--muted); }

/* The night's guestbook (pase/meetups/_guestbook, Pase::Guestbook): the
 * sheet cropped to its spots, as wide as the column: the art is the box's
 * background, sized and placed by percentages (Pase::Guestbook), so it scales
 * with the screen and nothing on the page is wider than the column.
 * Each signer stands on their spot at the spot's own size; the whole spot is
 * the tap target. */
.gb-mine { font-size: 16px; line-height: 20px; }
.gb-sheet {
  position: relative; width: 100%; background-color: var(--paper); background-repeat: no-repeat;
  border: 2px solid var(--ink); border-radius: 16px; box-shadow: var(--shadow);
}
.gb-spot {
  position: absolute; min-width: 44px; min-height: 44px; transform: translate(-50%, -50%);
  display: flex; align-items: center; justify-content: center; padding: 0; border: 0; border-radius: 12px;
  background: none; cursor: pointer; -webkit-tap-highlight-color: transparent;
}
.gb-av { display: block; flex: none; transition: transform .08s ease-out; filter: drop-shadow(2px 2px 0 rgb(23 21 15 / .3)); }
.gb-av .pase-av { width: 100%; height: 100%; overflow: visible; }
.gb-spot:active .gb-av { transform: scale(.9); }
/* Yours, with a halo: the first thing a member looks for on the sheet. */
.gb-spot--mine { background: radial-gradient(closest-side, rgb(249 201 1 / .75), rgb(249 201 1 / .25) 70%, transparent); }
.gb-loose { margin-top: 4px; }

/* No art, or no spots painted: the sheet as a plain numbered grid. */
.gb-grid { margin: 0; padding: 0; list-style: none; display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 8px; }
.gb-cell { position: relative; aspect-ratio: 1; min-width: 0; border: 2px dashed var(--sand-3); border-radius: 12px; background: var(--cream); }
.gb-cell--signed { border: 2px solid var(--ink); background: var(--paper); }
.gb-cell--mine { background: var(--yellow-50); outline: 3px solid var(--yellow); outline-offset: -5px; }
.gb-num { position: absolute; top: 4px; left: 8px; font-size: 14px; line-height: 16px; font-weight: 900; color: var(--muted); font-variant-numeric: tabular-nums; }
.gb-cell--signed .gb-num { color: var(--ink); }
.gb-cell-btn {
  width: 100%; height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: flex-end; gap: 2px;
  padding: 16px 4px 4px; border: 0; border-radius: 10px; background: none; cursor: pointer; min-width: 0;
}
.gb-cell-btn:active { background: var(--sand-2); }
.gb-cell-av { display: block; width: 64%; min-height: 0; flex: 1; }
.gb-cell-av .pase-av { width: 100%; height: 100%; overflow: visible; }
.gb-cell-name { max-width: 100%; font-size: 11px; line-height: 16px; font-weight: 800; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.gb-guests { padding: 16px; display: flex; flex-direction: column; gap: 12px; background: var(--yellow-50); }
.gb-guests p { font-size: 16px; line-height: 24px; }
/* The words, and the corner's × that closes it on this night (.invite-top). */
.gb-guests .invite-top p { flex: 1; min-width: 0; }

/* A signer's card, and a won logro (.sheet, sheet_controller): a sheet up
 * from the bottom of the screen, over the page. */
.gb-card, .sheet {
  width: 100%; max-width: 430px; max-height: none; margin: auto auto 0; padding: 0; border: 0; background: transparent; overflow: visible;
}
.gb-card::backdrop, .sheet::backdrop { background: rgb(23 21 15 / .6); }
.gb-card:focus, .sheet:focus { outline: none; }
.gb-card-in, .sheet-in {
  display: flex; flex-direction: column; gap: 16px; max-height: 88dvh; overflow-y: auto; overscroll-behavior: contain;
  padding: 16px 20px calc(24px + env(safe-area-inset-bottom, 0px));
  background: var(--paper); border: 2px solid var(--ink); border-bottom: 0; border-radius: 20px 20px 0 0;
}
.gb-card[open] .gb-card-in, .sheet[open] .sheet-in { animation: gb-up .2s ease-out; }
@keyframes gb-up { from { transform: translateY(32px); opacity: .5; } }
.gb-card-top, .sheet-top { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
button.gb-close, button.sheet-close { background: none; border-color: var(--sand-3); color: var(--ink); cursor: pointer; }
.gb-who { display: flex; align-items: center; gap: 16px; min-width: 0; }
.gb-who-av, .gb-who-av .pase-av { width: 72px; height: 66px; flex: none; overflow: visible; }
.gb-who-txt { min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.gb-who-txt .h2 { overflow-wrap: anywhere; }
.gb-sig {
  margin: 0; padding: 12px; display: flex; justify-content: center;
  border: 2px dashed var(--sand-3); border-radius: 12px; background: var(--cream);
}
.gb-sig img { width: auto; max-width: 100%; max-height: 160px; object-fit: contain; }
.gb-theirs { padding: 16px; display: flex; flex-direction: column; gap: 12px; }
.gb-guest-txt { font-size: 16px; line-height: 24px; color: var(--ink-2); }
/* Stickers: «Tu libro de firmas», the numbers signed so far. */
.spot-book { padding: 16px; display: flex; flex-direction: column; gap: 12px; }
.spot-book-grid { margin: 0; padding: 0; list-style: none; display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 8px; }
.spot-book-cell {
  min-width: 0; min-height: 52px; display: flex; flex-direction: column; align-items: center; justify-content: center;
  border: 2px dashed var(--sand-3); border-radius: 12px; color: var(--subtle);
}
.spot-book-cell b { font-size: 18px; line-height: 20px; font-weight: 900; font-variant-numeric: tabular-nums; }
.spot-book-cell--signed { border: 2px solid var(--ink); background: var(--yellow); color: var(--ink); }
.spot-book-link {
  width: 100%; min-height: 48px; display: flex; flex-direction: column; align-items: center; justify-content: center;
  color: var(--ink); text-decoration: none; border-radius: 10px;
}
button.spot-book-link { padding: 0; border: 0; background: none; font: inherit; cursor: pointer; }
.spot-book-link:active { background: rgb(23 21 15 / .08); }
/* A number signed on several nights: its sheet lists them, one tap each. */
.spot-book-picks { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 8px; }
.spot-book-pick { min-height: 64px; padding: 12px 16px; display: flex; flex-direction: column; justify-content: center; gap: 4px; color: var(--ink); text-decoration: none; }
.spot-book-pick:active { background: var(--sand-2); }
.spot-book-pick b { font-size: 16px; line-height: 20px; font-weight: 900; overflow-wrap: anywhere; }
.spot-book-link small { max-width: 100%; font-size: 11px; line-height: 14px; font-weight: 800; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding: 0 2px; }
/* «Fueron contigo»: the number each person signed, on their avatar. */
.person-av { position: relative; }
.person-spot {
  position: absolute; top: -4px; left: -4px; min-width: 24px; height: 24px; padding: 0 4px; border: 2px solid var(--ink); border-radius: 999px;
  background: var(--yellow); font-size: 12px; line-height: 20px; font-weight: 900; text-align: center; font-variant-numeric: tabular-nums;
}
@media (prefers-reduced-motion: reduce) {
  .gb-card[open] .gb-card-in, .sheet[open] .sheet-in { animation: none; }
  .gb-av { transition: none; }
}

/* The hunt: the night's image full screen, on ink. */
body.dark, body.dark .app { background: var(--ink); color: var(--sand); }
@media (min-width: 470px) { body.dark { background: #2A2721; } }
.hunt { display: flex; flex-direction: column; gap: 12px; min-height: calc(100svh - 64px); }
.hunt-top { display: flex; align-items: center; gap: 12px; }
.hunt-close {
  width: 44px; height: 44px; flex: none; border-radius: 50%; border: 2px solid var(--sand); color: var(--sand);
  display: flex; align-items: center; justify-content: center;
}
.hunt-title { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.hunt-title .mono-k { color: #D9D2BE; }
.hunt-h { font-size: 16px; line-height: 20px; font-weight: 900; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.secret-count--dark { background: var(--yellow); color: var(--ink); border-color: var(--yellow); }
.hunt-tabs { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 4px; padding: 4px; background: #2A2721; border-radius: 999px; }
.hunt-tab {
  min-height: 44px; display: flex; align-items: center; justify-content: center; border-radius: 999px;
  color: var(--sand); font-size: 14px; font-weight: 800; text-decoration: none; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.hunt-tab[aria-current="page"] { background: var(--sand); color: var(--ink); }
.hunt-stage { overflow: auto; border-radius: 16px; background: #2A2721; -webkit-overflow-scrolling: touch; overscroll-behavior: contain; }
.hunt-pic { position: relative; width: 100%; cursor: crosshair; touch-action: manipulation; }
.hunt-stage--zoomed .hunt-pic { width: 200%; }
.hunt-img { display: block; width: 100%; height: auto; user-select: none; -webkit-user-select: none; -webkit-touch-callout: none; }
.spot {
  position: absolute; border: 4px solid var(--yellow); border-radius: 8px;
  box-shadow: 0 0 0 2px var(--ink), inset 0 0 0 2px var(--ink); background: rgba(249, 201, 1, .16); pointer-events: none;
}
.spot-n { position: absolute; left: -14px; top: -16px; width: 28px; height: 28px; }
.spot-n .mm { width: 28px; height: 28px; filter: drop-shadow(1px 1px 0 var(--ink)); }
.spot-n .mm path { stroke-width: 22; }
.spot--pop { animation: pop .45s ease-out; }
@keyframes pop { from { transform: scale(1.4); opacity: 0; } }
.miss {
  position: absolute; width: 36px; height: 36px; margin: -18px 0 0 -18px; border-radius: 50%;
  border: 4px solid var(--sand); opacity: 0; pointer-events: none; animation: ring .6s ease-out;
}
@keyframes ring { from { opacity: .9; transform: scale(.4); } to { opacity: 0; transform: scale(1.3); } }
/* Two lines tall, so a message of one or two lines never moves the image. */
.hunt-sheet {
  min-height: 72px; padding: 12px 16px; border-radius: 16px; background: var(--sand); color: var(--ink);
  display: flex; align-items: center; font-size: 16px; line-height: 24px; overflow-wrap: anywhere;
}
.hunt-sheet--good { background: var(--yellow); font-weight: 700; }
.btn--dark { background: transparent; color: var(--sand); border-color: var(--sand); }

/* «Mi cuenta»: the meeple editor and the quiet settings. Every swatch and
 * pick is a real radio, so the pressed one shows the instant it is tapped
 * (:checked), before the page redraws with the new meeple. */
.av-editor { padding: 16px; display: flex; flex-direction: column; gap: 16px; }
/* Folded, the meeple as it is and «Personalizar»; open, the big one below
 * takes over and the head is only the title. */
.av-head { justify-content: flex-start; }
.av-head .h2 { flex: 1; min-width: 0; }
.av-head .fold-aside { gap: 4px; }
.av-small, .av-small .pase-av { width: 56px; height: 52px; flex: none; overflow: visible; }
.fold-label { font-size: 14px; line-height: 20px; font-weight: 800; text-decoration: underline; text-underline-offset: 3px; }
.av-editor[open] > .av-head :is(.av-small, .fold-label) { display: none; }
.av-body, .settings-body { gap: 16px; }
.av-big { align-self: center; width: 200px; height: 184px; }
.av-big .pase-av { width: 200px; height: 184px; overflow: visible; }
.av-actions { display: flex; flex-wrap: wrap; justify-content: center; gap: 12px; }
.av-action { display: contents; }
/* A legend sits closer to its own group than to the one above it. */
.av-form { display: flex; flex-direction: column; gap: 24px; }
.opt-group { border: 0; padding: 0; margin: 0; min-width: 0; display: flex; flex-direction: column; gap: 8px; }
.opt-group legend { padding: 0; margin: 0 0 8px; font-size: 14px; line-height: 20px; font-weight: 800; }
/* Even columns that fit six on the narrowest phone, so no swatch is left alone
 * on a row. */
.swatches { display: grid; grid-template-columns: repeat(auto-fill, minmax(44px, 1fr)); gap: 4px; justify-items: center; }
.swatch { position: relative; width: 44px; height: 44px; cursor: pointer; }
.swatch-input, .pick-input, .tog-input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.swatch-dot { position: absolute; inset: 0; border-radius: 50%; border: 2px solid var(--ink); background: var(--swatch); }
.swatch-input:checked + .swatch-dot { box-shadow: 0 0 0 4px var(--sand), 0 0 0 6px var(--ink); }
.swatch-input:focus-visible + .swatch-dot { outline: 3px solid var(--ink); outline-offset: 6px; }
.picks { display: flex; flex-wrap: wrap; gap: 8px; }
.pick { position: relative; cursor: pointer; }
.pick span {
  display: inline-flex; align-items: center; min-height: 44px; padding: 0 16px; border-radius: 999px;
  border: 2px solid var(--ink); background: var(--paper); font-size: 14px; font-weight: 700;
}
.pick-input:checked + span { background: var(--yellow); font-weight: 800; box-shadow: var(--shadow-sm); }
.pick-input:focus-visible + span { outline: 3px solid var(--ink); outline-offset: 2px; }
/* Hats and mouths, drawn: four a row at every width. The pressed one wears
 * the swatches' ring, not a yellow fill: the crown is yellow, and so is half
 * of nearly every other hat. */
.icon-picks { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
.icon-pick { position: relative; cursor: pointer; }
.icon-tile {
  display: flex; align-items: center; justify-content: center; height: 64px; padding: 4px; border-radius: 16px;
  border: 2px solid var(--ink); background: var(--paper);
}
.icon-tile .pase-icon { width: 100%; height: 100%; }
.pick-input:checked + .icon-tile { background: var(--paper); box-shadow: 0 0 0 4px var(--sand), 0 0 0 6px var(--ink); }
.pick-input:focus-visible + .icon-tile { outline: 3px solid var(--ink); outline-offset: 6px; }
.tog { position: relative; display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 44px; font-size: 16px; font-weight: 700; cursor: pointer; }
.tog-track { position: relative; width: 52px; height: 32px; flex: none; border-radius: 999px; border: 2px solid var(--ink); background: var(--sand-3); }
.tog-track i { position: absolute; top: 4px; left: 4px; width: 20px; height: 20px; border-radius: 50%; background: var(--paper); border: 2px solid var(--ink); transition: transform .12s ease-out; }
.tog-input:checked + .tog-track { background: var(--yellow); }
.tog-input:checked + .tog-track i { transform: translateX(20px); }
.tog-input:focus-visible + .tog-track { outline: 3px solid var(--ink); outline-offset: 2px; }
.av-reset { display: flex; justify-content: center; }
.settings { padding: 16px; display: flex; flex-direction: column; gap: 16px; }
.settings .entry { margin-top: 0; }
.settings-rows { display: flex; flex-direction: column; gap: 8px; }
.settings-row { display: flex; flex-direction: column; gap: 4px; }
.settings-row .entry-label { display: block; }
.settings-row .val { overflow-wrap: anywhere; }
.settings .opt-group { margin-top: 16px; }
.settings .actions { display: flex; }
/* «Avisos»: this device's row. A browser that takes pushes draws a line and
 * a row of buttons whatever it answers, so the answer never moves the
 * switches below; one that cannot (or was blocked) is known before the
 * first paint and has no buttons. */
.push-device { display: flex; flex-direction: column; gap: 12px; }
.push-status { margin: 0; min-height: 20px; font-size: 14px; line-height: 20px; font-weight: 600; color: var(--ink-2); }
/* One row in every state, filled: «Activar avisos aquí» alone, or «Enviar
 * prueba» and «Desactivar» sharing it — the same height either way. */
.push-buttons { display: flex; gap: 8px; min-height: 48px; }
.push-buttons .btn { flex: 1 1 auto; padding: 0 12px; white-space: nowrap; }
.push-device:is([data-state="ios"], [data-state="unsupported"], [data-state="denied"]) .push-buttons { display: none; }
.push-buttons .btn[hidden] { display: none; }
.push-kinds .note { margin-top: 4px; }
.settings .push-kinds .opt-group { margin-top: 0; }
.account-out { display: flex; }
.saved { padding: 8px 12px; border: 2px solid var(--ink); border-radius: 12px; background: var(--yellow-50); font-size: 14px; line-height: 20px; font-weight: 700; }
.saved--error { background: #FFE4DC; }

/* Installing the app, and the in-app QR scanner. */
.install { padding: 16px; display: flex; flex-direction: column; gap: 12px; }
.install > div { display: flex; flex-direction: column; gap: 12px; }
.install > div[hidden] { display: none; }
.install-top { display: flex; align-items: center; gap: 12px; }
.install-logo { width: 40px; height: 35px; }
.scanner { width: 100%; max-width: 430px; height: 100%; max-height: none; margin: 0 auto; padding: 0; border: 0; background: var(--ink); color: var(--sand); }
.scanner::backdrop { background: var(--ink); }
.scanner-in {
  min-height: 100%; display: flex; flex-direction: column; align-items: center; gap: 20px;
  padding: calc(16px + env(safe-area-inset-top, 0px)) 20px calc(24px + env(safe-area-inset-bottom, 0px));
}
.scanner-in .hunt-close { align-self: flex-end; }
/* .hunt-close was drawn for a link; as a button it sheds the browser's own. */
button.hunt-close { background: none; padding: 0; cursor: pointer; font: inherit; }
.scanner--failed .finder-line { animation: none; opacity: 0; }
.scanner-h { text-align: center; }
.finder { position: relative; width: min(80vw, 300px); aspect-ratio: 1; border-radius: 24px; overflow: hidden; background: #2A2721; border: 4px solid var(--yellow); container-type: size; }
.finder-video { width: 100%; height: 100%; object-fit: cover; }
/* Moved by transform, not `top`: the line sweeps without a layout per frame. */
.finder-line { position: absolute; left: 10%; right: 10%; top: 12%; height: 4px; background: var(--yellow); box-shadow: 0 0 12px var(--yellow); animation: scanline 1.8s ease-in-out infinite alternate; }
@keyframes scanline { to { transform: translateY(74cqh); } }
/* Three lines reserved: the longest message (no camera) never grows it. */
.scanner-status { min-height: 72px; text-align: center; font-size: 16px; line-height: 24px; color: #D9D2BE; max-width: 20rem; }

/* The ink tab bar: a yellow top rule, and the current tab's marker hangs
 * from it. It sits under the home indicator and pays for it. */
.tabbar {
  position: fixed; left: 50%; bottom: 0; transform: translateX(-50%); width: min(100%, 430px); z-index: 10;
  background: var(--ink); border-top: 4px solid var(--yellow);
  display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
  padding: 0 12px calc(8px + env(safe-area-inset-bottom, 0px));
}
@media (min-width: 470px) { .tabbar { border-inline: 2px solid var(--ink); } }
.tab {
  position: relative; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
  min-height: 64px; padding-top: 8px; color: #D9D2BE; text-decoration: none; font-size: 12px; line-height: 16px; font-weight: 700;
}
.tab[aria-current="page"] { color: var(--yellow); font-weight: 800; }
.tab[aria-current="page"]::before {
  content: ""; position: absolute; left: 50%; top: 0; width: 36px; height: 8px; transform: translateX(-50%);
  background: var(--yellow); clip-path: polygon(0 0, 100% 0, 80% 100%, 20% 100%);
}
.tab:active svg { transform: scale(.92); }

@media (prefers-reduced-motion: reduce) {
  .spot--pop, .miss, .finder-line { animation: none; }
  .tog-track i { transition: none; }
  .screen, .reveal--fresh:not(.reveal--held) :is(.reveal-sticker, .reveal-h, .chips, .new-medal) { animation: none; }
  .medal-toast { animation: toast-out 0s 6s forwards; }
  .btn { transition: none; }
}

/* ── «¿Alguien te invitó a esta reunión?» ── */
/* The night's people as buttons, laid out as «Fueron contigo» lays out its
 * links; the grid wraps however many came. */
.invite { padding: 16px; display: flex; flex-direction: column; gap: 12px; }
/* «¿Fuiste?» on a missed night (pase/meetups/show): the invite card's column. */
.ask { padding: 16px; display: flex; flex-direction: column; gap: 12px; scroll-margin-top: 16px; }
.invite-form { display: block; min-width: 0; }
button.person { width: 100%; background: none; border: 0; font: inherit; cursor: pointer; }
button.person[disabled] { cursor: progress; opacity: .6; }
.invite-answer { display: flex; align-items: center; gap: 12px; min-width: 0; }
.invite-txt { min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.invite-txt .h2 { overflow-wrap: anywhere; }
.invite--answered { background: var(--yellow-50); }
.invite-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; }
.invite-top .h2 { min-width: 0; padding-top: 10px; }
.invite-close-form { flex: none; margin: -6px -6px 0 0; }
button.invite-close { background: none; padding: 0; cursor: pointer; border-color: var(--sand-3); color: var(--ink); }

/* ── «¿Quién se lució?» (pase/shared/_gift_prompt) ── The invitation's card,
 * top and corner ×, holding a fold per logro: the medal beside its words as
 * on a companion's page, and the night's people under it as the invitation's
 * buttons. Somebody given it wears a check on their meeple. */
.lucio { padding: 16px; display: flex; flex-direction: column; gap: 12px; }
.lucio-medals { display: flex; flex-direction: column; gap: 8px; }
.lucio-medal { border-top: 2px solid var(--sand-2); padding-top: 8px; }
.lucio-head { display: grid; grid-template-columns: 56px minmax(0, 1fr) auto; align-items: center; column-gap: 12px; }
.lucio-head > svg { width: 56px; height: 48px; }
.lucio-head .gift-txt b { font-size: 16px; }
.lucio-medal .people { margin-top: 12px; }
.person--given .person-name { color: var(--ink); }
.person-check {
  position: absolute; right: -2px; bottom: -2px; width: 24px; height: 24px; display: flex; align-items: center; justify-content: center;
  border: 2px solid var(--ink); border-radius: 999px; background: var(--yellow); color: var(--ink);
}
span.person--given { opacity: .7; }

/* ── «Únete a la comunidad» (Inicio) ── The invitation's card, top and
 * corner ×, with a button per group; side by side when both fit. */
.groups { padding: 16px; display: flex; flex-direction: column; gap: 12px; }
.groups-links { display: flex; flex-wrap: wrap; gap: 12px; }
.groups-links .btn { flex: 1 1 180px; width: auto; }

/* ── «Tu año en GameOn» (pase/recaps, its card on Inicio, the links at the
 * foot of Logros) ── A stack of bold cards, one figure each, in the colours
 * of the ticket stack; the cards with something to press press like the rest. */
.recap-hero { padding: 16px; display: flex; align-items: center; gap: 16px; background: var(--yellow); }
.recap-av { width: 112px; height: 104px; flex: none; }
.recap-av .pase-av { width: 112px; height: 104px; overflow: visible; }
.recap-hero-txt { display: flex; flex-direction: column; align-items: flex-start; gap: 4px; min-width: 0; }
.recap-title { font-size: 32px; line-height: 36px; font-weight: 900; letter-spacing: -.03em; overflow-wrap: anywhere; }
.recap-sub { font-size: 16px; line-height: 20px; font-weight: 700; }
.recap-card { padding: 16px 20px; display: flex; flex-direction: column; gap: 4px; color: var(--ink); text-decoration: none; }
.recap-card--blue { background: #4B82F0; }
.recap-card--teal { background: #12B3B1; }
.recap-card--purple { background: #8B72F0; }
.recap-card--coral { background: #FF7A5C; }
.recap-card--cream { background: var(--cream); }
.recap-big { display: flex; align-items: center; gap: 8px; font-size: 64px; line-height: 64px; font-weight: 900; letter-spacing: -.04em; font-variant-numeric: tabular-nums; }
.recap-big svg { width: 40px; height: 40px; }
.recap-line { font-size: 18px; line-height: 24px; font-weight: 800; text-wrap: balance; overflow-wrap: anywhere; }
/* Six to a row, however many the season had: the strip never runs wider
 * than the card. */
.recap-stickers { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 4px; margin-top: 8px; }
.recap-stickers > * { width: 100%; height: auto; }
.recap-card .night-medals { margin-top: 8px; }
.recap-pair { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.recap-meet { min-width: 0; min-height: 44px; display: flex; flex-direction: column; gap: 4px; color: var(--ink); text-decoration: none; }
.recap-meet b { font-size: 16px; line-height: 20px; font-weight: 900; text-wrap: balance; overflow-wrap: anywhere; }
.recap-meet small { font-size: 14px; line-height: 20px; font-weight: 600; color: var(--ink-2); }
.recap-compa { flex-direction: row; align-items: center; gap: 16px; }
.recap-compa-av { width: 84px; height: 78px; flex: none; }
.recap-compa-av .pase-av { width: 84px; height: 78px; overflow: visible; }
.recap-compa-txt { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.recap-compa-name { font-size: 24px; line-height: 28px; font-weight: 900; overflow-wrap: anywhere; }
.recap-home { padding: 16px; display: flex; align-items: center; gap: 16px; background: var(--yellow); color: var(--ink); text-decoration: none; }
.recap-home-av { width: 56px; height: 52px; flex: none; }
.recap-home-av .pase-av { width: 56px; height: 52px; overflow: visible; }
.recap-home-txt { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.recap-home-txt .kicker { color: var(--ink-2); }
.recap-home-go { font-size: 16px; line-height: 20px; font-weight: 800; text-decoration: underline; text-underline-offset: 3px; }
.recap-compa:active, .recap-home:active { transform: translate(2px, 2px); box-shadow: var(--pressed); }
.recap-links { display: flex; flex-wrap: wrap; gap: 12px; }

/* ── Meeple unlocks ── */
/* «Mi cuenta»: a part the member has not unlocked is dimmed, with a padlock
 * laid over its corner, and exactly the size of every other option. Its input
 * is disabled, so a tap on it only shows which logro unlocks it, in a toast
 * over the page (locked_controller, .medal-toast). */
.is-locked .swatch-dot, .is-locked .icon-tile, .pick.is-locked > span, .is-locked .tog-track { opacity: .4; }
.lock-badge { position: absolute; width: 20px; height: 20px; pointer-events: none; }
.swatch .lock-badge { top: -4px; right: -4px; }
.icon-pick .lock-badge { top: 6px; right: 6px; }
.pick .lock-badge { top: -6px; right: -6px; }
.tog .lock-badge { top: calc(50% - 24px); right: -6px; }

/* ── Sticker reveal ── */
/* The week before a meetup its sticker is a mosaic, a little finer each day
 * (Pase::Reveal): a few pixels upscaled with hard edges, into a box already
 * the original's shape (pase_pixel_image). On the meetup it takes the place
 * of the face-down hex, with the shadow a sticker casts; on Inicio's pass it
 * sits beside the fields, no taller than they are, so the pass never grows. */
.pase-px { image-rendering: pixelated; object-fit: fill; }
.hero-sticker--reveal { filter: drop-shadow(4px 4px 0 var(--ink)); }
.t-fields--px { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto; }
.t-fields .t-sticker { height: 36px; transform: rotate(-6deg); }
/* A guess sealed until the night: the answer given, neither right nor wrong. */
span.opt--mine { color: var(--ink); border-color: var(--ink); background: var(--sand-2); }

/* The meeple editor's photo (Pase::PhotosController): the picker is a button
 * whose file input is out of sight but still takes the focus, and the crop
 * dialog (photo_crop_controller) shows the photo under the avatar's own frame. */
.av-photo { display: contents; }
.av-photo-pick { position: relative; cursor: pointer; }
.av-photo-pick:has(.av-photo-input:focus-visible) { outline: 3px solid var(--ink); outline-offset: 2px; }
.av-photo-input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.av-photo-note { font-size: 14px; line-height: 20px; font-weight: 600; color: var(--ink-2); text-align: center; }
.crop {
  width: min(100vw - 32px, 440px); max-height: calc(100dvh - 32px); padding: 16px; overflow: auto;
  border: 2px solid var(--ink); border-radius: 16px; background: var(--paper); color: var(--ink); box-shadow: var(--shadow);
}
.crop[open] { display: flex; flex-direction: column; gap: 12px; }
.crop::backdrop { background: rgba(23, 21, 15, .6); }
.crop-hint { font-size: 14px; line-height: 20px; color: var(--ink-2); }
/* Shaped like the avatar's viewBox (Pase::Mark::AVATAR_VIEW, written as the
 * stage's aspect-ratio in the page), so the frame and the crop agree. */
.crop-stage {
  position: relative; width: 100%; overflow: hidden; border-radius: 12px;
  background: var(--sand-3); touch-action: none; cursor: grab; user-select: none; -webkit-user-select: none;
}
.crop-stage:active { cursor: grabbing; }
.crop-image { position: absolute; top: 0; left: 0; max-width: none; transform-origin: 0 0; pointer-events: none; }
.crop-frame { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.crop-zoom { display: flex; align-items: center; gap: 12px; min-height: 44px; font-size: 14px; font-weight: 700; }
.crop:focus { outline: none; }
/* A thick dark track and a thumb a finger finds, like the app's toggles. */
.crop-zoom input { flex: 1; min-width: 0; height: 44px; margin: 0; background: none; appearance: none; -webkit-appearance: none; cursor: pointer; }
.crop-zoom input::-webkit-slider-runnable-track { height: 8px; border-radius: 999px; background: var(--ink); }
.crop-zoom input::-moz-range-track { height: 8px; border-radius: 999px; background: var(--ink); }
.crop-zoom input::-webkit-slider-thumb {
  -webkit-appearance: none; width: 28px; height: 28px; margin-top: -10px; border-radius: 50%;
  background: var(--yellow); border: 2px solid var(--ink); box-shadow: 2px 2px 0 var(--ink);
}
.crop-zoom input::-moz-range-thumb { width: 24px; height: 24px; border-radius: 50%; background: var(--yellow); border: 2px solid var(--ink); box-shadow: 2px 2px 0 var(--ink); }
.crop-zoom input:focus { outline: none; }
.crop-zoom input:focus-visible::-webkit-slider-thumb { outline: 3px solid var(--ink); outline-offset: 2px; }
.crop-zoom input:focus-visible::-moz-range-thumb { outline: 3px solid var(--ink); outline-offset: 2px; }
.crop-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }

/* «Cuéntanos» (Pase::FeedbacksController): the message, a screenshot, and
 * what the member already sent. 16px text in both fields, so iOS does not
 * zoom the page when one takes focus. */
.entry-area { height: auto; min-height: 144px; padding: 12px 16px; line-height: 24px; resize: vertical; }
.entry-file { width: 100%; min-height: 48px; font: inherit; font-size: 16px; color: var(--ink-2); }
.entry-file::file-selector-button {
  min-height: 44px; margin-right: 12px; padding: 0 16px; border: 2px solid var(--ink); border-radius: 999px;
  background: var(--paper); color: var(--ink); font: inherit; font-size: 16px; font-weight: 800; cursor: pointer;
}
.entry-file:focus-visible { outline: 3px solid var(--ink); outline-offset: 2px; border-radius: 999px; }
.feedback-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 12px; }
.feedback-item { padding: 12px 16px; display: flex; flex-direction: column; gap: 8px; box-shadow: none; }
.feedback-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.feedback-when { font-size: 14px; line-height: 20px; font-weight: 600; color: var(--ink-2); }
/* Where it stands, at the row's end: a label, not a control, so no border
 * like the picks above it have — only a fill. */
.feedback-status { margin-left: auto; min-height: 28px; padding: 4px 12px; border: 0; background: var(--sand-2); }
.feedback-status.status--next { background: var(--yellow); }
.feedback-body { font-size: 16px; line-height: 24px; white-space: pre-line; overflow-wrap: anywhere; }

/* The «?» at the end of a header whose top right is empty (pase/shared/_help),
 * and «Cuéntanos» in a dialog over the screen. The frame around the form is
 * no box of its own, here or on «Cuéntanos»'s page: its children are the
 * card's. */
.help { margin-left: auto; flex: none; }
.help-btn { padding: 0; font-size: 22px; line-height: 1; font-weight: 900; cursor: pointer; }
.frame-flat { display: contents; }
.help-sheet {
  width: min(100vw - 32px, 440px); max-width: none; max-height: calc(100dvh - 32px); padding: 0; border: 0; background: transparent; overflow: visible;
}
.help-sheet::backdrop { background: rgba(23, 21, 15, .6); }
.help-sheet:focus { outline: none; }
.help-sheet-in {
  position: relative; display: flex; flex-direction: column; gap: 16px; max-height: calc(100dvh - 32px);
  padding: 16px; overflow-y: auto; overscroll-behavior: contain;
  border: 2px solid var(--ink); border-radius: 16px; background: var(--paper); color: var(--ink); box-shadow: var(--shadow);
}
.help-sheet[open] .help-sheet-in { animation: help-in .18s ease-out; }
@keyframes help-in { from { transform: translateY(8px); opacity: .5; } }
/* The heading's line, which the close button shares. */
.help-sheet .h2 { min-height: 40px; display: flex; align-items: center; padding-right: 52px; }
/* Past sends, under the form. */
.help-sent { align-self: center; }
/* The hunt's ring (.hunt-close), inked for a paper sheet. */
button.help-close { position: absolute; top: 14px; right: 14px; background: none; padding: 0; cursor: pointer; border-color: var(--sand-3); color: var(--ink); }

/* A guest's «Agrega tu correo» (pase/shared/_guest_gate): «Cuéntanos»'s
 * sheet, with «Ahora no» under it. */
.guest-sheet-later { align-self: center; }
/* A guest's «Correo» in «Tus datos»: its own row under the name's form, since
 * adding it is the card's main action. */
.settings-rows--guest { margin-top: 8px; padding-top: 16px; border-top: 2px dashed var(--sand-3); }
