/* ============================================================
   The Potter's House Christian Church Frankston

   Colour system
   -------------
   Two tiers. Primitives are the raw pinned palette: the charcoal
   ladder and the ember ramp. Semantic roles are what the CSS below
   actually refers to, so a surface or a text level can be retuned
   in one place.

   The full fire gradient is rationed. It marks two things and
   nothing else:
     1. the promise  (the headline emphasis, via --action)
     2. the action   (primary buttons, via --action-fill)
   Everything that used to wear it - card edges, the quote mark, the
   avatar, icon chips - steps down to a solid ember tone. Rarity is
   what gives the gradient its force.

   Type system
   -----------
   Display  Archivo        the institutional voice: headings, numbers,
                           labels, times. Heavy and slightly condensed
                           so it echoes the logo lockup.
   Body     Source Sans 3  the human voice: all reading, and quoted
                           speech set large in italic.

   Spatial system
   --------------
   One 4px-based scale, --s-1 to --s-10. Sections use the three
   rhythm tokens rather than a single repeated value.
   ============================================================ */

:root {
  /* ---------- Primitives: charcoal ladder ---------- */
  --coal-900: #0a0a0c;
  --coal-800: #0e0e10;
  --coal-700: #131316;
  --coal-600: #1b1b1f;

  /* ---------- Primitives: ash ---------- */
  --ash-50: #ffffff;
  --ash-100: #f5f5f6;
  --ash-200: #ebebee;

  /* ---------- Primitives: ember ramp ---------- */
  --ember-700: #b8400a;
  --ember-600: #d1490d;
  --ember-500: #f2711f;
  --ember-300: #ffb35c;
  --fire-grad: linear-gradient(100deg, #e02d0d, #f2711f 55%, #ffc93c);

  /* ---------- Semantic: surfaces ---------- */
  --surface: var(--ash-100);
  --surface-sunken: var(--ash-200);
  --surface-raised: var(--ash-50);
  --surface-veil: rgba(245, 245, 246, 0.85);

  --surface-deep: var(--coal-700);
  --surface-deep-lift: var(--coal-600);
  --surface-deep-base: var(--coal-800);
  --surface-deepest: var(--coal-900);
  --surface-deep-veil: rgba(14, 14, 16, 0.78);

  /* A tinted chip, not the gradient. Used behind small icons. */
  --surface-accent-tint: linear-gradient(140deg, rgba(242, 113, 31, 0.18), rgba(255, 201, 60, 0.07));

  /* ---------- Semantic: text ----------
     On dark these are explicit rather than white-with-alpha. Alpha
     over a photo or a gradient makes the contrast depend on whatever
     sits behind it; these are deterministic, and carry a trace of
     warmth taken from the surface rather than reading as grey. */
  --text: var(--coal-700);
  --text-muted: #55555e;
  --text-on-dark: #f4f1ef;
  --text-on-dark-muted: #c4bdb8;
  --text-on-dark-faint: #9a938e;

  /* ---------- Semantic: action, focus ----------
     Two gradients, because they do two different jobs.

     --action clips to TEXT on a dark surface. There the pinned fire
     runs 4.0:1 at its red stop to 12.6:1 at its yellow one, and passes.

     --action-fill sits BEHIND a label. There the same gradient's
     yellow terminus left white text at 1.5:1 — a hard failure on the
     one button the whole site depends on. The fill raises only the
     first stop and pairs with a near-black label: 5.2:1 at its darkest
     point, 12.8:1 at its lightest, legible across the entire run. */
  --action: var(--fire-grad);
  --action-fill: linear-gradient(100deg, #e8500f, #f2711f 45%, #ffc93c);
  --action-label: var(--coal-900);
  --action-ink: var(--ember-700);
  --action-ink-on-dark: var(--ember-300);
  --focus-ring: var(--ember-700);
  --focus-ring-on-dark: var(--ember-300);

  /* ---------- Semantic: lines ---------- */
  --border: rgba(19, 19, 22, 0.12);
  --border-on-dark: rgba(255, 255, 255, 0.14);
  --border-control-on-dark: rgba(255, 255, 255, 0.38);

  /* The larger the surface, the softer the corner. These were computed
     from --radius with calc, which hid two fixed values behind
     arithmetic; they are stated plainly instead. */
  --radius: 18px;
  --radius-lifted: 24px;
  --radius-band: 26px;
  --shadow: 0 18px 50px -18px rgba(19, 19, 22, 0.25);

  /* ---------- Spacing scale, 4px base ---------- */
  --s-1: 0.25rem;
  --s-2: 0.5rem;
  --s-3: 0.75rem;
  --s-4: 1rem;
  --s-5: 1.25rem;
  --s-6: 1.5rem;
  --s-7: 2rem;
  --s-8: 2.5rem;
  --s-9: 3rem;
  --s-10: 4rem;

  /* Section cadence. Not every section breathes alike: loose marks a
     deliberate interruption, tight pulls a conclusion up to what it
     concludes. */
  --rhythm-tight: clamp(2.5rem, 5vw, 4rem);
  --rhythm-base: clamp(4rem, 8vw, 6.5rem);
  --rhythm-loose: clamp(5rem, 10vw, 8.5rem);

  /* ---------- Families ---------- */
  --font-display: "Archivo", "Helvetica Neue", Arial, sans-serif;
  --font-body: "Source Sans 3", -apple-system, "Segoe UI", Roboto, sans-serif;

  /* ---------- Text roles ---------- */
  --t-label: 0.72rem;
  --t-micro: 0.8125rem;
  --t-small: 0.875rem;
  --t-ui: 0.9375rem;
  --t-body: 1.0625rem;
  --t-lead: 1.1875rem;

  /* Heading roles: size, leading and tracking travel together,
     because a 20px heading and a 80px heading need different ones. */
  --t-subheading: 1.25rem;
  --lh-subheading: 1.3;
  --ls-subheading: -0.01em;

  --t-heading: 1.5rem;
  --lh-heading: 1.25;
  --ls-heading: -0.015em;

  --t-title: clamp(1.85rem, 1.35rem + 2.1vw, 2.6rem);
  --lh-title: 1.1;
  --ls-title: -0.025em;

  --t-page-title: clamp(2.2rem, 1.45rem + 3.2vw, 3.6rem);
  --lh-page-title: 1.05;
  --ls-page-title: -0.03em;

  --t-display: clamp(2.6rem, 1.15rem + 6.1vw, 5rem);
  --lh-display: 1;
  --ls-display: -0.035em;

  --t-quote: clamp(1.3rem, 1.05rem + 1.2vw, 1.7rem);

  --ls-label: 0.18em;

  /* Reading measure. Source Sans 3 runs narrow, so this is measured
     against real copy rather than assumed: 32rem lands at ~70 characters. */
  --measure: 32rem;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  /* The header is sticky, so an anchor must not park its target
     underneath it. Without this, "Service times" hid the day and the
     service name behind 77px of header. */
  scroll-padding-top: calc(var(--header-h, 74px) + var(--s-4));
}

body {
  font-family: var(--font-body);
  background: var(--surface);
  color: var(--text);
  line-height: 1.65;
  font-size: var(--t-body);
  -webkit-font-smoothing: antialiased;
}

/* height:auto is load-bearing. Images carry width/height attributes to
   reserve space against layout shift, and those attributes apply as
   presentational hints. Without this, any image sized by CSS width
   keeps its attribute height and renders distorted. */
img { max-width: 100%; height: auto; display: block; }

a { color: inherit; }

/* Keyboard focus. The ring changes tone with the surface so it stays
   visible on both the paper sections and the charcoal ones. */
:focus-visible {
  outline: 3px solid var(--focus-ring);
  outline-offset: 3px;
  border-radius: 3px;
}

.header-dark :focus-visible,
.on-dark :focus-visible,
.cta-band :focus-visible,
.prayer-card :focus-visible,
.visit-now :focus-visible,
.site-footer :focus-visible {
  outline-color: var(--focus-ring-on-dark);
}

/* Lets a keyboard visitor jump the seven nav links. Off-screen until
   focused, then it lands in the top-left corner. */
.skip-link {
  position: absolute;
  left: var(--s-3);
  top: -100%;
  z-index: 100;
  padding: var(--s-3) var(--s-5);
  border-radius: 0 0 12px 12px;
  background: var(--surface-deep);
  color: var(--text-on-dark);
  font-size: var(--t-ui);
  font-weight: 600;
  text-decoration: none;
}

/* Plain :focus, not :focus-visible. A skip link must appear for any
   focus, and only a keyboard can ever reach it. */
.skip-link:focus { top: 0; }

.container {
  width: min(1140px, 92vw);
  margin-inline: auto;
}

.narrow { width: min(var(--measure), 92vw); margin-inline: auto; }

/* Visually hidden, still announced. For structural headings the visual
   design does not need but the document outline does. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---------- Typography ---------- */

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 700;
  text-wrap: balance;
}

p { text-wrap: pretty; }

/* A centred intro above a grid. Used on the home and events pages. */
.section-intro {
  max-width: 40rem;
  margin-inline: auto;
  text-align: center;
}

.section-intro + .times-grid { margin-top: var(--s-8); }

.lead + p { margin-top: var(--s-4); }

.actions { margin-top: var(--s-7); }

/* One label role. Every kicker, key and column head shares it,
   so the tracking never drifts between components. */
.eyebrow,
.block-label,
.time-card .day,
.event-when,
.contact-list .label,
.site-footer h2 {
  font-family: var(--font-display);
  font-size: var(--t-label);
  font-weight: 700;
  line-height: 1.4;
  letter-spacing: var(--ls-label);
  text-transform: uppercase;
}

/* The site's one named kicker, on the home hero only. It tells a
   stranger which town this church is in, which the headline does not.
   It used to sit above all 23 sections, which made it grammar rather
   than a decision. */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  color: var(--action-ink);
}

/* A different job: labelling one block of content, such as the prayer
   or the account details. It introduces what follows, so it carries
   no rule and never opens a section. */
.block-label {
  display: block;
  color: var(--action-ink);
  margin-bottom: var(--s-2);
}

/* currentColor, so the rule always matches its own kicker instead of
   spending a gradient on a 28px dash. */
.eyebrow::before {
  content: "";
  width: 28px;
  height: 1.5px;
  background: currentColor;
}

.on-dark .eyebrow { color: var(--ember-500); }

/* No top margin: with the kickers gone, a section title opens its
   section and the section's own rhythm provides the space above it. */
.section-title {
  font-size: var(--t-title);
  line-height: var(--lh-title);
  letter-spacing: var(--ls-title);
  font-stretch: 93%;
  margin: 0 0 var(--s-4);
}

.lead {
  font-size: var(--t-lead);
  line-height: 1.6;
  color: var(--text-muted);
}

.on-dark .lead { color: var(--text-on-dark-muted); }

/* Light text on a dark surface reads thinner than the same text on
   white. Compensate on all three axes: leading, tracking, weight. */
.hero p,
.page-hero p,
.section-dark p,
.section-dark .lead,
.cta-band p,
.prayer-card p,
.on-dark .lead,
.site-footer {
  line-height: 1.7;
  letter-spacing: 0.006em;
  font-weight: 420;
}

/* ---------- Header ---------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--surface-veil);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom: 1px solid transparent;
  transition: border-color 0.3s ease, background 0.3s ease;
}

.site-header.scrolled { border-bottom-color: var(--border); }

.site-header.header-dark {
  background: var(--surface-deep-veil);
  color: var(--text-on-dark);
}

.site-header.header-dark.scrolled { border-bottom-color: var(--border-on-dark); }

.header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: var(--s-4) 0;
}

.brand {
  text-decoration: none;
  display: flex;
  align-items: center;
  gap: var(--s-3);
}

.brand-logo {
  width: 48px;
  height: 48px;
}

.brand-word {
  height: 52px;
  width: auto;
  /* Reserves the width before the PNG loads, so the header does not
     shift as it arrives. Matches the asset's 975x345. */
  aspect-ratio: 975 / 345;
  display: block;
  transform: translateY(6px);
}

.brand-name {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--t-subheading);
  letter-spacing: -0.01em;
}

.site-nav { display: flex; align-items: center; gap: var(--s-6); }

.site-nav a {
  text-decoration: none;
  font-size: var(--t-ui);
  font-weight: 500;
  opacity: 0.82;
  transition: opacity 0.2s ease;
}

.site-nav a:hover { opacity: 1; }

/* The current page is marked by an underline as well as a colour, so
   the state does not depend on seeing the hue. */
.site-nav a.active {
  opacity: 1;
  color: var(--action-ink);
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 0.45em;
}

.header-dark .site-nav a.active { color: var(--action-ink-on-dark); }

.nav-cta {
  padding: var(--s-2) var(--s-5);
  border-radius: 999px;
  background: var(--surface-deep);
  color: var(--text-on-dark) !important;
  opacity: 1 !important;
  font-weight: 600;
  text-decoration: none !important;
}

.header-dark .nav-cta {
  background: var(--action-fill);
  color: var(--action-label) !important;
}

.nav-toggle {
  display: none;
  background: none;
  border: none;
  cursor: pointer;
  width: 44px;
  height: 44px;
  border-radius: 10px;
  align-items: center;
  justify-content: center;
  color: inherit;
}

.nav-toggle svg { width: 24px; height: 24px; }

/* ---------- Hero ---------- */

/* The ember glow layers are an atmospheric composition rather than a
   role, so they stay literal. The scrim sits between them and the
   photograph. */
.hero {
  position: relative;
  color: var(--text-on-dark);
  background:
    radial-gradient(900px 500px at 85% -10%, rgba(224, 45, 13, 0.4), transparent 60%),
    radial-gradient(700px 480px at -10% 110%, rgba(242, 113, 31, 0.2), transparent 60%),
    linear-gradient(160deg, rgba(12, 12, 14, 0.92) 0%, rgba(18, 17, 19, 0.82) 55%, rgba(10, 10, 12, 0.94) 100%),
    url("../images/hero-frankston.jpg") center / cover no-repeat var(--coal-800);
  margin-top: calc(-1 * var(--header-h, 74px));
  padding-top: var(--header-h, 74px);
  overflow: hidden;
}

.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='0.06'/%3E%3C/svg%3E");
  pointer-events: none;
}

/* The extra bottom padding is the room the service-time cards pull
   back up into. Hero and times read as one unit. */
.hero-inner {
  position: relative;
  z-index: 1;
  padding: clamp(5.5rem, 11vw, 9.5rem) 0 clamp(7rem, 12vw, 10rem);
  text-align: center;
}

.hero h1 {
  font-size: var(--t-display);
  line-height: var(--lh-display);
  letter-spacing: var(--ls-display);
  font-weight: 800;
  font-stretch: 90%;
  margin: var(--s-5) auto var(--s-6);
  max-width: 15ch;
}

/* Reserved gradient role 1 of 2: the promise.
   The gradient is laid out at twice the width of the text so that the
   focal animation can slide it without the words ever losing their
   fill. See "Motion" at the foot of this file. */
.hero h1 em {
  font-style: italic;
  background: var(--action);
  background-size: 200% 100%;
  background-position: 0 0;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.hero p {
  max-width: 54ch;
  margin: 0 auto var(--s-8);
  color: var(--text-on-dark-muted);
  font-size: var(--t-lead);
}

.hero-actions { display: flex; gap: var(--s-4); justify-content: center; flex-wrap: wrap; }

/* ---------- Buttons ---------- */

.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  padding: var(--s-3) var(--s-7);
  border-radius: 999px;
  font-weight: 600;
  font-size: var(--t-ui);
  text-decoration: none;
  transition: transform 140ms cubic-bezier(0.16, 1, 0.3, 1),
              box-shadow 140ms ease,
              filter 140ms ease;
}

.btn:hover { transform: translateY(-2px); }

/* Hover never fires on a phone, and most of this congregation arrives
   on one. The press state is the only acknowledgement they get. */
.btn:active,
.nav-cta:active,
.nav-toggle:active {
  transform: translateY(0) scale(0.97);
  transition-duration: 80ms;
}

/* Reserved gradient role 2 of 2: the action. Also worn by the header
   "Plan a Visit" pill, which is the same role in a persistent slot. */
.btn-fire {
  background: var(--action-fill);
  color: var(--action-label);
  box-shadow: 0 10px 30px -10px rgba(232, 80, 15, 0.6);
}

.btn-fire:hover { filter: brightness(1.08); }

.btn-ghost {
  border: 1px solid var(--border-control-on-dark);
  color: var(--text-on-dark);
}

.btn-ghost:hover { border-color: rgba(255, 255, 255, 0.7); }

.btn-outline {
  border: 1.5px solid var(--text);
  color: var(--text);
}

/* ---------- Service times ---------- */

.times {
  position: relative;
  z-index: 2;
  margin-top: clamp(-5rem, -8vw, -4rem);
  padding-bottom: var(--s-4);
}

/* Content-driven rather than breakpoint-driven: three across when
   there is room, two on a tablet, one on a phone. A single 900px
   breakpoint used to drop straight to one, leaving 700px-wide cards
   holding three words. */
.times-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: var(--s-5);
}

/* The fire edge is a solid ember, not the gradient: it is a repeated
   card mark, and the gradient is reserved. It is painted as a
   background stripe rather than a thick top border, because a 3px
   border would taper into the 1px sides around the corner radius. */
.time-card {
  background: linear-gradient(var(--ember-500), var(--ember-500)) top / 100% 3px no-repeat, var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--s-7) var(--s-6) var(--s-6);
  box-shadow: var(--shadow);
}

.time-card .day { color: var(--action-ink); }

.time-card h3 {
  font-size: var(--t-subheading);
  line-height: var(--lh-subheading);
  letter-spacing: var(--ls-subheading);
  margin: var(--s-2) 0 var(--s-1);
}

/* The three services differ in name and message, not in shape. One
   line under the cards says so, in place of three per-card glosses
   that implied a hierarchy this church does not have. */
.times-note {
  max-width: 58ch;
  margin: var(--s-5) auto 0;
  text-align: center;
  color: var(--text-muted);
}

/* A service time is data, so it gets the display face and figures
   that line up between the three cards. */
.time-card .hour {
  font-family: var(--font-display);
  font-size: var(--t-lead);
  font-weight: 600;
  font-variant-numeric: tabular-nums lining-nums;
  letter-spacing: -0.01em;
  color: var(--text-muted);
}

/* ---------- Sections ---------- */

.section { padding: var(--rhythm-base) 0; }

/* A deliberate interruption: the dark band gets more air than its
   neighbours so the change of subject registers. */
.section--loose { padding: var(--rhythm-loose) 0; }

/* A conclusion sits close to what it concludes, and the CTA band
   carries its own generous internal padding already. */
.section--tight { padding: var(--rhythm-tight) 0; }

.section-dark {
  background:
    radial-gradient(800px 400px at 90% 0%, rgba(224, 45, 13, 0.22), transparent 55%),
    radial-gradient(600px 350px at 5% 100%, rgba(255, 179, 92, 0.08), transparent 55%),
    var(--surface-deep);
  color: var(--text-on-dark);
}

.section-paper-deep { background: var(--surface-sunken); }

.split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(2.5rem, 6vw, 5rem);
  align-items: center;
}

/* ---------- Cards ---------- */

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
  gap: var(--s-5);
  margin-top: var(--s-8);
}

.card {
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--s-7) var(--s-6);
}

.card .icon {
  width: 46px;
  height: 46px;
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--surface-accent-tint);
  color: var(--ember-600);
  margin-bottom: var(--s-5);
}

.card .icon svg { width: 22px; height: 22px; }

.card h3 {
  font-size: var(--t-subheading);
  line-height: var(--lh-subheading);
  letter-spacing: var(--ls-subheading);
  margin-bottom: var(--s-2);
}

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

/* ---------- Quote / pastor ---------- */

/* Quoted speech is a person talking, so it stays in the body face.
   The display face is reserved for the church's own voice. The mark
   is solid ember: it introduces the quote, it does not compete
   with it. */
.quote-mark {
  font-family: var(--font-body);
  font-size: 5rem;
  font-weight: 700;
  line-height: 1;
  color: var(--ember-500);
  height: var(--s-9);
}

blockquote.pull {
  font-family: var(--font-body);
  font-size: var(--t-quote);
  font-style: italic;
  line-height: 1.45;
  letter-spacing: -0.005em;
}

.attribution {
  margin-top: var(--s-6);
  display: flex;
  align-items: center;
  gap: var(--s-4);
}

.attribution .avatar {
  width: 52px;
  height: 52px;
  border-radius: 50%;
  /* One step down the ramp: on ember-600 the initials landed on
     exactly 4.5:1, with no margin for error. */
  background: var(--ember-700);
  color: var(--ash-50);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--t-body);
  letter-spacing: 0.02em;
}

.attribution .name { font-weight: 700; font-size: var(--t-ui); }

.attribution .role { font-size: var(--t-small); color: var(--text-muted); }

.on-dark .attribution .role { color: var(--text-on-dark-faint); }

/* ---------- CTA band ---------- */

.cta-band {
  border-radius: var(--radius-band);
  background:
    radial-gradient(600px 300px at 85% 10%, rgba(224, 45, 13, 0.4), transparent 60%),
    radial-gradient(500px 260px at 10% 90%, rgba(255, 179, 92, 0.12), transparent 60%),
    linear-gradient(150deg, var(--surface-deep-lift), var(--surface-deep-base));
  color: var(--text-on-dark);
  padding: clamp(2.8rem, 6vw, 4.5rem);
  text-align: center;
}

.cta-band h2 {
  font-size: var(--t-title);
  line-height: var(--lh-title);
  letter-spacing: var(--ls-title);
  font-stretch: 93%;
  margin-bottom: var(--s-4);
}

.cta-band p { color: var(--text-on-dark-muted); max-width: 52ch; margin: 0 auto var(--s-7); }

/* The Gospel path, kept available but no longer competing with the
   attendance ask for the loudest slot on the page. */
.cta-aside { margin-top: var(--s-6); margin-bottom: 0 !important; font-size: var(--t-small); }

.cta-aside a {
  display: inline-flex;
  align-items: center;
  min-height: 32px;
  color: var(--action-ink-on-dark);
  text-decoration: underline;
  text-underline-offset: 0.18em;
}

/* ---------- Page hero (inner pages) ---------- */

.page-hero {
  color: var(--text-on-dark);
  background:
    radial-gradient(700px 380px at 90% -20%, rgba(224, 45, 13, 0.32), transparent 60%),
    radial-gradient(500px 300px at 0% 100%, rgba(242, 113, 31, 0.12), transparent 55%),
    linear-gradient(155deg, var(--surface-deep-base), var(--surface-deep-lift));
  margin-top: calc(-1 * var(--header-h, 74px));
  padding: calc(var(--header-h, 74px) + clamp(3.5rem, 8vw, 6rem)) 0 clamp(3.5rem, 7vw, 5.5rem);
}

.page-hero h1 {
  font-size: var(--t-page-title);
  line-height: var(--lh-page-title);
  letter-spacing: var(--ls-page-title);
  font-weight: 800;
  font-stretch: 90%;
  max-width: 17ch;
}

/* Reserved gradient role 1 of 2: the promise. */
.page-hero h1 em {
  font-style: italic;
  background: var(--action);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.page-hero p {
  max-width: 58ch;
  margin-top: var(--s-5);
  color: var(--text-on-dark-muted);
  font-size: var(--t-lead);
}

/* ---------- Prose ---------- */

.prose h2 {
  font-size: var(--t-heading);
  line-height: var(--lh-heading);
  letter-spacing: var(--ls-heading);
  margin: var(--s-8) 0 var(--s-4);
}

.prose h3 {
  font-size: var(--t-subheading);
  line-height: var(--lh-subheading);
  letter-spacing: var(--ls-subheading);
  margin: var(--s-7) 0 var(--s-2);
}

.prose p { margin-bottom: var(--s-4); }

/* These four rules replace per-page inline overrides. The generous
   top margin on a prose heading is for headings that follow text, so
   it is removed when the heading opens the column, and reduced to the
   kicker gap when a label introduces it. */
.prose > :first-child { margin-top: 0; }

.prose .lead { margin-bottom: var(--s-6); }

.prose .detail-card { margin-top: var(--s-6); }

/* A card's own first child must not add to the card's padding. */
.detail-card > .attribution:first-child { margin-top: 0; }

.detail-rows { margin-top: var(--s-5); }

/* Underlined, not just coloured. A link inside a paragraph must not
   depend on seeing the hue to be found. */
.prose a {
  color: var(--action-ink);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.15em;
}

.prose a:hover { text-decoration-thickness: 2px; }

/* ---------- Beliefs list ---------- */

.beliefs-list { counter-reset: belief; display: grid; gap: var(--s-4); margin-top: var(--s-8); }

.belief {
  counter-increment: belief;
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--s-6) var(--s-7) var(--s-6) var(--s-10);
  position: relative;
}

.belief::before {
  content: counter(belief, decimal-leading-zero);
  position: absolute;
  left: var(--s-6);
  /* Optical: nudged off the scale so the figure sits on the heading's
     cap height rather than its line box. */
  top: calc(var(--s-6) + 0.1rem);
  font-family: var(--font-display);
  font-size: var(--t-body);
  font-weight: 700;
  font-variant-numeric: tabular-nums lining-nums;
  letter-spacing: 0.01em;
  color: var(--action-ink);
}

.belief h3 {
  font-size: var(--t-subheading);
  line-height: var(--lh-subheading);
  letter-spacing: var(--ls-subheading);
  margin-bottom: var(--s-2);
}

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

/* ---------- Prayer card ---------- */

.prayer-card {
  background:
    radial-gradient(500px 260px at 90% 0%, rgba(224, 45, 13, 0.35), transparent 60%),
    radial-gradient(400px 220px at 5% 100%, rgba(255, 179, 92, 0.12), transparent 55%),
    var(--surface-deep);
  color: var(--text-on-dark);
  border-radius: var(--radius-lifted);
  padding: clamp(2.2rem, 5vw, 3.4rem);
  margin: var(--s-9) 0;
}

.prayer-card .block-label { color: var(--action-ink-on-dark); }

.prayer-card blockquote {
  font-family: var(--font-body);
  font-size: var(--t-quote);
  font-style: italic;
  line-height: 1.55;
  letter-spacing: 0.004em;
  margin-top: var(--s-4);
}

/* ---------- Coming up ----------
   Hand-edited by the church, so it is built to fail safe. The whole
   section stays hidden until at least one .event exists, which means an
   empty list can never ship as a bare heading, and a browser without
   :has() support hides it rather than showing an empty shell. */

#coming-up { display: none; }

#coming-up:has(.event) { display: block; }

.event-list {
  list-style: none;
  display: grid;
  gap: var(--s-5);
  margin: var(--s-8) auto 0;
  max-width: 46rem;
}

/* Flyer left, details right. A fixed flyer column with natural height
   means a portrait, square or landscape Canva export all sit correctly
   without being cropped. */
.event {
  display: grid;
  grid-template-columns: 11rem 1fr;
  gap: var(--s-6);
  align-items: start;
  padding: var(--s-6);
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.event-flyer {
  display: block;
  border-radius: 12px;
  overflow: hidden;
  border: 1px solid var(--border);
}

.event-flyer img { width: 100%; height: auto; }

.event-when { color: var(--action-ink); }

.event h3 {
  font-size: var(--t-subheading);
  line-height: var(--lh-subheading);
  letter-spacing: var(--ls-subheading);
  margin: var(--s-2) 0;
}

.event p { margin: 0; color: var(--text-muted); }

/* An event with no flyer yet still needs to read properly. */
.event:not(:has(.event-flyer)) { grid-template-columns: 1fr; }

@media (max-width: 560px) {
  .event { grid-template-columns: 1fr; }
  .event-flyer { max-width: 13rem; }
}

/* ---------- Calendar ---------- */

.calendar-frame {
  margin-top: var(--s-8);
  border-radius: var(--radius);
  overflow: hidden;
  border: 1px solid var(--border);
  padding-top: 3px;
  background: linear-gradient(var(--ember-500), var(--ember-500)) top / 100% 3px no-repeat, var(--surface-raised);
  box-shadow: var(--shadow);
}

.calendar-frame img { width: 100%; height: auto; display: block; }

/* A whole month grid squeezed into phone width is unreadable however
   well the file is compressed: seven columns across 343px leaves the
   day numbers about a pixel tall. Below that threshold the calendar
   holds a legible width and the frame pans sideways instead. */
@media (max-width: 700px) {
  .calendar-frame {
    overflow-x: auto;
    overscroll-behavior-x: contain;
  }

  .calendar-frame img {
    width: auto;
    max-width: none;
    min-width: 52rem;
  }
}

.calendar-hint {
  text-align: center;
  margin-top: var(--s-4);
  font-size: var(--t-small);
  color: var(--text-muted);
}

/* The instruction differs by input: a pointer clicks through to the
   full size, a thumb pans the frame first. */
.hint-narrow { display: none; }

@media (max-width: 700px) {
  .hint-wide { display: none; }
  .hint-narrow { display: inline; }
}

/* ---------- Detail / info cards ---------- */

.detail-card {
  background: var(--surface-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--s-7);
}

.detail-card + .detail-card { margin-top: var(--s-4); }

/* A quoted or explanatory line sitting under a card or a block. */
.detail-quote { margin-top: var(--s-5); color: var(--text-muted); }

.note {
  margin-top: var(--s-6);
  color: var(--text-muted);
  font-size: var(--t-small);
}

.note a {
  color: var(--action-ink);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.15em;
}

.detail-row {
  display: flex;
  justify-content: space-between;
  gap: var(--s-6);
  padding: var(--s-3) 0;
  border-bottom: 1px dashed var(--border);
  font-size: var(--t-body);
}

.detail-row:last-child { border-bottom: none; }

.detail-row .k { color: var(--text-muted); }

/* Account and BSB numbers are copied by hand, so the figures are
   tabular and a little looser to keep digits distinct. */
.detail-row .v {
  font-weight: 600;
  text-align: right;
  font-variant-numeric: tabular-nums lining-nums;
  letter-spacing: 0.01em;
}

/* ---------- Contact ---------- */

.contact-grid {
  display: grid;
  grid-template-columns: 1fr 1.15fr;
  gap: var(--s-7);
  align-items: start;
}

.contact-list { list-style: none; display: grid; gap: var(--s-5); margin-top: var(--s-7); }

.contact-list li { display: flex; gap: var(--s-4); align-items: flex-start; }

.contact-list .icon {
  flex: none;
  width: 44px;
  height: 44px;
  border-radius: 12px;
  background: var(--surface-accent-tint);
  color: var(--ember-600);
  display: flex;
  align-items: center;
  justify-content: center;
}

.contact-list .icon svg { width: 20px; height: 20px; }

.contact-list .label { color: var(--text-muted); }

.contact-list .value {
  font-weight: 600;
  font-size: var(--t-body);
  font-variant-numeric: tabular-nums lining-nums;
  margin-top: var(--s-1);
}

.contact-list .value a { text-decoration: none; }

.contact-list .value a:hover {
  color: var(--action-ink);
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

.map-frame {
  border-radius: var(--radius);
  overflow: hidden;
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
}

.map-frame iframe { display: block; width: 100%; height: 460px; border: 0; }

/* ---------- Footer ---------- */

.site-footer {
  background: var(--surface-deepest);
  color: var(--text-on-dark-muted);
  padding: var(--s-10) 0 var(--s-7);
  font-size: var(--t-ui);
}

.footer-grid {
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr 1fr;
  gap: var(--s-8);
  padding-bottom: var(--s-9);
  border-bottom: 1px solid var(--border-on-dark);
}

.site-footer .brand-name { color: var(--text-on-dark); }

.footer-tagline { margin-top: var(--s-4); max-width: 30ch; font-size: var(--t-small); }

.site-footer h2 {
  color: var(--text-on-dark);
  margin-bottom: var(--s-4);
}

.site-footer ul { list-style: none; display: grid; gap: var(--s-2); }

/* Footer links were 21px tall, under the 24px WCAG 2.2 minimum and far
   under a thumb. Target size scales with the input device. */
.site-footer ul a,
.footer-bottom a {
  display: inline-flex;
  align-items: center;
  min-height: 32px;
}

@media (pointer: coarse) {
  .site-footer ul a { min-height: 44px; }
}

.site-footer a { color: inherit; text-decoration: none; transition: color 0.2s ease; }

.site-footer a:hover { color: var(--action-ink-on-dark); text-decoration: underline; }

.footer-bottom {
  display: flex;
  justify-content: space-between;
  gap: var(--s-4);
  flex-wrap: wrap;
  padding-top: var(--s-7);
  font-size: var(--t-micro);
  color: var(--text-on-dark-faint);
}

/* ---------- When and where ----------
   The two facts that produce attendance, directly under the service
   times instead of 4,200px below them. The address is a link, because
   asking a nervous stranger to retype it into Maps is friction at the
   exact moment their commitment is most fragile. */

.visit-now {
  margin-top: var(--s-5);
  padding: var(--s-6);
  border-radius: var(--radius);
  background: var(--surface-deep);
  color: var(--text-on-dark);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--s-3) var(--s-7);
  text-align: center;
}

.visit-now p {
  margin: 0;
  font-size: var(--t-lead);
  color: var(--text-on-dark);
}

.visit-now strong { font-weight: 700; }

.visit-now a {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  min-height: 44px;
  font-weight: 600;
  color: var(--action-ink-on-dark);
  text-decoration: underline;
  text-underline-offset: 0.18em;
}

.visit-now svg { width: 20px; height: 20px; flex: none; }

/* ---------- Street ministry ----------
   The one thing a neighbouring church cannot truthfully copy. It takes
   the slot the statistics used to hold. */

.street-list {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  gap: var(--s-5);
  margin-top: var(--s-8);
}

.street-list li {
  padding-top: var(--s-4);
  border-top: 1px solid var(--border-on-dark);
  color: var(--text-on-dark-muted);
}

.street-list b {
  display: block;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: var(--t-subheading);
  letter-spacing: var(--ls-subheading);
  color: var(--text-on-dark);
  margin-bottom: var(--s-2);
}

/* The worldwide figures, demoted from a four-up counter grid to one
   sentence that lands back on the local church. */
.street-note {
  margin-top: var(--s-8);
  text-align: center;
  font-size: var(--t-lead);
  color: var(--text-on-dark-muted);
}

/* ---------- Arrival timeline ---------- */

.timeline { list-style: none; display: grid; gap: 0; margin-top: var(--s-7); }

.timeline li {
  display: grid;
  grid-template-columns: 5.5rem 1fr;
  gap: var(--s-5);
  padding: var(--s-5) 0;
  border-top: 1px solid var(--border);
}

.timeline li:last-child { border-bottom: 1px solid var(--border); }

.timeline .when {
  font-family: var(--font-display);
  font-weight: 700;
  font-variant-numeric: tabular-nums lining-nums;
  color: var(--action-ink);
}

.timeline b { display: block; margin-bottom: var(--s-1); }

.timeline p { margin: 0; color: var(--text-muted); }

@media (max-width: 560px) {
  .timeline li { grid-template-columns: 1fr; gap: var(--s-1); }
}

/* ---------- Forced colours and unsupported clipping ----------
   background-clip:text paints nothing in forced-colors mode, so the
   headline emphasis and the figures would vanish entirely. Give the
   glyphs back a real colour in both cases. */

@supports not ((background-clip: text) or (-webkit-background-clip: text)) {
  .hero h1 em,
  .page-hero h1 em {
    background: none;
    color: var(--ember-300);
    -webkit-text-fill-color: var(--ember-300);
  }
}

@media (forced-colors: active) {
  .hero h1 em,
  .page-hero h1 em {
    background: none;
    color: CanvasText;
    -webkit-text-fill-color: CanvasText;
  }

  .time-card, .card, .belief, .detail-card { border: 1px solid CanvasText; }
}

/* ---------- Motion ----------
   One authored moment, then feedback. Nothing here hides content:
   every element is visible in its default state and motion is layered
   on top, so a failed script or a reduced-motion preference costs the
   visitor nothing but the flourish.

   Previously 43 elements across the site ran the same 0.7s fade-and-
   rise, which reads as wallpaper rather than intent. Entrance motion
   now belongs only to groups that genuinely arrive as a list. */

.nav-cta,
.nav-toggle { transition: transform 140ms cubic-bezier(0.16, 1, 0.3, 1); }

@media (prefers-reduced-motion: no-preference) {

  /* THE focal moment: the promise catching light.
     The gradient sits at 200% width, so sliding it from one end to the
     other changes which part of the fire lands on the words without
     ever leaving them unfilled. The headline is legible from the first
     frame; only its heat moves. */
  /* Not the arrival curve used elsewhere. On a sweep the travel IS
     the content, and cubic-bezier(0.16, 1, 0.3, 1) spends 83% of its
     distance in the first quarter, which reads as a flash rather than
     an ignition. This curve spreads the burn across the duration and
     still settles rather than stopping dead. The short delay lets the
     first paint and the webfont settle before it lights. */
  .hero h1 em {
    animation: ignite 780ms cubic-bezier(0.35, 0.8, 0.45, 1) 120ms both;
  }

  /* A list arriving as a list. Delay is capped so the fifth item and
     everything after it share the last step: thirteen belief cards
     must not become a thirteen-beat queue. */
  .stagger.in > * {
    animation: rise 520ms cubic-bezier(0.16, 1, 0.3, 1) backwards;
  }

  .stagger.in > *:nth-child(2) { animation-delay: 60ms; }
  .stagger.in > *:nth-child(3) { animation-delay: 120ms; }
  .stagger.in > *:nth-child(4) { animation-delay: 180ms; }
  .stagger.in > *:nth-child(n + 5) { animation-delay: 240ms; }

  /* The menu used to appear with no explanation of where it came
     from. It now arrives from the bar that opened it. */
  .site-nav.open {
    animation: menu-in 220ms cubic-bezier(0.16, 1, 0.3, 1);
  }
}

@keyframes ignite {
  from { background-position: 100% 0; }
  to { background-position: 0 0; }
}

@keyframes rise {
  from { opacity: 0; transform: translateY(14px); }
}

@keyframes menu-in {
  from { opacity: 0; transform: translateY(-8px); }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .btn { transition: none; }
  .btn:hover { transform: none; }
}

/* ---------- Responsive ---------- */

@media (max-width: 900px) {
  .split, .contact-grid { grid-template-columns: 1fr; }
  .footer-grid { grid-template-columns: 1fr 1fr; }

  .nav-toggle { display: flex; }

  .brand-logo { width: 40px; height: 40px; }

  .brand-word { height: 38px; transform: translateY(5px); }

  .site-nav {
    position: fixed;
    inset: var(--header-h, 74px) 0 auto 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    background: var(--surface);
    border-bottom: 1px solid var(--border);
    padding: var(--s-2) 4vw var(--s-5);
    display: none;
    box-shadow: 0 24px 40px -20px rgba(19, 19, 22, 0.25);
  }

  /* The panel is near-black here, so the light-surface hairline was
     invisible against it. */
  .header-dark .site-nav {
    background: var(--surface-deep-base);
    border-bottom-color: var(--border-on-dark);
  }

  .site-nav.open { display: flex; }

  .site-nav a { padding: var(--s-3) var(--s-2); font-size: var(--t-body); }

  .site-nav a.active { text-underline-offset: 0.3em; }

  .nav-cta { margin-top: var(--s-3); text-align: center; justify-content: center; display: inline-flex; }
}

/* Everything else on the site is visible without JavaScript, but the
   narrow-screen nav was not: the panel is display:none until a script
   adds .open, so with JS off the toggle rendered over seven
   unreachable links. Show the nav inline and drop the toggle. */
@media (max-width: 900px) and (scripting: none) {
  .site-nav {
    position: static;
    display: flex;
    inset: auto;
    padding: 0 0 var(--s-3);
    background: none;
    border-bottom: 0;
    box-shadow: none;
    flex-wrap: wrap;
    gap: var(--s-2) var(--s-5);
  }

  .header-dark .site-nav { background: none; }

  .nav-toggle { display: none; }

  .header-inner { flex-wrap: wrap; row-gap: var(--s-3); }
}

@media (max-width: 560px) {
  .footer-grid { grid-template-columns: 1fr; gap: var(--s-7); }
  .map-frame iframe { height: 320px; }
  .detail-row { flex-direction: column; gap: var(--s-1); }
  .detail-row .v { text-align: left; }

  /* Narrow columns need a touch less negative tracking to stay open. */
  .hero h1 { letter-spacing: -0.028em; }
  .page-hero h1 { letter-spacing: -0.024em; }
}
