/* ==========================================================================
   CCIQ Church Management Portal - design system
   Palette taken from the CCIQ seal: deep navy, red, sky blue, gold, green.
   Navy and white carry the interface; the accents mark status only.
   ========================================================================== */

/*
 * The icon sprite sheet: one <svg> holding every <symbol> the app reuses via
 * <use>, never shown directly. A class is used instead of an inline style
 * attribute — Chromium was not applying display:none written as a literal
 * style="" attribute on this particular element, so it rendered as a normal
 * inline SVG and pushed the whole page down by its own intrinsic height. A
 * stylesheet rule does not have that problem.
 */
.icon-sprite { display: none; }

/*
 * A general-purpose "hidden" utility. It needs !important: without it, this
 * class loses to any other single-class rule that also sets display and
 * happens to appear later in this file (e.g. .alert, .avatar--empty) — same
 * specificity, so source order decides the winner, not which class was
 * added to the element last. !important is what actually guarantees
 * "hidden means hidden" regardless of what else styles the element.
 */
.is-hidden { display: none !important; }

/*
 * The native `hidden` attribute needs the same guarantee as .is-hidden
 * above, for the same reason: the browser's own [hidden] { display: none }
 * rule is a user-agent style, and an author rule of equal specificity always
 * wins over it regardless of source order — so any class that sets its own
 * `display` (e.g. .field { display: flex }, .member-picker__selected
 * { display: flex }) silently defeats `hidden` on that element. This was
 * confirmed live: the Change Membership Status form's Destination
 * country/Departure notes fields (both `.field`) stayed visible no matter
 * what status was chosen, because .field's display:flex was overriding
 * [hidden] the whole time — not a JS logic bug. Fixed globally here instead
 * of one class at a time, since the same conflict silently affected the
 * member picker's own "selected" state too.
 */
[hidden] { display: none !important; }

/* General-purpose spacing utilities, for the many one-off inline styles like
   style="margin-top: 12px" that the portal's Content Security Policy does
   not allow — see the comment on .is-hidden above for why a stylesheet
   class is required here instead. */
.label--inline { display: inline; }
.u-mt-8 { margin-top: 8px; }
.u-mt-12 { margin-top: 12px; }
.u-mt-16 { margin-top: 16px; }
.u-mt-24 { margin-top: 24px; }
.u-narrow-card { max-width: 620px; margin: 24px auto 0; }

/* The rest of the margin/max-width/misc utilities the portal's views need,
   for the same Content-Security-Policy reason as .is-hidden above: an
   inline style="" attribute is blocked outright, so every one-off spacing
   or width tweak needs a real class instead. */
.u-mt-neg12 { margin-top: -12px; }
.u-mt-neg10 { margin-top: -10px; }
.u-mt-6 { margin-top: 6px; }
.u-mt-10 { margin-top: 10px; }
.u-mt-14 { margin-top: 14px; }
.u-mt-18 { margin-top: 18px; }
.u-mt-22 { margin-top: 22px; }
.u-mb-12 { margin-bottom: 12px; }
.u-mb-14 { margin-bottom: 14px; }
.u-mb-16 { margin-bottom: 16px; }
.u-mb-18 { margin-bottom: 18px; }
.u-m-0 { margin: 0; }
.u-mt-18-mb-neg12 { margin-top: -12px; margin-bottom: 18px; }
.u-max-220 { max-width: 220px; }
.u-max-260 { max-width: 260px; }
.u-max-520 { max-width: 520px; }
.u-max-560 { max-width: 560px; }
.u-max-620 { max-width: 620px; }
.u-max-720 { max-width: 720px; }
.u-max-780 { max-width: 780px; }
.u-max-820 { max-width: 820px; }
.u-max-940 { max-width: 940px; }
.u-pre-wrap { white-space: pre-wrap; }
.u-border-red { border: 1px solid var(--red-600); }
.u-no-border-top { border-top: 0; padding-top: 0; }
.u-border-top-0 { border-top: 0; }
.u-pt-0 { padding-top: 0; }
.u-pt-14 { padding-top: 14px; }
.u-fs-110 { font-size: 1.1rem; }
.u-fs-130 { font-size: 1.3rem; }
.u-cursor-pointer { cursor: pointer; }
.u-flex-1 { flex: 1; }
.u-no-frame { padding: 0; border: 0; }
.u-leader-row { border-bottom: 1px solid var(--line); padding-bottom: 14px; margin-bottom: 14px; }

/* The entrance check-in kiosk. */
.checkin-card { max-width: 520px; }
.checkin-label { font-weight: 600; display: block; margin-bottom: 8px; }
.checkin-scan-row { align-items: stretch; flex-wrap: nowrap; }
.checkin-input {
  font-size: 1.3rem; padding: 16px; flex: 1; min-width: 0; text-align: center;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
}
.checkin-hint { margin-top: 10px; text-align: center; }
/*
 * The general-purpose .fieldset__hint rule sets its own margin (including a
 * negative top, meant to pull a hint back up against its own field in an
 * ordinary form) later in this file. Same specificity, so source order — not
 * intent — decided the winner, and .checkin-hint's own margin-top was
 * silently overridden to -6px instead of the 10px written above, leaving the
 * scanner and search helper text almost touching the control above it.
 * Scoping to .checkin-card raises the specificity enough to win reliably,
 * without relying on where either rule happens to sit in the file.
 */
.checkin-card .checkin-hint { margin-top: 18px; margin-bottom: 4px; }
.checkin-error { margin-top: 14px; }
.checkin-result { text-align: center; }
.checkin-avatar { border-radius: 50%; object-fit: cover; margin: 0 auto 12px; }
.checkin-name { margin: 0 0 4px; }
.checkin-code { margin: 0 0 20px; }
.checkin-actions { justify-content: center; }
.checkin-success-message { font-size: 1.4rem; font-weight: 600; color: var(--green-700, #1a7f37); }

/*
 * The Attendance Kiosk: a restricted, single-purpose entrance screen, not a
 * smaller admin page. Larger controls and text throughout for a touchscreen
 * or a device viewed from arm's length, a fixed simple header (branding +
 * sign out, no search/nav/notifications), and no sidebar at all — the
 * layout (layouts/kiosk.ejs) never renders one.
 */
body.kiosk { background: var(--surface-sunk, #f3f4f6); font-size: 1.05rem; }
.kiosk__bar {
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px 20px; padding-top: calc(10px + env(safe-area-inset-top, 0px));
  background: var(--navy-900); color: #fff;
}
.kiosk__bar .brand__text strong { color: #fff; }
.kiosk__bar .brand__text span { color: rgba(255,255,255,.75); }
/* Compacted (less vertical padding and margin); touch targets stay at least 48px tall. */
.kiosk__main {
  max-width: 640px; margin: 0 auto; padding: 18px 16px 28px;
}
.kiosk__card { max-width: none; }
.kiosk__card .card__body { padding: 20px 22px; }
.kiosk__service { text-align: center; color: var(--muted); margin: 0 0 12px; font-size: 1rem; }
.kiosk__label { font-size: 1.1rem; text-align: center; margin-bottom: 6px; }
.kiosk__input { font-size: 1.3rem; padding: 14px 16px; min-height: 56px; }
.kiosk__or { text-align: center; color: var(--muted); margin: 12px 0; }
.kiosk__search-form { display: flex; flex-direction: column; gap: 12px; }
.kiosk__name { font-size: 1.7rem; }
.kiosk__family-list li { padding: 14px 0; }
.kiosk__family-list .avatar { width: 56px; height: 56px; }
.kiosk__success-icon { width: 64px; height: 64px; color: var(--green-700, #1a7f37); margin: 0 auto 14px; display: block; }

/* Kiosk reception layout: attendance primary, navigation QR secondary. */
.kiosk__main { max-width: 1440px; }
.kiosk__workspace { display: grid; grid-template-columns: minmax(0, 1fr); gap: 24px; align-items: start; }
.kiosk__attendance { min-width: 0; }
.kiosk__heading { margin: 0 0 6px; font-size: 1.45rem; }
.kiosk__count { margin: 0 0 12px; }
.kiosk__count p { margin: 0; }
.kiosk__count strong { font-size: 1.5rem; color: var(--navy-800); }
.kiosk__count small { display: block; color: var(--muted); }
.kiosk__bar { gap: 12px; flex-wrap: wrap; }
.kiosk__bar .brand--compact { display: flex; }
.kiosk__identity { margin-left: auto; min-width: 0; max-width: 100%; overflow-wrap: anywhere; }
.kiosk__bar .btn { min-height: 44px; }
.kiosk__lobby { min-width: 0; }
.kiosk__lobby-body { display: flex; flex-direction: column; gap: 12px; align-items: center; }
.kiosk__lobby-text { min-width: 0; }
.kiosk__lobby-title { margin: 0 0 10px; font-size: 1.25rem; }
.kiosk__lobby-qr { width: 220px; max-width: 100%; text-align: center; }
.kiosk__lobby-qr .quick-access__image { width: 100%; max-width: 100%; margin: 0 0 12px; }
.kiosk__lobby-qr .quick-access__url { font-size: .95rem; overflow-wrap: anywhere; }
.kiosk__lobby-qr .quick-access__date { display: none; }
.kiosk__lobby-qr .quick-access__hint { font-size: .85rem; }
.kiosk__lobby-qr .quick-access__actions { justify-content: center; }
.kiosk__lobby-qr .btn { min-height: 44px; }
.kiosk__record-feedback { margin-top: 14px; overflow-wrap: anywhere; }
@media (min-width: 820px) {
  .kiosk__workspace { grid-template-columns: minmax(0, 2fr) minmax(260px, 1fr); }
}
@media (max-width: 600px) {
  .kiosk__main { padding: 20px 12px 32px; }
  .kiosk__card .card__body { padding: 20px 16px; }
  .kiosk__identity { order: 3; flex-basis: 100%; margin: 0; font-size: .95rem; }
  .kiosk__input { font-size: 1.1rem; padding: 14px 12px; }
  .kiosk__bar { padding-left: 12px; padding-right: 12px; }
}


/* A large, obvious focus outline everywhere on the kiosk — used with a
   keyboard, a USB scanner (which types into the focused field), or a finger
   moving between controls, never just a mouse hover. */
.kiosk :focus-visible { outline: 3px solid var(--navy-500); outline-offset: 2px; }

/* A member's own QR code page. */
.qr-card { max-width: 420px; }
.qr-card__body { text-align: center; }
.qr-image { max-width: 100%; height: auto; }
.qr-hint { margin-top: 12px; }
.qr-actions { justify-content: center; margin-top: 16px; }
.qr-regenerate-form { margin-top: 16px; }

:root {
  /* The sign-in page hero: the approved worship photograph, bundled locally (wide file for wide screens, a 1000px copy for phones and tablets). It is generic worship imagery, not captioned or presented as CCIQ, its people or its place. To change it, replace the two files or point these two lines at others. */
  --login-backdrop: url("/branding/login-worship.webp");
  --login-backdrop-small: url("/branding/login-worship-1000.webp");
  --auth-paper: #f6f2ea;
  --navy-900: #0a2547;
  --navy-800: #10355f;
  --navy-700: #17457a;
  --navy-600: #1f5a95;
  --navy-500: #2f6aa8;
  --navy-50: #eef4fa;
  --sky-400: #4ea3d6;
  --sky-100: #e3f1fa;
  --red-600: #c22f26;
  --red-100: #fbe9e7;
  --gold-500: #dfa523;
  --gold-400: #ebb946;
  --gold-100: #fbf1d9;
  --gold-50: #fdf8ea;
  --green-600: #2c7a4d;
  --green-100: #e3f3ea;
  --faith-green-900: #133a26;
  --faith-green-700: #1f5c3c;
  --faith-green-500: #2f7a4f;
  --faith-cream: #f6f3e9;

  --paper: #f4f6f9;
  --surface: #ffffff;
  --surface-sunk: #fafbfd;
  --ink: #16202c;
  --ink-soft: #3c4a5a;
  --muted: #5b6b7d; /* secondary text: >= 4.5:1 on every surface it sits on (was #6a7a8c, 4.0-4.4:1) - see css-contrast.mjs */
  --line: #dde4ec;
  --line-soft: #e8edf3;
  --line-strong: #c6d1de;
  --control-border: #7d8da2; /* the edge of a text input, select or textarea: >= 3:1 on white and on the page (WCAG 1.4.11) - see css-contrast.mjs */
  --surface-muted: #f1f4f8;

  --font-display: "Segoe UI Semibold", "Helvetica Neue", system-ui, -apple-system, Roboto, Arial, sans-serif;
  --font-body: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;

  --radius-sm: 6px;
  --radius: 10px;
  --radius-lg: 16px;
  --shadow-card: 0 1px 2px rgba(16, 33, 56, .06), 0 6px 20px rgba(16, 33, 56, .05);
  --shadow-raised: 0 10px 34px rgba(10, 37, 71, .18);
  --sidebar-w: 264px;
  --topbar-h: 60px;

  /*
   * TYPE AND DENSITY TOKENS (docs/UX-STANDARDS.md). These are the phone/touch values - the roomier ones. The desktop
   * values are set once, in the "desktop density" block just after the responsive section, so the whole portal moves
   * together instead of each screen carrying its own override. The kiosk does not use them: it keeps its own large sizes.
   */
  --fs-body: 15.5px;        /* body, table and navigation text */
  --fs-control: 15.5px;     /* text inside inputs, selects and textareas */
  --fs-label: .86rem;       /* form labels */
  --fs-help: .82rem;        /* helper and error text, table sub-lines, metadata */
  --control-h: 42px;        /* input / select / button height */
  --btn-h: 42px;
  --btn-h-sm: 34px;
  --control-pad: 9px 12px;
  --space-card: 18px;       /* card body padding */
  --space-field: 16px;      /* between one field and the next */
  --gap-label: 6px;         /* label -> control */
  --gap-help: 6px;          /* control -> helper / error text */
  --cell-pad: 12px 16px;    /* table cells */
  --space-main: 26px;       /* page padding, top */
  --space-head: 22px;       /* under a page title */
  --nav-pad: 10px 12px;
}

/* --- base ---------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--fs-body);
  line-height: 1.55;
  color: var(--ink);
  background: var(--paper);
}

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.2;
  margin: 0 0 .4em;
  letter-spacing: -.005em;
}

h1 { font-size: 1.75rem; }
h2 { font-size: 1.3rem; }
h3 { font-size: 1.05rem; }
p { margin: 0 0 1em; }
p:last-child { margin-bottom: 0; }

a { color: var(--navy-700); text-underline-offset: 2px; }
a:hover { color: var(--navy-500); }

:focus-visible {
  outline: 3px solid var(--navy-500); /* 5.6:1 on white; sky-400 was 2.8:1 (below the 3:1 a focus indicator needs) */
  outline-offset: 2px;
  border-radius: 3px;
}
/* On the dark navy navigation and header the light blue is the one with contrast. */
.sidenav :focus-visible, .topbar :focus-visible, .scrim :focus-visible { outline-color: var(--sky-400); }

.sr-only {
  position: absolute; width: 1px !important; height: 1px !important; padding: 0 !important; margin: -1px !important;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip-link {
  position: absolute; left: 12px; top: -60px; z-index: 100;
  background: var(--surface); color: var(--navy-900);
  padding: 10px 16px; border-radius: var(--radius-sm); box-shadow: var(--shadow-raised);
  transition: top .15s ease;
}
.skip-link:focus { top: 12px; }

.icon { width: 20px; height: 20px; flex: none; }

/* --- app shell ----------------------------------------------------------- */

.topbar {
  position: fixed; top: 0; left: 0; right: 0; z-index: 40;
  display: flex; align-items: center; gap: 12px;
  height: var(--topbar-h); padding: 0 16px;
  padding-top: env(safe-area-inset-top, 0);
  background: var(--navy-900); color: #fff;
}

.topbar__menu, .topbar__bell, .brand--compact { flex: none; }

/* The header is out of the flow, so the page starts below it. */
.app { padding-top: calc(var(--topbar-h) + env(safe-area-inset-top, 0)); }

.topbar__menu {
  display: inline-flex; align-items: center; justify-content: center;
  width: 40px; height: 40px; border: 0; border-radius: var(--radius-sm);
  background: rgba(255,255,255,.1); color: #fff; cursor: pointer;
}
.topbar__menu:hover { background: rgba(255,255,255,.18); }

.topbar__spacer { flex: 1; }

.topbar__user { display: flex; align-items: center; gap: 10px; flex: none; }
.topbar__name { font-size: .9rem; color: rgba(255,255,255,.9); white-space: nowrap; }

.brand { display: flex; align-items: center; gap: 10px; text-decoration: none; color: inherit; }
.brand img { border-radius: 50%; background: #fff; }
.brand__text { display: flex; flex-direction: column; line-height: 1.15; }
.brand__text strong { font-family: var(--font-display); font-size: 1.05rem; letter-spacing: .02em; }
.brand__text span { font-size: .72rem; opacity: .75; }
/*
 * The brand block is PINNED: it never scrolls with the navigation (the sidenav is a flex column
 * that does not scroll itself; only .nav does). Compact, so a long menu keeps its room.
 */
.brand--stacked { flex: none; padding: 14px 18px 12px; color: #fff; border-bottom: 1px solid rgba(255,255,255,.08); }
.brand--stacked img { width: 44px; height: 44px; }
.brand--stacked .brand__text strong { font-size: 1.15rem; }

/*
 * Compact identity (name + role), shown only inside the off-canvas drawer at
 * the same width the topbar's own name/role copy hides — but Sign out itself
 * never lives here. Sign out belongs in .sidenav__foot below, alongside
 * Change password, so there is exactly one place to find it regardless of
 * whether this identity block is even present — never tied to it, and never
 * duplicated at the same width. See CCIQ_DECISIONS.md.
 */
.sidenav__identity {
  display: none; flex: none;
  flex-wrap: wrap; align-items: center; gap: 8px;
  padding: 16px 20px 12px;
}
.sidenav__identity-name { font-size: .95rem; font-weight: 600; color: #fff; }

.shell { display: flex; min-height: calc(100dvh - var(--topbar-h)); }

.sidenav {
  width: var(--sidebar-w); flex: none;
  background: var(--navy-900); color: rgba(255,255,255,.82);
  display: flex; flex-direction: column;
}

.nav {
  list-style: none; margin: 0; padding: 8px 12px 14px;
  flex: 1 1 auto; min-height: 0;          /* the ONLY part of the sidebar that scrolls */
  overflow-y: auto; overscroll-behavior: contain;
}
.nav__item { margin-bottom: 2px; }

.nav__link {
  display: flex; align-items: center; gap: 12px;
  padding: var(--nav-pad); border-radius: var(--radius-sm);
  color: rgba(255,255,255,.82); text-decoration: none; font-size: .93rem;
}
.nav__link:hover { background: rgba(255,255,255,.08); color: #fff; }
.nav__link.is-active {
  background: rgba(255,255,255,.12); color: #fff; font-weight: 600;
  box-shadow: inset 3px 0 0 var(--gold-500);
}

.nav__row { display: flex; align-items: center; }
.nav__row .nav__link { flex: 1; }
.nav__toggle {
  display: inline-flex; align-items: center; justify-content: center;
  flex: none; width: 32px; height: 32px; margin-right: 4px;
  border: 0; border-radius: var(--radius-sm);
  background: transparent; color: rgba(255,255,255,.6); cursor: pointer;
}
.nav__toggle:hover { background: rgba(255,255,255,.08); color: #fff; }
.nav__toggle .icon { width: 16px; height: 16px; transition: transform .15s ease; }
.nav__toggle[aria-expanded="false"] .icon { transform: rotate(-90deg); }

.nav__sub { list-style: none; margin: 2px 0 8px; padding: 0 0 0 44px; }
.nav__sub a {
  display: block; padding: 6px 0; font-size: .86rem;
  color: rgba(255,255,255,.68); text-decoration: none;
}
.nav__sub a:hover, .nav__sub a.is-active { color: #fff; }

.sidenav__foot {
  flex: none;
  display: flex; flex-direction: column; gap: 8px;
  padding: 12px 20px 16px; border-top: 1px solid rgba(255,255,255,.12);
  font-size: .82rem;
}
.sidenav__foot a { display: inline-block; padding: 4px 0; color: rgba(255,255,255,.72); text-decoration: none; }
.sidenav__foot a:hover { color: #fff; text-decoration: underline; }
/*
 * Hidden by default: desktop keeps Sign out in the topbar (.topbar__user),
 * and the sidebar is permanently visible there too, so showing it here as
 * well would put two Sign out controls on screen at once. Shown only at the
 * same width the topbar's own copy hides — see the max-width:860px block.
 */
.sidenav__foot .sidenav__signout-form { display: none; margin: 0; }
.sidenav__signout { width: 100%; justify-content: center; gap: 8px; min-height: 42px; }

.main { flex: 1; min-width: 0; padding: var(--space-main) clamp(16px, 3vw, 34px) 60px; }

.scrim { display: none; }

/* --- page furniture ------------------------------------------------------ */

.page-head {
  display: flex; flex-wrap: wrap; align-items: flex-end; gap: 12px 20px;
  margin-bottom: var(--space-head);
}
.page-head__text { flex: 1 1 260px; }
/* Long text with no break point (a long compound name, an e-mail address, a file or project name) wraps inside its box instead of widening the page. */
.page-head__text, .breadcrumb li { min-width: 0; }
.main { overflow-wrap: anywhere; } /* inherited by everything in the content area; only text that would otherwise overflow ever breaks mid-word */
.page-head h1 { margin-bottom: 2px; }
.page-head p { color: var(--muted); margin: 0; font-size: .95rem; }
.page-head__actions { display: flex; gap: 10px; flex-wrap: wrap; }

.breadcrumb { list-style: none; display: flex; flex-wrap: wrap; gap: 6px; padding: 0; margin: 0 0 10px; font-size: .83rem; color: var(--muted); }
.breadcrumb a { color: var(--muted); text-decoration: none; }
.breadcrumb a:hover { color: var(--navy-700); text-decoration: underline; }
.breadcrumb li + li::before { content: "/"; margin-right: 6px; color: var(--line-strong); }

.grid { display: grid; gap: 18px; }
/*
 * min(Npx, 100%) rather than a bare Npx: an auto-fit track's minimum is
 * normally a fine way to say "never get narrower than this, wrap to a new
 * row instead" — but taken literally it also means "demand this much room
 * even if the viewport itself is narrower," which on a phone forces the
 * grid item (and everything inside it) wider than the screen. Capping the
 * minimum at 100% removes that floor exactly when there isn't room for it,
 * while leaving every wider layout — where 100% is never the binding
 * constraint — completely unchanged. See CCIQ_DECISIONS.md.
 */
.grid--stats { grid-template-columns: repeat(auto-fit, minmax(min(190px, 100%), 1fr)); }
.grid--halves { grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr)); }

.card {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius); box-shadow: var(--shadow-card);
}
.card__head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 6px 12px; flex-wrap: wrap;
  padding: 16px 18px 0;
}
/* A status pill in a card header may carry a whole sentence; on a narrow phone it wraps rather than pushing the page wider. */
.card__head .pill { white-space: normal; max-width: 100%; }
.card__head h2, .card__head h3 { margin: 0; }
.card__head a { font-size: .85rem; }
.card__body { padding: var(--space-card); }
.card__foot { padding: 12px 18px; border-top: 1px solid var(--line); background: var(--surface-sunk); border-radius: 0 0 var(--radius) var(--radius); font-size: .87rem; }

.stat { padding: var(--space-card); }
.stat__label { font-size: var(--fs-help); color: var(--muted); margin: 0 0 6px; }
.stat__value { font-family: var(--font-display); font-size: 2rem; line-height: 1; margin: 0; }
.stat__meta { font-size: .82rem; color: var(--muted); margin: 8px 0 0; }
.stat--flag .stat__value { color: var(--red-600); }

/* Friday Service panel - the one deliberately bold element */
.service-panel {
  position: relative; overflow: hidden;
  background: linear-gradient(135deg, var(--navy-900) 0%, var(--navy-700) 100%);
  color: #fff; border-radius: var(--radius-lg); padding: 26px 28px;
  display: grid; gap: 22px; grid-template-columns: minmax(0, 1fr) auto; align-items: center;
}
.service-panel::after {
  content: ""; position: absolute; inset: auto -60px -110px auto;
  width: 260px; height: 260px; border-radius: 50%;
  background: rgba(78, 163, 214, .18);
}
.service-panel__label { font-size: .78rem; letter-spacing: .12em; color: rgba(255,255,255,.7); margin: 0 0 8px; }
.service-panel__date { font-family: var(--font-display); font-size: clamp(1.6rem, 4vw, 2.3rem); margin: 0 0 6px; }
.service-panel__meta { margin: 0; color: rgba(255,255,255,.82); font-size: .95rem; }
.service-panel__aside { position: relative; z-index: 1; text-align: right; }
.service-panel__count { font-family: var(--font-display); font-size: 2.4rem; line-height: 1; }
.service-panel__note { font-size: .82rem; color: rgba(255,255,255,.75); }
.service-panel a { color: #fff; }

/* --- pills, badges ------------------------------------------------------- */

.pill {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 10px; border-radius: 999px;
  font-size: .76rem; font-weight: 600; white-space: nowrap;
  border: 1px solid transparent;
}
.pill::before { content: ""; width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.pill--active   { background: var(--green-100); color: var(--green-600); border-color: #c3e3d1; }
.pill--inactive { background: var(--gold-100); color: #8a6210; border-color: #ecd9a8; }
.pill--pending  { background: var(--sky-100); color: var(--navy-700); border-color: #c5e2f3; }
.pill--archived { background: #eef1f5; color: var(--muted); border-color: var(--line); }
.pill--present  { background: var(--green-100); color: var(--green-600); }
.pill--absent   { background: var(--red-100); color: var(--red-600); }
.pill--excused  { background: var(--sky-100); color: var(--navy-700); }
.pill--visitor  { background: var(--gold-100); color: #8a6210; }
.pill--not_recorded { background: #eef1f5; color: var(--muted); }
/* Tracked-Friday display states (attendance-outcomes.js) */
.pill--pending, .pill--awaiting_finalization { background: var(--sky-100); color: var(--navy-700); }
.pill--not_expected, .pill--not_tracked, .pill--cancelled { background: #eef1f5; color: var(--muted); }
.pill--not_taken { background: var(--gold-100); color: #8a6210; }
/* The family's primary contact: a readable pill in the content area (.pill--role is for the dark top bar). */
.pill--primary { background: var(--gold-100); color: #7a5610; border-color: #ecd9a8; }
.pill--primary::before { background: var(--gold-500); }
.pill--role { background: rgba(255,255,255,.14); color: #fff; border-color: rgba(255,255,255,.2); }
.pill--role::before { background: var(--gold-500); }

/* Bonafide: a quiet church gold - a pale parchment fill, dark brown text (about 12:1) and a deeper gold edge. Flat on purpose (no gradient, glow or motion), and
   a different, calmer tone from the amber of "Inactive" and "Visitor" so the two are not confused. The word is always shown, so the status is never colour alone. */
.pill--bonafide { background: #f4ebcf; color: #3b2a06; border-color: #a07e2c; }
.pill--bonafide::before { background: #a07e2c; }

/* A MEMBER's "Inactive" status: a restrained pale rose with a deep rose-brown word (about 8:1), clearly apart from Bonafide's gold and from the amber that other
   "inactive" chips (draft, closed, not returned) keep. Scoped by .pill--member so only the member lifecycle status changes; the word is always shown. */
.pill--member.pill--inactive { background: #fbeceb; color: #8a2b25; border-color: #e6bcb8; }
.pill--member.pill--inactive::before { background: #b4504a; }

/* --- buttons ------------------------------------------------------------- */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: var(--btn-h); padding: 0 18px;
  border-radius: var(--radius-sm); border: 1px solid transparent;
  font: inherit; font-weight: 600; font-size: .92rem;
  cursor: pointer; text-decoration: none;
  background: var(--navy-800); color: #fff;
}
.btn:hover { background: var(--navy-700); color: #fff; }
.btn--secondary { background: var(--surface); color: var(--navy-800); border-color: var(--line-strong); }
.btn--secondary:hover { background: var(--surface-sunk); color: var(--navy-900); }
.btn--ghost { background: transparent; color: #fff; border-color: rgba(255,255,255,.35); }
.btn--ghost:hover { background: rgba(255,255,255,.12); color: #fff; }
.btn--danger { background: var(--red-600); }
.btn--danger:hover { background: #a92721; }
.btn--small { min-height: var(--btn-h-sm); padding: 0 12px; font-size: .84rem; }
.btn--large { min-height: 60px; padding: 0 28px; font-size: 1.15rem; border-radius: var(--radius); }
.btn--block { width: 100%; }
.btn[disabled] { opacity: .55; cursor: not-allowed; }

.inline-form { display: inline; }

/* --- forms --------------------------------------------------------------- */

.form { max-width: 880px; }
.fieldset { border: 0; padding: 0; margin: 0 0 26px; }
.fieldset > legend {
  font-family: var(--font-display); font-size: 1.1rem; font-weight: 600;
  padding: 0 0 4px; margin-bottom: 12px; width: 100%;
  border-bottom: 1px solid var(--line);
}
.fieldset__hint { color: var(--muted); font-size: var(--fs-help); margin: -6px 0 14px; }
/* .fieldset__hint's own negative top margin assumes it sits right under a
   fieldset legend; a hint placed after a button/.form__actions instead needs
   real separation, not a pull-up — this override (same .u-mt-* utility,
   higher specificity so it wins) covers that second case. */
.fieldset__hint.u-mt-16 { margin-top: 16px; }

/*
 * One form rhythm everywhere: Label, (gap) Control, (gap) Helper or error, (larger gap) next field.
 * The label always sits close to ITS control and clearly further from the previous field, so a label can never read
 * as belonging to the field above it.
 */
.field-grid { display: grid; gap: var(--space-field) 20px; grid-template-columns: repeat(auto-fit, minmax(230px, 1fr)); }
.field { display: flex; flex-direction: column; gap: var(--gap-label); min-width: 0; }
.field--wide { grid-column: 1 / -1; }
.field > label { font-size: var(--fs-label); font-weight: 600; color: var(--ink-soft); line-height: 1.3; }
.field small { color: var(--muted); font-size: var(--fs-help); line-height: 1.4; margin-top: calc(var(--gap-help) - var(--gap-label)); }
.field .field__error { margin-top: calc(var(--gap-help) - var(--gap-label)); line-height: 1.4; }
.field > .checkbox + small, .field > .checkbox + .field__error { margin-top: 2px; }
.field label .field__required, .field__required { color: var(--red-600); font-weight: 700; margin-left: 2px; }
.field--inline { flex-direction: row; align-items: center; gap: 10px; }
.field--inline > label { white-space: nowrap; }
.form > .field + .field, .form > .fieldset + .fieldset { margin-top: var(--space-field); }
input:disabled, select:disabled, textarea:disabled, input[readonly], textarea[readonly] {
  background: var(--surface-sunk); color: var(--ink-soft); border-style: dashed; cursor: not-allowed;
}
input[readonly] { cursor: default; }

input[type="text"], input[type="email"], input[type="password"], input[type="date"],
input[type="time"], input[type="search"], input[type="number"], input[type="tel"],
select, textarea {
  width: 100%; min-height: var(--control-h); padding: var(--control-pad);
  font: inherit; font-size: var(--fs-control); color: var(--ink);
  background: var(--surface); border: 1px solid var(--control-border);
  border-radius: var(--radius-sm);
}
textarea { min-height: 88px; resize: vertical; line-height: 1.45; }
input:hover, select:hover, textarea:hover { border-color: var(--navy-500); }
input[aria-invalid="true"], select[aria-invalid="true"], textarea[aria-invalid="true"] { border-color: var(--red-600); }

.field__error { color: var(--red-600); font-size: var(--fs-help); font-weight: 600; }

.checkbox { display: flex; align-items: flex-start; gap: 10px; line-height: 1.4; }
.checkbox input { width: 18px; height: 18px; min-height: 0; margin-top: 2px; flex: none; }
.checkbox > span { min-width: 0; }
.checkbox label { font-weight: 500; }

/* A read-only view of a set of checkboxes that must still submit their
   current values with the form (so the native `disabled` attribute, which
   drops a control from form submission entirely, is not an option — see
   the Roles section on the user account page). */
.is-locked { opacity: .65; pointer-events: none; }

.form__actions {
  display: flex; flex-wrap: wrap; gap: 10px 12px; align-items: center;
  margin-top: var(--space-field); padding-top: 14px; border-top: 1px solid var(--line);
}

.filters {
  display: flex; flex-wrap: wrap; gap: 10px; align-items: flex-end;
  padding: 14px 16px; background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--radius); margin-bottom: 16px;
}
.filters .field { flex: 1 1 180px; }
.filters__search { flex: 2 1 260px; }

/* --- tables -------------------------------------------------------------- */

.table-wrap {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  /* Wide tables such as the permission matrix scroll rather than being clipped. */
  overflow-x: auto;
  overflow-y: hidden;
}
table.data { width: 100%; border-collapse: collapse; font-size: .92rem; }
table.data caption { text-align: left; padding: 14px 16px 0; color: var(--muted); font-size: .85rem; }
table.data th, table.data td { padding: var(--cell-pad); text-align: left; vertical-align: middle; }
table.data thead th {
  font-size: .78rem; letter-spacing: .04em; color: var(--muted);
  background: var(--surface-sunk); border-bottom: 1px solid var(--line);
  font-weight: 600;
}
table.data tbody tr + tr td { border-top: 1px solid var(--line); }
table.data tbody tr:hover td { background: var(--surface-sunk); }
table.data a { font-weight: 600; text-decoration: none; }
table.data a:hover { text-decoration: underline; }
.cell-sub { display: block; color: var(--muted); font-size: var(--fs-help); }
.numeric { text-align: right; font-variant-numeric: tabular-nums; }

.pagination { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 14px 16px; border-top: 1px solid var(--line); background: var(--surface-sunk); font-size: .87rem; }
.pagination__links { display: flex; gap: 8px; }

/* --- tabs ---------------------------------------------------------------- */

.tabs { display: flex; gap: 4px; overflow-x: auto; border-bottom: 1px solid var(--line); margin-bottom: 20px; }
.tabs a {
  padding: 10px 14px; white-space: nowrap; text-decoration: none;
  color: var(--muted); font-size: .92rem; font-weight: 600;
  border-bottom: 3px solid transparent;
}
.tabs a:hover { color: var(--navy-700); }
.tabs a.is-active { color: var(--navy-900); border-bottom-color: var(--navy-800); }

/* --- alerts, empty states ------------------------------------------------ */

.alert {
  display: flex; gap: 12px; align-items: flex-start;
  padding: 12px 16px; border-radius: var(--radius);
  border: 1px solid var(--line); background: var(--surface);
  margin-bottom: 20px;
}
.alert p { margin: 0; font-size: .92rem; }
.alert[data-error-summary] { scroll-margin-top: 84px; }
.alert[data-error-summary]:focus { outline: 3px solid var(--red-600); outline-offset: 2px; }
.error-summary__list { margin: 6px 0 0; padding-left: 20px; font-size: .92rem; }
.error-summary__list a { color: inherit; text-decoration: underline; }
.alert--success { background: var(--green-100); border-color: #bfe3cd; color: #1e5c39; }
.alert--error   { background: var(--red-100); border-color: #f2cdc9; color: #8d231c; }
.alert--info    { background: var(--sky-100); border-color: #c5e2f3; color: var(--navy-800); }
.alert--warning { background: var(--gold-100); border-color: #ecd9a8; color: #7a5610; }

/* A non-zero count in a dependency summary — e.g. the delete-confirmation
   screen's "this member has N attendance records" list. */
.is-flagged { color: var(--red-600); font-weight: 600; }

.notice {
  border-left: 4px solid var(--gold-500);
  background: var(--gold-100); color: #6f4f0f;
  padding: 12px 16px; border-radius: var(--radius-sm); font-size: .9rem;
  margin-bottom: 18px;
}
.notice a { color: inherit; }

.empty { padding: 34px 20px; text-align: center; color: var(--muted); }
.empty h2 { color: var(--ink); font-size: 1.05rem; margin-bottom: 6px; }
.empty p { max-width: 44ch; margin: 0 auto 14px; font-size: .93rem; }

/* --- lists --------------------------------------------------------------- */

.list { list-style: none; margin: 0; padding: 0; }
.list li { display: flex; gap: 12px; align-items: baseline; justify-content: space-between; padding: 10px 0; }
.list li + li { border-top: 1px solid var(--line); }
.list__name { font-weight: 600; }
/*
 * Not nowrap: a follow-up reason ("N consecutive Friday Services without
 * recorded attendance") is genuinely long, and forcing it onto one line
 * was pushing the whole page wider than the viewport on a phone — a fixed
 * header positioned with left/right:0 then inherits that wider box too,
 * which is what pushed Sign out off a real phone screen. Short meta text
 * (dates, "See all") is unaffected either way since it never wraps anyway.
 */
.list__meta { color: var(--muted); font-size: var(--fs-help); }

.definition { display: grid; grid-template-columns: minmax(140px, 34%) 1fr; gap: 10px 16px; margin: 0; }
.definition dt { color: var(--muted); font-size: .86rem; }
.definition dd { margin: 0; }
.definition dd.is-empty { color: var(--muted); font-style: italic; }

.timeline { list-style: none; margin: 0; padding: 0 0 0 18px; border-left: 2px solid var(--line); }
.timeline li { position: relative; padding: 0 0 18px 18px; }
.timeline li::before {
  content: ""; position: absolute; left: -25px; top: 6px;
  width: 12px; height: 12px; border-radius: 50%;
  background: var(--surface); border: 2px solid var(--navy-500);
}
.timeline time { display: block; color: var(--muted); font-size: .82rem; }

.attendance-strip { display: flex; flex-wrap: wrap; gap: 6px; }
.attendance-strip span {
  display: inline-flex; flex-direction: column; align-items: center; gap: 4px;
  min-width: 62px; padding: 8px 6px; border-radius: var(--radius-sm);
  border: 1px solid var(--line); background: var(--surface-sunk);
  font-size: .72rem; color: var(--muted); text-align: center;
}
.attendance-strip span b { font-size: .8rem; color: var(--ink); }
.attendance-strip .is-present { background: var(--green-100); border-color: #bfe3cd; }
.attendance-strip .is-absent { background: var(--red-100); border-color: #f2cdc9; }
.attendance-strip .is-excused { background: var(--sky-100); border-color: #c5e2f3; }
.attendance-strip .is-not_recorded { background: #eef1f5; }
.attendance-strip .is-pending, .attendance-strip .is-awaiting_finalization { background: var(--sky-100); border-color: #c5e2f3; border-style: dashed; }
.attendance-strip .is-not_expected, .attendance-strip .is-not_tracked, .attendance-strip .is-cancelled { background: #eef1f5; }
.attendance-strip .is-not_taken { background: var(--gold-100); border-color: #ecd9a8; }

/*
 * Scrolls horizontally rather than squeezing every bar+label down to
 * illegibility (or, left unchecked, overflowing the whole page — a flex
 * row's items respect their own min-content width by default no matter how
 * little room the row is given). On any screen wide enough to fit every bar
 * at a comfortable width this has no visible effect at all: min-width only
 * binds once there genuinely isn't room, matching real-phone testing at
 * 320-390px. See CCIQ_DECISIONS.md.
 */
.chart-scroll { overflow-x: auto; }

.bars { display: flex; align-items: flex-end; gap: 10px; height: 120px; padding-top: 8px; min-width: max-content; }
.bars__col { flex: 1; display: flex; flex-direction: column; justify-content: flex-end; align-items: center; gap: 6px; height: 100%; min-width: 36px; }
.bars__bar { width: 100%; max-width: 42px; background: var(--navy-500); border-radius: 4px 4px 0 0; min-height: 3px; }
.bars__label { font-size: .72rem; color: var(--muted); }
.bars__value { font-size: .78rem; font-weight: 600; }

/* --- sign in ------------------------------------------------------------- */

/* --- sign-in pages (Login V2) -----------------------------------------------------------------------------------------------------------------------------------
   Desktop: one composition in two zones - a worship-atmosphere hero (about 60%) carrying the welcome and the verse of the day, and a warm off-white sign-in area (about 40%).
   Tablet: the hero becomes a shorter banner above the form. Phone: the form comes first under a slim atmospheric header, and the verse follows it.
   The hero is a bundled worship PHOTOGRAPH used as generic imagery: it is never captioned or presented as CCIQ, its people or its place. It is replaced by changing the two
   --login-backdrop lines in :root. Motion is one very slow zoom of the artwork, switched off for reduced motion. No script, no web font and
   no request leaves this server. */
.auth {
  min-height: 100vh; min-height: 100dvh;
  background: var(--navy-900);
}
.auth__shell { min-height: 100vh; min-height: 100dvh; display: grid; grid-template-columns: minmax(0, 1fr); grid-template-rows: auto 1fr; background: var(--auth-paper); }

/* the sign-in side (the plain layout - change password and the like - shares the card, brand and foot) */
.auth__panel {
  order: 1; width: 100%; max-width: 460px; margin: 0 auto; padding: 22px 16px 28px; align-self: start;
  display: flex; flex-direction: column; justify-content: center;
}
.auth__card {
  background: var(--surface); border-radius: var(--radius-lg);
  padding: 28px 26px 24px; box-shadow: var(--shadow-raised);
}
.auth__brand { text-align: center; margin-bottom: 20px; }
.auth__brand img { border-radius: 50%; }
.auth__brand h1 { font-size: 1.3rem; margin: 12px 0 2px; }
.auth__brand p { color: var(--muted); font-size: .88rem; margin: 0; }
.auth__foot { text-align: center; color: rgba(255,255,255,.72); font-size: .8rem; margin: 16px 0 0; }
.auth .field { margin-bottom: 14px; }

.auth__shell .auth__panel {
  position: relative; max-width: none; margin: 0; padding: 40px 24px 26px; align-self: stretch;
  display: grid; grid-template-rows: 1fr auto; align-items: center; justify-items: center; background-color: var(--auth-paper);
  background-image:
    radial-gradient(44% 34% at 50% 50%, rgba(255, 252, 246, .62), rgba(255, 252, 246, 0) 80%),
    radial-gradient(70% 52% at 96% 2%, rgba(236, 184, 64, .46), rgba(236, 184, 64, 0) 74%),
    radial-gradient(66% 48% at 0% 100%, rgba(23, 69, 122, .30), rgba(23, 69, 122, 0) 74%),
    linear-gradient(90deg, rgba(10, 37, 71, .14) 0%, rgba(10, 37, 71, 0) 8%),
    url("/branding/login-waves.svg");
  background-repeat: no-repeat; background-size: auto, auto, auto, auto, cover; background-position: 0 0, 0 0, 0 0, 0 0, 50% 50%;
}
.auth__shell .auth__card {
  width: 100%; max-width: 410px; padding: 34px 32px 26px; background: #fffdf9; border: 1px solid rgba(23, 69, 122, .09); border-radius: 18px;
  box-shadow: 0 1px 2px rgba(16, 33, 56, .06), 0 20px 48px rgba(16, 33, 56, .15);
}
.auth__shell .auth__brand { margin-bottom: 24px; }
.auth__shell .auth__brand img { width: 112px; height: 112px; }
.auth__shell .auth__brand h1 { font-size: 1.5rem; letter-spacing: -.01em; color: var(--navy-900); margin: 16px 0 4px; }
.auth__shell .auth__brand p { font-size: .92rem; letter-spacing: .02em; }
.auth__shell .field { margin-bottom: 16px; }
.auth__shell .field label { font-size: .86rem; font-weight: 600; color: var(--navy-800); }
.auth__shell input[type="text"], .auth__shell input[type="password"] { min-height: 48px; border-radius: 10px; background: #fff; }
.auth__forgot { display: flex; justify-content: flex-end; margin: -4px 0 20px; font-size: .86rem; }
.auth__forgot a { color: var(--navy-600); text-decoration: none; }
.auth__forgot a:hover, .auth__forgot a:focus-visible { text-decoration: underline; text-underline-offset: 3px; }
.auth__shell .btn--block { min-height: 50px; border-radius: 11px; font-size: 1rem; font-weight: 600; letter-spacing: .01em; box-shadow: 0 6px 16px rgba(10, 37, 71, .22); }
.auth__alt { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-top: 22px; padding-top: 20px; border-top: 1px solid var(--line); }
.auth__alt-item {
  display: flex; align-items: center; justify-content: center; gap: 8px; min-height: 48px; padding: 8px 10px; border: 1px solid var(--line); border-radius: 10px; background: #fff;
  color: var(--navy-800); font: inherit; font-size: .83rem; font-weight: 600; line-height: 1.2; text-align: center; text-decoration: none; cursor: pointer;
}
.auth__alt-item:hover { background: var(--navy-50); border-color: #b9cde2; }
.auth__alt-item:focus-visible { outline: 2px solid var(--navy-500); outline-offset: 2px; }
.auth__alt-item .icon { width: 18px; height: 18px; flex-shrink: 0; color: var(--navy-600); }
.auth__about { margin: 18px 0 0; text-align: center; font-size: .84rem; color: var(--muted); }
.auth__about a { color: var(--navy-600); text-decoration: underline; text-underline-offset: 3px; }
.auth__shell .auth__foot { margin: 20px 0 0; color: var(--muted); font-size: .78rem; letter-spacing: .02em; }

/* the atmosphere side */
.auth__hero { order: 0; position: relative; overflow: hidden; isolation: isolate; color: #fff; display: flex; background: var(--navy-900); }
.auth__hero-art {
  position: absolute; inset: -3%; z-index: -2;
  background: var(--login-backdrop-small) 72% 40% / cover no-repeat;
  animation: auth-drift 26s ease-in-out infinite alternate; transform-origin: 74% 38%;
}
.auth__hero::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: linear-gradient(90deg, rgba(5, 16, 36, .66) 0%, rgba(5, 16, 36, .34) 48%, rgba(5, 16, 36, 0) 78%),
              linear-gradient(180deg, rgba(5, 14, 30, .38) 0%, rgba(8, 24, 48, 0) 24%, rgba(5, 14, 30, .30) 52%, rgba(4, 11, 24, .82) 80%, rgba(3, 9, 20, .93) 100%);
}
.auth__hero-body { position: relative; width: 100%; display: flex; flex-direction: column; }
.auth__hero-brand { display: flex; align-items: center; gap: 14px; margin: 0; }
.auth__hero-brand strong { font-family: var(--font-display); font-size: 1.4rem; letter-spacing: .18em; }
.auth__hero-brand span { padding-left: 14px; border-left: 1px solid var(--gold-400); font-size: .78rem; letter-spacing: .16em; text-transform: uppercase; color: rgba(255, 255, 255, .8); }
.auth__hero-main { margin-top: auto; }
.auth .auth__welcome h2 { margin: 0 0 6px; font-family: var(--font-display); font-weight: 600; font-size: clamp(1.7rem, 1rem + 1.9vw, 3rem); line-height: 1.12; letter-spacing: -.01em; color: #fff; }
.auth__welcome p { margin: 0; font-size: 1.05rem; color: rgba(255, 255, 255, .84); }
.auth__verse { margin: 30px 0 0; padding-top: 22px; border-top: 1px solid rgba(235, 185, 70, .6); max-width: 34rem; }
.auth__verse-label { margin: 0 0 12px; font-size: .72rem; letter-spacing: .24em; text-transform: uppercase; color: var(--gold-400); }
.auth__verse-text { margin: 0; font-family: Georgia, "Iowan Old Style", "Palatino Linotype", "Book Antiqua", serif; font-size: clamp(1.4rem, .9rem + 1.4vw, 2.55rem); line-height: 1.34; font-weight: 400; color: #fff; text-wrap: balance; }
.auth__verse-ref { margin: 16px 0 0; font-size: .95rem; color: rgba(255, 255, 255, .9); }
.auth__verse-ref cite { font-style: normal; font-weight: 600; letter-spacing: .03em; }
.auth__verse-notice { margin: 30px 0 0; max-width: 62ch; font-size: .66rem; line-height: 1.5; color: rgba(255, 255, 255, .5); }
@keyframes auth-drift { from { transform: scale(1) translate3d(0, 0, 0); } to { transform: scale(1.06) translate3d(-.6%, -.4%, 0); } }
@media (prefers-reduced-motion: reduce) { .auth__hero-art { animation: none; } }

/* a phone: the form first under a slim atmospheric header; the welcome and the verse follow */
@media (max-width: 767px) {
  .auth__shell .auth__panel { padding: 92px 14px 18px; background-image: none; }
  .auth__shell .auth__panel::before {
    content: ""; position: absolute; inset: 0 0 auto 0; height: 168px; z-index: 0;
    background: linear-gradient(180deg, rgba(5, 14, 30, .12) 0%, rgba(5, 14, 30, 0) 38%, var(--auth-paper) 100%), var(--login-backdrop-small) 72% 22% / cover no-repeat;
  }
  .auth__shell .auth__card { position: relative; z-index: 1; padding: 22px 20px 18px; border-radius: 16px; }
  .auth__shell .auth__brand { margin-bottom: 16px; }
  .auth__shell .auth__brand img { width: 72px; height: 72px; }
  .auth__shell .auth__brand h1 { font-size: 1.22rem; margin-top: 10px; }
  .auth__shell .field { margin-bottom: 14px; }
  .auth__forgot { margin-bottom: 16px; }
  .auth__alt { margin-top: 18px; padding-top: 16px; }
  .auth__about { margin-top: 14px; }
  .auth__shell .auth__foot { margin-top: 14px; }
  .auth__hero { order: 2; background: linear-gradient(180deg, #0a2547 0%, #07182f 100%); }
  .auth__hero-art, .auth__hero::after, .auth__hero-brand { display: none; }
  .auth__hero-body { padding: 26px 22px 30px; }
  .auth .auth__welcome h2 { font-size: 1.35rem; }
  .auth__welcome p { font-size: .95rem; }
  .auth__verse { margin-top: 18px; padding-top: 16px; }
  .auth__verse-text { font-size: 1.15rem; }
  .auth__verse-notice { margin-top: 20px; }
}
@media (max-width: 400px) { .auth__alt { grid-template-columns: 1fr; } }

/* a tablet: the hero is a shorter banner above the form */
@media (min-width: 768px) and (max-width: 1099px) {
  .auth__hero { order: -1; min-height: 268px; }
  .auth__hero-art { background-image: var(--login-backdrop-small); background-position: 72% 36%; }
  .auth__hero-body { padding: 22px 40px 20px; }
  .auth__hero-main { max-width: 56%; }
  .auth .auth__welcome h2 { font-size: 1.75rem; }
  .auth__verse { margin: 14px 0 0; padding-top: 14px; max-width: none; }
  .auth__verse-text { font-size: 1.2rem; }
  .auth__verse-ref { margin-top: 10px; }
  .auth__verse-notice { margin-top: 12px; max-width: 56%; }
  .auth__shell .auth__panel { padding: 26px 24px 20px;
    /* a reduced version of the wide treatment: the same sweeps under a veil of ivory, so they stay quiet behind the form */
    background-image: radial-gradient(44% 30% at 50% 46%, rgba(255, 252, 246, .6), rgba(255, 252, 246, 0) 80%), radial-gradient(70% 50% at 94% 0%, rgba(236, 184, 64, .26), rgba(236, 184, 64, 0) 72%), linear-gradient(rgba(246, 242, 234, .5), rgba(246, 242, 234, .5)), url("/branding/login-waves.svg");
    background-size: auto, auto, auto, cover; background-position: 0 0, 0 0, 0 0, 50% 50%; }
  .auth__shell .auth__card { padding: 26px 30px 22px; }
  .auth__shell .auth__brand { margin-bottom: 18px; }
  .auth__shell .auth__brand img { width: 84px; height: 84px; }
  .auth__shell .auth__brand h1 { margin-top: 10px; font-size: 1.35rem; }
}

/* a wide display: the real two-zone composition */
@media (min-width: 1100px) {
  .auth__shell { grid-template-columns: minmax(0, 3fr) minmax(430px, 2fr); grid-template-rows: 1fr; }
  .auth__hero::before { content: ""; position: absolute; top: 0; right: 0; bottom: 0; width: clamp(48px, 6vw, 110px); z-index: -1; pointer-events: none; background: linear-gradient(90deg, rgba(246, 242, 234, 0) 0%, rgba(246, 242, 234, .20) 55%, rgba(246, 242, 234, .50) 100%); }
  .auth__hero { min-height: 100vh; min-height: 100dvh; }
  .auth__hero-art { background-image: var(--login-backdrop); background-position: 72% 40%; }
  .auth__hero-body { padding: clamp(36px, 4vw, 76px) clamp(40px, 5vw, 96px) clamp(30px, 3.4vw, 64px); }
  .auth__verse { max-width: 36rem; }
  .auth__shell .auth__panel { padding: 40px clamp(24px, 3vw, 56px) 26px; }
}
@media (min-width: 1700px) {
  .auth__verse { max-width: 40rem; }
}


/* A button that reads as a plain link — used where a click needs JavaScript
   (opening a dialog) rather than navigation, so it can't just be an <a>. */
.link-button {
  background: none; border: 0; padding: 0; font: inherit; color: var(--navy-700, #10355f);
  text-decoration: underline; cursor: pointer;
}
.link-button:hover { color: var(--navy-900); }

/*
 * Quick Access: a small, self-contained dialog offered from the login
 * screen so a Church Admin never has to find or type this computer's LAN
 * address. Built on the native <dialog> element rather than a bespoke modal
 * system, since this is the only modal anywhere in the portal.
 */
dialog.quick-access {
  border: 0; border-radius: var(--radius); padding: 0; max-width: 420px; width: calc(100% - 32px);
  max-height: 90vh; overflow-y: auto;
  box-shadow: 0 20px 60px rgba(10, 37, 71, .35);
}
dialog.quick-access::backdrop { background: rgba(10, 20, 35, .55); }
.quick-access__body { padding: 24px 24px 20px; text-align: center; }
.quick-access__close-form { display: flex; justify-content: flex-end; padding: 10px 10px 0; }
.quick-access__close {
  background: none; border: 0; font-size: 1.4rem; line-height: 1; color: var(--muted);
  cursor: pointer; padding: 4px 8px;
}
.quick-access__close:hover { color: var(--ink); }
.quick-access__logo { margin: 0 auto 10px; display: block; }
.quick-access__body h2 { margin: 0 0 4px; font-size: 1.2rem; }
.quick-access__hint { color: var(--muted); font-size: .88rem; margin: 0 0 16px; }
.quick-access__image { width: 100%; max-width: 280px; border-radius: var(--radius-sm); border: 1px solid var(--line); margin: 0 auto 14px; display: block; }
.quick-access__url {
  font-family: Consolas, 'Courier New', monospace; font-size: 1.05rem; font-weight: 700;
  color: var(--navy-800); word-break: break-all; margin: 0 0 10px;
}
.quick-access__date { color: var(--muted); font-size: .85rem; margin: 0 0 14px; }
.quick-access__notice {
  background: #fdf1e0; color: #8a5a10; font-weight: 700; font-size: .82rem;
  letter-spacing: .3px; border-radius: var(--radius-sm); padding: 8px 12px; margin: 0 0 14px;
}
.quick-access__actions { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; }

/* --- responsive ---------------------------------------------------------- */

@media (max-width: 960px) {
  .service-panel { grid-template-columns: 1fr; }
  .service-panel__aside { text-align: left; }
}

@media (max-width: 860px) {
  .sidenav {
    position: fixed; inset: calc(var(--topbar-h) + env(safe-area-inset-top, 0)) auto 0 0; z-index: 50;
    transform: translateX(-100%); transition: transform .22s ease;
    box-shadow: var(--shadow-raised); overflow: hidden;
  }
  body.drawer-open .sidenav { transform: translateX(0); }
  body.drawer-open .scrim {
    display: block; position: fixed; inset: calc(var(--topbar-h) + env(safe-area-inset-top, 0)) 0 0 0;
    background: rgba(8, 22, 40, .5); z-index: 45;
  }
  .brand--stacked { display: none; }
  .nav { padding-top: 8px; }
  .main { padding: 20px 16px 56px; }

  /*
   * The account controls move from the top header into the drawer below
   * this width. Identity (name/role) shows near the top of the drawer;
   * Sign out shows at the bottom, with Change password, in .sidenav__foot
   * — not tied to the identity block, so it is never missing merely because
   * that block is scrolled out of view or restyled. Kept as a full swap
   * (never both, never neither) at exactly the width the topbar's own copy
   * hides, so there is always exactly one place to find Sign out. See
   * CCIQ_DECISIONS.md for the real-device defect this corrects.
   */
  .topbar__user { display: none; }
  .sidenav__identity { display: flex; }
  .sidenav__foot .sidenav__signout-form { display: block; }
}

@media (min-width: 861px) {
  .topbar__menu { display: none; }
  .brand--compact { display: none; }

  /*
   * A sticky sidenav's resting position before any scrolling depends on the
   * document's normal flow, which is not reliably the same as "flush under
   * the topbar" in every browser — that gap is what left a blank strip above
   * the sidenav's own background on first load. Fixed positioning has no such
   * ambiguity: pinned at an exact point, with nothing to calculate. Mobile
   * already uses this for the same sidenav; desktop now matches it.
   */
  .sidenav {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    width: var(--sidebar-w);
    overflow: hidden;
    z-index: 45;
  }

  /*
   * The sidebar runs the full height of the window and its brand block sits in the same row as the
   * top bar (the top bar's left end is left clear for it), so the logo is at the very top of the
   * sidebar instead of under an empty strip. The navigation below it keeps all the remaining height.
   */
  .topbar { padding-left: calc(var(--sidebar-w) + 20px); }
  .brand--stacked {
    display: flex; align-items: center;
    height: var(--topbar-h); padding: 0 18px; border-bottom: 0;
  }
  .brand--stacked img { width: 40px; height: 40px; }

  /* The sidenav no longer takes flex space, so main is pushed clear of it. */
  .main { margin-left: var(--sidebar-w); }
}

/*
 * Compact mobile record list — a shared pattern for any page that lists many
 * repeating records (members, birthdays, visitors, documents, and similar):
 * one line combining the record's identity with its most important status,
 * one or two short metadata lines below, actions last. Built once here so
 * every list that needs it looks and behaves the same way, rather than each
 * page inventing its own mobile card. Hidden by default and shown only
 * alongside the max-width:720px rule below, next to whatever desktop
 * presentation (usually a `table.data`, marked `.u-desktop-only`) it
 * replaces at that width — never both at once. See CCIQ_DECISIONS.md.
 *
 * Declared here, before the max-width:720px block, so its override below
 * wins the cascade on source order (both are single-class selectors of
 * equal specificity) — the same ordering mistake once bit .sidenav__foot's
 * sign-out form, so the rule of thumb now is: unconditional defaults for a
 * class a media query later re-enables must come first in the file.
 */
.record-list { display: none; list-style: none; margin: 0; padding: 0; }

@media (max-width: 720px) {
  .page-head__actions { width: 100%; }
  .page-head__actions .btn { flex: 1 1 auto;  }

  /* Tables become stacked records, keeping every field labelled. */
  table.data thead { display: none; }
  table.data, table.data caption, table.data tbody, table.data tr, table.data td { display: block; width: 100%; }
  table.data tr { padding: 12px 14px; }
  table.data tr + tr { border-top: 1px solid var(--line); }
  table.data td { padding: 4px 0; border: 0 !important; }
  table.data td::before {
    content: attr(data-label); display: block;
    font-size: .74rem; color: var(--muted); font-weight: 600;
  }
  table.data td[data-label=""]::before { display: none; }
  .numeric { text-align: left; }
  .definition { grid-template-columns: 1fr; gap: 2px 0; }
  .definition dd { margin-bottom: 10px; }
  .pagination { flex-direction: column; align-items: stretch; }

  /* A page that renders its own .record-list (see below) hides the desktop
     table/element it replaces, rather than falling back to the generic
     "every column becomes its own labelled block" stacking above. */
  .u-desktop-only { display: none !important; }
  .record-list { display: block; }
}

/* The inverse of .u-desktop-only, for the rarer case where a small bit of
   text (e.g. a roster row's cell group) only needs to move — not become an
   entire separate list — on a narrow screen. Hidden above 720px so nothing
   appears twice; restores its normal block display only at that width. */
.cell-sub.u-mobile-only { display: none; }
@media (max-width: 720px) {
  .cell-sub.u-mobile-only { display: block; }
}

.record-list__item {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 12px 2px;
}
.record-list__item + .record-list__item { border-top: 1px solid var(--line); }

.record-list__avatar { flex: none; margin-top: 1px; }

.record-list__body { flex: 1; min-width: 0; }

.record-list__primary {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
}
.record-list__title {
  font-weight: 600; color: var(--ink); text-decoration: none;
  overflow-wrap: anywhere;
}
a.record-list__title:hover { text-decoration: underline; }
.record-list__status { flex: none; }

.record-list__meta {
  margin: 2px 0 0; color: var(--muted); font-size: .85rem;
  overflow-wrap: anywhere;
}

.record-list__actions {
  display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px;
}
.record-list__actions .btn { flex: none; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: .001ms !important; animation-duration: .001ms !important; }
}

@media print {
  .topbar, .sidenav, .page-head__actions, .pagination { display: none !important; }
  body { background: #fff; }
  .card { box-shadow: none; }

  /* A printed page is content only: no navigation aids, controls or transient messages, and nothing left
     of the text where the sidebar used to be (a wide paper size still matches the desktop layout). */
  .skip-link, .quick-drawer, .scrim, .alert, .filters, .btn, button, .topbar__bell, .quick-actions { display: none !important; }
  .app { padding-top: 0; }
  .main { margin-left: 0 !important; padding: 0; }
  /* A scrolling table container would clip the columns that do not fit on paper. */
  .table-wrap { overflow: visible !important; }
  table.data thead { display: table-header-group; }
  table.data tr, .card, .stat { break-inside: avoid; }
  h1, h2, h3 { break-after: avoid; }
  a { color: inherit; text-decoration: none; }
}

/* --- Identity: avatars and name blocks ---------------------------------- */

.identity {
  display: flex;
  align-items: center;
  gap: 14px;
}

.identity--row { gap: 10px; }

.identity__name {
  margin: 0;
  font-family: var(--font-display);
  font-size: 1.2rem;
  color: var(--navy-900);
}

.identity__meta {
  margin: 4px 0 0;
  color: var(--muted);
  font-size: 0.9rem;
}

.avatar {
  width: 36px;
  height: 36px;
  flex: 0 0 auto;
  border-radius: 50%;
  object-fit: cover;
  background: var(--paper);
  border: 1px solid var(--line);
}

.avatar--lg { width: 64px; height: 64px; }

/* A photo that opens larger on click, without changing how it normally looks. */
a.avatar--clickable {
  display: inline-flex;
  overflow: hidden;
  cursor: pointer;
  transition: opacity 120ms ease;
}
a.avatar--clickable img { width: 100%; height: 100%; object-fit: cover; }
a.avatar--clickable:hover, a.avatar--clickable:focus-visible { opacity: 0.85; }
img.avatar--clickable { cursor: pointer; transition: opacity 120ms ease; }
img.avatar--clickable:hover, img.avatar--clickable:focus-visible { opacity: 0.85; }

.avatar--empty {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-size: 1rem;
  color: var(--navy-900);
  background: var(--sky-100);
  border-color: transparent;
  text-transform: uppercase;
}

.avatar--lg.avatar--empty { font-size: 1.6rem; }

/* Timeline entries are colour-coded, but the label always says what happened. */
.timeline--status > time::after { content: ' · status'; color: var(--muted); }
.timeline--group > time::after { content: ' · cell group'; color: var(--muted); }
.timeline--attendance > time::after { content: ' · attendance'; color: var(--muted); }
.timeline--edit > time::after { content: ' · record'; color: var(--muted); }
.timeline--record > time::after { content: ' · membership'; color: var(--muted); }

input[type="file"] {
  width: 100%;
  padding: 10px;
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--paper);
  font: inherit;
}

input[type="file"]::file-selector-button {
  margin-right: 12px;
  padding: 7px 12px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: #fff;
  font: inherit;
  cursor: pointer;
}

/* --- Attendance recording ------------------------------------------------ */

.roster-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--line);
  background: var(--surface-sunk);
}

.choices {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0;
  padding: 0;
  border: 0;
}

.choice {
  display: inline-flex;
  align-items: center;
  cursor: pointer;
}

.choice input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
}

.choice span {
  display: inline-block;
  padding: 7px 12px;
  min-height: 38px;
  line-height: 24px;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  font-size: 0.85rem;
  color: var(--ink-soft);
  background: #fff;
  transition: background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}

.choice input:focus-visible + span {
  outline: 2px solid var(--sky-400);
  outline-offset: 2px;
}

/* Selected states carry a word as well as a colour. */
.choice--present input:checked + span {
  background: var(--green-100); border-color: var(--green-600); color: var(--green-600); font-weight: 600;
}
.choice--absent input:checked + span {
  background: var(--red-100); border-color: var(--red-600); color: var(--red-600); font-weight: 600;
}
.choice--excused input:checked + span {
  background: var(--gold-100); border-color: var(--gold-500); color: #8a6410; font-weight: 600;
}
.choice--visitor input:checked + span {
  background: var(--sky-100); border-color: var(--sky-400); color: var(--navy-800); font-weight: 600;
}
.choice--not_recorded input:checked + span {
  background: var(--paper); border-color: var(--line-strong); color: var(--muted); font-weight: 600;
}

.choices[disabled] .choice span { opacity: 0.75; cursor: default; }

.roster td { vertical-align: middle; }

@media (max-width: 720px) {
  .choices { gap: 6px; }
  .choice span { padding: 9px 12px; }
}

/* Notification bell and unread rows ---------------------------------------- */

.topbar__bell {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 999px;
  color: #fff;
  flex: none;
}

.topbar__bell:hover { background: rgba(255, 255, 255, 0.12); }
.topbar__bell:focus-visible { outline: 2px solid var(--gold-400); outline-offset: 2px; }

.topbar__badge {
  position: absolute;
  top: 3px;
  right: 2px;
  min-width: 18px;
  padding: 0 4px;
  border-radius: 999px;
  background: var(--red-600);
  color: #fff;
  font-size: 0.68rem;
  font-weight: 700;
  line-height: 18px;
  text-align: center;
}

/* Unread carries a marker as well as weight, not colour alone. */
.list li.is-unread .list__name { font-weight: 700; }

.list li.is-unread .list__name::before {
  content: "New";
  display: inline-block;
  margin-right: 8px;
  padding: 1px 7px;
  border-radius: 999px;
  background: var(--sky-100);
  color: var(--navy-800);
  font-size: 0.7rem;
  font-weight: 700;
  vertical-align: 2px;
}

.row-actions { display: flex; flex-wrap: wrap; gap: 6px; }

@media (max-width: 720px) {
  .row-actions { justify-content: flex-start; }
}

/* Gallery ------------------------------------------------------------------ */

.gallery {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 14px;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
}

.gallery__item {
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: #fff;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.gallery__item > a,
.gallery__item > video {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  background: var(--paper);
}

.gallery__item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.gallery__item > a:focus-visible { outline: 2px solid var(--sky-400); outline-offset: -2px; }

.gallery__doc {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  color: var(--navy-700);
  font-size: 0.85rem;
  font-weight: 600;
  text-align: center;
  padding: 12px;
}

.gallery__doc .icon { width: 30px; height: 30px; }

.gallery__caption {
  margin: 0;
  padding: 10px 12px;
  font-size: 0.85rem;
  color: var(--ink);
  border-top: 1px solid var(--line);
}

.gallery__caption .list__meta { display: block; margin-top: 4px; }

.gallery__manage {
  border-top: 1px solid var(--line);
  padding: 10px 12px;
  background: var(--paper);
}

.gallery__manage summary {
  cursor: pointer;
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--navy-700);
}

.gallery__manage summary:focus-visible { outline: 2px solid var(--navy-500); outline-offset: 2px; }
.gallery__manage .field { margin-top: 10px; }

/* Lightbox ----------------------------------------------------------------- */

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 24px;
  background: rgba(9, 20, 38, 0.92);
}

.lightbox[hidden] { display: none; }

.lightbox img {
  max-width: min(1100px, 96vw);
  max-height: 80vh;
  object-fit: contain;
  border-radius: var(--radius-sm);
  background: #000;
}

.lightbox__caption {
  color: #fff;
  font-size: 0.9rem;
  text-align: center;
  max-width: 60ch;
}

.lightbox__close {
  position: absolute;
  top: 16px;
  right: 16px;
  min-width: 44px;
  min-height: 44px;
  border-radius: 999px;
  border: 1px solid rgba(255, 255, 255, 0.4);
  background: transparent;
  color: #fff;
  font-size: 1.1rem;
  cursor: pointer;
}

.lightbox__close:focus-visible { outline: 2px solid var(--gold-400); outline-offset: 2px; }

/* Attendance grid marks ---------------------------------------------------- */

.mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border-radius: 6px;
  font-size: 0.78rem;
  font-weight: 700;
  border: 1px solid var(--line-strong);
  background: #fff;
  color: var(--muted);
}

.mark--present { background: var(--green-100); border-color: var(--green-600); color: var(--green-600); }
.mark--absent { background: var(--red-100); border-color: var(--red-600); color: var(--red-600); }
.mark--excused { background: var(--gold-100); border-color: var(--gold-500); color: #8a6410; }
.mark--visitor { background: var(--sky-100); border-color: var(--sky-400); color: var(--navy-800); }
.mark--not_recorded { background: var(--paper); border-style: dashed; }
.mark--pending, .mark--awaiting_finalization { background: var(--sky-100); border-color: var(--sky-400); border-style: dashed; color: var(--navy-800); }
.mark--not_expected, .mark--not_tracked, .mark--cancelled { background: var(--paper); color: var(--muted); }
.mark--not_taken { background: var(--gold-100); border-color: var(--gold-500); color: #8a6410; }

.timeline--activities strong { display: block; margin: 2px 0; }
.timeline--activities .pill { margin-left: 6px; }

@media (max-width: 720px) {
  .gallery { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px; }
  .lightbox { padding: 12px; }
}

/* Calendar ----------------------------------------------------------------- */

.calendar__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}

.calendar__bar h2 {
  margin: 0;
  font-size: 1.15rem;
  font-family: var(--font-display);
}

.calendar {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  background: #fff;
}

.calendar__head {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  background: var(--paper);
  border-bottom: 1px solid var(--line);
}

.calendar__head span {
  padding: 8px 6px;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--muted);
  text-align: center;
}

.calendar__head .is-service-day { color: var(--navy-700); }

.calendar__week {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  border-bottom: 1px solid var(--line);
}

.calendar__week:last-child { border-bottom: 0; }

.calendar__day {
  min-height: 108px;
  min-width: 0;
  padding: 6px;
  border-right: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.calendar__day:last-child { border-right: 0; }
.calendar__day.is-outside { background: var(--paper); }
.calendar__day.is-outside .calendar__date { color: var(--muted); }

.calendar__date {
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--ink-soft);
  padding: 2px 4px;
}

.calendar__day.is-today .calendar__date {
  background: var(--navy-800);
  color: #fff;
  border-radius: 999px;
  min-width: 24px;
  text-align: center;
}

.calendar__event {
  display: block;
  min-width: 0;
  padding: 3px 6px;
  border-radius: 5px;
  border-left: 3px solid var(--line-strong);
  background: var(--paper);
  font-size: 0.74rem;
  line-height: 1.25;
  color: var(--ink);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

a.calendar__event:hover { background: var(--sky-100); }
a.calendar__event:focus-visible { outline: 2px solid var(--sky-400); outline-offset: 1px; }

.calendar__event.is-service { border-left-color: var(--navy-700); background: #eef3f9; }
.calendar__event.is-church { border-left-color: var(--gold-500); background: var(--gold-100); }
.calendar__event.is-group { border-left-color: var(--green-600); background: var(--green-100); }
.calendar__event.is-birthday { border-left-color: var(--sky-400); background: var(--sky-100); }
.calendar__event.is-anniversary { border-left-color: var(--red-600); background: var(--red-100); }

.calendar__event.is-cancelled,
.list__name.is-cancelled { text-decoration: line-through; opacity: 0.75; }

.legend {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 10px 18px;
  margin: 14px 0 0;
  padding: 0;
  font-size: 0.8rem;
  color: var(--muted);
}

.legend li { display: flex; align-items: center; gap: 6px; }

.legend__swatch {
  display: inline-block;
  width: 12px;
  height: 12px;
  border-radius: 3px;
  border: 1px solid var(--line-strong);
  background: var(--paper);
}

.legend__swatch.is-service { background: #eef3f9; border-color: var(--navy-700); }
.legend__swatch.is-church { background: var(--gold-100); border-color: var(--gold-500); }
.legend__swatch.is-group { background: var(--green-100); border-color: var(--green-600); }
.legend__swatch.is-birthday { background: var(--sky-100); border-color: var(--sky-400); }
.legend__swatch.is-anniversary { background: var(--red-100); border-color: var(--red-600); }

/* Activity cards ----------------------------------------------------------- */

.cards {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 16px;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
}

.card--activity { display: flex; flex-direction: column; overflow: hidden; }

.card--activity__cover {
  display: block;
  aspect-ratio: 16 / 9;
  background: var(--paper);
}

.card--activity__cover img { width: 100%; height: 100%; object-fit: cover; display: block; }

.card--activity h2 { font-size: 1.05rem; margin: 6px 0 4px; }

.card--activity__meta { display: flex; flex-wrap: wrap; gap: 6px; margin: 0; }

.list--cards li.is-important { border-left: 3px solid var(--red-600); padding-left: 12px; }
.list__heading {
  font-size: 0.78rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
  padding-top: 10px;
}

.btn.is-current { background: var(--navy-800); color: #fff; border-color: var(--navy-800); }

/* On a phone the month grid becomes a readable stack of days with events. */
@media (max-width: 720px) {
  .calendar__head { display: none; }
  .calendar__week { grid-template-columns: 1fr; }
  .calendar__day {
    min-height: 0;
    border-right: 0;
    border-bottom: 1px solid var(--line);
    flex-direction: row;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 6px;
    padding: 8px 10px;
  }
  .calendar__day.is-outside { display: none; }
  .calendar__day:not(:has(.calendar__event)) { display: none; }
  .calendar__date { min-width: 46px; }
  .calendar__date::after {
    content: attr(data-weekday);
    margin-left: 4px;
    font-weight: 400;
    color: var(--muted);
  }
  .calendar__event { flex: 1 1 100%; white-space: normal; }
  .cards { grid-template-columns: 1fr; }
}

/* ECAQ project ------------------------------------------------------------- */

.project-hero {
  position: relative;
  border-radius: var(--radius);
  overflow: hidden;
  background: var(--navy-900);
}

.project-hero img {
  width: 100%;
  max-height: 340px;
  object-fit: cover;
  display: block;
  opacity: 0.55;
}

.project-hero__text {
  position: absolute;
  inset: auto 0 0 0;
  padding: 20px 22px;
  background: linear-gradient(to top, rgba(9, 20, 38, 0.92), rgba(9, 20, 38, 0));
  color: #fff;
}

.project-hero__eyebrow {
  margin: 0 0 2px;
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--gold-400);
}

.project-hero__text h1 { margin: 0; color: #fff; font-size: 1.7rem; }

.project-hero__motto {
  margin: 6px 0 0;
  font-family: var(--font-display);
  font-size: 1rem;
  color: #e8eef6;
}

.progress {
  height: 10px;
  border-radius: 999px;
  background: var(--line);
  overflow: hidden;
  margin-top: 12px;
}

.progress span {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--navy-700), var(--sky-400));
}

/* Giving Board ------------------------------------------------------------- */

.board-motto {
  font-family: var(--font-display);
  font-size: 1.15rem;
  color: var(--navy-800);
  text-align: center;
  margin: 4px 0 18px;
}

.board-summary {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 18px;
  padding: 16px 18px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: #fff;
}

.board-summary__bar { flex: 1 1 260px; }
.board-summary .stat__value span { font-size: 0.9rem; font-weight: 400; color: var(--muted); }
.board-summary .progress { margin-top: 0; }

/*
 * The board is one continuous image with the months laid over it. Each stub is
 * an opaque card; claiming a date turns the card transparent so the rendering
 * behind shows through. The state comes from the database, so a claimed date
 * stays uncovered after a refresh.
 */
.board {
  margin-top: 18px;
  padding: 14px;
  border-radius: var(--radius);
  border: 1px solid var(--line);
  background-image: var(--board-image, none);
  background-size: cover;
  background-position: center;
  background-attachment: local;
}

.board__month { margin-bottom: 16px; }
.board__month:last-child { margin-bottom: 0; }

.board__month h2 {
  font-size: 0.82rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #fff;
  margin: 0 0 6px;
  padding: 4px 8px;
  display: inline-block;
  background: rgba(9, 20, 38, 0.72);
  border-radius: 4px;
}

.board__stubs {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(46px, 1fr));
  gap: 4px;
}

.board__stub { position: relative; }

.board__available,
.board__revealed {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-height: 46px;
  padding: 4px 2px;
  border-radius: 4px;
  text-align: center;
  overflow: hidden;
}

/* Unclaimed: an opaque paper stub covering the artwork. */
.board__available {
  background: linear-gradient(180deg, #fdfdfb 0%, #f2f1ec 100%);
  border: 1px solid #ddd9cf;
  box-shadow: 0 1px 2px rgba(20, 30, 50, 0.16);
  color: var(--ink-soft);
  transition: transform 200ms ease, box-shadow 200ms ease;
}

a.board__available:hover {
  transform: translateY(-2px);
  box-shadow: 0 4px 10px rgba(20, 30, 50, 0.22);
}

a.board__available:focus-visible { outline: 2px solid var(--navy-700); outline-offset: 2px; }
.board__available.is-static { opacity: 0.92; cursor: default; }

/* Claimed: the stub is gone and the rendering shows through. */
.board__revealed {
  background: rgba(9, 20, 38, 0.12);
  border: 1px solid rgba(255, 255, 255, 0.45);
  color: #fff;
  text-shadow: 0 1px 3px rgba(9, 20, 38, 0.85);
  animation: stub-lift 520ms ease-out;
}

.board__stub.is-own .board__revealed {
  border-color: var(--gold-400);
  box-shadow: inset 0 0 0 1px var(--gold-400);
}

.board__day { font-size: 0.85rem; font-weight: 700; line-height: 1.1; }

.board__name {
  font-size: 0.58rem;
  line-height: 1.15;
  margin-top: 2px;
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The stub lifts away once, rather than repeating or drawing attention. */
@keyframes stub-lift {
  from { opacity: 0.15; transform: scale(1.04); }
  to { opacity: 1; transform: scale(1); }
}

.legend__swatch--stub { background: #f6f5f0; border-color: #ddd9cf; }
.legend__swatch--claimed { background: var(--navy-700); border-color: var(--navy-800); }
.legend__swatch--own { background: var(--gold-400); border-color: var(--gold-500); }

.finance-form {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
}

.finance-form input[type="text"] { max-width: 110px; }
.finance-form select { max-width: 170px; }

@media (max-width: 720px) {
  .board { padding: 10px; }
  .board__stubs { grid-template-columns: repeat(auto-fill, minmax(42px, 1fr)); }
  .board__name { display: none; }
  .project-hero img { max-height: 220px; }
  .project-hero__text h1 { font-size: 1.35rem; }
  .finance-form input[type="text"] { max-width: 90px; }
}

@media (prefers-reduced-motion: reduce) {
  .board__revealed { animation: none; }
  a.board__available:hover { transform: none; }
}

/* Administration ----------------------------------------------------------- */

.data__group th {
  background: var(--paper);
  font-size: 0.76rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
  text-align: left;
  padding: 8px 12px;
}

.mark .icon { width: 14px; height: 14px; }

.restore {
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  padding: 8px 10px;
  background: var(--paper);
  flex: 1 1 100%;
}

.restore summary {
  cursor: pointer;
  font-size: 0.82rem;
  font-weight: 700;
  color: var(--red-600);
}

.restore summary:focus-visible { outline: 2px solid var(--red-600); outline-offset: 2px; }
.restore .field { margin-top: 10px; }

/* An error shown to a signed-out visitor uses the sign-in shell. */
.auth__card .empty { padding: 6px 0 0; text-align: left; }
.auth__card .empty h2 { font-size: 1.15rem; color: var(--ink); margin-bottom: 8px; }
.auth__card .empty .btn { margin-top: 12px; }

/* Sectioned forms ---------------------------------------------------------- */

.form--sectioned { max-width: 940px; }

.form-section {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 18px;
  margin-bottom: 16px;
  display: grid;
  gap: 18px;
}

.form-section__intro h2 {
  font-size: 1.05rem;
  margin: 0 0 4px;
  color: var(--navy-800);
}

.form-section__intro p {
  margin: 0;
  font-size: 0.85rem;
  color: var(--muted);
  line-height: 1.5;
}

/* On a wide screen the explanation sits beside the fields it describes. */
@media (min-width: 900px) {
  .form-section {
    grid-template-columns: 260px 1fr;
    gap: 28px;
    padding: 22px 24px;
  }
  .form-section__intro { position: sticky; top: 84px; align-self: start; }
}

.fieldset--nested {
  margin-top: 16px;
  padding-top: 16px;
  border-top: 1px solid var(--line);
}

.form-actions-bar {
  position: sticky;
  bottom: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  padding: 14px 18px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: 0 -4px 14px rgba(20, 30, 50, 0.06);
}

.form-actions-bar__note { font-size: 0.82rem; color: var(--muted); }

/* Fields revealed by an earlier answer stay hidden until they apply. */
[data-reveal-target].is-hidden { display: none; }

/* Member photo ------------------------------------------------------------- */

.photo-row { display: flex; gap: 16px; align-items: flex-start; flex-wrap: wrap; }

.avatar {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--navy-700);
  color: #fff;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 0.85rem;
  overflow: hidden;
  flex: none;
}

.avatar img { width: 100%; height: 100%; object-fit: cover; }
.avatar--lg { width: 96px; height: 96px; font-size: 1.5rem; }

.profile-head {
  display: flex;
  gap: 16px;
  align-items: center;
  flex-wrap: wrap;
}

.badge-row { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 6px; }

.pill--baptized { background: var(--sky-100); color: var(--navy-800); border-color: #c5e2f3; }

/* Search in the header ------------------------------------------------------ */

.topbar__search {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 1 1 180px;
  max-width: 320px;
  padding: 0 10px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.14);
  color: #fff;
}

.topbar__search .icon { width: 16px; height: 16px; opacity: 0.85; flex: none; }

.topbar__search input {
  flex: 1;
  min-width: 0;
  height: 36px;
  border: 0;
  background: transparent;
  color: #fff;
  font-size: 0.88rem;
}

.topbar__search input::placeholder { color: rgba(255, 255, 255, 0.72); }
.topbar__search input:focus { outline: none; }
.topbar__search:focus-within { background: rgba(255, 255, 255, 0.22); outline: 2px solid var(--gold-400); outline-offset: 1px; }

.topbar__search-close { display: none; }

/* Not enough room for a persistent field once icons, brand and Sign out all
   compete for the same row — the field itself is still full desktop width
   and behaviour, just collapsed to an icon until tapped. */
.topbar__search-toggle { display: none; }

@media (max-width: 720px) {
  .topbar__search { flex-basis: 120px; }
  .topbar__search .icon { display: none; }
}

@media (max-width: 600px) {
  .topbar__search-toggle {
    display: inline-flex; align-items: center; justify-content: center;
    width: 40px; height: 40px; flex: none; border: 0; border-radius: 999px;
    background: transparent; color: #fff; cursor: pointer;
  }
  .topbar__search-toggle:hover { background: rgba(255, 255, 255, 0.12); }
  .topbar__search { display: none; }

  /*
   * While searching, the field takes over the header row as a full-width
   * overlay rather than fighting brand/bell/hamburger for a sliver of
   * space — the same pattern used by every mobile app search does. Nothing
   * beneath moves or reflows: this sits on top of the existing row.
   */
  .topbar.is-searching .topbar__search {
    display: flex;
    position: absolute;
    left: 16px; right: 16px;
    top: env(safe-area-inset-top, 0);
    height: var(--topbar-h);
    max-width: none; flex: none;
    z-index: 5;
  }
  .topbar.is-searching .topbar__search .icon { display: block; }
  .topbar.is-searching .topbar__search-close {
    display: inline-flex; align-items: center; justify-content: center;
    width: 28px; height: 28px; flex: none; border: 0; border-radius: 999px;
    background: transparent; color: #fff; cursor: pointer;
  }
  .topbar.is-searching .topbar__search-close:hover { background: rgba(255, 255, 255, 0.18); }
  .topbar.is-searching .topbar__menu,
  .topbar.is-searching .brand--compact,
  .topbar.is-searching .topbar__spacer,
  .topbar.is-searching .topbar__search-toggle,
  .topbar.is-searching .topbar__bell {
    visibility: hidden;
  }
}

/* Brief acknowledgements ---------------------------------------------------- */

.toast-host {
  position: fixed;
  left: 50%;
  bottom: 20px;
  transform: translateX(-50%);
  z-index: 70;
  display: flex;
  flex-direction: column;
  gap: 8px;
  align-items: center;
  pointer-events: none;
}

.toast {
  background: var(--navy-800);
  color: #fff;
  padding: 10px 16px;
  border-radius: 999px;
  font-size: 0.86rem;
  box-shadow: 0 6px 18px rgba(11, 35, 64, 0.28);
  max-width: min(90vw, 460px);
  text-align: center;
  animation: toast-in 180ms ease-out;
}

.toast.is-leaving { opacity: 0; transition: opacity 400ms ease; }

@keyframes toast-in {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
  .toast { animation: none; }
  .toast.is-leaving { transition: none; }
}

/* A notice that carries its own action ------------------------------------- */

.notice--action {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
  justify-content: space-between;
}

.notice--action p { margin: 4px 0 0; }
.notice--action .notice__actions { display: flex; flex-wrap: wrap; gap: 8px; }
/* `.notice a { color: inherit }` above made a button inside a notice take the notice's dark text on its own dark fill: unreadable. The button keeps its own white text. */
.notice a.btn, .notice a.btn:hover { color: #fff; }
.notice a.btn--secondary, .notice a.btn--secondary:hover { color: var(--navy-800); }

@media (max-width: 720px) {
  .notice--action .notice__actions { width: 100%; }
  .notice--action .notice__actions .btn { flex: 1; justify-content: center; }
}

/* Church leadership -------------------------------------------------------- */

/* Portrait cards: every portrait sits in the same 3:4 frame (the shape of the supplied photographs), cropped with object-fit rather than stretched, with the
   crop weighted to the top where faces are. A replacement portrait of any shape fits the same frame, so new approved files need no layout change. */
.leaders {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 16px;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 168px), 1fr));
}

.leaders li {
  display: flex;
  flex-direction: column;
  gap: 0;
  align-items: stretch;
  padding: 0;
  overflow: hidden;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
}
.leaders li > span:last-child { padding: 10px 12px 12px; min-width: 0; }

.leaders .avatar--lg {
  width: 100%; height: auto; aspect-ratio: 3 / 4; border-radius: 0; font-size: 2.6rem;
  background: var(--navy-700);
}
.leaders .avatar--lg img { width: 100%; height: 100%; object-fit: cover; object-position: center 18%; }
.leaders .list__name { display: block; overflow-wrap: anywhere; }

/* About our church --------------------------------------------------------- */

.church-motto {
  font-family: var(--font-display);
  font-size: 1.15rem;
  color: var(--navy-800);
  margin: 0 0 16px;
}

.meeting-card { border-left: 3px solid var(--gold-500); margin-bottom: 18px; }

.meeting-card__grid {
  display: grid;
  gap: 18px;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
}

.meeting-card__value {
  font-family: var(--font-display);
  font-size: 1.1rem;
  color: var(--navy-800);
  margin: 2px 0 4px;
}

/* Document library --------------------------------------------------------- */

.filters--library { flex-wrap: wrap; }

.library-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
  justify-content: space-between;
  margin: 14px 0;
}

.library-bar__tags { display: flex; flex-wrap: wrap; gap: 6px; }
.library-bar__view { display: flex; gap: 6px; }
.library-bar__view .is-current { background: var(--navy-800); color: #fff; border-color: var(--navy-800); }

.chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 4px 10px;
  border-radius: 999px;
  border: 1px solid var(--line);
  background: var(--surface);
  color: var(--navy-800);
  font-size: 0.78rem;
  text-decoration: none;
}

.chip:hover { border-color: var(--navy-700); }
.chip--on { background: var(--navy-800); color: #fff; border-color: var(--navy-800); }

.doc-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 14px;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
}

.doc-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition: border-color 120ms ease, box-shadow 120ms ease;
}

.doc-card:hover { border-color: var(--navy-500); box-shadow: 0 3px 12px rgba(16, 40, 70, 0.08); }

.doc-card__thumb {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 6px;
  height: 132px;
  background: var(--navy-50);
  color: var(--navy-700);
  text-decoration: none;
  overflow: hidden;
}

.doc-card__thumb img { width: 100%; height: 100%; object-fit: cover; }
.doc-card__thumb .icon { width: 34px; height: 34px; }
.doc-card__thumb span { font-size: 0.72rem; letter-spacing: 0.08em; text-transform: uppercase; }
.doc-card__thumb--image { background: var(--line-soft); }

.doc-card__body { padding: 12px; display: flex; flex-direction: column; gap: 6px; flex: 1; }

.doc-card__title {
  font-weight: 600;
  color: var(--navy-800);
  text-decoration: none;
  line-height: 1.35;
}

.doc-card__title:hover { text-decoration: underline; }
.doc-card__desc { margin: 0; font-size: 0.82rem; color: var(--muted); line-height: 1.5; }
.doc-card__meta { margin: 0; display: flex; flex-wrap: wrap; gap: 4px; }
.doc-card__foot { margin: auto 0 0; font-size: 0.75rem; color: var(--muted); }

.stat--link { text-decoration: none; display: block; }
.stat--link:hover { border-color: var(--navy-500); }

/* Upload -------------------------------------------------------------------- */

.dropzone {
  border: 2px dashed var(--line);
  border-radius: var(--radius);
  background: var(--surface-muted);
  padding: 22px;
  text-align: center;
  transition: border-color 120ms ease, background 120ms ease;
}

.dropzone.is-over { border-color: var(--navy-600); background: var(--navy-50); }
.dropzone.has-error { border-color: var(--red-600); background: var(--red-100); }
.dropzone .field-error { margin: 12px 0 0; color: var(--red-600); font-size: 0.85rem; font-weight: 600; }
.dropzone input[type="file"] { position: absolute; width: 1px; height: 1px; opacity: 0; }

.dropzone__label {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 6px;
  cursor: pointer;
  min-height: 44px;
}

.dropzone__label .icon { width: 28px; height: 28px; color: var(--navy-700); }
.dropzone__main { font-weight: 600; color: var(--navy-800); }
.dropzone__hint { font-size: 0.82rem; color: var(--muted); }

.dropzone__preview {
  margin-top: 16px;
  display: flex;
  gap: 12px;
  align-items: center;
  justify-content: center;
  text-align: left;
}

.dropzone__preview img {
  width: 84px;
  height: 84px;
  object-fit: cover;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
}

/* Document detail ----------------------------------------------------------- */

.doc-detail { display: grid; gap: 18px; }

@media (min-width: 960px) {
  .doc-detail { grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr); align-items: start; }
}

.doc-detail__side { display: grid; gap: 18px; }
.doc-preview__image { width: 100%; height: auto; border-radius: var(--radius-sm); display: block; }
.doc-preview__pdf { width: 100%; height: 60vh; min-height: 380px; border: 1px solid var(--line); border-radius: var(--radius-sm); }

.danger-zone {
  margin-top: 16px;
  padding-top: 16px;
  border-top: 1px solid var(--line);
}

.danger-zone h3 { font-size: 0.95rem; color: var(--red-600); margin: 0 0 6px; }
.btn--danger { background: var(--red-600); border-color: var(--red-600); color: #fff; }
.btn--danger:hover { background: #a32a22; border-color: #a32a22; }
.stack-form .field-grid { margin-bottom: 8px; }

/* Membership statuses beyond the original four --------------------------- */

.pill--temporarily_away { background: var(--gold-50); color: #7a5406; border-color: #e6cf94; }
.pill--returned_home,
.pill--migrated { background: var(--sky-100); color: var(--navy-800); border-color: #c5e2f3; }
.pill--transferred { background: var(--line-soft); color: var(--ink); border-color: var(--line); }
.pill--other { background: var(--surface-muted); color: var(--muted); border-color: var(--line); }

/* Member quick view from the attendance sheet ------------------------------ */

.quick-drawer { position: fixed; inset: 0; z-index: 80; }
.quick-drawer[hidden] { display: none; }

.quick-drawer__scrim {
  position: absolute;
  inset: 0;
  background: rgba(10, 25, 45, 0.42);
}

.quick-drawer__panel {
  position: absolute;
  background: var(--surface);
  display: flex;
  flex-direction: column;
  box-shadow: 0 10px 40px rgba(10, 25, 45, 0.28);
}

/* On a phone the profile rises from the bottom and covers most of the screen. */
.quick-drawer__panel {
  left: 0;
  right: 0;
  bottom: 0;
  max-height: 92vh;
  border-radius: 16px 16px 0 0;
  animation: quick-up 160ms ease-out;
}

@media (min-width: 860px) {
  .quick-drawer__panel {
    top: 0;
    bottom: 0;
    left: auto;
    right: 0;
    width: min(460px, 92vw);
    max-height: none;
    border-radius: 0;
    animation: quick-in 160ms ease-out;
  }
}

@keyframes quick-up { from { transform: translateY(14px); opacity: 0; } }
@keyframes quick-in { from { transform: translateX(18px); opacity: 0; } }

@media (prefers-reduced-motion: reduce) {
  .quick-drawer__panel { animation: none; }
}

.quick-drawer__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  padding: 16px 18px;
  border-bottom: 1px solid var(--line);
  background: var(--navy-900);
  color: #fff;
}

.quick-drawer__head h2 { margin: 2px 0 0; font-size: 1.05rem; color: #fff; }
.quick-drawer__context { margin: 0; font-size: 0.78rem; color: rgba(255, 255, 255, 0.78); }
.quick-drawer__head .btn { background: rgba(255, 255, 255, 0.14); border-color: rgba(255, 255, 255, 0.3); color: #fff; }
.quick-drawer__body { padding: 18px; overflow-y: auto; flex: 1; }

.quick__head { display: flex; gap: 14px; align-items: center; margin-bottom: 16px; }
.quick__head h3 { margin: 0; font-size: 1.1rem; }
.quick__code { margin: 2px 0 6px; font-size: 0.8rem; color: var(--muted); }
.quick__facts { margin-bottom: 18px; }

.quick__section {
  border-top: 1px solid var(--line);
  padding-top: 14px;
  margin-top: 14px;
}

.quick__section h4 { margin: 0 0 10px; font-size: 0.95rem; color: var(--navy-800); }

.quick__counts {
  list-style: none;
  margin: 0 0 10px;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 8px;
  text-align: center;
}

.quick__counts li {
  background: var(--surface-muted);
  border-radius: var(--radius-sm);
  padding: 8px 4px;
}

.quick__counts strong { display: block; font-size: 1.15rem; color: var(--navy-800); }
.quick__counts span { font-size: 0.72rem; color: var(--muted); }
.quick__note { font-size: 0.82rem; color: var(--muted); line-height: 1.55; margin: 0 0 10px; }

.quick__recent { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 10px; }
.quick__recent li { text-align: center; font-size: 0.72rem; color: var(--muted); }
.quick__recent .mark { display: block; margin: 0 auto 3px; }

.quick__actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 18px; }
.quick__actions .btn { flex: 1; justify-content: center; min-width: 140px; }

/* Group and ministry quick view -------------------------------------------- */

.quick__banner {
  margin: -18px -18px 16px;
  height: 150px;
  background: var(--navy-50);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.quick__banner img { width: 100%; height: 100%; object-fit: cover; }
.quick__banner-fallback .icon { width: 46px; height: 46px; color: var(--navy-500); }
.quick__description { font-size: 0.9rem; line-height: 1.6; margin: 0 0 14px; white-space: pre-wrap; }

.quick__people { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.quick__people li { display: flex; gap: 10px; align-items: center; }
.quick__people .avatar { width: 34px; height: 34px; font-size: 0.75rem; }

/* The public About page ---------------------------------------------------- */

.public { background: var(--surface-muted); min-height: 100vh; display: flex; flex-direction: column; }

.public__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 18px;
  background: var(--navy-900);
  color: #fff;
}

.public__brand { display: flex; align-items: center; gap: 10px; color: #fff; text-decoration: none; }
.public__brand img { border-radius: 50%; background: #fff; }
.public__brand strong { display: block; font-size: 0.95rem; }
.public__brand small { display: block; font-size: 0.74rem; color: rgba(255, 255, 255, 0.75); }
.public__bar .btn { background: rgba(255, 255, 255, 0.14); border-color: rgba(255, 255, 255, 0.32); color: #fff; }

.public__main { flex: 1; width: 100%; max-width: 900px; margin: 0 auto; padding: 22px 18px 40px; }

.public__foot {
  padding: 18px;
  text-align: center;
  font-size: 0.82rem;
  color: var(--muted);
  border-top: 1px solid var(--line);
}

.public__foot p { margin: 2px 0; }


/* A calmer dashboard ------------------------------------------------------- */

.page-head--plain { border-bottom: 0; padding-bottom: 4px; margin-bottom: 14px; }

.quick-actions {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 10px;
  margin-bottom: 18px;
}

.quick-action {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 14px;
  min-height: 56px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  color: var(--navy-800);
  font-weight: 600;
  text-decoration: none;
  transition: border-color 120ms ease, box-shadow 120ms ease;
}

.quick-action:hover { border-color: var(--navy-500); box-shadow: 0 2px 10px rgba(16, 40, 70, 0.08); }

.quick-action__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  flex: none;
  border-radius: 50%;
  background: var(--navy-50);
  color: var(--navy-700);
}

.quick-action__icon .icon { width: 18px; height: 18px; }

.next-service__date {
  font-family: var(--font-display);
  font-size: 1.2rem;
  color: var(--navy-800);
  margin: 0 0 2px;
}

/* Attendance over recent services, without a charting library. */
.trend {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  align-items: flex-end;
  gap: 10px;
  height: 150px;
  min-width: max-content;
}

.trend__item {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  height: 100%;
  gap: 4px;
  min-width: 32px;
}

.trend__bar {
  width: 100%;
  max-width: 44px;
  background: var(--navy-600);
  border-radius: 4px 4px 0 0;
  min-height: 4px;
}

.trend__value { font-size: 0.8rem; font-weight: 600; color: var(--navy-800); }
.trend__label { font-size: 0.7rem; color: var(--muted); }

@media (max-width: 720px) {
  .quick-actions { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .quick-action { flex-direction: column; align-items: flex-start; gap: 8px; font-size: 0.88rem; }
  .trend { height: 120px; gap: 6px; }
  .trend__label { font-size: 0.62rem; }
}


/* The Giving Board --------------------------------------------------------- */

/*
 * The board on the church wall: a picture of the worship centre with a paper
 * slip pinned over every day of the year. The picture is painted once on the
 * board itself and the slips sit over it, so a slip that comes off is simply
 * not drawn and the part of the building behind it lines up with the rest.
 *
 * A slip only comes off when the day has been paid. A promise alone does not
 * uncover the building, or the picture would say more than the church has
 * actually received.
 */

.board-years {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
  margin-bottom: 14px;
}

.board-years__tab {
  padding: 8px 16px;
  min-height: 40px;
  display: inline-flex;
  align-items: center;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--navy-800);
  font-weight: 600;
  text-decoration: none;
}

.board-years__tab:hover { border-color: var(--navy-500); }
.board-years__tab.is-current { background: var(--navy-900); border-color: var(--navy-900); color: #fff; }
.board-years__add { margin-left: auto; font-size: 0.85rem; color: var(--navy-700); display: inline-flex; align-items: center; min-height: 28px; }

.board-frame {
  background: linear-gradient(180deg, #12305a 0%, #0a2140 100%);
  border-radius: var(--radius);
  padding: 14px;
  box-shadow: 0 10px 30px rgba(9, 24, 44, 0.28);
}

.board-head {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) minmax(0, 1.1fr);
  gap: 14px;
  align-items: center;
  padding: 4px 6px 14px;
  color: #fff;
}

.board-head__logo { border-radius: 50%; background: #fff; padding: 2px; }
.board-head__title h1 { margin: 0; color: #fff; font-size: clamp(1.3rem, 3vw, 2rem); letter-spacing: 0.01em; }
.board-head__title p { margin: 2px 0 0; font-size: 0.86rem; color: rgba(255, 255, 255, 0.78); }

.board-head__verse {
  margin: 0;
  font-size: 0.78rem;
  line-height: 1.5;
  color: rgba(255, 255, 255, 0.82);
  font-style: italic;
  text-align: right;
}

.board-head__verse cite { display: block; font-style: normal; opacity: 0.75; margin-top: 2px; }

/* The wall itself does not clip: a slip's note must be able to rise above the top rows (it was cut off there). The picture clips its own corners instead. */
.board-wall {
  position: relative;
  border-radius: var(--radius-sm);
  background: #0d2440;
  padding: 8px;
}

/* One continuous picture under every slip. */
.board-wall__picture {
  position: absolute;
  inset: 0;
  border-radius: var(--radius-sm);
  overflow: hidden;
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
}

/*
 * Thirty columns of thirteen rows gives a board almost exactly the shape of the
 * photograph, so it is never cropped and the last slip uncovers the last piece
 * of the building. The count stays the same at every screen size for that
 * reason; only the slips get smaller.
 */
.board-wall__months {
  position: relative;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(30, minmax(0, 1fr));
  gap: 0;
}

/* On a wide screen the month sections add nothing to the layout: the slips flow into the one wall. The month headings stay for screen readers. */
.board-month, .board-month__stubs { display: contents; list-style: none; margin: 0; padding: 0; }
.board-month__name { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.board-month__short, .board-month__year { display: none; }

.stub { position: relative; aspect-ratio: 3 / 4; }

.stub__paper {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0;
  border: 0;
  padding: 0;
  overflow: hidden;
  text-decoration: none;
  cursor: pointer;
  color: #b03a2e;
  background: linear-gradient(180deg, #fdf6e6 0%, #f4e7ce 100%);
  /* Ruled edges, so the board reads as a grid of slips rather than one sheet. */
  box-shadow: inset -1px -1px 0 rgba(120, 95, 60, 0.5),
              inset 1px 1px 0 rgba(255, 255, 255, 0.72);
  transition: transform 120ms ease, box-shadow 120ms ease;
}

/* A day nobody has taken yet. */
.stub__paper--free { background: linear-gradient(180deg, #fdf6e6 0%, #f2e4c9 100%); }

/* Taken, but nothing paid yet: the same paper, marked with a red edge. */
.stub__paper--taken {
  background: linear-gradient(180deg, #f6ece0 0%, #e8d7bf 100%);
  box-shadow: inset 0 -3px 0 rgba(176, 58, 46, 0.6),
              inset -1px -1px 0 rgba(120, 95, 60, 0.5), inset 1px 1px 0 rgba(255, 255, 255, 0.62);
}

/* Part paid: the slip fills from the bottom as the money comes in. */
.stub__paper--partial {
  background: linear-gradient(180deg, #fdf6e6 0%, #f2e4c9 100%);
  box-shadow: inset 0 -3px 0 var(--gold-500),
              inset -1px -1px 0 rgba(120, 95, 60, 0.5), inset 1px 1px 0 rgba(255, 255, 255, 0.72);
}

.stub__fill {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(223, 165, 35, 0.32);
  pointer-events: none;
}

.stub__month,
.stub__year,
.stub__day { position: relative; z-index: 1; }

.stub__month { font-size: clamp(4px, 0.5vw, 9px); font-weight: 700; line-height: 1.1; }
.stub__year { font-size: clamp(3px, 0.4vw, 7px); line-height: 1.1; opacity: 0.85; }
.stub__day { font-size: clamp(7px, 0.95vw, 17px); font-weight: 700; line-height: 1.1; }

.stub__paper:hover,
.stub__paper:focus-visible {
  transform: translateY(-2px) rotate(-1.2deg);
  box-shadow: 0 4px 9px rgba(0, 0, 0, 0.38);
  z-index: 3;
  outline: none;
}

.stub__paper:focus-visible { box-shadow: 0 0 0 2px var(--gold-500), 0 4px 9px rgba(0, 0, 0, 0.38); }

/* Paid: nothing is drawn, so the building shows through. */
.stub--gone .stub__reveal {
  position: absolute;
  inset: 0;
  border: 0;
  padding: 0;
  background: transparent;
  cursor: pointer;
  /* The ruling continues over the picture, faintly, so the board holds together. */
  box-shadow: inset -1px -1px 0 rgba(255, 255, 255, 0.22),
              inset 1px 1px 0 rgba(0, 0, 0, 0.16);
}

.stub--gone .stub__reveal:hover,
.stub--gone .stub__reveal:focus-visible {
  box-shadow: inset 0 0 0 2px rgba(255, 255, 255, 0.85);
  outline: none;
}

.stub--mine .stub__reveal {
  box-shadow: inset 0 0 0 1px rgba(223, 165, 35, 0.7),
              inset -1px -1px 0 rgba(255, 255, 255, 0.22);
}

/* The date and the giver appear only on hover or tap, never over the picture. */
.stub__tip {
  position: absolute;
  bottom: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%);
  z-index: 20;
  width: max-content;
  max-width: 260px;
  display: none;
  flex-direction: column;
  gap: 1px;
  padding: 9px 11px;
  border-radius: var(--radius-sm);
  background: rgba(8, 22, 40, 0.97);
  color: #fff;
  font-size: 0.86rem;
  line-height: 1.5;
  text-align: left;
  pointer-events: none;
  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.36);
}

.stub__tip strong { font-size: 0.92rem; }
.stub__tip-state { color: var(--gold-300, #f2d18a); }
.stub__tip-own { color: #9fd8a8; }

.stub:hover .stub__tip,
.stub.is-open .stub__tip { display: flex; }
/* keyboard focus on the slip shows the same note (only for a keyboard user: after a mouse click the slip keeps focus but its note must not stay up over its neighbours) */
.board-wall__months.is-keyboard .stub:focus-within .stub__tip:not(.stub__tip--admin) { display: flex; }

.stub--edge-start .stub__tip { left: 0; transform: none; }
.stub--edge-end .stub__tip { left: auto; right: 0; transform: none; }

.board-foot { padding: 14px 6px 4px; color: #fff; }

.board-foot__figures {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 20px;
  font-size: 0.8rem;
  color: rgba(255, 255, 255, 0.8);
  margin-bottom: 8px;
}

.board-foot__figures strong { color: #fff; font-size: 0.95rem; }

.board-foot__bar {
  height: 8px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.16);
  overflow: hidden;
}

.board-foot__bar span { display: block; height: 100%; background: var(--gold-500); }
.board-foot__note { margin: 8px 0 0; font-size: 0.78rem; color: rgba(255, 255, 255, 0.72); }

.board-pick {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: flex-end;
  padding: 14px;
  margin-top: 16px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.board-pick .field { margin: 0; flex: 1; min-width: 190px; }

.board-key {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 8px 20px;
  margin: 14px 0 0;
  padding: 0;
  font-size: 0.82rem;
  color: var(--muted);
}

.board-key li { display: flex; align-items: center; gap: 7px; }

.board-key__swatch {
  width: 15px;
  height: 20px;
  border-radius: 2px;
  border: 1px solid var(--line);
  flex: none;
}

.board-key__swatch--free { background: linear-gradient(180deg, #fdf6e6, #f2e4c9); }
.board-key__swatch--taken { background: linear-gradient(180deg, #f6ece0, #e8d7bf); box-shadow: inset 0 -3px 0 rgba(176, 58, 46, 0.55); }
.board-key__swatch--partial { background: linear-gradient(180deg, #fdf6e6, #f2e4c9); box-shadow: inset 0 -3px 0 var(--gold-500); }
.board-key__swatch--gone { background: url('/branding/ecaq-worship-centre-small.jpg') center/cover; }

@media (max-width: 900px) {
  .board-frame { padding: 10px; }
  .board-head { grid-template-columns: auto minmax(0, 1fr); }
  .board-head__verse { grid-column: 1 / -1; text-align: left; }
  .board-wall { padding: 5px; }
  .stub__month, .stub__year { display: none; }
}

@media (max-width: 560px) {
  .stub__day { font-size: 6px; }
  .stub__tip { font-size: 0.72rem; max-width: 165px; }
}

@media (prefers-reduced-motion: reduce) {
  .stub__paper:hover, .stub__paper:focus-visible { transform: none; }
}

/* A day that has been taken opens its details on a tap as well as on hover. */
.stub--taken .stub__paper { cursor: pointer; }
.stub--taken.is-open .stub__paper { transform: translateY(-2px) rotate(-1.2deg); z-index: 3; }

.steps { margin: 0 0 12px; padding-left: 20px; display: grid; gap: 8px; font-size: 0.9rem; line-height: 1.55; }

/* Sortable table columns ---------------------------------------------------- */

.sortable-column {
  color: inherit;
  text-decoration: none;
  white-space: nowrap;
}

.sortable-column:hover { text-decoration: underline; }
.sortable-column.is-active { color: var(--navy-800); font-weight: 700; }

/* A sortable column header rendered as a button (client-side tables) rather
   than a link (server-driven ones) — same look, no browser default chrome. */
button.sortable-column {
  background: none;
  border: 0;
  padding: 0;
  font: inherit;
  cursor: pointer;
}

button.sortable-column::after { content: ''; display: inline-block; width: 0.9em; }
button.sortable-column.is-active::after { content: attr(data-arrow); }

.roster__select-col { width: 40px; text-align: center; }
.roster-actions[data-roster-bulk] { margin-top: 8px; }

/* Board picture upload on the campaign form ---------------------------------- */

.board-picture-preview {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 8px 0 10px;
}

.board-picture-preview img {
  width: 160px;
  height: 92px;
  object-fit: cover;
  border-radius: var(--radius-sm);
  border: 1px solid var(--line);
  background: var(--surface-muted);
}

/* "Who is inviting people" on the First Timers follow-up page ---------------- */

/*
 * One ordinary table. Each inviter is a real row whose cells sit in the same columns as the headings above them, so a heading and its numbers
 * cannot drift apart: the columns are fixed once, here, for the heading row and every data row alike. Numeric columns are right-aligned in
 * the heading AND in the cells. The sort arrow is hung outside the heading's text (absolute), so it never moves the label.
 */
table.inviter-table { table-layout: fixed; }
table.inviter-table col.inviter-table__name { width: auto; }
table.inviter-table col.inviter-table__num { width: 8.5rem; }
table.inviter-table thead th.numeric,
table.inviter-table tbody td.numeric { text-align: right; font-variant-numeric: tabular-nums; }
table.inviter-table thead th { white-space: normal; overflow-wrap: anywhere; vertical-align: bottom; }
table.inviter-table .sortable-column { position: relative; white-space: normal; }
table.inviter-table .sortable-column .sort-arrow { position: absolute; left: 100%; margin-left: 4px; }
table.inviter-table thead th.numeric { padding-right: 24px; }
table.inviter-table tbody td.numeric { padding-right: 24px; }
table.inviter-table tr.inviter-main td:first-child { overflow-wrap: anywhere; }
table.inviter-table tr.inviter-detail > td { padding: 0; border-top: 0; background: var(--surface-sunk); }
table.inviter-table tr.inviter-detail[hidden] { display: none; }
.inviter-detail__box { padding: 4px 12px 12px 36px; overflow-x: auto; }
.data--compact th, .data--compact td { padding: 6px 10px; font-size: 0.86rem; }

.inviter-toggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; margin: 0 6px 0 -6px; padding: 0;
  background: none; border: 0; border-radius: var(--radius-sm); color: var(--muted); cursor: pointer; vertical-align: middle;
}
.inviter-toggle[hidden] { display: none; }
.inviter-toggle:hover { background: var(--surface-sunk); color: var(--ink); }
.inviter-toggle__chevron { width: 0; height: 0; border-left: 6px solid currentColor; border-top: 5px solid transparent; border-bottom: 5px solid transparent; transition: transform 120ms ease; }
.inviter-toggle[aria-expanded="true"] .inviter-toggle__chevron { transform: rotate(90deg); }

@media (max-width: 720px) {
  /* The ordinary stacked-record layout of table.data takes over; the numbers are labelled by data-label. */
  table.inviter-table col { width: auto; }
  table.inviter-table thead th.numeric, table.inviter-table tbody td.numeric { padding-right: 0; text-align: left; }
  table.inviter-table tr.inviter-main td:first-child { display: flex; align-items: center; }
  table.inviter-table tr.inviter-main td:first-child::before { display: none; }
  .inviter-detail__box { padding: 4px 0 8px 12px; }
}

/* First Timer detail page: compact, in the portal's desktop density, without shrinking type ----------------------- */

.ft-detail { display: grid; gap: 12px; grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr)); align-items: start; }
.ft-detail .card__head { padding: 12px 14px 0; }
.ft-detail .card__body { padding: 10px 14px 12px; }
.ft-detail .definition { gap: 6px 12px; }
.ft-detail .definition dd { overflow-wrap: anywhere; }
.ft-detail .timeline li { padding-bottom: 8px; }
.ft-detail .timeline li:last-child { padding-bottom: 0; }
.ft-detail .fieldset__hint { margin: 8px 0 0; }
.ft-detail__stack { display: grid; gap: 12px; min-width: 0; }
.ft-inline-form { display: flex; align-items: flex-end; gap: 10px; flex-wrap: wrap; margin-top: 12px; }
.ft-inline-form .field { flex: 1 1 160px; }
.ft-stack-form { display: grid; gap: 8px; margin-top: 10px; }
.ft-detail textarea { min-height: 56px; }
@media (max-width: 720px) {
  .ft-detail .definition dd { margin-bottom: 6px; }
}

/* First Timer registration tab (administrative desk) -------------------------------------------------------------- */

.checkin-ft { max-width: 520px; }
.checkin-ft__form { display: grid; gap: var(--space-field); }
.checkin-ft__form .form__actions { margin-top: 4px; }
.checkin-ft-foot { display: flex; align-items: center; gap: 8px 14px; flex-wrap: wrap; }
.checkin-ft-foot small { color: var(--muted); font-size: var(--fs-help); }
.checkin-done .card__body { text-align: center; }
.checkin-done__icon { width: 40px; height: 40px; color: var(--green-700, #1a7f37); }
.checkin-done__title { font-size: 1.3rem; margin: 6px 0 8px; }
.checkin-done .checkin-actions { margin-top: 14px; }

/* Faith Promise pledge card ------------------------------------------------- */

.pledge-card {
  margin-top: 8px;
  background: var(--faith-green-900);
  border-radius: 18px;
  padding: 2px;
  box-shadow: 0 18px 40px -20px rgba(19, 58, 38, 0.55);
  max-width: 620px;
  margin: 0 auto;
}

.pledge-card__inner {
  background: var(--faith-cream);
  border-radius: 16px;
  padding: 32px 28px;
  border: 1px solid rgba(19, 58, 38, 0.15);
}

.pledge-card__header {
  text-align: center;
  color: var(--faith-green-900);
  margin-bottom: 18px;
}

.pledge-card__title {
  font-family: Georgia, 'Times New Roman', serif;
  font-size: 1.7rem;
  font-weight: 700;
  line-height: 1.25;
  margin: 0 0 4px;
}

.pledge-card__subtitle {
  font-size: 1rem;
  color: var(--faith-green-700);
  margin: 0;
}

.pledge-card__verse {
  text-align: center;
  font-style: italic;
  color: var(--faith-green-700);
  font-size: 0.9rem;
  margin: 14px 0;
  padding: 10px 0;
  border-top: 1px solid rgba(19, 58, 38, 0.2);
  border-bottom: 1px solid rgba(19, 58, 38, 0.2);
}

.pledge-card__statement {
  text-align: center;
  font-size: 1.02rem;
  color: var(--faith-green-900);
  line-height: 1.5;
  margin: 0 0 22px;
}

.pledge-card__field { margin-bottom: 14px; }
.pledge-card__field label {
  display: block;
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--faith-green-900);
  margin-bottom: 4px;
}
.pledge-card__field input,
.pledge-card__field select {
  width: 100%;
  padding: 9px 12px;
  border: 1.5px solid var(--faith-green-500);
  border-radius: 8px;
  background: #fff;
  font-size: 0.95rem;
}
.pledge-card__field input:focus,
.pledge-card__field select:focus { outline: 3px solid var(--sky-400); border-color: var(--faith-green-700); }

.pledge-card__frequency-label {
  display: block; font-size: 0.82rem; font-weight: 600; color: var(--faith-green-900); margin-bottom: 6px;
}

.pledge-card__frequency {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 8px;
  margin: 6px 0 20px;
}
.pledge-card__frequency label {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 10px 6px;
  border: 1.5px solid var(--faith-green-500);
  border-radius: 8px;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--faith-green-900);
  cursor: pointer;
  text-align: center;
}
.pledge-card__frequency input { accent-color: var(--faith-green-700); }
.pledge-card__frequency input:checked + span { color: var(--faith-green-900); }
.pledge-card__frequency label:has(input:checked) {
  background: var(--faith-green-700);
  color: #fff;
  border-color: var(--faith-green-700);
}
.pledge-card__frequency label:has(input:checked) span { color: #fff; }

.pledge-card__total {
  background: var(--faith-green-900);
  color: #fff;
  border-radius: 10px;
  padding: 14px 18px;
  text-align: center;
  margin-bottom: 20px;
}
.pledge-card__total-label { font-size: 0.8rem; opacity: 0.85; margin: 0; }
.pledge-card__total-amount { font-family: Georgia, serif; font-size: 1.8rem; font-weight: 700; margin: 2px 0 0; }

.pledge-card__period {
  text-align: center;
  font-size: 0.85rem;
  color: var(--faith-green-700);
  margin-bottom: 18px;
}

.pledge-card__submit {
  width: 100%;
  background: var(--faith-green-700);
  color: #fff;
  border: none;
  border-radius: 9px;
  padding: 13px;
  font-size: 1rem;
  font-weight: 700;
  cursor: pointer;
}
.pledge-card__submit:hover { background: var(--faith-green-900); }

@media (max-width: 480px) {
  .pledge-card__inner { padding: 22px 16px; }
  .pledge-card__title { font-size: 1.4rem; }
  .pledge-card__frequency { grid-template-columns: 1fr; }
}

/* --- Shared searchable member picker -------------------------------------
   Wherever an existing member must be linked (spouse, father, mother,
   guardian, and other locations — see CCIQ_DECISIONS.md), instead of a
   native <select> listing hundreds of members. */

.member-picker { position: relative; }
.member-picker__input {
  width: 100%; min-height: 42px; padding: 0 14px;
  border: 1px solid var(--control-border); border-radius: var(--radius-sm);
  font: inherit; background: var(--surface);
}
.member-picker__input:focus { outline: 3px solid var(--sky-400); outline-offset: 1px; }

/* Positioned below the input, never over it, so what was typed stays
   visible while results are open. */
.member-picker__results {
  position: absolute; z-index: 30; top: 100%; left: 0; right: 0; margin-top: 6px;
  background: var(--surface); border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm); box-shadow: var(--shadow-raised);
  max-height: 280px; overflow-y: auto; padding: 4px;
}
.member-picker__result {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  padding: 8px 10px; border: 0; border-radius: var(--radius-sm);
  background: transparent; cursor: pointer; font: inherit; color: inherit;
}
.member-picker__result:hover, .member-picker__result:focus-visible {
  background: var(--surface-sunk); outline: none;
}
.member-picker__result .list__name { display: block; }
.member-picker__result .list__meta { display: block; }
.member-picker__empty { padding: 10px; color: var(--muted); font-size: .88rem; }

.member-picker__selected {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  flex-wrap: wrap; padding: 8px 10px; border: 1px solid var(--line);
  border-radius: var(--radius-sm); background: var(--surface-sunk);
}
.member-picker__selected-actions { display: flex; gap: 8px; flex: none; }

/* Members summary and multi-status filter. */
.members-status-counts { display: flex; flex-wrap: wrap; gap: 6px; list-style: none; margin: 10px 0 0; padding: 0; }
.members-status-counts .pill { white-space: normal; overflow-wrap: anywhere; }
.members-status-counts .pill--attendee { background: var(--sky-100); color: var(--navy-800); border-color: #c5e2f3; }
.members-status-field { min-width: 0; width: 240px; max-width: 100%; }
.members-status-label { display: block; margin-bottom: 0; font-weight: 600; font-size: var(--fs-label); line-height: 1.3; color: var(--ink-soft); }
.members-status-filter { position: relative; border: 1px solid var(--line-strong); border-radius: 8px; background: #fff; }
.members-status-filter > summary { min-height: 44px; padding: 10px 12px; cursor: pointer; overflow-wrap: anywhere; }
.members-status-filter > summary:focus-visible { outline: 2px solid var(--navy-500); outline-offset: 2px; }
.members-status-filter__options { padding: 0 10px 10px; }
.members-status-filter fieldset { min-width: 0; border: 0; margin: 0; padding: 8px 0; }
.members-status-filter legend { font-size: .76rem; font-weight: 700; text-transform: uppercase; color: var(--muted); }
.members-status-filter .members-status-option { display: flex; align-items: center; gap: 8px; min-height: 44px; margin: 0; padding: 6px 0; cursor: pointer; font-weight: 400; }
.members-status-option input { flex-shrink: 0; }
.members-status-option span { min-width: 0; overflow-wrap: anywhere; }
.members-status-filter [data-member-status-clear] { min-height: 44px; }
.members-status-filter [data-member-status-clear][hidden] { display: none; }
.members-status-filter small { display: block; margin-top: 8px; }
@media (min-width: 721px) {
  .members-status-filter__options { position: absolute; top: 100%; left: 0; z-index: 15; width: 320px; max-width: calc(100vw - 64px); padding: 10px 14px; background: #fff; border: 1px solid var(--line-strong); border-radius: 8px; box-shadow: 0 6px 18px #10243b20; }
  /*
   * Inside a report-launcher's own configuration form, a floating popover
   * would sit on top of the row-actions buttons that follow it in the same
   * narrow column (unlike the Members filter bar, where nothing sits
   * directly beneath it) — clearer here to let it expand in place instead.
   */
  .report-launcher .members-status-filter__options { position: static; width: auto; max-width: none; box-shadow: none; margin-top: 6px; }
}

/*
 * Print a report's launcher: each report starts as a compact collapsed row
 * (name, one-line description, chevron) and expands in place to its own
 * configuration form — progressive disclosure instead of every report's
 * full form competing for space at once.
 */
.report-launcher { border-top: 1px solid var(--line); }
.report-launcher:first-of-type { border-top: 0; }
.report-launcher > summary { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 16px 4px; cursor: pointer; list-style: none; }
.report-launcher > summary::-webkit-details-marker { display: none; }
.report-launcher > summary:focus-visible { outline: 2px solid var(--navy-500); outline-offset: 2px; }
.report-launcher__text { min-width: 0; }
.report-launcher__name { font-weight: 600; }
.report-launcher__hint { color: var(--muted); font-size: .85rem; margin-top: 2px; }
.report-launcher__action { flex-shrink: 0; display: flex; align-items: center; gap: 6px; color: var(--navy-600); font-weight: 600; font-size: .87rem; white-space: nowrap; }
.report-launcher__action .icon { width: 16px; height: 16px; transition: transform .15s ease; }
.report-launcher[open] > summary .report-launcher__action .icon { transform: rotate(180deg); }
.report-launcher__body { padding: 4px 4px 22px; }
/*
 * One rhythm inside every launcher's form: 16px between one field (or group of fields) and the next, 6px label to control (the shared field rule), a helper line sits tight under
 * what it explains, and the buttons start 18px below the last field with 10px between them (wrapped buttons keep the same 10px above and below). Nothing in here overlaps.
 */
.report-launcher__body form > * + * { margin-top: var(--space-field); }
.report-launcher__body form > input[type="hidden"] + * { margin-top: 0; }
.report-launcher__body form > .fieldset__hint { margin: 6px 0 0; }
.report-launcher__body form > .fieldset__hint:first-child { margin-top: 0; }
.report-launcher__body form > .fieldset__hint:first-child + * { margin-top: 10px; }
.report-launcher__body form > .row-actions { margin-top: 18px; gap: 10px; }
.report-launcher__body > .fieldset__hint { margin: 14px 0 0; }

/* Attendance register: one colgroup supplies geometry for header and body. */
.register-settings > summary { padding: 16px; cursor: pointer; font-weight: 600; }
.register-settings > .grid { padding: 0 16px 16px; }
.register-savebar { position: sticky; top: 68px; z-index: 12; display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px; padding: 12px 16px; background: var(--surface); border: 1px solid var(--line); border-radius: 10px; box-shadow: 0 3px 12px #10243b12; }
.register-savebar small { display: block; color: var(--muted); }
.register-toolbar, .register-pagination { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding: 14px 0; }
.register-toolbar select { width: auto; min-width: 76px; }
.register-bulk select { width: auto; max-width: 100%; }
.register-bulk small { flex-basis: 100%; }
.register-table { width: 100%; table-layout: fixed; }
.register-col-select { width: 44px; }
.register-col-member { width: 25%; }
.register-col-code { width: 14%; }
.register-col-group { width: 17%; }
.register-col-attendance { width: auto; }
.register-table td, .register-table th { overflow-wrap: anywhere; }
.register-table .identity { min-width: 0; }
.register-table .identity > span { min-width: 0; }
.register-table .avatar { flex-shrink: 0; }
.register-table tr[data-pending="true"] { background: #fff9e8; }
.register-table [data-pending-label] { display: block; font-size: .78rem; color: #775711; }
.register-pagination [aria-current="page"] { background: var(--navy-800); color: #fff; }
.register-pagination .btn { min-width: 40px; }
.register-table .choices { min-width: 0; }
.register-table .choice span { padding: 5px 9px; }
[data-register-message][hidden], [data-register-empty][hidden] { display: none; }
@media (max-width: 860px) {
  .register-savebar { top: 64px; }
  .register-table colgroup, .register-table thead { display: none; }
  table.register-table, table.register-table caption, table.register-table tbody, table.register-table tr, table.register-table td { display: block; width: 100%; }
  table.register-table tr { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; padding: 10px 12px; }
  table.register-table tr + tr { border-top: 1px solid var(--line); }
  table.register-table td { min-width: 0; padding: 0; border: 0; }
  table.register-table td::before { display: none; }
  table.register-table td[data-label="Select"] { display: flex; align-items: center; justify-content: center; width: 28px; min-height: 44px; }
  table.register-table td[data-label="Member"] { flex: 1 0 calc(100% - 36px); width: calc(100% - 36px); }
  table.register-table--readonly td[data-label="Member"] { flex-basis: 100%; }
  table.register-table td[data-label="Member ID"] { width: auto; max-width: 100%; font-size: .8rem; color: var(--muted); }
  table.register-table td[data-label="Cell group"] { flex: 1; width: auto; font-size: .8rem; color: var(--muted); }
  table.register-table td[data-label="Cell group"]::before { content: '·'; display: inline; margin-right: 8px; }
  table.register-table td[data-label="Attendance"] { flex-basis: 100%; padding-top: 3px; }
  .register-table .avatar { width: 32px; height: 32px; }
  .register-table .choice span { min-height: 44px; padding: 9px 10px; }
  .register-bulk { padding: 12px; }
  .register-bulk select { width: 100%; }
  .register-savebar { padding: 10px; }
}

/* Cards in a grid keep their OWN height instead of stretching to the tallest neighbour. */
.grid--top { align-items: start; }

/* --- shared pager (partials/pager.ejs) ----------------------------------- */
.pager { flex-wrap: wrap; }
.pager__count { flex: 1 1 auto; }
.pager__size { display: flex; align-items: center; gap: 8px; margin: 0; }
.pager__size label { font-size: .82rem; color: var(--muted); white-space: nowrap; }
.pager__size select { width: auto; min-width: 72px; padding: 6px 28px 6px 10px; }
@media (max-width: 600px) {
  .pager { align-items: stretch; }
  .pager__size { justify-content: space-between; }
}

.logo-preview { background: #fff; border: 1px solid var(--line); border-radius: 8px; padding: 6px; max-width: 100%; height: auto; }

/* A denser table for lists of a dozen or two rows (cell groups). */
.data--dense th, .data--dense td { padding: 7px 12px; }
.data--dense .cell-sub { display: inline; margin-left: 6px; }

/* Until a photo has loaded (or if it never does) the browser must not draw its alt text in the circle. */
img.avatar { font-size: 0; color: transparent; object-fit: cover; }

/* Family Group member rows: one identity line (name, primary contact, status), metadata beneath,
   and the row action clearly apart at the end. */
.list--family li { align-items: center; }
.family-row { gap: 16px; }
.family-row__identity { flex: 1 1 auto; min-width: 0; }
.family-row__text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.family-row__line { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 8px; }
.family-row__line .list__name { margin-right: 2px; }
.family-row__action { flex: none; margin: 0; }
.family-row__action .btn { white-space: nowrap; }
.card--danger-zone .card__head h2 { font-size: 1rem; color: var(--muted); }
.family-delete .fieldset__hint { margin-top: 0; }
@media (max-width: 560px) {
  .family-row { flex-wrap: wrap; }
  .family-row__action { width: 100%; }
  .family-row__action .btn { width: 100%; }
}

/* My Profile: compact photo management - a thumbnail and one file control, not a second identity card. */
.profile-photo__row { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.profile-photo__form { flex: 1 1 280px; min-width: 0; }
.profile-photo__title { font-size: 1rem; margin: 0 0 6px; }
.profile-photo__controls { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-bottom: 4px; }
.profile-photo__controls input[type="file"] { flex: 1 1 220px; min-width: 0; max-width: 100%; }

/* Before tracking starts the next-service panel is a slim banner, not a hero, and there is no big figure. */
.service-panel--compact { padding: 14px 22px; grid-template-columns: minmax(0, 1fr); gap: 4px; }
.service-panel--compact::after { display: none; }
.service-panel--compact .service-panel__label { margin-bottom: 2px; }
.service-panel--compact .service-panel__date { font-size: clamp(1.25rem, 3vw, 1.6rem); margin-bottom: 2px; }
.notice__fact { display: block; margin-top: 4px; font-size: .88rem; }

.empty--compact { padding: 14px 18px; text-align: left; }
.empty--compact p { margin: 0; }
.empty--compact h2 { margin: 0 0 4px; font-size: 1.05rem; }
.empty--compact p { max-width: none; }

/* My Profile: room between the identity line and the details beneath it, and a form as wide as the cards above it. */
.identity + .definition { margin-top: 18px; }
.definition + .fieldset__hint { margin-top: 14px; }
.form.card--wide { max-width: none; }
.profile-photo__row { align-items: flex-start; }
.profile-photo__row > .avatar { margin-top: 2px; }

/* Shared pager: numbered window between First/Previous and Next/Last. */
.pager__numbers { display: inline-flex; gap: 4px; align-items: center; }
.pager__number, .pager__current {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 32px; height: 32px; padding: 0 8px; border-radius: var(--radius-sm); font-size: .9rem;
}
.pager__number { color: var(--navy-700); text-decoration: none; border: 1px solid transparent; }
.pager__number:hover { background: var(--sky-100); }
.pager__current { background: var(--navy-700); color: #fff; font-weight: 600; }
@media (max-width: 560px) { .pager__edge { display: none; } }

.kiosk__hint { margin: 10px 0 0; color: var(--muted); font-size: .95rem; }

/*
 * DESKTOP DENSITY (docs/UX-STANDARDS.md). On a mouse-and-keyboard desktop the portal is one step denser than on a
 * phone: body, table and navigation text about 14.5px, secondary text about 13px, controls about 38px tall.
 * Tablets in landscape (>= 861px but touch) keep the roomier controls via the pointer query below. The drawer/mobile
 * layout (<= 860px) is untouched. The kiosk is excluded - it keeps its own large, touch-first sizes.
 */
@media (min-width: 861px) {
  body:not(.kiosk) {
    --fs-body: 14.5px;
    --fs-control: 14.5px;
    --fs-label: .87rem;
    --fs-help: .83rem;
    --control-h: 38px;
    --btn-h: 38px;
    --btn-h-sm: 32px;
    --control-pad: 7px 11px;
    --space-card: 16px;
    --space-field: 16px;
    --cell-pad: 9px 14px;
    --space-main: 22px;
    --space-head: 18px;
    --nav-pad: 8px 12px;
    line-height: 1.5;
  }
  body:not(.kiosk) h1 { font-size: 1.85rem; }       /* ~29.6px */
  body:not(.kiosk) h2 { font-size: 1.3rem; }        /* ~20.8px */
  body:not(.kiosk) .stat__value { font-size: 1.8rem; }
  /* Avatars inside table rows are a line's height, not a card's - rows stay scannable. */
  body:not(.kiosk) table.data .avatar { width: 32px; height: 32px; font-size: .8rem; }
  body:not(.kiosk) .members-status-filter > summary { min-height: calc(var(--control-h) - 2px); padding: var(--control-pad); }
  body:not(.kiosk) .members-status-filter .members-status-option,
  body:not(.kiosk) .members-status-filter [data-member-status-clear] { min-height: var(--control-h); }
}
@media (min-width: 861px) and (pointer: coarse) {
  body:not(.kiosk) { --control-h: 44px; --btn-h: 44px; --btn-h-sm: 38px; --control-pad: 9px 12px; --nav-pad: 10px 12px; }
}

/* The look-back days box sits under its radio choice as a proper control (it used to be squeezed into the label text). */
.recent-days { margin: 2px 0 8px 28px; max-width: 220px; }
.recent-days input[type="number"] { width: 110px; }

/* Add a member to a cell group: search (takes the width), role (compact), action - one row on a wide screen, stacked on a narrow one. The picker is a grid
   cell of its own; it used to sit inside a .field inside the generic .filters bar, whose "flex: 1 1 180px" on every .field set a 180px HEIGHT on the picker. */
.add-member-form {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(9rem, 12rem) auto;
  gap: 12px 16px; align-items: end; margin: 0;
}
.add-member-form .member-picker { min-width: 0; }
.add-member-form__role { min-width: 0; }
.add-member-form__role select { width: 100%; min-height: 42px; }
.add-member-form__action .btn { min-height: 42px; white-space: nowrap; }
/* The layout follows the width of the card the form is in, not the window: with the menu open beside it the card is far narrower than the screen. */
.add-member-card { container: add-member / inline-size; }
@container add-member (max-width: 760px) {
  .add-member-form { grid-template-columns: minmax(0, 1fr) auto; }
  .add-member-form .member-picker { grid-column: 1 / -1; }
}
@container add-member (max-width: 420px) {
  .add-member-form { grid-template-columns: minmax(0, 1fr); }
  .add-member-form__action .btn { width: 100%; }
}

/* Cell group cover: a restrained header, not a banner. The group's own photo, or the shared CCIQ Cell Group artwork, in a fixed 8:3 frame (the artwork's own
   shape) beside the title on a wide card and above it on a narrow one. The layout follows the width of the content area, not the window. */
.group-header-wrap { container: group-header / inline-size; margin-bottom: 4px; }
.group-header { display: grid; grid-template-columns: minmax(0, 480px) minmax(0, 1fr); gap: 14px 24px; align-items: center; }
.group-header__main { min-width: 0; }
.group-header__main .page-head { margin-bottom: 8px; }
.group-cover {
  margin: 0; aspect-ratio: 8 / 3; overflow: hidden; border-radius: var(--radius);
  border: 1px solid var(--line); background: var(--surface-sunk);
}
.group-cover img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: center; }
.group-cover--custom img { object-position: center 40%; }
.group-cover__change { margin: 4px 0 0; }
.group-cover__change > summary { cursor: pointer; font-size: var(--fs-help); color: var(--ink-soft); width: fit-content; padding: 4px 0; }
.group-cover__form { display: grid; gap: 10px; max-width: 420px; margin-top: 8px; }
@container group-header (max-width: 760px) {
  .group-header { grid-template-columns: minmax(0, 1fr); }
  .group-cover { max-width: 560px; }
}
@media print { .group-cover, .group-cover__change { display: none !important; } }
/* The three controls of the Add-a-member row are exactly the same height, so their edges and the labels above them line up. */
.add-member-form .member-picker__input, .add-member-form__role select, .add-member-form__action .btn { box-sizing: border-box; height: 42px; min-height: 42px; }
.add-member-card > .fieldset__hint { margin-top: 12px; }

/* Dashboard welcome artwork: one restrained strip above the greeting. On a phone the whole picture is shown at its own 3:1 shape; from tablet width up it is a
   190px band cropped around the logo and the words, so it never grows into a banner. Flat: no overlay, text or effect is laid over it. */
.dashboard-hero {
  margin: 0 0 16px; overflow: hidden; border-radius: var(--radius); border: 1px solid var(--line);
  background: #cfe0f0; aspect-ratio: 3 / 1;
}
/* The artwork is 3:1 with the emblem and the CCIQ wordmark in the band between 16% and 51% of its height. From tablet width the strip is 4.8:1 (never narrower than the picture, so nothing
   is ever cut at the sides) and its window sits at 25%, so that band is fully inside it at every width up to a very wide screen; a fixed pixel height cut the emblem's top on wide screens. */
.dashboard-hero img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: center 25%; }
@media (min-width: 600px) { .dashboard-hero { aspect-ratio: 4.8 / 1; max-height: 260px; } }
@media print { .dashboard-hero { display: none !important; } }

/* Attendance check-in: the QR "Look up" action reads as a real, secondary button (a visible edge, a tinted face, a fixed minimum width), clearly weaker than the primary
   Search / Confirm buttons, which stay solid navy. Hover, pressed and keyboard-focus states are distinct; the touch target is the full button height. */
.checkin-lookup {
  flex: none; min-width: 8.5rem; background: var(--navy-50); color: var(--navy-800);
  border: 2px solid var(--navy-500); font-weight: 700;
}
.checkin-lookup:hover { background: #dde8f4; color: var(--navy-900); border-color: var(--navy-700); }
.checkin-lookup:active { background: #cddcee; }
.checkin-lookup:focus-visible { outline: 3px solid var(--navy-500); outline-offset: 2px; }
@media (max-width: 420px) { .checkin-lookup { min-width: 6.5rem; padding: 0 14px; } }

/* "Select all (N)" above the people a search found. */
.select-all { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; padding: 10px 0; border-bottom: 1px solid var(--line); margin-bottom: 4px; }
.select-all__label { font-weight: 600; align-items: center; min-height: 44px; }
.select-all__label input { width: 22px; height: 22px; margin-top: 0; }
.select-all__hint { color: var(--muted); font-size: var(--fs-help); }

/* Verse of the Day (NIV). It lives in header space that was empty (the portal's spacer between the brand and the search; the Kiosk's gap between the brand and the operator) and
   only shows when its slot is wide enough - a container query on the slot itself, so it follows the room the header really has, not the window. It cannot take room from a control:
   the slot is the flexible leftover, and the line inside truncates. */
.topbar__verse-slot, .kiosk__verse-slot { container: votd / inline-size; min-width: 0; display: flex; align-items: center; }
.kiosk__verse-slot { flex: 1 1 0; }
.votd { display: none; position: relative; width: 100%; min-width: 0; }
@container votd (min-width: 300px) { .votd { display: block; } }
.votd__details { position: relative; min-width: 0; }
.votd__summary {
  list-style: none; cursor: pointer; display: flex; flex-direction: column; justify-content: center; gap: 1px;
  min-height: 40px; padding: 4px 10px; border-radius: 8px; min-width: 0; color: rgba(255, 255, 255, 0.92);
}
.votd__summary::-webkit-details-marker { display: none; }
.votd__summary::marker { content: ""; }
.votd__summary:hover, .votd__details[open] > .votd__summary { background: rgba(255, 255, 255, 0.1); }
.votd__label { font-size: .64rem; letter-spacing: .1em; text-transform: uppercase; color: rgba(255, 255, 255, 0.66); font-weight: 700; line-height: 1.2; }
.votd__line { display: flex; gap: 8px; align-items: baseline; min-width: 0; font-size: .85rem; line-height: 1.3; }
.votd__text { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-style: italic; }
.votd__ref { flex: none; font-style: normal; font-size: .74rem; color: rgba(255, 255, 255, 0.74); white-space: nowrap; }
@container votd (max-width: 400px) { .votd__label { display: none; } }
.votd--kiosk .votd__summary { flex-direction: row; align-items: center; min-height: 44px; }
.votd--kiosk .votd__line { font-size: .8rem; flex: 1 1 auto; }
.votd--kiosk .votd__summary { color: rgba(255, 255, 255, 0.82); }

.votd__panel {
  position: absolute; z-index: 80; top: calc(100% + 8px); left: 0; width: min(460px, calc(100vw - 24px));
  background: var(--surface); color: var(--ink); border: 1px solid var(--line-strong); border-radius: var(--radius);
  box-shadow: var(--shadow-raised); padding: 14px 16px 12px; font-size: .95rem; line-height: 1.5; text-align: left; white-space: normal;
}
.votd__eyebrow { margin: 0 0 6px; font-size: .68rem; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); font-weight: 700; }
.votd__full { margin: 0 0 8px; padding: 0; font-size: 1.02rem; font-style: italic; color: var(--ink); }
.votd__full-ref { margin: 0 0 10px; color: var(--ink-soft); font-size: .88rem; }
.votd__notice { margin: 0; padding-top: 8px; border-top: 1px solid var(--line); color: var(--muted); font-size: .72rem; line-height: 1.4; }
@media print { .votd { display: none !important; } }

/* Attendance drill-down ------------------------------------------------------------------------------------------------------------------------------ */
.print-only { display: none; }
.attendance-people__summary { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; margin: 0 0 12px; }
.attendance-people__figure { text-decoration: none; color: inherit; display: flex; flex-direction: column; gap: 4px; }
.attendance-people__figure:hover { border-color: var(--navy-500); }
.attendance-people__figure.is-current { border-color: var(--navy-500); box-shadow: inset 0 0 0 1px var(--navy-500); background: var(--navy-50); }

/* A figure that opens the people behind it (a Friday Service tile, a bar of the attendance chart): the same quiet treatment everywhere, and only on the ones that are links.
   A hairline border change and a 2px lift on hover or keyboard focus, no animation beyond a short transition (none at all for people who ask for less motion), no hover-only meaning. */
.stat--drill, .bars__col--link { transition: transform .12s ease, box-shadow .12s ease, border-color .12s ease; }
.stat--drill { text-decoration: none; color: inherit; display: block; cursor: pointer; }
.stat--drill:hover, .stat--drill:focus-visible { border-color: var(--navy-500); transform: translateY(-2px); box-shadow: 0 4px 10px rgba(16, 42, 74, .12); }
.stat--drill:focus-visible { outline: 3px solid var(--navy-500); outline-offset: 2px; }
.stat__open { display: block; margin-top: 6px; font-size: var(--fs-help); color: var(--navy-700); }
.bars__col--link { text-decoration: none; color: inherit; cursor: pointer; border-radius: 6px; padding: 2px 4px; margin: 0 -4px; }
.bars__col--link:hover, .bars__col--link:focus-visible { background: var(--navy-50); transform: translateY(-2px); box-shadow: 0 3px 8px rgba(16, 42, 74, .14); }
.bars__col--link:hover .bars__bar, .bars__col--link:focus-visible .bars__bar { background: var(--navy-700); }
.bars__col--link:focus-visible { outline: 3px solid var(--navy-500); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { .stat--drill:hover, .stat--drill:focus-visible, .bars__col--link:hover, .bars__col--link:focus-visible { transform: none; } }

@media print {
  .screen-only { display: none !important; }
  .print-only { display: block !important; }
  .attendance-print { font-size: 10.5pt; color: #000; }
  .attendance-print__head { display: flex; gap: 12px; align-items: center; margin-bottom: 8px; border-bottom: 2px solid #000; padding-bottom: 8px; }
  .attendance-print__title { margin: 0; font-size: 16pt; font-weight: 700; }
  .attendance-print__head p { margin: 0; }
  .attendance-print__church { font-weight: 700; letter-spacing: .02em; }
  .attendance-print__totals { margin: 4px 0; }
  .attendance-print__table { width: 100%; border-collapse: collapse; margin-top: 8px; font-size: 9.5pt; }
  .attendance-print__table th, .attendance-print__table td { border: 1px solid #888; padding: 3px 6px; text-align: left; vertical-align: top; }
  .attendance-print__table thead { display: table-header-group; }
  .attendance-print__table tr { break-inside: avoid; }
  .attendance-print__table th { background: #eee; }
  .attendance-print__foot { margin-top: 10px; font-size: 9pt; color: #333; }
  @page { margin: 14mm; }
}
.attendance-people__table { width: 100%; }

/* Documents: "Who can view this?" - a compact summary that opens a short checklist, never a long permanent list. */
.audience { min-width: 0; }
.audience__details { position: relative; min-width: 0; }
.audience__summary {
  display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: var(--control-h, 42px); padding: 8px 12px;
  border: 1px solid var(--line-strong); border-radius: var(--radius-sm); background: var(--surface); color: var(--ink); cursor: pointer; list-style: none; line-height: 1.35;
}
.audience__summary::-webkit-details-marker { display: none; }
.audience__summary::after { content: ""; flex: none; width: 8px; height: 8px; border-right: 2px solid currentColor; border-bottom: 2px solid currentColor; transform: rotate(45deg) translateY(-2px); }
.audience__details[open] > .audience__summary::after { transform: rotate(-135deg) translateY(-2px); }
.audience__summary:focus-visible { outline: 2px solid var(--sky-400); outline-offset: 2px; }
.audience__options { display: grid; gap: 4px; margin-top: 6px; padding: 8px 12px; border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--surface); }
.audience__options .checkbox { min-height: 40px; align-items: center; }
.audience__options [hidden] { display: none; }

/* ECAQ payment ledgers: received comes from the payments; a payment is corrected or removed with a reason. */
.finance-form__received { font-weight: 600; white-space: nowrap; }
.payment-fix { min-width: 0; }
.payment-fix > summary { display: inline-block; cursor: pointer; list-style: none; }
.payment-fix > summary::-webkit-details-marker { display: none; }
.payment-fix__body { margin-top: 10px; padding: 12px; border: 1px solid var(--line); border-radius: 10px; background: var(--surface); display: grid; gap: 14px; min-width: 0; max-width: 560px; }
.payment-fix__form { min-width: 0; }
.payment-fix__title { margin: 0 0 8px; font-size: 1rem; }
.payment-fix__form--remove { padding-top: 12px; border-top: 1px solid var(--line); }

/* Kiosk verse: inline in the spare header space on wide screens; on a narrow screen it takes its own full-width row UNDER the brand and controls (never squeezed between them),
   wraps instead of clipping, and is always shown. */
@container votd (min-width: 200px) { .votd--kiosk { display: block; } }
@media (max-width: 899px) {
  .kiosk__verse-slot { order: 9; flex: 1 1 100%; }
  .votd--kiosk .votd__summary { min-height: 44px; }
  .votd--kiosk .votd__line { flex-wrap: wrap; row-gap: 2px; }
  .votd--kiosk .votd__text { white-space: normal; overflow: visible; text-overflow: clip; }
  .votd--kiosk .votd__label { display: none; }
}

/* Giving Board: the administrative card of a claimed date. Hover and keyboard focus show it beside the date; a tap opens it (JS toggles .is-open); on a phone or tablet it is a bottom
   sheet, so it can never push the page sideways. Received, balance and status are the payment ledger's. */
.stub__tip--admin { pointer-events: auto; min-width: 240px; max-width: 300px; gap: 4px; bottom: 100%; margin-bottom: 6px; }
.stub__tip--admin::after { content: ""; position: absolute; left: 0; right: 0; top: 100%; height: 8px; }
.stub__tip-line { font-weight: 600; }
.stub__facts { display: grid; grid-template-columns: auto 1fr; gap: 2px 12px; margin: 4px 0; }
.stub__facts dt { color: rgba(255, 255, 255, 0.7); }
.stub__facts dd { margin: 0; text-align: right; font-variant-numeric: tabular-nums; }
.stub__tip-open { color: var(--gold-300, #f2d18a); font-weight: 700; text-decoration: underline; padding: 6px 0; }
.stub__tip-close { display: none; margin-top: 4px; min-height: 44px; border: 1px solid rgba(255, 255, 255, 0.5); border-radius: var(--radius-sm); background: transparent; color: #fff; font: inherit; cursor: pointer; }
.stub:hover .stub__tip--admin,
.stub.is-open .stub__tip--admin { display: flex; }
/* keyboard: while focus is on the date or on anything inside its card (focus-within, so moving from the date to the link in the card never flickers it away); Escape / Close mark it dismissed until focus leaves */
.board-wall__months.is-keyboard .stub:focus-within:not(.is-dismissed) .stub__tip--admin { display: flex; }
.stub.is-dismissed .stub__tip--admin { display: none; }
.stub--taken .stub__paper--admin, .stub--gone .stub__reveal--admin { cursor: pointer; }
@media (hover: none), (max-width: 1100px) {
  .stub:hover:not(.is-open) .stub__tip--admin { display: none; }
  .stub__tip--admin { position: fixed; left: 12px; right: 12px; bottom: 12px; top: auto; width: auto; min-width: 0; max-width: none; margin: 0; transform: none; z-index: 60; padding: 14px 16px; font-size: 0.9rem; }
  .stub .stub__tip--admin { left: 12px; right: 12px; transform: none; }
  .stub__tip--admin::after { display: none; }
  .stub__tip-close { display: block; }
}

/* Wide screens: the slips of the first five rows show their note below them, so it is never cut off by the page's top bar or by the top of the screen. */
@media (min-width: 1101px) {
  .stub--tip-below .stub__tip { bottom: auto; top: calc(100% + 6px); }
  .stub--tip-below .stub__tip--admin { bottom: auto; top: 100%; margin: 6px 0 0; }
  .stub--tip-below .stub__tip--admin::after { top: auto; bottom: 100%; }
}
/*
 * Phones and tablets (up to 1100 px): the board is twelve month sections, each with its name, and the date slips are real touch targets. The photograph becomes a banner above
 * the months (the picture cannot line up behind slips that no longer sit in thirty columns). A paid day shows the building. Slip states (free, taken, part paid, paid) are the same
 * ones as on the wall, and none of them depends on colour alone (the labels, the part-paid bar and the tooltip text say it too).
 */
@media (max-width: 1100px) {
  .board-wall { padding: 10px; }
  .board-wall__picture { position: relative; inset: auto; height: clamp(110px, 24vw, 200px); border-radius: var(--radius-sm); margin-bottom: 12px; }
  .board-wall__months { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr)); gap: 12px; align-items: start; }
  .board-month { display: block; padding: 10px 10px 12px; border-radius: var(--radius-sm); background: rgba(255, 255, 255, 0.07); border: 1px solid rgba(255, 255, 255, 0.14); min-width: 0; }
  .board-month__name {
    position: static; width: auto; height: auto; margin: 0 0 8px; overflow: visible; clip: auto; white-space: normal;
    display: flex; align-items: baseline; gap: 8px; color: #fff; font-size: 1.05rem; line-height: 1.2; letter-spacing: 0.02em;
  }
  .board-month__short { display: inline; font-weight: 800; letter-spacing: 0.12em; text-transform: uppercase; }
  .board-month__long { display: none; }
  .board-month__year { display: inline; font-size: 0.8rem; color: rgba(255, 255, 255, 0.7); }
  .board-month__stubs { display: grid; grid-template-columns: repeat(auto-fill, minmax(44px, 1fr)); gap: 6px; }
  .stub { aspect-ratio: auto; min-height: 44px; height: 44px; }
  .stub__month, .stub__year { display: none; }
  .stub__day { font-size: 1rem; }
  .stub__paper { border-radius: 6px; }
  .stub--gone .stub__reveal {
    border-radius: 6px; background: url('/branding/ecaq-worship-centre-small.jpg') center / cover; box-shadow: inset 0 0 0 2px var(--gold-500);
  }
  /* The slip's note is a bottom sheet here (a tap opens it, a tap elsewhere closes it): a note centred on a slip near the screen edge would be cut off. */
  .stub__tip, .stub--edge-start .stub__tip, .stub--edge-end .stub__tip {
    position: fixed; left: 12px; right: 12px; bottom: 12px; top: auto; width: auto; max-width: none; transform: none; z-index: 60; padding: 14px 16px; font-size: 0.92rem;
  }
}
@media (max-width: 560px) {
  .stub__day { font-size: 1rem; }
  .board-month__stubs { grid-template-columns: repeat(auto-fill, minmax(42px, 1fr)); }
}

/* The Giving Board claims table: headings and amounts stay on one line (a heading broken as "Comm / itment" is unreadable); the table scrolls inside its wrapper if it must. */
.data--claims thead th { white-space: nowrap; }
.data--claims td.numeric { white-space: nowrap; }

/* One form rhythm also between a field and a field GRID, and the optional marker of a label. */
.form > .field + .field-grid, .form > .field-grid + .field, .form > .field-grid + .field-grid { margin-top: var(--space-field); }
.field__optional { font-weight: 400; color: var(--muted); }

/* The ministry cover shares the cell group cover's frame (8:3, the artwork's own shape). The CCIQ Ministries artwork keeps its wordmark in the upper part, so a narrower crop keeps the top. */
.ministry-cover:not(.group-cover--custom) img { object-position: center top; }

/* The Date of birth review table: the identifier, the stored value and the age stay on one line; the explanation takes the room. */
.data--dob-review th:nth-child(1), .data--dob-review td:nth-child(1),
.data--dob-review th:nth-child(3), .data--dob-review td:nth-child(3),
.data--dob-review th:nth-child(4), .data--dob-review td:nth-child(4) { white-space: nowrap; }
.data--dob-review td:nth-child(2) { min-width: 8rem; }
.data--dob-review td:nth-child(5) { min-width: 10rem; }
.data--dob-review td:nth-child(6) { min-width: 7rem; }
/* The Review button and the decision stay on one line (a button wrapped letter by letter at a laptop width). */
.data--dob-review td:nth-child(8) { white-space: nowrap; }
