/*
 * Manifest compiled by Propshaft into /assets/application-*.css.
 * No build step (Tailwind/Sass) -- plain CSS with cascade layers, so file
 * load order never matters and !important is never needed.
 */

@layer reset, base, layout, components, utilities;

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

  html, body {
    margin: 0;
  }

  img, svg {
    max-width: 100%;
    display: block;
    /* Required companion to the width/height attributes the image helpers
       now emit (see ApplicationHelper#web_image_dimensions). Those attributes
       are what let the browser reserve an image's box before it loads, but
       they also act as presentational hints -- so without this the height
       attribute is taken literally and the image is stretched to it: the
       posters came out 1104x633 instead of 1104x437. With height: auto the
       attributes are used only for the aspect ratio, which is the point.
       Anything that genuinely wants a fixed height (the hero, the circular
       pastor photos, the logos) sets one in a later layer and still wins. */
    height: auto;
  }

  a {
    color: inherit;
    text-decoration: none;
  }
}

@layer base {
  :root {
    /* Brand: navy + gold ("Biru-Emas Klasik") */
    --color-navy: #1E3A5F;
    --color-navy-dark: #142943;
    --color-gold: #C9A227;

    /* Decorative red for the Chinese-seal/stamp accents and festive
       banners (section-seal, ornament-divider) -- the same red
       .renungan-banner already used as a literal, now named so both share
       one source of truth. Distinct from --color-negative-ink, which is
       semantic (form/error state), not decorative. */
    --color-seal: #C0392B;

    --color-navy-light: color-mix(in oklch, var(--color-navy) 55%, white);
    --color-gold-light: color-mix(in oklch, var(--color-gold) 45%, white);
    --color-gold-dark: color-mix(in oklch, var(--color-gold) 80%, black);

    /* Site header background only -- rest of the brand's navy stays as-is
       (footer, buttons, text) so this doesn't ripple through the palette. */
    --color-header: #0284C7;

    --color-canvas: #ffffff;
    --color-canvas-subtle: #F6F7FA;
    --color-ink: #1F2933;
    --color-ink-light: #5B6573;
    --color-border: #E2E5EA;

    --color-link: var(--color-navy);

    /* Heading ink. Separate from --color-navy-dark even though it starts as
       the same colour: navy-dark doubles as a *background* (the hero, the
       page banner, the video frames), so the night theme below can't just
       re-point it -- it flips this one and leaves those backgrounds alone. */
    --color-heading: var(--color-navy-dark);

    --color-negative-bg: #FDECEC;
    --color-negative-ink: #9B1C1C;
    --color-positive-bg: #EAF7EE;
    --color-positive-ink: #1B6B3A;

    --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;

    --text-xs: 0.8rem;
    --text-sm: 0.925rem;
    --text-base: 1.05rem;
    --text-lg: 1.25rem;
    --text-xl: 1.6rem;
    --text-2xl: clamp(2rem, 4vw, 2.75rem);
    --text-3xl: clamp(2.25rem, 5vw, 3.5rem);

    --space-1: 0.5rem;
    --space-2: 1rem;
    --space-3: 1.5rem;
    --space-4: 2rem;
    --space-6: 3rem;
    --space-8: 4rem;

    --radius: 0.5rem;
    --radius-lg: 1rem;
    --shadow-sm: 0 1px 2px rgb(0 0 0 / 0.06);
    --shadow-md: 0 6px 16px rgb(0 0 0 / 0.10);
    --shadow-lg: 0 16px 40px rgb(0 0 0 / 0.16);

    --max-width: 72rem;

    color-scheme: light;
  }

  body {
    font-family: var(--font-sans);
    background: var(--color-canvas);
    color: var(--color-ink);
    font-size: var(--text-base);
    line-height: 1.65;
    -webkit-font-smoothing: antialiased;
  }

  h1, h2, h3, h4 {
    line-height: 1.2;
    font-weight: 700;
    color: var(--color-heading);
    margin: 0 0 var(--space-2);
  }

  h1 { font-size: var(--text-2xl); }
  h2 { font-size: var(--text-xl); margin-top: var(--space-4); }
  h3 { font-size: var(--text-lg); }

  p {
    margin: 0 0 var(--space-2);
    color: var(--color-ink-light);
    max-width: 70ch;
  }

  .indented-paragraph {
    text-indent: 2em;
    text-align: justify;
  }

  /* Tentang Kami page: larger body text on desktop only, headings untouched. */
  @media (min-width: 641px) {
    .about-content p {
      font-size: var(--text-lg);
    }
  }

  .about-content {
    font-family: "Quicksand", var(--font-sans);
    padding-inline: 1.5rem;
  }

  .about-content h1,
  .about-content h2 {
    font-family: "Playfair Display", "Quicksand", var(--font-sans);
    text-transform: uppercase;
    letter-spacing: 0.04em;
  }

  @media (min-width: 641px) {
    .about-content {
      padding-inline: 10rem;
    }
  }

  /* Kontak & Lokasi body: church info + prayer request form. One column on
     phones/tablets, two from 900px up -- the info column takes the extra
     width (the form's fields stop being comfortable past ~30rem, and the
     map below it needs the room more). The page gutter lives here rather
     than on .contact-content so both columns share it. */
  .contact-layout {
    display: grid;
    gap: var(--space-4);
    max-width: var(--max-width);
    margin-inline: auto;
    padding-inline: 1.5rem;
  }

  @media (min-width: 641px) {
    .contact-layout {
      padding-inline: 4rem;
    }
  }

  @media (min-width: 900px) {
    .contact-layout {
      grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
      align-items: start;
      gap: var(--space-6);
    }
  }

  /* Mobile only: the longest line ("Ibadah Wanita: Sabtu Pertama pukul
     16.00 WIB") wraps at narrow widths with just "WIB" dropping to its own
     line, reading as cut off. Shrinking the font (clamp so it scales with
     viewport instead of a single fixed size) keeps every line on one row
     on typical phone widths. Desktop is untouched -- this only applies
     under the same 640px breakpoint the rest of this page's mobile
     adjustments use. */
  @media (max-width: 640px) {
    .service-hours {
      font-size: clamp(0.8rem, 3.8vw, 0.95rem);
    }
  }

  /* Prayer request form (right column of .contact-layout). Sits on a subtle
     panel so it reads as a distinct thing to fill in rather than more page
     copy; sticky on desktop so it stays alongside the tall map. */
  .prayer-request {
    background: var(--color-canvas-subtle);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: var(--space-3);
  }

  @media (min-width: 900px) {
    .prayer-request {
      position: sticky;
      top: var(--space-3);
    }
  }

  /* Same Playfair vocabulary as .section-seal__title and the hero, so the
     panel reads as this site rather than a bolted-on widget. Overrides the
     global `h2 { margin-top: var(--space-4) }` -- it is the first thing in
     the panel, so leading space would just look like uneven padding. */
  .prayer-request__title {
    margin-top: 0;
    margin-bottom: var(--space-1);
    font-family: "Playfair Display", var(--font-sans);
    font-weight: 600;
    text-align: center;
  }

  .prayer-request__invite {
    margin-bottom: var(--space-1);
    text-align: center;
  }

  .prayer-request__note {
    margin-bottom: var(--space-3);
    font-size: var(--text-sm);
    color: var(--color-ink-light);
    text-align: center;
  }

  .prayer-request__form {
    display: grid;
    gap: var(--space-2);
  }

  .prayer-request__field {
    display: grid;
    gap: 0.35rem;
  }

  .prayer-request__field input,
  .prayer-request__field textarea {
    width: 100%;
  }

  .prayer-request__field textarea {
    resize: vertical;
    min-height: 7rem;
  }

  .prayer-request__submit {
    justify-self: start;
  }

  /* Honeypot (see _prayer_request_form.html.erb). Kept in the layout and
     merely clipped rather than `display: none` -- some bots skip fields
     that are display:none, which would defeat the trap. */
  .prayer-request__nickname {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .commission-show-content {
    padding-inline: 1.5rem;
  }

  @media (min-width: 641px) {
    .commission-show-content {
      padding-inline: 4rem;
    }

    .commission-show-content p {
      max-width: none;
    }
  }

  /* Override the global p { max-width: 70ch } cap so paragraphs stretch to
     the full content width instead of stopping partway across the page. */
  .about-content p {
    max-width: none;
  }

  a {
    color: var(--color-link);
  }

  a:hover {
    color: var(--color-gold-dark);
  }

  /* Animated hover underline for plain text/nav links (navbar, prose, footer).
     Scoped to unclassed <a> tags so card/button links (which style themselves
     via a class and already set text-decoration: none) are left untouched. */
  a:not([class]) {
    position: relative;
  }

  a:not([class])::after {
    content: "";
    position: absolute;
    left: 0;
    bottom: -0.15em;
    width: 100%;
    height: 1px;
    background: currentColor;
    transform: scaleX(0);
    transform-origin: right;
    transition: transform 0.2s ease;
  }

  a:not([class]):hover::after,
  a:not([class]):focus-visible::after {
    transform: scaleX(1);
    transform-origin: left;
  }

  ul {
    padding-left: 1.25rem;
  }

  li {
    margin-bottom: var(--space-1);
  }

  *:focus-visible {
    outline: 2px solid var(--color-gold);
    outline-offset: 2px;
  }
}

@layer layout {
  .site-header {
    /* Sky-blue vertical gradient: darker at the top, lighter toward the
       bottom. --color-header (#0284C7) is kept as the mid-tone and still
       drives the mobile drawer, so the drawer reads as part of the header. */
    background: linear-gradient(180deg, #0369A1 0%, var(--color-header) 50%, #38BDF8 100%);
    position: sticky;
    top: 0;
    z-index: 30;
    box-shadow: var(--shadow-sm);
    overflow: visible;
  }

  .site-nav {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding: var(--space-2) var(--space-3);
    height: 4.75rem;
    padding-block: 0;
    flex-wrap: wrap;
  }

  .site-nav .brand {
    display: flex;
    align-items: center;
    gap: 0.65rem;
    text-decoration: none;
  }

  .brand__logo {
    height: 5.5rem;
    width: auto;
    flex-shrink: 0;
  }

  .brand__name {
    font-weight: 700;
    font-size: var(--text-base);
    color: #fff;
    letter-spacing: 0.01em;
    line-height: 1.25;
  }

  .brand__sub {
    font-weight: 400;
    font-size: 1.6rem;
    color: var(--color-gold-light);
    letter-spacing: 0.02em;
  }

  .nav-links {
    display: flex;
    gap: var(--space-3);
    flex-wrap: wrap;
  }

  .nav-links a {
    color: #fff;
    font-size: var(--text-sm);
    font-weight: 700;
    transition: color 0.15s;
  }

  .nav-links a:hover {
    color: var(--color-gold);
  }

  /* "SEKOLAH " prefix on the Maranatha link. Visible by default (the mobile
     drawer, which has the width for the full name) and dropped from 801px
     up, where the horizontal bar is tight and "MARANATHA" alone is enough.
     Default-visible on purpose: if this rule ever fails to load, the link
     falls back to the complete school name rather than a truncated one.
     Keep the 800px boundary in sync with the drawer's own breakpoint. */
  @media (min-width: 801px) {
    .nav-link__prefix {
      display: none;
    }
  }

  .nav-overlay {
    display: none;
  }

  .nav-drawer-logo {
    display: none;
  }

  .nav-verse {
    display: none;
  }

  @media (max-width: 800px) {
    .site-nav {
      position: relative;
      height: auto;
      padding-block: var(--space-1);
      flex-wrap: nowrap;
    }

    .brand__logo {
      height: 3rem;
    }

    .brand__name {
      font-size: var(--text-sm);
    }

    .brand__sub {
      font-size: var(--text-xs);
    }

    .nav-overlay {
      display: block;
      position: fixed;
      inset: 0;
      background: rgba(0, 0, 0, 0.45);
      opacity: 0;
      pointer-events: none;
      transition: opacity 0.2s;
      z-index: 35;
    }

    .nav-overlay.is-open {
      opacity: 1;
      pointer-events: auto;
    }

    /* Same sky blue as .site-header (var(--color-header)) so the open
       drawer reads as an extension of the header, not a separate white
       sheet. Slide (transform) is paired with a fade + slight scale for a
       softer, less mechanical open/close than a plain translateX -- and
       each link fades/slides in with its own stagger delay (below) so
       opening the drawer reveals the menu one row after another. */
    .nav-links {
      position: fixed;
      inset-block: 0;
      left: 0;
      width: min(80vw, 300px);
      display: flex;
      flex-direction: column;
      /* Reset the desktop rule's flex-wrap: wrap (base .nav-links above) --
         left as-is here, a column-direction flex container that overflows
         its fixed height wraps into a second side-by-side column instead
         of just growing past the container, which is exactly wrong for an
         off-canvas drawer: it should never grow sideways, only scroll. */
      flex-wrap: nowrap;
      align-items: stretch;
      gap: 0;
      background: var(--color-header);
      box-shadow: 2px 0 16px rgba(0, 0, 0, 0.2);
      transform: translateX(-100%) scale(0.96);
      opacity: 0;
      transition: transform 0.35s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.3s ease;
      z-index: 40;
      overflow-x: hidden;
      overflow-y: auto;
      padding: 3.5rem var(--space-2) var(--space-2);
    }

    .nav-drawer-logo {
      display: block;
      position: absolute;
      top: 0.5rem;
      left: 1rem;
      height: 2.5rem;
      width: auto;
    }

    .nav-links.is-open {
      transform: translateX(0) scale(1);
      opacity: 1;
    }

    /* The logout button is a <button class="nav-logout-btn"> wrapped in an
       auto-generated <form> (button_to) -- the form, not the button, is
       the actual flex item inside .nav-links, so alignment/spacing goes
       here rather than on .nav-logout-btn itself. text-align: center
       centers the button (inline-flex, sized to its own text -- see the
       base .nav-logout-btn rule, and the display: block override for this
       same selector in the @layer components section below) inside the
       form. The auto top margin (matching .nav-verse below) pushes it
       down away from "PENGURUS" into the drawer's lower half instead of
       sitting right under it.

       display/width/max-width for this form are NOT set here: this block
       is inside @layer layout, and the global `form { display: flex;
       ... }` reset ("Forms" section below) lives in @layer components --
       later in the @layer reset,base,layout,components,utilities
       declaration at the top of this file, so it wins outright regardless
       of specificity. That override lives with the rest of the
       .nav-logout-btn rules in @layer components instead (search
       "blockifies"). */
    .nav-links form {
      margin-top: auto;
      text-align: center;
    }

    .nav-links a {
      width: 100%;
      color: #fff;
      padding: var(--space-2) var(--space-3);
      border-bottom: 1px solid rgba(255, 255, 255, 0.2);
      transition: background-color 0.15s ease, opacity 0.3s ease, transform 0.3s ease;
      opacity: 0;
      transform: translateX(-14px);
    }

    .nav-links a:hover {
      background: rgba(255, 255, 255, 0.12);
    }

    .nav-links a:active,
    .nav-links a.is-pressed {
      background: rgba(255, 255, 255, 0.22);
      transition-duration: 0.05s;
    }

    .nav-links.is-open a {
      opacity: 1;
      transform: translateX(0);
    }

    .nav-links.is-open a:nth-child(1) { transition-delay: 0.08s; }
    .nav-links.is-open a:nth-child(2) { transition-delay: 0.13s; }
    .nav-links.is-open a:nth-child(3) { transition-delay: 0.18s; }
    .nav-links.is-open a:nth-child(4) { transition-delay: 0.23s; }
    .nav-links.is-open a:nth-child(5) { transition-delay: 0.28s; }
    .nav-links.is-open a:nth-child(6) { transition-delay: 0.33s; }
    .nav-links.is-open a:nth-child(7) { transition-delay: 0.38s; }
    .nav-links.is-open a:nth-child(8) { transition-delay: 0.43s; }
    .nav-links.is-open a:nth-child(9) { transition-delay: 0.48s; }

    /* Verse footer under the last drawer link (LOGIN, or Logout when
       signed in). margin-top: auto pins it to the bottom of the drawer's
       flex column on short menus (guest with few links) instead of
       trailing right under the last link; on long menus (many open
       meetings) it just falls in normal flow after everything else and
       scrolls with the rest. Both lines are forced onto a single line
       (white-space: nowrap) with a vw-based clamp() font-size instead of a
       fixed size, so they shrink to fit the ~80vw-wide drawer on narrow
       phones rather than wrapping or clipping. */
    .nav-verse {
      display: block;
      margin-top: auto;
      padding: var(--space-3) var(--space-2) var(--space-1);
      text-align: center;
    }

    .nav-verse__zh {
      font-family: "Playfair Display", var(--font-sans);
      font-weight: 600;
      color: #fff;
      white-space: nowrap;
      font-size: clamp(0.8rem, 4.5vw, 1.1rem);
      letter-spacing: 0.04em;
      margin: 0 0 0.35rem;
    }

    .nav-verse__en {
      font-family: "Quicksand", var(--font-sans);
      font-style: italic;
      color: rgba(255, 255, 255, 0.85);
      white-space: nowrap;
      font-size: clamp(0.5rem, 3vw, 0.75rem);
      margin: 0;
    }
  }

  .container {
    max-width: var(--max-width);
    margin-inline: auto;
    padding: var(--space-4) var(--space-3);
  }

  .pengurus-main {
    max-width: var(--max-width);
    margin-inline: auto;
    padding-inline: var(--space-3);
  }

  /* Dua chart laporan: berdampingan di desktop -- saldo kiri, kehadiran kanan
     -- dan bertumpuk di layar sempit. Batas 801px sama dengan yang dipakai
     report_charts_controller.js untuk memutuskan label saldo tampil.

     Ditulis sebagai kelas, bukan style="" di partialnya: CSP style-src app ini
     tidak memuat 'unsafe-inline', jadi atribut style dibuang browser dan
     layoutnya tidak pernah benar-benar berlaku. */
  .report-charts {
    display: grid;
    gap: var(--space-4);
    margin: var(--space-2) 0;
  }

  @media (min-width: 801px) {
    .report-charts {
      grid-template-columns: 1fr 1fr;
    }
  }

  .report-charts__title {
    margin-bottom: var(--space-1);
  }

  /* Tinggi dipatok di sini, dan Chart.js jalan dengan maintainAspectRatio:
     false, supaya ruang chart sudah terpesan sebelum digambar. Tanpa itu
     kanvas mulai dari 300x150 bawaan lalu melar sendiri, dan seluruh isi
     halaman di bawahnya melompat turun. `position: relative` diminta Chart.js
     untuk mengukur induknya. */
  .report-charts__canvas {
    position: relative;
    height: 240px;
  }

  @media (min-width: 801px) {
    .report-charts__canvas {
      height: 300px;
    }
  }

  .site-footer {
    /* Light, airy blue gradient continuing the Hamba Tuhan section above it
       (starts on the same #C9E0F6) down to a slightly deeper sky blue --
       margin-top: 0 so the two gradients meet with no gap. Text is dark navy
       (set below) since the background is now light; the brand-coloured
       social SVGs stay legible on it as-is. */
    background: linear-gradient(180deg, #5E92C8 0%, #2C588C 100%);
    color: rgba(255, 255, 255, 0.85);
    margin-top: 0;
  }

  .footer-inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    padding-block: var(--space-3);
    flex-wrap: wrap;
  }

  .footer-social {
    display: flex;
    gap: var(--space-2);
    align-items: center;
  }

  .footer-social__link {
    display: flex;
    align-items: center;
    justify-content: center;
    transition: opacity 0.15s, transform 0.15s;
  }

  .footer-social__link:hover {
    opacity: 0.8;
    transform: translateY(-2px);
  }

  .footer-social__icon {
    width: 2rem;
    height: 2rem;
  }

  .footer-brand {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 0.6rem;
    flex-wrap: wrap;
  }

  .footer-brand__logo {
    height: 2rem;
    width: auto;
    opacity: 0.85;
    flex-shrink: 0;
  }

  .footer-brand__copy {
    color: rgba(255, 255, 255, 0.92);
    font-size: var(--text-sm);
    font-weight: 600;
    margin: 0;
    white-space: nowrap;
  }

  .footer-brand__detail {
    color: rgba(255, 255, 255, 0.72);
    font-size: var(--text-xs);
    margin: 0;
  }

  .footer-brand__detail a {
    color: rgba(255, 255, 255, 0.72);
  }

  .footer-brand__detail a:hover {
    color: var(--color-gold-light);
  }

  .site-footer p {
    color: rgba(255, 255, 255, 0.82);
    margin: 0;
  }

  .site-footer a {
    color: rgba(255, 255, 255, 0.72);
    font-size: var(--text-xs);
  }

  .site-footer a:hover {
    color: var(--color-gold-light);
  }
}

@layer components {
  /* Hero slideshow: each .hero__slide is a full-bleed <img> + dark overlay,
     crossfaded by toggling .is-active (see hero_slideshow_controller.js).
     Rendered via <img>, not a CSS background-image -- Propshaft 1.3.2 has
     no ERB/asset_path support inside .css files, and an inline
     style="background-image: url("...")" attribute would be silently
     dropped by the strict style-src CSP (no `unsafe-inline`). The first
     slide ships server-rendered with .is-active, so the hero still shows
     one photo correctly before/without JS. */
  .hero {
    position: relative;
    min-height: 100dvh;
    color: #fff;
    overflow: hidden;
    background: var(--color-navy-dark);
  }

  @media (max-width: 800px) {
    .hero {
      /* Plain 50dvh clips text on short viewports (landscape phones, a
         squeezed browser window, devtools' responsive mode) since it
         shrinks with the viewport with no floor -- 400px guarantees room
         for a 3-line title + subtitle + button regardless of how short the
         viewport gets, while still landing at roughly half height on a
         normal phone. */
      min-height: max(50dvh, 400px);
    }
  }

  .hero__slide {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    opacity: 0;
    pointer-events: none;
    z-index: 0;
  }

  .hero__slide.is-active {
    opacity: 1;
    pointer-events: auto;
    z-index: 2;
    /* Defined only here, not on the base rule -- the outgoing slide never
       transitions opacity at all (see .was-active below), so the only
       animated change is this 0->1 entrance. */
    transition: opacity 1.1s cubic-bezier(0.16, 1, 0.3, 1);
  }

  /* The slide just replaced (see hero_slideshow_controller.js): held fully
     opaque and untransitioned, one z-index below the incoming slide's
     fade-in, so it acts as a solid backdrop rather than also fading out.
     Without this, both slides were semi-transparent at once and .hero's
     navy background briefly showed through both midway through every
     crossfade -- a flash/dip that read as not-smooth. Removed once the
     fade-in completes. */
  .hero__slide.was-active {
    opacity: 1;
    z-index: 1;
  }

  .hero__slide::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(10, 20, 35, 0.45), rgba(10, 20, 35, 0.8));
  }

  /* No text overlay on this slide (e.g. a designed announcement graphic
     that already contains its own text) -- skip the dark gradient so it
     doesn't muddy the image's own design. */
  .hero__slide--plain::after {
    display: none;
  }

  .hero__image {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center 35%;
  }

  /* Slow Ken Burns drift while a slide is active -- purely decorative, so it
     only runs when motion is welcome; reduced-motion users get a static
     image (the crossfade in .hero__slide itself still applies either way). */
  @media (prefers-reduced-motion: no-preference) {
    @keyframes hero-kenburns {
      from { transform: scale(1); }
      to   { transform: scale(1.08); }
    }

    .hero__slide.is-active .hero__image {
      animation: hero-kenburns 9s ease-out forwards;
    }
  }

  /* Plain slides are designed announcement graphics with their own baked-in
     text (see the comment on .hero__slide--plain::after above). Fills the
     hero edge-to-edge on every device instead of letterboxing -- this
     crops whatever falls outside the hero's aspect ratio at a given
     viewport, so the poster's own design must keep important text (times,
     dates) in a centered "safe zone" rather than near the edges. */
  .hero__slide--plain .hero__image {
    object-fit: cover;
    object-position: center;
  }

  .hero__content {
    position: relative;
    z-index: 1;
  }

  /* Same Playfair Display + navy/gold vocabulary as .pastor-section__heading
     and .section-seal__title, so the two slides with real title/subtitle
     text (church building, school) read as this site's typography instead
     of generic bold system-sans. text-shadow keeps it legible over
     whatever photo a future slide uses, on top of .hero__slide::after's
     dark gradient. */
  .hero h1 {
    color: #fff;
    font-family: "Playfair Display", var(--font-sans);
    font-weight: 600;
    font-size: var(--text-3xl);
    letter-spacing: 0.01em;
    max-width: 24ch;
    text-shadow: 0 2px 14px rgba(0,0,0,0.55);
  }

  .hero p {
    color: rgba(255, 255, 255, 0.88);
    font-size: var(--text-lg);
    max-width: 48ch;
    text-shadow: 0 1px 8px rgba(0,0,0,0.5);
  }

  .cta-group {
    display: flex;
    gap: var(--space-2);
    margin-top: var(--space-3);
    flex-wrap: wrap;
  }

  /* Must come after the unconditional .hero h1/.hero p/.cta-group rules
     above -- same specificity, so an earlier position would lose the
     cascade on every viewport width, not just desktop. Shrinks the text
     overlay to fit the shorter mobile hero (see the min-height override
     above) and tightens the gaps so long titles/subtitles stop getting
     clipped by .hero's overflow: hidden. */
  @media (max-width: 800px) {
    .hero h1 {
      font-size: 1.5rem;
      margin-bottom: var(--space-1);
    }

    .hero p {
      font-size: var(--text-sm);
      margin-bottom: var(--space-1);
      /* Lets a literal newline in slide.subtitle force a line break here
         (e.g. avoiding an awkward mid-word wrap) without affecting desktop,
         where the same newline just collapses to a space as normal. */
      white-space: pre-line;
    }

    .hero .cta-group {
      margin-top: var(--space-1);
    }

    /* Slide-specific: this CTA sits right under a two-line subtitle and
       reads as cramped at this margin, unlike the other slides -- pushed
       down further on mobile only, per request. Scoped to the slide's own
       dom_id (not .hero__slide:nth-of-type) so it stays correct if slides
       get reordered or others are added/removed via the admin panel. */
    #hero_slide_3 .cta-group {
      margin-top: var(--space-6);
    }
  }

  /* Prev/next + dots, scoped under .hero so they out-specificity the
     generic `button:not(.btn)` rule below without relying on source order. */
  .hero .hero__nav {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    z-index: 2;
    width: 2.75rem;
    height: 2.75rem;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(0, 0, 0, 0.35);
    color: #fff;
    border: none;
    border-radius: 50%;
    font-size: 1.6rem;
    line-height: 1;
    cursor: pointer;
    transition: background 0.15s;
  }

  .hero .hero__nav:hover {
    background: rgba(0, 0, 0, 0.55);
  }

  .hero .hero__nav--prev { left: var(--space-3); }
  .hero .hero__nav--next { right: var(--space-3); }

  .hero__dots {
    position: absolute;
    bottom: var(--space-4);
    left: 50%;
    transform: translateX(-50%);
    z-index: 2;
    display: flex;
    gap: 0.6rem;
  }

  .hero .hero__dot {
    width: 0.65rem;
    height: 0.65rem;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.45);
    cursor: pointer;
    transition: background 0.15s, transform 0.15s;
  }

  .hero .hero__dot.is-active {
    background: var(--color-gold);
    transform: scale(1.3);
  }

  /* POS PI photo slideshow, below the page banner -- same crossfade
     behavior and hero-slideshow Stimulus controller as .hero, but a
     moderate in-page size instead of full-bleed, and plain photos with no
     text overlay. */
  .pos-pi-slideshow {
    position: relative;
    height: clamp(280px, 50vw, 600px);
    overflow: hidden;
    background: var(--color-navy-dark);
    border-radius: 0;
    margin: 0 0 var(--space-4);
  }

  .pos-pi-slideshow__slide {
    position: absolute;
    inset: 0;
    opacity: 0;
    pointer-events: none;
    transition: opacity 1s ease;
  }

  .pos-pi-slideshow__slide.is-active {
    opacity: 1;
    pointer-events: auto;
    z-index: 1;
  }

  .pos-pi-slideshow__image {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  /* Ancestor-scoped (two classes) so this out-specificities the generic
     `button:not(.btn)` reset below, same trick as `.hero .hero__nav`. */
  .pos-pi-slideshow .pos-pi-slideshow__nav {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    z-index: 2;
    width: 2.75rem;
    height: 2.75rem;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(0, 0, 0, 0.35);
    color: #fff;
    border: none;
    border-radius: 50%;
    font-size: 1.6rem;
    line-height: 1;
    cursor: pointer;
    transition: background 0.15s;
  }

  .pos-pi-slideshow .pos-pi-slideshow__nav:hover {
    background: rgba(0, 0, 0, 0.55);
  }

  .pos-pi-slideshow__nav--prev { left: var(--space-3); }
  .pos-pi-slideshow__nav--next { right: var(--space-3); }

  .pos-pi-slideshow__dots {
    position: absolute;
    bottom: var(--space-3);
    left: 50%;
    transform: translateX(-50%);
    z-index: 2;
    display: flex;
    gap: 0.6rem;
  }

  .pos-pi-slideshow .pos-pi-slideshow__dot {
    width: 0.65rem;
    height: 0.65rem;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.45);
    cursor: pointer;
    transition: background 0.15s, transform 0.15s;
  }

  .pos-pi-slideshow .pos-pi-slideshow__dot.is-active {
    background: var(--color-gold);
    transform: scale(1.3);
  }

  /* SKM Show: photo slideshow below the social row on the Sekolah
     Maranatha page. Same crossfade behavior as .pos-pi-slideshow, but the
     frame keeps a fixed 16:9 aspect ratio instead of a clamped height. */
  .school-show-slideshow {
    margin-top: var(--space-2);
    margin-bottom: var(--space-2);
  }

  @media (min-width: 641px) {
    .school-show-slideshow {
      margin-top: var(--space-4);
      margin-bottom: var(--space-4);
    }
  }

  .school-show-slideshow__frame {
    position: relative;
    aspect-ratio: 16 / 9;
    overflow: hidden;
    background: var(--color-navy-dark);
    border-radius: var(--radius-lg);
  }

  .school-show-slideshow__slide {
    position: absolute;
    inset: 0;
    opacity: 0;
    pointer-events: none;
    transition: opacity 1s ease;
  }

  .school-show-slideshow__slide.is-active {
    opacity: 1;
    pointer-events: auto;
    z-index: 1;
  }

  .school-show-slideshow__image {
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  .school-show-slideshow .school-show-slideshow__nav {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    z-index: 2;
    width: 2.75rem;
    height: 2.75rem;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(0, 0, 0, 0.35);
    color: #fff;
    border: none;
    border-radius: 50%;
    font-size: 1.6rem;
    line-height: 1;
    cursor: pointer;
    transition: background 0.15s;
  }

  .school-show-slideshow .school-show-slideshow__nav:hover {
    background: rgba(0, 0, 0, 0.55);
  }

  .school-show-slideshow__nav--prev { left: var(--space-3); }
  .school-show-slideshow__nav--next { right: var(--space-3); }

  .school-show-slideshow__dots {
    position: absolute;
    bottom: var(--space-3);
    left: 50%;
    transform: translateX(-50%);
    z-index: 2;
    display: flex;
    gap: 0.6rem;
  }

  .school-show-slideshow .school-show-slideshow__dot {
    width: 0.65rem;
    height: 0.65rem;
    padding: 0;
    border: none;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.45);
    cursor: pointer;
    transition: background 0.15s, transform 0.15s;
  }

  .school-show-slideshow .school-show-slideshow__dot.is-active {
    background: var(--color-gold);
    transform: scale(1.3);
  }

  /* YouTube embed shown above the poster sections on the POS PI page. */
  .pos-pi-video {
    position: relative;
    aspect-ratio: 16 / 9;
    max-width: 60rem;
    margin: var(--space-4) auto;
    border-radius: var(--radius-lg);
    overflow: hidden;
    background: var(--color-navy-dark);
  }

  .pos-pi-video iframe {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border: none;
  }

  /* Two manually-uploaded photos (poster_left/poster_right) shown side by
     side below the POS PI slideshow. Either one can be attached alone --
     the grid still lays out correctly with a single column filled. */
  .pos-pi-photo-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-3);
    margin: var(--space-4) 0;
    /* The gap only separates the two columns from each other; without this
       the pair still runs edge to edge. Same gutter as .schedule-poster
       below it, so the two posters share one left/right line. */
    padding-inline: var(--space-3);
  }

  /* Portrait aspect-ratio (not a viewport-width-driven height) so each
     column stays tall/elongated relative to its own width at any screen
     size -- a wide desktop column doesn't flatten out the way a fixed
     vw-based height would. */
  .pos-pi-photo-grid__image {
    width: 100%;
    aspect-ratio: 3 / 4;
    object-fit: cover;
    border-radius: var(--radius-lg);
  }

  .pos-pi-address {
    margin: var(--space-4) 0;
  }

  @media (min-width: 641px) {
    .pos-pi-address {
      font-size: var(--text-lg);
    }
  }

  /* Sekolah Maranatha page: autoplaying/looping hero video below the header,
     with a title + tagline overlaid on top (dark gradient for legibility
     over the moving footage, mirroring .page-hero's overlay treatment). */
  .school-hero-video {
    position: relative;
    width: 100%;
    aspect-ratio: 16 / 9;
    overflow: hidden;
    background: var(--color-navy-dark);
  }

  .school-hero-video__video {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  .school-hero-video__overlay {
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(10, 20, 35, 0.35), rgba(10, 20, 35, 0.75));
  }

  .school-hero-video__logo {
    position: absolute;
    top: var(--space-3);
    right: var(--space-3);
    z-index: 1;
    width: 3.5rem;
    height: auto;
    filter: drop-shadow(0 1px 6px rgba(0,0,0,0.6));
  }

  @media (min-width: 641px) {
    .school-hero-video__logo {
      width: 6rem;
    }
  }

  .school-hero-video__content {
    position: absolute;
    inset: 0;
    z-index: 1;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: flex-end;
    gap: var(--space-1);
    text-align: left;
    padding: var(--space-3);
  }

  .school-hero-video__content h1 {
    color: #fff;
    font-size: clamp(1.5rem, 6vw, 4.5rem);
    margin: 0;
    text-shadow: 0 1px 6px rgba(0,0,0,0.6);
  }

  .school-hero-video__content h2 {
    color: #fff;
    font-size: clamp(1rem, 3.5vw, var(--text-xl));
    font-weight: 400;
    margin: 0;
    text-shadow: 0 1px 6px rgba(0,0,0,0.6);
  }

  @media (min-width: 641px) {
    .school-hero-video__content {
      padding-bottom: 8rem;
    }

    .school-hero-video__content h2 {
      font-size: var(--text-3xl);
    }
  }

  /* Scripture verse centered below the Sekolah Maranatha hero video. */
  .school-verse {
    text-align: center;
    max-width: 42rem;
    padding-bottom: var(--space-2);
  }

  @media (min-width: 641px) {
    .school-verse {
      padding-bottom: var(--space-4);
    }
  }

  .school-verse__zh {
    font-size: clamp(0.7rem, 4vw, var(--text-base));
    font-weight: 600;
    color: var(--color-heading);
    margin: 0 0 var(--space-1);
    white-space: nowrap;
  }

  .school-verse__en {
    font-family: "Quicksand", var(--font-sans);
    font-size: var(--text-sm);
    font-style: italic;
    color: var(--color-ink-light);
    margin: 0;
  }

  .school-verse__en cite {
    font-style: normal;
  }

  .school-verse__social {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--space-2);
    margin-top: var(--space-2);
  }

  .school-verse__social-label {
    font-weight: 700;
    letter-spacing: 0.04em;
    color: var(--color-heading);
    font-size: var(--text-sm);
  }

  .school-verse__social-link {
    display: flex;
    align-items: center;
    justify-content: center;
    transition: opacity 0.15s, transform 0.15s;
  }

  .school-verse__social-link:hover {
    opacity: 0.8;
    transform: translateY(-2px);
  }

  .school-verse__social-icon {
    width: 1.75rem;
    height: 1.75rem;
  }

  @media (min-width: 641px) {
    .school-verse__zh {
      font-size: var(--text-xl);
    }

    .school-verse__en {
      font-size: var(--text-lg);
    }
  }

  /* Jenjang Pendidikan timeline: photo left, description right, a dot +
     animated connecting line runs down the middle between levels. */
  .school-levels {
    --school-levels-gap: var(--space-6);
    padding-top: var(--space-2);
  }

  @media (min-width: 641px) {
    .school-levels {
      padding-top: var(--space-4);
    }
  }

  .school-levels__list {
    display: flex;
    flex-direction: column;
    gap: var(--school-levels-gap);
    margin-top: var(--space-3);
  }

  .school-level {
    display: flex;
    align-items: flex-start;
    gap: var(--space-2);
  }

  .school-level__image-wrap {
    flex: 0 0 6rem;
    width: 6rem;
    aspect-ratio: 4 / 3;
    border-radius: var(--radius);
    overflow: hidden;
    box-shadow: var(--shadow-md);
  }

  .school-level__image {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  .school-level__track {
    position: relative;
    flex: 0 0 auto;
    width: 1rem;
    align-self: stretch;
    display: flex;
    justify-content: center;
  }

  .school-level__dot {
    width: 12px;
    height: 12px;
    margin-top: 0.35rem;
    border-radius: 50%;
    background: var(--color-gold);
    box-shadow: 0 0 0 3px var(--color-gold-light);
    position: relative;
    z-index: 1;
    opacity: 1;
    transform: scale(1);
    transition: opacity 0.4s ease, transform 0.4s ease;
  }

  .school-level__line {
    position: absolute;
    top: 0.85rem;
    bottom: calc(-1 * var(--school-levels-gap));
    left: 50%;
    width: 2px;
    background-color: var(--color-border);
    background-image: repeating-linear-gradient(
      to bottom,
      var(--color-gold) 0,
      var(--color-gold) 8px,
      transparent 8px,
      transparent 16px
    );
    background-size: 100% 16px;
    animation: school-level-line-march 0.8s linear infinite;
    transform: translateX(-50%) scaleY(1);
    transform-origin: top;
    transition: transform 0.8s ease;
  }

  @keyframes school-level-line-march {
    from { background-position-y: 0; }
    to { background-position-y: 16px; }
  }

  /* Without JS, the timeline renders fully visible (progressive
     enhancement). The controller adds .will-animate on connect, which is
     what actually hides items for the scroll-reveal to animate into. */
  .school-level.will-animate .school-level__dot {
    opacity: 0;
    transform: scale(0.4);
  }

  .school-level.will-animate .school-level__line {
    transform: translateX(-50%) scaleY(0);
  }

  .school-level.will-animate.is-visible .school-level__dot {
    opacity: 1;
    transform: scale(1);
  }

  .school-level.will-animate.is-visible .school-level__line {
    transform: translateX(-50%) scaleY(1);
  }

  .school-level__content {
    flex: 1 1 auto;
    min-width: 0;
  }

  .school-level__title {
    margin: 0 0 0.2rem;
    font-size: var(--text-base);
  }

  .school-level__subtitle {
    margin: 0 0 0.4rem;
    font-size: var(--text-xs);
    color: var(--color-ink-light);
  }

  .school-level__desc {
    margin: 0;
    font-size: var(--text-sm);
    color: var(--color-ink-light);
    text-align: justify;
  }

  @media (min-width: 641px) {
    .school-level {
      gap: calc(var(--space-6) * 2);
    }

    .school-level__image-wrap {
      flex-basis: 24rem;
      width: 24rem;
    }

    .school-level__title {
      font-size: var(--text-lg);
    }

    .school-level__subtitle {
      font-size: var(--text-sm);
    }

    .school-level__desc {
      font-size: var(--text-base);
    }
  }

  @media (prefers-reduced-motion: reduce) {
    .school-level__dot,
    .school-level__line {
      transition-duration: 0.01ms;
    }

    .school-level__line {
      animation: none;
    }
  }

  .school-whatsapp-heading,
  .school-whatsapp {
    margin-left: 1.5rem;
  }

  .school-whatsapp-heading {
    font-size: var(--text-base);
  }

  @media (min-width: 641px) {
    .school-whatsapp-heading {
      font-size: var(--text-xl);
    }

    .school-whatsapp-heading,
    .school-whatsapp {
      margin-left: 4rem;
    }
  }

  /* WhatsApp number below Jenjang Pendidikan, links out to wa.me. */
  .school-whatsapp__link {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    color: var(--color-ink);
    transition: opacity 0.15s;
  }

  .school-whatsapp__link:hover {
    opacity: 0.75;
  }

  .school-whatsapp__icon {
    width: 1.25rem;
    height: 1.25rem;
    flex-shrink: 0;
  }

  /* Floating WhatsApp button, Maranatha page only (pages/school.html.erb).
     Sits below the sticky header (z-index 30) and the mobile drawer/overlay
     (35/40) so an open menu covers it instead of the badge poking through. */
  .school-whatsapp-fab {
    position: fixed;
    right: var(--space-3);
    bottom: var(--space-3);
    z-index: 25;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 3.5rem;
    height: 3.5rem;
    border-radius: 50%;
    background: #25D366;
    color: #fff;
    box-shadow: var(--shadow-md);
    transition: transform 0.15s, box-shadow 0.15s;
  }

  .school-whatsapp-fab:hover {
    transform: scale(1.06);
    box-shadow: var(--shadow-lg);
  }

  .school-whatsapp-fab__icon {
    width: 1.875rem;
    height: 1.875rem;
    flex-shrink: 0;
  }

  @media (max-width: 640px) {
    .school-whatsapp-fab {
      right: var(--space-2);
      bottom: var(--space-2);
      width: 3.25rem;
      height: 3.25rem;
    }

    .school-whatsapp-fab__icon {
      width: 1.75rem;
      height: 1.75rem;
    }
  }

  @media (prefers-reduced-motion: reduce) {
    .school-whatsapp-fab {
      transition-duration: 0.01ms;
    }

    .school-whatsapp-fab:hover {
      transform: none;
    }
  }

  /* Static page banner (e.g. Kontak & Lokasi) -- a shorter, non-slideshow
     sibling of .hero: one fixed image with a dark overlay and a title. */
  .page-hero {
    position: relative;
    height: clamp(110px, 14vw, 170px);
    color: #fff;
    overflow: hidden;
    background: var(--color-navy-dark);
  }

  .page-hero__image {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
  }

  .page-hero::after {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(180deg, rgba(10, 20, 35, 0.45), rgba(10, 20, 35, 0.8));
  }

  /* Plain banner: a decorative photo/graphic with no CSS-rendered title on
     top of it (e.g. the "Tentang Kami" banner) -- skip the dark overlay so
     it doesn't muddy the image, and crop (not stretch) to fill the short,
     ultra-wide banner without distorting its proportions. */
  .page-hero--plain::after {
    display: none;
  }

  .page-hero--plain .page-hero__image {
    object-fit: cover;
  }

  .page-hero__content {
    position: relative;
    z-index: 1;
    height: 100%;
    display: flex;
    align-items: center;
  }

  /* Judul di atas banner yang harus lurus dengan tepi header. .container
     memberi padding tepi yang benar, tapi max-width 72rem-nya memusatkan
     diri di layar lebar -- di 1920px judulnya terdorong ke 401px, jauh dari
     logo di 24px. Modifier ini melepas pemusatan itu dan memakai padding
     tepi yang sama dengan .site-nav. */
  .page-hero__content--flush {
    padding-inline: var(--space-3);
  }

  .page-hero h1 {
    color: #fff;
    font-size: 2rem;
    margin: 0;
  }

  .page-hero__title--kontak {
    text-transform: uppercase;
  }

  /* Judul halaman yang tampil tanpa banner (POS PI sebelum gambar hero
     di-upload). Sengaja bukan .container: max-width 72rem itu memusatkan
     diri di layar lebar, jadi judulnya terseret jauh ke tengah. Padding
     tepi ini sama dengan .site-nav, sehingga judulnya lurus dengan logo
     di header. */
  .page-title-standalone {
    padding: var(--space-4) var(--space-3);
  }

  @media (max-width: 640px) {
    /* Sama spesifiknya dengan `.page-hero h1` di atas -- ditulis sebagai
       `.page-hero__title--pos-pi` saja aturan ini kalah dan judul di dalam
       banner tetap 2rem, lalu pecah dua baris di layar 390px. */
    .page-hero h1.page-hero__title--pos-pi,
    .page-title-standalone .page-hero__title--pos-pi {
      font-size: 1.3rem;
    }

    .page-hero__title--kontak {
      font-size: 1.6rem;
      white-space: nowrap;
    }
  }

  /* Desktop: judul POS PI lurus dengan tulisan "GKKB JEMAAT SIANTAN" di
     header, bukan dengan tepi logonya. Inset-nya = padding .site-nav
     (1.5rem) + lebar logo pada tinggi 5.5rem (8.17rem, hasil rasio
     gambarnya) + gap .brand (0.65rem). Kalau logo atau tingginya diganti,
     angka 8.17rem ikut disetel ulang. Mobile sengaja tidak ikut: di layar
     390px inset selebar itu tidak menyisakan ruang untuk judulnya. */
  @media (min-width: 641px) {
    .page-hero__content--flush,
    .page-title-standalone {
      padding-inline-start: calc(var(--space-3) + 8.17rem + 0.65rem);
    }

    .page-hero h1.page-hero__title--pos-pi,
    .page-title-standalone .page-hero__title--pos-pi {
      font-size: 2.6rem;
    }
  }

  /* Worship schedule poster */
  .schedule-poster {
    margin: var(--space-4) 0;
    /* Same gutter as .container, so the poster lines up with the headings
       and copy above and below it instead of running to the screen edge.
       Only bites below ~63rem -- past that the image has already hit its
       60rem max-width and sits centred with room to spare.

       This is for pages where the poster is a direct child of <main> (POS
       PI). On the homepage it sits inside .container instead -- see the
       rule below, which takes the gutter back off. */
    padding-inline: var(--space-3);
    text-align: center;
  }

  /* Inside .container the poster has to give up both of its own width
     constraints, or it will not line up with everything else in the column:
     the gutter (or it stacks with the container's and insets the poster 48px
     against the Highlight grid's 24px on mobile) and the 60rem cap (or it
     comes out 960px against the column's 1104px, 72px narrower on each side
     on desktop). The container is already capped at 72rem, so dropping the
     cap here does not let the poster run away on a wide screen.

     Both constraints stay on the base rule rather than moving to a wrapper,
     so a poster dropped outside a container -- POS PI, where it is a direct
     child of <main> -- is still correctly inset and capped on its own. */
  .container .schedule-poster {
    padding-inline: 0;
  }

  .container .schedule-poster__image {
    max-width: none;
  }

  .schedule-poster__image {
    width: 100%;
    max-width: 60rem;
    margin-inline: auto;
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
  }

  /* Homepage "Upcoming Events" section: animated heading + a side-by-side
     row of poster cards, shown above the Penatalayanan poster whenever any
     UpcomingPoster exists (see PagesController#home). */
  .upcoming {
    margin: var(--space-6) 0;
  }

  .upcoming__heading {
    margin: 0 0 var(--space-4);
    text-align: center;
    letter-spacing: 0.02em;
    font-size: clamp(1.9rem, 6vw, 3.5rem);
    line-height: 1.1;
  }

  .upcoming__heading-light {
    color: var(--color-ink-light);
    font-weight: 300;
  }

  .upcoming__heading-bold {
    color: var(--color-ink);
    font-weight: 800;
  }

  .upcoming__row {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--space-4);
  }

  .upcoming__card {
    flex: 0 1 15rem;
    max-width: 18rem;
  }

  .upcoming__image {
    width: 100%;
    height: auto;
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
    transition: transform 0.25s ease, box-shadow 0.25s ease;
  }

  .upcoming__card:hover .upcoming__image {
    transform: translateY(-4px);
    box-shadow: var(--shadow-lg);
  }

  /* Scroll-reveal: each item (heading + every poster/card) starts hidden and
     slides/fades up once reveal_controller adds `is-visible`. Staggered via
     a per-item transition-delay set in JS. Shared across every section that
     opts in via data-controller="reveal" so the whole homepage cascades in
     with one consistent motion instead of some sections popping in flat. */
  .upcoming [data-reveal-target="item"],
  .schedule-poster [data-reveal-target="item"],
  .media-grid [data-reveal-target="item"],
  .hub-card-grid [data-reveal-target="item"] {
    opacity: 0;
    transform: translateY(24px);
    transition: opacity 1s ease, transform 1s ease;
  }

  .upcoming [data-reveal-target="item"].is-visible,
  .schedule-poster [data-reveal-target="item"].is-visible,
  .media-grid [data-reveal-target="item"].is-visible,
  .hub-card-grid [data-reveal-target="item"].is-visible {
    opacity: 1;
    transform: none;
  }

  @media (max-width: 40rem) {
    /* On phones the cards would wrap into a cramped grid; scroll them
       side by side instead so each poster stays big and swipeable. */
    .upcoming__row {
      flex-wrap: nowrap;
      justify-content: flex-start;
      overflow-x: auto;
      scroll-snap-type: x mandatory;
      padding-bottom: var(--space-1);
      -webkit-overflow-scrolling: touch;
    }

    .upcoming__card {
      flex: 0 0 46%;
      scroll-snap-align: center;
    }
  }

  /* Homepage CTA banner for the Biodata Jemaat form -- only rendered when
     at least one of the 5 forms is aktif (see PagesController#home). */
  .biodata-banner {
    margin: var(--space-6) 0;
    padding: var(--space-4);
    text-align: center;
    background: #6B21A8;
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
  }

  .biodata-banner h2 {
    color: #fff;
    margin-top: 0;
  }

  /* Scales with viewport width so "BIODATA UNTUK GEREJAKU" always fits on
     one line on phones, instead of wrapping at the fixed --text-xl size. */
  @media (max-width: 640px) {
    .biodata-banner h2 {
      font-size: 5.5vw;
      white-space: nowrap;
    }
  }

  .biodata-banner p {
    color: rgba(255, 255, 255, 0.85);
    margin-inline: auto;
  }

  /* Homepage renungan banner (cover + title) shown just above the "Hamba
     Tuhan" slideshow. The whole banner links straight to the PDF; only
     rendered when a complete renungan exists (see Renungan#content_present?).
     The Galeri page reuses the same cover/title in a card (.renungan-card). */
  /* Row holding up to two "dua terbaru" banners side by side on desktop;
     they wrap to a stack on narrow screens. */
  .renungan-banner-row {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--space-4);
    max-width: 60rem;
    margin: var(--space-6) auto;
  }

  .renungan-banner {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    /* Two per row on desktop (each up to ~half); a lone banner caps at the
       same width instead of stretching full. Wraps to full width on phones. */
    flex: 1 1 20rem;
    max-width: 28rem;
    padding: var(--space-3);
    background: var(--color-seal);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
    text-decoration: none;
    color: #fff;
    transition: filter 0.15s, transform 0.15s;

    @media (any-hover: hover) {
      &:hover {
        filter: brightness(1.08);
        transform: translateY(-1px);
        color: #fff;
      }
    }
  }

  .renungan-banner__cover {
    width: 5rem;
    height: 6.5rem;
    flex: 0 0 auto;
    object-fit: cover;
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
  }

  .renungan-banner__body {
    flex: 1 1 auto;
    min-width: 0;
  }

  .renungan-banner__label {
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--color-gold);
  }

  .renungan-banner__title {
    font-size: var(--text-lg);
    font-weight: 700;
    margin: 0.15rem 0 0;
    overflow-wrap: anywhere;
  }

  .renungan-banner__cta {
    flex: 0 0 auto;
    font-weight: 700;
    color: var(--color-gold);
    white-space: nowrap;
  }

  /* Galeri renungan list -- responsive grid of cards (all renungan). */
  .renungan-card-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(22rem, 1fr));
    gap: var(--space-4);
    margin-bottom: var(--space-6);
  }

  /* Renungan card on the public Galeri page -- same cover/title as the
     homepage banner, but with explicit "Baca" and "Download" actions.
     Red background (matching the homepage banner); .btn--outline (white
     outline) stays readable on it. */
  .renungan-card {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    padding: var(--space-4);
    background: #c0392b;
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
    color: #fff;
  }

  .renungan-card__cover {
    width: 6rem;
    height: 8rem;
    flex: 0 0 auto;
    object-fit: cover;
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
  }

  .renungan-card__body {
    flex: 1 1 auto;
    min-width: 0;
  }

  .renungan-card__label {
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--color-gold);
  }

  .renungan-card__title {
    font-size: var(--text-lg);
    margin: 0.15rem 0 var(--space-3);
    color: #fff;
    overflow-wrap: anywhere;
  }

  .renungan-card__actions {
    display: flex;
    gap: var(--space-3);
    flex-wrap: wrap;
  }

  /* Mobile: keep "Baca" and "Download" on one row (shrunk to fit) and make
     the whole card more compact. */
  @media (max-width: 640px) {
    /* Homepage banner: tighten the cover + gap and drop the title a size so a
       short (5-6 char) Chinese title fits on one line instead of wrapping and
       getting clipped. overflow-wrap stays so a long title still wraps. */
    .renungan-banner {
      gap: var(--space-3);
    }

    .renungan-banner__cover {
      width: 4rem;
      height: 5.25rem;
    }

    .renungan-banner__title {
      font-size: var(--text-base);
    }

    .renungan-card {
      gap: var(--space-3);
      padding: var(--space-3);
    }

    .renungan-card__cover {
      width: 4.5rem;
      height: 6rem;
    }

    .renungan-card__title {
      font-size: var(--text-base);
      margin-bottom: var(--space-2);
    }

    .renungan-card__actions {
      flex-wrap: nowrap;
      gap: var(--space-2);
    }

    .renungan-card__actions .btn {
      font-size: var(--text-xs);
      padding: 0.4em 0.7em;
      white-space: nowrap;
    }
  }

  /* Buttons */
  .btn {
    --btn-bg: var(--color-gold);
    --btn-color: var(--color-navy-dark);
    display: inline-flex;
    align-items: center;
    gap: 0.4ch;
    background: var(--btn-bg);
    color: var(--btn-color);
    font-weight: 600;
    font-size: var(--text-sm);
    padding: 0.7em 1.4em;
    border-radius: 999px;
    border: none;
    cursor: pointer;
    transition: filter 0.15s, transform 0.15s;

    @media (any-hover: hover) {
      &:hover {
        filter: brightness(1.08);
        transform: translateY(-1px);
        color: var(--btn-color);
      }
    }
  }

  .btn--sm {
    font-size: var(--text-sm);
    padding: 0.3rem 0.75rem;
  }

  .btn--xs {
    font-size: var(--text-xs);
    padding: 0.2rem 0.5rem;
  }

  .btn--danger {
    --btn-bg: #c0392b;
    --btn-color: #fff;
  }

  .btn--outline {
    --btn-bg: transparent;
    --btn-color: #fff;
    border: 1px solid rgba(255, 255, 255, 0.6);
  }

  /* Secondary/"off" action on a light background (e.g. the admin "Sembunyikan
     dari homepage" toggle) -- navy outline stays readable, unlike .btn--outline
     which is white-on-red for the public Galeri card. */
  .btn--muted {
    --btn-bg: transparent;
    --btn-color: var(--color-navy);
    border: 1px solid var(--color-navy);
  }

  /* Default styling for un-classed submits/buttons. Both carry :not(.btn):
     an element+attribute selector like `input[type="submit"]` outranks the
     `.btn` class, so without it a `<%= f.submit class: "btn" %>` kept this
     navy background while .btn:hover (higher specificity again) swapped the
     text to navy-dark -- dark blue on blue, effectively invisible on hover. */
  input[type="submit"]:not(.btn),
  button:not(.btn) {
    display: inline-flex;
    align-items: center;
    background: var(--color-navy);
    color: #fff;
    font-weight: 600;
    font-size: var(--text-sm);
    padding: 0.65em 1.3em;
    border-radius: var(--radius);
    border: none;
    cursor: pointer;
    transition: filter 0.15s;
  }

  input[type="submit"]:not(.btn):hover,
  button:not(.btn):hover {
    filter: brightness(1.15);
  }

  /* Higher specificity than the button:not(.btn) reset above, needed
     since it lives in this same (components) layer and would otherwise
     win regardless of source order. */
  .nav-links .nav-logout-btn {
    display: inline-flex;
    background: none;
    border: 1px solid rgba(255, 255, 255, 0.45);
    color: rgba(255, 255, 255, 0.85);
    font-size: var(--text-sm);
    font-weight: 400;
    padding: 0.25em 0.85em;
    border-radius: 999px;
    cursor: pointer;
    transition: border-color 0.15s, color 0.15s;
  }

  .nav-links .nav-logout-btn:hover {
    border-color: var(--color-gold);
    color: var(--color-gold);
    filter: none;
  }

  .nav-links .nav-close {
    display: none;
  }

  @media (max-width: 800px) {
    /* .nav-logout-btn keeps its base (desktop) light-on-dark styling here
       -- the mobile drawer background is sky blue (var(--color-header)),
       same family as the desktop navy header, so no override is needed. */

    /* Overrides the global `form { display: flex; flex-direction: column;
       ... }` reset ("Forms" section further down this same @layer
       components) for the one-button logout form in the mobile drawer
       (see .nav-links form in @layer layout above, where this same
       selector sets margin/text-align -- those aren't contested by the
       reset, only display/width/max-width are, which is why only those
       three live here). Left as `display: flex` on mobile, this tiny form
       becomes a flex container with the default align-items: stretch,
       which both blockifies its only child .nav-logout-btn from
       inline-flex to flex AND stretches it to the form's full width --
       exactly the full-width bar look every other drawer link already
       has, when the point of this button being its own pill is to look
       different from them. */
    .nav-links form {
      display: block;
      width: auto;
      max-width: none;
    }

    .nav-links .nav-close {
      position: absolute;
      top: 0.5rem;
      right: 0.5rem;
      width: 2.5rem;
      height: 2.5rem;
      display: flex;
      align-items: center;
      justify-content: center;
      background: none;
      padding: 0;
      border: none;
      border-radius: 0;
      font-size: 1.75rem;
      font-weight: 400;
      line-height: 1;
      color: rgba(255, 255, 255, 0.85);
      cursor: pointer;
    }

    .nav-links .nav-close:hover {
      color: #fff;
      filter: none;
    }
  }

  .site-nav .nav-toggle {
    display: none;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: 5px;
    width: 2.5rem;
    height: 2.5rem;
    padding: 0;
    background: none;
    border: none;
    cursor: pointer;
    flex-shrink: 0;
  }

  .nav-toggle__bar {
    display: block;
    width: 1.5rem;
    height: 2px;
    background: #fff;
    border-radius: 2px;
    transition: transform 0.2s, opacity 0.2s;
  }

  .nav-toggle.is-open .nav-toggle__bar:nth-child(1) {
    transform: translateY(7px) rotate(45deg);
  }

  .nav-toggle.is-open .nav-toggle__bar:nth-child(2) {
    opacity: 0;
  }

  .nav-toggle.is-open .nav-toggle__bar:nth-child(3) {
    transform: translateY(-7px) rotate(-45deg);
  }

  @media (max-width: 800px) {
    .site-nav .nav-toggle {
      display: flex;
    }
  }

  /* Pengurus in-page nav (the pipe-separated link row under each admin
     page's <h1>, see pengurus/_nav.html.erb): a hamburger toggle on mobile
     only, since the link count varies a lot by role (a few for
     commission_leader/majelis, ~20 for admin) and wraps across several
     cramped lines at narrow widths. Desktop is untouched -- the toggle
     stays hidden and .pengurus-nav__links keeps its normal always-visible
     flow.

     Selectors below are scoped as .pengurus-nav .pengurus-nav-toggle
     (not just .pengurus-nav-toggle), same reasoning as .site-nav
     .nav-toggle above: needs higher specificity than the button:not(.btn)
     reset further down this same layer, or `display: none` loses to the
     reset's `display: inline-flex` and the button stays visibly stuck on
     at every width, desktop included. */
  .pengurus-nav .pengurus-nav-toggle {
    display: none;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: 5px;
    width: 2.5rem;
    height: 2.5rem;
    padding: 0;
    background: var(--color-navy-dark);
    border: none;
    border-radius: var(--radius);
    cursor: pointer;
  }

  .pengurus-nav-toggle__bar {
    display: block;
    width: 1.25rem;
    height: 2px;
    background: #fff;
    border-radius: 2px;
    transition: transform 0.2s, opacity 0.2s;
  }

  .pengurus-nav-toggle.is-open .pengurus-nav-toggle__bar:nth-child(1) {
    transform: translateY(7px) rotate(45deg);
  }

  .pengurus-nav-toggle.is-open .pengurus-nav-toggle__bar:nth-child(2) {
    opacity: 0;
  }

  .pengurus-nav-toggle.is-open .pengurus-nav-toggle__bar:nth-child(3) {
    transform: translateY(-7px) rotate(-45deg);
  }

  @media (max-width: 800px) {
    .pengurus-nav .pengurus-nav-toggle {
      display: flex;
      margin-bottom: var(--space-2);
    }

    /* Open/close is animated (see pengurus_nav_controller.js), not an
       instant display:none/block swap: JS measures scrollHeight and drives
       max-height so the panel genuinely expands/collapses, while opacity +
       transform give it a soft pop-in/out. border-color (not border, so
       the 1px width stays constant) and background fade in step with it --
       kept transparent while collapsed so no sliver of red/border shows
       through at max-height: 0. */
    .pengurus-nav__links {
      overflow: hidden;
      max-height: 0;
      opacity: 0;
      transform: translateY(-10px) scale(0.97);
      background: transparent;
      border: 1px solid transparent;
      border-radius: var(--radius);
      padding: 0 var(--space-2);
      margin: 0 0 var(--space-3);
      transition:
        max-height 0.4s cubic-bezier(0.4, 0, 0.2, 1),
        opacity 0.3s ease,
        transform 0.35s cubic-bezier(0.16, 1, 0.3, 1),
        background 0.3s ease,
        border-color 0.3s ease;
    }

    .pengurus-nav__links.is-open {
      opacity: 1;
      transform: translateY(0) scale(1);
      background: #6e1423;
      border-color: #6e1423;
    }

    /* "|" separators only make sense in the desktop paragraph flow --
       stacking one link per row (below) makes them redundant. */
    .pengurus-nav__links .pengurus-nav__sep {
      display: none;
    }

    /* One link per row, like a drawer/sidebar list, instead of the
       desktop paragraph wrapping several pipe-separated links per line.
       Mobile-only dark-red/white treatment with a decorative serif face
       (Playfair Display, already loaded for headings -- see
       layouts/application.html.erb) so the drawer reads as a distinct
       "menu" surface; desktop keeps the plain sans-serif paragraph flow
       untouched. Each row also fades/slides in with a small stagger (the
       nth-child delays below) so opening the menu reveals its items one
       after another instead of all at once. */
    .pengurus-nav__links a {
      display: block;
      padding: 0.7rem 0.25rem;
      border-bottom: 1px solid rgba(255, 255, 255, 0.25);
      color: #fff;
      font-family: "Playfair Display", var(--font-sans);
      font-weight: 600;
      font-size: 1.05rem;
      opacity: 0;
      transform: translateX(-14px);
      transition: opacity 0.3s ease, transform 0.3s ease, color 0.3s ease;
    }

    .pengurus-nav__links a:hover {
      color: #fff;
    }

    .pengurus-nav__links a:last-child {
      border-bottom: none;
    }

    .pengurus-nav__links.is-open a {
      opacity: 1;
      transform: translateX(0);
    }

    .pengurus-nav__links.is-open a:nth-child(1)  { transition-delay: 0.03s; }
    .pengurus-nav__links.is-open a:nth-child(2)  { transition-delay: 0.06s; }
    .pengurus-nav__links.is-open a:nth-child(3)  { transition-delay: 0.09s; }
    .pengurus-nav__links.is-open a:nth-child(4)  { transition-delay: 0.12s; }
    .pengurus-nav__links.is-open a:nth-child(5)  { transition-delay: 0.15s; }
    .pengurus-nav__links.is-open a:nth-child(6)  { transition-delay: 0.18s; }
    .pengurus-nav__links.is-open a:nth-child(7)  { transition-delay: 0.21s; }
    .pengurus-nav__links.is-open a:nth-child(8)  { transition-delay: 0.24s; }
    .pengurus-nav__links.is-open a:nth-child(9)  { transition-delay: 0.27s; }
    .pengurus-nav__links.is-open a:nth-child(10) { transition-delay: 0.3s; }
    .pengurus-nav__links.is-open a:nth-child(11) { transition-delay: 0.33s; }
    .pengurus-nav__links.is-open a:nth-child(12) { transition-delay: 0.36s; }
    .pengurus-nav__links.is-open a:nth-child(13) { transition-delay: 0.39s; }
    .pengurus-nav__links.is-open a:nth-child(14) { transition-delay: 0.42s; }
    .pengurus-nav__links.is-open a:nth-child(15) { transition-delay: 0.45s; }
    .pengurus-nav__links.is-open a:nth-child(16) { transition-delay: 0.48s; }
    .pengurus-nav__links.is-open a:nth-child(17) { transition-delay: 0.51s; }
    .pengurus-nav__links.is-open a:nth-child(18) { transition-delay: 0.54s; }
    .pengurus-nav__links.is-open a:nth-child(19) { transition-delay: 0.57s; }
    .pengurus-nav__links.is-open a:nth-child(20) { transition-delay: 0.6s; }
  }

  /* Weekly media row: 2 YouTube embeds + 1 photo, left/center/right */
  .media-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--space-3);
    margin: var(--space-4) 0;
  }

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

  /* Scripture verse below the homepage media row -- Chinese + English,
     same bilingual verse pattern as .school-verse but wraps onto multiple
     lines since this verse runs much longer. */
  .home-verse {
    text-align: center;
    max-width: 42rem;
    margin: 0 auto var(--space-4);
  }

  /* Override the global p { max-width: 70ch } cap (application.css:108) --
     without this, .home-verse__en (a <p>) is narrower than its Chinese
     sibling and its centering visibly drifts off the shared center. */
  .home-verse p {
    max-width: none;
  }

  /* Ayat yang berdiri sendiri di tengah halaman (POS PI Jungkat, Sekolah
     Maranatha) dan bukan penutup sebuah bagian seperti di beranda.
     .home-verse tidak punya margin atas -- di beranda, bagian di atasnyalah
     yang memberi jarak -- jadi di sini jaraknya dipasang sendiri, sepadan
     dengan jarak antar-section di sekitarnya. */
  .home-verse--page {
    margin-top: var(--space-6);
  }

  .home-verse__zh {
    font-size: clamp(0.85rem, 4vw, var(--text-lg));
    font-weight: 600;
    color: var(--color-heading);
    margin: 0 0 var(--space-1);
  }

  .home-verse__en {
    font-family: "Quicksand", var(--font-sans);
    font-size: var(--text-sm);
    font-style: italic;
    color: var(--color-ink-light);
    margin: 0;
  }

  .home-verse__citation {
    display: block;
    text-align: right;
    font-style: normal;
    margin-top: var(--space-1);
  }

  @media (min-width: 641px) {
    .home-verse {
      max-width: 60rem;
    }

    .home-verse__zh {
      font-size: var(--text-xl);
    }

    .home-verse__en {
      font-size: var(--text-lg);
    }
  }

  /* Keep the Chinese verse on one line -- but only once the line actually
     fits. It used to be pinned from 641px up, where the longest verse
     (John 3:16, ~900px of text at this size) ran ~250px past its box and out
     of the page: nothing in the ancestry clips it, so that was a real
     horizontal scrollbar on tablets. Below this it wraps, which Chinese does
     cleanly at any character. */
  @media (min-width: 64rem) {
    .home-verse__zh {
      white-space: nowrap;
    }

    /* Same breakpoint, same reason: below it the verse needs a break and the
       markup says where it should fall (at the question mark, so the
       question and its answer each get a line); from here up the line fits
       whole, so the authored break is dropped rather than splitting a verse
       that has room to stay together. */
    .home-verse__zh br {
      display: none;
    }
  }

  /* Same card language as .hub-card and .upcoming__image: borderless,
     shadow-elevated, image-forward, lifts on hover -- previously a bordered
     white frame with a flat shadow-sm, which read as a different (older)
     card style than the rest of the homepage. */
  .media-card {
    background: none;
    border: none;
    border-radius: 0;
    padding: 0;
    box-shadow: none;
  }

  .media-card__embed,
  .media-card__slideshow {
    position: relative;
    aspect-ratio: 16 / 9;
    border-radius: var(--radius-lg);
    overflow: hidden;
    background: var(--color-navy-dark);
    box-shadow: var(--shadow-md);
    transition: transform 0.25s ease, box-shadow 0.25s ease;
  }

  .media-card:hover .media-card__embed,
  .media-card:hover .media-card__slideshow {
    transform: translateY(-4px);
    box-shadow: var(--shadow-lg);
  }

  .media-card__embed iframe {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border: none;
  }

  .media-card__image {
    width: 100%;
    aspect-ratio: 16 / 9;
    object-fit: cover;
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
    transition: transform 0.25s ease, box-shadow 0.25s ease;
  }

  .media-card:hover .media-card__image {
    transform: translateY(-4px);
    box-shadow: var(--shadow-lg);
  }

  .media-card__slide {
    position: absolute;
    inset: 0;
    opacity: 0;
    transition: opacity 0.6s ease;
  }

  .media-card__slide.is-active {
    opacity: 1;
  }

  /* The slideshow's own container already lifts on hover (see
     .media-card:hover .media-card__slideshow above) -- reset the nested
     image's box-shadow/transform so it doesn't move a second time inside
     the now-shifted, overflow:hidden frame. */
  .media-card__slide .media-card__image {
    width: 100%;
    height: 100%;
    aspect-ratio: unset;
    border-radius: 0;
    box-shadow: none;
    transition: none;
  }

  .media-card:hover .media-card__slide .media-card__image {
    transform: none;
  }

  .media-card__nav {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    background: rgba(0,0,0,0.45);
    color: #fff;
    border: none;
    cursor: pointer;
    font-size: 1.5rem;
    line-height: 1;
    padding: 0.3rem 0.55rem;
    border-radius: var(--radius);
    z-index: 2;
    opacity: 0;
    transition: opacity 0.2s;
  }

  .media-card__slideshow:hover .media-card__nav {
    opacity: 1;
  }

  .media-card__nav--prev { left: 0.5rem; }
  .media-card__nav--next { right: 0.5rem; }

  .media-card__dots {
    position: absolute;
    bottom: 0.5rem;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    gap: 0.4rem;
    z-index: 2;
  }

  .media-card__dot {
    width: 0.45rem;
    height: 0.45rem;
    border-radius: 50%;
    background: rgba(255,255,255,0.5);
    border: none;
    cursor: pointer;
    padding: 0;
    transition: background 0.2s;
  }

  .media-card__dot.is-active {
    background: #fff;
  }

  .media-card__empty {
    aspect-ratio: 16 / 9;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--color-canvas-subtle);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
    color: var(--color-ink-light);
    margin: 0;
  }

  /* Titles are admin-entered (HomepageHighlight#title) and can run long --
     e.g. a full Chinese verse like "殷勤不可懶惰。要心裡火熱，常常服事主。"
     (19 characters, each roughly 1em wide) barely overflows the ~317px
     card width at the old var(--text-base) (1.05rem/16.8px), wrapping the
     last character or two onto their own line. clamp() shrinks it just
     enough to fit that line at typical card widths (desktop's 3-column
     grid is the tight case -- mobile's single-column cards are wider, so
     they have even more headroom) without needing white-space: nowrap,
     which would just overflow instead of wrap for longer non-CJK titles
     like "Jalani Harimu Bersama dengan Yesus". */
  .media-card h3 {
    margin: var(--space-2) 0 0.25rem;
    font-size: clamp(0.85rem, 2.6vw, 0.95rem);
  }

  .media-card p {
    margin: 0;
    font-size: var(--text-sm);
  }

  /* Poster grid — portrait poster display on jadwal & commission pages */
  .poster-grid {
    list-style: none;
    padding: 0;
    margin: var(--space-2) 0 0;
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--space-3);
  }

  .poster-grid__img {
    width: 100%;
    height: auto;
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    display: block;
  }

  /* Video posters, rendered below .poster-grid (see commissions/show.html.erb)
     rather than mixed into it -- a 16:9 embed doesn't fit the grid's
     portrait poster cells. One per row since a video needs real width to
     be watchable, unlike the 2-up poster thumbnails above it. */
  .poster-video-list {
    list-style: none;
    padding: 0;
    margin: var(--space-3) 0 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
  }

  /* Poster admin grid — smaller thumbnails with delete button */
  .poster-admin-grid {
    list-style: none;
    padding: 0;
    margin: var(--space-2) 0 0;
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--space-3);
  }

  .poster-admin-grid__img {
    width: 100%;
    height: auto;
    border-radius: var(--radius);
    display: block;
  }

  /* Video posters (Poster#kind: video) render an embed here instead of
     .poster-admin-grid__img -- same 16:9 box + absolutely-positioned
     iframe pattern as .media-card__embed. */
  .poster-admin-grid__embed {
    position: relative;
    aspect-ratio: 16 / 9;
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--color-navy-dark);
  }

  .poster-admin-grid__embed iframe {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border: none;
  }

  .poster-admin-grid__meta {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-top: 0.35rem;
    font-size: var(--text-xs);
    color: var(--color-ink-light);
  }

  /* Admin "Rekaman" page audio list -- one row per GalleryAudio. */
  .audio-admin-list {
    list-style: none;
    padding: 0;
    margin: var(--space-2) 0 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
  }

  .audio-admin-list li {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-2);
  }

  .audio-admin-list__meta {
    display: flex;
    flex-direction: column;
    min-width: 10rem;
  }

  .audio-admin-list audio {
    flex: 1 1 auto;
    min-width: 14rem;
  }

  /* Photo grid — 3-column gallery used on commission & galeri pages */
  .photo-grid {
    list-style: none;
    padding: 0;
    margin: 0;
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--space-2);
  }

  /* Galeri page only -- narrower 2-column layout instead of the shared 3-column default. */
  .photo-grid--2col {
    grid-template-columns: repeat(2, 1fr);
  }

  /* Komisi page only -- 1 column on mobile instead of the shared 3-column default. */
  @media (max-width: 640px) {
    .photo-grid--commission {
      grid-template-columns: 1fr;
    }

    .poster-grid--commission {
      grid-template-columns: 1fr;
    }
  }

  .photo-grid__item {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
  }

  .photo-grid__img {
    width: 100%;
    aspect-ratio: 1 / 1;
    object-fit: cover;
    border-radius: var(--radius);
  }

  .photo-grid__caption {
    margin: 0;
    font-size: var(--text-xs);
    color: var(--color-ink-light);
    text-align: center;
  }

  /* Gallery video grid -- Galeri page only, below the "GALERI" heading. */
  .gallery-video-grid {
    list-style: none;
    padding: 0;
    margin: 0 0 var(--space-4);
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: var(--space-2);
  }

  @media (max-width: 640px) {
    .gallery-video-grid {
      grid-template-columns: 1fr;
    }
  }

  .gallery-video-grid__item {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
  }

  /* Same 16:9 iframe pattern as .media-card__embed. */
  .gallery-video-grid__embed {
    position: relative;
    aspect-ratio: 16 / 9;
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--color-navy-dark);
  }

  .gallery-video-grid__embed iframe {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border: none;
  }

  .gallery-video-grid__caption {
    margin: 0;
    font-size: var(--text-xs);
    color: var(--color-ink-light);
    text-align: center;
  }

  /* Audio grid -- Galeri page only, below the video grid. */
  .audio-grid {
    list-style: none;
    padding: 0;
    margin: 0 0 var(--space-4);
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
  }

  .audio-grid__item {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
  }

  .audio-grid__title {
    margin: 0;
    font-weight: 700;
  }

  .audio-grid audio {
    width: 100%;
  }

  /* Cards */
  .card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
    gap: var(--space-3);
    margin: var(--space-3) 0 0;
    list-style: none;
    padding: 0;
  }

  .card {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    background: var(--color-canvas);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    padding: var(--space-3);
    box-shadow: var(--shadow-sm);
    transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
  }

  a.card {
    color: var(--color-ink);
  }

  .card:hover {
    transform: translateY(-4px);
    box-shadow: var(--shadow-md);
    border-color: var(--color-gold);
  }

  .card__icon {
    width: 2.75rem;
    height: 2.75rem;
    border-radius: 50%;
    background: color-mix(in oklch, var(--color-gold) 18%, white);
    color: var(--color-navy);
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: var(--space-1);
  }

  .card__icon svg {
    width: 1.5rem;
    height: 1.5rem;
  }

  .card h3 {
    margin: 0;
    font-size: var(--text-base);
    color: var(--color-heading);
  }

  /* Forms */
  form {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    max-width: 28rem;
  }

  /* Biodata Jemaat admin search (pengurus/biodata_jemaats#index) -- fields
     stack on mobile like any other form, but lay out in a wrapping row on
     desktop so the whole search fits without scrolling past it. */
  .search-form {
    max-width: none;
  }

  @media (min-width: 641px) {
    .search-form {
      flex-direction: row;
      flex-wrap: wrap;
      align-items: flex-end;
      gap: var(--space-3);
    }

    .search-form__field {
      flex: 1 1 12rem;
      min-width: 0;
    }

    .search-form__field--wide,
    .search-form__actions {
      flex-basis: 100%;
    }
  }

  .search-form__field--wide {
    border: none;
    padding: 0;
    margin: 0;
  }

  .search-form__field--wide legend {
    padding: 0;
    margin-bottom: var(--space-1);
    font-weight: 600;
    font-size: var(--text-sm);
    color: var(--color-ink);
  }

  .search-form__checkboxes {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1) var(--space-3);
  }

  .search-form__checkbox {
    display: flex;
    align-items: center;
    gap: var(--space-1);
  }

  .search-form__checkbox label {
    display: inline;
    font-weight: 400;
  }

  .search-form__actions {
    display: flex;
    align-items: center;
    gap: var(--space-2);
  }

  /* Admin table photo thumbnails (Baptisan, Biodata Jemaat) -- click a
     thumbnail to view it larger in the shared <dialog> lightbox
     (lightbox_controller.js). */
  .lightbox-thumb {
    cursor: zoom-in;
    border-radius: var(--radius);
  }

  .lightbox {
    max-width: min(90vw, 32rem);
    max-height: 90vh;
    padding: 0;
    border: none;
    border-radius: var(--radius);
    background: transparent;
  }

  .lightbox::backdrop {
    background: rgb(0 0 0 / 0.7);
  }

  .lightbox img {
    display: block;
    max-width: 100%;
    max-height: 90vh;
    border-radius: var(--radius);
  }

  .lightbox__close {
    position: absolute;
    top: var(--space-2);
    right: var(--space-2);
    width: 2rem;
    height: 2rem;
    border: none;
    border-radius: 999px;
    background: rgb(0 0 0 / 0.6);
    color: white;
    font-size: var(--text-lg);
    line-height: 1;
    cursor: pointer;
  }

  .form-preview-thumb {
    max-width: 12rem;
    border-radius: var(--radius);
  }

  /* Cover thumbnail in the Pengurus > Komisi table. A class rather than the
     `style="width:80px;height:60px"` this used to carry: style-src in the CSP
     has no 'unsafe-inline', so inline style attributes are dropped without a
     console error and the thumb rendered at its full upload size, pushing the
     Edit link a screenful down the page. */
  .commission-admin-thumb {
    width: 5rem;
    height: 3.75rem;
    object-fit: cover;
    border-radius: var(--radius);
  }

  /* Admin renungan list: each row shows the cover thumb, title (with a
     "Di homepage" badge when featured), and the toggle + delete buttons. */
  .renungan-admin-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
  }

  .renungan-admin-list__item {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    flex-wrap: wrap;
    padding: var(--space-2) var(--space-3);
    background: var(--color-surface, #fff);
    border: 1px solid var(--color-border, #e5e7eb);
    border-radius: var(--radius);
  }

  .renungan-admin-list__item .form-preview-thumb {
    max-width: 3.5rem;
    flex: 0 0 auto;
  }

  .renungan-admin-list__title {
    flex: 1 1 12rem;
    font-weight: 600;
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: wrap;
  }

  .renungan-admin-list__badge {
    display: inline-block;
    font-size: var(--text-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    padding: 0.15rem 0.5rem;
    border-radius: 999px;
    background: var(--color-navy, #1f3a5f);
    color: #fff;
  }

  .renungan-admin-list__badge--muted {
    background: transparent;
    color: var(--color-muted, #6b7280);
    border: 1px solid var(--color-border, #d1d5db);
  }

  label {
    display: block;
    font-weight: 600;
    font-size: var(--text-sm);
    color: var(--color-ink);
  }

  input, select, textarea {
    font: inherit;
    padding: 0.65em 0.85em;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-canvas);
    color: var(--color-ink);
  }

  input:focus, select:focus, textarea:focus {
    outline: 2px solid var(--color-gold);
    outline-offset: 1px;
    border-color: var(--color-gold);
  }

  /* Password field with a "show password" eye toggle button overlaid on
     the right edge of the input. */
  .password-field {
    position: relative;
    display: inline-block;
  }

  .password-field input {
    width: 100%;
    padding-right: 2.5em;
  }

  button.password-field__toggle {
    position: absolute;
    inset-block: 0;
    right: 0.15em;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2em;
    padding: 0;
    border: none;
    background: transparent;
    color: var(--color-ink-light);
    cursor: pointer;
  }

  button.password-field__toggle:hover {
    filter: none;
    color: var(--color-ink);
  }

  .password-field__icon {
    width: 1.2em;
    height: 1.2em;
  }

  .password-field__icon--hide {
    display: none;
  }

  .password-field__toggle.is-visible .password-field__icon--show {
    display: none;
  }

  .password-field__toggle.is-visible .password-field__icon--hide {
    display: block;
  }

  /* Public registration form headings ("Pendaftaran Calon Baptisan",
     "Pendaftaran Penyerahan Anak"): uppercase at every width, but the
     global h1 size (clamp(2rem, 4vw, 2.75rem)) wraps these long phrases
     onto two lines on phones, so mobile gets its own smaller size that
     scales with viewport width to stay on one line down to narrow phones. */
  .form-pendaftaran-title {
    text-transform: uppercase;
  }

  @media (max-width: 640px) {
    .form-pendaftaran-title {
      font-size: clamp(1rem, 5vw, 1.6rem);
      white-space: nowrap;
    }
  }

  /* Tables */
  table {
    width: 100%;
    border-collapse: collapse;
    margin-block: var(--space-3);
    font-size: var(--text-sm);
  }

  /* Admin tables commonly have more columns than a phone screen can fit
     (Biodata Jemaat, Baptisan, Katekisasi, etc.) -- scroll the table
     itself horizontally rather than letting it force the whole page to
     scroll sideways and clip content past the viewport edge. */
  @media (max-width: 640px) {
    table {
      display: block;
      overflow-x: auto;
      -webkit-overflow-scrolling: touch;
    }
  }

  th, td {
    text-align: left;
    padding: var(--space-1) var(--space-2);
    border-bottom: 1px solid var(--color-border);
  }

  th {
    color: var(--color-navy-dark);
    font-weight: 700;
    background: var(--color-canvas-subtle);
  }

  /* Title heading on each commission's detail page (Komisi Anak, Remaja, etc.) */
  .commission-title {
    text-transform: uppercase;
  }

  /* Description paragraph on each commission's detail page. */
  .commission-description {
    font-family: "Quicksand", var(--font-sans);
  }

  /* Facebook/Instagram/YouTube/TikTok icons on a commission's detail page
     (currently only Komisi Pemuda and Komisi Remaja have any URLs filled
     in, see CommissionSocialLink). */
  .commission-social {
    display: flex;
    align-items: center;
    gap: var(--space-2);
  }

  .commission-social__link {
    display: flex;
    align-items: center;
    justify-content: center;
    transition: opacity 0.15s, transform 0.15s;
  }

  .commission-social__link:hover {
    opacity: 0.8;
    transform: translateY(-2px);
  }

  .commission-social__icon {
    width: 1.75rem;
    height: 1.75rem;
  }

  @media (min-width: 641px) {
    .commission-description {
      font-size: var(--text-lg);
    }
  }

  /* Row pairing the commission's cover image with its description.
     Mobile: image floats left at its natural size so text wraps tightly
     around it. Desktop: switches to a stretched two-column layout. */
  .commission-description-row::after {
    content: "";
    display: block;
    clear: both;
  }

  .commission-description-row__image {
    float: left;
    width: 6.4rem;
    height: auto;
    margin-right: var(--space-3);
    margin-bottom: var(--space-2);
    border-radius: var(--radius-lg);
    object-fit: contain;
  }

  /* The service-time card, formerly a JPEG with the hour baked into the
     artwork (see Commission#schedule?). Drawn as text so the pengurus can
     change the hour from Pengurus > Komisi, and so it sits *on* the night
     sky -- no white rectangle punched through it. Solid #fff rather than the
     --color-heading token: the token's faint blue tint (#F2F6FD) reads as
     grey next to the white the card's type used to be printed in, and this
     page is night-only (see NIGHT_THEME_CONTROLLERS).

     Not floated the way the JPEG was: a line as long as PERSEKUTUAN WANITA
     wraps badly in a 6.4rem gutter, so on phones the card stacks above the
     paragraph and only becomes a left column at the desktop breakpoint. */
  .commission-schedule {
    margin-bottom: var(--space-3);
    color: #FFFFFF;
    line-height: 1.02;
    /* A line that has to wrap (PERSEKUTUAN WANITA, SABTU PERTAMA) splits
       evenly instead of dropping one short word on the last row. */
    text-wrap: balance;
  }

  .commission-schedule p {
    margin: 0;
    max-width: none;
  }

  .commission-schedule__time {
    font-size: clamp(2.5rem, 11vw, 3.1rem);
    font-weight: 800;
    letter-spacing: -0.03em;
  }

  .commission-schedule__day,
  .commission-schedule__name {
    font-weight: 800;
    text-transform: uppercase;
    letter-spacing: -0.01em;
  }

  .commission-schedule__day {
    font-size: clamp(1.55rem, 7vw, 1.8rem);
  }

  .commission-schedule__name {
    font-size: clamp(1.1rem, 5vw, 1.25rem);
  }

  /* The 中文 lines mirror the original card: regular weight under a bold
     Latin line, same white, one notch smaller. line-height gets a little
     more room than the Latin lines because CJK glyphs fill their em box. */
  .commission-schedule__day-zh,
  .commission-schedule__name-zh {
    font-size: clamp(1.3rem, 6vw, 1.45rem);
    font-weight: 400;
    line-height: 1.18;
  }

  .commission-schedule__name-zh {
    font-size: clamp(1.15rem, 5.5vw, 1.3rem);
  }

  /* Separates the "what" (service name) from the "when" (time + day), the
     same gap the printed card left between its two groups. */
  .commission-schedule__service {
    margin-top: var(--space-3);
  }

  @media (min-width: 641px) {
    .commission-description-row {
      display: flex;
      flex-direction: row;
      align-items: stretch;
      gap: var(--space-4);
    }

    /* Wide enough for the longest line any commission has -- the eight
       characters of 每月第一個星期六 -- so the card never drops a lone
       glyph onto a row of its own. */
    .commission-schedule {
      flex: 0 0 14rem;
      margin-bottom: 0;
    }

    .commission-description-row__image {
      float: none;
      flex: 0 0 6.4rem;
      width: 6.4rem;
      height: auto;
      margin: 0;
      object-fit: contain;
    }
  }

  /* Commission cards: 2×2 photo grid on Komisi & Pelayanan page */
  .commission-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-3);
    margin: var(--space-4) 0;
  }

  @media (max-width: 640px) {
    .commission-grid {
      grid-template-columns: 1fr;
    }
  }

  .commission-card {
    position: relative;
    display: block;
    overflow: hidden;
    border-radius: var(--radius-lg);
    aspect-ratio: 4 / 3;
    background: var(--color-navy);
    text-decoration: none;
  }

  .commission-card--no-image {
    background: linear-gradient(135deg, var(--color-navy) 0%, var(--color-navy-dark) 100%);
  }

  .commission-card__image {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center;
    transition: transform 0.4s ease;
  }

  .commission-card:hover .commission-card__image {
    transform: scale(1.06);
  }

  .commission-card__overlay {
    position: absolute;
    inset: 0;
    background: linear-gradient(to top, rgba(0,0,0,0.72) 0%, rgba(0,0,0,0.12) 55%, transparent 100%);
  }

  .commission-card__heading {
    position: absolute;
    inset: 0;
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: var(--space-3);
    color: #fff;
    font-size: var(--text-2xl);
    text-shadow: 0 1px 6px rgba(0,0,0,0.6);
    pointer-events: none;
  }

  .commission-card__body {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    padding: var(--space-3);
    z-index: 1;
  }

  .commission-card__name {
    color: #fff;
    font-size: var(--text-lg);
    margin: 0 0 var(--space-2);
    text-shadow: 0 1px 4px rgba(0,0,0,0.5);
  }

  .commission-card__btn {
    display: inline-block;
    background: var(--color-gold);
    color: var(--color-navy-dark);
    font-weight: 700;
    font-size: var(--text-xs);
    letter-spacing: 0.07em;
    text-transform: uppercase;
    padding: 0.5em 1.4em;
    border-radius: 999px;
    transition: filter 0.15s;
  }

  .commission-card:hover .commission-card__btn {
    filter: brightness(1.1);
  }

  /* Section seal: a small red-gold Chinese-seal-style badge (印章) paired
     with a Playfair Display title, standing in for the generic clip-art
     look elsewhere on the homepage. Shared by any section heading that
     wants the same bicultural accent (currently .hub-card-grid's and
     .media-grid's, neither of which had a visible heading before). The
     badge's 2-character mark reads top-to-bottom like a real seal and sits
     at a slight hand-stamped angle rather than perfectly square. */
  .section-seal {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-3);
    margin: 0 0 var(--space-4);
    /* No-op outside a grid; keeps this full-width when used as the first
       child of a CSS grid section (e.g. .media-grid) instead of becoming
       just one more grid item squeezed into a column. */
    grid-column: 1 / -1;
  }

  .section-seal__mark {
    flex: 0 0 auto;
    display: grid;
    place-items: center;
    width: 2.75rem;
    height: 2.75rem;
    background: var(--color-seal);
    border: 2px solid var(--color-gold);
    border-radius: 0.35rem;
    color: #fff;
    font-family: "Playfair Display", var(--font-sans);
    font-size: 1.15rem;
    font-weight: 700;
    line-height: 1;
    letter-spacing: 0.05em;
    writing-mode: vertical-rl;
    transform: rotate(-3deg);
    box-shadow: var(--shadow-sm);
  }

  .section-seal__title {
    margin: 0;
    font-family: "Playfair Display", var(--font-sans);
    font-weight: 600;
    font-size: clamp(1.35rem, 4vw, 1.85rem);
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: var(--color-heading);
  }

  /* Ornament divider: a thin gold rule flanking a repeating cloud-scroll
     glyph (a simplified 如意雲紋/ruyi-cloud lattice), used sparingly between
     sections instead of a plain margin gap. Decorative only. */
  .ornament-divider {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    max-width: 22rem;
    margin: var(--space-6) auto;
    color: var(--color-gold);
  }

  .ornament-divider__line {
    flex: 1 1 auto;
    height: 1px;
    background: linear-gradient(to right, transparent, currentColor);
  }

  .ornament-divider__line:last-child {
    background: linear-gradient(to left, transparent, currentColor);
  }

  .ornament-divider__glyph {
    flex: 0 0 auto;
    width: 2.75rem;
    height: 1.1rem;
    opacity: 0.85;
  }

  /* Hub cards: 3 tall portrait cards on homepage menu */
  .hub-card-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--space-3);
    margin: var(--space-4) 0;
  }

  @media (max-width: 640px) {
    .hub-card-grid {
      grid-template-columns: 1fr;
      margin: var(--space-2) 0;
    }
  }

  .hub-card {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-end;
    overflow: hidden;
    border-radius: var(--radius-lg);
    aspect-ratio: 3 / 4;
    text-decoration: none;
    color: #fff;
  }

  @media (max-width: 640px) {
    .hub-card {
      aspect-ratio: 16 / 9;
    }

    /* The 16:9 box is too short for the title+preview+button stack
       designed for the taller 3:4 card -- trim it down so nothing
       overflows. Preview is hover-only anyway, so drop it on touch. */
    .hub-card__center {
      flex: 0 0 auto;
      padding-bottom: var(--space-1);
    }

    .hub-card__title {
      font-size: var(--text-base);
      margin-bottom: 0;
    }

    .hub-card__footer {
      padding: var(--space-1) var(--space-2) var(--space-2);
    }

    .hub-card__btn {
      font-size: var(--text-xs);
      padding: 0.3em 1.2em;
    }
  }

  .hub-card--commissions { background: linear-gradient(160deg, #1a4a7a 0%, #0a1e38 100%); }
  .hub-card--galeri      { background: linear-gradient(160deg, #1a3d4a 0%, #0a1e28 100%); }
  .hub-card--pos_pi      { background: linear-gradient(160deg, #4a3a1a 0%, #28200a 100%); }

  .hub-card__image {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center;
    transition: transform 0.45s ease;
  }

  .hub-card:hover .hub-card__image {
    transform: scale(1.05);
  }

  .hub-card__overlay {
    position: absolute;
    inset: 0;
    background: linear-gradient(
      to top,
      rgba(0,0,0,0.80) 0%,
      rgba(0,0,0,0.25) 50%,
      rgba(0,0,0,0.08) 100%
    );
    transition: background 0.35s ease;
  }

  .hub-card:hover .hub-card__overlay {
    background: linear-gradient(
      to top,
      rgba(0,0,0,0.88) 0%,
      rgba(0,0,0,0.55) 60%,
      rgba(0,0,0,0.20) 100%
    );
  }

  .hub-card__center {
    position: relative;
    z-index: 1;
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-end;
    padding: 0 var(--space-3) var(--space-2);
    text-align: center;
    width: 100%;
  }

  .hub-card__title {
    color: #fff;
    font-size: var(--text-xl);
    margin: 0 0 var(--space-1);
    text-shadow: 0 2px 10px rgba(0,0,0,0.7);
    transition: transform 0.35s ease;
  }

  .hub-card__title-text--default {
    display: none;
  }

  .hub-card:hover .hub-card__title {
    transform: translateY(-8px);
  }

  /* Collapsed (reserves no height) by default so every card's heading sits
     at the same spot regardless of preview length; expands on hover. A
     grid-template-rows 0fr->1fr animation instead of max-height: 0->22em --
     the same visual effect without animating a layout property (max-height)
     that forces reflow on every frame. */
  .hub-card__preview-wrap {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows 0.35s ease;
  }

  .hub-card:hover .hub-card__preview-wrap {
    grid-template-rows: 1fr;
  }

  /* Preview is hover-only anyway, so drop it on touch (placed after the
     base rule above so it wins the cascade at this viewport). */
  @media (max-width: 640px) {
    .hub-card__preview-wrap {
      display: none;
    }
  }

  .hub-card__preview {
    min-height: 0;
    overflow: hidden;
    color: rgba(255,255,255,0.90);
    font-size: var(--text-sm);
    margin: 0;
    max-width: 22ch;
    line-height: 1.55;
    opacity: 0;
    transform: translateY(8px);
    transition: opacity 0.35s ease 0.05s, transform 0.35s ease 0.05s;
  }

  .hub-card:hover .hub-card__preview {
    opacity: 1;
    transform: translateY(-8px);
  }

  .hub-card__footer {
    position: relative;
    z-index: 1;
    width: 100%;
    display: flex;
    justify-content: center;
    padding: var(--space-2) var(--space-3);
    transition: transform 0.35s ease;
  }

  .hub-card:hover .hub-card__footer {
    transform: translateY(-8px);
  }

  .hub-card__btn {
    display: inline-block;
    background: rgba(255,255,255,0.92);
    color: var(--color-navy-dark);
    font-weight: 600;
    font-size: var(--text-sm);
    padding: 0.4em 1.6em;
    border-radius: 999px;
    transition: background 0.15s;
  }

  .hub-card:hover .hub-card__btn {
    background: #fff;
  }

  /* Pastor slideshow: circular photo cards above footer */
  .pastor-section {
    /* Full-bleed (it lives outside .container now); its inner .container
       re-centers the content. The blue gradient stays white behind the
       heading/cards up top and eases into light blue by the nav buttons at
       the bottom, then continues seamlessly into the footer (which starts on
       the same #C9E0F6 and has margin-top: 0). */
    background: linear-gradient(180deg, var(--color-canvas) 0%, var(--color-canvas) 38%, #5E92C8 100%);
    text-align: center;
  }

  .pastor-section__heading {
    margin-top: 0;
    margin-bottom: var(--space-4);
    color: var(--color-heading);
  }

  .pastor-slider {
    overflow: hidden;
  }

  .pastor-track {
    display: flex;
    gap: 2rem;
    transition: transform 0.4s ease;
    align-items: flex-start;
  }

  .pastor-card {
    flex: 0 0 calc((100% - 4rem) / 3);
    min-width: calc((100% - 4rem) / 3);
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 0 var(--space-3) var(--space-3);
    text-align: center;
  }

  @media (max-width: 639px) {
    .pastor-section {
      padding-top: var(--space-1);
    }

    .pastor-section__heading {
      font-family: "Playfair Display", var(--font-sans);
      font-weight: 600;
      letter-spacing: 0.03em;
      line-height: 1.5;
      margin-bottom: var(--space-3);
    }

    .pastor-section__heading-line1,
    .pastor-section__heading-line2 {
      display: block;
    }

    .pastor-track {
      gap: 1rem;
    }

    .pastor-card {
      flex: 0 0 calc((100% - 1rem) / 2);
      min-width: calc((100% - 1rem) / 2);
      padding: 0 0.5rem var(--space-2);
    }

    .pastor-card__photo-wrap {
      width: 6.5rem;
      height: 6.5rem;
      border-width: 2px;
      margin-bottom: 0.75rem;
    }

    .pastor-card__name {
      font-size: 0.95rem;
      line-height: 1.25;
    }

    .pastor-card__desc {
      font-size: 0.75rem;
      max-width: 16ch;
      line-height: 1.4;
    }

    .pastor-card__divider {
      width: 2rem;
      margin-top: var(--space-1);
    }
  }

  .pastor-card__photo-wrap {
    width: 9rem;
    height: 9rem;
    border-radius: 50%;
    overflow: hidden;
    margin-bottom: var(--space-3);
    box-shadow: var(--shadow-md);
    border: 3px solid var(--color-gold-light);
  }

  .pastor-card__photo {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center top;
    display: block;
  }

  .pastor-card__photo--placeholder {
    background: var(--color-canvas-subtle);
  }

  .pastor-card__name {
    color: var(--color-heading);
    font-size: var(--text-lg);
    margin: 0 0 var(--space-1);
  }

  .pastor-card__desc {
    color: var(--color-ink-light);
    font-size: var(--text-sm);
    margin: 0;
    max-width: 26ch;
    line-height: 1.6;
  }

  .pastor-card__divider {
    width: 3rem;
    height: 2px;
    background: var(--color-border);
    margin-top: var(--space-3);
  }

  .pastor-nav {
    display: flex;
    justify-content: center;
    gap: var(--space-2);
    margin-top: var(--space-3);
  }

  /* The Mazmur 121 verse closing the Hamba Tuhan section. .home-verse has no
     top margin of its own (higher up the page the section above it supplies
     the gap), so it needs one here or it reads as a caption hanging off the
     nav buttons rather than as the section's closing note. */
  .pastor-section .home-verse {
    margin-top: var(--space-4);
  }

  .pastor-nav__btn {
    width: 2.75rem;
    height: 2.75rem;
    border-radius: 50%;
    border: 1px solid var(--color-border);
    background: var(--color-canvas);
    color: var(--color-navy);
    font-size: 1.5rem;
    line-height: 1;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: border-color 0.15s, background 0.15s;
  }

  .pastor-nav__btn:hover:not(:disabled) {
    border-color: var(--color-gold);
    background: var(--color-navy-dark);
    color: #fff;
  }

  .pastor-nav__btn:disabled {
    opacity: 0.35;
    cursor: default;
  }

  /* Flash messages */
  .flash {
    padding: var(--space-2);
    border-radius: var(--radius);
    margin-bottom: var(--space-2);
    font-size: var(--text-sm);
    max-width: 28rem;
  }

  .flash--alert {
    background: var(--color-negative-bg);
    color: var(--color-negative-ink);
  }

  .flash--notice {
    background: var(--color-positive-bg);
    color: var(--color-positive-ink);
  }

  /* ── Meeting Notes – Notion-like workspace ───────────────────── */

  .mn-workspace {
    display: flex;
    align-items: flex-start;
    min-height: calc(100dvh - 4.75rem);
    background: #fff;
  }

  /* Sidebar */
  .mn-sidebar {
    width: 230px;
    flex-shrink: 0;
    background: #f7f7f5;
    border-right: 1px solid #e9e9e7;
    display: flex;
    flex-direction: column;
    position: sticky;
    top: 4.75rem;
    height: calc(100dvh - 4.75rem);
    overflow-y: auto;
  }

  .mn-sidebar__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    padding: 1.25rem 1rem 1rem;
    font-weight: 700;
    font-size: 0.8rem;
    color: #37352f;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    border-bottom: 1px solid #e9e9e7;
  }

  .mn-sidebar__close {
    display: none;
    font-size: 1.5rem;
    line-height: 1;
    color: #9b9a97;
    background: none;
    border: none;
    cursor: pointer;
    text-transform: none;
  }

  /* Off-canvas drawer toggle (mobile only, see @media (max-width: 800px)
     below): a floating button so the sidebar can be reopened from any of
     the 4 meeting-notes views (index/show/edit/new), not just the ones
     with their own header row.

     Scoped as `.mn-workspace .mn-sidebar-toggle` (not just
     `.mn-sidebar-toggle`) for the same reason as `.pengurus-nav
     .pengurus-nav-toggle` above: needs higher specificity than the
     `button:not(.btn)` reset in this same layer, or `display: none` loses
     and the button stays visibly stuck on at every width, desktop
     included. */
  .mn-workspace .mn-sidebar-toggle {
    display: none;
    position: fixed;
    left: 1rem;
    bottom: 1.25rem;
    z-index: 30;
    width: 3rem;
    height: 3rem;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 5px;
    border: none;
    border-radius: 999px;
    background: var(--color-navy-dark);
    box-shadow: var(--shadow-md);
    cursor: pointer;
  }

  .mn-sidebar-toggle__bar {
    display: block;
    width: 1.25rem;
    height: 2px;
    background: #fff;
    border-radius: 2px;
  }

  .mn-sidebar-overlay {
    display: none;
  }

  .mn-sidebar__nav {
    flex: 1;
    padding: 0.75rem 0.5rem;
    display: flex;
    flex-direction: column;
    gap: 2px;
  }

  .mn-sidebar__item {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.45rem 0.75rem;
    font-size: 0.875rem;
    color: #37352f;
    border-radius: 5px;
    transition: background 0.1s;
    text-decoration: none;
    cursor: pointer;
  }

  .mn-sidebar__item:hover {
    background: rgba(55, 53, 47, 0.08);
    color: #37352f;
  }

  .mn-sidebar__item.is-active {
    background: rgba(55, 53, 47, 0.11);
    font-weight: 600;
    color: #37352f;
  }

  .mn-sidebar__icon {
    font-size: 1rem;
    flex-shrink: 0;
  }

  .mn-sidebar__footer {
    padding: 0.75rem 1rem;
    border-top: 1px solid #e9e9e7;
  }

  .mn-sidebar__back {
    font-size: 0.775rem;
    color: #9b9a97;
    display: block;
    padding: 0.3rem 0;
    transition: color 0.1s;
  }

  .mn-sidebar__back:hover {
    color: #37352f;
  }

  @media (max-width: 800px) {
    .mn-sidebar {
      position: fixed;
      inset-block: 0;
      left: 0;
      top: 0;
      width: min(80vw, 280px);
      height: 100dvh;
      box-shadow: 2px 0 16px rgba(0, 0, 0, 0.2);
      transform: translateX(-100%);
      transition: transform 0.25s ease;
      z-index: 40;
    }

    .mn-sidebar.is-open {
      transform: translateX(0);
    }

    .mn-sidebar__close {
      display: block;
    }

    .mn-workspace .mn-sidebar-toggle {
      display: flex;
    }

    .mn-sidebar-overlay {
      display: block;
      position: fixed;
      inset: 0;
      background: rgba(0, 0, 0, 0.45);
      opacity: 0;
      pointer-events: none;
      transition: opacity 0.2s;
      z-index: 35;
    }

    .mn-sidebar-overlay.is-open {
      opacity: 1;
      pointer-events: auto;
    }
  }

  /* Main content */
  .mn-main {
    flex: 1;
    padding: 2.5rem 3rem;
    min-width: 0;
  }

  .mn-main__header {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    margin-bottom: 2rem;
    padding-bottom: 1.25rem;
    border-bottom: 1px solid #e9e9e7;
  }

  .mn-page-icon {
    font-size: 2.25rem;
    line-height: 1;
    margin-bottom: 0.4rem;
  }

  .mn-main__title {
    font-size: 1.85rem;
    font-weight: 700;
    color: #37352f;
    margin: 0;
    line-height: 1.2;
  }

  .mn-main__subtitle {
    font-size: 0.825rem;
    color: #9b9a97;
    margin: 0.25rem 0 0;
  }

  /* Note list */
  .mn-notes {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 1rem;
    align-items: start;
  }

  @media (max-width: 900px) {
    .mn-notes { grid-template-columns: repeat(2, 1fr); }
  }

  @media (max-width: 560px) {
    .mn-notes { grid-template-columns: 1fr; }
  }

  .mn-note-card {
    display: flex;
    flex-direction: column;
    background: #fff;
    border: 1px solid #e9e9e7;
    border-radius: 8px;
    padding: 1.1rem 1.15rem 0.9rem;
    transition: box-shadow 0.15s, border-color 0.15s;
    min-height: 140px;
  }

  .mn-note-card:hover {
    box-shadow: 0 3px 10px rgba(0, 0, 0, 0.08);
    border-color: #d4d4d2;
  }

  .mn-note-card__date {
    font-size: 0.7rem;
    font-weight: 600;
    color: #9b9a97;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    margin-bottom: 0.55rem;
  }

  .mn-note-card__link {
    display: block;
    flex: 1;
    text-decoration: none;
    color: inherit;
  }

  .mn-note-card__preview {
    font-size: 0.85rem;
    color: #37352f;
    line-height: 1.6;
    display: -webkit-box;
    -webkit-line-clamp: 5;
    -webkit-box-orient: vertical;
    overflow: hidden;
    margin: 0;
  }

  .mn-note-card__footer {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-top: 0.9rem;
    padding-top: 0.65rem;
    border-top: 1px solid #f0f0ef;
    min-height: 1.75rem;
  }

  .mn-note-card__actions {
    display: flex;
    align-items: center;
    gap: 0.25rem;
  }

  /* Inline any button_to <form> elements inside the workspace */
  .mn-note-card__actions form,
  .mn-form__actions form,
  .mn-note-view form {
    display: contents;
    max-width: none;
    gap: 0;
  }

  .mn-action-link {
    font-size: 0.775rem;
    color: #6b6b6b;
    padding: 0.25rem 0.6rem;
    border-radius: 4px;
    transition: background 0.1s;
    text-decoration: none;
    display: inline-block;
  }

  .mn-action-link:hover {
    background: rgba(55, 53, 47, 0.08);
    color: #37352f;
  }

  .mn-action-delete-btn {
    font-size: 0.775rem;
    color: #9b1c1c;
    padding: 0.25rem 0.6rem;
    border-radius: 4px;
    background: none;
    border: none;
    cursor: pointer;
    font-family: inherit;
    font-weight: 400;
    transition: background 0.1s;
    line-height: 1.4;
  }

  .mn-action-delete-btn:hover {
    background: #fdecec;
    filter: none;
  }

  /* Empty state */
  .mn-empty {
    text-align: center;
    padding: 5rem 2rem;
    color: #9b9a97;
  }

  .mn-empty__icon {
    font-size: 3rem;
    margin-bottom: 1rem;
  }

  .mn-empty p {
    color: #9b9a97;
    margin-bottom: 1.5rem;
    max-width: none;
  }

  /* Note show page */
  .mn-note-view {
    flex: 1;
    padding: 2.5rem 3rem;
    min-width: 0;
    max-width: 760px;
  }

  .mn-note-view__back {
    display: inline-flex;
    align-items: center;
    font-size: 0.825rem;
    color: #9b9a97;
    margin-bottom: 2rem;
    text-decoration: none;
    transition: color 0.1s;
  }

  .mn-note-view__back:hover {
    color: #37352f;
  }

  .mn-note-view__meta {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    margin-bottom: 1.5rem;
    flex-wrap: wrap;
  }

  .mn-note-view__date {
    font-size: 0.825rem;
    color: #9b9a97;
    background: #f0f0ef;
    padding: 0.25rem 0.75rem;
    border-radius: 999px;
  }

  .mn-note-view__category {
    font-size: 0.7rem;
    color: #6b6b6b;
    background: #eeeef0;
    padding: 0.25rem 0.75rem;
    border-radius: 999px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    font-weight: 600;
  }

  .mn-note-view__title {
    font-size: 2rem;
    font-weight: 700;
    color: #37352f;
    margin: 0 0 2rem;
    line-height: 1.25;
  }

  .mn-note-view__content {
    font-size: 1rem;
    color: #37352f;
    line-height: 1.85;
    white-space: pre-wrap;
    margin-bottom: 2rem;
  }

  /* Form wrapper */
  .mn-form-wrapper {
    flex: 1;
    padding: 2.5rem 3rem;
    min-width: 0;
    max-width: 760px;
  }

  .mn-form-back {
    display: inline-flex;
    align-items: center;
    font-size: 0.825rem;
    color: #9b9a97;
    margin-bottom: 2rem;
    text-decoration: none;
    transition: color 0.1s;
  }

  .mn-form-back:hover {
    color: #37352f;
  }

  .mn-form-header {
    margin-bottom: 1.5rem;
  }

  .mn-form-header__label {
    font-size: 0.8rem;
    color: #9b9a97;
    margin: 0.25rem 0 0;
  }

  @media (max-width: 800px) {
    .mn-main,
    .mn-note-view,
    .mn-form-wrapper {
      padding: 1.5rem 1rem 5rem;
    }
  }

  /* Notion-like form fields */
  .mn-form {
    display: flex;
    flex-direction: column;
    max-width: 100%;
    gap: 0;
  }

  .mn-form__date-row {
    display: flex;
    align-items: center;
    gap: 1rem;
    margin-bottom: 1.25rem;
  }

  .mn-form__date-label {
    font-size: 0.825rem;
    color: #9b9a97;
    font-weight: 400;
    flex-shrink: 0;
  }

  .mn-form__date-input {
    font-size: 0.875rem;
    color: #37352f;
    border: 1px solid #e9e9e7;
    background: #f7f7f5;
    padding: 0.35em 0.75em;
    border-radius: 5px;
    font-family: inherit;
  }

  .mn-form__date-input:focus {
    outline: 2px solid var(--color-gold);
    outline-offset: 1px;
    border-color: var(--color-gold);
  }

  .mn-form__title-input {
    font-size: 2rem;
    font-weight: 700;
    color: #37352f;
    border: none;
    outline: none;
    padding: 0.1rem 0;
    margin-bottom: 1rem;
    line-height: 1.25;
    background: transparent;
    width: 100%;
    font-family: inherit;
  }

  .mn-form__title-input::placeholder {
    color: #c4c3c1;
  }

  .mn-form__title-input:focus {
    outline: none;
    box-shadow: none;
    border-color: transparent;
  }

  .mn-form__divider {
    height: 1px;
    background: #e9e9e7;
    margin: 1.25rem 0;
  }

  .mn-form__content-input {
    font-size: 1rem;
    color: #37352f;
    border: none;
    outline: none;
    padding: 0;
    line-height: 1.85;
    background: transparent;
    width: 100%;
    resize: none;
    min-height: 420px;
    font-family: inherit;
  }

  .mn-form__content-input::placeholder {
    color: #c4c3c1;
  }

  .mn-form__content-input:focus {
    outline: none;
    box-shadow: none;
    border-color: transparent;
  }

  .mn-form__actions {
    display: flex;
    gap: 0.75rem;
    align-items: center;
  }

  /* Image upload section in form */
  .mn-form__images-section {
    margin-bottom: 0.5rem;
  }

  .mn-form__images-label {
    font-size: 0.825rem;
    color: #9b9a97;
    margin: 0 0 0.85rem;
  }

  .mn-form__file-input {
    display: block;
    font-size: 0.875rem;
    color: #37352f;
    border: 1.5px dashed #c4c3c1;
    border-radius: 6px;
    padding: 0.75rem 1rem;
    width: 100%;
    cursor: pointer;
    background: #fafaf9;
    transition: border-color 0.15s;
  }

  .mn-form__file-input:hover {
    border-color: #9b9a97;
  }

  .mn-form__file-input:focus {
    outline: 2px solid var(--color-gold);
    outline-offset: 1px;
    border-color: var(--color-gold);
  }

  .mn-form__file-hint {
    font-size: 0.75rem;
    color: #c4c3c1;
    margin: 0.4rem 0 0;
  }

  /* Image grid — used in form (edit/new) and show page */
  /* Grid di form (edit/new) — thumbnail kecil persegi */
  .mn-images-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: 0.75rem;
    margin-bottom: 1rem;
  }

  .mn-image-item {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
  }

  .mn-image-thumb {
    width: 100%;
    aspect-ratio: 1 / 1;
    object-fit: cover;
    border-radius: 6px;
    border: 1px solid #e9e9e7;
    display: block;
  }

  /* Grid di halaman detail — gambar besar, tampil penuh */
  .mn-images-grid--view {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 0.85rem;
    margin-top: 1.75rem;
    margin-bottom: 1.75rem;
  }

  .mn-images-grid--view .mn-image-item {
    gap: 0;
  }

  .mn-images-grid--view .mn-image-thumb {
    aspect-ratio: unset;
    width: 100%;
    height: auto;
    max-height: 480px;
    object-fit: contain;
    background: #f7f7f6;
    border-radius: 8px;
    border: 1px solid #e9e9e7;
    transition: opacity 0.15s;
  }

  .mn-images-grid--view .mn-image-item a:hover .mn-image-thumb {
    opacity: 0.88;
  }

  /* Jika hanya 1 gambar: tampilkan full lebar */
  .mn-images-grid--view:has(.mn-image-item:only-child) {
    grid-template-columns: 1fr;
  }

  .mn-images-grid--view:has(.mn-image-item:only-child) .mn-image-thumb {
    max-height: 600px;
  }

  .mn-image-remove {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.75rem;
    color: #9b1c1c;
    cursor: pointer;
    user-select: none;
  }

  .mn-image-remove input[type="checkbox"] {
    accent-color: #c0392b;
    width: 14px;
    height: 14px;
    padding: 0;
    border: none;
    border-radius: 3px;
  }

  /* Photo badge on note card in index */
  .mn-note-card__img-badge {
    font-size: 0.7rem;
    color: #9b9a97;
    margin-top: 0.25rem;
  }

  /* ── Trix / Action Text: Notion-like overrides ── */

  /* Toolbar: hide buttons not relevant for meeting notes */
  .mn-form trix-toolbar .trix-button--icon-strike,
  .mn-form trix-toolbar .trix-button--icon-quote,
  .mn-form trix-toolbar .trix-button--icon-heading-1,
  .mn-form trix-toolbar .trix-button--icon-code,
  .mn-form trix-toolbar .trix-button--icon-attach,
  .mn-form trix-toolbar .trix-button--icon-undo,
  .mn-form trix-toolbar .trix-button--icon-redo {
    display: none;
  }

  .mn-form trix-toolbar {
    padding: 0 0 0.6rem;
    border-bottom: 1px solid #e9e9e7;
    margin-bottom: 1rem;
  }

  .mn-form trix-toolbar .trix-button-group {
    border: none;
    border-radius: 5px;
    background: #f1f1ef;
    margin-bottom: 0;
    padding: 2px;
    gap: 1px;
  }

  .mn-form trix-toolbar .trix-button {
    border-bottom: none;
    border-radius: 4px;
    height: 1.75rem;
    width: 1.75rem;
    color: #787774;
    padding: 0;
    transition: background 0.1s, color 0.1s;
  }

  .mn-form trix-toolbar .trix-button:not(:first-child) {
    border-left: none;
  }

  .mn-form trix-toolbar .trix-button:hover {
    background: #e3e3e0;
    color: #37352f;
  }

  .mn-form trix-toolbar .trix-button.trix-active {
    background: #e3e3e0;
    color: #37352f;
  }

  /* Editor area */
  trix-editor.mn-form__content-input {
    border: none;
    padding: 0;
    min-height: 400px;
    font-family: inherit;
    font-size: 1rem;
    line-height: 1.85;
    color: #37352f;
    background: transparent;
  }

  /* Placeholder for trix-editor */
  trix-editor.mn-form__content-input:empty::before {
    color: #c4c3c1;
  }

  /* Bullet / numbered lists inside the editor */
  trix-editor ul, .trix-content ul {
    list-style-type: disc;
    padding-left: 1.5rem;
    margin: 0.25rem 0;
  }

  trix-editor ul ul, .trix-content ul ul {
    list-style-type: circle;
  }

  trix-editor ul ul ul, .trix-content ul ul ul {
    list-style-type: square;
  }

  trix-editor ol, .trix-content ol {
    list-style-type: decimal;
    padding-left: 1.5rem;
    margin: 0.25rem 0;
  }

  trix-editor li, .trix-content li {
    margin: 0.15rem 0;
    line-height: 1.75;
  }

  /* Rendered content on show page */
  .mn-note-view__content .trix-content {
    font-size: 1rem;
    line-height: 1.85;
    color: #37352f;
  }

  .mn-note-view__content .trix-content p {
    margin: 0 0 0.25rem;
  }

  /* Bold / italic in rendered content */
  .trix-content strong { font-weight: 600; }
  .trix-content em     { font-style: italic; }

  /* Tighter vertical rhythm between homepage sections on phones. Each of
     these carries the same --space-4/--space-6 (32px/48px) margin as
     desktop, which reads as an oversized gap once the viewport (and the
     content between the gaps) is this narrow -- roughly halve it instead.
     Placed last in the layer so it wins the cascade over each rule's own
     earlier, unconditional margin declaration. */
  @media (max-width: 640px) {
    /* .container's own top/bottom padding (32px) stacks on top of each
       section's margin -- e.g. the last section before .pastor-section
       (which sits right outside .container) had 32px of this padding
       plus that section's own margin, reading as one oversized gap. */
    .container,
    .page-title-standalone {
      padding-block: var(--space-2);
    }

    .schedule-poster,
    .media-grid {
      margin: var(--space-2) 0;
    }

    .home-verse {
      margin: 0 auto var(--space-2);
    }

    .upcoming,
    .biodata-banner {
      margin: var(--space-3) 0;
    }

    .ornament-divider {
      margin: var(--space-3) auto;
    }
  }
}

@layer utilities {
  .txt-center { text-align: center; }
  .txt-muted { color: var(--color-ink-light); }
}

/* ======================================================================== *
 * Night theme -- the public content pages (Beranda, Tentang Kami, Kontak,
 * Sekolah Maranatha, POS PI, Persembahan, Komisi, Galeri, Jadwal) swap the
 * white canvas for a deep blue starfield with a mountain silhouette along
 * the bottom. Opted into per page by ApplicationHelper#night_theme?, which
 * puts .theme-night on <body> and renders the .night-sky backdrop --
 * everything else (pengurus admin, the Biodata / Katekisasi / Penyerahan
 * Anak forms, login) keeps the light canvas, where dark text on white is
 * easier to fill in and proofread.
 *
 * The sky is drawn entirely in CSS (four tiled SVG starfields + gradients +
 * one SVG ridge line), not from a photo: it stays sharp from a 360px phone
 * to a 2560px monitor, costs no image request, and needs no art direction
 * when a section grows taller.
 *
 * The site header deliberately keeps its bright sky-blue gradient -- it is
 * the one accent bar that should not go dark with the rest.
 * ======================================================================== */

@layer base {
  body.theme-night {
    /* Surfaces. Translucent rather than solid so cards read as panes of
       glass over the sky instead of opaque holes punched through it, and
       tinted with the blue of the sky rather than a neutral grey. */
    --color-canvas: rgba(10, 24, 58, 0.72);
    --color-canvas-subtle: rgba(7, 18, 46, 0.78);
    --color-border: rgba(150, 182, 235, 0.24);

    /* Ink. #E9EFFC over the visible sky (#061034 to #0A1D55, the band the
       mountains do not cover) is 14:1 or better; the muted
       --color-ink-light still clears 8:1, so body copy and captions both
       pass AAA. */
    --color-ink: #E9EFFC;
    --color-ink-light: #AEBDD8;
    --color-heading: #F2F6FD;

    /* Navy links vanish against a night sky -- the brand gold is the one
       accent that stays legible on both canvases. */
    --color-link: var(--color-gold-light);

    /* Shadows have to work against dark, not light: a 6% black shadow is
       invisible here, so lean on depth instead of tint. */
    --shadow-sm: 0 1px 2px rgb(0 0 0 / 0.45);
    --shadow-md: 0 8px 22px rgb(0 0 0 / 0.55);
    --shadow-lg: 0 18px 46px rgb(0 0 0 / 0.65);

    /* Renders scrollbars, date pickers and select popups dark to match. */
    color-scheme: dark;

    /* Painted on the canvas behind .night-sky, so overscroll bounce and any
       gap under a short page stay night-coloured. */
    background-color: #050B24;
  }
}

@layer components {
  /* The backdrop. One fixed container rather than a pair of body
     pseudo-elements: the twinkle below needs each star group to be its own
     animatable box, and stacking them as real children keeps the paint
     order readable (sky, stars, ridge) instead of juggling negative
     z-indexes. position: fixed so it holds still while the page scrolls --
     the sky stays the sky rather than sliding away after one screenful.
     Rendered only on night-theme pages (see the layout), so no .theme-night
     scoping is needed here. */
  .night-sky {
    position: fixed;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    background-image:
      radial-gradient(30% 22% at 62% 24%, rgba(96, 156, 255, 0.20), rgba(96, 156, 255, 0) 68%),
      radial-gradient(24% 18% at 38% 34%, rgba(80, 140, 245, 0.16), rgba(80, 140, 245, 0) 70%),
      radial-gradient(42% 26% at 50% 100%, rgba(96, 176, 255, 0.55), rgba(96, 176, 255, 0) 72%),
      radial-gradient(85% 42% at 50% 102%, rgba(40, 110, 210, 0.38), rgba(40, 110, 210, 0) 74%),
      linear-gradient(180deg, #030718 0%, #061034 26%, #0A1D55 55%, #0F2E7A 78%, #17509E 92%, #1E64B8 100%);
  }

  /* Four starfield tiles at pairwise-coprime sizes (640, 809, 887, 1013),
     so their combined pattern only repeats after hundreds of thousands of
     pixels: far past any real viewport, which is what keeps the grid
     invisible at ~1,000 stars on a 1440x900 screen. */
  .night-sky__stars {
    position: absolute;
    inset: 0;
    background-repeat: repeat;
  }

  /* The fine grain, deliberately left static: it is the texture of the sky
     rather than individual stars, and pulsing it would read as the whole
     sky breathing. */
  .night-sky__stars--dust {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='640' height='640' viewBox='0 0 640 640'%3E%3Cg fill='%23cbdfff'%3E%3Ccircle cx='586.2' cy='211.0' r='0.53' opacity='0.63'/%3E%3Ccircle cx='491.4' cy='401.5' r='0.96' opacity='0.48'/%3E%3Ccircle cx='494.7' cy='575.7' r='0.53' opacity='0.57'/%3E%3Ccircle cx='362.8' cy='588.0' r='0.97' opacity='0.4'/%3E%3Ccircle cx='596.0' cy='139.1' r='0.72' opacity='0.41'/%3E%3Ccircle cx='275.7' cy='239.2' r='0.8' opacity='0.53'/%3E%3Ccircle cx='613.0' cy='421.5' r='0.8' opacity='0.74'/%3E%3Ccircle cx='13.5' cy='400.2' r='0.66' opacity='0.54'/%3E%3Ccircle cx='478.3' cy='56.8' r='0.93' opacity='0.46'/%3E%3Ccircle cx='24.2' cy='30.7' r='0.79' opacity='0.87'/%3E%3Ccircle cx='563.6' cy='358.2' r='0.89' opacity='0.85'/%3E%3Ccircle cx='233.5' cy='482.0' r='0.85' opacity='0.68'/%3E%3Ccircle cx='629.5' cy='297.1' r='0.39' opacity='0.88'/%3E%3Ccircle cx='419.5' cy='316.0' r='0.96' opacity='0.49'/%3E%3Ccircle cx='244.2' cy='35.6' r='0.45' opacity='0.53'/%3E%3Ccircle cx='169.6' cy='420.6' r='0.37' opacity='0.6'/%3E%3Ccircle cx='43.5' cy='335.2' r='0.78' opacity='0.48'/%3E%3Ccircle cx='292.7' cy='374.4' r='0.37' opacity='0.63'/%3E%3Ccircle cx='105.0' cy='205.2' r='0.88' opacity='0.8'/%3E%3Ccircle cx='438.2' cy='383.7' r='0.69' opacity='0.52'/%3E%3Ccircle cx='448.3' cy='558.9' r='0.63' opacity='0.69'/%3E%3Ccircle cx='20.1' cy='169.9' r='0.89' opacity='0.63'/%3E%3Ccircle cx='232.2' cy='545.4' r='0.7' opacity='0.86'/%3E%3Ccircle cx='80.2' cy='521.4' r='0.75' opacity='0.82'/%3E%3Ccircle cx='296.5' cy='35.8' r='0.96' opacity='0.72'/%3E%3Ccircle cx='488.6' cy='425.5' r='0.44' opacity='0.51'/%3E%3Ccircle cx='214.6' cy='433.3' r='0.99' opacity='0.9'/%3E%3Ccircle cx='486.5' cy='536.1' r='0.71' opacity='0.7'/%3E%3Ccircle cx='48.1' cy='154.6' r='0.41' opacity='0.57'/%3E%3Ccircle cx='136.2' cy='40.8' r='0.83' opacity='0.67'/%3E%3Ccircle cx='393.9' cy='552.1' r='0.56' opacity='0.81'/%3E%3Ccircle cx='3.0' cy='328.9' r='0.36' opacity='0.57'/%3E%3Ccircle cx='341.5' cy='319.3' r='0.81' opacity='0.44'/%3E%3Ccircle cx='493.5' cy='586.6' r='0.79' opacity='0.64'/%3E%3Ccircle cx='97.4' cy='609.5' r='0.47' opacity='0.94'/%3E%3Ccircle cx='177.0' cy='427.0' r='0.99' opacity='0.55'/%3E%3Ccircle cx='69.1' cy='636.5' r='0.97' opacity='0.55'/%3E%3Ccircle cx='93.9' cy='479.1' r='0.6' opacity='0.75'/%3E%3Ccircle cx='634.2' cy='510.7' r='0.56' opacity='0.77'/%3E%3Ccircle cx='462.3' cy='213.3' r='0.37' opacity='0.81'/%3E%3Ccircle cx='218.5' cy='369.1' r='0.69' opacity='0.57'/%3E%3Ccircle cx='131.3' cy='322.5' r='0.39' opacity='0.91'/%3E%3Ccircle cx='41.0' cy='438.0' r='0.57' opacity='0.67'/%3E%3Ccircle cx='634.8' cy='309.8' r='0.88' opacity='0.48'/%3E%3Ccircle cx='111.9' cy='6.7' r='0.73' opacity='0.42'/%3E%3Ccircle cx='32.5' cy='219.2' r='0.64' opacity='0.84'/%3E%3Ccircle cx='7.6' cy='613.2' r='0.65' opacity='0.91'/%3E%3Ccircle cx='164.3' cy='584.2' r='0.66' opacity='0.91'/%3E%3Ccircle cx='136.1' cy='320.3' r='0.47' opacity='0.7'/%3E%3Ccircle cx='80.1' cy='608.4' r='0.59' opacity='0.75'/%3E%3Ccircle cx='170.5' cy='222.0' r='0.72' opacity='0.74'/%3E%3Ccircle cx='420.0' cy='229.0' r='0.68' opacity='0.44'/%3E%3Ccircle cx='20.6' cy='625.7' r='0.42' opacity='0.57'/%3E%3Ccircle cx='353.3' cy='528.4' r='0.85' opacity='0.69'/%3E%3Ccircle cx='361.7' cy='621.1' r='0.37' opacity='0.91'/%3E%3Ccircle cx='592.9' cy='630.4' r='0.87' opacity='0.37'/%3E%3Ccircle cx='26.4' cy='636.7' r='0.8' opacity='0.77'/%3E%3Ccircle cx='599.8' cy='44.4' r='0.87' opacity='0.61'/%3E%3Ccircle cx='1.6' cy='184.2' r='0.61' opacity='0.79'/%3E%3Ccircle cx='580.6' cy='233.6' r='0.64' opacity='0.79'/%3E%3Ccircle cx='45.7' cy='327.8' r='0.38' opacity='0.71'/%3E%3Ccircle cx='530.5' cy='362.2' r='0.72' opacity='0.58'/%3E%3Ccircle cx='570.5' cy='177.7' r='0.91' opacity='0.75'/%3E%3Ccircle cx='554.1' cy='630.2' r='0.99' opacity='0.45'/%3E%3Ccircle cx='8.9' cy='409.0' r='0.71' opacity='0.47'/%3E%3Ccircle cx='422.9' cy='58.9' r='0.44' opacity='0.4'/%3E%3Ccircle cx='350.2' cy='115.5' r='0.88' opacity='0.93'/%3E%3Ccircle cx='112.1' cy='508.2' r='0.51' opacity='0.82'/%3E%3Ccircle cx='101.8' cy='377.1' r='0.56' opacity='0.57'/%3E%3Ccircle cx='404.7' cy='249.0' r='0.62' opacity='0.79'/%3E%3Ccircle cx='347.9' cy='37.4' r='0.71' opacity='0.71'/%3E%3Ccircle cx='404.4' cy='618.0' r='0.75' opacity='0.73'/%3E%3Ccircle cx='478.6' cy='488.7' r='0.45' opacity='0.59'/%3E%3Ccircle cx='107.1' cy='303.4' r='0.91' opacity='0.77'/%3E%3Ccircle cx='486.3' cy='538.3' r='0.38' opacity='0.5'/%3E%3Ccircle cx='319.4' cy='32.1' r='0.94' opacity='0.36'/%3E%3Ccircle cx='12.3' cy='82.0' r='0.72' opacity='0.84'/%3E%3Ccircle cx='542.0' cy='15.3' r='0.37' opacity='0.86'/%3E%3Ccircle cx='416.2' cy='622.5' r='0.96' opacity='0.88'/%3E%3Ccircle cx='494.0' cy='603.4' r='0.72' opacity='0.62'/%3E%3Ccircle cx='316.9' cy='306.9' r='0.71' opacity='0.86'/%3E%3Ccircle cx='83.2' cy='137.1' r='0.52' opacity='0.65'/%3E%3Ccircle cx='20.2' cy='271.8' r='0.47' opacity='0.72'/%3E%3Ccircle cx='461.0' cy='348.4' r='0.97' opacity='0.64'/%3E%3Ccircle cx='516.7' cy='383.0' r='0.86' opacity='0.91'/%3E%3Ccircle cx='36.2' cy='14.9' r='0.99' opacity='0.84'/%3E%3Ccircle cx='64.7' cy='482.2' r='0.68' opacity='0.65'/%3E%3Ccircle cx='350.3' cy='64.8' r='0.5' opacity='0.94'/%3E%3Ccircle cx='615.9' cy='27.9' r='0.52' opacity='0.71'/%3E%3Ccircle cx='534.7' cy='91.7' r='0.9' opacity='0.74'/%3E%3Ccircle cx='405.4' cy='490.7' r='0.49' opacity='0.87'/%3E%3Ccircle cx='281.9' cy='436.4' r='0.58' opacity='0.94'/%3E%3Ccircle cx='384.8' cy='322.3' r='0.52' opacity='0.87'/%3E%3Ccircle cx='446.1' cy='548.9' r='0.68' opacity='0.94'/%3E%3Ccircle cx='490.1' cy='17.2' r='0.97' opacity='0.84'/%3E%3Ccircle cx='484.0' cy='468.3' r='0.73' opacity='0.76'/%3E%3Ccircle cx='457.6' cy='357.3' r='0.53' opacity='0.45'/%3E%3Ccircle cx='585.2' cy='573.6' r='0.58' opacity='0.94'/%3E%3Ccircle cx='313.8' cy='326.7' r='0.82' opacity='0.46'/%3E%3Ccircle cx='503.5' cy='184.0' r='0.78' opacity='0.37'/%3E%3Ccircle cx='0.0' cy='551.8' r='0.95' opacity='0.54'/%3E%3Ccircle cx='52.8' cy='112.8' r='0.61' opacity='0.93'/%3E%3Ccircle cx='369.7' cy='157.0' r='0.47' opacity='0.75'/%3E%3Ccircle cx='36.5' cy='563.4' r='0.45' opacity='0.87'/%3E%3Ccircle cx='388.4' cy='615.8' r='0.37' opacity='0.51'/%3E%3Ccircle cx='375.1' cy='258.0' r='0.39' opacity='0.67'/%3E%3Ccircle cx='218.0' cy='550.7' r='0.59' opacity='0.81'/%3E%3Ccircle cx='300.5' cy='276.2' r='0.81' opacity='0.76'/%3E%3Ccircle cx='63.6' cy='174.6' r='0.65' opacity='0.95'/%3E%3Ccircle cx='115.5' cy='185.6' r='1.0' opacity='0.65'/%3E%3Ccircle cx='381.0' cy='212.6' r='0.99' opacity='0.58'/%3E%3Ccircle cx='373.4' cy='615.9' r='0.39' opacity='0.75'/%3E%3Ccircle cx='250.2' cy='378.9' r='0.73' opacity='0.87'/%3E%3Ccircle cx='12.7' cy='516.4' r='0.49' opacity='0.48'/%3E%3Ccircle cx='615.9' cy='581.4' r='0.52' opacity='0.8'/%3E%3Ccircle cx='149.5' cy='408.2' r='0.38' opacity='0.69'/%3E%3Ccircle cx='186.2' cy='302.5' r='0.83' opacity='0.48'/%3E%3Ccircle cx='545.5' cy='366.8' r='0.93' opacity='0.43'/%3E%3Ccircle cx='194.8' cy='113.8' r='0.45' opacity='0.73'/%3E%3Ccircle cx='251.3' cy='217.6' r='0.72' opacity='0.8'/%3E%3Ccircle cx='66.3' cy='204.3' r='0.62' opacity='0.48'/%3E%3Ccircle cx='473.9' cy='63.2' r='0.37' opacity='0.41'/%3E%3Ccircle cx='527.6' cy='121.0' r='0.76' opacity='0.86'/%3E%3Ccircle cx='583.9' cy='212.2' r='0.43' opacity='0.85'/%3E%3Ccircle cx='276.9' cy='209.0' r='0.36' opacity='0.72'/%3E%3Ccircle cx='616.1' cy='590.9' r='0.43' opacity='0.73'/%3E%3Ccircle cx='460.2' cy='311.7' r='0.83' opacity='0.9'/%3E%3Ccircle cx='249.3' cy='42.0' r='0.61' opacity='0.57'/%3E%3Ccircle cx='635.4' cy='232.9' r='0.7' opacity='0.95'/%3E%3Ccircle cx='145.3' cy='405.2' r='0.72' opacity='0.61'/%3E%3Ccircle cx='318.9' cy='330.6' r='0.48' opacity='0.91'/%3E%3Ccircle cx='422.4' cy='477.3' r='0.45' opacity='0.62'/%3E%3Ccircle cx='5.9' cy='622.7' r='0.37' opacity='0.83'/%3E%3Ccircle cx='570.3' cy='508.3' r='0.9' opacity='0.56'/%3E%3Ccircle cx='457.9' cy='313.2' r='0.73' opacity='0.68'/%3E%3Ccircle cx='240.1' cy='203.7' r='0.65' opacity='0.93'/%3E%3Ccircle cx='291.6' cy='510.4' r='0.66' opacity='0.76'/%3E%3Ccircle cx='464.8' cy='363.7' r='0.36' opacity='0.48'/%3E%3Ccircle cx='514.0' cy='54.8' r='0.57' opacity='0.6'/%3E%3Ccircle cx='441.2' cy='495.7' r='0.6' opacity='0.53'/%3E%3Ccircle cx='376.1' cy='557.5' r='0.49' opacity='0.41'/%3E%3Ccircle cx='28.6' cy='590.9' r='0.68' opacity='0.44'/%3E%3Ccircle cx='639.9' cy='623.5' r='0.96' opacity='0.54'/%3E%3Ccircle cx='1.9' cy='587.1' r='0.42' opacity='0.62'/%3E%3Ccircle cx='323.4' cy='623.2' r='0.67' opacity='0.86'/%3E%3Ccircle cx='458.0' cy='11.0' r='0.74' opacity='0.51'/%3E%3Ccircle cx='131.1' cy='41.3' r='0.55' opacity='0.4'/%3E%3Ccircle cx='458.6' cy='453.9' r='0.85' opacity='0.71'/%3E%3Ccircle cx='179.7' cy='286.9' r='0.48' opacity='0.78'/%3E%3Ccircle cx='360.3' cy='237.9' r='0.84' opacity='0.76'/%3E%3Ccircle cx='187.7' cy='469.7' r='0.81' opacity='0.47'/%3E%3Ccircle cx='224.8' cy='199.3' r='0.71' opacity='0.8'/%3E%3Ccircle cx='276.1' cy='163.0' r='0.96' opacity='0.66'/%3E%3Ccircle cx='150.7' cy='462.2' r='0.45' opacity='0.71'/%3E%3Ccircle cx='148.7' cy='190.4' r='0.84' opacity='0.51'/%3E%3Ccircle cx='522.2' cy='8.8' r='0.87' opacity='0.95'/%3E%3Ccircle cx='179.8' cy='168.3' r='0.46' opacity='0.94'/%3E%3Ccircle cx='157.9' cy='193.2' r='0.94' opacity='0.88'/%3E%3Ccircle cx='229.4' cy='390.0' r='0.84' opacity='0.53'/%3E%3Ccircle cx='34.8' cy='445.0' r='0.67' opacity='0.83'/%3E%3Ccircle cx='174.4' cy='143.0' r='0.66' opacity='0.81'/%3E%3Ccircle cx='488.8' cy='503.2' r='0.51' opacity='0.59'/%3E%3Ccircle cx='89.7' cy='460.5' r='0.71' opacity='0.71'/%3E%3Ccircle cx='472.4' cy='219.0' r='0.46' opacity='0.63'/%3E%3Ccircle cx='392.5' cy='41.3' r='0.66' opacity='0.47'/%3E%3Ccircle cx='425.7' cy='314.0' r='0.83' opacity='0.62'/%3E%3Ccircle cx='387.1' cy='180.0' r='0.98' opacity='0.9'/%3E%3Ccircle cx='15.0' cy='213.3' r='0.45' opacity='0.56'/%3E%3Ccircle cx='286.1' cy='377.7' r='0.81' opacity='0.67'/%3E%3Ccircle cx='477.2' cy='195.3' r='0.75' opacity='0.87'/%3E%3Ccircle cx='220.9' cy='376.3' r='0.75' opacity='0.46'/%3E%3Ccircle cx='501.4' cy='599.1' r='0.93' opacity='0.42'/%3E%3Ccircle cx='457.9' cy='483.1' r='0.55' opacity='0.63'/%3E%3Ccircle cx='274.6' cy='445.1' r='0.42' opacity='0.83'/%3E%3Ccircle cx='286.2' cy='250.3' r='1.0' opacity='0.56'/%3E%3Ccircle cx='608.4' cy='615.5' r='0.77' opacity='0.74'/%3E%3Ccircle cx='429.7' cy='313.0' r='0.36' opacity='0.78'/%3E%3Ccircle cx='89.0' cy='220.9' r='0.91' opacity='0.76'/%3E%3Ccircle cx='542.8' cy='447.6' r='0.66' opacity='0.55'/%3E%3Ccircle cx='469.6' cy='385.0' r='0.65' opacity='0.57'/%3E%3Ccircle cx='632.4' cy='205.3' r='0.85' opacity='0.64'/%3E%3Ccircle cx='287.2' cy='600.4' r='0.64' opacity='0.86'/%3E%3Ccircle cx='10.5' cy='500.3' r='0.7' opacity='0.44'/%3E%3Ccircle cx='489.3' cy='21.2' r='0.51' opacity='0.87'/%3E%3Ccircle cx='320.3' cy='27.6' r='1.0' opacity='0.66'/%3E%3Ccircle cx='263.8' cy='12.8' r='0.44' opacity='0.93'/%3E%3Ccircle cx='433.9' cy='620.9' r='0.62' opacity='0.47'/%3E%3Ccircle cx='95.6' cy='342.4' r='0.83' opacity='0.54'/%3E%3Ccircle cx='275.8' cy='529.1' r='0.61' opacity='0.82'/%3E%3Ccircle cx='246.1' cy='363.5' r='0.49' opacity='0.83'/%3E%3Ccircle cx='471.6' cy='311.4' r='0.54' opacity='0.87'/%3E%3Ccircle cx='637.1' cy='234.6' r='0.79' opacity='0.67'/%3E%3Ccircle cx='58.8' cy='203.2' r='0.42' opacity='0.85'/%3E%3Ccircle cx='251.3' cy='242.0' r='0.55' opacity='0.36'/%3E%3Ccircle cx='509.7' cy='426.0' r='0.68' opacity='0.52'/%3E%3Ccircle cx='627.1' cy='469.2' r='0.78' opacity='0.84'/%3E%3Ccircle cx='289.8' cy='334.1' r='0.7' opacity='0.45'/%3E%3Ccircle cx='488.6' cy='522.3' r='0.71' opacity='0.71'/%3E%3Ccircle cx='321.2' cy='152.5' r='0.76' opacity='0.58'/%3E%3Ccircle cx='25.5' cy='74.4' r='0.98' opacity='0.54'/%3E%3Ccircle cx='550.6' cy='270.4' r='0.74' opacity='0.69'/%3E%3Ccircle cx='200.2' cy='615.6' r='0.66' opacity='0.51'/%3E%3Ccircle cx='223.0' cy='635.9' r='0.41' opacity='0.71'/%3E%3Ccircle cx='319.4' cy='91.1' r='0.5' opacity='0.7'/%3E%3Ccircle cx='368.0' cy='79.3' r='0.85' opacity='0.57'/%3E%3Ccircle cx='194.1' cy='458.5' r='0.6' opacity='0.5'/%3E%3Ccircle cx='344.1' cy='616.0' r='0.85' opacity='0.53'/%3E%3Ccircle cx='47.6' cy='381.8' r='0.76' opacity='0.85'/%3E%3Ccircle cx='106.3' cy='591.8' r='0.98' opacity='0.42'/%3E%3Ccircle cx='546.7' cy='533.2' r='0.63' opacity='0.86'/%3E%3Ccircle cx='460.0' cy='460.2' r='0.67' opacity='0.54'/%3E%3Ccircle cx='35.5' cy='312.3' r='0.85' opacity='0.41'/%3E%3Ccircle cx='241.2' cy='503.7' r='0.77' opacity='0.83'/%3E%3Ccircle cx='182.9' cy='638.1' r='0.82' opacity='0.92'/%3E%3Ccircle cx='613.7' cy='255.9' r='0.64' opacity='0.53'/%3E%3Ccircle cx='183.9' cy='234.7' r='0.97' opacity='0.58'/%3E%3Ccircle cx='586.1' cy='396.9' r='0.83' opacity='0.76'/%3E%3Ccircle cx='97.4' cy='359.2' r='0.61' opacity='0.69'/%3E%3Ccircle cx='125.0' cy='350.6' r='0.68' opacity='0.7'/%3E%3Ccircle cx='411.2' cy='436.9' r='0.52' opacity='0.74'/%3E%3Ccircle cx='578.9' cy='524.3' r='0.42' opacity='0.72'/%3E%3Ccircle cx='14.2' cy='214.5' r='0.63' opacity='0.67'/%3E%3Ccircle cx='13.7' cy='191.7' r='0.81' opacity='0.76'/%3E%3Ccircle cx='142.9' cy='203.8' r='0.52' opacity='0.84'/%3E%3Ccircle cx='525.6' cy='75.6' r='0.71' opacity='0.6'/%3E%3Ccircle cx='215.6' cy='59.7' r='0.77' opacity='0.53'/%3E%3Ccircle cx='257.0' cy='67.9' r='0.84' opacity='0.78'/%3E%3Ccircle cx='561.5' cy='568.0' r='0.82' opacity='0.63'/%3E%3Ccircle cx='213.4' cy='259.6' r='0.98' opacity='0.86'/%3E%3Ccircle cx='481.3' cy='430.0' r='0.89' opacity='0.87'/%3E%3Ccircle cx='105.3' cy='391.8' r='0.77' opacity='0.38'/%3E%3Ccircle cx='398.7' cy='249.0' r='0.54' opacity='0.43'/%3E%3Ccircle cx='390.5' cy='362.0' r='0.62' opacity='0.88'/%3E%3Ccircle cx='148.1' cy='380.7' r='0.52' opacity='0.35'/%3E%3Ccircle cx='29.1' cy='147.1' r='0.87' opacity='0.92'/%3E%3Ccircle cx='540.0' cy='63.5' r='0.72' opacity='0.92'/%3E%3Ccircle cx='462.7' cy='545.9' r='0.4' opacity='0.76'/%3E%3Ccircle cx='502.8' cy='320.3' r='0.64' opacity='0.38'/%3E%3Ccircle cx='391.0' cy='204.2' r='0.61' opacity='0.86'/%3E%3Ccircle cx='537.7' cy='476.5' r='0.99' opacity='0.6'/%3E%3Ccircle cx='628.4' cy='535.5' r='0.67' opacity='0.56'/%3E%3Ccircle cx='349.4' cy='37.6' r='0.7' opacity='0.91'/%3E%3Ccircle cx='80.9' cy='81.2' r='0.44' opacity='0.44'/%3E%3Ccircle cx='621.9' cy='78.7' r='0.87' opacity='0.38'/%3E%3Ccircle cx='579.7' cy='248.7' r='0.47' opacity='0.42'/%3E%3Ccircle cx='66.0' cy='405.8' r='0.8' opacity='0.46'/%3E%3Ccircle cx='184.9' cy='479.4' r='0.36' opacity='0.69'/%3E%3Ccircle cx='558.1' cy='217.4' r='0.45' opacity='0.55'/%3E%3Ccircle cx='333.9' cy='179.8' r='0.43' opacity='0.55'/%3E%3Ccircle cx='308.4' cy='388.5' r='0.61' opacity='0.75'/%3E%3Ccircle cx='620.5' cy='523.1' r='0.66' opacity='0.77'/%3E%3Ccircle cx='234.6' cy='121.0' r='0.94' opacity='0.52'/%3E%3Ccircle cx='70.6' cy='129.9' r='0.4' opacity='0.36'/%3E%3Ccircle cx='602.2' cy='213.5' r='0.88' opacity='0.57'/%3E%3Ccircle cx='3.5' cy='508.6' r='0.86' opacity='0.36'/%3E%3Ccircle cx='159.3' cy='240.6' r='0.57' opacity='0.87'/%3E%3Ccircle cx='261.7' cy='564.3' r='0.98' opacity='0.63'/%3E%3Ccircle cx='184.3' cy='463.7' r='0.82' opacity='0.74'/%3E%3Ccircle cx='354.9' cy='168.9' r='0.39' opacity='0.48'/%3E%3Ccircle cx='239.9' cy='233.6' r='0.83' opacity='0.59'/%3E%3C/g%3E%3C/svg%3E");
    background-size: 640px 640px;
  }

  .night-sky__stars--a {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='809' height='809' viewBox='0 0 809 809'%3E%3Cdefs%3E%3CradialGradient id='h'%3E%3Cstop offset='0' stop-color='%23bcd8ff' stop-opacity='0.55'/%3E%3Cstop offset='0.4' stop-color='%237fb2ff' stop-opacity='0.16'/%3E%3Cstop offset='1' stop-color='%237fb2ff' stop-opacity='0'/%3E%3C/radialGradient%3E%3C/defs%3E%3Cg%3E%3Ccircle cx='357.3' cy='76.9' r='6.76' fill='url(%23h)'/%3E%3Ccircle cx='725.1' cy='41.8' r='6.53' fill='url(%23h)'/%3E%3Ccircle cx='521.8' cy='696.2' r='8.76' fill='url(%23h)'/%3E%3Ccircle cx='321.4' cy='650.1' r='10.69' fill='url(%23h)'/%3E%3Ccircle cx='668.9' cy='69.5' r='7.17' fill='url(%23h)'/%3E%3Ccircle cx='795.8' cy='175.0' r='9.9' fill='url(%23h)'/%3E%3Ccircle cx='602.1' cy='304.6' r='10.22' fill='url(%23h)'/%3E%3Ccircle cx='15.2' cy='530.4' r='5.72' fill='url(%23h)'/%3E%3Ccircle cx='297.9' cy='472.9' r='7.26' fill='url(%23h)'/%3E%3Ccircle cx='353.9' cy='560.3' r='5.83' fill='url(%23h)'/%3E%3Ccircle cx='332.7' cy='482.2' r='5.82' fill='url(%23h)'/%3E%3Ccircle cx='34.6' cy='543.9' r='10.3' fill='url(%23h)'/%3E%3Ccircle cx='351.8' cy='308.0' r='5.83' fill='url(%23h)'/%3E%3Ccircle cx='484.5' cy='171.9' r='6.8' fill='url(%23h)'/%3E%3Ccircle cx='461.8' cy='264.0' r='6.3' fill='url(%23h)'/%3E%3Ccircle cx='742.4' cy='552.8' r='9.12' fill='url(%23h)'/%3E%3C/g%3E%3Cg fill='%23eaf3ff'%3E%3Ccircle cx='357.3' cy='76.9' r='1.66' opacity='0.87'/%3E%3Ccircle cx='725.1' cy='41.8' r='1.29' opacity='0.81'/%3E%3Ccircle cx='521.8' cy='696.2' r='2.14' opacity='0.94'/%3E%3Ccircle cx='321.4' cy='650.1' r='2.19' opacity='0.81'/%3E%3Ccircle cx='668.9' cy='69.5' r='1.57' opacity='0.97'/%3E%3Ccircle cx='795.8' cy='175.0' r='1.87' opacity='0.94'/%3E%3Ccircle cx='602.1' cy='304.6' r='2.35' opacity='0.77'/%3E%3Ccircle cx='15.2' cy='530.4' r='1.39' opacity='0.89'/%3E%3Ccircle cx='297.9' cy='472.9' r='1.49' opacity='0.98'/%3E%3Ccircle cx='353.9' cy='560.3' r='1.4' opacity='0.9'/%3E%3Ccircle cx='332.7' cy='482.2' r='1.42' opacity='0.86'/%3E%3Ccircle cx='34.6' cy='543.9' r='2.16' opacity='0.91'/%3E%3Ccircle cx='351.8' cy='308.0' r='1.28' opacity='0.89'/%3E%3Ccircle cx='484.5' cy='171.9' r='1.39' opacity='0.95'/%3E%3Ccircle cx='461.8' cy='264.0' r='1.32' opacity='0.82'/%3E%3Ccircle cx='742.4' cy='552.8' r='2.23' opacity='0.82'/%3E%3Ccircle cx='530.4' cy='790.8' r='0.7' opacity='0.51'/%3E%3Ccircle cx='165.7' cy='305.6' r='0.97' opacity='0.7'/%3E%3Ccircle cx='597.4' cy='368.6' r='0.83' opacity='0.61'/%3E%3Ccircle cx='103.3' cy='286.2' r='0.78' opacity='0.76'/%3E%3Ccircle cx='229.8' cy='683.0' r='0.81' opacity='0.5'/%3E%3Ccircle cx='420.1' cy='472.1' r='0.96' opacity='0.96'/%3E%3Ccircle cx='687.8' cy='318.2' r='1.47' opacity='0.7'/%3E%3Ccircle cx='583.3' cy='417.3' r='0.77' opacity='0.96'/%3E%3Ccircle cx='347.6' cy='749.3' r='0.98' opacity='0.53'/%3E%3Ccircle cx='493.6' cy='132.4' r='0.86' opacity='0.72'/%3E%3Ccircle cx='348.3' cy='582.6' r='0.74' opacity='0.74'/%3E%3Ccircle cx='537.7' cy='696.9' r='1.1' opacity='0.61'/%3E%3Ccircle cx='675.9' cy='437.8' r='0.91' opacity='0.88'/%3E%3Ccircle cx='507.1' cy='142.7' r='1.33' opacity='0.68'/%3E%3Ccircle cx='515.4' cy='749.8' r='1.04' opacity='0.55'/%3E%3Ccircle cx='33.3' cy='781.0' r='0.84' opacity='0.8'/%3E%3Ccircle cx='340.5' cy='32.2' r='1.35' opacity='0.74'/%3E%3Ccircle cx='431.0' cy='553.0' r='1.49' opacity='0.65'/%3E%3Ccircle cx='103.3' cy='261.9' r='0.78' opacity='0.56'/%3E%3Ccircle cx='372.1' cy='237.6' r='1.46' opacity='0.9'/%3E%3Ccircle cx='419.6' cy='475.2' r='1.29' opacity='0.68'/%3E%3Ccircle cx='582.0' cy='614.6' r='1.47' opacity='0.66'/%3E%3Ccircle cx='394.6' cy='13.5' r='1.33' opacity='0.73'/%3E%3Ccircle cx='559.1' cy='624.0' r='1.46' opacity='0.99'/%3E%3Ccircle cx='210.7' cy='449.0' r='1.1' opacity='0.94'/%3E%3Ccircle cx='557.3' cy='87.2' r='1.4' opacity='0.56'/%3E%3Ccircle cx='767.1' cy='168.3' r='1.37' opacity='0.73'/%3E%3Ccircle cx='200.8' cy='559.1' r='1.36' opacity='0.98'/%3E%3Ccircle cx='243.3' cy='141.7' r='1.24' opacity='0.72'/%3E%3Ccircle cx='719.8' cy='620.4' r='1.19' opacity='0.61'/%3E%3Ccircle cx='769.0' cy='270.9' r='1.23' opacity='0.68'/%3E%3Ccircle cx='588.2' cy='16.6' r='1.16' opacity='0.52'/%3E%3Ccircle cx='5.5' cy='634.8' r='0.75' opacity='0.97'/%3E%3Ccircle cx='777.7' cy='83.1' r='0.81' opacity='0.66'/%3E%3C/g%3E%3C/svg%3E");
    background-size: 809px 809px;
  }

  .night-sky__stars--b {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='1013' height='1013' viewBox='0 0 1013 1013'%3E%3Cdefs%3E%3CradialGradient id='h'%3E%3Cstop offset='0' stop-color='%23bcd8ff' stop-opacity='0.55'/%3E%3Cstop offset='0.4' stop-color='%237fb2ff' stop-opacity='0.16'/%3E%3Cstop offset='1' stop-color='%237fb2ff' stop-opacity='0'/%3E%3C/radialGradient%3E%3C/defs%3E%3Cg%3E%3Ccircle cx='403.4' cy='109.8' r='5.16' fill='url(%23h)'/%3E%3Ccircle cx='238.3' cy='297.9' r='9.8' fill='url(%23h)'/%3E%3Ccircle cx='138.3' cy='464.8' r='7.88' fill='url(%23h)'/%3E%3Ccircle cx='742.4' cy='396.6' r='10.72' fill='url(%23h)'/%3E%3Ccircle cx='256.1' cy='6.7' r='8.56' fill='url(%23h)'/%3E%3Ccircle cx='894.7' cy='0.5' r='5.68' fill='url(%23h)'/%3E%3Ccircle cx='291.0' cy='633.4' r='5.55' fill='url(%23h)'/%3E%3Ccircle cx='613.6' cy='97.6' r='5.48' fill='url(%23h)'/%3E%3Ccircle cx='901.6' cy='335.7' r='7.51' fill='url(%23h)'/%3E%3Ccircle cx='85.7' cy='809.1' r='7.83' fill='url(%23h)'/%3E%3Ccircle cx='618.9' cy='311.3' r='11.13' fill='url(%23h)'/%3E%3Ccircle cx='883.0' cy='23.9' r='4.95' fill='url(%23h)'/%3E%3Ccircle cx='332.4' cy='600.1' r='7.93' fill='url(%23h)'/%3E%3Ccircle cx='474.0' cy='677.0' r='8.95' fill='url(%23h)'/%3E%3Ccircle cx='295.4' cy='553.7' r='10.67' fill='url(%23h)'/%3E%3C/g%3E%3Cg fill='%23eaf3ff'%3E%3Ccircle cx='403.4' cy='109.8' r='1.3' opacity='0.92'/%3E%3Ccircle cx='238.3' cy='297.9' r='2.02' opacity='0.86'/%3E%3Ccircle cx='138.3' cy='464.8' r='1.66' opacity='0.85'/%3E%3Ccircle cx='742.4' cy='396.6' r='2.18' opacity='0.76'/%3E%3Ccircle cx='256.1' cy='6.7' r='2.26' opacity='0.94'/%3E%3Ccircle cx='894.7' cy='0.5' r='1.37' opacity='0.97'/%3E%3Ccircle cx='291.0' cy='633.4' r='1.31' opacity='0.92'/%3E%3Ccircle cx='613.6' cy='97.6' r='1.48' opacity='0.92'/%3E%3Ccircle cx='901.6' cy='335.7' r='1.75' opacity='0.92'/%3E%3Ccircle cx='85.7' cy='809.1' r='2.09' opacity='0.84'/%3E%3Ccircle cx='618.9' cy='311.3' r='2.24' opacity='0.83'/%3E%3Ccircle cx='883.0' cy='23.9' r='1.35' opacity='0.98'/%3E%3Ccircle cx='332.4' cy='600.1' r='1.54' opacity='0.86'/%3E%3Ccircle cx='474.0' cy='677.0' r='2.03' opacity='0.94'/%3E%3Ccircle cx='295.4' cy='553.7' r='2.0' opacity='0.87'/%3E%3Ccircle cx='155.6' cy='503.9' r='0.75' opacity='0.66'/%3E%3Ccircle cx='451.7' cy='379.6' r='1.15' opacity='0.71'/%3E%3Ccircle cx='801.2' cy='353.4' r='1.32' opacity='0.6'/%3E%3Ccircle cx='133.3' cy='218.0' r='1.32' opacity='0.85'/%3E%3Ccircle cx='252.3' cy='749.9' r='1.34' opacity='0.68'/%3E%3Ccircle cx='734.1' cy='13.8' r='1.02' opacity='0.63'/%3E%3Ccircle cx='815.4' cy='348.4' r='0.9' opacity='0.56'/%3E%3Ccircle cx='978.0' cy='183.5' r='1.43' opacity='0.77'/%3E%3Ccircle cx='412.8' cy='540.4' r='1.03' opacity='0.6'/%3E%3Ccircle cx='165.9' cy='650.4' r='1.09' opacity='0.54'/%3E%3Ccircle cx='675.6' cy='381.3' r='1.2' opacity='0.53'/%3E%3Ccircle cx='245.8' cy='435.1' r='0.87' opacity='0.85'/%3E%3Ccircle cx='357.5' cy='117.8' r='1.18' opacity='0.71'/%3E%3Ccircle cx='175.5' cy='201.0' r='0.91' opacity='0.65'/%3E%3Ccircle cx='945.8' cy='234.2' r='0.97' opacity='0.52'/%3E%3Ccircle cx='822.0' cy='541.0' r='1.31' opacity='0.53'/%3E%3Ccircle cx='198.3' cy='744.8' r='1.37' opacity='0.61'/%3E%3Ccircle cx='986.3' cy='77.3' r='0.79' opacity='0.98'/%3E%3Ccircle cx='102.7' cy='969.3' r='1.36' opacity='0.66'/%3E%3Ccircle cx='441.4' cy='662.7' r='1.31' opacity='0.58'/%3E%3Ccircle cx='267.3' cy='50.0' r='1.33' opacity='0.65'/%3E%3Ccircle cx='637.0' cy='805.8' r='0.71' opacity='0.93'/%3E%3Ccircle cx='806.2' cy='376.5' r='0.92' opacity='0.79'/%3E%3Ccircle cx='358.8' cy='229.4' r='1.14' opacity='0.87'/%3E%3Ccircle cx='786.8' cy='825.7' r='1.02' opacity='0.79'/%3E%3Ccircle cx='470.0' cy='170.8' r='0.78' opacity='0.92'/%3E%3Ccircle cx='622.9' cy='351.2' r='1.07' opacity='0.69'/%3E%3Ccircle cx='584.1' cy='397.9' r='0.79' opacity='0.66'/%3E%3Ccircle cx='37.4' cy='426.0' r='1.24' opacity='0.74'/%3E%3Ccircle cx='376.8' cy='89.0' r='0.88' opacity='0.79'/%3E%3C/g%3E%3C/svg%3E");
    background-size: 1013px 1013px;
  }

  .night-sky__stars--c {
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='887' height='887' viewBox='0 0 887 887'%3E%3Cdefs%3E%3CradialGradient id='h'%3E%3Cstop offset='0' stop-color='%23bcd8ff' stop-opacity='0.55'/%3E%3Cstop offset='0.4' stop-color='%237fb2ff' stop-opacity='0.16'/%3E%3Cstop offset='1' stop-color='%237fb2ff' stop-opacity='0'/%3E%3C/radialGradient%3E%3C/defs%3E%3Cg%3E%3Ccircle cx='633.8' cy='806.4' r='8.05' fill='url(%23h)'/%3E%3Ccircle cx='389.9' cy='509.2' r='4.84' fill='url(%23h)'/%3E%3Ccircle cx='3.6' cy='672.8' r='6.16' fill='url(%23h)'/%3E%3Ccircle cx='78.7' cy='266.1' r='8.55' fill='url(%23h)'/%3E%3Ccircle cx='478.2' cy='111.0' r='5.27' fill='url(%23h)'/%3E%3Ccircle cx='395.2' cy='463.0' r='8.45' fill='url(%23h)'/%3E%3Ccircle cx='132.1' cy='605.6' r='5.36' fill='url(%23h)'/%3E%3Ccircle cx='151.8' cy='23.0' r='9.51' fill='url(%23h)'/%3E%3Ccircle cx='519.1' cy='364.4' r='9.22' fill='url(%23h)'/%3E%3Ccircle cx='2.7' cy='576.6' r='9.19' fill='url(%23h)'/%3E%3Ccircle cx='183.0' cy='88.3' r='8.15' fill='url(%23h)'/%3E%3Ccircle cx='132.7' cy='818.4' r='7.6' fill='url(%23h)'/%3E%3Ccircle cx='839.2' cy='272.6' r='6.79' fill='url(%23h)'/%3E%3Ccircle cx='279.9' cy='5.7' r='7.14' fill='url(%23h)'/%3E%3Ccircle cx='354.0' cy='588.8' r='8.07' fill='url(%23h)'/%3E%3C/g%3E%3Cg fill='%23eaf3ff'%3E%3Ccircle cx='633.8' cy='806.4' r='1.52' opacity='0.87'/%3E%3Ccircle cx='389.9' cy='509.2' r='1.27' opacity='0.9'/%3E%3Ccircle cx='3.6' cy='672.8' r='1.68' opacity='0.84'/%3E%3Ccircle cx='78.7' cy='266.1' r='1.61' opacity='0.79'/%3E%3Ccircle cx='478.2' cy='111.0' r='1.45' opacity='0.87'/%3E%3Ccircle cx='395.2' cy='463.0' r='2.34' opacity='0.92'/%3E%3Ccircle cx='132.1' cy='605.6' r='1.48' opacity='0.91'/%3E%3Ccircle cx='151.8' cy='23.0' r='1.84' opacity='0.77'/%3E%3Ccircle cx='519.1' cy='364.4' r='1.98' opacity='0.79'/%3E%3Ccircle cx='2.7' cy='576.6' r='2.33' opacity='0.78'/%3E%3Ccircle cx='183.0' cy='88.3' r='1.94' opacity='1.0'/%3E%3Ccircle cx='132.7' cy='818.4' r='1.53' opacity='0.88'/%3E%3Ccircle cx='839.2' cy='272.6' r='1.55' opacity='0.98'/%3E%3Ccircle cx='279.9' cy='5.7' r='1.81' opacity='0.84'/%3E%3Ccircle cx='354.0' cy='588.8' r='1.92' opacity='0.88'/%3E%3Ccircle cx='748.4' cy='229.0' r='1.28' opacity='0.81'/%3E%3Ccircle cx='435.7' cy='248.0' r='1.23' opacity='0.96'/%3E%3Ccircle cx='639.0' cy='758.7' r='0.96' opacity='0.92'/%3E%3Ccircle cx='105.9' cy='527.2' r='1.36' opacity='0.96'/%3E%3Ccircle cx='275.2' cy='154.1' r='1.13' opacity='0.57'/%3E%3Ccircle cx='808.7' cy='555.0' r='1.49' opacity='0.55'/%3E%3Ccircle cx='701.3' cy='500.6' r='0.94' opacity='0.79'/%3E%3Ccircle cx='120.3' cy='506.9' r='1.45' opacity='0.93'/%3E%3Ccircle cx='254.0' cy='793.4' r='0.75' opacity='0.9'/%3E%3Ccircle cx='81.1' cy='217.3' r='1.16' opacity='1.0'/%3E%3Ccircle cx='468.4' cy='245.9' r='0.9' opacity='0.62'/%3E%3Ccircle cx='445.8' cy='421.2' r='0.9' opacity='0.83'/%3E%3Ccircle cx='87.2' cy='334.9' r='1.17' opacity='0.74'/%3E%3Ccircle cx='436.5' cy='400.3' r='1.27' opacity='0.88'/%3E%3Ccircle cx='422.4' cy='654.2' r='0.78' opacity='0.68'/%3E%3Ccircle cx='548.0' cy='352.2' r='1.39' opacity='0.62'/%3E%3Ccircle cx='839.1' cy='437.1' r='0.95' opacity='0.91'/%3E%3Ccircle cx='482.6' cy='818.8' r='1.11' opacity='0.67'/%3E%3Ccircle cx='657.0' cy='721.5' r='1.02' opacity='0.63'/%3E%3Ccircle cx='162.6' cy='298.0' r='1.17' opacity='0.53'/%3E%3Ccircle cx='787.5' cy='730.6' r='1.04' opacity='0.79'/%3E%3Ccircle cx='645.2' cy='513.6' r='0.95' opacity='0.82'/%3E%3Ccircle cx='757.5' cy='694.9' r='1.28' opacity='0.65'/%3E%3Ccircle cx='792.4' cy='520.1' r='1.2' opacity='0.69'/%3E%3Ccircle cx='676.9' cy='129.9' r='0.72' opacity='0.87'/%3E%3Ccircle cx='35.2' cy='153.0' r='1.47' opacity='0.78'/%3E%3Ccircle cx='107.6' cy='820.2' r='0.91' opacity='0.87'/%3E%3Ccircle cx='505.3' cy='298.9' r='1.32' opacity='0.57'/%3E%3C/g%3E%3C/svg%3E");
    background-size: 887px 887px;
  }

  /* Twinkle. A whole layer can only fade as one, so the bright stars are
     split across three tiles that fade on mutually indivisible periods
     (4.7s / 6.9s / 9.3s), with negative delays to start them mid-cycle.
     Because the three tiles interleave spatially, neighbouring stars are
     almost always in different groups -- which is what reads as individual
     stars twinkling rather than the sky pulsing. Only opacity is animated,
     so this composites on the GPU without repainting. */
  @keyframes night-twinkle {
    from { opacity: var(--twinkle-min, 0.4); }
    to   { opacity: 1; }
  }

  .night-sky__stars--a {
    --twinkle-min: 0.38;
    animation: night-twinkle 4.7s ease-in-out -1.3s infinite alternate;
  }

  .night-sky__stars--b {
    --twinkle-min: 0.46;
    animation: night-twinkle 6.9s ease-in-out -3.1s infinite alternate;
  }

  .night-sky__stars--c {
    --twinkle-min: 0.42;
    animation: night-twinkle 9.3s ease-in-out -5.6s infinite alternate;
  }

  /* A sky that never stops moving is exactly what this setting asks us to
     stop doing -- hold every layer at full brightness instead. */
  @media (prefers-reduced-motion: reduce) {
    .night-sky__stars {
      animation: none;
      opacity: 1;
    }
  }

  /* The horizon: three ridge lines, palest at the back, near-black at the
     front, pinned to the bottom of the viewport in front of the stars. They
     sit against the brightest part of the gradient on purpose -- that is
     what turns them into silhouettes rather than shapes.
     preserveAspectRatio="none" plus an explicit background-size lets the
     range stretch to any viewport width -- a ridge line has no correct
     proportion, so stretching reads as a different mountain rather than a
     distorted one. */
  .night-sky__ridge {
    position: absolute;
    inset: auto 0 0 0;
    height: clamp(170px, 32vh, 400px);
    background: url("data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='1440'%20height='400'%20viewBox='0%200%201440%20400'%20preserveAspectRatio='none'%3E%3Cpath%20fill='%2316295A'%20d='M0,400%20L0,300%20L110,236%20L196,282%20L300,168%20L392,262%20L470,238%20L560,286%20L668,192%20L780,272%20L866,250%20L968,300%20L1070,206%20L1180,278%20L1268,254%20L1352,296%20L1440,244%20L1440,400%20Z'/%3E%3Cpath%20fill='%230C1836'%20d='M0,400%20L0,336%20L120,290%20L210,330%20L318,272%20L420,326%20L512,302%20L620,344%20L730,288%20L836,334%20L930,312%20L1040,352%20L1150,296%20L1256,338%20L1350,318%20L1440,290%20L1440,400%20Z'/%3E%3Cpath%20fill='%2304070F'%20d='M0,400%20L0,362%20Q130,330%20250,364%20Q380,400%20500,358%20Q640,312%20770,362%20Q900,410%201030,360%20Q1160,314%201290,362%20Q1370,388%201440,358%20L1440,400%20Z'/%3E%3C/svg%3E") bottom center / 100% 100% no-repeat;
  }

  /* The light theme paints the footer its own light blue, which would sit
     on the night sky as a pale slab, so it needs restating. Starting fully
     transparent rather than on a colour is what makes it read as part of
     the scene: the ridge line and the glow behind it carry on straight
     through the top of the footer, and the page only deepens toward its
     very bottom edge -- there is no horizon-to-footer seam to see, because
     there is no edge to draw one at.
     (.site-header is deliberately left as-is: its sky blue is the accent.)

     The stops stay dark enough, fast enough, for the footer's white text:
     the brightest sky the footer can ever overlap is the band just above
     the ridge, and 55% of #040916 over that still leaves the type well
     clear of 4.5:1. */
  body.theme-night .site-footer {
    background: linear-gradient(180deg,
      rgba(4, 9, 22, 0) 0%,
      rgba(4, 9, 22, 0.55) 40%,
      rgba(2, 5, 13, 0.90) 100%);
  }

  /* Hamba Tuhan section: the light theme fades white into the footer blue.
     Here it stays fully transparent -- the sky is already the thing both
     it and the footer share, so any darkening at the bottom would just
     paint a band that dead-ends at the (now transparent) top of the
     footer, which is the exact seam this is meant to avoid. */
  body.theme-night .pastor-section {
    background: transparent;
  }

  /* The prayer-request panel is translucent (see --color-canvas-subtle
     above): blurring what shows through keeps a busy patch of stars from
     competing with the labels and fields sitting on top of it. */
  body.theme-night .prayer-request {
    backdrop-filter: blur(3px);
  }
}
