/* Pendo, mobile first, desktop capable. One stylesheet, no framework.
 *
 * Beadwork in Pendo's own colours: bright rose, violet and gold, with blush and orchid
 * beads between and cream thread, on warm sand with a dusk sky behind the
 * art. Since the worldwide rebrand (October 2026) nothing wears the Kenyan
 * flag; html[data-look="kenya"] at the end of views.css puts the original
 * flag and shuka colours back (config LOOK=kenya).
 * There is no dark variant: it was tried and it made the product look like a
 * dashboard. Re-adding one is a single prefers-color-scheme block.
 */

:root {
  /* Pendo's palette. Every colour below is drawn from these. */
  --rose: #f72a73;
  --rose-deep: #d10f58;
  --rose-light: #ff5c93;
  --plum: #7b2fc9;           /* brightened from plum to violet */
  --gold: #ffc53d;
  --blush: #ff9ecb;
  --orchid: #b02cc4;
  --cream: #fffaf6;
  --accent-rgb: 247, 42, 115;   /* --rose, for see-through glows */
  /* The bands across the top and bottom and the bead frames, outside in. */
  --band-1: var(--plum);
  --band-2: var(--rose);
  --band-3: var(--gold);
  --band-thread: var(--cream);
  /* Question and persona cards that are not the lead colour. */
  --tone-2: var(--orchid);
  --tone-4: var(--rose-deep);
  --mark-ground: #3b0f5c;       /* behind the bead ring of the logo */
  --mark-bead: #c49bf5;         /* plum lightened, so it shows on that ground */

  /* The bead names the rest of the sheet still uses; renaming them is a
     later tidy. --bead-green is the success colour (answered, confirmed,
     done), not a bead: decorative beads use --blush in its place. */
  --shuka: var(--rose);
  --shuka-deep: var(--rose-deep);
  --bead-blue: var(--plum);
  --bead-yellow: var(--gold);
  --bead-green: #2e8b57;
  --bead-orange: var(--orchid);
  --bead-white: var(--cream);
  --earth: #3b2416;        /* red soil at dusk */
  --sand: #f3e5cf;
  --dusk-1: #f7c46c;
  --dusk-2: #e8743b;
  --dusk-3: #8f2f3f;
  --night: #2a1a2e;

  /* What the components use. */
  --bg: #f6ecdc;           /* savannah sand */
  --surface: #fffaf2;      /* bead white */
  --surface-2: #f1e2c9;
  --line: #e3cba6;
  --line-soft: #efe0c6;
  --text: #26170f;         /* warm near-black, never pure grey */
  --muted: #765c47;

  --accent: var(--shuka);
  --accent-soft: #ffe1ec;
  --accent-ink: var(--bead-white);
  --accent-grad: linear-gradient(135deg, var(--shuka) 0%, var(--bead-orange) 100%);
  --ochre: #c98a12;        /* bead yellow, deepened to hold up as text */
  --violet: var(--bead-blue);  /* the cool accent, kept under the old name */
  --ok: var(--bead-green);
  --warn: #c98a12;
  --danger: #a3201f;

  /* The page: a little dusk at the top, fading into sand. */
  --wash: linear-gradient(172deg, #fbd9a6 0%, #f8e6c8 28%, var(--bg) 60%);

  /* A row of beads: one colour per bead, cream between, repeating. */
  --beads: repeating-linear-gradient(90deg,
      var(--shuka) 0 9px, var(--bead-white) 9px 12px,
      var(--bead-blue) 12px 21px, var(--bead-white) 21px 24px,
      var(--bead-yellow) 24px 33px, var(--bead-white) 33px 36px,
      var(--blush) 36px 45px, var(--bead-white) 45px 48px,
      var(--bead-orange) 48px 57px, var(--bead-white) 57px 60px);

  /* The check: lead-colour ground, deep bands crossing. */
  --shuka-check:
      repeating-linear-gradient(0deg, rgba(123,47,201,.45) 0 6px, transparent 6px 22px),
      repeating-linear-gradient(90deg, rgba(123,47,201,.45) 0 6px, transparent 6px 22px),
      repeating-linear-gradient(0deg, rgba(20,10,10,.35) 0 2px, transparent 2px 11px),
      var(--shuka);

  /* Square. Rounded corners read as a modern consumer app; this is
     meant to look built rather than styled. */
  --radius: 0;
  --radius-lg: 0;
  --shadow: 0 1px 2px rgba(70, 45, 25, .05), 0 8px 24px rgba(70, 45, 25, .07);
  --shadow-sm: 0 1px 2px rgba(70, 45, 25, .06);

  /* A serif for anything that speaks, a sans for anything you operate.
     That pairing is what makes the thing read as considered rather than
     assembled. */
  /* Fraunces for anything that speaks, Inter for anything that labels.
     Both self-hosted, see fonts.css. The stacks behind them are the old
     system fonts, so nothing looks wrong in the moment before the files
     land or if they fail to. */
  --serif: "Fraunces", "Iowan Old Style", "Palatino Linotype", Palatino,
           Georgia, "Times New Roman", serif;
  --sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
          "Helvetica Neue", Arial, sans-serif;

  --app-w: 520px;   /* the app column on desktop */
  --header-h: 60px;
  --tab-h: 62px;
  --footer-h: 32px;
}

* { box-sizing: border-box; }

/* --- app shell -------------------------------------------------------
 * The page does not scroll. The header is pinned, the bottom bar is pinned
 * on phones, and everything between them is ONE scrolling region with a
 * bounded height, so content can never push the chrome off screen.
 */

html { height: 100%; }

body {
  margin: 0;
  height: 100dvh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--bg);
  color: var(--text);
  font: 16px/1.6 var(--sans);
  -webkit-font-smoothing: antialiased;
}

/* The bounded content area. max-height is what keeps the footer and the tab
 * bar where they belong however long the page gets. */
.viewport {
  flex: 1 1 auto;
  min-height: 0;
  /* Header, bottom nav and trademark strip are all flex:none, so this is the
     only thing that ever scrolls, and it can never push them off screen. */
  max-height: calc(100dvh - var(--header-h) - var(--tab-h) - var(--footer-h));
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  display: flex;
  flex-direction: column;
}

a { color: inherit; text-decoration: none; }

/* The hidden attribute only means display:none by way of a UA default, so
   any rule that sets display beats it. .deck-actions is display:grid, which
   is why the Pass and Introduce buttons stayed on screen after the stack ran
   out. One line, and hidden means hidden everywhere. */
[hidden] { display: none !important; }

h1, h2, h3 {
  font-family: var(--serif);
  font-optical-sizing: auto;
  font-weight: 600;
  line-height: 1.18;
  letter-spacing: -.01em;
  margin: 0 0 .55rem;
}
h1 { font-size: 1.85rem; }
h2 { font-size: 1.25rem; }
p { margin: 0 0 1rem; }

.shell { width: 100%; max-width: 640px; margin: 0 auto; padding: 18px 16px 28px; flex: 1 0 auto; }
.shell.wide { max-width: 980px; }
.muted { color: var(--muted); }
.small { font-size: .85rem; }
.center { text-align: center; }
.inline { display: inline; }
.stack > * + * { margin-top: 12px; }
.row { display: flex; gap: 10px; align-items: center; }
.row.wrap { flex-wrap: wrap; }
.spread { justify-content: space-between; }
.grow { flex: 1; min-width: 0; }

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

.site-header {
  position: relative;
  flex: none;
  height: var(--header-h);
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 0 16px;
  background: var(--surface);
  border-bottom: 1px solid var(--line);
  z-index: 40;
}

/* A plain divider. */
.rule { height: 1px; border: 0; margin: 20px 0; background: var(--line); }

.brand { display: flex; align-items: center; gap: 8px; font-weight: 750;
         letter-spacing: -.03em; font-size: 1.12rem; }
.brand-mark { font-size: 1.1rem; line-height: 1; }

.header-actions { display: flex; align-items: center; gap: 12px; margin-left: auto; }

.icon-btn {
  position: relative; display: grid; place-items: center;
  width: 38px; height: 38px; border-radius: 0;
  background: var(--surface-2); color: var(--muted); font-size: 1rem;
}
.icon-btn:hover { color: var(--accent); }
.icon-btn .badge {
  position: absolute; top: -3px; right: -3px;
  min-width: 18px; height: 18px; padding: 0 5px; font-size: .66rem;
}



/* --- bottom bar (phones) ---------------------------------------------- */

.tabbar {
  flex: none;
  /* Six now that membership has a tab. On a 360px phone that is 60px each,
     which fits the short labels but leaves nothing spare, so the label size
     steps down on the narrowest screens rather than wrapping or clipping. */
  display: grid; grid-template-columns: repeat(6, 1fr);
  padding-bottom: 0;
  background: var(--surface);
  border-top: 1px solid var(--line);
  padding-bottom: env(safe-area-inset-bottom);
  z-index: 40;
}
.tabbar a {
  position: relative;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 3px; height: var(--tab-h); color: var(--muted);
  font-size: .66rem; font-weight: 600; letter-spacing: .02em;
}
.tabbar.guest { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 380px) {
  .tabbar a { font-size: .60rem; letter-spacing: 0; }
  .tabbar .ico { font-size: 1rem; }
}
.tabbar a.on { color: var(--accent); }
.tabbar .ico { font-size: 1.1rem; line-height: 1; }

/* --- footer: trademark only, always visible --------------------------- */

.site-footer {
  position: relative;
  flex: none;
  height: calc(var(--footer-h) + env(safe-area-inset-bottom));
  padding-bottom: env(safe-area-inset-bottom);
  display: flex; align-items: center; justify-content: center; gap: 10px;
  background: var(--surface-2);
  border-top: 1px solid var(--line);
  font-size: .72rem; color: var(--muted);
}
.site-footer .mark { font-weight: 700; letter-spacing: .02em; color: var(--text); }
.site-footer .tm { opacity: .75; }

/* --- the floating privacy flag ---------------------------------------- */

.privacy-flag {
  position: fixed; right: 12px; z-index: 45;
  bottom: calc(var(--tab-h) + var(--footer-h) + env(safe-area-inset-bottom) + 10px);
  display: inline-flex; align-items: center; gap: 7px;
  padding: 8px 13px; border-radius: 0;
  background: var(--surface); border: 1px solid var(--accent);
  color: var(--accent); font-size: .75rem; font-weight: 700;
  box-shadow: var(--shadow);
}
.privacy-flag:hover { background: var(--accent-soft); }
.privacy-flag .flag-ico { font-size: .85rem; line-height: 1; }

@media (max-width: 380px) {
  .privacy-flag .flag-text { display: none; }
  .privacy-flag { padding: 9px; }
}

/* --- surfaces -------------------------------------------------------- */

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 0;
  padding: 22px 20px;
  box-shadow: none;
}
.card + .card { margin-top: 14px; }

.pill {
  display: inline-block; padding: 5px 11px; border-radius: 0;
  background: transparent; border: 1px solid var(--line);
  font-size: .7rem; font-weight: 700; color: var(--muted);
  letter-spacing: .06em; text-transform: uppercase;
}
.pill.accent { background: rgba(255, 92, 122, .12); border-color: rgba(255, 92, 122, .35); color: var(--accent); }
.pill.ok { background: rgba(61, 220, 151, .12); border-color: rgba(61, 220, 151, .3); color: var(--ok); }

/* --- forms ----------------------------------------------------------- */

label {
  display: block; margin-bottom: 8px;
  font-size: .72rem; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase;
  color: var(--muted);
}
.field + .field { margin-top: 14px; }

input[type="text"], input[type="email"], input[type="password"], input[type="date"],
input[type="number"], input[type="tel"], select, textarea {
  width: 100%; padding: 13px 14px; font: inherit; color: var(--text);
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 0; outline: none;
  transition: border-color .12s ease;
}
textarea { min-height: 96px; resize: vertical; }
input:focus, select:focus, textarea:focus {
  border-color: var(--accent);
  box-shadow: inset 0 0 0 1px var(--accent);
}

.hp { position: absolute; left: -9999px; width: 1px; height: 1px; opacity: 0; }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 13px 22px; min-height: 48px; border-radius: 0;
  border: 1px solid var(--text); background: transparent; color: var(--text);
  font: inherit; font-size: .82rem; font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase;
  cursor: pointer; text-align: center;
  transition: background .12s ease, color .12s ease, border-color .12s ease;
}
.btn:hover { background: var(--text); color: var(--surface); }
.btn.primary { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }
.btn.primary:hover { filter: brightness(.92); background: var(--accent); color: var(--accent-ink); }
.btn.ghost { border-color: var(--line); color: var(--muted); }
.btn.danger { color: var(--danger); border-color: rgba(255, 107, 107, .4); }
.btn.block { display: flex; width: 100%; }
.btn.small { padding: 8px 15px; min-height: 0; font-size: .88rem; border-radius: 0; }
.btn:disabled { opacity: .5; cursor: not-allowed; }
.linkish { background: none; border: 0; color: var(--muted); font: inherit; cursor: pointer; padding: 0; }
.linkish:hover { color: var(--text); }

.choices { display: flex; flex-wrap: wrap; gap: 8px; }
.choices input { position: absolute; opacity: 0; pointer-events: none; }
.choices label {
  margin: 0; padding: 10px 15px; border-radius: 0; cursor: pointer;
  background: transparent; border: 1px solid var(--line);
  font-size: .86rem; font-weight: 600; color: var(--text);
  letter-spacing: 0; text-transform: none;
  transition: border-color .12s ease, background .12s ease;
}
.choices input:checked + label {
  background: var(--accent); border-color: var(--accent); color: var(--accent-ink);
}
.choices label:hover { border-color: var(--text); }
.choices input:focus-visible + label { outline: 2px solid var(--violet); outline-offset: 2px; }

/* --- flashes --------------------------------------------------------- */

.flash {
  padding: 12px 14px; border-radius: 0; margin-bottom: 12px;
  border: 1px solid var(--line); background: var(--surface); font-size: .92rem;
}
.flash.error { border-color: rgba(255, 107, 107, .45); background: rgba(255, 107, 107, .1); }
.flash.success { border-color: rgba(61, 220, 151, .4); background: rgba(61, 220, 151, .1); }
.flash.paywall { border-color: rgba(255, 176, 87, .45); background: rgba(255, 176, 87, .1); }

/* --- discovery (faceless by design) ---------------------------------- */

.deck { position: relative; }
.profile-card { position: relative; overflow: hidden; }
.profile-card .who { display: flex; align-items: baseline; gap: 8px; }
.profile-card .who h2 { margin: 0; }
.profile-card .reasons { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 12px; }
.profile-card .bio { margin: 12px 0 0; color: var(--muted); }
.veil-note {
  margin-top: 14px; padding: 10px 12px; border-radius: 0;
  background: var(--surface-2); border: 1px dashed var(--line);
  font-size: .8rem; color: var(--muted);
}
.deck-actions { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-top: 14px; }

.empty { text-align: center; padding: 48px 16px; color: var(--muted); }
.empty .big { font-size: 2.5rem; margin-bottom: 10px; }

/* --- chat ------------------------------------------------------------ */

.thread-head {
  position: sticky; top: 0; z-index: 20;
  display: flex; align-items: center; gap: 12px;
  padding: 12px 16px; background: var(--surface); border-bottom: 1px solid var(--line);
}

.stage-banner {
  margin: 14px 0; padding: 16px; border-radius: 0;
  background: linear-gradient(160deg, rgba(139, 123, 255, .16), rgba(255, 92, 122, .12));
  border: 1px solid var(--line);
}
.stage-banner h3 { margin: 0 0 6px; font-size: 1.05rem; }
.stage-banner p { margin: 0; color: var(--muted); font-size: .9rem; }

/* The old two-dot progress bar for the photo exchange lived here. It was
   removed with that flow, but its `.step` rule survived and collided with the
   landing page's `.card step` blocks, pinning each of them to 4px tall. */

.msgs { display: flex; flex-direction: column; gap: 8px; padding: 14px 0; }
.msg { max-width: 78%; padding: 10px 14px; border-radius: 0; background: var(--surface-2); }
.msg.mine { align-self: flex-end; background: var(--accent); color: var(--accent-ink); }
.msg .meta { font-size: .68rem; opacity: .7; margin-top: 4px; text-align: right; }
.msg.photo { padding: 6px; background: var(--surface-2); }
.msg.photo.mine { background: rgba(255, 92, 122, .22); }
.msg .gone { padding: 14px; font-size: .85rem; color: var(--muted); font-style: italic; }

/* Shared photos: no save affordances anywhere. */
.shot {
  display: block; max-width: 240px; width: 100%; border-radius: 0;
  -webkit-user-select: none; user-select: none;
  -webkit-user-drag: none; -webkit-touch-callout: none;
  pointer-events: none;
}
.shot-wrap { position: relative; }
.shot-wrap::after { content: ""; position: absolute; inset: 0; }

body.blurred .shot { filter: blur(22px); transition: filter .12s; }

.composer {
  position: sticky; bottom: 0; z-index: 35;
  display: flex; gap: 8px; align-items: flex-end;
  margin: 0 -16px -28px; padding: 10px 14px 14px;
  background: var(--surface); border-top: 1px solid var(--line);
}
.composer textarea {
  min-height: 44px; max-height: 120px; padding: 11px 14px; border-radius: 0;
}
.composer .btn { min-height: 44px; padding: 11px 16px; border-radius: 0; }
.typing { font-size: .78rem; color: var(--muted); padding: 0 16px 6px; height: 18px; }

.msgs { padding-bottom: 14px; }

/* --- the question, once you have both seen each other --------------------
   This is the single most important screen in the app, so it gets room and
   a clear order: what has happened, what is being asked, the two answers,
   then the consequence.

   The class name .decide used to be a two-column grid for a pair of buttons
   from the original flow. Applied to the whole panel it split the heading
   and the explanation into columns, which is how a plain question turned
   into a jumble. */

.decide, .decide-wait {
  display: block;
  margin-top: 16px;
  padding: 22px 18px;
  text-align: center;
}

.decide {
  background: var(--accent-soft);
  border: 1px solid var(--accent);
  border-top: 3px solid var(--accent);
}

.decide h3, .decide-wait h3 {
  margin: 0 0 8px;
  font-size: 1.3rem;
  line-height: 1.25;
}

.decide > p, .decide-wait > p {
  margin: 0 auto;
  max-width: 30rem;
  font-size: .92rem;
  line-height: 1.55;
}

/* The two answers. Side by side where there is room, stacked where there is
   not, and never so close together that a thumb hits the wrong one. */
.decide-actions {
  display: grid;
  gap: 10px;
  margin: 20px auto 0;
  max-width: 26rem;
}
@media (min-width: 420px) {
  .decide-actions { grid-template-columns: 1fr 1fr; }
}
.decide-actions .btn {
  min-height: 52px;
  font-size: .95rem;
}

/* Yes is the affirmative one and looks it. No is plain with a red word, so
   it is unmistakable but never the thing your thumb lands on by accident. */
.decide-actions .btn.danger {
  background: var(--surface);
  border-color: var(--line);
  color: var(--danger);
}
.decide-actions .btn.danger:hover {
  border-color: var(--danger);
  background: rgba(255, 107, 107, .08);
}

/* Waiting on the other person. Quiet, because there is nothing to do. */
.decide-wait {
  background: var(--surface-2);
  border: 1px solid var(--line);
}
.decide-wait h3 { color: var(--ok); }

.paywall-banner {
  background: var(--accent-soft);
  border: 1px solid var(--accent);
  border-top: 3px solid var(--accent);
  padding: 20px 18px;
}

/* --- lists ----------------------------------------------------------- */

.list-item {
  display: flex; gap: 12px; align-items: center; padding: 14px;
  border: 1px solid var(--line); border-radius: 0;
  background: var(--surface);
}
.list-item + .list-item { margin-top: 10px; }
.list-item .avatar,
.list-item .face {
  width: 46px; height: 46px; flex: none;
}
.badge {
  min-width: 22px; height: 22px; padding: 0 7px; border-radius: 0;
  background: var(--accent); color: var(--accent-ink);
  font-size: .72rem; font-weight: 700; display: grid; place-items: center;
}

/* --- pricing --------------------------------------------------------- */

.plans { display: grid; gap: 12px; }
@media (min-width: 620px) { .plans { grid-template-columns: 1fr 1fr; } }
.plan { position: relative; }
.plan.featured { border-color: var(--accent); }
.plan .price { font-size: 2.1rem; font-weight: 750; letter-spacing: -.03em; }
.plan .per { color: var(--muted); font-size: .9rem; }

.locked { text-align: center; padding: 36px 20px; }
.locked .count { font-size: 3.4rem; font-weight: 750; color: var(--accent); line-height: 1; }

/* --- landing --------------------------------------------------------- */


/* --- search bar ------------------------------------------------------ */

.finder {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 0; margin-bottom: 14px; overflow: hidden;
}
.finder > summary {
  display: flex; align-items: center; gap: 10px; padding: 14px 16px;
  cursor: pointer; font-weight: 600; list-style: none;
}
.finder > summary::-webkit-details-marker { display: none; }
.finder-body { padding: 0 16px 16px; }

/* --- drip question --------------------------------------------------- */

.quiz { border-color: var(--violet); }
.quiz .choices .btn { padding: 9px 14px; min-height: 0; border-radius: 0; font-size: .88rem; }

.progress {
  height: 6px; border-radius: 0; background: var(--surface-2);
  overflow: hidden; margin: 10px 0 16px;
}
.progress span { display: block; height: 100%; background: var(--accent); }

.answers,
.facts {
  display: grid;
  grid-template-columns: minmax(7rem, auto) 1fr;
  margin: 16px 0 0;
  text-align: left;
  border-top: 1px solid var(--line);
}
.answers dt,
.facts dt,
.answers dd,
.facts dd {
  margin: 0;                       /* dd is indented 40px by default */
  padding: 9px 0;
  border-bottom: 1px solid var(--line-soft);
  min-width: 0;
}
.answers dt,
.facts dt {
  font-size: .7rem; font-weight: 700; letter-spacing: .07em;
  text-transform: uppercase; color: var(--muted);
  padding-right: 14px; align-self: center;
}
.answers dd,
.facts dd {
  font-family: var(--serif); font-size: .98rem; color: var(--text);
  text-align: right;
}

.badge.inline { display: inline-grid; vertical-align: middle; }
.tabbar .dot {
  position: absolute; margin: -16px 0 0 16px; width: 7px; height: 7px;
  border-radius: 0; background: var(--accent);
}
.tabbar.five { grid-template-columns: repeat(5, 1fr); }
.tabbar a { position: relative; }

/* --- admin ----------------------------------------------------------- */

.admin-head { margin-bottom: 16px; }
.admin-hub-back { display: inline-block; margin-bottom: 6px; font-size: .85rem; color: var(--muted); }
.admin-hub-back:hover { color: var(--accent); }
.admin-nav { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.admin-nav a {
  padding: 8px 14px; border-radius: 0; font-size: .88rem; font-weight: 600;
  background: var(--surface); border: 1px solid var(--line); color: var(--muted);
}
.admin-nav a.on { background: var(--accent); border-color: var(--accent); color: var(--accent-ink); }

.tiles { display: grid; gap: 12px; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); }
.tile {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: 0; padding: 16px; display: flex; flex-direction: column; gap: 4px;
}
.tile .k { font-size: .78rem; color: var(--muted); font-weight: 600; text-transform: uppercase;
           letter-spacing: .04em; }
.tile .v { font-size: 1.9rem; font-weight: 750; letter-spacing: -.03em; line-height: 1.1; }
.tile .s { font-size: .78rem; color: var(--muted); }

.cols { display: grid; gap: 14px; margin-top: 14px; }
@media (min-width: 820px) { .cols { grid-template-columns: 1fr 1fr; } }

.bars { display: flex; align-items: flex-end; gap: 4px; height: 110px; margin-top: 12px; }
.bar { flex: 1; display: flex; flex-direction: column; justify-content: flex-end;
       align-items: center; height: 100%; gap: 4px; }
.bar > span { width: 100%; min-height: 2px; background: var(--accent); border-radius: 0; }
.bar.alt > span { background: var(--violet); }
.bar > em { font-size: .62rem; color: var(--muted); font-style: normal; }

.grid { width: 100%; border-collapse: collapse; font-size: .9rem; }
.grid th { text-align: left; font-size: .72rem; text-transform: uppercase; letter-spacing: .05em;
           color: var(--muted); padding: 10px 12px; border-bottom: 1px solid var(--line); }
.grid td { padding: 9px 12px; border-bottom: 1px solid var(--line); }
.grid tr:last-child td { border-bottom: 0; }
.grid td.num,
.grid th.num { text-align: right; font-variant-numeric: tabular-nums; }
.grid.rows tbody tr:hover { background: var(--surface-2); }
.grid a { color: var(--accent); }
/* A group heading inside a table (Admin > Security: "Copying the site"...):
   small capitals like the column heads, with room above to start a section. */
.grid tr.group td { font-size: .72rem; font-weight: 700; text-transform: uppercase;
                    letter-spacing: .05em; color: var(--muted); padding-top: 16px; }
.grid.rows tbody tr.group:hover { background: none; }

.meter { height: 8px; border-radius: 0; background: var(--surface-2); overflow: hidden; }
.meter span { display: block; height: 100%; background: var(--violet); }

.pill.danger { background: rgba(255, 107, 107, .12); border-color: rgba(255, 107, 107, .4); color: var(--danger); }
.right { text-align: right; }

/* --- personas -------------------------------------------------------- */

.face {
  flex: none; width: 52px; height: 52px; border-radius: 0;
  display: grid; place-items: center; font-size: 1.6rem; line-height: 1;
  box-shadow: inset 0 -6px 14px rgba(0, 0, 0, .18);
}
.card-face { width: 62px; height: 62px; font-size: 2rem; }

.personas { display: grid; gap: 10px; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
            margin-bottom: 16px; }
.personas input { position: absolute; opacity: 0; pointer-events: none; }
.persona {
  margin: 0; display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 16px 12px; text-align: center; cursor: pointer;
  background: var(--surface); border: 1px solid var(--line); border-radius: 0;
}
.persona strong { font-size: .92rem; }
.persona em { font-style: normal; font-size: .74rem; color: var(--muted); line-height: 1.35; }
.personas input:checked + .persona {
  border-color: var(--accent); background: rgba(255, 92, 122, .08);
}
.personas input:focus-visible + .persona { outline: 2px solid var(--violet); outline-offset: 2px; }

.groups {
  display: grid; gap: 10px; margin-bottom: 14px;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
}
.group + .group { margin-top: 0; }


/* --- one theme for everybody ----------------------------------------------
 * The page wears the dusk wash from :root (views.css gives women and men
 * their own page backgrounds on top), and the main button is rose running
 * into orchid.
 *
 * --wash is the page itself, not a glow at the top. It sits on the scroll
 * region, which does not move with its content, so the gradient stays put
 * while the page scrolls over it. Cards and bars stay bead white, which is
 * what keeps the text on them readable.
 */

html[data-gender] .viewport {
  background-color: var(--bg);
  background-image: var(--wash);
  background-repeat: no-repeat;
  background-size: 100% 100%;
}

/* On a desktop the page outside the app column wears the same colour. */
html[data-gender] { background: var(--wash) no-repeat fixed, var(--bg); }

html[data-gender] .btn.primary {
  background: var(--accent-grad);
  border-color: transparent;
}

/* --- app column: PWA-shaped, centred ----------------------------------
 * On a phone this is full bleed. On a desktop the whole app, header, the
 * scroll region, the bottom nav and the trademark strip, is one centred
 * column, so it reads as the app it is rather than a stretched web page.
 */

html { background: var(--bg); }

@media (min-width: 760px) {
  body {
    max-width: var(--app-w);
    margin-inline: auto;
    border-inline: 1px solid var(--line);
    box-shadow: var(--shadow);
  }
  /* The admin dashboard is the one screen that genuinely needs the width.
     A class rather than body:has(.shell.wide): a :has() on body makes the
     browser re-check the whole page on every change, and views change in
     place now (nav.js), so that was paid on every tap. */
  body.no-app { max-width: 1060px; }
}

.shell { max-width: var(--app-w); }
.shell.wide { max-width: 1020px; }

/* --- centred content --------------------------------------------------- */

.center { text-align: center; }
.center .row.wrap,
.center .choices { justify-content: center; }
.center .lede { margin-inline: auto; }
.center ul { text-align: left; display: inline-block; }

.cta { display: grid; gap: 10px; margin: 20px 0 14px; }

/* --- illustrations ------------------------------------------------------ */

.art-frame {
  width: 100%;
  margin: 0 auto 18px;
  border: 1px solid var(--line);
  background: var(--surface-2);
  overflow: hidden;
}
.art-frame.small { max-width: 300px; }
.art { display: block; width: 100%; height: auto; }

.step { padding-top: 22px; }
.step-n {
  display: inline-block; margin-bottom: 6px;
  font-size: .68rem; font-weight: 800; letter-spacing: .16em;
  text-transform: uppercase; color: var(--accent);
}
.step h3 { margin: 0 0 8px; font-size: 1.1rem; }

.hero { padding: 8px 0 4px; }
.hero h1 { font-size: clamp(1.75rem, 6.5vw, 2.4rem); margin-bottom: 10px; }
.hero .lede {
  font-family: var(--serif); font-size: 1.12rem; line-height: 1.6;
  color: var(--muted); max-width: 40ch;
}

/* --- introductions ------------------------------------------------------ */

.intro-grid {
  display: grid; gap: 8px; grid-template-columns: repeat(2, 1fr);
  margin-bottom: 14px;
}
.intro-grid .shot-wrap { aspect-ratio: 3 / 4; overflow: hidden; }
.intro-grid .shot { width: 100%; height: 100%; object-fit: cover; max-width: none; }

.intro-note {
  margin: 0 0 12px; padding: 12px 14px;
  background: var(--surface-2); border-left: 3px solid var(--accent);
  font-size: .95rem; text-align: left;
}

/* --- the discovery card -------------------------------------------------
 * The head is centred, because it is somebody's face and name. Everything
 * below it is left aligned and sectioned, because it is information to read
 * rather than a poster to look at. The old card centred all of it, which
 * turned a dozen facts into one ragged column with no order to it.
 */

.profile-card { text-align: left; }
.profile-card .reasons { justify-content: flex-start; }

.card-head {
  display: flex; flex-direction: column; align-items: center;
  text-align: center; gap: 6px;
  padding-bottom: 16px; border-bottom: 1px solid var(--line);
}

.avatar {
  display: block; flex: none;
  object-fit: cover; border: 1px solid var(--line);
  background: var(--surface-2); border-radius: 0;
}
.avatar.card-avatar { width: 112px; height: 112px; margin-bottom: 4px; }
/* A block element ignores text-align, so an avatar dropped into a centred
   card sat against the left edge. Centre it the way a block has to be. */
.card.center > .avatar,
.center > .avatar { margin-inline: auto; }

.card-name {
  margin: 0; font-family: var(--serif); font-size: 1.5rem; line-height: 1.2;
}
.card-name .age {
  font-family: var(--sans); font-size: .95rem; font-weight: 400;
  color: var(--muted); margin-left: 4px;
}

/* The score, directly under the name. It is the only thing on this card
   that describes the two of you rather than them, so it gets the weight. */
/* The score is the point of the card. It gets a band of its own, full
   width, so it reads as the headline rather than as one more line of type
   among a dozen. */
.score {
  display: flex; flex-direction: column; align-items: center; gap: 0;
  align-self: stretch; margin: 12px 0 6px; padding: 12px 10px;
  background: var(--accent-soft);
  border-top: 2px solid var(--accent);
  border-bottom: 1px solid var(--line);
}
.score-figure {
  font-family: var(--serif); font-size: 3rem; font-weight: 700;
  line-height: 1; color: var(--accent);
}
.score-what {
  font-size: .72rem; font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; color: var(--muted); margin-top: 6px;
  text-align: center;
}
.score.full {
  background: rgba(61, 220, 151, .1);
  border-top-color: var(--ok);
}
.score.full .score-figure,
.score.full .score-what { color: var(--ok); }

/* Nothing asked for yet, so nothing to score. Saying so is better than
   printing 100% of nothing. */
.score.none {
  background: var(--surface-2); border-top-color: var(--line);
  gap: 6px;
}
.score-set {
  font-size: .85rem; font-weight: 600; color: var(--accent);
  text-decoration: underline;
}

.persona-line { margin: 2px 0 0; color: var(--muted); font-size: .92rem; }

/* intent, city, distance: one quiet line, not three competing pills */
.meta-line {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: 0 8px; margin: 8px 0 0; padding: 0; list-style: none;
  font-size: .78rem; font-weight: 600; letter-spacing: .04em;
  text-transform: uppercase; color: var(--muted);
}
.meta-line li + li::before { content: "\00b7"; margin-right: 8px; }
.meta-line .want { color: var(--accent); }

.profile-card .bio {
  margin: 16px 0 0; font-family: var(--serif); font-size: 1.06rem;
  line-height: 1.6; color: var(--text); text-align: center;
}

/* --- card sections ------------------------------------------------------ */

.card-block { margin-top: 20px; }
.block-head {
  margin: 0 0 10px; font-size: .7rem; font-weight: 700; letter-spacing: .1em;
  text-transform: uppercase; color: var(--muted);
  padding-bottom: 6px; border-bottom: 1px solid var(--line-soft);
  text-align: center;
}

/* Centred, because a wrapped row of chips left-aligned leaves a ragged
   gap on the last line that reads as a mistake. */
.chips { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; }
.chip {
  display: inline-block; padding: 5px 10px; border-radius: 0;
  background: var(--surface-2); border: 1px solid var(--line);
  font-size: .8rem; color: var(--text);
}
.chip.accent {
  background: var(--accent-soft); border-color: var(--accent);
  color: var(--accent); font-weight: 600;
}

/* --- you want / they said ----------------------------------------------- */

.all-matched {
  margin: 0 0 12px; padding: 10px 12px;
  background: var(--surface-2); border-left: 3px solid var(--ok);
  font-size: .9rem; color: var(--text);
}

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

.cmp {
  display: grid; gap: 4px;
  padding: 10px 0 10px 12px;
  border-bottom: 1px solid var(--line-soft);
  border-left: 3px solid transparent;
}
.cmp:last-child { border-bottom: 0; }
.cmp.yes { border-left-color: var(--ok); }
.cmp.near { border-left-color: var(--ochre); }
.cmp.no { border-left-color: var(--accent); background: var(--accent-soft); }

.cmp-label {
  font-size: .7rem; font-weight: 700; letter-spacing: .07em;
  text-transform: uppercase; color: var(--muted);
}
.cmp-agreed { font-family: var(--serif); font-size: .98rem; color: var(--text); }

/* A miss is shown as the two answers side by side, so the disagreement is
   the thing you read rather than something to work out. */
.cmp-split { display: grid; gap: 6px; }
.cmp-side {
  display: grid; gap: 1px;
  font-family: var(--serif); font-size: .96rem; color: var(--text);
}
.cmp-side b {
  font-family: var(--sans); font-size: .64rem; font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase; color: var(--muted);
}
.cmp-side.them b { color: var(--accent); }

@media (min-width: 420px) {
  .cmp-split { grid-template-columns: 1fr 1fr; gap: 12px; }
}



/* --- scenario group cards ---------------------------------------------- */

/* The art used to be a watermark behind the text: absolutely positioned,
   22% opacity, with 96px of right padding reserved for it. On a phone that
   left about 130px for the name, so "Taking it slow" rendered as "Taking
   it" and every tile looked like the same faint smudge. It leads now. */
.group {
  display: flex; flex-direction: column; gap: 0;
  padding: 0; overflow: hidden;
}
.group.mine { border-color: var(--accent); }
.group-art-wrap {
  display: block; width: 100%; height: 108px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--line);
  pointer-events: none;
}
.group-art { width: 100%; height: 100%; display: block; padding: 12px; }
.group.mine .group-art-wrap { background: var(--accent-soft); }

.group-body {
  display: flex; flex-direction: column; gap: 4px;
  padding: 12px 14px 14px;
}
.group-name {
  font-family: var(--serif); font-size: 1.02rem; line-height: 1.25;
  color: var(--text);
  /* The names are short phrases, so let them wrap rather than clip. */
  overflow-wrap: break-word;
}
.group-blurb {
  font-size: .8rem; line-height: 1.45; color: var(--muted);
}
.group-foot { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.chip.ok {
  background: rgba(61, 220, 151, .12); border-color: rgba(61, 220, 151, .4);
  color: var(--ok); font-weight: 600;
}

@media (max-width: 420px) {
  .group { padding-right: 76px; }
  .group-art-wrap { width: 84px; height: 58px; }
}

.personas.compact { grid-template-columns: repeat(auto-fit, minmax(104px, 1fr)); gap: 8px; }
.personas.compact .persona { padding: 10px 6px; gap: 4px; }
.personas.compact .persona strong { font-size: .74rem; }
.personas.compact .face { width: 40px; height: 40px; font-size: 1.2rem; }

/* The one decision that shapes everything else gets a little more room. */
.seeking-field {
  padding: 14px; background: var(--surface-2); border: 1px solid var(--line);
}
.seeking-field > label:first-child { font-size: .95rem; }

/* The search box is age and distance only, who you meet is set at signup. */
.finder-body .row { align-items: flex-end; }

/* The panel had every gap collapsed, so the Load button sat directly on the
   distance box and the two links underneath ran into each other. Give it a
   rhythm: fields apart, the action clear of them, the links clear of that. */
.finder-body .field + .field { margin-top: 16px; }
.finder-body .field:first-child { margin-top: 0; }
.finder-body .btn.primary { margin-top: 20px; }
.finder-body p.small { line-height: 1.6; }
.finder-body p.small + p.small { margin-top: 10px !important; }
.finder-body p.small:last-child { padding-bottom: 4px; }

/* --- alignment and rhythm ---------------------------------------------- */

/* Paired inputs: an age range or a number with its unit. One label above the
   pair, never one per input, three labels in a flex row was what collided. */
.pair { display: flex; align-items: center; gap: 10px; }
.pair input { flex: 1; min-width: 0; text-align: center; }
.pair-sep { flex: none; color: var(--muted); font-size: .85rem; font-weight: 600; }

/* A field row, when one is genuinely needed, aligns on the input baseline
   rather than the middle, labels of different lengths wrap otherwise. */
.row > .field { margin-top: 0; }
.finder-body .row { align-items: flex-end; }
.finder-body .field + .field { margin-top: 14px; }

.finder > summary {
  gap: 12px;
  border-bottom: 1px solid transparent;
}
.finder[open] > summary { border-bottom-color: var(--line); }
.finder > summary .grow { font-size: .95rem; }
.finder-body { padding-top: 16px; }

/* Consistent vertical rhythm between the stacked cards. */
.shell > * + * { margin-top: 14px; }
.shell > h1.shell > h2 { margin-top: 22px; }
.shell > .flash + * { margin-top: 14px; }

.card > h2:first-child.card > h3:first-child { margin-top: 0; }
.card p:last-child { margin-bottom: 0; }

/* The empty state should sit in the middle of the space it has, not float. */
.empty { padding: 56px 20px; }
.empty .big { opacity: .5; }
.empty h2 { margin-bottom: 8px; }
.empty p { max-width: 34ch; margin-inline: auto; }

/* Pills and chips line up on a shared baseline wherever they wrap. */
.row.wrap { row-gap: 8px; }
.choices { row-gap: 8px; }

/* Buttons in a pair get equal weight and equal width. */
.deck-actions { gap: 10px; }
.deck-actions .btn { width: 100%; }

/* --- photo picker ------------------------------------------------------- */

.picker { margin: 4px 0 0; }
.picker-label {
  margin: 0 0 10px; font-size: .72rem; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase; color: var(--muted);
}

/* --- the photo picker ---------------------------------------------------
   One grid. Your photos, anything you just added, and the add tile, all the
   same size and all in the same place. It used to be a grid, then a large
   dashed dropzone, then a second grid, which split somebody's pictures
   either side of the middle of the screen. */

.picker-grid {
  display: grid; gap: 8px; margin-bottom: 14px;
  grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
  align-items: start;
}

.picker-cell { position: relative; }

.picker-tile {
  position: relative; display: block; margin: 0; padding: 0; cursor: pointer;
  aspect-ratio: 3 / 4; overflow: hidden;
  border: 2px solid var(--line); background: var(--surface-2);
  transition: border-color .12s ease;
}
.picker-tile img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  -webkit-user-drag: none; user-select: none;
}
.picker-tile .tick {
  position: absolute; inset: auto 5px 5px auto;
  width: 26px; height: 26px; display: grid; place-items: center;
  background: var(--accent); color: #fff;
  font-size: .85rem; font-weight: 700;
  opacity: 0; transform: scale(.7); transition: all .12s ease;
}
.picker-tile:hover { border-color: var(--muted); }

/* Chosen: a thick accent border and the tick. Deliberately loud, because
   "which two am I sending" is the only question this screen asks. */
[data-lib]:checked + .picker-tile,
.picker-tile.chosen { border-color: var(--accent); }
[data-lib]:checked + .picker-tile .tick,
.picker-tile.chosen .tick { opacity: 1; transform: scale(1); }
[data-lib]:focus-visible + .picker-tile {
  outline: 2px solid var(--violet); outline-offset: 2px;
}

/* The x. Small, top corner, opposite the tick so they never overlap. */
.tile-remove {
  position: absolute; top: -6px; right: -6px; z-index: 2;
  width: 24px; height: 24px; padding: 0; line-height: 1;
  display: grid; place-items: center; cursor: pointer;
  background: var(--surface); color: var(--muted);
  border: 1px solid var(--line); border-radius: 0;
  font-size: 1rem; font-weight: 700;
}
.tile-remove:hover {
  background: var(--danger); color: #fff; border-color: var(--danger);
}
.tile-remove[disabled] { opacity: .4; cursor: default; }

/* The add tile is a cell like any other, so the grid stays even. */
.picker-add {
  display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 4px;
  aspect-ratio: 3 / 4; padding: 6px; cursor: pointer;
  background: var(--surface-2); color: var(--muted);
  border: 2px dashed var(--line); border-radius: 0;
  transition: border-color .12s ease, background .12s ease, color .12s ease;
}
.picker-add:hover,
.picker-add:focus-visible,
.picker-add.over {
  border-color: var(--accent); background: var(--accent-soft);
  color: var(--accent); outline: none;
}
.picker-add .add-ico { font-size: 1.6rem; line-height: 1; }
.picker-add .add-word {
  font-size: .7rem; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; text-align: center;
}

.picker-note { margin: 0; }

.preview-tile img { width: 100%; height: 100%; object-fit: cover; display: block; }

.picker-count {
  margin: 14px 0 6px; text-align: center;
  font-size: .72rem; font-weight: 700; letter-spacing: .09em;
  text-transform: uppercase; color: var(--muted);
}
.picker-count.ok { color: var(--ok); }
.picker-count.over { color: var(--danger); }

/* --- answer rows: the icon column -------------------------------------- */

.answers dt .ico,
.facts dt .ico {
  display: inline-block; width: 1.35em; margin-right: .4em;
  font-size: .95rem; text-align: center;
  filter: saturate(.85);
}

/* --- centred image grids ------------------------------------------------
   auto-fill left-aligns a short final row; centring the tracks keeps two
   photos in the middle of the card instead of hugging the left edge. */

/* The two photos of a sent introduction, side by side and centred. */
.intro-grid {
  justify-content: center;
  justify-items: center;
  margin-inline: auto;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  max-width: 380px;
}
.intro-grid .shot-wrap { width: 100%; }

/* The picker deliberately does NOT get auto-fit or a centred track list.
   auto-fit collapses empty tracks, so a member with one photo saw a single
   tile floating in the middle of the screen rather than the start of a
   grid. It fills from the left, like a photo roll. */

.shot-wrap { margin-inline: auto; }
.msg .shot-wrap { margin-inline: 0; }
.shot { margin-inline: auto; }

/* --- artwork containment ------------------------------------------------
   An inline SVG with no intrinsic size can spill out of its card if a
   stylesheet arrives half-applied. Pinning the box and the ratio means the
   layout holds even then. */

.art-frame { display: block; position: relative; overflow: hidden; line-height: 0; }
.art { display: block; width: 100%; height: auto; }
.art-hero { aspect-ratio: 4 / 3; }
.art-frame.small .art { aspect-ratio: 24 / 17; }

.card, .step { position: relative; overflow: hidden; }
.card::after { content: ""; display: table; clear: both; }

/* The card carries the spacing, so the artwork inside never adds its own. */
.step .art-frame { margin-bottom: 16px; }
.hero .art-frame { margin-bottom: 20px; }

/* --- location picker (see the place picker below) ------------------ */

#move-banner .row { margin-top: 4px; }
#move-banner form { margin: 0; }

/* --- locked photos ------------------------------------------------------ */

.locked-shot {
  display: grid; place-items: center;
  background: repeating-linear-gradient(
    45deg, var(--surface-2) 0 10px, var(--line-soft) 10px 20px);
  border: 1px solid var(--line);
}
.locked-shot .lock { font-size: 1.5rem; opacity: .55; }
.locked-grid { margin-bottom: 14px; }

/* --- payment rails ------------------------------------------------------ */

.rails { margin-top: 16px; display: grid; gap: 4px; }
.rails .btn { margin-top: 6px; }
.rail-note { margin: 0 0 6px; font-size: .74rem; }
.plan .price { font-size: 2.3rem; font-weight: 750; letter-spacing: -.03em;
               font-family: var(--serif); }
.plan .per { color: var(--muted); font-size: .86rem; }

/* A real photograph in an art frame crops to the same box as the drawing. */
.art.photo { object-fit: cover; height: 100%; }
.art-frame:has(.art.photo) { aspect-ratio: 4 / 3; }
.art-frame.small:has(.art.photo) { aspect-ratio: 24 / 17; }

/* --- persona families --------------------------------------------------- */

.persona-groups { display: grid; gap: 18px; }
.persona-group { margin: 0; }
.group-head {
  margin: 0 0 10px; font-family: var(--sans);
  font-size: .72rem; font-weight: 700; letter-spacing: .1em;
  text-transform: uppercase; color: var(--accent);
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
}
.group-head .muted {
  font-size: .68rem; font-weight: 600; letter-spacing: .02em;
  text-transform: none; color: var(--muted);
}

/* --- what are you looking for ------------------------------------------- */

.intents { display: grid; gap: 8px; }
.intents input { position: absolute; opacity: 0; pointer-events: none; }
.intents .intent {
  margin: 0; display: flex; align-items: center; gap: 12px;
  padding: 13px 15px; cursor: pointer;
  background: transparent; border: 1px solid var(--line);
  font-size: .95rem; font-weight: 600; color: var(--text);
  letter-spacing: 0; text-transform: none;
  transition: border-color .12s ease, background .12s ease;
}
.intents .intent:hover { border-color: var(--text); }
.intents input:checked + .intent {
  background: var(--accent-soft); border-color: var(--accent); color: var(--accent);
}
.intents input:focus-visible + .intent { outline: 2px solid var(--violet); outline-offset: 2px; }
.intent-ico { font-size: 1.15rem; line-height: 1; width: 1.4em; text-align: center; }

@media (min-width: 520px) {
  .intents { grid-template-columns: 1fr 1fr; }
}

/* --- date of birth ------------------------------------------------------ */

/* Three boxes, not one native date input. A date picker opens on today, which
   is the single date nobody filling this in was born on. */
.dob { display: grid; grid-template-columns: 5rem 1fr 6rem; gap: 8px; }
.dob select { padding: 13px 10px; text-align: left; }

@media (max-width: 380px) {
  .dob { grid-template-columns: 1fr 1fr; }
  .dob select:nth-child(2) { grid-column: span 2; }
}

/* The "skip" tile in a persona family, for anyone that family does not fit. */
.persona.skip strong { color: var(--muted); }
.face.plain {
  background: var(--surface-2); color: var(--muted);
  border: 1px dashed var(--line); font-size: 1.1rem;
}

/* A chosen character, shown as a chip with its glyph. */
.trait-pill { text-transform: none; letter-spacing: 0; font-size: .74rem; font-weight: 600; }

/* --- place picker -------------------------------------------------------
   A Select2-shaped combobox, written here because the content security
   policy allows scripts from this origin only, and Select2 would also drag
   in jQuery for one field on one screen. */

.place-picker { position: relative; }
.place-picker input {
  padding-right: 42px;          /* room for the clear button */
}
.place-picker.chosen input {
  border-color: var(--ok);
  box-shadow: inset 0 0 0 1px var(--ok);
}

.place-clear {
  position: absolute; top: 0; right: 0; width: 42px; height: 48px;
  display: none; place-items: center;
  background: none; border: 0; cursor: pointer;
  font-size: 1.4rem; line-height: 1; color: var(--muted);
}
.place-picker input:not(:placeholder-shown) ~ .place-clear { display: grid; }
.place-clear:hover { color: var(--accent); }

/* A thin bar along the top of the field while a search is in flight. */
.place-picker.busy::after {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 2px;
  background: var(--accent); opacity: .7;
}

.place-list {
  position: absolute; left: 0; right: 0; top: calc(100% + 4px); z-index: 60;
  max-height: 320px; overflow-y: auto;
  background: var(--surface); border: 1px solid var(--text);
  box-shadow: var(--shadow);
}

.place-row {
  display: flex; flex-direction: column; gap: 2px;
  padding: 11px 14px; cursor: pointer;
  border-bottom: 1px solid var(--line-soft);
}
.place-row:last-child { border-bottom: 0; }
.place-row.on { background: var(--accent-soft); }

.place-name { font-size: .95rem; font-weight: 600; color: var(--text); }
.place-name mark {
  background: none; color: var(--accent); font-weight: 800;
}
.place-row.on .place-name { color: var(--accent); }
.place-where {
  font-size: .72rem; letter-spacing: .04em; text-transform: uppercase;
  color: var(--muted);
}

.place-empty {
  padding: 16px 14px; font-size: .88rem; color: var(--muted); text-align: center;
}

/* --- question and answer spacing ----------------------------------------
   Answers sit below their question with room to breathe. There used to be a
   hairline spine down the left of every answer group as well; it was meant
   to show which options belonged to which question, and on a phone it just
   read as a stray mark beside an input. The gap does that job on its own. */

.field > .choices,
.field > .intents,
.field > .dob,
.field > .pair,
.field > .personas,
.field > .persona-groups,
.field > .picker {
  margin-top: 10px;
  /* The step in from the question stays. It is what shows which options
     belong to which question once a form runs to a dozen of them. Only the
     hairline that used to run down this edge is gone: on a phone it read as
     a stray mark beside an input rather than as structure. */
  margin-left: 14px;
}

/* The question itself stays flush left, so the answers step in from it. */
.field > label { margin-left: 0; }

@media (max-width: 380px) {
  /* Less of it where there is less room, but not none. */
  .field > .choices,
  .field > .intents,
  .field > .personas,
  .field > .persona-groups { margin-left: 8px; }
}

.field + .field { margin-top: 20px; }

/* Inside the families, the same idea one level down: indented, no line. */
.persona-group .personas { margin-top: 8px; margin-left: 12px; }

.place-empty.place-error { color: var(--danger); }

/* --- the verification code screen ----------------------------------------
   One field, and it should look like the only thing on the page. Wide
   letter spacing because six digits read as six digits, not as a number. */
.code-input {
  font-size: 2rem;
  letter-spacing: 0.4em;
  text-align: center;
  padding: 14px 10px;
  font-variant-numeric: tabular-nums;
  /* The trailing letter-space pushes the text off-centre without this. */
  text-indent: 0.4em;
}

.btn.link {
  background: none;
  border: none;
  color: var(--muted);
  text-decoration: underline;
  font-size: 0.85rem;
  padding: 6px;
}

.btn.link:hover { color: var(--ink); }

.btn[disabled] { opacity: 0.55; cursor: not-allowed; }

/* Present for a screen reader, absent for everyone else. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Pending verification. Amber rather than red: nothing is wrong with the
   account, it just has not proved its address yet. */
.pill.warn {
  background: rgba(255, 176, 87, .14);
  border-color: rgba(255, 176, 87, .4);
  color: #9a6413;
}

/* --- read state ---------------------------------------------------------
   Three different things, told apart on sight: something you have not
   opened, something you sent that they have not opened, and something they
   have opened and not answered. */

.list-head {
  display: flex; align-items: center; gap: 8px;
  margin: 18px 0 8px; font-size: .72rem; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase; color: var(--muted);
}
.list-head:first-of-type { margin-top: 6px; }

.list-item.is-new { border-left: 3px solid var(--accent); }
.list-item.quiet { opacity: .82; cursor: default; }

.preview.unread, .small.unread { color: var(--text); font-weight: 600; }

.badge.new {
  background: var(--accent); color: #fff; border-color: var(--accent);
  font-size: .62rem; letter-spacing: .06em; text-transform: uppercase;
  padding: 3px 7px; width: auto; min-width: 0;
}

/* Sent versus Seen. Deliberately quiet: it is a status, not a headline. */
.receipt {
  display: inline-block; margin-right: 5px;
  font-size: .64rem; font-weight: 700; letter-spacing: .07em;
  text-transform: uppercase; color: var(--muted);
}
.receipt.seen { color: var(--ok); }

/* A number on the tab, not just a dot: "3 waiting" beats "something". */
.tabbar .count {
  position: absolute; margin: -18px 0 0 14px;
  min-width: 16px; height: 16px; padding: 0 4px;
  background: var(--accent); color: #fff;
  font-size: .62rem; font-weight: 700; line-height: 16px;
  text-align: center; border-radius: 0;
}

/* A message that is on screen but not yet confirmed by the server. Shown
   straight away so sending feels instant, and dimmed so it never claims to
   have arrived when it has not. */
.msg.pending { opacity: .55; }

/* The composer grows with the message; the cap lives here so the JS and the
   stylesheet cannot drift apart. */
.composer textarea {
  resize: none; overflow-y: auto; line-height: 1.45;
}

/* --- the "You" menu ------------------------------------------------------
   Five buttons in a wrapping row came out ragged and said nothing about what
   was behind each one or whether it still needed attention. Tiles, two up,
   each carrying its own state. */
.you-nav {
  display: grid; gap: 8px; margin: 0 0 16px;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
}
.you-tile {
  display: grid; gap: 2px; padding: 12px 14px;
  background: var(--surface); border: 1px solid var(--line); border-radius: 0;
  color: var(--text);
}
.you-tile:hover { background: var(--surface-2); }
.you-tile.on { border-color: var(--accent); background: var(--accent-soft); }
.you-ico { font-size: 1rem; line-height: 1; opacity: .75; }
.you-label {
  font-size: .82rem; font-weight: 700; letter-spacing: .04em;
  text-transform: uppercase;
}
.you-hint { font-size: .76rem; color: var(--muted); line-height: 1.35; }

/* Something is not set that the app needs to do its job. Amber, not red:
   nothing is broken, it just cannot score anything yet. */
.you-tile.needs { border-left: 3px solid var(--ochre); }
.you-tile.needs .you-hint { color: var(--ochre); font-weight: 600; }

/* --- moving through the stack -------------------------------------------
   Passing on somebody is a small rejection and introducing yourself is a
   small act of nerve. Swapping silently to the next stranger makes both feel
   like nothing happened, so each one gets a beat. */

.deck { position: relative; }

.profile-card.sliding-out {
  animation: slide-out .26s ease-in forwards;
}
.profile-card.sliding-in {
  animation: slide-in .28s ease-out both;
}

@keyframes slide-out {
  to { transform: translateX(-18%) rotate(-1.5deg); opacity: 0; }
}
@keyframes slide-in {
  from { transform: translateX(14%); opacity: 0; }
  to { transform: translateX(0); opacity: 1; }
}

.moment {
  position: absolute; inset: 0; z-index: 20;
  display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 6px; padding: 24px; text-align: center;
  background: var(--surface); border: 1px solid var(--line);
  animation: moment-in .22s ease-out both;
}
.moment.going { animation: moment-out .26s ease-in forwards; }

.moment-mark { font-size: 2.4rem; line-height: 1; }
.moment-line {
  font-family: var(--serif); font-size: 1.25rem; color: var(--text);
}
.moment-sub {
  font-size: .85rem; color: var(--muted); max-width: 22rem; line-height: 1.5;
}

/* Passing is quiet and grey. Nobody is told they were passed on, and the
   screen should not celebrate it either. */
.moment.pass { background: var(--surface-2); }
.moment.pass .moment-mark { color: var(--muted); opacity: .7; }

/* Introducing yourself is the hopeful one. */
.moment.hope { background: var(--accent-soft); border-color: var(--accent); }
.moment.hope .moment-mark {
  color: var(--accent);
  animation: hope-pulse 1.4s ease-in-out infinite;
}
.moment.hope .moment-line { color: var(--accent); }

@keyframes moment-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes moment-out { to { opacity: 0; } }
@keyframes hope-pulse {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.18); }
}

/* Somebody who asked for less movement gets less of it. */
@media (prefers-reduced-motion: reduce) {
  .profile-card.sliding-out,
  .profile-card.sliding-in,
  .moment, .moment.going, .moment.hope .moment-mark {
    animation: none;
  }
  .profile-card.sliding-out { opacity: 0; }
}

/* --- "You" header --------------------------------------------------------
   Your own face at the top of your own page, with one tap to change it.
   Without it the only way to find out what people actually see was to go
   looking for it. */
/* Stacked and centred. This is a phone app first, and a face pushed against
   the left edge with the name beside it reads like a desktop settings page. */
.you-head {
  display: flex; flex-direction: column; align-items: center;
  gap: 10px; margin: 0 0 18px; text-align: center;
}
.you-head h1 { margin: 0; font-size: 1.5rem; line-height: 1.2; }
.you-who p { margin: 2px 0 0; }

.you-face { position: relative; display: block; flex: none; }
.you-face .avatar { width: 104px; height: 104px; margin-inline: auto; }
.you-face-edit {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 3px 0; text-align: center;
  background: rgba(0, 0, 0, .55); color: #fff;
  font-size: .62rem; font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase;
}
.you-face:hover .you-face-edit { background: var(--accent); }

/* The code, on screen, on a development server with no way to send it.
   Never rendered anywhere else: the template only receives it when the app
   is in debug and the console rail was used. */
.dev-code {
  margin: 0 auto 10px; padding: 10px 16px; display: inline-block;
  background: var(--surface-2); border: 1px dashed var(--accent);
  font-size: 1.8rem; font-weight: 700; letter-spacing: .3em;
  text-indent: .3em; font-variant-numeric: tabular-nums;
  color: var(--accent);
}

/* --- why the stack is empty ---------------------------------------------
   "Nobody new right now" on its own reads as a broken app. These are the
   actual counts, and the ones the member can do something about are the
   ones picked out. */
.why-empty {
  list-style: none; margin: 14px auto 16px; padding: 0;
  max-width: 24rem; text-align: left;
}
.why-empty li {
  display: flex; align-items: baseline; gap: 10px;
  padding: 9px 12px;
  border-left: 3px solid var(--line);
  background: var(--surface-2);
}
.why-empty li + li { margin-top: 6px; }
.why-count {
  font-family: var(--serif); font-size: 1.1rem; font-weight: 700;
  color: var(--muted); min-width: 1.4rem; text-align: right;
  font-variant-numeric: tabular-nums;
}
.why-what { font-size: .88rem; line-height: 1.4; color: var(--text); }

/* Yours to change. */
.why-empty li.fixable { border-left-color: var(--accent); }
.why-empty li.fixable .why-count { color: var(--accent); }

/* --- the app's own dialog -------------------------------------------------
   Replaces window.confirm and window.alert. Those cannot be styled, and they
   print "localhost:5050 says" above your words, so the app stopped looking
   like itself at the moment it was asking to delete somebody's photos. */

.modal-back {
  position: fixed; inset: 0; z-index: 90;
  display: grid; place-items: center; padding: 20px;
  background: rgba(30, 18, 14, .55);
  animation: modal-in .16s ease-out both;
}

.modal {
  width: 100%; max-width: 26rem;
  padding: 22px; border-radius: 0;
  background: var(--surface); border: 1px solid var(--line);
  border-top: 3px solid var(--accent);
  box-shadow: 0 12px 40px rgba(30, 18, 14, .3);
  animation: modal-rise .2s cubic-bezier(0, 0, 0, 1) both;
}
.modal.danger { border-top-color: var(--danger); }

.modal-title {
  margin: 0 0 8px; font-family: var(--serif); font-size: 1.25rem;
}
.modal-body {
  margin: 0 0 18px; font-size: .92rem; line-height: 1.55; color: var(--muted);
}
.modal-actions { display: flex; gap: 10px; justify-content: flex-end; }
.modal-actions .btn { min-width: 6.5rem; }

/* A destructive confirm should not look like the safe option. */
.btn.danger.solid {
  background: var(--danger); color: #fff; border-color: var(--danger);
}

/* The page behind must not scroll while a dialog is open. */
body.modal-open .viewport { overflow: hidden; }

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

@media (prefers-reduced-motion: reduce) {
  .modal-back, .modal { animation: none; }
}

.decide-note {
  margin: 14px auto 0; max-width: 28rem; line-height: 1.5;
  padding-top: 12px; border-top: 1px solid rgba(0, 0, 0, .08);
}

/* --- the join prompt -----------------------------------------------------
   The price, on the pages people use, before the moment it matters. Not a
   wall: browsing and matching stay free, and this can be dismissed. */
.join-prompt {
  display: grid; align-items: center; gap: 10px;
  grid-template-columns: 1fr auto;
  margin: 0 0 14px; padding: 14px 16px; position: relative;
  background: var(--accent-soft);
  border: 1px solid var(--accent);
  border-left: 3px solid var(--accent);
}
.join-words { display: grid; gap: 2px; min-width: 0; }
.join-words strong { font-size: .95rem; }
.join-words span { font-size: .8rem; color: var(--muted); line-height: 1.45; }

.join-price { display: none; }
.join-figure {
  font-family: var(--serif); font-size: 1.3rem; font-weight: 700;
  color: var(--accent); line-height: 1;
}
.join-per {
  font-size: .68rem; letter-spacing: .06em; text-transform: uppercase;
  color: var(--muted);
}

.join-prompt .btn.primary { min-height: 42px; padding: 9px 18px; }

.join-close {
  position: absolute; top: 4px; right: 6px;
  padding: 2px 6px; font-size: 1.1rem; text-decoration: none;
  line-height: 1; min-height: 0;
}

@media (min-width: 520px) {
  .join-prompt { grid-template-columns: 1fr auto auto; }
  .join-price { display: grid; justify-items: end; gap: 1px; padding-right: 6px; }
}

/* --- suggested opening lines ---------------------------------------------
   An empty box at the one moment somebody is nervous gets you either
   nothing or the placeholder typed back at you. These fill it, and stay
   editable, because a line somebody chose and then changed beats a better
   line they did not write. */
.note-suggest { margin: 10px 0 0; }
.note-suggest-label {
  display: block; margin-bottom: 8px;
  font-size: .68rem; font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; color: var(--muted);
}
.note-chips { display: grid; gap: 6px; }

.note-chip {
  display: block; width: 100%; text-align: left;
  padding: 10px 12px; cursor: pointer;
  background: var(--surface-2); border: 1px solid var(--line);
  border-left: 3px solid var(--line); border-radius: 0;
  font-family: var(--serif); font-size: .9rem; line-height: 1.4;
  color: var(--text);
  transition: border-color .12s ease, background .12s ease;
}
.note-chip:hover { border-left-color: var(--muted); background: var(--surface); }
.note-chip.chosen {
  border-color: var(--accent); border-left-color: var(--accent);
  background: var(--accent-soft);
}

/* --- the alert feed ---------------------------------------------------- */
/* One row per thing that happened. The sentence carries the meaning, so the
   glyph is a marker and not a picture: muted, small, and out of the way of
   the words. It goes accent only when the row is still unread, which is the
   one time the eye should be pulled to it. */

.alert-line {
  display: block; font-size: .92rem; line-height: 1.4; color: var(--muted);
}
.alert-line.unread { color: var(--text); font-weight: 600; }

.alert-ico {
  display: inline-block; width: 1.05em; margin-right: 6px;
  font-size: .92em; color: var(--muted);
}
.alert-line.unread .alert-ico { color: var(--accent); }

/* An ending keeps its weight and loses only the affordance: .quiet already
   drops the cursor and the opacity, so there is nothing more to say here
   than that the sentence is still the sentence. */

/* --- finishing the questionnaire ----------------------------------------
   The gate that holds matches back until these are answered is invisible
   from the member's side: every tap lands here. So this page has to say
   what is left and which ones they are. */
.finish-banner {
  display: grid; gap: 4px; margin: 0 0 14px; padding: 14px 16px;
  background: var(--accent-soft);
  border: 1px solid var(--accent);
  border-left: 3px solid var(--accent);
}
.finish-banner strong { font-size: 1rem; color: var(--accent); }
.finish-banner span { font-size: .85rem; color: var(--text); line-height: 1.5; }

.progress.nearly span { background: var(--ok); }

/* A question still waiting for an answer. */
.field.needs-answer > label { color: var(--text); }
.needs-mark {
  display: inline-block; margin-left: 8px; padding: 2px 7px;
  background: var(--ochre); color: #fff;
  font-size: .6rem; font-weight: 700; letter-spacing: .07em;
  text-transform: uppercase; vertical-align: middle;
}

/* --- the push switch ---------------------------------------------------- */
/* Rendered hidden and revealed by push.js, so it never flashes up on a
   browser that cannot do this. */

.push-panel {
  border: 1px solid var(--line); background: var(--surface-2);
  padding: 14px; margin-bottom: 16px;
}
.push-panel[hidden] { display: none; }

.push-row { display: flex; gap: 12px; align-items: center; }
.push-row .btn { flex: none; }

.push-detail {
  display: flex; gap: 10px; align-items: flex-start;
  margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line);
  cursor: pointer;
}
.push-detail[hidden] { display: none; }
.push-detail input { margin-top: 3px; flex: none; }


/* --- Pendo: the beaded look -------------------------------------------------
 * A row of beads under the header and between sections, a beaded mark, the
 * lead colour where the eye should land, and a short kicker over a few
 * headings. The
 * tokens it all draws on (--beads, --shuka-check and the bead colours) live
 * in :root at the top of this file.
 */

.bead-strip { height: 6px; background: var(--beads); flex: none; }
.bead-rule { height: 8px; margin: 26px 0; background: var(--beads); }

.brand-mark { display: inline-flex; font-size: 0; }
.brand-mark-svg { width: 30px; height: 30px; display: block; }
.brand-name {
  font-family: var(--serif); font-weight: 700; letter-spacing: .005em;
  font-size: 1.28rem; color: var(--shuka-deep);
}

/* The short line over a heading: small, wide-spaced, shuka red. */
.kicker {
  margin: 0 0 6px; font: 700 .72rem/1.2 var(--sans);
  letter-spacing: .16em; text-transform: uppercase; color: var(--shuka);
}

.hero h1 { color: var(--earth); }
.step-n { color: var(--shuka); }

/* Feature cards wear a beaded top edge. */
.card.ages, .card.communities, .card.price-card {
  border-top: 6px solid var(--shuka);
  border-image: var(--beads) 1;
}
.price-card h2 { color: var(--shuka); font-size: clamp(1.6rem, 6vw, 2.1rem); }

/* A strip of shuka check, for anywhere that wants the cloth itself. */
.shuka-band { height: 14px; background: var(--shuka-check); }

.pill.accent { background: var(--accent-soft); border-color: #f1b9b2; color: var(--shuka-deep); }
.pill.community { background: var(--bead-blue); border-color: var(--bead-blue); color: var(--bead-white); }

/* Community choices: real checkboxes, drawn as chips. */
.community-chips {
  justify-content: flex-start; max-height: 230px; overflow: auto;
  padding: 2px;
}
.community-chips input { position: absolute; opacity: 0; pointer-events: none; }
.community-chips .chip { cursor: pointer; user-select: none; }
.community-chips input:checked + .chip {
  background: var(--shuka); border-color: var(--shuka); color: var(--bead-white);
}
.community-chips input:focus-visible + .chip { outline: 2px solid var(--bead-blue); outline-offset: 2px; }

.check { display: flex; gap: 8px; align-items: flex-start; line-height: 1.45; }
.check input { margin-top: 3px; flex: none; }

.site-footer .mark { color: var(--shuka-deep); }

/* The drawn scenes sit on a dusk card rather than floating on the page. */
.hero .art-frame, .ages .art-frame, .communities .art-frame, .price-card .art-frame {
  background: linear-gradient(180deg, var(--dusk-1) 0%, #f3a35d 60%, var(--dusk-2) 100%);
}

/* Empty states get the lone acacia and its two empty stools. */
.empty-art { max-width: 240px; margin: 0 auto 14px; }
.empty-art svg { width: 100%; height: auto; display: block; }

/* The consent line is a sentence the member reads and agrees to, not a field
   label, so it drops the small-caps label styling it would otherwise inherit. */
.field label.check {
  text-transform: none; letter-spacing: normal; font-weight: 400;
  font-size: .9rem; color: var(--text);
}
/* Every community in view at once: an inner scroll box on a phone is a trap. */
.community-chips { max-height: none; overflow: visible; }

/* --- the footer, worn like a beaded bracelet ----------------------------------
 * Rows of beads in the band colours (--band-1 to --band-3) with cream between.
 * Bead rows are the stripes, small highlights and seams make them read as
 * beads rather than paint, and any words sit on a dark clasp in the middle so
 * they stay readable over every colour.
 */
html.footer-note { --footer-h: 64px; }

.site-footer.wristband {
  border-top: 0;
  background:
    radial-gradient(circle at 50% 38%, rgba(255, 255, 255, .28) 0 1.1px, transparent 1.7px) 0 0 / 8px 8px,
    repeating-linear-gradient(90deg, rgba(0, 0, 0, .22) 0 1px, transparent 1px 8px),
    linear-gradient(180deg,
      var(--band-1) 0 27%, var(--band-thread) 27% 33%,
      var(--band-2) 33% 67%,
      var(--band-thread) 67% 73%, var(--band-3) 73% 100%);
}
.site-footer.wristband .clasp {
  display: flex; flex-direction: column; align-items: center; gap: 1px;
  max-width: calc(100% - 20px);
  padding: 3px 12px;
  background: rgba(24, 12, 8, .78);
  border: 1px solid rgba(255, 250, 242, .35);
  text-align: center; line-height: 1.25;
}
.site-footer.wristband .note {
  color: var(--bead-yellow); font-weight: 700; font-size: .68rem;
}
.site-footer.wristband .line { display: flex; gap: 8px; justify-content: center; }
.site-footer.wristband .mark { color: var(--bead-white); font-size: .68rem; }
.site-footer.wristband .tm { color: rgba(255, 250, 242, .75); font-size: .68rem; opacity: 1; }

/* --- messages, in the bead palette --------------------------------------------
 * Your messages wear the lead colour with a row of beads along the foot;
 * theirs are cream with a plum bead edge. The bead row is the --beads token,
 * so it matches the header and the dividers.
 */
.msg {
  position: relative;
  background: var(--bead-white);
  border: 1px solid var(--line);
  box-shadow: inset 4px 0 0 var(--bead-blue);
  padding-left: 16px;
}
.msg.mine {
  background: linear-gradient(135deg, var(--shuka) 0%, var(--rose-deep) 100%);
  color: var(--bead-white);
  border-color: transparent;
  box-shadow: none;
  padding-left: 14px;
  margin-bottom: 4px;
}
.msg.mine::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: -4px; height: 4px;
  background: var(--beads);
}
.msg.mine .meta { color: rgba(255, 250, 242, .85); opacity: 1; }
.msg.photo.mine { background: #ffd3e3; color: var(--text); }
.msg.photo.mine .meta { color: var(--muted); }

/* --- the beaded band, everywhere -----------------------------------------------
 * One pattern, used three ways:
 *   --wristband       the band itself: rows of beads in --band-1 to --band-3,
 *                     top to bottom, for the strip across the top of the page
 *                     and the footer
 *   --wristband-edge  the same colours cut on the diagonal, so a thin border
 *                     shows beads along every side of a card or an image
 * The strips above the header (the wristband and the bead row under the
 * header) are counted in --band-h, so the scroll region still fits exactly.
 */
:root {
  --band-h: 28px;   /* 22px wristband + 6px bead strip under the header */
  --wristband:
    radial-gradient(circle at 50% 38%, rgba(255, 255, 255, .28) 0 1.1px, transparent 1.7px) 0 0 / 8px 8px,
    repeating-linear-gradient(90deg, rgba(0, 0, 0, .22) 0 1px, transparent 1px 8px),
    linear-gradient(180deg,
      var(--band-1) 0 27%, var(--band-thread) 27% 33%,
      var(--band-2) 33% 67%,
      var(--band-thread) 67% 73%, var(--band-3) 73% 100%);
  --wristband-edge: repeating-linear-gradient(45deg,
      var(--band-1) 0 7px, var(--band-thread) 7px 9px,
      var(--band-2) 9px 16px, var(--band-thread) 16px 18px,
      var(--band-3) 18px 25px, var(--band-thread) 25px 27px);
}

.viewport {
  max-height: calc(100dvh - var(--header-h) - var(--band-h) - var(--tab-h) - var(--footer-h));
}

.wristband-top {
  flex: none;
  height: calc(22px + env(safe-area-inset-top, 0px));
  padding-top: env(safe-area-inset-top, 0px);
  display: flex; align-items: center; justify-content: center;
  background: var(--wristband);
  position: relative; z-index: 41;
}
.wristband-top .clasp {
  font: 800 .62rem/1 var(--sans); letter-spacing: .3em; text-transform: uppercase;
  color: var(--bead-white);
  background: rgba(24, 12, 8, .84);
  border: 1px solid rgba(255, 250, 242, .45);
  padding: 3px 9px 3px 12px;
}
/* The band takes the notch; the header below it no longer needs to. */
body:not(.no-app) .wristband-top + .site-header { padding-top: 0; }

.site-footer.wristband { background: var(--wristband); }

/* Cards: a 3px wristband all the way round. */
.card {
  border: 3px solid transparent;
  background: linear-gradient(var(--surface), var(--surface)) padding-box,
              var(--wristband-edge) border-box;
}
.card.ages, .card.communities, .card.price-card { border-top-width: 3px; border-image: none; }

/* Images and drawn scenes: a 2px wristband. */
.art-frame {
  border: 2px solid transparent;
  background: linear-gradient(var(--surface-2), var(--surface-2)) padding-box,
              var(--wristband-edge) border-box;
}
.hero .art-frame, .ages .art-frame, .communities .art-frame, .price-card .art-frame {
  background: linear-gradient(180deg, var(--dusk-1) 0%, #f3a35d 60%, var(--dusk-2) 100%) padding-box,
              var(--wristband-edge) border-box;
}
img.shot, img.art.photo, .photo-grid img, .photos img, .intro-photos img {
  border: 2px solid transparent;
  background: var(--wristband-edge) border-box;
}

/* The tradition cards: the same dusk behind the drawing as the others. */
.heritage .art-frame, .table-card .art-frame {
  background: linear-gradient(180deg, var(--dusk-1) 0%, #f3a35d 60%, var(--dusk-2) 100%) padding-box,
              var(--wristband-edge) border-box;
}
.heritage h2, .table-card h2 { color: var(--earth); }

/* --- the woven bands ---------------------------------------------------------
 * The header and footer bands are SVG bead grids with the words worked into
 * the red rows in white beads (wristband.py). They fill their strip; the CSS
 * gradient stays underneath only as the colour while the SVG paints.
 */
.wristband-top { padding: 0; }
.wristband-top .wristband-svg,
.site-footer.wristband .wristband-svg {
  display: block; width: 100%; height: 100%;
}
.wristband-top { height: calc(22px + env(safe-area-inset-top, 0px)); }
.site-footer.wristband { padding: 0 0 env(safe-area-inset-bottom, 0px); }

/* --- the bead ring: compatibility, bead by bead ----------------------------------
 * The score as 24 beads round a member's picture, lit up to the share of your
 * asks they meet. Each lit bead pops in after the one before, so the ring
 * fills as the card arrives. Nothing moves for people who ask for less motion.
 */
.ring-wrap {
  position: relative; width: 150px; height: 150px;
  margin: 0 auto 6px; display: grid; place-items: center;
}
.ring-wrap .bead-ring { position: absolute; inset: 0; width: 100%; height: 100%; }
.ring-wrap .card-avatar, .ring-wrap .avatar { position: relative; z-index: 1; }
.ring-bead.on {
  transform-box: fill-box; transform-origin: center;
  animation: bead-in .35s cubic-bezier(.2, .9, .3, 1.4) both;
}
@keyframes bead-in {
  from { opacity: 0; transform: scale(.2); }
  to   { opacity: 1; transform: scale(1); }
}
.score .theirs { display: block; color: var(--bead-blue); font-weight: 600; }

/* A new card slides up into place rather than appearing. */
.profile-card:not([hidden]) { animation: card-in .45s cubic-bezier(.2, .8, .2, 1) both; }
@keyframes card-in {
  from { opacity: 0; transform: translateY(18px) scale(.985); }
  to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .ring-bead.on, .profile-card:not([hidden]) { animation: none; }
}

/* --- profile strength: a row of beads ---------------------------------------------- */
.strength-head { display: flex; align-items: baseline; justify-content: space-between; }
.strength-head h2 { margin: 0; font-size: 1.1rem; }
.strength-figure { font: 700 1.4rem/1 var(--serif); color: var(--shuka); }
.strength-beads { display: flex; gap: 8px; margin-top: 12px; }
.strength-bead {
  flex: 1; height: 16px; clip-path: inset(0 round 8px);
  background: #e3cba6; box-shadow: inset 0 -2px 0 rgba(0, 0, 0, .12);
}
.strength-bead.on { animation: bead-in .35s cubic-bezier(.2, .9, .3, 1.4) both;
                    animation-delay: calc(var(--i) * 70ms); }
.strength-bead.on:nth-child(6n+1) { background: var(--shuka); }
.strength-bead.on:nth-child(6n+2) { background: var(--bead-blue); }
.strength-bead.on:nth-child(6n+3) { background: var(--bead-yellow); }
.strength-bead.on:nth-child(6n+4) { background: var(--blush); }
.strength-bead.on:nth-child(6n+5) { background: var(--bead-orange); }
.strength-bead.on:nth-child(6n)   { background: var(--earth); }
@media (prefers-reduced-motion: reduce) { .strength-bead.on { animation: none; } }

/* --- chat: the money warning and the celebration ------------------------------------ */
.money-warning {
  border-left: 4px solid var(--bead-yellow);
  background: #fff6dc; color: var(--text); margin: 10px 0;
}
.msg.money { outline: 2px solid var(--bead-yellow); outline-offset: 2px; }
.money-tag {
  margin-top: 6px; font: 700 .66rem/1 var(--sans); letter-spacing: .08em;
  text-transform: uppercase; color: #8a5a00;
}

/* You both said yes: a burst of beads out of the banner, once. */
.stage-banner.celebrate { position: relative; overflow: visible; }
.bead-burst { position: absolute; left: 50%; top: 18px; width: 0; height: 0; pointer-events: none; }
.bead-burst span {
  position: absolute; width: 9px; height: 9px; clip-path: circle(50%);
  background: var(--shuka);
  animation: burst 1.1s cubic-bezier(.15, .8, .3, 1) both;
  --a: calc(var(--i) * 20deg);
}
.bead-burst span:nth-child(6n+2) { background: var(--bead-blue); }
.bead-burst span:nth-child(6n+3) { background: var(--bead-yellow); }
.bead-burst span:nth-child(6n+4) { background: var(--blush); }
.bead-burst span:nth-child(6n+5) { background: var(--bead-orange); }
.bead-burst span:nth-child(6n)   { background: var(--earth); }
@keyframes burst {
  0%   { transform: rotate(var(--a)) translateY(0) scale(.4); opacity: 0; }
  20%  { opacity: 1; }
  100% { transform: rotate(var(--a)) translateY(-70px) scale(1); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) { .bead-burst span { animation: none; display: none; } }

/* A confirmed phone number: the plainest sign of a real person. */
.legit-badge {
  display: inline-block; margin: 4px 0 6px; padding: 3px 10px;
  font: 700 .72rem/1.3 var(--sans); color: var(--bead-white);
  background: var(--bead-green);
}
.pill.legit { background: var(--bead-green); border-color: var(--bead-green); color: var(--bead-white); }

/* --- scenes behind the content -------------------------------------------------
 * The drawn scenes sit behind the content rather than in a box on it, in two
 * ways:
 *
 *   A whole page (sign in, join, the inbox): body.scene-page plus scene-<name>.
 *     The drawing runs edge to edge across the top of the page, with no
 *     frame, and fades into the red earth below it. It is the scroll region's
 *     own background, which does not move when its content scrolls, so a long
 *     form slides up over a scene that stays put. The card starts just under
 *     the people in it, so they are always in view above it.
 *
 *   One card (the homepage): .scene-block holds a scene() and a card. The
 *     drawing runs the full width of the column and the card rises over its
 *     foot. See _partials/scene.html.
 *
 * scene-<name> sets the drawing as --scene-img, so a photograph can take its
 * place inline. The paths are absolute so they mean the same wherever the
 * property ends up. Every drawing crops to fill (preserveAspectRatio slice),
 * so each one can be given an exact 4:3 box.
 */
.scene-hero     { --scene-img: url("/art/hero.svg"); }
.scene-chai     { --scene-img: url("/art/chai.svg"); }
.scene-elders   { --scene-img: url("/art/elders.svg"); }
.scene-heritage { --scene-img: url("/art/heritage.svg"); }
.scene-table    { --scene-img: url("/art/table.svg"); }
.scene-market   { --scene-img: url("/art/market.svg"); }
.scene-empty    { --scene-img: url("/art/empty.svg"); }
.scene-words    { --scene-img: url("/art/words.svg"); }
.scene-exchange { --scene-img: url("/art/exchange.svg"); }
.scene-reveal   { --scene-img: url("/art/reveal.svg"); }

/* A whole page. --scene-h is the drawing's height at the column's width. */
body.scene-page {
  --scene-w: min(100vw, var(--app-w));
  --scene-h: calc(var(--scene-w) * .75);
}
/* `html` in front so this wins over the savannah backdrop every page has,
 * which comes later in this file with the same weight. */
html body.scene-page .viewport {
  background-color: var(--earth);
  background-image:
    linear-gradient(180deg, rgba(59, 36, 22, 0) 0,
                    rgba(59, 36, 22, 0) calc(var(--scene-h) - 70px),
                    var(--earth) calc(var(--scene-h) + 10px)),
    var(--scene-img);
  background-repeat: no-repeat;
  background-position: top center, top center;
  background-size: 100% 100%, 100% var(--scene-h);
}
/* The page itself is the card: the content column becomes a frosted sheet
 * that starts at the people's feet, with the red earth around and below it.
 * So every page, from sign in to settings, has the same shape, and a page
 * never needs a card of its own just to sit on the scene. Its wristband edge
 * is a border-image here, not the background trick the other cards use,
 * because a see-through sheet would show that pattern through its face. */
body.scene-page .shell {
  position: relative; z-index: 1;
  width: auto; max-width: none; flex: none;
  margin: calc(var(--scene-h) * .9) 8px 28px;
  padding: 22px 14px 26px;
  border: 3px solid transparent;
  border-image: var(--wristband-edge) 3;
  background: rgba(255, 250, 242, .95);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
  box-shadow: 0 -10px 30px rgba(42, 26, 46, .25), 0 18px 44px rgba(42, 26, 46, .38);
}
/* One card. The block reaches out through the column's 16px gutter so the
 * drawing is edge to edge; the card comes back in and rises over the bottom
 * tenth of it (7.5% of the width is a tenth of a 4:3 height). */
.scene-block { margin-inline: -16px; }
.shell > * + .scene-block { margin-top: 30px; }
.scene-art {
  aspect-ratio: 4 / 3;
  background: linear-gradient(180deg, rgba(59, 36, 22, 0) 70%, var(--earth) 100%),
              var(--scene-img) center / 100% 100% no-repeat,
              linear-gradient(180deg, var(--dusk-2) 0%, var(--dusk-1) 55%, var(--sand) 100%);
}
.scene-block > .card {
  margin: -7.5% 16px 0;
  box-shadow: 0 -8px 24px rgba(42, 26, 46, .18), 0 14px 30px rgba(42, 26, 46, .16);
}
/* A photograph is not drawn to the box, so it crops instead. */
.scene-art[style] { background-size: 100% 100%, cover, auto; }

/* The homepage: every scene fades into the same red earth, and the cards and
 * headings sit on that one ground all the way down. */
html body.scene-stack .viewport { background: var(--earth); }
body.scene-stack .shell { padding-bottom: 36px; }
body.scene-stack .shell > section.center:not(.card) h2 { color: var(--bead-white); }
body.scene-stack .bead-rule { margin: 22px 0 0; }
.hero.scene-block { padding: 0; margin-top: -18px; }   /* up under the header */


/* --- touch first: inputs, buttons, choices and cards ---------------------------------
 * Made for a thumb on a phone. Every field is 52px tall at 16px (so iOS never
 * zooms), and lights up in shuka red with a red edge when it has the focus;
 * its label turns red with it. Buttons are chunky with a ledge underneath
 * that presses down under the thumb, so a tap feels like a tap. Choices are
 * big targets that fill with colour when picked. Selectors start at `html`
 * so they win over the generic rules in phone.css.
 */
html input[type="text"], html input[type="email"], html input[type="password"],
html input[type="number"], html input[type="tel"], html input[type="date"],
html input[type="search"], html select, html textarea {
  min-height: 52px; padding: 13px 14px; font-size: 16px;
  border: 2px solid var(--line); background-color: var(--bead-white);
  color: var(--text);
  transition: border-color .15s ease, box-shadow .2s ease, background-color .15s ease;
}
html textarea { min-height: 96px; }
html input:focus, html select:focus, html textarea:focus {
  outline: none; border-color: var(--shuka); background-color: #fff;
  box-shadow: inset 5px 0 0 var(--shuka), 0 0 0 4px rgba(var(--accent-rgb), .14);
}
.field:focus-within > label { color: var(--shuka); }
html input[type="checkbox"], html input[type="radio"] {
  accent-color: var(--shuka); width: 22px; height: 22px; min-height: 0;
}

html body .btn {
  min-height: 52px; font-weight: 800; letter-spacing: .06em;
  transition: transform .1s ease, box-shadow .15s ease, filter .15s ease;
}
html body .btn.primary { box-shadow: 0 4px 0 var(--shuka-deep); }
html body .btn.primary:active { transform: translateY(3px); box-shadow: 0 1px 0 var(--shuka-deep); }
html body .btn:not(.primary) {
  border: 2px solid var(--earth); background: var(--bead-white); color: var(--earth);
  box-shadow: 0 3px 0 var(--earth);
}
html body .btn:not(.primary):hover { background: var(--sand); color: var(--earth); }
html body .btn:not(.primary):active { transform: translateY(2px); box-shadow: 0 1px 0 var(--earth); }
html body .btn.ghost { border-color: var(--line); color: var(--muted); box-shadow: 0 3px 0 var(--line); }
html body .btn.danger { border-color: var(--danger); color: var(--danger); box-shadow: 0 3px 0 var(--danger); }
html body .btn.small { min-height: 42px; }
html body .btn.small.primary { box-shadow: 0 3px 0 var(--shuka-deep); }
html body .btn:focus-visible { outline: 3px solid var(--bead-blue); outline-offset: 2px; }
/* A link-style button stays a link: no box, no ledge. The close cross on the
 * membership prompt is one. */
html body .btn.link {
  min-height: 0; border: none; background: none; box-shadow: none;
  color: var(--muted); font-weight: 600; letter-spacing: 0;
}
html body .btn.link:hover { background: none; color: var(--ink); }
html body .btn.link:active { transform: none; box-shadow: none; }
html body:not(.no-app) .join-prompt .join-close {
  position: absolute; top: 4px; right: 6px; width: auto;
  padding: 4px 8px; font-size: 1.25rem; line-height: 1; text-decoration: none;
}

/* Choices: big, and they fill with colour when picked. */
.choices label, .intents .intent, .chips .chip {
  min-height: 46px; display: inline-flex; align-items: center;
  transition: transform .1s ease, background-color .15s ease, border-color .15s ease;
}
.choices label:active, .intents .intent:active, .community-chips .chip:active { transform: scale(.96); }
.choices input:checked + label, .intents input:checked + .intent {
  background: var(--shuka); border-color: var(--shuka); color: var(--bead-white);
}
.intents input:checked + .intent .intent-ico { filter: drop-shadow(0 0 2px rgba(255, 255, 255, .6)); }

/* Tappable cards press in, and lift a little under a mouse. */
.you-tile, .list-item, .group, .card.quiz { transition: transform .12s ease, box-shadow .2s ease; }
.you-tile:active, .list-item:active, .group:active { transform: scale(.985); }
@media (hover: hover) {
  .you-tile:hover, .group:hover { transform: translateY(-2px); }
}

/* --- Kenya behind every page ----------------------------------------------------------
 * A low savannah horizon, hills with acacias and a couple under one of them,
 * sits at the foot of the scroll region on every page, faint, behind the
 * content. The page scrolls over it, so it reads as the place the app lives
 * in rather than a picture on it.
 */
html[data-gender] .viewport {
  background-image:
    var(--wash),
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1200 200' preserveAspectRatio='xMidYMax slice'%3E%3Cg fill='%233b2416' opacity='.10'%3E%3Cpath d='M0 170 C150 120 300 150 450 132 C600 112 760 150 900 128 C1020 110 1110 136 1200 120 L1200 200 L0 200Z'/%3E%3Cpath d='M180 140 L186 96 L192 140Z'/%3E%3Cellipse cx='186' cy='92' rx='56' ry='9'/%3E%3Cellipse cx='176' cy='86' rx='34' ry='7'/%3E%3Cpath d='M820 132 L828 70 L836 132Z'/%3E%3Cellipse cx='828' cy='66' rx='80' ry='12'/%3E%3Cellipse cx='812' cy='58' rx='46' ry='9'/%3E%3Ccircle cx='852' cy='108' r='5'/%3E%3Cpath d='M846 113 h12 v20 h-12Z'/%3E%3Ccircle cx='866' cy='109' r='4.6'/%3E%3Cpath d='M861 114 h11 v19 h-11Z'/%3E%3Cpath d='M1040 128 L1045 100 L1050 128Z'/%3E%3Cellipse cx='1045' cy='97' rx='38' ry='7'/%3E%3C/g%3E%3C/svg%3E");
  background-repeat: no-repeat, no-repeat;
  background-position: top, bottom center;
  background-size: 100% 100%, 100% auto;
}

.page-lede { font-size: 1.02rem; color: var(--text); }

/* --- question cards -------------------------------------------------------------
 * Each questionnaire question is a card of its own (_partials/question_card).
 * The icon sits in a ring of beads, the answers are two big columns of tap
 * targets with a coloured bead each, and the picked one fills with the
 * card's colour and gets a tick. An answered card turns its edge green and
 * says so. Tones go red, blue, green, yellow, orange down the list, like a
 * strand of beads.
 */
.q-card {
  --q: var(--shuka); --q-soft: var(--accent-soft);
  position: relative; margin: 0; min-width: 0;
  background: #fff;
  border-left: 5px solid var(--q);
  box-shadow: 0 1px 0 var(--line), 0 10px 26px rgba(70, 45, 25, .10);
  transition: border-color .2s ease, box-shadow .2s ease;
}
.q-card.tone-1 { --q: var(--bead-blue);   --q-soft: #efe3fb; }
.q-card.tone-2 { --q: var(--tone-2);      --q-soft: #f7e1fb; }
.q-card.tone-3 { --q: var(--ochre);       --q-soft: #fbefd0; }
.q-card.tone-4 { --q: var(--tone-4);      --q-soft: #ffe0ea; }
.q-list { display: grid; gap: 16px; }

.q-head {
  display: flex; gap: 12px; align-items: center;
  padding: 14px 14px 12px;
  background: linear-gradient(180deg, var(--q-soft), #fff);
}
/* The icon on a white bead, inside a ring of the card's colour and white. */
.q-ico {
  width: 52px; height: 52px; flex: none; display: grid; place-items: center;
  font-size: 1.45rem; line-height: 1;
  background:
    radial-gradient(circle, #fff 0 60%, transparent 61%),
    repeating-conic-gradient(var(--q) 0 18deg, var(--bead-white) 18deg 30deg);
  clip-path: circle(50%);
}
.q-words { display: grid; gap: 3px; min-width: 0; }
.q-step {
  font: 800 .68rem/1.2 var(--sans); letter-spacing: .14em; text-transform: uppercase;
  color: var(--q);
}
.q-done, .q-card:has(input:checked) .q-count,
.q-card:has(input:checked) .q-needed { display: none; }
.q-needed { color: var(--shuka); margin-left: 8px; }
.q-question {
  font-family: var(--serif); font-weight: 700; font-size: 1.14rem; line-height: 1.25;
  color: var(--text);
}

.q-options {
  display: grid; grid-template-columns: 1fr 1fr; gap: 8px;
  padding: 4px 14px 16px;
}
@media (max-width: 359px) { .q-options { grid-template-columns: 1fr; } }
.q-options input { position: absolute; opacity: 0; pointer-events: none; }

html body .q-opt {
  display: flex; align-items: center; gap: 10px; min-height: 54px; margin: 0;
  padding: 10px 12px; cursor: pointer; user-select: none;
  background: var(--bead-white); border: 2px solid var(--line-soft); color: var(--text);
  font: 600 .92rem/1.25 var(--sans); letter-spacing: 0; text-transform: none;
  box-shadow: 0 2px 0 var(--line-soft);
  transition: background-color .15s ease, border-color .15s ease, color .15s ease, transform .1s ease;
}
/* Each answer's own bead: a coloured ring with a white centre. */
.q-opt::before {
  content: ""; width: 18px; height: 18px; flex: none; display: grid; place-items: center;
  background: radial-gradient(circle, var(--bead-white) 0 34%, var(--dot, var(--shuka)) 36%);
  clip-path: circle(50%);
  font: 900 .7rem/1 var(--sans); color: var(--q);
}
.q-opt:nth-of-type(6n+1) { --dot: var(--shuka); }
.q-opt:nth-of-type(6n+2) { --dot: var(--bead-blue); }
.q-opt:nth-of-type(6n+3) { --dot: var(--blush); }
.q-opt:nth-of-type(6n+4) { --dot: var(--bead-yellow); }
.q-opt:nth-of-type(6n+5) { --dot: var(--bead-orange); }
.q-opt:nth-of-type(6n)   { --dot: var(--dusk-3); }
.q-opt.quiet { --dot: var(--line); color: var(--muted); }
.q-opt:has(.q-opt-ico)::before { display: none; }
.q-opt-ico { font-size: 1.2rem; line-height: 1; flex: none; }

html body .q-opt:hover { border-color: var(--q); background: #fff; }
html body .q-opt:active { transform: scale(.97); }
html body .q-options input:checked + .q-opt {
  background: var(--q); border-color: var(--q); color: #fff;
  box-shadow: 0 3px 0 rgba(0, 0, 0, .18);
  animation: q-pick .28s ease;
}
.q-options input:checked + .q-opt::before {
  content: "\2713"; background: #fff;
}
.q-options input:focus-visible + .q-opt { outline: 3px solid var(--bead-blue); outline-offset: 2px; }

/* Answered: a green edge, a tick on the icon, and the step line says so. */
.q-card:has(input:checked) { border-left-color: var(--bead-green); }
.q-card:has(input:checked) .q-done { display: inline; color: var(--bead-green); }
.q-card:has(input:checked) .q-done::before { content: "\2713  "; }
.q-card:has(input:checked) .q-ico {
  background:
    radial-gradient(circle, #fff 0 60%, transparent 61%),
    repeating-conic-gradient(var(--bead-green) 0 18deg, var(--bead-white) 18deg 30deg);
}
.q-card.needed:not(:has(input:checked)) { border-left-color: var(--shuka); }
.q-card.just-answered { animation: q-done .5s ease; }

.q-number { display: flex; align-items: center; gap: 10px; padding: 4px 14px 16px; }
.q-number input { max-width: 180px; font-size: 1.15rem; font-weight: 700; }
.q-unit { font-weight: 700; color: var(--muted); }
.q-note { margin: -6px 14px 14px; font-size: .8rem; color: var(--muted); }

@keyframes q-pick { 0% { transform: scale(.94); } 60% { transform: scale(1.03); } 100% { transform: scale(1); } }
@keyframes q-done { 0% { box-shadow: 0 0 0 0 rgba(46, 139, 87, .45), 0 10px 26px rgba(70, 45, 25, .10); }
                    100% { box-shadow: 0 0 0 14px rgba(46, 139, 87, 0), 0 10px 26px rgba(70, 45, 25, .10); } }

/* The intro over a run of cards: a strand of beads that light up as each
 * question is answered. */
.q-intro { text-align: center; }
.q-intro-head { margin: 0 0 4px; font: 700 1.2rem/1.2 var(--serif); color: var(--text); }
.q-beads { display: flex; justify-content: center; gap: 8px; margin: 12px 0 6px; }
.q-bead {
  width: 18px; height: 18px; clip-path: circle(50%);
  background: radial-gradient(circle, var(--bead-white) 0 30%, var(--line) 32%);
  transition: background .25s ease, transform .25s ease;
}
.q-bead.on {
  background: radial-gradient(circle, var(--bead-white) 0 30%, var(--bead-green) 32%);
  transform: scale(1.15);
}
.q-tally { margin: 0; font-weight: 700; color: var(--muted); }

@media (prefers-reduced-motion: reduce) {
  .q-card.just-answered, html body .q-options input:checked + .q-opt { animation: none; }
}
/* Inside a padded card the question cards reach out to its edges, so two
 * columns of answers still fit "Single, never married" on two lines. */
.card .q-list { margin-inline: -12px; }
.q-head { padding-inline: 12px; }
.q-options { padding: 4px 12px 14px; }
html body .q-opt { padding: 10px; gap: 9px; font-size: .9rem; }
.q-group + .q-group { margin-top: 28px; }
.q-group > h2 { margin-bottom: 2px; }
.q-group > .small { margin: 0 0 12px; }

/* --- the swipe deck ---------------------------------------------------------------
 * The card moves under the thumb (discover.js). It leans and turns as it is
 * dragged, a stamp fades in on the side it is going, and it flies off when
 * it is let go past the line. Two more cards show their edges underneath, so
 * it reads as a stack of people rather than a page. The three buttons are
 * round beads: pass, super intro, introduce.
 */
.deck { position: relative; touch-action: pan-y; }
.deck::before, .deck::after {
  content: ""; position: absolute; left: 14px; right: 14px; height: 14px;
  bottom: -7px; z-index: 0;
  background: var(--bead-white); border: 2px solid var(--line);
  box-shadow: 0 6px 14px rgba(42, 26, 46, .12);
}
.deck::after { left: 28px; right: 28px; bottom: -14px; z-index: -1; opacity: .8; }
.deck .profile-card { z-index: 1; will-change: transform; user-select: none; -webkit-user-select: none; }
.deck .profile-card.dragging { animation: none !important; transition: none; cursor: grabbing; }
.deck .profile-card.fly-left, .deck .profile-card.fly-right, .deck .profile-card.fly-up {
  animation: none !important;
  transition: transform .34s cubic-bezier(.4, 0, .9, .6), opacity .34s ease-in;
  opacity: 0; pointer-events: none;
}
.deck .profile-card.fly-left  { transform: translateX(-135%) rotate(-22deg) !important; }
.deck .profile-card.fly-right { transform: translateX(135%) rotate(22deg) !important; }
.deck .profile-card.fly-up    { transform: translateY(-120%) scale(.92) !important; }
.deck .profile-card:not(.dragging):not(.fly-left):not(.fly-right):not(.fly-up) {
  transition: transform .28s cubic-bezier(.2, .9, .3, 1.3);
}

/* The stamps. --lean runs from -1 (all the way to pass) to 1 (introduce). */
.stamp {
  position: absolute; top: 22px; z-index: 5; pointer-events: none;
  padding: 6px 12px; border: 4px solid currentColor;
  font: 900 1.35rem/1 var(--sans); letter-spacing: .12em; text-transform: uppercase;
  background: rgba(255, 250, 242, .85);
  opacity: 0; transition: opacity .1s linear;
}
.stamp-pass {
  right: 18px; color: var(--muted); transform: rotate(14deg);
  opacity: clamp(0, calc(var(--lean, 0) * -1.4), 1);
}
.stamp-like {
  left: 18px; color: var(--bead-green); transform: rotate(-14deg);
  opacity: clamp(0, calc(var(--lean, 0) * 1.4), 1);
}
.profile-card.fly-left .stamp-pass, .profile-card.fly-right .stamp-like { opacity: 1; }

/* The buttons: three beads, the middle one gold. */
.swipe-actions {
  display: flex !important; justify-content: center; align-items: center; gap: 22px;
  margin-top: 26px; filter: drop-shadow(0 6px 10px rgba(42, 26, 46, .22));
}
.deck-btn {
  position: relative; display: grid; place-items: center;
  width: 64px; height: 64px; padding: 0; border: 0; cursor: pointer;
  clip-path: circle(50%); font-size: 1.7rem; line-height: 1; color: #fff;
  transition: transform .12s ease;
  -webkit-tap-highlight-color: transparent;
}
.deck-btn:active { transform: scale(.88); }
.deck-btn:focus-visible { outline: none; transform: scale(1.06); }
.deck-btn.pass {
  background: radial-gradient(circle, #fff 0 58%, var(--line) 60%);
  color: var(--muted); font-weight: 900;
}
.deck-btn.like {
  width: 78px; height: 78px; font-size: 2.1rem;
  background: radial-gradient(circle at 35% 30%, #ff7a4d, var(--shuka) 62%, var(--shuka-deep));
}
.deck-btn.super {
  width: 56px; height: 56px; font-size: 1.45rem;
  background: radial-gradient(circle at 35% 30%, #ffe08a, var(--bead-yellow) 55%, var(--ochre));
  color: #fff; text-shadow: 0 1px 0 rgba(0, 0, 0, .2);
}
.deck-btn.super.spent { filter: grayscale(1); opacity: .55; }
.deck-btn.super.nudge { animation: btn-nudge .4s ease; }
.deck-btn-count {
  position: absolute; bottom: 7px; right: 50%; transform: translateX(50%);
  font: 800 .6rem/1 var(--sans); color: rgba(255, 255, 255, .95);
}
.deck-btn.super > span { margin-top: -6px; }
.deck-hint { margin: 12px 0 0; }

/* Beads bursting out of a button when somebody makes a hopeful move. */
.swipe-burst { position: absolute; z-index: 30; width: 0; height: 0; pointer-events: none; }
.swipe-burst span {
  position: absolute; left: -6px; top: -6px; width: 12px; height: 12px;
  clip-path: circle(50%); background: var(--shuka);
  animation: burst-out .8s cubic-bezier(.15, .7, .3, 1) forwards;
}
.swipe-burst span:nth-child(4n+2) { background: var(--bead-blue); }
.swipe-burst span:nth-child(4n+3) { background: var(--blush); }
.swipe-burst span:nth-child(4n)   { background: var(--bead-yellow); }
.swipe-burst.super span { background: var(--bead-yellow); }
.swipe-burst.super span:nth-child(odd) { background: #fff3c4; }
.swipe-burst b {
  position: absolute; left: 0; top: 0; transform: translate(-50%, -50%);
  font-size: 2.6rem; color: var(--shuka); animation: burst-heart .8s ease-out forwards;
}
.swipe-burst.super b { color: var(--bead-yellow); }
@keyframes burst-out {
  0%   { transform: rotate(var(--a)) translateY(0) scale(.6); opacity: 1; }
  100% { transform: rotate(var(--a)) translateY(calc(var(--d) * -1)) scale(1); opacity: 0; }
}
@keyframes burst-heart {
  0%   { transform: translate(-50%, -50%) scale(.3); opacity: 0; }
  35%  { transform: translate(-50%, -80%) scale(1.25); opacity: 1; }
  100% { transform: translate(-50%, -150%) scale(1); opacity: 0; }
}
@keyframes btn-nudge {
  0%, 100% { transform: translateX(0); }
  25% { transform: translateX(-5px); }
  75% { transform: translateX(5px); }
}

/* The super intro moment wears gold. */
.moment.keen { background: #fff6dc; border-color: var(--bead-yellow); }
.moment.keen .moment-mark { color: var(--bead-yellow); animation: hope-pulse 1.4s ease-in-out infinite; }
.moment.keen .moment-line { color: var(--ochre); }

@media (prefers-reduced-motion: reduce) {
  .deck .profile-card.fly-left, .deck .profile-card.fly-right, .deck .profile-card.fly-up,
  .deck .profile-card:not(.dragging):not(.fly-left):not(.fly-right):not(.fly-up) { transition: none; }
  .moment.keen .moment-mark, .deck-btn.super.nudge { animation: none; }
}

/* --- super intros and gifts, around the app --------------------------------------- */
.keen-toggle {
  display: flex; gap: 12px; align-items: center; cursor: pointer;
  padding: 12px 14px; background: #fff6dc; border: 2px solid var(--bead-yellow);
}
.keen-toggle input { width: 22px; height: 22px; flex: none; accent-color: var(--ochre); }
.keen-star { font-size: 1.6rem; color: var(--bead-yellow); line-height: 1; }
.keen-words { display: grid; gap: 2px; }
.keen-words strong { color: var(--ochre); }
.keen-words span { font-size: .82rem; color: var(--muted); line-height: 1.4; }
.keen-toggle.spent { filter: grayscale(.8); opacity: .7; cursor: default; }
.keen-toggle:has(input:checked) { background: var(--bead-yellow); }
.keen-toggle:has(input:checked) .keen-star,
.keen-toggle:has(input:checked) .keen-words strong { color: #fff; }
.keen-toggle:has(input:checked) .keen-words span { color: var(--earth); }

.keen-tag {
  display: inline-block; margin-left: 6px; padding: 2px 7px;
  background: var(--bead-yellow); color: var(--earth);
  font: 800 .66rem/1.3 var(--sans); letter-spacing: .06em; text-transform: uppercase;
}
.list-item.is-keen {
  border: 2px solid var(--bead-yellow);
  background: linear-gradient(90deg, #fff6dc, var(--surface) 70%);
}
.keen-banner, .keen-badge {
  display: inline-flex; align-items: center; gap: 8px; margin: 0 0 10px;
  padding: 6px 14px; background: var(--bead-yellow); color: var(--earth);
  font-weight: 800;
}
.keen-badge { font-size: .8rem; }

.gift-hint {
  margin: 0; padding: 10px 12px; font-size: .85rem; line-height: 1.45;
  background: #f2e8fd; border-left: 4px solid var(--bead-blue); color: var(--text);
}
.gift-banner {
  display: flex; gap: 10px; align-items: flex-start; text-align: left;
  margin: 10px 0 4px; padding: 12px 14px;
  background: #f2e8fd; border: 2px solid var(--bead-blue); font-size: .88rem; line-height: 1.45;
}
.gift-banner strong { display: block; color: var(--bead-blue); }
.gift-ico { font-size: 1.8rem; line-height: 1; }
.gift-card h2 { margin: 6px 0; }
html body .btn.gift {
  background: linear-gradient(135deg, var(--bead-blue), #9b55e0); color: #fff;
  border: 0; box-shadow: 0 4px 0 #163a75;
}

/* The buttons stay in reach while a long card scrolls under them, and the
 * one on the side the card is leaning towards swells as it goes. */
.swipe-actions {
  position: sticky; bottom: 10px; z-index: 6;
  padding: 8px 0 2px;
}
.deck-btn.pass { transform: scale(calc(1 + max(0, var(--lean, 0) * -1) * .28)); }
.deck-btn.like { transform: scale(calc(1 + max(0, var(--lean, 0)) * .28)); }
.deck-btn.pass:active, .deck-btn.like:active { transform: scale(.88); }
.swipe-actions .deck-btn { transition: transform .12s ease; }

/* Discover is for swiping: nothing floats over the buttons. */
body.discover-page .privacy-flag { display: none; }

/* On a phone the privacy flag is just its lock, so it never sits on top of
 * a button or a line of text. The words come back on a wider screen. */
@media (max-width: 560px) {
  .privacy-flag .flag-text { display: none; }
  .privacy-flag { padding: 9px; }
}

/* A long list of answers (faith has thirteen, some of them a church and its
 * examples) reads better as one column of shorter rows than two columns of
 * three-line ones. */
.q-options.long { grid-template-columns: 1fr; gap: 6px; }
html body .q-options.long .q-opt { min-height: 46px; padding-block: 8px; }

/* --- reporting ------------------------------------------------------------------ */
.report-box { margin-top: 14px; font-size: .85rem; }
.report-box summary {
  cursor: pointer; color: var(--muted); font-weight: 700; list-style: none;
  padding: 8px 0; text-align: center;
}
.report-box summary::-webkit-details-marker { display: none; }
.report-box[open] summary { color: var(--danger); }
.report-box form { padding: 12px; background: #fdf1ef; border: 2px solid #ffc2d8; }
.report-reasons { display: grid; gap: 6px; }
.hold-reason { padding: 10px 12px; background: var(--surface-2); border-left: 4px solid var(--shuka); }
.hold-steps { padding-left: 18px; line-height: 1.6; }

/* The serious-relationship pledge on the join form. */
.pledge {
  display: flex; gap: 12px; align-items: flex-start; cursor: pointer;
  padding: 14px; background: #fff6dc; border: 2px solid var(--bead-yellow);
  font-size: .9rem; line-height: 1.5;
}
.pledge input { margin-top: 3px; flex: none; }
.pledge strong { display: block; color: var(--earth); font-family: var(--serif); font-size: 1.05rem; }
.pledge:has(input:checked) { border-color: var(--bead-green); background: #eef7ec; }
.legit-badge.pledge-badge { color: var(--ochre); }

/* --- inputs with a beaded hand ---------------------------------------------------
 * Every field wears a strip of beads down its left edge (rose, cream, plum,
 * cream, gold, cream, blush), on warm paper, with a small drawn icon
 * for what goes in it. The strip flows while the field has the focus, so the
 * one being typed in is the one that is alive. Each label starts with a bead
 * of its own colour. Selectors start at `html` to win over the touch rules.
 */
:root {
  --bead-strip: linear-gradient(180deg,
      var(--shuka) 0 8px, var(--bead-white) 8px 10px,
      var(--bead-blue) 10px 18px, var(--bead-white) 18px 20px,
      var(--bead-yellow) 20px 28px, var(--bead-white) 28px 30px,
      var(--blush) 30px 38px, var(--bead-white) 38px 40px);
}
html input[type="text"], html input[type="email"], html input[type="password"],
html input[type="number"], html input[type="tel"], html input[type="date"],
html input[type="search"], html select, html textarea {
  border: 2px solid #e6cfa6; border-left-width: 0;
  background-color: #fffdf8;
  background-image: var(--bead-strip);
  background-repeat: repeat-y;
  background-size: 8px 40px;
  background-position: 0 0;
  padding-left: 22px;
  box-shadow: inset 0 -3px 0 rgba(227, 203, 166, .6);
}
html input::placeholder, html textarea::placeholder { color: #b39a7f; }

/* The icon for what goes in the field, drawn in earth brown. */
html input[type="email"], html input[type="password"], html input[type="tel"],
html input[type="search"], html input[name="display_name"], html input#city {
  background-image: var(--bead-strip), var(--ico);
  background-repeat: repeat-y, no-repeat;
  background-size: 8px 40px, 20px 20px;
  background-position: 0 0, 18px center;
  padding-left: 48px;
}
html input[type="email"] {
  --ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238a6a4f' stroke-width='2' stroke-linejoin='round'%3E%3Crect x='3' y='5' width='18' height='14'/%3E%3Cpath d='M3 6l9 7 9-7'/%3E%3C/svg%3E");
}
html input[type="password"] {
  --ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238a6a4f' stroke-width='2' stroke-linejoin='round'%3E%3Crect x='5' y='11' width='14' height='10'/%3E%3Cpath d='M8 11V7a4 4 0 0 1 8 0v4'/%3E%3C/svg%3E");
}
html input[type="tel"] {
  --ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238a6a4f' stroke-width='2' stroke-linejoin='round'%3E%3Crect x='7' y='2' width='10' height='20'/%3E%3Cpath d='M11 18h2'/%3E%3C/svg%3E");
}
html input[type="search"] {
  --ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238a6a4f' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cpath d='M16.5 16.5L21 21'/%3E%3C/svg%3E");
}
html input[name="display_name"] {
  --ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238a6a4f' stroke-width='2' stroke-linecap='round'%3E%3Ccircle cx='12' cy='8' r='4'/%3E%3Cpath d='M4 21c0-4 4-6 8-6s8 2 8 6'/%3E%3C/svg%3E");
}
html input#city {
  --ico: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%238a6a4f' stroke-width='2' stroke-linejoin='round'%3E%3Cpath d='M12 22s7-7 7-12a7 7 0 0 0-14 0c0 5 7 12 7 12z'/%3E%3Ccircle cx='12' cy='10' r='2.5'/%3E%3C/svg%3E");
}

/* The one being typed in: shuka red, and the beads flow. */
html input:focus, html select:focus, html textarea:focus {
  outline: none; border-color: var(--shuka); background-color: #fff;
  box-shadow: inset 0 -3px 0 var(--shuka), 0 0 0 4px rgba(var(--accent-rgb), .14);
  animation: bead-flow 1.6s linear infinite;
}
@keyframes bead-flow { to { background-position: 0 40px, 18px center; } }
@media (prefers-reduced-motion: reduce) {
  html input:focus, html select:focus, html textarea:focus { animation: none; }
}
/* Checkboxes and radios keep their own look. */
html input[type="checkbox"], html input[type="radio"] {
  background-image: none; padding: 0; border: 0; box-shadow: none; animation: none;
}

/* A bead before every field label, each its own colour down the form. */
.field > label::before {
  content: ""; display: inline-block; width: 10px; height: 10px;
  margin-right: 8px; vertical-align: 0;
  clip-path: circle(50%);
  background: radial-gradient(circle, var(--bead-white) 0 28%, var(--shuka) 30%);
}
.field:nth-of-type(5n+2) > label::before { background: radial-gradient(circle, var(--bead-white) 0 28%, var(--bead-blue) 30%); }
.field:nth-of-type(5n+3) > label::before { background: radial-gradient(circle, var(--bead-white) 0 28%, var(--blush) 30%); }
.field:nth-of-type(5n+4) > label::before { background: radial-gradient(circle, var(--bead-white) 0 28%, var(--bead-yellow) 30%); }
.field:nth-of-type(5n)   > label::before { background: radial-gradient(circle, var(--bead-white) 0 28%, var(--bead-orange) 30%); }
.field:focus-within > label { color: var(--shuka); }

/* Chip choices (who you are, who you want to meet) get beads too. */
.choices label { gap: 8px; }
.choices label::before {
  content: ""; width: 14px; height: 14px; flex: none; clip-path: circle(50%);
  background: radial-gradient(circle, var(--bead-white) 0 34%, var(--dot, var(--shuka)) 36%);
}
.choices label:nth-of-type(5n+2) { --dot: var(--bead-blue); }
.choices label:nth-of-type(5n+3) { --dot: var(--blush); }
.choices label:nth-of-type(5n+4) { --dot: var(--bead-yellow); }
.choices label:nth-of-type(5n)   { --dot: var(--bead-orange); }
.choices input:checked + label::before { background: radial-gradient(circle, var(--shuka) 0 34%, #fff 36%); }

/* --- the character picker: one card per family ---------------------------------
 * Each family (character, money, sport, into, screen, romance) is a card in
 * its own bead colour. Faces are round beads; the picked one fills with the
 * card's colour and gets a tick, and the card says it is done.
 */
.persona-groups { gap: 16px; }
.persona-group {
  --q: var(--shuka); --q-soft: var(--accent-soft);
  background: #fff; border-left: 5px solid var(--q);
  box-shadow: 0 1px 0 var(--line), 0 10px 26px rgba(70, 45, 25, .10);
  padding-bottom: 12px;
  transition: border-color .2s ease;
}
.persona-group:nth-child(5n+2) { --q: var(--bead-blue);   --q-soft: #efe3fb; }
.persona-group:nth-child(5n+3) { --q: var(--tone-2);      --q-soft: #f7e1fb; }
.persona-group:nth-child(5n+4) { --q: var(--ochre);       --q-soft: #fbefd0; }
.persona-group:nth-child(5n)   { --q: var(--tone-4);      --q-soft: #ffe0ea; }
.persona-group .group-head {
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px 10px;
  margin: 0; padding: 12px 14px 10px;
  background: linear-gradient(180deg, var(--q-soft), #fff);
  color: var(--q); font: 800 .82rem/1.2 var(--sans);
  letter-spacing: .12em; text-transform: uppercase;
}
.persona-group .group-head::before {
  content: ""; width: 16px; height: 16px; flex: none; clip-path: circle(50%);
  background: radial-gradient(circle, #fff 0 30%, transparent 32%),
              repeating-conic-gradient(var(--q) 0 30deg, var(--bead-white) 30deg 45deg);
}
.persona-group .group-head .muted {
  text-transform: none; letter-spacing: 0; font-weight: 600; color: var(--muted);
}
.persona-group:has(input:checked) { border-left-color: var(--bead-green); }
.persona-group:has(input:checked) .group-head::after {
  content: "\2713  Picked"; margin-left: auto;
  color: var(--bead-green); letter-spacing: .08em;
}
.persona-group .personas {
  margin: 8px 12px 0; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px;
}
html body .personas.compact .persona {
  position: relative; text-align: center; padding: 12px 6px 10px; gap: 6px;
  background: var(--bead-white); border: 2px solid var(--line-soft);
  box-shadow: 0 2px 0 var(--line-soft);
  transition: transform .1s ease, background-color .15s ease, border-color .15s ease;
}
html body .personas.compact .persona:hover { border-color: var(--q, var(--shuka)); }
html body .personas.compact .persona:active { transform: scale(.96); }
.personas.compact .persona .face {
  width: 50px; height: 50px; font-size: 1.4rem; clip-path: circle(50%);
  transition: transform .2s ease;
}
.personas.compact .persona strong {
  font-size: .7rem; letter-spacing: .06em; color: var(--earth); line-height: 1.25;
}
html body .personas input:checked + .persona {
  background: var(--q, var(--shuka)); border-color: var(--q, var(--shuka));
  box-shadow: 0 3px 0 rgba(0, 0, 0, .18);
  animation: q-pick .28s ease;
}
.personas input:checked + .persona strong { color: #fff; }
.personas input:checked + .persona .face { transform: scale(1.1); }
.personas input:checked + .persona::after {
  content: "\2713"; position: absolute; top: 5px; right: 5px;
  width: 18px; height: 18px; display: grid; place-items: center;
  background: #fff; color: var(--q, var(--shuka));
  font: 900 .7rem/1 var(--sans); clip-path: circle(50%);
}

/* --- adding a photo ---------------------------------------------------------------
 * A drop zone edged in beads, with a camera in a bead ring. Once a photo is
 * chosen it shows in the same 4:5 portrait frame the server crops to.
 */
.photo-drop { display: grid; gap: 8px; }
.photo-drop-input {
  position: absolute; width: 1px; height: 1px; opacity: 0; overflow: hidden;
}
.photo-drop-zone {
  display: grid; place-items: center; text-align: center; cursor: pointer;
  min-height: 190px; padding: 18px;
  background:
    linear-gradient(#fffdf8, #fffdf8) padding-box,
    repeating-linear-gradient(90deg, var(--shuka) 0 10px, var(--bead-white) 10px 14px,
      var(--bead-blue) 14px 24px, var(--bead-white) 24px 28px,
      var(--blush) 28px 38px, var(--bead-white) 38px 42px) border-box;
  border: 3px dashed transparent;
  transition: transform .12s ease, background-color .15s ease, box-shadow .2s ease;
}
.photo-drop-zone:hover, .photo-drop.dragging .photo-drop-zone {
  box-shadow: 0 0 0 4px rgba(var(--accent-rgb), .14);
}
.photo-drop.dragging .photo-drop-zone { transform: scale(1.01); }
.photo-drop-input:focus-visible + .photo-drop-zone { outline: 3px solid var(--bead-blue); outline-offset: 3px; }
.photo-drop-empty { display: grid; justify-items: center; gap: 6px; color: var(--muted); font-size: .88rem; }
.photo-drop-empty strong { color: var(--earth); font: 700 1.1rem/1.2 var(--serif); }
.photo-drop-ico {
  width: 66px; height: 66px; display: grid; place-items: center; color: var(--shuka);
  background:
    radial-gradient(circle, #fff 0 60%, transparent 61%),
    repeating-conic-gradient(var(--shuka) 0 18deg, var(--bead-white) 18deg 30deg);
  clip-path: circle(50%);
}
.photo-drop-preview { display: block; width: min(240px, 70%); }
.photo-drop-preview img {
  display: block; width: 100%; aspect-ratio: 4 / 5; object-fit: cover;
  border: 3px solid transparent;
  background: var(--wristband-edge) border-box;
  animation: q-pick .3s ease;
}
.photo-drop.has-photo .photo-drop-zone { min-height: 0; padding: 14px; }
.photo-drop-meta { margin: 0; font-size: .82rem; color: var(--muted); line-height: 1.45; }
.photo-drop-change { justify-self: center; }

/* Photos already in the library: the same portrait frame. */
.library-photo {
  display: block; width: 100%; max-width: 360px; margin: 0 auto;
  aspect-ratio: 4 / 5; object-fit: cover;
}

/* --- the tab bar: always say where you are ------------------------------------------
 * The current tab fills with shuka red, its icon and label go white and
 * bold, and a bead sits over it, so the bar answers "where am I" at a glance
 * on every screen, including the ones under a tab (questions, location,
 * checkout).
 */
html body:not(.no-app) .tabbar a.on {
  color: #fff; font-weight: 800;
  background: linear-gradient(180deg, var(--shuka), var(--shuka-deep));
}
html body:not(.no-app) .tabbar a.on .ico,
html body:not(.no-app) .tabbar a.on > span:last-child { color: #fff; }
html body:not(.no-app) .tabbar a.on .ico::before { background: rgba(255, 255, 255, .2); }
html body:not(.no-app) .tabbar a.on::after {
  content: ""; position: absolute; top: 3px; left: 50%; width: 8px; height: 8px;
  transform: translateX(-50%); clip-path: circle(50%);
  background: var(--bead-yellow);
}

/* Headings between groups of questions on the join form. */
.q-group-head {
  margin: 22px 0 10px; font: 700 1.15rem/1.2 var(--serif); color: var(--earth);
}
.q-group-head span {
  display: block; margin-top: 2px; font: 500 .82rem/1.4 var(--sans); color: var(--muted);
}
.pick-count, .life-count { margin: 6px 0 0; font-weight: 700; }
.interest-choices label { text-transform: capitalize; }
/* The drop zone is a <label>, so it must not inherit the small-caps field label look. */
html body .photo-drop-zone, html body .photo-drop-zone span {
  text-transform: none; letter-spacing: 0; font-weight: 500;
}
html body .photo-drop-zone strong { font: 700 1.15rem/1.2 var(--serif); letter-spacing: 0; }

/* --- serious only, on the homepage ------------------------------------------------ */
.serious-strap {
  display: inline-block; margin: -2px 0 12px; padding: 5px 12px;
  background: var(--earth); color: var(--bead-white);
  font: 800 .78rem/1.3 var(--sans); letter-spacing: .08em; text-transform: uppercase;
}
.serious-card h2 { color: var(--earth); }
.serious-list { list-style: none; padding: 0; margin: 10px 0 0; display: grid; gap: 10px; text-align: left; }
.serious-list li {
  position: relative; padding: 10px 12px 10px 42px; font-size: .9rem; line-height: 1.5;
  background: var(--bead-white); border-left: 4px solid var(--bead-green);
}
.serious-list li::before {
  content: "\2713"; position: absolute; left: 10px; top: 10px;
  width: 22px; height: 22px; display: grid; place-items: center;
  background: var(--bead-green); color: #fff; font: 900 .75rem/1 var(--sans);
  clip-path: circle(50%);
}
.serious-list b { color: var(--earth); }

/* --- safe places for a first date ---------------------------------------------- */
.date-ideas { border-left: 5px solid var(--bead-green); }
.date-ideas summary {
  display: flex; gap: 10px; align-items: center; cursor: pointer; list-style: none;
}
.date-ideas summary::-webkit-details-marker { display: none; }
.date-ideas-ico {
  width: 40px; height: 40px; flex: none; display: grid; place-items: center; font-size: 1.2rem;
  background: radial-gradient(circle, #fff 0 58%, transparent 60%),
              repeating-conic-gradient(var(--bead-green) 0 18deg, var(--bead-white) 18deg 30deg);
  clip-path: circle(50%);
}
.date-ideas-list { display: grid; gap: 10px; margin-top: 12px; }
.date-ideas-list.wide { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
.date-spot {
  display: grid; gap: 4px; padding: 12px; background: var(--bead-white);
  border: 2px solid var(--line-soft); box-shadow: 0 2px 0 var(--line-soft);
}
.date-spot strong { font-family: var(--serif); font-size: 1.05rem; color: var(--earth); }
.date-spot-head { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
.date-kind {
  padding: 2px 8px; background: var(--earth); color: var(--bead-white);
  font: 800 .64rem/1.4 var(--sans); letter-spacing: .08em; text-transform: uppercase;
}
.date-partner {
  padding: 2px 8px; background: var(--bead-yellow); color: var(--earth);
  font: 800 .64rem/1.4 var(--sans); letter-spacing: .08em; text-transform: uppercase;
}
.date-price { margin-left: auto; font-size: .72rem; font-weight: 800; color: var(--ochre); }
.date-safe { color: var(--bead-green); }
.date-spot form { margin-top: 6px; }
.date-tips { margin: 10px 0 0; }

/* --- height, against a door ------------------------------------------------------
 * Five narrow tiles, each a person beside a standard 2.1 m door with a dashed
 * line at the top of their head, then the band, the centimetres and the feet.
 */
.q-options.figures { grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 6px; }
html body .q-options .q-opt.q-fig {
  flex-direction: column; justify-content: flex-start; gap: 2px; text-align: center;
  padding: 8px 2px 10px; min-height: 0;
}
.q-opt.q-fig::before { display: none; }
.door-fig { width: 100%; max-width: 64px; height: auto; color: var(--earth); }
.door-fig .door { fill: #f3e2c4; stroke: currentColor; stroke-width: 1.4; }
.door-fig .door-panel { fill: none; stroke: currentColor; stroke-width: .8; opacity: .45; }
.door-fig .knob { fill: currentColor; }
.door-fig .mark { stroke: var(--shuka); stroke-width: 1; stroke-dasharray: 2 2; }
.door-fig .body { fill: var(--q, var(--shuka)); }
.door-fig .ground { stroke: currentColor; stroke-width: 1.2; opacity: .5; }
.fig-name { font-weight: 800; font-size: .74rem; line-height: 1.15; }
.fig-cm { font-size: .62rem; line-height: 1.2; color: var(--muted); }
.fig-ft { font-size: .58rem; line-height: 1.2; color: var(--muted); }
.q-options input:checked + .q-opt.q-fig .door-fig { color: #fff; }
.q-options input:checked + .q-opt.q-fig .door-fig .door { fill: rgba(255, 255, 255, .18); }
.q-options input:checked + .q-opt.q-fig .door-fig .body,
.q-options input:checked + .q-opt.q-fig .door-fig .mark { fill: #fff; stroke: #fff; }
.q-options input:checked + .q-opt.q-fig .fig-cm,
.q-options input:checked + .q-opt.q-fig .fig-ft { color: rgba(255, 255, 255, .9); }
.fig-note { margin-top: 0; }
@media (max-width: 359px) { .q-options.figures { grid-template-columns: repeat(3, minmax(0, 1fr)); } }

/* --- what is left to answer ---------------------------------------------------------
 * A panel at the top of the questions page naming every unanswered question,
 * each a tap away, ticking itself off as they are answered. A switch hides
 * everything already done. Unanswered cards are tinted and ringed in red.
 */
.todo-panel {
  margin: 10px 0 16px; padding: 14px; background: #fff;
  border: 2px solid var(--shuka); border-left-width: 6px;
  box-shadow: 0 10px 24px rgba(var(--accent-rgb), .12);
}
.todo-head { display: grid; gap: 2px; margin-bottom: 10px; }
.todo-count { font: 700 1.35rem/1.1 var(--serif); color: var(--shuka); }
.todo-count b { font-size: 1.7rem; }
.todo-sub { font-size: .85rem; color: var(--muted); }
.todo-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.todo-list a {
  display: flex; align-items: center; gap: 10px; min-height: 48px; padding: 8px 12px;
  background: #fdf1ef; border: 2px solid #ffc2d8; color: var(--text); font-weight: 700;
}
.todo-list a:hover { border-color: var(--shuka); }
.todo-ico { font-size: 1.2rem; width: 26px; text-align: center; }
.todo-label { flex: 1; }
.todo-go {
  padding: 4px 10px; background: var(--shuka); color: #fff;
  font: 800 .7rem/1.3 var(--sans); letter-spacing: .08em; text-transform: uppercase;
}
.todo-list li.done a { background: #eef7ec; border-color: #bfdcb9; color: var(--muted); }
.todo-list li.done .todo-label { text-decoration: line-through; }
.todo-list li.done .todo-go { background: var(--bead-green); }
.todo-list li.done .todo-go::before { content: "\2713  "; }
.todo-panel.all-done { border-color: var(--bead-green); box-shadow: none; }
.todo-panel.all-done .todo-count { color: var(--bead-green); }
.todo-only { display: flex; gap: 8px; align-items: center; margin-top: 12px; font-weight: 700; cursor: pointer; }

/* The switch: only what was left when the page opened. questions.js puts
   .only-left on body while it is ticked (a class rather than body:has(),
   which re-checks the whole page on every change). */
body.only-left .q-card:not(.needed),
body.only-left .q-group.all-done { display: none; }

/* Unanswered cards stand out, and land clear of the top when jumped to. */
.q-card { scroll-margin-top: 14px; }
.q-card.needed:not(:has(input:checked)) {
  background: #fff8f7;
  box-shadow: 0 0 0 2px #ffc2d8, 0 10px 26px rgba(var(--accent-rgb), .12);
}
.q-card.needed:not(:has(input:checked)) .q-ico {
  background:
    radial-gradient(circle, #fff 0 60%, transparent 61%),
    repeating-conic-gradient(var(--shuka) 0 18deg, var(--bead-white) 18deg 30deg);
}
.q-card:target { animation: q-done .8s ease; }
