/* ==========================================================================
   designs.css — the five VISIBLE design shells  (site/d/**)
   Owner: Aria (Design Lead) · Round 6 · 2026-10-12
   --------------------------------------------------------------------------
   One stylesheet, five pages. Each page is
       site/d/{a,b,c,d,e}/index.html   with  <html data-design="a|b|c|d|e">
   and, since Round 6, its OWN markup: five different DOM structures generated
   by docs/design/build-design-shells.py. All colour comes from
   assets/design-tokens-v2.css (linked FIRST by every page); this file only
   consumes its tokens and wires the structural modifiers (--shell-ground /
   --hero-layout / --panel / --ornament / --display-*) plus the Round 6
   composition classes (.structure--journey|programme|mandala|letter|steps,
   .programme__front, .who, .programme__steps) and the motion system
   (@keyframes + tokens live in design-tokens-v2.css §6; THIS file consumes).

   RULES OBEYED HERE
   - No hardcoded palette hexes. Everything is var(--c-*) / var(--*-tint).
   - Contrast: text sits only on --c-bg / --c-surface / --c-surface-2, using
     --c-ink (body), --c-ink-muted (small captions) or --c-primary
     (eyebrow/link). --c-ink-subtle is never used for text. Verified against
     the 170-pair table in docs/design/DIRECTION-3.md §3.
   - --c-ink-muted for small captions, never --c-ink-subtle (R5 rule).
   - Phone-first 360–430px; nothing overflows at 320px.
   - Design B loads and renders with ZERO imagery (photo + all SVG hidden).
   - No Assamese/Bengali script, no Phad/haveli/zari/marigold register.
   - Motion is decorative only; every animation ends at a DESIGNED static
     frame, and prefers-reduced-motion (tokens §5 guard + this file's guard)
     rests each element on that frame — never on an empty state.
   ========================================================================== */

/* --------------------------------------------------------------------------
   0. FONT FACES — relative re-declaration of the token file's faces.
   The token file points at root-absolute /assets/fonts/*. That is correct
   when served (and it is what ships). These relative copies are the SAME
   files (../../assets/fonts from site/d/) so the shells also render correctly
   when opened directly from disk (file://), where an absolute path cannot
   resolve. Same family + weight + style + unicode-range ⇒ no visual change.
   -------------------------------------------------------------------------- */
@font-face{font-family:"Tiro Devanagari Hindi";font-style:normal;font-weight:400;font-display:swap;
  src:url("../../assets/fonts/tiro-devanagari-hindi-400.woff2") format("woff2");
  unicode-range:U+0900-097F,U+A8E0-A8FF,U+1CD0-1CFF,U+200C-200D,U+25CC,U+20B9;}
@font-face{font-family:"Tiro Devanagari Hindi";font-style:italic;font-weight:400;font-display:swap;
  src:url("../../assets/fonts/tiro-devanagari-hindi-400i.woff2") format("woff2");
  unicode-range:U+0900-097F,U+A8E0-A8FF,U+1CD0-1CFF,U+200C-200D,U+25CC,U+20B9;}
@font-face{font-family:"Noto Serif Devanagari";font-style:normal;font-weight:400;font-display:swap;
  src:url("../../assets/fonts/noto-serif-devanagari-400.woff2") format("woff2");
  unicode-range:U+0900-097F,U+A8E0-A8FF,U+1CD0-1CFF,U+200C-200D,U+25CC,U+20B9;}
@font-face{font-family:"Noto Serif Devanagari";font-style:normal;font-weight:600;font-display:swap;
  src:url("../../assets/fonts/noto-serif-devanagari-600.woff2") format("woff2");
  unicode-range:U+0900-097F,U+A8E0-A8FF,U+1CD0-1CFF,U+200C-200D,U+25CC,U+20B9;}
@font-face{font-family:"Noto Serif Devanagari";font-style:normal;font-weight:700;font-display:swap;
  src:url("../../assets/fonts/noto-serif-devanagari-700.woff2") format("woff2");
  unicode-range:U+0900-097F,U+A8E0-A8FF,U+1CD0-1CFF,U+200C-200D,U+25CC,U+20B9;}
@font-face{font-family:"Inter";font-style:normal;font-weight:400;font-display:swap;
  src:url("../../assets/fonts/inter-400.woff2") format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+2000-206F,U+20AC,U+2122,U+2212;}
@font-face{font-family:"Inter";font-style:normal;font-weight:600;font-display:swap;
  src:url("../../assets/fonts/inter-600.woff2") format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+2000-206F,U+20AC,U+2122,U+2212;}
@font-face{font-family:"Fraunces";font-style:normal;font-weight:600;font-display:swap;
  src:url("../../assets/fonts/fraunces-600.woff2") format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+2000-206F,U+20AC,U+2122,U+2212;}
@font-face{font-family:"Fraunces";font-style:italic;font-weight:600;font-display:swap;
  src:url("../../assets/fonts/fraunces-600i.woff2") format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+2000-206F,U+20AC,U+2122,U+2212;}
@font-face{font-family:"Space Grotesk";font-style:normal;font-weight:500;font-display:swap;
  src:url("../../assets/fonts/space-grotesk-500.woff2") format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+2000-206F,U+20AC,U+2122,U+2212;}
@font-face{font-family:"Space Grotesk";font-style:normal;font-weight:700;font-display:swap;
  src:url("../../assets/fonts/space-grotesk-700.woff2") format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+2000-206F,U+20AC,U+2122,U+2212;}
@font-face{font-family:"Outfit";font-style:normal;font-weight:600;font-display:swap;
  src:url("../../assets/fonts/outfit-600.woff2") format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+2000-206F,U+20AC,U+2122,U+2212;}
@font-face{font-family:"Outfit";font-style:normal;font-weight:700;font-display:swap;
  src:url("../../assets/fonts/outfit-700.woff2") format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+2000-206F,U+20AC,U+2122,U+2212;}
@font-face{font-family:"Lora";font-style:normal;font-weight:500;font-display:swap;
  src:url("../../assets/fonts/lora-500.woff2") format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+2000-206F,U+20AC,U+2122,U+2212;}

/* --------------------------------------------------------------------------
   1. BASE
   -------------------------------------------------------------------------- */
*,*::before,*::after{box-sizing:border-box;}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth;}
@media (prefers-reduced-motion:reduce){html{scroll-behavior:auto;}}
body{
  margin:0;background:var(--c-bg);color:var(--c-ink);
  font-family:var(--font-body);font-size:var(--fs-base);line-height:var(--lh-normal);
  font-weight:var(--fw-regular);
  text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;
  overflow-x:hidden;
}
img{max-width:100%;height:auto;}
h1,h2,h3,h4,p,dl,dd,figure,ol,ul{margin:0;}
a{color:var(--c-primary);text-decoration-thickness:1px;text-underline-offset:.18em;}
:focus-visible{outline:3px solid var(--c-focus);outline-offset:2px;border-radius:var(--r-xs);}

.wrap{max-width:var(--page-max);margin-inline:auto;padding-inline:var(--gutter);}
.skip{
  position:absolute;left:var(--sp-3);top:-100px;z-index:var(--z-toast);
  background:var(--c-primary);color:var(--c-on-primary);
  padding:var(--sp-2) var(--sp-4);border-radius:var(--r-sm);
  font-family:var(--font-latin-ui);font-size:var(--fs-sm);text-decoration:none;
}
.skip:focus{top:var(--sp-3);}

/* Section scaffolding ---------------------------------------------------- */
.section{margin-top:var(--section-gap);}
.section__heading{
  font-family:var(--font-display);font-weight:var(--fw-semibold);
  font-size:var(--fs-xl);line-height:var(--lh-snug);letter-spacing:var(--ls-tight);
}
.section__intro{margin-top:var(--sp-2);color:var(--c-ink-muted);font-size:var(--fs-base);}
.kicker{
  font-family:var(--font-dev-text);font-size:var(--fs-xs);letter-spacing:var(--ls-wide);
  color:var(--c-primary);margin-bottom:var(--sp-2);
}

/* Panels (.card) — structural modifier --panel ---------------------------- */
.card{
  background:var(--c-surface);color:var(--c-ink);
  border:1px solid var(--c-border);border-radius:var(--radius-panel);
  padding:var(--sp-6);
}
[data-design="a"] .card{border:1px solid var(--c-border);box-shadow:var(--sh-sm);}
[data-design="b"] .card{border:0;border-top:3px solid var(--c-primary);border-radius:0;
  background:transparent;padding:var(--sp-5) 0 0;}
[data-design="c"] .card{border:1px solid var(--c-border-strong);
  outline:1px solid var(--c-border-strong);outline-offset:4px;background:var(--c-surface);}
[data-design="d"] .card{border:1px solid var(--c-border);box-shadow:var(--sh-sm);
  background:var(--c-surface);}
[data-design="e"] .card{border:0;border-top:1px solid var(--c-border);border-radius:0;
  background:transparent;padding:var(--sp-6) 0 0;}

/* --------------------------------------------------------------------------
   2. HERO
   -------------------------------------------------------------------------- */
.hero{
  position:relative;isolation:isolate;
  padding-top:calc(var(--safe-top) + var(--sp-8));
  padding-bottom:var(--sp-8);
}
.hero__ground{position:absolute;inset:0;z-index:-1;pointer-events:none;}
.hero__inner{
  display:flex;flex-direction:column;align-items:center;text-align:center;
  gap:var(--sp-3);
}
.hero__invocation{
  font-family:var(--font-dev-display);color:var(--c-primary);
  font-size:var(--fs-md);line-height:var(--lh-snug);letter-spacing:var(--ls-wide);
}
.hero__eyebrow{
  font-family:var(--font-dev-text);font-size:var(--fs-xs);
  letter-spacing:.22em;color:var(--c-ink-muted);text-transform:none;
}
.hero__names{
  font-family:var(--font-display);
  font-weight:var(--display-weight);letter-spacing:var(--display-track);
  font-size:var(--display-size);line-height:var(--lh-tight);
  overflow-wrap:break-word;
}
.hero__name{display:block;}
.hero__amp{
  display:block;font-family:var(--font-dev-text);font-weight:400;
  font-size:var(--fs-md);line-height:1.2;color:var(--c-ink-muted);
  letter-spacing:var(--ls-wide);margin-block:.15em;
}
.hero__deva{
  font-family:var(--font-dev-display);font-size:var(--fs-lg);
  color:var(--c-ink-muted);line-height:var(--lh-snug);
}
.hero__date{
  font-family:var(--font-dev-text);font-size:var(--fs-lg);line-height:var(--lh-snug);
}
.hero__place{color:var(--c-ink-muted);font-size:var(--fs-base);}

/* Countdown */
.countdown{
  display:flex;justify-content:center;gap:var(--sp-4);margin-top:var(--sp-1);
  font-variant-numeric:tabular-nums;
}
.countdown .cd{display:flex;flex-direction:column;align-items:center;min-width:2.6em;}
.countdown b{
  font-family:var(--font-latin-ui);font-weight:600;font-size:var(--fs-xl);
  line-height:1.1;color:var(--c-ink);
}
.countdown small{
  font-family:var(--font-dev-text);font-size:var(--fs-2xs);color:var(--c-ink-muted);
  letter-spacing:var(--ls-wide);
}
.countdown__caption{font-size:var(--fs-sm);color:var(--c-ink-muted);}

.hero__actions{display:flex;flex-wrap:wrap;gap:var(--sp-3);justify-content:center;
  margin-top:var(--sp-3);width:100%;}

/* Hero photograph — shown on A, C, D only; on B, E the element is
   display:none, and a hidden background-image is never fetched, so B renders
   with a genuine ZERO imagery cost (verified: 0 requests, cold or warm).
   image-set() negotiates WebP with a JPEG fallback; aspect-ratio reserves the
   box so there is no layout shift. */
.hero__photo{
  margin:0 auto var(--sp-6);
  width:100%;max-width:min(100%,30rem);
  aspect-ratio:560/366;
  background-position:center;background-size:cover;background-repeat:no-repeat;
  border:1px solid var(--c-border);border-radius:var(--radius-panel);
  background-image:image-set(
    url("../../assets/photo/couple-360.webp") type("image/webp"),
    url("../../assets/photo/couple-360.jpg") type("image/jpeg"));
}
@media (min-width:420px){
  .hero__photo{
    background-image:image-set(
      url("../../assets/photo/couple-560.webp") type("image/webp"),
      url("../../assets/photo/couple-560.jpg") type("image/jpeg"));
  }
}
[data-design="a"] .hero__photo{border-color:var(--c-border-strong);box-shadow:var(--sh-md);}
[data-design="c"] .hero__photo{border-color:var(--c-border-strong);}
[data-design="d"] .hero__photo{box-shadow:var(--sh-md);border-color:var(--c-border);}
[data-design="b"] .hero__photo,
[data-design="e"] .hero__photo{display:none;}

/* Hero layout per design -------------------------------------------------- */
[data-design="a"] .hero__ground{
  background:
    radial-gradient(120% 70% at 50% 118%, var(--c-primary-tint), transparent 62%),
    linear-gradient(180deg, var(--c-surface-sunken), var(--c-bg) 42%);
}
[data-design="a"] .hero__inner{align-items:center;text-align:center;}
[data-design="a"] .hero__invocation{}

[data-design="b"] .hero__inner{align-items:flex-start;text-align:left;gap:var(--sp-2);}
[data-design="b"] .hero__eyebrow{margin-bottom:var(--sp-2);}
[data-design="b"] .hero__amp{margin:.05em 0;}
[data-design="b"] .hero__actions{justify-content:flex-start;}
[data-design="b"] .hero__invocation{font-size:var(--fs-lg);}

[data-design="c"] .hero__ground{
  background-image:radial-gradient(var(--c-border) 1.3px, transparent 1.5px);
  background-size:20px 20px;background-position:center;
}
[data-design="c"] .hero__inner{
  align-items:center;text-align:center;
  border:1px solid var(--c-border-strong);outline:1px solid var(--c-border-strong);
  outline-offset:5px;border-radius:var(--radius-panel);
  background:var(--c-surface);padding:var(--sp-6);gap:var(--sp-3);
}

[data-design="d"] .hero__ground{
  background:
    radial-gradient(80% 55% at 12% 4%, var(--c-primary-tint), transparent 60%),
    radial-gradient(70% 50% at 92% 96%, var(--c-success-tint), transparent 62%);
}
[data-design="d"] .hero__inner{align-items:center;text-align:center;}

[data-design="e"] .hero__inner{align-items:center;text-align:center;gap:var(--sp-4);
  padding-block:var(--sp-6);}
[data-design="e"] .hero__eyebrow{color:var(--c-ink-muted);}
[data-design="e"] .hero__invocation{font-size:var(--fs-base);color:var(--c-ink-muted);}

/* --------------------------------------------------------------------------
   3. ORNAMENT slot (shared markup; one glyph per design via CSS)
   -------------------------------------------------------------------------- */
.ornament{display:flex;justify-content:center;color:var(--c-primary);margin-block:var(--sp-1);}
.ornament .orn{display:none;max-width:100%;height:auto;}
[data-design="a"] .orn--rule,
[data-design="b"] .orn--rule{display:block;}
[data-design="c"] .orn--kolam{display:block;color:var(--c-accent);}
[data-design="d"] .orn--vine{display:block;color:var(--c-accent);}
[data-design="e"] .orn--flame{display:block;color:var(--c-primary);}
[data-design="c"] .ornament,
[data-design="d"] .ornament{margin-block:var(--sp-3);}
[data-design="e"] .ornament{margin-bottom:var(--sp-2);}

/* --------------------------------------------------------------------------
   4. TIMELINE (overnight) — two nights, no invented clock times
   -------------------------------------------------------------------------- */
.timeline{list-style:none;padding:0;margin:var(--sp-4) 0 0;}
.timeline__row{
  position:relative;padding:0 0 var(--sp-6) var(--sp-6);
  border-left:2px solid var(--c-border-strong);
}
.timeline__row:last-child{border-left-color:transparent;padding-bottom:0;}
.timeline__row::before{
  content:"";position:absolute;left:-7px;top:.45em;
  width:12px;height:12px;border-radius:50%;
  background:var(--c-primary);box-shadow:0 0 0 4px var(--c-bg);
}
[data-design="c"] .timeline__row::before,
[data-design="d"] .timeline__row::before{box-shadow:0 0 0 4px var(--c-bg);}
.timeline__when{
  font-family:var(--font-latin-ui);font-size:var(--fs-xs);letter-spacing:var(--ls-wide);
  color:var(--c-primary);
}
.timeline__what{
  font-family:var(--font-display);font-size:var(--fs-lg);font-weight:var(--fw-semibold);
  line-height:var(--lh-snug);margin-top:.1em;
}
.timeline__note{color:var(--c-ink-muted);font-size:var(--fs-sm);margin-top:.1em;}

/* --------------------------------------------------------------------------
   5. DETAILS
   -------------------------------------------------------------------------- */
.details{
  display:grid;grid-template-columns:auto 1fr;gap:var(--sp-2) var(--sp-5);
  margin-top:var(--sp-3);
}
.details dt{color:var(--c-ink-muted);font-size:var(--fs-sm);letter-spacing:var(--ls-wide);}
.details dd{margin:0;font-size:var(--fs-md);line-height:var(--lh-snug);}
.details__address{color:var(--c-ink-muted);font-size:var(--fs-base);}
.details__note{margin-top:var(--sp-4);color:var(--c-ink-muted);font-size:var(--fs-sm);}
.section--details .btn{margin-top:var(--sp-5);}

/* --------------------------------------------------------------------------
   6. LINEAGE — the Brahmin register, confirmed fields only
   -------------------------------------------------------------------------- */
.lineage{display:grid;gap:var(--sp-4);margin-top:var(--sp-4);}
.lineage__col{
  border:1px solid var(--c-border);border-radius:var(--radius-panel);
  padding:var(--sp-4) var(--sp-5);background:var(--c-surface);
}
[data-design="b"] .lineage__col{border:0;border-radius:0;background:transparent;
  padding-inline:0;border-left:3px solid var(--c-primary);border-radius:0;padding-left:var(--sp-4);}
[data-design="c"] .lineage__col{border:1px solid var(--c-border-strong);background:var(--c-surface);}
[data-design="e"] .lineage__col{border:0;border-radius:0;background:transparent;
  padding:var(--sp-3) 0;border-top:1px solid var(--c-border);}
.lineage__role{
  font-family:var(--font-latin-ui);font-size:var(--fs-2xs);letter-spacing:.18em;
  color:var(--c-primary);text-transform:uppercase;
}
.lineage__name{
  font-family:var(--font-dev-display);font-size:var(--fs-xl);line-height:var(--lh-snug);
  margin-top:var(--sp-1);
}
.lineage__name--latin{font-family:var(--font-latin-display);font-size:var(--fs-base);
  color:var(--c-ink-muted);margin-top:0;}
.lineage__line{margin-top:var(--sp-2);font-size:var(--fs-sm);color:var(--c-ink);line-height:var(--lh-snug);}
.lineage__note{margin-top:var(--sp-1);font-size:var(--fs-sm);color:var(--c-ink-muted);}
@media (min-width:520px){
  .lineage{grid-template-columns:1fr 1fr;}
}

/* --------------------------------------------------------------------------
   7. FOOD
   -------------------------------------------------------------------------- */
.food__line{
  font-family:var(--font-display);font-size:var(--fs-md);line-height:var(--lh-snug);
}
.section--food .card{padding:var(--sp-5) var(--sp-6);}

/* --------------------------------------------------------------------------
   8. RSVP FORM
   -------------------------------------------------------------------------- */
.rsvp{display:grid;gap:var(--sp-5);margin-top:var(--sp-5);}
.field{display:grid;gap:var(--sp-2);border:0;padding:0;margin:0;}
.label{color:var(--c-ink-muted);font-size:var(--fs-sm);line-height:var(--lh-snug);}
.field--radios .label{color:var(--c-ink);font-size:var(--fs-base);margin-bottom:var(--sp-1);}
.radio{display:flex;align-items:flex-start;gap:var(--sp-3);min-height:var(--tap-min);
  padding:var(--sp-2) 0;cursor:pointer;}
.radio input{
  inline-size:1.35rem;block-size:1.35rem;margin:0;flex:none;margin-top:.15em;
  accent-color:var(--c-primary);
}
.radio span{font-size:var(--fs-base);line-height:var(--lh-snug);}
input[type="text"],textarea,select{
  width:100%;font:inherit;color:var(--c-ink);background:var(--c-surface-2);
  border:1px solid var(--c-border-strong);border-radius:var(--r-sm);
  padding:var(--sp-3) var(--sp-4);min-height:var(--tap-min);
}
textarea{min-height:5.5rem;resize:vertical;}
::placeholder{color:var(--c-ink-muted);opacity:1;}

/* Buttons ----------------------------------------------------------------- */
.btn{
  display:inline-flex;align-items:center;justify-content:center;gap:.55em;
  min-height:var(--tap-comfortable);padding:0 var(--sp-5);
  font-family:var(--font-body);font-size:var(--fs-base);font-weight:var(--fw-semibold);
  line-height:1;text-decoration:none;cursor:pointer;
  border:1px solid transparent;border-radius:var(--radius-panel);
}
.btn--block{width:100%;}
.btn--primary{background:var(--c-primary);color:var(--c-on-primary);border-color:var(--c-primary);}
.btn--ghost{background:transparent;color:var(--c-ink);border-color:var(--c-border-strong);}
@media (hover:hover){
  .btn--primary:hover{background:var(--c-primary-pressed);border-color:var(--c-primary-pressed);}
  .btn--ghost:hover{background:var(--c-primary-tint);}
}
.btn:disabled{background:var(--c-disabled-bg);color:var(--c-disabled-ink);border-color:transparent;cursor:not-allowed;}

/* --------------------------------------------------------------------------
   9. FOOTER
   -------------------------------------------------------------------------- */
.footer{
  margin-top:var(--section-gap);
  background:var(--c-footer-bg);color:var(--c-footer-ink);
  padding:var(--sp-8) 0 calc(var(--sp-7) + var(--safe-bottom));
}
.footer__inner{display:grid;gap:var(--sp-2);text-align:center;}
.footer__line{font-family:var(--font-display);font-size:var(--fs-md);}
.footer__meta{font-size:var(--fs-sm);}
.footer__privacy{font-size:var(--fs-2xs);color:var(--c-footer-ink-muted);margin-top:var(--sp-3);}

/* --------------------------------------------------------------------------
   9b. FAMILY BLOCK — injected by family/build_family.py between the
       <!-- FAMILY:BEGIN --> / <!-- FAMILY:END --> markers. Every name comes
       from family/family.csv; a blank name prints nothing (no placeholder,
       no empty line). Styled here so the injected block matches these five
       designs instead of falling back to bare browser defaults.
   -------------------------------------------------------------------------- */
.section-heading{
  font-family:var(--font-display);font-weight:var(--fw-semibold);
  font-size:var(--fs-xl);line-height:var(--lh-snug);letter-spacing:var(--ls-tight);
}
.section.family .card{padding:var(--sp-6);}
.family__host-deva{
  font-family:var(--font-dev-text);font-size:var(--fs-md);line-height:var(--lh-relaxed);
  margin-top:var(--sp-3);
}
.family__host,.family__group,.family__native{
  margin-top:var(--sp-3);font-size:var(--fs-base);line-height:var(--lh-relaxed);color:var(--c-ink);
}
.family__group-label{
  font-family:var(--font-dev-text);font-size:var(--fs-sm);color:var(--c-ink-muted);
  margin-inline-end:var(--sp-2);white-space:nowrap;
}
.family__elders,.family__pet,.family__contact{
  margin-top:var(--sp-3);font-size:var(--fs-sm);color:var(--c-ink-muted);line-height:var(--lh-relaxed);
}
/* the contact row can carry a wa.me link injected by build_family.py — give it
   a full 44px touch height so it is a real tap target, not a 17px text run */
.family__contact a{display:inline-flex;align-items:center;min-height:44px;}

/* ---- family TREE (R6): relationship tree, chips verbatim, unlabelled
   degrade. Emitted by family/build_family.py — this block styles it. ----
   Every node = a small-cap chip with the CSV's OWN English relation word
   (Grandmother / Late Grandfather / Elder Brother / Mother / Father) plus the
   name. A relationship the CSV leaves UNKNOWN/blank renders as a quiet
   unlabelled node: hollow ring, muted name, aligned to the same grid. */
.family__tree{
  margin-top:var(--sp-5);
  display:grid;gap:var(--sp-4);
}
.family__side{
  padding:var(--sp-4) var(--sp-5);
  border:1px solid var(--c-border);border-radius:var(--radius-panel);
  background:var(--c-surface-2);
}
.family__side-label{
  font-family:var(--font-dev-text);font-size:var(--fs-sm);letter-spacing:var(--ls-wide);
  color:var(--c-primary);margin-bottom:var(--sp-3);
}
.family__nodes{list-style:none;margin:0;padding:0;display:grid;gap:var(--sp-2);}
.family__node{
  display:grid;grid-template-columns:max-content 1fr;gap:0 var(--sp-3);
  align-items:baseline;min-width:0;
}
.family__rel{
  font-family:var(--font-latin-ui);font-size:var(--fs-xs);font-variant:small-caps;
  letter-spacing:.1em;color:var(--c-ink-muted);white-space:nowrap;
}
.family__name{
  font-family:var(--font-display);font-size:var(--fs-base);line-height:var(--lh-snug);
  min-width:0;
}
.family__node--unlabelled::before{
  content:"";width:.5em;height:.5em;border-radius:50%;
  border:1px solid var(--c-border-strong);align-self:center;justify-self:center;
}
.family__node--unlabelled .family__name{color:var(--c-ink-muted);}

/* family tree per design — C panels double-bordered, B ledgers side by side,
   E hairlines, D soft cluster */
[data-design="b"] .family__side{
  background:transparent;border:0;border-radius:0;padding:var(--sp-2) 0;
  border-top:3px solid var(--c-primary);
}
[data-design="c"] .family__side{
  background:var(--c-bg);border:1px solid var(--c-border-strong);
  outline:1px solid var(--c-border-strong);outline-offset:4px;
}
[data-design="d"] .family__side{background:var(--c-surface);box-shadow:var(--sh-sm);}
[data-design="e"] .family__side{
  background:transparent;border:0;border-radius:0;padding:var(--sp-2) 0;
  border-top:1px solid var(--c-border);
}
@media (min-width:560px){
  [data-design="b"] .family__tree{grid-template-columns:1fr 1fr;gap:var(--sp-6);}
  [data-design="b"] .family__side:nth-child(2){
    border-top:0;border-left:3px solid var(--c-primary);
    padding-left:var(--sp-5);
  }
}

/* --------------------------------------------------------------------------
   9c. STRUCTURE COMPOSITION — one real DOM per design (R6). The five
   <main class="structure--…"> wrappers and their section order/groupings are
   generated by build-design-shells.py; these rules make the composition
   visible: programme__front is one editorial band, who is one letter-cluster,
   programme__steps is a numbered ritual, the mandala is ground-framed panels.
   -------------------------------------------------------------------------- */
.group{margin-top:var(--section-gap);}
.group > .section{margin-top:0;}

/* B — programme front: details + timeline join in one band under a single
   vermilion rule; on wide screens the two read side by side. */
[data-design="b"] .programme__front{
  border-top:3px solid var(--c-primary);padding-top:var(--sp-6);
}
[data-design="b"] .programme__front .card{
  border:0;background:transparent;padding:0;
}
[data-design="b"] .programme__front .section + .section{
  margin-top:var(--sp-5);border-top:1px solid var(--c-border);padding-top:var(--sp-5);
}
@media (min-width:560px){
  [data-design="b"] .programme__front{
    display:grid;grid-template-columns:1fr 1fr;gap:var(--sp-7);
  }
  [data-design="b"] .programme__front .section + .section{
    margin-top:0;border-top:0;padding-top:0;
    border-left:1px solid var(--c-border);padding-left:var(--sp-7);
  }
}
[data-design="b"] .hero__names{padding-bottom:.15em;}

/* C — mandala: the dot-grid continues down the main column; panels stay
   double-framed. Family comes first (order in the generator). */
[data-design="c"] #main{
  background-image:radial-gradient(var(--c-border) 1.3px, transparent 1.5px);
  background-size:20px 20px;background-position:center top;
}

/* D — letter: family + lineage sit back-to-back in one "who we are" cluster. */
[data-design="d"] .who{
  background:var(--c-surface);border:1px solid var(--c-border);
  border-radius:var(--radius-panel);box-shadow:var(--sh-sm);
  padding:var(--sp-6);
}
[data-design="d"] .who .section + .section{
  margin-top:var(--sp-6);border-top:1px dashed var(--c-border);padding-top:var(--sp-6);
}
[data-design="d"] .who .card{background:transparent;border:0;box-shadow:none;padding:0;}

/* E — steps: details + timeline become numbered ritual steps (Devanagari
   numerals १ २ … via CSS counters), one hairline per step. */
[data-design="e"] .programme__steps{counter-reset:step;}
[data-design="e"] .programme__steps .section{
  counter-increment:step;position:relative;
  padding-left:var(--sp-8);padding-top:var(--sp-5);
}
[data-design="e"] .programme__steps .section + .section{
  border-top:1px solid var(--c-border);margin-top:var(--sp-5);
}
[data-design="e"] .programme__steps .card{
  border:0;background:transparent;padding:0;
}
[data-design="e"] .programme__steps .section::before{
  content:counter(step, devanagari);
  position:absolute;left:0;top:var(--sp-4);
  font-family:var(--font-dev-display);font-size:var(--fs-2xl);line-height:1;
  color:var(--c-primary);
}
[data-design="e"] .programme__steps .card + .timeline{margin-top:var(--sp-4);}

/* a — journey: the descent. Bronze hairline under section headings anchors
   the single monumental column already defined by A's tokens. */
[data-design="a"] .section__heading{
  position:relative;padding-bottom:var(--sp-2);
}
[data-design="a"] .section__heading::after{
  content:"";position:absolute;left:0;bottom:0;
  width:2.25rem;height:2px;background:var(--c-primary);
}

/* --------------------------------------------------------------------------
   9d. PHERA ARC — the overnight→dawn panel behind the phera card.
   The static picture (night at the foot, dawn glow at the head) is the
   DESIGNED resting state: reduced-motion rests on it, an unsupported browser
   rests on it, and the scroll choreography only moves the dawn line across
   it — it is never empty.
   -------------------------------------------------------------------------- */
.phera__card{position:relative;isolation:isolate;overflow:hidden;}
.phera__arc{
  position:absolute;inset:0;z-index:0;pointer-events:none;
  background:
    radial-gradient(120% 90% at 50% -6%, var(--c-primary-tint), transparent 52%),
    linear-gradient(180deg, var(--c-surface-sunken) 0%, var(--c-surface-2) 34%,
                    var(--c-surface) 100%);
}
.phera__card > *:not(.phera__arc){position:relative;z-index:1;}
.phera__arc::after{
  content:"";position:absolute;left:7%;right:7%;top:var(--m-arc-close);
  height:2px;border-radius:2px;
  background:linear-gradient(90deg, transparent, var(--c-primary) 32%,
                             var(--c-accent) 68%, transparent);
  box-shadow:0 0 14px var(--c-primary-tint);
  animation:m-usha-arc var(--m-arc-dur) var(--ease-out) both;
}
@supports (animation-timeline: view()){
  .phera__arc::after{
    animation-timeline:view();
    animation-range:var(--m-range-entry);
  }
}

/* --------------------------------------------------------------------------
   10. MOTION — the R6 system. @keyframes + choreography tokens live in
   design-tokens-v2.css §6; this file only WIRES them per design. Every
   animation ends at a DESIGNED static frame; the tokens guard (§5) snaps
   reduced-motion to that frame — never to empty.
   -------------------------------------------------------------------------- */
@keyframes rise{from{opacity:0;transform:translateY(var(--m-rise));}to{opacity:1;transform:none;}}
/* Same rule as the body: the hero LIFTS, it never fades from nothing.
   Measured 13 Oct: the 5th+ hero children (date, countdown, caption,
   venue, actions) sat at opacity 0 with playState 'running' and a
   currentTime frozen at ~90ms, because they wait on a stagger of up to
   640ms before a 400ms fade. Any throttled or backgrounded engine
   strands them invisible. The names keep their own light-wipe; the rest
   of the hero now moves without ever touching opacity. */
@keyframes lift{from{transform:translateY(14px);}to{transform:none;}}
.hero__inner > *{opacity:1;animation:lift var(--m-dur-4) var(--ease-out) both;}
.hero__inner > *:nth-child(2){animation-delay:calc(var(--m-stagger) * 1);}
.hero__inner > *:nth-child(3){animation-delay:calc(var(--m-stagger) * 2);}
.hero__inner > *:nth-child(4){animation-delay:calc(var(--m-stagger) * 3);}
.hero__inner > *:nth-child(5){animation-delay:calc(var(--m-stagger) * 4);}
.hero__inner > *:nth-child(6){animation-delay:calc(var(--m-stagger) * 5);}
.hero__inner > *:nth-child(n+7){animation-delay:calc(var(--m-stagger) * 6);}
@keyframes glow{from{opacity:.75;}to{opacity:1;}}
[data-design="a"] .hero__ground{animation:glow 9s var(--ease-standard) infinite alternate;}

/* A — light-wipe: a bronze band sweeps left→right across the couple names,
   then rests clean off-frame (the reduced-motion static: plain names). */
[data-design="a"] .hero__names{position:relative;}
[data-design="a"] .hero__names::before{
  content:"";position:absolute;inset:0;pointer-events:none;
  background-image:linear-gradient(100deg,
    transparent 0%, transparent 35%,
    var(--c-primary-tint) 50%, transparent 65%, transparent 100%);
  background-size:250% 100%;background-repeat:no-repeat;
  animation:m-wipe var(--m-wipe-dur) var(--ease-out) both;
}
[data-design="a"] .hero__names > *{position:relative;}

/* B — line-wipe: the vermilion rule draws across beneath the names (and the
   programme band owns a static rule of its own). Rest = fully drawn. */
[data-design="b"] .hero__names{position:relative;padding-bottom:.4em;}
[data-design="b"] .hero__names::after{
  content:"";position:absolute;left:0;right:0;bottom:0;height:3px;
  background:var(--c-primary);transform-origin:left;
  animation:m-thread var(--m-thread-dur) var(--ease-out) both;
}

/* C — kolam: the diamond outline draws itself (stroke-dashoffset), the grid
   dots fade in a 40ms step. Rest = fully drawn ornament. */
[data-design="c"] .orn--kolam path[fill="none"]{
  stroke-dasharray:140;stroke-dashoffset:140;
  animation:m-draw var(--m-draw-dur) var(--ease-out) both;
}
[data-design="c"] .orn--kolam g circle{
  animation:m-dots var(--m-dur-3) var(--ease-out) both;
}
[data-design="c"] .orn--kolam g circle:nth-of-type(4n+1){animation-delay:var(--m-dot-step);}
[data-design="c"] .orn--kolam g circle:nth-of-type(4n+2){animation-delay:calc(var(--m-dot-step) * 2);}
[data-design="c"] .orn--kolam g circle:nth-of-type(4n+3){animation-delay:calc(var(--m-dot-step) * 3);}

/* D — bloom: the watercolour wash settles 1.03→1 behind the hero while the
   vine draws and its leaves lift. Rest = settled, drawn. */
[data-design="d"] .hero__ground{animation:m-bloom var(--m-bloom-dur) var(--ease-out) both;}
[data-design="d"] .orn--vine path{
  stroke-dasharray:200;stroke-dashoffset:200;
  animation:m-draw var(--m-draw-dur) var(--ease-out) both;
}
[data-design="d"] .orn--vine ellipse{animation:m-dots var(--m-dur-3) var(--ease-out) both;}
[data-design="d"] .orn--vine ellipse:nth-of-type(2){animation-delay:calc(var(--m-dot-step) * 2);}
[data-design="d"] .orn--vine ellipse:nth-of-type(3){animation-delay:calc(var(--m-dot-step) * 3);}

/* E — flame: the diya flame flickers slowly; reduced-motion rests it fully
   lit (100% frame), a designed static. */
[data-design="e"] .orn--flame{
  animation:m-diya var(--m-flicker-dur) var(--ease-standard) infinite alternate;
}

/* SCROLL CHOREOGRAPHY — sections rise into place as they cross the viewport
   (supported browsers only; timing fallback is the section's own presence,
   and reduced-motion rests everything at the static 100% frame). */
/* A LIFT, NOT A FADE. This used to be `rise` (opacity 0 -> 1) with
   animation-fill-mode:both on a view() timeline, which meant a section's
   text existed only while the scroll timeline was inside its entry range.
   Measured on live /d/b/ and /d/a/ on 13 Oct 2026: every main .card, the
   .timeline, the .lineage and the .family__tree computed to opacity 0 —
   a blank card. It is also the known view()-timeline trap: scroll back up
   and `both` re-applies the from-state, so the text disappears a second
   time. A wedding invitation must be readable at every scroll position, so
   the reveal now animates TRANSFORM ONLY and never touches opacity. */
@keyframes lift{from{transform:translateY(14px);}to{transform:none;}}
@media (prefers-reduced-motion:no-preference){
  @supports (animation-timeline: view()){
    .section > .wrap > .card,
    .section > .wrap > .section__heading,
    .section > .wrap > .section-heading,
    .section > .wrap > .timeline,
    .section > .wrap > .lineage,
    .family__tree,
    .section--rsvp .rsvp{
      animation:lift var(--m-dur-4) var(--ease-out) both;
      animation-timeline:view();
      animation-range:var(--m-range-entry);
    }
  }
}

/* --------------------------------------------------------------------------
   11. WIDE SCREENS — phone-first; these are gentle widenings only
   -------------------------------------------------------------------------- */
@media (min-width:480px){
  .card{padding:var(--sp-7);}
  [data-design="b"] .card,[data-design="e"] .card{padding-inline:0;}
}

/* TEMPORARY (design review): clears the fixed design-switcher bar so it never
   covers the footer. Remove together with SHOW_DESIGN_SWITCHER=False in
   docs/design/build-design-shells.py once a design is approved. */
body{ padding-bottom:calc(64px + env(safe-area-inset-bottom)); }

/* ----- Family tree -------------------------------------------------------
 * These classes are emitted by family/build_family.py, which splits each side
 * of the family into its own labelled section with one row per person:
 *
 *   .family__tree            the two sides, side by side
 *   .family__side            one side
 *   .family__side-label      its heading, वधू पक्ष / वर पक्ष
 *   .family__nodes           the list of people
 *   .family__node            one person
 *   .family__rel             their relationship
 *   .family__name            their name
 *   .family__node--unlabelled  a person whose relationship is not confirmed,
 *                             so only the name prints
 *
 * They arrived with no CSS at all, which rendered a bare bulleted list with
 * English relationship words. These rules are duplicated verbatim into
 * styles.css and d/designs.css on purpose: the two files share almost no
 * rules, and only these tokens exist in both.
 */
.family__tree {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--sp-5) var(--sp-6);
  margin: var(--sp-5) 0;
  text-align: left;
}
@media (max-width: 640px) {
  .family__tree { grid-template-columns: 1fr; gap: var(--sp-4); }
}

.family__side-label {
  font-family: var(--font-display);
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-wide, .06em);
  color: var(--c-primary);
  margin: 0 0 var(--sp-3);
  padding-bottom: var(--sp-2);
  border-bottom: 1px solid var(--c-border, rgba(0, 0, 0, .1));
}

.family__nodes {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
}

/* Block, not flex. As flex the relationship chip and the name were flex items,
   so a long name (MOTHER / Smt Jayasri Prabhakar Rao Paladugu) wrapped onto a
   line of its own and left the chip stranded above it. Inline keeps the chip
   attached to the start of the name however the line breaks. */
.family__node {
  font-size: var(--fs-sm, .9375rem);
  line-height: var(--lh-normal, 1.6);
  color: var(--c-ink);
}

.family__rel {
  display: inline-block;
  vertical-align: 0.12em;
  margin-right: var(--sp-2, 8px);
  font-family: var(--font-body);
  font-size: var(--fs-xs, .75rem);
  letter-spacing: var(--ls-wide, .05em);
  text-transform: uppercase;
  color: var(--c-ink-muted);
  background: var(--c-primary-tint, rgba(0, 0, 0, .05));
  border-radius: var(--r-pill, 999px);
  padding: 2px 10px;
  white-space: nowrap;
}

.family__name {
  font-family: var(--font-body);
  color: var(--c-ink);
}

/* Relationship not confirmed. Kept visually quiet rather than hidden, so the
   person is visibly present and the gap is visible too. */
.family__node--unlabelled .family__name {
  color: var(--c-ink-muted);
  font-style: italic;
}
/* ----- Design switcher ---------------------------------------------------
 * TEMPORARY (design review). Remove together with SHOW_DESIGN_SWITCHER=False
 * in docs/design/build-design-shells.py once a design is approved.
 *
 * Two bugs this file exists to fix, both found by measuring a 360px viewport:
 *
 * 1. The bar wrapped onto THREE rows at phone width. Five pills carrying
 *    "A USHA / USHA" cannot fit in 320px of usable width, so flex-wrap gave
 *    them three lines and the bar ate ~150px of a 620px screen. The Latin
 *    design name is now hidden below 520px, leaving the letter plus the
 *    Devanagari name, which does fit on one row.
 *
 * 2. The bar had z-index 1000 and the opening gate has z-index 100, so the
 *    switcher floated ON TOP of the gate overlay during the opening moment,
 *    breaking out of the card. It now sits behind the gate and only appears
 *    once the invitation is open.
 *
 * Styles are in the stylesheet, not inline, because a media query cannot
 * override an inline style - which is exactly rule 1 above.
 */

.design-switcher {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 90;                 /* below .gate (z-index 100) */
  display: flex;
  flex-wrap: nowrap;           /* never stack */
  justify-content: center;
  gap: 8px;
  padding: max(8px, env(safe-area-inset-bottom)) 12px 8px;
  background: var(--c-footer-bg, #2E0A0E);
  border-top: 1px solid var(--c-border, rgba(255, 255, 255, .18));
  box-shadow: 0 -2px 8px rgba(0, 0, 0, .25);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.design-switcher::-webkit-scrollbar { display: none; }

.switcher__item {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 36px;
  padding: 7px 12px;
  border: 1px solid var(--c-border, rgba(255, 255, 255, .35));
  border-radius: 999px;
  background: transparent;
  color: var(--c-ink, #F5F1E8);
  text-decoration: none;
  font-size: 12px;
  line-height: 1.15;
  white-space: nowrap;
  opacity: .75;
  -webkit-tap-highlight-color: transparent;
}
.switcher__item:hover { opacity: 1; }

.switcher__item--active,
.switcher__item[aria-current="page"] {
  background: var(--c-primary, #FF5A36);
  border-color: var(--c-primary, #FF5A36);
  color: var(--c-on-primary, #1A0A05);
  opacity: 1;
  font-weight: 700;
}

.switcher__letter { font-weight: 700; letter-spacing: .08em; }
.switcher__name { white-space: nowrap; }

/* Below 520px there is not room for the Latin name, so it is dropped and the
   Devanagari name alone identifies the design. The full label stays in the
   aria-label and the title attribute for anyone who needs it. */
@media (max-width: 520px) {
  .switcher__latin { display: none; }
  .design-switcher { gap: 6px; padding-left: 8px; padding-right: 8px; }
  .switcher__item { padding: 6px 10px; font-size: 11.5px; gap: 5px; }
}

/* Very narrow phones (iPhone SE and below) */
@media (max-width: 360px) {
  .switcher__name { font-size: 11px; }
  .switcher__item { padding: 5px 8px; min-height: 34px; }
  .design-switcher { gap: 4px; }
}
/* ----- Long names must not be forced wider than their column (23:56) ---
 * ".family__node" is a grid of max-content + 1fr. The name sits in the 1fr
 * track, and a grid item's automatic minimum size lets that track shrink
 * below the text, so "Lt. P. Ranganayakamma" (138px) overflowed a 127px box
 * at 320px. min-width:0 plus wrapping fixes it. Appended, not substituted:
 * an earlier attempt rewrote this file and destroyed it.
 */
.family__name { min-width:0; overflow-wrap:anywhere; }

/* Switcher contrast fix (00:00). The bar sits on --c-footer-bg but the pills
 * were taking their colour from --c-ink. On the light designs --c-ink is dark,
 * so design D rendered five empty outlines: dark brown text on a dark brown
 * bar. Footer ink is the correct pairing and every design defines it with
 * 12.8:1 or better against its own footer background. */
.switcher__item { color: var(--c-footer-ink, #F5F1E8); border-color: var(--c-footer-ink-muted, rgba(255,255,255,.35)); opacity:.75; }
.switcher__item:hover { opacity:1; }
