/* ==========================================================================
   Ghumushara Vaidya Sangha -- design system
   --------------------------------------------------------------------------
   Direction: warm ivory light, deep forest green, and a restrained antique
   gold used only for rings, rules and ornament. Sections alternate between
   ivory and a pale sage; content sits on light parchment-yellow cards with
   soft edges -- never pure white, which read as clinical against the warm
   grounds and the painted artwork; the footer is a deep green block. Headings are set in the serif, body in the
   sans, with a small gold leaf ornament marking each section.

   How this arrived: two earlier palettes were rejected as "too brown" -- a
   flat palm-leaf tan, then an ink-and-marigold scheme -- and a plain white and
   green build after them. What was actually wrong was not warmth but
   flatness. The warm tones here work because they are carried by luminous
   painted imagery rather than by slabs of tan, which is the distinction to
   hold on to before touching this palette again. See docs/DECISIONS.md.

   Explicitly avoided: mortar-and-pestle stock photography, lotus icons as
   decoration, and any claim-shaped copy or imagery -- see the compliance notes
   in CLAUDE.md before adding anything to a page.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */

:root {
  /* Ground */
  --ivory: #fbf8f0;         /* page */
  --cream: #f5f1e4;         /* alternating band */
  --sage: #eaefdf;          /* second alternating band */
  /* Boxes are a light parchment yellow, never pure white -- white read as
     clinical against the warm grounds and the painted artwork. Warmer and
     lighter than every band, so a card still lifts off whatever it sits on.
     Text on it: ink 12.8:1, forest 11.6:1, green 7.0:1. */
  --card: #fdf6de;

  /* Ink */
  --ink: #2a2e26;           /* body                          13.1:1 on ivory */
  --ink-soft: #555b4e;      /* secondary                      6.6:1 on ivory */

  /* Green */
  --forest: #1b3a22;        /* headings, buttons             11.8:1 on ivory */
  --forest-deep: #122a18;   /* footer ground */
  --green: #2f5d33;         /* labels, links, hover           7.2:1 on ivory */

  /* Gold. Decorative weight only -- 2.4:1, never text. */
  --gold: #c0a050;
  --gold-soft: #e3d5aa;

  /* A word or value the Sangha's handwriting did not let us read, left as a
     highlighted blank for the organiser to fill in. Loud on purpose -- it is a
     to-do, not part of the design, and every one must be gone before launch. */
  --fill: #ffe45c;
  --fill-edge: #b58900;

  /* Rules */
  --rule: #e4ddca;
  --rule-strong: #cfc4a6;

  /* Type */
  --font-body: 'Noto Sans Oriya', 'Noto Sans Devanagari',
    system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-display: 'Cormorant Garamond', 'Noto Serif Oriya',
    'Noto Serif Devanagari', Georgia, 'Times New Roman', serif;

  /* Odia conjuncts stack tall; 1.78 is what real Odia paragraphs need to stop
     the ascenders of one line touching the descenders of the last. Tested with
     Odia copy, not lorem ipsum. */
  --lh-body: 1.78;
  --lh-heading: 1.34;
  --lh-display: 1.24;

  /* Pulled down one notch on 3 Sep 2026: the body scale started at 17-19px,
     which is generous even for Odia and left the members section unable to
     fit a group on one screen. Odia keeps its leading (--lh-body) instead;
     that is what conjuncts actually need, not point size. */
  --step--1: clamp(0.8125rem, 0.79rem + 0.11vw, 0.875rem);
  --step-0: clamp(0.9375rem, 0.9rem + 0.18vw, 1.0625rem);
  --step-1: clamp(1.0625rem, 1rem + 0.3vw, 1.25rem);
  --step-2: clamp(1.3125rem, 1.15rem + 0.75vw, 1.75rem);
  --step-3: clamp(1.5rem, 1.25rem + 1.2vw, 2.25rem);
  --step-4: clamp(1.875rem, 1.45rem + 2.1vw, 3rem);

  --sp-1: 0.25rem;
  --sp-2: 0.5rem;
  --sp-3: 0.75rem;
  --sp-4: 1rem;
  --sp-5: 1.5rem;
  --sp-6: 2rem;
  --sp-7: 3rem;
  --sp-8: 4.5rem;

  --measure: 34rem;

  /* How an illustration's edge is dissolved into the page it sits on, so it
     reads as painted onto the ground rather than pasted onto it.

     Two crossed linear fades, intersected -- not a radial one. A radial mask
     over a rectangle cannot feather it evenly: sized to clear the corners it
     leaves the edges hard, and sized to catch the edges it turns the picture
     into an oval vignette, which is a period effect rather than the absence
     of one. Both were tried. Crossing a horizontal fade with a vertical one
     feathers all four edges by the same amount and takes the corners twice
     over, which is right -- the corners are what give a rectangle away. */
  --plate-feather:
    linear-gradient(to right, transparent 0, #000 7%, #000 93%, transparent 100%),
    linear-gradient(to bottom, transparent 0, #000 7%, #000 93%, transparent 100%);
  --wrap: 68rem;
  --band-pad: clamp(3rem, 2rem + 5vw, 5.5rem);
  --gutter: clamp(1.125rem, 0.7rem + 2.2vw, 2.25rem);

  /* Height of the sticky bar and nav above the hero, measured by
     assets/js/hero.js. 0 is a safe default: the hero is then a full viewport
     tall and merely a little long, rather than broken. */
  --chrome: 0px;

  /* How the masthead's green dies away before it reaches the figure in the
     hero. One token, because the brand strip, the nav and the dissolve below
     the nav must fade on exactly the same curve or the seams show. */
  --masthead-falloff: linear-gradient(
    to right,
    #000 0,
    #000 30%,
    rgb(0 0 0 / 0.6) 42%,
    rgb(0 0 0 / 0.15) 50%,
    transparent 58%
  );

  --radius: 10px;
  --lift: 0 1px 2px rgb(27 58 34 / 0.05), 0 10px 30px -12px rgb(27 58 34 / 0.18);
  --lift-strong: 0 2px 6px rgb(27 58 34 / 0.07), 0 20px 46px -18px rgb(27 58 34 / 0.28);
}

/* --------------------------------------------------------------------------
   2. Reset
   -------------------------------------------------------------------------- */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: 5rem;     /* anchor targets clear the sticky bar */
}

body {
  background: var(--ivory);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--step-0);
  line-height: var(--lh-body);
  font-synthesis-weight: none;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
}

img, svg { max-width: 100%; display: block; height: auto; }
button, input, textarea, select { font: inherit; color: inherit; }
h1, h2, h3, h4 { font-weight: 700; line-height: var(--lh-heading); }

/* Cormorant sets noticeably smaller and lighter than Noto Serif Oriya at the
   same px, so Latin display text is nudged up to sit level with the Odia.

   The nudge is a MULTIPLIER ON THE TYPE SCALE, not `font-size: 1.12em`. `em`
   in a font-size resolves against the parent's size, not the element's own,
   so that spelling threw --step-4 away instead of scaling it: every display
   heading in English computed to 1.12 x the body size. The hero headline set
   at 19px where it should have been 48, band titles at 19 instead of 36, and
   the masthead name at 19 instead of 20. Odia and Hindi never matched the
   selector, which is why the site looked right in the language it is
   authored in and wrong in the one most likely to be read by anyone
   checking it. Shipped that way until 4 September 2026. */
:root { --display-scale: 1; }
html[data-lang='en'] { --display-scale: 1.12; }
html[data-lang='en'] .hero__name,
html[data-lang='en'] .band__title,
html[data-lang='en'] .brand__name { letter-spacing: 0.005em; }

a { color: var(--green); text-underline-offset: 0.18em; }
a:hover { color: var(--forest); }

::selection { background: #c0a05055; color: var(--ink); }

/* --------------------------------------------------------------------------
   3. Language switching
   --------------------------------------------------------------------------
   Every translated block ships in the page with all three variants present in
   the DOM. Switching is a CSS attribute flip: instant, works offline once the
   page has loaded, and costs no Firestore read -- which is what lets the
   pre-rendered member pages carry all three languages in one file.
   -------------------------------------------------------------------------- */

[data-t] { display: none; }

html[data-lang='od'] [data-t='od'],
html[data-lang='en'] [data-t='en'],
html[data-lang='hi'] [data-t='hi'] { display: revert; }

/* --------------------------------------------------------------------------
   4. Layout primitives
   -------------------------------------------------------------------------- */

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

.band { padding-block: var(--band-pad); background: var(--ivory); }
.band--cream { background: var(--cream); }
.band--sage { background: var(--sage); }

.band__title {
  font-family: var(--font-display);
  font-size: calc(var(--step-3) * var(--display-scale));
  color: var(--forest);
  margin-bottom: var(--sp-3);
}

.band__lead {
  color: var(--ink-soft);
  max-width: var(--measure);
  margin-bottom: var(--sp-6);
}

/* Eyebrow: a small green label with a gold leaf, above a section title. */
.eyebrow {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.12em;
  color: var(--green);
  margin-bottom: var(--sp-3);
}

.leaf {
  flex: none;
  width: 0.7rem;
  height: 0.7rem;
  background: var(--gold);
  border-radius: 0 60% 0 60%;
  transform: rotate(-45deg);
}

/* Section ornament: two gold hairlines flanking a leaf. */
.ornament {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  max-width: 16rem;
  margin-block: var(--sp-4) var(--sp-6);
}

.ornament::before,
.ornament::after {
  content: '';
  flex: 1 1 auto;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--gold-soft), transparent);
}

.ornament--center { margin-inline: auto; }

/* --------------------------------------------------------------------------
   5. Header
   -------------------------------------------------------------------------- */

.skip-link {
  position: absolute;
  left: var(--sp-3);
  top: var(--sp-3);
  z-index: 30;
  padding: var(--sp-2) var(--sp-4);
  background: var(--gold);
  color: var(--forest-deep);
  border-radius: 4px;
  transform: translateY(-250%);
}

.skip-link:focus { transform: none; }

/* The bar is the darkest green and the nav a step lighter, so the two read as
   one masthead with a clear hierarchy rather than as two stacked strips. Both
   are opaque -- a translucent bar over the painted hero muddied the artwork
   as it scrolled underneath. */
.site-bar {
  position: sticky;
  top: 0;
  z-index: 20;
  background: var(--forest-deep);
  border-bottom: 1px solid rgb(255 255 255 / 0.1);
}

.site-bar__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  min-height: 4rem;
  padding-block: var(--sp-2);
}

.brand {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  text-decoration: none;
  color: inherit;
  min-width: 0;
}

/* The emblem is generated on a transparent ground, so it needs a light plate
   to be legible on the dark bar. Same parchment as every other surface. */
.brand__mark {
  flex: none;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 50%;
  background: var(--card);
  padding: 3px;
}

.brand__name {
  font-family: var(--font-display);
  font-size: calc(var(--step-1) * var(--display-scale));
  font-weight: 700;
  line-height: 1.18;
  color: #fff;                /* on the dark bar: 15.4:1 */
  overflow-wrap: break-word;
  hyphens: none;
}

.brand__tag {
  display: block;
  font-family: var(--font-body);
  font-size: 0.75rem;
  font-weight: 400;
  letter-spacing: 0.1em;
  color: #b9c6b2;
  margin-top: 0.1rem;
}

/* Language control: three endonyms, always visible, never a dropdown.
   Every button clears a 44px touch target on a phone. */
.lang {
  display: flex;
  flex: none;
  border: 1px solid rgb(255 255 255 / 0.28);
  border-radius: 999px;
  overflow: hidden;
  background: rgb(255 255 255 / 0.06);
}

.lang__btn {
  appearance: none;
  border: 0;
  border-inline-start: 1px solid rgb(255 255 255 / 0.2);
  background: transparent;
  color: #dfe7da;
  font-size: var(--step--1);
  line-height: 1;
  padding: 0.6rem 0.65rem;
  min-height: 2.5rem;
  cursor: pointer;
  white-space: nowrap;
}

.lang__btn:first-of-type { border-inline-start: 0; }
.lang__btn:hover { background: rgb(255 255 255 / 0.12); color: #fff; }

/* Gold on the dark bar: 6.1:1 against the deep green, and it ties the active
   state to the ornament colour used everywhere else. */
.lang__btn[aria-pressed='true'] { background: var(--gold); color: var(--forest-deep); font-weight: 700; }

/* On a phone the bar is sticky, so it has to stay cheap. "Ghumushara Vaidya
   Sangha" wraps to three lines at 360px and the tagline adds a fourth, which
   costs a quarter of the screen on every scroll. Drop the tagline and step the
   mark and name down. */
@media (max-width: 30rem) {
  .site-bar__inner { min-height: 3.25rem; gap: var(--sp-2); }
  .brand { gap: var(--sp-2); }
  .brand__mark { width: 2rem; height: 2rem; }
  .brand__name { font-size: calc(var(--step-0) * var(--display-scale)); }
  .brand__tag { display: none; }
  .lang__btn { padding: 0.55rem 0.5rem; }
}

/* z-index, because .hero is a positioned, isolated element that now starts
   ABOVE this bar rather than below it -- a static nav would be painted over
   by the picture and simply vanish. position:relative is what makes z-index
   apply at all; the nav still scrolls away, unlike the sticky .site-bar. */
.site-nav {
  position: relative;
  z-index: 19;
  background: var(--forest);
  border-bottom: 3px solid var(--gold);
}

/* This element also carries .wrap. Do NOT reset padding or margin wholesale
   here -- `padding: 0` and `margin: 0` would wipe out .wrap's padding-inline
   and margin-inline:auto, and the nav would run to the window edge while the
   rest of the page stayed centred. */
.site-nav__list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1) var(--sp-5);
  list-style: none;
  padding-block: var(--sp-2) var(--sp-3);
}

.site-nav a {
  color: #dbe4d5;
  text-decoration: none;
  font-size: var(--step--1);
  letter-spacing: 0.04em;
  padding-block: var(--sp-2);
  border-bottom: 2px solid transparent;
}

.site-nav a:hover { color: #fff; border-bottom-color: var(--gold-soft); }

/* --------------------------------------------------------------------------
   6. Hero -- Option A
   --------------------------------------------------------------------------
   One painted scene with the copy over its open left. Two shapes from one
   piece of markup, because the two targets want opposite things:

   DESKTOP -- the picture must fill the entire viewport, not sit in a band in
   the middle or in one half. So the image is absolutely positioned across the
   whole section, the section is at least one screen tall, and the copy is laid
   over it behind a diagonal wash.

   PHONE -- the picture must never be cut in half by the fold. So the section
   becomes a two-row grid: copy first on a plain ivory ground, then the image
   below at its own full height, whole and uncropped-looking. No wash is needed
   because no text sits on the image at all.
   -------------------------------------------------------------------------- */

.hero {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background: var(--cream);
}

.hero__art {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Holds the figure in frame as the viewport narrows; the open left stays
     open for the headline. */
  object-position: 72% center;
  z-index: -2;
}

.hero::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(
    100deg,
    rgb(251 248 240 / 0.96) 0%,
    rgb(251 248 240 / 0.88) 30%,
    rgb(251 248 240 / 0.38) 56%,
    rgb(251 248 240 / 0) 78%
  );
}

.hero__inner { max-width: 34rem; padding-block: clamp(3rem, 2rem + 6vw, 6rem); }

.hero__name {
  font-family: var(--font-display);
  font-size: calc(var(--step-4) * var(--display-scale));
  line-height: var(--lh-display);
  color: var(--forest);
  margin-bottom: var(--sp-2);
}

.hero__lede {
  font-size: var(--step-1);
  line-height: 1.7;
  color: var(--ink-soft);
  margin-bottom: var(--sp-6);
}

.hero__actions { display: flex; flex-wrap: wrap; gap: var(--sp-3); }

/* Desktop: the scene fills the screen edge to edge, and exactly one screen
   tall -- minus the bar and nav stacked above it, or the call to action ends
   up below the fold. svh, not vh, so mobile browser chrome cannot overflow it
   either. */
@media (min-width: 52rem) {
  .hero {
    min-height: calc(100svh - var(--chrome));
    display: grid;
    align-items: center;
  }

  /* Two problems, one fix.

     The figure's face was being sliced across the eyes by the nav: the crop
     was anchored at centre, which on a wide short box puts his head above the
     top edge. Anchoring near the top brings the whole face into frame.

     And rather than the image starting at a hard green line, the bar now
     bleeds into it -- the deep green of the nav continues a short way down and
     dissolves. His crown sits inside that dissolve, which reads as the bar
     resting on the picture instead of cutting it. The face clears the fade
     entirely.

     The green is listed FIRST in the background shorthand so it paints on top
     of the ivory scrim below it; later layers sit behind earlier ones. */
  .hero__art { object-position: 72% 8%; }

  .hero::after {
    background:
      linear-gradient(
        to bottom,
        var(--forest-deep) 0,
        rgb(27 58 34 / 0.55) 2.5rem,
        rgb(27 58 34 / 0) 7rem
      ),
      linear-gradient(
        100deg,
        rgb(251 248 240 / 0.96) 0%,
        rgb(251 248 240 / 0.88) 30%,
        rgb(251 248 240 / 0.38) 56%,
        rgb(251 248 240 / 0) 78%
      );
  }

  /* ------------------------------------------------------------------------
     The hero owns the top of the page.

     The bar used to stop where the picture started, so the deep green ended
     on a ruled line and the figure began underneath it, his crown just below
     the cut. The painting now runs the full height, up behind both strips,
     and at the top of the page the strips are simply not drawn: no green, no
     hairline, no gold rule, no links. Nothing but the picture.

     The header itself STAYS -- green, links, white lettering, exactly as it
     is everywhere else on the site. What changes is where it stops. It is
     painted as one wash that dissolves rightward before it reaches the
     figure, so his halo and the foliage behind him run clean to the top of
     the page, and dissolves downward on the left so it does not end on a
     ruled line either. Two soft edges, no hard ones.

     Two earlier attempts are recorded because both were wrong in ways worth
     not repeating. Fading each strip's own background along its length left
     the gold rule and the hairline still drawn full width -- lines the eye
     reads as the edge of something, which is what "blend completely" was
     asking to be rid of. Drawing no bar at all, and lettering the mark and
     links straight onto the painting, removed the lines and the masthead
     with them: a home page with no logo and no navigation is not a blend.

     So: ONE element carries the green, not two. The strips go transparent
     and the wash lives on the hero, which is what lets it keep fading below
     the nav instead of stopping at that element's edge. mask-image does the
     horizontal falloff; the gradient itself does the vertical. Neither could
     do both alone -- a background gradient runs in one direction only.

     The lettering stays white BECAUSE the green stays: the mark, the name
     and the links all sit inside the solid part of the wash on the left.

     --chrome is the measured height of both strips, published by hero.js. If
     that never runs it is 0px, the lift is a no-op and the ordinary opaque
     masthead stands, which is the correct fallback. */
  .hero-lift .hero {
    margin-top: calc(var(--chrome) * -1);
    padding-top: var(--chrome);
    min-height: 100svh;
    /* Un-clipped so the art layer below can hang past the bottom edge. */
    overflow: visible;
  }

  /* THIS BLOCK IS WHAT PUTS THE PAINTING AT THE TOP OF THE PAGE. It has now
     been deleted twice by edits anchored in the comment above it, and both
     times the symptom was the same and unmistakable: the figure drops below
     the masthead and a band of bare ivory appears over him. If the Lord has
     "come down", look here first.

     The art layer alone hangs below the hero; the hero itself stays exactly
     one viewport. Padding the hero instead made an 817px hero in a 695px
     viewport and pushed the headline and buttons off the bottom. Pulling the
     pillars card up instead cost no height but sat the opaque card on the
     lede. Neither box moves. */
  .hero-lift .hero__art,
  .hero-lift .hero::after {
    height: auto;
    bottom: -12rem;
  }

  /* The old top-down green veil goes with it: it existed to soften the join
     between a solid bar and the image below, and there is no join now. Left
     in, it lays a dark film over exactly the band the crown occupies. The
     bottom-up ivory fade replaces it so the painting dissolves into the page
     ground rather than ending on a line. */
  .hero-lift .hero::after {
    background:
      linear-gradient(
        to top,
        var(--ivory) 0,
        rgb(251 248 240 / 0.86) 3rem,
        rgb(251 248 240 / 0.35) 7rem,
        rgb(251 248 240 / 0) 12rem
      ),
      linear-gradient(
        100deg,
        rgb(251 248 240 / 0.96) 0%,
        rgb(251 248 240 / 0.88) 30%,
        rgb(251 248 240 / 0.38) 56%,
        rgb(251 248 240 / 0) 78%
      );
  }

  .hero-lift .site-bar,
  .hero-lift .site-nav {
    background-image: none;
    background-color: transparent;
    border-bottom-color: transparent;
    transition: background-color 0.25s linear, border-bottom-color 0.25s linear;
  }

  /* The green rides on the two strips themselves, each masked so it dissolves
     before it reaches the figure. Not on the hero: an absolutely positioned
     child of .hero resolves against its CONTENT box, and the hero carries
     padding-top: var(--chrome), so the wash landed 118px low -- under the very
     bar it was meant to be behind. The strips have no such ambiguity. */
  /* The green is painted by a pseudo-element BEHIND the bar's contents, and
     the mask goes on that -- not on the bar itself.

     mask-image masks everything an element renders, its children included.
     Masking .site-bar directly therefore faded out the brand and the language
     control along with the green. The brand survived because it sits at the
     left, inside the solid end of the falloff; the language pills sit at 78%
     of the width, where the mask is fully transparent, so they vanished
     completely. Reported as the buttons disappearing on switching language --
     switching had nothing to do with it, that is just when anyone looks at
     them.

     Both strips are already positioned and carry a z-index, so each makes its
     own stacking context and a ::before at -1 sits behind its contents
     without falling behind the page. */
  .hero-lift .site-bar,
  .hero-lift .site-nav {
    background-color: transparent;
    background-image: none;
    -webkit-mask-image: none;
    mask-image: none;
  }

  .hero-lift .site-bar::before,
  .hero-lift .site-nav::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    -webkit-mask-image: var(--masthead-falloff);
    mask-image: var(--masthead-falloff);
  }

  .hero-lift .site-bar::before { background: var(--forest-deep); }
  .hero-lift .site-nav::before { background: var(--forest); }

  /* The dissolve BELOW the nav. It hangs off the nav rather than living in
     the hero for the same containing-block reason, and carries the identical
     mask so the two fades meet instead of crossing. */
  .hero-lift .site-nav::after {
    content: '';
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    height: 5.5rem;
    pointer-events: none;
    background: linear-gradient(
      to bottom,
      var(--forest) 0,
      rgb(27 58 34 / 0.55) 1.6rem,
      rgb(27 58 34 / 0.18) 3.2rem,
      rgb(27 58 34 / 0) 5.5rem
    );
    -webkit-mask-image: var(--masthead-falloff);
    mask-image: var(--masthead-falloff);
  }

  /* The gold rule under the nav is carried by the wash's own edge rather than
     drawn, because a border is one flat colour for its whole length and
     cannot fade with it. */
  .hero-lift .site-nav { border-bottom-color: transparent; }

  /* The pills sit out at ~75% of the width, past where the wash has gone, so
     they keep a ground of their own to hold their light text. */
  .hero-lift .lang { background: rgb(18 42 24 / 0.55); }

  /* Off the hero it is an ordinary masthead again, links and all. */
  /* Off the hero the mask has to be lifted as well as the colour restored --
     a masked bar over the rest of the page would keep dissolving on the right
     with nothing behind it to dissolve into, and the links at that end would
     go with it. The dissolve below the nav is removed outright. */
  .hero-lift.is-past-hero .site-bar::before,
  .hero-lift.is-past-hero .site-nav::before,
  .hero-lift.is-past-hero .site-nav::after { display: none; }

  .hero-lift.is-past-hero .site-bar {
    background-color: var(--forest-deep);
    background-image: none;
    border-bottom-color: rgb(255 255 255 / 0.1);
  }
  .hero-lift.is-past-hero .site-nav {
    background-color: var(--forest);
    background-image: none;
    border-bottom-color: var(--gold);
  }

  /* The nav does not stick anywhere else on the site -- it scrolls away and
     the brand strip alone follows the reader. Here it sticks, so that the
     masthead that was lettered onto the painting arrives as one piece when
     the green comes back under it, rather than the brand strip alone
     following the reader and the links vanishing off the top. */
  .hero-lift.is-past-hero .site-nav {
    position: sticky;
    top: var(--bar, 4rem);
  }
  .hero-lift.is-past-hero .lang { background: rgb(255 255 255 / 0.06); }

  /* align-items:center already centres the copy in that height, so the block
     padding only needs to keep it off the edges on a short laptop screen.
     The larger clamp used elsewhere pushed the buttons past the fold at
     647px of viewport height. */
  .hero__inner { padding-block: clamp(2rem, 1rem + 2.5vw, 3.5rem); }
}

/* Phone: copy above, whole picture below. The image is taken out of absolute
   flow and given its own row, so it can never straddle the fold. */
@media (max-width: 51.999rem) {
  .hero {
    display: grid;
    grid-template-rows: auto auto;
    background: var(--ivory);
  }

  /* No text over the image here, so the wash would only mute the painting. */
  .hero::after { display: none; }

  /* Picture first, copy under it. Copy-first was tried and put the image at
     616px on a 640px screen -- straddling the fold, which is the one thing
     this must not do. The Odia headline and lede simply need more height than
     is left over. Leading with the picture puts it whole and well above the
     fold, and the text below it can run as long as it needs to. */
  .hero__inner {
    max-width: none;
    padding-block: var(--sp-5) var(--sp-6);
  }

  .hero__art {
    position: static;
    width: 100%;
    height: clamp(13rem, 38svh, 18rem);
    object-position: 70% center;
    border-bottom: 1px solid var(--rule);
  }

  .hero__lede { font-size: var(--step-0); margin-bottom: var(--sp-5); }
  .hero__actions .btn { flex: 1 1 auto; justify-content: center; }
}

/* --------------------------------------------------------------------------
   7. What the Sangha does -- the four-up strip
   --------------------------------------------------------------------------
   Deliberately describes activity, never outcomes. Nothing here may drift
   into what a treatment achieves; see the compliance notes in CLAUDE.md.
   -------------------------------------------------------------------------- */

.pillars {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--sp-2);
  list-style: none;
  margin: 0;
  padding: var(--sp-5);
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  box-shadow: var(--lift);
}

@media (min-width: 34rem) { .pillars { grid-template-columns: repeat(2, 1fr); gap: var(--sp-4); } }
@media (min-width: 60rem) { .pillars { grid-template-columns: repeat(4, 1fr); gap: var(--sp-5); padding: var(--sp-6); } }

/* Lifted so the strip overlaps the hero, as a card sitting on the image. */
.pillars-holder { margin-top: calc(var(--sp-7) * -1); position: relative; z-index: 2; }

.pillar { display: flex; gap: var(--sp-3); align-items: flex-start; padding-block: var(--sp-2); }

@media (min-width: 60rem) { .pillar { flex-direction: column; gap: var(--sp-3); } }

.pillar__badge {
  flex: none;
  width: 2.75rem;
  height: 2.75rem;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--sage);
  border: 1px solid var(--gold-soft);
}

.pillar__badge svg { width: 1.375rem; height: 1.375rem; stroke: var(--forest); fill: none; stroke-width: 1.6; }

.pillar__title,
.pillar__body { display: block; }

.pillar__title { font-family: var(--font-display); font-size: var(--step-0); color: var(--forest); margin-bottom: 0.15rem; }
.pillar__body { font-size: var(--step--1); color: var(--ink-soft); line-height: 1.6; }

/* --------------------------------------------------------------------------
   8. Prose and About
   -------------------------------------------------------------------------- */

.about { display: grid; gap: var(--sp-6); align-items: center; }

@media (min-width: 52rem) {
  .about { grid-template-columns: minmax(0, 1fr) 20rem; gap: var(--sp-8); }
}

.about__figure { margin: 0; }

.about__figure img {
  width: 100%;
  max-width: 20rem;
  margin-inline: auto;
  border-radius: var(--radius);
  box-shadow: var(--lift);
  background: var(--card);
}

.about__figure figcaption {
  margin-top: var(--sp-3);
  font-size: var(--step--1);
  color: var(--ink-soft);
  text-align: center;
}

.prose { max-width: var(--measure); }

/* Each language variant is wrapped in its own [data-t] div, so the paragraphs
   are grandchildren, not children -- space both levels. */
.prose > * + *,
.prose > [data-t] > * + * { margin-top: var(--sp-5); }

.prose p { text-wrap: pretty; }

.prose h3 { font-family: var(--font-display); font-size: var(--step-1); color: var(--forest); margin-top: var(--sp-6); }
.prose ul, .prose ol { padding-inline-start: 1.4em; }
.prose li + li { margin-top: var(--sp-2); }

/* --------------------------------------------------------------------------
   The history spreads at /about

   One paragraph beside one illustration, alternating sides down the page.

   The measure stays close to .prose's 34rem even though there is now half a
   page to fill: line length is set by what is readable, not by what is
   available, and Odia conjuncts stack tall enough that a long line is harder
   here than it would be in Latin. The picture takes the space the text should
   not.

   Below 52rem the two stack, picture first, and the alternation stops
   mattering -- a single column has no sides to alternate between.
   -------------------------------------------------------------------- */
.spread {
  display: grid;
  gap: var(--sp-5);
  align-items: center;
  margin-top: var(--sp-7);
}

.spread:first-child { margin-top: var(--sp-6); }

.spread__text > [data-t] > * + * { margin-top: var(--sp-5); }
.spread__text p { text-wrap: pretty; }

/* The illustrations are square and painted right to the edge of their frame,
   which on an ivory page reads as a photograph pasted onto it. The mask fades
   all four edges out so each one settles into the ground instead -- the same
   thing the hero does at its bottom edge, and the reason nothing had to be
   regenerated to fix it. radial-gradient rather than four linear ones so the
   corners go too; they are the part that gives a rectangle away. */
.spread__art {
  margin: 0;
  -webkit-mask-image: var(--plate-feather);
  mask-image: var(--plate-feather);
  /* Both spellings: the standard keyword and the older WebKit one, which
     Chrome still needs alongside -webkit-mask-image. Without a composite the
     two gradients stack and the picture keeps its hard edges. */
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
}

.spread__art img { width: 100%; height: auto; }

@media (min-width: 52rem) {
  .spread {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: var(--sp-6);
    margin-top: var(--sp-8, 5rem);
  }

  /* The alternation. Text leads on the odd spreads, the picture on the even
     ones; `order` rather than re-ordering the markup, so the reading order
     stays paragraph-then-picture for a screen reader and for a page with no
     CSS at all. */
  .spread:nth-child(even) .spread__text { order: 2; }
  .spread:nth-child(even) .spread__art { order: 1; }

  .spread__text { max-width: 34rem; }
  .spread:nth-child(even) .spread__text { justify-self: end; }
}

@media (max-width: 51.999rem) {
  /* Picture first on a phone: it is what tells the reader a new part of the
     story has started, and it arrives while the previous paragraph is still
     being read. */
  .spread { grid-template-columns: 1fr; }
  .spread__art { order: -1; max-width: 22rem; margin-inline: auto; }
}

/* --------------------------------------------------------------------------
   9. Member cards
   --------------------------------------------------------------------------
   One column at 360px -- the primary target -- then two, then three. The whole
   card is the link, so it is a large touch target rather than a small one.
   -------------------------------------------------------------------------- */

.cards { display: grid; grid-template-columns: 1fr; gap: var(--sp-4); list-style: none; padding: 0; margin: 0; }

/* Rows are short and wide, so a wide screen fits four across. The gap shrinks
   as the columns multiply: four columns separated by 32px read as four lists
   rather than one grid. */
@media (min-width: 30rem) { .cards { grid-template-columns: repeat(2, 1fr); gap: var(--sp-3); } }
@media (min-width: 52rem) { .cards { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 72rem) { .cards { grid-template-columns: repeat(4, 1fr); } }

/* A row, at every width, not a tall poster.

   These were 4:3 plates over three lines of text, about 340px each, which
   meant no group in the members section could fit on one screen and a reader
   looking for one name had to scroll through the lot. As rows they are about
   a quarter of that: the portrait shrinks to a circle beside the name, the
   "View details" line becomes a chevron, and five office bearers, six
   advisors or a page of members each land inside one screen. */
.card {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  height: 100%;
  padding: var(--sp-3);
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  text-decoration: none;
  color: inherit;
  box-shadow: var(--lift);
}

.card:hover { box-shadow: var(--lift-strong); border-color: var(--gold-soft); }

.card__figure {
  position: relative;
  flex: none;
  width: 3.25rem;
  height: 3.25rem;
  border-radius: 50%;
  background: var(--sage);
  overflow: hidden;
}

.card__photo { width: 100%; height: 100%; object-fit: cover; }

/* The painted figure is already a circle on a transparent ground, so it needs
   no crop -- only the sage disc behind it. */
.card__photo--avatar { object-fit: contain; }

/* And where even the figure would be a guess -- the roll contradicts itself
   about one member -- the initial, which claims nothing. */
.card__plate {
  display: grid;
  place-items: center;
  width: 100%;
  height: 100%;
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-weight: 700;
  color: var(--forest);
}

.card__body {
  display: flex;
  flex-direction: column;
  gap: 0.05rem;
  min-width: 0;          /* or a long Odia name pushes the chevron off the card */
  flex: 1 1 auto;
}

.card__role {
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--green);
}

.card__name {
  font-family: var(--font-display);
  font-size: var(--step-0);
  line-height: 1.35;
  color: var(--forest);
}

.card__meta { font-size: var(--step--1); line-height: 1.4; color: var(--ink-soft); }
.card__meta .sep { color: var(--rule-strong); padding-inline: 0.35em; }

/* The whole card is the link; this is the affordance, not a second target. */
.card__go {
  flex: none;
  align-self: center;
  color: var(--gold);
  font-size: var(--step-1);
  line-height: 1;
}

/* The head of the pyramid earns a little more presence, but not another
   layout -- one size of card keeps every row in the section aligned. */
.card--lead { border-color: var(--gold-soft); }
.card--lead .card__figure { width: 3.75rem; height: 3.75rem; }
.card--lead .card__name { font-size: var(--step-1); }

/* Advisors. No photograph and no profile page -- they are not vaidyas and the
   Sangha holds nothing about them beyond the office they hold -- so the card
   is a quiet plate rather than a link, and it sits on the gold side of the
   palette to read as a distinct group without shouting for attention. */
.advisor {
  background: var(--card);
  border: 1px solid var(--rule);
  border-left: 3px solid var(--gold);
  border-radius: var(--radius);
  padding: var(--sp-3);
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.05rem;
  min-height: 100%;
  box-shadow: var(--lift);
}

.advisor__name {
  font-family: var(--font-display);
  font-size: var(--step-0);
  line-height: 1.35;
  color: var(--forest);
  margin: 0;
}

.advisor__meta { font-size: var(--step--1); color: var(--ink-soft); margin: 0; line-height: 1.4; }
.advisor .card__role { font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.08em; }
.advisor__meta .sep { color: var(--rule-strong); padding-inline: 0.35em; }

.cards__group {
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.12em;
  color: var(--ink-soft);
  margin-block: var(--sp-6) var(--sp-3);
}

.cards__group:first-of-type { margin-top: 0; }

/* The group label and its search box share a line where there is room, and
   stack where there is not. */
.cards__group-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-2) var(--sp-4);
  margin-block: var(--sp-6) var(--sp-3);
}

.cards__group-head .cards__group { margin: 0; }

.members__search { flex: 1 1 14rem; max-width: 22rem; }

.members__search input {
  width: 100%;
  padding: 0.4rem 0.75rem;
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius);
  background: var(--card);
  color: inherit;
  font: inherit;
  font-size: var(--step--1);
}

.members__search input:focus-visible { outline: 2px solid var(--green); outline-offset: 1px; }

/* Tightened on the smallest screens only. The layout is now the same at every
   width; this just closes the gaps up so a page of members still lands on one
   screen at 360px. */
@media (max-width: 29.999rem) {
  .cards { gap: var(--sp-2); }
  .card { padding: var(--sp-2) var(--sp-3); gap: var(--sp-3); }
  .card__figure { width: 2.75rem; height: 2.75rem; }
  .card--lead .card__figure { width: 3rem; height: 3rem; }
  .pyramid { gap: var(--sp-2); margin-bottom: var(--sp-5); }
  .pyramid__tier { gap: var(--sp-2); }
  .advisor { padding: var(--sp-2) var(--sp-3); }
}

/* --------------------------------------------------------------------------
   10. Patrika
   -------------------------------------------------------------------------- */

.issues { display: grid; gap: var(--sp-5); grid-template-columns: 1fr; }

/* --------------------------------------------------------------------------
   Patrika: a rail on the home page, capped cards in the archive.

   The archive groups issues by year, and a year with ONE issue in it got a
   card the full width of the page -- a 3:2 cover blown up to 1000px with
   three lines of text under it, so three issues ran to several screens. The
   cap is on the column, not the card, so a lone issue sits at the same size
   as one of three.
   -------------------------------------------------------------------- */
@media (min-width: 40rem) {
  .issues { grid-template-columns: repeat(auto-fill, minmax(16rem, 22rem)); }
}

/* The home page shows the three most recent side by side and scrolls them
   sideways when they do not fit, which on a 360px phone is always. Snap, so
   it comes to rest on a cover rather than halfway across one.

   scrollbar-width: none hides the bar without disabling the scrolling; the
   arrows are what tell a mouse user the rail moves, and they are added only
   when there is somewhere to go. */
.rail {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(15rem, 20rem);
  gap: var(--sp-5);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-padding-inline: var(--sp-1);
  overscroll-behavior-x: contain;
  padding-bottom: var(--sp-2);
  scrollbar-width: none;
}

.rail::-webkit-scrollbar { display: none; }
.rail > * { scroll-snap-align: start; }

.rail-nav { display: flex; gap: var(--sp-2); margin-top: var(--sp-4); }

.rail-nav button {
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 999px;
  border: 1px solid var(--rule);
  background: #fff;
  color: var(--forest);
  font-size: var(--step-0);
  line-height: 1;
  cursor: pointer;
}

.rail-nav button:hover:not(:disabled) { border-color: var(--gold); background: var(--gold-soft); }
.rail-nav button:disabled { opacity: 0.35; cursor: default; }


.issue {
  display: flex;
  flex-direction: column;
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--lift);
}

/* Top-anchored: a real patrika cover is portrait, and its masthead is the
   part that identifies the issue. The landscape fallback fits 3:2 exactly. */
.issue__cover { width: 100%; aspect-ratio: 3 / 2; object-fit: cover; object-position: top; border-bottom: 1px solid var(--rule); }

/* A blank the organiser is to fill in -- see fill() in i18n.js. */
.fill {
  background: var(--fill);
  box-shadow: inset 0 -2px 0 var(--fill-edge);
  border-radius: 2px;
  padding: 0 0.15em;
  color: var(--ink);
}
.issue__body { padding: var(--sp-5); display: flex; flex-direction: column; gap: var(--sp-3); flex: 1 1 auto; }
.issue__date { font-size: var(--step--1); letter-spacing: 0.06em; color: var(--green); font-weight: 700; }
.issue__title { font-family: var(--font-display); font-size: var(--step-1); color: var(--forest); }
.issue__summary { color: var(--ink-soft); font-size: var(--step--1); flex: 1 1 auto; }

.archive__year {
  font-family: var(--font-display);
  font-size: var(--step-2);
  color: var(--forest);
  margin-block: var(--sp-7) var(--sp-4);
  padding-bottom: var(--sp-2);
  border-bottom: 1px solid var(--gold-soft);
}

.archive__year:first-of-type { margin-top: 0; }

/* --------------------------------------------------------------------------
   11. Buttons
   -------------------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  min-height: 2.875rem;
  padding: var(--sp-3) var(--sp-6);
  border: 1px solid var(--forest);
  border-radius: 6px;
  background: var(--forest);
  color: #fff;
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.03em;
  text-decoration: none;
  cursor: pointer;
}

.btn:hover { background: var(--green); border-color: var(--green); color: #fff; }
.btn .leaf { background: var(--gold-soft); }

.btn--quiet { background: transparent; color: var(--forest); border-color: var(--rule-strong); }
.btn--quiet:hover { background: var(--sage); color: var(--forest); border-color: var(--gold); }

.link-more { display: inline-block; margin-top: var(--sp-5); font-size: var(--step--1); font-weight: 700; letter-spacing: 0.04em; }

/* --------------------------------------------------------------------------
   12. Contact
   -------------------------------------------------------------------------- */

.details { display: grid; gap: var(--sp-5); }

@media (min-width: 40rem) {
  .details { grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); gap: var(--sp-5) var(--sp-6); }
}

.detail__label {
  display: block;
  font-size: var(--step--1);
  letter-spacing: 0.06em;
  color: var(--green);
  font-weight: 700;
  margin-bottom: var(--sp-1);
}

.detail__value { font-size: var(--step-0); overflow-wrap: break-word; }

/* --------------------------------------------------------------------------
   13. Notices
   --------------------------------------------------------------------------
   The disclaimer is a legal requirement under the Drugs and Magic Remedies
   (Objectionable Advertisements) Act, 1954 and the NCISM code of ethics. Set
   at full body size on a distinct ground -- a readable notice, not 9px grey.
   -------------------------------------------------------------------------- */

.notice {
  padding: var(--sp-5);
  background: var(--card);
  border: 1px solid var(--rule);
  border-inline-start: 3px solid var(--gold);
  border-radius: var(--radius);
  max-width: 48rem;
}

.notice__title {
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.1em;
  color: var(--green);
  margin-bottom: var(--sp-2);
}

.notice__body { font-size: var(--step-0); color: var(--ink); }
.notice--inline { margin-top: var(--sp-7); }

/* --------------------------------------------------------------------------
   14. Footer
   -------------------------------------------------------------------------- */

.site-footer {
  background: var(--forest-deep);
  color: #e6ece2;
  padding-block: var(--sp-8) var(--sp-6);
  border-top: 3px solid var(--gold);
}

.site-footer a { color: #e6ece2; }
.site-footer a:hover { color: var(--gold-soft); }

.site-footer .notice {
  background: rgb(255 255 255 / 0.05);
  border-color: rgb(255 255 255 / 0.14);
  border-inline-start-color: var(--gold);
  color: #eef2ea;
}

.site-footer .notice__title { color: var(--gold-soft); }
.site-footer .notice__body { color: #e6ece2; }

.footer-brand { display: flex; align-items: center; gap: var(--sp-3); margin-bottom: var(--sp-5); }
.footer-brand img { width: 2.5rem; height: 2.5rem; border-radius: 50%; background: var(--card); padding: 3px; }
.footer-brand__name { font-family: var(--font-display); font-size: var(--step-1); color: #fff; }

.site-footer__meta {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--sp-3) var(--sp-5);
  margin-top: var(--sp-6);
  padding-top: var(--sp-4);
  border-top: 1px solid rgb(255 255 255 / 0.16);
  font-size: var(--step--1);
  color: #c3cdbc;
}

/* PatroVenture credit. The whole attribution is this one rule plus the single
   <p class="credit"> partial the pages share, so clearing
   config/site.showPatroventureCredit removes it with nothing left behind. */
.credit a { color: #c3cdbc; text-decoration-color: rgb(255 255 255 / 0.3); }
.credit a:hover { color: var(--gold-soft); }

/* --------------------------------------------------------------------------
   15. States
   -------------------------------------------------------------------------- */

.state { padding: var(--sp-5) 0; color: var(--ink-soft); font-size: var(--step--1); }
.state--error { color: #8c2f1d; }

.fallback-note {
  font-size: var(--step--1);
  color: var(--ink-soft);
  font-style: italic;
  margin-bottom: var(--sp-3);
  padding-inline-start: var(--sp-3);
  border-inline-start: 2px solid var(--gold);
}

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* --------------------------------------------------------------------------
   16. Focus, motion, print
   -------------------------------------------------------------------------- */

:focus-visible { outline: 3px solid var(--green); outline-offset: 2px; border-radius: 3px; }
.site-footer :focus-visible,
.site-bar :focus-visible,
.site-nav :focus-visible { outline-color: var(--gold); }
.lang__btn:focus-visible { outline-offset: -3px; }

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

@media print {
  .site-bar, .site-nav, .skip-link, .card__go, .link-more, .hero__art, .pillars-holder { display: none; }
  body { background: #fff; color: #000; font-size: 11pt; }
  .band, .hero, .site-footer, .notice, .issue, .card { background: #fff; color: #000; box-shadow: none; }
  .hero::after { display: none; }
  a, .site-footer a, .hero__name, .band__title { color: #000; }
  .notice { border: 1px solid #000; }
  .card, .issue { break-inside: avoid; }
}

/* --------------------------------------------------------------------------
   17. Image-backed bands, feature rows, footer columns
   --------------------------------------------------------------------------
   These were lost once already: they lived in a section appended after the
   sample-content ribbon, and removing the ribbon by truncating the file took
   them with it. Keep them above any section that might later be deleted
   wholesale, or check what follows before truncating.
   -------------------------------------------------------------------------- */

/* A band whose artwork sits behind its own content rather than beside it. The
   wash is heavy on purpose: the picture should be felt, not read, and the text
   over it must never depend on what the image happens to be doing there. */
.band--image { position: relative; isolation: isolate; overflow: hidden; }

.band__art {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  z-index: -2;
}

.band--image::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--wash, rgb(253 246 222 / 0.82));
}

/* Each section takes its own tint, so a long page reads as a sequence of
   places rather than one surface. All four are light enough that body ink
   clears 11:1 over them, whatever the photograph behind is doing. */
.wash--parchment { --wash: rgb(253 246 222 / 0.82); }
.wash--saffron   { --wash: rgb(252 233 200 / 0.82); }
.wash--sage      { --wash: rgb(228 239 221 / 0.82); }
.wash--olive     { --wash: rgb(239 240 214 / 0.82); }

/* A dark band breaks up a long page of warm light. The grove sits behind at
   reduced opacity; the panel over it carries the text at full contrast. */
.band--dark {
  position: relative;
  isolation: isolate;
  background: var(--forest-deep);
  color: #eef2ea;
  overflow: hidden;
}

.band--dark::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: url('/img/grove.webp') center / cover no-repeat;
  opacity: 0.6;
}

.panel {
  background: rgb(253 246 222 / 0.95);
  color: var(--ink);
  padding: clamp(1.5rem, 1rem + 3vw, 2.75rem);
  border-radius: var(--radius);
  border: 1px solid rgb(192 160 80 / 0.4);
  max-width: 38rem;
  box-shadow: var(--lift-strong);
}

.panel .band__title { margin-bottom: var(--sp-3); }

/* Alternating image-and-text rows. */
.feature { display: grid; gap: var(--sp-6); align-items: center; }

@media (min-width: 52rem) {
  .feature { grid-template-columns: 1fr 1fr; gap: var(--sp-8); }
  .feature--flip .feature__media { order: -1; }
}

.feature__media img {
  width: 100%;
  border-radius: var(--radius);
  box-shadow: var(--lift);
}

.feature__media figcaption {
  margin-top: var(--sp-3);
  font-size: var(--step--1);
  color: var(--ink-soft);
}

/* Footer columns. */
.footer-cols { display: grid; gap: var(--sp-6); margin-bottom: var(--sp-6); }

@media (min-width: 44rem) {
  .footer-cols { grid-template-columns: 1.5fr 1fr 1fr; gap: var(--sp-7); }
}

.footer-col__title {
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.12em;
  color: var(--gold-soft);
  margin-bottom: var(--sp-3);
}

.footer-col ul { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--sp-2); }
.footer-col a { text-decoration: none; }
.footer-col a:hover { text-decoration: underline; }
.footer-col p { color: #c9d3c2; font-size: var(--step--1); }


/* --------------------------------------------------------------------------
   18. Office-bearer pyramid, member photos, progressive reveal
   -------------------------------------------------------------------------- */

/* The office bearers step down: president alone, then the two others beside
   him, then the membership at large in the ordinary grid below. */
.pyramid { display: grid; gap: var(--sp-4); margin-bottom: var(--sp-7); }

@media (min-width: 30rem) { .pyramid { gap: var(--sp-3); } }

.pyramid__tier { display: grid; gap: var(--sp-4); list-style: none; padding: 0; margin: 0; }

@media (min-width: 30rem) {
  .pyramid__tier { gap: var(--sp-3); }
  .pyramid__tier--lead { max-width: 24rem; margin-inline: auto; }
  .pyramid__tier--pair { grid-template-columns: repeat(2, minmax(0, 1fr)); max-width: 49rem; margin-inline: auto; }
}

/* The president's card carries a little more weight without becoming a
   different component -- one card height keeps every row in the section
   aligned. */
.card--lead { border-color: var(--gold); box-shadow: var(--lift-strong); }
.card--lead .card__name { font-size: var(--step-1); }

/* Nobody has a biography yet, so this is usually empty; when one arrives it
   is clamped to two lines so one member cannot make their row twice the
   height of everyone else's. */
.card__desc {
  font-size: var(--step--1);
  color: var(--ink-soft);
  line-height: 1.5;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
}

.card__desc:empty { display: none; }

/* The link to the full list, under the carousel.

   This comment used to argue AGAINST a carousel, on the grounds that it hides
   most of the roll behind a timer and is hostile to anyone reading slowly.
   That argument still holds and is why the carousel has a pause button, why
   it stops on hover and focus, why it never starts under
   prefers-reduced-motion, and why there is a search box above it and an
   unpaginated table at /directory. The roll is never only behind the timer. */
.reveal-more { margin-top: var(--sp-4); display: flex; justify-content: center; }

/* The members carousel: ten cards a page, advancing on its own.

   The window is sized by JS to the page currently showing rather than to the
   tallest one. The last page is usually short -- three cards where the others
   have ten -- and a fixed height leaves a hole under it that looks like a
   loading failure. */
.rotator__viewport {
  overflow: hidden;
  transition: height 400ms ease;
}

.rotator__track {
  display: flex;
  transition: transform 550ms cubic-bezier(0.4, 0, 0.2, 1);
}

.rotator__page {
  flex: 0 0 100%;
  min-width: 0;          /* or a long Odia name stretches the page past 100% */
  align-content: start;
}

.rotator__controls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-3);
  margin-top: var(--sp-4);
}

.rotator__arrow,
.rotator__toggle {
  display: grid;
  place-items: center;
  width: 2.25rem;
  height: 2.25rem;
  border: 1px solid var(--rule-strong);
  border-radius: 50%;
  background: var(--card);
  color: var(--forest);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
}

.rotator__arrow:hover,
.rotator__toggle:hover { border-color: var(--gold); background: var(--gold-soft); }

/* Two bars for pause, one triangle for play. Drawn rather than fetched --
   an icon font or an SVG request for 12px of glyph is not worth a round trip. */
.rotator__toggle-icon {
  width: 0.6rem;
  height: 0.7rem;
  border-inline: 0.2rem solid currentColor;
}

.rotator__toggle.is-paused .rotator__toggle-icon {
  width: 0;
  height: 0;
  border: 0.35rem solid transparent;
  border-inline-start: 0.6rem solid currentColor;
  margin-inline-start: 0.15rem;
}

.rotator__dots {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  list-style: none;
  margin: 0;
  padding: 0;
}

.rotator__dots button {
  display: block;
  width: 0.55rem;
  height: 0.55rem;
  padding: 0;
  border: 1px solid var(--rule-strong);
  border-radius: 50%;
  background: transparent;
  cursor: pointer;
}

.rotator__dots button[aria-current='true'] {
  background: var(--forest);
  border-color: var(--forest);
  transform: scale(1.25);
}

/* A tap target of 9px fails every guideline going. The dot stays small and
   the hit area grows around it. */
.rotator__dots li { display: grid; place-items: center; width: 1.5rem; height: 1.5rem; }

/* A reader who has asked for less motion gets no movement at all: the
   carousel never starts itself, and paging by dot or arrow is instant. */
@media (prefers-reduced-motion: reduce) {
  .rotator__viewport,
  .rotator__track { transition: none; }
}

@media (max-width: 29.999rem) {
  /* Compact rows on a phone, matching the general grid. */
  .card--lead .card__photo,
  .card__photo { height: 100%; }
  .pyramid { gap: var(--sp-3); }
  .pyramid__tier { gap: var(--sp-3); }
}

/* --------------------------------------------------------------------------
   19. Member detail page
   --------------------------------------------------------------------------
   Used only by the pages functions/render-member.js writes to Storage. Those
   pages link this stylesheet rather than inlining it, so it stays in the
   browser cache across every member a reader opens.
   -------------------------------------------------------------------------- */

.member { display: grid; gap: var(--sp-6); align-items: start; }

@media (min-width: 46rem) {
  .member { grid-template-columns: 18rem minmax(0, 1fr); gap: var(--sp-7); }
}

.member__photo {
  width: 100%;
  max-width: 18rem;
  border-radius: var(--radius);
  border: 1px solid var(--rule);
  box-shadow: var(--lift);
  background: var(--card);
}

/* The drawn figure is a circle on a square canvas, not a portrait: it gets a
   plain parchment ground and no frame, so it does not pose as a photograph. */
.member__photo--avatar {
  max-width: 14rem;
  border: 0;
  box-shadow: none;
  background: transparent;
}

.member__body > * + * { margin-top: var(--sp-6); }

/* Detail rows stack on the member page rather than sitting in columns -- there
   are only a handful and several may be absent entirely. */
.member .details { grid-template-columns: 1fr; gap: var(--sp-4); }

@media (min-width: 34rem) {
  .member .details { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* --------------------------------------------------------------------------
   21. Member directory (/directory)

   The whole membership as one table, unpaginated. A table rather than more
   cards: nobody has a photograph yet, so a card is mostly empty space around
   three short facts, and as rows the entire Sangha fits in about two screens
   on a phone.
   -------------------------------------------------------------------------- */

.directory__controls {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-3);
  margin-block: var(--sp-5) var(--sp-4);
}

.directory__search { flex: 1 1 16rem; }

.directory__search input {
  width: 100%;
  padding: 0.6rem 0.85rem;
  border: 1px solid var(--rule-strong);
  border-radius: var(--radius);
  background: var(--card);
  color: inherit;
  font: inherit;
}

.directory__search input:focus-visible { outline: 2px solid var(--green); outline-offset: 1px; }

.directory__count { color: var(--ink-soft); font-size: var(--step--1); margin: 0; }

.directory {
  width: 100%;
  border-collapse: collapse;
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  overflow: hidden;
}

.directory th {
  text-align: start;
  font-size: var(--step--1);
  font-weight: 700;
  letter-spacing: 0.08em;
  color: var(--ink-soft);
  padding: var(--sp-3) var(--sp-4);
  border-bottom: 1px solid var(--rule-strong);
  background: var(--sage);
}

.directory td {
  padding: var(--sp-3) var(--sp-4);
  border-top: 1px solid var(--rule);
  vertical-align: top;
  font-size: var(--step--1);
  color: var(--ink-soft);
}

.directory tbody tr:first-child td { border-top: 0; }
.directory tbody tr:hover td { background: var(--sage); }

.directory__name { color: var(--ink); }

.directory__name a {
  font-family: var(--font-display);
  font-size: var(--step-0);
  color: var(--forest);
  text-decoration: none;
}

.directory__name a:hover { text-decoration: underline; }

.directory__role { font-weight: 700; letter-spacing: 0.05em; color: var(--green); }

.directory__sub { display: block; font-size: var(--step--1); color: var(--ink-soft); }
.directory__sub .sep { color: var(--rule-strong); padding-inline: 0.35em; }

.directory__age { text-align: end; white-space: nowrap; }

/* The asterisk marks an age that was recorded in a given year rather than
   computed from a date of birth. Explained in the footnote under the table --
   a title attribute alone is invisible on a phone. */
.directory__asof { color: var(--gold); padding-inline-start: 0.15em; }

.directory__footnote {
  margin-block: var(--sp-3) var(--sp-6);
  font-size: var(--step--1);
  color: var(--ink-soft);
}

.directory__heading {
  font-family: var(--font-display);
  font-size: var(--step-1);
  color: var(--forest);
  margin-block: var(--sp-6) var(--sp-3);
}

/* On a phone the practice line is the first thing to go: it repeats
   "Traditional Healer" fifty-three times and costs a line each. The village
   and the age carry the information someone is actually scanning for. */
@media (max-width: 29.999rem) {
  .directory th,
  .directory td { padding: var(--sp-3); }
  .directory__sub { line-height: 1.5; }
}
