/* ============================================================================
   DivyaSanyog — Design System
   ----------------------------------------------------------------------------
   Read this before adding a colour or a shadow anywhere.

   The site used to carry 622 inline style="" attributes and 42 distinct hex
   colours, with Bootstrap's stock green/blue/purple sitting next to the brand
   saffron/maroon/gold. This file is the single source of truth instead.

   RULES OF THE PALETTE (this is what "colour combination sahi ho" means here):
     MAROON   structure — nav, footer, headings, page headers
     SAFFRON  action — primary buttons and nothing else
     GOLD     accent — rules, borders, small marks. NEVER body text: gold on
              white is ~1.9:1 and unreadable. --ds-gold is already darkened to
              #C79200 so it passes AA when it must carry text.
     CREAM    the page. Cards are ivory on top of it — that contrast is what
              gives depth, so we don't need heavy shadows or gradients.

   Section 5 re-themes Bootstrap by overriding its own local custom properties.
   That is deliberate: templates we have not converted still say .btn-primary
   and .text-success, and they pick up brand colour automatically.
   ========================================================================== */

/* ============================================================================
   1. TOKENS
   ========================================================================== */
:root {
    /* --- brand ------------------------------------------------------------ */
    --ds-maroon:        #7A1122;
    --ds-maroon-dark:   #5E0D1A;
    --ds-maroon-light:  #9A2436;
    --ds-maroon-soft:   #F7EBEC;   /* tint for backgrounds */

    /* Saffron carries white button text, so it is bound by AA on *its own*
       label: white on #B74A00 = 4.6:1. #FF6B00 was 2.86:1 and #E05A00 3.73:1 —
       both fail. Every value below was solved for, not eyeballed. */
    --ds-saffron:       #B74A00;   /* buttons + saffron text on cream/sand */
    --ds-saffron-dark:  #9A3E00;   /* hover */
    --ds-saffron-bright:#E05A00;   /* decorative only, on DARK grounds */
    --ds-saffron-soft:  #FFF1E6;

    --ds-gold:          #AD9200;   /* accents, borders, stars — 3.05:1 on white */
    --ds-gold-text:     #8A7400;   /* when gold must carry small text — 4.59:1 */
    --ds-gold-bright:   #FFD700;   /* decorative only, on dark grounds (7.75:1 on maroon) */
    --ds-gold-soft:     #FBF3DC;

    /* --- surfaces ---------------------------------------------------------- */
    --ds-cream:         #FBF7F1;   /* page background */
    --ds-ivory:         #FFFFFF;   /* cards */
    --ds-sand:          #F5EEE4;   /* alternating section band */
    --ds-ink-surface:   #241A14;   /* footer / dark blocks */

    /* --- text -------------------------------------------------------------- */
    --ds-ink:           #2B2118;   /* body */
    --ds-ink-muted:     #6B5D4F;   /* secondary */
    --ds-ink-faint:     #92857A;   /* tertiary — captions only */
    --ds-on-dark:       #FFFFFF;
    --ds-on-dark-muted: rgba(255, 255, 255, .76);

    /* --- semantic (brand-tinted, not Bootstrap's) --------------------------- */
    --ds-success:       #1E7A5A;
    --ds-success-soft:  #E8F5F0;
    --ds-warn:          #A35F0D;   /* 4.55:1 on its own tint */
    --ds-warn-soft:     #FDF3E3;
    --ds-danger:        #A32B2B;
    --ds-danger-soft:   #FBECEC;
    --ds-info:          #1F5C7A;
    --ds-info-soft:     #EAF3F7;

    /* Secondary accent. Used where a third colour is genuinely meaningful —
       the Yogini dasha card, matrimonial "girl" columns — not for decoration. */
    --ds-accent:        #6D4AA6;
    --ds-accent-soft:   #F3EEFA;

    /* --- lines & shadow ------------------------------------------------------ */
    --ds-line:          #E9DFD1;
    --ds-line-strong:   #D8C9B4;
    --ds-shadow-sm:     0 1px 2px rgba(43, 33, 24, .06);
    --ds-shadow:        0 2px 8px rgba(43, 33, 24, .07);
    --ds-shadow-lg:     0 12px 32px rgba(43, 33, 24, .12);

    /* --- radius -------------------------------------------------------------- */
    --ds-r-sm: 8px;
    --ds-r:    12px;
    --ds-r-lg: 18px;
    --ds-r-pill: 999px;

    /* --- spacing scale -------------------------------------------------------- */
    --ds-1: .25rem;  --ds-2: .5rem;   --ds-3: .75rem;  --ds-4: 1rem;
    --ds-5: 1.5rem;  --ds-6: 2rem;    --ds-7: 3rem;    --ds-8: 4rem;

    /* Vertical rhythm for page sections. The old site had ~200px dead gaps in
       places and none in others; every section now uses one of these two. */
    --ds-section-y:      clamp(2.5rem, 5vw, 4rem);
    --ds-section-y-lean: clamp(1.75rem, 3.5vw, 2.75rem);

    /* --- type ----------------------------------------------------------------- */
    --ds-font: 'Poppins', system-ui, -apple-system, 'Segoe UI', sans-serif;
    --ds-font-deva: 'Noto Serif Devanagari', 'Poppins', serif;
}

/* Devanagari text that stays visible in BOTH language modes.
   Not to be confused with .lang-hi, which is display:none until the visitor
   switches to Hindi. Hidden text is discounted by search engines and, in
   quantity, reads as keyword stuffing — so anything meant to be found in a
   Hindi search has to be on the page for everyone, and uses this instead. */
.ds-deva { font-family: var(--ds-font-deva); }

/* ============================================================================
   2. BASE
   ========================================================================== */
body {
    font-family: var(--ds-font);
    background-color: var(--ds-cream);
    color: var(--ds-ink);
    -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, h5, h6 { color: var(--ds-maroon); font-weight: 700; }
h1 { font-size: clamp(1.9rem, 3.6vw, 2.75rem); line-height: 1.15; }
h2 { font-size: clamp(1.5rem, 2.6vw, 2rem);    line-height: 1.2; }
h3 { font-size: clamp(1.25rem, 2vw, 1.5rem); }
h4 { font-size: 1.2rem; }
h5 { font-size: 1.05rem; }
h6 { font-size: .95rem; }

a { color: var(--ds-maroon); text-decoration-color: rgba(122, 17, 34, .3); }
a:hover { color: var(--ds-maroon-dark); }

.text-muted { color: var(--ds-ink-muted) !important; }
.ds-faint   { color: var(--ds-ink-faint); }

/* Focus ring — one visible style everywhere, for keyboard users. */
:focus-visible {
    outline: 3px solid rgba(224, 90, 0, .45);
    outline-offset: 2px;
    border-radius: 4px;
}

/* ============================================================================
   3. LAYOUT — sections & page headers
   ========================================================================== */
.ds-section       { padding: var(--ds-section-y) 0; }
.ds-section--lean { padding: var(--ds-section-y-lean) 0; }
.ds-section--sand { background: var(--ds-sand); }
.ds-section--cream{ background: var(--ds-cream); }
.ds-section--ivory{ background: var(--ds-ivory); }
.ds-section--ruled{ border-bottom: 1px solid var(--ds-line); }

/* Section heading: small kicker + title + optional lede. */
.ds-kicker {
    font-size: .74rem;
    font-weight: 700;
    letter-spacing: .16em;
    text-transform: uppercase;
    color: var(--ds-saffron);
    margin-bottom: .4rem;
}
.ds-title { margin-bottom: .5rem; }
.ds-lede  { color: var(--ds-ink-muted); max-width: 62ch; margin-bottom: 0; }
.ds-head--center { text-align: center; }
.ds-head--center .ds-lede { margin-left: auto; margin-right: auto; }

/* Thin gold rule under centred section titles (replaces the old ::after bar). */
.ds-head--center .ds-title::after {
    content: '';
    display: block;
    width: 52px; height: 3px;
    margin: .7rem auto 0;
    background: var(--ds-gold);
    border-radius: 2px;
}

/* Page header. Replaces the full-bleed 300px gradient hero that every single
   inner page used to repeat — that is why the site felt heavy and samey. */
.ds-page-header {
    background: linear-gradient(135deg, var(--ds-maroon-dark), var(--ds-maroon));
    color: var(--ds-on-dark);
    padding: var(--ds-6) 0;
    position: relative;
    overflow: hidden;
}
.ds-page-header::after {          /* faint om, low contrast, purely texture */
    content: '\0950';
    position: absolute;
    right: 2rem; top: 50%;
    transform: translateY(-50%);
    font-size: 9rem;
    line-height: 1;
    opacity: .07;
    pointer-events: none;
}
.ds-page-header :is(h1, h2, h3, h4, h5, h6) { color: var(--ds-on-dark); margin-bottom: .25rem; }
.ds-page-header p  { color: var(--ds-on-dark-muted); margin-bottom: 0; }
.ds-page-header a  { color: var(--ds-gold-bright); }

/* Large emoji/glyph above a centred page-header title */
.ds-page-header__glyph { font-size: 2.6rem; line-height: 1; margin-bottom: .5rem; }

/* Breadcrumb inside a page header */
.ds-crumbs { font-size: .82rem; color: var(--ds-on-dark-muted); margin-bottom: .5rem; }
.ds-crumbs a { color: var(--ds-on-dark-muted); text-decoration: none; }
.ds-crumbs a:hover { color: var(--ds-gold-bright); }

/* ============================================================================
   4. COMPONENTS
   ========================================================================== */

/* --- Buttons -------------------------------------------------------------- */
.ds-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .5rem;
    padding: .62rem 1.25rem;
    border-radius: var(--ds-r-sm);
    border: 1.5px solid transparent;
    font-weight: 600;
    font-size: .95rem;
    line-height: 1.3;
    text-decoration: none;
    cursor: pointer;
    transition: background .15s, border-color .15s, color .15s, transform .1s;
}
.ds-btn:active { transform: translateY(1px); }

.ds-btn--primary {
    background: var(--ds-saffron);
    border-color: var(--ds-saffron);
    color: #fff;
}
.ds-btn--primary:hover { background: var(--ds-saffron-dark); border-color: var(--ds-saffron-dark); color: #fff; }

.ds-btn--secondary {
    background: transparent;
    border-color: var(--ds-maroon);
    color: var(--ds-maroon);
}
.ds-btn--secondary:hover { background: var(--ds-maroon); color: #fff; }

/* For use on the maroon page header / hero, where the above would vanish. */
.ds-btn--on-dark {
    background: transparent;
    border-color: rgba(255, 255, 255, .55);
    color: #fff;
}
.ds-btn--on-dark:hover { background: rgba(255, 255, 255, .14); border-color: #fff; color: #fff; }

.ds-btn--ghost { background: transparent; border-color: var(--ds-line-strong); color: var(--ds-ink); }
.ds-btn--ghost:hover { background: var(--ds-sand); color: var(--ds-ink); }

.ds-btn--sm  { padding: .38rem .8rem;  font-size: .85rem; }
.ds-btn--lg  { padding: .8rem 1.6rem;  font-size: 1.05rem; }
.ds-btn--block { width: 100%; }

/* --- Cards ---------------------------------------------------------------- */
.ds-card {
    background: var(--ds-ivory);
    border: 1px solid var(--ds-line);
    border-radius: var(--ds-r);
    box-shadow: var(--ds-shadow-sm);
    overflow: hidden;
}
.ds-card__body   { padding: var(--ds-5); }
.ds-card__header {
    padding: var(--ds-4) var(--ds-5);
    border-bottom: 1px solid var(--ds-line);
    background: var(--ds-ivory);
}
.ds-card__header h5, .ds-card__header h6 { margin-bottom: 0; }
.ds-card__footer {
    padding: var(--ds-3) var(--ds-5);
    border-top: 1px solid var(--ds-line);
    background: var(--ds-cream);
}

/* Interactive card (a whole card that is a link) */
.ds-card--link { display: block; color: inherit; text-decoration: none; height: 100%; }
.ds-card--link:hover {
    color: inherit;
    border-color: var(--ds-gold);
    box-shadow: var(--ds-shadow-lg);
    transform: translateY(-3px);
}
.ds-card--link { transition: transform .18s, box-shadow .18s, border-color .18s; }

/* Accent strip along the card top. Use sparingly — one per group. */
.ds-card--accent { border-top: 3px solid var(--ds-gold); }

/* --- Service tile (homepage grid) ----------------------------------------- */
.ds-tile { text-align: center; padding: var(--ds-5) var(--ds-4); }
.ds-tile__icon {
    width: 60px; height: 60px;
    margin: 0 auto var(--ds-3);
    border-radius: var(--ds-r);
    display: flex; align-items: center; justify-content: center;
    font-size: 1.8rem;
    background: var(--ds-saffron-soft);
    border: 1px solid var(--ds-line);
}
.ds-tile h5 { margin-bottom: .35rem; }
.ds-tile p  { color: var(--ds-ink-muted); font-size: .9rem; margin-bottom: 0; }

/* --- Stat ----------------------------------------------------------------- */
.ds-stat { text-align: center; }
.ds-stat__value {
    font-size: clamp(1.6rem, 3vw, 2.2rem);
    font-weight: 700;
    color: var(--ds-maroon);
    line-height: 1.1;
}
.ds-stat__label { font-size: .85rem; color: var(--ds-ink-muted); }
.ds-section--dark .ds-stat__value { color: var(--ds-gold-bright); }
.ds-section--dark .ds-stat__label { color: var(--ds-on-dark-muted); }

/* --- Badges / pills ------------------------------------------------------- */
.ds-badge {
    display: inline-flex; align-items: center; gap: .3rem;
    padding: .22rem .6rem;
    border-radius: var(--ds-r-pill);
    font-size: .76rem;
    font-weight: 600;
    border: 1px solid transparent;
    white-space: nowrap;
}
.ds-badge--neutral { background: var(--ds-sand);        color: var(--ds-ink-muted); border-color: var(--ds-line); }
.ds-badge--brand   { background: var(--ds-maroon-soft); color: var(--ds-maroon);    border-color: #EBD5D8; }
.ds-badge--gold    { background: var(--ds-gold-soft);   color: #7A5A00;             border-color: #EFDFB4; }
.ds-badge--success { background: var(--ds-success-soft);color: var(--ds-success);   border-color: #C9E5DB; }
.ds-badge--warn    { background: var(--ds-warn-soft);   color: var(--ds-warn);      border-color: #F0DDBE; }
.ds-badge--danger  { background: var(--ds-danger-soft); color: var(--ds-danger);    border-color: #EFCFCF; }
.ds-badge--info    { background: var(--ds-info-soft);   color: var(--ds-info);      border-color: #CBDEE8; }

/* --- Tab pill (a filter you can SEE the whole set of) ---------------------- */
/*
 * For the vidha tabs on /pandits/. Not `.ds-chip` — that is a 56px flat tile
 * for "what you get" lists, and ten of them make a wall rather than a row of
 * filters. Not `.ds-badge` either: a badge is a label you read, this is a
 * control you press, and it needs a hit area and a hover.
 *
 * The active state is `--ds-maroon` filled, NOT saffron. Saffron is the primary
 * button, and the "Register with us" button sits in the same header — two
 * saffron fills would make a filter look like a second call to action. Same
 * reasoning as the language toggle. White on --ds-maroon is 9.4:1.
 */
.ds-tab {
    display: inline-flex; align-items: center; gap: .3rem;
    padding: .38rem .8rem;
    border: 1px solid var(--ds-line);
    border-radius: var(--ds-r-pill);
    background: var(--ds-ivory);
    color: var(--ds-ink-muted);
    font-size: .85rem;
    font-weight: 600;
    text-decoration: none;
    white-space: nowrap;
}
.ds-tab:hover { border-color: var(--ds-line-strong); color: var(--ds-ink); }
.ds-tab.is-active {
    background: var(--ds-maroon);
    border-color: var(--ds-maroon);
    color: #fff;
}
.ds-tab.is-active:hover { color: #fff; }

/* --- Chip (flat labelled tile, e.g. "what you get" lists) ------------------ */
.ds-chip {
    display: flex; align-items: center; justify-content: center;
    text-align: center;
    height: 100%;
    min-height: 56px;
    padding: var(--ds-3);
    border: 1px solid var(--ds-line);
    border-radius: var(--ds-r-sm);
    background: var(--ds-ivory);
    font-size: .9rem;
    font-weight: 500;
}

/* --- Verdict banner (guna score, compatibility result) --------------------- */
.ds-verdict {
    border-radius: var(--ds-r-lg);
    color: #fff;
    text-align: center;
    padding: var(--ds-6) var(--ds-5);
}
.ds-verdict :is(h1, h2, h3, h4, h5, h6) { color: #fff; }
.ds-verdict--good { background: linear-gradient(135deg, #14513C, var(--ds-success)); }
.ds-verdict--bad  { background: linear-gradient(135deg, #6E1D1D, var(--ds-danger)); }
.ds-verdict__score { font-size: clamp(3rem, 9vw, 5rem); font-weight: 800; line-height: 1; }
.ds-verdict__of    { font-size: 1.25rem; opacity: .78; }

/* Severity edge for a result card */
.ds-card--edge-danger  { border-left: 5px solid var(--ds-danger); }
.ds-card--edge-warn    { border-left: 5px solid var(--ds-saffron); }
.ds-card--edge-success { border-left: 5px solid var(--ds-success); }

/* Filled status pills (the outlined .ds-badge--* are the quiet versions) */
.ds-badge--solid-danger  { background: var(--ds-danger);  color: #fff; border-color: var(--ds-danger); }
.ds-badge--solid-warn    { background: var(--ds-saffron); color: #fff; border-color: var(--ds-saffron); }
.ds-badge--solid-success { background: var(--ds-success); color: #fff; border-color: var(--ds-success); }

/* --- Meter (koota score bars) ---------------------------------------------
   Only the fill WIDTH stays inline — it is a per-row computed value, which is
   the one legitimate use of a style attribute. The colour is a class. */
.ds-meter {
    height: 8px;
    border-radius: var(--ds-r-pill);
    background: var(--ds-line);
    overflow: hidden;
}
.ds-meter--sm { height: 6px; }
.ds-meter__fill { height: 100%; border-radius: inherit; display: block; }
.ds-meter__fill--full    { background: var(--ds-success); }
.ds-meter__fill--partial { background: var(--ds-info); }
.ds-meter__fill--none    { background: var(--ds-danger); }

/* --- Price ---------------------------------------------------------------- */
.ds-price { font-weight: 700; color: var(--ds-maroon); white-space: nowrap; }
.ds-price small { font-weight: 500; color: var(--ds-ink-faint); }

/* --- Forms ---------------------------------------------------------------- */
.ds-label { font-size: .85rem; font-weight: 600; color: var(--ds-ink); margin-bottom: .3rem; }
.ds-help  { font-size: .8rem;  color: var(--ds-ink-faint); }

.form-control, .form-select {
    border-color: var(--ds-line-strong);
    border-radius: var(--ds-r-sm);
    padding: .55rem .8rem;
    color: var(--ds-ink);
}
.form-control:focus, .form-select:focus {
    border-color: var(--ds-saffron);
    box-shadow: 0 0 0 .2rem rgba(224, 90, 0, .15);
}
.form-control::placeholder { color: var(--ds-ink-faint); }

/* A bordered panel to group form fields */
.ds-fieldset {
    border: 1px solid var(--ds-line);
    border-radius: var(--ds-r);
    padding: var(--ds-5);
    background: var(--ds-ivory);
}
.ds-fieldset__legend {
    font-size: .78rem; font-weight: 700;
    letter-spacing: .1em; text-transform: uppercase;
    color: var(--ds-saffron);
    margin-bottom: var(--ds-4);
}

/* --- Card media (image or emoji banner at the top of a card) --------------- */
.ds-media {
    display: block;
    width: 100%;
    height: 170px;
    object-fit: cover;
    background: var(--ds-sand);
}
.ds-media--short { height: 120px; }
.ds-media--tall  { height: 280px; }
.ds-media--placeholder {
    display: flex; align-items: center; justify-content: center;
    height: 120px;
    font-size: 2.8rem;
    background: linear-gradient(135deg, var(--ds-maroon), var(--ds-maroon-light));
}

/* --- Numbered step (how-it-works) ----------------------------------------- */
.ds-step-num {
    width: 42px; height: 42px;
    margin: 0 auto;
    border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    font-weight: 700; font-size: 1.1rem;
    color: var(--ds-maroon);
    background: var(--ds-gold-soft);
    border: 1.5px solid var(--ds-gold);
}

/* --- Avatar --------------------------------------------------------------- */
.ds-avatar {
    width: 80px; height: 80px;
    border-radius: 50%;
    object-fit: cover;
    display: block;
    margin-inline: auto;
    border: 2px solid var(--ds-line);
}
.ds-avatar--initial {
    display: flex; align-items: center; justify-content: center;
    background: linear-gradient(135deg, var(--ds-maroon), var(--ds-saffron));
    color: #fff; font-weight: 700; font-size: 1.6rem;
    border: 0;
}
/* One avatar scale. Templates carried eight arbitrary sizes (38/44/48/52/55/
   60/65/70/80/100/110px); everything now snaps to the nearest step below. */
.ds-avatar--xs { width: 40px;  height: 40px;  font-size: .95rem; }
.ds-avatar--sm { width: 48px;  height: 48px;  font-size: 1.1rem; }
.ds-avatar--md { width: 60px;  height: 60px;  font-size: 1.3rem; }
.ds-avatar--lg { width: 80px;  height: 80px;  font-size: 1.6rem; }
.ds-avatar--xl { width: 110px; height: 110px; font-size: 2.2rem; }
.ds-avatar--xs, .ds-avatar--sm, .ds-avatar--md,
.ds-avatar--lg, .ds-avatar--xl { margin-inline: 0; flex-shrink: 0; }

/* --- Star rating ---------------------------------------------------------- */
/* Gold on white is unreadable at #FFD700 — this is the darkened token. */
.ds-stars { color: var(--ds-gold); letter-spacing: .1em; font-size: .95rem; line-height: 1; }

/* --- Daan strip ----------------------------------------------------------- */
.ds-daan-strip {
    display: flex; align-items: center; gap: var(--ds-4);
    flex-wrap: wrap;
    padding: var(--ds-5);
    border: 1px solid var(--ds-gold);
    border-radius: var(--ds-r-lg);
    background: linear-gradient(120deg, var(--ds-gold-soft), var(--ds-saffron-soft));
}
.ds-daan-strip__icon { font-size: 2rem; line-height: 1; flex-shrink: 0; }

/* --- Closing CTA band ------------------------------------------------------ */
.ds-cta {
    background: linear-gradient(135deg, var(--ds-maroon-dark), var(--ds-maroon));
    color: #fff;
    padding: var(--ds-section-y) 0;
}
/* All six levels, not just h1-h3: these bands carry h5 headings in several
   templates, and headings default to maroon — which is invisible here. */
.ds-cta :is(h1, h2, h3, h4, h5, h6) { color: #fff; }
.ds-cta p { color: var(--ds-on-dark-muted); }

/* --- Honeypot ---------------------------------------------------------------
   Must be invisible to people but present in the DOM for a bot to find and
   fill. Not display:none — some scrapers skip those. See core/antispam.py. */
.as-hp {
    position: absolute !important;
    left: -9999px !important;
    top: auto;
    width: 1px; height: 1px;
    overflow: hidden;
}

/* --- Utility ---------------------------------------------------------------
   A deliberately small set. These exist so templates stop writing
   style="color:#7A1122" — they are NOT a licence to build a utility framework.
   If you need a new one, ask first whether it belongs on a component instead.
   -------------------------------------------------------------------------- */
.min-w-0 { min-width: 0; }
.ds-clickable { cursor: pointer; }

/* Brand text colours */
.text-brand    { color: var(--ds-maroon)    !important; }
.text-saffron  { color: var(--ds-saffron)   !important; }
.text-gold     { color: var(--ds-gold-text) !important; }
.text-accent   { color: var(--ds-accent)    !important; }
.text-ok       { color: var(--ds-success)   !important; }
.text-bad      { color: var(--ds-danger)    !important; }
.text-info-ds  { color: var(--ds-info)      !important; }

/* Surfaces */
.bg-cream  { background: var(--ds-cream) !important; }
.bg-sand   { background: var(--ds-sand)  !important; }
.bg-brand  { background: var(--ds-maroon) !important; color: #fff !important; }
.bg-warm   { background: linear-gradient(135deg, var(--ds-cream), var(--ds-sand)) !important; }

/* Small uppercase label above a value */
.ds-eyebrow {
    font-size: .75rem;
    font-weight: 600;
    letter-spacing: .1em;
    text-transform: uppercase;
}

/* Decorative emoji/glyph sizes — replaces style="font-size:2.5rem" etc. */
.ds-glyph      { font-size: 2.5rem; line-height: 1; }
.ds-glyph--lg  { font-size: 3rem;   line-height: 1; }
.ds-glyph--xl  { font-size: 4rem;   line-height: 1; }

/* Card top-accent colour variants (.ds-card--accent alone is gold) */
.ds-card--accent-brand   { border-top: 3px solid var(--ds-maroon); }
.ds-card--accent-saffron { border-top: 3px solid var(--ds-saffron); }
.ds-card--accent-success { border-top: 3px solid var(--ds-success); }
.ds-card--accent-danger  { border-top: 3px solid var(--ds-danger); }
.ds-card--accent-info    { border-top: 3px solid var(--ds-info); }
.ds-card--accent-purple  { border-top: 3px solid var(--ds-accent); }

/* Left-edge accent (used where a card sits in a vertical list) */
.ds-card--edge-brand   { border-left: 3px solid var(--ds-maroon); }
.ds-card--edge-saffron { border-left: 3px solid var(--ds-saffron); }
/* Named to match the --accent- set above so the two families stay in step. */
.ds-card--edge-success { border-left: 3px solid var(--ds-success); }
.ds-card--edge-danger  { border-left: 3px solid var(--ds-danger); }

.bg-white      { background: var(--ds-ivory) !important; }
.bg-accent     { background: var(--ds-accent) !important; color: #fff !important; }
.bg-brand-grad {
    background: linear-gradient(135deg, var(--ds-maroon-dark), var(--ds-maroon)) !important;
    color: #fff !important;
}
.ds-text-xxs { font-size: .65rem; }
.ds-text-xs  { font-size: .72rem; }
.ds-text-sm  { font-size: .78rem; }
.ds-score-lg { font-size: 1.6rem; line-height: 1; }
.ds-w-110    { width: 110px; }
.ds-track    { letter-spacing: .08em; }
/* Sidebar that follows the reader down a long booking/detail page. */
.ds-sticky   { position: sticky; top: 80px; }
.bg-saffron    { background: var(--ds-saffron) !important; color: #fff !important; }
.bg-ok         { background: var(--ds-success) !important; color: #fff !important; }
.bg-gold       { background: var(--ds-gold)    !important; color: #fff !important; }
.bg-brand-soft { background: var(--ds-maroon-soft) !important; }
.ds-card--accent-muted { border-top: 3px solid var(--ds-info); }
.ds-card--edge-info    { border-left: 4px solid var(--ds-info); }
.ds-card--edge-muted   { border-left: 4px solid var(--ds-line-strong); }
.ds-card--edge-purple  { border-left: 4px solid var(--ds-accent); }

/* Gender tint for matrimonial cards + avatars. Info blue = boy, danger red =
   girl, matching the pandit match report so the two screens agree. */
.ds-avatar--boy  { background: linear-gradient(135deg, var(--ds-info),   #5B93AC); }
.ds-avatar--girl { background: linear-gradient(135deg, var(--ds-danger), #C96A6A); }

/* Tattva (element) badges on the planetary-positions table. */
.ds-tattva { color: #fff; }
.ds-tattva--fire  { background: var(--ds-danger); }
.ds-tattva--earth { background: var(--ds-success); }
.ds-tattva--air   { background: var(--ds-info); }
.ds-tattva--water { background: #1D7A8C; }
/* Avatar sitting on the maroon page header, so it needs a light ground. */
.ds-avatar--onhead { background: rgba(255, 255, 255, .2); }
/* The accent gradient marks the girl's side in the pandit match report. */
.ds-avatar--accent { background: linear-gradient(135deg, var(--ds-accent), var(--ds-saffron)); }

/* --- Info line (icon bubble + label + value), e.g. the contact column ------ */
.ds-infoline { display: flex; gap: var(--ds-3); margin-bottom: var(--ds-5); }
.ds-infoline__icon {
    flex: 0 0 44px; width: 44px; height: 44px;
    border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    background: var(--ds-maroon-soft);
    color: var(--ds-maroon);
}
.ds-infoline__icon--wa { background: #E7F8EE; color: #128C4A; }
.ds-infoline__label {
    font-size: .7rem; font-weight: 700;
    letter-spacing: .12em; text-transform: uppercase;
    color: var(--ds-ink-faint);
    margin-bottom: .15rem;
}
.ds-infoline a { text-decoration: none; }
.ds-infoline a:hover { text-decoration: underline; }

/* WhatsApp keeps its own brand green — it is a recognised mark, not our palette.
   #128C4A instead of #25D366 so white text on it clears AA. */
.ds-btn--wa { background: #128C4A; border-color: #128C4A; color: #fff; }
.ds-btn--wa:hover { background: #0E7038; border-color: #0E7038; color: #fff; }

/* --- Inline note / callout ------------------------------------------------- */
.ds-note {
    display: flex; gap: .6rem;
    padding: .75rem .9rem;
    border-radius: var(--ds-r-sm);
    border-left: 3px solid var(--ds-line-strong);
    background: var(--ds-sand);
    font-size: .875rem;
    color: var(--ds-ink-muted);
}
.ds-note i { margin-top: .12rem; flex-shrink: 0; }

/* Let the note wrap on a phone — and ONLY on a phone.
   This box is written two ways across the site: an <i> icon beside a <div>,
   which is what the flex is for, and — in about half its uses — raw text with
   a <strong> or two in it. In that second form every text run and every
   <strong> becomes its own flex item, so a paragraph is laid out as columns
   side by side. The columns will not shrink past their longest word, and at
   320px that took the whole PAGE 17px wider than the screen (/privacy/ was the
   worst case).

   Deliberately NOT applied at every width. Tried that first and it changed the
   desktop: /matrimonial/'s note has two <p> children that were being shrunk to
   sit on one row, and wrapping moved the second onto a row of its own — 95px
   tall to 100px. Harmless, but it was not asked for and it is not this fix's
   business. On a phone a note stacking is right anyway. */
@media (max-width: 575.98px) {
    .ds-note { flex-wrap: wrap; }
}
.ds-note--warn    { background: var(--ds-warn-soft);    border-left-color: var(--ds-warn);    color: #6E3F08; }
.ds-note--success { background: var(--ds-success-soft); border-left-color: var(--ds-success); color: #14513C; }
.ds-note--danger  { background: var(--ds-danger-soft);  border-left-color: var(--ds-danger);  color: #6E1D1D; }
.ds-note--info    { background: var(--ds-info-soft);    border-left-color: var(--ds-info);    color: #143D52; }

/* --- Empty state ---------------------------------------------------------- */
.ds-empty { text-align: center; padding: var(--ds-7) var(--ds-4); color: var(--ds-ink-muted); }
.ds-empty__icon { font-size: 2.5rem; opacity: .5; margin-bottom: var(--ds-3); }

/* --- Collapse row (Vimshottari / Yogini mahadasha -> antardasha) -----------
   Plain <details>/<summary>, no JS. The summary marker is hidden because the
   row already reads as expandable from its layout. */
.ds-collapse {
    border: 1px solid var(--ds-line);
    border-radius: var(--ds-r-sm);
    overflow: hidden;
    margin-bottom: .5rem;
}
.ds-collapse__head {
    cursor: pointer;
    padding: .65rem .9rem;
    background: var(--ds-cream);
    list-style: none;
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: .5rem;
    flex-wrap: wrap;
}
.ds-collapse__head::-webkit-details-marker { display: none; }
.ds-collapse__head:hover { background: var(--ds-sand); }
.ds-collapse[open] .ds-collapse__head { border-bottom: 1px solid var(--ds-line); }
/* Yogini uses the secondary accent so the two dasha cards stay distinguishable. */
.ds-collapse__head--accent { background: var(--ds-accent-soft); }
.ds-collapse__head--accent:hover { background: #E9E0F5; }

/* --- Gold rule under a centred heading -------------------------------------- */
.ds-rule-gold {
    width: 70px; height: 3px;
    margin-inline: auto;
    background: var(--ds-gold);
    border-radius: 2px;
}

/* --- Prose measure ---------------------------------------------------------- */
.ds-measure    { max-width: 62ch; margin-inline: auto; }
.ds-measure--sm{ max-width: 46ch; margin-inline: auto; }
.ds-measure--lg{ max-width: 80ch; margin-inline: auto; }

/* --- Rounded CTA block (a ds-cta boxed inside a container) ------------------- */
.ds-cta--boxed { border-radius: var(--ds-r-lg); }

/* --- Divider -------------------------------------------------------------- */
.ds-rule { height: 1px; background: var(--ds-line); border: 0; margin: var(--ds-6) 0; }

/* --- Phaladesh prose -------------------------------------------------------
   Six topic sections on the kundli result page. This is the one block on that
   page meant to be READ rather than scanned, so it gets a reading measure and
   real line-height — everything around it is tables and diagrams.

   The provenance line (`__from`) is deliberately small and quiet but always
   present: it names the placement the paragraph was read from, which is what
   separates this from the "Powered by Swiss Ephemeris" card it replaced.
   -------------------------------------------------------------------------- */
.ds-phal__sec + .ds-phal__sec {
    margin-top: var(--ds-5);
    padding-top: var(--ds-5);
    border-top: 1px solid var(--ds-line);
}
.ds-phal__title {
    font-size: 1.02rem;
    font-weight: 700;
    color: var(--ds-maroon);
    margin-bottom: .15rem;
}
.ds-phal__from {
    font-size: .76rem;
    color: var(--ds-ink-faint);
    margin-bottom: var(--ds-2);
}
.ds-phal__text {
    font-size: .97rem;
    line-height: 1.75;
    color: var(--ds-ink);
    max-width: 68ch;
    margin-bottom: 0;
}

/* --- Tile grid: icon + name, nothing else ----------------------------------
   The home page used ds-card--link + ds-tile for its services: icon, name, a
   two-line description and a button, 256px per card, ONE per row on a phone.
   Six of them ran 1,846px. Measured on the real page at 390px.

   A visitor who is not comfortable with a website does not read the
   description — they look for the thing they came for and press it. So the
   description goes and the grid gets three across, which puts nine services in
   ~415px. Same information density argument as an app's home screen, and the
   reason this is a component rather than home-page CSS: the same grid answers
   "what else is there" at the foot of any section page.

   THREE ACROSS IS THE FLOOR, NOT A CHOICE. At 390px a tile is ~118px wide, and
   "अंक ज्योतिष" needs about 96px of that. Four across gives 88px and the label
   wraps to three lines or clips. If a name longer than that is ever added,
   shorten the name — do not narrow the tile.
   -------------------------------------------------------------------------- */
.ds-tilegrid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--ds-2);
}
@media (min-width: 576px) { .ds-tilegrid { grid-template-columns: repeat(4, 1fr); gap: var(--ds-3); } }
@media (min-width: 992px) { .ds-tilegrid { grid-template-columns: repeat(6, 1fr); } }

.ds-tilegrid__item {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--ds-2);
    min-height: 104px;
    padding: var(--ds-3) var(--ds-1);
    text-align: center;
    text-decoration: none;
    color: var(--ds-ink);
    background: var(--ds-ivory);
    border: 1px solid var(--ds-line);
    border-radius: var(--ds-r);
    box-shadow: var(--ds-shadow-sm);
    position: relative;
    transition: border-color .15s, box-shadow .15s, transform .15s;
}
.ds-tilegrid__item:hover,
.ds-tilegrid__item:focus-visible {
    color: var(--ds-ink);
    border-color: var(--ds-gold);
    box-shadow: var(--ds-shadow);
    transform: translateY(-2px);
}
@media (prefers-reduced-motion: reduce) {
    .ds-tilegrid__item { transition: none; }
    .ds-tilegrid__item:hover, .ds-tilegrid__item:focus-visible { transform: none; }
}
.ds-tilegrid__icon { font-size: 1.65rem; line-height: 1; }
.ds-tilegrid__name { font-size: .78rem; font-weight: 700; line-height: 1.25; }

/* "New" flag. Absolutely positioned, so the tile keeps its height whether or
   not it carries one — a taller flagged tile would break the grid's rhythm. */
.ds-tilegrid__flag {
    position: absolute; top: -6px; right: -4px;
    padding: 2px 6px;
    border-radius: var(--ds-r-pill);
    background: var(--ds-saffron);
    color: #fff;
    font-size: .58rem; font-weight: 700; letter-spacing: .04em;
    box-shadow: var(--ds-shadow-sm);
}

/* Unreleased sections (core/features.py). Dashed and warn-coloured because the
   person seeing them — staff, or a Pandit ji holding a PreviewAccess row — must
   be able to tell at a glance that their yajmaan cannot see the same tile. */
.ds-tilegrid--preview { margin-top: var(--ds-4); padding-top: var(--ds-4); border-top: 1px dashed var(--ds-line); }
.ds-tilegrid__item--preview { border-style: dashed; border-color: var(--ds-warn); background: var(--ds-warn-soft); }

/* --- Rashi strip: twelve chips, scrolled sideways --------------------------
   Twelve items do not fit across a phone and must not become a dropdown — a
   dropdown hides eleven of the twelve and asks the reader to know their rashi's
   spelling. Sideways scroll keeps the first four visible, which is what tells
   somebody the row scrolls.
   -------------------------------------------------------------------------- */
.ds-chipstrip {
    display: flex;
    gap: var(--ds-2);
    overflow-x: auto;
    padding-bottom: var(--ds-2);
    scrollbar-width: thin;
    -webkit-overflow-scrolling: touch;
}
.ds-chipstrip__item {
    flex: 0 0 auto;
    width: 74px;
    padding: var(--ds-2) var(--ds-1);
    text-align: center;
    text-decoration: none;
    color: var(--ds-ink);
    background: var(--ds-ivory);
    border: 1px solid var(--ds-line);
    border-radius: var(--ds-r);
}
.ds-chipstrip__item:hover,
.ds-chipstrip__item:focus-visible { color: var(--ds-ink); border-color: var(--ds-gold); }
.ds-chipstrip__sym  { font-size: 1.2rem; line-height: 1.2; color: var(--ds-saffron); }
.ds-chipstrip__name { font-size: .72rem; font-weight: 600; }

/* --- A Bootstrap .row that scrolls sideways on a phone ----------------------
   Three cards that are right at 4 across on a desktop become three FULL-WIDTH
   cards stacked on a phone — the acharya row measured 792px that way, for three
   names. Sideways it is one card tall.

   The 78% width is doing work: at 100% the next card is invisible and nothing
   says the row moves; leaving 22% of the neighbour showing is the whole hint.
   scroll-snap so a flick lands on a card rather than between two.

   Applied ON TOP of the normal grid classes, so the desktop layout is whatever
   the col-* classes already said. Only the phone changes.
   -------------------------------------------------------------------------- */
@media (max-width: 767.98px) {
    .ds-scroll-row {
        flex-wrap: nowrap;
        overflow-x: auto;
        scroll-snap-type: x proximity;
        padding-bottom: var(--ds-2);
        -webkit-overflow-scrolling: touch;
    }
    .ds-scroll-row > [class*="col-"] {
        flex: 0 0 78%;
        max-width: 78%;
        scroll-snap-align: start;
    }
}

/* ============================================================================
   5. BOOTSTRAP RE-THEME
   ----------------------------------------------------------------------------
   Bootstrap 5.3 defines component colours as *local* custom properties on each
   class (e.g. .btn-primary sets --bs-btn-bg). Overriding those here re-skins
   every unconverted template — dashboards, admin screens, pandit workflows —
   without editing them. Remove nothing from this section without checking what
   still relies on stock Bootstrap classes.
   ========================================================================== */
:root {
    --bs-body-color: var(--ds-ink);
    --bs-body-bg: var(--ds-cream);
    --bs-border-color: var(--ds-line);
    --bs-link-color: var(--ds-maroon);
    --bs-link-hover-color: var(--ds-maroon-dark);

    --bs-primary: #7A1122;
    --bs-primary-rgb: 122, 17, 34;
    --bs-success: #1E7A5A;   --bs-success-rgb: 30, 122, 90;
    --bs-danger:  #A32B2B;   --bs-danger-rgb: 163, 43, 43;
    --bs-warning: #A35F0D;   --bs-warning-rgb: 163, 95, 13;
    --bs-info:    #1F5C7A;   --bs-info-rgb: 31, 92, 122;
    --bs-light:   #F5EEE4;   --bs-light-rgb: 245, 238, 228;
    --bs-dark:    #241A14;   --bs-dark-rgb: 36, 26, 20;
}

.btn-primary   { --bs-btn-bg: var(--ds-maroon);  --bs-btn-border-color: var(--ds-maroon);
                 --bs-btn-hover-bg: var(--ds-maroon-dark); --bs-btn-hover-border-color: var(--ds-maroon-dark);
                 --bs-btn-active-bg: var(--ds-maroon-dark); --bs-btn-active-border-color: var(--ds-maroon-dark); }
.btn-danger    { --bs-btn-bg: var(--ds-danger);  --bs-btn-border-color: var(--ds-danger);
                 --bs-btn-hover-bg: #8A2323; --bs-btn-hover-border-color: #8A2323;
                 --bs-btn-active-bg: #8A2323; --bs-btn-active-border-color: #8A2323; }
.btn-success   { --bs-btn-bg: var(--ds-success); --bs-btn-border-color: var(--ds-success);
                 --bs-btn-hover-bg: #196547; --bs-btn-hover-border-color: #196547; }
.btn-warning   { --bs-btn-bg: var(--ds-saffron); --bs-btn-border-color: var(--ds-saffron);
                 --bs-btn-color: #fff; --bs-btn-hover-color: #fff;
                 --bs-btn-hover-bg: var(--ds-saffron-dark); --bs-btn-hover-border-color: var(--ds-saffron-dark);
                 --bs-btn-active-color: #fff; --bs-btn-active-bg: var(--ds-saffron-dark); }
.btn-info      { --bs-btn-bg: var(--ds-info);    --bs-btn-border-color: var(--ds-info); --bs-btn-color: #fff;
                 --bs-btn-hover-color: #fff; --bs-btn-hover-bg: #194A62; --bs-btn-hover-border-color: #194A62; }
.btn-light     { --bs-btn-bg: var(--ds-ivory);   --bs-btn-border-color: var(--ds-line-strong);
                 --bs-btn-hover-bg: var(--ds-sand); --bs-btn-hover-border-color: var(--ds-line-strong); }
.btn-dark      { --bs-btn-bg: var(--ds-ink-surface); --bs-btn-border-color: var(--ds-ink-surface); }

.btn-outline-primary { --bs-btn-color: var(--ds-maroon);  --bs-btn-border-color: var(--ds-maroon);
                       --bs-btn-hover-bg: var(--ds-maroon); --bs-btn-hover-border-color: var(--ds-maroon); }
.btn-outline-danger  { --bs-btn-color: var(--ds-danger);  --bs-btn-border-color: var(--ds-danger);
                       --bs-btn-hover-bg: var(--ds-danger); --bs-btn-hover-border-color: var(--ds-danger); }
.btn-outline-success { --bs-btn-color: var(--ds-success); --bs-btn-border-color: var(--ds-success);
                       --bs-btn-hover-bg: var(--ds-success); --bs-btn-hover-border-color: var(--ds-success); }
.btn-outline-warning { --bs-btn-color: var(--ds-saffron); --bs-btn-border-color: var(--ds-saffron);
                       --bs-btn-hover-bg: var(--ds-saffron); --bs-btn-hover-border-color: var(--ds-saffron);
                       --bs-btn-hover-color: #fff; }
.btn-outline-light   { --bs-btn-color: #fff; --bs-btn-border-color: rgba(255,255,255,.55);
                       --bs-btn-hover-bg: rgba(255,255,255,.14); --bs-btn-hover-color: #fff;
                       --bs-btn-hover-border-color: #fff; }

/* Stock .bg-warning / .text-warning were pure #ffc107 — illegible on white. */
.text-warning { color: var(--ds-warn) !important; }
.bg-warning   { background-color: var(--ds-saffron) !important; color: #fff !important; }
.bg-light     { background-color: var(--ds-sand) !important; }

.card         { border-color: var(--ds-line); border-radius: var(--ds-r); }
.badge        { font-weight: 600; }
.table        { --bs-table-border-color: var(--ds-line); }
.table > thead { --bs-table-bg: var(--ds-sand); }
.alert        { border-radius: var(--ds-r); border-width: 1px; }
.dropdown-menu{ border-color: var(--ds-line); border-radius: var(--ds-r); box-shadow: var(--ds-shadow-lg); }
.modal-content{ border-radius: var(--ds-r-lg); border-color: var(--ds-line); }

/* ============================================================================
   6. NAVBAR & FOOTER
   ========================================================================== */
.sm-navbar {
    background: linear-gradient(135deg, var(--ds-maroon-dark), var(--ds-maroon));
    box-shadow: 0 1px 0 rgba(255, 255, 255, .06), var(--ds-shadow);
}
.sm-logo-icon { font-size: 2rem; line-height: 1; }
.sm-brand-mark { filter: drop-shadow(0 0 6px rgba(255, 215, 0, .53)); }
.sm-brand-name { font-weight: 700; line-height: 1.1; color: #fff; }
.sm-tagline {
    font-size: .62rem;
    letter-spacing: .18em;
    color: var(--ds-gold-bright);
    text-transform: uppercase;
}

/* The navbar is the one .container-fluid on the site — see the comment in
   base.html for why. Capped so the brand does not drift to the far edge of a
   wide monitor while still beating .container's 960px on a laptop. */
.sm-navbar__inner { max-width: 1560px; }

/* ── Which links are in the bar and which fall back into "More" ──
   MEASURED at 1163px, logged out: brand 234 + all six links 652 + the utility
   cluster 200 = 1086px, against 1139px of container-fluid. Comfortable.

   Two cases take the row below what it needs, and in both the three
   `sm-nav-extra` links go back into the "More" menu:

   1. Under 1140px. container-fluid gives (viewport - 24px), so 1086px of
      content needs a 1110px window to survive at all; 1140px leaves 30px of
      slack for a longer label or a browser that rounds differently. At 992px
      the row is 118px short, so there is no question there.

      The cut-off is NOT Bootstrap's 1200px xl. 1163px is an ordinary laptop
      width — hiding the links there would defeat the point of putting them in
      the bar. Hindi is not the risk: Devanagari measures 1029px, narrower
      than English.

   2. Logged in, at any width. "Login" (72px) becomes Dashboard/Admin plus the
      account dropdown — roughly 180px more — and that is enough to overflow.
      Only pandits and staff have accounts (clients have none), so this costs
      the public nothing and keeps a working pandit's bar short.

   `.sm-nav-extra-alt` marks the copies inside the menu and must stay the exact
   inverse of these rules, or a link goes missing at some width. Below 992px
   neither applies: the menu is a vertical panel with room for everything.

   ORDER MATTERS HERE. The default below and the band rule inside the media
   query have the same specificity (0,1,0) and both are !important, so a media
   query does NOT win by being a media query — the later rule wins. The default
   must stay FIRST. Move it below and the menu copies never appear at all. */

/* Default: the link is in the bar, so its menu copy stays out. */
.sm-nav-extra-alt { display: none !important; }

/* Under 1140px the bar cannot hold all six links, so the three extras go back
   into "More". This band was deleted while the navbar was briefly -xl, where
   there was no horizontal bar in this range for it to protect; it is restored
   with navbar-expand-lg. */
@media (min-width: 992px) and (max-width: 1139.98px) {
    .sm-nav-extra     { display: none  !important; }
    .sm-nav-extra-alt { display: block !important; }
}

/* The last 27px, and where it actually was.

   A LOGGED-OUT bar never overflows — measured clean at 390, 992, 1006, 1043
   and 1100. Only a signed-in one does, because its utility cluster is 433px
   against a logged-out 235px: 27px over at 992, 13px at 1006, and fine from
   1020 up.

   So the fix is a signed-in one, in that band only: "Dashboard" (or "Admin")
   drops its label and keeps its icon, which buys back about 75px — far more
   than the 27 needed, and it costs the public site nothing at any width. The
   alternative that was tried first, moving the whole navbar to expand-xl, took
   the link row away from every window up to 1200px to solve this. Do not do
   that again; see the comment on <nav> in base.html.

   Below 992px the menu is a vertical panel with room for the words, so the
   band starts there. */
@media (min-width: 992px) and (max-width: 1039.98px) {
    .sm-nav-dash__label { display: none; }
}

/* Signed in, the extras go back to the menu — but only in a BAND, not forever.

   This used to apply at every width from the expand breakpoint up, and that is
   what made a signed-in pandit's bar look arbitrary: on a 1920px monitor with
   hundreds of pixels to spare it still showed "Kundli Milan · Biodata · More",
   with Kundli and Panchang buried in the menu for no reason the reader could
   see. Below 1400 it is not arbitrary — the bar genuinely cannot hold them.

   MEASURED, extras forced visible, brand + nav + utilities:

       logged out          1095   (5 links + More, "Login")
       pandit              1180   (4 links + More, Dashboard + account menu)
       staff (estimated)   1293   (the public 5 links with a signed-in cluster;
                                   staff get "Admin", which is shorter than
                                   "Dashboard", so this is an upper bound)

   container-fluid gives viewport - 24px, so 1293 needs a 1317px window. The
   band ends at 1400 rather than 1320: the account menu carries the USERNAME,
   and 83px of slack is about eight more characters than "demo_pandit". A
   1366px laptop therefore still gets the menu copies — the documented, working
   fallback — and anything wider gets the same bar a logged-out visitor sees.

   Two class names (0,2,0), so it beats the rule above on specificity whichever
   order they end up in. */
@media (min-width: 992px) and (max-width: 1399.98px) {
    .sm-nav-main--compact .sm-nav-extra     { display: none  !important; }
    .sm-nav-main--compact .sm-nav-extra-alt { display: block !important; }
}

/* The utility cluster on the right: search icon, language pill, Login.
   Three controls of three different shapes and heights sat flush against each
   other and read as clutter rather than as one group. A slightly wider gap and
   one shared height is the whole fix — no new colours, no new components.

   992px, matching navbar-expand-lg: below it these three are stacked in a
   vertical panel, where a shared height and a divider before them mean
   nothing. */
@media (min-width: 992px) {
    .sm-nav-utils { gap: .45rem !important; margin-left: var(--ds-3); }
    .sm-nav-utils .sm-nav-search__toggle,
    .sm-nav-utils .sm-nav-lang,
    .sm-nav-utils .ds-btn { height: 34px; }
    .sm-nav-utils .ds-btn { display: inline-flex; align-items: center; }
    /* A hairline before the utilities so the eye reads "links | tools", not
       one long undifferentiated row. */
    .sm-nav-utils::before {
        content: "";
        align-self: center;
        width: 1px; height: 22px;
        margin-right: .35rem;
        background: rgba(255, 255, 255, .22);
    }
}

/* Search + language control, sitting on the maroon bar.
   Both are kept narrow on purpose: an expanded search box alone needed 219px,
   which forced the whole menu behind a hamburger until 1200px. */
.sm-nav-search { display: flex; align-items: center; }
.sm-nav-search .form-control,
.sm-nav-lang {
    background: rgba(255, 255, 255, .14);
    border-color: rgba(255, 255, 255, .3);
    color: #fff;
}
.sm-nav-search .form-control { width: 150px; border-radius: var(--ds-r-pill) 0 0 var(--ds-r-pill); }
.sm-nav-search .form-control::placeholder { color: rgba(255, 255, 255, .6); }
.sm-nav-search .form-control:focus {
    background: rgba(255, 255, 255, .22);
    color: #fff;
    border-color: var(--ds-gold-bright);
    box-shadow: none;
}
.sm-nav-search .btn {
    border-radius: 0 var(--ds-r-pill) var(--ds-r-pill) 0;
    background: var(--ds-saffron);
    border: 1px solid var(--ds-saffron);
    color: #fff;
}
.sm-nav-search .btn:hover { background: var(--ds-saffron-dark); border-color: var(--ds-saffron-dark); color: #fff; }

/* Icon that reveals the search field — desktop only. */
.sm-nav-search__toggle {
    align-items: center; justify-content: center;
    width: 34px; height: 34px;
    border-radius: 50%;
    border: 1px solid rgba(255, 255, 255, .3);
    background: rgba(255, 255, 255, .14);
    color: #fff;
    cursor: pointer;
    flex-shrink: 0;
}
.sm-nav-search__toggle:hover { background: rgba(255, 255, 255, .24); }

/* ── Language toggle ──
   Replaced a <select> showing "🌐 EN", which read as decoration rather than a
   control. Both languages are on screen now, so the choice is visible without
   opening anything, and the filled pill says which one is on.

   NO NEW COLOURS. The active pill is plain white with --ds-maroon text, which
   is the strongest "selected" the palette has and — importantly — is NOT
   saffron: saffron is the Login button sitting right beside it, and two saffron
   fills in one cluster would make a language toggle look like a second call to
   action. The icon is --ds-gold-bright, 7.75:1 on maroon. */
.sm-lang {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    padding: 2px 2px 2px .5rem;
    border: 1px solid rgba(255, 255, 255, .3);
    border-radius: var(--ds-r-pill);
    background: rgba(255, 255, 255, .14);
}
.sm-lang__icon { color: var(--ds-gold-bright); font-size: .95rem; margin-right: .15rem; }
.sm-lang__opt {
    border: 0;
    background: transparent;
    color: rgba(255, 255, 255, .82);
    font-size: .78rem;
    font-weight: 600;
    line-height: 1;
    padding: .3rem .55rem;
    border-radius: var(--ds-r-pill);
    cursor: pointer;
    white-space: nowrap;
    transition: background .15s, color .15s;
}
.sm-lang__opt:hover { background: rgba(255, 255, 255, .16); color: #fff; }
.sm-lang__opt.is-active {
    background: #fff;
    color: var(--ds-maroon);
}
/* Devanagari needs the serif face and sits small next to Latin at the same
   font-size — the toggle looked lopsided until this. */
.sm-lang__opt[lang="hi"] { font-family: 'Noto Serif Devanagari', 'Poppins', serif; font-size: .82rem; }

/* The phone copy, sitting beside the hamburger. No icon, so the .5rem lead-in
   the icon needed would just be a lopsided gap.

   The pills are given a real height here. Inherited from the desktop control
   they measured 28x21 and 22x21 — fine for a mouse, too small for a thumb, and
   this is the one control on the page a struggling visitor most needs to hit
   first time. 34px min-height puts the whole group at ~38px, which also lines
   it up with the 39px hamburger beside it instead of floating small next to
   it. Width stays tight: at 375px the row measures brand 193 + this 57 +
   hamburger 55 inside 371, and there is no room to be generous sideways. */
.sm-lang--bar { padding: 2px; }
.sm-lang--bar .sm-lang__opt {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 34px;
    padding: .3rem .6rem;
}

/* At 360px the brand, this control and the hamburger compete for one row.
   Tighten the type, never the height — a smaller tap target is the wrong thing
   to trade away, and the brand is what tells a first-time visitor where they
   are, so it is not shrinking either. */
@media (max-width: 400px) {
    .sm-lang--bar .sm-lang__opt { padding: .3rem .45rem; font-size: .74rem; }
    .sm-lang--bar .sm-lang__opt[lang="hi"] { font-size: .78rem; }
}

/* ============================================================================
   6b. "AAJ KA PANCHANG" RIBBON  (templates/includes/_panchang_strip.html)
   ==========================================================================
   Reads as the bottom edge of the header, not as a strip laid on the page.
   That is why it is maroon-dark and not a cream band: the home hero is a dark
   maroon gradient, and a light ribbon between navbar and hero cut the header
   in two. As a darker shade of the same family it works over every page.

   Palette: --ds-maroon-dark ground, --ds-gold-bright labels (7.75:1) and white
   values (12.6:1). The gold hairline on top is the same rule the design system
   already uses to separate bands. No new hex anywhere in this block. */
.ds-panchang-bar {
    background: var(--ds-maroon-dark);
    border-top: 1px solid rgba(255, 215, 0, .28);
    border-bottom: 1px solid rgba(0, 0, 0, .25);
    font-size: .78rem;
}
.ds-panchang-bar__inner {
    display: flex;
    align-items: center;
    gap: var(--ds-3);
    padding-top: .4rem;
    padding-bottom: .4rem;
}

/* "Today · Friday" — the anchor of the row, so it gets the gold. */
.ds-panchang-bar__day {
    display: inline-flex; align-items: center; gap: .35rem;
    color: var(--ds-gold-bright);
    text-decoration: none;
    white-space: nowrap;
    flex-shrink: 0;
}
.ds-panchang-bar__day b { color: #fff; font-weight: 600; }
.ds-panchang-bar__day:hover { color: var(--ds-gold-bright); }
.ds-panchang-bar__day:hover b { text-decoration: underline; }

/* The facts. On a phone this row scrolls sideways INSIDE the ribbon rather
   than wrapping to three lines or pushing the page wider — a horizontal
   scrollbar on <body> is the one thing a sticky header must never cause. */
/* gap is --ds-2, not --ds-3. With Surya Tithi added the row is seven items and
   12px gaps put it 12px over the available width at 1163px — it still scrolled
   rather than breaking the page, but Rahu Kaal sat visibly cut in half, which
   reads as broken rather than as "there is more". 8px gaps buy back 24px and
   the whole row lands. */
.ds-panchang-bar__items {
    display: flex;
    align-items: center;
    gap: .375rem;
    flex: 1 1 auto;
    min-width: 0;
    overflow-x: auto;
    scrollbar-width: none;
    white-space: nowrap;
}
.ds-panchang-bar__items::-webkit-scrollbar { display: none; }

/* Every fact is its own outlined pill.

   It started as a hairline divider between items, which was already better
   than nothing — seven label/value pairs separated only by whitespace read as
   one long sentence, and "Shravana Tithi" looked like a term of its own. The
   pill closes the shape instead of just marking the join, so each fact is a
   thing you can see before you read it. Dividers are gone: a border and a
   separator between the same two items is one boundary drawn twice. */
.ds-panchang-bar__item {
    color: #fff;
    display: inline-flex; align-items: baseline; gap: .25rem;
    flex-shrink: 0;
    border: 1px solid rgba(255, 215, 0, .26);
    border-radius: var(--ds-r-pill);
    padding: .1rem .45rem;
}

/* Surya tithi still leads. All pills now, so it can no longer stand out by
   BEING a pill — it does it with a brighter border and a bold value instead.
   It is a date, not a panchang limb, and it is the number people scan for.
   Still an outline and not a fill: the filled chip on this row means
   "festival", and two filled chips would compete. */
.ds-panchang-bar__item--date {
    border-color: rgba(255, 215, 0, .55);
    background: rgba(255, 215, 0, .07);
}
.ds-panchang-bar__item--date b { font-weight: 600; }
/* <em> is the label, not emphasis-italic — reset it and make it the gold. */
.ds-panchang-bar__item em {
    font-style: normal;
    color: var(--ds-gold-bright);
    opacity: .85;
    /* A shade smaller than its value: the label is what you skip once you know
       the row, and it bought back some of the width the borders cost. */
    font-size: .94em;
}
.ds-panchang-bar__till { font-style: normal; color: rgba(255, 255, 255, .6); }

/* A festival is why most people open a panchang, so it gets the one filled
   chip on the row: gold ground, maroon text — the navbar pair inverted. */
.ds-panchang-bar__fest {
    display: inline-flex; align-items: center; gap: .3rem;
    flex-shrink: 0;
    background: var(--ds-gold-bright);
    color: var(--ds-maroon-dark);
    font-weight: 600;
    padding: .12rem .55rem;
    border-radius: var(--ds-r-pill);
    text-decoration: none;
}
.ds-panchang-bar__fest:hover { background: #fff; color: var(--ds-maroon); }

.ds-panchang-bar__more {
    display: inline-flex; align-items: center; gap: .2rem;
    color: rgba(255, 255, 255, .85);
    text-decoration: none;
    white-space: nowrap;
    flex-shrink: 0;
}
.ds-panchang-bar__more:hover { color: var(--ds-gold-bright); }

/* ── Phone: WRAP, do not scroll ──
   MEASURED at 386px: the row needs 826px and only 242px are visible, so 70% of
   the panchang sat behind a sideways scroll — and a scroll container with no
   scrollbar gives the reader no clue it is even there. All anyone saw was
   "Praviste 16 Shravana".

   So on a phone the row wraps and the three timings drop out (they carry
   `--time`). What is left — praviste, tithi with its end time, nakshatra, and
   any festival — fits in two lines and is entirely visible. Sunrise, sunset and
   Rahu Kaal are look-up values; "Full Panchang" stays as the tap target for
   them, which is why it is no longer hidden here. */
/* Wrap for the whole collapsed-navbar range, not just phones. At 816px the row
   still needed 826px and cut 333px off — the same fault one screen size up. */
@media (max-width: 991.98px) {
    .ds-panchang-bar__inner { flex-wrap: wrap; row-gap: .25rem; }
    .ds-panchang-bar__items {
        flex-wrap: wrap;
        overflow-x: visible;
        white-space: normal;
        row-gap: .25rem;
    }
    .ds-panchang-bar__more { display: inline-flex; }
}

/* The three timings drop out below 1140px — the SAME threshold the navbar uses
   for its extra links, so there is one number to remember rather than two.

   Measured: at 996px the single-line row still cut 153px, at 1096px 53px. What
   survives everywhere is praviste, tithi with its end time, nakshatra and any
   festival — the things a visitor glances at. Sunrise, sunset and Rahu Kaal are
   looked UP, and "Full Panchang" is right there. */
@media (max-width: 1139.98px) {
    .ds-panchang-bar__item--time { display: none; }
}
@media (max-width: 767.98px) {
    .ds-panchang-bar { font-size: .72rem; }
}

/* ── Phone: back to ONE line ──────────────────────────────────────────────
   Wrapping cost too much. Measured on a 390px screen: the ribbon stood 129px
   tall over four rows, and with the 59px navbar that is 188px — better than a
   quarter of the first screen gone before a word of content, on the page that
   has to sell the site.

   The wrap was introduced for a real reason, and it is not forgotten: as a
   silent scroller "all anyone saw was Praviste 16 Shravana", with nothing to
   suggest there was more. Restoring one line without answering that would just
   restore the bug. So the row scrolls AND says so — a fade at the right edge
   over the ribbon's own maroon, which is the standard "this continues" cue and
   costs no height. The three timings stay hidden here (they already are, from
   1140px down) so the scroll stays short: praviste, tithi, nakshatra and any
   festival, then "Full Panchang" as the end stop.

   ONE line, not two: at two the fade has to sit on both rows and the saving
   halves. Overriding the 991.98px wrap block above, so it must stay after it. */
@media (max-width: 575.98px) {
    .ds-panchang-bar { position: relative; }

    /* The whole row scrolls, not just __items. Keeping "Today Sunday" and
       "Full Panchang" pinned outside it left ~170px of the 390 for the panchang
       itself, which is the part people came for. */
    .ds-panchang-bar__inner {
        flex-wrap: nowrap;
        overflow-x: auto;
        scrollbar-width: none;              /* the fade is the cue, not a bar */
        -webkit-overflow-scrolling: touch;
        padding-right: 1.75rem;             /* clears the fade at the far end */
    }
    .ds-panchang-bar__inner::-webkit-scrollbar { display: none; }

    .ds-panchang-bar__items {
        flex-wrap: nowrap;
        white-space: nowrap;
        overflow-x: visible;                /* the parent is the scroller now */
        row-gap: 0;
        /* flex: 0 0 auto, NOT the inherited 1 1 auto with min-width:0. With
           that, this box stayed as narrow as the ribbon while its content
           painted straight out of it — so "Full Panchang", laid out after the
           BOX rather than after the content, printed on top of the tithi. It
           has to take its content's width for the scroller to have anything to
           scroll. */
        flex: 0 0 auto;
        min-width: auto;
    }
    .ds-panchang-bar__item,
    .ds-panchang-bar__fest,
    .ds-panchang-bar__more { flex-shrink: 0; white-space: nowrap; }

    /* One line was too thin at 36px — it read as a rule between the navbar and
       the page rather than as a band of its own, and the type inside it was
       .72rem (~11.5px), small enough to be a squint on a phone.

       The type goes back to the .78rem the rest of the site uses and the chips
       get real vertical padding. That also fixes something the height win had
       left behind: "Today Sunday", the festival chip and "Full Panchang" were
       17-21px tall, well under any sane tap target, on a row whose whole job is
       to be tapped through to /panchang/.

       It costs about 10px against the wrapped version's 129px, which is a
       trade worth making. Still one line. */
    .ds-panchang-bar { font-size: .78rem; }
    .ds-panchang-bar__inner { padding-top: .5rem; padding-bottom: .5rem; }
    .ds-panchang-bar__item { padding: .28rem .55rem; }
    .ds-panchang-bar__fest { padding: .3rem .6rem; }
    .ds-panchang-bar__day,
    .ds-panchang-bar__more { padding-block: .3rem; }

    /* Sits over the ribbon, not inside the scroller, so it stays at the edge
       while the content moves under it. */
    .ds-panchang-bar::after {
        content: '';
        position: absolute;
        top: 0; bottom: 0; right: 0;
        width: 2rem;
        /* rgba(94,13,26,0) is --ds-maroon-dark at zero alpha, not `transparent`.
           `transparent` is rgba(0,0,0,0), and interpolating towards it drags
           the fade through grey — a dirty smudge over a maroon ribbon. Same
           colour, no new hex. */
        background: linear-gradient(to right,
                    rgba(94, 13, 26, 0), var(--ds-maroon-dark) 75%);
        pointer-events: none;
    }
}

/* ── North Indian (diamond) chart ──
   Lived in a <style> block inside kundli/result.html while that page was the
   only one drawing a chart. The pandit match report draws four of its own, and
   an included partial whose CSS only exists on one page renders as a pile of
   unpositioned text everywhere else. The markup is templates/kundli/_ni_chart.html. */
.ni-chart {
    position: relative;
    width: 340px;
    height: 340px;
    margin: 0 auto;
    max-width: 100%;
}
.ni-chart svg {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
}
.ni-house {
    position: absolute;
    transform: translate(-50%, -50%);
    width: 24%;
    text-align: center;
    pointer-events: none;
}
.ni-rashi-num {
    font-size: 0.58rem;
    font-weight: 700;
    color: #b0a08a;
    line-height: 1;
    margin-bottom: 1px;
}
.ni-planets {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0 6px;
}
.ni-planet {
    font-size: 0.72rem;
    font-weight: 800;
    white-space: nowrap;
    line-height: 1.25;
}
.ni-planet sup { font-size: 0.5rem; font-weight: 600; opacity: 0.8; }
.ni-planet.is-asc { color: #B74A00 !important; }

/* 992px, matching navbar-expand-lg: the overlay only makes sense once there
   is a horizontal bar to overlay. In the panel the field shows in full. */
@media (min-width: 992px) {
    /* The open field OVERLAYS the bar rather than pushing it. Expanding inline
       cost ~200px the bar does not have: "Matrimonial" wrapped to two lines and
       the language/account controls fell off the right edge. */
    .sm-nav-search { position: relative; }
    .sm-nav-search__box {
        position: absolute;
        right: 0;
        top: 50%;
        transform: translateY(-50%);
        z-index: 5;
        flex-wrap: nowrap;          /* an input-group wraps once space runs out */
        width: 0;
        overflow: hidden;
        opacity: 0;
        pointer-events: none;
        border-radius: var(--ds-r-pill);
        /* Opaque so the nav links underneath do not read through the field. */
        background: var(--ds-maroon-dark);
        transition: width .18s ease, opacity .18s ease;
    }
    .sm-nav-search.is-open .sm-nav-search__box {
        width: 260px;
        opacity: 1;
        pointer-events: auto;
    }
    /* The fixed 150px is for the mobile panel; in the overlay it must flex. */
    .sm-nav-search__box .form-control { width: auto; flex: 1 1 auto; min-width: 0; }
    .sm-nav-search__box .btn { flex: 0 0 auto; }
}

/* Collapsed (mobile) menu: the maroon bar becomes a panel, so give the
   dropdowns room and stop them looking like floating white cards.

   THIS BREAKPOINT MUST MATCH navbar-expand-* IN base.html. It has been wrong
   before: it said 1199.98px while the bar was -lg, so a 1024px laptop got
   desktop dropdowns wearing panel styling. It is 991.98px because the bar is
   navbar-expand-lg. If the expand breakpoint ever changes, change this with
   it — and the three other rules listed in base.html's navbar comment. */
@media (max-width: 991.98px) {
    /* ── The panel must scroll ITSELF, not hand the job to the page ──────
       Reported 20 Aug 2026: on a phone, tapping "…और" and then trying to
       reach the items lower down closed the whole menu instead.

       MEASURED at 390x780 with the panel and the submenu both open:

           navbar        position: sticky
           panel height  1,784px   against a 780px viewport
           page scrolled 1,500px -> the panel did NOT move (pinned)
           off screen    1,058px, on max-height:none / overflow:visible

       The panel lives inside a sticky navbar, so it stays pinned to the top
       of the window. Scrolling moves the PAGE behind it and never the panel —
       and that scroll gesture lands outside the menu, which is what made
       Bootstrap close it. Roughly 1,058px of links could not be reached at
       all, and trying was the thing that shut the menu.

       An earlier check on this same file read `document.scrollHeight >
       innerHeight` and concluded the page would scroll to it. That reasoning
       was wrong: a tall document says nothing about a pinned panel.

       100dvh first, because on a phone 100vh is the height WITHOUT the
       browser's own address bar — it overshoots by exactly the bar's height,
       and the last menu item ends up under it. The vh line stays as the
       fallback for anything that does not know dvh. */
    .navbar-collapse {
        /* Two things are in the way, not one, and the second was missed on the
           first attempt: the sticky navbar ABOVE (3.7rem) and the fixed
           .ds-bottomnav BELOW (52px min-height + the iPhone home indicator).
           The bottom bar is position:fixed and paints OVER this panel, so
           without subtracting it the last stretch of the menu sits behind the
           bar — visible, but untappable.

           MEASURED at 390x760: bar top 701px, panel bottom 754px, and 23 links
           unreachable — Hast Rekha, Aarti & Chalisa, Ratna, the ten pandit
           vidhas, About, Margdarshan, Contact, Daan and Admin among them.

           The first measurement missed it by comparing against innerHeight
           (760) instead of the bar's top (701). A fixed overlay does not
           change the viewport, so it has to be subtracted by hand.

           `body { padding-bottom: 60px }` further down solves the same problem
           for the PAGE; it cannot help this panel, which is pinned inside the
           navbar rather than laid out in the body flow. */
        max-height: calc(100vh - 3.7rem - 60px);
        max-height: calc(100dvh - 3.7rem - 60px - env(safe-area-inset-bottom, 0px));
        overflow-y: auto;
        /* Reaching the end must not start scrolling the page underneath. */
        overscroll-behavior: contain;
        /* A little air so the last item does not sit flush on the bar. */
        padding-bottom: var(--ds-4);
    }
    .navbar-nav .dropdown-menu {
        background: rgba(0, 0, 0, .18);
        border: 0;
        box-shadow: none;
        margin: .15rem 0 .4rem .9rem;
        padding: .25rem 0;
    }
    .navbar-nav .dropdown-item { color: rgba(255, 255, 255, .85); }
    .navbar-nav .dropdown-item:hover { background: rgba(255, 255, 255, .12); color: #fff; }
    .navbar-nav .dropdown-header { color: var(--ds-gold-bright); }
    .navbar-nav .dropdown-divider { border-color: rgba(255, 255, 255, .18); }

    /* Search fills the panel width. `width: 100%` on the INPUT was wrong — the
       input is a flex child of the .input-group, so 100% pushed the submit
       button onto its own line below, where it sat as a stray orange circle.
       The BOX takes the width; the input flexes inside it. */
    .sm-nav-search { width: 100%; }
    .sm-nav-search__box { width: 100%; }
    .sm-nav-search .form-control { width: auto; flex: 1 1 auto; min-width: 0; }
}
.navbar-nav .nav-link {
    font-size: .9rem;
    font-weight: 500;
    padding: .5rem .7rem !important;
    border-radius: var(--ds-r-sm);
    color: rgba(255, 255, 255, .88);
    transition: background .15s, color .15s;
    /* A nav item must never break between its icon and its label — "Matrimonial"
       was wrapping onto a second line and pushing the bar out of alignment. */
    white-space: nowrap;
}
.navbar-nav .nav-link:hover,
.navbar-nav .nav-link:focus-visible { background: rgba(255, 255, 255, .14); color: #fff; }
.navbar-nav .nav-link.active { background: rgba(255, 255, 255, .18); color: #fff; }

.dropdown-item { font-size: .9rem; padding: .5rem .9rem; border-radius: 6px; }
.dropdown-item:hover  { background: var(--ds-saffron-soft); color: var(--ds-maroon); }
.dropdown-item.active { background: var(--ds-maroon); color: #fff; }
.dropdown-header {
    font-size: .7rem; font-weight: 700; letter-spacing: .12em;
    text-transform: uppercase; color: var(--ds-saffron);
}

.sm-footer { background: var(--ds-ink-surface); color: rgba(255, 255, 255, .78); }
.sm-footer h6 {
    color: var(--ds-gold-bright);
    font-size: .78rem; letter-spacing: .12em; text-transform: uppercase;
    margin-bottom: var(--ds-3);
}
.sm-footer a { color: rgba(255, 255, 255, .72); text-decoration: none; font-size: .9rem; }
.sm-footer a:hover { color: var(--ds-gold-bright); }
.sm-footer-bottom {
    border-top: 1px solid rgba(255, 255, 255, .1);
    font-size: .82rem;
    color: rgba(255, 255, 255, .55);
}

/* --- Footer link columns: accordion on a phone, plain column on desktop -----
   Stacked, these two columns were 270px of the mobile footer's 845px, and the
   bottom bar now carries the four links people open daily. They collapse rather
   than disappear: every link stays in the HTML, because they are internal
   linking a crawler follows.

   BUILT ON BOOTSTRAP'S COLLAPSE, NOT ON <details>, AND THAT IS DELIBERATE.
   <details> was tried first and is subtly broken here: a closed <details> lays
   its box out at summary height (35px) even when author CSS forces the list
   visible, so at desktop width the list rendered at its full 189px OUTSIDE its
   own box and overlapped the row beneath it. Measured, not theorised. Bootstrap
   is already loaded, `.collapse` is ordinary block layout with no UA magic, and
   one class more specific than `.collapse:not(.show)` reopens it for good.

   The button is styled to look exactly like the <h6> it replaced, so the
   desktop footer looks unchanged.
   -------------------------------------------------------------------------- */
.sm-foot-acc__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    width: 100%;
    background: none;
    border: 0;
    padding: var(--ds-2) 0;
    margin-bottom: var(--ds-2);
    text-align: left;
    cursor: pointer;
    /* matches the h6 these replaced */
    font-size: .78rem; font-weight: 700;
    letter-spacing: .12em; text-transform: uppercase;
    color: #fff;
}
/* Chevron, rotated by aria-expanded — the attribute Bootstrap already keeps in
   sync, so the mark can never disagree with the state. */
.sm-foot-acc__head::after {
    content: '';
    width: .5rem; height: .5rem;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    transform: rotate(45deg) translate(-2px, -2px);
    transition: transform .18s;
}
.sm-foot-acc__head[aria-expanded="true"]::after { transform: rotate(225deg) translate(-2px, -2px); }
@media (prefers-reduced-motion: reduce) { .sm-foot-acc__head::after { transition: none; } }

/* The list carries its own grid INSTEAD of Bootstrap's `d-grid gap-2` utility.
   `.d-grid` is `display: grid !important`, which beats `.collapse:not(.show)`
   (more specific, but not !important) — so with d-grid on it the accordion was
   permanently open on a phone. Same trap for any collapsible built from
   Bootstrap utilities: a `d-*` display utility silently defeats .collapse. */
.sm-foot-acc__list { display: grid; gap: var(--ds-2); }

@media (min-width: 992px) {
    .sm-foot-acc__head {
        cursor: default;
        pointer-events: none;         /* not a control once it cannot collapse */
        padding-top: 0;
    }
    .sm-foot-acc__head::after { display: none; }
    /* Beats Bootstrap's `.collapse:not(.show) { display: none }` — one class
       more specific, and !important because Bootstrap's own rule is not. */
    .sm-foot-acc__list.collapse:not(.show) { display: grid !important; }
}

/* --- Bottom navigation bar (phones only) -----------------------------------
   Five destinations within reach of a thumb: home, kundli, panchang, rashifal,
   menu. The pattern every Indian phone user already knows from WhatsApp and
   PhonePe, which is the whole argument for it — a visitor who is not confident
   with websites does not go looking for a hamburger, and the three pages worth
   opening daily were all behind one.

   IT IS TIED TO THE NAVBAR BREAKPOINT (991.98px), like the four things listed
   in base.html. Above it the link row is on screen and a second navigation
   would be one too many; below it the bar IS the navigation.

   The last item opens the same Bootstrap collapse the hamburger does, so there
   is one menu, not two — see #mainNav in base.html.
   -------------------------------------------------------------------------- */
.ds-bottomnav { display: none; }

@media (max-width: 991.98px) {
    .ds-bottomnav {
        display: grid;
        grid-template-columns: repeat(5, 1fr);
        position: fixed;
        left: 0; right: 0; bottom: 0;
        z-index: 1030;              /* over sticky content, under Bootstrap modals (1055) */
        background: var(--ds-ivory);
        border-top: 1px solid var(--ds-line);
        box-shadow: 0 -3px 14px rgba(43, 33, 24, .09);
        /* Clears the iPhone home indicator; 0 everywhere else. */
        padding-bottom: env(safe-area-inset-bottom, 0);
    }
    .ds-bottomnav__item {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 1px;
        min-height: 52px;
        padding: var(--ds-2) 2px;
        text-decoration: none;
        color: var(--ds-ink-faint);
        background: none;
        border: 0;
        font: inherit;
    }
    .ds-bottomnav__item:hover { color: var(--ds-saffron); }
    /* aria-current, not a class — the state is announced as well as drawn. */
    .ds-bottomnav__item[aria-current="page"] { color: var(--ds-saffron); }
    .ds-bottomnav__icon  { font-size: 1.15rem; line-height: 1.25; }
    .ds-bottomnav__label { font-size: .64rem; font-weight: 700; }

    /* The bar is fixed, so it sits ON the last of the page. Without this the
       footer's final row is unreachable — you scroll to the end and the bar is
       still covering it. */
    body { padding-bottom: 60px; }
}

/* ============================================================================
   7. HOME HERO
   ========================================================================== */
.sm-hero {
    /* The bright saffron is fine here — it is a decorative wash on a dark
       ground, never behind text. Text on this hero is white or gold-bright. */
    background:
        radial-gradient(1100px 420px at 78% 18%, rgba(224, 90, 0, .34), transparent 62%),
        linear-gradient(135deg, var(--ds-maroon-dark) 0%, var(--ds-maroon) 62%, #A32C1A 100%);
    color: #fff;
    padding: clamp(2.5rem, 6vw, 4.5rem) 0;
    position: relative;
    overflow: hidden;
}
.sm-hero h1 { color: #fff; text-shadow: 0 2px 12px rgba(0, 0, 0, .22); }
.sm-hero .slogan {
    display: inline-flex; align-items: center; gap: .45rem;
    font-size: .76rem; font-weight: 700;
    color: var(--ds-gold-bright);
    letter-spacing: .18em; text-transform: uppercase;
    margin-bottom: var(--ds-3);
}
.sm-hero .lede { color: rgba(255, 255, 255, .86); max-width: 52ch; font-size: 1.02rem; }
.sm-hero__art { max-width: 100%; height: auto; filter: drop-shadow(0 10px 28px rgba(0, 0, 0, .3)); }

/* The home hero, once it stopped being the page's whole table of contents.
   It held two buttons and four pills; the services grid below carries all six
   of those now, so what is left is one sentence and one action. On a phone the
   top padding is what decides whether that action is visible without scrolling
   — it was at y=388 on a 390px screen, which an iPhone SE does not show. */
.sm-hero--lean { padding: clamp(1.5rem, 4vw, 3.5rem) 0; }

/* Primary action with a sub-label. The label answers "what will it ask me for",
   which is the question the deleted "How It Works" section existed to answer.
   align-items:flex-start because a two-line label must not centre against the
   icon, and the height is left to the content. */
.sm-hero__cta { padding-block: .8rem; text-align: left; align-items: flex-start; }
.sm-hero__cta small {
    font-size: .74rem; font-weight: 400;
    opacity: .9; margin-top: .1rem;
}

/* Secondary entry points under the hero CTAs — quiet, uniform, one row. */
.sm-hero__links { display: flex; flex-wrap: wrap; gap: .5rem; }
.sm-hero__link {
    display: inline-flex; align-items: center; gap: .35rem;
    padding: .32rem .75rem;
    border-radius: var(--ds-r-pill);
    background: rgba(255, 255, 255, .1);
    border: 1px solid rgba(255, 255, 255, .22);
    color: rgba(255, 255, 255, .9);
    font-size: .82rem; font-weight: 500; text-decoration: none;
}
.sm-hero__link:hover { background: rgba(255, 255, 255, .2); color: #fff; }

/* ============================================================================
   8. LEGACY ALIASES
   ----------------------------------------------------------------------------
   Class names the old templates still use. Kept so nothing breaks mid-migration;
   delete an alias once no template references it.
   ========================================================================== */
.sm-section-title {
    font-size: clamp(1.5rem, 2.6vw, 2rem);
    font-weight: 700;
    color: var(--ds-maroon);
    position: relative;
    padding-bottom: .75rem;
}
.sm-section-title::after {
    content: ''; position: absolute; bottom: 0; left: 50%;
    transform: translateX(-50%);
    width: 52px; height: 3px; background: var(--ds-gold); border-radius: 2px;
}
.sm-page-header {
    background: linear-gradient(135deg, var(--ds-maroon-dark), var(--ds-maroon));
    color: #fff; padding: var(--ds-6) 0; margin-bottom: var(--ds-6);
}
.sm-page-header h1, .sm-page-header h2, .sm-page-header h3 { color: #fff; }
.sm-service-card {
    border: 1px solid var(--ds-line);
    border-radius: var(--ds-r);
    background: var(--ds-ivory);
    overflow: hidden; text-decoration: none; color: inherit; display: block;
    transition: transform .18s, box-shadow .18s, border-color .18s;
}
.sm-service-card:hover {
    transform: translateY(-3px);
    box-shadow: var(--ds-shadow-lg);
    border-color: var(--ds-gold);
    color: inherit;
}
.sm-service-icon { font-size: 2.6rem; display: block; margin-bottom: .75rem; }
.sm-service-card .card-body { padding: var(--ds-5); text-align: center; }
.sm-service-card h5 { color: var(--ds-maroon); font-weight: 700; }
.sm-stats { background: linear-gradient(135deg, var(--ds-maroon-dark), var(--ds-maroon)); color: #fff; padding: var(--ds-6) 0; }
.sm-stat-item h3 { font-size: 2.2rem; font-weight: 700; color: var(--ds-gold-bright); }
.sm-testimonial {
    background: var(--ds-ivory);
    border: 1px solid var(--ds-line);
    border-left: 3px solid var(--ds-gold);
    border-radius: var(--ds-r);
    padding: var(--ds-5);
    box-shadow: var(--ds-shadow-sm);
}
.btn-saffron { background: var(--ds-saffron); color: #fff; border: none; font-weight: 600; }
.btn-saffron:hover { background: var(--ds-saffron-dark); color: #fff; }
.btn-maroon  { background: var(--ds-maroon); color: #fff; border: none; font-weight: 600; }
.btn-maroon:hover { background: var(--ds-maroon-dark); color: #fff; }

/* ============================================================================
   8b. MOBILE
   ----------------------------------------------------------------------------
   Measured on the real pages at 360/390/414px, not guessed. The layout never
   overflowed horizontally — what actually hurt was thumb-sized targets, a
   72px sticky bar eating a tenth of a short screen, and the kundli result page
   running to 10,700px.
   ========================================================================== */

/* Anything a finger has to hit gets a real target. WCAG 2.5.8 asks for 24px;
   Apple and Google both say 44.
   Both conditions on purpose: `pointer: coarse` is the correct signal but is
   invisible to a desktop browser, so it cannot be tested here — the width
   clause covers phone-sized screens and IS verifiable. Desktop mouse users at
   full width keep the tighter rhythm. */
@media (max-width: 767.98px), (pointer: coarse) {
    .ds-btn,
    .btn,
    .navbar-nav .nav-link,
    .dropdown-item,
    .sm-hero__link,
    .page-link {
        min-height: 44px;
        display: inline-flex;
        align-items: center;
        justify-content: center;
    }
    .ds-btn--sm, .btn-sm { padding-inline: 1rem; }
    .dropdown-item { justify-content: flex-start; }

    /* Links sitting inside a run of text must NOT become 44px blocks —
       that would wreck the paragraph. Only standalone links are targets. */
    p a, li a, small a, .ds-lede a, td a, .text-muted a {
        min-height: 0;
        display: inline;
    }

    /* Footer links are standalone but stacked; give them room without
       turning them into buttons. */
    .sm-footer a { display: inline-block; padding-block: .35rem; }
}

@media (max-width: 575.98px) {
    /* The bar is fixed at the top of a ~660px viewport. 72px was over a tenth
       of the screen on every scroll. */
    .sm-navbar { padding-block: .35rem; }
    .sm-brand-mark { width: 38px; height: 38px; }
    .sm-brand-name { font-size: 1rem; }
    .sm-tagline { font-size: .55rem; letter-spacing: .12em; }

    /* Below ~420px the tagline is what breaks the header. Measured at 360px:
       the brand is 193px wide and the tagline is ~145px of that — wider than
       the name it sits under, because of the letter-spacing. Brand 193 +
       language 60 + hamburger 55 + margins came to exactly the 356px available,
       so the language control and the hamburger wrapped onto a second row.

       The tagline is the thing to drop. The logo and the name still say whose
       site this is; a strapline nobody reads is not worth a broken header or a
       language switch pushed below the fold. It returns at 420px. */
    @media (max-width: 419.98px) {
        .sm-tagline { display: none; }
    }

    /* 320px (iPhone SE, older Androids) missed a single row by 3px even with
       the tagline gone: brand 156 + language 60 + hamburger 55 + Bootstrap's
       1rem brand margin + 1.5rem of container padding = 319 in 316. Reclaiming
       the outer padding and the brand margin is invisible; a wrapped, 98px-tall
       header on the smallest screen there is, is not. */
    @media (max-width: 359.98px) {
        .sm-navbar__inner { padding-left: .5rem; padding-right: .5rem; }
        .sm-navbar .navbar-brand { margin-right: .25rem; }
    }

    .ds-page-header { padding: var(--ds-5) 0; }
    .ds-page-header::after { font-size: 6rem; opacity: .05; }
    .ds-page-header__glyph { font-size: 2rem; }

    /* Give long pages back some vertical budget. */
    .ds-section       { padding: 2rem 0; }
    .ds-section--lean { padding: 1.5rem 0; }
    .ds-card__body    { padding: var(--ds-4); }
    .ds-tile          { padding: var(--ds-4) var(--ds-3); }

    /* 10px captions are unreadable at arm's length. */
    .ds-text-xxs { font-size: .72rem; }
    .ds-text-xs  { font-size: .78rem; }
    .ds-eyebrow  { font-size: .7rem; }

    /* Stacked CTAs read better full width than as a ragged wrap. */
    .ds-cta .ds-btn,
    .sm-hero .ds-btn--lg { width: 100%; }

    .ds-verdict__score { font-size: 3rem; }
    .ds-daan-strip { flex-direction: column; text-align: center; }
    .ds-daan-strip .ds-btn { width: 100%; }

    /* Bootstrap's g-5 sets a 3rem gutter, so .row carries -24px margins either
       side while .container only has 12px of padding to absorb them. The 12px
       that is left over pushed About, Contact and Daan into a sideways scroll.
       Cap only the HORIZONTAL gutter — the columns are stacked at this width,
       so the 3rem vertical gutter is what keeps them apart and must survive. */
    .row.g-5,
    .row.gx-5 { --bs-gutter-x: 1.5rem; }

    /* Shrink to fit the narrowest phones with the container padding, and
       nudge the planet codes back up — at 0.66rem they were ~10px. */
    .ni-chart { width: min(300px, 100%); height: auto; aspect-ratio: 1; }
    .ni-planet { font-size: 0.7rem; }
    .ni-rashi-num { font-size: 0.55rem; }
}

/* A table that scrolls sideways needs to LOOK like it does, or a phone user
   simply never sees the right-hand columns. */
@media (max-width: 767.98px) {
    .table-responsive {
        position: relative;
        -webkit-overflow-scrolling: touch;
        scrollbar-width: thin;
    }
    .table-responsive::after {
        content: '';
        position: absolute;
        top: 0; right: 0; bottom: 0;
        width: 26px;
        pointer-events: none;
        background: linear-gradient(to right, transparent, rgba(43, 33, 24, .10));
    }
    .table-responsive > .table { margin-bottom: 0; }
}

/* ============================================================================
   9. PRINT — kundli reports get printed a lot
   ========================================================================== */
@media print {
    .sm-navbar, .sm-footer, .ds-no-print, .btn, .ds-btn { display: none !important; }
    /* The panchang ribbon is today's date, not the client's chart — it has no
       business on a printed kundli. */
    .ds-panchang-bar { display: none !important; }
    /* The bottom bar MUST be hidden here explicitly, and the reason is a trap:
       it is shown by `@media (max-width: 991.98px)`, and A4 is about 794 CSS px
       wide — so paper matches that query and the bar would print. Worse, it is
       `position: fixed`, which Chrome lays out ONCE against the whole document
       (see the letterhead notes in CLAUDE.md), so it would land in the middle of
       a page of somebody's kundli. Same for the padding that clears it. */
    .ds-bottomnav { display: none !important; }
    body { background: #fff; padding-bottom: 0 !important; }

    /* Phaladesh prose on the letterhead report. Kept whole per section so a
       heading never sits alone at the foot of a page with its paragraph
       overleaf — the same rule the chart columns follow. Tighter than on
       screen: on paper, whitespace is extra sheets. */
    .ds-print__phal { break-inside: avoid; margin-bottom: 3mm; }
    .ds-print__phal-t { font-size: 10pt; font-weight: 700; color: #7A1122; margin: 0 0 .5mm; }
    .ds-print__phal-f { font-size: 7pt; color: #6B5D4F; margin: 0 0 1mm; }
    .ds-print__phal-x { font-size: 8.5pt; line-height: 1.5; margin: 0; }
    .ds-card, .card { break-inside: avoid; box-shadow: none; border-color: #ccc; }
    .ds-page-header { background: #fff !important; color: #000 !important; padding: 0 0 1rem; }
    .ds-page-header h1, .ds-page-header p { color: #000 !important; }
    .ds-page-header::after { display: none; }
}

/* ── Pandit's printable kundli report (templates/pandits/kundli_print.html) ──
   Styled for paper first and screen second, which is the opposite of every
   other block in this file. It has to survive being handed to a client, so the
   rules that matter are the page ones: margins, where it may break, and the
   letterhead repeating.

   Printing goes through the BROWSER's own dialog (Save as PDF) — no PDF
   library. See the note in pandits.views.pandit_kundli_print. */
/* Room for the running header, footer and the frame that sit outside the text.
   Top/bottom carry a header and a footer, so they are deeper than the sides. */
@page { margin: 22mm 16mm 20mm; }

/* ── The printed sheet: frame + running header/footer + watermark ──
   `.ds-sheet` is a ONE-CELL TABLE wrapping the whole report, and the structure
   is load-bearing. `position: fixed` was tried first — it is what most advice
   suggests and it does NOT work: Chrome lays a fixed element out once against
   the whole document rather than per page, so the frame printed off the paper
   and the watermark landed near the foot of page 1. Confirmed against a real
   headless-Chrome PDF, not from the screen.

   A table is the one thing Chrome repeats per printed page:
     thead  -> top border + running header, on every page
     tfoot  -> bottom border + running footer, on every page
     td     -> Chrome paints the cell's LEFT and RIGHT borders on every page
               fragment, which closes the box

   On screen the table is a plain full-width block with no borders, so the page
   looks exactly as it did. */
.ds-sheet { width: 100%; border-collapse: collapse; }
.ds-sheet__head, .ds-sheet__foot { display: none; }
.ds-sheet__body { padding: 0; }

@media print {
    .ds-sheet__head, .ds-sheet__foot { display: table-cell; }

    /* Chrome drops backgrounds — and the watermark IS a background — unless
       "Background graphics" is ticked. This forces them regardless, which the
       report's identity should not depend on. */
    .ds-sheet, .ds-sheet__head, .ds-sheet__foot, .ds-sheet__body {
        -webkit-print-color-adjust: exact;
        print-color-adjust: exact;
    }

    /* The double rule: maroon outside, gold inside. thead/tfoot carry the
       horizontal edges, the body cell the verticals. */
    /* Flex, not floats: the header is brand | mantra | jatak and the mantra has
       to sit in the true centre regardless of how long the other two are. A
       float-right jatak block cannot do that. The watermark img inside is
       absolutely positioned, so it stays out of the flex flow. */
    .ds-sheet__head {
        border: 2pt solid var(--ds-maroon);
        border-bottom: 0.8pt solid var(--ds-gold);
        padding: 1.5mm 3mm;
        font-size: 7.5pt;
        font-weight: 400;
        color: var(--ds-ink-muted);
        text-align: left;
        display: flex;
        align-items: center;
        gap: 2mm;
    }
    .ds-sheet__mantra {
        flex: 1 1 auto;
        text-align: center;
        color: var(--ds-gold-text);
        font-weight: 700;
        letter-spacing: .04em;
    }
    .ds-sheet__head .ds-sheet__right { flex: 0 0 auto; float: none; }
    /* Flex, like the header. On floats the swastik ended up wedged against the
       domain ("卐www.divyasanyog.com") because the first right-floated element
       takes the rightmost slot, and that was the domain. */
    .ds-sheet__foot {
        border: 2pt solid var(--ds-maroon);
        border-top: 0.8pt solid var(--ds-gold);
        padding: 1.5mm 3mm;
        font-size: 7.5pt;
        color: var(--ds-ink-muted);
        display: flex;
        align-items: center;
        gap: 2mm;
    }
    .ds-sheet__foot .ds-sheet__right { flex: 1 1 auto; text-align: right; float: none; }
    .ds-sheet__body {
        border-left: 2pt solid var(--ds-maroon);
        border-right: 2pt solid var(--ds-maroon);
        padding: 3mm 4mm;
    }

    /* ── Watermark ──
       Inside <thead>, absolutely positioned relative to the header cell. thead
       repeats on every printed page, so the image repeats with it and the
       offset drops it into the middle of each page.

       Two approaches were tried and printed nothing at all: a background on
       the body cell (Chrome does not repaint a cell background on later page
       fragments) and `position: fixed` (laid out once against the whole
       document). Only this one survives a real PDF.

       The file is logo.png with its alpha baked down — a printed image cannot
       be faded by `opacity` reliably across engines, and a background could not
       be faded at all. Regenerate it if the logo changes; recipe in CLAUDE.md. */
    .ds-sheet__head { position: relative; }
    .ds-sheet__mark {
        position: absolute;
        left: 50%;
        top: 55mm;
        transform: translateX(-50%);
        width: 88mm;
        height: auto;
        z-index: 0;
    }
    .ds-sheet__brand { color: var(--ds-maroon); font-weight: 700; }
    .ds-sheet__right { float: right; }
    /* Holds either the ॐ character or the swastik SVG — inline-flex so the
       drawn path sits on the same line as the text beside it. */
    .ds-sheet__om {
        font-family: 'Noto Serif Devanagari', serif;
        color: var(--ds-gold-text);
        font-size: 9pt;
        display: inline-flex;
        align-items: center;
        flex: 0 0 auto;
    }
    .ds-sheet__om svg { display: block; }

    /* The report sits over the watermark, on its own opaque-free layer. */
    .ds-print { position: relative; }
}

.ds-letterhead {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: var(--ds-4);
    padding-bottom: .4rem;
    border-bottom: 2px solid var(--ds-gold);
    margin-bottom: .5rem;
}
.ds-letterhead__brand { display: flex; align-items: center; gap: .6rem; }
.ds-letterhead__name {
    font-weight: 700; font-size: 1.15rem; line-height: 1.15;
    color: var(--ds-maroon);
}
.ds-letterhead__tag {
    font-size: .62rem; letter-spacing: .11em; text-transform: uppercase;
    color: var(--ds-gold-text);
}
.ds-letterhead__meta { font-size: .68rem; color: var(--ds-ink-muted); line-height: 1.5; }
.ds-letterhead__pandit {
    text-align: right;
    border-left: 1px solid var(--ds-line);
    padding-left: var(--ds-3);
    /* Wide enough that "Demo Pandit Ji · DS-UJ8GRN93" stays on ONE line — the
       code broke across two at 170px, and a code split mid-string is the one
       thing on this page a client may have to read back over the phone. */
    flex: 0 0 62mm;
    font-size: .76rem;
    line-height: 1.45;
}
.ds-letterhead__brand { min-width: 0; }
.ds-letterhead__label {
    text-transform: uppercase; letter-spacing: .1em;
    font-size: .6rem;
    color: var(--ds-gold-text);
}

/* Title centred between ॐ and the swastik, with a gold rule running out to
   both margins so the three read as one band rather than three loose things. */
.ds-print__title {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--ds-3);
    font-size: 1.4rem; font-weight: 700; color: var(--ds-maroon);
    margin: .2rem 0 var(--ds-2);
    text-align: center;
}
.ds-print__title::before,
.ds-print__title::after {
    content: "";
    flex: 1 1 auto;
    height: 1px;
    background: var(--ds-gold);
    opacity: .55;
}
.ds-print__title-text { flex: 0 0 auto; }
.ds-print__mark {
    flex: 0 0 auto;
    color: var(--ds-gold-text);
    font-size: 1.15rem;
    line-height: 1;
    display: inline-flex;
    align-items: center;
}
.ds-print__mark svg { display: block; }
.ds-print__h2 {
    font-size: 1rem; font-weight: 700; color: var(--ds-maroon);
    margin: var(--ds-3) 0 .35rem;
    padding-bottom: .15rem;
    border-bottom: 1px solid var(--ds-gold);
}
/* ── Label / value grids ──
   Every cell is itself a two-column grid with a FIXED label column, so the
   values line up down the page. Before this the label and value simply sat
   next to each other, so "Name", "Birth place" and "Age" each pushed their
   value to a different x — three columns of data that never lined up, which
   is what made the report look scattered. */
.ds-print__summary,
.ds-print__grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(175px, 1fr));
    gap: .22rem var(--ds-4);
    font-size: .82rem;
}
.ds-print__summary > div,
.ds-print__grid > div {
    display: grid;
    grid-template-columns: 24mm 1fr;
    align-items: baseline;
    column-gap: .3rem;
}
/* The summary has only four items and the longest label is "Chandra rashi",
   which wrapped in a 3-across layout. Two columns, wider label track. */
.ds-print__summary { grid-template-columns: repeat(2, 1fr); }
.ds-print__summary > div { grid-template-columns: 28mm 1fr; }
.ds-print__summary {
    background: var(--ds-sand);
    border-radius: var(--ds-r-sm);
    padding: .4rem var(--ds-3);
    margin-top: .35rem;
}
/* The dosha grid is prose, not label/value — keep it a single column. */
.ds-print__doshas > div { display: block; }
/* Wider label track for the Varshfal sheet. Its labels are longer than the
   kundli report's — "Janam Lagna" and "Varsh Lagna" both wrapped onto two lines
   in the 24mm track, which dragged the neighbouring cell down with them. A
   modifier, not a change to the shared track: the kundli report's labels fit
   24mm and widening it there would only cost space. */
.ds-print__grid--wide > div { grid-template-columns: 30mm 1fr; }
.ds-print__k { color: var(--ds-ink-muted); }
.ds-print__table { font-size: .78rem; margin-bottom: .5rem; }
.ds-print__table td, .ds-print__table th { padding: .22rem .4rem; }
/* The period the jatak is actually in — the one row anyone looks for first. */
.ds-print__row--now { background: var(--ds-gold-soft) !important; font-weight: 600; }
.ds-print__doshas { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: .4rem var(--ds-3); }
.ds-print__dosha {
    font-size: .82rem;
    border-left: 3px solid var(--ds-gold);
    padding-left: .5rem;
}
.ds-print__list { font-size: .8rem; margin: 0; padding-left: 1.1rem; }
.ds-print__list li { margin-bottom: .15rem; }
/* A caveat under a section — which reckoning was used, where a number is not
   settled. Small, but it must still be READABLE on paper: a caveat printed too
   faint to notice is worse than none, because the sheet then reads as certain.
   Hence --ds-ink-muted rather than a lighter grey, and a rule to tie it to the
   section above it. */
.ds-print__note {
    font-size: .72rem;
    color: var(--ds-ink-muted);
    margin: .15rem 0 .5rem;
    padding-left: .5rem;
    border-left: 2px solid var(--ds-gold-soft);
}
.ds-print__foot {
    margin-top: var(--ds-3);
    padding-top: var(--ds-2);
    border-top: 1px solid var(--ds-gold);
    font-size: .7rem;
    color: var(--ds-ink-muted);
    display: flex;
    justify-content: space-between;
    gap: var(--ds-3);
    flex-wrap: wrap;
}

@media print {
    .ds-print,
    .ds-print .container { padding: 0 !important; }

    /* ── The gap problem ──
       Section 9's blanket `.ds-card, .card { break-inside: avoid }` is right for
       a short card and wrong for a tall one: the Grah/Bhav Spasht card is over
       half a page, so whenever it did not fit in what was left it jumped to the
       next sheet and left the rest of the current one blank. Same for the chart
       rows. Tall blocks must be ALLOWED to break; only the small units that
       look broken when split — one chart, one table row, one grid — are kept
       whole. */
    .ds-print .ds-card,
    .ds-print .card,
    .ds-print .row,
    .ds-print .table-responsive { break-inside: auto !important; }
    .ds-print__table tr, .ds-print__dosha,
    .ds-print__summary, .ds-print__foot { break-inside: avoid; }
    /* A heading alone at the foot of a page reads as a mistake. */
    .ds-print__h2 { break-after: avoid; break-inside: avoid; }
    .ds-letterhead { break-after: avoid; }

    /* ── Chart rows: FLOATS on paper, not flex and not inline-block ──
       Three layouts were printed and measured before this one:

       flex (Bootstrap's own .row)  — a flex container does not fragment at all.
         The whole row jumped to the next sheet while the labels, being separate
         elements, stayed behind: "नवांश (D9)  भाव चलित" at the foot of one page,
         half a page of nothing, the diamonds overleaf.

       inline-block                 — fragments in normal flow, but each row is
         one LINE BOX, and a line box inside the fragmenting table cell could
         not be placed in the space left on page 1. Result: the charts skipped
         to page 2 and page 1 was half empty. This is the one that survived
         review because it looks right on screen.

       float                        — fragments correctly INSIDE the table cell.
         Charts now start immediately under the summary on page 1.

       Each column keeps break-inside: avoid so a label is never split from its
       diamond. */
    .ds-print__charts { display: block !important; }
    .ds-print__charts::after { content: ""; display: block; clear: both; }
    .ds-print__charts > [class*="col-"] {
        display: block !important;
        float: left !important;
        width: 49% !important;
        break-inside: avoid;
        page-break-inside: avoid;   /* older engines still read this one */
    }
    /* ALL chart rows are two across, vargas included.

       The vargas were three across to save paper and it does not work: at 60mm
       a diamond cannot hold a crowded house. Hora (D2) puts every graha into
       Cancer or Leo by definition — seven in one house — and they printed
       clean outside the square; D4 and D10 lost letters off the right edge;
       "Chaturthamsa (D4)" and "Dwadashamsa (D12)" wrapped and left the row
       standing at three different heights.

       Shrinking the text was tried twice and only made it smaller AND still
       overflowing. Two across gives every chart the same 250px as D1, so there
       is one size to reason about and nothing spills. It costs about one extra
       sheet, which is the right trade for a report a client keeps. */

    /* ── Chart size is what decides the page count ──
       MEASURED on A4 (usable 186 x 269mm): the header, jatak block, summary and
       the "Charts" heading take 339px of a 1012px page. At its natural size a
       chart column is 380px, so the first row fitted and the second did not —
       261px, about 69mm, left blank at the foot of page one, every time.

       Capping the diamond at 250px makes a column ~300px: 339 + 300 + 300 = 939,
       and both rows land on the page. The diamond stays perfectly legible — it
       is 250px of print, roughly 66mm, larger than most published kundlis.
       Re-measure if the letterhead or the jatak block ever grows. */
    /* WIDTH AND HEIGHT BOTH. `.ni-chart` is a fixed 340x340 square, so capping
       only max-width gave a 250x340 rectangle — a squashed diamond that was no
       shorter than before. The houses are positioned in %, so the square just
       scales. */
    /* 230px, not 250. MEASURED: page 1 has ~700px left under the letterhead,
       jatak block and summary. At 250px a chart PAIR is ~290px tall, so two
       pairs came to 580px — which fits on paper but not once each pair is
       `break-inside: avoid` and needs its full height in one go; the second
       pair fell to page 2 and left a quarter-page blank. At 230px the pair is
       ~270px and both land. The diamond is still ~61mm, larger than most
       published kundlis. */
    .ds-print__charts .ni-chart {
        width: 230px !important; height: 230px !important;
        margin-left: auto; margin-right: auto;
    }
    

    /* ── The graha text has to shrink WITH the diamond ──
       `.ni-house` is 24% wide and `.ni-planet` a fixed .72rem, both sized for
       the 340px screen chart. Shrink only the box and the text stays put: in
       the varga row the grahas spilled clean outside the square — worst in
       Hora (D2), where every graha lands in Cancer or Leo by definition, so one
       house holds seven of them and wrapped to four lines. D4 and D10 lost
       letters off the right edge.

       So the font scales with the chart and the house box widens to fit more
       per line. */
    .ds-print__charts .ni-planet { font-size: .52rem; line-height: 1.1; }
    .ds-print__charts .ni-planet sup { font-size: .36rem; }
    .ds-print__charts .ni-rashi-num { font-size: .42rem; margin-bottom: 0; }
    /* NOT wider than the screen's 24%. Widening it to fit more per line pushed
       the edge houses (3, 4, 9, 10) past the diamond's own border — the graha
       codes printed on top of the frame line. */
    .ds-print__charts .ni-planets { gap: 0 3px; }

    .ds-print__charts .ds-card__header h5 { font-size: .85rem; }

    /* Floats of unequal height stagger, so every second chart starts a fresh
       row and each pair lines up on its own baseline. */
    .ds-print__charts > [class*="col-"]:nth-child(2n+1) { clear: left; }

    /* The blurb ("Wealth & resources") is a screen affordance; on paper the
       label already says which varga it is. */
    .ds-print__charts--small .ds-card__header small { display: none !important; }

    /* Card chrome is whitespace on paper. The charts and the spasht tables come
       from shared partials that wrap themselves in .ds-card for the screen. */
    .ds-print .ds-card,
    .ds-print .card {
        border: 0 !important;
        box-shadow: none !important;
        margin-bottom: .4rem !important;
        /* `.ds-card` is `overflow: hidden` for its rounded corners. On screen
           the header's padding keeps the text away from that edge; print
           strips the padding, so the title sat flush at x=0 and the clip
           sliced the first letter off every chart — "Navamsa" printed as
           "avamsa", "Bhava Chalit" as "hava Chalit". It also cut the graha
           codes in the left-hand houses, which legitimately overhang the
           diamond. Nothing here needs clipping. */
        overflow: visible !important;
    }
    .ds-print .ds-card__header,
    .ds-print .card-header { padding: .1rem 0 .1rem 2px !important; background: none !important; }
    .ds-print .card-body { padding: .2rem 0 !important; }
    .ds-print .ni-chart { margin-bottom: 0; }

    /* A scroll box on paper is a truncated table. */
    .table-responsive { overflow: visible !important; }
    .ds-print { font-size: .8rem; }
}

/* ── Cookie consent bar ───────────────────────────────────────────────────
   Same corner and same shape as the install bar below, one step higher in the
   stack (1085 vs 1080), because on a first visit both want that corner and
   this one has to be answered first. .ds-consent-open on <body> holds the
   install bar back until then rather than letting them overlap.

   Cream on maroon here, where the install bar is the reverse: this is the
   quieter of the two, and a second identical maroon slab reads as one broken
   element when they follow each other. */
.ds-consent {
    position: fixed;
    left: .75rem; right: .75rem;
    bottom: calc(.75rem + env(safe-area-inset-bottom, 0px));
    z-index: 1085;

    display: flex;
    align-items: center;
    gap: 1rem;

    padding: .8rem 1rem;
    border-radius: 14px;
    border: 1px solid var(--ds-gold);
    background: var(--ds-cream);
    color: var(--ds-maroon);
    box-shadow: 0 10px 30px rgba(0, 0, 0, .28);

    transform: translateY(140%);
    opacity: 0;
    transition: transform .25s ease, opacity .25s ease;
}
.ds-consent.is-in { transform: translateY(0); opacity: 1; }

.ds-consent__text {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    line-height: 1.35;
}
.ds-consent__text b { font-size: .95rem; font-weight: 600; }

.ds-consent__sub {
    font-size: .82rem;
    color: #5a3a3a;                 /* 7.1:1 on the cream */
}
.ds-consent__sub a { color: var(--ds-maroon); text-decoration: underline; }

.ds-consent__actions {
    flex: 0 0 auto;
    display: flex;
    gap: .5rem;
}

/* Decline and Accept are deliberately the same size and weight. A reject that
   is smaller, greyer or further away than the accept is not a real choice. */
.ds-consent__btn {
    border: 1px solid var(--ds-maroon);
    border-radius: 999px;
    padding: .45rem 1.1rem;
    font-size: .9rem;
    font-weight: 600;
    background: transparent;
    color: var(--ds-maroon);
    cursor: pointer;
}
.ds-consent__btn:hover { background: rgba(139, 0, 0, .08); }

.ds-consent__btn--yes {
    background: var(--ds-maroon);
    color: #fff;
}
.ds-consent__btn--yes:hover { background: #6d0000; }

/* Below ~575px the two buttons need the full width, or the text column
   squeezes them to a couple of characters each. */
@media (max-width: 575.98px) {
    .ds-consent { flex-direction: column; align-items: stretch; gap: .7rem; }
    .ds-consent__actions { justify-content: stretch; }
    .ds-consent__btn { flex: 1 1 0; }
}

/* One at a time: the install bar waits for the cookie question to be answered. */
body.ds-consent-open .ds-install { display: none !important; }

@media print { .ds-consent { display: none !important; } }

/* ── "Install app" bar ────────────────────────────────────────────────────
   Bottom bar, shown once, dismissible. Deliberately NOT in the navbar: the
   navbar has already been reworked twice for overflow, and installing is a
   one-time act — a permanent button for it is permanent clutter.

   Sits above everything (z-index 1080) because Bootstrap's sticky navbar is
   1030 and its modals are 1055; the bar must not slide under either. It is
   also kept clear of the iOS home indicator with safe-area-inset. */
.ds-install {
    position: fixed;
    left: .75rem; right: .75rem;
    bottom: calc(.75rem + env(safe-area-inset-bottom, 0px));
    z-index: 1080;

    display: flex;
    align-items: center;
    gap: .75rem;

    padding: .7rem .85rem;
    border-radius: 14px;
    border: 1px solid var(--ds-gold);
    background: var(--ds-maroon);
    color: #fff;
    box-shadow: 0 10px 30px rgba(0, 0, 0, .28);

    /* Starts pushed down and clear; .is-in slides it up. `hidden` on the
       element still wins over all of this, so nothing flashes before JS
       decides whether to show it. */
    transform: translateY(140%);
    opacity: 0;
    transition: transform .25s ease, opacity .25s ease;
}
.ds-install.is-in { transform: translateY(0); opacity: 1; }

.ds-install__icon {
    flex: 0 0 auto;
    width: 44px; height: 44px;
    border-radius: 10px;
    background: var(--ds-cream);
}

.ds-install__text {
    flex: 1 1 auto;
    min-width: 0;               /* lets the text ellipsis instead of pushing
                                   the buttons off a narrow phone */
    display: flex;
    flex-direction: column;
    line-height: 1.3;
}
.ds-install__text b { font-size: .95rem; font-weight: 600; }

.ds-install__sub {
    font-size: .8rem;
    color: var(--ds-gold-bright);   /* 7.75:1 on maroon */
}

.ds-install__go {
    flex: 0 0 auto;
    border: 0;
    border-radius: 999px;
    padding: .45rem 1.1rem;
    font-size: .9rem;
    font-weight: 600;
    background: var(--ds-gold-bright);
    color: var(--ds-maroon);        /* inverse of the navbar pair */
    cursor: pointer;
}
.ds-install__go:hover { background: #fff; }

.ds-install__x {
    flex: 0 0 auto;
    border: 0;
    background: transparent;
    color: rgba(255, 255, 255, .75);
    font-size: .9rem;
    line-height: 1;
    padding: .35rem;
    cursor: pointer;
}
.ds-install__x:hover { color: #fff; }

/* On a phone the sub-line is what gets cut first, so it wraps rather than
   truncating — the iOS instructions ("tap Share, then Add to Home Screen")
   are useless half-shown. */
@media (max-width: 575.98px) {
    .ds-install { gap: .6rem; padding: .65rem .7rem; }
    .ds-install__text b { font-size: .9rem; }
    .ds-install__sub { font-size: .75rem; }
    .ds-install__go { padding: .4rem .85rem; font-size: .85rem; }
}

/* Never on paper. */
@media print { .ds-install { display: none !important; } }

/* iOS variant of the install bar.
   Apple allows no install button, so this bar is pure instruction — and an
   owner testing on an iPhone read it, looked at the toolbar, and found nothing
   to press. The arrow gives the words somewhere to point: it sits where the
   Install button would have been and nods towards Safari's bottom toolbar. */
.ds-install--ios::after {
    content: "\2193";              /* ↓ */
    order: 2;                      /* between the text and the × */
    flex: 0 0 auto;
    font-size: 1.5rem;
    line-height: 1;
    color: var(--ds-gold-bright);
    animation: ds-install-nudge 1.4s ease-in-out infinite;
}
.ds-install--ios .ds-install__x { order: 3; }

@keyframes ds-install-nudge {
    0%, 100% { transform: translateY(0);   opacity: .7; }
    50%      { transform: translateY(5px); opacity: 1;  }
}

/* A looping animation is a real problem for some vestibular conditions, and
   this one would run for as long as the bar is on screen. */
@media (prefers-reduced-motion: reduce) {
    .ds-install--ios::after { animation: none; }
}

/* ── Panchak on the month grid ────────────────────────────────────────────
   A whole-cell tint, not a badge. Panchak runs five days, and five separate
   badges read as five unrelated notes instead of one block — which is the
   thing someone picking a date actually needs to see.

   Kept very pale: this sits behind tithi and festival text that must stay
   readable, and the day's own colour still has to show through. */
/* Set through Bootstrap's own variable, NOT background-color. Bootstrap 5.3
   paints every table cell with `box-shadow: inset 0 0 0 9999px …`, which lands
   ON TOP of the cell's background — so a plain `background:` here is drawn and
   then covered, and the cell comes out exactly the same colour as its
   neighbours. Measured, not guessed: both tinted and untinted cells reported
   rgb(251,247,241) until this changed. */
.ds-cal--warn { --bs-table-bg-state: rgba(220, 53, 69, .09); }
.ds-cal--good { --bs-table-bg-state: rgba(25, 135, 84, .09); }

/* ── Month calendar, phone shape  (templates/pages/panchang_month.html) ────
   Below 768px the month used to be a plain list only. A list answers "what is
   on the 14th" and never "is the 14th a Sunday" — which is most of why anyone
   opens a calendar. This puts the shape back.

   It does NOT put the desktop cells back: seven columns of tithi, gate, panchak
   and festival names is unreadable at ~51px a column, which is why they were
   dropped in the first place. A cell here carries the date, the gate number,
   and a dot when something is on that day. Tapping it jumps to that day's full
   entry in the list below, which still holds every detail.

   grid, not a table: seven equal columns with no table-layout arithmetic, and
   the empty leading/trailing days are just empty cells. */
.ds-mcal { padding: .5rem; }

.ds-mcal__head,
.ds-mcal__grid {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 3px;
}

.ds-mcal__head {
    margin-bottom: 3px;
    font-size: .62rem;
    font-weight: 600;
    letter-spacing: .02em;
    text-transform: uppercase;
    color: var(--ds-ink-muted);
    text-align: center;
}

.ds-mcal__cell {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1px;

    min-height: 44px;                /* a real tap target, and square-ish at 51px wide */
    padding: .2rem 0;
    border: 1px solid var(--ds-line);
    border-radius: var(--ds-r-sm);
    background: var(--ds-ivory);
    color: var(--ds-ink);
    text-decoration: none;
}
.ds-mcal__cell b { font-size: .88rem; font-weight: 600; line-height: 1; }
/* The gate number. <i> is the tag, not italics — the whole site uses gate
   numbers upright. */
.ds-mcal__cell i {
    font-style: normal;
    font-size: .6rem;
    line-height: 1;
    color: var(--ds-ink-muted);
}

/* A festival is the one thing worth marking at this size, and a dot is all
   that fits. It is a hint to tap, not the information itself — the name is in
   the list, three lines further down the page. */
.ds-mcal__dot {
    width: 5px; height: 5px;
    border-radius: 50%;
    background: var(--ds-maroon);
}

/* Same two tints as the desktop grid, same rgba values, so a panchak block
   reads identically on both. Plain `background` works here because these are
   not Bootstrap table cells — that is the whole reason .ds-cal--warn/good had
   to go through --bs-table-bg-state instead. */
.ds-mcal__cell--warn { background: rgba(220, 53, 69, .09); }
.ds-mcal__cell--good { background: rgba(25, 135, 84, .09); }

.ds-mcal__cell--today {
    border-color: var(--ds-maroon);
    box-shadow: inset 0 0 0 1px var(--ds-maroon);
}
.ds-mcal__cell--today b { color: var(--ds-maroon); }

.ds-mcal__cell--empty {
    border-color: transparent;
    background: transparent;
}

/* The jump target sits under a sticky navbar (59px) and the panchang ribbon
   (46px). Without this the row you tapped lands underneath both of them. */
.ds-mcal-target { scroll-margin-top: 118px; }

/* ── Aarti / Chalisa / Stotra  (templates/paath/) ─────────────────────────
   A page whose whole job is to be READ ALOUD, often from a phone held in one
   hand at a mandir. That drives every value here:

   white-space: pre-line, not <br> or a <p> per line. Where a line ends is part
   of the metre — the reader is chanting it — so the text renders exactly as it
   was typed and nothing reflows it.

   Bigger and looser than body copy: 1.12rem with 2.05 line-height. Devanagari
   carries matras above and below the line, and at body size and body leading
   they collide and a chaupai becomes hard to track. This is the one place on
   the site where reading comfort beats density.

   Centred, because an aarti is centred everywhere it has ever been printed. */
.ds-paath__verse {
    white-space: pre-line;
    font-family: var(--ds-font-deva);
    font-size: 1.12rem;
    line-height: 2.05;
    text-align: center;
    color: var(--ds-ink);
}

/* A gap between verses, and a hairline that says "new verse" without drawing a
   box around each one. Not on the last, or the page ends on a rule. */
.ds-paath .ds-paath__verse + .ds-paath__verse {
    margin-top: 1.4rem;
    padding-top: 1.4rem;
    border-top: 1px solid var(--ds-line);
}

/* ॥ दोहा ॥ / ॥ चौपाई ॥ — a section label, not a line of the poem. Smaller than
   the verses and in the gold, so the eye reads it as a signpost and skips over
   it while chanting. It also breaks the + adjacency above, which is what stops
   the first couplet of a section starting with a stray rule. */
.ds-paath__head {
    margin: 2.2rem 0 1.2rem;
    text-align: center;
    font-size: .95rem;
    font-weight: 600;
    letter-spacing: .06em;
    color: var(--ds-gold);
}
.ds-paath > .ds-paath__head:first-child { margin-top: 0; }

.ds-paath__roman summary {
    cursor: pointer;
    font-weight: 600;
    font-size: .9rem;
    color: var(--ds-maroon);
}
.ds-paath__roman .ds-paath__verse {
    font-family: 'Poppins', sans-serif;   /* Roman text, not the Devanagari face */
    font-size: 1rem;
    line-height: 1.9;
    color: var(--ds-ink-muted);
}

/* On a phone the verse should still breathe, but 1.12rem centred starts to
   wrap awkwardly on a 320px screen. */
@media (max-width: 575.98px) {
    .ds-paath__verse { font-size: 1.05rem; line-height: 1.95; }
    .ds-paath .ds-paath__verse + .ds-paath__verse { margin-top: 1.1rem; padding-top: 1.1rem; }
}

/* Printing an aarti out for a pooja is a real thing people do. */
@media print {
    .ds-paath__verse { font-size: 12pt; line-height: 1.9; color: #000; }
    .ds-paath__roman { display: none; }
}

/* ── Birth date / time selects  (includes/_dob_fields.html) ───────────────
   Three dropdowns in a row, and on a phone they must stay in a row: stacked,
   the birth date alone would be three full-width controls and push everything
   below it off the first screen.

   grid rather than flex, with the middle column wider — the month is a name
   ("सितम्बर") while the day and year are numbers, so equal thirds would clip it
   while wasting space either side. */
.ds-dob {
    display: grid;
    /* The middle column carries a month NAME while the outer two carry two and
       four digits, so the thirds are deliberately uneven. 1.8, not 1.4: at
       320px "September" needs 86px and 1.4 gave it 60. The month is the one
       thing here that must never be clipped — a half-read month is the one
       mistake in a birth date nobody notices. */
    grid-template-columns: 1fr 1.8fr 1fr;
    gap: .4rem;
}

/* The time row needs different proportions again: "Minute" is a word where the
   date row has two digits, and the last box holds "AM/PM" until something is
   chosen. Measured at 320px, where the whole group is only 233px wide. */
.ds-dob--time { grid-template-columns: 1fr 1.3fr 1.25fr; }
.ds-dob .form-select {
    /* 16px, deliberately. iOS Safari zooms the whole page in on focus when a
       control's text is under 16px, and the page never zooms back out. */
    font-size: 1rem;

    /* The two paddings are set SEPARATELY, and that is the whole point.
       `padding-inline: .5rem` was the first attempt and it drew the chevron
       straight through the text — "Day" rendered as "Da⌄" on a laptop.
       Bootstrap's .form-select paints the arrow as a background image and
       reserves room for it with padding-right: 2.25rem, so collapsing both
       sides to one value takes that reservation away.

       2.25rem is more than there is to spare here — at 320px the day box is
       66px wide — so the arrow is moved in and shrunk to match, and the right
       padding clears it with a few pixels over. */
    padding-left: .5rem;
    padding-right: 1rem;
    background-position: right .25rem center;
    background-size: 9px 7px;
}

/* Below 360px the three simply do not fit side by side. Measured: the group is
   233px wide there, and three arrow gutters alone take 48px of it — "September"
   needs 89px and has 79.

   So they stack, rather than clipping the month. A half-read month is the one
   mistake in a birth date nobody catches, and this is a form for people who
   find date pickers hard in the first place. It costs about 86px of height on
   the narrowest phones and nothing on any other. */
@media (max-width: 359.98px) {
    .ds-dob,
    .ds-dob--time { grid-template-columns: 1fr; }
}

/* ── Blog prose  (templates/blog/detail.html) ─────────────────────────────
   The rendered body of a lekh. Only element selectors, scoped to .ds-prose,
   because blog/render.py emits bare <p>/<h2>/<ul>/<ol> — there is no class to
   hang anything on and adding one per tag would put the styling decisions in
   a Python file.

   Measure before decoration. This is long-form Devanagari read on a phone:
   line-height 1.85 rather than the site's 1.6, because Devanagari carries
   matras above and below the line and 1.6 makes consecutive rows touch. The
   65ch cap is the readability rule that matters most and the one a full-width
   container silently breaks on a laptop. */
.ds-prose { max-width: 65ch; }
.ds-prose p { line-height: 1.85; margin-bottom: var(--ds-4); }
.ds-prose ul,
.ds-prose ol { line-height: 1.85; margin-bottom: var(--ds-4); padding-left: var(--ds-5); }
.ds-prose li { margin-bottom: var(--ds-2); }

/* Headings inside prose sit closer to the text they introduce than to the
   paragraph above — otherwise a heading reads as belonging to the section it
   just ended. Asymmetric margins, not a single value. */
.ds-prose h2,
.ds-prose h3 { margin-top: var(--ds-6); margin-bottom: var(--ds-3); }
.ds-prose > h2:first-child,
.ds-prose > h3:first-child { margin-top: 0; }

/* A gold rule under each h2, which is what the rest of the site uses to say
   "new section" — same device as .ds-rule, at the weight a heading can carry. */
.ds-prose h2 { padding-bottom: var(--ds-2); border-bottom: 1px solid var(--ds-line); }

/* Links inside an article are underlined, unlike the rest of the site.
   In a wall of prose, colour alone is not a reliable signal — and these links
   are the whole point of the section, the path from the article to the tool
   that answers it. */
.ds-prose a { text-decoration: underline; text-underline-offset: 2px; }

/* ── "Other cities in this state"  (templates/pages/panchang.html) ────────
   Six or seven neighbours on a city page, a dozen popular ones on /panchang/.

   This replaced a directory of all 132 cities, tried first as a flat row of
   pills and then as columns behind a disclosure. Both were a screenful of
   links under a panchang, and neither was how anybody picks a city — they type
   it in the box at the top of the page.

   What survives is the crawl path: a datalist <option> is not a link and no
   crawler follows one, so without these the city pages would exist only in the
   sitemap. Every city is linked from the others in its state; the states reach
   each other through the popular row on /panchang/.

   One line that wraps, not a block: labelled, inline, and quiet enough to sit
   under the ephemeris note without competing with it. */
.ds-citynear {
    border-top: 1px solid var(--ds-line);
    padding-top: var(--ds-3);
    font-size: .85rem;
    line-height: 2;
    /* ── The row must be allowed to wrap ─────────────────────────────────
       MEASURED on a 375px phone: this row ran to 597px and dragged the whole
       /panchang/ page sideways with it — 222px of horizontal scroll, the only
       page of twelve that had any.

       The cause is in the markup, not here: the links are emitted with NO
       whitespace between them ({% for %}<a>…</a>{% endfor %} on one line), and
       inline elements only break at whitespace. Six city names with no space
       between them are one unbreakable run, however narrow the screen.

       flex + wrap gives the break opportunity that the markup does not, and
       leaves the template alone — a space added there would sit on the wrong
       side of the drawn middot. The `a + a::before` separator is unaffected:
       it belongs to the <a>, so it travels with it onto the next line. */
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    column-gap: 0;
    row-gap: .1rem;
}
.ds-citynear__label {
    color: var(--ds-ink-faint);
    margin-right: var(--ds-2);
}
.ds-citynear a {
    color: var(--ds-ink-muted);
    text-decoration: none;
    white-space: nowrap;
}
/* A middot between the names, drawn rather than typed, so the markup stays a
   plain run of <a> and the separator never ends up inside a link's hit area
   or read aloud by a screen reader. */
.ds-citynear a + a::before {
    content: "·";
    color: var(--ds-line-strong);
    margin: 0 var(--ds-2);
}
.ds-citynear a:hover { color: var(--ds-saffron); text-decoration: underline; }

/* Screen only. A printed panchang is one day for one place; a row of links to
   other towns on the back of it is noise. */
@media print { .ds-citynear { display: none !important; } }

/* ═══════════════════════════════════════════════════════════════════════════
   PANCHANG — muhurat, vas, bhadra, hora
   Added for the owner's ask (16 Aug 2026): hora, bhadra, agni/shiv vas, shubh
   muhurat, samvat raja & mantri, and a 12-hour clock throughout.

   The whole brief was "thoda professional look, easy to read". These rules do
   that with three moves and no new colours — every value below is an existing
   token:

     1. The TIME is the loud element, not the label. On this page the clock is
        what a reader is hunting for; the name of the muhurat is how they
        confirm they found the right one.
     2. Quality is carried on a left edge, never by colouring the text itself.
        Coloured body text at 14px fails contrast for the 45+ readers who are
        most of this audience, and a 3px edge reads at a glance on a phone.
     3. Nothing is only colour. Good/avoid also differ in weight and wording,
        so the page still works for a colour-blind reader and in greyscale
        print.
   ═════════════════════════════════════════════════════════════════════════ */

/* A time window: "5:53 AM – 4:53 PM". Tabular figures so a column of these
   lines up instead of jittering on the 1s. */
.ds-window,
.ds-muhurat__time,
.ds-limb-time {
    font-variant-numeric: tabular-nums;
}
.ds-muhurat__time,
.ds-limb-time { white-space: nowrap; }

/* NOT nowrap. The Bhadra window can read "sunrise – 4:53 PM" rather than two
   clock times, and at 360px that overflowed its card. The wrap is allowed on
   the window and forbidden INSIDE each end (.ds-window__t), so the line may
   break at the dash but never in the middle of "4:53 PM". */
.ds-window {
    font-size: 1.05rem;
    font-weight: 700;
    color: var(--ds-ink);
    letter-spacing: .01em;
    white-space: normal;
}
.ds-window__t { white-space: nowrap; }
.ds-window__dash {
    color: var(--ds-ink-faint);
    font-weight: 400;
    padding: 0 .3em;
}

/* The "till 4:25 PM" that follows a tithi / nakshatra / yoga / karana. */
.ds-limb-note {
    display: inline-block;
    margin-left: .4rem;
    font-size: .82rem;
    color: var(--ds-ink-muted);
}
.ds-limb-time {
    color: var(--ds-maroon);
    font-weight: 700;
}

/* ── Shubh muhurat list ─────────────────────────────────────────────────── */
.ds-muhurat-list { list-style: none; margin: 0; padding: 0; }

.ds-muhurat {
    padding: .75rem 1rem .75rem calc(1rem - 3px);
    border-left: 3px solid var(--ds-gold);
    border-bottom: 1px solid rgba(0, 0, 0, .06);
}
.ds-muhurat:last-child { border-bottom: 0; }
.ds-muhurat--best    { border-left-color: var(--ds-success); background: var(--ds-success-soft); }
.ds-muhurat--special { border-left-color: var(--ds-accent); }

.ds-muhurat__top {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: .75rem;
    flex-wrap: wrap;
}
.ds-muhurat__name { font-weight: 600; color: var(--ds-ink); min-width: 0; }
.ds-muhurat__time {
    font-weight: 700;
    color: var(--ds-maroon);
    font-size: 1rem;
    margin-left: auto;
}
.ds-muhurat__note {
    font-size: .82rem;
    color: var(--ds-ink-muted);
    margin-top: .15rem;
}

/* ── Shiv vas / Agni vas ────────────────────────────────────────────────── */
.ds-vas {
    padding: .85rem 1rem;
    border-left: 3px solid var(--ds-ink-faint);
    border-bottom: 1px solid rgba(0, 0, 0, .06);
}
.ds-vas:last-child { border-bottom: 0; }
.ds-vas--good { border-left-color: var(--ds-success); }
.ds-vas--bad  { border-left-color: var(--ds-danger); }

.ds-vas__head {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: .75rem;
    flex-wrap: wrap;
}
.ds-vas__label {
    font-size: .78rem;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--ds-ink-muted);
}
.ds-vas__value { font-weight: 700; font-size: 1.02rem; margin-left: auto; }
.ds-vas--good .ds-vas__value { color: var(--ds-success); }
.ds-vas--bad  .ds-vas__value { color: var(--ds-danger); }

/* The derivation, printed so a pandit can check it rather than trust it.
   Deliberately quiet — it is evidence, not a headline. */
.ds-vas__formula {
    margin-top: .4rem;
    font-size: .74rem;
    color: var(--ds-ink-faint);
    font-variant-numeric: tabular-nums;
}

/* ── Folded cards (Hora, Choghadiya) ────────────────────────────────────── */
/* <details> styled as a card. The owner's note was that these two ate the
   page — 16 + 24 rows of times below the fold on a phone — so they open on a
   tap and stay shut otherwise.

   Everything here is CSS on native <details>. No script, nothing to initialise,
   and it keeps working when the Google-translate widget rewrites the page. */
.ds-fold > summary {
    list-style: none;               /* Firefox */
    cursor: pointer;
    user-select: none;
}
.ds-fold > summary::-webkit-details-marker { display: none; }

.ds-fold__head {
    display: flex;
    align-items: center;
    gap: .6rem;
    padding: .85rem 1rem;
    border-bottom: 1px solid transparent;
    transition: background .15s ease;
    /* Wraps by the BOX, not by a viewport media query. This card sits in a
       column whose width has nothing to do with the window's — a media query
       on the viewport left the chip clipped inside a narrow column on a wide
       screen, and the clipped part was the time it exists to show. */
    flex-wrap: wrap;
}
.ds-fold__title { flex: 1 1 auto; min-width: 0; }
.ds-fold[open] > .ds-fold__head { border-bottom-color: var(--ds-line, rgba(0,0,0,.08)); }
.ds-fold > summary:hover .ds-fold__head { background: var(--ds-sand); }
.ds-fold > summary:focus-visible {
    outline: 2px solid var(--ds-saffron);
    outline-offset: -2px;
}

.ds-fold__title { font-weight: 700; font-size: 1.05rem; color: var(--ds-ink); }

/* Pushed right, and quiet — it is a count, not news. */
.ds-fold__hint {
    margin-left: auto;
    font-size: .78rem;
    color: var(--ds-ink-faint);
}

/* The chevron is the only thing that moves, so the control reads as a control
   without needing a border or a button shape around it. */
.ds-fold__chev {
    color: var(--ds-ink-faint);
    font-size: .8rem;
    transition: transform .18s ease;
}
.ds-fold__hint + .ds-fold__chev,
.ds-now + .ds-fold__chev { margin-left: 0; }
.ds-fold[open] .ds-fold__chev { transform: rotate(180deg); }

.ds-fold__body { padding: 0; }

/* "Now" — what makes a shut card still worth having. Set only on today's page. */
.ds-now {
    margin-left: auto;
    display: inline-flex;
    align-items: baseline;
    gap: .35rem;
    padding: .2rem .55rem;
    border-radius: 999px;
    font-size: .8rem;
    font-weight: 600;
    background: var(--ds-sand);
    color: var(--ds-ink);
    /* May wrap onto its own line when the head is narrow; never inside a time,
       which kundli.muhurat.h12 binds with a non-breaking space. */
    flex-wrap: wrap;
    min-width: 0;
    max-width: 100%;
}
.ds-now__label {
    font-size: .66rem;
    text-transform: uppercase;
    letter-spacing: .07em;
    color: var(--ds-ink-faint);
    font-weight: 700;
}
.ds-now__time { font-variant-numeric: tabular-nums; color: var(--ds-ink-muted); font-weight: 500; }
.ds-now--good, .ds-now--best { background: var(--ds-success-soft); }
.ds-now--bad,  .ds-now--avoid { background: var(--ds-danger-soft); }

/* ── Slot tables (choghadiya + hora rows) ───────────────────────────────── */
.ds-slots { --slot-pad: .45rem; }
.ds-slots td, .ds-slots th { padding: var(--slot-pad) 1rem; }

/* Section band. Quieter than a full sand row — this is a divider, not data. */
.ds-slots__band th {
    background: var(--ds-sand);
    font-size: .7rem;
    text-transform: uppercase;
    letter-spacing: .08em;
    color: var(--ds-ink-muted);
    font-weight: 700;
    padding-top: .35rem;
    padding-bottom: .35rem;
}

/* Only the two extremes are marked. Marking all seven would be a rainbow, and
   a table where every row is highlighted highlights nothing. */
.ds-slot--good  td:first-child,
.ds-slot--best  td:first-child { box-shadow: inset 3px 0 0 var(--ds-success); }
.ds-slot--bad   td:first-child,
.ds-slot--avoid td:first-child { box-shadow: inset 3px 0 0 var(--ds-danger); }

/* The row running right now. Weight AND tint, so it is not carried by colour
   alone for a reader who cannot separate the two. */
.ds-slot--now { background: var(--ds-gold-soft); }
.ds-slot--now td { font-weight: 700; }

@media print {
    /* Paper has no affordance to tap. A closed <details> is display:none in the
       UA stylesheet, so without this a printed panchang silently loses both the
       hora and the choghadiya — the reader would not even see a gap. Forcing
       the non-summary children visible is the only way to open one from CSS;
       there is no `open` property to set. */
    .ds-fold > *:not(summary) { display: block !important; }
    .ds-fold__chev { display: none; }
    .ds-fold__head { border-bottom: 1px solid rgba(0, 0, 0, .15); }
}

/* ── Print ──────────────────────────────────────────────────────────────── */
/* A printed panchang is read on paper where colour may not survive, so the
   edges become borders and the tints are dropped. */
@media print {
    .ds-muhurat, .ds-vas { background: none !important; }
    .ds-muhurat--best { border-left-width: 4px; }
}

/* ═══════════════════════════════════════════════════════════════════════════
   PANCHANG — the page's own typographic system
   Scoped to .ds-panchang, so nothing here can reach another page.

   The owner's note was that the page did not look professional. It was not any
   one element: it was that every card was a default Bootstrap table, so a
   LABEL and a VALUE and a TIME all arrived at the same weight, the same size
   and the same colour, and the eye had nothing to sort them by. An almanac is
   read by scanning for one value, so the fix is a hierarchy, not decoration:

     label   — small, muted, wide-tracked. Present, never competing.
     value   — ink, medium weight. The answer.
     time    — tabular, semibold, maroon. The thing being hunted for.

   Plus quieter rules (Bootstrap's default table borders are heavy at this
   density) and one consistent row height everywhere on the page.
   ═════════════════════════════════════════════════════════════════════════ */

/* ── Card headers: an eyebrow, not a heading ────────────────────────────── */
.ds-panchang .ds-card__header,
.ds-panchang .ds-fold__head { padding: .7rem 1rem; }

.ds-panchang .ds-card__header h5,
.ds-panchang .ds-fold__title {
    font-size: .82rem;
    font-weight: 700;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--ds-maroon);
}
/* Devanagari has no case, so `text-transform` does nothing to it and the wide
   tracking alone would just look loose. Hindi gets size and colour instead. */
.ds-panchang .lang-hi { text-transform: none; letter-spacing: 0; }
.ds-panchang .ds-card__header h5 .lang-hi,
.ds-panchang .ds-fold__title .lang-hi { font-size: .98rem; }

/* ── Tables: hairlines, one row height ──────────────────────────────────── */
.ds-panchang .table { border-color: transparent; }
.ds-panchang .table > :not(caption) > * > * {
    padding: .55rem 1rem;
    border-bottom-color: rgba(0, 0, 0, .05);
    background-image: none;
}
.ds-panchang .table > tbody > tr:last-child > * { border-bottom: 0; }

/* Row labels. Muted and small — the reader already knows what they came for. */
.ds-panchang .table th {
    font-weight: 600;
    font-size: .82rem;
    color: var(--ds-ink-muted);
    letter-spacing: .02em;
}
.ds-panchang .table td { color: var(--ds-ink); }

/* Every clock time on the page reads the same, wherever it sits. */
.ds-panchang .table td,
.ds-panchang .ds-now,
.ds-panchang .ds-slot td:last-child { font-variant-numeric: tabular-nums; }

/* ── Sun & Moon, day's timings: the number is the point ─────────────────── */
.ds-panchang .table td.text-nowrap { font-weight: 600; }

/* ── Spacing rhythm ─────────────────────────────────────────────────────── */
/* Cards were mb-4 (1.5rem) against ~0.5rem internal rows, so the gaps between
   cards read louder than the data inside them. */
.ds-panchang .ds-card { margin-bottom: 1rem !important; }
.ds-panchang .ds-card:last-child { margin-bottom: 0 !important; }

/* The muhurat list and the vas blocks set their own padding; bring them onto
   the same 1rem gutter as the tables so the two columns line up. */
.ds-panchang .ds-muhurat { padding-left: calc(1rem - 3px); padding-right: 1rem; }
.ds-panchang .ds-vas { padding-left: calc(1rem - 3px); padding-right: 1rem; }

/* ═══════════════════════════════════════════════════════════════════════════
   SHARE BLOCK — templates/includes/_share.html
   Users asked to be able to pass the site on, and on this audience's phones
   that means WhatsApp. So the three controls are not equals:

     WhatsApp   solid, brand green, first, and it grows to fill the row.
     Share      the native sheet, only where it exists.
     Copy link  quiet outline; the fallback, not the invitation.

   #128C4A rather than WhatsApp's own #25D366: the brand green is 2.4:1 against
   white and fails for button text, and this reuses .ds-btn--wa's already
   corrected value so the two can never drift apart.
   ═════════════════════════════════════════════════════════════════════════ */
.ds-share {
    border: 1px solid var(--ds-line);
    border-radius: var(--ds-r);
    background: var(--ds-ivory);
    padding: .9rem 1rem 1rem;
}
.ds-share--compact { border: 0; background: none; padding: 0; }

.ds-share__head {
    display: flex;
    align-items: center;
    gap: .45rem;
    margin-bottom: .65rem;
    font-size: .82rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--ds-ink-muted);
}
.ds-share__head .lang-hi { text-transform: none; letter-spacing: 0; font-size: .95rem; }
.ds-share__head i { color: var(--ds-saffron); }

.ds-share__row { display: flex; flex-wrap: wrap; gap: .5rem; }

.ds-share__btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .45rem;
    /* 44px tall. This audience is ~90% phone and mostly 45+; a 32px control is
       a mis-tap waiting to happen. */
    min-height: 44px;
    padding: .5rem 1rem;
    border-radius: var(--ds-r-sm);
    border: 1px solid var(--ds-line);
    background: var(--ds-ivory);
    color: var(--ds-ink);
    font-size: .95rem;
    font-weight: 600;
    text-decoration: none;
    cursor: pointer;
    transition: background .15s ease, border-color .15s ease;
}
.ds-share__btn:hover { background: var(--ds-sand); color: var(--ds-ink); }
.ds-share__btn:focus-visible { outline: 2px solid var(--ds-saffron); outline-offset: 2px; }

/* Takes the room the other two do not want. On a narrow phone the row wraps
   and this ends up a full-width bar, which is the right answer there. */
.ds-share__btn--wa {
    flex: 1 1 12rem;
    background: #128C4A;
    border-color: #128C4A;
    color: #fff;
}
.ds-share__btn--wa:hover { background: #0E7038; border-color: #0E7038; color: #fff; }
.ds-share__btn--wa i { font-size: 1.15rem; }

.ds-share__btn--copy.is-done {
    border-color: var(--ds-success);
    color: var(--ds-success);
}

/* A share block is an invitation to send this page somewhere. On paper there
   is nowhere to send it. */
@media print { .ds-share { display: none !important; } }

/* Shown only when both copy paths refuse — see static/js/share.js manual(). */
.ds-share__manual { margin-top: .6rem; }
.ds-share__manual-label {
    display: block;
    font-size: .78rem;
    color: var(--ds-danger);
    margin-bottom: .25rem;
}
.ds-share__manual-input {
    display: block;
    margin-top: .25rem;
    width: 100%;
    min-height: 44px;
    padding: .45rem .6rem;
    border: 1px solid var(--ds-line);
    border-radius: var(--ds-r-sm);
    background: var(--ds-cream);
    color: var(--ds-ink);
    font-size: .9rem;
    /* Wraps rather than scrolling sideways — on this path the reader has to
       read the URL, and half of it is no use. */
    resize: none;
    word-break: break-all;
}

/* ── "मेरा शहर" — the one-tap location button on /panchang/ ─────────────── */
/* Sits under the city box as a quiet secondary action. It must not compete
   with "दिखाएँ": picking from the list is still the primary path, and this is
   the shortcut for somebody who does not want to look their town up. */
.ds-near {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    margin-top: .4rem;
    /* 44px, like every other control this phone-first audience taps. */
    min-height: 44px;
    padding: .35rem .7rem;
    border: 1px solid var(--ds-line);
    border-radius: var(--ds-r-sm);
    background: var(--ds-cream);
    color: var(--ds-saffron);
    font-size: .85rem;
    font-weight: 600;
    cursor: pointer;
    transition: background .15s ease, border-color .15s ease;
}
.ds-near:hover:not(:disabled) { background: var(--ds-saffron-soft); border-color: var(--ds-saffron); }
.ds-near:focus-visible { outline: 2px solid var(--ds-saffron); outline-offset: 2px; }
.ds-near:disabled { opacity: .7; cursor: default; }
.ds-near i { font-size: 1rem; }

/* The pin ticks while the fix is being fetched — the only signal that a tap
   registered, since the permission dialog can take a second to appear. */
.ds-near.is-busy i { animation: ds-near-pulse 1s ease-in-out infinite; }
@keyframes ds-near-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .35; } }

@media (prefers-reduced-motion: reduce) {
    .ds-near.is-busy i { animation: none; }
}

/* A location button is meaningless on paper. */
@media print { .ds-near, .ds-near-msg { display: none !important; } }

/* ── Share the site, from the footer of every page ──────────────────────── */
/* The footer is a DARK block (--ds-ink-surface), so the share partial's own
   ivory card and ink text would be invisible here. `--compact` already strips
   the card; these rules re-colour the buttons for the dark ground. */
.sm-footer-share {
    margin-top: 1.75rem;
    padding-top: 1.25rem;
    border-top: 1px solid rgba(255, 255, 255, .1);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: .9rem;
}
.sm-footer-share__text {
    font-size: .88rem;
    color: rgba(255, 255, 255, .7);
    min-width: 0;
}
.sm-footer-share__text strong { color: var(--ds-gold-bright); font-weight: 700; }

/* WhatsApp keeps its own green — it is the one colour people recognise before
   they read the label. Only the neutral buttons need re-dressing. */
.sm-footer-share .ds-share__btn:not(.ds-share__btn--wa) {
    background: transparent;
    border-color: rgba(255, 255, 255, .28);
    color: rgba(255, 255, 255, .85);
}
.sm-footer-share .ds-share__btn:not(.ds-share__btn--wa):hover {
    background: rgba(255, 255, 255, .08);
    color: #fff;
}
.sm-footer-share .ds-share__manual-label { color: var(--ds-gold-bright); }
.sm-footer-share .ds-share__manual-input {
    background: rgba(0, 0, 0, .25);
    border-color: rgba(255, 255, 255, .25);
    color: #fff;
}

/* On a phone the row stacks, and the WhatsApp button should then be the full
   width of the footer rather than a stub beside two others. */
@media (max-width: 575.98px) {
    .sm-footer-share { flex-direction: column; align-items: stretch; }
    .sm-footer-share .ds-share__row { width: 100%; }
}

@media print { .sm-footer-share { display: none !important; } }

/* ═══════════════════════════════════════════════════════════════════════════
   THE DASHA RUNNING TODAY — Vimshottari and Yogini alike
   Owner's ask: the period actually running should stand out. A reader opens
   the dasha section to answer one question — "what is on right now?" — and was
   given nine collapsed rows spanning 120 years with nothing to separate them.

   Marked THREE ways, not one: a gold ground, a heavier weight, and a worded
   tag. Colour alone fails a colour-blind reader and disappears in greyscale
   print, and this is the one row on the page that must not be missed.
   ═════════════════════════════════════════════════════════════════════════ */

/* The mahadasha, which also opens by itself — see kundli/result.html. */
.ds-collapse--now {
    border-color: var(--ds-gold);
    box-shadow: 0 0 0 1px var(--ds-gold);
}
.ds-collapse--now > .ds-collapse__head {
    background: var(--ds-gold-soft);
}
.ds-collapse--now > .ds-collapse__head:hover { background: #F6EBC9; }

/* The antardasha row inside it. */
.ds-row-now > td {
    background: var(--ds-gold-soft);
    font-weight: 700;
    color: var(--ds-ink);
}

/* The word, so the highlight is never carried by colour alone. Small, because
   the row it sits on is already loud. */
.ds-now-tag {
    display: inline-block;
    margin-right: .4rem;
    padding: .05rem .45rem;
    border-radius: 999px;
    background: var(--ds-maroon);
    color: #fff;
    font-size: .64rem;
    font-weight: 700;
    letter-spacing: .05em;
    text-transform: uppercase;
    vertical-align: .1em;
    white-space: nowrap;
}
.ds-now-tag .lang-hi { text-transform: none; letter-spacing: 0; font-size: .74rem; }

/* When the badge TRAILS a name rather than leading it, the gap belongs on the
   other side. {% spaceless %} removes the template's own separating space, so
   it has to come from here. */
.ds-praty .ds-now-tag { margin-left: .35rem; margin-right: 0; }

/* On paper the tint may not survive, so the running row also gets a rule down
   its left edge. .ds-print__row--now already sets the gold ground. */
@media print {
    .ds-collapse--now { box-shadow: none; border-left: 3px solid #000; }
    .ds-row-now > td:first-child,
    .ds-print__row--now > td:first-child { box-shadow: inset 3px 0 0 #000; }
    .ds-now-tag { background: none; color: #000; border: 1px solid #000; }
}

/* ── The dasha drill-down: mahadasha > antardasha > pratyantardasha ─────── */
/* Three levels of the same kind of thing, so each has to read as a level DOWN
   and not as more of the list above it. Three moves do that, and none of them
   is colour: each level indents, its type gets smaller, and only the outermost
   keeps a full border. The gold "now" treatment is layered on top and is the
   only place colour is used at all. */
.ds-dasha__inner { padding: .35rem .5rem .5rem; }

/* ── level 2: antardasha ── */
.ds-sub {
    border-left: 2px solid var(--ds-line);
    margin: 0 0 .2rem .25rem;
}
.ds-sub--accent { border-left-color: rgba(109, 74, 166, .25); }
.ds-sub > summary { list-style: none; cursor: pointer; }
.ds-sub > summary::-webkit-details-marker { display: none; }

.ds-sub__head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: .3rem .75rem;
    padding: .4rem .6rem;
    font-size: .9rem;
    transition: background .15s ease;
}
.ds-sub > summary:hover .ds-sub__head { background: var(--ds-sand); }
.ds-sub > summary:focus-visible { outline: 2px solid var(--ds-saffron); outline-offset: -2px; }
.ds-sub__name { font-weight: 600; color: var(--ds-ink); }

/* The chevron is drawn from the border colour so it needs no icon font, and it
   is the only thing that moves — enough to read as a control. */
.ds-sub__head::before {
    content: '';
    width: .38rem; height: .38rem;
    border-right: 2px solid var(--ds-ink-faint);
    border-bottom: 2px solid var(--ds-ink-faint);
    transform: rotate(-45deg);
    transition: transform .18s ease;
    flex: 0 0 auto;
    margin-right: .1rem;
}
.ds-sub[open] > summary .ds-sub__head::before { transform: rotate(45deg); }

.ds-sub__when {
    margin-left: auto;
    font-size: .8rem;
    color: var(--ds-ink-muted);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.ds-sub--now { border-left-color: var(--ds-gold); }
.ds-sub--now > summary .ds-sub__head { background: var(--ds-gold-soft); }
.ds-sub--now > summary:hover .ds-sub__head { background: #F6EBC9; }

@media (prefers-reduced-motion: reduce) {
    .ds-sub__head::before { transition: none; }
}

/* ── level 3: pratyantardasha ── */
/* Sits inside its antardasha's <details>, indented once more again. */
.ds-praty {
    border-left: 2px solid var(--ds-maroon);
    background: var(--ds-cream);
    padding: .4rem 0 .3rem;
    margin: 0 0 .35rem 1rem;
}
.ds-praty--accent { border-left-color: var(--ds-accent); }

.ds-praty__head {
    font-size: .72rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--ds-ink-muted);
    padding: 0 1rem .35rem;
}
.ds-praty__head .lang-hi { text-transform: none; letter-spacing: 0; font-size: .84rem; }

/* Smaller than its parent table — three levels of the same type size read as
   one flat list, which is the thing the indent is trying to undo. */
.ds-praty .table { background: transparent; font-size: .86rem; }
.ds-praty .table > tbody > tr > td {
    padding: .3rem .5rem .3rem 1rem;
    color: var(--ds-ink-muted);
}
/* The name column carries the weight; the dates are reference. Set here rather
   than with `small text-muted` on every cell — there are ~1,450 of these rows,
   and two utility classes on each is a measurable slice of the page. */
.ds-praty .table > tbody > tr > td:first-child {
    color: var(--ds-ink);
    font-weight: 600;
}
.ds-praty .table > tbody > tr > td:not(:first-child) { font-variant-numeric: tabular-nums; }
.ds-praty .table > tbody > tr:last-child > td { border-bottom: 0; }

/* Told rather than left as an empty box — an antardasha cut short at birth
   cannot be divided, and silence there reads as a bug. */
.ds-praty__none {
    margin: 0;
    padding: .5rem 1rem .6rem 1.5rem;
    font-size: .82rem;
    color: var(--ds-ink-faint);
}

/* On a narrow phone the indents cost more than they buy. */
@media (max-width: 575.98px) {
    .ds-praty { margin-left: .4rem; }
    .ds-sub { margin-left: 0; }
    .ds-dasha__inner { padding-left: .25rem; padding-right: .25rem; }
    .ds-sub__when { margin-left: 0; flex-basis: 100%; }
}

/* ═══════════════════════════════════════════════════════════════════════
   ADMIN DASHBOARD — the work strip and the tally band
   ═══════════════════════════════════════════════════════════════════════
   The screen the office actually runs on had grown to nine full-width cards
   and the owner's word for it was "lengthy". Two things fixed the length
   without taking anything off the page: the queues with nothing in them stop
   drawing a card at all, and the three rows of four stat cards became the one
   band below. What is left of the height is the work itself.

   No JavaScript anywhere here — the sections that fold use the same native
   <details> the panchang does (.ds-fold). */

/* Anchor targets sit under a sticky navbar, so they need the clearance or the
   heading you jumped to lands behind it. */
.ds-jump { scroll-margin-top: 96px; }

/* ── The work strip ────────────────────────────────────────────────────── */
/* Everything waiting, in one line of chips at the top. Built in the view and
   holding only the non-zero queues, so it is short by construction — five
   chips at the very worst, usually one or none. */
.ds-worklist {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem;
    padding: .75rem 1rem;
    background: var(--ds-warn-soft);
    border: 1px solid var(--ds-line-strong);
    border-left: 5px solid var(--ds-saffron);
    border-radius: var(--ds-r);
}
.ds-worklist__title {
    font-weight: 700;
    color: var(--ds-ink);
    margin-right: .25rem;
}
.ds-worklist__item {
    display: inline-flex;
    align-items: center;
    gap: .4rem;
    padding: .3rem .7rem;
    background: var(--ds-ivory);
    border: 1px solid var(--ds-line-strong);
    border-radius: var(--ds-r-pill);
    color: var(--ds-ink);
    text-decoration: none;
    font-size: .85rem;
    font-weight: 600;
}
.ds-worklist__item:hover,
.ds-worklist__item:focus-visible {
    border-color: var(--ds-saffron);
    color: var(--ds-saffron-dark);
}
/* The count is the whole point of the chip, so it leads and it is the only
   thing carrying the alarm colour. */
.ds-worklist__n {
    background: var(--ds-saffron);
    color: #fff;
    border-radius: var(--ds-r-pill);
    min-width: 1.5rem;
    padding: 0 .4rem;
    text-align: center;
    font-variant-numeric: tabular-nums;
}
/* Nothing waiting. One quiet green line, in place of the five cards that each
   used to say it separately. */
.ds-worklist--clear {
    background: var(--ds-success-soft);
    border-left-color: var(--ds-success);
    color: var(--ds-success);
    font-weight: 600;
}

/* ── The tally band ────────────────────────────────────────────────────── */
/* Twelve figures that were twelve cards. Grouped by the question each set
   answers, because "12 approved" and "12 married" are not the same 12 and the
   old grid gave no clue which was which. */
.ds-tally {
    display: flex;
    flex-wrap: wrap;
    gap: .75rem 2rem;
    padding: .9rem 1rem;
    background: var(--ds-ivory);
    border: 1px solid var(--ds-line);
    border-radius: var(--ds-r);
    box-shadow: var(--ds-shadow-sm);
}
.ds-tally__group { flex: 1 1 15rem; min-width: 0; }
.ds-tally__lab {
    font-size: .72rem;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--ds-ink-faint);
    margin-bottom: .25rem;
}
.ds-tally__row { display: flex; flex-wrap: wrap; gap: .25rem .9rem; }
.ds-tally__item {
    font-size: .82rem;
    color: var(--ds-ink-muted);
    white-space: nowrap;
}
.ds-tally__item b {
    font-size: 1.05rem;
    color: var(--ds-ink);
    font-variant-numeric: tabular-nums;
}
/* Colour only where it means something: a figure worth acting on, and the two
   worth being pleased about. A total is just a total. */
.ds-tally__item--warn b { color: var(--ds-warn); }
.ds-tally__item--ok   b { color: var(--ds-success); }

/* ═══════════════════════════════════════════════════════════════════════
   ONE BIODATA, COMPLETE — templates/matrimonial/_biodata_full.html
   ═══════════════════════════════════════════════════════════════════════
   64 fields is a lot to read down a single column, so they are grouped by the
   question each group answers and laid out as definition lists that wrap into
   however many columns fit. The label column is fixed, the value column takes
   what is left: the office scans DOWN the labels looking for one field, and a
   ragged label edge is what makes that slow.

   Used inside a <details> per biodata on the pandit's own file, which is why
   nothing here sets a background — it inherits the card it opens inside. */

.ds-bio__grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr));
    gap: 1rem 1.75rem;
}
/* The two groups whose values are long sentences rather than words — a
   partner preference and an office note both run past a narrow column. */
.ds-bio__group--wide { grid-column: 1 / -1; }

.ds-bio__lab {
    font-size: .72rem;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--ds-ink-faint);
    border-bottom: 1px solid var(--ds-line);
    padding-bottom: .2rem;
    margin-bottom: .35rem;
}

/* A <dl> rather than a table: this is label/value pairs, and a table here
   would need a header row saying "field" and "value" to be honest markup. */
.ds-bio__dl {
    display: grid;
    grid-template-columns: 9.5rem 1fr;
    gap: .18rem .75rem;
    margin: 0;
    font-size: .86rem;
}
.ds-bio__dl dt {
    color: var(--ds-ink-muted);
    font-weight: 500;
}
.ds-bio__dl dd {
    margin: 0;
    color: var(--ds-ink);
    min-width: 0;
    overflow-wrap: anywhere;   /* a long email must not push the grid wider */
}

.ds-bio__about {
    margin-top: 1rem;
    padding: .75rem 1rem;
    background: var(--ds-sand);
    border-radius: var(--ds-r-sm);
    font-size: .88rem;
}

.ds-bio__files {
    display: flex;
    flex-wrap: wrap;
    gap: 1.5rem;
    margin-top: 1rem;
}
.ds-bio__img {
    max-height: 220px;
    max-width: 100%;
    border-radius: var(--ds-r-sm);
    border: 1px solid var(--ds-line);
    display: block;
    margin-top: .25rem;
}

/* On a phone the fixed label column leaves the values a few characters wide,
   so the pairs stack instead. */
@media (max-width: 575.98px) {
    .ds-bio__dl { grid-template-columns: 1fr; gap: 0 0; }
    .ds-bio__dl dt { margin-top: .4rem; font-size: .78rem; }
}

/* The body of one biodata's <details>, indented to sit under its own row. */
.ds-sub__body { padding: .5rem .6rem .75rem; }

/* ═══════════════════════════════════════════════════════════════════════
   आध्यात्मिक ज्ञान — /gyan/
   ═══════════════════════════════════════════════════════════════════════
   The colour scheme here carries the argument, so it is not decoration and
   should not be "tidied" into one palette.

   परंपरा is drawn in the warm/sand family and शास्त्र in the green/proven
   family, and the two blocks never share a border colour. A reader who
   skims — which is most readers — must be able to tell from three feet away
   which half of the page is custom and which half is citation. Every other
   Hindi site on these subjects renders both as the same grey prose, and that
   sameness is exactly what makes them untrustworthy. */

.ds-gyan__short {
    background: var(--ds-gold-soft);
    border-left: 5px solid var(--ds-gold);
    border-radius: var(--ds-r);
    padding: 1rem 1.15rem;
    font-size: 1.06rem;
    line-height: 1.85;
    margin-bottom: .75rem;
}
.ds-gyan__lab {
    font-size: .72rem;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--ds-ink-faint);
    margin-bottom: .3rem;
}
.ds-gyan__basis { display: flex; flex-wrap: wrap; gap: .5rem; }

.ds-gyan__h {
    font-size: 1.12rem;
    font-weight: 700;
    color: var(--ds-maroon);
    margin: 0 0 .5rem;
}
.ds-gyan__block {
    padding: 1rem 1.15rem;
    border-radius: var(--ds-r);
    border: 1px solid var(--ds-line);
    margin-bottom: 1rem;
    line-height: 1.9;
}
/* The two that must never look alike. */
.ds-gyan__block--parampara {
    background: var(--ds-sand);
    border-left: 4px solid var(--ds-saffron);
}
.ds-gyan__block--shastra {
    background: var(--ds-success-soft);
    border-left: 4px solid var(--ds-success);
}

/* Proven beside believed, side by side, so neither can be read as the other.
   Stacks on a phone — but the labels stay, which is the part that matters. */
.ds-gyan__split {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
    gap: 1rem;
    margin: 1.25rem 0;
}
.ds-gyan__col {
    padding: .9rem 1rem;
    border-radius: var(--ds-r);
    line-height: 1.85;
}
.ds-gyan__col--proven { background: var(--ds-success-soft); }
.ds-gyan__col--belief { background: var(--ds-warn-soft); }

.ds-gyan__sources {
    margin-top: 2rem;
    padding: 1rem 1.15rem;
    border: 1px dashed var(--ds-line-strong);
    border-radius: var(--ds-r);
    font-size: .9rem;
}
.ds-gyan__sources ul { padding-left: 1.1rem; }
.ds-gyan__sources li { margin-bottom: .5rem; }

/* "एक सवाल से दूसरा सवाल" — the cards are the whole engagement idea, so they
   are given a real hit area rather than a list of links. */
.ds-gyan__related {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
    gap: .75rem;
}
.ds-gyan__card {
    display: flex;
    flex-direction: column;
    gap: .4rem;
    align-items: flex-start;
    padding: .9rem 1rem;
    background: var(--ds-ivory);
    border: 1px solid var(--ds-line);
    border-radius: var(--ds-r);
    text-decoration: none;
    color: var(--ds-ink);
    transition: border-color .15s, transform .15s;
}
.ds-gyan__card:hover,
.ds-gyan__card:focus-visible {
    border-color: var(--ds-gold);
    transform: translateY(-2px);
    color: var(--ds-maroon);
}
.ds-gyan__card-cat { font-size: .72rem; color: var(--ds-ink-faint); }
.ds-gyan__card-title { font-weight: 600; line-height: 1.5; }

/* ── A dropdown must not fall off the bottom of the window ──────────────── */
/*
   Reported 20 Aug 2026 with a screenshot: the "…और" menu ran past the bottom
   of the screen and the items down there could not be reached at all.

   MEASURED before changing anything, because a navbar rule applies to
   everybody (see the navbar-expand-xl episode):

     staff, 1280 x 631 window : menu 1,480px tall, 30 items,
                                overflows the viewport by 907px,
                                overflow-y: visible — so no scroll, and
                                roughly 18 items simply unreachable.
     phone, 390 x 780         : NOT affected. Below the expand breakpoint the
                                menu is position:static inside the collapse
                                panel, the document is 6,331px tall, and the
                                PAGE scrolls to it normally.

   So the bug belongs to the floating desktop dropdown only, and the fix is
   scoped to that breakpoint rather than applied globally. The phone panel is
   working and is deliberately left alone.

   `min-width: 992px` is the other half of the `max-width: 991.98px` block
   above and must move with it if navbar-expand-* ever changes. */
@media (min-width: 992px) {
    .navbar .dropdown-menu {
        /* 5rem clears the sticky navbar the menu hangs from, plus a little
           air so the last item never sits flush against the window edge. */
        max-height: calc(100vh - 5rem);
        overflow-y: auto;
        /* Without this, reaching the end of the menu hands the scroll to the
           page behind it — the list jumps away under the cursor just as
           somebody arrives at the item they were going for. */
        overscroll-behavior: contain;
    }
    /* A quiet scrollbar. The default one is wide enough to sit on top of the
       `preview` badges at the right-hand edge of the gated items. */
    .navbar .dropdown-menu::-webkit-scrollbar { width: 8px; }
    .navbar .dropdown-menu::-webkit-scrollbar-thumb {
        background: var(--ds-line-strong);
        border-radius: var(--ds-r-pill);
    }
    .navbar .dropdown-menu::-webkit-scrollbar-track { background: transparent; }
}

/* The review controls at the foot of a knowledge article. Fenced off from the
   article itself — this is the checker's furniture, not the reader's, and the
   dashed rule says so without needing a heading. */
.ds-gyan__verify {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .6rem;
    padding: 1rem 1.15rem;
    border: 1px dashed var(--ds-line-strong);
    border-radius: var(--ds-r);
    background: var(--ds-sand);
}
.ds-gyan__verify form {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .6rem;
    margin: 0;
}

/* ── Rudraksh guide (/rudraksh/) ─────────────────────────────────────────── */
/*
   Reuses the /gyan/ blocks for the parampara-vs-fact split, so the two pages
   teach the reader the same visual language: sand for what tradition holds,
   green for what can be checked. Only the pieces with no equivalent there are
   defined below.

   The warning line inside a table cell is drawn in the danger colour on
   purpose. On this page a warning is not a footnote — "the round one mukhi you
   are being offered is almost certainly not one" is the most valuable sentence
   in the row, and it has to survive being skimmed. */
.ds-rudra__qa { display: grid; gap: .75rem; }
.ds-rudra__qa-item {
    padding: .9rem 1.05rem;
    border: 1px solid var(--ds-line);
    border-left: 4px solid var(--ds-gold);
    border-radius: var(--ds-r);
    background: var(--ds-ivory);
}
.ds-rudra__q {
    font-weight: 700;
    color: var(--ds-maroon);
    margin-bottom: .3rem;
}
.ds-rudra__a { line-height: 1.9; font-size: .94rem; }

.ds-rudra__warn {
    margin-top: .35rem;
    color: var(--ds-danger);
    font-size: .84rem;
    font-weight: 600;
}
.ds-rudra__table td { vertical-align: top; }

.ds-rudra__steps, .ds-rudra__care { line-height: 1.95; padding-left: 1.2rem; }
.ds-rudra__steps li, .ds-rudra__care li { margin-bottom: .5rem; }

/* ── Typing filter over a long admin table ───────────────────────────────── */
/*
   Sits between the fold's summary and the table it filters, so it is the first
   thing under the heading — a search box below the rows would be found only by
   the scrolling it exists to save. */
.ds-tablefilter {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: .6rem .9rem;
    border-bottom: 1px solid var(--ds-line);
    background: var(--ds-sand);
}
.ds-tablefilter .bi { color: var(--ds-ink-faint); }
.ds-tablefilter input { max-width: 26rem; }
.ds-tablefilter__count {
    margin-left: auto;
    font-size: .78rem;
    color: var(--ds-ink-faint);
    font-variant-numeric: tabular-nums;
}

/* ── Preview-access checkboxes, and the bar that saves them ──────────────── */
/*
   Drawn as chips rather than as bare checkboxes because the row can carry
   five or six of them and a column of small squares with labels beside them
   reads as a form to fill in. A chip that is ON is filled; one that is OFF is
   an outline. That is the same language the old buttons spoke, so nobody has
   to relearn the screen — only the number of clicks changed. */
.ds-grantset { display: flex; flex-wrap: wrap; gap: .3rem; }

.ds-grant {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    padding: .2rem .55rem;
    border: 1px solid var(--ds-line-strong);
    border-radius: var(--ds-r-pill);
    font-size: .78rem;
    cursor: pointer;
    user-select: none;
    background: var(--ds-ivory);
    color: var(--ds-ink-muted);
    transition: background .12s, border-color .12s, color .12s;
}
.ds-grant:hover { border-color: var(--ds-saffron); }
.ds-grant input { margin: 0; cursor: pointer; }

/* `:has()` keeps the fill in step with the box the instant it is ticked,
   with no script. Browsers without it still show the server-rendered
   --on class, so the row is never wrong — only slower to react. */
.ds-grant--on,
.ds-grant:has(input:checked) {
    background: var(--ds-success-soft);
    border-color: var(--ds-success);
    color: var(--ds-success);
    font-weight: 600;
}
.ds-grant:has(input:focus-visible) { outline: 2px solid var(--ds-saffron); outline-offset: 1px; }

.ds-savebar {
    position: sticky;
    bottom: 0;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .75rem;
    padding: .75rem 1rem;
    background: var(--ds-sand);
    border-top: 1px solid var(--ds-line-strong);
    z-index: 2;
}

/* ── Step indicator: which screen of a multi-part form you are on ─────────
   Built for pandit registration, whose applicants the owner describes as
   "itne tech friendly nahi hote". A three-screen form with nothing showing
   the position reads as an endless one; three dots and a label answer "how
   much more is there" before the applicant has to ask.

   No JavaScript, and it degrades to a plain list if the CSS never loads. */
.ds-steps {
    display: flex;
    flex-wrap: wrap;
    gap: .4rem .75rem;
    list-style: none;
    padding: 0;
    margin: 0;
    font-size: .8rem;
    counter-reset: ds-step;
}
.ds-steps li {
    display: flex;
    align-items: center;
    gap: .4rem;
    color: var(--ds-muted, #6c757d);
}
.ds-steps li::before {
    counter-increment: ds-step;
    content: counter(ds-step);
    display: grid;
    place-items: center;
    width: 1.4rem;
    height: 1.4rem;
    border-radius: 50%;
    border: 1px solid currentColor;
    font-size: .7rem;
    font-weight: 700;
    flex: 0 0 auto;
}
.ds-steps__done {
    color: var(--ds-success, #198754);
}
.ds-steps__done::before {
    content: "\2713";           /* a tick, so "done" reads as done */
    border-color: currentColor;
}
.ds-steps__now {
    color: var(--ds-brand, #8b1a1a);
    font-weight: 700;
}
.ds-steps__now::before {
    background: currentColor;
    color: #fff;
    border-color: currentColor;
}

/* The word that makes a fold safe to skip.
   A long form reads as a demand unless each closed section says otherwise —
   the biodata form had 48 boxes and needed 6, and nothing on the page said so,
   so people filled nothing and left. */
.ds-fold__hint {
    font-weight: 400;
    color: var(--ds-muted, #6c757d);
    font-size: .85em;
}
