:root {
  --bg: #14161a;
  --panel: #1e2127;
  --panel2: #2b303b;
  --ink: #f5f6f8;
  --muted: #b7bbc7;
  --purple: #a855f7;
  --purple-glow: #c084fc;
  --blue: #38bdf8;
  --blue-glow: #7dd3fc;
  --gold: #ffb020;
  --good: #4ade80;
  --bad: #f87171;
}
* { box-sizing: border-box; }
body {
  margin: 0;
  font-family: 'Nunito', system-ui, sans-serif;
  background: var(--bg);
  color: var(--ink);
  font-size: 17px;
}
main { max-width: 680px; margin: 0 auto; padding: 16px 16px 90px; position: relative; z-index: 1; }
.loading { color: var(--muted); text-align: center; margin-top: 60px; }
a { color: var(--blue-glow); }
button { font-family: inherit; cursor: pointer; }
input, select, textarea {
  width: 100%; padding: 12px; border-radius: 10px; border: 2px solid var(--panel2);
  background: #191c22; color: var(--ink); font-size: 16px; font-family: inherit; margin: 4px 0 12px;
}
label { font-weight: 800; font-size: 14px; color: var(--muted); }
/* Password show/hide (eye) toggle (Shane, Oct 26, 2026): a big plain
   Show/Hide button inside the field so you can check what you typed.
   The button is type="button" in the markup — it never submits. */
.pw-wrap { position: relative; }
.pw-wrap input { padding-right: 96px; }
.pw-eye {
  position: absolute; right: 6px; top: 4px; height: 44px; min-width: 78px;
  padding: 0 14px; border-radius: 9px; border: 2px solid var(--purple);
  background: rgba(168, 85, 247, .18); color: var(--ink);
  font-family: inherit; font-size: 16px; font-weight: 900; cursor: pointer;
}
.welcome-content .pw-eye {
  background: rgba(15, 11, 32, .45); border-color: rgba(255, 255, 255, .55); color: #fff;
}
.btn {
  display: inline-block; border: 0; border-radius: 12px; padding: 13px 20px;
  background: var(--purple); color: #fff; font-weight: 900; font-size: 16px; text-decoration: none;
}
.btn.blue { background: #0284c7; }
.btn.ghost { background: transparent; border: 2px solid var(--purple); color: var(--ink); }
.btn.gold { background: var(--gold); color: #14161a; }
.btn.small { padding: 8px 14px; font-size: 14px; }
.btn:disabled { opacity: .5; cursor: default; }
.btnrow { display: flex; gap: 10px; flex-wrap: wrap; margin: 12px 0; }
.err { color: var(--bad); min-height: 22px; font-weight: 700; }
.hint { color: var(--muted); font-size: 15px; }
.card {
  background: var(--panel); border-radius: 18px; padding: 20px; margin: 14px 0;
  box-shadow: 0 6px 24px rgba(0,0,0,.35);
}
.card h2, .card h3 { margin-top: 0; }

/* ---- welcome background (naked: photo only, no color wash) ---- */
.welcome-bg {
  position: fixed;
  /* longhands first: fallback for Safari < 14.1, which drops `inset` */
  top: 0; right: 0; bottom: 0; left: 0;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image: url('/ca-bg-wide.webp');
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
}
@media (max-aspect-ratio: 4/5) {
  .welcome-bg { background-image: url('/ca-bg-tall.webp'); }
}
.welcome-content { position: relative; z-index: 1; }
.welcome-content .card {
  background: transparent;
  box-shadow: none;
}
.welcome-content h2,
.welcome-content .hint,
.welcome-content label,
.welcome-content .foot {
  color: #fff;
  text-shadow: 0 1px 12px rgba(0, 0, 0, .68), 0 1px 4px rgba(0, 0, 0, .8);
}
.welcome-content .err { text-shadow: 0 1px 8px rgba(0, 0, 0, .75); }
.welcome-content input {
  background: rgba(15, 11, 32, .45);
  border-color: rgba(255, 255, 255, .55);
  color: #fff;
}
/* welcome only: Log in gets the same readable treatment as the inputs
   (its ghost styling — transparent fill, pale text — washed out
   against the bright photo). Sign up free keeps the purple fill. */
.welcome-content .btn.ghost {
  background: rgba(15, 11, 32, .45);
  border-color: rgba(255, 255, 255, .55);
  color: #fff;
}
/* ---- full-page photo backdrops (Shane, Oct 27, 2026) ----
   Every page looks like the welcome page: a real-life photo fills
   the whole screen (the fixed .page-bg layer, set per route by
   setBackdrop() in app.js) and the content floats over it.
   Tipping5 rule (Shane, later Oct 27): SHOW THE PHOTOGRAPH, NOT AN
   UNDERLAY. The photo renders at full strength — no screen-wide
   scrim, only light local gradients behind the header zone and the
   tab bar. Text does NOT sit in filled boxes: cards are transparent
   and words ride directly on the picture with the welcome
   treatment (white text, soft shadow); containers that need a
   boundary get at most a thin white line (the host's speech bubble
   is an outline bubble — transparent fill, white line, tail
   included). The only translucency left is where typing or long
   reading genuinely needs it (inputs, sheets, chat bubbles), kept
   as thin as readability allows. Plain purple page backgrounds
   stay retired — blue-violet is brand accent only (logo, buttons).
   The talent + tip-book sheets borrow the backdrop for their own
   photo while open. */
.page-bg {
  position: fixed;
  /* longhands first: fallback for Safari < 14.1, which drops `inset` */
  top: 0; right: 0; bottom: 0; left: 0;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-position: center;
  background-size: cover;
  background-repeat: no-repeat;
}
.page-bg::after {
  content: '';
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
  /* edge-only shading: a light gradient behind the header/logo zone
     at the top and behind the tab bar at the bottom — the middle of
     the photograph stays completely untouched and vivid. */
  background: linear-gradient(to bottom,
    rgba(8, 9, 12, .42) 0, rgba(8, 9, 12, 0) 150px,
    rgba(8, 9, 12, 0) calc(100% - 118px), rgba(8, 9, 12, .48) 100%);
}
body.bg-on #topbar {
  background: rgba(13, 15, 18, .3);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
}
/* logo floats directly on the photo, exactly like the welcome page */
body.bg-on .brand .panel { background: transparent; border-color: transparent; }
body.bg-on .tagline {
  color: #fff;
  text-shadow: 0 1px 10px rgba(0, 0, 0, .82), 0 1px 3px rgba(0, 0, 0, .85);
}
body.bg-on nav.tabs {
  background: rgba(13, 15, 18, .45);
  -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
}
/* NO underlay: cards are transparent, their words sit straight on
   the photograph with the welcome shadow treatment. */
body.bg-on .card {
  background: transparent;
  box-shadow: none;
  text-shadow: 0 1px 12px rgba(0, 0, 0, .6), 0 1px 4px rgba(0, 0, 0, .85);
}
body.bg-on .match-row {
  background: transparent;
  border-bottom: 1px solid rgba(255, 255, 255, .22);
  border-radius: 0;
  text-shadow: 0 1px 10px rgba(0, 0, 0, .6), 0 1px 4px rgba(0, 0, 0, .85);
}
body.bg-on #app > h2,
body.bg-on .loading {
  color: #fff;
  text-shadow: 0 1px 12px rgba(0, 0, 0, .7), 0 1px 4px rgba(0, 0, 0, .85);
}
/* catch-all: any bare words anywhere in the app ride on the photo
   with the welcome shadow (blocks above restate it a touch stronger) */
body.bg-on #app {
  text-shadow: 0 1px 10px rgba(0, 0, 0, .5), 0 1px 3px rgba(0, 0, 0, .75);
}
body.bg-on .city-footer {
  color: #fff;
  text-shadow: 0 1px 8px rgba(0, 0, 0, .8);
}
body.bg-on #app > p { text-shadow: 0 1px 8px rgba(0, 0, 0, .8); }
/* Chat bubbles are content, not panels — thinned as far as
   comfortable reading allows (frosted .8 + blur, down from .97);
   my own bubbles keep the solid brand purple. System notices get
   only a thin wash (.4) over their dashed outline. */
body.bg-on .msg {
  background: rgba(38, 43, 54, .8);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
}
body.bg-on .msg.mine { background: var(--purple); }
body.bg-on .msg.system {
  background: rgba(18, 20, 26, .4); color: #e8eaf0;
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
}
body.bg-on .sheet-overlay { background: rgba(8, 9, 12, .22); }
/* Sheets carry long text (advice, ratings, tip book): the thinnest
   wash that still reads — .35 dark + blur under a white top line,
   never a solid panel. */
body.bg-on .sheet {
  background: rgba(22, 25, 32, .35);
  border-top: 1px solid rgba(255, 255, 255, .3);
  -webkit-backdrop-filter: blur(16px); backdrop-filter: blur(16px);
  text-shadow: 0 1px 10px rgba(0, 0, 0, .55), 0 1px 4px rgba(0, 0, 0, .8);
}
body.bg-on footer.foot {
  color: #fff;
  text-shadow: 0 1px 8px rgba(0, 0, 0, .8);
}
/* Small grey text is the first thing a bright photo eats — lift it
   toward white wherever the backdrop is on. */
body.bg-on .hint,
body.bg-on .q,
body.bg-on label,
body.bg-on .match-row .last,
body.bg-on .rate-hint { color: #dde1ea; }
/* Inputs you type in: the thinnest backing that keeps typed text
   legible over any photo (mirrors the welcome inputs), with a
   pale outline. */
body.bg-on input,
body.bg-on select,
body.bg-on textarea {
  background: rgba(15, 17, 23, .38);
  border-color: rgba(255, 255, 255, .55);
  color: #fff;
}
body.bg-on .slotbox {
  background: rgba(15, 17, 23, .38);
  border-color: rgba(255, 255, 255, .45);
  color: #dfe3ec;
}
body.bg-on .slotbox.on { background: var(--purple); border-color: var(--purple); color: #fff; }
body.bg-on .tag { background: rgba(43, 48, 59, .55); color: #e8eaf0; }
/* semantic tag colours survive the backdrop (SAMPLE above all) */
body.bg-on .tag.sample { background: #7c2d12; color: #fed7aa; }
body.bg-on .tag.seeing { background: #713f12; color: #fde68a; }
body.bg-on .tag.shared { background: #14532d; color: #bbf7d0; }
body.bg-on .tag.seeking { background: #1e3a5f; color: #bfdbfe; }
body.bg-on .rating-entry,
body.bg-on .tip-send-row { border-color: rgba(255, 255, 255, .3); }
body.bg-on .tip-line { border-bottom-color: rgba(255, 255, 255, .22); }
body.bg-on .videogrid button { background: rgba(20, 23, 30, .3); }

/* welcome only: header floats directly on the photo (no dark bar / pill) */
body:has(.welcome-bg) #topbar { background: transparent; }
body:has(.welcome-bg) .brand .panel { background: transparent; border-color: transparent; }
body:has(.welcome-bg) .tagline {
  color: #fff;
  text-shadow: 0 1px 10px rgba(0, 0, 0, .82), 0 1px 3px rgba(0, 0, 0, .85);
}
/* same treatment via a body class (set by app.js) for Safari < 15.4, which drops :has() rules entirely */
body.welcome-on #topbar { background: transparent; }
body.welcome-on .brand .panel { background: transparent; border-color: transparent; }
body.welcome-on .tagline {
  color: #fff;
  text-shadow: 0 1px 10px rgba(0, 0, 0, .82), 0 1px 3px rgba(0, 0, 0, .85);
}

/* ---- header / wordmark ---- */
#topbar { background: #0d0f12; padding: 10px 16px; position: -webkit-sticky; position: sticky; top: 0; z-index: 20; }
.brand { display: flex; align-items: center; gap: 12px; max-width: 680px; margin: 0 auto; }
.brand .panel {
  background: rgba(246,248,255,.94); border-radius: 14px; padding: 8px 18px 10px; display: inline-block;
  border: 1px solid rgba(18,38,94,.25);
}
/* This Week Dating wordmark (Shane, Oct 31, 2026): a text lockup —
   THIS [flag] WEEK over DATING, dark blue, sitting on the photo.
   Text (not an image) so every market's flag drops into the slot.
   The soft light halo keeps the dark-blue letters readable over
   darker photo areas. */
.wordmark { display: inline-block; font-family: 'Archivo Black', sans-serif; color: #12265E; line-height: 1.05; text-align: center;
  text-shadow: 0 0 3px rgba(255,255,255,.85), 0 1px 10px rgba(255,255,255,.65), 0 0 20px rgba(255,255,255,.45); }
.wm-l1 { display: block; font-size: 30px; letter-spacing: 2px; white-space: nowrap; }
.wm-l2 { display: flex; justify-content: space-between; font-size: 14px; margin-top: 4px; padding: 0 2px; }
.wm-flag { height: .30em; width: auto; vertical-align: baseline; position: relative; top: .02em; margin: 0 .06em; box-shadow: 0 0 0 1px rgba(18,38,94,.3); }
.wordmark.compact .wm-l1 { font-size: 21px; }
.wordmark.compact .wm-l2 { font-size: 11px; margin-top: 3px; }

/* ---- mascot: layered — the body stays still, only the arm waves ---- */
.mascot-row { display: flex; gap: 14px; align-items: flex-start; margin: 14px 0; }
.mascot {
  position: relative; display: inline-block; flex: 0 0 auto;
  width: 84px; aspect-ratio: 646 / 595;
}
.mascot img { position: absolute; inset: 0; width: 100%; height: 100%; display: block; }
.mascot .mascot-arm {
  transform-origin: 76% 44%;
  animation: arm-wave 2.6s ease-in-out infinite;
}
@keyframes arm-wave {
  0%, 100% { transform: rotate(-6deg); }
  50% { transform: rotate(10deg); }
}
@media (prefers-reduced-motion: reduce) {
  .mascot .mascot-arm { animation: none; }
}
/* Host speech bubble (Shane, Oct 27, 2026): an OUTLINE bubble —
   transparent fill, a thin white line (tail included), words right
   on the photograph. No white underlay anywhere it appears:
   welcome, in-app mascot rows, every host moment. */
.bubble {
  background: transparent; color: #fff;
  border: 2px solid rgba(255, 255, 255, .92);
  border-radius: 16px; padding: 12px 16px;
  position: relative; font-weight: 700; flex: 1;
  text-shadow: 0 1px 10px rgba(0, 0, 0, .65), 0 1px 4px rgba(0, 0, 0, .85);
}
.bubble::before {
  content: ''; position: absolute; left: -10px; top: 26px; width: 15px; height: 15px;
  background: transparent; transform: rotate(45deg); border-radius: 3px;
  border-left: 2px solid rgba(255, 255, 255, .92);
  border-bottom: 2px solid rgba(255, 255, 255, .92);
}
.cheer .mascot .mascot-arm { animation-duration: 1.1s; }

/* ---- nav tabs ---- */
nav.tabs {
  position: fixed; bottom: 0; left: 0; right: 0; background: #0d0f12; z-index: 20;
  display: flex; justify-content: center; gap: 2px; padding: 8px 4px calc(8px + env(safe-area-inset-bottom));
}
nav.tabs button {
  background: transparent; border: 0; color: var(--muted); font-weight: 900; font-size: 14px;
  padding: 10px 12px; border-radius: 10px;
}
nav.tabs button.active { background: var(--panel2); color: #fff; }
nav.tabs .dot { color: var(--gold); }

/* ---- profile cards / deck ---- */
/* Profile photos display PAN-IN (Shane, Oct 27, 2026): the on-site
   display is always a face-focused step closer than the uploaded
   original — a full-body shot shows as face-and-shoulders, a closer
   shot as a tight face close-up. Pure CSS crop (object-fit: cover in
   a tighter window, biased toward the face at the top): cover can
   only ever show a SUBSET of the original, never more, and the
   stored original is untouched. Tapping opens the lightbox, which
   pans back out to the exact original framing (see .lightbox). */
.photo { width: 100%; border-radius: 14px; display: block; aspect-ratio: 4/5; object-fit: cover; object-position: center 22%; }
/* Preview silhouette (Shane, Oct 29, 2026): a no-photo member's
   preview card carries a simple gender outline on the photo
   footprint (POF-style) instead of a photo or initials. */
.silhouette { display: flex; align-items: center; justify-content: center; color: #e9e6f5; background: linear-gradient(135deg, #4b4560, #221f2e); }
.silhouette svg { width: 58%; height: auto; }
img[data-zoom] { cursor: zoom-in; }
/* Photo gallery: main photo first, extras after — swipe/scroll strip */
.gallery { display: flex; gap: 8px; overflow-x: auto; scroll-snap-type: x mandatory; border-radius: 14px; }
.gallery-img { width: 100%; flex: 0 0 100%; scroll-snap-align: start; border-radius: 14px; display: block; object-fit: cover; aspect-ratio: 4/5; object-position: center 22%; }
/* Extra-photo manager in the edit form */
.extras-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin: 8px 0; }
.extra-thumb img { width: 100%; border-radius: 12px; display: block; object-fit: cover; object-position: center 22%; aspect-ratio: 1; }
.extra-acts { display: flex; gap: 6px; margin-top: 6px; }
.extra-acts .btn { flex: 1; }
/* Lightbox: tap a profile photo to see it big; tap anywhere to close */
.lightbox { position: fixed; top: 0; right: 0; bottom: 0; left: 0; inset: 0; background: rgba(8, 9, 11, .92); z-index: 90; display: flex; align-items: center; justify-content: center; cursor: zoom-out; overflow: hidden; }
/* Pan-out (Shane, Oct 27, 2026): the lightbox opens framed on the
   face close-up and pulls back over ~1s to the WHOLE original photo
   — the img's resting layout is max-width/max-height contain, i.e.
   the picture exactly as uploaded, uncropped; the animation only
   scales it (GPU transform, origin at the face area) and lands
   precisely on that framing. */
.lightbox img { max-width: 94vw; max-height: 92vh; border-radius: 12px; transform-origin: 50% 22%; animation: panout 1.05s ease-out; will-change: transform; }
@keyframes panout { from { transform: scale(2.3); } to { transform: scale(1); } }
@media (prefers-reduced-motion: reduce) { .lightbox img { animation: none; } }
.lightbox-close { position: absolute; top: 14px; right: 14px; width: 44px; height: 44px; border-radius: 50%; border: 0; background: rgba(255,255,255,.14); color: #fff; font-size: 20px; cursor: pointer; }
.avatar {
  width: 100%; aspect-ratio: 1.2; border-radius: 14px; display: flex; align-items: center; justify-content: center;
  background: linear-gradient(135deg, var(--purple), #0284c7); font-size: 72px; font-weight: 900; color: #fff;
}
.avatar.sm { width: 54px; height: 54px; aspect-ratio: auto; font-size: 22px; border-radius: 50%; flex: 0 0 auto; }
img.avatar-img { width: 54px; height: 54px; border-radius: 50%; object-fit: cover; object-position: center 25%; flex: 0 0 auto; }
.badge-verified { color: var(--gold); font-weight: 900; }
.badge-id { color: #7aa2ff; font-weight: 900; }
.badge-founding { color: var(--purple-glow); font-weight: 900; }
.launch-card { text-align: center; }
.countdown { font-size: 30px; font-weight: 900; letter-spacing: 1px; margin: 6px 0; }
.tag {
  display: inline-block; background: var(--panel2); border-radius: 999px; padding: 3px 10px;
  font-size: 13px; font-weight: 800; color: var(--muted); margin: 2px 2px 2px 0;
}
.tag.sample { background: #7c2d12; color: #fed7aa; }
.tag.seeing { background: #713f12; color: #fde68a; }
.tag.shared { background: #14532d; color: #bbf7d0; }
.tag.seeking { background: #1e3a5f; color: #bfdbfe; }
.q { color: var(--muted); font-weight: 800; font-size: 14px; margin: 12px 0 2px; }
.deck-actions { display: flex; gap: 12px; margin-top: 16px; }
.deck-actions .btn { flex: 1; font-size: 18px; padding: 16px; }
.pass-btn { background: #3f3f46 !important; }

/* ---- availability grid ---- */
table.grid { border-collapse: collapse; width: 100%; }
table.grid th, table.grid td { padding: 6px 4px; text-align: center; font-size: 14px; }
table.grid th { color: var(--muted); }
.slotbox {
  width: 100%; padding: 9px 2px; border-radius: 9px; border: 2px solid var(--panel2);
  background: #191c22; color: var(--muted); font-weight: 800; font-size: 13px;
}
.slotbox.on { background: var(--purple); border-color: var(--purple); color: #fff; }

/* ---- chat ---- */
.thread { display: flex; flex-direction: column; gap: 8px; margin: 12px 0; }
.msg { max-width: 80%; padding: 10px 14px; border-radius: 16px; background: var(--panel2); align-self: flex-start; }
.msg.mine { background: var(--purple); align-self: flex-end; }
.msg .when { display: block; font-size: 11px; color: rgba(255,255,255,.65); margin-top: 4px; }
.msg.system { align-self: center; background: transparent; border: 1px dashed var(--purple); color: var(--muted); font-size: 13px; text-align: center; max-width: 92%; }
.match-row { display: flex; gap: 12px; align-items: center; width: 100%; text-align: left; background: var(--panel); border: 0; border-radius: 14px; padding: 12px; color: var(--ink); margin: 8px 0; }
.match-row .last { color: var(--muted); font-size: 14px; }

/* ---- video picker ---- */
.videogrid { display: grid; grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)); gap: 10px; }
.videogrid button { background: var(--panel2); border: 3px solid transparent; border-radius: 12px; padding: 4px; color: var(--ink); font-weight: 800; font-size: 13px; }
.videogrid button.sel { border-color: var(--gold); }
.videogrid img { width: 100%; border-radius: 8px; display: block; }
video.preview { width: 100%; border-radius: 14px; margin: 10px 0; background: #000; }

.price { font-size: 22px; font-weight: 900; }
.strike { text-decoration: line-through; color: var(--muted); }
.date-status { font-weight: 900; }
.date-status.confirmed { color: var(--good); }
.date-status.pending { color: var(--gold); }
footer.foot { text-align: center; color: var(--muted); font-size: 13px; padding: 10px 0 30px; }

/* ---- host: mascot as continuous assistant ---- */
.host {
  position: fixed; left: 12px; z-index: 30;
  bottom: calc(84px + env(safe-area-inset-bottom));
  display: flex; align-items: flex-end; gap: 8px;
  max-width: calc(100vw - 24px);
}
.host-btn {
  background: var(--panel); border: 2px solid var(--panel2); border-radius: 50%;
  width: 58px; height: 58px; padding: 5px; flex: 0 0 auto; cursor: pointer;
  box-shadow: 0 6px 18px rgba(0,0,0,.4);
  display: flex; align-items: center; justify-content: center;
}
.host-btn .mascot { width: 100%; }
.host-bubble {
  background: transparent; color: #fff;
  border: 2px solid rgba(255, 255, 255, .92);
  border-radius: 14px; padding: 9px 12px;
  font-weight: 700; font-size: 14px;
  text-shadow: 0 1px 10px rgba(0, 0, 0, .65), 0 1px 4px rgba(0, 0, 0, .85);
  position: relative; max-width: 204px; cursor: pointer;
}
.host-bubble::before {
  content: ''; position: absolute; left: -8px; bottom: 16px; width: 11px; height: 11px;
  background: transparent; transform: rotate(45deg); border-radius: 2px;
  border-left: 2px solid rgba(255, 255, 255, .92);
  border-bottom: 2px solid rgba(255, 255, 255, .92);
}
.host-tip { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 180px; }
.host[data-state="open"] .host-bubble { max-width: 266px; cursor: default; }
.host[data-state="open"] .host-tip { white-space: normal; max-width: 240px; }
.host-actions { display: none; gap: 8px; margin-top: 10px; }
.host[data-state="open"] .host-actions { display: flex; }
.host[data-state="mini"] .host-bubble { display: none; }
.impr-btn { width: 100%; margin-top: 10px; }

/* ---- bottom sheets (advice / impressions) ---- */
.sheet-overlay {
  position: fixed;
  top: 0; right: 0; bottom: 0; left: 0;
  inset: 0;
  background: rgba(10, 7, 24, .72); z-index: 40;
  display: flex; align-items: flex-end; justify-content: center;
}
.sheet {
  background: var(--panel); width: 100%; max-width: 680px; max-height: 88vh; overflow-y: auto;
  border-radius: 18px 18px 0 0; padding: 18px 18px calc(18px + env(safe-area-inset-bottom));
}
.sheet-head { display: flex; justify-content: space-between; align-items: center; gap: 12px; }
.sheet-head h3 { margin: 0; }
.sheet-x { background: transparent; border: 0; color: var(--muted); font-size: 28px; font-weight: 900; line-height: 1; padding: 4px 8px; }
.advice-tip { font-size: 20px; font-weight: 800; line-height: 1.45; margin: 16px 0; }
.advice-nav { justify-content: space-between; align-items: center; }

/* ---- impression star ratings + owner report card ---- */
.rate-row { padding: 9px 0; border-bottom: 1px solid var(--panel2); }
.rate-label { font-weight: 900; font-size: 16px; }
.rate-hint { display: block; color: var(--muted); font-weight: 700; font-size: 13px; }
.rate-stars { margin-top: 2px; }
.star {
  background: transparent; border: 0; padding: 2px 3px; cursor: pointer;
  font-size: 30px; line-height: 1.1; color: #5a5f6e;
}
.star.on { color: var(--gold); }
.tally {
  display: flex; justify-content: space-between; align-items: center;
  padding: 7px 0; border-bottom: 1px solid var(--panel2); font-weight: 800;
}
.tally:last-child { border-bottom: 0; }
.tally-stars { color: var(--gold); font-size: 15px; letter-spacing: 1px; }
.tally-stars strong { color: var(--ink); }

/* ---- rating entries (locked / unlocked) ---- */
.rating-entry {
  border: 1px solid var(--panel2); border-radius: 12px;
  padding: 12px 14px; margin: 10px 0;
}
.rating-head { display: flex; justify-content: space-between; align-items: baseline; }
.rating-line { display: flex; justify-content: space-between; padding: 2px 0; font-weight: 700; }
.rating-comment { margin: 8px 0 2px; }
.rating-entry .blur { filter: blur(5px); opacity: .8; user-select: none; pointer-events: none; }
.imp-comment { padding: 8px 0; border-bottom: 1px solid var(--panel2); }
.imp-comment:last-child { border-bottom: 0; }

/* ---- sense of humor page ---- */
.humor-img { width: 100%; border-radius: 14px; display: block; }
.humor-caption {
  background: #fff; color: #1e2127; border-radius: 16px; padding: 14px 16px;
  font-weight: 800; font-size: 19px; line-height: 1.4; margin-top: 14px; position: relative;
}
.humor-caption::before {
  content: ''; position: absolute; left: 44px; top: -7px; width: 14px; height: 14px;
  background: #fff; transform: rotate(45deg); border-radius: 2px;
}
.humor-empty { font-weight: 800; margin: 12px 0 4px; }
.humor-thumb { width: 132px; border-radius: 10px; display: block; margin: 6px 0 4px; }
.form-sub { margin: 20px 0 4px; }

/* ---- smart puzzles ---- */
.puzzle-block { padding: 12px 0 14px; border-bottom: 1px solid var(--panel2); }
.puzzle-row { display: flex; gap: 6px; }
.matrix-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; max-width: 302px; }
.puzzle-panel {
  background: #191c22; border: 2px solid var(--panel2); border-radius: 10px;
  aspect-ratio: 1; display: flex; align-items: center; justify-content: center; flex: 1; min-width: 0;
}
.matrix-grid .puzzle-panel { flex: none; }
.puzzle-panel.qmark { color: var(--muted); font-size: 26px; font-weight: 900; }
.puzzle-panel.their-pick { border-color: var(--gold); }
.puzzle-opts { display: flex; gap: 6px; margin-top: 8px; }
.puzzle-opt {
  flex: 1; min-width: 0; background: #191c22; border: 3px solid var(--panel2);
  border-radius: 10px; padding: 3px; cursor: pointer;
}
.puzzle-opt.sel { border-color: var(--gold); }
.puzzle-opt.right { border-color: var(--good); }
.puzzle-opt.wrong { border-color: var(--bad); }
.puzzle-opt:disabled { opacity: 1; cursor: default; }
.glyph { width: 100%; height: auto; display: block; }
.smart-score { font-size: 20px; font-weight: 900; margin: 10px 0 2px; }

/* ---- talent videos ---- */
.talent-video { width: 100%; border-radius: 14px; margin: 10px 0; background: #000; }
.talent-slot-line { font-weight: 800; }

/* ---- quest: "Before you bother" ---- */
.quest-row { display: flex; justify-content: space-between; gap: 12px; padding: 8px 0; border-bottom: 1px solid rgba(127, 127, 127, 0.18); }
.quest-row:last-of-type { border-bottom: 0; }
.quest-q { font-weight: 700; }
.quest-a { font-weight: 900; white-space: nowrap; }
.quest-edit { margin: 14px 0; }
.quest-edit .quest-q { margin: 0 0 6px; }
.quest-opt.on { background: var(--purple); border-color: var(--purple); color: #fff; }
.align-note { background: rgba(127, 127, 127, 0.12); border-radius: 12px; padding: 10px 12px; margin-top: 12px; }

/* ---- ask your host ---- */
.ask-form { display: flex; gap: 8px; margin-top: 12px; }
.ask-form input { flex: 1; min-width: 0; }
.ask-q { font-weight: 800; margin: 12px 0 4px; }
.ask-a { margin: 0 0 8px; }
#ask-log { max-height: 40vh; overflow-y: auto; }

/* ---- older-Safari fallbacks ----
   Flexbox `gap` needs Safari 14.5+. app.js probes for it and adds
   .no-flex-gap to <html> when missing; these margins then carry the
   spacing `gap` was providing. Grid gap (Safari 10.1+) and the 2px
   nav-tab gap (padding already separates the buttons) need no cover. */
.no-flex-gap .brand > * + * { margin-left: 12px; }
.no-flex-gap .mascot-row .bubble { margin-left: 14px; }
.no-flex-gap .btnrow > * + * { margin-left: 10px; }
.no-flex-gap .deck-actions .btn + .btn { margin-left: 12px; }
.no-flex-gap .thread .msg + .msg { margin-top: 8px; }
.no-flex-gap .match-row > * + * { margin-left: 12px; }
.no-flex-gap .host .host-bubble { margin-left: 8px; }
.no-flex-gap .host-actions .btn + .btn { margin-left: 8px; }
.no-flex-gap .puzzle-row .puzzle-panel + .puzzle-panel { margin-left: 6px; }
.no-flex-gap .puzzle-opts .puzzle-opt + .puzzle-opt { margin-left: 6px; }
.no-flex-gap .sheet-head .sheet-x { margin-left: 12px; }

/* Country flag badge — top-right corner, makes each market feel like home */
.country-flag { position: fixed; top: 10px; right: 10px; width: 32px; height: auto; border-radius: 5px; box-shadow: 0 1px 6px rgba(0,0,0,.45); z-index: 60; }

.ask-a { white-space: pre-line; }
.ask-pending { opacity: .55; }

/* "Who do you want to meet?" — big tappable option cards */
.pick-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin: 8px 0 14px; }
.pick-card { padding: 18px 12px; font-size: 17px; font-weight: 700; border-radius: 14px; border: 2px solid var(--purple); background: transparent; color: inherit; cursor: pointer; }
.pick-card.on { background: var(--purple); color: #fff; }

/* ---- talent tipping (paid stars) ---- */
.tip-earned { color: var(--gold); font-weight: 900; font-size: 17px; margin: 10px 0 4px; }
.tip-send-row {
  border: 1px solid var(--panel2); border-radius: 12px;
  padding: 12px 14px; margin: 10px 0;
}
.tip-send-label { font-weight: 900; margin: 0 0 4px; }
.tip-send-btns { margin: 6px 0; }
.tip-send-btn { background: var(--gold); color: #14161a; }
.tip-send-msg { color: var(--gold); font-weight: 800; min-height: 20px; margin: 6px 0 0; }
.tip-buy-panel {
  border-top: 1px dashed var(--panel2); margin-top: 10px; padding-top: 10px;
}
.tip-buy-q { font-weight: 900; margin: 0 0 6px; }
.tip-qty-stepper { align-items: center; gap: 12px; }
.tip-qty-n { font-size: 20px; font-weight: 900; min-width: 34px; text-align: center; }
.tip-qty-chip.gold { background: var(--gold); color: #14161a; }
.tip-totals-line { font-weight: 900; font-size: 17px; }
.tip-payout-line { margin: 8px 0; }
.tip-line {
  display: flex; gap: 12px; align-items: center;
  padding: 10px 0; border-bottom: 1px solid var(--panel2);
}
.tip-line:last-of-type { border-bottom: 0; }
.tip-ava-btn { background: transparent; border: 0; padding: 0; flex: 0 0 auto; cursor: pointer; }
.tip-ava { width: 54px; height: 54px; border-radius: 50%; object-fit: cover; display: block; }
.tip-ava-letter {
  display: flex; align-items: center; justify-content: center;
  background: linear-gradient(135deg, var(--purple), #0284c7);
  color: #fff; font-size: 22px; font-weight: 900;
}
.tip-line-main { flex: 1; min-width: 0; }
.tip-line-text { margin: 0 0 2px; }
.tip-line-main .hint { margin: 0; }

/* Celebration overlay: sits above everything, never blocks the app —
   only its control buttons take taps. Created once on document.body
   by initTipping() in app-features.js, so it persists across routes. */
#tip-overlay {
  position: fixed;
  top: 0; right: 0; bottom: 0; left: 0;
  inset: 0;
  z-index: 9999;
  pointer-events: none;
  display: flex; align-items: center; justify-content: center;
}
#tip-overlay:empty { display: none; }
.tip-beat { text-align: center; padding: 20px; max-width: 92vw; }
.tip-star-wrap { position: relative; width: 150px; height: 150px; margin: 0 auto; }
.tip-star {
  font-size: 110px; line-height: 150px; color: var(--gold);
  text-shadow: 0 0 34px rgba(255, 176, 32, .85), 0 0 80px rgba(255, 176, 32, .45);
  animation: tipStarPop .7s ease-out both;
}
@keyframes tipStarPop {
  0% { transform: scale(0) rotate(-24deg); opacity: 0; }
  60% { transform: scale(1.2) rotate(6deg); opacity: 1; }
  100% { transform: scale(1) rotate(0deg); opacity: 1; }
}
.tip-particle {
  position: absolute; left: 50%; top: 50%;
  color: var(--gold); font-size: 18px; line-height: 1;
  animation: tipFly 1.1s ease-out both;
}
@keyframes tipFly {
  0% { transform: translate(-50%, -50%) scale(.4); opacity: 1; }
  100% { transform: translate(calc(-50% + var(--dx)), calc(-50% + var(--dy))) scale(1.1); opacity: 0; }
}
.tip-amount {
  font-size: 44px; font-weight: 900; color: var(--gold); margin-top: 6px;
  text-shadow: 0 2px 18px rgba(0, 0, 0, .55);
  animation: tipAmountIn .45s ease-out .7s both;
}
@keyframes tipAmountIn {
  0% { opacity: 0; transform: scale(.6); }
  100% { opacity: 1; transform: scale(1); }
}
.tip-from {
  display: flex; gap: 14px; align-items: flex-start; justify-content: center;
  background: var(--panel); border: 1px solid var(--panel2); border-radius: 16px;
  padding: 14px 18px; margin-top: 16px;
  box-shadow: 0 6px 24px rgba(0, 0, 0, .35);
  animation: tipAmountIn .45s ease-out .9s both;
}
.tip-from-ava { text-align: center; flex: 0 0 auto; }
.tip-from-text { text-align: left; display: flex; flex-direction: column; gap: 2px; padding-top: 6px; }
.tip-from-text strong { font-size: 19px; }
.tip-claps { display: flex; gap: 2px; justify-content: center; margin-top: 4px; }
.tip-clap { display: inline-block; font-size: 22px; animation: tipClap .55s ease-in-out infinite alternate; }
.tip-clap:last-child { animation-delay: .18s; }
@keyframes tipClap {
  0% { transform: rotate(-9deg) scale(1); }
  100% { transform: rotate(9deg) scale(1.18); }
}
.tip-wave { display: flex; flex-wrap: wrap; gap: 8px; align-items: flex-start; justify-content: center; max-width: 96vw; }
.tip-beat-mini { padding: 8px; width: 168px; }
.tip-beat-mini .tip-star-wrap { width: 84px; height: 84px; }
.tip-beat-mini .tip-star { font-size: 60px; line-height: 84px; }
.tip-beat-mini .tip-amount { font-size: 26px; }
.tip-beat-mini .tip-from { flex-direction: column; align-items: center; padding: 10px; margin-top: 8px; }
.tip-beat-mini .tip-from-text { text-align: center; align-items: center; padding-top: 0; }
.tip-totals {
  position: relative; overflow: hidden; text-align: center;
  background: var(--panel); border: 1px solid var(--panel2); border-radius: 18px;
  padding: 30px 28px; max-width: 92vw;
  box-shadow: 0 6px 24px rgba(0, 0, 0, .4);
}
.tip-totals-star { font-size: 64px; line-height: 1.1; animation: tipStarPop .7s ease-out both; }
.tip-totals h3 { font-size: 26px; margin: 8px 0 4px; }
.tip-confetti {
  position: absolute; top: -12px; width: 9px; height: 14px; border-radius: 2px;
  animation: tipFall 2.6s linear infinite;
}
@keyframes tipFall {
  0% { transform: translateY(0) rotate(0deg); opacity: 1; }
  100% { transform: translateY(340px) rotate(340deg); opacity: .25; }
}
.tip-controls { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; margin-top: 16px; }
.tip-controls .btn { pointer-events: auto; }
.tip-controls-corner { position: fixed; top: 14px; right: 14px; margin-top: 0; }
@media (prefers-reduced-motion: reduce) {
  .tip-star, .tip-totals-star { animation: none; }
  .tip-particle { animation: none; opacity: 0; }
  .tip-clap { animation: none; }
  .tip-confetti { animation: none; opacity: 0; }
}

/* FREE banner on the welcome screen (Shane, Oct 28, 2026 — POF early-days
   style: the word FREE where a visitor can't miss it). */
.free-banner { text-align: center; margin: 0 0 14px; }
.free-badge { display: inline-block; background: #ffb020; color: #17122b; font-weight: 900; font-size: 24px; letter-spacing: .5px; border-radius: 10px; padding: 8px 20px; box-shadow: 0 4px 18px rgba(0,0,0,.35); }
.free-banner p { margin: 8px 0 0; font-weight: 800; color: #fff; text-shadow: 0 1px 8px rgba(0,0,0,.65); }
