/* Faithy web — design system.
   One stylesheet, custom properties for theming, mobile-first with two breakpoints:
   - phone            single column, bottom tab bar
   - >= 900px         navigation rail + feed
   - >= 1240px        rail + feed + communities sidebar
   Light/dark follow the OS preference unless the user pinned a theme (data-theme on <html>). */

:root {
  color-scheme: light dark;

  --bg: #f2f4f7;
  --surface: #ffffff;
  --surface-2: #f7f9fb;
  --surface-3: #eef2f6;
  --border: #dfe4ea;
  --border-strong: #c8d0d9;
  --text: #14181d;
  --muted: #5d6873;
  --faint: #8a949e;

  --primary: #2f86e0;
  --primary-strong: #1f6dc0;
  --primary-soft: #e8f2fd;
  --on-primary: #ffffff;
  --gold: #c98a12;
  --ok: #17864a;
  --warn: #a76a00;
  --bad: #cf2f2f;
  --bad-soft: #fdecec;

  --radius: 14px;
  --radius-sm: 9px;
  --radius-pill: 999px;
  --shadow: 0 1px 2px rgba(16, 24, 40, .06), 0 4px 14px rgba(16, 24, 40, .05);
  --shadow-lg: 0 8px 34px rgba(16, 24, 40, .18);

  --topbar-h: 56px;
  --tabbar-h: 58px;
  --sans: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
  --serif: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
}

/* The dark palette, applied both by OS preference and by an explicit pin. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --bg: #0d1117;
    --surface: #161b22;
    --surface-2: #1b222c;
    --surface-3: #222b36;
    --border: #29313c;
    --border-strong: #3b4553;
    --text: #e6edf3;
    --muted: #9aa7b4;
    --faint: #6e7c8a;
    --primary: #5aa5f0;
    --primary-strong: #7cb9f5;
    --primary-soft: #16304a;
    --on-primary: #06121f;
    --gold: #e0ac48;
    --ok: #4cc38a;
    --warn: #d9a03c;
    --bad: #f0736c;
    --bad-soft: #3a1f1f;
    --shadow: 0 1px 2px rgba(0, 0, 0, .4), 0 4px 14px rgba(0, 0, 0, .3);
    --shadow-lg: 0 10px 40px rgba(0, 0, 0, .55);
  }
}

:root[data-theme="dark"] {
  --bg: #0d1117;
  --surface: #161b22;
  --surface-2: #1b222c;
  --surface-3: #222b36;
  --border: #29313c;
  --border-strong: #3b4553;
  --text: #e6edf3;
  --muted: #9aa7b4;
  --faint: #6e7c8a;
  --primary: #5aa5f0;
  --primary-strong: #7cb9f5;
  --primary-soft: #16304a;
  --on-primary: #06121f;
  --gold: #e0ac48;
  --ok: #4cc38a;
  --warn: #d9a03c;
  --bad: #f0736c;
  --bad-soft: #3a1f1f;
  --shadow: 0 1px 2px rgba(0, 0, 0, .4), 0 4px 14px rgba(0, 0, 0, .3);
  --shadow-lg: 0 10px 40px rgba(0, 0, 0, .55);
}

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

/* Several layout classes set an explicit display, which ties `[hidden]` on specificity and wins on
   source order — so the attribute the JS toggles would never hide them. Force hidden to win. */
[hidden] { display: none !important; }

html, body { height: 100%; }

body {
  margin: 0;
  font: 15px/1.55 var(--sans);
  background: var(--bg);
  color: var(--text);
  -webkit-font-smoothing: antialiased;
  overflow-wrap: break-word;
}

a { color: var(--primary); text-decoration: none; }
a:hover { text-decoration: underline; }
h1, h2, h3, h4 { margin: 0; line-height: 1.25; font-weight: 650; }
h1 { font-size: 22px; }
h2 { font-size: 19px; }
h3 { font-size: 16px; }
p { margin: 0 0 10px; }
img { max-width: 100%; }

:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
  border-radius: 4px;
}

.muted { color: var(--muted); }
.faint { color: var(--faint); }
.small { font-size: 13px; }
.tiny { font-size: 12px; }
.strong { font-weight: 650; }
.center { text-align: center; }
.spacer { flex: 1; }
.row { display: flex; align-items: center; gap: 10px; }
.row-wrap { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.stack { display: flex; flex-direction: column; gap: 12px; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.error-text { color: var(--bad); }
.error-text:empty { display: none; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ---------- boot ---------------------------------------------------------- */

.boot {
  position: fixed; inset: 0; display: grid; place-content: center;
  justify-items: center; gap: 16px; background: var(--bg); z-index: 40;
}
.boot-mark {
  width: 76px; height: 76px;
  background: url("logo.png") center / contain no-repeat;
  animation: pulse 1.4s ease-in-out infinite;
}
.boot-text { color: var(--muted); margin: 0; }
@keyframes pulse { 0%, 100% { opacity: .35; transform: scale(.92); } 50% { opacity: 1; transform: scale(1); } }

/* ---------- brand mark ---------------------------------------------------- */

/* The mark is the Android client's intro_logo.png, used as-is. It carries its own colours (the
   praying hands on the blue disc), so it is deliberately not tinted or themed — the logo looks the
   same on a light screen, a dark screen and a phone. */
.brand { display: flex; align-items: center; gap: 9px; color: var(--text); font-weight: 700; }
.brand:hover { text-decoration: none; }
.brand-mark {
  width: 30px; height: 30px; flex: none;
  background: url("logo.png") center / contain no-repeat;
}
.brand-name { font-size: 18px; letter-spacing: -.01em; }

/* ---------- auth ---------------------------------------------------------- */

.auth {
  min-height: 100dvh; display: grid; place-items: center; padding: 24px 18px;
  background:
    radial-gradient(1000px 460px at 50% -8%, var(--primary-soft), transparent 70%),
    var(--bg);
}
.auth-card {
  width: min(420px, 100%); background: var(--surface); border: 1px solid var(--border);
  border-radius: 18px; padding: 26px 24px 24px; box-shadow: var(--shadow);
}
/* Sits above the logo on every auth screen: someone who cannot read the form yet is exactly who
   needs to reach this, and it has to work before an account exists. */
.auth-language { display: flex; justify-content: flex-end; margin-bottom: 6px; }
.auth-language select {
  width: auto; padding: 5px 9px; font-size: 13px; font-weight: 600;
  border-radius: var(--radius-pill); background: var(--surface-3); border-color: transparent;
}

.auth-head { display: grid; justify-items: center; gap: 8px; margin-bottom: 20px; text-align: center; }
/* Intro-sized, matching the logo's presence on the Android sign-in flow. */
.auth-head .brand-mark { width: 104px; height: 104px; }
.auth-head h1 { font-size: 26px; letter-spacing: -.01em; }
.auth-head p { margin: 0; color: var(--muted); font-size: 14px; }
.auth-foot { margin-top: 18px; text-align: center; font-size: 14px; color: var(--muted); }
.auth-foot button { margin-left: 4px; }

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

.field { display: block; margin-bottom: 14px; }
.field > span {
  display: block; margin-bottom: 5px; font-size: 13px; font-weight: 600; color: var(--muted);
}
input[type="text"], input[type="email"], input[type="password"], input[type="search"],
input[type="tel"], input[type="number"], input[type="url"], input[type="datetime-local"],
select, textarea {
  width: 100%; padding: 10px 12px; font: inherit; color: var(--text);
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius-sm);
  transition: border-color .15s, background .15s, box-shadow .15s;
}
input:focus, select:focus, textarea:focus {
  outline: none; border-color: var(--primary); background: var(--surface);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 18%, transparent);
}

/* ---------- dropdown ------------------------------------------------------
   A custom control (js/ui/select.js), not a styled <select>: the OS draws a native option list that
   ignores the app's type, spacing and dark theme, and cannot show a flag, a right-aligned dial code
   or a filter box. The trigger deliberately matches the text inputs exactly, so a form reads as one
   set of controls. */

.dropdown { position: relative; display: block; }
.dropdown-trigger {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 10px 12px; font: inherit; text-align: left; color: var(--text);
  background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--radius-sm);
  cursor: pointer; transition: border-color .15s, background .15s, box-shadow .15s;
}
.dropdown-trigger:hover { border-color: var(--border-strong); }
.dropdown-trigger:focus-visible {
  outline: none; border-color: var(--primary); background: var(--surface);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 18%, transparent);
}
.dropdown-trigger[aria-expanded="true"] {
  border-color: var(--primary); background: var(--surface);
}
.dropdown-label { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; }
.dropdown-text { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dropdown-prefix { flex: none; font-size: 17px; line-height: 1; }
.dropdown-detail { flex: none; color: var(--muted); font-size: 13px; font-variant-numeric: tabular-nums; }
.dropdown-placeholder { color: var(--faint); }
.dropdown-chevron {
  flex: none; width: 18px; height: 18px; background: var(--muted);
  -webkit-mask: var(--i-chevron) center / contain no-repeat;
  mask: var(--i-chevron) center / contain no-repeat;
  transition: transform .15s;
}
.dropdown-trigger[aria-expanded="true"] .dropdown-chevron { transform: rotate(180deg); background: var(--primary); }
:root { --i-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M7 10l5 5 5-5z'/%3E%3C/svg%3E"); }

/* The popup is a popover positioned in fixed coordinates, so neither a card's overflow nor a modal
   dialog's top layer can clip or cover it. `inset: auto` and `margin: 0` undo the UA popover
   defaults (which centre it), leaving the JS-computed top/left in charge. */
.dropdown-popup {
  position: fixed; inset: auto; margin: 0; padding: 0; z-index: 80;
  flex-direction: column; overflow: hidden;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-lg); color: var(--text);
  animation: dropdown-in .12s ease;
}
/* `display` is deliberately NOT set on the base rule. The UA hides a closed popover with
   `[popover]:not(:popover-open) { display: none }`, and overriding that leaves the element laid out
   while invisible — which also stalls the entry animation at frame 0, i.e. permanently transparent
   and untouchable by the pointer. Declare the display only for the two states that are actually
   shown. */
.dropdown-popup:popover-open { display: flex; }
.dropdown-popup:not([popover]) { display: flex; }
.dropdown-popup::backdrop { background: transparent; }
/* Fallback for browsers without the popover API, where the popup is parented INTO the dialog: the
   modal's own clipping has to give way, or the list is cut off at the card edge. */
.modal:has(.dropdown-popup) { overflow: visible; }
.modal:has(.dropdown-popup) .modal-body { overflow: visible; }
/* Transform only, deliberately no opacity. An animation that starts at `opacity: 0` leaves the
   popup invisible yet still hit-testable for as long as the animation does not advance — which is
   exactly what happens in a document that is not being rendered. A slide has the same feel and no
   state in which the list can be clicked but not seen. */
@keyframes dropdown-in { from { transform: translateY(-5px) scale(.99); } }

.dropdown-search-wrap { padding: 8px; border-bottom: 1px solid var(--border); flex: none; }
.dropdown-search { padding: 8px 11px; border-radius: var(--radius-sm); }
.dropdown-search::-webkit-search-cancel-button { cursor: pointer; }

.dropdown-list { overflow-y: auto; padding: 6px; outline: none; overscroll-behavior: contain; }
.dropdown-option {
  display: flex; align-items: center; gap: 9px; padding: 9px 10px;
  border-radius: var(--radius-sm); cursor: pointer; color: var(--text); line-height: 1.35;
}
.dropdown-option .dropdown-text { flex: 1; }
/* One highlight, driven by the keyboard AND the pointer, so arrowing and hovering cannot disagree
   about which row is current. */
.dropdown-option.active { background: var(--surface-3); }
.dropdown-option.selected { color: var(--primary-strong); font-weight: 650; }
.dropdown-option.selected.active { background: var(--primary-soft); }
.dropdown-option.disabled { opacity: .5; cursor: not-allowed; }
.dropdown-check {
  flex: none; width: 17px; height: 17px; background: var(--primary);
  -webkit-mask: var(--i-check) center / contain no-repeat;
  mask: var(--i-check) center / contain no-repeat;
}
:root { --i-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='m9.6 16.6-4.2-4.2 1.4-1.4 2.8 2.8 7.6-7.6 1.4 1.4z'/%3E%3C/svg%3E"); }
.dropdown-empty { padding: 18px 12px; text-align: center; color: var(--muted); font-size: 13.5px; }

/* Compact form for a settings row, where the control sits at the end of a line of text. */
.dropdown.inline { display: inline-block; min-width: 150px; }
.dropdown.inline .dropdown-trigger { padding: 7px 11px; font-size: 13.5px; }
.dropdown.inline .dropdown-prefix { font-size: 15px; }

/* A field wrapper adds its own bottom margin; the control must not add a second one. */
.field > .dropdown { margin: 0; }
input::placeholder, textarea::placeholder { color: var(--faint); }
input:disabled, select:disabled, textarea:disabled, button:disabled { opacity: .55; cursor: not-allowed; }
textarea { resize: vertical; min-height: 84px; }
.field-row { display: flex; gap: 10px; }
.field-row > * { flex: 1; min-width: 0; }
.hint { font-size: 12px; color: var(--faint); margin-top: 4px; }

/* Inline validation. The message lives under its own field so a rejected value is marked where it
   can be fixed, never only in a summary at the top. It is collapsed to zero height when empty, so
   the form does not jump as messages come and go. */
.field-error {
  margin: 4px 0 0; min-height: 0; font-size: 12.5px; font-weight: 550; color: var(--bad);
}
.field-error:empty { display: none; }
.field.invalid input, .field.invalid select, .field.invalid textarea {
  border-color: var(--bad); background: var(--bad-soft);
}
.field.invalid input:focus { border-color: var(--bad); }
/* A quiet tick rather than a green field: confirmation without shouting. */
.field.valid input {
  border-color: color-mix(in srgb, var(--ok) 55%, var(--border));
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%2317864a'%3E%3Cpath d='m9.6 16.6-4.2-4.2 1.4-1.4 2.8 2.8 7.6-7.6 1.4 1.4z'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 10px center;
  background-size: 17px;
  padding-right: 34px;
}
/* The phone channel is a country picker and a number that read as one control. The picker is given
   a fixed, generous share so long country names truncate rather than squeezing the number. */
.phone-group { display: flex; gap: 10px; align-items: flex-start; }
.phone-group > .field { flex: 1; min-width: 0; margin-bottom: 14px; }
.phone-group > .field.country { flex: 0 0 44%; }
.phone-group .select-wrap { display: block; }
.phone-group select { text-overflow: ellipsis; }
.phone-group input { font-variant-numeric: tabular-nums; letter-spacing: .02em; }
.field.code input {
  letter-spacing: .4em; text-align: center; font-size: 21px; font-weight: 650;
  font-variant-numeric: tabular-nums;
}

/* Request-level failures — unreachable, rate-limited, wrong credentials — sit directly above the
   inputs. A toast is the wrong home for these: it disappears while the member is still reading, it
   is nowhere near the button they pressed, and on a phone it can hide behind the keyboard. */
.form-error {
  display: flex; align-items: flex-start; gap: 8px;
  margin: 0 0 14px; padding: 10px 13px;
  border: 1px solid color-mix(in srgb, var(--bad) 35%, transparent);
  border-radius: var(--radius-sm);
  background: var(--bad-soft); color: var(--bad);
  font-size: 13.5px; font-weight: 550; line-height: 1.45;
}
.form-error::before { content: "!"; font-weight: 800; }

.code-input {
  letter-spacing: .5em; text-align: center; font-size: 21px; font-weight: 650;
  font-variant-numeric: tabular-nums;
}

/* Social sign-in. Google draws its own button into `.social-slot` (its brand guidelines require
   it), so the Facebook button is styled to sit beside it at the same height and radius rather than
   the two looking like they came from different apps. */
.social-buttons { display: grid; gap: 9px; margin-bottom: 4px; }
.social-slot { display: flex; justify-content: center; min-height: 40px; }
.social-slot > div { max-width: 100%; }
.btn.social {
  height: 40px; gap: 10px; font-size: 14.5px; font-weight: 600;
  border-color: var(--border-strong);
}
.btn.social.facebook { background: #1877f2; border-color: #1877f2; color: #fff; }
.btn.social.facebook:hover:not(:disabled) { background: #1568d8; border-color: #1568d8; }
.social-mark {
  width: 19px; height: 19px; flex: none; background: currentColor;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-position: center; mask-position: center;
  -webkit-mask-size: contain; mask-size: contain;
}
.social-mark.facebook {
  -webkit-mask-image: var(--i-facebook); mask-image: var(--i-facebook);
}
:root {
  --i-facebook: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M22 12a10 10 0 10-11.6 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.4v7A10 10 0 0022 12z'/%3E%3C/svg%3E");
}

/* "or" rule between the social buttons and the form. */
.social-divider {
  display: flex; align-items: center; gap: 12px; margin: 16px 0 14px;
  color: var(--faint); font-size: 12px; text-transform: uppercase; letter-spacing: .06em;
}
.social-divider::before, .social-divider::after {
  content: ""; flex: 1; height: 1px; background: var(--border);
}

/* Channel chooser on the auth forms — a real radio group, mirroring the RadioGroup at the top of
   the Android sign-in / sign-up / reset forms. Real <input type="radio"> rather than styled buttons
   so arrow keys, labels and screen readers all behave as expected. */
.channel-choice { display: flex; gap: 20px; margin: 0 0 14px; }
.channel-choice label {
  display: inline-flex; align-items: center; gap: 7px; cursor: pointer;
  font-weight: 600; color: var(--text);
}
.channel-choice input[type="radio"] {
  width: 18px; height: 18px; margin: 0; accent-color: var(--primary); cursor: pointer;
}

/* ---------- buttons ------------------------------------------------------- */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  padding: 9px 15px; font: inherit; font-weight: 600; line-height: 1.2;
  border: 1px solid var(--border); border-radius: var(--radius-pill);
  background: var(--surface); color: var(--text); cursor: pointer;
  transition: background .15s, border-color .15s, transform .06s;
  white-space: nowrap;
}
.btn:hover:not(:disabled) { background: var(--surface-3); text-decoration: none; }
.btn:active:not(:disabled) { transform: translateY(1px); }
.btn.primary { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }
.btn.primary:hover:not(:disabled) { background: var(--primary-strong); border-color: var(--primary-strong); }
.btn.danger { color: var(--bad); border-color: var(--border); }
.btn.danger:hover:not(:disabled) { background: var(--bad-soft); }
.btn.ghost { border-color: transparent; background: transparent; }
.btn.ghost:hover:not(:disabled) { background: var(--surface-3); }
.btn.wide { width: 100%; }
.btn.small { padding: 6px 11px; font-size: 13px; }
.btn.busy { position: relative; color: transparent !important; }
.btn.busy::after {
  content: ""; position: absolute; width: 15px; height: 15px; border-radius: 50%;
  border: 2px solid currentColor; border-top-color: transparent;
  color: var(--on-primary); animation: spin .7s linear infinite;
}
.btn.ghost.busy::after, .btn:not(.primary).busy::after { color: var(--text); }
@keyframes spin { to { transform: rotate(360deg); } }

.icon-button {
  position: relative; display: inline-grid; place-items: center;
  width: 38px; height: 38px; border: 0; border-radius: 50%;
  background: transparent; color: var(--muted); cursor: pointer;
}
.icon-button:hover { background: var(--surface-3); color: var(--text); text-decoration: none; }

/* Icons are drawn with CSS masks over a single inline SVG sprite-free approach: each glyph is a
   data-URI mask so it inherits currentColor and needs no icon font. */
.icon { width: 21px; height: 21px; display: inline-block; background: currentColor; flex: none; }
.icon-home { -webkit-mask: var(--i-home) center/contain no-repeat; mask: var(--i-home) center/contain no-repeat; }
.icon-search { -webkit-mask: var(--i-search) center/contain no-repeat; mask: var(--i-search) center/contain no-repeat; }
.icon-people { -webkit-mask: var(--i-people) center/contain no-repeat; mask: var(--i-people) center/contain no-repeat; }
.icon-groups { -webkit-mask: var(--i-groups) center/contain no-repeat; mask: var(--i-groups) center/contain no-repeat; }
.icon-calendar { -webkit-mask: var(--i-calendar) center/contain no-repeat; mask: var(--i-calendar) center/contain no-repeat; }
.icon-book { -webkit-mask: var(--i-book) center/contain no-repeat; mask: var(--i-book) center/contain no-repeat; }
.icon-bookmark { -webkit-mask: var(--i-bookmark) center/contain no-repeat; mask: var(--i-bookmark) center/contain no-repeat; }
.icon-gift { -webkit-mask: var(--i-gift) center/contain no-repeat; mask: var(--i-gift) center/contain no-repeat; }
.icon-settings { -webkit-mask: var(--i-settings) center/contain no-repeat; mask: var(--i-settings) center/contain no-repeat; }
.icon-bell { -webkit-mask: var(--i-bell) center/contain no-repeat; mask: var(--i-bell) center/contain no-repeat; }
.icon-chat { -webkit-mask: var(--i-chat) center/contain no-repeat; mask: var(--i-chat) center/contain no-repeat; }
.icon-person { -webkit-mask: var(--i-person) center/contain no-repeat; mask: var(--i-person) center/contain no-repeat; }
.icon-theme { -webkit-mask: var(--i-theme) center/contain no-repeat; mask: var(--i-theme) center/contain no-repeat; }

:root {
  --i-home: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 3 2 11h3v10h6v-6h2v6h6V11h3z'/%3E%3C/svg%3E");
  --i-search: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M10 2a8 8 0 105.3 14l5.4 5.4 1.4-1.4-5.4-5.4A8 8 0 0010 2zm0 2a6 6 0 110 12 6 6 0 010-12z'/%3E%3C/svg%3E");
  --i-people: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 2 4 6v6c0 5 3.4 9.3 8 10 4.6-.7 8-5 8-10V6z'/%3E%3C/svg%3E");
  --i-groups: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M8 11a3 3 0 100-6 3 3 0 000 6zm8 0a3 3 0 100-6 3 3 0 000 6zM2 19c0-3 3-5 6-5s6 2 6 5zm12.5-4.6c2 .7 3.5 2.3 3.5 4.6h4c0-2.7-2.6-4.4-7.5-4.6z'/%3E%3C/svg%3E");
  --i-calendar: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M7 2v2H5a2 2 0 00-2 2v13a2 2 0 002 2h14a2 2 0 002-2V6a2 2 0 00-2-2h-2V2h-2v2H9V2zm12 8v9H5v-9z'/%3E%3C/svg%3E");
  --i-book: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6 2a2 2 0 00-2 2v16a2 2 0 002 2h13V2zm1 3h9v10H7z'/%3E%3C/svg%3E");
  --i-bookmark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M6 2h12v20l-6-4.5L6 22z'/%3E%3C/svg%3E");
  --i-gift: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 4.2A3 3 0 0117.8 6H20a1 1 0 011 1v3H3V7a1 1 0 011-1h2.2A3 3 0 0112 4.2zM4 12h7v9H5a1 1 0 01-1-1zm9 0h7v8a1 1 0 01-1 1h-6z'/%3E%3C/svg%3E");
  --i-settings: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 8a4 4 0 100 8 4 4 0 000-8zm9 4-2.1-1.2.4-2.4-2.1-1.2-1.8 1.6-2.2-1L12 5l-1.2 2.8-2.2 1L6.8 7.2 4.7 8.4l.4 2.4L3 12l2.1 1.2-.4 2.4 2.1 1.2 1.8-1.6 2.2 1L12 19l1.2-2.8 2.2-1 1.8 1.6 2.1-1.2-.4-2.4z'/%3E%3C/svg%3E");
  --i-bell: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 22a2.5 2.5 0 002.5-2.5h-5A2.5 2.5 0 0012 22zm7-6v-5a7 7 0 10-14 0v5l-2 2v1h18v-1z'/%3E%3C/svg%3E");
  --i-chat: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M4 3h16a2 2 0 012 2v10a2 2 0 01-2 2H9l-5 4V5a2 2 0 012-2z'/%3E%3C/svg%3E");
  --i-person: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 12a5 5 0 100-10 5 5 0 000 10zm0 2c-4.4 0-8 2.5-8 5.5V22h16v-2.5c0-3-3.6-5.5-8-5.5z'/%3E%3C/svg%3E");
  --i-theme: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M12 2a10 10 0 000 20zm0 2.5A7.5 7.5 0 0112 19.5z'/%3E%3C/svg%3E");
}

/* ---------- app shell ----------------------------------------------------- */

.app { min-height: 100dvh; display: flex; flex-direction: column; }

.topbar {
  position: sticky; top: 0; z-index: 20; height: var(--topbar-h);
  display: flex; align-items: center; gap: 12px; padding: 0 14px;
  background: var(--surface); border-bottom: 1px solid var(--border);
}
.topbar-search { flex: 1; max-width: 420px; }
.topbar-search input {
  border-radius: var(--radius-pill); padding-left: 15px; background: var(--surface-3); border-color: transparent;
}
.topbar-actions { display: flex; align-items: center; gap: 4px; margin-left: auto; }
.topbar-avatar { display: block; width: 34px; height: 34px; margin-left: 4px; }

.badge {
  position: absolute; top: 3px; right: 2px; min-width: 17px; height: 17px; padding: 0 4px;
  display: grid; place-items: center; border-radius: var(--radius-pill);
  background: var(--bad); color: #fff; font-size: 11px; font-weight: 700; line-height: 1;
  border: 2px solid var(--surface);
}

.shell {
  flex: 1; width: 100%; max-width: 1360px; margin: 0 auto;
  display: grid; grid-template-columns: 1fr; min-height: 0;
}
.rail, .side { display: none; }
.view {
  min-width: 0; padding: 16px 14px calc(var(--tabbar-h) + 26px);
  outline: none;
}

.tabbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 20; height: var(--tabbar-h);
  display: flex; background: var(--surface); border-top: 1px solid var(--border);
  padding-bottom: env(safe-area-inset-bottom);
}
.tabbar a {
  position: relative; flex: 1; display: grid; place-items: center; gap: 2px;
  color: var(--muted); font-size: 11px; font-weight: 600; padding-top: 7px;
}
.tabbar a:hover { text-decoration: none; }
.tabbar a.active { color: var(--primary); }
.tabbar .badge { top: 4px; right: 50%; margin-right: -22px; }

@media (min-width: 900px) {
  .shell { grid-template-columns: 216px minmax(0, 1fr); gap: 20px; padding: 0 16px; }
  .rail {
    display: block; position: sticky; top: calc(var(--topbar-h) + 14px);
    align-self: start; padding: 14px 0; max-height: calc(100dvh - var(--topbar-h) - 20px); overflow: auto;
  }
  .rail a {
    display: flex; align-items: center; gap: 12px; padding: 9px 13px; margin-bottom: 2px;
    border-radius: var(--radius-pill); color: var(--text); font-weight: 550;
  }
  .rail a:hover { background: var(--surface-3); text-decoration: none; }
  .rail a.active { background: var(--primary-soft); color: var(--primary-strong); font-weight: 700; }
  .rail .icon { color: var(--muted); }
  .rail a.active .icon { color: var(--primary-strong); }
  .nav-section {
    margin: 16px 13px 5px; font-size: 11px; font-weight: 700; letter-spacing: .06em;
    text-transform: uppercase; color: var(--faint);
  }
  .view { padding: 18px 0 40px; }
  .tabbar { display: none; }
}

@media (min-width: 1240px) {
  .shell { grid-template-columns: 216px minmax(0, 1fr) 300px; }
  .side {
    display: block; position: sticky; top: calc(var(--topbar-h) + 14px);
    align-self: start; padding: 18px 0; max-height: calc(100dvh - var(--topbar-h) - 20px); overflow: auto;
  }
}

/* ---------- page furniture ------------------------------------------------ */

.page-head {
  display: flex; align-items: center; gap: 12px; margin-bottom: 14px; min-height: 38px;
}
.page-head h1 { flex: 1; min-width: 0; }
.back-link {
  display: inline-grid; place-items: center; width: 34px; height: 34px; flex: none;
  border-radius: 50%; background: var(--surface); border: 1px solid var(--border); color: var(--text);
  font-size: 17px; line-height: 1;
}
.back-link:hover { background: var(--surface-3); text-decoration: none; }

.card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: var(--shadow); margin-bottom: 14px;
}
.card-pad { padding: 15px; }
.card-head {
  display: flex; align-items: center; gap: 10px; padding: 13px 15px; border-bottom: 1px solid var(--border);
}
.card-head h2, .card-head h3 { flex: 1; min-width: 0; }

.section-title {
  font-size: 12px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--faint); margin: 22px 2px 9px;
}
.side .section-title { margin-top: 0; }

.empty {
  padding: 42px 22px; text-align: center; color: var(--muted);
  background: var(--surface); border: 1px dashed var(--border); border-radius: var(--radius);
}
.empty h3 { margin-bottom: 6px; color: var(--text); }
.empty p { margin: 0 auto; max-width: 34ch; }
.empty .btn { margin-top: 14px; }

.loading { padding: 34px; text-align: center; color: var(--muted); }

.skeleton {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 15px; margin-bottom: 14px;
}
.skeleton-line, .skeleton-avatar {
  background: linear-gradient(90deg, var(--surface-3) 25%, var(--surface-2) 37%, var(--surface-3) 63%);
  background-size: 400% 100%; animation: shimmer 1.3s ease infinite; border-radius: 6px;
}
.skeleton-avatar { width: 40px; height: 40px; border-radius: 50%; flex: none; }
.skeleton-line { height: 11px; margin-top: 9px; }
@keyframes shimmer { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }

.tabs {
  display: flex; gap: 4px; overflow-x: auto; margin-bottom: 14px;
  border-bottom: 1px solid var(--border); scrollbar-width: none;
}
.tabs::-webkit-scrollbar { display: none; }
.tabs button {
  padding: 9px 13px; border: 0; border-bottom: 2px solid transparent; background: none;
  font: inherit; font-weight: 600; color: var(--muted); cursor: pointer; white-space: nowrap;
}
.tabs button:hover { color: var(--text); }
.tabs button.active { color: var(--primary); border-bottom-color: var(--primary); }

.chip {
  display: inline-flex; align-items: center; gap: 5px; padding: 3px 10px;
  border-radius: var(--radius-pill); background: var(--surface-3); color: var(--muted);
  font-size: 12px; font-weight: 600; border: 1px solid transparent;
}
.chip.tint { background: var(--primary-soft); color: var(--primary-strong); }
.chip.gold { background: color-mix(in srgb, var(--gold) 16%, transparent); color: var(--gold); }
.chip.ok { background: color-mix(in srgb, var(--ok) 15%, transparent); color: var(--ok); }
.chip.warn { background: color-mix(in srgb, var(--warn) 16%, transparent); color: var(--warn); }
.chip.bad { background: var(--bad-soft); color: var(--bad); }
button.chip { cursor: pointer; }
button.chip:hover { border-color: var(--border-strong); }
button.chip.active { background: var(--primary); color: var(--on-primary); }

.filters { display: flex; gap: 7px; flex-wrap: wrap; margin-bottom: 14px; }

/* ---------- avatars ------------------------------------------------------- */

.avatar {
  position: relative; display: inline-grid; place-items: center; flex: none;
  width: 40px; height: 40px; border-radius: 50%; overflow: hidden;
  background: var(--primary); color: #fff; font-weight: 650; font-size: 15px;
  user-select: none;
}
.avatar img { width: 100%; height: 100%; object-fit: cover; display: block; }
.avatar.sm { width: 32px; height: 32px; font-size: 13px; }
.avatar.lg { width: 64px; height: 64px; font-size: 23px; }
.avatar.xl { width: 92px; height: 92px; font-size: 32px; }
.avatar.square { border-radius: var(--radius-sm); }
.presence {
  position: absolute; right: -1px; bottom: -1px; width: 11px; height: 11px; border-radius: 50%;
  background: var(--ok); border: 2px solid var(--surface);
}
.avatar-link { display: inline-block; line-height: 0; }
.avatar-link:hover { text-decoration: none; }

.verified {
  display: inline-block; width: 14px; height: 14px; flex: none; vertical-align: -2px;
  background: var(--primary);
  -webkit-mask: var(--i-verified) center/contain no-repeat;
  mask: var(--i-verified) center/contain no-repeat;
}
:root {
  --i-verified: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='m12 1 2.6 2.1 3.3-.3.9 3.2 2.8 1.8-1.3 3.1 1.3 3.1-2.8 1.8-.9 3.2-3.3-.3L12 23l-2.6-2.1-3.3.3-.9-3.2L2.4 16l1.3-3.1L2.4 9.8l2.8-1.8.9-3.2 3.3.3zm-1.2 14.4 5.7-5.7-1.5-1.4-4.2 4.2-2-2-1.4 1.4z'/%3E%3C/svg%3E");
}

/* ---------- list rows ----------------------------------------------------- */

.list { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; }
.list-row {
  display: flex; align-items: center; gap: 12px; padding: 12px 14px;
  border-bottom: 1px solid var(--border); color: var(--text); background: none;
  border-left: 0; border-right: 0; border-top: 0; width: 100%; text-align: left; font: inherit;
}
.list-row:last-child { border-bottom: 0; }
a.list-row:hover, button.list-row:hover { background: var(--surface-2); text-decoration: none; cursor: pointer; }
.list-row-main { flex: 1; min-width: 0; }
.list-row-title { font-weight: 600; display: flex; align-items: center; gap: 6px; }
.list-row-sub { color: var(--muted); font-size: 13px; }
.list-row-side { color: var(--faint); font-size: 12px; text-align: right; flex: none; }
.list-row.unread { background: var(--primary-soft); }
.list-row.unread:hover { background: var(--primary-soft); }

/* ---------- post & event cards -------------------------------------------- */

.post { padding: 0; overflow: hidden; }
.post-head { display: flex; align-items: flex-start; gap: 11px; padding: 13px 15px 9px; }
.post-head-main { flex: 1; min-width: 0; }
.post-author { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; font-weight: 650; }
.post-author a { color: inherit; }
.post-meta { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; color: var(--muted); font-size: 12.5px; }
.post-meta a { color: var(--muted); font-weight: 600; }
.dot-sep::before { content: "·"; margin: 0 2px; }

.role-pill {
  padding: 1px 7px; border-radius: var(--radius-pill); font-size: 11px; font-weight: 700;
  background: var(--surface-3); color: var(--muted);
}
.role-pill.leader { background: color-mix(in srgb, var(--gold) 18%, transparent); color: var(--gold); }
.role-pill.admin { background: var(--primary-soft); color: var(--primary-strong); }

.post-body { padding: 0 15px 11px; white-space: pre-wrap; }
.post-body:empty { display: none; }
.post-body a { font-weight: 550; }
.mention, .scripture-ref { font-weight: 600; cursor: pointer; }
.scripture-ref { color: var(--gold); }

/* A text-only post written on one of the client's canvas presets. */
.post-canvas {
  display: grid; place-items: center; min-height: 190px; padding: 26px 22px; margin: 0 0 11px;
  text-align: center; font-size: 21px; font-weight: 650; line-height: 1.35; color: #fff;
  white-space: pre-wrap;
}

.post-media { display: grid; gap: 2px; background: var(--surface-3); }
.post-media.count-1 { grid-template-columns: 1fr; }
.post-media.count-2 { grid-template-columns: 1fr 1fr; }
.post-media.count-3 { grid-template-columns: 1fr 1fr; }
.post-media.count-3 > :first-child { grid-row: span 2; }
.post-media.count-4 { grid-template-columns: 1fr 1fr; }
.post-media-item {
  position: relative; display: block; overflow: hidden; background: var(--surface-3);
  aspect-ratio: 4 / 3; border: 0; padding: 0; cursor: pointer; width: 100%;
}
.post-media.count-1 .post-media-item { aspect-ratio: auto; max-height: 520px; }
.post-media.count-1 .post-media-item img { max-height: 520px; }
.post-media-item img, .post-media-item video { width: 100%; height: 100%; object-fit: cover; display: block; }
.post-media-item .play {
  position: absolute; inset: 0; margin: auto; width: 52px; height: 52px; border-radius: 50%;
  background: rgba(0, 0, 0, .55); color: #fff; display: grid; place-items: center; font-size: 20px;
}
.media-more {
  position: absolute; inset: 0; display: grid; place-items: center;
  background: rgba(0, 0, 0, .5); color: #fff; font-size: 22px; font-weight: 700;
}

.link-preview {
  display: block; margin: 0 15px 11px; border: 1px solid var(--border);
  border-radius: var(--radius-sm); overflow: hidden; color: var(--text);
}
.link-preview:hover { text-decoration: none; background: var(--surface-2); }
.link-preview img { width: 100%; display: block; aspect-ratio: 16/9; object-fit: cover; }
.link-preview-text { padding: 9px 11px; }

.post-counts {
  display: flex; align-items: center; gap: 12px; padding: 8px 15px;
  color: var(--muted); font-size: 12.5px; border-top: 1px solid var(--border);
}
.post-actions { display: flex; padding: 4px 7px; border-top: 1px solid var(--border); }
.post-action {
  flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 8px 6px; border: 0; background: none; border-radius: var(--radius-sm);
  font: inherit; font-weight: 600; font-size: 13.5px; color: var(--muted); cursor: pointer;
}
.post-action:hover { background: var(--surface-3); color: var(--text); }
.post-action.on { color: var(--primary); }
.post-action.on.love { color: var(--bad); }
.post-action.on.saved { color: var(--gold); }

.reaction-menu {
  position: absolute; z-index: 30; display: flex; gap: 4px; padding: 6px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-pill);
  box-shadow: var(--shadow-lg);
}
.reaction-menu button {
  width: 40px; height: 40px; border: 0; border-radius: 50%; background: none;
  font-size: 21px; cursor: pointer; line-height: 1;
}
.reaction-menu button:hover { background: var(--surface-3); transform: scale(1.12); }

.post-banner {
  padding: 7px 15px; font-size: 12.5px; font-weight: 600;
  background: color-mix(in srgb, var(--warn) 12%, transparent); color: var(--warn);
}
.post-banner.pinned { background: var(--primary-soft); color: var(--primary-strong); }

/* ---------- event cards --------------------------------------------------- */

.event-cover { position: relative; display: block; aspect-ratio: 2 / 1; background: var(--surface-3); }
.event-cover img { width: 100%; height: 100%; object-fit: cover; display: block; }
.event-date-badge {
  position: absolute; top: 12px; left: 12px; width: 52px; padding: 5px 0; text-align: center;
  background: var(--surface); border-radius: var(--radius-sm); box-shadow: var(--shadow); line-height: 1.1;
}
.event-date-badge .m { font-size: 11px; font-weight: 700; text-transform: uppercase; color: var(--bad); }
.event-date-badge .d { font-size: 19px; font-weight: 700; }
.event-when { color: var(--primary); font-weight: 650; font-size: 13px; }
.event-where { color: var(--muted); font-size: 13px; }
.rsvp-group { display: flex; gap: 7px; padding: 11px 15px; border-top: 1px solid var(--border); }

/* ---------- comments ------------------------------------------------------ */

.comment { display: flex; gap: 10px; padding: 10px 15px; }
.comment-bubble {
  background: var(--surface-3); border-radius: var(--radius); padding: 8px 12px; min-width: 0;
}
.comment-bubble .name { font-weight: 650; font-size: 13.5px; }
.comment-body { white-space: pre-wrap; }
.comment-quote {
  border-left: 3px solid var(--border-strong); padding-left: 8px; margin-bottom: 5px;
  color: var(--muted); font-size: 12.5px;
}
.comment-tools { display: flex; gap: 12px; margin: 3px 0 0 12px; font-size: 12px; color: var(--faint); }
.comment-tools button { border: 0; background: none; font: inherit; color: inherit; cursor: pointer; padding: 0; font-weight: 600; }
.comment-tools button:hover { color: var(--text); }
.comment.reply { padding-left: 48px; }
.comment.highlight .comment-bubble { outline: 2px solid var(--primary); }

.composer-inline {
  display: flex; gap: 10px; align-items: flex-end; padding: 11px 15px; border-top: 1px solid var(--border);
}
.composer-inline textarea {
  min-height: 40px; max-height: 160px; border-radius: var(--radius); padding: 9px 12px;
}

/* ---------- composer ------------------------------------------------------ */

.composer-trigger {
  display: flex; align-items: center; gap: 11px; padding: 13px 15px; width: 100%;
  border: 0; background: none; font: inherit; cursor: pointer; text-align: left;
}
.composer-trigger span {
  flex: 1; padding: 9px 14px; border-radius: var(--radius-pill);
  background: var(--surface-3); color: var(--muted);
}
.composer-trigger:hover span { background: var(--border); }

.composer-form textarea { min-height: 120px; border: 0; background: none; padding: 0; font-size: 16px; }
.composer-form textarea:focus { background: none; }
.composer-previews { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 12px; }
.composer-preview { position: relative; width: 92px; height: 92px; border-radius: var(--radius-sm); overflow: hidden; }
.composer-preview img, .composer-preview video { width: 100%; height: 100%; object-fit: cover; }
.composer-preview button {
  position: absolute; top: 3px; right: 3px; width: 22px; height: 22px; border-radius: 50%;
  border: 0; background: rgba(0, 0, 0, .65); color: #fff; cursor: pointer; line-height: 1; font-size: 14px;
}
.composer-bar {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  padding-top: 12px; margin-top: 12px; border-top: 1px solid var(--border);
}
.backgrounds { display: flex; gap: 7px; flex-wrap: wrap; margin-top: 12px; }
.background-swatch {
  width: 30px; height: 30px; border-radius: 50%; border: 2px solid transparent; cursor: pointer;
}
.background-swatch.active { border-color: var(--primary); }
.upload-progress { height: 3px; border-radius: 3px; background: var(--primary); transition: width .2s; }

.mention-popup {
  position: absolute; z-index: 30; width: 260px; max-height: 240px; overflow: auto;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
}

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

.chat { display: flex; flex-direction: column; height: calc(100dvh - var(--topbar-h) - var(--tabbar-h)); }
@media (min-width: 900px) { .chat { height: calc(100dvh - var(--topbar-h) - 58px); } }
.chat-head {
  display: flex; align-items: center; gap: 11px; padding: 10px 14px;
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius) var(--radius) 0 0;
}
.chat-log {
  flex: 1; overflow-y: auto; padding: 14px; display: flex; flex-direction: column; gap: 4px;
  background: var(--surface-2); border-left: 1px solid var(--border); border-right: 1px solid var(--border);
}
.bubble-row { display: flex; }
.bubble-row.out { justify-content: flex-end; }
.bubble {
  max-width: min(78%, 520px); padding: 8px 12px; border-radius: 16px;
  background: var(--surface); border: 1px solid var(--border); box-shadow: var(--shadow);
}
.bubble-row.out .bubble { background: var(--primary); border-color: var(--primary); color: var(--on-primary); }
.bubble-row.out .bubble .bubble-meta { color: color-mix(in srgb, var(--on-primary) 75%, transparent); }
.bubble-row.first .bubble { border-top-left-radius: 6px; }
.bubble-row.out.first .bubble { border-top-left-radius: 16px; border-top-right-radius: 6px; }
.bubble-text { white-space: pre-wrap; }
.bubble-meta { display: flex; align-items: center; justify-content: flex-end; gap: 4px; font-size: 11px; color: var(--faint); margin-top: 2px; }
.bubble-quote {
  border-left: 3px solid currentColor; opacity: .8; padding-left: 7px; margin-bottom: 4px; font-size: 12.5px;
}
.bubble img { border-radius: 10px; display: block; margin-bottom: 4px; }
.chat-day { align-self: center; margin: 8px 0; }
.chat-compose {
  display: flex; gap: 9px; align-items: flex-end; padding: 10px 12px; background: var(--surface);
  border: 1px solid var(--border); border-radius: 0 0 var(--radius) var(--radius);
}
.chat-compose textarea { min-height: 40px; max-height: 140px; border-radius: var(--radius-pill); padding: 9px 14px; }
.typing-dots { display: inline-flex; gap: 3px; align-items: center; height: 14px; }
.typing-dots i { width: 5px; height: 5px; border-radius: 50%; background: var(--muted); animation: bounce 1.1s infinite; }
.typing-dots i:nth-child(2) { animation-delay: .15s; }
.typing-dots i:nth-child(3) { animation-delay: .3s; }
@keyframes bounce { 0%, 60%, 100% { transform: translateY(0); opacity: .5; } 30% { transform: translateY(-4px); opacity: 1; } }

/* ---------- profile / community headers ----------------------------------- */

.cover {
  height: 168px; background: linear-gradient(135deg, var(--primary), var(--primary-strong));
  border-radius: var(--radius) var(--radius) 0 0; overflow: hidden;
}
.cover img { width: 100%; height: 100%; object-fit: cover; }
.profile-head { padding: 0 16px 16px; margin-top: -46px; }
.profile-head .avatar { border: 4px solid var(--surface); box-shadow: var(--shadow); }
.profile-name { display: flex; align-items: center; gap: 7px; margin-top: 10px; }
.profile-stats { display: flex; gap: 18px; margin-top: 10px; color: var(--muted); font-size: 13.5px; }
.profile-stats b { color: var(--text); }
.profile-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 14px; }

.stat-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 11px; }
.stat {
  background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); padding: 13px 15px;
}
.stat .v { font-size: 22px; font-weight: 700; line-height: 1.2; }
.stat .k { color: var(--muted); font-size: 12.5px; }

/* ---------- scripture reader ---------------------------------------------- */

.reader { font-family: var(--serif); font-size: 18px; line-height: 1.85; }
.reader .verse { display: block; padding: 2px 4px; border-radius: 5px; }
.reader .verse:hover { background: var(--surface-3); }
.reader .verse-number {
  font-family: var(--sans); font-size: 11px; font-weight: 700; color: var(--primary);
  vertical-align: super; margin-right: 4px;
}
.reader .verse.has-posts { background: color-mix(in srgb, var(--gold) 12%, transparent); }
.book-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(148px, 1fr)); gap: 7px; }
.chapter-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(48px, 1fr)); gap: 7px; }
.chapter-grid button { padding: 9px 0; }

/* ---------- giving -------------------------------------------------------- */

.amount-input { font-size: 26px; font-weight: 700; text-align: center; font-variant-numeric: tabular-nums; }
.receipt { display: flex; justify-content: space-between; padding: 6px 0; border-bottom: 1px dashed var(--border); }
.receipt:last-child { border-bottom: 0; }
.receipt .k { color: var(--muted); }
.receipt.total { font-weight: 700; font-size: 16px; }
.ussd {
  font-family: ui-monospace, SFMono-Regular, Consolas, monospace; font-size: 15px;
  background: var(--surface-3); padding: 10px 12px; border-radius: var(--radius-sm); word-break: break-all;
}

/* ---------- modal, toast, lightbox ---------------------------------------- */

.modal {
  width: min(520px, calc(100vw - 28px)); max-height: min(86dvh, 780px); padding: 0;
  border: 1px solid var(--border); border-radius: 18px; background: var(--surface); color: var(--text);
  box-shadow: var(--shadow-lg); overflow: hidden;
}
.modal::backdrop { background: rgba(10, 15, 22, .55); backdrop-filter: blur(2px); }
.modal-head { display: flex; align-items: center; gap: 10px; padding: 15px 18px; border-bottom: 1px solid var(--border); }
.modal-head h2 { flex: 1; min-width: 0; font-size: 17px; }
.modal-body { padding: 18px; overflow-y: auto; max-height: calc(86dvh - 132px); }
.modal-foot { display: flex; justify-content: flex-end; gap: 9px; padding: 13px 18px; border-top: 1px solid var(--border); }

.toasts {
  position: fixed; left: 50%; transform: translateX(-50%);
  bottom: calc(var(--tabbar-h) + 16px); z-index: 60;
  display: flex; flex-direction: column; gap: 8px; align-items: center; pointer-events: none;
}
@media (min-width: 900px) { .toasts { bottom: 24px; } }
.toast {
  padding: 10px 16px; border-radius: var(--radius-pill); background: var(--text); color: var(--bg);
  box-shadow: var(--shadow-lg); font-size: 14px; font-weight: 550; max-width: 90vw;
  animation: toast-in .22s ease;
}
.toast.bad { background: var(--bad); color: #fff; }
@keyframes toast-in { from { opacity: 0; transform: translateY(10px); } }

.connection {
  position: fixed; top: calc(var(--topbar-h) + 8px); left: 50%; transform: translateX(-50%); z-index: 50;
  padding: 6px 14px; border-radius: var(--radius-pill); background: var(--warn); color: #fff;
  font-size: 12.5px; font-weight: 650; box-shadow: var(--shadow);
}

.lightbox {
  position: fixed; inset: 0; z-index: 70; background: rgba(0, 0, 0, .93);
  display: grid; place-items: center; padding: 20px;
}
.lightbox img, .lightbox video { max-width: 100%; max-height: 88dvh; object-fit: contain; }
.lightbox-close {
  position: absolute; top: 14px; right: 16px; width: 40px; height: 40px; border-radius: 50%;
  border: 0; background: rgba(255, 255, 255, .16); color: #fff; font-size: 21px; cursor: pointer;
}
.lightbox-nav {
  position: absolute; top: 50%; transform: translateY(-50%); width: 46px; height: 46px; border-radius: 50%;
  border: 0; background: rgba(255, 255, 255, .16); color: #fff; font-size: 22px; cursor: pointer;
}
.lightbox-nav.prev { left: 14px; }
.lightbox-nav.next { right: 14px; }

.sentinel { height: 1px; }
.load-more { display: grid; place-items: center; padding: 16px; color: var(--muted); }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .001ms !important; transition-duration: .001ms !important; }
}
