﻿/* ── Google Fonts ─────────────────────────────────────────── */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Poppins:wght@300;400;600&display=swap');

/* ── Design tokens ────────────────────────────────────────── */
:root {
  --grad-stop-1: #2e2148;
  --grad-stop-2: #1a1430;
  --grad-stop-3: #0e0c16;
  --bg-gradient: radial-gradient(circle at 25% 15%, var(--grad-stop-1) 0%, var(--grad-stop-2) 45%, var(--grad-stop-3) 100%);
  --gold:        #FAC775;
  --gold-dim:    rgba(250,199,117,0.12);
  --purple:      #534AB7;
  --purple-dim:  rgba(83,74,183,0.18);
  --card-bg:     rgba(255,255,255,0.04);
  --card-border: rgba(255,255,255,0.08);
  --text:        #f0edf8;
  --text-muted:  #9e98c0;
  --text-dim:    #6a638a;
  --status-online-bg:  rgba(99,153,34,0.2);
  --status-online-fg:  #8FCB4A;
  --status-busy-bg:    rgba(239,159,39,0.2);
  --status-busy-fg:    #F5C24A;
  --status-offline-bg: rgba(224,75,74,0.2);
  --status-offline-fg: #F08A8A;
  --danger:      #F08A8A;
  --success:     #8FCB4A;
  --radius:      10px;
  --radius-sm:   6px;
}

/* ── Reset / base ─────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

/* html has no background of its own by default (white). On mobile, elastic
   overscroll/bounce can reveal a sliver of html's box beyond body's edge —
   giving html the same gradient means that sliver matches the design instead
   of flashing white. Harmless on desktop, which doesn't bounce-scroll. */
html { font-size: 16px; -webkit-font-smoothing: antialiased; background: var(--bg-gradient); }

body {
  font-family: 'Inter', system-ui, sans-serif;
  background: var(--bg-gradient);
  background-attachment: fixed;
  color: var(--text);
  min-height: 100vh;
  line-height: 1.6;
  display: flex;
  flex-direction: column;
}

/* Flex items default to min-width:auto, so a direct child of body (the flex
   container above) refuses to shrink below its own widest descendant's
   content — e.g. a wide table deep inside .page-wrap — growing past the
   viewport instead of letting that descendant's own overflow rules (scroll/
   wrap/ellipsis) handle it. mobile's html,body{overflow-x:hidden} then
   clips that silently instead of showing a page scrollbar, so the symptom
   looks like "content is just gone" rather than "the page scrolls." This
   restores normal shrink-to-fit sizing for body's direct children so
   descendants' own overflow handling actually gets a chance to run. */
body > * {
  min-width: 0;
  width: 100%;
  box-sizing: border-box;
}

/* Mobile-only overscroll/overflow hardening (desktop's rubber-band/scrollbar behaviour is
   out of scope and unaffected by any of this):
   - `background: var(--bg-gradient)` above only sets background-IMAGE (a gradient has no
     color of its own) — background-color is left at its initial 'transparent', so if the
     gradient is ever a frame late repainting (overscroll bounce briefly renders past the
     normally-painted area; fast scrolling forces rapid repaints), there's nothing behind it
     and the browser's own default canvas (white, or black in dark mode) shows through for
     that frame — this is the reported white/black flash. A solid background-color needs no
     computation, so it paints immediately and can never be "late" — it's a permanent,
     free fallback directly behind the gradient.
   - background-attachment:fixed (base rule above) is a well-documented source of scroll
     jank/flicker on mobile WebKit/Blink, since it forces the background to be
     re-evaluated against the viewport on every scroll frame rather than scrolling as part
     of the normal content layer — switched to the default `scroll` on mobile only, where
     scroll-driven repaint cost actually matters (desktop keeps `fixed`, unaffected, its own
     rule above still applies since this only overrides the value inside this media query).
   - `background-attachment:scroll` reintroduces a different problem though: without an
     explicit size, a radial-gradient's background image sizes itself against its own
     element's full content box, not the viewport — so on a short page (e.g. the reader
     dashboard's Availability tab, barely taller than one screen) the gradient's whole
     bloom-to-black falloff is visible exactly as designed, but on a tall page (e.g. that
     same dashboard's Earnings/Payouts tabs, with cards/tables stacked below the fold) the
     SAME gradient gets stretched across a much taller box, so the viewport at scroll
     position 0 only shows a tiny, nearly-flat slice near the gradient's bright origin
     stop — this is what reads as "flatter/more solid purple" on longer tabs, even though
     it's the exact same background rule. Fixed by pinning the gradient's background-size to
     one viewport height with no-repeat: the vivid bloom now always renders identically
     within the first screen regardless of total page height, and anything below that first
     screen falls through to the plain background-color above — which is already an exact
     match for the gradient's own tail color (--grad-stop-3: #0e0c16), so the transition is
     seamless, the same effect .page-wrap content scrolling past a `fixed` background
     achieves without actually using `fixed` (and its scroll-jank cost).
   - Sizing that box to exactly 100vw 100vh (a first attempt at the fix above) introduced a
     new problem: on a narrow portrait phone, 100vw is much smaller than 100vh (e.g. 375 x
     812), so `circle at 25% 15%` — with no explicit radius, sized by default to the
     "farthest-corner" distance from the center point — gets computed against a tall,
     narrow box, and that farthest corner ends up much farther down than across. The
     falloff reads as dominated by the vertical dimension: lighter-at-top/darker-at-bottom,
     not desktop's lighter-left/darker-right (on desktop, body's `fixed` attachment sizes
     the background against the viewport with no explicit size at all, which for a
     landscape browser window is naturally wider than tall, so the same formula falls off
     mostly left-to-right there).
   - A second attempt widened the box (background-size: 160vh 100vh, keeping default
     farthest-corner sizing) to force a landscape-shaped canvas. That fixed the direction in
     theory, but two real problems surfaced once actually measured: (1) widening the box
     moves the farthest corner much farther from the center, so the gradient no longer
     finishes fading to black within the one visible screen height — verified numerically at
     the time: only ~58-64% of the way to full black at the bottom edge, versus ~93-100% with
     the narrower 100vw 100vh box, which is exactly why a visible seam appeared against the
     flat background-color fallback below it. (2) Re-deriving the numbers for THIS fix
     surfaced an arithmetic error in that attempt's own reasoning: at 160vh width, the
     gradient's bright spot (25% of the WIDENED box, not the viewport) actually lands at
     ~87% across the visible crop, not ~25-33% as that fix assumed — meaning it likely read
     as darker-on-left/lighter-on-right, backwards from the desktop reference, not just
     "close enough."
   - Fixed properly this time by giving the gradient an *explicit* radius instead of relying
     on default (farthest-corner) sizing: `circle 90vw at 25% 15%`, still using the shared
     --grad-stop-1/2/3 variables, just with an explicit size argument so `--bg-gradient`
     itself (used as-is everywhere else, including desktop) never needs touching. An
     explicit radius decouples the two previously-tangled concerns — how far across the
     gradient reads (controlled by the circle's radius, in vw so it's a fixed fraction of
     viewport WIDTH specifically) from how tall the box the image is painted into is
     (background-size, unchanged at 100vw 100vh — no need to widen it anymore, the radius
     alone now does the work). Verified numerically across 320-768px-wide viewports: the
     LEFT edge consistently lands at ~28% (a bright purple, between stop1/stop2), the RIGHT
     edge at ~83% (a dark purple, between stop2/stop3) — clearly lighter-left/darker-right,
     matching desktop — and the BOTTOM edge (where the painted image ends and the flat
     fallback begins) is 100% — fully clamped to --grad-stop-3 — at every point across the
     full width, on every viewport size tested, independent of how tall the actual page
     content is. No more retuning needed if a future page is even taller: the fade already
     completes with comfortable margin (the closest point on the bottom edge to the
     gradient's center is always exactly 85vh away — see the geometry note below — well
     outside this 90vw-ish radius on any phone-width viewport).
   - overflow-x:hidden is a page-level safety net: even with the specific overflow causes
     fixed elsewhere (.rr-logo__wordmark, .filter-bar — see their own rules), this guarantees
     no future stray element can ever reintroduce horizontal scroll/swipe site-wide. */
@media (max-width: 768px) {
  html, body {
    background-color: #0e0c16;
    overflow-x: hidden;
  }
  body {
    /* Same --grad-stop-* tokens as --bg-gradient (public/style.css :root), just with an
       explicit circle radius instead of --bg-gradient's default farthest-corner sizing —
       see the comment above for why. --bg-gradient itself is untouched and still used
       as-is everywhere else (desktop, topnav, footer, etc). */
    background-image: radial-gradient(circle 90vw at 25% 15%, var(--grad-stop-1) 0%, var(--grad-stop-2) 45%, var(--grad-stop-3) 100%);
    background-attachment: scroll;
    background-repeat: no-repeat;
    background-size: 100vw 100vh;
  }
}

/* ── Typography ───────────────────────────────────────────── */
h1, h2, h3, h4 {
  font-family: 'Inter', system-ui, sans-serif;
  font-weight: 600;
  line-height: 1.25;
  color: var(--text);
}

h1 { font-size: 2rem; }
h2 { font-size: 1.45rem; }
h3 { font-size: 1.15rem; }

p { color: var(--text-muted); }

a { color: var(--gold); text-decoration: none; transition: opacity .15s; }
a:hover { opacity: .78; }

strong { color: var(--text); font-weight: 600; }

small { font-size: 0.82em; color: var(--text-dim); }

/* ── Layout helpers ───────────────────────────────────────── */
.page-wrap {
  max-width: 1100px;
  margin: 0 auto;
  padding: 0 24px 80px;
}

.page-wrap--wide {
  width: 100%;
  padding: 0 24px;
}

.page-wrap--narrow {
  max-width: 480px;
  margin: 0 auto;
  padding: 0 24px 80px;
}

/* ── Shared panel background ─────────────────────────────────────────────
   .panel-gradient is the canonical utility class for the header-style
   purple gradient. Add it to any element that needs this background.
   The topnav is included here directly (it has no HTML-level class change)
   so all 18 templates stay untouched. Everything else — footer, rar-section,
   and any future section — simply gets class="... panel-gradient" in HTML.
   ──────────────────────────────────────────────────────────────────────── */
.topnav,
.panel-gradient {
  background: var(--bg-gradient);
}

/* ── Top navigation bar ───────────────────────────────────── */
.topnav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 20px 28px;
  border-bottom: 1px solid var(--card-border);
  margin-bottom: 12px;
  gap: 16px;
  flex-wrap: wrap;
}

.topnav__brand {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
}

/* ── Brand logo lockup (topnav + auth pages) ──────────────── */
.rr-logo {
  display: inline-flex;
  align-items: center;
  gap: 14px;
  line-height: 1;
}

.rr-logo__leaf {
  width: 56px;
  height: 52px;
  flex-shrink: 0;
  display: block;
}

.rr-logo__text {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.rr-logo__wordmark {
  font-family: 'Poppins', 'Inter', system-ui, sans-serif;
  font-size: 2.3rem;
  line-height: 1;
  letter-spacing: 0;
  white-space: nowrap;
}

.rr-logo__remedy {
  color: #FAC775;
  font-weight: 600;
}

.rr-logo__readings {
  color: #f1eefb;
  font-weight: 300;
}

.rr-logo__tagline {
  font-family: 'Poppins', 'Inter', system-ui, sans-serif;
  font-size: 0.82rem;
  color: #a89fcf;
  letter-spacing: 0.14em;
  font-weight: 400;
  line-height: 1;
  text-transform: uppercase;
}

/* Unscoped (not tied to .home-body/.chat-body) so every page's plain .topnav gets this —
   .rr-logo__wordmark's 2.3rem + white-space:nowrap is wider than a mobile viewport can fit
   next to the leaf icon and topnav__links, causing horizontal page overflow on any page
   that doesn't already have its own mobile-specific logo override (confirmed via
   scrollWidth vs innerWidth: /readers, /readers/calls, /readers/chats, /about and likely
   every other plain-body page were all overflowing to ~422px at a 390px viewport, purely
   from this one element — .home-body and .chat-body already shrink it their own way, this
   just extends the same treatment to everywhere else). */
@media (max-width: 768px) {
  .rr-logo__wordmark { font-size: 1.5rem; }
  .rr-logo__tagline { display: none; }
}

.topnav__links {
  display: flex;
  align-items: center;
  gap: 20px;
  flex-wrap: wrap;
}

.topnav__links a { color: var(--text-muted); font-size: 0.9rem; }
.topnav__links a:hover { color: var(--text); }

/* ── Wallet balance chip ──────────────────────────────────── */
.wallet-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: var(--purple-dim);
  border: 1px solid rgba(83,74,183,0.35);
  border-radius: 20px;
  padding: 4px 14px;
  font-size: 0.875rem;
  font-weight: 600;
  color: #b8b3e8;
  position: relative;
  cursor: help;
}

.wallet-chip .wb-tip {
  display: none;
  position: absolute;
  left: 0; top: calc(100% + 8px);
  background: #1e1934;
  border: 1px solid var(--card-border);
  border-radius: var(--radius-sm);
  padding: 12px 16px;
  white-space: nowrap;
  font-size: 0.8rem;
  font-weight: 400;
  line-height: 2;
  z-index: 100;
  color: var(--text-muted);
  box-shadow: 0 8px 32px rgba(0,0,0,0.4);
}

.wallet-chip:hover .wb-tip { display: block; }

/* ── Page hero ────────────────────────────────────────────── */
.page-hero {
  padding: 48px 0 32px;
  text-align: center;
}

.page-hero h1 { font-size: 2.6rem; color: var(--text); margin-bottom: 10px; }
.page-hero p  { font-size: 1.05rem; color: var(--text-muted); }

/* ── Cards ────────────────────────────────────────────────── */
.card {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--radius);
  padding: 24px;
}

.card + .card { margin-top: 16px; }

/* ── Buttons ──────────────────────────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  border: none;
  border-radius: var(--radius-sm);
  padding: 10px 22px;
  font-family: 'Inter', sans-serif;
  font-size: 0.9rem;
  font-weight: 600;
  cursor: pointer;
  transition: opacity .15s, transform .1s;
  text-decoration: none;
}

.btn:active { transform: scale(.98); }
.btn:disabled { opacity: .4; cursor: not-allowed; transform: none; }

.btn--primary {
  background: var(--gold);
  color: #1a1430;
}
.btn--primary:hover { opacity: .88; }

.btn--secondary {
  background: var(--purple);
  color: #fff;
}
.btn--secondary:hover { opacity: .88; }

.btn--ghost {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  color: var(--text-muted);
}
.btn--ghost:hover { border-color: rgba(255,255,255,0.2); color: var(--text); }

.btn--outline-gold {
  background: var(--gold-dim);
  border: 1px solid var(--gold);
  color: var(--gold);
}
.btn--outline-gold:hover { background: rgba(250,199,117,0.2); }

.btn--danger {
  background: rgba(240,138,138,0.15);
  border: 1px solid rgba(240,138,138,0.3);
  color: var(--danger);
}
.btn--danger:hover { background: rgba(240,138,138,0.25); }

.btn--sm { padding: 7px 14px; font-size: 0.82rem; }
.btn--lg { padding: 13px 30px; font-size: 1rem; }

/* ── Forms ────────────────────────────────────────────────── */
.form-group {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 20px;
}

.form-group label {
  font-size: 0.85rem;
  font-weight: 500;
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: .05em;
}

.form-control {
  background: rgba(255,255,255,0.06);
  border: 1px solid var(--card-border);
  border-radius: var(--radius-sm);
  padding: 10px 14px;
  font-family: 'Inter', sans-serif;
  font-size: 0.95rem;
  color: var(--text);
  outline: none;
  transition: border-color .15s;
  width: 100%;
}

.form-control:focus {
  border-color: rgba(250,199,117,0.5);
}

.form-control::placeholder { color: var(--text-dim); }

select.form-control {
  appearance: none;
  -webkit-appearance: none;
  background-color: #241d34;
  border: 1px solid #3a2f52;
  border-radius: 10px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%239e98c0' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  padding-right: 32px;
}

/* The open dropdown list's <option> items are a separate rendering surface from the closed
   select box above — this is honored by Chromium/Firefox (Windows/Linux/Android), but
   Safari (macOS/iOS) always renders this popup via native Cocoa/UIKit chrome and ignores
   option background/color entirely. No CSS workaround exists for that; the closed select
   box is unaffected and stays fully themed either way. Colors match the approved mockup. */
select.form-control option {
  background-color: #241d34;
  color: #c9c3d4;
  border-bottom: 1px solid #2c2440;
  border-radius: 10px;
}

select.form-control option:checked,
select.form-control option:hover,
select.form-control option:focus {
  background-color: #3a2f52;
  color: var(--gold);
}

textarea.form-control { resize: vertical; min-height: 100px; }

input[type="range"].form-control {
  padding: 0;
  background: transparent;
  border: none;
  accent-color: var(--gold);
}

input[type="radio"] { accent-color: var(--gold); }

/* color-scheme:dark switches the calendar-icon glyph and, in Chromium, the calendar popup
   itself over to the browser's own built-in dark palette. This is the only lever CSS has
   over that popup — no property lets a page inject its own custom colors into it in any
   browser, so it renders in the browser's generic dark grey, not the site's purple/gold
   theme. The visible input box itself is fully themed via .form-control above. */
input[type="date"].form-control { color-scheme: dark; }

/* ── Alerts / banners ─────────────────────────────────────── */
.alert {
  padding: 12px 16px;
  border-radius: var(--radius-sm);
  font-size: 0.9rem;
  margin-bottom: 20px;
}

.alert--error {
  background: rgba(240,138,138,0.12);
  border: 1px solid rgba(240,138,138,0.3);
  color: var(--danger);
}

.alert--success {
  background: rgba(143,203,74,0.12);
  border: 1px solid rgba(143,203,74,0.3);
  color: var(--success);
}

.alert--warning {
  background: rgba(245,194,74,0.12);
  border: 1px solid rgba(245,194,74,0.3);
  color: var(--status-busy-fg);
}

.alert--info {
  background: var(--purple-dim);
  border: 1px solid rgba(83,74,183,0.35);
  color: #b8b3e8;
}

/* ── Login page — "Don't have an account" line + register CTA card ── */
.login-register-line {
  text-align: center;
  font-size: 0.88rem;
  margin-bottom: 14px;
}

.login-register-line a {
  font-weight: 700;
}

.login-cta {
  border: 1px solid var(--gold);
  border-radius: 12px;
  overflow: hidden;
}

.login-cta__promo {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 16px;
  background: var(--gold-dim);
}

.login-cta__icon {
  flex-shrink: 0;
  display: flex;
}

.login-cta__headline {
  font-size: 0.92rem;
  line-height: 1.4;
  color: var(--text);
}

.login-cta__highlight {
  font-family: 'Poppins', 'Inter', system-ui, sans-serif;
  font-weight: 700;
  color: var(--gold);
}

.login-cta__subtext {
  font-size: 0.78rem;
  color: var(--text-muted);
  margin-top: 2px;
}

/* Flush against .login-cta__promo above it — same border-radius as .login-cta itself so
   its bottom corners stay rounded once clipped by the parent's overflow:hidden; the top
   corners are square, which is what makes the two sections read as one connected card. */
.login-cta__button {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  padding: 14px;
  background: var(--gold);
  color: #1a1430;
  font-family: 'Poppins', 'Inter', system-ui, sans-serif;
  font-weight: 700;
  font-size: 0.95rem;
  text-decoration: none;
  transition: opacity .15s;
}
.login-cta__button:hover { opacity: .88; }

/* Post-registration welcome page — two intro CTA cards side by side (free-reading promo +
   wallet top-up promo), stacked on mobile. The gold card reuses .login-cta verbatim (the same
   promo card already used on the login page) rather than a second gold style; .welcome-card
   below is the neutral counterpart for the wallet card, mirroring the same icon+headline+button
   structure and box model. Scoped to .welcome-cta-grid rather than modifying .login-cta itself
   so login.ejs's own (non-grid, non-stretched) usage is untouched. */
.welcome-cta-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  align-items: stretch;
  gap: 16px;
  margin-bottom: 28px;
}
.welcome-cta-grid > .login-cta,
.welcome-cta-grid > .welcome-card {
  display: flex;
  flex-direction: column;
}
.welcome-cta-grid > .login-cta > .login-cta__promo,
.welcome-cta-grid > .welcome-card > .welcome-card__promo {
  flex: 1;
}

.welcome-card {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: 12px;
  overflow: hidden;
}
.welcome-card__promo {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 16px;
}
.welcome-card__icon {
  flex-shrink: 0;
  display: flex;
  color: var(--text-muted);
  font-size: 1.6rem;
}
.welcome-card__headline {
  font-size: 0.92rem;
  line-height: 1.4;
  color: var(--text);
  font-family: 'Poppins', 'Inter', system-ui, sans-serif;
  font-weight: 700;
}
.welcome-card__subtext {
  font-size: 0.78rem;
  color: var(--text-muted);
  margin-top: 2px;
}
.welcome-card__button {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  padding: 14px;
  background: var(--purple);
  color: #fff;
  font-family: 'Poppins', 'Inter', system-ui, sans-serif;
  font-weight: 700;
  font-size: 0.95rem;
  text-decoration: none;
  transition: opacity .15s;
}
.welcome-card__button:hover { opacity: .88; }

@media (max-width: 768px) {
  .welcome-cta-grid {
    grid-template-columns: 1fr;
  }
}

/* ── Status badges ────────────────────────────────────────── */
.status-badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 0.78rem;
  font-weight: 600;
  padding: 3px 10px;
  border-radius: 20px;
  letter-spacing: .03em;
}

.status-badge::before {
  content: '';
  display: inline-block;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: currentColor;
}

.status-badge--online {
  background: var(--status-online-bg);
  color: var(--status-online-fg);
}

.status-badge--busy {
  background: var(--status-busy-bg);
  color: var(--status-busy-fg);
}

.status-badge--offline {
  background: var(--status-offline-bg);
  color: var(--status-offline-fg);
}

/* "New reader" pill — gold outline, transparent fill. Same pill shape/padding rhythm as
   .status-badge (the "Offline" badge on the same card) but its own class since this isn't a
   presence status and shouldn't get .status-badge::before's colored dot. */
.new-reader-badge {
  display: inline-flex;
  align-items: center;
  font-size: 0.72rem;
  font-weight: 600;
  padding: 3px 10px;
  border-radius: 20px;
  border: 1px solid var(--gold);
  color: var(--gold);
  background: transparent;
}

/* ── Reader card grid — 5-across desktop, scales down on smaller screens ─── */
.readers-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 12px;
  margin-top: 0;
}

@media (max-width: 1100px) { .readers-grid { grid-template-columns: repeat(4, 1fr); } }
@media (max-width: 840px)  { .readers-grid { grid-template-columns: repeat(3, 1fr); } }
@media (max-width: 580px)  { .readers-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 360px)  { .readers-grid { grid-template-columns: 1fr; } }

/* Homepage desktop only: 6 across instead of the shared 5. Scoped with min-width so it only
   wins in the same "widest tier" range the default 5-column rule covers above — without the
   min-width, .home-body's extra class would out-specificity the 1100/840px breakpoints too
   and get stuck at 6 columns even as the viewport narrows. /readers (no .home-body class)
   is completely unaffected and stays at 5. */
@media (min-width: 1101px) {
  .home-body .readers-grid { grid-template-columns: repeat(6, 1fr); }
}

/* ── Reader card — vertical layout with banner photo ─────── */
.reader-card {
  background: #1a1430;
  border: 1px solid #2e2148;
  border-radius: var(--radius);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition: border-color .2s;
  position: relative;
}

.reader-card:hover {
  border-color: #4a3d6e;
}

/* Hidden by category filter */
.reader-card--cat-hidden { display: none !important; }

/* Photo banner — landscape 4:3, fills card width */
.reader-card__photo-wrap {
  position: relative;
  width: 100%;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  flex-shrink: 0;
  background: rgba(255,255,255,0.04);
}

/* --photo-pos-card/--photo-pos-mobile-card are set inline per-<img> (see readers-grid.ejs)
   from the reader's saved photoPositionCard/photoPositionMobileCard. Desktop and the
   /readers page (no .home-body) both stay true 4:3 and read --photo-pos-card here; the
   homepage's mobile row-layout override below switches to --photo-pos-mobile-card, since
   that layout stretches this same element to a different, non-4:3 shape (see that override
   for the current exact dimensions - it changes whenever the mobile card's own height does). */
.reader-card__photo {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: var(--photo-pos-card, 50% 50%);
  display: block;
}

.reader-card__photo-placeholder {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 3rem;
  color: var(--text-dim);
}

/* Status badge overlaid at bottom-left of photo. */
.reader-card__status-badge {
  position: absolute;
  bottom: 8px;
  left: 8px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.5);
  font-size: 0.72rem;
}

/* Free-reading corner badge — homepage/browse grid cards only (not the profile page), top-
   right of the photo. Same eligibility flag as the Chat/Call button's own gift line
   (reader.showFreeReadingLine — see readers-grid.ejs), so this and that button never disagree
   about whether a reader is currently eligible. Bottom-left is already the status badge, so
   top-right is clear by default — except the favourite heart button (.fav-form, logged-in
   customers only) also sits top-right; the sibling-combinator override below shifts this
   badge down below the heart on the (fairly common) cards where both render, rather than the
   two overlapping. */
.reader-card__gift-badge {
  position: absolute;
  top: 8px;
  right: 8px;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 3px;
  background: #FAC775;
  color: #150f24;
  font-size: 0.64rem;
  font-weight: 700;
  padding: 3px 8px;
  border-radius: 20px;
  box-shadow: 0 2px 8px rgba(0,0,0,0.5);
  white-space: nowrap;
}
.reader-card__gift-badge i { font-size: 0.85em; }
.fav-form ~ .reader-card__gift-badge { top: 44px; }
.reader-card__gift-badge--hidden { display: none; }

/* Solid (not translucent) background so it reads clearly over any photo — a shared
   modifier (not scoped to .reader-card__status-badge) so the reader profile page's own
   availability badge can opt into the exact same colors via the same declaration, rather
   than maintaining a second, separately-styled implementation that can drift out of sync
   (previously .profile-avail-pill/.profile-avail-dot, a visually different dot+muted-pill
   scheme — see reader-profile.ejs). Scoped to .status-badge--solid specifically so the
   plain .status-badge--* classes used elsewhere (admin panel, reviews) are untouched. */
.status-badge--solid.status-badge--online {
  background: #1e7e34;
  color: #fff;
}

.status-badge--solid.status-badge--busy {
  background: #FAC775;
  color: #150f24;
}

.status-badge--solid.status-badge--offline {
  background: #9b2335;
  color: #fff;
}

/* Content below photo — gradient matches topnav surface (#2e2148 → #1a1430) */
.reader-card__body {
  flex: 1;
  display: flex;
  flex-direction: column;
  padding: 12px;
  gap: 6px;
  background: linear-gradient(160deg, #2e2148 0%, #1a1430 100%);
}

.reader-card__name {
  font-size: 1rem;
  font-weight: 600;
  color: var(--text);
  line-height: 1.25;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.reader-card__stars {
  display: flex;
  align-items: center;
  gap: 4px;
  line-height: 1;
  min-height: 20px;
}

.reader-media-icons {
  display: flex;
  gap: 5px;
  flex-shrink: 0;
  position: relative;
  z-index: 2;
}

.reader-media-btn {
  background: transparent;
  border: 1px solid #FAC775;
  border-radius: 20px;
  padding: 2px 8px;
  cursor: pointer;
  color: #FAC775;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  line-height: 1;
  font-family: 'Poppins', sans-serif;
  transition: background 0.15s ease;
}

.reader-media-btn .ti {
  font-size: 10px;
}

.reader-media-btn span {
  font-size: 10px;
  color: #FAC775;
}

.reader-card .reader-media-btn {
  background: transparent;
}

.reader-card .reader-media-btn:hover {
  background: #150f24 !important;
  transition: background 0.15s ease;
  cursor: pointer;
}

.reader-card__bio {
  font-size: 0.8rem;
  color: var(--text-muted);
  line-height: 1.5;
  display: -webkit-box;
  -webkit-line-clamp: 4;
  -webkit-box-orient: vertical;
  overflow: hidden;
  flex: 1;
}

.reader-card__rate-badge {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: var(--gold-dim);
  border: 1px solid rgba(250,199,117,0.22);
  color: var(--gold);
  font-size: 0.75rem;
  font-weight: 600;
  padding: 2px 8px;
  border-radius: 20px;
  align-self: flex-start;
}

.reader-card__actions {
  display: flex;
  gap: 6px;
  margin-top: auto;
  padding-top: 4px;
  position: relative;
  z-index: 2;
}

.reader-card__actions .btn--sm {
  flex: 1;
  font-size: 0.78rem;
  padding: 6px 8px;
}

.reader-card__stars { position: relative; z-index: 2; }

/* Stretched profile link — covers whole card, lifted elements sit above it */
.reader-card__profile-link {
  color: inherit;
  text-decoration: none;
}
.reader-card__profile-link::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  cursor: pointer;
}

/* ── Promo banner (decorative — replace gradient with a real image when available) ── */
.promo-banner {
  /* Replace this gradient with a real background image when one is available:
     background: url('/img/banner.jpg') center/cover no-repeat; */
  background: radial-gradient(circle at 25% 30%, #3c3489 0%, #1a1430 70%);
  border-radius: var(--radius);
  padding: 0 28px;
  height: 68px;
  display: flex;
  align-items: center;
  gap: 20px;
  /* 15px, not 20px: matching the box-model margin alone (20px, same as .trust-strip's own
     margin-bottom above) still left the gap below visibly bigger, because the "Browse our
     talented readers" h2 has ~4.75px of invisible line-height leading above its own text
     glyph (normal font rendering, confirmed by pixel-sampling the actual glyph's first
     visible pixel) that the trust strip's border-bottom doesn't have — that border is a
     painted line flush with its box edge, not text with leading above it. 15px + that 4.75px
     of leading gets the two visually equal (measured ~20px each), not just equal on paper. */
  margin-bottom: 15px;
  overflow: hidden;
}

.promo-banner__text {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
  flex: 1;
}

.promo-banner__line1 {
  font-family: 'Inter', system-ui, sans-serif;
  font-size: 1rem;
  font-weight: 600;
  color: var(--text);
  margin: 0;
}

.promo-banner__line2 {
  font-size: 0.8rem;
  color: var(--text-muted);
  margin: 0;
}

.promo-banner__cta {
  background: #FAC775;
  color: #1a1430;
  border: none;
  border-radius: 6px;
  padding: 8px 20px;
  font-family: 'Inter', system-ui, sans-serif;
  font-size: 0.85rem;
  font-weight: 600;
  cursor: pointer;
  flex-shrink: 0;
  transition: opacity .15s;
}

.promo-banner__cta:hover { opacity: 0.82; }

.promo-banner__cta--two-line {
  height: 34px;
  padding: 0 22px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  text-align: center;
  text-decoration: none;
  white-space: nowrap;
}
.promo-banner__cta--two-line .cta-headline {
  font-size: 0.82rem;
  font-weight: 700;
  line-height: 1.1;
}
.promo-banner__cta--two-line .cta-sub {
  font-size: 0.63rem;
  font-weight: 400;
  line-height: 1.1;
  opacity: 0.88;
}

.promo-banner__icon {
  font-size: 1.5rem;
  line-height: 1;
  user-select: none;
  flex-shrink: 0;
  color: rgba(250, 199, 117, 0.85);
}

.promo-banner__icon i {
  color: rgba(250, 199, 117, 0.85);
}

/* ── "Real answers" section (homepage) ── */
.rar-section {
  background: linear-gradient(180deg, #2e2148 0%, #1a1430 100%);
  border-top: 1px solid #3a3360;
  border-bottom: 1px solid #3a3360;
  padding: 52px 40px 48px;
  margin: 0 -24px 0;
}

.rar-section__heading {
  color: #FAC775;
  font-size: 1.6rem;
  font-weight: 700;
  text-align: center;
  margin: 0 0 16px;
}

.rar-section__intro {
  color: #a89fcf;
  text-align: center;
  max-width: 1100px;
  margin: 0 auto 40px;
  font-size: 0.92rem;
  line-height: 1.65;
}

.rar-columns {
  display: grid;
  grid-template-columns: 1fr 0.8fr 1fr;
  gap: 20px;
  align-items: stretch;
}

.rar-card {
  background: #1a1430;
  border: 1px solid #2e2148;
  border-radius: 12px;
  padding: 22px;
}

.rar-card__header {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 18px;
}

.rar-card__icon {
  color: #FAC775;
  font-size: 1.2rem;
  flex-shrink: 0;
}

.rar-card__heading {
  color: var(--text);
  font-size: 1rem;
  font-weight: 700;
  margin: 0;
}

.rar-questions {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.rar-question {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  color: #cfc9e8;
  font-size: 0.88rem;
  line-height: 1.5;
}

.rar-question__check {
  color: #7f77dd;
  font-size: 0.95rem;
  margin-top: 2px;
  flex-shrink: 0;
}

.rar-center {
  background: radial-gradient(circle at 50% 30%, #3c3489 0%, #1a1430 75%);
  border: 1px solid #534ab7;
  border-radius: 12px;
  padding: 22px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
}

.rar-center__icon {
  color: #FAC775;
  font-size: 1.875rem;
  margin-bottom: 14px;
}

.rar-center__heading {
  color: var(--text);
  font-size: 0.97rem;
  font-weight: 700;
  margin: 0 0 10px;
}

.rar-center__text {
  color: #a89fcf;
  font-size: 0.82rem;
  line-height: 1.6;
  margin: 0;
}

.rar-closing {
  text-align: center;
  color: #FAC775;
  font-weight: 700;
  font-size: 1.0625rem;
  margin: 36px 0 0;
}

@media (max-width: 680px) {
  .rar-section {
    padding: 40px 20px 36px;
  }
  .rar-columns {
    grid-template-columns: 1fr;
  }
}

/* ── "Why thousands trust RemedyReadings" section (Part 1) ── */
.wtt-section {
  position: relative;
  isolation: isolate;
  background-color: #0e0c16;
  margin: 0 -24px;
  padding: 52px 40px 48px;
  border-top: 1.4px solid #FAC775;
}

.wtt-top-header {
  margin: 0 0 28px;
}

.wtt-top-heading {
  color: #f1eefb;
  font-size: 2.0625rem;
  font-weight: 700;
  margin: 0 0 10px;
  line-height: 1.2;
}

.wtt-top-desc {
  color: #cfc9e8;
  font-size: 0.8625rem;
  line-height: 1.6;
  max-width: 700px;
  margin: 0;
}

.wtt-highlight {
  color: #FAC775;
  font-weight: 700;
}

.wtt-section__inner {
  display: grid;
  grid-template-columns: 1.9fr 1fr;
  gap: 40px;
  align-items: stretch;
  max-width: 1200px;
  margin: 0 auto;
}

.wtt-heading {
  color: #FAC775;
  font-size: 1.5625rem;
  font-weight: 700;
  margin: 0 0 20px;
  line-height: 1.25;
}

.wtt-para {
  color: #cfc9e8;
  font-size: 0.8625rem;
  line-height: 1.7;
  margin: 0 0 14px;
}

.wtt-para:last-child { margin-bottom: 0; }

.wtt-steps {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.wtt-step {
  background: linear-gradient(135deg, #2e2148 0%, #1a1430 100%);
  border: 1.4px solid #FAC775;
  border-radius: 10px;
  padding: 10px 13px;
  display: flex;
  gap: 10px;
  align-items: flex-start;
  flex: 1;
}

.wtt-step__badge {
  width: 30px;
  height: 30px;
  flex-shrink: 0;
  background: #1a1430;
  border: 1.4px solid #FAC775;
  border-radius: 6px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.875rem;
  font-weight: 700;
  color: #FAC775;
  line-height: 1;
}

.wtt-step__content { flex: 1; min-width: 0; }

.wtt-step__heading {
  font-size: 0.78125rem;
  font-weight: 700;
  color: #f1eefb;
  margin: 0 0 5px;
  line-height: 1.3;
}

.wtt-step__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.wtt-step__list li {
  font-size: 0.7125rem;
  color: #cfc9e8;
  line-height: 1.5;
  padding-left: 10px;
  position: relative;
}

.wtt-step__list li::before {
  content: '–';
  position: absolute;
  left: 0;
  color: #FAC775;
}

@media (max-width: 680px) {
  .wtt-section {
    padding: 40px 20px 36px;
  }
  .wtt-section__inner {
    grid-template-columns: 1fr;
    align-items: start;
  }
  .wtt-step { flex: none; }
}

/* ── "Life-changing benefits" bar (Part 2) ───────────────── */
.benefits-bar {
  background: #150f24;
  margin: 0 -24px;
  padding: 24px 40px;
  border-top: 1.4px solid #FAC775;
}

.benefits-bar__heading {
  color: #f1eefb;
  font-size: 1rem;
  font-weight: 700;
  margin: 0 0 10px;
}

.benefits-bar__text {
  color: #a89fcf;
  font-size: 0.825rem;
  line-height: 1.6;
  margin: 0;
  max-width: 1200px;
}

@media (max-width: 680px) {
  .benefits-bar {
    padding: 18px 20px;
  }
}

/* ── Category filter chips ────────────────────────────────── */
.cat-bar {
  display: flex;
  gap: 6px;
  margin: 16px 0 20px;
  flex-wrap: nowrap;
  overflow-x: auto;
  scrollbar-width: none;
}

.cat-bar::-webkit-scrollbar { display: none; }

.cat-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  flex: 1;
  min-width: 0;
  padding: 7px 10px;
  border-radius: 7px;
  border: 1px solid #3a3360;
  background: #1a1430;
  color: #cfc9e8;
  font-size: 0.78rem;
  font-weight: 500;
  cursor: pointer;
  white-space: nowrap;
  transition: border-color .15s, color .15s;
  font-family: 'Inter', sans-serif;
}

.cat-chip:hover {
  border-color: rgba(250,199,117,0.35);
  color: #e8e4f5;
}

.cat-chip--active {
  border-color: var(--gold);
  color: var(--gold);
  background: #1a1430;
}

/* Collapsed/expanded homepage category bar (chips 8-21 stay in the DOM for filtering,
   just hidden until "Browse more" is clicked) */
.cat-chip--extra {
  display: none;
}

/* Grid (not flex-wrap) so the row-break point is fixed instead of depending on viewport
   width: 24 visible items (All + 22 categories + Browse less) at 8 columns = exactly 3 full
   rows (8 + 8 + 8), so every row fills edge-to-edge with no empty trailing slot. */
.cat-bar--expanded {
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  overflow-x: visible;
}

.cat-bar--expanded .cat-chip--extra {
  display: inline-flex;
}

/* Equal-width grid columns mean long labels (e.g. "Love & Relationships") no longer get
   extra room the way flex-basis:auto gave them — truncate with an ellipsis instead of
   letting the text visually spill into the next chip. Collapsed row is unaffected. */
.cat-chip__label {
  min-width: 0;
}

.cat-bar--expanded .cat-chip__label {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.cat-chip--browse-more {
  border-color: var(--gold);
  color: var(--gold);
  background: #1a1430;
}

/* Chat button — gold primary */
.btn--chat {
  background: var(--gold);
  color: #1a1430;
  font-weight: 700;
}
.btn--chat:hover:not(:disabled) { opacity: .88; }
.btn--chat:disabled {
  background: rgba(255,255,255,0.07);
  color: var(--text-dim);
  border: 1px solid var(--card-border);
  cursor: not-allowed;
  opacity: 1;
}

/* Call button — purple secondary */
.btn--call {
  background: var(--purple);
  color: #fff;
  font-weight: 600;
}
.btn--call:hover:not(:disabled) { opacity: .88; }
.btn--call:disabled {
  background: rgba(255,255,255,0.07);
  color: var(--text-dim);
  border: 1px solid var(--card-border);
  cursor: not-allowed;
  opacity: 1;
}

/* Reader card action buttons: both active Chat/Call buttons are gold (not purple for Call) —
   scoped to the card only. The standalone .btn--call elsewhere (profile page, call-confirm)
   keeps its purple styling untouched. */
.reader-card__actions .btn--chat:not(:disabled),
.reader-card__actions .btn--call:not(:disabled) {
  background: #FAC775;
  color: #150f24;
}

/* ── Filter bar (readers directory) ──────────────────────── */
.filter-bar {
  display: flex;
  align-items: center;
  gap: 3px;
  background: rgba(255,255,255,0.05);
  border: 1px solid var(--card-border);
  border-radius: 999px;
  padding: 4px;
  width: fit-content;
  margin: 0 auto 40px;
}

/* All 3 nowrap pill items ("All Readers"/"Call Readings"/"Chat Readings") together are
   wider than the smallest common phone viewports (e.g. ~320px, where .page-wrap's 24px
   side padding only leaves ~272px) — confirmed via scrollWidth vs innerWidth on /readers,
   /readers/calls, /readers/chats, causing page-level horizontal overflow there. Smaller
   padding/font-size buys back space for most phones; max-width:100% + overflow-x:auto is a
   contained fallback so on the very narrowest devices this bar scrolls WITHIN itself
   (a normal, expected pattern for pill tab bars) instead of ever pushing the page itself
   wider than the viewport. -webkit-overflow-scrolling:touch keeps the scroll momentum
   smooth on iOS. */
@media (max-width: 768px) {
  .filter-bar {
    max-width: 100%;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }
  .filter-bar__item {
    padding: 8px 14px;
    font-size: 0.8rem;
  }
}

.filter-bar__item {
  padding: 8px 22px;
  border-radius: 999px;
  font-size: 0.87rem;
  font-weight: 500;
  color: var(--text-muted);
  text-decoration: none;
  transition: background .15s, color .15s;
  white-space: nowrap;
  /* Buttons get a UA-stylesheet line-height:normal that <a> elements don't — without this,
     an <a>-rendered pill (reader-filter-bar.ejs's isHomePage:false branch, used on About/
     legal pages) instead inherits body's line-height:1.6, standing ~6px taller than the
     <button>-rendered pill on the homepage and throwing off the whole banner's height. */
  line-height: normal;
}

.filter-bar__item:hover {
  color: var(--text);
  background: rgba(255,255,255,0.07);
  opacity: 1;
}

.filter-bar__item--active,
.filter-bar__item--active:hover {
  background: var(--gold);
  color: #1a1430;
  font-weight: 600;
  opacity: 1;
}

button.filter-bar__item {
  border: none;
  cursor: pointer;
  font-family: inherit;
}
button.filter-bar__item:not(.filter-bar__item--active) {
  background: none;
}

.filter-bar-row {
  display: flex;
  align-items: center;
}

.filter-bar-trust {
  display: flex;
  align-items: center;
  gap: 8px;
  color: #cfc9e8;
  font-size: 1rem;
  white-space: nowrap;
}

.filter-bar-trust i {
  color: #FAC775;
  font-size: 16px;
  flex-shrink: 0;
}

.filter-bar-search {
  margin-left: auto;
  margin-right: auto;
  flex-shrink: 0;
  position: relative;
  width: 220px;
}

.filter-bar-search .ti-search {
  position: absolute;
  left: 12px;
  top: 50%;
  transform: translateY(-50%);
  color: #FAC775;
  font-size: 15px;
  pointer-events: none;
}

.reader-search-input {
  width: 100%;
  box-sizing: border-box;
  background: #2e2148;
  border: 1px solid #FAC775;
  border-radius: 999px;
  color: var(--text);
  font-family: inherit;
  font-size: 0.87rem;
  font-weight: 500;
  padding: 7px 18px 7px 32px;
  outline: none;
}

.reader-search-input:focus {
  box-shadow: 0 0 0 2px rgba(250,199,117,0.18);
}

.reader-search-input::placeholder { color: #cfc9e8; }

@media (max-width: 900px) {
  .filter-bar-search { display: none; }
}

@media (max-width: 768px) {
  .filter-bar-trust { display: none; }
}

/* Desktop-only banner on non-home pages (about.ejs, static-page.ejs — see
   reader-filter-bar.ejs's isHomePage:false branch). Mobile on those pages already has its
   own equivalent (the fixed mobile-quickstats trust bar + .mobile-bottom-nav's Search/Chat/
   Call links), so this whole row is hidden below the site's standard mobile breakpoint
   rather than showing a second, redundant filter UI. Unlike .filter-bar-search/.filter-bar-
   trust above, this hides the ENTIRE row (pills included) — home.ejs's own filter-bar-wrap
   has no --page-banner modifier, so its mobile behaviour (pills still visible) is untouched. */
@media (max-width: 768px) {
  .filter-bar-wrap--page-banner { display: none; }
}

/* ── Trust strip (4-item info row, shared by every .home-body page) ───────
   border-top lives here rather than on .readers-section (home.ejs's dark reader-grid
   slab) because trust-strip.ejs is the one thing every page — home, about, legal — always
   wraps in. Previously .readers-section supplied this line on the homepage only, so
   about.ejs/static-page.ejs's own instance of trust-strip.ejs (which has no readers-section
   equivalent) rendered with only its own border-bottom, missing the matching top line.
   Homepage rendering is unchanged: trust-strip already sat flush against
   .readers-section's old border-top with zero gap, so moving the line onto trust-strip's
   own top edge lands it at the exact same pixel row. */
.trust-strip {
  background: #150f24;
  margin: 0 -24px 20px;
  padding: 14px 32px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  border-top: 1.4px solid #FAC775;
  border-bottom: 1.4px solid #FAC775;
}

/* Reader profile page's fixed mobile stat bar reuses the .trust-strip class itself (so it
   picks up .home-body .trust-strip's existing fixed-position mobile CSS verbatim, with zero
   new positioning rules) — but unlike the homepage, this page has no desktop equivalent of
   the trust strip, so the base .trust-strip rule above (unconditional, always-on) would
   otherwise make it a new, unwanted visible element on desktop too. This second class,
   present only on the profile page's instance, hides it by default; same (0,1,0)
   specificity as the base rule above and later in the source, so it wins the tie on any
   viewport where .home-body's higher-specificity (0,2,0) mobile override doesn't apply
   (i.e. desktop) — and correctly loses to that override inside the mobile media query,
   where it's the only place this needs to be visible. The homepage's own .trust-strip has
   no such class and is completely unaffected. (.home-body .trust-strip below needed an
   explicit display:flex added for this to actually work — it previously only ever set
   position/sizing and relied on the base rule above for display, which is exactly the
   property this override needs to beat.) */
.profile-fixed-statbar {
  display: none;
}

.trust-strip__item {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 1;
}

.trust-strip__item i {
  font-size: 1.25rem;
  color: var(--gold);
  flex-shrink: 0;
}

.trust-strip__text {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.trust-strip__heading {
  font-size: 0.75rem;
  font-weight: 600;
  color: #e8e4f5;
  line-height: 1.2;
}

.trust-strip__desc {
  font-size: 0.67rem;
  color: var(--text-muted);
  line-height: 1.3;
}

/* ── Dark slab (homepage) — trust strip → banner → reader grid on near-black ──
   No border-top here — trust-strip (the first thing inside this section) now supplies
   its own, shared with every other page that includes it. See .trust-strip's comment. */
.readers-section {
  position: relative;
  isolation: isolate;
  background-color: #0e0c16;
  margin: 0 -24px;
  padding: 0 24px 60px;
  border-bottom: 1.4px solid #FAC775;
}

/* ── Animated starfield + nebula background ───────────────── */
.starfield-layer {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  overflow: hidden;
}

/* Four irregular nebula blooms — site purples only, soft edges */
.starfield-layer::before {
  content: '';
  position: absolute;
  inset: 0;
  background:
    radial-gradient(ellipse 340px 240px at 12% 28%, rgba(83,74,183,0.38) 0%, transparent 65%),
    radial-gradient(ellipse 260px 340px at 88% 68%, rgba(60,52,137,0.32) 0%, transparent 65%),
    radial-gradient(ellipse 320px 180px at 50% 88%, rgba(127,119,221,0.26) 0%, transparent 65%),
    radial-gradient(ellipse 240px 280px at 76% 15%, rgba(83,74,183,0.30) 0%, transparent 65%);
}

/* Stars: tiled SVG drifting horizontally — seamless loop at 900px tile width.
   Animates transform (GPU-compositable), not background-position — animating
   background-position forces a full repaint on every frame for the entire 90s duration,
   measured as 2.5-4x higher Paint cost and real >50ms visible-stutter frames during scroll
   (worst on tall pages like reader profiles) in the scroll-jank diagnosis.
   The element itself is widened by exactly one tile width (900px, matching
   background-size) and shifted left by that same amount, so translating it right by
   0-900px never exposes a gap at either edge — the parent's overflow:hidden clips the
   overhang either way. Shifting a seamlessly-tiled pattern by exactly one full tile width
   is pixel-identical to not shifting it at all (the same property the original
   background-position version already relied on for its 900px->0 loop point), so this
   produces mathematically the same rendered pixels at every instant, not just at the loop
   boundary — verified frame-by-frame against the old version, not just "looks the same". */
.starfield-layer::after {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  left: -900px;
  width: calc(100% + 900px);
  background-image: url('/starfield.svg');
  background-size: 900px 600px;
  background-repeat: repeat;
  will-change: transform;
  backface-visibility: hidden;
  animation: star-drift 90s linear infinite;
}

@keyframes star-drift {
  /* translate3d (not translateX) — the 3D form is what reliably triggers GPU layer
     promotion across browsers, same reasoning as will-change:transform above; see the
     equivalent will-change + translateZ(0) pairing on the fixed mobile bars elsewhere in
     this file for the same dual-technique convention (there via a static transform, here
     via the animation's own transform since this element's transform IS what's animated). */
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(900px, 0, 0); }
}

/* Individual twinkling stars: three opacity-range variants, staggered via animation-delay */
.twinkle-star {
  position: absolute;
  border-radius: 50%;
}

@keyframes twinkle-a { 0%,100% { opacity: .72; } 50% { opacity: .12; } }
@keyframes twinkle-b { 0%,100% { opacity: .60; } 50% { opacity: .12; } }
@keyframes twinkle-c { 0%,100% { opacity: .82; } 50% { opacity: .15; } }

@media (prefers-reduced-motion: reduce) {
  .starfield-layer::after { animation: none; }
  .twinkle-star { animation: none !important; }
}

/* ── Offline reader toggling ──────────────────────────────── */
.offline-hidden .reader-card--offline { display: none; }

/* ── Tab navigation ───────────────────────────────────────── */
.tabs {
  display: flex;
  gap: 4px;
  border-bottom: 1px solid var(--card-border);
  margin-bottom: 32px;
}

.tabs__link {
  padding: 10px 20px;
  font-size: 0.88rem;
  font-weight: 500;
  color: var(--text-muted);
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
  transition: color .15s, border-color .15s;
}

.tabs__link:hover { color: var(--text); }

.tabs__link--active {
  color: var(--gold);
  border-bottom-color: var(--gold);
}

/* Same disabled recipe as .btn:disabled (opacity + not-allowed cursor), applied to a
   tab-style nav link — used by the reader dashboard's "Live Session" item when there's
   no active session to jump back into. pointer-events:none backs up the disabled state
   so a stray click can't navigate even before any JS/href changes take effect. */
.tabs__link--disabled {
  opacity: .4;
  cursor: not-allowed;
  pointer-events: none;
}

/* ── Tables ───────────────────────────────────────────────── */
.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.88rem;
}

.data-table th {
  text-align: left;
  padding: 10px 14px;
  font-size: 0.78rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--text-muted);
  border-bottom: 1px solid var(--card-border);
}

.data-table td {
  padding: 12px 14px;
  border-bottom: 1px solid rgba(255,255,255,0.04);
  color: var(--text-muted);
  vertical-align: middle;
}

.data-table tr:last-child td { border-bottom: none; }
.data-table tr:hover td { background: rgba(255,255,255,0.02); }

.data-table td strong { color: var(--text); }

.traffic-page-path {
  font-size: 11px;
  color: var(--text-dim);
  margin-top: 2px;
}

/* ── Earnings totals strip ────────────────────────────────── */
.earnings-strip {
  display: flex;
  gap: 1px;
  background: var(--card-border);
  border-radius: var(--radius);
  overflow: hidden;
  margin-bottom: 28px;
}

.earnings-strip__item {
  flex: 1;
  background: var(--card-bg);
  padding: 16px 20px;
  text-align: center;
}

.earnings-strip__label {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--text-dim);
  margin-bottom: 4px;
}

.earnings-strip__value {
  font-size: 1.35rem;
  font-weight: 700;
  color: var(--gold);
}

/* ── Earnings date-range filter (Earnings tab, From/To + Filter/Clear) ──── */
.earnings-filter-form {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 20px;
  flex-wrap: wrap;
}

.earnings-filter-form__field {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 0.85rem;
  color: var(--text-dim);
}

/* Overrides .form-control's own width:100% — these inputs sit inline next to
   their label text in the desktop row, not stretched to fill it. */
.earnings-filter-form__field input {
  width: auto;
}

/* Mobile-only day/month/year picker (see reader-dashboard.ejs) — hidden on desktop, where
   the plain native <input type="date"> above is used as-is. */
.earnings-filter-form__mobile-picker {
  display: none;
}

/* ── Details / accordion ──────────────────────────────────── */
details.accordion {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--radius-sm);
  margin-bottom: 8px;
  overflow: hidden;
}

details.accordion summary {
  padding: 12px 16px;
  cursor: pointer;
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 0.9rem;
  color: var(--text);
  list-style: none;
  user-select: none;
}

details.accordion summary::-webkit-details-marker { display: none; }

details.accordion summary::after {
  content: '›';
  font-size: 1.1rem;
  color: var(--text-dim);
  transition: transform .15s;
}

details.accordion[open] summary::after { transform: rotate(90deg); }

details.accordion .accordion-body {
  padding: 12px 16px 16px;
  border-top: 1px solid var(--card-border);
  font-size: 0.875rem;
  color: var(--text-muted);
  max-height: 280px;
  overflow-y: auto;
}

/* Non-interactive counterpart to details.accordion — same summary-row look, but for
   sessions outside the reader dashboard's 5-most-recent-total display limit, which have no
   message content to expand into. */
.accordion-static {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--radius-sm);
  margin-bottom: 6px;
  padding: 12px 16px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 0.85rem;
  color: var(--text);
}

/* ── Chat top bar ─────────────────────────────────────────── */
.chat-topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 14px 28px;
  border-bottom: 1.4px solid var(--gold);
  gap: 16px;
  flex-wrap: wrap;
}

.chat-topbar__identity {
  display: flex;
  align-items: center;
  gap: 12px;
}

.chat-topbar__avatar {
  width: 46px;
  height: 46px;
  border-radius: 12px;
  object-fit: cover;
  border: 2px solid var(--gold);
  flex-shrink: 0;
}

.chat-topbar__avatar--initials {
  background: rgba(83,74,183,0.35);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.15rem;
  font-weight: 600;
  color: var(--text);
}

.chat-topbar__label {
  display: flex;
  align-items: center;
  gap: 5px;
  font-size: 0.75rem;
  color: var(--gold);
  margin-bottom: 3px;
}

.chat-topbar__name {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--text);
  line-height: 1.2;
}

/* ── Live session status dot ───────────────────────────────── */
.chat-status-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
  background: var(--text-dim);
}

.chat-status-dot[data-status="active"] {
  background: var(--success);
  animation: status-dot-pulse 2s ease-in-out infinite;
}

.chat-status-dot[data-status="ended"] {
  background: var(--text-dim);
}

@keyframes status-dot-pulse {
  0%, 100% { opacity: 1; box-shadow: 0 0 0 0 rgba(143,203,74,0.5); }
  60%       { opacity: 0.9; box-shadow: 0 0 0 5px rgba(143,203,74,0); }
}

.chat-topbar__timer {
  display: none;
  align-items: center;
  gap: 6px;
  font-size: 0.88rem;
  color: var(--text-muted);
}

.chat-topbar__timer strong {
  font-size: 1.1rem;
  font-variant-numeric: tabular-nums;
  color: inherit;
  margin-left: 2px;
}

.chat-topbar__timer.is-timer-warning { color: var(--danger); }

/* ── Chat page ────────────────────────────────────────────── */
@keyframes waiting-pulse {
  0%, 100% { opacity: 1; }
  50%       { opacity: 0.3; }
}

.chat-body { display: flex; flex-direction: column; }

/* Starfield fixed-covers full viewport on the chat page */
.chat-body .starfield-layer { position: fixed; }

/* Flush header: remove margin only — border-bottom (var(--card-border)) stays as the faint divider */
.chat-body .topnav {
  margin-bottom: 0;
}

.chat-page {
  flex: 1;
  display: flex;
  flex-direction: column;
  width: 100%;
  padding: 12px 20px 20px;
  min-height: 0;
}

/* Two-column layout when a side panel is present */
.chat-columns {
  flex: 1;
  display: flex;
  gap: 20px;
  min-height: 0;
  align-items: stretch;
}

.chat-main {
  flex: 1;
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  border: 1.4px solid #FAC775;
  border-radius: var(--radius);
}

.chat-main.panel-gradient {
  border-radius: var(--radius);
}

.chat-main.panel-gradient .chat-panel {
  background: transparent;
  border-color: rgba(255,255,255,0.1);
}

/* Shared dark-purple background for all chat side panels */
.chat-side-panel {
  background: #150f24;
  border: 1.4px solid #FAC775;
  border-radius: var(--radius);
  overflow-y: auto;
}

/* Past sessions / extend side panel */
.chat-sidebar {
  width: 260px;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
  padding: 12px 14px;
  background: #150f24;
}

/* Right-panel cascade guard: the body's background-attachment:fixed gradient
   can produce a contrast-difference between left and right panels at runtime.
   This scoped two-class rule (specificity 0,2,0) with !important ensures the
   right panel background is definitively #150f24 regardless of any cascade
   collision introduced by future CSS changes. */
.chat-columns .chat-sidebar {
  background: #150f24 !important;
}

.chat-sidebar__heading {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: var(--text-dim);
  padding: 0 4px 6px;
  border-bottom: 1px solid var(--card-border);
  margin-bottom: 2px;
}

.transcript-link {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 10px 14px;
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--radius-sm);
  text-decoration: none;
  transition: border-color .15s, background .15s;
  cursor: pointer;
}

.transcript-link:hover {
  border-color: rgba(255,255,255,0.16);
  background: rgba(255,255,255,0.06);
}

.transcript-link__date {
  font-size: 0.82rem;
  color: var(--text);
  font-weight: 500;
}

.transcript-link__meta {
  font-size: 0.75rem;
  color: var(--text-dim);
  margin-top: 1px;
}

.transcript-link__icon {
  font-size: 0.75rem;
  color: var(--text-dim);
  flex-shrink: 0;
}

.chat-sidebar__list {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

/* Overflow items hidden until expanded */
.chat-sidebar__list .transcript-link.is-overflow {
  display: none;
}

/* Expanded state: fixed height, internal scroll, all items visible */
.chat-sidebar__list.is-expanded {
  max-height: 320px;
  overflow-y: auto;
  padding-right: 2px;
  scrollbar-width: thin;
  scrollbar-color: rgba(255,255,255,0.12) transparent;
}

.chat-sidebar__list.is-expanded .transcript-link.is-overflow {
  display: flex;
}

.chat-sidebar__more {
  margin-top: 2px;
}

/* Empty state when no past sessions exist */
.chat-sidebar__empty {
  font-size: 0.82rem;
  color: var(--text-dim);
  text-align: center;
  padding: 28px 12px;
  line-height: 1.6;
}

.chat-sidebar__empty p { color: var(--text-dim); margin: 0; }

/* ── Inline report panel (left column, reader/customer view) ── */
.chat-report-panel {
  width: 200px;
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 16px 14px;
  background: #150f24;
}

.chat-report-panel__heading {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: var(--text-dim);
  padding: 0 4px 6px;
  border-bottom: 1px solid var(--card-border);
  margin-bottom: 4px;
}

/* ── Mobile toggle button (report / side panel) — shared by chat.ejs and call.ejs.
   Hidden by default; shown only inside the mobile chat/call layout below. Fill
   reuses .msg-bubble--mine's exact dark purple ("my messages" bubble colour),
   with gold border/icon/text kept from the previous version. ── */
.mobile-panel-toggle {
  display: none;
  align-items: center;
  justify-content: center;
  gap: 5px;
  height: 32px;
  padding: 0 12px;
  border-radius: 20px;
  background: #211a31;
  border: 1px solid rgba(250,199,117,0.35);
  color: var(--gold);
  font-family: 'Poppins', 'Inter', system-ui, sans-serif;
  font-size: 0.78rem;
  font-weight: 600;
  cursor: pointer;
  flex-shrink: 0;
  white-space: nowrap;
  transition: background .15s, border-color .15s;
}
.mobile-panel-toggle i { font-size: 0.92rem; }
.mobile-panel-toggle:hover,
.mobile-panel-toggle:active { background: #2b2240; border-color: var(--gold); }

/* In-panel "Back" button for the mobile off-canvas drawers (Report/Extend/History), and
   the "back to readers"/"back to dashboard" link that replaces the Extend/History toggle
   once a session ends — both reuse .back-link's exact existing muted style. Hidden by
   default: on desktop these panels are static columns (nothing to "go back" from), and
   .back-link is defined later in this file with an unconditional display:inline-flex, so
   !important is needed on both rules here to reliably win that cascade regardless of
   which one a browser would otherwise apply last. */
.drawer-back-btn { display: none !important; }
@media (max-width: 768px) {
  .drawer-back-btn {
    display: inline-flex !important;
    background: none;
    border: none;
    padding: 0;
    font-family: 'Poppins', 'Inter', system-ui, sans-serif;
    cursor: pointer;
  }
}

/* Applied alongside .drawer-back-btn on the ended-session "back to readers" link while
   the session is still pending/active, so it stays hidden regardless of viewport width —
   .drawer-back-btn alone would already show it on mobile. Removed (via JS) once the
   session actually ends, at which point .drawer-back-btn's own mobile-only default takes
   back over. */
.ended-nav-hidden { display: none !important; }

.mobile-drawer-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(10,8,22,0.8);
  backdrop-filter: blur(4px);
  z-index: 205;
}
.mobile-drawer-backdrop.is-open { display: block; }

/* ── Mobile: chat + call screens ──────────────────────────────────────────────
   Below 768px, .chat-columns' two fixed-width side panels (200px report panel +
   260px sidebar) leave no room for the center chat/call panel — on mobile they
   become off-canvas drawers (slide in from their original edge, using the same
   dark backdrop treatment as .modal-overlay) opened via the toggle buttons
   above, so the center panel gets the full screen by default. Everything in
   this block is scoped to the media query — desktop layout is untouched. ── */
@media (max-width: 768px) {
  .mobile-panel-toggle { display: inline-flex; }

  .chat-report-panel,
  .chat-columns .chat-sidebar {
    position: fixed;
    top: 0;
    bottom: 0;
    width: 82%;
    max-width: 300px;
    z-index: 210;
    border-radius: 0;
    border-top: none;
    border-bottom: none;
    transition: transform .25s ease;
    box-shadow: 0 0 40px rgba(0,0,0,0.5);
  }

  .chat-report-panel {
    left: 0;
    border-left: none;
    transform: translateX(-100%);
  }

  .chat-columns .chat-sidebar {
    right: 0;
    border-right: none;
    transform: translateX(100%);
  }

  .chat-report-panel.is-open,
  .chat-columns .chat-sidebar.is-open {
    transform: translateX(0);
  }

  .chat-page { padding: 8px 10px 10px; }
  .chat-header { padding: 4px 10px 10px; }
  .chat-topbar { padding: 12px 14px; }
  .chat-input-bar { padding: 10px; }

  /* Compact, centered logo lockup on the chat/call screens only — scoped to
     .chat-body so the desktop-sized topnav on every other page (home, profile,
     dashboards, admin) is completely untouched. The brand link is taken out of
     normal flex flow and centered absolutely, so it can't be pushed off-row by
     the Home/Dashboard link's width, and the Home/Dashboard link — the only
     remaining flex item — naturally lands flush right, vertically centered by
     .topnav's own (unchanged) align-items:center. */
  .chat-body .topnav {
    padding: 10px 14px;
    justify-content: flex-end;
    align-items: center;
    gap: 10px;
    position: relative;
    min-height: 52px;
  }
  .chat-body .topnav__brand {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    /* Defensive: this is a left:50%+transform centering trick on a
       nowrap-content child (.rr-logo__wordmark) — its un-transformed box
       could in principle extend past the viewport on very narrow screens.
       Capping it keeps that geometrically impossible regardless of content. */
    max-width: calc(100vw - 24px);
    overflow: hidden;
  }
  .chat-body .rr-logo { gap: 8px; }
  .chat-body .rr-logo__leaf { width: 32px; height: 30px; }
  .chat-body .rr-logo__wordmark { font-size: 1.2rem; }
  .chat-body .rr-logo__tagline { display: none; }

  /* Give the report/extend pill buttons room: let the reader/customer name
     truncate with an ellipsis instead of squeezing the buttons illegibly.
     .chat-topbar__identity's un-shrinkable min-width:auto default (per
     flexbox spec) wasn't the only place this bit — the plain <div> wrapping
     __label/__name (chat.ejs's un-classed div holding both) is ALSO a flex
     item here and had no min-width:0 of its own, so its nowrap text content
     forced it (and everything downstream) to stay at full intrinsic width
     regardless of the ellipsis rules below — this is the actual root cause
     of the horizontal overflow/swipe on chat.ejs and call.ejs, since a long
     enough name pushed the whole .chat-topbar row past the viewport. */
  .chat-topbar__identity { min-width: 0; flex: 1 1 auto; }
  .chat-topbar__identity > div { min-width: 0; }
  .chat-topbar__name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .chat-header__title {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
    flex: 1 1 auto;
    font-size: 1.15rem;
  }
}

.chat-header {
  padding: 4px 0 14px;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}

.chat-header__title {
  font-size: 1.5rem;
  font-weight: 600;
  color: var(--text);
}

/* ── Customer waiting screen ─────────────────────────────── */
@keyframes spin-ring {
  to { transform: rotate(360deg); }
}

.chat-waiting {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 56px 24px;
}

.chat-waiting__ring {
  width: 52px;
  height: 52px;
  border: 3px solid rgba(250,199,117,0.14);
  border-top-color: var(--gold);
  border-radius: 50%;
  animation: spin-ring 0.95s linear infinite;
  margin-bottom: 28px;
}

.chat-waiting__reader {
  font-size: 1.65rem;
  font-weight: 600;
  color: var(--text);
  margin-bottom: 10px;
}

.chat-waiting__label {
  font-size: 0.95rem;
  color: var(--text-muted);
  margin: 0 0 8px;
}

.chat-waiting__hint {
  font-size: 0.82rem;
  color: var(--text-dim);
  margin: 0;
}

.chat-waiting__error-icon {
  font-size: 2.6rem;
  line-height: 1;
  margin-bottom: 20px;
  color: var(--danger);
}

.chat-waiting__actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  justify-content: center;
  margin-top: 24px;
}

/* ── Chat status strip ────────────────────────────────────── */
.chat-status {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 11px 16px;
  border-radius: var(--radius-sm);
  font-size: 0.88rem;
  margin-bottom: 12px;
}

.chat-status--pending {
  background: var(--purple-dim);
  border: 1px solid rgba(83,74,183,0.3);
  color: #c0baf0;
}

.chat-status--active {
  background: rgba(143,203,74,0.08);
  border: 1px solid rgba(143,203,74,0.2);
  color: var(--success);
}

.chat-status--ended {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  color: var(--text-muted);
}

.chat-status--error {
  background: rgba(240,138,138,0.1);
  border: 1px solid rgba(240,138,138,0.25);
  color: var(--danger);
}

.waiting-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: currentColor;
  animation: waiting-pulse 1.4s ease-in-out infinite;
  flex-shrink: 0;
}

/* ── Timer bar ────────────────────────────────────────────── */
.timer-bar {
  display: none;
  align-items: center;
  gap: 8px;
  padding: 9px 14px;
  background: rgba(143,203,74,0.08);
  border: 1px solid rgba(143,203,74,0.2);
  border-radius: var(--radius-sm);
  font-size: 0.88rem;
  color: var(--success);
  margin-bottom: 12px;
}

.timer-bar--warning {
  background: rgba(240,138,138,0.1);
  border-color: rgba(240,138,138,0.25);
  color: var(--danger);
}

/* ── Chat panel (messages + input as one card) ────────────── */
.chat-panel {
  flex: 1;
  display: flex;
  flex-direction: column;
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--radius);
  overflow: hidden;
  min-height: 320px;
}

.chat-messages {
  flex: 1;
  overflow-y: auto;
  padding: 20px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.msg-bubble {
  max-width: 72%;
  padding: 9px 14px;
  border-radius: 14px;
  font-size: 0.9rem;
  line-height: 1.5;
}

.msg-bubble--mine {
  align-self: flex-end;
  border-bottom-right-radius: 4px;
}

.msg-bubble--theirs {
  align-self: flex-start;
  border-bottom-left-radius: 4px;
}

/* Colours by viewer perspective: own messages dark purple, other person's messages gold */
.msg-bubble--mine {
  background: #211a31;
  color: #d9d2ea;
}

.msg-bubble--theirs {
  background: #FAC775;
  color: #2a1f08;
}

.msg-bubble--theirs .msg-bubble__meta {
  color: rgba(42,31,8,0.5);
}

.msg-bubble--preview {
  opacity: 0.6;
  border: 1.5px dashed #FAC775;
}

.msg-preview-label {
  font-size: 0.72rem;
  color: rgba(250, 199, 117, 0.6);
  align-self: flex-start;
  padding-left: 4px;
  margin-bottom: 3px;
}

.typing-dots {
  opacity: 0.65;
  font-style: italic;
}

.msg-bubble__meta {
  font-size: 0.72rem;
  color: rgba(255,255,255,0.4);
  margin-top: 3px;
}

/* Same size/spacing as a regular .msg-bubble (padding, border-radius, font-size, line-height)
   so it reads as a normal line of chat, not a small caption — just recoloured (darker purple,
   #150f24, the project's established "info bar/panel" darker-purple background — see
   CLAUDE.md) to distinguish it from either party's own bubble colour. Deliberately carries no
   timestamp in the live view (device-local time caused confusion); the transcript view (see
   reader-transcript.ejs / admin views) is where a proper UK-time timestamp belongs instead. */
.msg-system {
  align-self: center;
  max-width: 72%;
  padding: 9px 14px;
  border-radius: 14px;
  font-size: 0.9rem;
  line-height: 1.5;
  text-align: center;
  background: #150f24;
  color: var(--text);
}

.chat-input-bar {
  display: flex;
  gap: 8px;
  padding: 12px 16px;
  border-top: 1px solid var(--card-border);
  background: rgba(0,0,0,0.15);
}

.chat-input-bar .form-control { flex: 1; }

/* End-of-session CTA card — chat.ejs/call.ejs, shown in place of the removed input bar/call
   controls once a session (paid or free, chat or call, either role) has ended, so the main
   panel never goes blank. Same DOM node on desktop and mobile — the center panel is never
   drawer-ified like the side panels are (see the mobile media queries below), so no separate
   mobile rule is needed here. */
.session-ended-cta {
  text-align: center;
  padding: 28px;
  margin: 16px 20px 20px;
}
.session-ended-cta--hidden { display: none; }

/* ── Extension modal ──────────────────────────────────────── */
.modal-overlay {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(10,8,22,0.8);
  backdrop-filter: blur(4px);
  align-items: center;
  justify-content: center;
  z-index: 200;
}

.modal {
  background: #1e1834;
  border: 1px solid var(--card-border);
  border-radius: 14px;
  padding: 32px;
  min-width: 320px;
  max-width: 400px;
  text-align: center;
  box-shadow: 0 16px 64px rgba(0,0,0,0.6);
}

.modal h3 { color: var(--gold); margin-bottom: 8px; }
.modal p { margin-bottom: 16px; font-size: 0.9rem; }

.modal-options {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: center;
  margin-bottom: 16px;
}

/* ── Incoming-request overlay ────────────────────────────── */
@keyframes alertFlash {
  0%   { background: rgba(20,14,38,0.92); }
  100% { background: rgba(120,0,0,0.65); }
}

.incoming-overlay {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 9999;
  align-items: center;
  justify-content: center;
  animation: alertFlash .45s infinite alternate;
}

.incoming-card {
  background: #1e1834;
  border: 1px solid rgba(240,138,138,0.3);
  border-radius: 16px;
  padding: 44px 52px;
  text-align: center;
  min-width: 320px;
  box-shadow: 0 0 60px rgba(220,50,0,0.7);
}

.incoming-card__icon { font-size: 2.8rem; margin-bottom: 8px; }

.incoming-card h2 { color: var(--text); font-size: 1.4rem; margin-bottom: 6px; }

.incoming-card__name { font-size: 1.3rem; font-weight: 700; color: var(--gold); margin: 10px 0 20px; }

.incoming-card__countdown {
  font-size: 3.6rem;
  font-weight: 700;
  color: var(--danger);
  line-height: 1;
}

.incoming-card__bar-wrap {
  margin: 10px auto 24px;
  width: 220px;
  background: rgba(255,255,255,0.1);
  border-radius: 4px;
  height: 8px;
  overflow: hidden;
}

.incoming-card__bar {
  background: var(--danger);
  height: 100%;
  width: 100%;
}

/* ── Missed badge ─────────────────────────────────────────── */
.missed-badge {
  position: fixed;
  bottom: 16px; left: 16px;
  background: rgba(240,138,138,0.15);
  border: 1px solid rgba(240,138,138,0.35);
  color: var(--danger);
  padding: 8px 16px;
  border-radius: 20px;
  font-size: 0.85rem;
  z-index: 100;
}

/* ── Admin reader photo in table ─────────────────────────── */
.admin-photo {
  width: 52px; height: 52px;
  object-fit: cover;
  border-radius: 6px;
  display: block;
}

/* ── Auth pages ───────────────────────────────────────────── */
.auth-wrap {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}

.auth-box {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: 14px;
  padding: 40px;
  width: 100%;
  max-width: 420px;
}

.auth-box__brand {
  display: flex;
  justify-content: center;
  margin-bottom: 12px;
}

.auth-box__brand .rr-logo__leaf {
  width: 44px;
  height: 41px;
}

.auth-box__brand .rr-logo__wordmark {
  font-size: 1.75rem;
}

.auth-box__brand .rr-logo__tagline {
  font-size: 0.6rem;
  letter-spacing: 0.18em;
}

.auth-box__subtitle {
  text-align: center;
  font-size: 0.9rem;
  color: var(--text-muted);
  margin-bottom: 32px;
}

/* Small role-identifying label under the logo on role-specific auth pages (currently just
   the reader login) — "muted" is achieved via size/letter-spacing, not opacity: gold is
   never rendered at anything but full strength anywhere on the site (see CLAUDE.md). */
.auth-box__portal-label {
  text-align: center;
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: 20px;
}

.auth-box h2 {
  text-align: center;
  margin-bottom: 28px;
  font-size: 1.25rem;
  color: var(--text);
}

/* ── Top-up pack options ──────────────────────────────────── */
.pack-option {
  display: block;
  cursor: pointer;
}

.pack-option input[type="radio"] { display: none; }

.pack-option__card {
  position: relative;
  background: var(--card-bg);
  border: 2px solid var(--card-border);
  border-radius: var(--radius);
  padding: 20px 16px 18px;
  transition: border-color .15s, background .15s;
  height: 100%;
  box-sizing: border-box;
}

.pack-option input[type="radio"]:checked + .pack-option__card {
  border-color: var(--gold);
  background: var(--gold-dim);
}

.pack-option__card--popular {
  border-color: var(--gold);
}

.pack-badge {
  position: absolute;
  top: -1px;
  right: -1px;
  background: var(--gold);
  color: #1a1430;
  font-size: 0.62rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  padding: 3px 8px;
  border-radius: 0 8px 0 6px;
}

.pack-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
  margin-bottom: 16px;
}

.pack-option__price {
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--gold);
  margin-bottom: 8px;
}

.pack-option__example {
  font-size: 0.75rem;
  color: var(--text-dim);
  margin-bottom: 6px;
  line-height: 1.4;
}

.pack-option__desc {
  font-size: 0.78rem;
  color: var(--text-muted);
  line-height: 1.6;
  white-space: nowrap;
}

/* ── Discount pricing ─────────────────────────────────────── */
.discount-notice {
  display: flex;
  align-items: center;
  gap: 8px;
  background: rgba(250,199,117,0.1);
  border: 1px solid rgba(250,199,117,0.28);
  border-radius: var(--radius);
  padding: 10px 14px;
  color: var(--gold);
  font-size: 0.85rem;
  font-weight: 500;
  margin-bottom: 16px;
}

.pack-option__price-orig {
  text-decoration: line-through;
  color: var(--text-dim);
  font-size: 0.85em;
  font-weight: 400;
  margin-right: 5px;
}

.pack-option__price-disc {
  color: var(--gold);
}

/* ── New-customer promo strip (homepage) ─────────────────── */
.new-customer-strip {
  display: flex;
  justify-content: center;
  padding: 10px 24px 14px;
}

.promo-cta {
  flex-direction: column;
  gap: 3px;
  padding: 14px 36px;
  line-height: 1.2;
  text-align: center;
  height: auto;
}

.promo-cta__headline {
  font-size: 1.05rem;
  font-weight: 700;
  display: block;
}

.promo-cta__sub {
  font-size: 0.8rem;
  font-weight: 400;
  opacity: 0.82;
  display: block;
}

/* ── Availability radio options ──────────────────────────── */
.radio-option {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 14px 16px;
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--radius-sm);
  margin-bottom: 10px;
  cursor: pointer;
  transition: border-color .15s;
}

.radio-option:hover { border-color: rgba(255,255,255,0.15); }

.radio-option input[type="radio"]:checked ~ * { color: var(--text); }

.radio-option__label { font-weight: 600; font-size: 0.9rem; color: var(--text); }
.radio-option__desc  { font-size: 0.82rem; color: var(--text-muted); margin-top: 2px; }

/* ── Availability toggle switches (reader dashboard: independent chat/call) ── */
.toggle-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 14px 16px;
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--radius-sm);
  margin-bottom: 10px;
}

.toggle-row__label {
  display: flex;
  align-items: center;
  gap: 8px;
  font-weight: 600;
  font-size: 0.9rem;
  color: var(--text);
}

.toggle-switch {
  position: relative;
  width: 44px;
  height: 24px;
  flex-shrink: 0;
  border: none;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
  cursor: pointer;
  transition: background .15s;
}

.toggle-switch::before {
  content: '';
  position: absolute;
  top: 3px;
  left: 3px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--text-dim);
  transition: transform .15s, background .15s;
}

.toggle-switch--on {
  background: var(--gold-dim);
}

.toggle-switch--on::before {
  transform: translateX(20px);
  background: var(--gold);
}

/* ── Divider ──────────────────────────────────────────────── */
.divider {
  border: none;
  border-top: 1px solid var(--card-border);
  margin: 28px 0;
}

/* ── Monospace credential display ────────────────────────── */
.cred-box {
  background: rgba(0,0,0,0.25);
  border: 1px solid var(--card-border);
  border-radius: var(--radius-sm);
  padding: 20px 24px;
  font-family: 'Courier New', monospace;
  font-size: 1.1rem;
  color: var(--gold);
  letter-spacing: .04em;
  word-break: break-all;
  margin: 16px 0;
}

/* ── Back link ────────────────────────────────────────────── */
.back-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 0.88rem;
  color: var(--text-muted);
  margin-bottom: 28px;
}

.back-link:hover { color: var(--text); }

/* ── Utility ──────────────────────────────────────────────── */
.text-gold   { color: var(--gold); }
.text-muted  { color: var(--text-muted); }
.text-danger { color: var(--danger); }
.text-success{ color: var(--success); }
.mt-0 { margin-top: 0; }
.mb-0 { margin-bottom: 0; }
.mb-8 { margin-bottom: 8px; }
.mb-16{ margin-bottom: 16px; }
.mb-24{ margin-bottom: 24px; }
.flex { display: flex; }
.flex-center { display: flex; align-items: center; }
.gap-8  { gap: 8px; }
.gap-12 { gap: 12px; }
.gap-16 { gap: 16px; }

/* ── Site footer ──────────────────────────────────────────── */
.site-footer {
  /* background governed by the shared .topnav, .site-footer rule above */
  border-top: 1.4px solid #FAC775;
  padding: 32px 40px 20px;
  margin-top: auto;
}

.site-footer__inner {
  max-width: 1200px;
  margin: 0 auto;
}

.site-footer__groups {
  display: flex;
  gap: 56px;
  flex-wrap: wrap;
  margin-bottom: 20px;
}

.site-footer__group-label {
  display: block;
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: #FAC775;
  margin-bottom: 10px;
}

.site-footer__group nav {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.site-footer__group nav a {
  font-size: 0.82rem;
  color: #9e98c0;
  transition: color 0.15s;
}

.site-footer__group nav a:hover {
  color: #FAC775;
  opacity: 1;
}

.site-footer__copy {
  font-size: 0.75rem;
  color: #6a638a;
  border-top: 1px solid rgba(255,255,255,0.06);
  padding-top: 16px;
}

/* ── Cookie notice banner ──────────────────────────────────────────────────
   Informational, not a consent gate — hidden until cookie-banner.ejs's own script adds
   .is-visible (avoids a flash of the banner before its localStorage-dismissed check runs).
   #150f24 background matches this codebase's established dark info-bar/panel value (see
   .trust-strip's own comment on the same value) at full opacity, since this sits on top of
   arbitrary page content and needs to read clearly rather than blend with what's under it. */
.cookie-banner {
  display: none;
  position: fixed;
  /* left/right:0 + an explicit calc() width, rather than left/right:16px with width left to
     resolve as 'auto' — a fixed-position flex element with left AND right set but no
     explicit width doesn't reliably compute width as "fill the gap between them" (confirmed
     via computed styles: width was resolving to ~100% of the viewport regardless of `right`,
     producing a negative auto margin and a real ~10px overflow past the right edge on every
     mobile width tested). An explicit width removes that ambiguity; margin:auto still does
     the centering, same as before. */
  left: 0;
  right: 0;
  bottom: 16px;
  z-index: 215;
  width: calc(100% - 32px);
  max-width: 640px;
  margin: 0 auto;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  background: #150f24;
  border: 1px solid var(--card-border);
  border-radius: var(--radius);
  padding: 14px 18px;
  box-shadow: 0 4px 24px rgba(0,0,0,0.4);
}

.cookie-banner.is-visible {
  display: flex;
}

.cookie-banner__text {
  margin: 0;
  font-size: 0.85rem;
  color: var(--text-muted);
}

.cookie-banner__text a {
  color: var(--gold);
}

.cookie-banner__actions {
  display: flex;
  flex-shrink: 0;
  gap: 8px;
}

.cookie-banner__btn {
  flex-shrink: 0;
  white-space: nowrap;
  background: var(--gold);
  color: #150f24;
  border: none;
  border-radius: 999px;
  padding: 9px 22px;
  font-family: 'Poppins', sans-serif;
  font-weight: 600;
  font-size: 0.85rem;
  cursor: pointer;
}

.cookie-banner__btn:hover {
  opacity: 0.85;
}

.cookie-banner__btn--ghost {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  color: var(--text-muted);
}

@media (max-width: 768px) {
  .cookie-banner {
    bottom: 10px;
    width: calc(100% - 20px);
    flex-direction: column;
    align-items: stretch;
    text-align: center;
    padding: 14px 16px;
  }
  .cookie-banner__actions {
    /* Base rule is display:flex with no direction override, so this stayed a ROW —
       .cookie-banner__btn's own flex-shrink:0 (base rule) then refused to let two
       width:100% buttons share that row, pushing the second one (Accept) off-screen.
       Stacking vertically here (matching .cookie-banner's own column layout one level up)
       gives each button its own row, so width:100% has an unambiguous single-child row to
       fill — same fix approach the brief suggested, and consistent with the outer banner's
       existing mobile stacking rather than fighting flex-shrink at each width tested. */
    flex-direction: column;
    width: 100%;
  }
  .cookie-banner__btn {
    width: 100%;
  }
}

@media (max-width: 600px) {
  .site-footer { padding: 28px 20px 16px; }
  .site-footer__groups { gap: 28px; }
}

/* ── Checkout consent checkboxes ──────────────────────────── */
.consent-checks {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin: 20px 0 12px;
}

.consent-check {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  cursor: pointer;
  font-size: 0.88rem;
  color: var(--text-muted);
  line-height: 1.45;
}

.consent-check input[type="checkbox"] {
  -webkit-appearance: none;
  appearance: none;
  width: 17px;
  height: 17px;
  min-width: 17px;
  border: 1.5px solid rgba(250,199,117,0.45);
  border-radius: 3px;
  background: #1a1430;
  margin-top: 1px;
  cursor: pointer;
  transition: border-color 0.15s, background 0.15s;
}

.consent-check input[type="checkbox"]:checked {
  background: #FAC775;
  border-color: #FAC775;
  background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 16 16' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M3 8.5l3 3 7-7' stroke='%231a1430' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round' fill='none'/%3E%3C%2Fsvg%3E");
  background-size: 11px;
  background-repeat: no-repeat;
  background-position: center;
}

.consent-check a { color: var(--gold); }

/* Static page content area. Prose spacing rules below exist because of this file's own
   global reset (`*, *::before, *::after { margin: 0; padding: 0; }`) — without them, the
   admin-authored HTML rendered here (h2/p/ul/li from content_pages, e.g. Terms &
   Conditions) would run together with no visual separation at all. h2/p/a/strong already
   pick up their colour/weight from the global typography rules earlier in this file; only
   spacing is added here. */
.static-page-content {
  max-width: 780px;
  padding-bottom: 40px;
}

.static-page-content h2 { margin: 32px 0 12px; }
.static-page-content h2:first-child { margin-top: 0; }
.static-page-content p { margin-bottom: 14px; line-height: 1.7; }
.static-page-content ul,
.static-page-content ol { margin: 0 0 14px 22px; }
.static-page-content li { margin-bottom: 6px; line-height: 1.7; }

/* ── My Account page ──────────────────────────────────────── */
.account-tabs {
  display: flex;
  gap: 4px;
  margin-bottom: 28px;
  border-bottom: 1.4px solid #FAC775;
  padding-bottom: 0;
  flex-wrap: wrap;
}

.account-tab {
  display: inline-block;
  padding: 9px 20px;
  font-size: 0.88rem;
  font-weight: 600;
  color: var(--text-dim);
  text-decoration: none;
  border-radius: 6px 6px 0 0;
  border: 1px solid transparent;
  transition: color .15s, background .15s;
  position: relative;
  top: 1px;
}

.account-tab:hover { color: var(--text); background: rgba(255,255,255,0.04); }

.account-tab--active {
  color: var(--gold);
  background: rgba(250,199,117,0.08);
  border-color: #FAC775 #FAC775 transparent;
}

/* Favourite heart button on reader cards */
.fav-form { position: absolute; top: 8px; right: 8px; z-index: 2; margin: 0; }

.fav-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  border: none;
  background: rgba(14,12,22,0.72);
  cursor: pointer;
  font-size: 1.1rem;
  line-height: 1;
  color: rgba(255,255,255,0.55);
  transition: background .15s, color .15s;
  backdrop-filter: blur(4px);
}

.fav-btn:hover { background: rgba(14,12,22,0.92); color: #FAC775; }
.fav-btn--active { color: #FAC775; }

/* Favourites grid (simpler than main reader grid) */
.fav-readers-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 16px;
  margin-bottom: 32px;
}

.fav-reader-card {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: 10px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

/* This card is the one place a single reader photo genuinely switches shape at different
   breakpoints (4:3 landscape desktop -> 1:1 square mobile, see the mobile override below),
   so it needs BOTH saved positions and must pick whichever one matches the shape currently
   rendered. --photo-pos-card/--photo-pos-profile are set inline per-<img> (see account.ejs)
   from the reader's saved photoPositionCard/photoPositionProfile; object-position here reads
   the "card" one to match this rule's 4:3 shape, and the mobile override below switches to
   the "profile" one to match its 1:1 shape. */
.fav-reader-card__photo {
  width: 100%;
  aspect-ratio: 4/3;
  object-fit: cover;
  object-position: var(--photo-pos-card, 50% 50%);
  display: block;
}

.fav-reader-card__photo-placeholder {
  width: 100%;
  aspect-ratio: 4/3;
  background: rgba(255,255,255,0.04);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 2.5rem;
  color: var(--text-dim);
}

.fav-reader-card__body {
  padding: 12px 14px 14px;
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.fav-reader-card__name {
  font-weight: 700;
  font-size: 0.95rem;
}

.fav-reader-card__status {
  font-size: 0.75rem;
  font-weight: 600;
}

.fav-reader-card__status--online { color: var(--success); }
.fav-reader-card__status--busy   { color: var(--warning, #f5c842); }
.fav-reader-card__status--offline{ color: var(--text-dim); }

.fav-reader-card__rate {
  font-size: 0.78rem;
  color: var(--text-dim);
  margin-top: auto;
  padding-top: 6px;
}

.fav-reader-card__actions {
  display: flex;
  gap: 6px;
  margin-top: 8px;
}

/* Account balance ledger */
.ledger-entry {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 12px 16px;
  border-bottom: 1px solid var(--card-border);
  gap: 12px;
}

.ledger-entry:last-child { border-bottom: none; }

.ledger-entry__label { font-size: 0.88rem; flex: 1; }
.ledger-entry__date  { font-size: 0.78rem; color: var(--text-dim); white-space: nowrap; }
.ledger-entry__amount { font-weight: 700; font-size: 0.92rem; white-space: nowrap; }
.ledger-entry__amount--credit { color: var(--success); }
.ledger-entry__amount--debit  { color: var(--text-dim); }

/* SMS settings form in account */
.sms-settings-card { padding: 24px; }
.sms-opt-row {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-top: 12px;
}
.sms-opt-row input[type="checkbox"] { accent-color: var(--gold); width: 16px; height: 16px; }

.sms-settings-card--highlight {
  animation: sms-card-flash 2.2s ease-out;
}
@keyframes sms-card-flash {
  0%   { border-color: var(--gold); box-shadow: 0 0 0 3px var(--gold-dim); }
  100% { border-color: var(--card-border); box-shadow: none; }
}

/* ── My Account page (mobile) ────────────────────────────────────────────
   account.ejs has none of this session's other mobile treatment (no
   .home-body, no fixed header/hamburger) — its .topnav and .account-tabs
   are both plain in-flow elements. Rather than adopt the .home-body fixed
   header + bottom-nav stack wholesale (this page has no bottom-nav/hamburger
   of its own to match it), the fix stays in normal document flow: the nav
   is tightened so it wraps cleanly, the wallet-chip's hover tooltip (which
   gets stuck open after a tap on touch browsers, since :hover is the only
   thing gating it) is disabled outright since there's no reliable way to
   dismiss it on mobile, and the tab row is a 2x2 grid — all 4 tabs visible
   at once, no horizontal scroll and no risk of tab text landing on top of
   the heading or table below it. */
@media (max-width: 768px) {
  .account-body .topnav {
    padding: 14px 16px;
    gap: 8px;
  }
  .account-body .topnav__links {
    gap: 8px 14px;
    font-size: 0.85rem;
  }
  .account-body .wallet-chip:hover .wb-tip {
    display: none;
  }
  .account-body h1 {
    font-size: 1.5rem;
  }
  .account-body .account-tabs {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
    margin-bottom: 20px;
    border-bottom: none;
  }
  .account-body .account-tab {
    top: 0;
    text-align: center;
    padding: 10px 8px;
    font-size: 0.8rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    border: 1px solid var(--card-border);
    border-radius: var(--radius-sm);
  }
  .account-body .account-tab--active {
    border-color: #FAC775;
    background: rgba(250,199,117,0.08);
  }
  /* Swap Balance Report and Past Readings' visual position in the 2x2 grid
     via `order` rather than reordering the actual <a> tags in account.ejs —
     desktop's tab row has no `order` set, so it keeps the original
     Past Readings / Balance Report / My Reviews / My Favourites DOM order
     untouched; only this mobile grid is affected. All four get an explicit
     order so the untouched pair (My Reviews, My Favourites) don't shift
     ahead of the swapped pair (default order:0 would otherwise beat 1/2). */
  .account-body .account-tabs .account-tab:nth-child(1) { order: 2; } /* Past Readings */
  .account-body .account-tabs .account-tab:nth-child(2) { order: 1; } /* Balance Report */
  .account-body .account-tabs .account-tab:nth-child(3) { order: 3; } /* My Reviews */
  .account-body .account-tabs .account-tab:nth-child(4) { order: 4; } /* My Favourites */

  /* Past Readings: swap the clipped 8-column table for stacked cards
     showing the exact same per-session data (see .readings-mobile-list in
     account.ejs) — nothing hidden, just re-laid-out so Cost etc. are never
     cut off without horizontal scrolling. */
  .account-body .readings-table-wrap {
    display: none;
  }
  .account-body .readings-mobile-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
  }
  .account-body .reading-card {
    background: var(--card-bg);
    border: 1px solid var(--card-border);
    border-radius: var(--radius);
    padding: 14px 16px;
  }
  .account-body .reading-card__top {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    margin-bottom: 4px;
  }
  .account-body .reading-card__date {
    font-weight: 700;
    font-size: 0.85rem;
  }
  .account-body .reading-card__cost {
    font-weight: 700;
    color: var(--gold);
    font-size: 0.95rem;
  }
  .account-body .reading-card__reader a {
    color: var(--text);
    font-size: 0.92rem;
    text-decoration: none;
  }
  .account-body .reading-card__meta {
    font-size: 0.8rem;
    color: var(--text-dim);
    margin-top: 4px;
  }
  .account-body .reading-card__dot {
    margin: 0 4px;
  }
  .account-body .reading-card__footer {
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
    margin-top: 10px;
    padding-top: 10px;
    border-top: 1px solid var(--card-border);
    font-size: 0.82rem;
  }
  .account-body .reading-card__note {
    color: var(--text-dim);
  }

  /* Balance Report summary boxes: "Current Balance"/"Last Topped Up" used
     flex:1 in a wrapping row, which let them settle at different sizes
     depending on how many landed per row at phone widths. Stacking them
     one-per-row guarantees identical width, height and padding for both
     regardless of content. */
  .account-body .balance-summary-row {
    flex-direction: column;
  }
  .account-body .balance-summary-box {
    flex: none !important;
    width: 100%;
    box-sizing: border-box;
  }

  /* My Favourites: same compact horizontal-card spirit as the homepage's
     mobile .reader-card (small fixed photo + info alongside it) rather
     than a full-width photo dominating the screen before any info shows. */
  .account-body .fav-readers-grid {
    grid-template-columns: 1fr;
    gap: 10px;
  }
  .account-body .fav-reader-card {
    flex-direction: row;
    align-items: stretch;
  }
  .account-body .fav-reader-card__photo,
  .account-body .fav-reader-card__photo-placeholder {
    width: 84px;
    aspect-ratio: 1;
    flex-shrink: 0;
  }
  /* 1:1 here (unlike the 4:3 desktop rule above) — switch to the reader's saved "profile"
     shape position, not "card", to match. */
  .account-body .fav-reader-card__photo {
    object-position: var(--photo-pos-profile, 50% 50%);
  }
  .account-body .fav-reader-card__photo-placeholder {
    font-size: 1.6rem;
  }
  .account-body .fav-reader-card__body {
    padding: 10px 12px;
    gap: 3px;
  }
  .account-body .fav-reader-card__name {
    font-size: 0.9rem;
  }
  .account-body .fav-reader-card__rate {
    margin-top: 2px;
    padding-top: 0;
  }
  .account-body .fav-reader-card__actions {
    margin-top: auto;
  }
}

/* ── Wallet top-up page (mobile) ─────────────────────────────────────────
   The package boxes were a fixed 2-column grid; .pack-option__desc's
   white-space:nowrap text ("~24 min at £1.50/min — Tier 1") doesn't fit in
   a ~155px column at phone widths, so the grid track — and the whole page
   — was forced wider than the viewport, clipping the right column and
   throwing off everything below it (including the consent checkboxes).
   Single column removes the width pressure; letting the desc text wrap
   removes it at the source too. */
@media (max-width: 768px) {
  .topup-body .pack-grid {
    grid-template-columns: 1fr;
  }
  .topup-body .pack-option__desc {
    white-space: normal;
  }
  .topup-body .consent-checks {
    margin-top: 22px;
  }
}

/* ── Reader dashboard page (mobile) ──────────────────────────────────────
   Same class of bug as .account-body above: reader-dashboard.ejs has none
   of this session's other mobile treatment, so its .topnav and .tabs (the
   site-wide "Live Session / Availability / Rates / Earnings / Customer
   History" nav, shared verbatim with admin-sessions.ejs — hence scoping
   everything here to .reader-dashboard-body rather than editing .tabs
   itself) were both plain in-flow/unwrapped elements. 5 tabs in an
   unwrapped flex row (.tabs's base rule has no wrap or overflow handling)
   ran wider than the viewport, which — exactly like .topup-body .pack-grid
   above — forced the whole page wider than the viewport rather than just
   that one row, which is what actually dragged the Chat/Call toggle
   switches (and everything else) out to the right where they needed a
   horizontal scroll to reach, even though the toggle row itself was never
   too wide on its own. Same fix shape as .account-body's 2x2 tab grid:
   switch to a wrapping grid (3 columns here, for 2 rows of 5 items) so
   nothing overflows in the first place. */
@media (max-width: 768px) {
  /* .topnav's own base rule (near the top of this file) paints it with its OWN
     independent copy of var(--bg-gradient), sized against topnav's own (short)
     box rather than the page's. On desktop this goes unnoticed — body's
     background is position:fixed (viewport-relative) and topnav sits right at
     the viewport's own top edge, so the two independently-computed gradients
     land on very similar colors there and the seam is invisible. On mobile,
     body's background is now pinned to exactly one viewport height (see the
     mobile body rule near the top of this file), which makes ITS top-of-page
     region render the gradient's real, distinct bloom-to-dark shape — right
     next to topnav's own separately-scaled copy of the same formula, evaluated
     over a box maybe 70px tall instead of a full screen height. Two different
     sizes of the same gradient never line up, which is the visible seam.
     Making topnav's background transparent here lets body's single gradient
     (already correctly sized/positioned) show through underneath it instead,
     so header and body read as one continuous background — matching the
     desktop reference. Safe specifically because the reader dashboard's
     mobile topnav is a normal in-flow element, not position:fixed (unlike
     home.ejs's mobile header, which intentionally keeps its own opaque
     background since content scrolls beneath a FIXED header there — do not
     make that one transparent too, it needs to stay opaque). */
  .reader-dashboard-body .topnav {
    background: transparent;
    padding: 14px 16px;
    gap: 8px;
    flex-wrap: wrap;
  }
  .reader-dashboard-body .topnav__links {
    gap: 8px 14px;
    font-size: 0.85rem;
    flex-wrap: wrap;
  }
  .reader-dashboard-body h1 {
    font-size: 1.5rem;
  }
  /* Live Session (nth-child(1), always first in reader-dashboard.ejs's DOM
     order) gets its own full-width row on top; the other four tabs
     (Availability/Rates/Earnings/Customer History) fall naturally into a
     2x2 grid below it — no DOM reordering needed, just grid-column on the
     one item. */
  .reader-dashboard-body .tabs {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 8px;
    margin-bottom: 20px;
    border-bottom: none;
  }
  .reader-dashboard-body .tabs__link {
    text-align: center;
    padding: 10px 6px;
    font-size: 0.76rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    border: 1px solid var(--card-border);
    border-radius: var(--radius-sm);
    margin-bottom: 0;
  }
  .reader-dashboard-body .tabs__link:nth-child(1) {
    grid-column: 1 / -1;
  }
  .reader-dashboard-body .tabs__link--active {
    border-color: #FAC775;
    background: rgba(250,199,117,0.08);
  }
  /* Toggle rows: force-wrap and constrain to the container's own width so
     the switch itself can never be pushed past the visible edge, whether
     or not anything upstream still tries to overflow. */
  .reader-dashboard-body .toggle-row {
    width: 100%;
    box-sizing: border-box;
    flex-wrap: nowrap;
  }
  .reader-dashboard-body .toggle-row__label {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  /* Earnings table (5 columns) doesn't fit 375px-ish widths even with a contained
     horizontal scroll (an earlier stopgap) — swapped for the same stacked-card pattern
     already used for Past Readings (see .readings-mobile-list): nothing hidden or clipped,
     no scrolling needed, just re-laid-out (see .earnings-mobile-list in reader-dashboard.ejs). */
  .reader-dashboard-body .earnings-table-wrap {
    display: none;
  }
  .reader-dashboard-body .earnings-mobile-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
  }
  .reader-dashboard-body .earnings-card {
    background: var(--card-bg);
    border: 1px solid var(--card-border);
    border-radius: var(--radius);
    padding: 14px 16px;
  }
  .reader-dashboard-body .earnings-card__top {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    margin-bottom: 4px;
  }
  .reader-dashboard-body .earnings-card__date {
    font-weight: 700;
    font-size: 0.85rem;
  }
  .reader-dashboard-body .earnings-card__earned {
    font-weight: 700;
    color: var(--gold);
    font-size: 0.95rem;
  }
  .reader-dashboard-body .earnings-card__customer {
    font-size: 0.92rem;
  }
  .reader-dashboard-body .earnings-card__meta {
    font-size: 0.8rem;
    color: var(--text-dim);
    margin-top: 4px;
  }
  .reader-dashboard-body .earnings-card__dot {
    margin: 0 4px;
  }
  /* Earnings strip (Today/Week/Month/All-time): an earlier brief allowed a
     contained horizontal scroll here as a stopgap. This brief asks for zero
     scrolling instead — a 2x2 grid fits all four boxes at once. Desktop's
     base .earnings-strip (flex row) is untouched. */
  .reader-dashboard-body .earnings-strip {
    display: grid;
    grid-template-columns: 1fr 1fr;
  }
  /* .earnings-strip is also reused by the Payouts tab for its single
     "Outstanding" stat — with only one grid item, the 2-column grid above
     leaves it stuck in the first cell with a blank cell beside it. This
     modifier (added only to the Payouts tab's markup, not Earnings') forces
     a single full-width column instead, without touching the Earnings tab's
     own unmodified 2x2 grid. */
  .reader-dashboard-body .earnings-strip--single {
    grid-template-columns: 1fr;
  }
  .reader-dashboard-body .earnings-strip__item {
    padding: 14px 10px;
  }
  .reader-dashboard-body .earnings-strip__value {
    font-size: 1.15rem;
  }
  /* Earnings date-range filter: two date pickers + Filter/Clear buttons
     side-by-side (desktop's flex-wrap row) don't all fit one line at phone
     widths — stack each control on its own full-width row instead of
     letting flex-wrap break them at an unpredictable point.
     Each field's caption + input also switch from side-by-side to stacked
     (caption above, input below), guaranteeing both fields the same width
     and left edge regardless of caption text length. */
  .reader-dashboard-body .earnings-filter-form {
    flex-direction: column;
    align-items: stretch;
  }
  .reader-dashboard-body .earnings-filter-form__field {
    flex-direction: column;
    align-items: stretch;
    gap: 4px;
    min-width: 0;
  }
  /* The native <input type="date"> is replaced by the 3-select day/month/year
     picker below on mobile — its internal day/month/year segments have a
     browser-enforced minimum rendering width that no amount of width/
     min-width/box-sizing CSS (on the input itself or any ancestor) can
     shrink below, confirmed by a full containment-chain audit after CSS-only
     fixes repeatedly failed to stop it overflowing the viewport. It stays in
     the DOM (just hidden) since it's still the actual field the form submits
     — see the sync script in reader-dashboard.ejs. */
  .reader-dashboard-body .earnings-filter-form__native {
    display: none;
  }
  .reader-dashboard-body .earnings-filter-form__mobile-picker {
    display: flex;
    gap: 8px;
    width: 100%;
  }
  .reader-dashboard-body .earnings-filter-form__mobile-picker select {
    flex: 1;
    min-width: 0;
    width: auto;
  }
  .reader-dashboard-body .earnings-filter-form button,
  .reader-dashboard-body .earnings-filter-form a {
    width: 100%;
    min-width: 0;
    box-sizing: border-box;
  }
}

.earnings-table-wrap {
  overflow: hidden;
}

/* ── Reader profile page ─────────────────────────────────── */

/* Full-page starfield wrapper */
.profile-page {
  position: relative;
  isolation: isolate;
  background-color: #0e0c16;
  min-height: 100vh;
  margin-top: -12px;
}

/* The -12px margin above is a desktop-only spacing correction (pulls this flush against
   .topnav there). On mobile, .home-body's padding-top:97px already reserves exactly the
   space needed below the fixed header+stat bar — this same -12px then eats 12px back into
   that reserved band, so .profile-hero visibly overlapped/clipped under the fixed stat bar.
   Cancelling it here (mobile-only) restores the full 97px gap; desktop's own -12px above is
   untouched. */
@media (max-width: 768px) {
  .home-body .profile-page {
    margin-top: 0;
  }
}

/* Hero banner */
.profile-hero {
  border-bottom: 1.5px solid #FAC775;
  min-height: 110px;
  display: flex;
  align-items: flex-end;
  justify-content: flex-end;
  padding: 18px 24px;
  box-sizing: border-box;
  position: relative;
  z-index: 1;
}

.profile-hero__info { text-align: right; }

.profile-hero__name {
  font-size: 26px;
  font-weight: 600;
  color: #fff;
  font-family: 'Poppins', sans-serif;
  line-height: 1.2;
}

.profile-hero__cats {
  font-size: 12.5px;
  color: #cfc6e8;
  margin-top: 3px;
}

/* Grid layout */
.profile-grid {
  display: grid;
  grid-template-columns: 210px 1fr;
  gap: 14px;
  padding: 14px;
  max-width: 1100px;
  margin: 0 auto;
  align-items: start;
  position: relative;
  z-index: 1;
}

/* Left sidebar column */
.profile-sidebar {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

/* Desktop only — sticky sidebar. The topnav is only ever position:fixed inside the
   mobile (max-width:768px) media query, so no fixed-header offset needs accounting for
   here; top is just visual breathing room from the viewport edge.
   No JS needed for the "release before the footer" behaviour: .profile-grid's
   align-items:start (above) already sizes each grid item to its own content height
   instead of stretching it to match the row, so the row's height is naturally set by
   .profile-main (the longer column). That row is .profile-sidebar's containing block,
   so position:sticky can only push it down as far as that row's bottom edge — i.e. it
   releases and resumes normal flow right as .profile-main's content (and therefore the
   footer below the whole grid) runs out, never overlapping the footer. */
@media (min-width: 769px) {
  .profile-sidebar {
    position: sticky;
    top: 90px;
  }
}

/* LEFT card — unified sidebar card */
.profile-card-left {
  background: #150f24;
  border: 1px solid #FAC775;
  border-radius: 12px;
  padding: 18px;
  text-align: center;
}

.profile-card-left .profile-label {
  justify-content: center;
}

.profile-rating-block {
  cursor: pointer;
  border-radius: var(--radius-sm);
  padding: 6px 8px;
  margin: -6px -8px;
  transition: background 0.15s ease;
}
.profile-rating-block:hover { background: rgba(250, 199, 117, 0.06); }
.profile-rating-block:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }

/* RIGHT cards — all right-column cards */
.profile-card-right {
  border: 1px solid #FAC775;
  border-radius: 12px;
  padding: 18px;
}

/* Internal divider between sidebar sections */
.profile-card-divider {
  border: none;
  border-top: 0.5px solid #2a2238;
  margin: 14px -18px;
}

/* Circular photo overlapping up into hero */
.profile-photo-wrap {
  display: flex;
  justify-content: center;
  margin-top: -80px;
  margin-bottom: 10px;
}

.profile-photo {
  width: 160px;
  height: 160px;
  border-radius: 50%;
  border: 2.5px solid #FAC775;
  object-fit: cover;
  display: block;
  background: #150f24;
  flex-shrink: 0;
}

.profile-photo--initials {
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 3.5rem;
  font-weight: 700;
  color: #FAC775;
  font-family: 'Poppins', sans-serif;
}

/* Rate display */
.profile-rate-val {
  font-size: 20px;
  font-weight: 600;
  color: #FAC775;
  font-family: 'Poppins', sans-serif;
  line-height: 1.1;
}

.profile-rate-val span { font-size: 12px; font-weight: 400; color: var(--text-muted); }
.profile-rate-sub { font-size: 10px; color: var(--text-muted); margin-top: 2px; margin-bottom: 12px; }

/* Full-width buttons in sidebar */
.profile-btn {
  width: 100%;
  padding: 8px 10px;
  border-radius: 6px;
  font-size: 12.5px;
  font-weight: 600;
  font-family: 'Poppins', sans-serif;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  display: block;
  box-sizing: border-box;
  margin-bottom: 8px;
  line-height: 1.4;
}

.profile-btn:last-child { margin-bottom: 0; }

/* Free-reading gift line — a muted secondary line inside the existing Chat now/Call now
   button (no new button, no layout change when absent). The button's own background is
   gold (#FAC775, see .profile-btn--chat/--call above), so the line uses the button's dark
   text color at reduced opacity for "muted" rather than --gold itself, which would be
   invisible against a gold background; the ti-gift icon stays fully opaque as the one gold-
   adjacent accent, matching the brief's "small gold gift icon" while still being legible. */
.profile-btn__gift-line {
  display: block;
  margin-top: 3px;
  font-size: 10px;
  font-weight: 700;
  color: rgba(21, 15, 36, 0.72);
  letter-spacing: 0.01em;
}
.profile-btn__gift-line i { color: #150f24; margin-right: 2px; font-size: 11px; }

/* Free-reading gift line — homepage/browse grid card variant. Same treatment as
   .profile-btn__gift-line above (muted dark text on the button's own gold background, gold-
   adjacent ti-gift icon), but scaled down for this much smaller card button, and paired with
   .btn--sm--gift below, which shrinks the main "Chat now"/"Call now" label slightly ONLY on a
   button that actually carries this second line — every other card's button (i.e. almost all
   of them, since eligibility is narrow) is completely unaffected, so the card grid never grows
   uneven row heights over a handful of eligible cards mixed in with ineligible ones.
   .btn/.btn--chat is display:inline-flex (unlike .profile-btn, which is plain display:block) —
   a flex row lays every child out side-by-side regardless of the child's own `display`, so the
   gift line needs flex-wrap + flex-basis:100% (the standard "force a line break inside a flex
   row" technique) to actually land on its own line under "Chat now" instead of beside it.
   Padding/line-height/font-size below were tuned live against the actual rendered button
   (getBoundingClientRect) until this button's height matched a plain single-line "Chat now"
   button (~32px) to within sub-pixel rounding — not a guess, confirmed both ways side by side
   in-browser (see the reader-profile.ejs gift-line brief this extends). */
.reader-card__actions .btn--sm.btn--sm--gift {
  font-size: 0.68rem;
  padding: 5px 6px;
  line-height: 1.1;
  flex-wrap: wrap;
  row-gap: 0;
}
.reader-card__gift-line {
  flex-basis: 100%;
  margin-top: 0;
  font-size: 8px;
  font-weight: 700;
  color: rgba(21, 15, 36, 0.72);
  letter-spacing: 0.01em;
  white-space: nowrap;
}
.reader-card__gift-line i { color: #150f24; margin-right: 1px; font-size: 9px; }

/* Call matches Chat exactly (same gold fill) rather than the previous gold-outline
   treatment, so the pair reads as matched buttons, not two different styles. */
.profile-btn--chat,
.profile-btn--call     { background: #FAC775; color: #150f24; border: none; }
.profile-btn--chat-off,
.profile-btn--call-off { background: #6f6790; color: #150f24; border: none; cursor: not-allowed; }

/* Gold section label used in both card types */
.profile-section-heading {
  font-size: 18px;
}

.profile-label {
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: #FAC775;
  font-family: 'Poppins', sans-serif;
  display: flex;
  align-items: center;
  gap: 6px;
  margin-bottom: 12px;
}

/* Rating section */
.profile-avg-num {
  font-size: 26px;
  font-weight: 600;
  color: #FAC775;
  font-family: 'Poppins', sans-serif;
  line-height: 1;
  margin-bottom: 5px;
}

/* Save reader section */
.profile-save-icons { display: flex; justify-content: center; gap: 32px; }

.profile-save-btn {
  background: none;
  border: none;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  font-family: 'Poppins', sans-serif;
  text-decoration: none;
  padding: 0;
}

.profile-save-btn .ti { font-size: 1.55rem; }
.profile-save-btn--on  .ti { color: #FAC775; }
.profile-save-btn--off .ti { color: #6f6790; }
.profile-save-btn span { font-size: 10px; color: var(--text-muted); }

/* Back link below sidebar */
.profile-back-link {
  display: block;
  text-align: center;
  font-size: 11.5px;
  color: var(--text-muted);
  text-decoration: none;
}

.profile-back-link:hover { color: var(--gold); }

/* Right column */
.profile-main { display: flex; flex-direction: column; gap: 12px; }

/* Specialisms card two-column layout */
.profile-spec-card-inner { display: block; }

.profile-spec-card-inner--split {
  display: flex;
  gap: 0;
  align-items: flex-start;
}

.profile-spec-col {
  flex: 1;
  min-width: 0;
}

.profile-media-col {
  border-left: 0.5px solid rgba(250, 199, 117, 0.25);
  padding-left: 20px;
  min-width: 160px;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.profile-media-label {
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: #FAC775;
  font-family: 'Poppins', sans-serif;
  text-align: center;
  margin-bottom: 14px;
}

.profile-media-boxes {
  display: flex;
  gap: 12px;
  justify-content: center;
  flex-wrap: wrap;
}

.media-intro-box {
  width: 72px;
  height: 72px;
  background: #150f24;
  border: 1px solid #FAC775;
  border-radius: 10px;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: background 0.2s ease, box-shadow 0.2s ease;
}

.media-intro-box:hover {
  background: #2a1f4e;
  box-shadow: 0 0 10px rgba(250, 199, 117, 0.2);
}

.media-intro-box__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
}

.media-intro-box__inner .ti {
  color: #FAC775;
  font-size: 1.75rem;
  line-height: 1;
}

.media-intro-box__label {
  font-size: 11px;
  color: #cfc6e8;
  font-family: 'Poppins', sans-serif;
  white-space: nowrap;
}

/* Video modal */
.media-modal {
  display: none;
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.88);
  z-index: 1000;
  align-items: center;
  justify-content: center;
}

.media-modal__inner {
  position: relative;
  max-width: 90vw;
  max-height: 85vh;
}

.media-modal__close {
  position: absolute;
  top: -36px;
  right: 0;
  background: none;
  border: none;
  color: #FAC775;
  font-size: 2rem;
  cursor: pointer;
  line-height: 1;
  padding: 0;
}

.media-modal__video {
  display: block;
  max-width: 90vw;
  max-height: 80vh;
  border-radius: 10px;
}

/* Specialisms grid */
.profile-spec-grid { display: flex; flex-wrap: wrap; gap: 10px; }

.profile-spec-item {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: 13px;
  color: #e0d8f0;
}

.specialism-chip {
  display: flex;
  align-items: center;
  gap: 7px;
  background: radial-gradient(circle at 25% 30%, #3c3489 0%, #1a1430 70%);
  border: 0.5px solid rgba(250, 199, 117, 0.35);
  border-radius: 8px;
  padding: 8px 14px;
  font-size: 13px;
  color: #e0d8f0;
}

.specialism-chip .ti { color: #FAC775; font-size: 1rem; }

/* About text on gradient background */
.profile-about-text {
  font-size: 0.9rem;
  color: #e0d8f0;
  line-height: 1.75;
  margin: 0;
}

.profile-qa-question {
  font-weight: 600;
  font-family: 'Poppins', sans-serif;
  color: #FAC775;
  margin: 0 0 6px 0;
}

.profile-qa-answer {
  color: #c9c1e0;
  line-height: 1.7;
}

/* Review summary block inside reviews card */
.profile-review-summary {
  display: flex;
  gap: 20px;
  align-items: flex-start;
  flex-wrap: wrap;
  margin-bottom: 16px;
  padding-bottom: 16px;
  border-bottom: 0.5px solid rgba(250,199,117,0.2);
}

.profile-review-summary__score { text-align: center; flex-shrink: 0; }

.profile-review-summary__avg {
  font-size: 28px;
  font-weight: 600;
  color: #FAC775;
  font-family: 'Poppins', sans-serif;
  line-height: 1;
  margin-bottom: 4px;
}

/* Breakdown bar rows */
.profile-breakdown { flex: 1; min-width: 160px; }

.profile-breakdown-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 6px;
}

.profile-breakdown-row:last-child { margin-bottom: 0; }

.profile-breakdown-bar-wrap {
  flex: 1;
  background: rgba(255,255,255,0.1);
  border-radius: 4px;
  height: 7px;
  overflow: hidden;
}

.profile-breakdown-bar-fill {
  height: 100%;
  background: #FAC775;
  border-radius: 4px;
}

/* Nested review cards */
.profile-review-card {
  background: #150f24;
  border: 0.5px solid #FAC775;
  border-radius: 10px;
  padding: 12px 14px;
  margin-bottom: 10px;
}

.profile-review-card:last-child { margin-bottom: 0; }

.profile-review-card__top {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 10px;
  margin-bottom: 6px;
}

.profile-review-card__meta { text-align: right; font-size: 11px; color: var(--text-dim); white-space: nowrap; }

.profile-review-card__verified {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 11px;
  color: #7fd9a8;
  margin-bottom: 6px;
}
.profile-review-card__verified i { font-size: 14px; }

.pg-hidden-review { display: none; }

.profile-review-pagination {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 14px;
}
.profile-review-page-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 32px;
  height: 32px;
  padding: 0 10px;
  border-radius: 999px;
  border: 1px solid rgba(250, 199, 117, 0.25);
  background: transparent;
  color: var(--text-muted);
  font-family: inherit;
  font-size: 12.5px;
  line-height: 1;
  cursor: pointer;
}
.profile-review-page-btn:hover { border-color: var(--gold); color: var(--text); }
.profile-review-page-btn.is-active {
  background: var(--gold);
  border-color: var(--gold);
  color: #150f24;
  font-weight: 600;
}
.profile-review-page-btn--nav {
  min-width: 32px;
  padding: 0;
  font-size: 14px;
}
.profile-review-page-btn:disabled {
  opacity: 0.35;
  cursor: default;
}
.profile-review-page-btn:disabled:hover {
  border-color: rgba(250, 199, 117, 0.25);
  color: var(--text-muted);
}
.profile-review-page-ellipsis {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 20px;
  height: 32px;
  color: var(--text-dim);
  font-size: 12.5px;
  user-select: none;
}

/* Responsive */
@media (max-width: 680px) {
  .profile-grid { grid-template-columns: 1fr; }
  .profile-hero { min-height: 80px; padding: 12px 16px; }
  .profile-hero__name { font-size: 20px; }
  .profile-spec-item { width: 100%; }
  .profile-photo-wrap { margin-top: -70px; }
}

/* The -70px above (and desktop's own -80px) is a deliberate "avatar overlapping the cover
   banner" effect — at this narrower hero height (min-height:80px, set just above) that
   negative margin pulls the photo up far enough to visibly bleed into the hero's
   name/star-sign text rather than just grazing its bottom edge. Same (0,1,0)-specificity
   selector as the -70px rule above, later in the source, so it wins across the full
   ≤768px range this brief scopes to (not just ≤680px) without needing !important —
   margin-top:0 keeps the photo fully inside its own card, starting right at the card's own
   18px top padding, no overlap into the hero at all.
   Photo reshaped from a 190px circle to a bigger rounded-rectangle per this brief:
   width:100% fills the card's own content width (~326px at 390px viewport, ~256px at the
   narrowest 320px phones tested — comfortably bigger than the old fixed 190px circle at
   every width), aspect-ratio:1 keeps it square rather than an arbitrary rectangle, and
   Changed back to a circle (border-radius:50%, matching every other circular avatar on the
   site — .reader-card__photo, .profile-photo on desktop, etc.) per a later brief, while
   keeping this same bigger width:100%/aspect-ratio:1 sizing — only the corner rounding
   reverted, not the dimensions.
   .profile-photo--initials (the no-photo fallback) shares this same element/size — its own
   font-size is scaled up to match so the letter doesn't look small and lost in the bigger
   box. */
@media (max-width: 768px) {
  .profile-back-link {
    display: none;
  }
  .profile-photo-wrap {
    margin-top: 0;
  }
  .profile-photo {
    width: 100%;
    height: auto;
    aspect-ratio: 1;
    border-radius: 50%;
  }
  .profile-photo--initials {
    font-size: 6rem;
  }

  /* Name/star-sign line: right-aligned on desktop (text-align:right + the hero's own
     justify-content:flex-end above), switched to left per an earlier brief's approved
     mockup.
     Height shrunk ~30% per a later brief: the 680px rule below sets min-height:80px +
     padding:12px 16px (name font-size:20px there too) — this same (0,1,0)-specificity
     selector, later in the source, overrides all three for the full ≤768px range this
     brief scopes to, same technique already established for the photo/margin overrides
     above. min-height 80px → 56px is exactly 30%; padding and font-sizes were reduced more
     modestly (measured via rendering the actual hero, including a long-name case, to
     confirm neither line wraps awkwardly or crowds the box edges at the smaller size) so
     the box doesn't end up feeling cramped just to hit an exact percentage on every value. */
  .profile-hero {
    justify-content: flex-start;
    min-height: 56px;
    padding: 8px 16px;
  }
  .profile-hero__info {
    text-align: left;
  }
  .profile-hero__name {
    font-size: 16px;
  }
  .profile-hero__cats {
    font-size: 11px;
  }

  /* Specialisms + "Get to know me" back to sharing ONE outer .profile-card-right box
     (a prior brief had split them into two independently-boxed sections; this reverts
     that per a later brief while keeping the stacked column layout, since side-by-side
     columns don't fit phone widths). .profile-card-right keeps its normal border/radius/
     padding/gradient (no neutralization needed here), .profile-spec-card-inner--split
     just stacks its children vertically inside that one box, and the per-column
     border/background/padding + divider are removed so there's a single shared border
     instead of two boxes with a gap. Internal content (chips, audio/video intro boxes)
     is untouched — only the surrounding container styling changed. */
  .profile-spec-card-inner--split {
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
  }
  .profile-media-col {
    border-left: none;
    padding-left: 0;
    min-width: 0;
  }
}

/* ══════════════════════════════════════════════════════════════════════════
   Mobile homepage redesign — everything below is scoped under .home-body,
   a class that exists ONLY on home.ejs's <body>. readers.ejs, readers-calls.ejs
   and readers-chats.ejs all render the same shared .reader-card/.cat-bar
   markup via the readers-grid partial, so every rule here is written as
   `.home-body .thing` specifically to keep this change homepage-only, per
   the brief — those other pages are completely unaffected. The compound
   selector also gives each rule higher specificity than the equivalent
   unscoped/global rule it needs to override (e.g. .filter-bar-search's
   existing `display:none` at 900px), so none of this needs !important or
   careful placement relative to older rules elsewhere in the file.
   ══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 768px) {

  /* ── 1. Header: fixed, logo LEFT (bigger), hamburger button RIGHT ───────
     Now position:fixed so it stays put while scrolling (uses the existing
     shared .topnav gradient rule already applied site-wide, per CLAUDE.md —
     no new gradient class needed). The old inline account-links row
     (.topnav__links: wallet chip / Top Up / My Account / Logout, or Sign
     In / Register) is hidden on mobile now that all of that is reachable
     from the new hamburger menu below — replaced by a single hamburger
     button. Per this brief, the header no longer forces a fixed height —
     vertical padding restored instead, so the bigger logo below grows the
     bar modestly (~60px) rather than being squeezed into a fixed 52px.
     Hamburger button is untouched (per this brief's "don't touch the
     hamburger icon"), still 36px, and simply centers within the now-taller
     row via the existing align-items:center. */
  .home-body .topnav {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    z-index: 220;
    box-sizing: border-box;
    padding: 10px 14px;
    justify-content: space-between;
    align-items: center;
    gap: 6px;
    /* Promotes this fixed element to its own GPU compositing layer, independent of the
       scrolling content layer beneath it — without this, mobile WebKit/Blink can fall
       behind repainting fixed elements during fast/momentum scrolling, producing a brief
       flash of whatever's underneath (here: body's own gradient) before it catches up.
       transform:translateZ(0) is the traditional trigger for this; will-change:transform
       is the modern equivalent hint — both included since browser support for which one
       alone is reliable varies. Applied to all three fixed mobile bars (topnav, trust-strip,
       mobile-bottom-nav) that share this pattern. */
    will-change: transform;
    transform: translateZ(0);
    backface-visibility: hidden;
    /* .topnav's own base border-bottom (a faint 1px rgba(255,255,255,0.08)
       line, unrelated to the gold dividers) added 1px to this element's
       total rendered height, pushing it to 61px against the trust bar's
       fixed top:60px. Sitting 1px into the header's higher stacking
       context (z-index 220 vs the trust bar's 219), that extra pixel
       visually painted over the top of the trust bar's gold border-top,
       diluting it — that was the "thinner" gold line from the brief, not
       an actual differing thickness value. Removing this border (it's not
       a visible divider on mobile anyway — the trust bar's own gold
       border-top is now the real one) fixes both the 1px height mismatch
       and the visual dilution in one move. */
    border-bottom: none;
  }
  .home-body .topnav__links {
    display: none;
  }
  .home-body .rr-logo { gap: 6px; }
  .home-body .rr-logo__leaf { width: 42px; height: 40px; }
  .home-body .rr-logo__wordmark { font-size: 1.42rem; }
  .home-body .rr-logo__tagline { display: none; }
  .home-body .mobile-hamburger-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    flex-shrink: 0;
    background: none;
    border: 1.4px solid #FAC775;
    border-radius: var(--radius-sm);
    color: #FAC775;
    font-size: 1.3rem;
    cursor: pointer;
  }
  /* Icon font glyphs aren't always vertically centered within their own
     line box by default (font metrics vary) — flexing the <i> itself with
     line-height:1 guarantees the bars sit dead-center in the button
     regardless of the icon font's baseline, fixing the alignment brief
     item 2 called out. */
  .home-body .mobile-hamburger-btn i {
    display: flex;
    align-items: center;
    justify-content: center;
    line-height: 1;
  }

  /* ── 2. Top search box + All/Call/Chat tabs: removed on mobile ─────────
     Both are now redundant with the fixed bottom nav (Search icon covers
     search, Chat/Call icons cover the type tabs), so both are fully hidden
     at the top of the page. The search input stays in its original DOM
     position — tapping the bottom nav's Search icon still reveals the same
     element via the same .is-open class, but it's now pulled out of the
     page flow with position:fixed and anchored directly above the bottom
     nav instead of rendering inline where the tabs used to be. */
  /* This wrapper has no visible children left on mobile now — .filter-bar
     is hidden below, .filter-bar-search's default (closed) state is
     display:none, and .filter-bar-trust is already hidden site-wide at
     this breakpoint (see the unscoped rule near .filter-bar-trust's base
     styles). Collapse its spacing so it doesn't leave a dead gap at the
     top of the page. !important is required here — the element carries an
     inline style="padding-top:4px; margin-bottom:12px" in home.ejs, and
     inline styles always beat external stylesheet rules regardless of
     selector specificity or media query. Without !important this rule was
     silently never applying: the un-collapsed 16px gap let the page's own
     background gradient (--bg-gradient, lighter purple near the top of
     the page) show through as a thin stray strip directly below the fixed
     trust bar — this is the "extra lighter-purple banner" from the brief,
     not a distinct element, just this uncollapsed inline-styled gap. */
  .home-body .filter-bar-wrap {
    padding-top: 0 !important;
    margin-bottom: 0 !important;
  }
  .home-body .filter-bar {
    display: none;
  }
  .home-body .filter-bar-row {
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
  }
  .home-body .filter-bar-search {
    display: none;
  }
  /* bottom must match .mobile-bottom-nav's actual rendered height, not a guess — measured
     at 58.08px (padding + border-top + content, safe-area-inset-bottom 0 in the test
     environment), not the previous 62px, which left a ~4px gap between this reveal and the
     nav below it. env(safe-area-inset-bottom, 0px) is repeated here (matching the nav's own
     bottom padding formula) so the two stay flush on notched devices too, where the nav
     grows taller by that same inset. */
  .home-body .filter-bar-search.is-open {
    display: block;
    position: fixed;
    left: 0;
    right: 0;
    bottom: calc(58px + env(safe-area-inset-bottom, 0px));
    z-index: 221;
    width: auto;
    margin: 0;
    background: #150f24;
    border-top: var(--mobile-gold-divider);
    padding: 2px 14px;
  }
  /* Vertical padding taken down further (wrapper 6px→2px, input 13px→8px, measured via
     rendering the actual reveal) for a total ~42px reveal height — a 30% reduction from the
     previous 60px, per this brief. Padding alone got there without touching font-size (left
     at 0.95rem, per the brief's stated preference): the input itself still lands at 37px
     tall, comfortably tappable across its full width. */
  .home-body .reader-search-input {
    width: 100%;
    padding: 8px 18px 8px 42px;
    font-size: 0.95rem;
  }
  .home-body .filter-bar-search .ti-search {
    left: 26px;
    font-size: 18px;
  }

  /* ── 3. Sticky bar below header: gold line / dark strip / gold line ─────
     Structural treatment (fixed at top of header height, dark purple
     #150f24 background already the strip's base color, gold border-top +
     border-bottom) is kept from the previous brief. Content is now the
     approved compact 4-column layout — icon stacked above short text, no
     separators — via a new .mobile-quickstats block (added in home.ejs)
     rather than restyling .trust-strip__item, since that element's layout
     (icon beside two-line text) doesn't fit an icon-above-text stack
     cleanly. Both .mobile-browse-heading and the original .trust-strip__item
     row (desktop's real content) are hidden on mobile — untouched on
     desktop.

     Root cause of the persisting thickness mismatch, found by inspecting
     actual computed styles + paint stacking rather than just reading
     source: the two lines were declared with an IDENTICAL but FRACTIONAL
     width (1.4px). A non-integer CSS px border has no exact physical-pixel
     mapping, so the browser anti-aliases it — and because the two borders
     sit at different absolute Y positions (different cumulative rounding
     of preceding heights/padding), each one can rasterize with a
     different blend of full/partial pixels, making functionally-identical
     CSS render visibly differently on a real device. There was also a
     genuine SECOND competing rule at the bottom boundary: .readers-section
     (immediately below the trust bar in normal flow, unrelated to this
     session, its border unscoped from desktop) declares its own
     border-top: 1.4px solid #FAC775 at that same exact Y position,
     stacking on top of .trust-strip's border-bottom. Both fixes below:
     (1) a single custom property, --mobile-gold-divider, is now the only
     declared value for both lines, using a whole-pixel width (2px) so it
     rasterizes identically regardless of position, and (2) the
     .readers-section duplicate is suppressed on mobile so only one rule
     ever draws the bottom line. */
  .home-body .trust-strip {
    display: flex;
    position: fixed;
    top: 60px;
    left: 0;
    right: 0;
    z-index: 219;
    height: 37px;
    box-sizing: border-box;
    margin: 0;
    padding: 0 10px;
    justify-content: center;
    border-top: var(--mobile-gold-divider);
    border-bottom: var(--mobile-gold-divider);
    /* GPU layer promotion — see .home-body .topnav's identical rule above for why. */
    will-change: transform;
    transform: translateZ(0);
    backface-visibility: hidden;
  }
  /* border-top:none (below) removed the border that used to block margin
     collapse here — with nothing left to contain it, #browse-readers'
     margin-top (added in a later brief for heading spacing) was collapsing
     straight through this element's top edge and pushing its own
     background + starfield down, exposing a flat strip of the page's
     lighter --bg-gradient in the gap between the gold line and where the
     starfield actually started. overflow:hidden establishes a block
     formatting context, containing the child's margin inside this element
     instead of letting it escape upward — the starfield/background now
     starts flush against the gold line, and the heading still keeps its
     20px gap (just correctly inside the section now, not collapsed out of
     it). */
  .home-body .readers-section {
    border-top: none;
    overflow: hidden;
    /* Base rule is padding:0 24px 60px — the negative margin:-24px above
       (unchanged, base rule) cancels .page-wrap--wide's own 24px padding
       so this section's background/border can bleed edge-to-edge, then
       this padding re-insets the actual CONTENT (reader cards). Reducing
       just the left/right values to 14px (explicit properties, not the
       shorthand, so top/bottom stay at their base 0/60px) widens every
       card by 20px total without touching the section's own edge-to-edge
       background/border — 14px matches the fixed header's own side
       padding (.home-body .topnav's padding: 10px 14px), the one
       consistent side-inset value already established among this page's
       fixed mobile elements. */
    padding-left: 14px;
    padding-right: 14px;
    /* .trust-strip (position:fixed, z-index:219 on mobile) is a DOM descendant of this
       section, which the base (desktop+mobile) rule gives isolation:isolate — a stacking
       context that .starfield-layer's z-index:-1 nebula/stars NEED to stay sunk behind this
       section's own content (reader cards etc.) instead of escaping past it. Without that
       containment, the starfield's z-index:-1 has nothing scoping it to this section, so it
       escapes all the way to the page root — rendering behind <body>'s own static
       radial-gradient background (--bg-gradient) instead of behind THIS section's much
       darker background, i.e. invisible, replaced by what looks like a flat purple slab.
       (This was tried as isolation:auto in an earlier fix for the item below and broke the
       starfield — auto is wrong; isolation must stay isolate.)
       The trust-bar problem this isolation causes: because it makes THIS WHOLE section a
       stacking context with the default z-index:auto, it ties with later siblings that are
       ALSO positioned+isolated (.wtt-section, "Create your account in three easy steps" —
       also position:relative + isolation:isolate) for paint order, and DOM order breaks that
       tie in .wtt-section's favour once it scrolls up to overlap the fixed trust bar's screen
       band — the trapped trust bar can't out-rank it locally since the tie is decided one
       level up, between the two SECTIONS. Giving this section an explicit z-index (any value
       > the implicit 0 of .wtt-section's auto) settles that tie in this section's favour
       instead — the entire section (and everything correctly layered within its own
       preserved local stacking context, trust bar included, still on top locally via its own
       z-index:219) now wins against every later sibling, for the whole scroll range, while
       the starfield stays correctly contained. Verified both together: full-page scroll
       (every ~70px step, top to bottom) keeps the trust bar on top, and the starfield's
       twinkling stars are visible behind the reader cards again. */
    isolation: isolate;
    z-index: 1;
  }
  .home-body .mobile-browse-heading {
    display: none;
  }
  .home-body .trust-strip__item {
    display: none;
  }
  .home-body .mobile-quickstats {
    display: flex;
    justify-content: space-between;
    align-items: center;
    width: 100%;
  }
  .home-body .mobile-quickstats__item {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    flex: 1;
    min-width: 0;
  }
  .home-body .mobile-quickstats__item i {
    color: var(--gold);
    font-size: 0.95rem;
    line-height: 1;
  }
  .home-body .mobile-quickstats__item span {
    font-size: 8.5px;
    line-height: 1.1;
    color: var(--text);
    white-space: nowrap;
  }

  /* ── Hero tagline banner: removed on mobile ─────────────────────────────
     This is the .promo-banner block ("Wondering what they're really
     thinking? / Get clarity in minutes — real readers online now." + the
     10%-off register CTA) — the closest match on this page to the brief's
     paraphrased "Get clarity in seconds" hero text. Removed entirely on
     mobile, not replaced; display:none takes its own margin-bottom out of
     the flow too, so no dead gap is left between the trust bar and the
     "Browse our talented readers" heading below it. */
  .home-body .promo-banner {
    display: none;
  }

  /* "Browse our talented readers" was sitting almost flush against the
     trust bar's bottom gold line (0px margin-top), and its inline
     style="margin-bottom:0" meant zero space below it too, crowding the
     reader cards — spacing was lopsided (all above, none below).
     margin-bottom needs !important since inline styles always beat
     external stylesheet rules regardless of selector specificity; without
     it this rule would silently never apply, same class of bug as the
     .filter-bar-wrap fix earlier this session. Both values match (20px)
     so the heading now sits evenly between the stat bar above and the
     reader list below. */
  .home-body #browse-readers {
    margin-top: 20px;
    margin-bottom: 20px !important;
  }

  /* ── 4. Category chips row: removed on mobile ───────────────────────────
     Superseded by the "Skills" item in the new fixed bottom nav below,
     which opens a sheet listing these same 23 categories (same data, same
     filterByCategory() call). Desktop keeps the chips row exactly as-is —
     this only ever hides it under .home-body, i.e. the homepage, at
     ≤768px. (This replaces an earlier brief's horizontal-scroll treatment
     for the same row, now moot since the row itself is hidden.) */
  .home-body .cat-bar {
    display: none;
  }

  /* ── 5. Reader cards: single column, horizontal (photo left, info right) ─
     .readers-grid's existing 1100/840/580/360px breakpoints already step
     the column count down as the viewport narrows, but none of them force
     a single column until 360px — .home-body's higher specificity here
     forces 1 column for the whole ≤768px mobile range without needing to
     touch those existing (still-desktop-relevant, e.g. a narrowed desktop
     browser window) rules at all. */
  .home-body .readers-grid {
    grid-template-columns: 1fr;
  }
  /* min-height (not a fixed height) is deliberate: it gives every card the
     same floor, sized for the worst case at the CURRENT shortBio limit
     (125 chars, enforced server-side via <textarea maxlength="125"> in the
     admin form — lowered from 150 in a later brief after the 150-char
     ceiling this value was originally sized against turned out to leave
     unused blank space below the bio once the limit shrank). Cards with
     shorter or no bio simply reserve the same space and stay visually
     uniform; if content is ever unexpectedly longer than planned for
     (e.g. a reader grandfathered in with a pre-125-limit bio), the card
     grows rather than clipping — .reader-card's overflow:hidden (base
     rule) only exists to round the photo's corners and never constrains
     height itself, so this can't clip.
     205px, down from the original 222px: re-measured the worst-case
     natural content height with a real maxed-out 125-char bio substituted
     into several real reader cards at this same 390px width (audio/video
     intro badges present or not, rate badge present or not) — every
     combination bottomed out at the same 200.53px natural body height
     (125 chars needs at most 4 wrapped lines at this font-size/width,
     confirmed across 9 varied realistic bio styles including deliberately
     awkward word-length patterns — down from the 5-6 lines the old
     150-char ceiling could reach). 205px keeps the same small ~4-5px
     safety buffer for cross-browser font-rendering variance as before. */
  .home-body .reader-card {
    flex-direction: row;
    align-items: stretch;
    min-height: 205px;
  }
  /* Widened from 92px so the text column (below) is narrower, wrapping the bio onto more
     lines and letting natural content height close the remaining gap above the buttons —
     rather than pushing min-height/padding further, which previous fixes already tried.
     120px is the narrowest width at which BOTH real non-trivial shortBio rows in the
     database (147 and 144 chars, same two rows the min-height above was sized against)
     wrap to 5 lines instead of 4 at this same 390px reference width, measured by rendering
     the actual .reader-card partial with the real row content: card height stays at the
     222px min-height floor (no reader-card__actions gap grows below content) and the
     gapBelowContent shrinks from 26-29px to 8-11px for both. Below 120px neither reaches 5
     lines; going wider only helps once a bio is long enough to reach a 6th line, which
     neither real row does until ~160px — past that point the text column (244px → 216px
     here) starts feeling cramped for no further gap benefit. A reader with a very short bio
     (e.g. the real 10-char row in the database) still shows a visible gap at any photo
     width, since a one-line bio can't be made to wrap further — accepted tradeoff, not
     fixable without reintroducing fixed-height/padding guesswork this brief moved away
     from. */
  .home-body .reader-card__photo-wrap {
    width: 120px;
    flex-shrink: 0;
  }
  /* This row layout (align-items:stretch on .home-body .reader-card above, no explicit
     height/aspect-ratio here) stretches the photo to the row's full height instead of
     preserving the base rule's 4:3 — confirmed by measurement to render ~120x203px
     (ratio ~0.59; was ~120x220px/0.55 before the card shrank for the 125-char bio limit —
     see .home-body .reader-card's own min-height comment above), a genuinely different
     shape from desktop/the /readers page. Switch to the reader's saved mobile-card
     position to match.
     IMPORTANT: this shape change means any reader's already-saved photoPositionMobileCard
     value was set against the OLD, taller box — existing saved positions likely need
     re-checking/re-adjusting in the admin tool after this change (see admin-reader-form.ejs's
     Mobile Card preview, whose own box size was updated alongside this rule). */
  .home-body .reader-card__photo {
    object-position: var(--photo-pos-mobile-card, 50% 50%);
  }
  .home-body .reader-card__status-badge {
    font-size: 0.6rem;
    padding: 2px 6px;
    bottom: 4px;
    left: 4px;
  }
  .home-body .reader-card__gift-badge {
    font-size: 0.54rem;
    padding: 2px 6px;
    top: 4px;
    right: 4px;
  }
  .home-body .fav-form ~ .reader-card__gift-badge {
    top: 40px;
  }
  .home-body .reader-card__body {
    padding: 10px 12px 6px;
    gap: 4px;
  }
  /* Root cause of the lingering gap above the buttons: .reader-card__actions'
     base (desktop) rule uses margin-top:auto, which absorbs ALL leftover
     vertical space in the flex column as extra gap directly above the
     buttons specifically — every other internal gap is the fixed 4px
     above (from .reader-card__body's own flex gap), unaffected.
     margin-top:0 here removes the auto-stretch entirely, so this gap is
     governed purely by the parent's existing 4px flex gap — same as every
     other gap in the column, instead of stretching to fill whatever
     height is left over. */
  .home-body .reader-card__actions {
    margin-top: 0;
  }
  .home-body .reader-card__name {
    font-size: 0.92rem;
  }
  /* Status dot next to the reader's name, driven by the same data-reader-status
     attribute the existing socket handler already keeps in sync (see
     readers-grid.ejs) — no template or JS change needed, this is pure CSS
     reading state that's already there. The existing photo-overlay status
     badge (Available/Busy · countdown/Offline) is untouched and still fully
     functional; this dot is a supplementary at-a-glance indicator for the
     info column per the approved layout, not a replacement for it. */
  .home-body .reader-card__profile-link {
    display: inline-flex;
    align-items: center;
    gap: 6px;
  }
  .home-body .reader-card__profile-link::before {
    content: '';
    display: inline-block;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    flex-shrink: 0;
    background: var(--status-offline-fg);
  }
  .home-body .reader-card[data-reader-status="online_chat"] .reader-card__profile-link::before,
  .home-body .reader-card[data-reader-status="online_call"] .reader-card__profile-link::before {
    background: var(--status-online-fg);
  }
  .home-body .reader-card[data-reader-status="busy"] .reader-card__profile-link::before {
    background: var(--status-busy-fg);
  }
  /* -webkit-line-clamp:6 comfortably covers a full 150-char bio (roughly
     4-5 lines at this width/font-size) with headroom to spare — raised
     from the previous 1-line clamp, which was cutting descriptions off.
     min-height: 7.5em (5 lines at this rule's own 1.5 line-height) fixes the
     rate pill/Chat/Call row to the same vertical position on every card,
     regardless of bio length — without it, .reader-card__body's flex column
     (flex-start, no justify-content override) packs shorter content upward
     and leaves the leftover space at the very bottom of the card instead,
     which is what let a 1-line bio and a 5-line bio (the two real lengths in
     the database) land the buttons ~100px apart. 5 lines, not the full
     6-line clamp ceiling, deliberately: the two real longest bios already
     wrap to 5 lines and the card's own 222px min-height (above) was already
     sized right against that — reserving a full 6th line here would push
     total content past 222px and grow the card, which the brief this was
     built against explicitly ruled out. A theoretical future 6-line bio
     still renders in full (line-clamp isn't shortened) — that one card
     would just grow past 222px, same accepted "grows rather than clips"
     tradeoff as the base .reader-card rule's own min-height already lives with. */
  .home-body .reader-card__bio {
    -webkit-line-clamp: 6;
    font-size: 0.76rem;
    flex: none;
    min-height: 6em;
  }
  /* min-height 20px (not 0): the plain star-rating row measures ~14.4px tall but the
     "New reader" pill (.new-reader-badge — its own border+padding box) measures ~19.5px,
     so a reviewed card and a never-reviewed card would land the rate pill/actions below
     this at two different offsets even with the bio fix above holding bio height fixed.
     20px covers the taller of the two with a small buffer, same "measured, not min-height:0
     guesswork" approach as this block's own reader-card/reader-card__bio rules. */
  .home-body .reader-card__stars {
    min-height: 20px;
  }
  .home-body .reader-card__actions .btn--sm {
    font-size: 0.72rem;
    padding: 6px 4px;
  }
  .home-body .reader-card__actions .btn--sm.btn--sm--gift {
    font-size: 0.62rem;
    padding: 4px 4px;
  }
  .home-body .reader-card__gift-line {
    font-size: 8px;
  }

  /* ── 6. Fixed bottom nav: Search / Chat / Call / Skills / Log in ────────
     Search and Log in reuse the exact icons already established elsewhere
     (ti-search from the existing search box; ti-messages/ti-phone from the
     reader-card Chat/Call fix). No existing site-wide icon convention
     exists for "skills" or "log in/account" specifically, so ti-wand
     (already used for "Specialisms" on the reader profile page — the same
     concept, different word) was reused for Skills, and standard ti-login/
     ti-user icons were chosen for the log-in/logged-in states since there
     was nothing existing to reuse there. Gold active state matches
     .cat-chip--active/.filter-bar__item--active elsewhere. */
  .home-body .mobile-bottom-nav {
    display: flex;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 220;
    background: #150f24;
    border-top: var(--mobile-gold-divider);
    padding: 6px 4px calc(6px + env(safe-area-inset-bottom, 0px));
    justify-content: space-around;
    align-items: center;
    /* GPU layer promotion — see .home-body .topnav's identical rule for why. */
    will-change: transform;
    transform: translateZ(0);
    backface-visibility: hidden;
  }
  .home-body .mobile-bottom-nav__item {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    flex: 1;
    background: none;
    border: none;
    color: var(--text-muted);
    font-family: 'Poppins', 'Inter', sans-serif;
    font-size: 0.62rem;
    padding: 4px 6px;
    cursor: pointer;
    text-decoration: none;
  }
  .home-body .mobile-bottom-nav__item i {
    font-size: 1.2rem;
  }
  .home-body .mobile-bottom-nav__item--active {
    color: var(--gold);
  }
  /* Reserve room at the top (fixed header 60px + fixed trust bar, now 37px
     since it's ~10% taller per this brief = 97px) and bottom (fixed nav,
     62px) of the page so none of the fixed bars ever overlap page content
     — .home-body is the <body> tag itself.
     --mobile-gold-divider is the SINGLE site-wide (mobile) source of truth
     for every gold divider line on the page — the trust bar's top/bottom,
     the bottom nav bar's top border, the search-reveal bar's top border,
     the Skills sheet's top border, and the hamburger menu's right border
     all reference it (see each below). Value: 1.4px, chosen because it's
     the bottom nav bar's own existing/current thickness (this brief's
     designated reference value) — and it's also exactly what a 30%
     reduction of the trust bar's previous 2px produces (2 * 0.7 = 1.4),
     so both of this brief's instructions land on the same number with no
     conflict. The other lines (search bar, Skills sheet, hamburger menu)
     were already 1.4px and keep that value, just now via this shared
     variable instead of separate hardcoded literals, so none of them can
     drift out of sync again. */
  .home-body {
    padding-top: 97px;
    padding-bottom: 62px;
    --mobile-gold-divider: 1.4px solid #FAC775;
  }
  /* 404.ejs is the one .home-body page with neither a trust-strip (37px of the 97px above)
     nor a .mobile-bottom-nav (the 62px below) — the base rule's reserved space would just
     be excess blank padding around its content otherwise. Higher specificity than the
     compound .home-body rule above via the second class, no !important needed. */
  .home-body.error-page-body {
    padding-top: 60px;
    padding-bottom: 0;
  }
  /* Content/legal pages (static-page.ejs) reuse .home-body for the fixed
     header + stat bar + hamburger menu, and — same as home.ejs/about.ejs/
     reader-profile.ejs — now also have the fixed bottom nav (Search/Chat/
     Call/Skills/Log in), so the base .home-body padding-bottom above
     (reserved for that nav) applies here unmodified; no override needed.
     "Back to home" sits immediately after the fixed stat bar with no gap
     of its own (unlike about.ejs's hero, whose own generous padding
     already clears the stat bar) — margin-top here gives it the same
     breathing room, reusing .page-wrap's existing 24px horizontal-padding
     unit for consistency rather than introducing a new spacing value. */
  .home-body.static-page-body .back-link {
    margin-top: 24px;
  }

  /* ── Skills bottom sheet — reuses the .mobile-drawer-backdrop component
     from the chat/call drawers, plus the same transform-based slide/toggle
     mechanic (translateY here instead of translateX, since this slides up
     from the bottom nav rather than in from a side edge). */
  .home-body .mobile-skills-sheet {
    display: block;
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 230;
    max-height: 70vh;
    background: #150f24;
    border-top: var(--mobile-gold-divider);
    border-radius: 16px 16px 0 0;
    padding: 14px 16px calc(14px + 62px);
    overflow-y: auto;
    transform: translateY(100%);
    transition: transform .25s ease;
    box-shadow: 0 -8px 32px rgba(0,0,0,0.5);
  }
  .home-body .mobile-skills-sheet.is-open {
    transform: translateY(0);
  }
  .home-body #mobile-skills-backdrop.is-open {
    z-index: 225;
  }
  .home-body .mobile-skills-sheet__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding-bottom: 10px;
    margin-bottom: 8px;
    border-bottom: 1px solid var(--card-border);
    font-family: 'Poppins', sans-serif;
    color: var(--gold);
    font-weight: 600;
  }
  .home-body .mobile-skills-sheet__list {
    display: flex;
    flex-direction: column;
    gap: 4px;
  }
  .home-body .mobile-skills-sheet__item {
    display: flex;
    align-items: center;
    gap: 10px;
    background: none;
    border: none;
    text-align: left;
    color: var(--text);
    font-family: 'Inter', sans-serif;
    font-size: 0.9rem;
    padding: 10px 6px;
    cursor: pointer;
    border-radius: var(--radius-sm);
  }
  .home-body .mobile-skills-sheet__item:active {
    background: rgba(255,255,255,0.06);
  }
  .home-body .mobile-skills-sheet__item i {
    color: var(--gold);
    font-size: 1.05rem;
    flex-shrink: 0;
  }

  /* ── Hamburger slide-out menu — reuses .mobile-drawer-backdrop again
     (a second instance, #mobile-hamburger-backdrop) plus the same
     transform-based slide/toggle mechanic as the Skills sheet, but sliding
     in from the LEFT edge (translateX) since it's triggered from the fixed
     header rather than the bottom nav. */
  .home-body .mobile-hamburger-menu {
    display: block;
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    z-index: 230;
    width: 78%;
    max-width: 320px;
    background: #150f24;
    border-right: var(--mobile-gold-divider);
    overflow-y: auto;
    transform: translateX(-100%);
    transition: transform .25s ease;
    box-shadow: 8px 0 32px rgba(0,0,0,0.5);
  }
  .home-body .mobile-hamburger-menu.is-open {
    transform: translateX(0);
  }
  .home-body #mobile-hamburger-backdrop.is-open {
    z-index: 225;
  }
  .home-body .mobile-hamburger-menu__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 14px 16px;
    border-bottom: 1px solid var(--card-border);
  }
  .home-body .mobile-hamburger-menu__close {
    background: none;
    border: none;
    color: var(--gold);
    font-size: 1.3rem;
    cursor: pointer;
    padding: 4px;
  }
  .home-body .mobile-hamburger-menu__list {
    display: flex;
    flex-direction: column;
    padding: 8px 10px calc(8px + 62px);
  }
  .home-body .mobile-hamburger-menu__item {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    box-sizing: border-box;
    background: none;
    border: none;
    text-align: left;
    color: var(--text);
    font-family: 'Inter', sans-serif;
    font-size: 0.92rem;
    padding: 12px 10px;
    cursor: pointer;
    text-decoration: none;
    border-radius: var(--radius-sm);
  }
  .home-body .mobile-hamburger-menu__item:active {
    background: rgba(255,255,255,0.06);
  }
  .home-body .mobile-hamburger-menu__item i {
    color: var(--gold);
    font-size: 1.1rem;
    flex-shrink: 0;
    width: 20px;
    text-align: center;
  }
  .home-body .mobile-hamburger-menu__divider {
    border: none;
    border-top: 1px solid var(--card-border);
    margin: 8px 10px;
  }
  /* Balance row — sits above the rest of __list (its own <% if (user) %>
     block ahead of the "Homepage" item), styled distinctly from the plain
     __item rows below it since it's meant to read as a standalone
     shortcut to top-up, not just another menu link. */
  .home-body .mobile-hamburger-menu__balance {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    box-sizing: border-box;
    background: var(--gold-dim);
    border: 1px solid rgba(250,199,117,0.35);
    border-radius: var(--radius-sm);
    padding: 12px 14px;
    margin: 2px 0 10px;
    font-family: 'Poppins', sans-serif;
    font-size: 0.92rem;
    font-weight: 700;
    color: var(--gold);
    text-decoration: none;
  }
  .home-body .mobile-hamburger-menu__balance i { font-size: 1.15rem; }
  .home-body .mobile-hamburger-menu__balance:active { background: rgba(250,199,117,0.22); }
}

/* New mobile-only components (bottom nav + Skills sheet + hamburger menu/
   button) need an explicit base display:none outside the media query
   above — unlike rules that only ever override an EXISTING (already
   site-wide-hidden-by-default) class, these elements have no other CSS
   touching them at all, so without this they'd render as plain visible
   elements on desktop by default. */
.mobile-bottom-nav,
.mobile-skills-sheet,
.mobile-hamburger-menu,
.mobile-hamburger-btn,
.mobile-browse-heading,
.mobile-quickstats,
.readings-mobile-list,
.earnings-mobile-list {
  display: none;
}

/* ── Incremental "Show more" pagination ──────────────────────────────────
   Shared by account.ejs (Past Readings/Balance Report/My Reviews, 5 per
   batch) and reader-dashboard.ejs (Earnings/Customer History, 10 per
   batch) — see /js/paginate.js. Every paginated item carries
   data-pg-group + data-pg-idx; items beyond the initial batch start with
   .pg-hidden. One button per section (data-pg-group/-batch/-shown/-total)
   reveals the next batch in place and updates its own remaining count,
   on both mobile and desktop — no separate scrollable "reveal everything"
   box needed. */
.pg-hidden {
  display: none;
}
.show-more-btn {
  display: block;
  width: 100%;
  margin-top: 12px;
}

/* ── Mobile: "All Readers"/"Call Readings"/"Chat Readings" type-filter tabs ──
   Unscoped (not .home-body) — this exact .filter-bar/.filter-bar__item markup
   is shared verbatim by home.ejs, readers.ejs, readers-calls.ejs and
   readers-chats.ejs, and the brief asked for the fix everywhere it appears,
   not just the homepage. Padding is cut first (22px → 10px horizontal, by
   far the biggest space saver) with only a modest, secondary font-size trim
   — per the brief's "reduce padding before shrinking text" — so the three
   tabs fit one row without wrapping while staying comfortably tappable. */
@media (max-width: 768px) {
  .filter-bar {
    gap: 2px;
    padding: 3px;
  }
  .filter-bar__item {
    padding: 8px 10px;
    font-size: 0.78rem;
  }
}

/* ── About Us page (about.ejs) ────────────────────────────────────────────
   Small uppercase gold eyebrow label reused across every section header on
   this page (hero, "Why we exist", "What our readers offer", "Our
   standards", closing CTA) rather than inventing a differently-styled
   label per section. */
.about-eyebrow {
  display: block;
  font-family: 'Poppins', sans-serif;
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: 12px;
}

/* Hero: .panel-gradient (shared header/footer gradient) + .starfield-layer
   (shared nebula/star component, see home.ejs/reader-profile.ejs) behind a
   centered headline. Self-contained position:relative + isolation:isolate
   so the starfield's inset:0 layer fills just this section, matching the
   .readers-section technique rather than the full-page .profile-page one. */
.about-hero {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  padding: 72px 24px;
  text-align: center;
  border-bottom: 1.4px solid #FAC775;
}

.about-hero__inner {
  max-width: 720px;
  margin: 0 auto;
}

.about-hero__title {
  font-size: 2.3rem;
  line-height: 1.25;
  color: #fff;
  margin-bottom: 16px;
}

.about-hero__sub {
  font-size: 1.05rem;
  color: var(--text-muted);
  max-width: 600px;
  margin: 0 auto;
}

.about-page-wrap {
  padding-top: 56px;
}

/* text-align: center centers the eyebrow label and any direct-child intro
   paragraph (see .about-section > p below) per the approved design. Grids
   inside a section (.about-grid) opt back out to normal left-aligned card
   text — see the reset there — so this only affects section-level copy,
   never card content. */
.about-section {
  margin-bottom: 56px;
  text-align: center;
}

.about-section > p {
  max-width: 720px;
  margin: 0 auto 14px;
  line-height: 1.6;
}

/* Photo strip: three real photos. Each panel clips its <img> to a 4:3 box
   (same aspect-ratio + overflow:hidden + object-fit:cover pattern as
   .reader-card__photo) so the source images can stay a single shared
   square crop without art-directing each one individually. */
.about-photo-strip {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px;
  margin-bottom: 56px;
}

.about-photo {
  position: relative;
  aspect-ratio: 4 / 3;
  border-radius: var(--radius);
  border: 1px solid var(--card-border);
  overflow: hidden;
}

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

/* Title pill overlay — centered on the photo, sized to its own text (not stretched
   edge-to-edge). Background is #150f24 (this codebase's one dark-purple "info bar/panel"
   value — see e.g. .trust-strip/.filter-bar-search's own use of it) at 85% opacity, written
   as rgba() since a hex value can't carry opacity on its own here without a new custom
   property, which the design system reference explicitly rules out for --gold and this is
   the same value. */
.about-photo__caption {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background: rgba(21, 15, 36, 0.85);
  color: var(--gold);
  font-family: 'Poppins', sans-serif;
  font-weight: 600;
  font-size: 1.05rem;
  white-space: nowrap;
  padding: 12px 28px;
  border-radius: 999px;
  pointer-events: none;
}

@media (max-width: 768px) {
  .about-photo__caption {
    font-size: 0.92rem;
    padding: 10px 22px;
  }
}

/* "What our readers offer" / "Our standards" grids — 2 columns down to 1 on
   mobile, reusing the site's existing .card conventions (background,
   border, radius, padding) rather than a new card style.
   align-items: stretch (grid's own default, made explicit here) stretches
   every card in a row to match the tallest sibling, so card height never
   depends on how much description text a given card happens to have.
   text-align: left resets the centered text-align inherited from
   .about-section above — only the section label/intro copy should be
   centered, never the card titles/descriptions themselves.
   The higher-specificity ".about-grid > .card + .card" cancels out the
   base ".card + .card { margin-top: 16px }" rule (site.css's convention
   for vertically-STACKED cards) — inside a grid every card is already
   separated by `gap`, so that extra margin was stacking on top of the
   grid gap for every card after the first, silently pushing later cards
   down out of alignment with their row and making the whole grid look
   uneven/left-shifted despite `gap` itself being perfectly even. */
.about-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  align-items: stretch;
  text-align: left;
  gap: 16px;
}

.about-grid > .card + .card {
  margin-top: 0;
}

.about-offer-card,
.about-standard-card {
  display: flex;
  flex-direction: column;
  height: 100%;
}

.about-offer-card__title {
  font-family: 'Poppins', sans-serif;
  font-weight: 600;
  color: var(--gold);
  margin-bottom: 6px;
}

.about-standard-card i {
  font-size: 1.3rem;
  color: var(--gold);
  margin-bottom: 10px;
  display: block;
}

.about-standard-card__title {
  font-family: 'Poppins', sans-serif;
  font-weight: 600;
  color: var(--text);
  margin-bottom: 6px;
}

.about-offer-card p,
.about-standard-card p {
  font-size: 0.9rem;
  line-height: 1.5;
}

/* Closing CTA: same shared gradient as the hero, centered content, gold
   pill button (.btn--primary's existing gold/dark-text/hover treatment,
   just rounded fully for this one CTA). */
.about-cta {
  border-radius: var(--radius);
  border: 1px solid var(--card-border);
  padding: 56px 24px;
  text-align: center;
  margin-bottom: 24px;
}

.about-cta__title {
  font-size: 1.8rem;
  color: #fff;
  margin-bottom: 24px;
}

.about-cta__btn {
  border-radius: 999px;
  padding: 13px 34px;
  font-size: 1rem;
}

/* 404 page — same panel-gradient-centered-content pattern as .about-cta above, own
   classes since this isn't About-Us-specific content. */
.error-404 {
  border-radius: var(--radius);
  border: 1px solid var(--card-border);
  padding: 72px 24px;
  text-align: center;
  margin: 40px 0;
}

.error-404__code {
  display: block;
  font-family: 'Poppins', sans-serif;
  font-weight: 700;
  font-size: 5rem;
  color: var(--gold);
  line-height: 1;
  margin-bottom: 12px;
}

.error-404__title {
  font-size: 1.8rem;
  color: #fff;
  margin-bottom: 12px;
}

.error-404__text {
  max-width: 420px;
  margin: 0 auto 28px;
}

.error-404__btn {
  border-radius: 999px;
  padding: 13px 34px;
  font-size: 1rem;
}

@media (max-width: 768px) {
  .about-hero {
    padding: 48px 20px;
  }
  .about-hero__title {
    font-size: 1.7rem;
  }
  .about-hero__sub {
    font-size: 0.95rem;
  }
  .about-photo-strip {
    grid-template-columns: 1fr;
  }
  .about-grid {
    grid-template-columns: 1fr;
  }
  .error-404 {
    padding: 56px 20px;
  }
  .error-404__code {
    font-size: 3.4rem;
  }
  .error-404__title {
    font-size: 1.4rem;
  }
  .about-cta {
    padding: 40px 20px;
  }
  .about-cta__title {
    font-size: 1.4rem;
  }
}
