/* Ta'ziyah
 *
 * The design brief, since it is easy to lose: this is used by people at the
 * worst moment of their week, often in a hurry, often on a phone. It should
 * feel calm, dignified and unmistakably trustworthy. Warmth over sterility,
 * clarity over cleverness, and nothing that draws attention to itself.
 *
 * Breakpoints. There is no single global switch-over: almost everything here
 * is sized with clamp(), flex-wrap and auto-fit grids, which adapt on their
 * own without a media query at all. Where a component does need a hard
 * line — because a layout genuinely changes shape rather than just
 * reflowing — the values below are the ones in use, each picked for what
 * the component next to it stops fitting, not a rounded number:
 *
 *   460px   the account controls give up "Create account" for "Sign in"
 *   560px   a Janazah row stacks instead of compressing
 *   640px   the general phone tier: hero, tabs, forms, cards, the guide
 *   760px   the settings menu becomes a horizontal scroll row
 *   900px   the sidebar and the console bar become a drawer
 *
 * A component gets its own number only when its own content demands one;
 * forcing every breakpoint onto one shared value would mean either the
 * settings menu collapsing a hundred pixels too early or the drawer arriving
 * a hundred pixels too late for something else. What stays consistent is the
 * unit (px, matching the viewport widths a phone is actually measured in)
 * and the direction (max-width, mobile-first only where content is already
 * simple enough not to need a floor).
 */

/* ---------- tokens ---------- */

:root {
  color-scheme: light;

  --parchment: #faf7f2;
  --bg: var(--parchment);
  --bg-sunk: #f2eee6;
  --surface: #ffffff;
  --surface-2: #f8f5ef;

  --ink: #16201c;
  --ink-2: #40504a;
  --ink-3: #6c7d76;

  --line: #e4ded3;
  --line-strong: #d3ccbe;

  --accent: #14503f;
  --accent-hover: #0e3d30;
  --accent-ink: #ffffff;
  --accent-soft: #e8f0ec;
  --accent-line: #b9d3c8;

  --gold: #8a6a1f;
  --gold-soft: #fbf3e0;
  --gold-line: #e8d5a8;

  --danger: #8f2d2d;
  --danger-soft: #fbedeb;
  --danger-line: #edc7c2;

  --radius-sm: 8px;
  --radius: 14px;
  --radius-lg: 20px;

  --shadow-sm: 0 1px 2px rgba(22, 32, 28, .05);
  --shadow: 0 1px 2px rgba(22, 32, 28, .04), 0 6px 20px -8px rgba(22, 32, 28, .12);
  --shadow-lg: 0 24px 60px -20px rgba(22, 32, 28, .3);

  --sans: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --serif: 'Source Serif 4', Georgia, 'Times New Roman', serif;
  --mono: ui-monospace, SFMono-Regular, Menlo, monospace;
  /* Arabic is set in naskh, never in the Latin sans: the fallback is
     cramped, and religious text that is hard to read is the one thing
     this page cannot afford. */
  --arabic: 'Noto Naskh Arabic', 'Geeza Pro', 'Traditional Arabic', serif;

  --page: 46rem;
  --page-wide: 62rem;

  /* Motion. One easing and three durations, so everything moves the same way.
     Short on purpose: this is a calm app, not a slow one. */
  --ease: cubic-bezier(.2, .8, .3, 1);
  --dur-fast: .14s;
  --dur: .22s;
  --dur-slow: .38s;
}

/* The dark palette. Defined once and used by two selectors: the system
   preference, and an explicit choice made in Settings. tests/prefs.test.js
   asserts the two copies stay identical, since a token added to one and
   not the other is a theme that is subtly wrong only for some people. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;

    --bg: #121614;
    --bg-sunk: #0d100f;
    --surface: #1a201d;
    --surface-2: #212824;

    --ink: #eef1ee;
    --ink-2: #b3bfb9;
    --ink-3: #83948c;

    --line: #2c3733;
    --line-strong: #3b4842;

    --accent: #6fc4a4;
    --accent-hover: #86d3b6;
    --accent-ink: #0b1a14;
    --accent-soft: #16302a;
    --accent-line: #2b4d43;

    --gold: #d9b26a;
    --gold-soft: #2b2417;
    --gold-line: #473b23;

    --danger: #ef9b95;
    --danger-soft: #2e1c1b;
    --danger-line: #4c2e2c;

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, .4);
    --shadow: 0 1px 2px rgba(0, 0, 0, .35), 0 8px 24px -12px rgba(0, 0, 0, .6);
    --shadow-lg: 0 30px 70px -24px rgba(0, 0, 0, .8);
  }
}

/* dark-palette-copy */
:root[data-theme="dark"] {

  color-scheme: dark;

  --bg: #121614;
  --bg-sunk: #0d100f;
  --surface: #1a201d;
  --surface-2: #212824;

  --ink: #eef1ee;
  --ink-2: #b3bfb9;
  --ink-3: #83948c;

  --line: #2c3733;
  --line-strong: #3b4842;

  --accent: #6fc4a4;
  --accent-hover: #86d3b6;
  --accent-ink: #0b1a14;
  --accent-soft: #16302a;
  --accent-line: #2b4d43;

  --gold: #d9b26a;
  --gold-soft: #2b2417;
  --gold-line: #473b23;

  --danger: #ef9b95;
  --danger-soft: #2e1c1b;
  --danger-line: #4c2e2c;

  --shadow-sm: 0 1px 2px rgba(0, 0, 0, .4);
  --shadow: 0 1px 2px rgba(0, 0, 0, .35), 0 8px 24px -12px rgba(0, 0, 0, .6);
  --shadow-lg: 0 30px 70px -24px rgba(0, 0, 0, .8);
}


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

html { -webkit-text-size-adjust: 100%; }

/* Text size, set from Settings. Everything in this sheet is in rem, so moving
   the root size moves the whole interface together rather than leaving
   headings and controls at their old scale around larger body copy. */
:root[data-text="large"] { font-size: 112.5%; }

@media (prefers-reduced-motion: no-preference) {
  html { scroll-behavior: smooth; }
}
/* Anchored content clears the sticky masthead instead of hiding under it.
   scroll-padding on the scroll container covers everything the browser
   scrolls to, including keyboard focus moving into a form field behind the
   header; :target keeps working for links that predate it. */
html { scroll-padding-top: 5rem; }
:target { scroll-margin-top: 5rem; }

/* A drawer or a dialog that has been scrolled to its end should not start
   scrolling the page behind it. */
.modal, .sidenav, .settings-nav, .tabs, .address-results {
  overscroll-behavior: contain;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 1rem;
  line-height: 1.55;
  letter-spacing: -0.005em;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3 { font-family: var(--serif); font-weight: 600; letter-spacing: -0.015em; }
h1 { font-size: 1.9rem; line-height: 1.2; margin: 0 0 .35rem; }
h2 { font-size: 1.25rem; line-height: 1.3; margin: 0 0 .25rem; }
h3 { font-size: 1.05rem; margin: 1.5rem 0 .5rem; }
p { margin: 0 0 .75rem; }
a { color: var(--accent); text-underline-offset: 2px; }

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

.icon { flex: none; vertical-align: -.18em; }
.mono { font-family: var(--mono); font-size: .85em; }
.muted { color: var(--ink-3); }
.small { font-size: .85rem; }
.nowrap { white-space: nowrap; }

/* ---------- chrome ---------- */

.env-banner {
  margin: 0;
  padding: .5rem 1rem;
  text-align: center;
  background: var(--gold-soft);
  color: var(--gold);
  font-size: .8rem;
  font-weight: 500;
  border-bottom: 1px solid var(--gold-line);
}

.sample-banner {
  margin: 0;
  padding: .55rem 1rem;
  text-align: center;
  background: var(--gold-soft);
  color: var(--gold);
  font-size: .82rem;
  border-bottom: 1px solid var(--gold-line);
}
.sample-banner strong { font-weight: 600; }

.masthead {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  gap: .75rem;
  height: 3.5rem;
  padding: 0 clamp(.75rem, 3vw, 1.25rem);
  background: color-mix(in srgb, var(--surface) 88%, transparent);
  backdrop-filter: saturate(1.4) blur(12px);
  border-bottom: 1px solid var(--line);
}
.masthead__spacer { flex: 1; }

.brand {
  display: flex;
  align-items: center;
  gap: .55rem;
  font-family: var(--serif);
  font-size: 1.05rem;
  font-weight: 600;
  color: var(--ink);
  text-decoration: none;
  letter-spacing: -0.02em;
}
.brand__mark {
  /* The logo is a self-contained circular mark (public/logo.svg): its own
     background and colours are drawn into the file, fixed regardless of
     light/dark theme, the way a badge-style logo normally stays fixed rather
     than re-colouring itself with the page around it. */
  display: block;
  flex: none;
  width: 1.7rem;
  height: 1.7rem;
}
.brand__sub { font-weight: 400; color: var(--ink-3); font-size: .8em; }

/* ---------- application shell ---------- */
/* A sidebar of sections and one scrolling column beside it. The nav does not
   move with the page: on a site people open in a hurry, the way to every
   other section should not require scrolling back to the top first. */

.app-body {
  display: grid;
  grid-template-columns: var(--sidenav, 15rem) minmax(0, 1fr);
  align-items: start;
  /* Collapsing the sidebar slides the content across rather than snapping it.
     Browsers that cannot interpolate grid tracks simply jump, which is what
     happened before. */
  transition: grid-template-columns var(--dur) var(--ease);
}
body.is-nav-collapsed .app-body { --sidenav: 3.75rem; }

.app-main { min-width: 0; }

.sidenav {
  position: sticky;
  top: 3.5rem;
  height: calc(100dvh - 3.5rem);
  display: flex;
  flex-direction: column;
  gap: .3rem;
  padding: 1rem .6rem;
  overflow-y: auto;
  border-right: 1px solid var(--line);
  background: var(--bg-sunk);
  transition: width var(--dur) var(--ease);
}

.sidenav__group { display: flex; flex-direction: column; gap: .1rem; }
.sidenav__rule {
  height: 1px;
  margin: .7rem .5rem;
  background: var(--line);
}

.nav-item {
  display: flex;
  align-items: center;
  gap: .7rem;
  border: 0;
  background: none;
  cursor: pointer;
  padding: .52rem .7rem;
  border-radius: 9px;
  color: var(--ink-2);
  font: inherit;
  font-size: .9rem;
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.nav-item .icon { flex: none; opacity: .75; }
/* Same specificity trap as .tab above, plus one more reason here: a hover
   background would paint over the sliding marker. */
.nav-item:hover:not(.nav-item--active) { background: var(--surface-2); color: var(--ink); }
.nav-item--active {
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: 600;
}
.nav-item--active .icon { opacity: 1; }
.nav-item--quiet { color: var(--ink-3); }

/* Leads somewhere most signed-in people cannot go, so it is marked out
   without shouting: a tint rather than another filled button. */
.nav-item--admin { color: var(--gold); }
.nav-item--admin:hover { background: var(--gold-soft); color: var(--gold); }

.sidenav__collapse {
  display: flex;
  align-items: center;
  gap: .7rem;
  margin-top: auto;
  padding: .52rem .7rem;
  border: 0;
  border-radius: 9px;
  background: none;
  color: var(--ink-3);
  font: inherit;
  font-size: .82rem;
  cursor: pointer;
  white-space: nowrap;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.sidenav__collapse:hover { background: var(--surface-2); color: var(--ink-2); }

/* Drawer only; the desktop sidebar has nothing to close. */
.sidenav__close {
  display: none;
  align-items: center;
  gap: .7rem;
  margin-bottom: .5rem;
  padding: .52rem .7rem;
  border: 0;
  border-radius: 9px;
  background: none;
  color: var(--ink-3);
  font: inherit;
  font-size: .86rem;
  cursor: pointer;
}
.sidenav__close:hover { background: var(--surface-2); color: var(--ink-2); }

body.is-nav-collapsed .sidenav { padding-inline: .5rem; }
body.is-nav-collapsed .nav-item,
body.is-nav-collapsed .sidenav__collapse { justify-content: center; padding-inline: .4rem; }
/* Kept in the DOM, out of sight: the label is still the accessible name. */
body.is-nav-collapsed .nav-item__label {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}
/* The labels fade rather than vanishing mid-slide. */
.nav-item__label { transition: opacity var(--dur-fast) var(--ease); }
body.is-nav-collapsed .nav-item__label { opacity: 0; }
body.is-nav-collapsed .sidenav__collapse .icon { transform: rotate(180deg); }

.nav-scrim {
  position: fixed;
  inset: 0;
  /* Below the masthead (40) and the drawer (45), not above them: the
     masthead establishes its own stacking context, so a scrim placed above
     it would dim the whole bar, including controls that have nothing to do
     with the drawer it belongs to. (The drawer itself still ends up on top
     of the masthead where the two overlap — that is why the drawer carries
     its own close row rather than relying on the hamburger underneath it.) */
  z-index: 39;
  background: rgba(0, 0, 0, .4);
  backdrop-filter: blur(1px);
}

/* ---------- the console's own nav ----------
   console.html keeps a horizontal bar in the masthead rather than a sidebar:
   it has five routes, all of them tools, and a coordinator is there to do one
   task at a time. Same .nav-item, laid out differently. */

.nav {
  display: flex;
  align-items: center;
  gap: .2rem;
  flex: 1;
  flex-wrap: wrap;
}
.nav .nav-item { gap: 0; }
.nav-spacer { flex: 1; }
.nav-user { color: var(--ink-3); font-size: .82rem; padding: 0 .3rem; }
.nav-item--ghost { color: var(--ink-3); }

/* The console masthead carries its whole nav, so it sizes to it rather than
   holding the public site's fixed bar height. Above the drawer breakpoint
   the whole bar can wrap onto a second line if it has to; below it, the nav
   is a drawer instead and there is nothing left in the masthead to wrap. */
.masthead--console { height: auto; min-height: 3.5rem; flex-wrap: wrap; gap: 1.25rem; }

/* ---------- account menu ---------- */

.account { display: flex; align-items: center; gap: .5rem; }
.account__wrap { position: relative; }

.account__button {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .3rem .55rem .3rem .3rem;
  border: 1px solid transparent;
  border-radius: 999px;
  background: none;
  color: var(--ink-2);
  font: inherit;
  font-size: .86rem;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.account__button:hover { background: var(--surface-2); border-color: var(--line); }

.account__avatar {
  display: grid;
  place-items: center;
  width: 1.8rem;
  height: 1.8rem;
  flex: none;
  border-radius: 50%;
  background: var(--accent-soft);
  color: var(--accent);
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .02em;
}
.account__name {
  max-width: 10rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.account__caret {
  width: 0; height: 0;
  border-left: 4px solid transparent;
  border-right: 4px solid transparent;
  border-top: 5px solid currentColor;
  opacity: .6;
}

.account__menu {
  position: absolute;
  top: calc(100% + .45rem);
  right: 0;
  z-index: 50;
  min-width: 13rem;
  padding: .35rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow);
}
.account__who {
  padding: .5rem .6rem .55rem;
  margin: 0 0 .25rem;
  border-bottom: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  gap: .1rem;
}
.account__who-name { font-size: .88rem; font-weight: 600; color: var(--ink); }
.account__who-mail { font-size: .78rem; color: var(--ink-3); overflow-wrap: anywhere; }

.account__item {
  display: block;
  width: 100%;
  padding: .5rem .6rem;
  border: 0;
  border-radius: 8px;
  background: none;
  color: var(--ink-2);
  font: inherit;
  font-size: .88rem;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.account__item:hover { background: var(--surface-2); color: var(--ink); }
.account__item--danger { color: var(--danger); }
.account__item--danger:hover { background: var(--danger-soft); color: var(--danger); }

/* Hidden by default; only meaningful once the media query below shows it. */
.nav-toggle {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: .3rem;
  width: 2.2rem;
  height: 2.2rem;
  flex: none;
  border: 0;
  border-radius: 8px;
  background: none;
  cursor: pointer;
}
.nav-toggle:hover { background: var(--surface-2); }
.nav-toggle__bar {
  display: block;
  height: 2px;
  border-radius: 2px;
  background: var(--ink-2);
  transition: transform .18s ease, opacity .18s ease;
}
.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

@media (max-width: 900px) {
  /* The sidebar becomes a drawer. Not a compressed sidebar: on a phone the
     nav is somewhere you visit and leave, so it gets out of the way entirely
     rather than taking a permanent slice of a small screen. */
  .nav-toggle { display: flex; }
  .app-body { grid-template-columns: minmax(0, 1fr); }
  .sidenav {
    position: fixed;
    top: 0;
    left: 0;
    height: 100dvh;
    /* Above the masthead, not below it. The masthead sits under one or two
       banners depending on the deployment, so a drawer anchored to a guessed
       offset lands over the banner on some pages and short of it on others. */
    z-index: 45;
    width: min(17rem, 82vw);
    transform: translateX(-102%);
    background: var(--surface);
    box-shadow: var(--shadow-lg);
    /* visibility, not only transform: a drawer that is merely translated off
       screen is still in the tab order, so a keyboard user tabs into links
       they cannot see. It stays visible for the length of the slide out. */
    visibility: hidden;
    transition: transform var(--dur) var(--ease), visibility var(--dur);
  }
  .sidenav.is-open { transform: translateX(0); visibility: visible; }
  .sidenav__close { display: flex; }
  .sidenav__collapse { display: none; }
  body.is-drawer-open { overflow: hidden; }
  body.is-nav-collapsed .nav-item,
  body.is-nav-collapsed .sidenav__collapse { justify-content: flex-start; padding-inline: .7rem; }
  body.is-nav-collapsed .nav-item__label {
    position: static; width: auto; height: auto; clip-path: none;
  }
  .account__name { display: none; }
  .account__button { padding: .3rem; }
}

/* Below the same breakpoint, the console's horizontal bar becomes an
   off-canvas drawer too, opened by #console-nav-toggle. Its own block, not
   folded into .sidenav's above: the console has no app-body grid to
   collapse, and keeping the two separate keeps each easy to read on its
   own even though they change at the same width. */
@media (max-width: 900px) {
  .masthead--console .nav-toggle { display: flex; }
  .masthead--console .nav {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 45;
    width: min(17rem, 82vw);
    height: 100dvh;
    flex-direction: column;
    align-items: stretch;
    flex-wrap: nowrap;
    gap: .3rem;
    padding: 1rem .6rem;
    overflow-y: auto;
    background: var(--surface);
    box-shadow: var(--shadow-lg);
    transform: translateX(-102%);
    visibility: hidden;
    transition: transform var(--dur) var(--ease), visibility var(--dur);
  }
  .masthead--console .nav.is-open { transform: translateX(0); visibility: visible; }
  .masthead--console .nav .nav-item {
    justify-content: flex-start;
    padding-inline: .7rem;
  }
  .masthead--console .nav-spacer { display: none; }
  .masthead--console .nav-user {
    padding: .6rem .7rem 0;
    margin-top: .4rem;
    border-top: 1px solid var(--line);
    font-size: .78rem;
  }
}

@media (max-width: 460px) {
  /* Two controls plus the brand does not fit. Sign in is the one that stays:
     somebody returning needs it more often than a first-time visitor needs
     the other, and /signin offers account creation on arrival anyway. */
  .account .btn--primary { display: none; }
  .account .nav-item--quiet {
    border: 1px solid var(--line);
    border-radius: 999px;
    padding: .38rem .8rem;
  }
}

.view {
  max-width: var(--page);
  margin: 0 auto;
  padding: clamp(1.25rem, 4vw, 2.5rem) clamp(1rem, 4vw, 2rem) 6rem;
}
.view--wide { max-width: var(--page-wide); }

.footer {
  max-width: var(--page);
  margin: 0 auto;
  padding: 2rem clamp(1rem, 4vw, 2rem) 5rem;
  border-top: 1px solid var(--line);
  color: var(--ink-3);
  font-size: .84rem;
}
.footer a { color: var(--ink-2); }

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

.page-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 1.5rem;
}

.feed-intro { margin-bottom: 1.5rem; }
.feed-intro h1 { font-size: clamp(1.75rem, 5vw, 2.3rem); }
.feed-intro p { color: var(--ink-2); max-width: 34rem; }

/* ---------- home ---------- */

@keyframes settle { from { opacity: 0; transform: translateY(10px) } }

.hero {
  padding: clamp(2rem, 7vw, 4.5rem) 0 clamp(2.5rem, 6vw, 4rem);
  max-width: 42rem;
  animation: settle .5s cubic-bezier(.2, .8, .3, 1);
}
.hero__eyebrow {
  color: var(--accent);
  font-weight: 600;
  font-size: .84rem;
  letter-spacing: .04em;
  text-transform: uppercase;
  margin-bottom: .6rem;
}
.hero h1 {
  font-size: clamp(2rem, 5.5vw, 2.9rem);
  line-height: 1.15;
  margin: 0 0 1rem;
}
.hero__lede { color: var(--ink-2); font-size: 1.05rem; max-width: 38rem; }
.hero__actions { display: flex; gap: .75rem; flex-wrap: wrap; margin: 1.5rem 0 1rem; }
.hero__note { color: var(--ink-3); font-size: .86rem; }

.promise {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 1rem;
  margin-bottom: clamp(2rem, 5vw, 3.5rem);
  animation: settle .5s .1s cubic-bezier(.2, .8, .3, 1) backwards;
}
.promise-card {
  padding: 1.4rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  transition: transform .18s ease, box-shadow .18s ease;
}
.promise-card:hover { transform: translateY(-2px); box-shadow: var(--shadow); }
.promise-card__mark {
  display: grid;
  place-items: center;
  width: 2.4rem;
  height: 2.4rem;
  border-radius: 10px;
  background: var(--accent-soft);
  color: var(--accent);
  margin-bottom: .8rem;
}
.promise-card h3 { margin: 0 0 .4rem; font-size: 1.02rem; }
.promise-card p { margin: 0; font-size: .92rem; }

.cta-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: 1rem;
  margin-bottom: 2.5rem;
}
.cta-card {
  padding: 1.6rem;
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
}
.cta-card h2 { margin: 0 0 .4rem; font-size: 1.15rem; }
.cta-card__actions { display: flex; gap: .6rem; flex-wrap: wrap; margin-top: 1.1rem; }

.hero--compact { padding-bottom: 2rem; }

/* ---------- numbered process steps ---------- */

.steps { margin-bottom: clamp(2rem, 5vw, 3rem); }
.steps__list { list-style: none; padding: 0; margin: 1.25rem 0 0; counter-reset: none; }
.steps__item {
  display: grid;
  grid-template-columns: 2rem 1fr;
  gap: .9rem;
  padding: 1rem 0;
  border-top: 1px solid var(--line);
}
.steps__item:first-child { border-top: 0; padding-top: 0; }
.steps__num {
  display: grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: 600;
  font-size: .9rem;
}
.steps__item h3 { margin: .25rem 0 .3rem; font-size: 1rem; }
.steps__item p { margin: 0; font-size: .93rem; }

/* ---------- address autocomplete ---------- */

.location-fields > .field-group + .field-group { margin-top: 0; }
.address-picker { position: relative; }

.address-results {
  list-style: none;
  margin: .35rem 0 0;
  padding: .25rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  box-shadow: var(--shadow);
  max-height: 16rem;
  overflow-y: auto;
}
.address-result {
  padding: .55rem .65rem;
  border-radius: 6px;
  cursor: pointer;
  font-size: .9rem;
  color: var(--ink-2);
}
.address-result:hover,
.address-result:focus {
  background: var(--accent-soft);
  color: var(--accent);
  outline: none;
}

.address-chosen {
  margin-top: .6rem;
  padding: .75rem .85rem;
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-sm);
  background: var(--accent-soft);
}
.address-chosen__label { margin: 0 0 .35rem; font-size: .92rem; color: var(--ink); }
.address-chosen .hint { margin: .4rem 0 0; }
.address-chosen .btn { margin-left: .6rem; }

/* One location on the notice composer: a typed name and a searched address. */
.place-picker {
  margin: 1.4rem 0;
  padding: 1rem 1.1rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface-2);
}
.place-picker__legend {
  margin: 0 0 .3rem;
  font-family: var(--serif);
  font-size: 1rem;
  font-weight: 600;
}
.place-picker__shortcut { margin: .6rem 0 .9rem; }
.place-picker .field-group + .field-group { margin-top: .9rem; }

/* ---------- verification state ---------- */

.verify-state { max-width: 38rem; }
.verify-state h1 { font-size: clamp(1.4rem, 4vw, 1.8rem); margin: 0; }
.verify-state h2 { font-size: 1rem; margin: 1.6rem 0 .5rem; }
.verify-state .notice-strip { flex-direction: column; align-items: flex-start; gap: .2rem; }
.verify-state .notice-strip strong { display: block; }
.verify-state .notice-strip p { margin: 0; }
.verify-state ol.list { padding-left: 1.15rem; }
.verify-state ol.list li { margin-bottom: .45rem; color: var(--ink-2); }

@media (max-width: 640px) {
  .hero { padding-top: 1.25rem; }
  .hero__actions .btn { flex: 1 1 auto; }
}

/* ---------- dashboard ---------- */

.dash-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
  gap: 1rem;
  align-items: start;
}
.dash-card { margin-bottom: 0; }
.dash-card--wide { grid-column: 1 / -1; }
.dash-card h2 { font-size: 1.02rem; margin: 0 0 .6rem; }
.dash-card .public-notice { padding: .8rem 0; border-top: 1px solid var(--line); }
.dash-card .public-notice:first-of-type { border-top: 0; }
.dash-card__account .page-head { margin-bottom: 1rem; }
.dash-card__account h1 { font-size: 1.02rem; }
.dash-card__account .card--narrow { max-width: none; margin-inline: 0; }

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

.auth-divider {
  display: flex;
  align-items: center;
  gap: .75rem;
  color: var(--ink-3);
  font-size: .8rem;
  margin: .3rem 0;
}
.auth-divider::before, .auth-divider::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--line);
}

.stack > * + * { margin-top: .9rem; }

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: clamp(1rem, 3vw, 1.4rem);
  box-shadow: var(--shadow-sm);
  margin-bottom: .9rem;
}
.card--narrow { max-width: 30rem; margin-inline: auto; }
.card--flat { box-shadow: none; background: var(--surface-2); }
.card--urgent {
  position: relative;
  padding-left: calc(clamp(1rem, 3vw, 1.4rem) - 3px);
  border-left: 3px solid var(--danger);
}
.card-head {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  align-items: flex-start;
}
.card-actions, .row-actions {
  display: flex;
  gap: .45rem;
  flex-wrap: wrap;
  align-items: center;
  margin-top: 1.1rem;
}
.row-actions { margin-top: 0; }

.empty {
  display: grid;
  justify-items: center;
  gap: .3rem;
  text-align: center;
  padding: 3rem 1.5rem;
  background: var(--surface);
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius);
  color: var(--ink-3);
}
.empty .icon { color: var(--line-strong); margin-bottom: .5rem; }
.empty h2 { color: var(--ink); }
.empty .btn { margin-top: .75rem; }

/* ---------- tabs, and the phone tab bar ---------- */

.tabs {
  position: relative;
  display: flex;
  gap: .25rem;
  padding: .25rem;
  margin-bottom: 1.5rem;
  background: var(--bg-sunk);
  border-radius: 999px;
  overflow-x: auto;
  scrollbar-width: none;
}
.tabs::-webkit-scrollbar { display: none; }

.tab {
  flex: 1 0 auto;
  border: 0;
  background: none;
  cursor: pointer;
  font: inherit;
  font-size: .88rem;
  font-weight: 500;
  white-space: nowrap;
  padding: .5rem .9rem;
  border-radius: 999px;
  color: var(--ink-2);
  transition: background .15s ease, color .15s ease, box-shadow .15s ease;
}
/* :not(.tab--active) because .tab:hover outranks .tab--active on specificity:
   without it, hovering the tab you are already on repaints its label as if it
   were inactive. */
.tab:hover:not(.tab--active) { color: var(--ink); }
/* On a wide screen the segmented control reads better as words alone. */
.tab .icon { display: none; }
.tab--active {
  color: var(--accent);
  font-weight: 600;
}
/* Where the highlight lives when JavaScript has not placed the marker: the
   control still reads correctly, it simply does not travel. */
.tabs:not(.has-slider) .tab--active {
  background: var(--surface);
  box-shadow: var(--shadow-sm);
}

@media (max-width: 640px) {
  .tabs {
    position: fixed;
    left: 0; right: 0; bottom: 0;
    z-index: 40;
    margin: 0;
    padding: .3rem max(.4rem, env(safe-area-inset-left))
             calc(.3rem + env(safe-area-inset-bottom)) max(.4rem, env(safe-area-inset-right));
    border-radius: 0;
    background: color-mix(in srgb, var(--surface) 92%, transparent);
    backdrop-filter: saturate(1.4) blur(12px);
    border-top: 1px solid var(--line);
    box-shadow: 0 -4px 20px -12px rgba(0, 0, 0, .35);
  }
  .tab {
    flex: 1 1 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .15rem;
    font-size: .68rem;
    font-weight: 500;
    letter-spacing: -0.01em;
    padding: .45rem .2rem;
    text-align: center;
  }
  .tab .icon { display: block; }
  .tabs:not(.has-slider) .tab--active { box-shadow: none; background: var(--accent-soft); }
  .tabs .slider { background: var(--accent-soft); box-shadow: none; }
  /* "Masajid I follow (2)" will not fit a quarter of a phone; trim to the
     part that identifies it, keeping the count. */
  .tab__label {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  /* Not every .tabs is the app's own bottom bar. The admin portal reuses the
     same segmented-control look for its eight-item section switcher, which
     has no icons and was never meant to dock to the bottom of the screen —
     eight unlabelled columns is not a thumb-width control. .tabs--plain
     opts a tab group out of the phone treatment above and keeps the
     horizontally-scrolling segmented control instead. */
  .tabs.tabs--plain {
    position: static;
    inset: auto;
    margin: 0 0 1.5rem;
    padding: .25rem;
    border-radius: 999px;
    background: var(--bg-sunk);
    border-top: 0;
    box-shadow: none;
    backdrop-filter: none;
  }
  .tabs.tabs--plain .tab {
    flex: 1 0 auto;
    flex-direction: row;
    font-size: .82rem;
    font-weight: 500;
    padding: .5rem .9rem;
  }
  .tabs.tabs--plain .tab .icon { display: none; }
  .tabs.tabs--plain .tab__label { overflow: visible; text-overflow: clip; }
  .tabs.tabs--plain:not(.has-slider) .tab--active {
    background: var(--surface);
    box-shadow: var(--shadow-sm);
  }
  .tabs.tabs--plain .slider { background: var(--surface); box-shadow: var(--shadow-sm); }
}

/* ---------- the notice ---------- */

.date-heading {
  position: sticky;
  top: 3.6rem;
  z-index: 10;
  display: inline-block;
  font-family: var(--sans);
  font-size: .72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .09em;
  color: var(--ink-3);
  background: var(--bg-sunk);
  padding: .3rem .7rem;
  border-radius: 999px;
  margin: 1.9rem 0 .75rem;
}
.date-heading:first-child { margin-top: 0; }

.notice-card { position: relative; overflow: hidden; padding-left: clamp(1rem, 3vw, 1.4rem); }
.notice-card::before {
  content: '';
  position: absolute;
  inset: 0 auto 0 0;
  width: 3px;
  background: var(--line-strong);
}
.notice-card--published::before { background: var(--accent); }
.notice-card--cancelled::before { background: var(--danger); }
.notice-card--draft::before {
  background: repeating-linear-gradient(
    180deg, var(--line-strong) 0 6px, transparent 6px 12px);
}

.public-notice {
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.1rem;
  margin: .75rem 0;
}
.public-notice--compact { background: transparent; border: 0; padding: 0; margin: 0; }

.public-notice__head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: .75rem;
  margin-bottom: .35rem;
}
.public-notice__org {
  margin: 0;
  font-size: .74rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--ink-3);
}
.public-notice__title {
  font-family: var(--serif);
  font-size: 1.4rem;
  line-height: 1.25;
  margin: 0 0 .5rem;
  color: var(--ink);
}
.public-notice__time {
  display: flex;
  align-items: center;
  gap: .45rem;
  margin: 0 0 .9rem;
  font-weight: 600;
  font-size: 1rem;
  color: var(--accent);
}
.public-notice--cancelled .public-notice__title { text-decoration: line-through; }
.public-notice--cancelled .public-notice__time { color: var(--ink-3); }

.kv { display: grid; gap: .7rem; margin: 0; }
.kv-row { display: flex; gap: .6rem; align-items: flex-start; }
.kv-row .icon { color: var(--ink-3); margin-top: .18rem; }
.kv-label {
  font-size: .72rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .07em;
  color: var(--ink-3);
  margin: 0 0 .05rem;
}
.kv-value { margin: 0; font-weight: 500; }
.kv-sub { margin: 0; color: var(--ink-3); font-size: .9rem; }

/* Console/admin definition lists keep a simpler two-column form. */
dl.kv { grid-template-columns: max-content 1fr; gap: .3rem 1rem; font-size: .92rem; margin-top: .9rem; }
dl.kv dt { color: var(--ink-3); }
dl.kv dd { margin: 0; }

.link-inline {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  margin-top: .3rem;
  font-size: .88rem;
  font-weight: 500;
  color: var(--accent);
}

.instructions {
  white-space: pre-wrap;
  margin: .9rem 0 0;
  padding-top: .9rem;
  border-top: 1px solid var(--line);
  color: var(--ink-2);
  font-size: .95rem;
}

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

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .4rem;
  padding: .55rem 1rem;
  border-radius: 999px;
  cursor: pointer;
  border: 1px solid var(--line-strong);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: .9rem;
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
  transition: background .15s ease, border-color .15s ease, transform .05s ease;
}
.btn:hover:not(:disabled) { background: var(--surface-2); border-color: var(--ink-3); }
.btn:active:not(:disabled) { transform: translateY(1px); }
.btn:disabled { opacity: .45; cursor: not-allowed; }

.btn--primary {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
  font-weight: 600;
}
.btn--primary:hover:not(:disabled) { background: var(--accent-hover); border-color: var(--accent-hover); }

.btn--danger { color: var(--danger); border-color: var(--danger-line); background: transparent; }
.btn--danger:hover:not(:disabled) { background: var(--danger-soft); border-color: var(--danger); }

.btn--active { background: var(--accent-soft); border-color: var(--accent-line); color: var(--accent); font-weight: 600; }

.btn--small { padding: .35rem .7rem; font-size: .82rem; }
.btn--link {
  border: 0; background: none; color: var(--accent);
  padding: .4rem 0; font-weight: 500; text-decoration: underline;
}
.btn--link:hover:not(:disabled) { background: none; }
.btn--quiet { color: var(--ink-3); border-color: transparent; }
.btn--quiet:hover:not(:disabled) { color: var(--ink); border-color: var(--line-strong); }

.btn--lg { padding: .8rem 1.5rem; font-size: 1rem; }

.btn--google {
  width: 100%;
  background: var(--surface);
  border-color: var(--line-strong);
  color: var(--ink);
}

.link { color: var(--accent); }

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

.field-group { margin-bottom: 1rem; flex: 1 1 11rem; }
.field-row { display: flex; gap: .75rem; flex-wrap: wrap; }

.label {
  display: block;
  font-size: .82rem;
  font-weight: 600;
  color: var(--ink-2);
  margin-bottom: .3rem;
}
.label--inline { display: inline; margin-right: .4rem; }

.field {
  width: 100%;
  padding: .6rem .75rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: .95rem;
  transition: border-color .15s ease, box-shadow .15s ease;
}
.field:hover { border-color: var(--ink-3); }
.field:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
/* max-width, not just width: auto, or a select whose longest option is a
   long organization name sizes itself to that text and pushes past the
   viewport on a narrow screen (the org picker on the notices tab does
   exactly this). Capped, the browser clips the selected option's label
   inside the control instead, which is what a native select already does
   well once it is not allowed to grow past its container. */
.field--inline { width: auto; max-width: 100%; display: inline-block; }
textarea.field { resize: vertical; line-height: 1.5; }
select.field { cursor: pointer; }

.check { display: flex; gap: .6rem; align-items: flex-start; margin: .6rem 0; font-size: .92rem; }
.check input { margin-top: .3rem; accent-color: var(--accent); width: 1rem; height: 1rem; }

.hint { font-size: .82rem; color: var(--ink-3); margin: .35rem 0 0; }
.hint--boxed {
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-left: 3px solid var(--line-strong);
  padding: .7rem .85rem;
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  margin-top: .85rem;
}

.fieldset {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.1rem;
  margin: 1.5rem 0;
  background: var(--surface);
}
.fieldset legend {
  padding: 0 .5rem;
  font-family: var(--serif);
  font-weight: 600;
  font-size: 1rem;
}
.fieldset--private { background: var(--surface-2); border-style: dashed; }

.form-actions { display: flex; gap: .5rem; flex-wrap: wrap; align-items: center; margin-top: 1.4rem; }
.form-actions--sticky {
  position: sticky;
  bottom: 0;
  background: color-mix(in srgb, var(--surface) 92%, transparent);
  backdrop-filter: blur(8px);
  padding: .9rem 0;
  border-top: 1px solid var(--line);
  margin-inline: calc(-1 * clamp(1rem, 3vw, 1.4rem));
  padding-inline: clamp(1rem, 3vw, 1.4rem);
}

.form-error {
  background: var(--danger-soft);
  color: var(--danger);
  border: 1px solid var(--danger-line);
  border-radius: var(--radius-sm);
  padding: .75rem .9rem;
  margin: .9rem 0;
  font-size: .9rem;
}
.form-error ul { margin: 0; padding-left: 1.1rem; }

/* ---------- badges and strips ---------- */

.badge {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  padding: .2rem .6rem;
  border-radius: 999px;
  font-size: .7rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .05em;
  white-space: nowrap;
  border: 1px solid transparent;
}
.badge--ok { background: var(--accent-soft); color: var(--accent); border-color: var(--accent-line); }
.badge--warn { background: var(--gold-soft); color: var(--gold); border-color: var(--gold-line); }
.badge--error { background: var(--danger-soft); color: var(--danger); border-color: var(--danger-line); }
.badge--muted { background: var(--bg-sunk); color: var(--ink-3); border-color: var(--line); }

.notice-strip {
  display: flex;
  gap: .5rem;
  align-items: flex-start;
  padding: .7rem .85rem;
  border-radius: var(--radius-sm);
  font-size: .88rem;
  margin: .85rem 0;
  border: 1px solid transparent;
}
.notice-strip--ok { background: var(--accent-soft); color: var(--accent); border-color: var(--accent-line); }
.notice-strip--warn { background: var(--gold-soft); color: var(--gold); border-color: var(--gold-line); }
.notice-strip--error { background: var(--danger-soft); color: var(--danger); border-color: var(--danger-line); }
.notice-strip--muted { background: var(--bg-sunk); color: var(--ink-3); border-color: var(--line); }
.notice-strip:empty { display: none; }
.notice-strip p:last-child { margin-bottom: 0; }

/* ---------- lists and tables ---------- */

.list { list-style: none; margin: .6rem 0; padding: 0; }
.list--plain li { padding: .25rem 0; }
.list-row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  padding: .8rem 0;
  border-bottom: 1px solid var(--line);
}
.list-row:last-child { border-bottom: 0; }
.list-row p { margin: 0; }
.list-row__link { color: inherit; text-decoration: none; }
.list-row__link:hover strong { color: var(--accent); text-decoration: underline; }

.org-header h1 { font-size: clamp(1.4rem, 4vw, 1.9rem); margin: 0; }
.org-page__heading { margin: 2rem 0 1rem; font-size: 1.1rem; }

.table-scroll {
  overflow-x: auto;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}
.table { width: 100%; border-collapse: collapse; font-size: .84rem; }
.table th, .table td {
  text-align: left;
  padding: .6rem .8rem;
  border-bottom: 1px solid var(--line);
  vertical-align: top;
}
.table tr:last-child td { border-bottom: 0; }
.table th {
  color: var(--ink-3);
  font-weight: 600;
  font-size: .72rem;
  text-transform: uppercase;
  letter-spacing: .06em;
  background: var(--surface-2);
  position: sticky;
  top: 0;
}

/* ---------- nearby and consent ---------- */

.consent { max-width: 34rem; }
.consent h2 { font-size: 1.4rem; }
.consent h3 { font-size: .95rem; }
.consent__list { margin: 0; }
.consent__list li {
  position: relative;
  padding: .35rem 0 .35rem 1.6rem;
  font-size: .93rem;
  color: var(--ink-2);
}
.consent__list li::before {
  content: '';
  position: absolute;
  left: 0; top: .72rem;
  width: .75rem; height: .4rem;
  border-left: 2px solid var(--accent);
  border-bottom: 2px solid var(--accent);
  transform: rotate(-45deg);
}

.nearby-settings { margin-bottom: 1.25rem; }
.nearby-settings__row {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
}
.alerts-panel { margin-top: 1rem; padding-top: 1rem; border-top: 1px solid var(--line); }
.alerts-panel .notice-strip { flex-direction: column; gap: .2rem; }
.alerts-panel .notice-strip strong { display: block; }
.alerts-panel .notice-strip p { margin: 0; }

@media (max-width: 640px) {
  .nearby-settings__row { flex-direction: column; align-items: stretch; }
  .nearby-settings__row .row-actions .btn { flex: 1; }
}

/* ---------- modal and toast ---------- */

.modal-backdrop {
  position: fixed;
  inset: 0;
  z-index: 60;
  background: rgba(12, 18, 16, .5);
  backdrop-filter: blur(3px);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  animation: fade .16s ease;
}
.modal {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: clamp(1.2rem, 4vw, 1.75rem);
  max-width: 30rem;
  width: 100%;
  max-height: 88vh;
  overflow-y: auto;
  box-shadow: var(--shadow-lg);
  animation: rise .18s cubic-bezier(.2, .8, .3, 1);
}
.modal--wide { max-width: 44rem; }
.modal-actions {
  display: flex;
  gap: .5rem;
  justify-content: flex-end;
  margin-top: 1.4rem;
  flex-wrap: wrap;
}

@keyframes fade { from { opacity: 0 } }
@keyframes rise { from { opacity: 0; transform: translateY(8px) scale(.99) } }

.toast {
  position: fixed;
  left: 50%;
  bottom: 1.75rem;
  transform: translate(-50%, 1rem);
  z-index: 70;
  padding: .7rem 1.15rem;
  border-radius: 999px;
  background: var(--ink);
  color: var(--bg);
  font-size: .88rem;
  font-weight: 500;
  box-shadow: var(--shadow-lg);
  opacity: 0;
  pointer-events: none;
  transition: opacity .2s ease, transform .2s ease;
  max-width: min(90vw, 30rem);
  text-align: center;
}
.toast.is-visible { opacity: 1; transform: translate(-50%, 0); }
.toast--error { background: var(--danger); color: #fff; }
.toast--warn { background: var(--gold); color: #fff; }

@media (max-width: 640px) {
  .toast { bottom: 5rem; }
}

/* ---------- loading ---------- */

.skeletons { display: grid; gap: .9rem; }
.skeleton-card {
  display: grid;
  gap: .6rem;
  padding: 1.4rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}
.skeleton {
  display: block;
  height: .75rem;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--bg-sunk) 25%, var(--surface-2) 50%, var(--bg-sunk) 75%);
  background-size: 200% 100%;
  animation: shimmer 1.4s linear infinite;
}
.skeleton--sm { width: 30%; }
.skeleton--md { width: 65%; }
.skeleton--lg { width: 85%; height: 1.2rem; }

@keyframes shimmer { to { background-position: -200% 0 } }

/* ---------- policy page ---------- */

.policy { max-width: 40rem; }
.policy h1 { font-size: clamp(1.9rem, 5vw, 2.4rem); }
.policy h2 {
  margin-top: 2.25rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--line);
}
.policy h3 { margin-top: 1.4rem; font-size: .98rem; }
.policy p, .policy li { color: var(--ink-2); }
.policy ul { padding-left: 1.1rem; }
.policy li { margin-bottom: .45rem; }
.policy__updated { font-size: .84rem; color: var(--ink-3); }

/* ---------- misc ---------- */

.dup-warning { flex-direction: column; }
.dup-warning strong { display: block; margin-bottom: .2rem; }
.dup-warning ul { margin: .5rem 0 0; width: 100%; }
.dup-warning li { padding: .5rem 0; border-top: 1px solid currentColor; }

.report-card__meta { display: flex; gap: .6rem; align-items: center; flex-wrap: wrap; }

@media (max-width: 640px) {
  /* A phone screen is mostly for the notices, so the introduction gives way
     to them rather than filling the first view. */
  .feed-intro { margin-bottom: 1.1rem; }
  .feed-intro h1 { font-size: 1.55rem; }
  .feed-intro p { font-size: .88rem; margin-bottom: 0; }
  .view { padding-top: 1.1rem; }
  .public-notice__title { font-size: 1.2rem; }
  .public-notice__time { font-size: .95rem; }

  .page-head { flex-direction: column; align-items: stretch; }
  .page-head .btn { width: 100%; }
  dl.kv { grid-template-columns: 1fr; gap: .1rem; }
  dl.kv dt { margin-top: .55rem; }
  .form-actions--sticky { flex-direction: column; align-items: stretch; }
  .view { padding-bottom: 5.5rem; }
  .date-heading { top: 3.4rem; }
}

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

/* ---------- motion ----------
 *
 * Everything here animates opacity and transform only, so it stays on the
 * compositor and a mid-range phone scrolling a long feed does no layout work.
 * The reduced-motion block at the end of this file switches all of it off.
 *
 * Content is never hidden by CSS alone: .reveal starts slightly faded, and
 * public/js/motion.js adds .is-revealed. If that script never runs, the rule
 * below its declaration still leaves everything readable, because a broken
 * animation must never mean an unreadable Janazah notice.
 */

.reveal {
  opacity: 0;
  transform: translateY(12px);
  transition: opacity var(--dur-slow) var(--ease), transform var(--dur-slow) var(--ease);
}
.reveal.is-revealed { opacity: 1; transform: none; }
/* Deliberately no will-change. It was hinted here, which meant every row of a
   long feed that had not yet been revealed held its own compositor layer —
   dozens of them on a phone, which is the opposite of what the hint is for.
   Opacity and transform are composited without it. */

/* The safety net: with no JavaScript at all, nothing stays invisible. */
@media (scripting: none) {
  .reveal { opacity: 1; transform: none; }
}

/* Staggered only within a group, and only slightly. A long feed must not
   have the last card waiting on a queue of twenty. */
.reveal:nth-child(2) { transition-delay: .04s; }
.reveal:nth-child(3) { transition-delay: .08s; }
.reveal:nth-child(4) { transition-delay: .12s; }
.reveal:nth-child(5) { transition-delay: .16s; }
.reveal:nth-child(6) { transition-delay: .20s; }
.reveal:nth-child(7) { transition-delay: .24s; }
.reveal:nth-child(8) { transition-delay: .28s; }

/* A route change is the same app moving, not a browser reload. 180ms and
   6px: the most this application should ever do to a page somebody opened to
   find out when a funeral is. Applied by motion.js, which skips it entirely
   under reduced motion rather than relying on the media query below. */
@keyframes pageEnter {
  from { opacity: 0; transform: translateY(6px); }
}
.view.is-entering { animation: pageEnter var(--dur) var(--ease); }

/* ---------- interactive polish ---------- */

.card {
  transition: border-color var(--dur) var(--ease),
              box-shadow var(--dur) var(--ease),
              transform var(--dur) var(--ease);
}
/* Only cards that lead somewhere lift. A static card that moves under the
   cursor suggests it is clickable when it is not. */
.notice-card:hover { box-shadow: var(--shadow); border-color: var(--line-strong); }

.cta-card { transition: transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease); }
.cta-card:hover { transform: translateY(-2px); box-shadow: var(--shadow); }

.btn { transition: background var(--dur-fast) var(--ease),
                   border-color var(--dur-fast) var(--ease),
                   color var(--dur-fast) var(--ease),
                   transform var(--dur-fast) var(--ease),
                   box-shadow var(--dur-fast) var(--ease); }
.btn--primary:hover:not(:disabled) { box-shadow: 0 4px 14px -6px var(--accent); }
.btn:active:not(:disabled) { transform: translateY(1px) scale(.99); }

.link, .btn--link { transition: color var(--dur-fast) var(--ease); }

.tab { transition: background var(--dur) var(--ease), color var(--dur) var(--ease),
                   box-shadow var(--dur) var(--ease); }

.address-result { transition: background var(--dur-fast) var(--ease),
                              color var(--dur-fast) var(--ease); }

/* Following a masjid changes nothing on screen except the word on a button,
   so the button acknowledges the press itself. */
@keyframes followPulse {
  0%   { transform: scale(1); }
  40%  { transform: scale(1.06); }
  100% { transform: scale(1); }
}
.btn--pulse { animation: followPulse .32s var(--ease); }

/* ---------- form feedback ---------- */

.field {
  transition: border-color var(--dur-fast) var(--ease),
              box-shadow var(--dur-fast) var(--ease);
}
.field:focus {
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}

/* An error appearing should register, without shaking the page around. */
@keyframes errorIn { from { opacity: 0; transform: translateY(-4px); } }
.form-error:not([hidden]) { animation: errorIn var(--dur) var(--ease); }

/* ---------- menus and panels ---------- */

@keyframes menuIn { from { opacity: 0; transform: translateY(-6px); } }

/* The drawer slides rather than fading; that transform lives with the layout
   rule so the open and closed states cannot drift apart. */
.account__menu:not([hidden]) { animation: menuIn var(--dur-fast) var(--ease); }
.nav-scrim:not([hidden]) { animation: scrimIn var(--dur) var(--ease); }
@keyframes scrimIn { from { opacity: 0; } }

.address-results { animation: menuIn var(--dur-fast) var(--ease); }

/* The masthead already blurs what passes under it. Flat against the top of an
   unscrolled page that reads correctly; once content is moving beneath it the
   edge has to be visible, or the header looks like part of the article. */
.masthead {
  transition: box-shadow var(--dur) var(--ease), border-color var(--dur) var(--ease);
  border-bottom-color: transparent;
}
body.is-scrolled .masthead {
  border-bottom-color: var(--line);
  box-shadow: 0 1px 12px -6px rgba(0, 0, 0, .35);
}

/* ---------- reduced motion ----------
 *
 * Everything above is decoration. Someone who has asked their system for
 * less movement gets the app with none of it, including the parts CSS alone
 * would not have caught: smooth scrolling, and the reveal's starting state.
 */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .reveal, .reveal.is-revealed {
    opacity: 1;
    transform: none;
    transition: none;
  }
  /* The drawer and the account menu still open and close; they just arrive
     rather than travelling. Removing the transition, not the state. */
  .sidenav, .account__menu, .nav-scrim, .nav-item, .jrow, .qa__item {
    transition: none;
    animation: none;
  }

  /* Everything in the "reactive controls" section is a response to a hover,
     a press or a focus. All of it is switched off here rather than being
     assumed harmless, so this block stays the single place that answers
     "what moves". */
  .view.is-entering,
  .settings-panel.is-entering,
  .home-results:not([hidden]) { animation: none; }

  .btn--primary:hover:not(:disabled),
  .btn--primary:active:not(:disabled),
  .btn--small:active:not(:disabled),
  .mgrid .mrow:hover,
  .qa__item:hover .icon,
  .section-head__link:hover,
  .home-more:hover,
  .account__button:hover .account__avatar,
  .account__button[aria-expanded="true"] .account__caret,
  .sidenav .nav-item:hover .icon {
    transform: none;
  }

  .app-body,
  .slider, .slider.is-settled,
  .masthead,
  .settings-panel.is-entering,
  .settings-nav__item,
  .switch__track, .switch__track::after,
  .nav-item__label,
  .nav-item::before,
  .account__caret,
  .account__avatar,
  .jrow__go, .jrow__org, .mrow, .qa__item .icon,
  .section-head__link, .home-more, .finder__locate,
  .place-picker, .stepper__num, .guide-strip, .check {
    transition: none;
  }
}

/* ---------- Janazah prayer guide ----------
 *
 * Reading conditions this is designed for: a phone, held one-handed, in a
 * hall, by someone who may be about to pray this for the first time and is
 * probably upset. So: large Arabic, generous line-height, short measure, and
 * nothing decorative between the reader and the text.
 */

.guide-head { max-width: 40rem; padding: clamp(1rem, 4vw, 2rem) 0 1.5rem; }
.guide-head h1 { font-size: clamp(1.8rem, 5vw, 2.5rem); line-height: 1.15; }
.guide-head__lede { color: var(--ink-2); font-size: 1.03rem; margin-bottom: 1.25rem; }

.guide-scope { margin-bottom: 2rem; }
.guide-scope p { margin: 0; }

.guide-divider {
  margin: clamp(2rem, 6vw, 3rem) 0 1.25rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--line);
  font-size: 1.4rem;
}

/* ---------- steps ---------- */

.guide-step { margin-bottom: 2rem; max-width: 40rem; }
.guide-step__head { display: flex; align-items: center; gap: .75rem; margin-bottom: .5rem; }
.guide-step__num {
  display: grid;
  place-items: center;
  flex: none;
  width: 2rem;
  height: 2rem;
  border-radius: 999px;
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: 600;
  font-size: .9rem;
}
.guide-step__head h2 { margin: 0; font-size: 1.25rem; }
.guide-step__lede { color: var(--ink-2); }

.guide-points { margin: 1rem 0 0; }
.guide-points dt {
  font-weight: 600;
  color: var(--ink);
  margin-top: 1.1rem;
}
.guide-points dd { margin: .25rem 0 0; color: var(--ink-2); }

/* ---------- a takbir ---------- */

.takbir {
  margin-bottom: 1.25rem;
  padding: clamp(1.1rem, 3.5vw, 1.6rem);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
}
.takbir__head { display: flex; gap: .9rem; align-items: flex-start; }
.takbir__num {
  display: grid;
  place-items: center;
  flex: none;
  width: 2.2rem;
  height: 2.2rem;
  border-radius: 999px;
  background: var(--accent);
  color: var(--accent-ink);
  font-weight: 600;
}
.takbir__label { margin: 0; font-size: 1.1rem; }
.takbir__say {
  font-family: var(--arabic);
  font-size: clamp(1.5rem, 5vw, 1.9rem);
  line-height: 1.9;
  margin: .2rem 0 0;
  color: var(--accent);
}
.takbir__translit { margin: 0; font-size: .95rem; }
.takbir__intro { color: var(--ink-2); margin: 1rem 0 0; }

/* ---------- a recitation ---------- */

.recite {
  margin-top: 1.25rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--line);
}
.recite__title { margin: 0 0 .3rem; font-size: 1rem; font-family: var(--serif); }
.recite__note { color: var(--ink-3); font-size: .88rem; margin: 0 0 .75rem; }

/* The largest text on the page, deliberately. */
.recite__arabic {
  font-family: var(--arabic);
  font-size: clamp(1.45rem, 5.2vw, 1.75rem);
  line-height: 2.15;
  color: var(--ink);
  margin: .5rem 0 1rem;
  padding: 1rem 1.1rem;
  background: var(--surface-2);
  border-radius: var(--radius);
  /* Arabic diacritics sit above and below; without this they clip. */
  overflow-wrap: break-word;
}

.recite__translit {
  color: var(--ink-2);
  font-style: italic;
  font-size: .97rem;
  line-height: 1.75;
  margin: 0 0 .6rem;
}
.recite__meaning { color: var(--ink); margin: 0 0 .6rem; }
.recite__source { color: var(--ink-3); font-size: .82rem; margin: 0; }

.recite--closing { border-top-style: dashed; }

/* ---------- asides ---------- */

.guide-aside {
  margin-top: 1.25rem;
  padding: 1rem 1.15rem;
  border-left: 3px solid var(--accent-line);
  border-radius: var(--radius-sm);
  background: var(--accent-soft);
}
.guide-aside--warm { border-left-color: var(--gold-line); background: var(--gold-soft); }
.guide-aside h4 { margin: 0 0 .4rem; font-size: .98rem; }
.guide-aside p { margin: 0 0 .5rem; font-size: .93rem; }
.guide-aside .hint { margin: 0; }

.pronouns { list-style: none; margin: .75rem 0; padding: 0; display: grid; gap: .4rem; }
.pronouns li {
  display: flex;
  align-items: baseline;
  gap: .75rem;
  flex-wrap: wrap;
  padding: .4rem .6rem;
  background: var(--surface);
  border-radius: var(--radius-sm);
}
.pronouns__who { flex: 1 1 8rem; font-size: .9rem; color: var(--ink-2); }
.pronouns__ar { font-family: var(--arabic); font-size: 1.3rem; line-height: 1.8; }
.pronouns__tr { font-style: italic; color: var(--ink-3); font-size: .9rem; }

/* ---------- quick reference ---------- */

.quick-ref {
  margin: clamp(2rem, 6vw, 3rem) 0 2rem;
  padding: clamp(1.25rem, 4vw, 1.75rem);
  background: var(--accent-soft);
  border: 1px solid var(--accent-line);
  border-radius: var(--radius-lg);
  scroll-margin-top: 5rem;
}
.quick-ref h2 { margin: 0 0 .25rem; }
.quick-ref__list { list-style: none; margin: 1.25rem 0 0; padding: 0; display: grid; gap: .6rem; }
.quick-ref__list li {
  display: flex;
  align-items: flex-start;
  gap: .75rem;
  padding: .8rem .9rem;
  background: var(--surface);
  border-radius: var(--radius);
}
.quick-ref__num {
  display: grid;
  place-items: center;
  flex: none;
  width: 1.7rem;
  height: 1.7rem;
  border-radius: 999px;
  background: var(--accent);
  color: var(--accent-ink);
  font-size: .8rem;
  font-weight: 600;
}
.quick-ref__what { display: block; color: var(--ink-2); font-size: .92rem; }

/* ---------- homepage invitation ---------- */

.guide-invite {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.25rem;
  flex-wrap: wrap;
  margin-bottom: 2rem;
  padding: clamp(1.25rem, 4vw, 1.75rem);
  background: var(--surface-2);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
}
.guide-invite__body { flex: 1 1 20rem; }
.guide-invite h2 { margin: 0 0 .35rem; font-size: 1.15rem; }
.guide-invite p { margin: 0; font-size: .94rem; }

.guide-foot {
  margin-top: 2.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--line);
}

@media (max-width: 640px) {
  .takbir__head { gap: .7rem; }
  .recite__arabic { padding: .9rem .8rem; }
  .guide-invite .btn { width: 100%; }
}

/* ---------------------------------------------------------------------------
   Multi-step organization registration.

   Four short passes instead of one intimidating page. The stepper exists so
   somebody halfway through knows how much is left; a form of this length with
   no end in sight gets abandoned, and an abandoned registration means a masjid
   that cannot publish a Janazah notice.
   --------------------------------------------------------------------------- */

.stepper {
  display: flex;
  flex-wrap: wrap;
  gap: .4rem 1.1rem;
  list-style: none;
  margin: 0 0 1.6rem;
  padding: 0;
}

.stepper__item {
  display: flex;
  align-items: center;
  gap: .5rem;
  font-size: .86rem;
  color: var(--muted);
}

.stepper__num {
  display: grid;
  place-items: center;
  width: 1.6rem;
  height: 1.6rem;
  border-radius: 50%;
  border: 1px solid var(--line);
  font-size: .78rem;
  font-variant-numeric: tabular-nums;
}

.stepper__item.is-current { color: var(--text); font-weight: 600; }
.stepper__item.is-current .stepper__num {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
}

.stepper__item.is-done .stepper__num {
  border-color: var(--accent);
  color: var(--accent);
}
/* A tick rather than the number, so completed steps read at a glance. */
.stepper__item.is-done .stepper__num { font-size: 0; }
.stepper__item.is-done .stepper__num::after { content: "✓"; font-size: .8rem; }

@media (max-width: 30rem) {
  /* On a narrow screen the labels wrap into an unreadable stack; the numbers
     alone still answer "how much is left". */
  .stepper__label { display: none; }
  .stepper { gap: .5rem; }
}

.step > h2 { margin-top: 0; }
.step + .step { margin-top: 0; }

/* A read-only value that should still line up with the real fields. */
.field--static {
  margin: 0;
  padding: .55rem .7rem;
  border: 1px dashed var(--line);
  border-radius: var(--radius-sm, 8px);
  background: transparent;
  color: var(--muted);
}

.check-list {
  display: grid;
  gap: .2rem;
  margin-bottom: 1.2rem;
}

.check--consent {
  margin-top: 1.2rem;
  padding: .9rem 1rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm, 8px);
  background: var(--surface-2, transparent);
}

.review-summary h3 {
  margin: 1.4rem 0 .5rem;
  font-size: .82rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted);
}

.review-summary dl { margin: 0; }

.review-row {
  display: grid;
  grid-template-columns: minmax(7rem, 30%) 1fr;
  gap: .3rem 1rem;
  padding: .45rem 0;
  border-top: 1px solid var(--line);
}

.review-row dt { color: var(--muted); font-size: .88rem; }
.review-row dd { margin: 0; overflow-wrap: anywhere; }

@media (max-width: 30rem) {
  .review-row { grid-template-columns: 1fr; gap: .1rem; }
}

.review-list { margin: .2rem 0 0; padding-left: 1.1rem; }
.review-list li { margin: .2rem 0; }

/* Verification signals in the admin portal.

   Colour carries emphasis, never a verdict: an amber signal means "check
   this", not "reject this". There is deliberately no green-means-approve
   treatment, because a reviewer who reads the colour instead of the sentence
   is the failure mode this whole panel exists to prevent. */

.signal-list { list-style: none; margin: 0 0 1.4rem; padding: 0; display: grid; gap: .6rem; }

.signal {
  padding: .7rem .9rem;
  border-left: 3px solid var(--line);
  background: var(--surface-2, transparent);
  border-radius: 0 var(--radius-sm, 8px) var(--radius-sm, 8px) 0;
}

.signal strong { display: block; font-size: .92rem; }
.signal p { margin: .25rem 0 0; font-size: .86rem; }

.signal--match { border-left-color: var(--ok, #2f7d4f); }
.signal--public,
.signal--mismatch { border-left-color: var(--warn, #b7791f); }
.signal--unknown { border-left-color: var(--line); }

.hint--error { color: var(--error, #b3261e); }

/* ---------------------------------------------------------------------------
   The home page.

   An index, not a pitch. Somebody opening this has usually just been told a
   Janazah is happening, often today, often while driving somewhere. So the
   first screen carries content rather than an argument: a search box, then
   the actual notices. The explanation of what this service is lives on
   /about, where somebody who wants it will go looking.

   Everything below is built from rows, rules and small chips instead of a
   grid of cards. Rows scan in a hurry; a page of rounded boxes does not.
   --------------------------------------------------------------------------- */

.home-head {
  padding-bottom: 1.4rem;
  border-bottom: 1px solid var(--line);
  margin-bottom: 1.6rem;
}

.home-head__title {
  font-family: var(--serif);
  /* Restrained on purpose. The old headline was the size of the screen, which
     put the actual notices below the fold on every phone. */
  font-size: clamp(1.5rem, 3.4vw, 1.95rem);
  line-height: 1.15;
  letter-spacing: -0.02em;
  margin: 0 0 .35rem;
}

.home-head__sub {
  margin: 0 0 1.1rem;
  color: var(--ink-3);
  font-size: .92rem;
  max-width: 34rem;
}

.finder {
  display: flex;
  align-items: center;
  gap: .5rem;
  flex-wrap: wrap;
}

.finder__field {
  display: flex;
  align-items: center;
  gap: .55rem;
  flex: 1 1 18rem;
  min-width: 0;
  padding: 0 .8rem;
  height: 2.7rem;
  border: 1px solid var(--line-strong);
  border-radius: 10px;
  background: var(--surface);
  transition: border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
.finder__field:focus-within {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.finder__field .icon { flex: none; color: var(--ink-3); }

.finder__input {
  flex: 1;
  min-width: 0;
  border: 0;
  background: none;
  color: var(--ink);
  font: inherit;
  font-size: .94rem;
  outline: none;
}
.finder__input::placeholder { color: var(--ink-3); }
.finder__input::-webkit-search-cancel-button { filter: grayscale(1) opacity(.6); }

.finder__locate { flex: none; height: 2.7rem; }

.home-section { margin-bottom: 2.2rem; }
.home-results:not([hidden]) { margin-bottom: 2.2rem; }

.section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: .75rem;
}
.section-head__title {
  font-family: var(--serif);
  font-size: 1.02rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin: 0;
}
.section-head__link {
  font-size: .84rem;
  color: var(--ink-3);
  text-decoration: none;
  white-space: nowrap;
}
.section-head__link:hover { color: var(--accent); text-decoration: underline; }

/* ---------- a Janazah, as a row ---------- */

.jlist, .mlist, .mgrid, .qa {
  list-style: none;
  margin: 0;
  padding: 0;
}

.jlist { border-top: 1px solid var(--line); }

.jrow {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .85rem .25rem;
  border-bottom: 1px solid var(--line);
  border-radius: 8px;
  transition: background var(--dur-fast) var(--ease);
}
.jrow:hover { background: var(--surface-2); }
.jrow--cancelled { opacity: .68; }

.jrow__main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: .25rem;
  padding: 0 .5rem;
  color: inherit;
  text-decoration: none;
}

.jrow__top { display: flex; align-items: center; gap: .4rem; flex-wrap: wrap; }
.jrow__org {
  font-weight: 600;
  font-size: .96rem;
  color: var(--ink);
}

.jrow__time,
.jrow__where {
  display: flex;
  align-items: flex-start;
  gap: .4rem;
  margin: 0;
  font-size: .875rem;
  color: var(--ink-2);
}
.jrow__time .icon,
.jrow__where .icon { flex: none; margin-top: .12rem; color: var(--ink-3); }
.jrow__time span { font-variant-numeric: tabular-nums; }

.jrow__place { display: block; }
.jrow__addr { display: block; color: var(--ink-3); font-size: .84rem; }
.jrow__burial { margin: 0; font-size: .82rem; color: var(--ink-3); }

.jrow__go { flex: none; }

/* ---------- chips ---------- */

.chip {
  display: inline-flex;
  align-items: center;
  gap: .22rem;
  padding: .1rem .45rem;
  border: 1px solid var(--line);
  border-radius: 5px;
  background: var(--surface-2);
  color: var(--ink-3);
  font-size: .72rem;
  font-weight: 500;
  letter-spacing: .01em;
  white-space: nowrap;
}
.chip--verified {
  border-color: var(--accent-line);
  background: var(--accent-soft);
  color: var(--accent);
}
.chip--danger {
  border-color: var(--danger-line);
  background: var(--danger-soft);
  color: var(--danger);
}

/* ---------- masjids ---------- */

.mlist { border-top: 1px solid var(--line); }
.mlist .mrow { border-bottom: 1px solid var(--line); }

.mgrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
  gap: .5rem;
}
.mgrid .mrow {
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface);
}

.mrow { transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease); }
.mrow:hover { background: var(--surface-2); }
.mgrid .mrow:hover { border-color: var(--line-strong); }

.mrow__main {
  display: flex;
  flex-direction: column;
  gap: .2rem;
  padding: .7rem .75rem;
  color: inherit;
  text-decoration: none;
}
.mrow__name { font-weight: 600; font-size: .92rem; color: var(--ink); }
.mrow__meta {
  display: flex;
  align-items: center;
  gap: .4rem;
  flex-wrap: wrap;
  margin: .1rem 0 .15rem;
  font-size: .82rem;
  color: var(--ink-3);
}
.mrow__next { margin: 0; font-size: .84rem; color: var(--ink-2); font-variant-numeric: tabular-nums; }
.mrow__next--none { color: var(--ink-3); }

/* ---------- prompts and empties ---------- */
/* A prompt asks for something (location, a follow). An empty reports a fact.
   They look different so that "nothing here yet" is not mistaken for
   "you have to do something". */

.prompt {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  padding: .95rem 1.05rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--surface);
}
.prompt__body { flex: 1 1 18rem; min-width: 0; }
.prompt__lede { margin: 0 0 .2rem; font-size: .92rem; color: var(--ink); }
.prompt__note { margin: 0; font-size: .8rem; color: var(--ink-3); }

.home-empty {
  padding: .9rem 0;
  border-top: 1px solid var(--line);
  font-size: .9rem;
  color: var(--ink-2);
}
.home-empty p { margin: 0 0 .25rem; }
.home-empty p:last-child { margin-bottom: 0; }

.home-note {
  margin: 0 0 .6rem;
  font-size: .82rem;
  color: var(--ink-3);
}

.home-more {
  display: inline-block;
  margin-top: .6rem;
  font-size: .84rem;
  color: var(--ink-3);
  text-decoration: none;
}
.home-more:hover { color: var(--accent); text-decoration: underline; }

/* ---------- quick actions ---------- */

.qa {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
  gap: .4rem;
}
.qa__item {
  display: flex;
  align-items: center;
  gap: .55rem;
  padding: .65rem .8rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  color: var(--ink-2);
  font-size: .88rem;
  text-decoration: none;
  transition: background var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease),
              color var(--dur-fast) var(--ease);
}
.qa__item .icon { color: var(--ink-3); flex: none; }
.qa__item:hover {
  background: var(--surface-2);
  border-color: var(--line-strong);
  color: var(--ink);
}
.qa__item:hover .icon { color: var(--accent); }

/* ---------- the guide ---------- */

.guide-strip {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  padding: 1.1rem 1.2rem;
  border: 1px solid var(--accent-line);
  border-radius: 12px;
  background: var(--accent-soft);
}
.guide-strip__title {
  font-family: var(--serif);
  font-size: 1.02rem;
  margin: 0 0 .2rem;
  color: var(--ink);
}
.guide-strip__sub { margin: 0; font-size: .86rem; color: var(--ink-2); }

@media (max-width: 560px) {
  /* Stacked, not squeezed: the directions button keeps a full tap target
     instead of becoming a sliver beside the text. */
  .jrow { align-items: stretch; flex-direction: column; gap: .5rem; }
  .jrow__go { align-self: flex-start; margin-left: .5rem; }
  .finder__locate { flex: 1 1 100%; justify-content: center; }
  .prompt, .guide-strip { align-items: stretch; }
}

/* ---------------------------------------------------------------------------
   Reactive controls.

   The rule this follows: motion confirms something the person did, or it does
   not happen. A control that moves on its own, glows, or animates to draw
   attention has no place on a page about a funeral. Everything below is a
   response to a hover, a press, or a keyboard focus, and all of it is short.
   --------------------------------------------------------------------------- */

/* Keyboard focus, everywhere, in one place. Visible enough to follow with the
   eye and never shown to somebody using a mouse. */
.btn:focus-visible,
.nav-item:focus-visible,
.account__button:focus-visible,
.account__item:focus-visible,
.qa__item:focus-visible,
.jrow__main:focus-visible,
.mrow__main:focus-visible,
.section-head__link:focus-visible,
.tab:focus-visible,
.link:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 8px;
}

/* A press should be felt. Primary actions lift slightly on hover and settle
   under the finger; the lift is 1px, not a bounce. */
.btn--primary:hover:not(:disabled) { transform: translateY(-1px); }
.btn--primary:active:not(:disabled) { transform: translateY(0) scale(.985); }
.btn--small:active:not(:disabled) { transform: scale(.97); }

/* A control that is working says so by dimming, rather than by staying
   identical while nothing appears to happen. */
.btn:disabled { transition: opacity var(--dur) var(--ease); }

/* ---------- home page ---------- */

/* The row itself lifts nothing; the surface behind it warms and its
   directions button steps forward. A whole row that moves under the cursor
   makes a list feel unstable to scan. */
.jrow {
  transition: background var(--dur-fast) var(--ease),
              box-shadow var(--dur-fast) var(--ease);
}
.jrow:hover { box-shadow: inset 2px 0 0 var(--accent-line); }
.jrow__go { transition: background var(--dur-fast) var(--ease),
                        border-color var(--dur-fast) var(--ease),
                        transform var(--dur-fast) var(--ease); }
.jrow:hover .jrow__go {
  border-color: var(--accent-line);
  background: var(--accent-soft);
  color: var(--accent);
}
.jrow__org { transition: color var(--dur-fast) var(--ease); }
.jrow:hover .jrow__org { color: var(--accent); }

.mrow { transition: background var(--dur-fast) var(--ease),
                    border-color var(--dur-fast) var(--ease),
                    transform var(--dur) var(--ease); }
.mgrid .mrow:hover { transform: translateY(-2px); box-shadow: var(--shadow-sm); }

/* The icon leads the eye into the action. Two pixels. */
.qa__item .icon { transition: color var(--dur-fast) var(--ease),
                              transform var(--dur) var(--ease); }
.qa__item:hover .icon { transform: translateX(2px); }

.section-head__link {
  transition: color var(--dur-fast) var(--ease), transform var(--dur) var(--ease);
}
.section-head__link:hover { transform: translateX(2px); }

.home-more { transition: color var(--dur-fast) var(--ease), transform var(--dur) var(--ease); }
.home-more:hover { transform: translateX(2px); }

.finder__locate { transition: background var(--dur-fast) var(--ease),
                              border-color var(--dur-fast) var(--ease),
                              transform var(--dur-fast) var(--ease); }
.finder__locate:hover:not(:disabled) {
  border-color: var(--accent-line);
  background: var(--accent-soft);
  color: var(--accent);
}

.guide-strip { transition: border-color var(--dur) var(--ease); }
.guide-strip:hover { border-color: var(--accent); }

/* Search results replacing the page should arrive, not blink into place. */
.home-results:not([hidden]) { animation: pageEnter var(--dur) var(--ease); }

/* ---------- sidebar ---------- */

/* The active section is marked by a bar that grows from nothing rather than
   a background that snaps on. */
.nav-item { position: relative; }
.nav-item::before {
  content: "";
  position: absolute;
  left: .18rem;
  top: 50%;
  width: 2px;
  height: 0;
  border-radius: 2px;
  background: var(--accent);
  transform: translateY(-50%);
  transition: height var(--dur) var(--ease);
}
.nav-item--active::before { height: 1.1rem; }
.sidenav .nav-item:hover::before { height: .7rem; background: var(--line-strong); }
.sidenav .nav-item--active:hover::before { height: 1.1rem; background: var(--accent); }
/* The console's horizontal bar has no room for a left rule. */
.nav .nav-item::before { display: none; }

.nav-item .icon { transition: transform var(--dur) var(--ease); }
.sidenav .nav-item:hover .icon { transform: translateX(1px); }

/* ---------- account menu ---------- */

.account__avatar { transition: background var(--dur-fast) var(--ease),
                               transform var(--dur-fast) var(--ease); }
.account__button:hover .account__avatar { transform: scale(1.04); }
.account__caret { transition: transform var(--dur) var(--ease); }
.account__button[aria-expanded="true"] .account__caret { transform: rotate(180deg); }

/* ---------- forms and the composer ---------- */

.place-picker { transition: border-color var(--dur) var(--ease); }
.place-picker:focus-within { border-color: var(--accent-line); }

.check { transition: color var(--dur-fast) var(--ease); }
.check:hover { color: var(--ink); }

/* The stepper's completed marks fill in rather than appearing. */
.stepper__num { transition: background var(--dur) var(--ease),
                            border-color var(--dur) var(--ease),
                            color var(--dur) var(--ease); }

/* ---------------------------------------------------------------------------
   Settings.

   A menu down the side and one section at a time, rather than one long card.
   The point is that somebody looking for the alert distance can see where it
   lives without reading everything else on the way there.
   --------------------------------------------------------------------------- */

.settings {
  display: grid;
  grid-template-columns: 12.5rem minmax(0, 1fr);
  gap: 2rem;
  align-items: start;
}

.settings-nav {
  position: sticky;
  top: 4.5rem;
  display: flex;
  flex-direction: column;
  gap: .1rem;
}

.settings-nav__item {
  display: flex;
  align-items: center;
  gap: .6rem;
  padding: .5rem .65rem;
  border: 0;
  border-radius: 9px;
  background: none;
  color: var(--ink-2);
  font: inherit;
  font-size: .9rem;
  text-align: left;
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
}
.settings-nav__item .icon { flex: none; opacity: .7; }
.settings-nav__item:hover:not(.is-active) { background: var(--surface-2); color: var(--ink); }
.settings-nav__item.is-active {
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: 600;
}
.settings-nav__item.is-active .icon { opacity: 1; }

.settings-panel { min-width: 0; }
/* Switching section moves the panel, not the page: the menu stays put and the
   scroll position is kept. */
.settings-panel.is-entering { animation: pageEnter var(--dur) var(--ease); }

.set-group { margin-bottom: 2.2rem; }
.set-group__title {
  margin: 0 0 .2rem;
  font-family: var(--serif);
  font-size: 1.02rem;
}
.set-group > .hint { margin-top: .5rem; }

.set-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.25rem;
  padding: .85rem 0;
  border-bottom: 1px solid var(--line);
}
.set-row__text { min-width: 0; }
.set-row__label { margin: 0; font-size: .93rem; color: var(--ink); }
.set-row__desc { margin: .15rem 0 0; font-size: .82rem; color: var(--ink-3); }
.set-row__value { color: var(--ink-2); overflow-wrap: anywhere; }
.set-row__control { flex: none; display: flex; align-items: center; gap: .5rem; }

.set-actions { display: flex; gap: .5rem; flex-wrap: wrap; padding: .85rem 0 0; }

.set-identity { display: flex; align-items: center; gap: .9rem; margin: .8rem 0 .2rem; }
.set-avatar {
  display: grid;
  place-items: center;
  width: 3rem;
  height: 3rem;
  flex: none;
  border-radius: 50%;
  object-fit: cover;
}
.set-avatar--initials {
  background: var(--accent-soft);
  color: var(--accent);
  font-weight: 700;
  font-size: 1rem;
}
.set-identity__name { margin: 0; font-weight: 600; }
.set-identity__mail { margin: .1rem 0 0; font-size: .85rem; color: var(--ink-3); overflow-wrap: anywhere; }

/* A real checkbox, drawn as a switch. Keyboard-reachable and announced as a
   switch; the visible part is decoration over it. */
.switch { display: inline-flex; cursor: pointer; }
.switch__input {
  position: absolute;
  width: 1px; height: 1px;
  opacity: 0;
  margin: 0;
}
.switch__track {
  position: relative;
  display: block;
  width: 2.5rem;
  height: 1.4rem;
  border-radius: 999px;
  background: var(--surface-2);
  border: 1px solid var(--line-strong);
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.switch__track::after {
  content: "";
  position: absolute;
  top: 50%;
  left: .17rem;
  width: 1rem;
  height: 1rem;
  border-radius: 50%;
  background: var(--ink-3);
  transform: translateY(-50%);
  transition: transform var(--dur) var(--ease), background var(--dur) var(--ease);
}
.switch__input:checked + .switch__track {
  background: var(--accent);
  border-color: var(--accent);
}
.switch__input:checked + .switch__track::after {
  transform: translateY(-50%) translateX(1.05rem);
  background: var(--accent-ink);
}
.switch__input:focus-visible + .switch__track {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

@media (max-width: 760px) {
  /* Stacked, with the menu across the top as a scrollable row. A sidebar at
     this width would leave the settings themselves in a column too narrow to
     put a label and a control on the same line. */
  .settings { grid-template-columns: minmax(0, 1fr); gap: 1.25rem; }
  /* relative rather than static: still not sticky at this width, but the
     marker needs something to be positioned against. top: 0 matters here —
     left at the desktop rule's 4.5rem (a sticky *threshold* there, harmless)
     it becomes a literal offset under relative and drops this row onto the
     panel beneath it. */
  .settings-nav {
    position: relative;
    top: 0;
    flex-direction: row;
    gap: .3rem;
    overflow-x: auto;
    padding-bottom: .5rem;
    border-bottom: 1px solid var(--line);
    scrollbar-width: none;
  }
  .settings-nav::-webkit-scrollbar { display: none; }
  .settings-nav__item { white-space: nowrap; }
  .set-row { align-items: flex-start; flex-direction: column; gap: .6rem; }
  .set-row__control { align-self: flex-start; }
}

/* ---------- two-factor setup ---------- */

.mfa__lede { font-size: .95rem; margin-bottom: .75rem; }
.mfa__steps { margin: 0 0 1.1rem; padding-left: 1.2rem; font-size: .88rem; color: var(--ink-2); }
.mfa__steps li { margin: .3rem 0; }

.mfa__qr {
  display: grid;
  place-items: center;
  padding: 1rem;
  margin-bottom: 1rem;
  /* White, always. A QR code tinted to match the page is a QR code some
     cameras will not read. */
  background: #ffffff;
  border-radius: var(--radius);
  border: 1px solid var(--line);
}
.qr { display: block; }

.mfa__manual { margin-bottom: 1.1rem; }
.mfa__manual summary { cursor: pointer; font-size: .88rem; color: var(--accent); }
.mfa__key {
  margin: .4rem 0 .3rem;
  padding: .6rem .7rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  font-size: .95rem;
  letter-spacing: .06em;
  overflow-wrap: anywhere;
  user-select: all;
}

.mfa--done { text-align: center; }
.mfa__tick {
  display: grid;
  place-items: center;
  width: 3.2rem;
  height: 3.2rem;
  margin: .2rem auto 1rem;
  border-radius: 50%;
  background: var(--accent-soft);
  color: var(--accent);
}

#totp-code, #mfa-code {
  font-size: 1.3rem;
  letter-spacing: .32em;
  text-align: center;
  font-family: var(--mono);
}

/* ---------------------------------------------------------------------------
   The sliding marker.

   One highlight that travels between tabs rather than a highlight that is
   repainted somewhere else. On the widest jump — leftmost tab to rightmost —
   a repaint gives the eye no clue that anything moved; this shows the whole
   distance. Placed by indicator.js, which measures the current item.
   --------------------------------------------------------------------------- */

.slider {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 0;
  border-radius: 999px;
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  pointer-events: none;
  /* No transition until the first placement has happened, so it appears where
     it belongs instead of sliding in from the corner. */
  transition: opacity var(--dur-fast) var(--ease);
}
/* Its own easing rather than the app's --ease, which is heavily front-loaded:
   over a short hop that reads as crisp, but across the full width of a
   segmented control it arrives before the eye has followed it, which is the
   thing this replaced. This one spreads the travel more evenly so the
   distance is actually seen. */
.slider.is-settled {
  --slide: .34s cubic-bezier(.4, 0, .2, 1);
  transition: transform var(--slide), width var(--slide), height var(--slide),
              opacity var(--dur-fast) var(--ease);
}
/* The buttons sit above the marker; without this it covers their labels. */
.has-slider > *:not(.slider) { position: relative; z-index: 1; }

/* The settings menu is a column on a desktop and a row on a phone. The marker
   carries both offsets and both dimensions, so it follows either without
   knowing which one it is in.

   No `position: relative` here: the menu is already `position: sticky`, which
   is a positioned element and therefore the containing block the marker needs.
   Setting relative would have quietly cancelled the sticky and let the menu
   scroll away with the page. */
.settings-nav .slider {
  border-radius: 9px;
  background: var(--accent-soft);
  box-shadow: none;
}
.settings-nav:not(.has-slider) .settings-nav__item.is-active { background: var(--accent-soft); }
.settings-nav.has-slider .settings-nav__item.is-active { background: none; }

/* The console's own bar, same treatment. */
.nav { position: relative; }
.nav .slider { border-radius: 999px; background: var(--accent-soft); box-shadow: none; }
.nav:not(.has-slider) .nav-item--active { background: var(--accent-soft); }
.nav.has-slider .nav-item--active { background: none; }

/* ---------------------------------------------------------------------------
   Long pages.

   content-visibility: auto was tried here and removed. It does skip layout and
   paint for rows nobody is looking at, but a skipped row is not rendered, and
   an unrendered row's text is absent from innerText — so a notice off the
   bottom of the screen quietly stopped existing as far as anything reading the
   page was concerned. On lists this length the saving was not worth a rule
   that changes what the page says it contains.

   Containment on the list itself has no such cost: it stops a row changing
   from forcing layout of the whole column, and affects nothing readable.
   --------------------------------------------------------------------------- */

.stack, .jlist, .mgrid, .mlist { contain: layout style; }

/* ---------------------------------------------------------------------------
   The welcome page.

   Shown once, to somebody who has been sent a link and does not yet know
   whether to trust it. It is allowed more room than the rest of the app —
   this is the one screen whose job is to make a case — but the restraint
   holds: this is a service about funerals, and a page that performs at
   somebody who has just been bereaved would be the wrong thing entirely.

   The scroll effects are CSS scroll-driven animation where the browser has
   it, and simply absent where it does not. No scroll listener, no library,
   nothing running on the main thread while a long page moves.
   --------------------------------------------------------------------------- */

.welcome {
  max-width: 46rem;
  margin: 0 auto;
}

/* A hairline that fills as the page is read. Decoration, and it says so: it
   is aria-hidden and carries no information the page does not. */
.wel-progress {
  position: fixed;
  top: 0;
  left: 0;
  height: 2px;
  width: 100%;
  transform-origin: 0 50%;
  transform: scaleX(0);
  background: var(--accent);
  opacity: .7;
  z-index: 50;
  pointer-events: none;
}

@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    .wel-progress {
      animation: welProgress linear both;
      animation-timeline: scroll(root block);
    }
  }
}
@keyframes welProgress { to { transform: scaleX(1); } }

/* ---------- the opening ---------- */

.wel-hero {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: min(78vh, 40rem);
  padding: 2rem 0 3rem;
}

.wel-hero__eyebrow {
  margin: 0 0 1.25rem;
  font-family: var(--serif);
  font-size: .95rem;
  letter-spacing: .04em;
  color: var(--accent);
}

.wel-hero__title {
  font-family: var(--serif);
  /* Larger than anywhere else in the app, and still nowhere near the
     screen-filling headline this replaced on the home page. */
  font-size: clamp(2rem, 6vw, 3.1rem);
  line-height: 1.12;
  letter-spacing: -0.03em;
  margin: 0 0 1.25rem;
}
.wel-hero__line { display: block; }

.wel-hero__lede {
  margin: 0 0 1.9rem;
  max-width: 30rem;
  font-size: 1.05rem;
  color: var(--ink-2);
}

.wel-hero__actions { display: flex; gap: .7rem; flex-wrap: wrap; margin-bottom: 1rem; }
.wel-hero__note { margin: 0; font-size: .86rem; color: var(--ink-3); }

/* Three lines that arrive one after another, and the whole opening drifting
   up as it is scrolled past. Both are opacity and transform only. */
@media (prefers-reduced-motion: no-preference) {
  .wel-hero__eyebrow,
  .wel-hero__line,
  .wel-hero__lede,
  .wel-hero__actions,
  .wel-hero__note {
    animation: welRise .7s var(--ease) both;
  }
  .wel-hero__line:nth-child(1) { animation-delay: .06s; }
  .wel-hero__line:nth-child(2) { animation-delay: .14s; }
  .wel-hero__line:nth-child(3) { animation-delay: .22s; }
  .wel-hero__lede { animation-delay: .34s; }
  .wel-hero__actions { animation-delay: .42s; }
  .wel-hero__note { animation-delay: .5s; }
}
@keyframes welRise {
  from { opacity: 0; transform: translateY(14px); }
}

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    /* Leaving the top of the screen, the opening fades rather than sliding
       away under the header. */
    .wel-hero__title,
    .wel-hero__lede {
      animation: welFade linear both;
      animation-timeline: view(block);
      animation-range: exit 0% exit 70%;
    }
  }
}
@keyframes welFade { to { opacity: .15; transform: translateY(-10px); } }

.wel-scroll {
  display: block;
  width: 1px;
  height: 3rem;
  margin-top: 2.5rem;
  overflow: hidden;
}
.wel-scroll__line {
  display: block;
  width: 1px;
  height: 100%;
  background: linear-gradient(var(--line-strong), transparent);
}
@media (prefers-reduced-motion: no-preference) {
  .wel-scroll__line { animation: welTrickle 2.4s var(--ease) infinite; }
}
@keyframes welTrickle {
  0%   { transform: translateY(-100%); }
  60%, 100% { transform: translateY(100%); }
}

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

.wel-eyebrow {
  margin: 0 0 1rem;
  font-family: var(--sans);
  font-size: .76rem;
  font-weight: 600;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.wel-section__title {
  font-family: var(--serif);
  font-size: clamp(1.3rem, 3vw, 1.7rem);
  line-height: 1.25;
  letter-spacing: -0.02em;
  margin: 0 0 .9rem;
}

.wel-proof,
.wel-how,
.wel-privacy,
.wel-org,
.wel-end { padding: 3.5rem 0; border-top: 1px solid var(--line); }

.wel-proof__list .jlist { border-top: 0; }

/* ---------- how it works ---------- */

.wel-steps { list-style: none; margin: 2rem 0 0; padding: 0; }

.wel-step {
  display: flex;
  gap: 1.25rem;
  padding-bottom: 2rem;
  position: relative;
}
/* A line joining the numbers, so the three read as a sequence rather than
   three cards that happen to be stacked. */
.wel-step:not(:last-child)::before {
  content: "";
  position: absolute;
  left: 1.1rem;
  top: 2.6rem;
  bottom: .6rem;
  width: 1px;
  background: var(--line);
}
.wel-step__num {
  display: grid;
  place-items: center;
  width: 2.2rem;
  height: 2.2rem;
  flex: none;
  border-radius: 50%;
  border: 1px solid var(--accent-line);
  background: var(--accent-soft);
  color: var(--accent);
  font-size: .85rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.wel-step__title { margin: .3rem 0 .35rem; font-size: 1.02rem; }
.wel-step__body { margin: 0; color: var(--ink-2); font-size: .95rem; }

/* ---------- privacy ---------- */

.wel-privacy__body { color: var(--ink-2); max-width: 34rem; }

.wel-facts { list-style: none; margin: 1.6rem 0 1.2rem; padding: 0; display: grid; gap: .8rem; }
.wel-fact { display: flex; gap: .7rem; align-items: flex-start; }
.wel-fact .icon { flex: none; margin-top: .2rem; color: var(--accent); }
.wel-fact strong { display: block; font-size: .95rem; }
.wel-fact span { font-size: .88rem; color: var(--ink-3); }

/* ---------- masjids ---------- */

.wel-org {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  flex-wrap: wrap;
}
.wel-org__body { margin: 0; color: var(--ink-2); max-width: 30rem; font-size: .95rem; }

/* ---------- closing ---------- */

.wel-end { text-align: center; padding-bottom: 5rem; }
.wel-end__title {
  font-family: var(--arabic);
  font-size: clamp(1.5rem, 4.5vw, 2.1rem);
  line-height: 1.9;
  direction: rtl;
  margin: 0 0 .5rem;
}
.wel-end__translit { margin: 0 0 .2rem; color: var(--ink-2); font-size: .95rem; }
.wel-end__meaning { margin: 0 0 .4rem; color: var(--ink-3); font-size: .9rem; }
.wel-end__source { margin: 0 0 2rem; color: var(--ink-3); font-size: .8rem; opacity: .8; }
.wel-end__actions { display: flex; gap: .7rem; justify-content: center; flex-wrap: wrap; }
.wel-end__note { margin: 1.6rem 0 0; font-size: .86rem; color: var(--ink-3); }

@media (max-width: 600px) {
  .wel-hero { min-height: min(70vh, 32rem); }
  .wel-hero__actions .btn { flex: 1 1 auto; justify-content: center; }
  .wel-org { align-items: stretch; }
}

/* ---------------------------------------------------------------------------
   Mobile touch and input handling.

   Two problems that only show up on a real phone, not in a resized desktop
   browser, so they get their own block rather than living beside the rules
   they adjust:

   1. Any text input under 16px triggers iOS Safari's zoom-on-focus. .field
      is .95rem, which is 15.2px at the default root size — just under the
      line, and easy to miss on a laptop where nothing zooms. Bumped to a
      true 16px here rather than everywhere, since desktop has no such limit
      and the rest of the type scale is deliberately tuned for it.
   2. A button or tab sized for a mouse pointer is smaller than a fingertip.
      44px is the common comfortable-tap-target figure (Apple's own HIG and
      the WCAG 2.5.5 target-size guidance both land near it); most controls
      here already clear it once padding is added to their line-height, but
      the smaller variants do not, so this raises only what needs it. */
@media (max-width: 640px) {
  .field, select.field, textarea.field {
    font-size: 16px;
  }
  #totp-code, #mfa-code {
    /* Already large and centred; kept in step with the rule above rather
       than left at a value that happens to already clear it. */
    font-size: max(1.3rem, 16px);
  }

  .btn, .tab, .nav-item, .account__button, .settings-nav__item,
  .qa__item, .jrow__go, .finder__locate {
    min-height: 2.75rem;
  }
  .btn--small { min-height: 2.25rem; }
  .check input, .switch__track { flex: none; }
  /* The switch itself stays its visual size; the row around it gets the
     room instead, so the control everyone recognises does not grow. */
  .set-row__control { min-height: 2.75rem; align-items: center; }

  /* .field--inline sizes to its content on a desktop, which is fine for a
     short option list. The notices tab's organization picker can hold a
     long masjid name, and a <select> does not wrap that text — it just
     keeps growing, taking the page past the edge of the phone with it.
     max-width alone does not stop this: shrink-to-fit still floors the box
     at the content's own width. An explicit width does, because at that
     point the browser clips the label inside the control instead of
     resizing around it. Full width also means one column instead of a
     label and a control competing for the same narrow row. */
  .field--inline { display: block; width: 100%; margin-top: .35rem; }

  /* A masjid name long enough to wrap sat centred against its Follow
     button, which put the button beside the name's second line rather than
     its first. Top-aligned reads correctly whether the name wraps or not. */
  .list-row { align-items: flex-start; }
}
