/* ==========================================================================
   BBABS Sangha — site stylesheet
   One file for the whole site. Sections are labelled; use your editor's
   search (Ctrl/Cmd+F) to jump to the one you need.

   1. Design tokens        — colours, fonts, spacing. Change things here first.
   2. Reset & base
   3. Layout shell         — sidebar + main content
   4. Sidebar navigation
   5. Mobile topbar & drawer
   6. Hero band            — per-page background images live here
   7. Kolam divider        — the signature motif
   8. Content blocks       — sections, cards, prose, meta rows
   9. Buttons & links
  10. Songbook
  11. Footer
  12. Motion & accessibility
  13. Media archives gallery — Media Archives page only
   ========================================================================== */


/* ==========================================================================
   1. DESIGN TOKENS
   ========================================================================== */

:root {
  /* --- Palette ----------------------------------------------------------- */
  --paper:        #F7F2E8;  /* page background, warm cream                   */
  --paper-raised: #FFFDF7;  /* cards sitting on top of the page              */
  --paper-sunk:   #EFE7D6;  /* wells, table stripes, inset areas             */

  --maroon:       #8A2433;  /* kumkum maroon — primary brand colour          */
  --maroon-deep:  #5E1622;  /* darker maroon — sidebar, hero base            */
  --maroon-soft:  #A64652;  /* hover/pressed tints                           */

  --gold:         #D98E1F;  /* marigold — accents, the kolam motif           */
  --gold-soft:    #E8B45F;
  --green:        #3D6B4F;  /* leaf green — secondary accent                 */

  --ink:          #2B2018;  /* body text                                     */
  --ink-soft:     #6B5B4E;  /* secondary text, captions                      */
  --rule:         #DED2BD;  /* hairline borders                              */

  --on-dark:      #FBF6EC;  /* text on maroon                                */
  --on-dark-soft: #E4D3C4;

  /* --- Type -------------------------------------------------------------- */
  --font-display: "Fraunces", Georgia, "Times New Roman", serif;
  --font-body:    "Karla", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-ml:      "Noto Sans Malayalam", "Manjari", sans-serif;

  /* --- Spacing & shape --------------------------------------------------- */
  --sidebar-w:    272px;
  --topbar-h:     60px;
  --page-max:     1080px;
  --radius:       14px;
  --radius-sm:    9px;

  /* --- Hero scrims ------------------------------------------------------
     Four recipes. See section 6 for how a page opts in.

     --hero-scrim-plain      no photograph; the gradient IS the background.
     --hero-scrim-photo      a photograph CROPPED to fill the band. Much
                             lighter, with the darkening concentrated on the
                             left, under the text.
     --hero-scrim-photo-top  a photograph filling the band with the text
                             sitting over its top edge. The darkening runs
                             across the top only and the rest is left almost
                             clear, so the picture below the headline is seen
                             as a picture — a left-weighted scrim would dim
                             half of it.
     --hero-scrim-photo-band a WHOLE photograph shown as a strip across the
                             top of the band (background-size: contain) with
                             the text BELOW it, on the band's own maroon.
                             Nothing needs darkening for legibility there, so
                             this one stays light throughout: it only settles
                             the picture into the page and deepens the foot.
     -------------------------------------------------------------------- */
  --hero-scrim-plain:
    radial-gradient(58% 78% at 78% 12%, rgba(217,142,31,.34), transparent 62%),
    radial-gradient(46% 60% at 8% 92%,  rgba(166,70,82,.40),  transparent 60%),
    linear-gradient(180deg, rgba(56,13,20,.72) 0%, rgba(56,13,20,.55) 45%, rgba(56,13,20,.82) 100%);

  --hero-scrim-photo:
    radial-gradient(52% 70% at 82% 10%, rgba(217,142,31,.16), transparent 64%),
    linear-gradient(100deg,
      rgba(26,16,12,.82) 0%,
      rgba(26,16,12,.68) 38%,
      rgba(26,16,12,.30) 70%,
      rgba(26,16,12,.10) 100%),
    linear-gradient(180deg, rgba(26,16,12,.16) 0%, rgba(26,16,12,.04) 45%, rgba(26,16,12,.32) 100%);

  --hero-scrim-photo-top:
    linear-gradient(180deg,
      rgba(26,16,12,.88) 0%,
      rgba(26,16,12,.78) 16%,
      rgba(26,16,12,.42) 32%,
      rgba(26,16,12,.12) 46%,
      rgba(26,16,12,.06) 70%,
      rgba(26,16,12,.22) 100%);

  --hero-scrim-photo-band:
    linear-gradient(180deg,
      rgba(26,16,12,.26) 0%,
      rgba(26,16,12,.10) 30%,
      rgba(26,16,12,.10) 62%,
      rgba(26,16,12,.32) 100%);

  --shadow-sm:    0 1px 2px rgba(43, 32, 24, .06),
                  0 2px 8px rgba(43, 32, 24, .05);
  --shadow-md:    0 2px 4px rgba(43, 32, 24, .07),
                  0 12px 28px rgba(43, 32, 24, .10);

  --ease:         cubic-bezier(.4, 0, .2, 1);
}


/* ==========================================================================
   2. RESET & BASE
   ========================================================================== */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Anchor links land below the mobile topbar instead of under it. */
  scroll-padding-top: calc(var(--topbar-h) + 1rem);
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 1.0625rem;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

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

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.15;
  color: var(--maroon-deep);
  margin: 0 0 .6em;
  /* Fraunces variable axes: slightly softer optical size for headings. */
  font-variation-settings: "SOFT" 20, "WONK" 0;
  letter-spacing: -.01em;
}

h1 { font-size: clamp(2rem, 4.4vw, 3rem); }
h2 { font-size: clamp(1.5rem, 2.6vw, 2rem); }
h3 { font-size: 1.1875rem; }
h4 { font-size: 1.0625rem; font-family: var(--font-body); font-weight: 700; }

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

a { color: var(--maroon); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--maroon-deep); }

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

strong { font-weight: 700; }

::selection { background: var(--gold-soft); color: var(--maroon-deep); }

:focus-visible {
  outline: 2.5px solid var(--gold);
  outline-offset: 2px;
  border-radius: 3px;
}

/* Screen-reader-only text (labels, skip link target descriptions). */
.sr-only {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip-link {
  position: absolute; top: .5rem; left: .5rem;
  z-index: 200;
  transform: translateY(-200%);
  background: var(--maroon-deep); color: var(--on-dark);
  padding: .6rem 1rem; border-radius: var(--radius-sm);
  text-decoration: none; font-weight: 700;
}
.skip-link:focus { transform: translateY(0); color: var(--on-dark); }


/* ==========================================================================
   3. LAYOUT SHELL
   ========================================================================== */

.shell { min-height: 100vh; }

.main {
  margin-left: var(--sidebar-w);
  min-width: 0;                /* lets long words/tables shrink correctly */
}

.wrap {
  max-width: var(--page-max);
  margin-inline: auto;
  padding-inline: clamp(1.25rem, 4vw, 3rem);
}

/* Vertical rhythm between page sections. */
.section { padding-block: clamp(2.75rem, 6vw, 4.5rem); }
.section--tight { padding-block: clamp(1.75rem, 3.5vw, 2.5rem); }
.section--sunk  { background: var(--paper-sunk); }

/* --- Photographic section band -------------------------------------------
   A mid-page section sitting on a photograph instead of on paper, with
   everything inside switching to light-on-dark, cards included. No page
   uses this at present — see the note in the per-page block in section 6.

   To use it: add class="section section--photo" to the <section>, then set
   its image in the per-page block in section 6 below.

   This band carries far more text than a hero does, so its overlay is
   heavier than the hero's. Legibility wins over showing the photograph.
   ------------------------------------------------------------------------ */
.section--photo {
  position: relative;
  isolation: isolate;
  background-color: var(--maroon-deep);
  color: var(--on-dark);
  overflow: hidden;
}
.section--photo::before {
  content: "";
  position: absolute; inset: 0; z-index: -2;
  background-image: var(--section-img, none);
  background-repeat: no-repeat;
  background-size: cover;
  background-position: var(--section-pos, center);
  transform: scale(var(--section-zoom, 1));
}
.section--photo::after {
  content: "";
  position: absolute; inset: 0; z-index: -1;
  background:
    radial-gradient(60% 70% at 85% 8%, rgba(217,142,31,.14), transparent 66%),
    linear-gradient(180deg, rgba(24,14,11,.80) 0%, rgba(24,14,11,.70) 45%, rgba(24,14,11,.86) 100%);
}

.section--photo h2,
.section--photo h3            { color: var(--on-dark); }
.section--photo .section__lede,
.section--photo > .wrap > p   { color: var(--on-dark-soft); }
.section--photo .section__eyebrow { color: var(--gold-soft); }
.section--photo .section__head    { text-shadow: 0 1px 3px rgba(16,8,6,.6); }

/* Cards become translucent panels so the photograph still reads behind
   them instead of being blocked out by six solid rectangles. */
.section--photo .card {
  background: rgba(24,14,11,.58);
  border-color: rgba(251,246,236,.20);
  box-shadow: none;
  -webkit-backdrop-filter: blur(7px);
          backdrop-filter: blur(7px);
}
.section--photo .card p       { color: var(--on-dark-soft); }
.section--photo .card a       { color: var(--gold-soft); }
.section--photo .card__num    { color: var(--gold); }

.section--photo .notice {
  background: rgba(24,14,11,.58);
  border-left-color: var(--gold);
  color: var(--on-dark-soft);
  -webkit-backdrop-filter: blur(7px);
          backdrop-filter: blur(7px);
}
.section--photo .notice strong,
.section--photo .notice a { color: var(--gold-soft); }

/* The divider's centre diamond normally masks the dots with an opaque
   paper fill; over a photograph it needs the band's own dark tone. */
.section--photo .kolam::after {
  border-color: var(--gold);
  background: rgba(24,14,11,.85);
}

.section__head { max-width: 62ch; margin-bottom: 2rem; }
.section__eyebrow {
  font-size: .78rem; font-weight: 700;
  letter-spacing: .14em; text-transform: uppercase;
  color: var(--gold); margin: 0 0 .55rem;
}
.section__lede { color: var(--ink-soft); font-size: 1.09rem; margin: 0; }


/* ==========================================================================
   4. SIDEBAR NAVIGATION
   Markup is generated by assets/js/site.js — edit the NAV_LINKS array there
   to add or rename a page.
   ========================================================================== */

.sidebar {
  position: fixed;
  inset: 0 auto 0 0;
  z-index: 60;
  display: flex; flex-direction: column;
  background: var(--maroon-deep);
  color: var(--on-dark);
  overflow-y: auto;
  overscroll-behavior: contain;
  /* overflow-y stays auto rather than hidden, on purpose: on a short window
     the nav list, the audio player and the footer together can be taller
     than the screen, and the sidebar needs to be able to scroll to reach
     "Contact us" rather than simply cutting it off. What it must never do is
     LOOK like it scrolls — a visible track down the sidebar's own edge reads
     as a stray browser control on a page that otherwise has none. These
     three rules hide the track in every engine while leaving the actual
     scrolling untouched — wheel, trackpad and keyboard scrolling all still
     work exactly as before. */
  scrollbar-width: none;         /* Firefox */
  -ms-overflow-style: none;      /* legacy Edge */
}
.sidebar::-webkit-scrollbar { display: none; } /* Chrome, Safari, Edge */

/* Faint gold hairline plus a soft glow so the sidebar doesn't read as flat. */
.sidebar::after {
  content: "";
  position: absolute; inset: 0 0 0 auto; width: 1px;
  background: linear-gradient(180deg, rgba(217,142,31,.55), rgba(217,142,31,.06));
}

.sidebar__brand {
  display: block;
  padding: 1.5rem 1.4rem 1.25rem;
  text-decoration: none; color: inherit;
  border-bottom: 1px solid rgba(251,246,236,.12);
}
.sidebar__brand:hover { color: inherit; background: rgba(251,246,236,.04); }

.sidebar__mark {
  width: 40px; height: 40px;
  display: grid; place-items: center;
  margin-bottom: .8rem;
  border: 1.5px solid var(--gold);
  border-radius: 50%;
  color: var(--gold);
  font-family: var(--font-display);
  font-size: 1.15rem; font-weight: 600;
  line-height: 1;
}

.sidebar__name {
  font-family: var(--font-display);
  font-size: 1.06rem; font-weight: 600;
  line-height: 1.25; margin: 0 0 .3rem;
  color: var(--on-dark);
}
.sidebar__sub {
  margin: 0;
  font-size: .74rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--on-dark-soft);
}

.sidebar__nav { padding: 1rem .7rem; flex: 1; }
.sidebar__list { list-style: none; margin: 0; padding: 0; }
.sidebar__list li + li { margin-top: 2px; }

.sidebar__link {
  display: flex; align-items: center; gap: .7rem;
  padding: .6rem .75rem;
  border-radius: var(--radius-sm);
  color: var(--on-dark-soft);
  text-decoration: none;
  font-size: .96rem; font-weight: 500;
  transition: background .16s var(--ease), color .16s var(--ease),
              transform .1s var(--ease);
}
/* The small leading dot doubles as the active indicator. */
.sidebar__link::before {
  content: "";
  width: 5px; height: 5px; flex: none;
  border-radius: 50%;
  background: rgba(251,246,236,.28);
  transition: background .16s var(--ease), transform .16s var(--ease);
}
.sidebar__link:hover {
  background: rgba(251,246,236,.07);
  color: var(--on-dark);
}
.sidebar__link:hover::before { background: var(--gold-soft); }
.sidebar__link:active { transform: translateX(1px) scale(.995); }

.sidebar__link[aria-current="page"],
.sidebar__link.is-active {
  background: rgba(217,142,31,.15);
  color: var(--on-dark);
  font-weight: 700;
}
.sidebar__link[aria-current="page"]::before,
.sidebar__link.is-active::before {
  background: var(--gold);
  transform: scale(1.5);
}

/* Sub-links: in-page anchors shown under the current page only. */
.sidebar__sublist {
  list-style: none;
  margin: 2px 0 4px;
  padding-left: 1.55rem;
  border-left: 1px solid rgba(251,246,236,.14);
  margin-left: 1.05rem;
}
.sidebar__sublink {
  display: block;
  padding: .3rem .5rem;
  border-radius: 6px;
  font-size: .875rem;
  color: rgba(228,211,196,.75);
  text-decoration: none;
}
.sidebar__sublink:hover { background: rgba(251,246,236,.06); color: var(--on-dark); }
.sidebar__sublink.is-active { color: var(--gold-soft); font-weight: 700; }

.sidebar__foot {
  padding: 1rem 1.4rem 1.5rem;
  border-top: 1px solid rgba(251,246,236,.12);
  font-size: .78rem; line-height: 1.5;
  color: rgba(228,211,196,.65);
}
.sidebar__foot a { color: var(--gold-soft); }

/* --- Ambient audio toggle (lives in the sidebar foot) -------------------- */
.audio-toggle {
  display: flex; align-items: center; gap: .6rem;
  width: 100%; margin-bottom: .9rem;
  padding: .55rem .7rem;
  background: rgba(251,246,236,.06);
  border: 1px solid rgba(251,246,236,.16);
  border-radius: 999px;
  color: var(--on-dark-soft);
  font: inherit; font-size: .84rem;
  cursor: pointer; text-align: left;
  transition: background .16s var(--ease), color .16s var(--ease),
              border-color .16s var(--ease);
}
.audio-toggle:hover {
  background: rgba(251,246,236,.12);
  border-color: rgba(217,142,31,.5);
  color: var(--on-dark);
}
.audio-toggle:active { transform: scale(.985); }
.audio-toggle[aria-pressed="true"] {
  background: rgba(217,142,31,.16);
  border-color: rgba(217,142,31,.6);
  color: var(--on-dark);
}

.audio-toggle__icon { flex: none; display: grid; place-items: center; width: 16px; }
.audio-toggle__bars { display: flex; align-items: flex-end; gap: 2px; height: 13px; }
.audio-toggle__bars i {
  width: 2.5px; height: 4px;
  background: currentColor; border-radius: 1px;
}
.audio-toggle[aria-pressed="true"] .audio-toggle__bars i {
  animation: eq .9s var(--ease) infinite alternate;
}
.audio-toggle__bars i:nth-child(2) { animation-delay: .18s; }
.audio-toggle__bars i:nth-child(3) { animation-delay: .36s; }
@keyframes eq { from { height: 4px; } to { height: 13px; } }


/* ==========================================================================
   5. MOBILE TOPBAR & DRAWER
   ========================================================================== */

.topbar {
  display: none;                        /* shown below 900px */
  position: fixed; inset: 0 0 auto 0;
  z-index: 70; height: var(--topbar-h);
  align-items: center; gap: .8rem;
  padding-inline: 1rem;
  background: var(--maroon-deep);
  color: var(--on-dark);
  box-shadow: 0 1px 0 rgba(217,142,31,.4);
}
.topbar__title {
  font-family: var(--font-display);
  font-size: 1.02rem; font-weight: 600;
  margin: 0; color: var(--on-dark);
  text-decoration: none;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.burger {
  flex: none;
  width: 40px; height: 40px;
  display: grid; place-items: center; gap: 0;
  background: transparent;
  border: 1px solid rgba(251,246,236,.22);
  border-radius: var(--radius-sm);
  cursor: pointer; color: var(--on-dark);
}
.burger:hover { background: rgba(251,246,236,.08); }
.burger__box { display: grid; gap: 4px; width: 18px; }
.burger__box span {
  height: 2px; background: currentColor; border-radius: 2px;
  transition: transform .2s var(--ease), opacity .15s var(--ease);
}
.burger[aria-expanded="true"] .burger__box span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.burger[aria-expanded="true"] .burger__box span:nth-child(2) { opacity: 0; }
.burger[aria-expanded="true"] .burger__box span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

.scrim {
  position: fixed; inset: 0; z-index: 55;
  background: rgba(43,22,18,.5);
  opacity: 0; pointer-events: none;
  transition: opacity .22s var(--ease);
  -webkit-backdrop-filter: blur(2px); backdrop-filter: blur(2px);
}
body.nav-open .scrim { opacity: 1; pointer-events: auto; }
body.nav-open { overflow: hidden; }

@media (max-width: 900px) {
  .topbar { display: flex; }
  .main   { margin-left: 0; padding-top: var(--topbar-h); }

  .sidebar {
    width: min(310px, 84vw);
    transform: translateX(-102%);
    transition: transform .26s var(--ease);
    box-shadow: var(--shadow-md);
  }
  body.nav-open .sidebar { transform: translateX(0); }
}


/* ==========================================================================
   6. HERO BAND
   Each page sets --hero-img on <body>. See the per-page block at the bottom
   of this section. The dark overlay is always applied, so any photo you drop
   in stays legible without further editing.
   ========================================================================== */

.hero {
  position: relative;
  isolation: isolate;
  background-color: var(--maroon-deep);
  color: var(--on-dark);
  overflow: hidden;
}

/* Layer 1 — the photograph, if the page defines one.

   --hero-zoom scales the image up to crop in tighter. It is applied as a
   transform rather than via background-size because a percentage
   background-size is relative to the element box, which changes shape
   between desktop and mobile — at some widths the image would stop
   covering and leave a gap. Scaling the whole layer always covers, and
   .hero has overflow:hidden so the excess is clipped.

   --hero-size overrides background-size outright (default: cover). Use it
   for a small source photo you do NOT want stretched past its own pixel
   resolution — e.g. "736px auto" shows the file at exactly its real size
   instead of being upscaled to fill the band. background-repeat is pinned
   to no-repeat because a fixed, less-than-full-bleed size would otherwise
   tile the image sideways. */
.hero::before {
  content: "";
  position: absolute; inset: 0; z-index: -2;
  background-image: var(--hero-img, none);
  background-repeat: no-repeat;
  background-size: var(--hero-size, cover);
  background-position: var(--hero-pos, center);
  transform: scale(var(--hero-zoom, 1));
  transform-origin: var(--hero-origin, center);
}

/* Layer 2 — marigold glow + scrim. Doubles as the standalone CSS-only
   background when a page has no photo.

   Kept deliberately light so the photograph reads clearly. Legibility is
   handled two ways instead of by drowning the image:
     · the horizontal scrim is concentrated on the left, under the text,
       and falls away quickly across the middle
     · the text itself carries a shadow (see .hero h1 / .hero__lede below)

   The scrim is a neutral warm-dark rather than maroon, so it darkens the
   photo without tinting its colours. */
.hero::after {
  content: "";
  position: absolute; inset: 0; z-index: -1;
  /* Defaults to the rich maroon wash used by pages with no photograph.
     A page that sets --hero-img swaps in --hero-scrim-photo alongside it. */
  background: var(--hero-scrim, var(--hero-scrim-plain));
}

.hero__inner { padding-block: clamp(3rem, 8vw, 6rem); position: relative; }

.hero h1 {
  color: var(--on-dark);
  max-width: 22ch;
  font-variation-settings: "SOFT" 30, "WONK" 1;
  text-wrap: balance;
}

.hero__lede {
  max-width: 52ch;
  font-size: clamp(1.02rem, 1.6vw, 1.18rem);
  color: var(--on-dark-soft);
}

/* Text shadows carry the legibility over a photograph, so the scrim above
   it can stay light. They are imperceptible on the plain maroon heroes. */
.hero h1,
.hero__lede,
.meta-row__value,
.meta-row__label,
.hero .pill {
  text-shadow: 0 1px 2px rgba(20,10,8,.55), 0 2px 12px rgba(20,10,8,.35);
}

.pill {
  display: inline-flex; align-items: center; gap: .5rem;
  margin-bottom: 1.1rem;
  padding: .34rem .85rem .34rem .7rem;
  border: 1px solid rgba(217,142,31,.6);
  border-radius: 999px;
  background: rgba(217,142,31,.14);
  color: var(--gold-soft);
  font-size: .8rem; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase;
}
.pill::before {
  content: ""; width: 6px; height: 6px;
  border-radius: 50%; background: var(--gold);
}

/* --- .pill--lead — the emphasised badge ----------------------------------
   For the one badge on the site that has to carry weight: the Mandala
   Vilakku season line on the About Us page. One size step up from a
   normal pill, in brighter gold, with a thicker border and a stronger
   fill behind it.

   It is a separate modifier class rather than a change to .pill itself so
   that the quieter badges elsewhere — "Songbook", "Archives", "Our
   office", "Every Saturday" — keep their current understated look.
   ------------------------------------------------------------------------ */
.pill--lead {
  padding: .46rem 1.1rem .46rem .9rem;
  border-width: 2px;
  border-color: rgba(232,180,95,.85);
  background: rgba(217,142,31,.26);
  color: #F3D9A4;                    /* brighter than --gold-soft          */
  font-size: .95rem;                 /* up from .8rem                      */
  letter-spacing: .11em;
}
.pill--lead::before { width: 7px; height: 7px; background: var(--gold-soft); }

/* Date / venue / theme row under the headline. */
.meta-row {
  display: flex; flex-wrap: wrap;
  gap: .6rem 2rem;
  margin: 1.6rem 0 2rem;
  padding-top: 1.4rem;
  border-top: 1px solid rgba(251,246,236,.2);
}
.meta-row__item { min-width: 0; }
.meta-row__label {
  margin: 0 0 .1rem;
  font-size: .72rem; font-weight: 700;
  letter-spacing: .13em; text-transform: uppercase;
  color: rgba(217,142,31,.9);
}
.meta-row__value {
  margin: 0;
  font-family: var(--font-display);
  font-size: 1.06rem; font-weight: 600;
  color: var(--on-dark);
}

.hero__actions { display: flex; flex-wrap: wrap; gap: .8rem; }


/* ==========================================================================
   6b. SPLASH — the landing page only
   A full-screen devotional opening: one photograph, one line of text, and
   nothing else. Only index.html uses this.

   WHY IT IS NOT JUST A TALL .hero
   A hero crops its photograph to fill the band (background-size: cover).
   That is right for a wide strip of a larger scene, but wrong here: the
   Vilakku photograph is a single centred composition — the deity framed by
   garlands — and cropping it cuts the garlands off. So the splash uses
   `contain` instead, showing the picture whole, at any window shape.

   `contain` leaves empty bars beside the image, and those bars are filled
   with the Sangha's kumkum maroon rather than left black.

   THE JOIN BETWEEN THE TWO. The photograph's own corners are black, so
   maroon meeting them directly would draw a hard rectangle around the
   picture. What prevents that is --splash-wash: a soft dark pool sitting
   over the maroon, deepest in the middle where the photograph sits and
   thinning out towards the edges of the screen. The picture's dark corners
   land in the dark part of the pool and the maroon reads at the margins,
   so the two meet gradually instead of at a line.

   Note the photo is NOT uniformly black-edged — the garland reaches the
   picture's edge at mid-height, so only the corners need this treatment.

   If you swap in another photograph, adjust --splash-wash to suit its own
   edges, or set --splash-size to `cover` and accept the crop instead.
   ========================================================================== */

.splash {
  position: relative;
  isolation: isolate;
  display: grid;
  /* Two rows — the invocation and the milestone banner — pushed to opposite
     ends of the screen, with the photograph between them. */
  align-content: space-between;
  gap: 1.5rem;
  /* Fill the window exactly, so nothing peeks in below the fold.
     100dvh tracks mobile browsers whose toolbars hide on scroll; the 100vh
     line above it is the fallback for browsers without dvh. */
  min-height: 100vh;
  min-height: 100dvh;
  padding-block: clamp(2rem, 6vh, 4rem);
  /* --splash-bg is the flat colour behind everything; --splash-wash is the
     gradient stack drawn on top of it. Both sit BEHIND the photograph,
     which is painted by ::before at a negative z-index. */
  background-color: var(--splash-bg, var(--maroon-deep));
  background-image: var(--splash-wash, none);
  color: var(--on-dark);
  overflow: hidden;
  text-align: center;
}

/* Layer 1 — the photograph, shown whole. */
.splash::before {
  content: "";
  position: absolute; inset: 0; z-index: -2;
  background-image: var(--splash-img, none);
  background-repeat: no-repeat;
  background-size: var(--splash-size, contain);
  background-position: var(--splash-pos, center);
}

/* Layer 2 — a scrim ONLY where the words are, which is now BOTH ends:
   the invocation at the top and the milestone banner at the foot. The
   middle band stays completely clear, so nothing dims the deity or the
   garlands around him — the picture is still the point of this page. */
.splash::after {
  content: "";
  position: absolute; inset: 0; z-index: -1;
  background:
    linear-gradient(180deg,
      rgba(0,0,0,.66) 0%,
      rgba(0,0,0,.40) 13%,
      rgba(0,0,0,0)   30%,
      rgba(0,0,0,0)   66%,
      rgba(0,0,0,.40) 86%,
      rgba(0,0,0,.72) 100%);
}

.splash__title {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(1.9rem, 5.4vw, 3.4rem);
  font-weight: 600;
  font-variation-settings: "SOFT" 30, "WONK" 1;
  line-height: 1.12;
  color: var(--on-dark);
  text-wrap: balance;
  /* Heavier than the hero's text shadow — this text sits directly on the
     photograph rather than on a scrimmed band. */
  text-shadow: 0 1px 3px rgba(0,0,0,.85), 0 3px 20px rgba(0,0,0,.6);
}

/* The milestone banner across the foot of the landing page.

   A ruled band rather than a plain line of text, so it reads as something
   being announced. Deliberately quieter than the invocation above it: gold
   on a translucent maroon strip, which sits over the photograph without
   blocking it out. The blur keeps the garlands legible behind the strip
   instead of turning it into a solid bar. */
.splash__banner {
  margin: 0;
  padding: .8rem 1.1rem;
  border-top: 1px solid rgba(217,142,31,.5);
  border-bottom: 1px solid rgba(217,142,31,.5);
  background: rgba(94,22,34,.52);
  -webkit-backdrop-filter: blur(3px);
          backdrop-filter: blur(3px);
  font-family: var(--font-display);
  font-size: clamp(1rem, 2.05vw, 1.38rem);
  font-weight: 600;
  font-variation-settings: "SOFT" 30, "WONK" 1;
  line-height: 1.3;
  color: #F3D9A4;
  text-wrap: balance;
  text-shadow: 0 1px 3px rgba(0,0,0,.8);
}

/* On mobile the fixed topbar takes 60px out of .main (see section 5), so a
   full 100dvh splash inside it would overflow by exactly that much and
   leave the page scrollable. Subtract it back. */
@media (max-width: 900px) {
  .splash {
    min-height: calc(100vh - var(--topbar-h));
    min-height: calc(100dvh - var(--topbar-h));
  }
}

/* --- Per-page hero images ------------------------------------------------
   Drop a WebP or JPG file (~1600px wide, under 300KB) into assets/img/ and
   then uncomment the matching line. Until you do, the page falls back to
   the CSS-only maroon/marigold glow above, which looks intentional on its
   own.
   ------------------------------------------------------------------------ */
/* Hero photographs are portrait, so they are cropped hard by this wide band.
     --hero-pos    which part of the photo stays visible
     --hero-zoom   1 = fit, higher crops in tighter (upscales the image)
     --hero-size   overrides background-size outright — use this instead of
                   --hero-zoom to show a small photo at its own native
                   resolution rather than stretching it, e.g. "736px auto"
     --hero-scrim  the lighter overlay, so the photograph reads clearly
   A page adding a photograph wants --hero-img, --hero-pos and --hero-scrim
   at minimum; --hero-size only if the source is too small to enlarge well.

   THE LANDING PAGE (index.html) IS DIFFERENT — it has no hero at all. It
   uses the .splash component in section 6b instead, configured just below.

   The About Us image (Ayyappa) is only 736px wide. Letting `cover`
   stretch it to fill a band well over 1000px wide made it visibly soft, so
   --hero-size pins it to "736px auto" — its own real resolution, crisp,
   with the scrim's maroon showing either side rather than a blurred-up
   photo filling the whole band.

   --hero-pos keeps the deity's face ABOVE the headline rather than behind
   it. It was set by comparing renders at 38/46/52/58%, not by calculation.

   HOW THE Y PERCENTAGE BEHAVES, because it is counter-intuitive: the photo
   is taller than the band, so the band shows a window onto it. A feature
   `d` pixels down the photo appears at `d - P*(photoH - bandH)` from the
   top of the band. A BIGGER percentage therefore pulls the image UP, so the
   face rises but the crown starts to be cut off at the top edge.

   THE TRADE-OFF, so nobody re-tunes this expecting to win both ways: the
   photo is 868px tall and the band only about 535px, and the figure fills
   most of the photo. There is not room to show the whole crown AND keep the
   face above a two-line headline. 38% favours the face sitting clear of the
   headline, at the cost of a few pixels off the top of the crown. Lower it
   towards 30% for more crown and the face closer to the text; raise it and
   the crown is cut harder. */
body.page-sangha       { --hero-img: url("../img/hero-home.jpg");
                         --hero-pos: center 38%;
                         --hero-size: 736px auto;
                         --hero-scrim: var(--hero-scrim-photo); }

/* The About Us headline is the Sangha's full registered name — far longer
   than a normal page title. At the usual 22ch measure it breaks into three
   lines, which makes the hero tall and crowds the photograph. A wider
   measure holds it to two. A proper name reads fine at this width. */
body.page-sangha .hero h1 { max-width: 30ch; }

/* --- The landing splash (see .splash in section 6b) ----------------------
   index.html only. --splash-size stays at its `contain` default so the
   whole garlanded composition shows.

   The space around the photograph is kumkum maroon: #8A2433 at the top
   easing into #5E1622 and a little deeper at the foot, so it belongs to the
   same palette as the rest of the site.

   The radial layer listed FIRST paints on top of that maroon — a dark pool
   behind the middle of the screen, fading out by the edges. It exists so
   the photograph's black corners have something dark to sit against
   instead of meeting the maroon at a hard line. Read the note at the top of
   section 6b before changing it.
   ------------------------------------------------------------------------ */
body.page-home         { --splash-img: url("../img/hero-landing.jpg");
                         --splash-bg: var(--maroon-deep);
                         --splash-wash:
                           radial-gradient(74% 60% at 50% 50%,
                             rgba(0,0,0,.62) 0%,
                             rgba(0,0,0,.44) 42%,
                             rgba(0,0,0,.16) 74%,
                             rgba(0,0,0,0)  100%),
                           linear-gradient(176deg,
                             #8A2433 0%,
                             #5E1622 58%,
                             #4C111B 100%); }

/* The shrine at the Sangha office, behind the Ayyappa Bhaktha Sangha hero,
   filling the whole opening screen.

   ►► THIS MUST BE A REAL PHOTOGRAPH OF THE OFFICE SHRINE. ◄◄

   An AI-widened version of this scene was tried here and removed. It looked
   like the right room, but every deity in every frame on that wall had been
   repainted — different faces, different postures. These are the Sangha's
   own murtis and pictures; they are not decoration and they are not
   interchangeable. If a wider or sharper picture is ever wanted, take one at
   the office. Do not generate one.

   THE SOURCE. hero-weekly-shrine.jpg is 1600x1060, prepared from
   images/PHOTO-2025-10-02-16-04-13.jpg — cut down from 1600x1200 to drop the
   camera's timestamp burned into the bottom-right corner, then saved at
   JPEG quality 42 to land under 300KB. See assets/img/README.md for the
   `sips --cropOffset 0 0` trap hit while making it.

   Being a landscape frame already, no tricks are needed — plain `cover`
   fills the band at every desktop size while trimming only a few percent off
   the left and right. --hero-pos: center keeps the wall centred; there is no
   spare height to slide around in, so there is little reason to move it.

   THE TRADE-OFF, so nobody re-tunes this expecting to win both ways: in a
   window much taller than it is wide — a small, nearly square desktop
   window — `cover` takes more off both sides, and the outermost frames start
   to go. Wider windows lose about 5%, which falls on wall and on frames the
   photographer had already clipped. If that ever matters more than filling
   the screen, the fix is --hero-size: 100% auto, which pins the picture to
   the band's full width and crops top and bottom instead; the cost is a
   maroon strip under the photo in tall windows.

   The scrim darkens the TOP only, where the pill and headline sit. Swapping
   in --hero-scrim-photo would dim the left half of the picture, which
   defeats the point of showing the full width of the wall.               */
body.page-weekly       { --hero-img: url("../img/hero-weekly-shrine.jpg");
                         --hero-size: cover;
                         --hero-pos: center;
                         --hero-scrim: var(--hero-scrim-photo-top); }
body.page-weekly .hero { min-height: 100vh; min-height: 100dvh; }

/* On a phone the topbar has already taken 60px out of .main, so a full
   100dvh band here would overflow the screen by exactly that much. */
@media (max-width: 900px) {
  body.page-weekly .hero { min-height: calc(100vh - var(--topbar-h));
                           min-height: calc(100dvh - var(--topbar-h)); }
}

/* A PHONE HELD UPRIGHT is the one shape this picture cannot cover. A 3:2
   frame in a tall window would have to lose roughly two thirds of its width
   to `cover`, taking most of the wall with it. So on portrait phones the
   photograph stops being a backdrop and becomes a strip: shown whole across
   the top, with the text underneath it on the band's own maroon. Nothing is
   cropped at any width.

   The padding-top is what keeps the text clear of the strip, so the two are
   tied together: at full width the picture stands 1060/1600 of its own width
   tall, hence 66.25vw, plus a little breathing room. Recompute that number
   if you replace the photograph, or the text will collide with it. */
@media (max-width: 900px) and (orientation: portrait) {
  body.page-weekly .hero { min-height: 0;
                           --hero-size: contain;
                           --hero-pos: center top;
                           --hero-scrim: var(--hero-scrim-photo-band); }
  /* Written as .hero .hero__inner, not just .hero__inner, on purpose: the
     interior-page rule further down this file sets padding-block — a
     shorthand, so it resets padding-top — at the same specificity as
     `body.page-weekly .hero__inner` and would win on source order alone.
     The extra class puts this out of reach of that. */
  body.page-weekly .hero .hero__inner { padding-top: calc(66.25vw + 1.25rem); }
}

/* A phone turned sideways is a wide, very short band. `cover` still spans
   the full width there, so nothing is lost; it simply shows a thinner
   horizontal slice of the wall. Nothing extra to do. */

/* The Mandala Vilakku pandal, behind the Mandala Vilakku hero — the same
   full-bleed treatment as the Ayyappa Bhaktha Sangha page above, so read
   that page's comment first; this one only notes what differs.

   THE SOURCE. hero-updates-pandal.jpg is 1700x1901, prepared from
   images/IMG_9050.HEIC — a photograph of the pandal's palm-leaf shrines
   at the 2025 program. Three things were done to the original and all three
   matter if it is ever re-made:
     · HEIC has no browser support worth relying on, so it was converted to
       JPEG first;
     · the phone had recorded it on its side — sips -r 90 turns it upright
       (try -r -90 first if a future photo comes out upside down instead;
       there is no way to know which without looking);
     · the extreme top (bare tent ceiling) and bottom (bare paving) were
       trimmed before resizing — neither carried anything worth the pixels,
       and removing them let quality-32 JPEG land at 353KB instead of over
       600KB for what is a visually dense, hard-to-compress photograph
       (fabric, crowd, patterned paving all resist compression far more
       than the plain-walled shrine room on the other page).

   Unlike that other hero, this source is portrait even after trimming
   (1901 tall against 1700 wide) rather than landscape, so `cover` crops
   top and bottom instead of the sides on an ordinary wide desktop window.
   --hero-pos: center 25% keeps both little shrines' roof peaks AND the
   floor lamps in frame; the comment on the Ayyappa Bhaktha Sangha hero
   explains the underlying percentage mechanics if this needs re-aiming.

   Being portrait already, it needs the SAME phone treatment as that other
   hero for the SAME reason — `cover` on a tall phone window would take a
   large bite out of the sides here too, since even trimmed the photo is
   still nearly square rather than phone-shaped. The 111.82vw below is
   1901/1700 — recompute it if this photograph is ever replaced.         */
body.page-updates       { --hero-img: url("../img/hero-updates-pandal.jpg");
                         --hero-size: cover;
                         --hero-pos: center 25%;
                         --hero-scrim: var(--hero-scrim-photo-top); }
body.page-updates .hero { min-height: 100vh; min-height: 100dvh; }

@media (max-width: 900px) {
  body.page-updates .hero { min-height: calc(100vh - var(--topbar-h));
                            min-height: calc(100dvh - var(--topbar-h)); }
}

@media (max-width: 900px) and (orientation: portrait) {
  body.page-updates .hero { min-height: 0;
                            --hero-size: contain;
                            --hero-pos: center top;
                            --hero-scrim: var(--hero-scrim-photo-band); }
  body.page-updates .hero .hero__inner { padding-top: calc(111.82vw + 1.25rem); }
}

/* A PHONE LAID FLAT — landscape, short — is what the two rules above don't
   cover, and it broke first on this page. `hero-scrim-photo-top` is built
   for a splash-sized hero, where the text sits in the top fraction of a box
   much taller than the text itself and the picture gets the rest of the box
   to breathe clear. Force that same box down to ~330px and the text now
   reaches almost to the bottom of it — past where the scrim has already
   faded to nearly nothing, so the lede's last line landed on bare,
   undarkened photograph. Ayyappa Bhaktha Sangha's hero has no lede, so the
   same squeeze never showed there — this is specific to a hero with three
   text blocks stacked on a short screen, not to any one page.

   Dropping the forced viewport height (below) only gets you halfway: the
   box then sizes to its own content instead, but that means the text now
   fills nearly the WHOLE box by construction, so a scrim built to clear
   through its lower half is fighting the one shape guaranteed to fail it.
   The second half of the fix is swapping in --hero-scrim-plain — evenly
   dark top to bottom rather than fading — which is exactly what a hero
   whose text can sit anywhere in the box needs. Losing the picture's clear
   middle is the trade; on a strip this short, legibility wins it. */
@media (max-width: 900px) and (max-height: 500px) {
  body.page-weekly .hero,
  body.page-updates .hero { min-height: 0;
                            --hero-scrim: var(--hero-scrim-plain); }
}

/* body.page-decisions { --hero-img: url("../img/hero-decisions.webp"); } */
/* body.page-archives  { --hero-img: url("../img/hero-archives.webp"); } */
/* body.page-songs     { --hero-img: url("../img/hero-songs.webp"); } */
/* body.page-contact   { --hero-img: url("../img/hero-contact.webp"); } */

/* --- Photographic section bands (see .section--photo in section 8) -------
   For a mid-page band sitting on a photograph, rather than the hero. Not
   currently used by any page: the band it was built for became the Ayyappa
   Bhaktha Sangha page, where the shrine photograph ended up in the hero
   instead. Kept ready for the next place a photograph needs to sit behind a
   whole section:
     #your-section-id { --section-img: url("../img/your-file.jpg");
                        --section-pos: center 42%; }
   ------------------------------------------------------------------------ */

/* Interior pages get a shorter hero than the home page. */
body:not(.page-home) .hero__inner { padding-block: clamp(2.5rem, 5.5vw, 4rem); }


/* ==========================================================================
   7. KOLAM DIVIDER — the signature motif. Use it sparingly: between major
   sections, not between every block.  Markup: <div class="kolam"></div>
   ========================================================================== */

.kolam {
  position: relative;
  height: 26px;
  margin-block: clamp(1.5rem, 4vw, 2.75rem);
}
/* Dotted row, faded at both ends. Deliberately narrow and centred — it is a
   small mark, not a rule across the page. */
.kolam::before {
  content: "";
  position: absolute; top: 0; bottom: 0;
  left: 50%; width: 208px;
  transform: translateX(-50%);
  background-image: radial-gradient(circle at center, var(--gold) 1.7px, transparent 1.8px);
  background-size: 13px 13px;
  background-repeat: repeat-x;
  background-position: center;
  opacity: .8;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 30%, #000 70%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 30%, #000 70%, transparent);
}
/* Centre diamond. */
.kolam::after {
  content: "";
  position: absolute; left: 50%; top: 50%;
  width: 9px; height: 9px;
  transform: translate(-50%, -50%) rotate(45deg);
  border: 1.5px solid var(--maroon);
  background: var(--paper);
}
.section--sunk .kolam::after { background: var(--paper-sunk); }
.kolam--on-dark::after { border-color: var(--gold); background: var(--maroon-deep); }

/* As the last thing in a section, the divider's own bottom margin would
   stack on top of the section's padding and leave a conspicuous void. */
.kolam:last-child { margin-bottom: 0; }


/* ==========================================================================
   8. CONTENT BLOCKS
   ========================================================================== */

.prose { max-width: 68ch; }
.prose h2 { margin-top: 2.2rem; }
.prose h3 { margin-top: 1.8rem; }
.prose ul, .prose ol { padding-left: 1.3rem; margin-bottom: 1.1em; }
.prose li { margin-bottom: .4em; }
.prose li::marker { color: var(--gold); }

.lead { font-size: 1.16rem; line-height: 1.6; color: var(--ink-soft); }

blockquote {
  margin: 1.8rem 0;
  padding: .2rem 0 .2rem 1.3rem;
  border-left: 3px solid var(--gold);
  font-family: var(--font-display);
  font-size: 1.16rem; font-style: italic;
  color: var(--maroon-deep);
}

/* --- Grid --------------------------------------------------------------- */
.grid { display: grid; gap: 1.25rem; }
/* min() keeps a single column from overflowing on narrow screens. */
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 400px), 1fr)); }
.grid--3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 240px), 1fr)); }

/* --- Card --------------------------------------------------------------- */
.card {
  position: relative;
  padding: 1.4rem;
  background: var(--paper-raised);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  transition: transform .18s var(--ease), box-shadow .18s var(--ease),
              border-color .18s var(--ease);
}
.card h3 { margin-bottom: .5rem; }
.card p  { color: var(--ink-soft); font-size: .98rem; }

/* A card that is itself a link: strip the inherited underline, otherwise
   every line of body text inside it gets underlined. */
.card--link {
  display: block;
  text-decoration: none;
  color: inherit;
}
.card--link h3 { color: var(--maroon-deep); transition: color .16s var(--ease); }

/* Only cards that actually do something get lift on hover. */
.card--link:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-md);
  border-color: var(--gold-soft);
  color: inherit;
}
.card--link:hover h3 { color: var(--maroon); }
.card--link:active { transform: translateY(-1px); }

/* The arrow inside a link-card has no hover of its own — drive it from
   the card so the whole thing responds as one control. */
.card--link .arrow-link { color: var(--maroon); margin-top: .9rem; }
.card--link:hover .arrow-link::after { transform: translateX(3px); }

.card__num {
  font-family: var(--font-display);
  font-size: .82rem; font-weight: 700;
  letter-spacing: .1em;
  color: var(--gold);
  margin: 0 0 .5rem;
}

/* --- Year cards (Archives) ---------------------------------------------- */
.year-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 1rem 1.5rem;
  align-items: start;
}
.year-card__year {
  grid-column: 1 / -1;
  display: flex; align-items: baseline; gap: .7rem;
  margin: 0 0 .2rem;
  font-family: var(--font-display);
  font-size: 1.6rem; color: var(--maroon);
}
.year-card__year small {
  font-family: var(--font-body);
  font-size: .74rem; font-weight: 700;
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--ink-soft);
}
.year-card__links {
  grid-column: 1 / -1;
  display: flex; flex-wrap: wrap; gap: .6rem;
  margin-top: .3rem;
}

/* --- Milestone band -----------------------------------------------------
   Used for the 60-years-of-Mandala-Vilakku note in 2026. Deliberately a
   separate component from the evergreen content so it can be deleted in
   one go when the year changes.
   ------------------------------------------------------------------------ */
.milestone {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 1rem 1.6rem;
  align-items: center;
  padding: 1.5rem 1.7rem;
  border: 1px solid var(--gold-soft);
  border-radius: var(--radius);
  background:
    radial-gradient(70% 130% at 0% 50%, rgba(217,142,31,.16), transparent 70%),
    var(--paper-raised);
  box-shadow: var(--shadow-sm);
}
.milestone__num {
  font-family: var(--font-display);
  font-size: clamp(2.8rem, 8vw, 4rem);
  font-weight: 600;
  line-height: .85;
  color: var(--gold);
  font-variation-settings: "SOFT" 40, "WONK" 1;
}
.milestone__num small {
  display: block;
  margin-top: .3rem;
  font-family: var(--font-body);
  font-size: .7rem; font-weight: 700;
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--ink-soft);
}
.milestone h2 { font-size: 1.35rem; margin-bottom: .4rem; }
.milestone p  { margin: 0; color: var(--ink-soft); font-size: .99rem; }

@media (max-width: 520px) {
  .milestone { grid-template-columns: 1fr; gap: .6rem; }
}

/* --- Notice / callout --------------------------------------------------- */
.notice {
  padding: 1rem 1.2rem;
  border-left: 3px solid var(--green);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  background: rgba(61,107,79,.08);
  font-size: .97rem;
}
.notice strong { color: var(--green); }
.notice--todo { border-left-color: var(--gold); background: rgba(217,142,31,.1); }
.notice--todo strong { color: #A06810; }

/* --- Timeline (Mandala Vilakku / Decisions) ----------------------------- */
.timeline { list-style: none; margin: 0; padding: 0; }
.timeline > li {
  position: relative;
  padding: 0 0 1.9rem 1.9rem;
  border-left: 1px solid var(--rule);
}
.timeline > li:last-child { border-left-color: transparent; padding-bottom: 0; }
.timeline > li::before {
  content: "";
  position: absolute; left: -5.5px; top: .5rem;
  width: 10px; height: 10px;
  border-radius: 50%;
  background: var(--paper);
  border: 2px solid var(--gold);
}
.timeline > li:first-child::before { background: var(--gold); }
.timeline__date {
  display: block;
  margin-bottom: .25rem;
  font-size: .78rem; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase;
  color: var(--ink-soft);
}
.timeline h3 { margin-bottom: .35rem; }
.timeline p  { color: var(--ink-soft); }

/* --- Definition-style detail list (Contact) ----------------------------- */
.detail-list { margin: 0; }
.detail-list div + div { margin-top: 1.1rem; padding-top: 1.1rem; border-top: 1px solid var(--rule); }
.detail-list dt {
  font-size: .74rem; font-weight: 700;
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: .2rem;
}
.detail-list dd { margin: 0; font-size: 1.05rem; }


/* ==========================================================================
   9. BUTTONS & LINKS
   ========================================================================== */

.btn {
  display: inline-flex; align-items: center; gap: .5rem;
  padding: .68rem 1.3rem;
  border: 1px solid transparent;
  border-radius: 999px;
  font-family: var(--font-body);
  font-size: .96rem; font-weight: 700;
  text-decoration: none;
  cursor: pointer;
  transition: background .16s var(--ease), color .16s var(--ease),
              border-color .16s var(--ease), transform .1s var(--ease),
              box-shadow .16s var(--ease);
}
.btn:active { transform: translateY(1px); }

.btn--primary {
  background: var(--gold); color: #3B2205;
  box-shadow: 0 1px 0 rgba(0,0,0,.12), 0 6px 16px rgba(217,142,31,.28);
}
.btn--primary:hover { background: var(--gold-soft); color: #3B2205; box-shadow: 0 1px 0 rgba(0,0,0,.12), 0 8px 22px rgba(217,142,31,.36); }

.btn--ghost {
  background: transparent; color: var(--on-dark);
  border-color: rgba(251,246,236,.42);
}
.btn--ghost:hover { background: rgba(251,246,236,.12); border-color: var(--on-dark); color: var(--on-dark); }

.btn--outline {
  background: var(--paper-raised); color: var(--maroon);
  border-color: var(--rule);
}
.btn--outline:hover { border-color: var(--maroon); background: #fff; color: var(--maroon-deep); }

.btn--sm { padding: .48rem 1rem; font-size: .875rem; }

/* Small labelled link chips — used for the archive year links. */
.chip {
  display: inline-flex; align-items: center; gap: .45rem;
  padding: .4rem .85rem;
  border: 1px solid var(--rule);
  border-radius: 999px;
  background: var(--paper);
  color: var(--maroon);
  font-size: .875rem; font-weight: 700;
  text-decoration: none;
  transition: border-color .16s var(--ease), background .16s var(--ease),
              transform .1s var(--ease);
}
.chip:hover { border-color: var(--gold); background: #fff; transform: translateY(-1px); }
.chip:active { transform: translateY(0); }
.chip[aria-disabled="true"] {
  color: var(--ink-soft); background: var(--paper-sunk);
  pointer-events: none; font-weight: 500;
}
.chip__dot { width: 6px; height: 6px; border-radius: 50%; background: var(--gold); flex: none; }
.chip--photos  .chip__dot { background: var(--gold); }
.chip--video   .chip__dot { background: var(--maroon); }
.chip--summary .chip__dot { background: var(--green); }

/* Plain arrow link. */
.arrow-link {
  display: inline-flex; align-items: center; gap: .4rem;
  font-weight: 700; text-decoration: none;
}
.arrow-link::after { content: "→"; transition: transform .16s var(--ease); }
.arrow-link:hover { text-decoration: underline; }
.arrow-link:hover::after { transform: translateX(3px); }


/* ==========================================================================
   10. SONGBOOK
   ========================================================================== */

.song-search {
  position: sticky; top: 0;
  z-index: 20;
  display: flex; flex-wrap: wrap; align-items: center; gap: .8rem;
  margin-bottom: 1.5rem;
  padding-block: 1rem;
  background: var(--paper);
  border-bottom: 1px solid var(--rule);
}
@media (max-width: 900px) { .song-search { top: var(--topbar-h); } }

.song-search__field { position: relative; flex: 1 1 260px; }
.song-search input {
  width: 100%;
  padding: .7rem 1rem .7rem 2.4rem;
  border: 1px solid var(--rule);
  border-radius: 999px;
  background: var(--paper-raised);
  font: inherit; font-size: 1rem;
  color: var(--ink);
}
.song-search input::placeholder { color: var(--ink-soft); }
.song-search input:focus { border-color: var(--gold); outline-offset: 1px; }
.song-search__icon {
  position: absolute; left: .9rem; top: 50%;
  transform: translateY(-50%);
  color: var(--ink-soft); pointer-events: none;
  font-size: .95rem;
}
.song-search__count { font-size: .88rem; color: var(--ink-soft); }

.song-list { list-style: none; margin: 0; padding: 0; }
.song-list > li { border-bottom: 1px solid var(--rule); }
.song-list > li[hidden] { display: none; }

.song { }
.song > summary {
  display: flex; align-items: baseline; gap: .8rem;
  padding: 1rem .4rem;
  cursor: pointer;
  list-style: none;
  transition: background .14s var(--ease);
}
.song > summary::-webkit-details-marker { display: none; }
.song > summary:hover { background: rgba(217,142,31,.07); }
.song[open] > summary { background: rgba(217,142,31,.07); }

.song__num {
  flex: none;
  min-width: 2.2rem;
  font-family: var(--font-display);
  font-size: .9rem; font-weight: 700;
  color: var(--gold);
}
.song__title {
  font-family: var(--font-ml), var(--font-display);
  font-size: 1.1rem; font-weight: 600;
  color: var(--maroon-deep);
  line-height: 1.5;
}
.song__title-en {
  display: block;
  font-family: var(--font-body);
  font-size: .84rem; font-weight: 500;
  color: var(--ink-soft);
  letter-spacing: .02em;
}
.song > summary::after {
  content: "+";
  margin-left: auto; flex: none;
  font-size: 1.3rem; line-height: 1;
  color: var(--ink-soft);
  transition: transform .18s var(--ease);
}
.song[open] > summary::after { content: "−"; }

.song__body {
  padding: .4rem .4rem 1.6rem 3rem;
}
@media (max-width: 600px) { .song__body { padding-left: .4rem; } }

.song__lyrics {
  margin: 0;
  font-family: var(--font-ml), var(--font-body);
  font-size: 1.09rem;
  line-height: 2.05;                 /* Malayalam needs generous leading */
  white-space: pre-line;             /* keeps the line breaks you type   */
  color: var(--ink);
}
.song__note {
  margin: 1rem 0 0;
  font-size: .86rem; color: var(--ink-soft);
  font-style: italic;
}

.song-empty {
  padding: 2.5rem .4rem;
  color: var(--ink-soft);
  text-align: center;
}


/* ==========================================================================
   11. FOOTER
   ========================================================================== */

.site-foot {
  margin-top: auto;
  padding-block: 2.25rem;
  border-top: 1px solid var(--rule);
  background: var(--paper-sunk);
  font-size: .9rem; color: var(--ink-soft);
}
.site-foot__inner {
  display: flex; flex-wrap: wrap;
  gap: 1rem 2rem; align-items: center;
  justify-content: space-between;
}
.site-foot p { margin: 0; }
.site-foot__links { display: flex; flex-wrap: wrap; gap: 1.2rem; }
.site-foot a { color: var(--maroon); font-weight: 600; text-decoration: none; }
.site-foot a:hover { text-decoration: underline; }


/* ==========================================================================
   12. MOTION & ACCESSIBILITY
   ========================================================================== */

/* Scroll-reveal. JS adds .is-in when the element enters the viewport.
   Without JS, .reveal never gets hidden in the first place — the
   opacity:0 below is applied by JS via the js-reveal class on <html>. */
.js-reveal .reveal {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity .55s var(--ease), transform .55s var(--ease);
}
.js-reveal .reveal.is-in { opacity: 1; transform: none; }
.js-reveal .reveal-2 { transition-delay: .08s; }
.js-reveal .reveal-3 { transition-delay: .16s; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  .js-reveal .reveal { opacity: 1; transform: none; }
}

/* Nav rendered by JS is hidden from the no-JS fallback and vice versa. */
.nojs-nav {
  padding: 1rem;
  background: var(--maroon-deep);
  color: var(--on-dark);
}
.nojs-nav ul { display: flex; flex-wrap: wrap; gap: 1rem; list-style: none; margin: 0; padding: 0; }
.nojs-nav a { color: var(--gold-soft); font-weight: 700; }


/* ==========================================================================
   13. MEDIA ARCHIVES GALLERY — Media Archives page only
   See "MEDIA ARCHIVES GALLERY" in assets/js/site.js for how this is built,
   and the window.ARCHIVE_YEARS block near the bottom of archives.html for
   what it's built from.
   ========================================================================== */

/* --- Year tabs + the "Earlier years" dropdown ----------------------------- */

.year-tabs {
  display: flex;
  align-items: center;
  gap: .5rem;
  width: 100%;    /* pinned explicitly, not left to default block sizing — see
                      below for why */
  min-width: 0;
  box-sizing: border-box;
  margin-bottom: 1.75rem;
  padding-bottom: .9rem;
  border-bottom: 1px solid var(--rule);
  overflow-x: auto;      /* a phone gets a horizontally-scrolling strip rather
                             than tabs wrapping onto a second line */
  -webkit-overflow-scrolling: touch;
}
/* Without an explicit width, a flex container holding several flex:none
   children (tabs) that don't fit can end up sized to its own content's
   min-content width in some layout contexts, rather than staying at its
   parent's width and scrolling internally the way overflow-x:auto above
   is meant to make it — the tabs then push past .wrap on the right with no
   scrollbar to reach the rest. Pinning width:100% removes the ambiguity:
   this box is always exactly as wide as .wrap allows, full stop, so the
   overflow-x:auto above always has a fixed box to clip against.

   ONE THING THAT LOOKS LIKE OVERFLOW BUT ISN'T: with this fix in place,
   document.documentElement.scrollWidth on this page still reads a few
   dozen pixels wider than clientWidth — that looks exactly like an
   overflow bug to an automated check, and it will trip one. It isn't one:
   document.body.scrollWidth reads correctly on this same page, and
   nothing anywhere on it has an unclipped edge past the viewport — checked
   directly, not assumed. This is Chrome's documentElement.scrollWidth
   picking up .year-tabs' own internal scrollWidth (how far its hidden
   content would reach, not how far it's ever drawn) even though that
   content is properly clipped and never actually renders past this box.
   If you're chasing an "overflow" that only documentElement.scrollWidth
   reports on this specific page, check body.scrollWidth and a real
   screenshot before trusting it — this is why. */

.year-tab {
  flex: none;
  padding: .55rem 1.15rem;
  border: 1px solid transparent;
  border-radius: 999px;
  background: transparent;
  color: var(--ink-soft);
  font-family: var(--font-body);
  font-size: .95rem; font-weight: 700;
  line-height: 1.25;
  text-align: center;
  cursor: pointer;
  transition: background .16s var(--ease), color .16s var(--ease);
}
.year-tab:hover { background: var(--paper-sunk); color: var(--ink); }
.year-tab:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
.year-tab[aria-selected="true"] { background: var(--maroon-deep); color: var(--on-dark); }
.year-tab[aria-selected="true"]:hover { background: var(--maroon); }

.year-tab__badge {
  display: block;
  margin-top: .15rem;
  font-size: .66rem; font-weight: 700;
  letter-spacing: .03em;
  color: var(--gold);
}
.year-tab[aria-selected="true"] .year-tab__badge { color: var(--gold-soft); }

.year-tabs__earlier {
  flex: none;
  margin-left: .25rem;
}
.year-tabs__earlier select {
  padding: .52rem 1.1rem;
  border: 1px solid var(--rule);
  border-radius: 999px;
  background: var(--paper-raised);
  color: var(--ink-soft);
  font-family: var(--font-body);
  font-size: .9rem; font-weight: 700;
  cursor: pointer;
  transition: border-color .16s var(--ease), color .16s var(--ease), background .16s var(--ease);
}
.year-tabs__earlier select:hover { border-color: var(--gold-soft); color: var(--ink); }
.year-tabs__earlier select:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }
/* Set by JS once a dropdown year is the active one — the same treatment as
   an active tab, so it's clear the dropdown IS the current selection
   rather than a second, separate control. */
.year-tabs__earlier select.is-active { background: var(--maroon-deep); border-color: var(--maroon-deep); color: var(--on-dark); }

/* --- The note above the grid ------------------------------------------------ */

.gallery-note {
  margin: 0 0 1.25rem;
  max-width: 62ch;
  color: var(--ink-soft);
}

/* --- The grid itself, and its empty state ----------------------------------- */

.gallery-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
  gap: 1.1rem;
}

.gallery-empty {
  padding: 2.75rem 1.5rem;
  border-radius: var(--radius);
  background: var(--paper-sunk);
  color: var(--ink-soft);
  font-size: .98rem;
  text-align: center;
}

.gallery-item {
  display: flex;
  flex-direction: column;
  gap: .75rem;
  padding: .9rem;
  background: var(--paper-raised);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  color: inherit;
  text-decoration: none;
  transition: transform .16s var(--ease), box-shadow .16s var(--ease), border-color .16s var(--ease);
}
.gallery-item:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-md);
  border-color: var(--gold-soft);
  color: inherit;
}
.gallery-item:active { transform: translateY(-1px); }
.gallery-item:focus-visible { outline: 2px solid var(--gold); outline-offset: 2px; }

/* A photo tile shows its folder mark by default. If the data gives it an
   item.thumbnail, a real cover image fills the same box instead — see
   photoTileHtml() in site.js. */
.gallery-item--photo .gallery-item__visual {
  display: grid; place-items: center;
  aspect-ratio: 4 / 3;
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--paper-sunk);
  color: var(--gold); /* only read by the fallback icon below */
}
.gallery-item--photo .gallery-item__visual svg { width: 38%; height: 38%; }
.gallery-item--photo .gallery-item__visual img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
}

/* A video tile gets a real YouTube thumbnail. paper-sunk shows through
   while it loads and if it ever fails, rather than a broken-image icon.
   display:flex + centering here is for the FALLBACK icon below, not the
   thumbnail — an <img> with width/height 100% fills the box regardless
   and ignores its parent's alignment. */
.gallery-item--video .gallery-item__visual {
  position: relative;
  display: flex; align-items: center; justify-content: center;
  aspect-ratio: 4 / 3;
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--paper-sunk);
  color: var(--gold); /* only read by the fallback icon below */
}
.gallery-item--video .gallery-item__visual img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
}
/* Falls back to the same folder mark as a photo tile, in the same gold,
   when no video ID could be read from the link (see youtubeId() in
   site.js) — this is what a playlist link looks like here. */
.gallery-item--video .gallery-item__visual > svg { width: 38%; height: 38%; }

.gallery-item__play { position: absolute; inset: 0; display: grid; place-items: center; }
.gallery-item__play::before {
  content: "";
  position: absolute;
  width: 44px; height: 44px;
  border-radius: 50%;
  background: rgba(43, 32, 24, .55);
  transition: background .16s var(--ease), transform .16s var(--ease);
}
.gallery-item:hover .gallery-item__play::before { background: var(--maroon); transform: scale(1.08); }
.gallery-item__play::after {
  content: "";
  position: relative;
  margin-left: 3px; /* a triangle's own visual centre sits left of its box */
  width: 0; height: 0;
  border-style: solid;
  border-width: 8px 0 8px 13px;
  border-color: transparent transparent transparent #fff;
}

.gallery-item__label {
  font-size: .95rem; font-weight: 700;
  color: var(--maroon-deep);
  transition: color .16s var(--ease);
}
.gallery-item:hover .gallery-item__label { color: var(--maroon); }
.gallery-item__meta { font-weight: 400; color: var(--ink-soft); }

/* --- Switching years ---------------------------------------------------------
   A short fade, driven by JS toggling this class before it swaps the grid's
   contents. Skipped under prefers-reduced-motion by the global override in
   section 12 (that block sets every transition-duration to .01ms), and the
   JS skips the wait that would otherwise go with it — see showYear() in
   site.js — so nothing pauses for a fade that isn't happening. */
#year-gallery { transition: opacity .16s var(--ease); }
#year-gallery.is-switching { opacity: 0; }
