/* ============================================================================
   Rayspring Ministry Digital — design system
   ----------------------------------------------------------------------------
   Architecture (this order matters, do not reshuffle):

     1. @font-face          self-hosted, no external request
     2. :root               the LIGHT base — Warm Ivory, the brand default
     3. html[data-mode]     shared dark base, applied by the dark themes
     4. html[data-theme]    per-theme overrides (5 themes)
     5. base / layout / components

   THE RULE: every colour in this file must be a var(--token). A literal hex
   outside the token blocks will look correct in one theme and wrong in the
   other four. There is a checker in scripts/check-tokens.php.

   These are the THEMES OF THIS MARKETING SITE. They are not the website
   templates we sell to churches — those live in the database
   (`ministry_templates`) and are rendered as screenshots, not as CSS.
   ========================================================================== */

/* ── 1. Fonts ────────────────────────────────────────────────────────────── */

@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url("../fonts/inter-latin.woff2") format("woff2");
}

/* The Inter Latin subset claims (blank) glyphs for the Myanmar block, so
   Burmese words inside an English page render as boxes unless this same-family
   face wins for that range. */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  unicode-range: U+1000-109F, U+A9E0-A9FF, U+AA60-AA7F;
  src: url("../fonts/noto-myanmar-400.woff2") format("woff2");
}

/* Lora: the editorial serif used only for large headlines. Warm, readable and
   quietly traditional — the "trustworthy, not corporate" signal. */
@font-face {
  font-family: "Lora";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/lora-latin.woff2") format("woff2");
}
@font-face {
  font-family: "Lora";
  font-style: italic;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/lora-latin-italic.woff2") format("woff2");
}

@font-face {
  font-family: "Noto Sans Myanmar";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/noto-myanmar-400.woff2") format("woff2");
}
@font-face {
  font-family: "Noto Sans Myanmar";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("../fonts/noto-myanmar-500.woff2") format("woff2");
}
@font-face {
  font-family: "Noto Sans Myanmar";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("../fonts/noto-myanmar-600.woff2") format("woff2");
}
@font-face {
  font-family: "Noto Sans Myanmar";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("../fonts/noto-myanmar-700.woff2") format("woff2");
}

/* ── 2. :root — "Ivory", the light default ───────────────────────────────── */

:root {
  /* Brand constants — the palette from the brief */
  --ivory: #faf7f0;
  --ink: #20252b;
  --gold: #c59a4a;
  --blue: #617d98;
  --warm-white: #ffffff;
  --soft-gray: #eceae5;

  /* Semantic surfaces */
  --bg: var(--ivory);
  --bg-2: #f4f0e7;
  --surface: var(--warm-white);
  --surface-2: #f7f4ee;
  --surface-sunken: #efebe2;
  --surface-ink: #20252b;         /* deep panels that stay dark in light themes */
  --surface-ink-2: #272d34;

  /* Text */
  --text: #20252b;
  --text-strong: #12161a;
  --text-muted: #5d666f;
  --text-subtle: #5f666d;
  --text-on-ink: #f3f0e9;
  --text-on-ink-muted: #b6bcc2;
  --text-on-accent: #ffffff;

  /* Accents */
  /* Bronze rather than bright gold: this token is used for SMALL TEXT
     (eyebrows, ghost links, price labels), and #b3873a measured only
     2.87:1 against the tinted band — well under the 4.5:1 that size needs.
     #7a5a1f clears 5.0:1 on every light surface in every light theme, and
     white text on it as a button clears 6.3:1. The bright gold survives as
     --gold, used for decorative fills where nothing has to be read. */
  --accent: #7a5a1f;
  --accent-strong: #5f4616;
  --accent-soft: rgba(197, 154, 74, 0.16);
  --accent-line: rgba(160, 122, 48, 0.42);
  --accent-2: #4f6b86;            /* muted blue, darkened for contrast */
  --accent-2-soft: rgba(97, 125, 152, 0.14);

  /* Lines & shadows */
  --line: rgba(32, 37, 43, 0.11);
  --line-strong: rgba(32, 37, 43, 0.2);
  --line-on-ink: rgba(255, 255, 255, 0.14);
  --shadow-sm: 0 2px 8px rgba(32, 37, 43, 0.05), 0 8px 24px rgba(32, 37, 43, 0.05);
  --shadow-md: 0 4px 16px rgba(32, 37, 43, 0.07), 0 20px 48px rgba(32, 37, 43, 0.07);
  --shadow-lg: 0 8px 32px rgba(32, 37, 43, 0.09), 0 36px 80px rgba(32, 37, 43, 0.1);

  /* Status */
  --ok-text: #1f6b46;
  --ok-bg: rgba(31, 107, 70, 0.09);
  --ok-line: rgba(31, 107, 70, 0.28);
  --warn-text: #8a5a12;
  --warn-bg: rgba(181, 126, 30, 0.12);
  --warn-line: rgba(181, 126, 30, 0.32);
  --err-text: #97302a;
  --err-bg: rgba(151, 48, 42, 0.09);
  --err-line: rgba(151, 48, 42, 0.28);
  --info-text: #3c5f80;
  --info-bg: rgba(97, 125, 152, 0.12);

  /* Header */
  --header-bg: rgba(250, 247, 240, 0.86);
  --header-bg-scrolled: rgba(250, 247, 240, 0.96);
  --header-line: rgba(32, 37, 43, 0.08);

  /* Typography */
  --font-body: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    "Helvetica Neue", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei",
    "Noto Sans SC", "Noto Sans Myanmar", sans-serif;
  --font-display: "Lora", "Iowan Old Style", Georgia, "Songti SC", "SimSun", serif;
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;

  /* Scale — fluid, clamped so nothing explodes on a 4K monitor */
  --step--1: clamp(0.82rem, 0.79rem + 0.14vw, 0.9rem);
  --step-0: clamp(1rem, 0.96rem + 0.2vw, 1.09rem);
  --step-1: clamp(1.18rem, 1.11rem + 0.35vw, 1.4rem);
  --step-2: clamp(1.42rem, 1.29rem + 0.63vw, 1.85rem);
  --step-3: clamp(1.7rem, 1.47rem + 1.1vw, 2.45rem);
  --step-4: clamp(2.05rem, 1.65rem + 1.9vw, 3.25rem);
  --step-5: clamp(2.4rem, 1.75rem + 3vw, 4.1rem);

  /* Shape & motion */
  --radius-xs: 6px;
  --radius-sm: 10px;
  --radius-md: 16px;
  --radius-lg: 24px;
  --radius-pill: 999px;
  --container: 1180px;
  --container-narrow: 780px;
  --gutter: clamp(1.15rem, 4vw, 2.5rem);
  --header-height: 72px;
  --ease: cubic-bezier(0.22, 1, 0.36, 1);
  --speed: 0.28s;

  color-scheme: light;
}

/* ── 3. Shared dark base ─────────────────────────────────────────────────── */

html[data-mode="dark"] {
  --bg: #15181c;
  --bg-2: #1a1e23;
  --surface: #1d2228;
  --surface-2: #232830;
  --surface-sunken: #171b20;
  --surface-ink: #101317;
  --surface-ink-2: #171b20;

  --text: #e9e5dc;
  --text-strong: #f6f3ec;
  --text-muted: #a3aab2;
  --text-subtle: #868d95;
  --text-on-ink: #e9e5dc;
  --text-on-ink-muted: #a3aab2;
  --text-on-accent: #17120a;

  /* In dark mode the gold can be brighter — it is text ON a dark field, so a
     lighter tone is what passes contrast, the opposite of light mode. */
  --accent: #d7b273;
  --accent-strong: #e6c68f;
  --accent-soft: rgba(215, 178, 115, 0.15);
  --accent-line: rgba(215, 178, 115, 0.34);
  --accent-2: #8aa6c2;
  --accent-2-soft: rgba(138, 166, 194, 0.15);

  --line: rgba(255, 255, 255, 0.1);
  --line-strong: rgba(255, 255, 255, 0.18);
  --line-on-ink: rgba(255, 255, 255, 0.12);
  --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.3), 0 8px 24px rgba(0, 0, 0, 0.24);
  --shadow-md: 0 4px 16px rgba(0, 0, 0, 0.36), 0 20px 48px rgba(0, 0, 0, 0.3);
  --shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.42), 0 36px 80px rgba(0, 0, 0, 0.4);

  --ok-text: #6fd3a4;
  --ok-bg: rgba(111, 211, 164, 0.12);
  --ok-line: rgba(111, 211, 164, 0.3);
  --warn-text: #e5bf76;
  --warn-bg: rgba(229, 191, 118, 0.13);
  --warn-line: rgba(229, 191, 118, 0.32);
  --err-text: #f0a29b;
  --err-bg: rgba(240, 162, 155, 0.12);
  --err-line: rgba(240, 162, 155, 0.3);
  --info-text: #9fbcd8;
  --info-bg: rgba(159, 188, 216, 0.12);

  --header-bg: rgba(21, 24, 28, 0.84);
  --header-bg-scrolled: rgba(21, 24, 28, 0.96);
  --header-line: rgba(255, 255, 255, 0.09);

  color-scheme: dark;
}

/* ── 4. Themes ───────────────────────────────────────────────────────────── */

/* Ivory is :root; this block exists so the selector is explicit. */
html[data-theme="ivory"] { }

/* Linen — softer, more paper, less contrast; the quietest of the light set. */
html[data-theme="linen"] {
  --bg: #f6f3ec;
  --bg-2: #efeade;
  --surface: #fdfbf7;
  --surface-2: #f3efe5;
  --surface-sunken: #e9e4d8;
  --line: rgba(52, 44, 32, 0.12);
  --line-strong: rgba(52, 44, 32, 0.2);
  --text: #2c2a25;
  --text-strong: #1b1a16;
  --text-muted: #63605a;
  --accent: #75551d;
  --accent-strong: #5b4215;
  --header-bg: rgba(246, 243, 236, 0.88);
  --header-bg-scrolled: rgba(246, 243, 236, 0.97);
}

/* Dayspring — cooler light, blue-forward; reads more "organisation". */
html[data-theme="dayspring"] {
  --bg: #f5f7f9;
  --bg-2: #eaeff4;
  --surface: #ffffff;
  --surface-2: #f2f5f8;
  --surface-sunken: #e6ecf2;
  --surface-ink: #1c2937;
  --surface-ink-2: #23323f;
  --text: #1e2a36;
  --text-strong: #101a24;
  --text-muted: #55636f;
  --accent: #2f5677;
  --accent-strong: #23415a;
  --accent-soft: rgba(56, 98, 135, 0.12);
  --accent-line: rgba(56, 98, 135, 0.32);
  --accent-2: #6d5220;
  --accent-2-soft: rgba(160, 124, 51, 0.14);
  --line: rgba(30, 42, 54, 0.12);
  --line-strong: rgba(30, 42, 54, 0.2);
  --header-bg: rgba(245, 247, 249, 0.88);
  --header-bg-scrolled: rgba(245, 247, 249, 0.97);
}

/* Vesper — warm dark; charcoal and brass, the evening version of Ivory. */
html[data-theme="vesper"] {
  --bg: #191713;
  --bg-2: #1f1c17;
  --surface: #23201a;
  --surface-2: #2b2721;
  --surface-sunken: #14120f;
  --surface-ink: #100e0b;
  --surface-ink-2: #17150f;
  --text: #ece5d6;
  --text-strong: #f7f2e6;
  --text-muted: #a9a08e;
  --accent: #dcb672;
  --accent-strong: #ecca8e;
  --line: rgba(236, 229, 214, 0.11);
  --line-strong: rgba(236, 229, 214, 0.2);
  --header-bg: rgba(25, 23, 19, 0.85);
  --header-bg-scrolled: rgba(25, 23, 19, 0.97);
}

/* Nightwatch — cool deep dark; the highest-contrast option. */
html[data-theme="nightwatch"] {
  --bg: #10151b;
  --bg-2: #141b23;
  --surface: #18202a;
  --surface-2: #1e2833;
  --surface-sunken: #0c1116;
  --surface-ink: #090d12;
  --surface-ink-2: #0f151c;
  --text: #e3e9ef;
  --text-strong: #f4f7fa;
  --text-muted: #97a3b0;
  --accent: #86aed3;
  --accent-strong: #a4c4e2;
  --accent-soft: rgba(134, 174, 211, 0.15);
  --accent-line: rgba(134, 174, 211, 0.34);
  --accent-2: #d5b477;
  --accent-2-soft: rgba(213, 180, 119, 0.15);
  --line: rgba(227, 233, 239, 0.1);
  --line-strong: rgba(227, 233, 239, 0.19);
  --header-bg: rgba(16, 21, 27, 0.85);
  --header-bg-scrolled: rgba(16, 21, 27, 0.97);
}

/* ── 5. Base ─────────────────────────────────────────────────────────────── */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-height) + 1rem);
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-body);
  font-size: var(--step-0);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* A long word in a Burmese heading must wrap rather than push the layout
     sideways on a 360px phone. */
  overflow-wrap: break-word;
}

/* Burmese is a tall, dense script: it needs looser leading and a slightly
   smaller display size or headings collide with their own diacritics. */
html[lang="my"] body { line-height: 1.95; }
html[lang="my"] h1,
html[lang="my"] h2,
html[lang="my"] h3 { line-height: 1.6; font-size: 0.92em; }
html[lang="my"] .button { line-height: 1.45; }

html[lang="zh-CN"] body { line-height: 1.85; }

h1, h2, h3, h4, h5, h6 {
  margin: 0 0 0.6em;
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.18;
  letter-spacing: -0.012em;
  color: var(--text-strong);
  text-wrap: balance;
}

/* CJK and Burmese have no need for a Latin serif — the fallback would be a
   random system serif and look accidental. */
html[lang="zh-CN"] h1, html[lang="zh-CN"] h2, html[lang="zh-CN"] h3,
html[lang="my"] h1, html[lang="my"] h2, html[lang="my"] h3 {
  font-family: var(--font-body);
  font-weight: 700;
  letter-spacing: 0;
}

h1 { font-size: var(--step-5); }
h2 { font-size: var(--step-4); }
h3 { font-size: var(--step-2); }
h4 { font-size: var(--step-1); }

p { margin: 0 0 1.1em; }
p:last-child { margin-bottom: 0; }

a {
  color: var(--accent);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
  transition: color var(--speed) var(--ease);
}
a:hover { color: var(--accent-strong); }

img, svg, video { max-width: 100%; height: auto; display: block; }

hr {
  border: 0;
  border-top: 1px solid var(--line);
  margin: 2.5rem 0;
}

::selection { background: var(--accent-soft); color: var(--text-strong); }

/* Focus: visible on every interactive element, in every theme. Removing this
   is how a site becomes unusable by keyboard. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: var(--radius-xs);
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 200;
  padding: 0.85rem 1.3rem;
  background: var(--accent);
  color: var(--text-on-accent);
  border-radius: 0 0 var(--radius-sm) 0;
  font-weight: 600;
}
.skip-link:focus { left: 0; }

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ── Layout ──────────────────────────────────────────────────────────────── */

.container {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.container--narrow { max-width: var(--container-narrow); }

.section {
  padding-block: clamp(3.25rem, 7vw, 6rem);
  position: relative;
}
.section--tight { padding-block: clamp(2.25rem, 4.5vw, 3.75rem); }
.section--muted { background: var(--bg-2); }
.section--sunken { background: var(--surface-sunken); }

/* Ink sections stay dark in every theme, so their contents need the inverted
   text tokens. Scoping the tokens here means the components inside do not
   each need a modifier class. */
.section--ink {
  background: var(--surface-ink);
  --text: var(--text-on-ink);
  --text-strong: #fdfbf6;
  --text-muted: var(--text-on-ink-muted);
  --surface: var(--surface-ink-2);
  --surface-2: var(--surface-ink-2);
  --line: var(--line-on-ink);
  --line-strong: rgba(255, 255, 255, 0.22);
  --accent: #dcb672;
  --accent-strong: #ecca8e;
  /* Inside a dark panel the accent is the BRIGHT gold, so text sitting on it
     must go back to dark ink — white on #dcb672 is only 1.91:1. */
  --text-on-accent: #1c1509;
  color: var(--text-on-ink);
}
.section--ink h1, .section--ink h2, .section--ink h3, .section--ink h4 { color: #fdfbf6; }

.section__head { max-width: 46rem; margin-bottom: clamp(1.75rem, 3.5vw, 3rem); }
.section__head--center { margin-inline: auto; text-align: center; }

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin: 0 0 0.9rem;
  font-family: var(--font-body);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--accent);
}
.eyebrow::before {
  content: "";
  width: 1.6rem;
  height: 1px;
  background: currentColor;
  opacity: 0.65;
}
.section__head--center .eyebrow::before { display: none; }

.lede {
  font-size: var(--step-1);
  color: var(--text-muted);
  max-width: 42rem;
  line-height: 1.6;
}
.section__head--center .lede { margin-inline: auto; }

.grid { display: grid; gap: clamp(1rem, 2.2vw, 1.75rem); }
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 21rem), 1fr)); }
.grid--3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 17.5rem), 1fr)); }
.grid--4 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr)); }

.stack > * + * { margin-top: 1rem; }
.cluster { display: flex; flex-wrap: wrap; gap: 0.75rem; align-items: center; }

/* ── Buttons ─────────────────────────────────────────────────────────────── */

.button {
  --btn-bg: var(--accent);
  --btn-fg: var(--text-on-accent);
  --btn-line: transparent;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.55rem;
  padding: 0.78rem 1.5rem;
  border: 1px solid var(--btn-line);
  border-radius: var(--radius-pill);
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-family: var(--font-body);
  font-size: var(--step-0);
  font-weight: 600;
  line-height: 1.3;
  text-decoration: none;
  cursor: pointer;
  transition: transform var(--speed) var(--ease), background var(--speed) var(--ease),
    border-color var(--speed) var(--ease), color var(--speed) var(--ease),
    box-shadow var(--speed) var(--ease);
  /* 44px minimum touch target — a phone is the primary device for most of
     the people this site is for. */
  min-height: 44px;
}
.button:hover:not(:disabled) {
  background: var(--accent-strong);
  color: var(--btn-fg);
  transform: translateY(-1px);
  box-shadow: var(--shadow-sm);
}
.button:active:not(:disabled) { transform: translateY(0); }
.button:disabled,
.button[aria-disabled="true"] {
  opacity: 0.5;
  cursor: not-allowed;
  transform: none;
  box-shadow: none;
}

.button--secondary {
  --btn-bg: transparent;
  --btn-fg: var(--text-strong);
  --btn-line: var(--line-strong);
}
.button--secondary:hover:not(:disabled) {
  background: var(--accent-soft);
  border-color: var(--accent-line);
  color: var(--text-strong);
}

.button--ghost {
  --btn-bg: transparent;
  --btn-fg: var(--accent);
  --btn-line: transparent;
  padding-inline: 0.4rem;
}
.button--ghost:hover:not(:disabled) {
  background: transparent;
  color: var(--accent-strong);
  transform: none;
  box-shadow: none;
  text-decoration: underline;
}

.button--sm { padding: 0.55rem 1.1rem; font-size: var(--step--1); min-height: 38px; }

.button--lg { padding: 0.95rem 1.9rem; font-size: var(--step-1); }
.button--block { width: 100%; }

/* ── Cards ───────────────────────────────────────────────────────────────── */

.card {
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  padding: clamp(1.3rem, 2.4vw, 1.85rem);
  transition: border-color var(--speed) var(--ease), transform var(--speed) var(--ease),
    box-shadow var(--speed) var(--ease);
}
.card--link:hover,
.card--link:focus-within {
  border-color: var(--accent-line);
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
}
.card__icon {
  width: 2.75rem;
  height: 2.75rem;
  display: grid;
  place-items: center;
  margin-bottom: 1rem;
  border-radius: var(--radius-sm);
  background: var(--accent-soft);
  color: var(--accent);
}
.card__icon svg { width: 1.4rem; height: 1.4rem; }
.card__title { margin: 0 0 0.5rem; font-size: var(--step-1); }
.card__text { margin: 0; color: var(--text-muted); font-size: var(--step-0); }
.card__foot { margin-top: auto; padding-top: 1.1rem; }

.card__media {
  margin: calc(-1 * clamp(1.3rem, 2.4vw, 1.85rem));
  margin-bottom: 1.2rem;
  border-radius: var(--radius-md) var(--radius-md) 0 0;
  overflow: hidden;
  background: var(--surface-sunken);
  aspect-ratio: 16 / 10;
}
.card__media img { width: 100%; height: 100%; object-fit: cover; }

/* A card whose whole surface is clickable: the pseudo-element covers the card
   so the entire area is a target, without nesting interactive elements. */
.card__stretch::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
}
.card--link { position: relative; }

/* ── Header ──────────────────────────────────────────────────────────────── */

.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: var(--header-bg);
  border-bottom: 1px solid transparent;
  backdrop-filter: saturate(180%) blur(14px);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  transition: background var(--speed) var(--ease), border-color var(--speed) var(--ease),
    box-shadow var(--speed) var(--ease);
}
.site-header.is-scrolled {
  background: var(--header-bg-scrolled);
  border-bottom-color: var(--header-line);
  box-shadow: var(--shadow-sm);
}
.site-header__inner {
  display: flex;
  align-items: center;
  gap: 1rem;
  min-height: var(--header-height);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.65rem;
  text-decoration: none;
  color: var(--text-strong);
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.05rem;
  line-height: 1.15;
  letter-spacing: -0.01em;
  flex-shrink: 0;
}
.brand:hover { color: var(--text-strong); }
.brand__mark {
  width: 2.1rem;
  height: 2.1rem;
  flex-shrink: 0;
  border-radius: 8px;
}
.brand__text { display: flex; flex-direction: column; }
.brand__text small {
  font-family: var(--font-body);
  font-size: 0.66rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-subtle);
}

.primary-nav { margin-left: auto; }
/* A button in a horizontal bar must never wrap: two lines of label make the pill
   57px tall against a 39px neighbour and the whole row looks mis-built. */
.primary-nav__cta .button { white-space: nowrap; }
.primary-nav__list {
  display: flex;
  align-items: center;
  gap: 0.15rem;
  list-style: none;
  margin: 0;
  padding: 0;
}
.primary-nav__link {
  display: block;
  padding: 0.5rem 0.78rem;
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  font-size: 0.94rem;
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
  transition: color var(--speed) var(--ease), background var(--speed) var(--ease);
}
.primary-nav__link:hover { color: var(--text-strong); background: var(--accent-soft); }
.primary-nav__link.is-active { color: var(--accent); font-weight: 600; }

.header-actions { display: flex; align-items: center; gap: 0.4rem; }

/* Dropdowns (language + theme) */
.dropdown { position: relative; }
.dropdown__btn {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  min-height: 38px;
  padding: 0.4rem 0.6rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--text-muted);
  font: inherit;
  font-size: 0.86rem;
  cursor: pointer;
  transition: border-color var(--speed) var(--ease), color var(--speed) var(--ease);
}
.dropdown__btn:hover { border-color: var(--line-strong); color: var(--text-strong); }
.dropdown__menu {
  position: absolute;
  right: 0;
  top: calc(100% + 0.45rem);
  z-index: 110;
  min-width: 11.5rem;
  padding: 0.35rem;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  box-shadow: var(--shadow-md);
}
.dropdown__menu[hidden] { display: none; }
.dropdown__item {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  width: 100%;
  padding: 0.52rem 0.7rem;
  border: 0;
  border-radius: var(--radius-xs);
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: 0.9rem;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
}
.dropdown__item:hover { background: var(--accent-soft); color: var(--text-strong); }
.dropdown__item[aria-current="true"] { color: var(--accent); font-weight: 600; }
.theme-swatch {
  width: 1rem;
  height: 1rem;
  flex-shrink: 0;
  border-radius: 50%;
  border: 1px solid var(--line-strong);
}

/* The theme button used to show the ACTIVE theme's colour. In Warm Ivory that is
   #faf7f0 on an ivory header — a circle the same colour as the thing behind it,
   which is an invisible control. It shows a half-filled circle now: the standard
   "appearance" mark, legible in all five themes. The real colour swatches stay
   in the dropdown, where each one sits on a surface and is worth seeing. */
.theme-dropdown__icon {
  width: 1.05rem;
  height: 1.05rem;
  flex-shrink: 0;
  border-radius: 50%;
  border: 1.5px solid currentColor;
  background: linear-gradient(90deg, currentColor 0 50%, transparent 50% 100%);
}

.nav-toggle {
  display: none;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-strong);
  cursor: pointer;
}

/* Below ~400px the header ran out of room and pushed the page sideways.
   The controls must keep their touch size, so the brand is what gives way. */
@media (max-width: 430px) {
  .site-header__inner { gap: 0.5rem; }
  .brand { min-width: 0; flex: 1 1 auto; gap: 0.45rem; }
  .brand__text {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 0.95rem;
  }
  .brand__text small { display: none; }
  .header-actions { flex-shrink: 0; gap: 0.25rem; }
  .dropdown__btn { padding-inline: 0.45rem; }
  /* The chevron is decoration; the half-circle mark carries the meaning. */
  .theme-dropdown__chevron { display: none; }
}

/* 1200px, measured, not guessed: brand 195 + nav 753 + actions 121 + gutters 80
   needs about 1197px. At the old 1000px the desktop nav appeared 200px before it
   fitted, so between those widths the CTA was squeezed to 90px and its label
   wrapped onto two lines — which is what made the header look broken. */
@media (max-width: 1200px) {
  .nav-toggle { display: inline-flex; }
  .primary-nav {
    position: fixed;
    inset: var(--header-height) 0 0;
    z-index: 99;
    margin: 0;
    padding: 1.5rem var(--gutter) 3rem;
    background: var(--bg);
    overflow-y: auto;
    transform: translateY(-8px);
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--speed) var(--ease), transform var(--speed) var(--ease);
  }
  .primary-nav.is-open { opacity: 1; transform: none; pointer-events: auto; }
  .primary-nav__list { flex-direction: column; align-items: stretch; gap: 0.15rem; }
  .primary-nav__link {
    padding: 0.9rem 0.75rem;
    font-size: 1.05rem;
    border-bottom: 1px solid var(--line);
    border-radius: 0;
  }
  .primary-nav__cta { margin-top: 1.5rem; }
  .primary-nav__cta .button { width: 100%; }
  body.nav-open { overflow: hidden; }
}

/* ── Hero ────────────────────────────────────────────────────────────────── */

.hero {
  position: relative;
  padding-block: clamp(3rem, 8vw, 6.5rem);
  background: var(--bg);
  overflow: hidden;
}
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  /* A single soft radial warmth rather than a heavy gradient — enough to lift
     the page off flat white without looking like a 2012 template. */
  background:
    radial-gradient(60rem 32rem at 78% -12%, var(--accent-soft), transparent 62%),
    radial-gradient(46rem 26rem at 8% 104%, var(--accent-2-soft), transparent 66%);
  pointer-events: none;
}
.hero__inner {
  position: relative;
  display: grid;
  gap: clamp(2rem, 4vw, 3.5rem);
  align-items: center;
  grid-template-columns: minmax(0, 1.08fr) minmax(0, 1fr);
}
@media (max-width: 900px) {
  .hero__inner { grid-template-columns: 1fr; }
}

/* No hero image: one centred column rather than a conspicuously empty half. */
.hero__inner--solo {
  grid-template-columns: minmax(0, 1fr);
  max-width: 54rem;
  text-align: center;
}
.hero__inner--solo .hero__lede { margin-inline: auto; }
.hero__inner--solo .hero__actions { justify-content: center; }
.hero__inner--solo .eyebrow { justify-content: center; }
.hero__inner--solo .eyebrow::before { display: none; }
.hero__title { margin-bottom: 1rem; }
.hero__lede { font-size: var(--step-1); color: var(--text-muted); max-width: 34rem; }
.hero__actions { margin-top: 1.9rem; }
.hero__note {
  margin-top: 1.3rem;
  font-size: var(--step--1);
  color: var(--text-subtle);
}
.hero__media {
  position: relative;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--surface-2);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-lg);
  aspect-ratio: 4 / 3;
}
.hero__media img { width: 100%; height: 100%; object-fit: cover; }

/* Showcase hero — real client websites on the first screen.
   The copy column gets the wider share: the sites are the proof, but the
   sentence explaining what is being sold still has to be read first. */
.hero--showcase .hero__inner { grid-template-columns: minmax(0, 1fr) minmax(0, 1.02fr); }
@media (max-width: 980px) {
  .hero--showcase .hero__inner { grid-template-columns: 1fr; }
}

/* Half the width means the h1 needs a step down: at the full display size this
   headline broke into four short lines and pushed everything else off the
   screen, including the two buttons it exists to lead to. */
.hero--showcase .hero__title { font-size: var(--step-4); }
.hero--showcase .hero__actions .button {
  padding-inline: 1.2rem;
  font-size: var(--step-0);
}

.hero__showcase {
  position: relative;
  padding-block-end: clamp(2rem, 5vw, 3.5rem);
}
.hero__showcase--single { padding-block-end: 0; }
.hero__showcase .browser--lead { position: relative; z-index: 2; }
/* The second site peeks out from behind the first: two proofs in the space of
   one, and the overlap reads as a stack of real work rather than a gallery. */
.hero__showcase .browser--trail {
  position: absolute;
  inset-block-end: 0;
  inset-inline-end: 0;
  width: 58%;
  z-index: 3;
  /* A ring in the page colour separates the two frames where they overlap;
     without it the front one reads as a rendering glitch on the back one. */
  outline: 6px solid var(--bg);
}

/* A browser frame. The address bar carries the site's real host, which is the
   entire point — a screenshot proves a design, a domain proves it is online. */
.browser {
  display: block;
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--line);
  box-shadow: var(--shadow-lg);
  text-decoration: none;
  color: inherit;
  transition: transform var(--speed) var(--ease), box-shadow var(--speed) var(--ease);
}
a.browser:hover { transform: translateY(-3px); }
.browser__bar {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.5rem 0.7rem;
  background: var(--surface-2);
  border-block-end: 1px solid var(--line);
}
.browser__dots { display: inline-flex; gap: 0.28rem; flex: none; }
.browser__dots i {
  width: 0.46rem;
  height: 0.46rem;
  border-radius: 50%;
  background: var(--line-strong);
}
.browser__url {
  flex: 1;
  min-width: 0;
  padding: 0.2rem 0.7rem;
  border-radius: var(--radius-pill);
  background: var(--bg);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.browser > img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  object-position: top center;
  background: var(--surface-sunken);
}

/* Below this width the overlap becomes a pile. Stack them instead. */
@media (max-width: 620px) {
  .hero__showcase { padding: 0; }
  .hero__showcase .browser--trail {
    position: static;
    width: 100%;
    margin-block-start: 1rem;
  }
}

/* Live figures, never typed copy — see Controller::heroFacts(). */
.hero__facts {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(1.25rem, 3.5vw, 2.75rem);
  margin: clamp(1.75rem, 3.5vw, 2.5rem) 0 0;
  padding-block-start: clamp(1.25rem, 2.5vw, 1.75rem);
  border-block-start: 1px solid var(--line);
}
.hero__inner--solo .hero__facts { justify-content: center; }
.hero__fact-value {
  font-family: var(--font-display);
  font-size: var(--step-2);
  font-weight: 600;
  line-height: 1.1;
  color: var(--text-strong);
}
.hero__fact-label {
  margin: 0.3rem 0 0;
  max-width: 10rem;
  font-size: var(--step--1);
  line-height: 1.4;
  color: var(--text-muted);
}

/* Page hero — the smaller variant on inner pages */
.page-hero {
  padding-block: clamp(2.5rem, 5.5vw, 4.5rem) clamp(1.75rem, 3.5vw, 3rem);
  background: var(--bg-2);
  border-bottom: 1px solid var(--line);
}
.page-hero__title { margin-bottom: 0.75rem; }

.breadcrumbs {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-bottom: 1.1rem;
  padding: 0;
  list-style: none;
  font-size: var(--step--1);
  color: var(--text-subtle);
}
.breadcrumbs li + li::before { content: "/"; margin-right: 0.4rem; opacity: 0.5; }
.breadcrumbs a { color: var(--text-muted); text-decoration: none; }
.breadcrumbs a:hover { color: var(--accent); text-decoration: underline; }

/* ── Pricing ─────────────────────────────────────────────────────────────── */

.plan {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: clamp(1.4rem, 2.6vw, 2rem);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
}
.plan--recommended {
  border-color: var(--accent-line);
  box-shadow: var(--shadow-md);
}
.plan__badge {
  position: absolute;
  top: -0.75rem;
  left: clamp(1.4rem, 2.6vw, 2rem);
  padding: 0.25rem 0.75rem;
  border-radius: var(--radius-pill);
  background: var(--accent);
  color: var(--text-on-accent);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.plan__name { margin: 0 0 0.35rem; font-size: var(--step-1); }
.plan__best-for { margin: 0 0 1.2rem; font-size: var(--step--1); color: var(--text-subtle); }
.plan__price {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.4rem;
  margin-bottom: 0.35rem;
  font-family: var(--font-display);
  font-size: var(--step-3);
  font-weight: 600;
  color: var(--text-strong);
  line-height: 1.1;
}
.plan__price-note { font-family: var(--font-body); font-size: var(--step--1); font-weight: 500; color: var(--text-muted); }
.plan__hosting { margin: 0 0 1.3rem; font-size: var(--step--1); color: var(--text-muted); }
.plan__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1rem;
  margin-bottom: 1.2rem;
  padding-bottom: 1.2rem;
  border-bottom: 1px solid var(--line);
  font-size: var(--step--1);
  color: var(--text-muted);
}
.plan__features { list-style: none; margin: 0 0 1.5rem; padding: 0; font-size: var(--step-0); }
.plan__features li {
  position: relative;
  padding-left: 1.6rem;
  margin-bottom: 0.5rem;
  color: var(--text-muted);
}
.plan__features li::before {
  content: "";
  position: absolute;
  left: 0.15rem;
  top: 0.62em;
  width: 0.55rem;
  height: 0.3rem;
  border-left: 2px solid var(--accent);
  border-bottom: 2px solid var(--accent);
  transform: rotate(-45deg);
}
.plan__features--excluded li { color: var(--text-subtle); }
.plan__features--excluded li::before {
  border: 0;
  top: 0.72em;
  width: 0.6rem;
  height: 0;
  border-top: 2px solid var(--text-subtle);
  transform: none;
  opacity: 0.7;
}
.plan__excluded-title {
  margin: 0 0 0.55rem;
  font-family: var(--font-body);
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--text-subtle);
}
.plan__cta { margin-top: auto; }

.addon-table { width: 100%; border-collapse: collapse; font-size: var(--step-0); }
.addon-table th,
.addon-table td { padding: 0.85rem 0.6rem; text-align: left; border-bottom: 1px solid var(--line); }
.addon-table th { font-weight: 600; color: var(--text-subtle); font-size: var(--step--1); text-transform: uppercase; letter-spacing: 0.05em; }
.addon-table td:last-child { text-align: right; white-space: nowrap; font-weight: 600; }

/* ── Templates ───────────────────────────────────────────────────────────── */

.template-card { position: relative; overflow: hidden; padding: 0; }
.template-card__shots {
  position: relative;
  aspect-ratio: 16 / 11;
  background: var(--surface-sunken);
  overflow: hidden;
}
.template-card__desktop { width: 100%; height: 100%; object-fit: cover; object-position: top center; }
.template-card__mobile {
  position: absolute;
  right: 5%;
  bottom: -8%;
  width: 24%;
  border-radius: 10px;
  border: 3px solid var(--surface);
  box-shadow: var(--shadow-md);
  object-fit: cover;
  object-position: top center;
}
/* Shown until a real screenshot exists. Communicates the template's palette
   instead of pretending an image failed to load. */
.template-card__placeholder {
  position: relative;
  width: 100%;
  height: 100%;
  display: grid;
  place-items: center;
  background: var(--surface-2);
}
.template-card__bands {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
}
.template-card__bands span { flex: 1; }
.template-card__code {
  position: relative;
  padding: 0.4rem 1.1rem;
  border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, 0.9);
  /* The pill is deliberately white in every theme, so its text has to be dark
     in every theme — which means the theme-scoped --text is wrong here. --ink
     is a brand constant and never re-scoped, so it says what is meant. */
  color: var(--ink);
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-weight: 600;
  letter-spacing: 0.02em;
  box-shadow: var(--shadow-sm);
}

.template-card__actions { display: flex; flex-wrap: wrap; gap: 0.5rem; }

/* Template detail: a browser frame with the phone overlapping its lower edge. */
.template-shots { position: relative; padding-block-end: clamp(1.5rem, 5vw, 3rem); }
.template-shots__desktop > img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  object-position: top center;
}
.template-shots__phone {
  position: absolute;
  inset-block-end: 0;
  inset-inline-end: 4%;
  width: 26%;
  min-width: 5.5rem;
  max-width: 11rem;
  aspect-ratio: 9 / 17;
  overflow: hidden;
  border-radius: 14px;
  /* The ring is the page colour, so the phone reads as sitting in front of the
     browser rather than as a hole cut in it. */
  border: 5px solid var(--bg);
  box-shadow: var(--shadow-lg);
  background: var(--surface-sunken);
}
.template-shots__phone img { width: 100%; height: 100%; object-fit: cover; object-position: top center; }

@media (max-width: 560px) {
  .template-shots { padding-block-end: 0; }
  .template-shots__phone {
    position: static;
    width: 9rem;
    margin-block-start: 1rem;
    border-color: var(--line);
    border-width: 1px;
  }
}

.template-card__body { padding: clamp(1.2rem, 2.2vw, 1.6rem); }
.template-card__palette { display: flex; gap: 0.3rem; margin-bottom: 0.85rem; }
.template-card__swatch {
  width: 1.1rem;
  height: 1.1rem;
  border-radius: 50%;
  border: 1px solid var(--line-strong);
}
.template-card__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin: 0.9rem 0 0;
  padding: 0;
  list-style: none;
}
.tag {
  display: inline-block;
  padding: 0.2rem 0.6rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  font-size: 0.76rem;
  color: var(--text-muted);
  background: var(--surface-2);
}
.tag--accent { border-color: var(--accent-line); color: var(--accent); background: var(--accent-soft); }

.filter-bar { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 2rem; }
.filter-bar__btn {
  padding: 0.45rem 1rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--text-muted);
  font: inherit;
  font-size: 0.9rem;
  text-decoration: none;
  cursor: pointer;
  min-height: 38px;
  display: inline-flex;
  align-items: center;
}
.filter-bar__btn:hover { border-color: var(--accent-line); color: var(--text-strong); }
.filter-bar__btn.is-active {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--text-on-accent);
  font-weight: 600;
}

/* ── Process / steps ─────────────────────────────────────────────────────── */

.process-layout {
  display: grid;
  gap: clamp(1.5rem, 4vw, 3.5rem);
  grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
  align-items: start;
}
@media (max-width: 860px) {
  .process-layout { grid-template-columns: 1fr; }
}
.process-note {
  padding: clamp(1.25rem, 2.5vw, 1.9rem);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  background: var(--surface-2);
  font-size: var(--step-0);
}

.process { counter-reset: step; list-style: none; margin: 0; padding: 0; }
.process__item {
  counter-increment: step;
  position: relative;
  padding-left: 3.4rem;
  padding-bottom: 2rem;
}
.process__item::before {
  content: counter(step);
  position: absolute;
  left: 0;
  top: 0;
  width: 2.35rem;
  height: 2.35rem;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--accent-soft);
  border: 1px solid var(--accent-line);
  color: var(--accent);
  font-family: var(--font-display);
  font-weight: 600;
}
.process__item::after {
  content: "";
  position: absolute;
  left: 1.17rem;
  top: 2.6rem;
  bottom: 0.35rem;
  width: 1px;
  background: var(--line);
}
.process__item:last-child { padding-bottom: 0; }
.process__item:last-child::after { display: none; }
.process__title { margin: 0.25rem 0 0.4rem; font-size: var(--step-1); }
.process__text { margin: 0; color: var(--text-muted); }

/* ── Stats ───────────────────────────────────────────────────────────────── */

.stat { text-align: center; }
.stat__value {
  display: block;
  font-family: var(--font-display);
  font-size: var(--step-4);
  font-weight: 600;
  color: var(--accent);
  line-height: 1.1;
}
.stat__label { display: block; margin-top: 0.4rem; font-size: var(--step--1); color: var(--text-muted); }

/* ── FAQ ─────────────────────────────────────────────────────────────────── */

.faq { border-top: 1px solid var(--line); }
.faq__item { border-bottom: 1px solid var(--line); }
.faq__question {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  width: 100%;
  padding: 1.25rem 0;
  border: 0;
  background: transparent;
  color: var(--text-strong);
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-weight: 600;
  text-align: left;
  cursor: pointer;
  line-height: 1.35;
}
html[lang="zh-CN"] .faq__question,
html[lang="my"] .faq__question { font-family: var(--font-body); }
.faq__icon {
  flex-shrink: 0;
  width: 1.15rem;
  height: 1.15rem;
  margin-top: 0.3rem;
  position: relative;
}
.faq__icon::before,
.faq__icon::after {
  content: "";
  position: absolute;
  inset: 50% 0 auto 0;
  height: 2px;
  background: var(--accent);
  border-radius: 2px;
  transition: transform var(--speed) var(--ease);
}
.faq__icon::after { transform: rotate(90deg); }
.faq__question[aria-expanded="true"] .faq__icon::after { transform: rotate(0deg); }
.faq__answer {
  overflow: hidden;
  color: var(--text-muted);
}
.faq__answer[hidden] { display: none; }
.faq__answer-inner { padding-bottom: 1.4rem; max-width: 48rem; }

/* ── Forms ───────────────────────────────────────────────────────────────── */

.form { display: grid; gap: 1.15rem; }
.form-row { display: grid; gap: 1.15rem; grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr)); }
.field { display: flex; flex-direction: column; gap: 0.4rem; }
.field__label {
  font-size: var(--step--1);
  font-weight: 600;
  color: var(--text-strong);
  letter-spacing: 0.01em;
}
.field__label .req { color: var(--err-text); margin-left: 0.15rem; }
.field__hint { font-size: 0.82rem; color: var(--text-subtle); }
.field__error { font-size: 0.82rem; color: var(--err-text); font-weight: 500; }

.input,
.select,
.textarea {
  width: 100%;
  padding: 0.72rem 0.9rem;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text);
  font: inherit;
  font-size: var(--step-0);
  line-height: 1.5;
  min-height: 46px;
  transition: border-color var(--speed) var(--ease), box-shadow var(--speed) var(--ease);
}
.input::placeholder,
.textarea::placeholder { color: var(--text-subtle); opacity: 1; }
.input:focus,
.select:focus,
.textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.input[aria-invalid="true"],
.textarea[aria-invalid="true"],
.select[aria-invalid="true"] { border-color: var(--err-line); }
.textarea { min-height: 8.5rem; resize: vertical; }
.select {
  appearance: none;
  padding-right: 2.4rem;
  /* Inline caret so no image request is needed and it recolours per theme. */
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position: calc(100% - 1.15rem) 55%, calc(100% - 0.8rem) 55%;
  background-size: 0.35rem 0.35rem, 0.35rem 0.35rem;
  background-repeat: no-repeat;
}

/* Groups a long form into named parts. The supported-ministry form does the
   same thing with an inline font-size; this is that, named, so a third form
   does not invent a third version of it. */
.form-heading {
  margin: 2rem 0 0.25rem;
  font-size: var(--step-1);
}
.form-heading:first-child { margin-top: 0; }

.checkbox {
  display: flex;
  align-items: flex-start;
  gap: 0.65rem;
  font-size: var(--step--1);
  color: var(--text-muted);
  line-height: 1.5;
  cursor: pointer;
}
.checkbox input {
  flex-shrink: 0;
  width: 1.15rem;
  height: 1.15rem;
  margin-top: 0.15rem;
  accent-color: var(--accent);
  cursor: pointer;
}

/* The honeypot. Hidden from people, present for bots. Not display:none —
   some bots skip those; off-screen with aria-hidden is the reliable shape. */
.hp-field {
  position: absolute !important;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.form-status {
  padding: 0.9rem 1.1rem;
  border: 1px solid;
  border-radius: var(--radius-sm);
  font-size: var(--step-0);
}
.form-status--success { color: var(--ok-text); background: var(--ok-bg); border-color: var(--ok-line); }
.form-status--error { color: var(--err-text); background: var(--err-bg); border-color: var(--err-line); }
.form-status--warning { color: var(--warn-text); background: var(--warn-bg); border-color: var(--warn-line); }
.form-status--info { color: var(--info-text); background: var(--info-bg); border-color: var(--accent-line); }

.notice {
  padding: 1rem 1.2rem;
  border-left: 3px solid var(--accent);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  background: var(--accent-soft);
  font-size: var(--step-0);
}
.notice--warn { border-left-color: var(--warn-line); background: var(--warn-bg); color: var(--warn-text); }

/* ── Prose (article body, sanitised HTML from the CMS) ───────────────────── */

.prose { max-width: 44rem; font-size: var(--step-1); line-height: 1.75; color: var(--text); }
.prose > * + * { margin-top: 1.15em; }
.prose h2 { margin-top: 2em; font-size: var(--step-3); }
.prose h3 { margin-top: 1.6em; font-size: var(--step-2); }
.prose ul, .prose ol { padding-left: 1.4em; }
.prose li + li { margin-top: 0.4em; }
.prose blockquote {
  margin-inline: 0;
  padding: 0.4em 0 0.4em 1.3em;
  border-left: 3px solid var(--accent-line);
  color: var(--text-muted);
  font-style: italic;
}
.prose img { border-radius: var(--radius-md); margin-block: 1.6em; }
.prose figure { margin: 1.6em 0; }
.prose figcaption { margin-top: 0.6em; font-size: var(--step--1); color: var(--text-subtle); text-align: center; }
.prose table { width: 100%; border-collapse: collapse; font-size: var(--step-0); }
.prose th, .prose td { padding: 0.6em 0.7em; border: 1px solid var(--line); text-align: left; }
.prose th { background: var(--surface-2); font-weight: 600; }
.prose code {
  padding: 0.15em 0.4em;
  border-radius: var(--radius-xs);
  background: var(--surface-2);
  font-family: var(--font-mono);
  font-size: 0.88em;
}
.prose pre {
  padding: 1rem 1.2rem;
  border-radius: var(--radius-sm);
  background: var(--surface-ink);
  color: var(--text-on-ink);
  overflow-x: auto;
}
.prose pre code { background: transparent; padding: 0; }
/* Any embedded iframe (a sermon video) must stay inside its column. */
.prose iframe { width: 100%; aspect-ratio: 16 / 9; border: 0; border-radius: var(--radius-md); }

/* ── Media / embeds ──────────────────────────────────────────────────────── */

.embed {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--surface-ink);
}
.embed iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

/* ── Testimonials ────────────────────────────────────────────────────────── */

.quote { display: flex; flex-direction: column; gap: 1.2rem; }
.quote__text {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--step-1);
  line-height: 1.55;
  color: var(--text-strong);
}
html[lang="zh-CN"] .quote__text,
html[lang="my"] .quote__text { font-family: var(--font-body); }
.quote__author { display: flex; align-items: center; gap: 0.85rem; margin-top: auto; }
.quote__avatar { width: 2.75rem; height: 2.75rem; border-radius: 50%; object-fit: cover; flex-shrink: 0; }
.quote__name { font-weight: 600; font-size: var(--step-0); }
.quote__role { font-size: var(--step--1); color: var(--text-subtle); }

/* ── Pagination ──────────────────────────────────────────────────────────── */

.pagination {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  justify-content: center;
  align-items: center;
  margin-top: 3rem;
  list-style: none;
  padding: 0;
}
.pagination a,
.pagination span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 42px;
  min-height: 42px;
  padding: 0 0.7rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  text-decoration: none;
  font-size: 0.92rem;
}
.pagination a:hover { border-color: var(--accent-line); color: var(--accent); }
.pagination [aria-current="page"] {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--text-on-accent);
  font-weight: 600;
}

/* ── Footer ──────────────────────────────────────────────────────────────── */

.site-footer {
  margin-top: clamp(3rem, 7vw, 6rem);
  padding-block: clamp(2.75rem, 6vw, 4.5rem) 2rem;
  background: var(--surface-ink);
  color: var(--text-on-ink);
  --text: var(--text-on-ink);
  --text-muted: var(--text-on-ink-muted);
  --line: var(--line-on-ink);
  --accent: #dcb672;
  --accent-strong: #ecca8e;
  --text-on-accent: #1c1509;
}
.site-footer h2, .site-footer h3, .site-footer h4 { color: #fdfbf6; }
.site-footer__grid {
  display: grid;
  gap: clamp(1.75rem, 4vw, 3rem);
  grid-template-columns: minmax(0, 1.4fr) repeat(auto-fit, minmax(min(100%, 10rem), 1fr));
  padding-bottom: 2.5rem;
  border-bottom: 1px solid var(--line-on-ink);
}
.site-footer__about { max-width: 24rem; }
.site-footer__about p { color: var(--text-on-ink-muted); font-size: var(--step--1); line-height: 1.7; }
.site-footer__title {
  margin: 0 0 0.9rem;
  font-family: var(--font-body);
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-on-ink-muted);
}
.site-footer__list { list-style: none; margin: 0; padding: 0; }
.site-footer__list li + li { margin-top: 0.55rem; }
.site-footer__list a {
  display: inline-flex;
  align-items: center;
  color: var(--text-on-ink);
  text-decoration: none;
  font-size: var(--step--1);
  opacity: 0.86;
}
.site-footer__list a:hover { color: var(--accent); opacity: 1; text-decoration: underline; }
.site-footer__bottom {
  display: flex;
  flex-wrap: wrap;
  gap: 0.8rem 1.6rem;
  align-items: center;
  justify-content: space-between;
  padding-top: 1.75rem;
  font-size: 0.82rem;
  color: var(--text-on-ink-muted);
}
.site-footer__legal { display: flex; flex-wrap: wrap; gap: 1rem; list-style: none; margin: 0; padding: 0; }
.site-footer__legal a { display: inline-flex; align-items: center; color: var(--text-on-ink-muted); text-decoration: none; }
.site-footer__legal a:hover { color: var(--accent); text-decoration: underline; }

/* Every link in the footer is one line of small type — about sixteen pixels
   tall, stacked, roughly twenty of them. On a desktop that is fine; on the
   phone that is the primary device for most of the people this site is for, it
   is a column of targets too small and too close together to hit reliably.
   Scoped to the touch breakpoint so the desktop footer stays compact.

   These were invisible to the audit for months: its inline-link exception
   matched anything inside an <li>, which is every navigation link there is. */
@media (max-width: 820px) {
  .site-footer__list a,
  .site-footer__legal a { min-height: 44px; }
  /* Full width, so the tap area is the row rather than the width of the word.
     "FAQ" is 25px of text; the finger aiming at it is not. */
  .site-footer__list a { width: 100%; }
  .site-footer__list li + li { margin-top: 0; }
  .site-footer__about a { display: inline-flex; align-items: center; min-height: 44px; }

  /* A two-character breadcrumb ("首页") is 26px of text. The hit box is widened
     with padding and pulled back with an equal negative margin, so the target
     grows without the crumb trail visibly shifting. */
  .breadcrumbs a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding-inline: 0.5rem;
    margin-inline: -0.5rem;
  }

  /* A link that is alone in its paragraph is a control, not part of a
     sentence — an email address in a card, for instance. min-height alone does
     nothing to an inline element, so it has to become inline-flex first. */
  .card p > a:only-child:not(.button) {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }
}

/* The "powered by" line. Honest about what this is: one person, with
   Rayspring Tech behind it. */
.site-footer__parent { font-size: 0.8rem; opacity: 0.72; }

/* ── CTA panel ───────────────────────────────────────────────────────────── */

.cta-panel {
  padding: clamp(2rem, 5vw, 3.75rem);
  border-radius: var(--radius-lg);
  background: var(--surface-ink);
  color: var(--text-on-ink);
  --text: var(--text-on-ink);
  --text-muted: var(--text-on-ink-muted);
  --line: var(--line-on-ink);
  --accent: #dcb672;
  --accent-strong: #ecca8e;
  --text-on-accent: #1c1509;
  text-align: center;
}
.cta-panel h2 { color: #fdfbf6; }
.cta-panel .lede { color: var(--text-on-ink-muted); margin-inline: auto; }
.cta-panel .cluster { justify-content: center; margin-top: 1.9rem; }
.cta-panel .button--secondary {
  --btn-fg: #fdfbf6;
  --btn-line: rgba(255, 255, 255, 0.28);
}

/* ── Utilities ───────────────────────────────────────────────────────────── */

.text-center { text-align: center; }
.text-muted { color: var(--text-muted); }
.text-small { font-size: var(--step--1); }
.mt-0 { margin-top: 0; }
.mt-1 { margin-top: 0.5rem; }
.mt-2 { margin-top: 1rem; }
.mt-3 { margin-top: 1.75rem; }
.mt-4 { margin-top: 2.5rem; }
.mb-0 { margin-bottom: 0; }
.flow > * + * { margin-top: 1.1rem; }

.empty-state {
  padding: clamp(2rem, 5vw, 3.5rem);
  border: 1px dashed var(--line-strong);
  border-radius: var(--radius-md);
  text-align: center;
  color: var(--text-muted);
}

/* Entrance animation.
   
   SCOPED TO html.js ON PURPOSE. Starting at opacity:0 means that if the
   JavaScript never runs — a parse error, a blocked file, an old browser —
   every element carrying .reveal stays permanently invisible, which on this
   site is most of the home page. The inline head script adds the `js` class,
   so without it the content is simply visible with no animation.

   Switched off entirely for anyone who asked for reduced motion (handled at
   the top of the file). */
html.js .reveal {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.6s var(--ease), transform 0.6s var(--ease);
}
html.js .reveal.is-visible { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  html.js .reveal { opacity: 1; transform: none; }
}

/* ── Touch targets ───────────────────────────────────────────────────────── */
/* 38px is comfortable with a mouse and too small for a thumb. Rather than
   inflating every control everywhere, they grow only on small screens and
   touch devices. This block lives at the END of the file on purpose: the
   component rules it overrides are defined later than the button section, so
   an earlier copy lost on cascade order despite equal specificity. */

@media (max-width: 820px), (pointer: coarse) {
  .button--sm,
  .dropdown__btn,
  .filter-bar__btn,
  .nav-toggle {
    min-height: 44px;
  }
  .button--sm { padding-block: 0.7rem; }
  .pagination a,
  .pagination span { min-height: 44px; min-width: 44px; }

  /* The brand is a link too — 34px of image is a small target for a thumb. */
  .brand { padding-block: 0.35rem; }
  .site-footer .brand { padding-block: 0.5rem; }
}

/* ── Print ───────────────────────────────────────────────────────────────── */

@media print {
  .site-header, .site-footer, .nav-toggle, .header-actions, .cta-panel { display: none !important; }
  body { background: #fff; color: #000; }
  a[href^="http"]::after { content: " (" attr(href) ")"; font-size: 0.8em; }
}

/* ── Case study card ─────────────────────────────────────────────────────── */
/*
   Replaces the stretched-link card. Two real actions instead of one invisible
   one, and a fixed-ratio shot so two cards of unequal text still line up —
   the old grid left one card's button floating half a screen above the other.
*/

.case-card {
  display: flex;
  flex-direction: column;
  padding: 0;
  overflow: hidden;
}
.case-card__shot {
  display: block;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  background: var(--surface-sunken);
  border-bottom: 1px solid var(--line);
}
.case-card__shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top center;
  transition: transform 0.5s ease;
}
.case-card:hover .case-card__shot img { transform: scale(1.02); }

.case-card__body {
  display: flex;
  flex-direction: column;
  flex: 1;
  gap: 0.6rem;
  padding: clamp(1.2rem, 2.2vw, 1.7rem);
}
.case-card__meta {
  margin: 0;
  font-size: var(--step--1);
  color: var(--text-subtle);
}
.case-card__title { margin: 0; font-size: var(--step-2); line-height: 1.25; }
.case-card__text { margin: 0; color: var(--text-muted); }

/* Pushed to the bottom so both cards' buttons sit on the same line. */
.case-card__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-top: auto;
  padding-top: 0.9rem;
}
.case-card__actions .button { display: inline-flex; align-items: center; }

@media (prefers-reduced-motion: reduce) {
  .case-card__shot img { transition: none; }
  .case-card:hover .case-card__shot img { transform: none; }
}

/* Case study at full width, screenshot and story side by side, alternating
   down the page. The home page shows its only two projects this way: at card
   size a ministry website is an unreadable smudge, which is the opposite of
   what a portfolio is for. */
.case-features { display: grid; gap: clamp(2.5rem, 5.5vw, 4.5rem); }
.case-feature {
  display: grid;
  gap: clamp(1.5rem, 3.5vw, 3rem);
  align-items: center;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
}
.case-feature--textonly { grid-template-columns: minmax(0, 1fr); max-width: 46rem; }
.case-feature__shot { order: 1; }
.case-feature__body { order: 2; }
/* Alternate the sides so a list of projects does not read as a form. */
.case-feature:nth-child(even) .case-feature__shot { order: 2; }
.case-feature:nth-child(even) .case-feature__body { order: 1; }

@media (max-width: 860px) {
  .case-feature { grid-template-columns: 1fr; }
  /* Stacked, the picture always comes first — an alternating stack just looks
     like the markup is inconsistent. */
  .case-feature__shot,
  .case-feature:nth-child(even) .case-feature__shot { order: 1; }
  .case-feature__body,
  .case-feature:nth-child(even) .case-feature__body { order: 2; }
}

.case-feature__meta {
  margin: 0 0 0.6rem;
  font-size: var(--step--1);
  color: var(--text-subtle);
}
.case-feature__title { margin: 0 0 0.7rem; font-size: var(--step-3); line-height: 1.2; }
.case-feature__text { margin: 0; color: var(--text-muted); font-size: var(--step-0); }
.case-feature__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-block-start: 1.4rem;
}
.case-feature__actions .button { display: inline-flex; align-items: center; }

/* Who this is for. Read from `audience_types`, and kept deliberately lighter
   than a card: it used to sit directly above a second six-card grid and the
   two blocks were indistinguishable. */
.audiences {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.5rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 19rem), 1fr));
}
.audience {
  display: flex;
  align-items: flex-start;
  gap: 0.9rem;
  height: 100%;
  padding: 1rem 1.1rem;
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  color: inherit;
  text-decoration: none;
  transition: background var(--speed) var(--ease), border-color var(--speed) var(--ease),
    box-shadow var(--speed) var(--ease);
}
a.audience:hover,
a.audience:focus-visible {
  background: var(--surface);
  border-color: var(--line);
  box-shadow: var(--shadow-sm);
}
.audience__icon {
  flex: none;
  display: grid;
  place-items: center;
  width: 2.4rem;
  height: 2.4rem;
  border-radius: var(--radius-sm);
  background: var(--accent-soft);
  color: var(--accent);
}
.audience__icon svg { width: 1.15rem; height: 1.15rem; }
.audience__name {
  display: block;
  font-weight: 600;
  color: var(--text-strong);
  transition: color var(--speed) var(--ease);
}
a.audience:hover .audience__name { color: var(--accent); }
.audience__blurb {
  display: block;
  margin-block-start: 0.28rem;
  font-size: var(--step--1);
  line-height: 1.55;
  color: var(--text-muted);
}

/* card_grid settings.style = "list": the same items with the boxes taken away,
   ruled like a ledger. Used where a card grid would be the second one in a row. */
.point-list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 23rem), 1fr));
  column-gap: clamp(2rem, 4.5vw, 4rem);
}
.point {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
  padding-block: clamp(1.1rem, 2vw, 1.5rem);
  border-block-start: 1px solid var(--line);
}
.point__icon {
  flex: none;
  display: grid;
  place-items: center;
  width: 1.9rem;
  height: 1.9rem;
  color: var(--accent);
}
.point__icon svg { width: 1.3rem; height: 1.3rem; }
.point__body { min-width: 0; }
.point__title { margin: 0 0 0.3rem; font-size: var(--step-0); line-height: 1.35; }
.point__text {
  margin: 0;
  font-size: var(--step--1);
  line-height: 1.65;
  color: var(--text-muted);
}
.point__foot { margin: 0.5rem 0 0; }

.link-arrow {
  font-size: var(--step--1);
  font-weight: 600;
  color: var(--accent);
  text-decoration: none;
}
.link-arrow:hover { text-decoration: underline; }

@media (prefers-reduced-motion: reduce) {
  a.browser:hover { transform: none; }
}

/* Case study detail: the story, and the facts a visitor is checking. */
.case-story {
  display: grid;
  gap: clamp(2rem, 5vw, 4rem);
  grid-template-columns: minmax(0, 1fr) minmax(0, 19rem);
  align-items: start;
}
@media (max-width: 900px) {
  .case-story { grid-template-columns: 1fr; }
}
.case-story__body { max-width: 42rem; }

.case-facts {
  position: sticky;
  top: calc(var(--header-height) + 1.5rem);
  padding: clamp(1.25rem, 2.5vw, 1.75rem);
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  background: var(--surface);
}
@media (max-width: 900px) { .case-facts { position: static; } }

.case-facts__list { margin: 0 0 1.25rem; }
.case-facts__list > div + div {
  margin-top: 0.85rem;
  padding-top: 0.85rem;
  border-top: 1px solid var(--line);
}
.case-facts__list dt {
  font-size: var(--step--1);
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: 0.2rem;
}
.case-facts__list dd { margin: 0; color: var(--text); }
.case-facts__note {
  margin: 1rem 0 0;
  font-size: var(--step--1);
  line-height: 1.55;
  color: var(--text-subtle);
}

.case-gallery {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: clamp(1rem, 2.2vw, 1.75rem);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr));
}
.case-gallery img {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  object-position: top center;
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  background: var(--surface-sunken);
}

/* A three-column grid holding one or two items stretches them across the whole
   page. These cap the row so the cards keep the size they were designed at. */
.grid--fill-1 { grid-template-columns: minmax(0, min(100%, 24rem)); }
.grid--fill-2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 17.5rem), 24rem)); }

/* A list that reads as prose, for places where a card grid would be the third
   card grid on the page. Marker is a token, not a colour literal. */
.plain-list { margin: 0; padding: 0; list-style: none; display: grid; gap: 0.9rem; }
.plain-list li {
  position: relative;
  padding-inline-start: 1.6rem;
  color: var(--text-muted);
  line-height: 1.6;
}
.plain-list li::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  top: 0.62em;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--accent);
}

/* ── Phone bottom bar ────────────────────────────────────────────────────────
   Five destinations one tap away, where the thumb already is. Everything else
   stays behind the hamburger.

   Only below 820px: that is the width this project already treats as "touch"
   (the tap-target audit uses the same number), and a tab bar on a laptop is
   just a strip of wasted screen.

   Driven by the `mobile` navigation menu — see app/views/layout/bottom-nav.php.
   Every colour is a token, so it follows all five themes. */

.bottom-nav { display: none; }

@media (max-width: 820px) {
  .bottom-nav {
    position: fixed;
    inset-inline: 0;
    inset-block-end: 0;
    z-index: 60;
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    background: var(--header-bg-scrolled);
    border-block-start: 1px solid var(--line);
    /* The blur is what stops text scrolling underneath from showing through
       and making the labels unreadable. */
    backdrop-filter: blur(12px);
    /* The iPhone home indicator sits in the bottom ~34px. Without this the
       last row of labels is under it and the whole bar feels mis-aligned. */
    padding-block-end: env(safe-area-inset-bottom, 0px);
  }

  .bottom-nav__item {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.2rem;
    /* 56px of bar plus whatever the safe area adds — comfortably past the 44px
       minimum, and the tap area is the full column width. */
    min-height: 56px;
    padding-block: 0.45rem 0.4rem;
    color: var(--text-muted);
    text-decoration: none;
    position: relative;
  }

  .bottom-nav__icon { display: grid; place-items: center; }
  .bottom-nav__icon svg { width: 1.35rem; height: 1.35rem; }

  .bottom-nav__label {
    font-size: 0.66rem;
    font-weight: 600;
    letter-spacing: 0.01em;
    /* A long Burmese label must not push the columns out of alignment. */
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .bottom-nav__item.is-current { color: var(--accent); }
  /* The short rule above the active item, so the current place is legible
     without relying on colour alone. */
  .bottom-nav__item.is-current::before {
    content: "";
    position: absolute;
    inset-block-start: 0;
    inset-inline-start: 50%;
    transform: translateX(-50%);
    width: 1.6rem;
    height: 2px;
    border-radius: 0 0 2px 2px;
    background: var(--accent);
  }

  /* The bar floats over the page, so the end of the footer would otherwise sit
     underneath it and be unreachable. */
  body { padding-block-end: calc(56px + env(safe-area-inset-bottom, 0px)); }
}

@media print {
  .bottom-nav { display: none !important; }
}
