/* Noto Sans Georgian, self-hosted (SIL Open Font License 1.1).
   Served from our own origin rather than fonts.googleapis.com: that request
   handed Google the IP address of every visitor, was never disclosed in the
   privacy policy, and blocked first render on a third-party host.

   One file per subset, because Google serves the same variable font for every
   weight — `font-weight: 400 700` lets the browser interpolate instead of
   downloading three copies. Basic Cyrillic (U+0400-045F) is absent from this
   family entirely, so Russian text falls back to system-ui exactly as it
   always has. */
/* The typeface of the 2026 design is Outfit — a geometric sans, and a good part
   of how the mockup reads. It has no Cyrillic at all, so Russian is set in
   Manrope, the nearest geometric face that does, and Georgian stays on Noto
   Sans Georgian. The browser picks per glyph from the unicode-ranges below, so
   one stack serves all three languages without a wrong glyph anywhere.
   Both are OFL, self-hosted like the Georgian face — no third-party request. */
@font-face {
  font-family: "Guli Sans"; font-style: normal; font-weight: 400 700;
  font-display: swap; src: url("/static/fonts/outfit-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
                 U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Guli Sans"; font-style: normal; font-weight: 400 700;
  font-display: swap; src: url("/static/fonts/outfit-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
                 U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB,
                 U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Guli Sans"; font-style: normal; font-weight: 400 700;
  font-display: swap; src: url("/static/fonts/manrope-cyrillic.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: "Guli Sans"; font-style: normal; font-weight: 400 700;
  font-display: swap; src: url("/static/fonts/manrope-cyrillic-ext.woff2") format("woff2");
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}

@font-face {
  font-family: "Noto Sans Georgian"; font-style: normal; font-weight: 400 700;
  font-display: swap; src: url("/static/fonts/noto-sans-georgian-georgian.woff2") format("woff2");
  unicode-range: U+0589, U+10A0-10FF, U+1C90-1CBA, U+1CBD-1CBF, U+205A, U+2D00-2D2F, U+2E31;
}
@font-face {
  font-family: "Noto Sans Georgian"; font-style: normal; font-weight: 400 700;
  font-display: swap; src: url("/static/fonts/noto-sans-georgian-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
                 U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Noto Sans Georgian"; font-style: normal; font-weight: 400 700;
  font-display: swap; src: url("/static/fonts/noto-sans-georgian-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
                 U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB,
                 U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

:root {
  /* One source of truth: design/tokens.json → app/static/tokens.css, which is
     loaded before this file. Everything below is an alias, kept so the older
     component rules keep reading the names they were written with. Never put a
     literal here — change tokens.json and re-run scripts/gen_tokens.py. */
  --wine: var(--c-accent);
  --wine-dark: var(--c-accent-dark);
  --gold: var(--c-star);
  --green: var(--c-like);
  --ink: var(--c-ink);
  --muted: var(--c-muted);
  --bg: var(--c-bg);
  --card: #ffffff;
  --fill: #f5efe7;
  --line: #ece3d8;
  --accent-tint: var(--c-accent-tint);
  --accent-tint-mid: var(--c-accent-tint-mid);
  --wine-soft: var(--c-accent-tint);

  --radius: 18px;
  --radius-lg: var(--r-topbar);
  --radius-nav: var(--r-nav);
  --radius-card: var(--r-card);
  --radius-panel: var(--r-panel);
  --radius-bubble: var(--r-bubble);
  --radius-pill: var(--r-pill);

  --shadow: 0 10px 30px rgba(90, 40, 30, .10);
  --shadow-float: var(--glass-float-shadow);
  --shadow-card: var(--glass-card-shadow);
  --shadow-photo: 0 20px 60px rgba(80, 20, 40, .2);

  --glass-float: var(--glass-float-bg);
  --glass-card: var(--glass-card-bg);
  --glass-pill: var(--glass-pill-bg);
  --glass-pill-dark: var(--glass-pill-dark-bg);
}

* { box-sizing: border-box; }
body {
  margin: 0; background: var(--c-bg); color: var(--c-ink);
  /* The blobs live in .guli-orbs (generated, with the prototype's own sizes and
     offsets) rather than on the body — they are a layer behind the column, not
     a page background, and only that keeps their absolute offsets honest. */
  font-family: "Guli Sans", "Noto Sans Georgian", system-ui, -apple-system, sans-serif;
  line-height: 1.5;
}
/* Everything sits in one 430px column, as the prototype's shell does.
   The bars are inset by the gutter *within* that column, so their cap is the
   column minus both gutters — capping them at the full 430 made them stretch
   edge to edge on any window wider than the column, which is exactly where
   screenshots are taken. */
.wrap { max-width: var(--s-shell-max); margin-inline: auto; }
.topbar, .tabbar {
  max-width: calc(var(--s-shell-max) - var(--s-gutter) * 2);
  margin-inline: auto;
}
/* A single element wider than the column used to widen the document and shove
   the whole column sideways — at 430px that is one long word away. Nothing
   scrolls horizontally here by design. */
/* No sideways page: overflow-x clips what shadows/modals may paint past the
   edge (fixed overlays are unaffected), overscroll-behavior-x kills the
   horizontal rubber-band/навигационный overscroll a card drag could trigger.
   Vertical scroll and overscroll stay native. */
html, body { overflow-x: hidden; overscroll-behavior-x: none; }
.topbar > * { min-width: 0; }
a { color: var(--wine); text-decoration: none; }
a:hover { text-decoration: underline; }

/* ---- top bar ---- */
/* The prototype's bar: a 52px glass pill inset by the 16px gutter, radius 26,
   holding the mark and the name and nothing else. Sticky rather than fixed so
   it stays in the flow and no page needs top padding of its own. */
.topbar {
  display: flex; align-items: center; justify-content: space-between;
  height: var(--s-topbar-h); padding: 0 12px;
  width: calc(100% - var(--s-gutter) * 2);
  background: var(--glass-float-bg);
  -webkit-backdrop-filter: blur(var(--glass-float-blur));
  backdrop-filter: blur(var(--glass-float-blur));
  border: 1px solid var(--glass-float-line);
  border-radius: var(--r-topbar); box-shadow: var(--glass-float-shadow);
  position: sticky; z-index: 200;
  /* The shell reserves the notch and then 20px, so the bar starts where the
     prototype's does. */
  top: max(env(safe-area-inset-top, 20px), 20px);
  margin-top: max(env(safe-area-inset-top, 20px), 20px);
  /* mb-1 in the prototype — the gap under the bar is 4, not the page gutter. */
  margin-bottom: 4px;
}
/* Deletion page: the losses spelled out, then a box that has to be ticked. */
.top-left { display: flex; align-items: center; gap: 10px; min-width: 0; }
/* Back is the chat header's own control in the design: a 36px glass circle with
   an accent chevron. Same part here, so inner pages read as the same product. */
.topback {
  width: 36px; height: 36px; flex: none; display: grid; place-items: center;
  border-radius: 50%; cursor: pointer; color: var(--c-accent);
  background: var(--glass-pill-bg);
  -webkit-backdrop-filter: blur(var(--glass-pill-blur));
  backdrop-filter: blur(var(--glass-pill-blur));
  border: 1px solid var(--glass-pill-line);
  transition: transform .12s ease;
}
.topback:active { transform: scale(.9); }
.brand { display: flex; align-items: center; gap: 10px; font-weight: 700; min-width: 0; }
.brand:hover { text-decoration: none; }
.brand-mark {
  width: var(--s-logo); height: var(--s-logo); flex: none;
  display: grid; place-items: center;
  border-radius: var(--r-logo); background: var(--c-accent);
}
.brand-name { color: var(--c-ink); font-size: var(--t-chat-name); line-height: 1;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.top-right { display: flex; align-items: center; gap: 10px; flex: 0 1 auto; }
.nav { display: flex; gap: 18px; align-items: center; font-weight: 600; }
.nav a { color: var(--ink); }
.nav a.muted { color: var(--muted); font-weight: 400; }
.lang-switch { display: flex; gap: 2px; background: #f3ede4; border-radius: 999px; padding: 3px; }
.lang-switch .lang {
  font-size: .78rem; font-weight: 700; color: var(--muted); padding: 4px 8px;
  border-radius: 999px; line-height: 1;
}
.lang-switch .lang:hover { text-decoration: none; color: var(--wine); }
.lang-switch .lang.active { background: var(--wine); color: #fff; }

/* The content column: the prototype's 430px shell with a 16px gutter. */
/* pt-3 in the prototype for the list screens; the feed sits tighter (mt-1). */
/* --web-chrome is zero on the web — the screens own their top edge. Inside
   Telegram the same variable carries the Fullscreen Mode insets (--tg-top,
   published by tg.js), so every clearance rule below serves the Mini App
   and costs the web nothing. */
:root { --web-chrome: 0px; }
/* Inside Telegram the strip itself never draws, but in Fullscreen Mode the
   app sits under the phone's status bar and Telegram's floating controls —
   tg.js publishes that inset as --tg-top, and mapping the shared variable to
   it lets every clearance rule serve both worlds. Old clients (no
   fullscreen): the inset is 0 and everything is as before. */
html.tg-app { --web-chrome: var(--tg-top, 0px); }
/* Straight under the top edge (web) or the fullscreen insets (Telegram). */
.wrap { padding: max(12px, env(safe-area-inset-top, 0px)) var(--s-gutter) 40px; }
.wrap.has-chrome { padding-top: calc(var(--web-chrome) + 12px); }
.wrap.feed.has-chrome { padding-top: calc(var(--web-chrome) + 4px); }
.wrap.profile.has-chrome { padding-top: calc(var(--web-chrome) + 8px); }
/* The chat's own header slides under the strip too. */
.topbar.chatbar { margin-top: var(--web-chrome); }
.wrap.feed { padding-top: 4px; }
/* The profile card sits 4px lower than the deck's — mt-2 against the feed's
   own inset, as the design has it. */
.wrap.profile { padding-top: 8px; }
/* Room for the floating nav: 72 tall, 16 clear of the bottom, 16 of air. */
.wrap.has-bottomnav { padding-bottom: calc(var(--s-nav-h) + var(--s-gutter) * 2 + 16px + var(--tg-bottom, 0px)); }


/* ---- bottom navigation ---- */
/* The prototype's bar: 72 tall, radius 33, inset by the gutter, floating 16px
   clear of the bottom edge. Four icons, no labels — the words live in each
   screen's own heading. */
.tabbar {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(var(--s-gutter) + env(safe-area-inset-bottom, 0px) + var(--tg-bottom, 0px));
  width: calc(100% - var(--s-gutter) * 2);
  height: var(--s-nav-h); z-index: 150;
  display: flex; align-items: center; justify-content: space-around;
  padding: 0 8px;
  background: var(--glass-float-bg);
  -webkit-backdrop-filter: blur(var(--glass-float-blur));
  backdrop-filter: blur(var(--glass-float-blur));
  border: 1px solid var(--glass-float-line);
  border-radius: var(--r-nav); box-shadow: var(--glass-float-shadow);
}
.tabbar a {
  flex: 1; display: grid; place-items: center; padding: 8px 0;
  transition: transform .12s ease;
}
.tabbar a:hover { text-decoration: none; }
.tabbar a:active { transform: scale(.9); }
/* The icon sits in a 44px circle that only the active tab fills and outlines. */
.tab-ico {
  position: relative; width: var(--s-nav-icon-box); height: var(--s-nav-icon-box);
  display: grid; place-items: center; border-radius: calc(var(--s-nav-icon-box) / 2);
  border: 1.5px solid transparent; color: rgba(0, 0, 0, .32);
  transition: color .2s ease, background .2s ease, border-color .2s ease;
}
.tab-ico svg { width: var(--s-nav-icon-off); height: var(--s-nav-icon-off); }
.tabbar a.active .tab-ico {
  color: var(--c-accent); background: var(--c-accent-tint); border-color: var(--c-accent);
}
.tabbar a.active .tab-ico svg { width: var(--s-nav-icon-on); height: var(--s-nav-icon-on); }
/* Discover is the one tab whose icon fills when active — the design's way of
   saying the heart is the home screen. */
.tabbar a.active[href="/discover"] .tab-ico svg { fill: var(--c-accent); }
.tab-badge {
  position: absolute; top: 2px; right: 2px; min-width: 16px; height: 16px; padding: 0 4px;
  border-radius: 999px; background: var(--c-accent); color: #fff;
  font-size: .62rem; font-weight: 700; display: grid; place-items: center;
  border: 2px solid #fff; line-height: 1;
}

/* Admin quick panel (admins only), sits above the main nav */

/* Messages inbox */
.chat-inbox { margin-top: 12px; display: flex; flex-direction: column; }
.inbox-row {
  display: flex; align-items: center; gap: 12px; padding: 12px 4px;
  border-bottom: 1px solid var(--line); color: var(--ink);
}
.inbox-row:hover { text-decoration: none; }
.inbox-avatar {
  width: 54px; height: 54px; border-radius: 50%; overflow: hidden; flex-shrink: 0;
  background: #f0e6da; display: grid; place-items: center; font-size: 24px;
}
.inbox-avatar img { width: 100%; height: 100%; object-fit: cover; }
.inbox-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.inbox-main strong { display: flex; align-items: center; }
.inbox-preview {
  color: var(--muted); font-size: .9rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.inbox-row.is-unread .inbox-preview { color: var(--ink); font-weight: 600; }
.nav-logout { font-weight: 400; }

/* ---- profile header (premium) ---- */
.profile-header {
  display: flex; align-items: center; gap: 14px; margin-top: 4px;
  background: linear-gradient(135deg, #fff, #fbf5ef); border: 1px solid var(--line);
  border-radius: 20px; padding: 16px; box-shadow: var(--shadow);
}
.ph-avatar { position: relative; width: 72px; height: 72px; flex-shrink: 0; }
.ph-ring { position: absolute; inset: 0; width: 72px; height: 72px; transform: rotate(-90deg); }
.ph-ring-bg { fill: none; stroke: #eadfce; stroke-width: 4; }
.ph-ring-fg {
  fill: none; stroke: url(#phg); stroke-width: 4; stroke-linecap: round;
  stroke-dasharray: 207.3; transition: stroke-dashoffset .5s ease;
}
.ph-photo {
  position: absolute; inset: 6px; border-radius: 50%; overflow: hidden;
  background: #f0e6da; display: grid; place-items: center; font-size: 30px;
}
.ph-photo img { width: 100%; height: 100%; object-fit: cover; }
.ph-info { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.ph-info h2 { margin: 0; font-size: 1.25rem; display: flex; align-items: center; }
.ph-complete { color: var(--wine); font-weight: 600; font-size: .82rem; }
.ph-edit {
  flex-shrink: 0; width: 40px; height: 40px; border-radius: 12px; display: grid; place-items: center;
  background: #fff; border: 1px solid var(--line); color: var(--wine); align-self: flex-start;
}
.ph-edit svg { width: 18px; height: 18px; }
.ph-edit:hover { border-color: var(--wine); text-decoration: none; }

/* The "your profile is hidden" notice. It used to be a solid pink block capped
   at 400px — louder than anything around it and narrower than the column, so it
   read as a warning stuck onto the page. Now it is the same glass as every
   other card, tinted just enough to be noticed, and full width like its
   neighbours. */
.pause-banner {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  background: rgba(234, 47, 92, .06); border: 1px solid var(--accent-tint-mid);
  -webkit-backdrop-filter: blur(20px); backdrop-filter: blur(20px);
  color: var(--wine-dark); border-radius: var(--radius-panel);
  padding: 14px 16px; margin: 0 0 14px; font-size: 14px; font-weight: 500;
}
.pause-banner .btn { flex-shrink: 0; }
@media (max-width: 420px) {
  /* On a phone the sentence and the button stop fitting side by side. */
  .pause-banner { flex-direction: column; align-items: stretch; text-align: left; }
  .pause-banner .btn { width: 100%; }
}

/* These lists are rows now, so the like-back buttons sit at the end of the row
   rather than floating over a card photo. */
.like-cell { position: relative; }
.like-actions { display: flex; gap: 8px; align-items: center; flex-shrink: 0; }
.lb-btn {
  width: 42px; height: 42px; border-radius: 50%; border: none;
  box-shadow: 0 2px 10px rgba(0, 0, 0, .10);
  font-size: 17px; cursor: pointer; display: grid; place-items: center; padding: 0;
  transition: transform .12s ease;
}
.lb-pass { background: rgba(255, 255, 255, .94); color: #d94040; }
.lb-yes { background: var(--wine); color: #fff; font-size: 19px; box-shadow: 0 4px 14px rgba(107, 30, 46, .33); }
.lb-btn:active { transform: scale(.9); }
.lb-btn[disabled] { opacity: .55; }
.lb-matched {
  background: var(--wine); color: #fff; padding: 12px 18px; border-radius: 999px;
  font-weight: 600; box-shadow: var(--shadow); white-space: nowrap;
}
.lb-matched:hover { text-decoration: none; color: #fff; }
a.stat-tile:hover { text-decoration: none; }

/* verification badge (blue check) */
.verified-badge {
  display: inline-grid; place-items: center; width: 20px; height: 20px; margin-left: 6px;
  background: #1d9bf0; color: #fff; border-radius: 50%; font-size: 12px; font-weight: 700;
  vertical-align: middle; line-height: 1; flex-shrink: 0;
}
.verified-badge.sm { width: 16px; height: 16px; font-size: 10px; margin-left: 4px; }
.verified-pill {
  display: inline-flex; align-items: center; gap: 6px; background: #e8f5fe; color: #1d9bf0;
  border: 1px solid #bfe3fb; border-radius: 999px; padding: 5px 14px; font-weight: 700;
  font-size: .85rem; margin: 4px 0 2px;
}
.verified-tick { font-size: .9rem; }
.report-btn { position: absolute; top: 12px; left: 12px; width: 34px; height: 34px;
  border-radius: 50%; border: none; background: rgba(0,0,0,.35); color: #fff; font-size: 16px;
  cursor: pointer; line-height: 1; }
.report-btn:hover { background: rgba(178,58,72,.85); }
/* Telegram sign-in button — glass, tuned for the light auth card. */
.tg-login { margin-bottom: 6px; }
.tg-login .or-divider { margin: 14px 0 4px; }
.btn-tg-glass {
  display: flex; align-items: center; justify-content: center; gap: 9px;
  width: 100%; margin: 10px 0 2px; padding: 13px 20px;
  font-weight: 700; font-size: 1rem; text-decoration: none;
  color: var(--wine); border-radius: 999px;
  background: linear-gradient(180deg, rgba(255,255,255,.75), rgba(255,255,255,.45));
  border: 1px solid rgba(122, 31, 43, .22);
  box-shadow: 0 4px 16px rgba(122, 31, 43, .10), inset 0 1px 0 rgba(255,255,255,.9);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  transition: transform .12s ease, box-shadow .12s ease, background .12s ease;
}
.btn-tg-glass:hover {
  text-decoration: none;
  background: linear-gradient(180deg, rgba(255,255,255,.9), rgba(255,255,255,.6));
  box-shadow: 0 6px 20px rgba(122, 31, 43, .16), inset 0 1px 0 rgba(255,255,255,.95);
}
.btn-tg-glass:active { transform: translateY(1px); }
.btn-tg-glass .tg-ico { width: 22px; height: 22px; color: #29a9eb; flex: none; }
/* Same glass button, Facebook's own blue on the mark. */
.btn-tg-glass .fb-ico { width: 22px; height: 22px; color: #1877f2; flex: none; }
/* Clear-conversation button in the chat header. */
.chat-clear { margin-left: auto; }
.chat-clear-btn {
  background: none; border: 0; cursor: pointer; font-size: 1.05rem;
  padding: 6px 8px; border-radius: 10px; opacity: .55; line-height: 1;
}
.chat-clear-btn:hover { opacity: 1; background: rgba(122, 31, 43, .08); }
.btn-tg-glass.btn-inline { width: auto; display: inline-flex; }
.btn-tg-glass.center-block { margin: 0 auto 12px; }
.btn-tg-glass .lp-tg-ico { width: 22px; height: 22px; color: #29a9eb; flex: none; }
.lp-author { text-align: center; }
.lp-author p { color: #5c524c; max-width: 460px; margin: 0 auto 18px; }
.lp-author-h { color: var(--muted) !important; font-size: .86rem; margin-top: 10px !important; }

.or-divider { text-align: center; color: var(--muted); margin: 8px 0; position: relative; }
.or-divider span { background: var(--card); padding: 0 10px; position: relative; z-index: 1; font-size: .82rem; }
.or-divider::before { content: ''; position: absolute; left: 0; right: 0; top: 50%; height: 1px; background: var(--line); }

/* admin moderation */

/* ---- welcome ---- */
.welcome { max-width: 480px; margin: 0 auto; text-align: center; padding: 10px 4px 30px; }
.welcome-heart { font-size: 56px; }
.welcome h1 { font-size: 26px; font-weight: 700; color: var(--ink); margin: 8px 0 18px; line-height: 1.3; }
.welcome p { color: #4a423d; margin: 14px 0; font-size: 1.02rem; }
.welcome .welcome-em { color: var(--wine-dark); font-weight: 600; }
.welcome .welcome-strong { font-weight: 700; color: var(--ink); font-size: 1.1rem; }
.welcome .welcome-sign { color: var(--muted); font-style: italic; margin-top: 6px; }
.welcome-cta { margin-top: 22px; }

/* ---- hero ---- */
.hero { text-align: center; padding: 30px 0; }
.hero-badge {
  display: inline-block; background: #fff; border: 1px solid var(--line);
  padding: 6px 14px; border-radius: 999px; font-weight: 600; color: var(--wine);
  box-shadow: var(--shadow);
}
.hero h1 { font-size: 2.3rem; margin: 20px 0 12px; line-height: 1.2; }
.accent { color: var(--wine); }
.lead { color: #5c524c; max-width: 520px; margin: 0 auto 26px; font-size: 1.08rem; }
.cta-row { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }
.cta-row.center { justify-content: center; }
.feature-list {
  list-style: none; padding: 0; margin: 40px auto 0; max-width: 460px;
  display: grid; gap: 14px;
}
.feature-list li {
  background: var(--card); border: 1px solid var(--line); border-radius: 14px;
  padding: 16px 18px; text-align: left; display: flex; flex-direction: column;
}
.feature-list strong { color: var(--wine); }
.feature-list span { color: var(--muted); font-size: .94rem; }

/* ---- landing (promo, liquid glass) ---- */
/* The landing breaks out of the narrow app .wrap to run full-bleed. */
.wrap:has(.lp-hero) { max-width: none; padding: 0; }

/* dark ambient hero */
.lp-hero {
  /* The 2026 design has no dark slab anywhere: the page is warm paper with
     glass floating on it, so the hero is lit the same way as every screen
     behind the login. */
  color: var(--ink); overflow: hidden;
  background:
    radial-gradient(620px circle at 10% 12%, rgba(234, 47, 92, .10), transparent 58%),
    radial-gradient(560px circle at 92% 96%, rgba(200, 130, 160, .12), transparent 58%),
    radial-gradient(400px circle at 78% 6%, rgba(210, 170, 200, .10), transparent 60%),
    var(--bg);
}
.lp-hero-inner {
  max-width: 980px; margin: 0 auto; padding: 40px 22px 48px;
  display: grid; grid-template-columns: 1fr; gap: 30px; align-items: center;
}
.lp-badge {
  display: inline-block; background: var(--glass-pill); border: 1px solid var(--glass-pill-line);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
  color: var(--wine);
  padding: 6px 14px; border-radius: 999px; font-weight: 700; font-size: .82rem;
}
.lp-hero h1 { font-size: 2.4rem; line-height: 1.12; margin: 18px 0 12px; text-wrap: balance; font-weight: 800; letter-spacing: -.02em; }
.lp-hero h1 .accent { color: var(--wine); }
.lp-lead { color: var(--muted); max-width: 440px; font-size: 1.05rem; margin: 0 0 24px; }
.lp-cta { display: flex; gap: 12px; flex-wrap: wrap; }
.lp-btn { display: inline-flex; align-items: center; gap: 8px; padding: 13px 24px; border-radius: 999px; font-weight: 700; font-size: 1rem; border: 1px solid transparent; cursor: pointer; }
.lp-btn:hover { text-decoration: none; }
.lp-btn-tg { background: #229ED9; color: #fff; box-shadow: 0 10px 24px rgba(34, 158, 217, .35); }
.lp-btn-tg:hover { background: #1b8ec2; }
.lp-btn-glass {
  background: var(--glass-card); color: var(--wine); border-color: var(--glass-card-line);
  box-shadow: var(--shadow-card);
  backdrop-filter: blur(20px); -webkit-backdrop-filter: blur(20px);
}
.lp-btn-glass:hover { background: #fff; }
.lp-tg-ico { width: 20px; height: 20px; }
.lp-visual { display: flex; justify-content: center; }

/* liquid-glass phone */
.lp-phone {
  width: 320px; max-width: 100%; border-radius: 44px; padding: 16px 14px 0;
  background: linear-gradient(180deg, rgba(250, 246, 240, .95), rgba(244, 236, 226, .92));
  border: 1px solid rgba(255, 255, 255, .7);
  box-shadow: 0 30px 60px rgba(80, 20, 40, .18), inset 0 1.5px 0 rgba(255, 255, 255, 1);
  color: var(--ink);
}
.lp-p-top { display: flex; align-items: center; justify-content: space-between; padding: 2px 6px 10px; }
.lp-p-logo { display: flex; align-items: center; gap: 8px; font-weight: 800; color: var(--wine); font-size: 1.05rem; }
.lp-p-mark { width: 30px; height: 30px; display: block; object-fit: contain; }
.lp-p-langs { display: flex; gap: 3px; background: rgba(255, 255, 255, .6); border: 1px solid rgba(0, 0, 0, .05); border-radius: 999px; padding: 3px; }
.lp-p-langs span { font-size: .68rem; font-weight: 700; color: var(--muted); padding: 3px 8px; border-radius: 999px; line-height: 1; }
.lp-p-langs span.on { background: var(--wine); color: #fff; }
.lp-p-eyebrow { color: var(--wine); font-size: .62rem; font-weight: 700; letter-spacing: .16em; padding: 0 8px; }
.lp-p-titlerow { display: flex; align-items: center; justify-content: space-between; padding: 2px 8px 12px; }
.lp-p-title { font-size: 1.6rem; font-weight: 700; letter-spacing: -.01em; }
.lp-p-filter { display: inline-flex; align-items: center; gap: 6px; background: rgba(255, 255, 255, .7); border: 1px solid rgba(0, 0, 0, .06); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); padding: 8px 14px; border-radius: 999px; font-weight: 700; font-size: .82rem; color: var(--wine); }
.lp-p-card { position: relative; border-radius: var(--radius-card); overflow: hidden; height: 416px; box-shadow: 0 12px 30px rgba(90, 40, 30, .22); }
.lp-p-photo { position: absolute; inset: 0; background: radial-gradient(120% 80% at 50% 8%, #e9e2d8, #cdbfae 55%, #8f7f6e); }
.lp-p-illus { position: absolute; inset: 0; width: 100%; height: 100%; z-index: 1; display: block; }
.lp-p-img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: 1; }
.lp-p-shield { position: absolute; top: 14px; left: 14px; z-index: 2; width: 38px; height: 38px; border-radius: 50%; background: rgba(255, 255, 255, .55); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); border: 1px solid rgba(255, 255, 255, .6); display: grid; place-items: center; color: var(--wine); box-shadow: 0 4px 12px rgba(0, 0, 0, .12); }
.lp-p-shield svg { width: 18px; height: 18px; }
.lp-p-match { position: absolute; top: 16px; right: 14px; z-index: 2; background: rgba(255, 255, 255, .62); backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px); border: 1px solid rgba(255, 255, 255, .6); color: var(--wine); font-weight: 800; font-size: .8rem; padding: 7px 13px; border-radius: 999px; box-shadow: 0 4px 12px rgba(0, 0, 0, .1); }
.lp-p-overlay { position: absolute; left: 0; right: 0; bottom: 0; z-index: 2; padding: 50px 16px 30px; color: #fff; background: linear-gradient(180deg, transparent, rgba(20, 10, 8, .82)); }
.lp-p-active { display: inline-flex; align-items: center; gap: 6px; font-size: .72rem; font-weight: 600; margin-bottom: 8px; }
.lp-p-active .dot { width: 8px; height: 8px; border-radius: 50%; background: #37d67a; box-shadow: 0 0 0 3px rgba(55, 214, 122, .3); }
.lp-p-name { font-size: 1.45rem; font-weight: 800; display: flex; align-items: center; gap: 8px; }
.lp-p-verif { width: 20px; height: 20px; border-radius: 50%; background: #3897f0; display: grid; place-items: center; font-size: 12px; color: #fff; }
.lp-p-loc { display: flex; align-items: center; gap: 5px; font-size: .82rem; opacity: .9; margin-top: 3px; }
.lp-p-tags { display: flex; gap: 7px; flex-wrap: wrap; margin-top: 12px; }
.lp-p-tag { background: rgba(255, 255, 255, .16); border: 1px solid rgba(255, 255, 255, .28); backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); padding: 5px 12px; border-radius: 999px; font-size: .74rem; font-weight: 600; }
.lp-p-actions { display: flex; align-items: center; justify-content: center; gap: 16px; margin-top: -26px; position: relative; z-index: 3; padding-bottom: 10px; }
.lp-p-act { width: 52px; height: 52px; border-radius: 50%; display: grid; place-items: center; font-size: 22px; background: rgba(255, 255, 255, .78); backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px); border: 1px solid rgba(255, 255, 255, .7); box-shadow: 0 8px 20px rgba(90, 40, 30, .2); }
.lp-p-act.pass { color: #c25; }
.lp-p-act.rose { color: #c49a3a; width: 44px; height: 44px; font-size: 18px; }
.lp-p-act.like { color: #fff; background: var(--green); border-color: rgba(255, 255, 255, .4); }
.lp-p-nav { display: flex; justify-content: space-around; padding: 12px 4px 14px; margin-top: 6px; border-top: 1px solid rgba(0, 0, 0, .05); }
.lp-p-navitem { display: flex; flex-direction: column; align-items: center; gap: 3px; font-size: .64rem; font-weight: 600; color: var(--muted); position: relative; }
.lp-p-navitem.on { color: var(--wine); }
.lp-p-navitem svg { width: 23px; height: 23px; }
.lp-p-navbadge { position: absolute; top: -4px; right: 6px; min-width: 15px; height: 15px; padding: 0 4px; border-radius: 999px; background: var(--wine); color: #fff; font-size: .58rem; font-weight: 700; display: grid; place-items: center; }

/* warm body */
.lp-body { background: var(--bg); }
.lp-body-inner { max-width: 760px; margin: 0 auto; padding: 4px 22px 40px; }
.lp-section { padding: 34px 0; }
.lp-section:first-child { border-top: none; }
.lp-title { text-align: center; font-size: 1.6rem; font-weight: 700; margin: 0 0 22px; text-wrap: balance; }
.lp-steps { display: grid; grid-template-columns: 1fr; gap: 14px; max-width: 460px; margin: 0 auto; }
.lp-step {
  background: var(--glass-card); border: 1px solid var(--glass-card-line);
  box-shadow: var(--shadow-card); border-radius: var(--radius-panel);
  padding: 18px; text-align: left;
}
.lp-step-n { width: 34px; height: 34px; border-radius: 50%; background: var(--wine); color: #fff; display: flex; align-items: center; justify-content: center; font-weight: 700; margin-bottom: 8px; }
.lp-step-ico { font-size: 26px; margin-bottom: 6px; }
.lp-step strong { display: block; color: var(--wine); margin-bottom: 3px; }
.lp-step span { color: var(--muted); font-size: .92rem; }
.lp-feats { list-style: none; padding: 0; margin: 0 auto; max-width: 460px; display: grid; gap: 14px; }
.lp-feats li { background: var(--card); border: 1px solid var(--line); border-radius: 14px; padding: 16px 18px; text-align: left; display: flex; flex-direction: column; }
.lp-feats strong { color: var(--wine); }
.lp-feats span { color: var(--muted); font-size: .94rem; }
.lp-appcta { text-align: center; }
.lp-appcta p, .lp-final p { color: #5c524c; max-width: 460px; margin: 0 auto 22px; }
.lp-stores { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; }
.lp-store { display: inline-flex; align-items: center; gap: 10px; background: #1e1a17; color: #fff; border-radius: 12px; padding: 10px 18px; font-weight: 600; opacity: .9; }
.lp-store em { font-style: normal; font-size: .64rem; background: var(--wine); color: #fff; padding: 2px 7px; border-radius: 999px; font-weight: 700; text-transform: uppercase; }
.lp-final { text-align: center; }
.lp-final .lp-cta { justify-content: center; }
.lp-foot { text-align: center; color: var(--muted); font-size: .85rem; padding: 24px 0 8px; }

@media (min-width: 780px) {
  .lp-hero-inner { grid-template-columns: 1.05fr .95fr; padding: 54px 22px; }
  .lp-steps { grid-template-columns: repeat(3, 1fr); max-width: 720px; }
  .lp-feats { grid-template-columns: repeat(3, 1fr); max-width: 720px; }
}

/* ---- buttons ---- */
.btn {
  display: inline-block; padding: 13px 26px; border-radius: 999px; font-weight: 700;
  border: 1px solid transparent; cursor: pointer; font-size: 15px; font-family: inherit;
  transition: transform .12s ease;
}
.btn:hover { text-decoration: none; }
.btn:active { transform: scale(.96); }
/* The accent button carries its own glow, as everywhere in the design. */
.btn-primary { background: var(--wine); color: #fff; box-shadow: 0 4px 16px rgba(107, 30, 46, .33); }
.btn-primary:hover { background: var(--wine-dark); }
.btn-ghost {
  background: var(--glass-pill); color: var(--wine); border-color: var(--glass-pill-line);
  -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
}

/* ---- cards / forms ---- */
/* Content panels use the design's card level: a white that is not quite opaque,
   a near-white hairline, and a shadow with an inner highlight along the top.
   No `backdrop-filter` here, unlike the bars: the page behind a card is a flat
   wash, so blurring it would cost compositing on every card for no visible
   difference. Blur stays where something actually moves behind glass. */
.card {
  background: var(--glass-card); border: 1px solid var(--glass-card-line);
  border-radius: var(--radius-panel);
  padding: 26px; box-shadow: var(--shadow-card);
}
.auth-card { max-width: 400px; margin: 30px auto; }
.card h2 { margin-top: 0; }
label { display: block; font-weight: 600; margin-bottom: 14px; font-size: .95rem; }
input, select, textarea {
  width: 100%; padding: 12px 14px; margin-top: 6px;
  /* Solid white with a real hairline: on a glass card the translucent pill
     version disappeared, and a form you can't see the fields of is unusable. */
  border: 1px solid var(--line); background: #fff;
  border-radius: 12px; font-size: 1rem; font-family: inherit;
  font-weight: 400;
  color: var(--ink);         /* dark text on the white field... */
  caret-color: var(--ink);   /* ...and a visible dark typing caret (was white in some contexts) */
}
/* Focus in the accent, not the gold — gold belonged to the old palette. */
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--wine); box-shadow: 0 0 0 3px var(--accent-tint);
}
button.btn { width: auto; }

.grid-form { display: grid; grid-template-columns: 1fr 1fr; gap: 4px 16px; }
.grid-form .span2 { grid-column: 1 / -1; }
fieldset {
  border: 1px solid var(--glass-card-line); background: var(--glass-card);
  box-shadow: var(--shadow-card); border-radius: var(--radius-panel);
  margin: 0 0 14px; padding: 16px;
}
legend {
  float: left; width: 100%; padding: 0 0 10px; margin: 0;
  font-size: 15px; font-weight: 600; color: var(--ink);
}
legend + * { clear: both; }

.alert { background: #fdecea; color: #a02a1a; padding: 12px 16px; border-radius: 12px; margin-bottom: 14px; font-size: 14px; }
.alert.ok { background: #e7f5ec; color: #1f7a4d; }
.dev-box { margin-top: 20px; padding: 14px; border: 1px dashed var(--accent-tint-mid); border-radius: 12px;
  text-align: center; display: flex; flex-direction: column; gap: 8px; align-items: center; }
.btn-sm { padding: 6px 14px; font-size: .85rem; }
.verify-strip {
  background: var(--glass-card); border: 1px solid var(--glass-card-line);
  box-shadow: var(--shadow-card); border-radius: var(--radius-panel);
  padding: 12px 16px; margin: 12px auto; }
.verify-row { display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 8px 0; }
.verify-row + .verify-row { border-top: 1px solid var(--line); }
.muted { color: var(--muted); }
.small { font-size: .88rem; }
.center { text-align: center; }
.row-between { display: flex; align-items: center; justify-content: space-between; }

/* ---- discover deck ---- */
.discover { display: flex; flex-direction: column; align-items: center; }
.filters-link { align-self: flex-end; font-weight: 600; color: var(--wine); font-size: .9rem;
  background: var(--card); border: 1px solid var(--line); border-radius: 999px; padding: 6px 14px; margin-bottom: 10px; }
.filters-link:hover { text-decoration: none; border-color: var(--wine); }
/* The deck takes all the height between the floating bars — in the design the
   card is the screen, not a tile on it. Height is what's left after the top bar
   (52 + margins) and the tab bar (70 + 10 + safe area). */
/* The card fills what's left between the two floating bars. The height of the
   lower one is NOT a constant: admins get a second row of links above the tabs,
   which made the card — and the buttons on it — disappear under the dock.
   Whoever changes the dock changes this variable, not this formula. */
.wrap.has-bottomnav { --dock: 92px; }
.deck {
  position: relative; width: 100%;
  /* The swipe zone only, never the whole page: the browser keeps vertical
     panning (the profile under the card still scrolls), horizontal panning is
     ours — app.js decides by the first pixels of travel which one a gesture is. */
  touch-action: pan-y;
  /* With no app top bar the card starts at 8 (the feed wrap's 4 + its own 4)
     plus the system safe area, and still ends 104 above the bottom (12
     spacer + 4 nav mt + 72 nav + 16 nav mb). */
  height: calc(var(--vh, 100dvh) - 8px - 104px
               - var(--web-chrome) - env(safe-area-inset-bottom, 0px) - var(--tg-bottom, 0px));
  min-height: 340px;
}
.deck-item { border-radius: var(--radius-card); }
/* The card behind, peeking out from under the top one. `.is-top` is maintained
   in app.js rather than matched with :first-child, because swiped cards stay in
   the DOM marked `.gone` — so the top card is the first one NOT gone, which CSS
   cannot express. */
.deck-item:not(.is-top) { transform: scale(.93) translateY(16px); opacity: .4; }
.deck-item:not(.is-top) .pcard-overlay,
.deck-item:not(.is-top) .card-actions,
.deck-item:not(.is-top) .photo-bars { display: none; }
.deck-item.gone { pointer-events: none; }
/* Desktop (mouse) swipe: stop the browser from grabbing the photo as a native
   image-drag / selecting text, which swallowed the swipe gesture on Mac. */
.deck-item, .deck-item * { -webkit-user-select: none; user-select: none; }
.pcard img {
  -webkit-user-drag: none; -webkit-touch-callout: none; pointer-events: auto;
}
.deck-item {
  position: absolute; inset: 0; will-change: transform;
  transition: transform .35s ease, opacity .35s ease;
}
.deck-item.gone { opacity: 0; }
/* The prototype throws the card 460px out at 25°, over 0.35s. */
.deck-item.fly-right { transform: translateX(460px) rotate(25deg); }
.deck-item.fly-left { transform: translateX(-460px) rotate(-25deg); }

/* The feed card: no frame at all in the design — a 32px-rounded photo held by a
   deep soft shadow. The 3px border used to do the holding; the shadow does it
   now, and the picture gains the width the border was eating. */
.pcard {
  background: var(--card); border: 0; border-radius: var(--radius-card);
  overflow: hidden; box-shadow: var(--shadow-photo); height: 100%; display: flex; flex-direction: column;
  user-select: none; position: relative;
}
/* Whole-card tap target -> open the profile (controls sit above via z-index). */
.card-link { position: absolute; inset: 0; z-index: 2; }
.pcard .carousel-nav, .pcard .report-btn, .pcard .translate-btn { z-index: 4; }
.pcard .translate-btn { position: relative; }
.pcard-photo {
  position: relative; height: 440px; background: linear-gradient(135deg, #f0e6da, #e8dccb);
  display: grid; place-items: center; flex-shrink: 0; overflow: hidden;
  z-index: 3;   /* above .card-link so tapping the photo opens the viewer */
}

/* ---- feed card: the photo IS the card ---- */
.pcard-feed { height: 100%; }
.pcard-feed .pcard-photo { height: 100%; flex: 1; }
/* A photo served through /img takes a moment, and until it lands the card must
   not be a white sheet with dark chips floating on it. The warm gradient is
   underneath from the start; a photo that fails to load leaves that, not a
   broken-image glyph and its alt text. */
.pcard-feed .carousel { background: linear-gradient(160deg, #e6d8c8, #c8b3a3); }
.pcard-feed .carousel-track img { color: transparent; }
/* No photo. The design never drew this state — it assumes everyone has one —
   so it is built from the same parts: the card's warm gradient stays, and the
   middle carries one quiet glass disc instead of a giant emoji. The info block
   below is unchanged, which is the point: the card still reads as a card. */
.pcard-feed .photo-emoji, .pv-photo .photo-emoji {
  width: 88px; height: 88px; border-radius: 50%;
  display: grid; place-items: center; font-size: 34px;
  background: var(--glass-pill-bg);
  -webkit-backdrop-filter: blur(var(--glass-pill-blur));
  backdrop-filter: blur(var(--glass-pill-blur));
  border: 1px solid var(--glass-pill-line);
  box-shadow: 0 8px 24px rgba(80, 20, 40, .10);
  opacity: .92;
}
/* The design's scrim: transparent for the top quarter, then down to 78% black,
   so white text holds over any photograph without dimming the face. */
.pcard-scrim {
  position: absolute; inset: 0; pointer-events: none; z-index: 4;
  background: linear-gradient(to bottom, rgba(0,0,0,0) 25%, rgba(0,0,0,.15) 50%, rgba(0,0,0,.78) 100%);
}
.pcard-overlay {
  position: absolute; left: 20px; right: 20px; bottom: 110px; z-index: 6;
  color: #fff; display: block;
}
.pcard-overlay:hover { text-decoration: none; }
.ov-name {
  margin: 0 0 4px; font-size: 32px; line-height: 1.1; font-weight: 700; color: #fff;
  text-shadow: 0 2px 8px rgba(0,0,0,.45);
  display: flex; align-items: center; gap: 8px;
}
/* The one verification mark: a blue seal filled from the token, a white
   tick inside. Placement classes (ov-check, avatar-check, head-check,
   pv-verified) only position it — the drawing never changes. */
.verified-star { flex: none; }
.verified-star .vs-seal { fill: var(--c-verified-row); }
.verified-star .vs-tick {
  fill: none; stroke: #fff; stroke-width: 2.6;
  stroke-linecap: round; stroke-linejoin: round;
}
.ov-check {
  flex-shrink: 0;
  filter: drop-shadow(0 0 5px rgba(91, 216, 255, .55));
}
.ov-loc {
  display: flex; align-items: center; gap: 6px; margin-bottom: 4px;
  color: rgba(255,255,255,.75); font-size: 16px;
}
.ov-loc svg { flex-shrink: 0; }
.ov-zodiac { margin-bottom: 12px; }
.chip-row { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 8px; }
.chip-row:last-child { margin-bottom: 0; }
/* Dark glass, the design's `pillDark` — the only chip that stays readable on a
   photograph, because it darkens what is behind it instead of tinting it. */
.chip-dark {
  /* gap 4, not 5: the prototype sets gap-1 here. One pixel, but it widened
     every chip that carries an icon and pushed its label a pixel right —
     the whole remaining disagreement on the feed was this line. */
  display: inline-flex; align-items: center; gap: 4px;
  padding: 6px 12px; border-radius: 999px;
  background: var(--glass-pill-dark-bg);
  -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  border: 1px solid var(--glass-pill-dark-line);
  color: #fff; font-size: 13px; font-weight: 500; line-height: 1.5;
  /* Georgian runs about twice the length of the design's English. A job title
     of five words was taking a whole line and pushing the chips up over half
     the photograph, so a chip is allowed one line and no more. */
  max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ov-zodiac .chip-dark { font-size: 14px; padding: 4px 12px; }
/* On your own card the design sets the fact chips a size smaller than the
   feed's — 12 on an 18 line, against 13/19.5 — so the block of five fits
   without a fourth row. The zodiac chip keeps its own size. */
.pcard-hero .chip-row .chip-dark { font-size: 12px; line-height: 1.5; }
.chip-dark.soft { color: rgba(255, 255, 255, .9); padding: 4px 12px; }
/* Chip glyphs: 12px and dimmed, as the prototype draws them — the label leads,
   the icon only says which kind of fact this is. */
.chip-ico { width: 12px; height: 12px; flex: none; opacity: .7; }

/* Photo paging: bars along the top, and invisible tap targets on the sides. */
.photo-bars {
  position: absolute; top: 16px; left: 16px; right: 16px; z-index: 6;
  display: flex; gap: 6px; justify-content: center; pointer-events: none;
}
.photo-bars .pbar {
  height: 3px; width: 6px; border-radius: 999px; background: rgba(255,255,255,.45);
  transition: width .3s ease, background .3s ease;
}
.photo-bars .pbar.on { width: 22px; background: #fff; box-shadow: 0 0 6px rgba(255,255,255,.7); }
/* The whole third of the card pages the gallery, but an invisible target tells
   nobody it exists — so the tap zone now carries a small glass chevron at its
   outer edge. The zone stays wide; only the hint is small. */
.carousel-tap {
  position: absolute; top: 0; bottom: 0; width: 33%; z-index: 5;
  border: 0; background: transparent; padding: 0; cursor: pointer;
  display: flex; align-items: center;
}
.carousel-tap.prev { left: 0; justify-content: flex-start; }
.carousel-tap.next { right: 0; justify-content: flex-end; }
.tap-arrow {
  width: 30px; height: 30px; margin: 0 10px; border-radius: 50%;
  background: rgba(0, 0, 0, .3); border: 1px solid var(--glass-pill-dark-line);
  -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  color: #fff; font-size: 19px; line-height: 1;
  display: grid; place-items: center;
  opacity: .75; transition: opacity .15s ease, transform .12s ease;
}
.carousel-tap:hover .tap-arrow { opacity: 1; }
.carousel-tap:active .tap-arrow { transform: scale(.9); }

/* Round glass buttons in the card's top corner. */
.card-actions {
  position: absolute; top: 16px; right: 16px; z-index: 7;
  display: flex; gap: 8px;
}
.glass-icon {
  width: var(--s-card-filter-btn); height: var(--s-card-filter-btn); border-radius: 50%; border: 1px solid var(--glass-pill-dark-line);
  background: var(--glass-pill-dark);
  -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  color: #fff; font-size: 15px; line-height: 1; cursor: pointer; padding: 0;
  display: grid; place-items: center; transition: transform .12s ease;
}
.glass-icon:hover { text-decoration: none; }
.glass-icon:active { transform: scale(.9); }

/* LIKE / NOPE stamps — opacity driven from app.js while dragging. */
.stamp {
  position: absolute; top: 56px; z-index: 8; opacity: 0; pointer-events: none;
  padding: 6px 16px; border-radius: 12px; font-weight: 900; font-size: 20px;
  letter-spacing: .1em; background: rgba(0,0,0,.2);
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
}
.stamp-like { right: 20px; transform: rotate(14deg); border: 2.5px solid #4ade80; color: #4ade80; }
.stamp-nope { left: 20px; transform: rotate(-14deg); border: 2.5px solid var(--wine); color: var(--wine); }
.carousel-track img { cursor: zoom-in; }

/* Fullscreen photo viewer */
.lightbox {
  position: fixed; inset: 0; z-index: 1000; background: rgba(0,0,0,.94);
  display: grid; place-items: center; padding: env(safe-area-inset-top) 0 env(safe-area-inset-bottom);
}
.lb-img { max-width: 100%; max-height: 100%; object-fit: contain; }
.lb-close {
  position: fixed; top: calc(10px + env(safe-area-inset-top)); right: 14px; z-index: 1001;
  width: 42px; height: 42px; border-radius: 50%; border: none; cursor: pointer;
  background: rgba(255,255,255,.16); color: #fff; font-size: 19px; display: grid; place-items: center;
}
.lb-counter {
  position: fixed; top: calc(18px + env(safe-area-inset-top)); left: 50%; transform: translateX(-50%);
  color: #fff; font-size: .9rem; opacity: .85;
}
.lb-nav {
  position: fixed; top: 50%; transform: translateY(-50%); z-index: 1001;
  width: 46px; height: 46px; border-radius: 50%; border: none; cursor: pointer;
  background: rgba(255,255,255,.12); color: #fff; font-size: 28px; line-height: 1;
}
.lb-prev { left: 10px; }
.lb-next { right: 10px; }
.pcard-photo img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: center 38%;
}
.photo-emoji { font-size: 96px; }

/* Photo carousel */
.carousel { position: absolute; inset: 0; overflow: hidden; }
.carousel-track {
  display: flex; height: 100%; width: 100%;
  transition: transform .28s ease;
}
.carousel-track img {
  position: static; flex: 0 0 100%; width: 100%; height: 100%;
  object-fit: cover; object-position: center 38%;
}
.carousel-nav {
  position: absolute; top: 50%; transform: translateY(-50%);
  width: 36px; height: 36px; border: none; border-radius: 50%;
  background: rgba(0,0,0,.32); color: #fff; font-size: 1.5rem; line-height: 1;
  cursor: pointer; display: grid; place-items: center; z-index: 3; padding: 0;
}
.carousel-nav.prev { left: 8px; }
.carousel-nav.next { right: 8px; }
.carousel-dots {
  position: absolute; bottom: 10px; left: 0; right: 0; z-index: 3;
  display: flex; gap: 6px; justify-content: center;
}
.carousel-dots .dot {
  width: 6px; height: 6px; border-radius: 50%; background: rgba(255,255,255,.5);
}
.carousel-dots .dot.on { background: #fff; }

/* Photo section in the profile editor */
.photo-edit { margin-top: 4px; }
.field-title { display: block; margin-bottom: 8px; font-size: .95rem; font-weight: 600; }
.photo-thumbs { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 6px; }
.photo-thumbs .thumb {
  width: 64px; height: 64px; border-radius: 10px; overflow: hidden;
  background: #e8dccb; flex-shrink: 0; position: relative;
}
.photo-thumbs .thumb img { width: 100%; height: 100%; object-fit: cover; }
.photo-thumbs .thumb.cover { outline: 2px solid #7a1f2b; outline-offset: 1px; }
/* Gallery manager (add photos one-by-one) */
.gallery-manage { display: flex; flex-wrap: wrap; gap: 10px; margin: 8px 0 4px; }
.gthumb {
  position: relative; width: 84px; height: 84px; border-radius: 12px;
  overflow: hidden; background: #e8dccb; flex-shrink: 0;
}
.gthumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.gthumb-x {
  position: absolute; top: 3px; right: 3px; width: 22px; height: 22px; padding: 0;
  border: none; border-radius: 50%; background: rgba(0,0,0,.55); color: #fff;
  font-size: 15px; line-height: 1; cursor: pointer; display: grid; place-items: center;
}
.gthumb-add {
  border: 2px dashed var(--line); background: #faf5ee; display: grid; place-items: center;
  cursor: pointer; color: var(--wine); font-size: 30px; line-height: 1;
}
.gthumb-add.busy { opacity: .5; pointer-events: none; }
.gallery-manage .gthumb:first-child:not(.gthumb-add)::after {
  content: '★'; position: absolute; left: 4px; top: 3px; font-size: 12px;
  color: #fff; background: rgba(122,31,43,.9); border-radius: 999px;
  width: 18px; height: 18px; display: grid; place-items: center; line-height: 1;
}
/* "Make main" star on non-cover thumbs (tap → becomes first/cover) */
.gthumb-star {
  position: absolute; left: 3px; top: 3px; width: 22px; height: 22px; padding: 0;
  border: none; border-radius: 50%; background: rgba(0,0,0,.55); color: #fff;
  font-size: 13px; line-height: 1; cursor: pointer; display: grid; place-items: center;
}
.gallery-manage .gthumb:first-child .gthumb-star { display: none; }
/* Profile completeness meter (/me) */
.completeness {
  /* 12 above it and 16 inside, as the design has it. */
  display: block; margin: 12px auto 0; padding: 16px;
  border: 1px solid var(--glass-card-line); border-radius: var(--radius-panel);
  background: var(--glass-card); box-shadow: var(--shadow-card);
}
.completeness:hover { text-decoration: none; }
.cmp-head { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; margin-bottom: 10px; }
/* The design writes this line in the same quiet grey as the rest of the card,
   semibold at 15 — not in accent and not bold. It read as an alarm. */
.cmp-head strong { font-size: 15px; font-weight: 600; color: #555; }
.cmp-head .muted { font-size: 13px; color: #bbb; }
.cmp-bar { height: 6px; border-radius: 999px; background: var(--accent-tint); overflow: hidden; }
.cmp-bar span { display: block; height: 100%; background: var(--wine); border-radius: 999px; }
/* Goal filter chips */
.goal-filter { display: flex; flex-wrap: wrap; gap: 8px; margin: 6px 0; }
.chip-check { position: relative; cursor: pointer; }
.chip-check input { position: absolute; opacity: 0; width: 0; height: 0; }
.chip-check span {
  display: inline-block; padding: 9px 14px; border: 1px solid var(--glass-pill-line);
  border-radius: 12px; font-size: 14px; font-weight: 600; color: #555;
  background: var(--glass-pill); transition: all .15s;
}
.chip-check input:checked + span {
  background: var(--wine); color: #fff; border-color: var(--wine);
  box-shadow: 0 2px 12px rgba(107, 30, 46, .33);
}
.age-confirm {
  display: flex; align-items: center; gap: 10px; padding: 12px 14px;
  border: 1px solid var(--line); border-radius: 12px; background: #faf5ee; cursor: pointer;
}
.age-confirm input { width: 20px; height: 20px; flex-shrink: 0; margin: 0; accent-color: var(--wine); }
.age-confirm span { font-size: .95rem; }
.prompt-slot { display: flex; flex-direction: column; gap: 6px; }
.prompt-slot select { margin: 0; }
.prompt-slot input { margin: 0; }

/* Profile prompts on cards */
.prompts { display: flex; flex-direction: column; gap: 10px; margin: 12px 0; }
.prompt-card {
  background: var(--glass-card); border: 1px solid var(--glass-card-line);
  box-shadow: var(--shadow-card); border-radius: var(--radius-panel);
  padding: 14px 16px; display: flex; flex-direction: column; gap: 4px;
}
.prompt-card .prompt-q { font-size: .82rem; color: var(--muted); }
.prompt-card .prompt-a { font-size: 1.02rem; font-weight: 600; line-height: 1.3; }
.score-badge {
  position: absolute; top: 12px; right: 12px; background: rgba(122,31,43,.92); color: #fff;
  padding: 6px 12px; border-radius: 999px; font-weight: 700; font-size: .85rem;
}
.pcard-body { padding: 16px 18px; overflow-y: auto; }
.pcard-body h3 { margin: 0 0 8px; font-size: 1.4rem; }
.pcard-meta { display: flex; flex-direction: column; gap: 3px; color: #5c524c; font-size: .92rem; }
.pcard-bio { margin: 12px 0; color: #4a423d; }
.translate-btn { background: none; border: none; color: var(--wine); font-weight: 600;
  font-size: .82rem; cursor: pointer; padding: 0; margin: -6px 0 8px; font-family: inherit; }
.translate-btn:hover { text-decoration: underline; }
.tags { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.tag { background: var(--glass-pill); border: 1px solid var(--glass-pill-line); border-radius: 999px; padding: 6px 12px; font-size: 14px; font-weight: 500; color: #555; }
.reasons { list-style: none; padding: 0; margin: 12px 0 0; }
.reasons li { color: var(--green); font-size: .88rem; }

/* Floating over the card, 24px above its bottom edge, as in the design: three
   white glass discs, the like one larger than its neighbours. */
/* Above the cards, which carry inline z-indexes counting down from 100. */
.swipe-controls {
  position: absolute; left: 0; right: 0; bottom: 24px; z-index: 200;
  display: flex; gap: 24px; align-items: center; justify-content: center;
}
.swipe-btn {
  width: var(--s-action-sm); height: var(--s-action-sm); border-radius: 50%;
  border: none; cursor: pointer;
  font-size: 22px; background: rgba(255, 255, 255, .94);
  -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
  box-shadow: 0 4px 20px rgba(0, 0, 0, .14);
  display: grid; place-items: center; transition: transform .12s ease;
}
.swipe-btn.pass { color: var(--c-nope); }
.swipe-btn.like {
  width: var(--s-action-lg); height: var(--s-action-lg); color: var(--c-accent);
  background: rgba(255, 255, 255, .97); box-shadow: 0 6px 28px rgba(0, 0, 0, .16);
}
.swipe-btn.rose { position: relative; color: var(--c-star); }
/* Icon sizes are the prototype's: 22 on the small buttons, 28 on the heart. */
.swipe-btn svg { width: var(--s-action-icon-sm); height: var(--s-action-icon-sm); }
.swipe-btn.like svg { width: var(--s-action-icon-lg); height: var(--s-action-icon-lg); }
.rose-count {
  position: absolute; top: -2px; right: -2px; background: var(--wine); color: #fff;
  font-size: .62rem; min-width: 17px; height: 17px; border-radius: 999px;
  display: grid; place-items: center; padding: 0 4px; font-weight: 700;
}
.free-rose-toast {
  position: fixed; top: 68px; left: 50%; transform: translateX(-50%);
  background: linear-gradient(90deg, #b3123f, #e0538a); color: #fff; padding: 9px 18px;
  border-radius: 999px; font-weight: 600; font-size: .9rem; z-index: 60;
  box-shadow: var(--shadow); animation: freeRoseFade 4.5s ease forwards;
}
@keyframes freeRoseFade { 0%, 65% { opacity: 1; } 100% { opacity: 0; visibility: hidden; } }
.swipe-btn:active { transform: scale(.92); }
.deck-item.fly-up { transform: translateY(-140%) rotate(4deg); }

.row-card.rose-like { border-color: rgba(107, 30, 46, .35); }

/* ---- match modal ---- */
.modal { position: fixed; inset: 0; background: rgba(40,20,20,.55); display: grid; place-items: center; z-index: 300; }
.modal[hidden] { display: none; }
/* The `hidden` attribute has to win over a component's own display. Every
   flex/grid rule in this file outranks the browser's [hidden] { display: none },
   which is why the gift sheet once showed its "sent" state at the same time as
   the one that sends it. */
[hidden] { display: none !important; }
.modal-inner { background: #fff; border-radius: 22px; padding: 36px 30px; text-align: center; max-width: 340px; }
.match-emoji { font-size: 70px; }
.modal-inner h2 { color: var(--wine); margin: 8px 0; }

/* ---- screen furniture shared by matches, messages and profile ---- */
/* A heading that carries its own count, a segmented switch, and list rows —
   the three shapes the design repeats on every list screen. */
/* mb-4 under the title in the design, and the count sits on its baseline. */
.screen-head { display: flex; align-items: baseline; gap: 10px; margin: 0 0 16px; }
/* mb-5 in the design on the messages screen, mb-4 on matches. */
.screen-head.wide { margin-bottom: 20px; }
.screen-head h1 { margin: 0; font-size: var(--t-screen-title); font-weight: 700;
  color: var(--c-ink); line-height: 1.5; }
.count-pill {
  background: var(--wine); color: #fff; font-size: 13px; font-weight: 700;
  padding: 1px 10px; border-radius: 999px; line-height: 1.5;
}

.segmented {
  display: flex; gap: 0; padding: 4px; border-radius: var(--r-panel);
  background: rgba(255, 255, 255, .6);
  -webkit-backdrop-filter: blur(24px); backdrop-filter: blur(24px);
  border: 1px solid var(--glass-float-line);
  box-shadow: 0 4px 24px rgba(80, 20, 40, .06), inset 0 1.5px 1.5px rgba(255, 255, 255, .9);
  margin-bottom: 20px;
}
.seg {
  flex: 1; text-align: center; padding: 10px 8px; border-radius: 12px;
  font-size: 14px; font-weight: 600; color: #aaa; border: 0; background: none;
  cursor: pointer; font-family: inherit;
}
.seg:hover { text-decoration: none; }
.seg.on { background: var(--wine); color: #fff; box-shadow: 0 2px 10px rgba(107, 30, 46, .27); }

.row-list { display: flex; flex-direction: column; gap: 12px; }
.row-card {
  display: flex; align-items: center; gap: 16px; padding: 16px;
  border-radius: var(--radius-panel); color: var(--ink);
  background: var(--glass-card); border: 1px solid var(--glass-card-line);
  box-shadow: var(--shadow-card); transition: transform .12s ease;
}
.row-card:hover { text-decoration: none; }
.row-card:active { transform: scale(.98); }
/* The wrapper can't clip — the verification tick hangs off its corner — so the
   photo is positioned against it and rounded itself. Sized any other way the
   image resolves to its intrinsic height and stretches the row. */
.row-avatar {
  position: relative; width: 66px; height: 66px; border-radius: 50%; flex-shrink: 0;
  background: var(--fill); display: grid; place-items: center;
  font-size: 26px; border: 2px solid rgba(107, 30, 46, .33);
}
.row-avatar img {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; border-radius: 50%;
}
/* The design does not put a filled badge on the avatar — it puts the same
   line glyph there at 17px, hanging half a pixel off the corner, and a 14px
   one beside the name. Ours was a solid blue disc with a white border. */
.avatar-check {
  position: absolute; right: -2px; bottom: -2px; width: 17px; height: 17px;
  color: var(--c-verified-row); background: none; border: 0;
}
/* The design spaces this column with margins, not a gap: 2 under the name,
   6 above the bar. A gap on top of those margins made every row 2px tall. */
.row-main { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.row-name { font-size: var(--t-row-name); font-weight: 600; color: var(--c-ink);
  display: flex; align-items: center; gap: 6px; }
.row-name svg { width: 14px; height: 14px; color: var(--c-verified-row); flex: none; }
.row-sub { display: flex; align-items: center; gap: 4px; font-size: 13px; color: #ccc; }
.row-sub svg { flex-shrink: 0; }
.row-chevron { color: #ddd; font-size: 22px; line-height: 1; flex-shrink: 0; }
/* The × that removes a "Liked you" card — a quiet round target, not a shout. */
.row-dismiss {
  flex-shrink: 0; width: 32px; height: 32px; border-radius: 50%;
  display: grid; place-items: center; cursor: pointer;
  color: var(--c-muted); background: var(--glass-pill-bg);
  border: 1px solid var(--glass-pill-line);
}
.row-dismiss:active { transform: scale(.9); }

/* Messages: the smaller row of the design (58px face, 16px name) and the strip
   of faces above it. */
.row-avatar.sm { width: 58px; height: 58px; border: 1.5px solid rgba(0, 0, 0, .06); }
/* A match with nothing said yet is ringed in accent — the design's only visual
   claim on the eye in this list. */
.row-avatar.sm.is-new { border: 2px solid var(--wine); box-shadow: 0 0 8px rgba(107, 30, 46, .27); }
.row-name.sm { font-size: var(--t-row-name-sm); display: flex; align-items: center; gap: 6px; }
/* 13px beside the name in the conversation list — smaller than the 14 on
   the matches row, as the design has it. */
.row-name.sm svg { width: 13px; height: 13px; color: var(--c-verified-row); flex: none; }
.name-check { color: #22c0f0; font-size: 13px; }
/* 14px and 2 under the name — the design's line, not 13 and a gap. */
.row-preview {
  margin-top: 2px; font-size: var(--t-row-sub); color: var(--c-muted-4);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.row-preview.unread { color: #333; font-weight: 600; }
.row-preview.new { font-style: italic; }
.unread-dot {
  width: 24px; height: 24px; border-radius: 50%; background: var(--wine); color: #fff;
  font-size: 11px; font-weight: 700; display: grid; place-items: center; flex-shrink: 0;
}
.face-row {
  display: flex; gap: 16px; overflow-x: auto; padding-bottom: 4px; margin-bottom: 24px;
  scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.face-row::-webkit-scrollbar { display: none; }
.face { display: flex; flex-direction: column; align-items: center; gap: 8px; flex-shrink: 0; color: inherit; }
.face:hover { text-decoration: none; }
.face-photo {
  position: relative; width: 58px; height: 58px; border-radius: 50%;
  border: 2.5px solid rgba(107, 30, 46, .33); background: var(--fill);
  display: grid; place-items: center; font-size: 24px;
}
.face-photo img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; border-radius: 50%; }
.face-name { font-size: 12px; color: #999; max-width: 66px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.compat { display: flex; align-items: center; gap: 8px; margin-top: 6px; }
.compat-track { flex: 1; height: 6px; border-radius: 999px; background: rgba(234, 47, 92, .08); overflow: hidden; }
.compat-fill { display: block; height: 100%; border-radius: 999px; }
.compat-val { font-size: 12px; font-weight: 700; flex-shrink: 0; }

/* The sheet that used to live here belonged to the standalone filters page.
   That page is gone — /filters renders the feed with the design's sheet over
   it — and its styles shared every .sheet-* name with the new one, so half of
   the new sheet was inheriting properties from a component nobody could see.
   The living styles are at the end of this file. */

/* Actions at the foot of someone's profile. They had no styles at all, so the
   link sat at its natural width next to a form-wrapped button and the pair
   looked accidental. Full-width stack, primary first — the page ends with the
   thing you came to do. */
.pv-actions {
  display: flex; flex-direction: column; gap: 10px;
  margin: 20px 0 8px;
}
.pv-actions form { width: 100%; margin: 0; }
.pv-actions .btn { display: block; width: 100%; text-align: center; }

/* ---- profile ---- */
/* Your own card is shorter than a feed card — it shares the screen with the
   tiles below it rather than owning the whole of it. */
.pcard-hero { height: 58vh; min-height: 380px; border-radius: var(--radius-card); overflow: hidden; }
.pcard-hero .pcard-overlay { bottom: 20px; }
.pcard-hero .ov-name { font-size: 30px; }

.stat-tiles { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin: 16px auto 0; }
.stat-tile {
  display: flex; flex-direction: column; align-items: center; padding: 16px 6px;
  border-radius: var(--radius-panel); color: var(--ink);
  background: var(--glass-card); border: 1px solid var(--glass-card-line);
  box-shadow: var(--shadow-card);
}
.stat-tile:hover { text-decoration: none; }
.stat-top { display: flex; align-items: center; gap: 6px; }
.stat-ico { font-size: 18px; line-height: 1; }
.stat-num { font-size: 34px; font-weight: 700; line-height: 1; color: var(--ink); }
.stat-lbl { margin-top: 6px; font-size: 12px; color: #bbb; text-align: center; }

/* A row is a tinted square, a label, and — if there's something to say about
   it — a value at the end. */
.icon-row {
  display: flex; align-items: center; gap: 12px; padding: 14px 16px; margin-bottom: 10px;
  border-radius: 12px; color: #444; font-size: 15px;
  background: var(--glass-card); border: 1px solid var(--glass-card-line);
  box-shadow: var(--shadow-card);
}
.icon-row:hover { text-decoration: none; }
.icon-box {
  width: 36px; height: 36px; border-radius: 12px; flex-shrink: 0;
  background: var(--accent-tint); display: grid; place-items: center;
  font-size: 17px; line-height: 1;
}
.row-end { margin-left: auto; color: #bbb; font-size: 14px; flex-shrink: 0; text-align: right; }
.row-end.ok { color: #1f7a4d; font-weight: 600; }
/* A row that acts is still a row: buttons and form submits take the same shape
   as the links around them, so the profile reads as one list. */
.row-btn {
  width: 100%; text-align: left; cursor: pointer; font-family: inherit;
  font-size: 15px; color: #444;
}
/* The language picker keeps its three cards, so its row stacks instead. */
.row-stack { flex-direction: column; align-items: stretch; gap: 12px; }
.row-line { display: flex; align-items: center; gap: 12px; }
.row-danger { color: #b3261e; }
.row-danger .icon-box { background: rgba(179, 38, 30, .08); }
.pane-card { padding: 16px; }
.chips-plain { display: flex; flex-wrap: wrap; gap: 8px; }
.chip-plain {
  padding: 6px 12px; border-radius: 999px; font-size: 14px; font-weight: 500; color: #555;
  background: var(--glass-pill); border: 1px solid var(--glass-pill-line);
}

/* Section label: small caps, wide tracking, accent — the design's way of
   naming a block without a heading's weight. */
.sec-label {
  /* tracking-widest is 0.1em; ours was .14, which pushed this caption a full
     character wider than the design's. */
  display: block; margin: 0 0 12px; color: var(--wine);
  font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: .1em;
}

/* ---- matches / chat ---- */
.match-grid { display: grid; grid-template-columns: 1fr; gap: 12px; margin-top: 16px; }
.match-cell { display: flex; align-items: center; gap: 14px; background: var(--card);
  border: 1px solid var(--line); border-radius: 14px; padding: 12px 16px; }
.match-cell:hover { text-decoration: none; border-color: var(--wine); }
.match-avatar { width: 54px; height: 54px; border-radius: 50%; overflow: hidden;
  background: #f0e6da; display: grid; place-items: center; font-size: 28px; flex-shrink: 0; }
.match-avatar.sm { width: 40px; height: 40px; font-size: 20px; }
.match-avatar img { width: 100%; height: 100%; object-fit: cover; }
.match-info { display: flex; flex-direction: column; }
.single-card { max-width: 400px; margin: 16px auto; position: relative; }
/* Edit pencil on own card: sits on the name row (photo 260px + body padding) */
.card-edit {
  position: absolute; top: 268px; right: 14px; z-index: 6;
  background: #fff; box-shadow: var(--shadow);
}
.me-card .pcard-photo { height: 260px; }
.me-card .photo-emoji { font-size: 64px; }

/* Chat fills the screen below the header (no bottom nav here) and uses dvh so it
   shrinks when the mobile keyboard opens — otherwise the input got covered. */
/* The floating header now sits above this, and the input pill hangs below it,
   so the column has to stop short of both — otherwise the pill's lower edge is
   clipped by the viewport. */
/* No extra 6 above the log: the bar's own 4px clearance plus the log's 16
   puts the first bubble at y92, exactly the prototype's. */
.wrap.chat-page { padding: 0 12px 0; height: calc(100vh - 78px); height: calc(var(--vh, 100dvh) - 78px - var(--web-chrome) - var(--tg-bottom, 0px)); }
.chat { display: flex; flex-direction: column; height: 100%; }
.chat-head { display: flex; align-items: center; gap: 12px; padding-bottom: 12px; border-bottom: 1px solid var(--line); flex-shrink: 0; }
.back { font-size: 24px; color: var(--ink); }
.chat-log { flex: 1; min-height: 0; overflow-y: auto; padding: 16px 4px; display: flex; flex-direction: column; gap: 8px; }
/* 20px with a 6px corner on the speaker's side, and a tinted glow under your
   own messages instead of a hairline under theirs. */
.bubble { max-width: 75%; padding: 10px 16px; border-radius: var(--radius-bubble); font-size: 1rem; }
.bubble.mine {
  align-self: flex-end; background: var(--wine); color: #fff;
  border-bottom-right-radius: 6px; box-shadow: 0 4px 16px rgba(107, 30, 46, .27);
}
.bubble.theirs {
  align-self: flex-start; background: rgba(255, 255, 255, .85); border: 0;
  border-bottom-left-radius: 6px; box-shadow: 0 2px 8px rgba(0, 0, 0, .06);
}
/* The conversation header: the app's floating bar, wearing the other person. */
.topbar.chatbar { gap: 12px; padding: 8px 10px; }
.round-btn {
  width: 36px; height: 36px; border-radius: 50%; flex-shrink: 0; cursor: pointer;
  background: var(--glass-pill); border: 1px solid var(--glass-pill-line);
  -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
  color: var(--wine); font-size: 20px; line-height: 1; padding: 0;
  display: grid; place-items: center; transition: transform .12s ease;
}
.round-btn:active { transform: scale(.9); }
.chat-head-link { display: flex; align-items: center; gap: 10px; flex: 1; min-width: 0; color: inherit; }
.chat-head-avatar {
  position: relative; width: 36px; height: 36px; border-radius: 50%; flex-shrink: 0;
  border: 2px solid rgba(107, 30, 46, .33); background: var(--fill);
  display: grid; place-items: center; font-size: 16px;
}
.chat-head-avatar img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; border-radius: 50%; }
.chat-head-info { display: flex; flex-direction: column; min-width: 0; line-height: 1.25; }
.chat-head-name {
  /* font-semibold on a 24 line, as the prototype's header names it. */
  font-size: 16px; font-weight: 600; line-height: 1.5; color: var(--ink);
  display: flex; align-items: center; gap: 4px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.peer-status { font-size: 12px; line-height: 1.25; color: var(--c-muted-3); min-height: 15px; }
.peer-status.on { color: #2e9e5b; }
.chat-menu-wrap { position: relative; flex-shrink: 0; }
.chat-menu {
  position: absolute; right: 0; top: calc(100% + 8px); min-width: 190px; z-index: 60;
  border-radius: var(--radius-panel); overflow: hidden;
  background: var(--glass-float); border: 1px solid var(--glass-float-line);
  -webkit-backdrop-filter: blur(20px); backdrop-filter: blur(20px);
  box-shadow: var(--shadow-float);
}
.chat-menu a, .chat-menu button {
  display: flex; align-items: center; gap: 10px; width: 100%; padding: 12px 16px;
  background: none; border: 0; border-bottom: 1px solid rgba(0, 0, 0, .05);
  font: inherit; font-size: 14px; font-weight: 500; color: var(--ink);
  text-align: left; cursor: pointer;
}
.chat-menu form:last-child button, .chat-menu > :last-child { border-bottom: 0; }
.chat-menu a:hover, .chat-menu button:hover { text-decoration: none; background: rgba(0, 0, 0, .03); }

/* The message field takes the tab bar's place: same pill, same height, tinted
   outline so it reads as active rather than as navigation. */
.chat-input {
  /* The composer replaces the tab bar and takes its shape: 72 tall, radius 33,
     the same 16px gutter and the same 16 of clearance underneath. */
  display: flex; gap: 10px; align-items: center; flex-shrink: 0;
  margin: 4px 0 calc(var(--s-gutter) + env(safe-area-inset-bottom, 0px));
  height: var(--s-nav-h); padding: 0 var(--s-gutter); border-radius: var(--r-nav);
  background: var(--glass-float); border: 1.5px solid rgba(234, 47, 92, .12);
  -webkit-backdrop-filter: blur(20px); backdrop-filter: blur(20px);
  box-shadow: var(--shadow-float);
}
.chat-input input, .chat-input textarea {
  margin: 0; border: 0; background: transparent; box-shadow: none; border-radius: 0;
}
.chat-input textarea {
  /* 16 on a 24 line, as the design's input — 1.35 left the row 2px short. */
  resize: none; overflow-y: auto; line-height: 1.5; min-height: 24px; max-height: 110px;
  border: 0; background: transparent; padding: 6px 0; font-size: 16px;
}
.chat-input textarea:focus { outline: none; }
.chat-photo-btn {
  flex-shrink: 0; width: 20px; height: 20px; padding: 0; border: 0; background: none;
  color: var(--c-muted-6); font-size: 20px; line-height: 1; cursor: pointer;
  display: grid; place-items: center;
}
.send-btn {
  flex-shrink: 0; width: 40px; height: 40px; border-radius: 50%; border: 0; cursor: pointer;
  background: rgba(0, 0, 0, .08); color: #ccc; display: grid; place-items: center;
  transition: background .15s ease, color .15s ease, transform .12s ease;
}
/* Lit only once there is something to send — the design's way of saying the
   button is not decoration. */
.chat-input.has-text .send-btn {
  background: var(--wine); color: #fff; box-shadow: 0 4px 16px rgba(107, 30, 46, .33);
}
.send-btn:active { transform: scale(.9); }

/* ---- Reply to a message. The bar floats over the composer (the composer is
   a fixed-height flex row — putting the bar inside the row would squash it),
   the quote sits at the top of a bubble, and ↩ rides along each message. */
.chat-input { position: relative; }
.reply-bar {
  position: absolute; left: 0; right: 0; bottom: calc(100% + 6px);
  display: flex; align-items: center; gap: 10px;
  padding: 8px 14px; border-radius: 18px;
  background: var(--glass-float); border: 1.5px solid rgba(234, 47, 92, .12);
  -webkit-backdrop-filter: blur(20px); backdrop-filter: blur(20px);
  box-shadow: var(--shadow-float);
}
.reply-bar-info {
  flex: 1; min-width: 0; display: flex; flex-direction: column;
  border-left: 3px solid var(--wine); padding-left: 10px;
}
.rq-name { display: block; font-size: .8rem; font-weight: 600; color: var(--wine); }
.rq-text {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; font-size: .85rem; word-break: break-word;
}
.reply-bar-cancel {
  flex-shrink: 0; border: 0; background: none; cursor: pointer;
  color: var(--c-muted-6); font-size: 16px; line-height: 1; padding: 4px;
}
.reply-quote {
  display: block; width: 100%; text-align: left; cursor: pointer; font: inherit;
  color: inherit; border: 0; border-left: 3px solid var(--wine);
  background: rgba(107, 30, 46, .08); border-radius: 10px;
  padding: 6px 10px; margin: 0 0 6px;
}
.bubble.mine .reply-quote {
  background: rgba(0, 0, 0, .16); border-left-color: rgba(255, 255, 255, .7);
}
.bubble.mine .reply-quote .rq-name { color: #ffd7de; }
.bubble.mine .reply-quote .rq-text { color: rgba(255, 255, 255, .85); }
.reply-quote.gone { cursor: default; }
.reply-quote.gone .rq-text { font-style: italic; opacity: .7; }
.bubble.photo .reply-quote { width: auto; margin: 2px 2px 6px; }
.bubble-reply {
  border: 0; background: none; cursor: pointer; padding: 0 2px; margin-left: 6px;
  font-size: .8rem; line-height: 1; opacity: .4; color: inherit; vertical-align: baseline;
}
.bubble-reply:active { transform: scale(.9); }
.bubble.photo .bubble-reply { display: inline-block; margin: 2px 4px 0 0; opacity: .55; }
.bubble.flash { animation: bubble-flash 1.2s ease; }
@keyframes bubble-flash {
  0%, 60% { box-shadow: 0 0 0 3px rgba(234, 47, 92, .45); }
  100% { box-shadow: none; }
}

/* Chat presence / typing / read receipts */
/* Empty chat. Sized to fill the log so the openers land near the thumb rather
   than clinging to the top of the screen. */
.chat-empty {
  /* Centred in the whole log, with the design's 20px rhythm between blocks. */
  flex: 1; display: flex; flex-direction: column; align-items: center;
  justify-content: center; text-align: center; gap: 20px; padding-bottom: 38px;
}
/* 96px, ringed in translucent accent rather than white, with the accent's own
   glow beneath — the design makes the face the warmest thing on the screen. */
.chat-empty-avatar {
  /* No extra margin under it: the stack's gap-5 (20px) is the whole rhythm,
     and the stray 6px stretched the block past the design's. */
  width: 96px; height: 96px; border-radius: 50%; overflow: hidden;
  background: var(--fill, #f3ece4); display: grid; place-items: center;
  font-size: 2.4rem; box-shadow: 0 8px 32px rgba(107, 30, 46, .13);
  border: 3px solid rgba(107, 30, 46, .27);
}
.chat-empty-avatar img { width: 100%; height: 100%; object-fit: cover; }
.chat-empty-name { font-size: var(--t-chat-name); font-weight: 700; color: var(--c-ink); }
.chat-empty-lead { margin: 4px 0 0; color: var(--c-muted-4); font-size: var(--t-row-sub); }
.chat-empty-hint { margin: 0; color: var(--c-muted-3); font-size: var(--t-chip); font-weight: 600; }
/* The caption and the buttons are one sub-column in the design, spaced 12
   inside it — the stack's own 20 minus this pull-up. */
.chat-openers { display: flex; gap: 12px; flex-wrap: wrap; justify-content: center; margin-top: -8px; }
/* 48px, unframed, on a barely-there white — the emoji carries the button. */
.chat-opener {
  width: 48px; height: 48px; border-radius: 50%; border: 0;
  background: rgba(255, 255, 255, .7); font-size: 24px; line-height: 1; cursor: pointer;
  box-shadow: 0 2px 12px rgba(0, 0, 0, .08);
  transition: transform .12s ease, box-shadow .12s ease;
}
.chat-opener:hover { transform: translateY(-2px); box-shadow: 0 6px 18px rgba(0, 0, 0, .12); }
.chat-opener:active { transform: scale(.9); }

.chat-head-link { display: flex; align-items: center; gap: 12px; flex: 1; color: inherit; text-decoration: none; }
.chat-head-link:hover { text-decoration: none; }
/* Name on a 24 line, 6 under it, status at 12/18 — the header column then
   centres to exactly the prototype's rows: name y22, status y52. */
.chat-head-info { display: flex; flex-direction: column; gap: 6px; }
.peer-status { font-size: .78rem; color: var(--muted); }
.peer-status.on { color: #2e9e5b; }
.bubble-body { white-space: pre-wrap; word-break: break-word; }
.bubble.mine .ticks { margin-left: 6px; font-size: .68rem; opacity: .65; vertical-align: baseline; }
.bubble.mine .ticks.read { color: #7fd4ff; opacity: 1; }
.bubble.photo { padding: 4px; max-width: 62%; }
.chat-photo { display: block; width: 100%; max-width: 220px; border-radius: 12px; }
.bubble.photo .ticks { display: block; text-align: right; margin: 2px 4px 0 0; }
.chat-photo-btn {
  flex-shrink: 0; border: none; background: none; font-size: 22px; cursor: pointer;
  padding: 0 4px; line-height: 1; align-self: center;
}
.chat-photo-btn:disabled, .chat-photo-btn.busy { opacity: .5; pointer-events: none; }
.typing-bubble { padding: 12px 14px; }
.typing-dots { display: inline-flex; gap: 4px; align-items: center; }
.typing-dots i {
  width: 6px; height: 6px; border-radius: 50%; background: var(--muted);
  display: inline-block; animation: typing-blink 1.2s infinite ease-in-out both;
}
.typing-dots i:nth-child(2) { animation-delay: .2s; }
.typing-dots i:nth-child(3) { animation-delay: .4s; }
@keyframes typing-blink { 0%, 80%, 100% { opacity: .3; } 40% { opacity: 1; } }

@media (max-width: 520px) {
  .grid-form { grid-template-columns: 1fr; }
  .hero h1 { font-size: 1.9rem; }
}

/* ---------------------------------------------------------- legal documents */
/* The shell every public document and content page uses — same card level as
   the app, so /faq and /privacy don't look like a different site. */
/* ---- documents ----
   Privacy, terms, the deletion instructions and the content pages. One panel
   per section instead of one slab with rules between headings: the sections
   are what people scan, and the shape is the app's own everywhere else.
   The text is never touched by any of this — it comes whole out of legal.py
   and content.py. */
.doc { display: flex; flex-direction: column; gap: 16px; padding-top: 8px; }
.doc .auth-title { text-align: left; }
.doc-head { padding-bottom: 20px; }
.doc-updated { margin: 6px 0 0; font-size: var(--t-chip); color: var(--c-muted-4); }
.doc-lead {
  margin: 12px 0 0; padding: 12px 14px; border-radius: var(--r-tile);
  background: var(--c-accent-tint); border: 1px solid var(--c-accent-tint-mid);
  font-size: var(--t-body); line-height: 1.6; color: var(--c-ink-2);
}
.doc-sec h2 { margin: 0 0 12px; }
.doc-sec p { margin: 0 0 10px; font-size: var(--t-body); line-height: 1.65; color: #444; }
.doc-sec p:last-child { margin-bottom: 0; }
.doc-sec ul, .doc-list { margin: 0; padding-left: 20px; }
.doc-sec li, .doc-list li {
  margin-bottom: 8px; font-size: var(--t-body); line-height: 1.6; color: #444;
}
.doc-sec li:last-child, .doc-list li:last-child { margin-bottom: 0; }
.doc-sec b { color: var(--c-ink); font-weight: 600; }
.doc-switch {
  display: flex; flex-wrap: wrap; justify-content: center; gap: 8px 16px;
  padding: 4px 0 8px; font-size: var(--t-chip);
}
.doc-switch a { color: var(--c-muted); }
.lp-foot-legal { display: block; margin-top: 6px; }
.lp-foot-legal a { margin: 0 2px; }
.lp-foot-nav { display: block; margin-bottom: 10px; }
.lp-foot-nav a { margin: 0 2px; color: var(--wine); }


/* Screen openers — the warmth that used to sit in the tab labels lives here now. */
.screen-title {
  margin: 4px 0 14px; font-size: 1.02rem; font-weight: 600; line-height: 1.4;
  color: var(--ink); letter-spacing: .1px;
}
.screen-title::first-letter { font-size: 1.15em; }
@media (max-width: 520px) {
  .screen-title { font-size: .96rem; margin-bottom: 12px; }
}

/* ---- profile editor ---- */
/* One section per card, the same shape as the rows elsewhere; the grid lives
   inside each card rather than running the length of the screen. */
.form-card { padding: 18px 16px; margin-bottom: 14px; }
.form-card > .grid-form { margin-top: 4px; }
.form-card label { margin-bottom: 12px; font-size: .9rem; color: var(--muted); font-weight: 600; }
.form-card .age-confirm { display: flex; align-items: flex-start; gap: 10px; color: var(--ink); font-weight: 400; }
.form-card .age-confirm input { width: auto; margin: 3px 0 0; flex-shrink: 0; }
.form-card fieldset { border: 0; background: none; padding: 0; margin: 0 0 12px; }
.form-card legend { padding: 0; font-size: .9rem; color: var(--muted); font-weight: 600; }
.form-submit { display: block; width: 100%; margin: 4px 0 8px; }

/* ---- filter sheet ----------------------------------------------------------
   The prototype's FilterScreen: a sheet over the feed, radius 28 on the top
   corners, at most 92% of the screen, sliding up from the bottom. Its numbers
   are the design's; the sections below the country card are Guli's own filters
   built from the same parts. */
.sheet-backdrop {
  position: fixed; inset: 0; z-index: 300;
  background: rgba(0, 0, 0, .35);
  -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
  display: flex; align-items: flex-end; justify-content: center;
}
.sheet-backdrop[hidden] { display: none; }
/* Tapping the dimmed area closes the sheet — a link, so it works without JS. */
.sheet-close { position: absolute; inset: 0; }
.sheet {
  position: relative; width: 100%; max-width: var(--s-shell-max);
  max-height: 92%; display: flex; flex-direction: column;
  background: var(--c-bg); border-radius: 28px 28px 0 0;
  box-shadow: 0 -8px 40px rgba(80, 20, 40, .14);
  animation: sheet-up .32s cubic-bezier(.2, .8, .2, 1);
}
@keyframes sheet-up { from { transform: translateY(100%); } to { transform: none; } }
@media (prefers-reduced-motion: reduce) { .sheet { animation: none; } }
.sheet-handle { display: grid; place-items: center; padding: 12px 0 4px; flex: none; }
.sheet-handle span { width: 40px; height: 4px; border-radius: 999px; background: rgba(0, 0, 0, .14); }
.sheet-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 0 20px 12px; flex: none;
}
.sheet-head h2 { margin: 0; font-size: 22px; font-weight: 700; color: var(--c-ink); }
.sheet-apply {
  /* line-height 1.5, like every other button in the design: without it the
     button was 29 tall against the prototype's 34.5, which made the whole
     header 1.5px short and shifted every card in the sheet. */
  border: 0; cursor: pointer; font-weight: 700; font-size: 15px; line-height: 1.5;
  padding: 6px 16px; border-radius: 999px; background: var(--c-accent); color: #fff;
}
.sheet-body {
  flex: 1; min-height: 0; overflow-y: auto; padding: 0 20px 24px;
  display: flex; flex-direction: column; gap: 16px;
}
.sheet-body::-webkit-scrollbar { display: none; }
.sheet-card {
  padding: 20px; border-radius: var(--r-panel);
  background: var(--glass-card-bg);
  -webkit-backdrop-filter: blur(var(--glass-card-blur));
  backdrop-filter: blur(var(--glass-card-blur));
  border: 1px solid var(--glass-card-line); box-shadow: var(--glass-card-shadow);
}
.sheet-card.row { display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.sheet-label {
  margin: 0 0 12px; font-size: var(--t-section-label); font-weight: 700;
  text-transform: uppercase; letter-spacing: .1em; color: var(--c-accent);
}
/* The age card is the one place the label stands further off — 16 against the
   12 everywhere else, as the prototype has it. Its own class, not an adjacency
   rule: that one added its margin on top of the label's instead of replacing it. */
.sheet-label.wide { margin-bottom: 16px; }
.age-row { display: flex; align-items: center; margin-bottom: 16px; }
/* 32px at the inherited 1.5 — the numbers row is 48 tall in the design, and
   setting line-height:1 here quietly took 16px out of the card. */
.age-num { font-size: 32px; font-weight: 700; color: var(--c-ink); }
.age-rule { flex: 1; height: 2px; margin: 0 16px; border-radius: 999px; background: var(--c-accent-tint-mid); }

/* Two native range inputs share one track. Native inputs preserve keyboard and
   accessibility behaviour; JS only keeps the handles ordered and paints the
   selected interval. */
.range-values {
  display: flex; align-items: center; justify-content: center; gap: 14px;
  margin-bottom: 14px; color: var(--c-ink); font-size: 25px; font-weight: 700;
}
.range-values output { min-width: 72px; text-align: center; }
.dual-range { position: relative; height: 34px; margin: 2px 2px 0; }
.dual-range-track {
  position: absolute; top: 15px; left: 0; right: 0; height: 4px;
  border-radius: 999px; background:
    linear-gradient(to right, var(--c-accent-tint-mid) 0 var(--range-left, 0%),
      var(--c-accent) var(--range-left, 0%) var(--range-right, 100%),
      var(--c-accent-tint-mid) var(--range-right, 100%) 100%);
}
.dual-range input[type="range"] {
  position: absolute; inset: 0; width: 100%; height: 34px; margin: 0;
  border: 0; padding: 0; background: transparent; pointer-events: none;
  appearance: none; -webkit-appearance: none;
}
.dual-range input[type="range"]::-webkit-slider-runnable-track { height: 4px; background: transparent; }
.dual-range input[type="range"]::-moz-range-track { height: 4px; background: transparent; }
.dual-range input[type="range"]::-webkit-slider-thumb {
  appearance: none; -webkit-appearance: none; pointer-events: auto; cursor: grab;
  width: 24px; height: 24px; margin-top: -10px; border-radius: 50%;
  border: 3px solid #fff; background: var(--c-accent);
  box-shadow: 0 2px 9px rgba(80, 20, 40, .35);
}
.dual-range input[type="range"]::-moz-range-thumb {
  pointer-events: auto; cursor: grab; width: 20px; height: 20px;
  border-radius: 50%; border: 3px solid #fff; background: var(--c-accent);
  box-shadow: 0 2px 9px rgba(80, 20, 40, .35);
}
.dual-range input[type="range"]:focus-visible::-webkit-slider-thumb { outline: 3px solid var(--c-accent-tint-mid); }
.dual-range input[type="range"]:focus-visible::-moz-range-thumb { outline: 3px solid var(--c-accent-tint-mid); }

/* Chips. A label wrapping its own input: the choice survives without JS, and
   the input itself is never seen. */
/* The chips are laid out as blocks, not as text. Left inline, each row of the
   grid grew by the container's line box — 39px chips in 53px rows — and the
   error stacked down the whole sheet. The container carries no line box; the
   chips bring their own back. */
.f-grid { display: flex; flex-wrap: wrap; gap: 8px; }
.f-row { display: flex; flex-wrap: wrap; gap: 8px; }
.f-pill {
  /* The chips are <label>s, and the app has a global label rule with a 14px
     bottom margin for form fields. That margin was the whole drift: 14px under
     every chip row, compounding down the sheet. */
  margin: 0;
  display: inline-flex; align-items: center; justify-content: center; cursor: pointer;
  padding: 8px 16px; border-radius: 999px; font-size: 14px; font-weight: 500;
  color: var(--c-ink-3); background: var(--glass-pill-bg);
  -webkit-backdrop-filter: blur(var(--glass-pill-blur)); backdrop-filter: blur(var(--glass-pill-blur));
  border: 1px solid var(--glass-pill-line);
  transition: background .15s ease, color .15s ease, box-shadow .15s ease;
}
/* Four to a row, the design's grid — as flex rather than grid, because a grid
   row here sized itself from a line box and came out 14px taller than the chip
   inside it, which then stacked down the whole sheet. */
.f-grid .f-pill {
  flex: 0 0 calc((100% - 24px) / 4);
  padding: 8px 0; border-radius: var(--r-tile); font-weight: 600;
}
.f-pill.sm { font-size: 13px; font-weight: 600; }
.f-pill input { position: absolute; opacity: 0; pointer-events: none; width: 0; height: 0; margin: 0; }
.f-pill.on, .f-pill:has(input:checked) {
  background: var(--c-accent); color: #fff; border-color: transparent;
  box-shadow: 0 2px 12px rgba(107, 30, 46, .33);
}
.f-pill:active { transform: scale(.97); }

/* Country: one control, the design's pill, with the native select on top of it
   so the phone's own picker does the scrolling. */
.sheet-select {
  margin: 0; position: relative; display: flex; align-items: center; gap: 8px;
  padding: 12px 16px; border-radius: var(--r-tile); font-size: 15px; color: var(--c-ink-2);
  background: var(--glass-pill-bg);
  -webkit-backdrop-filter: blur(var(--glass-pill-blur)); backdrop-filter: blur(var(--glass-pill-blur));
  border: 1px solid var(--glass-pill-line);
}
.sheet-select > svg:first-child { color: var(--c-accent); flex: none; }
.sheet-select select {
  flex: 1; min-width: 0; border: 0; background: none; padding: 0; margin: 0;
  font: inherit; color: inherit; appearance: none; -webkit-appearance: none;
}
.sheet-select select:focus { outline: none; }
.sel-chevron { color: var(--c-muted-3); flex: none; }

/* Verified switch — 48×28 with a 24px knob, as drawn. */
.sw-title { margin: 0; font-size: 16px; font-weight: 600; color: var(--c-ink); }
.sw-sub { margin: 2px 0 0; font-size: 14px; color: var(--c-muted-2); }
.switch { flex: none; cursor: pointer; margin: 0; }
.switch input { position: absolute; opacity: 0; width: 0; height: 0; }
.switch-track {
  display: block; width: 48px; height: 28px; border-radius: 999px;
  background: rgba(0, 0, 0, .12); position: relative; transition: background .18s ease;
}
.switch-knob {
  position: absolute; top: 2px; left: 2px; width: 24px; height: 24px; border-radius: 50%;
  background: #fff; box-shadow: 0 1px 3px rgba(0, 0, 0, .2);
  transition: transform .22s cubic-bezier(.2, .8, .2, 1);
}
.switch input:checked + .switch-track { background: var(--c-accent); }
.switch input:checked + .switch-track .switch-knob { transform: translateX(20px); }

.sheet-cta {
  width: 100%; padding: 16px; border: 0; cursor: pointer;
  border-radius: var(--r-panel); background: var(--c-accent); color: #fff;
  font-size: 17px; font-weight: 700; box-shadow: 0 6px 24px rgba(107, 30, 46, .33);
}
.sheet-reset {
  width: 100%; padding: 12px; border-radius: var(--r-panel);
  display: flex; align-items: center; justify-content: center; gap: 8px;
  font-size: 15px; font-weight: 600; color: var(--c-muted);
  background: var(--glass-pill-bg);
  -webkit-backdrop-filter: blur(var(--glass-pill-blur)); backdrop-filter: blur(var(--glass-pill-blur));
  border: 1px solid var(--glass-pill-line);
}
.sheet-reset:hover { text-decoration: none; }
.sheet-reset svg { color: var(--c-muted-4); }


/* ---- empty deck ----
   The design has no drawing for "nobody left", so this is assembled from what
   it does draw: the panel glass, the accent section label, and the sheet's own
   Apply/Reset pair. The old version was a 56px emoji on a card, which belonged
   to the interface this replaces. */
/* The empty deck centres its card in the AVAILABLE area, not the document:
   the same span the deck occupies — from under the top chrome/safe-area down
   to just above the floating nav — so the card sits in the middle of what the
   viewer can see and never drifts under the bottom navigation. The exact same
   arithmetic as .deck, so it is identical in the browser and in Telegram
   fullscreen (--web-chrome / --tg-top and --tg-bottom carry the insets).
   min-height, not height, so a long RU/KA card grows instead of clipping. */
#deck-empty, .deck-empty {
  display: grid; place-items: center;
  min-height: calc(var(--vh, 100dvh) - 8px - 104px
                   - var(--web-chrome) - env(safe-area-inset-bottom, 0px) - var(--tg-bottom, 0px));
}
#deck-empty[hidden] { display: none; }
.deck-empty-card {
  width: 100%; padding: 32px 24px; border-radius: var(--r-panel); text-align: center;
  background: var(--glass-panel-bg);
  -webkit-backdrop-filter: blur(var(--glass-panel-blur));
  backdrop-filter: blur(var(--glass-panel-blur));
  border: 1px solid var(--glass-panel-line); box-shadow: var(--glass-panel-shadow);
}
.deck-empty-mark {
  display: grid; place-items: center; width: 64px; height: 64px; margin: 0 auto 16px;
  border-radius: 50%; color: var(--c-accent);
  background: var(--c-accent-tint); border: 1px solid var(--c-accent-tint-mid);
}
.deck-empty-mark svg { width: 30px; height: 30px; }
.deck-empty-label {
  margin: 0 0 8px; font-size: var(--t-section-label); font-weight: 700;
  text-transform: uppercase; letter-spacing: .1em; color: var(--c-accent);
}
.deck-empty-text { margin: 0 0 20px; font-size: var(--t-body); color: var(--c-muted); }
.deck-empty .sheet-cta { display: block; text-align: center; margin-bottom: 10px; }
.deck-empty .sheet-cta:hover { text-decoration: none; }


/* The matches row can end in a gift instead of a chevron — the design's round
   tile, in the accent tint. */
.row-gift {
  flex: none; width: 40px; height: 40px; border-radius: 50%;
  display: grid; place-items: center; font-size: 18px;
  background: var(--c-accent-tint); border: 1px solid var(--c-accent-tint-mid);
}
/* The locked and empty states of this screen use the deck's card, centred in
   the content column rather than filling the screen. */
.screen .deck-empty-card { margin-top: 4px; }

.row-main .row-sub { margin-top: 2px; }
.row-main .compat { margin-top: 6px; }

/* The chat header's own tick — 13px, as in the design, and the accent-blue of
   every other verified mark. */
.head-check { width: 13px; height: 13px; color: var(--c-verified-row); flex: none; }

/* ---- someone else's profile ------------------------------------------------
   The prototype's PersonDetailScreen: a photo that owns the top of the screen,
   the round actions straddling its lower edge, then the person in blocks. White
   underneath rather than the app's cream — the design switches surface here. */
/* Full-bleed: this screen is a sheet over the app, not a page inside the
   column's padding. */
/* The prototype lays this screen over the app across the whole content area —
   no inset, no rounded shell. A rounded white panel inside the column left a
   visible band down both edges. */
/* The page must scroll past its last block: the floating nav takes
   72px + a 16px offset off the bottom, plus the phone's own safe area, and
   32px of air keeps the final line fully readable above the glass. */
.wrap.person {
  padding: 0 0 calc(var(--s-nav-h) + var(--s-gutter) + env(safe-area-inset-bottom, 0px) + var(--tg-bottom, 0px) + 32px);
  max-width: var(--s-shell-max);
}
.wrap.person.has-chrome {
  padding-top: var(--web-chrome);   /* 0 inside Telegram */
}
html { scroll-padding-bottom: calc(var(--s-nav-h) + var(--s-gutter) + 32px); }
/* One surface for the whole profile: photo and panel share a single card —
   one background token, one radius, one shadow, and the only overflow:hidden
   sits here. The photo's corners are the card's corners, so nothing white
   can peek out around them; the trio straddles the photo's edge INSIDE the
   card and is never clipped.
   dvh, not vh: the URL bar's collapse must not leave a stripe of body
   background under a "100vh" page. */
/* One surface for the whole profile: the photo on top melts into the
   information below, sharing a single card — one background, one radius, one
   shadow, and the clip that rounds the photo's top and the panel's bottom.
   (The chips and long-block cards inside keep their own raised look.) */
.pv {
  background: var(--card); min-height: 100dvh;
  margin: 4px var(--s-gutter) 0;
  border-radius: var(--radius-card); overflow: hidden;
  box-shadow: var(--shadow-photo);
}
/* The action row hangs below the photo, so this box cannot clip. */
/* The accepted edge-to-edge frame: the prototype's 54vh header, unchanged.
   Web keeps this geometry even while a browser URL bar is visible; Telegram
   gets its own svh override below because its fullscreen WebView has no URL
   bar and reports the small viewport reliably. */
.pv-photo { position: relative; height: 54vh; min-height: 320px; }
/* Mobile web browsers expose a smaller `svh` while their URL bar is visible.
   That made this portrait frame shorter than the accepted web geometry and
   cropped the top of some faces. Telegram has no browser URL bar, so keep its
   fullscreen framing on the small viewport unit only inside the Mini App. */
html.tg-app .pv-photo { height: 54svh; }

/* The white round pager rides ON the photo — no card, no extra chrome.
   Visible, keyboard-focusable, and it says what it does; drawn only when
   there is more than one photo. */
.pv-arrow {
  position: absolute; top: 50%; transform: translateY(-50%); z-index: 6;
  width: 40px; height: 40px; border: 0; border-radius: 50%; cursor: pointer;
  display: grid; place-items: center; color: #444;
  background: rgba(255, 255, 255, .94); box-shadow: 0 4px 20px rgba(0, 0, 0, .18);
}
.pv-arrow.prev { left: 12px; }
.pv-arrow.next { right: 12px; }
.pv-arrow:active { transform: translateY(-50%) scale(.92); }

.pv-photo-img { width: 100%; height: 100%; object-fit: cover; display: block; }
.pv-photo-none {
  width: 100%; height: 100%; display: grid; place-items: center;
  background: linear-gradient(160deg, #e6d8c8, #c8b3a3);
}
/* The face stays clean: no darkening in the photo's upper 60% at all, and
   the gradient only climbs through the lower 38% to carry the white name.
   The top layer melts the photo's last 28px into the surface's white, so the
   photo and the information read as one plate with no seam. */
.pv-scrim {
  position: absolute; inset: 0; pointer-events: none; z-index: 2;
  background:
    linear-gradient(to bottom, rgba(255,255,255,0) calc(100% - 28px), var(--card) 100%),
    linear-gradient(to bottom, rgba(0,0,0,0) 62%, rgba(0,0,0,.58) 100%);
}
.pv-bars { top: 56px; }
/* Only the active frame exists on screen: the stacked mode shows one <img>
   and display:none's the rest, so frames cannot blend or shine through at
   any paging speed. */
/* The single .pv surface does the clipping and the rounding, so the stacked
   frames need none of their own — and the trio, hanging past the photo edge,
   stays unclipped. */
.pv-carousel.stacked { overflow: visible; }
.pv-carousel.stacked .carousel-track img { display: none; }
.pv-carousel.stacked .carousel-track img.on { display: block; }
/* Name and place, pinned to the photo's lower zone — never its middle. */
.pv-overlay {
  position: absolute; left: 20px; right: 20px; bottom: 52px; z-index: 5;
  color: #fff; pointer-events: none;
  text-shadow: 0 1px 8px rgba(0, 0, 0, .45);
}
.pv-overlay .pv-name {
  margin: 0; font-size: 26px; font-weight: 700; line-height: 1.25; color: #fff;
  display: flex; align-items: center; gap: 8px;
}
.pv-overlay .pv-verified { color: #fff; flex: none; }
.pv-overlay .pv-where {
  display: flex; align-items: center; gap: 6px; margin-top: 2px;
  font-size: 14px; color: rgba(255, 255, 255, .92);
}
.pv-back {
  position: absolute; top: max(env(safe-area-inset-top, 16px), 16px); left: 16px;
  z-index: 6;
  width: 40px; height: 40px; border-radius: 50%; display: grid; place-items: center;
  color: #fff; cursor: pointer;
  background: var(--glass-pill-dark-bg); border: 1px solid var(--glass-pill-dark-line);
  -webkit-backdrop-filter: blur(var(--glass-pill-dark-blur));
  backdrop-filter: blur(var(--glass-pill-dark-blur));
  transition: transform .12s ease;
}
.pv-back:active { transform: scale(.9); }
/* The row hangs 38px below the photo's edge, as the design draws it. */
.pv-float {
  /* ActionButtons size="lg" in the prototype: bottom −38 = half the 76px
     centre button, so its middle rides the photo edge exactly. */
  position: absolute; left: 0; right: 0; bottom: -38px; z-index: 3;
  display: flex; justify-content: center; align-items: center; gap: 24px;
}
.pv-float-form { margin: 0; }
/* The person trio is the "lg" variant: 62px side buttons with 26px icons,
   a 76px middle one with a 34px icon. X red, the gift star gold and filled,
   the report triangle quiet grey. */
.pv-float .swipe-btn { width: 62px; height: 62px; }
.pv-float .swipe-btn.like { width: 76px; height: 76px; }
.pv-float .swipe-btn svg { width: 26px; height: 26px; }
.pv-float .swipe-btn.like svg { width: 34px; height: 34px; }
.pv-float .swipe-btn.pass { color: #d94040; }
.pv-float .swipe-btn.like { color: #c49a3a; }
.pv-float .swipe-btn { color: #999; }

/* The information flows straight under the photo on the shared surface — no
   overlap, no separate shadow or radius. The top padding clears the trio,
   which hangs 38px past the photo edge. The chips and long-block cards inside
   carry their own raised look. */
.pv-body { padding: 56px 20px 40px; }
/* The name and place moved onto the photograph; the panel opens with the
   quieter metadata — occupation, then the chips. */
.pv-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 20px; }
/* The light chip — the design's `pill` on a white surface, not the dark glass
   the photo card uses. */
.chip-light {
  /* gap 4, like every chip in the design — 5 shifted each label a pixel. */
  display: inline-flex; align-items: center; gap: 4px;
  padding: 6px 12px; border-radius: 999px; font-size: var(--t-chip); font-weight: 500;
  color: var(--c-ink-3); background: var(--glass-pill-bg);
  border: 1px solid var(--glass-pill-line);
}
.chip-light svg { opacity: .6; flex: none; }
/* On the raised panel the chips sit on white, so a white pill needs its own
   quiet lift to read as a separate element — a hair of a light border and a
   soft, shallow shadow. Size, padding, gap and radius are untouched. */
.pv-body .chip-light {
  background: #fff;
  border-color: rgba(0, 0, 0, .06);
  box-shadow: 0 1px 3px rgba(80, 20, 40, .07);
}

.pv-cta { display: flex; gap: 12px; margin-bottom: 24px; }
.pv-btn {
  flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  /* The prototype's py-3.5 button computes to 53px outer — its line box runs
     2px past 15×1.5, so the height is pinned rather than re-derived. */
  padding: 14px 0; height: 53px; box-sizing: border-box;
  border-radius: var(--r-panel); font-size: 15px; font-weight: 600;
  transition: transform .12s ease;
}
.pv-btn:hover { text-decoration: none; }
.pv-btn:active { transform: scale(.98); }
.pv-btn.primary { background: var(--c-accent); color: #fff; box-shadow: 0 4px 20px rgba(107, 30, 46, .33); }
.pv-btn.ghost {
  color: var(--c-accent); background: var(--glass-card-bg);
  border: 1.5px solid var(--c-accent-tint-mid);
}
.pv-sec { margin-bottom: 24px; }
.pv-sec h3 { margin: 0 0 8px; font-size: 18px; font-weight: 700; color: var(--c-ink); }
.pv-sec:has(.pv-chips) h3, .pv-sec:has(.pv-prompts) h3 { margin-bottom: 12px; }
.pv-about { margin: 0; font-size: var(--t-body); line-height: 1.6; color: #666; }
.pv-more {
  margin-top: 4px; padding: 0; border: 0; background: none; cursor: pointer;
  color: var(--c-accent); font-weight: 600; font-size: var(--t-body);
}
.pv-more.inline { display: inline; margin: 0 0 0 6px; vertical-align: baseline; }
/* The wide raised card: the long blocks (About, prompts) wear the same
   fill / light border / soft shadow as the short chips, only wider and with
   the panel radius instead of a pill. One visual system for the whole
   profile — nothing is a bare paragraph on the panel any more. */
.pv-card {
  background: #fff;
  border: 1px solid rgba(0, 0, 0, .06);
  border-radius: var(--r-panel);
  box-shadow: 0 1px 3px rgba(80, 20, 40, .07);
  padding: 14px 16px;
}
.pv-prompts { display: flex; flex-direction: column; gap: 10px; }
.pv-prompt { display: flex; flex-direction: column; gap: 4px; }
.pv-prompt-q { font-size: var(--t-chip); font-weight: 700; color: var(--c-accent);
  text-transform: uppercase; letter-spacing: .06em; }
.pv-prompt-a { font-size: var(--t-body); color: var(--c-ink); }
.pv-admin { margin-top: 8px; }

/* The profile's switch is taller than the one on matches — py-3 against py-2.5
   in the design, which is what makes it read as a section header rather than a
   filter. */
/* The profile's switch, measured off the prototype: a 15px label on a 1.5
   line inside 12px of padding — 46.5 tall, 56.5 with the shell — and it sits
   16 below the completeness card, 12 above the pane. The matches screen keeps
   the plain .segmented, which the design draws smaller. */
.segmented.tall { margin-top: 16px; margin-bottom: 12px; gap: 8px; }
.segmented.tall .seg {
  padding: 12px 0; font-size: 15px; line-height: 1.5;
}
/* The design's stat tile is a number and a word; the icons above them were
   ours, and emoji cannot take the accent. */
/* .stat-num / .stat-lbl are defined once, up with the tiles they belong to.
   A second copy used to sit here and win by order: 26px accent instead of the
   design's 34px ink, which made every tile 5px short. */

/* ---- the profile's rows ----------------------------------------------------
   The design's row, used for every line on this screen: a card, a 40px tinted
   tile with a line glyph, the label, what it says right now, and a chevron.
   Replaces `.icon-row` with its emoji-in-a-square, which was the last of the
   old interface here. */
.mrow {
  display: flex; align-items: center; gap: 14px; width: 100%;
  padding: 14px 16px; margin-top: 10px; border-radius: var(--r-tile);
  background: var(--glass-card-bg);
  -webkit-backdrop-filter: blur(var(--glass-card-blur));
  backdrop-filter: blur(var(--glass-card-blur));
  border: 1px solid var(--glass-card-line); box-shadow: var(--glass-card-shadow);
  color: var(--c-ink); font: inherit; text-align: left; cursor: pointer;
  transition: transform .12s ease;
}
.mrow:hover { text-decoration: none; }
.mrow:active { transform: scale(.98); }
.mrow-form { margin: 0; }
.mrow-ico {
  flex: none; width: 40px; height: 40px; border-radius: var(--r-tile);
  display: grid; place-items: center;
  color: var(--c-accent); background: var(--c-accent-tint);
  border: 1px solid var(--c-accent-tint-mid);
}
.mrow-ico svg { width: 18px; height: 18px; }
.mrow-label { flex: 1; min-width: 0; font-size: var(--t-body); color: #444; }
.mrow-value { flex: none; font-size: var(--t-body); font-weight: 700; color: var(--c-accent); }
.mrow-chevron { flex: none; width: 15px; height: 15px; color: var(--c-muted-6); }
.mrow.danger .mrow-ico { color: var(--c-nope); background: rgba(217, 64, 64, .08); border-color: rgba(217, 64, 64, .2); }
.mrow.danger .mrow-value { color: var(--c-muted-4); font-weight: 500; }
.mrow-sec { margin: 24px 0 4px; }
/* The language row carries its chips underneath rather than beside the label. */
.mrow.mrow-stack { flex-direction: column; align-items: stretch; gap: 12px; cursor: default; }
.mrow.mrow-stack:active { transform: none; }
.mrow-line { display: flex; align-items: center; gap: 14px; }
.mrow-stack .f-pill { text-decoration: none; }

/* The invite card, as the design draws it: accent tile, the promise, the link
   in a tinted box, one button. */
.ref-card {
  display: flex; gap: 12px; padding: 16px; margin-top: 10px;
  border-radius: var(--r-panel);
  background: var(--glass-card-bg); border: 1px solid var(--c-accent-tint-mid);
  box-shadow: var(--glass-card-shadow);
}
.ref-card-ico {
  flex: none; width: 40px; height: 40px; border-radius: var(--r-tile);
  display: grid; place-items: center; background: var(--c-accent); color: #fff;
}
.ref-card-ico svg { width: 17px; height: 17px; }
.ref-card-body { flex: 1; min-width: 0; }
.ref-card-head { margin: 0; font-size: var(--t-row-name-sm); font-weight: 600; color: var(--c-ink); }
.ref-card-hint { margin: 4px 0 0; font-size: var(--t-chip); line-height: 1.5; color: var(--c-muted-2); }
.ref-card-link {
  margin-top: 12px; padding: 8px 12px; border-radius: 10px;
  background: var(--c-accent-tint); color: #777; font-size: var(--t-section-label);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ref-card-actions { display: flex; align-items: center; gap: 8px; margin-top: 12px; }
.ref-card-btn {
  padding: 10px 20px; border-radius: 999px; background: var(--c-accent); color: #fff;
  font-size: var(--t-row-sub); font-weight: 700;
}
.ref-card-btn:hover { text-decoration: none; }
.ref-card-copy {
  padding: 10px 16px; border-radius: 999px; cursor: pointer;
  background: var(--glass-pill-bg); border: 1px solid var(--glass-pill-line);
  font-size: var(--t-row-sub); font-weight: 600; color: var(--c-muted);
}

.stat-top { display: flex; align-items: center; justify-content: center; gap: 6px; }
.stat-ico { width: 17px; height: 17px; flex: none; }

/* Your own card is set a notch smaller than a feed card — the design uses 15px
   for the location line and unbordered interest chips here, which is what let
   five of them sit on one row instead of wrapping onto two. Measured against
   the prototype: location 22.5 tall, zodiac 29.5, interests 28. */
.pcard-hero .ov-loc { font-size: 15px; }
.pcard-hero .ov-zodiac { margin-bottom: 10px; }
.pcard-hero .ov-zodiac .chip-dark { padding: 4px 12px; font-size: 13px; }
/* Only the interests lose their outline — that 1px each is what pushed the
   fifth chip onto a second row. */
/* The interest chips keep the same hairline as every other dark chip — the
   prototype draws one, and dropping it made this row 2px shorter, which was
   the last of the overlay's drift. */
.pcard-hero .chip-dark.soft { padding: 4px 12px; }

/* ---- the way in ------------------------------------------------------------
   The design draws no sign-in screen, so these are built from what it does
   draw: the panel glass, the accent section label, the sheet's own field and
   its two buttons. One shell for login, registration, the welcome and the
   e-mail code — they are one flow and should not look like four pages. */
.auth { display: flex; flex-direction: column; gap: 16px; padding-top: 8px; }
.auth-card {
  padding: 24px 20px; border-radius: var(--r-panel);
  background: var(--glass-panel-bg);
  -webkit-backdrop-filter: blur(var(--glass-panel-blur));
  backdrop-filter: blur(var(--glass-panel-blur));
  border: 1px solid var(--glass-panel-line); box-shadow: var(--glass-panel-shadow);
}
.auth-mark {
  width: 64px; height: 64px; margin: 0 auto 16px; border-radius: 50%;
  display: grid; place-items: center; color: var(--c-accent);
  background: var(--c-accent-tint); border: 1px solid var(--c-accent-tint-mid);
}
.auth-mark svg { width: 30px; height: 30px; }
.auth-title {
  margin: 0; font-size: var(--t-screen-title); font-weight: 700; color: var(--c-ink);
  line-height: 1.5; text-align: center;
}
.auth-sub {
  margin: 6px 0 0; font-size: var(--t-body); line-height: 1.5;
  color: var(--c-muted); text-align: center;
}
.auth-form { display: flex; flex-direction: column; gap: 14px; margin-top: 20px; }
.field { display: block; }
.field > span {
  display: block; margin-bottom: 8px; font-size: var(--t-section-label); font-weight: 700;
  text-transform: uppercase; letter-spacing: .1em; color: var(--c-accent);
}
.field input, .field textarea, .field select {
  width: 100%; margin: 0; padding: 12px 16px; border-radius: var(--r-tile);
  font: inherit; font-size: var(--t-body); color: var(--c-ink-2);
  background: var(--glass-pill-bg); border: 1px solid var(--glass-pill-line);
  -webkit-backdrop-filter: blur(var(--glass-pill-blur));
  backdrop-filter: blur(var(--glass-pill-blur));
}
.field input:focus, .field textarea:focus, .field select:focus {
  outline: none; border-color: var(--c-accent-tint-mid);
}
.field-hint { margin: 6px 0 0; font-size: var(--t-chip); color: var(--c-muted-3); }
.auth-alert {
  margin-top: 16px; padding: 12px 16px; border-radius: var(--r-tile);
  font-size: var(--t-row-sub); color: var(--c-nope);
  background: rgba(217, 64, 64, .07); border: 1px solid rgba(217, 64, 64, .2);
}
.auth-alert.ok {
  color: #2e7d5b; background: rgba(46, 125, 91, .07); border-color: rgba(46, 125, 91, .2);
}
.auth-foot { margin: 0; text-align: center; font-size: var(--t-row-sub); color: var(--c-muted); }
.auth-foot a { font-weight: 600; }
/* The divider between one way in and another. */
.auth-or {
  display: flex; align-items: center; gap: 12px; margin: 4px 0;
  font-size: var(--t-chip); color: var(--c-muted-3);
}
.auth-or::before, .auth-or::after {
  content: ""; flex: 1; height: 1px; background: rgba(0, 0, 0, .07);
}
/* Consent is a row you tick, in the same card, never a line of small print. */
.auth-check {
  display: flex; align-items: flex-start; gap: 12px; margin: 0;
  padding: 14px 16px; border-radius: var(--r-tile); cursor: pointer;
  background: var(--glass-card-bg); border: 1px solid var(--glass-card-line);
  font-size: var(--t-chip); line-height: 1.5; color: #444; font-weight: 400;
}
.auth-check input { flex: none; width: 20px; height: 20px; margin: 0; accent-color: var(--c-accent); }
.auth-check:has(input:checked) { border-color: var(--c-accent-tint-mid); }

/* The welcome: one card, the design's parts, and the step it leads to. */
.welcome-lines { display: flex; flex-direction: column; gap: 10px; margin: 20px 0 0; }
.welcome-lines p { margin: 0; font-size: var(--t-body); line-height: 1.6; color: #555; }
.welcome-lines p.em { color: var(--c-accent); font-weight: 600; }
.welcome-sign { margin: 16px 0 0; font-size: var(--t-chip); color: var(--c-muted-3); text-align: right; }

/* Two fields on one line (day and month), and the prompt slot's pair. */
.field-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.prompt-slot { display: flex; flex-direction: column; gap: 8px; margin-top: 10px; }
.prompt-slot select, .prompt-slot input {
  width: 100%; margin: 0; padding: 12px 16px; border-radius: var(--r-tile);
  font: inherit; font-size: var(--t-body); color: var(--c-ink-2);
  background: var(--glass-pill-bg); border: 1px solid var(--glass-pill-line);
}
.prompt-slot select:focus, .prompt-slot input:focus {
  outline: none; border-color: var(--c-accent-tint-mid);
}
/* The chips in a form are choices, not filters — the same pill, wrapping. */
.field .f-row { margin-top: 0; }

/* Where you are in the three cards. */
.tut-dots { display: flex; justify-content: center; gap: 8px; margin-top: 24px; }
.tut-dot {
  width: 6px; height: 6px; border-radius: 999px; background: var(--c-accent-tint-mid);
  transition: width .2s ease, background .2s ease;
}
.tut-dot.on { width: 22px; background: var(--c-accent); }

/* The accent button is a <button> in the sheets and an <a> here; an anchor does
   not centre its own text, which left "Next" hanging on the left. */
a.sheet-cta {
  display: flex; align-items: center; justify-content: center; text-align: center;
}
a.sheet-cta:hover { text-decoration: none; }

/* Verification: the mark turns accent-green once it is actually done, so the
   state is legible before any text is read. */
.auth-mark.ok { color: #2e7d5b; background: rgba(46, 125, 91, .10); border-color: rgba(46, 125, 91, .25); }
/* What is about to be sent, drawn from the file the browser already holds. */
.vp-preview { border-radius: var(--r-tile); overflow: hidden; background: var(--c-fill, #f5efe7); }
.vp-preview img { display: block; width: 100%; max-height: 320px; object-fit: cover; }
/* A six-digit code reads better spaced out and centred. */
.code-input { letter-spacing: .4em; text-align: center; font-size: 1.25rem; }
.dev-code { letter-spacing: .3em; font-size: 1.3rem; }

/* ---- support ----
   A request has a topic and a state, and both are chosen or read before
   anything else happens. The topics are the sheet's chips turned into full
   rows: "Технические проблемы и платежи" does not fit a quarter of the width
   in any of the three languages. */
.sup-topics { display: flex; flex-direction: column; gap: 8px; }
.sup-topic {
  width: 100%; justify-content: flex-start; text-align: left;
  padding: 12px 16px; border-radius: var(--r-tile); font-weight: 600;
}
.sup-topic span { display: block; }

/* The state of a request, said in one word next to it. */
.sup-status {
  flex: none; padding: 4px 10px; border-radius: 999px;
  font-size: var(--t-chip); font-weight: 700; white-space: nowrap;
  color: var(--c-accent); background: var(--c-accent-tint);
  border: 1px solid var(--c-accent-tint-mid);
}
.sup-status.closed { color: var(--c-muted-4); background: rgba(0, 0, 0, .04); border-color: rgba(0, 0, 0, .07); }
.sup-status.waiting_user { color: #8a5a12; background: rgba(216, 149, 32, .12); border-color: rgba(216, 149, 32, .28); }
.sup-dot { flex: none; width: 8px; height: 8px; border-radius: 999px; background: var(--c-accent); }

.sup-row-topic {
  display: block; font-size: var(--t-row-name-sm); color: var(--c-ink);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sup-row-last {
  display: block; margin-top: 2px; font-size: var(--t-chip); color: var(--c-muted-2);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sup-head { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; }
/* The conversation sits inside the card rather than filling the screen: a
   request is read from top to bottom, not scrolled like a chat. */
.sup-log { max-height: 52vh; overflow-y: auto; padding: 0; }
/* The composer is the chat's, and it needs the width: with the card's own
   20px padding the field was narrow enough to wrap its placeholder. */
.sup-compose { padding: 10px 12px; }
/* In the panel it is one card of a stack, in the flow under the conversation:
   it drops the chat's own bottom clearance, and can neither cover a message
   nor fall off the screen. Scoped — the person's own /support keeps that
   clearance, because the floating tab bar sits right below it there. */
.adm-stack .sup-compose .chat-input { margin: 0; max-width: 100%; }
.adm-stack .sup-compose .chat-input textarea { flex: 1 1 auto; min-width: 0; }

/* ---- Premium, gifts and the lists of people ----
   These six screens were the last of the old style: emoji slabs, bordered
   plan buttons and a text chevron. They are built from the same parts as the
   rest now — the panel card, the accent section label, the wide accent CTA. */

/* A plan or a pack: label on the left, price on the right, in the design's
   tile rather than a bordered button. */
.plan-rows { display: flex; flex-direction: column; gap: 10px; }
.plan-row {
  display: flex; align-items: center; gap: 10px; width: 100%;
  padding: 16px; border-radius: var(--r-tile); cursor: pointer;
  background: var(--glass-card-bg);
  -webkit-backdrop-filter: blur(var(--glass-card-blur));
  backdrop-filter: blur(var(--glass-card-blur));
  border: 1px solid var(--glass-card-line); box-shadow: var(--glass-card-shadow);
  color: var(--c-ink); font: inherit; text-align: left;
  transition: transform .12s ease;
}
.plan-row:active { transform: scale(.98); }
.plan-row[disabled] { opacity: .55; cursor: default; }
.plan-row.best { border-color: var(--c-accent-tint-mid); }
.plan-name { flex: 1; min-width: 0; font-size: var(--t-body); font-weight: 600; }
.plan-price { flex: none; font-size: var(--t-body); font-weight: 700; color: var(--c-accent); }
.plan-tag {
  flex: none; padding: 2px 10px; border-radius: 999px;
  font-size: var(--t-chip); font-weight: 700; color: #fff; background: var(--c-accent);
}

/* What Premium is, as three lines with the accent tile the rest of the app
   uses for an icon. */
.perk-list { display: flex; flex-direction: column; gap: 12px; }
.perk { display: flex; align-items: center; gap: 12px; font-size: var(--t-body); color: #444; }
.perk-ico {
  flex: none; width: 36px; height: 36px; border-radius: var(--r-tile);
  display: grid; place-items: center; color: var(--c-accent);
  background: var(--c-accent-tint); border: 1px solid var(--c-accent-tint-mid);
}
.perk-ico svg { width: 17px; height: 17px; }

/* The gift balance, the one number this screen is about. */
.gift-balance {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  margin: 18px 0 12px; padding: 14px; border-radius: var(--r-tile);
  background: var(--c-accent-tint); border: 1px solid var(--c-accent-tint-mid);
}
.gift-balance-emoji { font-size: 26px; line-height: 1; }
.gift-balance-num { font-size: 28px; font-weight: 700; color: var(--c-accent); line-height: 1; }
.gift-balance-label { font-size: var(--t-chip); color: var(--c-muted-2); }

/* The line under a name that says a gift was sent — inside the row's column,
   not pinned to the photo. */
.row-note {
  display: inline-flex; align-items: center; gap: 4px; margin-top: 4px;
  width: fit-content; padding: 3px 10px; border-radius: 999px;
  font-size: var(--t-chip); font-weight: 700;
  color: var(--c-accent); background: var(--c-accent-tint);
}
/* A row you answer is not a link, so the two halves that still open a profile
   are. They must not add their own spacing on top of the row's gap. */
.row-face { display: flex; min-width: 0; color: inherit; }
.row-face:hover { text-decoration: none; }
.row-face.grow { flex: 1; }
.screen-note { margin: -6px 0 14px; font-size: var(--t-body); color: var(--c-muted); }

/* ---- the gift sheet ----
   The design's sheet, with one tile where the mockup has a grid of six: the
   gift is decided by who is sending it, so there is nothing to choose. */
/* Measured against the prototype's own sheet: 20 under the sub-line, 24 above
   the button, and a button whose text sits on a 1.5 line like everything else
   in the design (ours was 52 tall against 57.5). */
/* The prototype dims this sheet a shade deeper than the filter one (0.4 vs
   0.35), and holds 20px over the handle, 16 under it, 32 at the bottom. */
#giftSheet.sheet-backdrop { background: rgba(0, 0, 0, .4); }
/* The design's sheet is edge-to-edge on a phone; the 430 cap is a desktop
   nicety. Anything phone-ish gets the full bleed, exactly as the mockup
   draws it (and as headless capture lays it out). */
@media (max-width: 520px) { #giftSheet .sheet { max-width: none; } }
.gift-sheet .sheet-handle { padding: 20px 0 16px; }
.gift-sheet .sheet-body { padding-top: 0; padding-bottom: 32px; gap: 20px; }
.gift-sheet .sheet-cta { margin-top: 4px; line-height: 1.5; }
.gift-title { margin: 0; font-size: 20px; font-weight: 700; color: var(--c-ink); }
.gift-sub { margin: 4px 0 0; font-size: 14px; line-height: 1.5; color: var(--c-muted-4); }
.gift-sub.center { text-align: center; }
.gift-tile {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  /* py-4 in the mockup, whose emoji line-box adds its own slack — measured
     against it, the tile is 121px tall with the glyph 29px in. */
  padding: 24px 16px 20px; border-radius: var(--r-panel);
  background: var(--c-accent-tint); border: 1.5px solid var(--c-accent);
  box-shadow: 0 0 0 3px rgba(107, 30, 46, .13);
}
.gift-tile.out { background: rgba(0, 0, 0, .04); border-color: rgba(0, 0, 0, .08); box-shadow: none; }
.gift-tile-emoji { font-size: 32px; line-height: 1; }
/* The tile's type is the mockup's grid tile: a 13px medium label, 12px count. */
.gift-tile-label { font-size: 13px; font-weight: 500; color: var(--c-accent); }
.gift-tile.out .gift-tile-label { color: var(--c-muted-4); }
.gift-tile-left { font-size: 12px; color: var(--c-muted-2); }
.gift-done { align-items: center; text-align: center; padding-top: 24px; padding-bottom: 24px; }
.gift-done-emoji { font-size: 56px; line-height: 1; }
.gift-done-text { margin: 12px 0 0; font-size: 20px; font-weight: 700; color: var(--c-ink); }

/* ---- the values quiz ----
   Six cards of chips. The only new parts are the header's state line and the
   marker on a card that was left blank; everything else is the sheet's. */
.quiz-state { display: flex; align-items: center; gap: 10px; margin: 16px 0 8px; }
.quiz-count { font-size: var(--t-chip); color: var(--c-muted-2); }
.sup-status.done { color: #2e7d5b; background: rgba(46, 125, 91, .10); border-color: rgba(46, 125, 91, .25); }
.sup-status.new { color: var(--c-muted-4); background: rgba(0, 0, 0, .04); border-color: rgba(0, 0, 0, .07); }
.quiz-missing { margin: 8px 0 0; padding-left: 18px; font-size: var(--t-chip); }
.quiz-missing li { margin-top: 4px; }
.quiz-q { margin: 0 0 14px; font-size: var(--t-body); font-weight: 600; color: var(--c-ink); line-height: 1.5; }
/* A question that was left blank keeps its own outline until it is answered. */
.auth-card.miss { border-color: rgba(217, 64, 64, .45); }
/* The quiz is a form of cards; it must space them like the shell around it. */
form.auth { display: flex; flex-direction: column; gap: 16px; }

/* ---- invites ----
   A code is either a link to hand out or the person who took it. Both shapes
   sit inside one card, as rows, so the screen holds one panel and not eight. */
.inv-list { display: flex; flex-direction: column; gap: 12px; margin-top: 12px; }
.inv-item {
  padding: 14px; border-radius: var(--r-tile);
  background: var(--glass-card-bg);
  -webkit-backdrop-filter: blur(var(--glass-card-blur));
  backdrop-filter: blur(var(--glass-card-blur));
  border: 1px solid var(--glass-card-line);
}
.inv-item.used { background: rgba(0, 0, 0, .02); }
.inv-head { display: flex; align-items: center; gap: 10px; }
.inv-code {
  flex: 1; min-width: 0; padding: 6px 10px; border-radius: 8px;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 15px; font-weight: 700; letter-spacing: .12em;
  color: var(--c-accent); background: var(--c-accent-tint);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.inv-code.spent { color: var(--c-muted-4); background: rgba(0, 0, 0, .04); text-decoration: line-through; }

.inv-actions { margin-top: 10px; }
.inv-link {
  width: 100%; margin: 0 0 8px; padding: 9px 12px; border-radius: 10px;
  font-size: 13px; color: var(--c-muted-2);
  background: #fff; border: 1px solid var(--glass-card-line);
  overflow: hidden; text-overflow: ellipsis;
}
/* Two buttons, side by side and equal — in Georgian "გაზიარება" and
   "კოპირება" are long enough that a fixed width would clip one of them. */
.inv-btns { display: flex; gap: 8px; }
.inv-btn {
  flex: 1; min-width: 0; padding: 10px 8px; border-radius: 999px; cursor: pointer;
  font: inherit; font-size: var(--t-chip); font-weight: 700;
  color: var(--c-accent); background: var(--c-accent-tint);
  border: 1px solid var(--c-accent-tint-mid);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  transition: transform .12s ease;
}
.inv-btn.primary { color: #fff; background: var(--c-accent); border-color: transparent; }
.inv-btn:active { transform: scale(.97); }

.inv-who { display: flex; align-items: center; gap: 10px; margin-top: 10px; color: var(--c-ink); }
.inv-who:hover { text-decoration: none; }
.inv-who-face {
  flex: none; width: 34px; height: 34px; border-radius: 50%; overflow: hidden;
  display: grid; place-items: center; background: var(--c-accent-tint); font-size: 15px;
}
.inv-who-face img { width: 100%; height: 100%; object-fit: cover; }
.inv-who-name { font-size: var(--t-chip); color: var(--c-muted-2); }
.inv-who-name strong { color: var(--c-ink); }

/* Deletion, and the two other states that are not good news: the mark takes
   the warning colour rather than the accent. */
.auth-mark.danger { color: var(--c-nope); background: rgba(217, 64, 64, .08); border-color: rgba(217, 64, 64, .22); }
.auth-mark.warn { color: #8a5a12; background: rgba(216, 149, 32, .12); border-color: rgba(216, 149, 32, .28); }
.sheet-cta.danger { background: var(--c-nope); box-shadow: 0 6px 24px rgba(217, 64, 64, .3); }
/* A single full-width choice — the deletion tick is one, and it is not a row
   of chips competing for space. Unlike the chips, this one draws a box: a
   consent tick that looks like a text field is a consent nobody knows they
   have to give. */
.f-pill.wide {
  width: 100%; justify-content: flex-start; gap: 12px;
  padding: 14px 16px; text-align: left;
}
.f-pill.wide::before {
  content: ""; flex: none; width: 20px; height: 20px; border-radius: 6px;
  border: 2px solid var(--c-muted-6); background: #fff;
  transition: background .15s, border-color .15s;
}
.f-pill.wide:has(input:checked)::before {
  border-color: #fff;
  background: #fff url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23D94040' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E") center/14px no-repeat;
}
.f-pill.wide.danger.on, .f-pill.wide.danger:has(input:checked) {
  background: var(--c-nope); border-color: transparent; box-shadow: 0 2px 12px rgba(217, 64, 64, .3);
}

/* ---- moderation ----
   The admin screens are the same product as the rest: the panel, the accent
   label, the chips. What is different is density — a moderator is looking at a
   queue, so the rows are tighter and every one of them carries its state. */
.adm-nav {
  display: flex; gap: 6px; overflow-x: auto; margin-bottom: 16px; padding: 4px;
  border-radius: var(--r-panel);
  background: rgba(255, 255, 255, .6);
  -webkit-backdrop-filter: blur(24px); backdrop-filter: blur(24px);
  border: 1px solid var(--glass-float-line);
  -webkit-overflow-scrolling: touch;
}
.adm-nav::-webkit-scrollbar { display: none; }
.adm-tab {
  flex: none; display: inline-flex; align-items: center; gap: 6px;
  padding: 9px 14px; border-radius: 12px; white-space: nowrap;
  font-size: var(--t-chip); font-weight: 600; color: var(--c-muted-4);
}
.adm-tab:hover { text-decoration: none; }
/* Four tabs in three languages do not fit 320px, so the bar scrolls — and the
   tab you are on has to be findable in it: it carries the accent, a lift, and
   a margin the browser respects when it brings it into view. */
.adm-tab.on { background: var(--c-accent); color: #fff; box-shadow: 0 2px 10px rgba(107, 30, 46, .28); }
.adm-tab { scroll-margin-inline: 12px; }
.adm-count {
  display: inline-grid; place-items: center; min-width: 18px; height: 18px;
  padding: 0 5px; border-radius: 999px; font-size: 11px; font-weight: 700;
  background: var(--c-accent); color: #fff;
}
.adm-tab.on .adm-count { background: rgba(255, 255, 255, .28); }

.adm-list { display: flex; flex-direction: column; gap: 12px; }
/* A card in a list is the list's width and nothing else. The shell's original
   .auth-card still carries `max-width: 400px; margin: 30px auto` from the very
   first version of the site; inside this flex column those margins do not
   collapse, so the cards stood 72px apart and each one stopped short of the
   column it lives in. That, and not the contents, is why the panel looked
   scattered. */
.adm-list > .auth-card, .adm-panel { max-width: none; margin: 0; }
/* An admin screen stacks panels the way the list stacks cards — one rule for
   the spacing instead of a margin on each. */
.adm-stack { display: flex; flex-direction: column; gap: 12px; }
.adm-item { padding: 16px; min-width: 0; }
.adm-item.banned { opacity: .6; }
a.adm-row { display: block; color: inherit; }
a.adm-row:hover { text-decoration: none; }
.adm-item-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 10px; min-width: 0; }
.adm-code {
  padding: 3px 8px; border-radius: 8px; min-width: 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px; font-weight: 700; letter-spacing: .06em;
  color: var(--c-muted-2); background: rgba(0, 0, 0, .04);
  /* An invite code is the point of the row it sits in: it wraps, it is never
     cut short. */
  overflow-wrap: anywhere;
}
.adm-label {
  margin: 10px 0 4px; font-size: var(--t-section-label); font-weight: 700;
  text-transform: uppercase; letter-spacing: .1em; color: var(--c-muted-4);
}
.adm-topic {
  margin: 0 0 4px; font-size: var(--t-row-name-sm); font-weight: 600; color: var(--c-ink);
  min-width: 0; overflow-wrap: anywhere;
}
/* The first line of a request, two lines at most: the row is there to be
   chosen from, not read from. A photo is already reduced to 📷 upstream, so
   nothing here can be a URL. */
.adm-preview {
  margin: 6px 0 0; font-size: var(--t-chip); line-height: 1.45; color: var(--c-muted-2);
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; line-clamp: 2;
  overflow: hidden; white-space: normal; overflow-wrap: anywhere;
}
/* One request, as a row: the id on the left, the state and what is unread on
   the right, on one line always. They used to be three items in a wrapping
   flex row, so a long status ("ველოდებით შენს პასუხს") pushed the count onto
   a line of its own. The status shrinks; the count never does. */
.adm-row-top { display: flex; align-items: center; gap: 8px; min-width: 0; margin-bottom: 8px; }
.adm-row-top > .adm-code {
  flex: 0 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.adm-row-state { flex: 0 1 auto; min-width: 0; margin-left: auto; display: flex; align-items: center; gap: 6px; }
.adm-row-state .sup-status { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.adm-row-state .adm-count { flex: none; }
.adm-row-name {
  margin: 0; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Something is waiting for an answer. A shadow, not a border: a border would
   move the contents of the card by the width of the mark. */
.adm-row.unread {
  border-color: var(--c-accent-tint-mid);
  box-shadow: inset 3px 0 0 var(--c-accent), var(--glass-panel-shadow);
}
/* "Sent" and "in progress" were the same chip — the two states a moderator
   actually sorts by. Kept inside the panel so the person's own /support page
   is untouched. */
.adm-item .sup-status.in_progress, .adm-panel .sup-status.in_progress {
  color: #2f5aa8; background: rgba(47, 90, 168, .10); border-color: rgba(47, 90, 168, .26);
}
.adm-reason {
  margin: 10px 0 0; padding: 10px 12px; border-radius: var(--r-tile);
  background: rgba(0, 0, 0, .03); font-size: var(--t-body); line-height: 1.5; color: #444;
}
.adm-flags { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 8px; min-width: 0; }

.adm-who { display: flex; align-items: center; gap: 10px; min-width: 0; color: var(--c-ink); }
.adm-who:hover { text-decoration: none; }
.adm-who.plain { cursor: default; }
.adm-face {
  flex: none; width: 40px; height: 40px; border-radius: 50%; overflow: hidden;
  display: grid; place-items: center; background: var(--c-accent-tint); font-size: 17px;
}
.adm-face img { width: 100%; height: 100%; object-fit: cover; }
.adm-who-text { display: flex; flex-direction: column; min-width: 0; }
.adm-who-text strong { font-size: var(--t-row-name-sm); min-width: 0; overflow-wrap: anywhere; }
.adm-who-sub { font-size: var(--t-chip); color: var(--c-muted-2); min-width: 0; overflow-wrap: anywhere; }

/* Who somebody is, and what they are: the name on the left, the Admin/Banned/
   Premium chips on the right. The name keeps 190px before the chips give up
   and take a line of their own, which is what happens at 320-360px. A name or
   a city that still does not fit is cut with an ellipsis — the chips are never
   pushed off the card by it. */
.adm-ident { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 8px 10px; }
.adm-ident > .adm-who { flex: 1 1 190px; min-width: 0; }
.adm-ident > .adm-flags { flex: 0 1 auto; margin: 0 0 0 auto; justify-content: flex-end; }
.adm-ident .adm-who-text strong, .adm-ident .adm-who-sub {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Where somebody came from, as one quiet strip: who invited them and on which
   code. Both are links or codes, so both are allowed to wrap rather than to
   widen the card. */
.adm-meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; min-width: 0;
  margin: 10px 0 0; padding: 8px 10px; border-radius: var(--r-tile);
  background: rgba(0, 0, 0, .03); font-size: var(--t-chip); color: var(--c-muted-2);
}
.adm-meta-label {
  flex: none; font-size: var(--t-section-label); font-weight: 700;
  text-transform: uppercase; letter-spacing: .08em; color: var(--c-muted-4);
}
.adm-meta-value { min-width: 0; overflow-wrap: anywhere; }
.adm-note { margin: 10px 0 0; font-size: var(--t-chip); color: var(--c-muted-2); }

/* The two pictures a selfie decision is made from, side by side and equal. */
.adm-pair { display: flex; gap: 10px; margin-bottom: 12px; }
.adm-pair figure { flex: 1; min-width: 0; margin: 0; text-align: center; }
.adm-pair img {
  width: 100%; height: 170px; object-fit: cover; border-radius: var(--r-tile);
  background: var(--c-accent-tint);
}
.adm-pair figcaption { margin-top: 6px; font-size: var(--t-chip); color: var(--c-muted-4); }

/* The actions are a grid, not a wrapping row of `flex: 1 1 auto` buttons.
   In a row the last button of a line was stretched by whatever space was
   left — one control could end up as wide as the card and the next one a
   third of it, which is most of what "scattered" meant here. A grid gives
   every action the same width and the same height, and drops to two columns
   (one, on a card narrower than a single track) on its own. `min(112px, 100%)`
   is the part that makes it safe: a bare 112px track overflows a card
   narrower than 112px, and nothing on these screens may scroll sideways. */
.adm-actions {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(112px, 100%), 1fr));
  gap: 8px; margin-top: 12px;
}
/* Banning and deleting are not in the same group as Telegram and Premium. */
.adm-actions.adm-danger { margin-top: 10px; padding-top: 10px; border-top: 1px dashed rgba(217, 64, 64, .28); }
/* A form is one action, so it is one item of that grid. It used to be
   `display: contents`, which handed the buttons over to the grid but left the
   form itself with no box at all — nothing could size or align it, and a form
   holding two buttons could not be placed as one thing. */
.adm-act { display: grid; min-width: 0; }
.adm-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  width: 100%; min-width: 0; padding: 10px 12px; border-radius: 999px; cursor: pointer;
  font: inherit; font-size: var(--t-chip); font-weight: 700; line-height: 1.25;
  /* A long translation wraps inside the button instead of running out of the
     card: "ბანის მოხსნა", "Разбанить", "Delete" are not one width. */
  text-align: center; white-space: normal; overflow-wrap: anywhere;
  color: var(--c-accent); background: var(--c-accent-tint);
  border: 1px solid var(--c-accent-tint-mid); transition: transform .12s ease;
}
.adm-btn:hover { text-decoration: none; }
.adm-btn:active { transform: scale(.97); }
.adm-btn.primary { color: #fff; background: var(--c-accent); border-color: transparent; }
.adm-btn.danger { color: var(--c-nope); background: rgba(217, 64, 64, .08); border-color: rgba(217, 64, 64, .22); }

/* Two tiles on a 320px screen, three once there is room for them — and a
   number nobody expected wraps inside its tile rather than widening it. */
.adm-stats-card { margin-bottom: 12px; }
.adm-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(96px, 100%), 1fr)); gap: 10px; }
.adm-stat {
  display: flex; flex-direction: column; justify-content: center; gap: 4px;
  padding: 12px 8px; min-width: 0;
  border-radius: var(--r-tile); text-align: center;
  background: var(--c-accent-tint); border: 1px solid var(--c-accent-tint-mid);
}
.adm-stat-n {
  font-size: 20px; font-weight: 700; color: var(--c-accent); line-height: 1.15;
  min-width: 0; overflow-wrap: anywhere;
}
.adm-stat-l { font-size: 11px; line-height: 1.3; color: var(--c-muted-2); min-width: 0; overflow-wrap: anywhere; }

/* The person photo runs the feed's carousel; the frame just has to fill the
   rounded photo box and clip like the single image used to. */
.pv-carousel { position: absolute; inset: 0; overflow: hidden; }
.pv-carousel .carousel-track { display: flex; height: 100%; transition: transform .25s ease; }
.pv-carousel .carousel-track img {
  width: 100%; height: 100%; object-fit: cover; flex: none;
  /* The deck's 38% framing is the deck's: the prototype's person header is a
     plain object-cover, i.e. dead centre. */
  object-position: center;
}

/* ---- instant feedback (v176) ------------------------------------------- */
/* The tap answers immediately: a dimmed control means "taken, working". */
button.busy, .btn.busy, .swipe-btn.busy { opacity: .55; pointer-events: none; }
/* A light press-down on the things people tap most. */
.tabbar a:active .tab-ico, .swipe-btn:active, .row-dismiss:active { transform: scale(.88); }
.tabbar a .tab-ico, .swipe-btn, .row-dismiss { transition: transform .08s ease; }
/* The navigation bar: grows while the next page is on its way. Never reaches
   the end on its own — the arriving page (or pageshow) removes it. */
.guli-navbar {
  position: fixed; top: 0; left: 0; height: 3px; width: 0;
  background: var(--c-accent, #6b1e2e); z-index: 9999;
  opacity: 0; pointer-events: none; border-radius: 0 2px 2px 0;
}
.guli-navbar.on { opacity: 1; animation: guliNavGrow 8s cubic-bezier(.15,.6,.3,1) forwards; }
@keyframes guliNavGrow { 0% { width: 0; } 12% { width: 35%; } 60% { width: 82%; } 100% { width: 96%; } }

/* ---- the Mini App splash (v177) ----------------------------------------- */
/* Brand wine in both themes — the splash IS the brand moment, and a constant
   ground reads cleaner than adapting to the Telegram palette for one second. */
#guliSplash {
  position: fixed; inset: 0; z-index: 10000;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 14px; background: var(--c-accent, #6b1e2e);
  padding: calc(env(safe-area-inset-top, 0px) + var(--tg-top, 0px))
           env(safe-area-inset-right, 0px)
           calc(env(safe-area-inset-bottom, 0px) + var(--tg-bottom, 0px))
           env(safe-area-inset-left, 0px);
  animation: gsIn .3s ease;
}
#guliSplash.gs-out { opacity: 0; transition: opacity .4s ease; }
#guliSplash .gs-mark {
  width: 64px; height: 64px; border-radius: 20px;
  display: flex; align-items: center; justify-content: center;
  background: rgba(255, 255, 255, .14);
  animation: gsPulse 1.1s ease-in-out infinite;
}
#guliSplash .gs-name {
  color: #fff; font-size: 26px; font-weight: 700; letter-spacing: .04em;
}
@keyframes gsIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes gsPulse { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.12); } }
@media (prefers-reduced-motion: reduce) {
  #guliSplash { animation: none; }
  #guliSplash .gs-mark { animation: none; }
  #guliSplash.gs-out { transition-duration: .15s; }
}
