/* ==================================================================
   SITE.CSS — index.html's full stylesheet, moved out to an external
   file 2 October 2026.

   WHY: Home Vastu Consultation's "Book Consultation" button used to
   link to ../index.html?svc=vastu/home-vastu, which worked but
   actually navigated away before the modal opened — Abhishek asked
   for the modal to open in place instead. The modal's markup, the
   booking form, Sarthi (the chat assistant that can fill and submit
   it), and every rule that styles any of them live ONLY in
   index.html today. Rather than copy ~2,800 lines of CSS into every
   service page by hand — two copies drifting apart being exactly the
   failure mode this project has avoided everywhere else — this file
   is the ONE copy, and both index.html and any real service page
   (starting with services/home-vastu-consultation.html) load it.

   CONTENT IS UNCHANGED, VERBATIM, line for line, from what used to
   sit inside index.html's own <style> tag — except the one path that
   had to change: .fold .right's zodiac-wheel background image, which
   was `url("img/zodiac-wheel.svg")`, relative to index.html's own
   location. A CSS url() resolves relative to the STYLESHEET's
   location, not the page that loads it, so moving the rule here
   without fixing the path would have pointed it at a nonexistent
   css/img/zodiac-wheel.svg. Now `url("../img/zodiac-wheel.svg")`.

   WHY THIS IS SAFE TO LOAD ON A SERVICE PAGE TOO, EVEN THOUGH IT ALSO
   STYLES THE WHOLE HOMEPAGE: load order. Each service page links this
   file FIRST, then keeps its own <style> block (the one
   tools/build-service-pages.py already generates) AFTER it, in the
   same <head>. Where both define the same selector — header, body,
   h1, a, footer, main — the later rule wins, so the service page's
   own look is untouched. Where this file defines a selector the
   service page's own stylesheet never mentions — .cscrim, .cbox,
   .sarthi-*, .vscrim, #stars and the rest of the booking/Sarthi/
   video-lightbox chrome — those rules are the ONLY ones in play, and
   apply normally. No selector in the two files was found to collide
   in a way that would change the service page's existing appearance;
   the one borderline case, the --tulsi custom property, is defined
   identically (#5FD3A3) in both files, so it is a non-issue even
   where it does overlap.

   Do not fork a second copy of this file. A change to the booking
   form, the modal, or Sarthi belongs here and only here, and reaches
   every page that loads it the next time either generator runs (for
   the service pages) or on save (for index.html, which references it
   directly). See js/enquiry-engine.js for the matching JS extraction.
   ================================================================== */

/* ---- TYPE SCALE ----
   Five steps for everything below body size. There were fifteen: sizes
   0.16px apart that nobody can see and everybody has to maintain.

     0.72rem  11.5px   labels, the smallest anything gets
     0.79rem  12.6px   captions, hints, small print
     0.86rem  13.8px   secondary copy
     0.92rem  14.7px   body copy in tight places
     1rem     16px     body

   Headings above 1rem stay as they are — those are meant to differ.
   Three weights only: 400, 500, 600. One serif stack, one sans stack.
   Nothing below 11px. */
:root{
  /* gautamnight, verbatim from BRAND-GUIDELINES.md §4. This page had
     drifted onto its own near-miss palette; two systems is no system. */
  --void:#0D191F;        /* --void  */
  --void2:#16272F;     /* --void2 */
  --chalk:#EBEEF0;      /* --chalk */
  --dim:#A8B6BD;     /* --dim   */
  --amber:#0693D9;    /* --amber */
  --haldi:#3FB6EE; /* --haldi */
  --faint:#25404C;      /* --faint */
  /* --faint is right for dividers but measures 1.34:1 against the panel,
     so as a FORM FIELD border it is invisible. WCAG 2.1 asks 3:1 for the
     boundary of a UI control — you have to be able to see where to type. */
  --edge-lit:#5C89A0;   /* --edge-lit */
  /* Type tokens, matching the portal. The stacks were written out in
     full at each use here; naming them means one place to change and
     one vocabulary across both sites. */
  --serif:'Fraunces',Georgia,'Times New Roman',serif;
  --sans:'Inter','Noto Sans','Noto Sans Devanagari',-apple-system,
         BlinkMacSystemFont,'Segoe UI',sans-serif;
  --alert:#EF7076;
  --tulsi:#5FD3A3;         /* --tulsi */

  /* THE PAGE GUTTER — the same token the portal uses, so both sides of
     the brand breathe the same way.

     This was a flat 94%, which is a percentage of the viewport and so
     collapses exactly where it is needed most: 12px each side on a phone,
     which is why the copy was running into the bezel. A clamp with a px
     FLOOR cannot collapse — 24px is the minimum at any width. */
  /* The card carries its own 26px of padding, so a 24px outer gutter on a
     phone means 50px of inset before any field starts — a seventh of the
     screen spent twice over. The card provides the containment at that
     size; the page does not need to as well. */
  /* Matched to the portal. The two sheets both had --gut and gave it
     different values — 16px here, 24px there — so the same brand had
     two different page margins on a phone. The portal's comment even
     claimed it had been "matched to the holding page", which it had
     not. 24px is the better floor: 16 is a thin margin on a handset,
     and the floor is what does the work below roughly 690px wide. */
  color-scheme:dark;   /* was a second :root block further down */
  /* Both of these were being written as var(--void3) and
     var(--lit) — a token name with a hard-coded hex behind it,
     which is a loose hex value wearing a token's clothes. Neither was
     ever defined. Values taken from the portal so one name means one
     colour across the brand. */
  --void3:#1B2F39;
  --lit:#FFFFFF;
  /* ONE OFFSET, USED BY THE LAUNCHER AND THE PANEL.

     They were two identical clamps in two rules, which is how the two
     drift apart. Raised from clamp(14,3vw,26) — on a 390px phone that
     resolved to 14px, and 14px around a 58px circle reads as stuck to
     the corner rather than placed in it.

     max() with env() is the safe-area guard. Without viewport-fit=cover
     iOS already insets the viewport, so env() reports 0 and the clamp
     wins; if that meta is ever added, this keeps the button off the
     home indicator instead of under it. Costs nothing either way. */
  --sar-gap-x:max(clamp(20px,4.5vw,32px), env(safe-area-inset-right, 0px));
  --sar-gap-y:max(clamp(20px,4.5vw,32px), env(safe-area-inset-bottom, 0px));
  /* DESIGN-SYSTEM.md §2: nothing outside :root may hold a hex value.
     Eight were loose in this sheet — five #fff, and #cbd8de / #cfdde4 /
     #08151b / #061015 / #6f838e / #2f7ba8 typed inline because no token
     existed for them. Three of those I added myself while building
     Sarthi, which is how the rule erodes: one at a time, each one
     reasonable on its own.

     --soft and --softer are the two chalk steps between --chalk and
     --dim that the sheet had been improvising.
     --on-fill is the only text colour that goes on --amber.
     #000 behind a video stays: a letterbox tinted with a theme colour
     shows as coloured bars down the sides of someone else's footage,
     and that is the one documented exception. */
  --soft:#CFDDE4;
  --softer:#CBD8DE;
  --on-fill:#08151B;
  --edge-dim:#2F7BA8;
  /* --hint WAS NEVER DEFINED, AND SEVEN RULES HAVE BEEN USING IT.

     .sarthi-who span, .sar-note, .sar-chip.ghost, .sar-card-m, .sar-q,
     .sar-typing i and the date/time picker icon all say
     var(--hint). With no fallback and no definition the declaration is
     invalid at computed-value time, which for an inherited property
     means colour falls back to the PARENT. So every one of those bits
     of quiet meta text has been rendering at the same colour as the
     text it was supposed to sit underneath, since Sarthi was built.

     Nothing looked broken. It only meant a hierarchy that was designed
     and then silently did not happen — which is why it survived a
     contrast audit, a text audit and several rounds of screenshots.

     #8FA1AB is chosen to clear AA on ALL THREE surfaces this page has,
     because these rules span all of them: Sarthi's panel is --void3,
     its cards are --void2 and .area-note sits on --void.

       on --void 6.68 | on --void2 5.75 | on --void3 5.19

     That is the mistake --hint2 makes and this token must not: --hint2
     is 4.52 on --void and 3.51 on --void3, so it was only ever safe on
     one of the three. */
  --hint:#8FA1AB;
  --hint2:#6F838E;
  --gut:clamp(24px,5.5vw,52px);

  /* THE BREAK BETWEEN SECTIONS. One number, because it was three.
     .showcase-sec, .voices and .creds each carried their own copy of
     clamp(26px,4svh,48px), which is how three things that must stay
     equal end up unequal.

     MARGINS DO NOT COLLAPSE HERE. <body> is a flex column — every
     section carries flex:none for that reason — and adjacent margins
     in a flex container do not collapse the way they do in normal
     flow. So the gap is ONE margin, not the larger of two, which is
     also why `.showcase-sec + .voices{margin-top:0}` exists: without
     it that one join would have been double every other.

     RAISED FROM 4svh TO 7svh on 31 August 2026. Measured, the old
     value gave 36px at every width — even, but smaller than the space
     inside some of the sections it was separating, so a section
     boundary read as a paragraph break. The certificates ran into the
     FAQ. 7svh is about 63px on a laptop and 47px on a phone, where
     there is less height to give away.

     svh, not vh: on iOS vh is the tallest the viewport ever gets, so
     vh-based spacing jumps as the address bar hides. */
  --sec-gap:clamp(34px,7svh,72px);

  /* ---- FORM SPACING SYSTEM ----
     Four numbers govern the whole enquiry card. Every field, fixed or
     built at runtime, reads from these — so a field added to the service
     catalogue in six months cannot come out spaced differently from the
     ones beside it. That was the inconsistency: dynamic fields carried
     their own hard-coded margins. */
  --fld-gap:20px;                    /* one field to the next */
  --lbl-gap:7px;                     /* label down to its control */
  --ctl-h:48px;                      /* every control, same height */
  --card-pad:clamp(26px,2.4vw,34px); /* the card's inner padding */

  /* The usable height between the header and the footer. Both columns are
     given this as a MINIMUM, which is what lets the hero sit in the middle
     of the screen while staying immune to the form's height. */
  --fold-h:max(520px,calc(100svh - 150px));
}
/* Tells the browser this is a dark UI, so every native control it draws
   for us — the date picker popup, the time spinner, the select list —
   comes back dark instead of a white panel on a dark page. */

*{box-sizing:border-box}
/* .form-body is a grid, and a grid container assigns display to its
   children; make sure the hidden sub-service block stays hidden. */
[hidden]{display:none !important}

/* THE WHEEL IS WIDER THAN THE PHONE — BY DESIGN.
   On a 390px screen the halo is 548px and runs ~100px past the right
   edge. Without containment the document grows to fit it and the whole
   page drags sideways under your thumb.

   This was already set, but on BODY alone, which iOS does not reliably
   honour for absolutely-positioned overflow. It has to be on the root.

   clip, not hidden. Both stop the drag, but `hidden` turns the element
   into a scroll container, which breaks position:sticky inside it and
   lets iOS keep a rubber-band axis. `clip` just clips. `hidden` stays as
   the first declaration so anything too old for `clip` still gets it.

   overflow-y:scroll + scrollbar-gutter:stable, 1 October 2026 — this
   page is long enough to always need a vertical scrollbar, but the 23
   service pages and the three policy pages are shorter and some do,
   some don't, depending on content and viewport height. Without a
   forced scrollbar, the header's centered 1180px column sits a
   scrollbar's-width (roughly 15px) further right on a page that
   doesn't need to scroll than on one that does — small, but enough
   that clicking from here into a shorter detail page reads as the
   header visibly shifting/"jerking" sideways. Reserving the gutter
   everywhere, on every page, removes the inconsistency instead of
   patching each page's content length to force a scrollbar on or off.
   scrollbar-gutter:stable is the modern way (Chrome/Firefox/Edge);
   overflow-y:scroll is the classic fallback for browsers that don't
   support it (older Safari) — harmless together, since scrollbar-
   gutter has no effect once overflow is already forced to 'scroll'. */
/* overflow-y:scroll / scrollbar-gutter split off BODY onto HTML alone,
   1 October 2026 — a non-visible overflow value on BOTH html and body
   turns body into its own nested scroll container, which quietly took
   the sticky header's positioning context away from the real viewport
   scroller (html) and broke position:sticky site-wide ("the top
   navigation is not fixed"). html keeps the scroll + gutter reservation;
   body keeps only the horizontal clip the zodiac wheel still needs. */
html{overflow-x:hidden;overflow-x:clip;overflow-y:scroll;
     scrollbar-gutter:stable}
body{overflow-x:hidden;overflow-x:clip}

body{
  margin:0;background:var(--void);color:var(--chalk);
  font-family:var(--sans);line-height:1.55;
  position:relative;
  min-height:100svh;display:flex;flex-direction:column;
}
/* the cosmic backdrop — sits behind everything, catches no clicks */
#stars{position:fixed;inset:0;z-index:-1;pointer-events:none;opacity:.55}
.container{width:min(1180px,100% - var(--gut)*2);max-width:100%;margin-inline:auto}

/* ---------- header ---------- */
/* The header held one thing and so needed no layout. It holds two now:
   the lockup on the left, WhatsApp pushed to the right. */
/* THE HEADER IS STICKY NOW — 1 October 2026, at Abhishek's request,
   once the nav (below) actually had real sections to jump to: "the top
   header navigation is not fixed" was the report, and a nav you have to
   scroll back to the top to use again isn't much of a nav on a page
   this long.

   padding-bottom used to be clamp(16px,3.4svh,34px) — fold-opening
   spacing, fine for a header that appears once and scrolls away with
   everything else. A STICKY header carries that padding with it for
   the rest of the visit, so what used to be "room before the hero"
   would become a permanent band of empty space under the logo on every
   scroll position. Shrunk to a flat 14px, and the spacing it gave up is
   added back as main's own top padding just below, so the page looks
   exactly as before on first load — the only thing that changed is
   what happens once you scroll. */
header{padding:14px 0;flex:none;
       position:sticky;top:0;z-index:50;
       background:rgba(13,25,31,.92);
       -webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);
       border-bottom:1px solid var(--faint)}
.header-row{display:flex;align-items:center;justify-content:space-between;gap:16px}
/* The header went sticky above. Without this, clicking a .site-nav
   link (or any #why-vastu-style anchor) scrolls that section's own
   top edge to y=0 — straight under the now-permanent header, hiding
   its heading. scroll-padding-top leaves that much room above the
   landing point instead. ~75px header (14+14 padding, 46px logo,
   1px border) plus a little air. */
html{scroll-padding-top:92px}
/* The .wa / .wa-i rules went with the WhatsApp pill on 31 August 2026 —
   about 1.3 KB of them, including a 430px query that hid the label and
   left the glyph. See the note in the header markup for why the button
   went and why WhatsApp itself did not.

   Deleted rather than commented out. This stylesheet is inlined into
   the page, so every unused rule ships on every visit, and a selector
   that matches nothing gets copied into the next component because it
   reads as house style. The names are written here so a search for
   `.wa` lands on an explanation instead of on silence. */
.brand{display:inline-flex;align-items:center;gap:13px;
       text-decoration:none;color:var(--chalk)}
.brand img{width:46px;height:46px;object-fit:contain}
/* §3: Acharya in regular, Gautam in the accent. The mark and the
   wordmark are the brand; typing the name plainly is not it. */
.brand-name{font-family:var(--serif);font-size:1.16rem;
            letter-spacing:-.01em}
.brand-name em{font-style:normal;color:var(--haldi)}

/* THE NAV CAME BACK. See the "THE HEADER IS THE BRAND, AND NOTHING
   ELSE" comment in the markup below for why it left on 31 August 2026 —
   that reasoning held while the page had nothing but the form to point
   at. It doesn't any more: Why Vastu matters, Types of Vastu service,
   Why numerology matters and Types of numerology service are all real
   sections now, not a table of contents for pages that don't exist.
   Hidden under 860px rather than collapsed into a menu button — a
   five-link nav on a one-page site is a convenience, not a feature
   worth a hamburger and its own focus trap. */
.site-nav{display:flex;align-items:center;gap:clamp(16px,2.4vw,28px)}
/* font-size:.86rem, 1 October 2026 (later again) — was .88rem, a
   leftover from before the mega-menu nav unified this rule across
   every page (tools/navdata.py's mega_css() generates .86rem
   everywhere else: the 23 service pages, vastu.html, numerology.html,
   privacy/terms/refund/shop.html). Two sizes for one selector meant
   the five nav items measured a few px wider here than on every other
   page, so the whole nav visibly shifted left/right on the click
   between index.html and any other page — this is the second,
   separate cause of that same symptom this session (the first was
   .site-nav's gap value, fixed just above in the build-service-pages.py
   history; this one lived only in index.html's own hand-copied rule,
   never generated, so build-service-pages.py's fix never reached it). */
.nav-link{display:inline-flex;align-items:center;gap:4px;
         color:var(--soft);text-decoration:none;font-size:.86rem;
         font-weight:500;white-space:nowrap;position:relative;padding:4px 1px}
.nav-link::after{content:"";position:absolute;left:1px;right:1px;bottom:-2px;
                height:2px;border-radius:1px;background:var(--haldi);
                transform:scaleX(0);transform-origin:left;
                transition:transform .22s ease}
.nav-link:hover{color:var(--chalk)}
.nav-link:hover::after{transform:scaleX(1)}
.nav-link.is-active{color:var(--haldi)}
.nav-link.is-active::after{transform:scaleX(1)}
.nav-link:focus-visible{outline:2px solid var(--haldi);outline-offset:4px;
                       border-radius:4px}
/* Bridges the gap between the TRIGGER's own bottom edge and where the
   panel now starts. Anchoring the panel to <header> (see the comment
   on .mega-panel below) removed the old fixed 18px gap, but did not
   remove the gap itself: the trigger sits vertically centered inside
   a taller header bar, so its own bottom edge is still measurably
   above the header's bottom edge, where the panel begins (~22px,
   measured) — and that strip is not part of .nav-item's own box (the
   panel is out of flow, so it does not enlarge it), so :hover drops
   the instant the pointer crosses it, closing the panel before the
   pointer ever reaches it. This fix shipped once already and was
   accidentally undone when the panel was re-anchored to <header> —
   the earlier comment here claimed "no gap", which was true of
   panel-to-header but not of trigger-to-header. 30px covers the ~22px
   measured gap with margin for small header-height differences. */
.mega-trigger::before{content:"";position:absolute;left:0;right:0;
                     top:100%;height:30px}
.nav-caret{transition:transform .2s ease;flex:none}
.nav-item.has-mega:hover .nav-caret,
.nav-item.has-mega.is-open .nav-caret,
.nav-link.mega-trigger:focus-visible .nav-caret{transform:rotate(180deg)}

/* MEGA-MENU PANEL — see the markup comment above .site-nav. Same
   component, same behaviour script (near the other IIFEs below) as
   tools/navdata.py generates for the 23 service pages and the three
   policy pages; only the colour tokens differ (--chalk/--soft/--haldi/
   --faint/--void2 here vs --text/--muted/--accent-hi/--line/--panel
   there), because this page never adopted that token vocabulary (see
   the --void/--chalk/--haldi comment block at the top of :root).

   The panel is positioned off <header> itself, not off .header-row or
   the trigger — <header> is already position:sticky (see header{}
   above), which is a valid containing block for an absolutely
   positioned descendant same as relative/absolute would be, and
   nothing between here and there sets its own position, so <header>
   wins as the nearest one. <header> spans the full viewport (it has
   no horizontal padding; .header-row/.container is what insets the
   logo and nav to 1180px, not header itself), so left:0;right:0 here
   is truly edge to edge of the page, not just edge to edge of the
   1180px column — and top:100% (no added gap) sits the panel flush
   against the header's own bottom border, sharing that line as its
   top edge instead of floating a gap below it. This removes the gap
   between the PANEL and the header — it does NOT remove the gap
   between the TRIGGER and the panel, which still exists because the
   trigger sits above the header's own bottom edge (it's vertically
   centered inside a taller header row); see the .mega-trigger::before
   bridge above for that one.

   Open = slide down, close = slide up, both driven by the panel's
   REAL content height rather than a guessed max-height (a fixed
   max-height is the usual way to fake this and the usual way it goes
   wrong: too small clips a tall panel, too large makes the animation
   visibly finish early and then sit idle while the unused remainder
   keeps interpolating). Grid with a single row sized 0fr when closed
   and 1fr when open, transitioning grid-template-rows, animates
   between "no height" and "exactly this content's height" with no
   guess involved — the technique needs the clipping (overflow:hidden,
   min-height:0) on the GRID ITEM, so the padding that used to live on
   .mega-panel moved to .mega-cols, the one child. No top border/radius
   either, since the panel now shares the header's own bottom border
   as its top edge rather than drawing a second line right under it. */
.mega-panel{position:absolute;top:100%;left:0;right:0;
  width:auto;overflow:hidden;
  background:var(--void2);border:1px solid var(--faint);border-top:none;
  border-radius:0 0 14px 14px;box-shadow:0 20px 44px rgba(0,0,0,.4);
  opacity:0;visibility:hidden;pointer-events:none;
  display:grid;grid-template-rows:0fr;
  transition:opacity .2s ease,visibility .32s,
             grid-template-rows .32s cubic-bezier(.4,0,.2,1);
  z-index:60}
.nav-item.has-mega:hover .mega-panel,
.nav-item.has-mega:focus-within .mega-panel,
.nav-item.has-mega.is-open .mega-panel{
  opacity:1;visibility:visible;pointer-events:auto;grid-template-rows:1fr}
/* The background is full-bleed (see .mega-panel above), but the
   CONTENT inside it should line up with everything else on the page —
   the logo, the nav, the body copy — not with the viewport edge. Same
   width/centering formula as .container, so "Homes & flats" starts at
   exactly the same x as "Acharya Gautam" above it, instead of a
   smaller, independent inset.

   justify-content stays at its flex-start default rather than
   space-between: space-between stretches the columns across the FULL
   row width regardless of how many there are, which looked fine for
   Vastu's three but, at this width, dragged Numerology's two apart to
   the opposite edges of a 1180px row with a canyon of empty space
   between them. Left-aligned with a fixed gap, both menus just read
   as "here are the columns", however many there are. */
.mega-cols{display:flex;flex-wrap:wrap;gap:8px 64px;min-height:0;
          overflow:hidden;
          width:min(1180px,100% - var(--gut)*2);margin-inline:auto;
          padding:22px 0}
.mega-col{min-width:188px}
.mega-col-h{display:flex;align-items:center;gap:7px;margin:0 0 10px;
           font-size:.7rem;letter-spacing:.09em;text-transform:uppercase;
           font-weight:600;color:var(--haldi)}
.mega-col-icon{flex:none;opacity:.9}
.mega-link{display:block;padding:7px 9px;margin:0 -9px;border-radius:7px;
          color:var(--chalk);text-decoration:none;font-size:.85rem;
          line-height:1.3;
          transition:background .15s ease,color .15s ease,transform .15s ease}
.mega-link:hover,.mega-link:focus-visible{background:rgba(255,255,255,.06);
                                         color:var(--haldi);
                                         transform:translateX(3px)}
.mega-link:focus-visible{outline:2px solid var(--haldi);outline-offset:-2px}
.mega-all{flex:0 0 100%;display:flex;align-items:center;gap:7px;font-weight:600;color:var(--haldi)}

/* HEADER SEARCH, 2 October 2026 — icon-only trigger (so it costs
   no extra width in a nav bar already carrying five items) that
   opens a small dropdown, not a full-width always-open search box.
   .nav-search sets its own position:relative so the panel anchors
   to the TRIGGER, unlike .mega-panel above (anchored to <header>
   itself, full-bleed) — this is a compact, right-aligned dropdown,
   not a mega menu, so it does not need that trick. */
.nav-search{position:relative}
.nav-search-trigger{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;border-radius:50%;background:none;border:none;color:var(--soft);cursor:pointer;padding:0;transition:color .15s ease,background .15s ease}
.nav-search-trigger:hover{color:var(--chalk);background:rgba(255,255,255,.06)}
.nav-search-trigger:focus-visible{outline:2px solid var(--haldi);outline-offset:2px}
.nav-search-trigger[aria-expanded="true"]{color:var(--haldi)}
.nav-search-panel{position:absolute;top:calc(100% + 14px);right:0;width:300px;max-height:360px;overflow-y:auto;background:var(--void2);border:1px solid var(--faint);border-radius:12px;box-shadow:0 20px 44px rgba(0,0,0,.4);padding:12px;z-index:70}
.nav-search-box{position:relative;margin:0 0 8px}
.nav-search-box svg{position:absolute;left:10px;top:50%;transform:translateY(-50%);color:var(--soft);pointer-events:none}
.nav-search-box input{width:100%;padding:9px 10px 9px 32px;border-radius:8px;border:1px solid var(--faint);background:rgba(255,255,255,.05);color:var(--chalk);font-family:inherit;font-size:.86rem}
.nav-search-box input::placeholder{color:var(--soft)}
.nav-search-box input:focus-visible{outline:2px solid var(--haldi);outline-offset:1px}
.nav-search-results{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:2px}
.nav-search-result{display:block;padding:8px 10px;border-radius:7px;color:var(--chalk);text-decoration:none;font-size:.85rem;line-height:1.3;transition:background .15s ease,color .15s ease}
.nav-search-result small{display:block;color:var(--soft);font-size:.7rem;margin-top:2px}
.nav-search-result:hover,.nav-search-result:focus-visible{background:rgba(255,255,255,.06);color:var(--haldi)}
.nav-search-result:focus-visible{outline:2px solid var(--haldi);outline-offset:-2px}
.nav-search-empty{margin:4px 0 0;color:var(--soft);font-size:.82rem}
/* MOBILE NAV, 2 October 2026 — this used to be just
   `.site-nav{display:none}` below 860px, with nothing to replace it.
   That was a deliberate call on 31 August 2026 ("a five-link nav on a
   one-page site is a convenience, not a feature worth a hamburger and
   its own focus trap") and it was right at the time — but the site
   has since grown vastu.html, numerology.html, shop.html and 23
   service pages, so a mobile visitor landing on any inner page had
   zero navigation. Reported directly: "i dont see the hamburger".
   Mirrors tools/navdata.py's mega_css() block of the same date —
   keep the two in sync if either changes. */
.nav-burger{display:none;flex:none;align-items:center;justify-content:center;flex-direction:column;gap:5px;
  width:40px;height:40px;border-radius:9px;border:1px solid var(--faint);background:none;padding:0;cursor:pointer}
.nav-burger-bar{display:block;width:18px;height:2px;border-radius:1px;background:var(--chalk);
  transition:transform .2s ease,opacity .2s ease}
.nav-burger[aria-expanded="true"] .nav-burger-bar:nth-child(1){transform:translateY(7px) rotate(45deg)}
.nav-burger[aria-expanded="true"] .nav-burger-bar:nth-child(2){opacity:0}
.nav-burger[aria-expanded="true"] .nav-burger-bar:nth-child(3){transform:translateY(-7px) rotate(-45deg)}
.nav-burger:hover{border-color:var(--haldi)}
.nav-burger:focus-visible{outline:2px solid var(--haldi);outline-offset:2px}

@media (max-width:860px){
  .nav-burger{display:inline-flex}
  .site-nav{position:fixed;top:75px;left:0;right:0;bottom:0;
    flex-direction:column;align-items:stretch;gap:0;
    background:var(--void2);border-top:1px solid var(--faint);
    padding:6px max(18px,env(safe-area-inset-left)) 28px;
    overflow-y:auto;-webkit-overflow-scrolling:touch;
    transform:translateY(-10px);opacity:0;visibility:hidden;pointer-events:none;
    transition:opacity .2s ease,transform .2s ease,visibility .25s;z-index:80}
  .site-nav.is-open{transform:translateY(0);opacity:1;visibility:visible;pointer-events:auto}
  .nav-link{width:100%;padding:14px 2px;font-size:.98rem;border-bottom:1px solid var(--faint)}
  .nav-link::after{display:none}
  .nav-item.has-mega{width:100%}
  .mega-trigger{width:100%;border-bottom:1px solid var(--faint);justify-content:space-between}
  .mega-trigger::before{display:none}
  /* Static + in-flow, not the desktop dropdown — see the block
     comment above for why. */
  .mega-panel{position:static;width:auto;opacity:1;visibility:visible;pointer-events:auto;
    background:none;border:none;box-shadow:none;border-radius:0;z-index:auto;
    display:grid;grid-template-rows:0fr;transition:grid-template-rows .25s ease}
  .nav-item.has-mega.is-open .mega-panel{grid-template-rows:1fr}
  .mega-cols{flex-direction:column;flex-wrap:nowrap;width:auto;margin:0;padding:4px 0 10px;gap:0}
  .mega-col{min-width:0}
  .mega-all{flex:0 0 auto;padding:11px 2px}
  .mega-col-h{margin:12px 0 6px}
  .mega-link{padding:11px 2px;margin:0}
  .nav-search{width:100%;padding:10px 0;border-bottom:1px solid var(--faint)}
  .nav-search-panel{position:static;width:auto;margin-top:10px;box-shadow:none;border:1px solid var(--faint)}
}
/* body.nav-open header, 3 October 2026 — "imenu is goinig behinde the
   body content". header{} has its own backdrop-filter (frosted-glass
   look), and backdrop-filter — same as transform/filter/perspective —
   makes its element the CONTAINING BLOCK for any position:fixed
   descendant. .site-nav.is-open above is position:fixed and lives
   inside <header>, so instead of measuring itself against the real
   viewport it was being measured against header's own box — a thin
   ~75px strip — and clipped to that, which is why only the top sliver
   of the panel (the Home link) painted at all and the real page
   showed through underneath. THE BURGER's openMenu()/closeMenu()
   toggle this class on <body> for exactly the window the panel is
   open, so header stops being a containing block and the panel is
   measured against the viewport like it was always meant to be.
   Mirrors tools/navdata.py's mega_css() of the same date — keep in
   sync if either changes. */
body.nav-open header{backdrop-filter:none;-webkit-backdrop-filter:none}

/* ---------- the fold ---------- */
/* ---------- the fold ----------
   Two columns again, in one screen. The form is back beside the hero, at
   its natural height, with no internal scrollbar.

   THE ONE CHANGE THAT MATTERS: align-items is START, not center.

   Centred, both columns sat in a row whose height was the taller of the
   two, and everything was positioned against that row — so growing the
   form grew the row and shifted the portrait, headline and social links.
   Top-aligned, the left column begins at the top of the row and stays
   there no matter how tall the card gets. The card can now grow freely
   without a fixed height or an inner scroll, and the page scrolls if a
   long service needs the room. */
/* ---------- the fold ----------
   TWO COLUMNS AGAIN, 1 October 2026 — the single-centred-column
   version (same day, earlier) stacked the portrait directly above a
   full column of text, which is the tallest the two can possibly sit
   together. Abhishek asked for the height back: portrait (with its
   zodiac-wheel illustration, see .portrait::before) on the right,
   content on the left, side by side instead of stacked. align-
   items:center rather than the old align-items:start, because there
   is no longer a tall carousel box on the right forcing .left to do
   its own internal centring — the grid can just centre both columns
   against each other directly. */
/* Top padding absorbs the fold-spacing the (now slim, sticky) header's
   old clamp(16px,3.4svh,34px) bottom padding used to provide — see the
   header CSS comment. clamp(20px,4.2svh,46px) ≈ the old two values
   added together, so first paint looks the same; only scrolled-down
   behavior changed. */
main{flex:1;display:flex;align-items:flex-start;
     padding:clamp(20px,4.2svh,46px) 0 clamp(10px,1.6svh,22px)}
.fold{
  display:grid;grid-template-columns:minmax(0,1.1fr) minmax(0,.9fr);
  gap:clamp(28px,4vw,60px);align-items:start;
  width:min(1180px,100% - var(--gut)*2);max-width:100%;margin-inline:auto;
}
.left{
  min-width:0;
}
.right{
  min-width:0;display:flex;justify-content:center;
}
/* a long unbroken word in the serif headline can still push a column
   past its share; let it break rather than blow the layout open */
h1,.intro{overflow-wrap:break-word;min-width:0}

.eyebrow{
  color:var(--amber);font-size:.72rem;letter-spacing:.17em;
  text-transform:uppercase;margin:0 0 12px;
}
h1{
  font-family:var(--serif);font-weight:400;
  /* svh in the clamp is what keeps this inside the fold on short screens */
  font-size:clamp(2.3rem,3.7vw + 1.2svh,4rem);
  line-height:1.02;letter-spacing:-.035em;margin:0 0 18px;
}
.intro{font-size:1rem;color:var(--dim);max-width:34em;margin:0 0 20px}

.tags{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 22px;padding:0;list-style:none}
.tags li{
  border:1px solid var(--edge-dim);border-radius:999px;padding:6px 13px;
  color:var(--softer);font-size:0.86rem;
}
/* The one-line "what and where". Sized between the intro and the small
   print: it has to be readable, not shouted, because its job is to answer
   a question a visitor actually has rather than to decorate. */
.where{
  margin:0 0 24px;max-width:44rem;
  color:var(--dim);font-size:0.86rem;line-height:1.7;
}

.social-title{color:var(--dim);font-size:0.72rem;letter-spacing:.17em;margin-bottom:9px}
.social{display:flex;gap:11px}
.social a{
  display:inline-flex;align-items:center;justify-content:center;
  width:42px;height:42px;border-radius:50%;
  border:1px solid var(--edge-lit);color:var(--soft);
  transition:border-color .2s,color .2s,background .2s;
}
.social a:hover{border-color:var(--amber);color:var(--lit);background:rgba(53,166,233,.14)}
.social a:focus-visible{outline:3px solid var(--amber);outline-offset:3px}
.social svg{width:20px;height:20px}
.social{flex-wrap:wrap}
.social a{transition:transform .2s,border-color .2s,color .2s,background .2s,box-shadow .2s}
.social a:hover,.social a:focus-visible{transform:translateY(-4px) scale(1.1);box-shadow:0 8px 20px rgba(0,0,0,.4)}
.social a[aria-label="Facebook"]:hover{color:#4599ff;border-color:#4599ff;background:rgba(69,153,255,.14)}
.social a[aria-label="Instagram"]:hover{color:#ff5c9a;border-color:#ff5c9a;background:rgba(255,92,154,.14)}
.social a[aria-label="YouTube"]:hover{color:#ff4b4b;border-color:#ff4b4b;background:rgba(255,75,75,.14)}
.social a[aria-label="LinkedIn"]:hover{color:#4da3e6;border-color:#4da3e6;background:rgba(77,163,230,.14)}
.social a[aria-label="WhatsApp"]:hover{color:#3fe07a;border-color:#3fe07a;background:rgba(63,224,122,.14)}

/* --fig is the single source of truth for the figure's size. The portrait
   and the halo behind it both derive from it, so a breakpoint can no
   longer resize one and leave the other behind.

   This also fixes the bug that made the wheel enormous: it was sized in
   percent, and percent here resolves against .portrait — a full-width
   block in the column, not the image. The wheel was being measured
   against the column and came out roughly twice the size intended.

   Width is pinned to --fig so the box hugs the portrait. Left as a plain
   block it filled the whole column, and since .zodiac is positioned
   against this box, the wheel's offset was set by whatever the column
   happened to measure — an accident, not a decision. It is now an
   explicit ratio on .zodiac below, which is what lets the homepage match
   this page exactly. */
/* --fig raised 25%, 1 October 2026 (later again), at Abhishek's
   request — every number in every clamp()/min() below is the old
   value * 1.25, so the fluid shape (how fast it grows with viewport
   width/height, and its floor/ceiling) is preserved exactly, just
   scaled up. */
.portrait{margin:0 0 18px;position:relative;width:var(--fig);
          --fig:clamp(369px,18.75vw + 15svh,538px)}
.portrait img{
  display:block;width:var(--fig);height:auto;
  filter:drop-shadow(0 18px 32px rgba(0,0,0,.62));
  position:relative;z-index:1;          /* above the wheel */

  /* Nudged down, 1 October 2026 (later again), at Abhishek's request
     ("move this image a little bit down to the center of the
     circle"). The wheel's own position can't move to fix this — see
     the long comment on .portrait::before below, its top edge is
     deliberately pinned to the portrait's top edge so it is never cut
     off under the sticky header, which leaves the wheel's visual
     CENTER sitting well below the image's own center (close to
     .45 * --fig below it, since the wheel is 1.9x the figure and the
     portrait is roughly square). Shifting the photo itself down
     instead moves it toward that center without touching the wheel.
     Not a full mathematical re-centering (that would push the man
     almost to the wheel's middle, which read as too low) — just
     enough to close most of the empty gap of circle below him. */
  transform:translateY(calc(var(--fig) * .14));
}

/* ---------- zodiac wheel ----------
   The wheel places the figure — it says "astrology" and gives the portrait
   somewhere to stand. It is a halo, so it is sized off the man rather than
   off the column, and the whole wheel is meant to read, sign names
   included. What keeps it clear of the headline is opacity, not cropping.

   TWO THINGS WERE WRONG HERE AND BOTH ARE NOW GONE.

   1. It was an <img>. A decorative image that 404s still occupies its box
      and can paint a placeholder — a rotating rectangle where a wheel
      should be. As a background-image a missing file paints NOTHING, which
      is the correct failure for decoration.

   2. The rim fade was a CSS mask, and the geometry was wrong: a
      radial-gradient with no size defaults to farthest-corner, which on a
      square element is the half-DIAGONAL. The stops landed up to 141% of
      the way to the edge, so the fade sat outside the artwork entirely and
      did nothing. It now lives inside the SVG as a real <mask>, where the
      radius is measured against the artwork itself and cannot be dropped
      by the browser.

   img/zodiac-wheel.svg: one colour declaration drives all 503 paths, so
   recolouring is a one-line edit in the file. Currently --haldi #3FB6EE.
   126KB gzipped against 275KB for an equivalent 1400px WebP. */
.portrait::before{
  content:'';
  position:absolute;left:50%;top:50%;

  /* 1.9x the figure — a ring around the man, not a field behind the page.
     Derived from --fig so it can never drift out of step again. */
  width:calc(var(--fig) * 1.9);aspect-ratio:1;

  /* NUDGED DOWN, 1 October 2026 (later again) — a *different* problem
     from the one the removed 87px/.164*fig offset above used to cause.
     Dead-centred, the wheel's top edge sits (1.9-1)/2 = .45 * --fig
     ABOVE the portrait's own top edge — at the old --fig that's ~194px,
     now ~242px with the 25%-bigger figure. .right/.fold are top-
     aligned directly under the sticky header with only
     clamp(20px,4.2svh,46px) of breathing room above the portrait, so
     that much of the wheel was rendering above the very top of the
     page: not merely covered by the header, genuinely off-canvas, with
     nowhere to scroll UP to reach it. That is what read as "the circle
     is cut off, not a full circle" in Abhishek's screenshot.

     The fix shifts the whole wheel down by exactly that .45 * --fig,
     so its top edge now lands AT the portrait's own top edge — zero
     overflow above, the one guaranteed-visible edge of this column —
     instead of dead-centred on it. The extra room goes to the BOTTOM
     overflow instead (.9 * --fig below the portrait), which is safe:
     that direction is simply more of the scrollable page, never
     off-canvas. Tied to --fig, like the 1.9x sizing above, so it keeps
     working at every breakpoint and through the 25% size bump without
     needing its own separate tuning. */
  transform:translate(-50%,calc(-50% + var(--fig) * .45));

  background:url("../img/zodiac-wheel.svg") center/contain no-repeat;

  /* Measured band by band against the artwork's ink map: at .10 nothing on
     the disc rises above 1.18:1, so it reads as texture and cannot compete
     with type. */
  opacity:.10;

  pointer-events:none;
  z-index:0;
  animation:zodiac-turn 240s linear infinite;
}
/* The translate has to be repeated inside the keyframe, or the element
   snaps back to its untranslated position the moment the animation
   takes over. */
@keyframes zodiac-turn{
  from{transform:translate(-50%,calc(-50% + var(--fig) * .45)) rotate(0deg)}
  to  {transform:translate(-50%,calc(-50% + var(--fig) * .45)) rotate(360deg)}
}

/* ---------- form ---------- */
/* ---------- the enquiry card ----------
   No fixed height and no internal scrollbar. It is as tall as the chosen
   service needs; the fold above is top-aligned, so nothing else on the
   page moves when it grows. */
/* ============================================================
   THE CARD IS A FIXED HEIGHT AND THE FIELDS SCROLL INSIDE IT.

   It used to be min-height:var(--fold-h) — a floor with no ceiling. The
   base form is 8 fields; choosing a service adds up to 5 more (Property
   Vastu and Non-Destructive Vastu are the worst, at 5 each). So the card
   went from 8 fields to 13, and because .fold is align-items:start the
   left column stayed put while this one grew past the fold. That is the
   misalignment: not a spacing problem, an uncapped column.

   height, not max-height. With max-height the card would still be
   SHORTER than the fold when few fields are showing and taller when
   many are — so it would still change size, just within bounds. A fixed
   height means picking a service changes nothing about the layout at
   all.

   The head and the submit button are pinned; only the fields between
   them move. Scrolling the whole card instead would carry "Send
   enquiry" off the bottom, and a submit button you have to go looking
   for is worse than a long form.
   ============================================================ */
.card{
  background:var(--void2);border:1px solid var(--faint);
  border-radius:14px;
  padding:var(--card-pad);
  height:var(--fold-h);
  display:flex;flex-direction:column;
}
.card-head{flex:none;margin-bottom:var(--fld-gap)}
/* min-height:0 IS LOAD-BEARING, HERE AND ON .form-body.

   A flex item defaults to min-height:auto, which refuses to shrink below
   its content. Without these two the form would simply push the card
   taller and overflow-y would never fire — the rule would look right and
   do nothing. This is the single most common way a flex scroll area
   silently fails. */
.card form{display:flex;flex-direction:column;flex:1;min-height:0}
.form-body{
  display:grid;gap:var(--fld-gap);align-content:start;min-width:0;
  flex:1;min-height:0;overflow-y:auto;
  /* Stop a flick at the end of this list from scrolling the page behind
     it. */
  overscroll-behavior:contain;
  /* A REAL GUTTER BESIDE THE FIELDS, NOT A BORROWED ONE.

     This was padding-right:6px with margin-right:-6px — the negative
     margin pulled the box back out so the scrollbar sat in the card's
     own padding. That works while the scrollbar is a faint hairline and
     stops working the moment it is visible: the thumb ends up nearly
     touching the inputs. The padding is now real and the negative margin
     is gone, so there is a column of space that belongs to the
     scrollbar. */
  padding-right:16px;
  /* scrollbar-gutter reserves the track ALWAYS, so the fields do not
     shift sideways by 10px the moment the content becomes long enough to
     scroll. Without it, picking a service nudges every input left. */
  scrollbar-gutter:stable;
  /* 'auto', not 'thin' — asked for a visible scrollbar. Firefox reads
     these two; WebKit reads the ::-webkit rules below. Both are needed,
     neither alone covers every browser. */
  scrollbar-width:auto;
  scrollbar-color:var(--edge-lit) rgba(255,255,255,.06);
  background:
    linear-gradient(var(--void2) 30%, rgba(22,39,47,0)) top    / 100% 22px no-repeat local,
    linear-gradient(rgba(22,39,47,0), var(--void2) 70%)  bottom / 100% 22px no-repeat local,
    radial-gradient(farthest-side at 50% 0,
                    rgba(0,0,0,.30), rgba(0,0,0,0))      top    / 100% 11px no-repeat scroll,
    radial-gradient(farthest-side at 50% 100%,
                    rgba(0,0,0,.30), rgba(0,0,0,0))      bottom / 100% 11px no-repeat scroll;
}
/* SCROLL SHADOWS, NO JAVASCRIPT.

   Two pairs of gradients. The 'local' ones scroll with the content; the
   'scroll' ones are fixed to the box. At the top of the list the local
   gradient sits over the fixed shadow and hides it; scroll down and it
   moves away, revealing it. So the shadow appears only when there is
   more to see and vanishes at each end — which is the whole point. A
   permanent fade would say "there is more" even at the bottom.

   The solid stops must be --void2, the card's own background, or the
   fade blends toward the wrong colour. */
/* Visible at rest, not only on hover. Safari and Chrome hide overlay
   scrollbars by default on a trackpad, which is exactly the case where
   nobody can tell the form scrolls at all — so the track is given a
   background of its own rather than left transparent. */
.form-body::-webkit-scrollbar{width:10px}
.form-body::-webkit-scrollbar-track{
  background:rgba(255,255,255,.06);border-radius:99px;
}
.form-body::-webkit-scrollbar-thumb{
  background:var(--edge-lit);border-radius:99px;
  /* The border is transparent and clipped to the padding box, which
     insets the thumb inside its track — a 10px bar with a 6px thumb,
     without needing a second element. */
  border:2px solid transparent;background-clip:padding-box;
}
.form-body::-webkit-scrollbar-thumb:hover{background:var(--amber)}
/* Pinned. flex:none so it keeps its height while .form-body takes the
   slack; the old margin-top:auto is no longer what holds it down. */
.submit-row{flex:none;padding-top:var(--fld-gap);display:grid;gap:11px}
/* CONSENT ROW.

   align-items:start, not center: the label wraps to three lines on a
   phone and a centred box would float beside the middle of the
   paragraph instead of sitting against its first line.

   accent-color paints the native checkbox's checked state without
   rebuilding the control out of a span and a pseudo-element. The
   rebuilt kind is where checkbox accessibility usually goes wrong —
   this one keeps the real input, so the space bar, the label click and
   every screen reader work because they were never taken away.

   18px is above the 16px that stops iOS zooming the page on focus, and
   the label is a real <label for>, so the whole sentence is a hit
   target — which matters more than the box size on a phone. */
.consent{display:flex;align-items:flex-start;gap:11px;margin:2px 0 0}
.consent input{
  width:18px;height:18px;flex:none;margin:2px 0 0;min-height:0;padding:0;
  accent-color:var(--amber);cursor:pointer;
}
.consent input:focus-visible{outline:3px solid var(--amber);outline-offset:3px}
.consent label{
  margin:0;font-size:.79rem;line-height:1.55;color:var(--dim);
  text-transform:none;letter-spacing:normal;cursor:pointer;
}
.consent a{color:var(--haldi)}
/* .svc-check, 4 October 2026 — a service-level optional checkbox
   (SvcFields.build()'s `{ type: 'checkbox' }` fields, first used for
   'addCall' on Detailed Vastu Report). Reuses .consent's exact shape
   (18px box, real input kept for a11y, label beside it) rather than
   letting it fall through the generic input/select/textarea rule
   below, which stretches a checkbox to fill a full-width bordered box
   — the oversized square Abhishek flagged with a screenshot. */
.svc-check{display:flex;align-items:flex-start;gap:11px;margin:0;cursor:pointer}
.svc-check input{
  width:18px;height:18px;flex:none;margin:2px 0 0;min-height:0;padding:0;
  accent-color:var(--amber);cursor:pointer;
}
.svc-check input:focus-visible{outline:3px solid var(--amber);outline-offset:3px}
.svc-check span{
  margin:0;font-size:.86rem;line-height:1.55;color:var(--chalk);
  text-transform:none;letter-spacing:normal;cursor:pointer;
}
/* Styled inert, still reachable. Not opacity on the whole button —
   opacity multiplies against whatever is behind it and the label would
   drop below AA on the amber fill. The fill is muted directly instead,
   and the label keeps a colour measured against it. */
button[aria-disabled="true"]{
  background:var(--void3);color:var(--dim);
  border:1px solid var(--faint);cursor:not-allowed;
}
button[aria-disabled="true"]:hover{background:var(--void3)}
.consent input[aria-invalid="true"]{outline:2px solid var(--alert);outline-offset:2px}
.card h2{
  font-family:var(--serif);font-weight:400;
  font-size:clamp(1.35rem,1.5vw + .5svh,1.8rem);margin:0 0 4px;
}
.card .lede{color:var(--dim);font-size:0.86rem;margin:0 0 16px}

form{min-width:0}
form > *,.form-body > *{min-width:0}
label{font-size:0.72rem;letter-spacing:.09em;color:var(--dim);
      display:block;margin-bottom:var(--lbl-gap);text-transform:uppercase}
input,select,textarea{
  width:100%;max-width:100%;min-width:0;padding:11px 14px;background:var(--void);
  color:var(--chalk);border:1px solid var(--edge-lit);border-radius:8px;
  font:inherit;font-size:.92rem;min-height:var(--ctl-h);
}
::placeholder{color:var(--hint2);opacity:1}
/* EVERY <select> ON THE FORM GETS THE SAME CHEVRON AS .tel select.
   Added 30 September 2026. Without appearance:none a <select> keeps
   whatever arrow the browser/OS draws — on Android Chrome that is a
   small grey triangle with no colour control, invisible or barely
   visible against this page's dark fields (--void), which is what
   "the dropdown arrow is not fixed" was pointing at on Property type,
   Type of office, Type of premises and every other select built by
   SvcFields.build(). .tel select solved this exact problem for the
   phone country code back when this form was written; this is the
   same fix, generalised to every select instead of just that one. */
select{
  appearance:none;-webkit-appearance:none;-moz-appearance:none;
  background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6' fill='none' stroke='%23A8B6BD' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1 1l4 4 4-4'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-size:11px 7px;
  background-position:right 14px center;
  padding-right:38px;
  cursor:pointer;
}
select::-ms-expand{display:none}
select option{background:var(--void2);color:var(--chalk)}
/* Firefox draws its own ring inside the control; this removes the
   double outline without losing the focus state, which comes from the
   :focus rule below. Same fix .tel select already carries. */
select:-moz-focusring{color:transparent;text-shadow:0 0 0 var(--chalk)}
input:focus,select:focus,textarea:focus{
  outline:none;border-color:var(--amber);box-shadow:0 0 0 3px rgba(53,166,233,.25);
}
/* THE INVALID STATE, AND WHY IT IS A RING AND NOT JUST A BORDER.

   This was border-color alone. A 1px hairline changing from --edge-lit
   to --alert is a real change and still easy to miss on a dark form
   with eight fields, especially when the thing that told you something
   was wrong is a line of text at the bottom. The ring gives the field a
   silhouette you can find while scrolling past it.

   It is deliberately the SAME shape as the focus ring three lines up —
   0 0 0 3px — because the page should have one idea of what "this
   control is being pointed at" looks like. Only the colour differs.

   COLOUR IS NOT DOING THIS ON ITS OWN. Every invalid field also gets
   its .err message below it, from mark(), and the summary above the
   button counts them. That is the rule in ART-DIRECTION §4: no state on
   this site is signalled by colour alone.

   textarea is in the list now. It was missing, so "Specific question or
   concern" could fail validation and show nothing at all.

   Measured: --alert on --void (the field fill) 6.16 — well past the 3:1
   WCAG 1.4.11 needs for a control boundary, and better than the normal
   --edge-lit at 4.71. The ring is decorative and carries no meaning the
   border does not already carry. */
input[aria-invalid="true"],
select[aria-invalid="true"],
textarea[aria-invalid="true"]{
  border-color:var(--alert);
  box-shadow:0 0 0 3px rgba(239,112,118,.14);
}
/* Focus must still be findable ON an invalid field, so the ring gets
   stronger rather than turning blue — going blue on focus would hide
   the error exactly when the person is trying to fix it. Later in the
   source than the :focus rule above, which is what makes it win. */
input[aria-invalid="true"]:focus,
select[aria-invalid="true"]:focus,
textarea[aria-invalid="true"]:focus{
  border-color:var(--alert);
  box-shadow:0 0 0 3px rgba(239,112,118,.38);
}
textarea{min-height:calc(var(--ctl-h) * 1.7);resize:vertical;line-height:1.5}
/* Dial code and number are one control visually — a single border round
   the pair, with a hairline between them, so it does not read as two
   unrelated fields sitting next to each other. */
/* 132px left about 95px for the text once the padding and the arrow were
   taken out — enough for "+91" and an ellipsis, which is why the country
   name disappeared on a phone. The column now scales with the space
   available instead of being a fixed guess. */
.tel{display:grid;grid-template-columns:clamp(146px,46%,158px) minmax(0,1fr);
     align-items:stretch}
.tel select{
  appearance:none;-webkit-appearance:none;-moz-appearance:none;
  background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6' fill='none' stroke='%23A8B6BD' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M1 1l4 4 4-4'/%3E%3C/svg%3E");
  background-repeat:no-repeat;background-size:11px 7px;
  cursor:pointer;
  width:100%;border-radius:8px 0 0 8px;border-right:0;
  font-size:0.86rem;
  padding-left:11px;padding-right:20px;
  background-position:right 6px center;
  font-size:0.92rem;
  text-overflow:ellipsis;white-space:nowrap;overflow:hidden;
}
.tel input{border-radius:0 8px 8px 0}
/* Firefox draws its own ring inside the control; this removes the double
   outline without losing the focus state, which comes from :focus above. */
.tel select:-moz-focusring{color:transparent;text-shadow:0 0 0 var(--chalk)}
.tel select option{background:var(--void2);color:var(--chalk)}
/* The focus ring must surround whichever half has focus without the other
   half painting over it. */
.tel select:focus,.tel input:focus{position:relative;z-index:1}
.tel select[aria-invalid="true"],.tel input[aria-invalid="true"]{border-color:var(--alert)}
@media(max-width:430px){ .tel{grid-template-columns:104px minmax(0,1fr)} }

/* ---------- searchable service picker ---------- */
/* ---------- place of birth ----------
   The same popup as the two service pickers, so the page has one idea of
   what a suggestion list looks like — but the behaviour underneath is
   different: matches arrive from the network, and anything typed is
   accepted whether it matches or not. */
.geo{position:relative}
.geo input{padding-left:38px}
.geo-pin{
  position:absolute;left:13px;top:50%;transform:translateY(-50%);
  width:15px;height:15px;color:var(--dim);pointer-events:none;
}
.geo input:focus ~ .geo-pin,.geo input:focus + .geo-pin{color:var(--haldi)}
/* A quiet spinner while a lookup is in flight. Never a blocking state:
   the field stays typable throughout. */
.geo-busy{
  position:absolute;right:13px;top:50%;margin-top:-7px;
  width:14px;height:14px;border-radius:50%;display:none;
  border:2px solid var(--faint);border-top-color:var(--haldi);
  animation:geo-spin .7s linear infinite;
}
.geo.is-busy .geo-busy{display:block}
@keyframes geo-spin{to{transform:rotate(360deg)}}
.geo .combo-list li{display:block}
.geo-sub{display:block;font-size:0.79rem;color:var(--dim);margin-top:2px}
@media(prefers-reduced-motion:reduce){ .geo-busy{animation-duration:2.4s} }

.combo{position:relative}
/* room for the chevron, and for the clear button once there is something
   to clear — otherwise a long service name runs underneath them */
.combo input{padding-right:38px}
.combo.has-value input{padding-right:66px}

/* CLEAR THE SELECTION.
   The list had no way out: once you picked something you could change it,
   but you could not go back to nothing. Typing over it left a stray query
   that the picker then discarded on blur, so the old answer came back.
   This is the way out — and it only exists when there is something to
   undo, so it never sits there as a dead control. */
.combo-clear{
  position:absolute;right:37px;top:50%;transform:translateY(-50%);
  width:22px;height:22px;display:none;
  background:none;border:0;padding:0;min-height:0;border-radius:50%;
  color:var(--dim);cursor:pointer;line-height:0;
  align-items:center;justify-content:center;
  transition:color .18s ease,background .18s ease;
}
.combo.has-value .combo-clear{display:flex}
.combo-clear:hover{color:var(--chalk);background:rgba(255,255,255,.08)}
.combo-clear:focus-visible{outline:2px solid var(--amber);outline-offset:2px}
.combo-clear svg{width:10px;height:10px}
.combo-toggle{
  position:absolute;right:1px;top:1px;bottom:1px;width:36px;
  /* every other button on this page is full-width and filled; this one
     has to opt out of all of it */
  background:none;border:0;color:var(--dim);cursor:pointer;
  display:flex;align-items:center;justify-content:center;
  min-height:0;padding:0;border-radius:0 8px 8px 0;
}
.combo-toggle svg{width:11px;height:7px;transition:transform .18s ease}
.combo[data-open="true"] .combo-toggle svg{transform:rotate(180deg)}

.combo-list{
  position:absolute;z-index:30;left:0;right:0;top:calc(100% + 6px);
  /* the fixed height that a native <select> would not give us */
  max-height:266px;overflow-y:auto;overscroll-behavior:contain;
  margin:0;padding:6px;list-style:none;
  background:var(--void2);border:1px solid var(--edge-lit);
  border-radius:10px;box-shadow:0 18px 38px rgba(2,10,15,.55);
}
/* Opens upward when there is more room above the field than below it
   inside the scrolling part of the modal. fitComboList() in the script
   decides and also overrides the max-height above with the room it
   actually measured — read the comment on that function first; the
   reason the list is NOT portalled to <body> is written there.

   top:auto is required, not tidiness: without it the rule above still
   applies and an element with both top and bottom set stretches. */
.combo-list.is-up{top:auto;bottom:calc(100% + 6px)}
.combo-list li{
  padding:10px 12px;border-radius:6px;cursor:pointer;
  font-size:.92rem;line-height:1.4;color:var(--chalk);
}
.combo-list li:hover,.combo-list li.is-active{background:rgba(6,147,217,.20)}
.combo-list li[aria-selected="true"]{color:var(--haldi);font-weight:500}
.combo-empty{padding:12px;color:var(--dim);font-size:0.86rem;text-align:center}

/* ---------- service-specific fields ----------
   No new visual language: these reuse the label / input / select /
   textarea / .err rules already defined above, so a field added to the
   config in six months inherits the form's styling for free.

   The wrapper matches the form's own grid gap, so the dynamic block sits
   in the same rhythm as the fixed fields rather than reading as a panel
   bolted underneath. It collapses to nothing when empty — :empty keeps a
   stray gap from appearing before a service is chosen. */
.svc-fields{display:grid;gap:var(--fld-gap);min-width:0}
.svc-fields:empty{display:none}

/* ---------- THE FEE, AND HOW IT IS DELIVERED ----------
   What was here: the 30/60/90 duration picker's styles. The rates are
   now per service, so the picker went; these rules did not, because the
   two-option online / site-visit choice for Vastu is the same control
   in a different hat — a radio card with a name and a price. Renaming
   .dur to .mode would have been a hundred-line diff that changed
   nothing a visitor can see, so the class names stayed and this comment
   explains why they read oddly. */

/* .fee-range styled a "fees run from Rs 3,500 to Rs 35,000" line that
   existed for a few hours, only because the exact fee could not be
   reached from the top of the form. Moving the service picker up made
   the real number reachable there, so the range went. Deleted rather
   than left dangling: this sheet is inlined, so a rule matching nothing
   ships on every visit. */

/* The panel directly under the service picker. */
.fee{margin:0;padding:13px 15px;background:var(--void3);
     border:1px solid var(--faint);border-radius:10px;min-width:0}
.fee:empty{display:none}
.fee-name{margin:0;font-size:.72rem;letter-spacing:.13em;
          text-transform:uppercase;color:var(--hint)}
.fee-amt{margin:4px 0 0;font-family:var(--serif);font-size:1.32rem;
         line-height:1.2;color:var(--haldi)}
.fee-when{margin:3px 0 0;font-size:.79rem;color:var(--dim)}
/* The travel terms for a site visit outside Mumbai, Navi Mumbai and
   Thane — section 29.7 of the blueprint. Shown only when a physical
   visit is the selected mode, because that is the only time it is
   true. */
.fee-note{margin:9px 0 0;font-size:.76rem;line-height:1.5;
          color:var(--hint)}
.fee .dur-set{margin:11px 0 0}
/* .fee-addon, 4 October 2026 — the optional add-on checkbox the Fee
   module now builds inside this panel (RATES[...].addon; see that
   property's own comment and Fee's paint()). Reuses .svc-check's exact
   shape, this class only adds the gap above it that .fee-when's own
   margin doesn't provide for a sibling checkbox row. */
.fee-addon{margin-top:11px}
/* .fee-addon-total, 4 October 2026 (later the same day) — the running
   total printed under the checkbox (Fee's paint()), so the visitor
   sees the real amount next to the toggle that changes it rather than
   having to look back up at .fee-amt. Styled like .fee-amt (serif,
   haldi) but smaller — it is a confirmation of a number already shown
   above, not the primary price. */
.fee-addon-total{margin:7px 0 0 29px;font-family:var(--serif);
                 font-size:1rem;color:var(--haldi)}

.dur-set{border:0;padding:0;margin:0 0 4px;min-width:0}
/* min-width:0 — a fieldset carries an intrinsic minimum width in every
   browser and will not shrink below its content, which is how one
   element inside a 375px modal ends up wider than the modal. */
.dur-set legend{padding:0;display:block;font-size:.8rem;font-weight:500;
                color:var(--soft);margin-bottom:7px}
.dur-row{display:grid;gap:8px}
/* Two columns, not three. The control now carries online vs site visit;
   repeat(3,1fr) left an empty third column and made the two cards
   narrower than the space they had. */
@media (min-width:520px){.dur-row{grid-template-columns:repeat(2,1fr)}}
.dur{position:relative;display:block;cursor:pointer}
/* Clipped, NOT display:none — a hidden input cannot take focus, so the
   keyboard would lose the control and the focus ring would have nothing
   to sit on. */
.dur input{position:absolute;width:1px;height:1px;
           overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
/* THE BORDER IS THE CONTROL. These cards have no fill and no native
   chrome — the real radio is clipped to a pixel — so the outline is the
   only thing saying "this is something you can choose". WCAG 1.4.11
   asks 3:1 for exactly that, and --faint is 1.63:1 against --void.
   It was invisible, and the failure was silent because the LABEL is
   perfectly readable: nothing looked broken, there just appeared to be
   text floating where a control should be.

   --edge-lit is 4.71:1 on --void, 4.06 on --void2 and 3.66 on --void3,
   so it clears the bar on every surface this card can land on. It was
   defined for this job and then used only on hover. */
.dur-in{position:relative;display:block;min-height:48px;padding:11px 34px 11px 13px;
        background:var(--void);border:1px solid var(--edge-lit);
        border-radius:9px;
        transition:border-color .18s ease,background .18s ease}
/* Hover lifts the SURFACE, not the border. The border used to go from
   --faint to --edge-lit on hover, which is now where it starts — so
   that rule had become a no-op and hover feedback would have vanished
   with the fix above. A surface change also leaves the border free to
   mean one thing only: --edge-lit resting, --amber chosen, --alert
   wrong. */
.dur:hover .dur-in{background:var(--void2)}
.dur input:focus-visible + .dur-in{outline:3px solid var(--amber);
                                   outline-offset:2px}
/* CHECKED IS NOT COLOUR ALONE — WCAG 1.4.1. The border thickens and the
   surface lifts, so the chosen option is distinguishable without hue. */
.dur input:checked + .dur-in{border-color:var(--amber);
                             background:var(--void3);
                             box-shadow:inset 0 0 0 1px var(--amber)}
/* A SECOND, NON-COLOUR SIGNAL ON TOP OF THAT ONE. The border/background
   change above already passes 1.4.1 in principle, but on this card pair
   — two similarly-worded options with only a border weight/colour
   difference between them — sighted users kept reporting they could not
   tell at a glance which one was actually chosen. A checkmark badge is
   a shape, not a colour, so it reads as "chosen" even at a glance or in
   grayscale. This is a CSS pseudo-element, not a real DOM node, so it
   adds nothing for a screen reader to trip over — the input's own
   checked state is already what gets announced there; this badge is
   for the eye only. */
.dur input:checked + .dur-in::after{
  content:'\2713'; /* a checkmark character, not an icon font — nothing to load */
  position:absolute;top:8px;right:8px;width:18px;height:18px;
  border-radius:50%;background:var(--amber);color:var(--void);
  font-size:12px;font-weight:700;line-height:18px;text-align:center;
}
.dur-t{display:block;font-size:.86rem;font-weight:500;color:var(--chalk)}
.dur-p{display:block;font-family:var(--serif);font-size:1.08rem;
       line-height:1.25;color:var(--haldi);margin-top:3px}
/* .dur-n styled the per-option tier name. It went with the label when
   the control moved above the service selects — see the note in the
   markup. Deleted rather than left: this sheet is inlined, so a rule
   matching nothing ships on every visit. */
/* .dur-usd carried "Outside India — $110 · $265 · $449" under the old
   ladder. There is no USD figure to show now: the blueprint's section
   27.6 asks for USD 125–799, the retired ladder said $110–$449, and the
   new INR card converts to something else again — three different
   answers, recorded as an open decision in section 28.8 item 2. Showing
   any one of them would be picking for Gautam. The rule is deleted
   rather than left dangling; this sheet is inlined, so a rule matching
   nothing ships on every visit. */
.dur-set[aria-invalid="true"] .dur-in{border-color:var(--alert)}
.svc-fields > *{min-width:0}
/* the two birth fields sit together — they are one question asked twice */
/* The date and time pair.
   This was a fixed two columns with a max-width:420px escape hatch, and
   420px was simply the wrong guess: a 430px phone stayed two-up and gave
   each field ~159px. A native date input on iOS needs more than that to
   show dd/mm/yyyy — below roughly 190px it renders as an empty-looking
   box, which is exactly what the screenshot showed.

   auto-fit means the row decides for itself: it only goes two-up when
   BOTH columns can actually be 190px. No breakpoint to get wrong, and no
   phone size can slip through it. */
.svc-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(190px,1fr));gap:12px}
.hint{font-size:0.79rem;color:var(--dim);margin:6px 0 0;line-height:1.45}
/* .field-note, 4 October 2026 — split out of .hint so a standalone
   note (SvcFields.build()'s `{ type: 'note' }` fields, e.g. "A 20-minute
   online call.") gets the same bordered box treatment as the
   input/select fields around it (background var(--void), border
   var(--edge-lit)) instead of sitting bare on the modal's own darker
   background (var(--void3)) — see that function's own comment for the
   report this came from. .hint itself is untouched and still used for
   the small per-field helper line under an individual input. */
.field-note{font-size:0.82rem;color:var(--dim);line-height:1.55;
            background:var(--void);border:1px solid var(--edge-lit);
            border-radius:8px;padding:11px 14px;margin:0}
/* .upload-status, 2 October 2026 — the "Attaching…" / "<name> attached."
   / error line wireUpload() shows under the plan-upload field in
   js/enquiry-engine.js. Shares .hint's sizing; .upload-err swaps in the
   same red already used for .err's validation messages, so an upload
   problem reads the same way a field error does rather than inventing
   a third colour for "something went wrong". */
.upload-status.upload-err{color:var(--alert)}
/* Section heading inside the dynamic block. Kundli matching asks for two
   birth charts; without a heading over each, six near-identical fields
   read as one confusing list. */
.svc-head{font-size:0.72rem;letter-spacing:.13em;text-transform:uppercase;
          color:var(--haldi);margin:6px 0 -4px;font-weight:600}
.svc-fields > .svc-head:first-child{margin-top:0}
/* Native file inputs cannot be styled directly; the button inside them can,
   and the control itself takes the same box as every other field. */
.svc-fields input[type="file"]{padding:8px 10px;font-size:.86rem;cursor:pointer}
.svc-fields input[type="file"]::file-selector-button{
  font:inherit;font-size:0.86rem;margin-right:10px;padding:6px 12px;
  border-radius:6px;border:1px solid var(--edge-lit);
  background:var(--void2);color:var(--chalk);cursor:pointer;
}
.svc-fields input[type="file"]::file-selector-button:hover{border-color:var(--amber)}
/* THE DATE AND TIME FIELDS WERE TALLER THAN EVERY OTHER CONTROL.

   --ctl-h is applied as min-height, and min-height cannot pull a control
   DOWN — it only stops it going below. iOS gives input[type=date] and
   [type=time] their own intrinsic height from the native picker, which
   sits above 48px, so those two boxes stood proud of the email, phone and
   place fields beside them.

   An explicit height fixes it, and the vertical padding has to go with it
   or the value gets pushed out of a box that can no longer grow.

   input[type="time"] USED TO BE HERE TOO, until 28 September 2026: a
   real visitor found it completely unusable on their phone — focused
   but no picker opened and no typing registered. Two attempts at
   fixing the native control with CSS alone (recorded in
   PROJECT-STATE.md Version 23.0, in case this history is ever useful
   again) were not something I could actually confirm without a real
   device to test on, so #tob was rebuilt as a plain text field
   instead — see the markup comment there. This rule and the two
   below are now input[type="date"] only, because that is the only
   native date/time picker left on the page, and it was never the one
   that broke. */
input[type="date"]{
  height:var(--ctl-h);
  padding-top:0;padding-bottom:0;
  /* ---- IT WAS ALSO WIDER THAN THE BOX. ----

     On iOS this carries an INTRINSIC WIDTH from the native picker,
     the same way it carries an intrinsic height. width:100% does not
     beat it, because the intrinsic size acts as a floor — so on a
     390px phone the date field hung ~40px past the right edge of the
     card while email and phone sat correctly inside it.

     -webkit-appearance:none is what removes that floor. min-width:0 is
     belt and braces: it sits in a grid cell, and a grid item defaults
     to min-width:auto, which also refuses to shrink below content. */
  -webkit-appearance:none;appearance:none;
  width:100%;min-width:0;max-width:100%;
}
/* The grid ITEM, not just the input. minmax(190px,1fr) sizes the track;
   the div inside it still has min-width:auto and would be pushed wide by
   its own content. This is the same fault one level up. */
.svc-row > *{min-width:0}

/* Date and time pickers draw their own indicator, black by default — all
   but invisible on a dark field.

   THIS RULE WAS SCOPED TO .svc-fields, which was right when the birth
   fields were built by script. Version 6.0 moved them into static markup
   at the top of the form and the selector was left behind, so the icons
   went dark. It is unscoped now: any date or time input on the page gets
   it, wherever it lives. */
/* ============================================================
   AN IN-FIELD HINT FOR DATE AND TIME.

   iOS renders an EMPTY date input completely blank — no dd/mm/yyyy, no
   placeholder, nothing. The screenshot showed two empty boxes that could
   have been anything. The format was already written underneath in
   .hint, but a hint below an apparently broken field is read after the
   confusion, not before it.

   HOW IT WORKS, AND WHY IT IS NOT JUST AN OVERLAY.

   Desktop Chrome DOES draw its own dd/mm/yyyy, so an overlay alone would
   double up. So the two are swapped rather than stacked: while the field
   is empty and unfocused, the browser's own editor text is hidden and
   ours shows. Focus it, or give it a value, and the native one comes
   back and ours goes.

   The whole thing is inside @supports selector(::-webkit-datetime-edit).
   Firefox cannot hide its native placeholder, so in Firefox none of this
   applies and its own dd/mm/yyyy is left alone — which is correct, since
   Firefox never had the problem.

   pointer-events:none on the span, or tapping the middle of the field
   would hit the span instead of opening the picker. */
.dtf{display:block;position:relative}
.dtf-ph{display:none}

@supports selector(::-webkit-datetime-edit){
  .dtf-ph{
    display:flex;align-items:center;
    position:absolute;inset:0;
    /* matches the input's own 14px padding plus its 1px border */
    padding-left:15px;
    color:var(--hint);font-size:.95rem;letter-spacing:.02em;
    pointer-events:none;
  }
  .dtf.has-value .dtf-ph,
  .dtf.is-focus .dtf-ph{display:none}
  .dtf:not(.has-value):not(.is-focus) input::-webkit-datetime-edit{opacity:0}
}

input[type="date"]::-webkit-calendar-picker-indicator{
  filter:invert(78%) sepia(9%) saturate(400%) hue-rotate(157deg);cursor:pointer;
}
/* a thin scrollbar that belongs to the page rather than the OS */
.combo-list::-webkit-scrollbar{width:10px}
.combo-list::-webkit-scrollbar-thumb{background:var(--edge-lit);
  border-radius:99px;border:3px solid var(--void2)}

.err{display:none;color:var(--alert);font-size:.79rem;margin:5px 0 0}
.err.show{display:block}
.err.summary{font-weight:600;margin:0}
/* the button and its footnote are one block, spaced tighter than
   the 18px that separates one field from the next */
/* Scrolls with the fields — only the title and the standfirst above stay
   put. No hairline: it was there to mark the end of the scroll area, and
   the scroll area now runs past it to the bottom of the card. */
/* .submit-row was declared twice at top level — layout in one place,
   the grid in another. Both sets moved into the single rule above. A
   comment excusing a duplicate is not as good as not having one. */
button{
  border:0;background:var(--amber);color:var(--on-fill);padding:13px 20px;
  border-radius:8px;font-weight:600;font-size:1rem;cursor:pointer;
  min-height:48px;width:100%;
}
button[disabled]{opacity:.6;cursor:default}
.again{
  background:none;color:var(--amber);
  border:1px solid var(--edge-lit);
  font-weight:400;font-size:0.92rem;min-height:42px;width:auto;
  padding:10px 20px;margin-top:18px;margin-bottom:0;
  transition:border-color .2s,color .2s,background .2s;
}
.again:hover{border-color:var(--amber);color:var(--lit);background:rgba(53,166,233,.12)}
.again:focus-visible{outline:3px solid var(--amber);outline-offset:3px}
.form-note{display:none;margin:0;font-size:0.86rem;color:var(--alert)}
.form-note.show{display:block}
.alt{color:var(--dim);font-size:0.79rem;margin:0;text-align:center}
.privacy-note{color:var(--dim);font-size:0.79rem;line-height:1.5;
              margin:0;text-align:center}
.privacy-note a{color:var(--amber)}
.alt a{color:var(--amber)}

/* confirmation */
.sent{display:none;text-align:center;padding:14px 0}
/* margin:auto on a flex child centres it in the column. The card is a
   fixed height now, so without this the confirmation sat at the top of
   a tall panel with the rest of it empty — it read as though something
   had failed to load below. */
.sent.show{display:block;margin:auto 0}
.sent-tick{
  width:50px;height:50px;margin:0 auto 14px;border-radius:50%;
  border:2px solid var(--tulsi);color:var(--tulsi);
  display:flex;align-items:center;justify-content:center;
}
.sent-tick svg{width:24px;height:24px}
.sent h3{font-family:var(--serif);font-weight:400;
         font-size:1.5rem;margin:0 0 8px}
.sent p{color:var(--dim);margin:0;font-size:.92rem}
.sent-recap{margin-top:16px !important;padding-top:14px;
            border-top:1px solid var(--faint);text-align:left;font-size:0.86rem}

/* ---------- areas of guidance ----------
   Placed BELOW the fold, not inside the hero. The 27 services are the
   words people actually type into a search — kundli matching, non-
   destructive Vastu, business growth — and until now they existed only
   as options inside a JavaScript dropdown, which search engines do not
   reliably read.

   Below the fold on purpose: the hero is a composition that took a long
   time to settle, and this does not belong in it. Here it earns the page
   its vocabulary without touching anything above. */
/* ================= SERVICE ARCHITECTURE =================
   Generated markup — see tools/build-services.py. Twenty-seven entries,
   every one of them a real control that opens the consultation form
   with that service already chosen.

   THESE LOOK NOTHING LIKE .sl-subs, AND THAT IS THE POINT.

   The carousel's sub-service tags are outlined pills with no hover and
   no cursor, because they are labels that do nothing. These are the
   opposite: they DO something, so they get an underline, a hover, a
   focus ring and a pointer. Two lists of the same service names, a
   screen apart, and a person can tell which one is clickable without
   trying it. That distinction is only worth anything if it is kept.

   NOT FILLED BUTTONS. The global button{} rule paints every <button>
   with --amber, which would put 27 solid amber blocks on one screen and
   break the one-filled-button-per-view rule four times over. Everything
   in .svc-list button is undoing that rule, which is also why the rule
   has already had to be undone for .sarthi-open, .sar-chip and
   .vcta-btn. It is the most expensive declaration in this stylesheet.

   <button>, not <a>. There is no URL to go to — it opens a dialog. An
   anchor with href="#" would promise navigation it cannot deliver and
   would break middle-click and "open in new tab" for anyone who tried. */
/* THE SERVICES SECTION'S STYLES WENT WITH THE SECTION, 31 Aug 2026.

   .svc, .svc-lede, .svc-all, .tile-grid, .tile, .tile-in, .tile-say,
   .tile-svcs and .tile-svc all styled "What Acharya Gautam advises on",
   which was removed. Roughly 4.6 KB of rules that matched nothing.

   Deleted rather than left in place. Dead CSS is not free: it is read
   as part of the system by whoever comes next, gets copied into a new
   component because it looks like the house style, and ships on every
   page load of a page that no longer has the markup. This sheet is
   inlined into one file, so every byte of it is in the critical path.

   The names are listed above so a search for any of them lands here
   and finds out where they went, rather than finding nothing. */

/* The top menu's styles went with the menu — .nav, .nav a/.nav button,
   .nav-book, and the 720px rule that hid the lot on a phone. About
   1.1 KB matching nothing.

   Deleted, not commented out: this sheet is inlined, so a dead rule
   ships on every visit, and a selector that matches nothing gets
   copied into the next component because it looks like house style.
   The names are here so a search for `.nav` finds an explanation. */

.svc-note{margin:0;color:var(--hint);font-size:.76rem;line-height:1.55;
          max-width:46ch}
/* The one caveat allowed to be louder than the text above it — see the
   same rule on the old .area-safe. */
.svc-safe{color:var(--soft);margin-top:6px}
.areas-where{margin:26px 0 0;color:var(--dim);font-size:0.86rem;line-height:1.7;
             max-width:72ch}
.areas-where strong{color:var(--softer);font-weight:500}

/* ============================================================
   HERO CTAs + THE PROBLEM/SOLUTION CAROUSEL
   Replaced the enquiry form in the right column.
   ============================================================ */
.hero-cta{display:flex;flex-wrap:wrap;gap:10px;margin:0 0 22px}
.h-cta,.h-alt{
  width:auto;                          /* global button{width:100%} */
  display:inline-flex;align-items:center;justify-content:center;gap:9px;
  padding:13px 24px;min-height:50px;box-sizing:border-box;
  border-radius:999px;
  font-family:var(--sans);font-size:.95rem;font-weight:600;cursor:pointer;
  transition:filter .2s,transform .2s,border-color .2s,background .2s,color .2s;
}
/* One filled button per view — DESIGN-SYSTEM.md §2. Booking is it. */
.h-cta{border:0;background:var(--amber);color:var(--on-fill)}
.h-cta:hover{filter:brightness(1.08);transform:translateY(-1px)}
.h-alt{border:1px solid var(--edge-lit);background:none;color:var(--soft)}
.h-alt:hover{border-color:var(--amber);color:var(--lit);background:rgba(53,166,233,.14)}
.h-cta:focus-visible,.h-alt:focus-visible{outline:3px solid var(--haldi);outline-offset:3px}
.h-alt .si{width:20px;height:20px;flex:none;--si-line:currentColor;--si-robe:var(--haldi)}
@media (max-width:560px){ .hero-cta{flex-direction:column} .h-cta,.h-alt{width:100%} }

/* ---- the carousel ----
   REMOVED 1 October 2026, at Abhishek's request. The hero's right
   column (.slides#slides: "Where people usually start", six swipeable
   topic cards behind prev/next arrows and dots) is gone — all of
   .sl-head/.sl-view/.sl-track/.sl/.sl-fig/.sl-cat/.sl-subs/.sl-ask/
   .sl-how/.sl-say/.sl-foot/.sl-arrow/.sl-dots/.sl-dot went with it,
   along with the JS that drove it ("THE HERO CAROUSEL", further down
   this file). .fold dropped from a two-column grid to one centred
   column — see the comment on .fold itself, just above .left, for the
   layout reasoning that no longer applies now there is no second
   column to match heights with. Sarthi (the chat assistant) is
   untouched: its hero button, launcher and chat panel live elsewhere
   and never depended on this carousel existing. */
@media (prefers-reduced-motion:reduce){
  .h-cta:hover{transform:none}
}

/* ---- the consultation modal ---- */
.cscrim{
  position:fixed;inset:0;z-index:80;
  background:rgba(4,12,17,.88);
  -webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);
  display:grid;place-items:center;padding:clamp(12px,4vw,40px);
  opacity:0;visibility:hidden;transition:opacity .2s ease,visibility .2s;
}
.cscrim.is-open{opacity:1;visibility:visible}
.cbox{
  position:relative;width:min(640px,100%);max-height:92svh;
  display:flex;flex-direction:column;
  background:var(--void3);border:1px solid var(--edge-lit);border-radius:16px;
  box-shadow:0 0 0 1px rgba(3,9,12,.9),
             0 18px 38px -14px rgba(0,0,0,.8),
             0 48px 96px -40px rgba(0,0,0,.95);
  transform:translateY(10px) scale(.985);
  transition:transform .22s cubic-bezier(.2,.8,.3,1);
}
.cscrim.is-open .cbox{transform:none}
.cbox-top{flex:none;display:flex;align-items:flex-start;gap:14px;
          padding:22px 22px 16px;border-bottom:1px solid var(--faint)}
.cbox-top h2{margin:0 0 4px;font-family:var(--serif);font-weight:400;
             font-size:1.5rem;color:var(--chalk)}
.cbox-top p{margin:0;color:var(--dim);font-size:.88rem;line-height:1.55}
/* --edge-lit, and it used to say var(--edge) — a token that is not
   defined anywhere in this file.

   An undefined custom property inside a SHORTHAND takes the whole
   declaration down: `border:1px solid var(--edge)` was invalid at
   computed-value time, so border-style stayed at its initial `none` and
   this button has never had the outline it was drawn with. The same
   line appears on .sarthi-x, so both close buttons on the site were
   bare glyphs. It is visible in the modal screenshots and reads as a
   stray x rather than a control.

   --edge-lit is the documented token for a border on a raised surface,
   and it is the only one of the three that clears WCAG 1.4.11 where
   these buttons actually sit: on --void3 it measures 3.66, against
   3.31 for --edge-dim and 1.27 for --faint. A close button is a UI
   component, so 3:1 is required, not optional. */
.cbox-x{
  width:36px;height:36px;flex:none;min-height:0;padding:0;border-radius:50%;
  margin-left:auto;background:none;border:1px solid var(--edge-lit);color:var(--dim);
  display:grid;place-items:center;cursor:pointer;transition:border-color .2s,color .2s;
}
.cbox-x:hover{border-color:var(--amber);color:var(--chalk)}
.cbox-x:focus-visible{outline:3px solid var(--amber);outline-offset:2px}
.cbox-x svg{width:16px;height:16px}
/* The form scrolls, the title and the close stay. Same reasoning as
   Sarthi's panel: a submit button you have to hunt for is worse than a
   long form. */
.cbox-body{flex:1;min-height:0;overflow-y:auto;padding:20px 22px 22px;
           overscroll-behavior:contain}
/* The card came from the hero with its own frame. Inside the modal the
   modal IS the frame, so it drops its own. */
.cbox-body .card{background:none;border:0;border-radius:0;padding:0;
                 height:auto;min-height:0}
/* ============================================================
   ONE SCROLL CONTAINER INSIDE THE MODAL. NOT TWO.

   The bug this fixes: after choosing a service the extra fields render,
   the browser scrolls the newly focused field into view — and then the
   form could not be scrolled back UP.

   Why. The card was built for the hero, where it is a fixed --fold-h
   box and .form-body is the part that scrolls inside it. The modal sets
   .card height:auto, so .form-body is as tall as its content and has
   nothing to scroll. But it is still declared overflow-y:auto, and an
   overflow:auto box is a scroll container even with zero scrollable
   range — so overscroll-behavior:contain on it SWALLOWED the wheel
   instead of chaining it up to .cbox-body, the container that was
   actually scrolled. Pointer over the fields, which is most of the
   modal, meant the wheel did nothing.

   That is also why the fields sat further from the right edge than the
   header: padding-right + scrollbar-gutter were reserving a track for a
   scrollbar that can never appear here.

   Two nested scroll containers is the underlying mistake; the wheel is
   just where it showed. Inside the modal .cbox-body scrolls and nothing
   inside it does. The hero card is untouched — it still scrolls its own
   .form-body, because there it genuinely has a bounded height.

   overflow:visible also un-clips the open dropdown, which is why
   fitComboList() looks for .cbox-body BEFORE .form-body. Change one and
   the other has to change with it. */
.cbox-body .card form{flex:none;min-height:0}
.cbox-body .form-body{
  flex:none;min-height:0;
  overflow:visible;overscroll-behavior:auto;
  padding-right:0;scrollbar-gutter:auto;
}
.cbox-body .card-head{display:none}   /* the modal header says it already */
/* Near full screen on a phone, per §9. */
@media (max-width:560px){
  .cscrim{padding:0;place-items:stretch}
  .cbox{width:100%;max-height:100svh;height:100svh;border-radius:0;border:0}
  /* THE MODAL'S OWN PADDING BECOMES THE PAGE MARGIN HERE, so it has to
     be the page's margin.

     Above this breakpoint the modal floats inside .cscrim's padding and
     its 22px is internal card padding — a different job, left alone.
     Below it the scrim's padding goes to zero and the box is edge to
     edge, at which point 22px IS the distance from the screen edge to
     the text. The page uses --gut everywhere else, whose floor is 24px,
     so every field in the modal sat 2px closer to the bezel than every
     other line of text on the site.

     Two pixels is not much to look at. It is the kind of difference
     nobody can name and everybody can feel when the modal opens over
     the page — and the page has one number for this, written down as a
     token, which the modal was quietly not using.

     Horizontal only: the shorthands above set the vertical padding
     asymmetrically (22/16 on the header, 20/22 on the body) and those
     are deliberate. */
  .cbox-top,
  .cbox-body{padding-left:var(--gut);padding-right:var(--gut)}
}
@media (prefers-reduced-motion:reduce){
  .cscrim,.cbox{transition:none}
}

/* The client-video player. Reuses .vscrim for the backdrop and .vclose
   for the button; only the frame differs, because these are portrait.

   Capped by HEIGHT and the width derived from it. aspect-ratio with a
   max-height does not letterbox — the height simply wins and the
   picture stretches. That was learned the hard way once already. */
.vobox{
  position:relative;
  width:min(calc(min(78svh,760px) * 9 / 16), calc(100vw - 32px));
  display:flex;flex-direction:column;
  transform:translateY(10px) scale(.985);
  transition:transform .22s cubic-bezier(.2,.8,.3,1);
}
.voscrim.is-open .vobox{transform:none}
.voframe{width:100%;aspect-ratio:9/16;border-radius:14px;overflow:hidden;
         background:#000;border:1px solid var(--edge-lit)}
.voframe video{width:100%;height:100%;display:block;object-fit:cover}
@media (prefers-reduced-motion:reduce){ .vobox{transition:none} }

/* ---- IN THEIR OWN WORDS ----
   Same card treatment as the showcase below it, so the two read as one
   sequence rather than two ideas that happen to be adjacent. */
/* TWO FAULTS CAME WITH THE MOVE, AND BOTH ARE THE SAME MISTAKE.

   body is display:flex, so SIBLING MARGINS DO NOT COLLAPSE here. In
   normal flow the 48px above and the 44px below would have merged into
   48; in a flex column they add up to 92 — about double every other gap
   on the page.

   And this band now sits between the showcase and .areas, which draws a
   full-width border-top. With no bottom margin that rule lands hard
   against the rounded card, which is the exact "two lines a few pixels
   apart" fault fixed on the showcase a few versions ago. Moving a
   section moved the bug with it.

   So: the same margin shape as .showcase-sec, and the adjacent-sibling
   rule below cancels the doubling where the two meet. */
.voices{flex:none;margin:clamp(20px,4svh,44px) 0 var(--sec-gap)}
.showcase-sec + .voices{margin-top:0}
.voices .container{background:var(--void2);border:1px solid var(--edge-lit);
                   border-radius:14px;padding:clamp(22px,3vw,40px)}
/* SAME TYPE AS THE SIGNATURE SERVICE BAND.

   This was 1.05rem, matching .watch and .areas — the small heading used
   for a shelf of things. That was the wrong company to keep. Those two
   are lists; this is proof, and proof is the strongest thing on the
   page after the claim it supports.

   Values copied from .wedge-eyebrow / .wedge-in h2 / .wedge-lede rather
   than approximated, so the two bands are identical rather than
   nearly so. */
.voices-eyebrow{display:block;font-size:.72rem;letter-spacing:.13em;
                text-transform:uppercase;font-weight:600;color:var(--haldi);
                margin-bottom:10px}
.voices h2{font-family:var(--serif);font-weight:400;
           font-size:clamp(1.5rem,3.2vw,2.1rem);line-height:1.12;
           letter-spacing:-.015em;margin:0 0 14px;color:var(--chalk)}
/* The three-part line sits between the heading and the paragraph. A
   step brighter than body copy and a step quieter than the heading, so
   the eye reads heading, claim, explanation in that order. --soft
   rather than --chalk: at --chalk it competes with the h2 above it. */
/* NO 46ch CAP HERE.

   That number was copied from .wedge-lede, which sits in a HALF-width
   column — 46ch is right there and wrong in a band that spans the whole
   card. It was folding two short sentences into four lines with the
   right half of the card empty.

   Uncapped is normally a readability problem: this card is about
   1100px inside its padding, which is roughly 130 characters, well past
   the 75ch where the eye starts losing its place tracking back.

   It is fine HERE because both lines are short. The tagline sits on one
   line and the paragraph on two, so there is barely any tracking back
   to lose. If either ever grows past three lines, put a cap back. */
.voices-tag{color:var(--soft);font-size:1rem;line-height:1.6;
            font-weight:500;margin:0 0 10px}
.voices-lede{color:var(--dim);font-size:0.92rem;line-height:1.7;
             margin:0 0 22px}
/* Three portrait clips. Not six — they are people rather than content,
   and a wall of faces reads as stock photography. */
.vc-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:12px;
         margin:0;padding:0;list-style:none}
@media (max-width:620px){ .vc-grid{grid-template-columns:repeat(2,1fr)} }
@media (max-width:400px){ .vc-grid{grid-template-columns:1fr} }
.vc{
  width:100%;padding:0;min-height:0;border-radius:10px;overflow:hidden;
  position:relative;display:block;cursor:pointer;
  background:var(--void);border:1px solid var(--faint);
  transition:border-color .2s,transform .2s;
}
.vc:hover{border-color:var(--amber);transform:translateY(-2px)}
.vc:focus-visible{outline:3px solid var(--amber);outline-offset:3px}
/* 4:5, NOT THE SOURCE'S 9:16.

   Three 9:16 cards at 324px wide are 576px tall, and most of that is
   the wall behind somebody's shoulders. Cropped to 4:5 they are 405px —
   30% shorter — and nothing that matters is lost.

   object-position 22% from the top is the number that makes it safe. A
   phone selfie puts the face in the upper third; centre-cropping a
   9:16 to 4:5 takes the crop out of the middle and cuts foreheads.
   Checked against all three at 9:16, 3:4, 4:5 and 1:1 before choosing —
   1:1 is shorter still and starts clipping. */
.vc img{display:block;width:100%;height:auto;
        aspect-ratio:4/5;object-fit:cover;object-position:center 22%}
.vc-play{
  position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);
  width:44px;height:44px;border-radius:50%;display:grid;place-items:center;
  background:rgba(8,20,26,.72);color:var(--lit);transition:background .2s;
}
.vc:hover .vc-play{background:var(--amber);color:var(--on-fill)}
.vc-play svg{width:19px;height:19px;margin-left:2px}
/* Duration on the card. It is the one thing somebody wants to know
   before pressing play on a stranger talking. */
.vc-len{
  position:absolute;right:8px;bottom:8px;
  padding:3px 8px;border-radius:5px;
  background:rgba(6,14,18,.82);color:var(--soft);
  font-size:.72rem;font-weight:600;letter-spacing:.02em;
}
@media (prefers-reduced-motion:reduce){ .vc,.vc-play{transition:none} .vc:hover{transform:none} }

/* ---- SIGNATURE SERVICE + WATCH: one box ----
   Added 26 Aug 2026.

   THE BOX GOES ON THE WIDTH-LIMITED ELEMENT.

   First version put the panel on the <section>. A section is
   block-level, so it filled the viewport, and .container centred the
   content inside it — the border ran off both edges of the screen while
   the text sat in a 1180px column in the middle. .showcase now carries
   BOTH the width cap and the panel, so the two cannot come apart again.

   min(1180px, 100% - gut*2) is the same expression .container and .fold
   use, so this box lines up exactly with the fold above it. Copied
   deliberately rather than nesting .container inside — nesting is what
   caused the bug. */
/* Margin on BOTH ends. It was `clamp(...) 0 0` — top only — so .areas
   below, which carries a full-width border-top, drew its rule hard
   against the bottom edge of this box. Two lines a few pixels apart,
   one rounded and one not, reads as a rendering fault rather than as a
   divider. */
.showcase-sec{flex:none;margin:clamp(20px,4svh,44px) 0 var(--sec-gap)}
.showcase{
  width:min(1180px,100% - var(--gut)*2);max-width:100%;margin-inline:auto;
  background:var(--void2);border:1px solid var(--edge-lit);
  border-radius:14px;overflow:hidden;
}
.showcase-part{padding:clamp(22px,3vw,40px)}
/* The rule spans the full box, so it is a divider between two parts of
   one card rather than an underline on the part above it. */
.showcase-split{height:1px;background:var(--faint)}

/* ---- top half: the claim ---- */
.wedge-in{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);
          gap:clamp(20px,3vw,40px);align-items:center}
/* minmax(0,1fr), not a bare 1fr: a bare 1fr keeps min-width:auto, so the
   thumbnail would push its column — and the page — wider than the
   viewport on a narrow screen. */
@media (max-width:780px){ .wedge-in{grid-template-columns:minmax(0,1fr)} }
.wedge-eyebrow{display:block;font-size:.72rem;letter-spacing:.13em;
               text-transform:uppercase;font-weight:600;color:var(--haldi);
               margin-bottom:10px}
.showcase h2{font-family:var(--serif);font-weight:400;
             letter-spacing:-.015em;color:var(--chalk)}
/* Deliberately smaller than the portal's 2.5rem. This page is one fold
   plus a short tail, and a 2.5rem headline below the fold would outweigh
   the h1 above it. */
.wedge-in h2{font-size:clamp(1.5rem,3.2vw,2.1rem);line-height:1.12;margin:0 0 14px}
.wedge-lede{color:var(--dim);font-size:0.92rem;line-height:1.7;
            margin:0 0 22px;max-width:46ch}
/* ---- proof block (replaced the CTA button) ----
   A recommendation marker and a short stat line. Quiet on purpose: this
   sits under a claim about not breaking your walls, and a loud badge
   under a restrained claim reads as a sales sticker on a consultation. */
.wedge-proof{margin:0}
.wedge-badge{
  display:inline-flex;align-items:center;gap:8px;
  padding:7px 14px;border-radius:999px;
  border:1px solid rgba(95,211,163,.34);background:rgba(95,211,163,.10);
  color:var(--tulsi);
  font-size:.74rem;font-weight:600;letter-spacing:.06em;
  text-transform:uppercase;
}
.wedge-badge svg{width:14px;height:14px;flex:none}
.wedge-stats{
  display:flex;flex-wrap:wrap;align-items:center;gap:8px 16px;
  margin:16px 0 0;color:var(--dim);font-size:.86rem;line-height:1.5;
}
/* A separator BETWEEN items, never a trailing one — ::after on every
   item leaves a dot hanging off the end of the row.

   REBUILT, 2 October 2026 — the old version positioned the dot with
   vertical-align:middle on an inline-block at only 3px across, next to
   .86rem bold text: too small to read as a deliberate mark, which is
   what read as "misaligned, not visible, too small" in Abhishek's
   screenshot. It also used a negative-margin trick (margin-right:22px;
   margin-left:-22px) to fit the dot inside the existing flex gap,
   fragile the same way most negative-margin layout hacks are.

   FIRST FIX made .wedge-stat itself display:inline-flex so the dot
   could center via flexbox instead of font-metric-dependent
   vertical-align — and broke something worse: turning .wedge-stat into
   a flex container turns "<b>25 years</b> of practice" into two
   separate flex items (the <b> and the text after it), and a flex
   item's OWN leading whitespace collapses away at that boundary, in
   every major browser. The space before "of"/"required"/"diploma"
   silently vanished ("25 yearsof practice") — caught from Abhishek's
   next screenshot. .wedge-stat is reverted to its normal (non-flex)
   display so that whitespace collapsing works the ordinary way again;
   the dot stays inline-block with vertical-align:middle, just bigger
   (3px → 5px, close enough to visually center at this size without
   needing flexbox for it) and spaced with a plain margin-right instead
   of the old negative-margin counter-trick. */
.wedge-stat + .wedge-stat::before{
  content:'';display:inline-block;vertical-align:middle;
  width:5px;height:5px;border-radius:50%;background:var(--edge-lit);
  margin-right:16px;
}
.wedge-stat b{color:var(--softer);font-weight:600}
/* Stack on a phone: three stats with dot separators wrap into a ragged
   two-and-a-half lines at that width. */
@media (max-width:560px){
  .wedge-stats{flex-direction:column;gap:7px}
  .wedge-stat + .wedge-stat::before{display:none}
}
/* The signature-service CTA. Reuses .h-cta's filled-pill styling so it
   matches the header's "Book a consultation" button rather than
   introducing a second button look, but needs its own top margin since
   it isn't inside .hero-cta's flex gap here.

   1 October 2026 (later again) — now holds a second button, "Explore
   all Vastu/Numerology services" (.h-alt, the same outline style as
   the hero's "Not sure? Ask Sarthi"), linking to vastu.html/
   numerology.html. This replaces the standalone "why it matters"
   teaser sections that briefly sat between the two .showcase-sec
   blocks (see the removed-content comments where those used to be,
   just above each "A few minutes on Vastu/numerology" showcase) —
   Abhishek asked for that content gone and the button moved here
   instead, next to the one action most visitors on this page actually
   want. display:flex rather than .hero-cta's own rule because this
   sits in a single-column signature-service panel, not the two-column
   hero. */
.wedge-cta{margin:22px 0;display:flex;flex-wrap:wrap;gap:10px}
.wedge-media{margin:0}
/* .vfacade img is locked to 9:16 for the Shorts below. This slot holds a
   16:9 frame, so it overrides — one exception, stated once. */
.wedge-media .vfacade img{aspect-ratio:16/9}
.wedge-media .vplay{top:50%;width:46px;height:46px}
.wedge-media .vplay svg{width:20px;height:20px}
/* The list spans the full width under the text+image row, so it reads as
   three tidy columns rather than one long stack in the left half. */
.wedge-list{margin:clamp(20px,2.4vw,28px) 0 0;padding:0;list-style:none;
            display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));
            gap:12px clamp(20px,3vw,44px)}
.wedge-list li{display:flex;gap:10px;align-items:flex-start;
               color:var(--dim);font-size:0.88rem;line-height:1.55}
.wedge-list svg{width:16px;height:16px;flex:none;color:var(--tulsi);
                margin-top:3px}

/* ---- bottom half: the evidence ----
   The heading stays at 1.05rem rather than taking the wedge's scale. The
   top half is a claim and this is a shelf of examples; matching headline
   sizes would say the two carry equal weight. */
.watch h2{font-size:1.05rem;margin:0 0 6px}
.watch-lede{color:var(--dim);font-size:0.86rem;line-height:1.6;margin:0 0 18px}
/* --faint is a hairline against --void and nearly invisible against the
   --void2 panel these now sit on, so the card borders step up. */
.watch .vfacade{border-color:var(--edge-lit);
                display:flex;flex-direction:column;width:100%}
/* Bottom-align the card feet — the six thumbnails are not the same
   height once a title wraps to two lines, and a ragged row of feet is
   the first thing the eye picks up. */
.watch .vgrid{align-items:stretch}
.watch .vgrid li{display:flex}
/* Portrait, because the videos are. Six across on a wide screen, and it
   steps down rather than letting a 9:16 card grow to the width of a
   phone screen — a full-bleed vertical thumbnail is a poster, not a
   card in a row. */
.vgrid{display:grid;grid-template-columns:repeat(6,1fr);
       gap:12px;margin:0;padding:0;list-style:none}
@media (max-width:1040px){ .vgrid{grid-template-columns:repeat(3,1fr)} }
@media (max-width:560px) { .vgrid{grid-template-columns:repeat(2,1fr)} }
.vfacade{
  display:block;position:relative;border-radius:10px;overflow:hidden;
  border:1px solid var(--faint);text-decoration:none;
  transition:border-color .2s,transform .2s;
}
.vfacade:hover{border-color:var(--amber);transform:translateY(-2px)}
.vfacade:focus-visible{outline:3px solid var(--amber);outline-offset:3px}
.vfacade img{display:block;width:100%;height:auto;aspect-ratio:9/16;
             object-fit:cover}
.vplay{
  position:absolute;top:34%;left:50%;transform:translate(-50%,-50%);
  width:38px;height:38px;border-radius:50%;display:grid;place-items:center;
  background:rgba(8,20,26,.72);color:var(--lit);
  transition:background .2s;
}
.vfacade:hover .vplay{background:var(--amber)}
.vplay svg{width:17px;height:17px;margin-left:2px}
/* Over the foot of the thumbnail rather than below it: a Short's lower
   third is usually empty, and a caption block under six tall cards
   would add another 60px of height to each. */
.vmeta{
  position:absolute;left:0;right:0;bottom:0;
  padding:26px 10px 10px;
  background:linear-gradient(to top,rgba(6,14,18,.94) 40%,rgba(6,14,18,0));
}
.vtopic{display:block;font-size:.72rem;letter-spacing:.1em;
        text-transform:uppercase;color:var(--haldi);margin-bottom:3px}
.vname{display:block;color:var(--softer);font-size:.79rem;line-height:1.35}
.vfacade:hover .vname{color:var(--lit)}
.watch-more{margin:20px 0 0}
.watch-btn{
  display:inline-flex;align-items:center;gap:9px;
  padding:12px 20px;min-height:48px;box-sizing:border-box;
  border:1px solid var(--edge-lit);border-radius:8px;
  background:none;color:var(--soft);
  font-size:.92rem;font-weight:600;text-decoration:none;
  transition:border-color .2s,color .2s,background .2s;
}
.watch-btn:hover{
  border-color:var(--amber);color:var(--lit);background:rgba(53,166,233,.14);
  text-decoration:none;
}
.watch-btn:focus-visible{outline:3px solid var(--amber);outline-offset:3px}
.watch-btn svg{width:19px;height:19px;flex:none}
/* The outbound arrow is the only signal that this leaves the site, so it
   is part of the label rather than decoration that might be missed. */
.watch-btn-x{font-size:.9em;opacity:.7}
/* Full width on a phone: a 48px target floating in a wide column is
   harder to hit than one that fills it. */
@media (max-width:560px){
  .watch-btn{width:100%;justify-content:center}
}

/* ---- the video lightbox ----
   Built on first use by the script at the bottom, so the markup carries
   nothing that is only needed after a click. */
.vscrim{
  position:fixed;inset:0;z-index:90;
  background:rgba(4,12,17,.9);
  -webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);
  display:grid;place-items:center;padding:clamp(16px,4vw,44px);
  opacity:0;visibility:hidden;transition:opacity .2s ease,visibility .2s;
}
.vscrim.is-open{opacity:1;visibility:visible}
/* The ratio is held by a WIDTH cap, not a max-height: aspect-ratio and
   max-height together do not letterbox, the height simply wins and the
   picture stretches. */
.vbox{
  position:relative;width:min(1000px,100%);
  max-width:calc(min(74svh,620px) * 16 / 9);
  transform:translateY(10px) scale(.985);
  transition:transform .22s cubic-bezier(.2,.8,.3,1);
}
.vscrim.is-open .vbox{transform:none}
.vframe{
  position:relative;width:100%;aspect-ratio:16/9;
  border-radius:12px;overflow:hidden;
  /* true black, because a letterbox tinted with a theme colour shows as
     coloured bars down the sides of the footage */
  background:#000;border:1px solid var(--edge-lit);
}
.vframe iframe{width:100%;height:100%;border:0;display:block}
.vclose{
  position:absolute;top:-50px;right:0;
  width:40px;height:40px;min-height:0;padding:0;border-radius:50%;
  background:rgba(11,20,24,.7);border:1px solid var(--edge-lit);
  color:var(--soft);display:grid;place-items:center;cursor:pointer;
  transition:border-color .2s,color .2s;
}
.vclose:hover{border-color:var(--amber);color:var(--lit)}
.vclose:focus-visible{outline:3px solid var(--amber);outline-offset:3px}
.vclose svg{width:17px;height:17px}
/* The CTA under the player. .vbox is capped by 74svh so the frame fits
   the screen; this sits under that cap, which is why the close button
   is offset above the box rather than below it. */
.vcta{display:flex;align-items:center;justify-content:center;
      gap:14px 18px;flex-wrap:wrap;margin-top:14px}
.vcta p{margin:0;color:var(--dim);font-size:.92rem}
.vcta-btn{
  /* Same global button{width:100%} trap. As a flex item beside the
     sentence it would take the full row and drop to its own line —
     which looks like a wrap that was meant to happen. */
  width:auto;
  display:inline-flex;align-items:center;justify-content:center;
  padding:12px 24px;min-height:46px;box-sizing:border-box;
  border:1px solid transparent;border-radius:999px;
  background:var(--amber);color:var(--on-fill);
  font-family:var(--sans);font-size:.92rem;font-weight:600;
  cursor:pointer;transition:filter .2s,transform .2s;
}
.vcta-btn:hover{filter:brightness(1.08);transform:translateY(-1px)}
.vcta-btn:focus-visible{outline:3px solid var(--haldi);outline-offset:3px}
/* Stacked on a phone: the sentence and the button side by side at that
   width leaves the button about 90px wide. */
@media (max-width:560px){
  .vcta{flex-direction:column;gap:10px;margin-top:12px}
  .vcta p{font-size:.86rem;text-align:center}
  .vcta-btn{width:100%}
}
@media (max-width:640px){
  .vclose{top:8px;right:8px;background:rgba(4,12,17,.78);z-index:2}
}
@media (prefers-reduced-motion:reduce){
  .vscrim,.vbox{transition:none}
}
@media (prefers-reduced-motion:reduce){
  .vfacade,.vplay{transition:border-color .2s,background .2s}
  .vfacade:hover{transform:none}
}

/* FOOTER — 1 October 2026 (later again). Restructured into a visibly
   distinct band and a labelled "Support" nav; see the markup comment
   above <footer> for the full reasoning and tools/navdata.py's
   footer_html()/footer_css() for the shared source this is pasted
   from (index.html's own token names, same as the mega-menu CSS
   above it — this page never adopted the --text/--muted/--accent-hi/
   --line/--panel vocabulary the other seven pages use).

   margin-top, not the old padding-top:var(--sec-gap), carries the
   section gap above the footer now: the footer has a background of
   its own, so pushing it down with MARGIN keeps that gap un-coloured
   (the band starts exactly at its own border-top) where padding would
   have painted the gap in the footer's background colour instead.
   This also fixes the old zero-gap bug for free — .faq above carries
   no bottom margin, and a flex-column body doesn't collapse adjacent
   margins, so margin-top here was always going to open a real gap
   regardless of what .faq does on its own side.

   --dim stays the body-text colour (not --hint2 — see the text-audit
   rule that rejects --hint2 on --void2, which this band's background
   now actually is, not just adjacent to). --soft/--chalk problem from
   the old single-line footer doesn't apply the same way with a real
   background: contrast is checked against --void2, the footer's own
   background, not --void, the page's. */
.footer-grid{display:flex;flex-wrap:wrap;gap:28px 64px}
.footer-about{flex:0 1 460px;min-width:240px}
/* Logo + write-up + social icons, 1 October 2026 (later again) — see
   the markup comment above footer_html() in tools/navdata.py for the
   full reasoning (reference screenshot, real account URLs, reused
   bio copy). */
.foot-brand{display:flex;align-items:center;gap:9px;margin:0 0 10px;
           width:fit-content;text-decoration:none;color:var(--chalk)}
.foot-brand img{display:block;width:30px;height:30px;border-radius:50%}
.foot-brand-name{font-family:var(--serif);font-size:1rem;font-weight:600}
.foot-brand-name em{font-style:normal;color:var(--haldi)}
.foot-brand:focus-visible{outline:3px solid var(--haldi);outline-offset:3px;
                          border-radius:6px}
.foot-write{margin:0 0 14px;line-height:1.6;max-width:42ch}
.foot-social{display:flex;flex-wrap:wrap;gap:14px;margin:0 0 20px}
.foot-social a{display:flex;align-items:center;justify-content:center;
              width:46px;height:46px;border-radius:50%;
              border:1px solid var(--faint);color:var(--soft);
              transition:color .2s,border-color .2s,background .2s}
.foot-social svg{width:24px;height:24px}
.foot-social a:hover{color:var(--haldi);border-color:var(--haldi)}
.foot-social a:focus-visible{outline:3px solid var(--haldi);outline-offset:2px}
.foot-social a{transition:transform .2s,color .2s,border-color .2s,background .2s,box-shadow .2s}
.foot-social a:hover,.foot-social a:focus-visible{transform:translateY(-4px) scale(1.1);box-shadow:0 8px 20px rgba(0,0,0,.4);background:rgba(255,255,255,.07)}
.foot-social a[aria-label="Facebook"]:hover{color:#4599ff;border-color:#4599ff}
.foot-social a[aria-label="Instagram"]:hover{color:#ff5c9a;border-color:#ff5c9a}
.foot-social a[aria-label="YouTube"]:hover{color:#ff4b4b;border-color:#ff4b4b}
.foot-social a[aria-label="LinkedIn"]:hover{color:#4da3e6;border-color:#4da3e6}
.foot-social a[aria-label="WhatsApp"]:hover{color:#3fe07a;border-color:#3fe07a}
@media(prefers-reduced-motion:reduce){.foot-social a:hover,.foot-social a:focus-visible{transform:none}}
.foot-note{margin:0 0 12px;line-height:1.6}
.foot-c{margin:0}
.foot-support{flex:0 0 auto;display:flex;flex-direction:column;gap:9px;min-width:160px}
.foot-support-h{font-size:.7rem;letter-spacing:.09em;text-transform:uppercase;
                font-weight:600;color:var(--haldi);margin-bottom:2px}
.foot-support a{color:var(--soft);text-decoration:none;width:fit-content;
                border-bottom:1px solid transparent;transition:color .2s,border-color .2s}
.foot-support a:hover{color:var(--chalk);border-bottom-color:var(--faint)}
.foot-support a:focus-visible{outline:3px solid var(--haldi);outline-offset:3px}
.foot-email{margin:0 0 10px}
.foot-email a{color:var(--haldi);text-decoration:none;
              border-bottom:1px solid transparent;transition:border-color .2s}
.foot-email a:hover{border-bottom-color:var(--haldi)}
.foot-email a:focus-visible{outline:3px solid var(--haldi);outline-offset:3px}
@media (max-width:560px){.footer-grid{flex-direction:column;gap:22px}}
footer{flex:none;margin-top:var(--sec-gap);padding:34px 0 28px;
       background:var(--void2);border-top:1px solid var(--faint);
       color:var(--soft);font-size:0.79rem}

/* ---------- credentials ----------
   Typography matched to .voices deliberately: eyebrow, serif h2, then
   the content. Two bands in a row with different heading treatments
   would read as two different sites stitched together.

   The certificates are LINKS to the full-size file, not lightboxed.
   A modal here would need focus trapping, an escape key and a close
   button — three more things to get wrong — to show a document people
   look at for two seconds. The browser already has a viewer.

   .creds-list is a grid rather than flex so the two cards keep the same
   width regardless of the very different aspect ratios of the two
   images (520x735 portrait, 520x332 landscape). */
/* ---------- WHY IT MATTERS / TYPES OF SERVICE ----------
   .info-sec/.info-eyebrow/.info-lede (and the short-lived
   .remedy-ladder/.info-cta-wrap/.info-note that followed them) are
   gone as of 1 October 2026 (later again): the four sections that used
   to share these classes — Why Vastu matters, Types of Vastu service,
   Why numerology matters, Types of numerology service, and then their
   condensed teaser replacements — have all either moved to
   vastu.html/numerology.html or been removed outright at Abhishek's
   request, and nothing on this page uses these selectors any more.
   Deleted rather than commented out, per house style — a selector that
   matches nothing invites the next addition to copy it by habit. See
   the "Explore all Vastu/Numerology services" buttons in .wedge-cta
   for where that teaser content's one actionable piece (the link to
   the full listing) ended up instead. */

/* The three/four short "why" examples — plain text, no card chrome,
   because these are illustrations of a claim, not a catalogue. */
.example-grid{list-style:none;margin:0;padding:0;display:grid;gap:22px;
              grid-template-columns:repeat(auto-fit,minmax(220px,1fr));
              max-width:1040px}
.example-grid li{padding:18px 0 0;border-top:1px solid var(--faint)}
.example-t{margin:0 0 6px;color:var(--chalk);font-size:.92rem;font-weight:600}
.example-p{margin:0;color:var(--dim);font-size:.86rem;line-height:1.6}

/* The service catalogue. Grouped under .svc-group-title headings
   (doc02's own section breaks), each group a grid of bordered cards. */
.svc-group{margin:0 0 30px}
.svc-group:last-child{margin-bottom:0}
.svc-group-title{margin:0 0 14px;color:var(--dim);font-size:.78rem;
                 font-weight:600;letter-spacing:.06em;text-transform:uppercase}
.svc-grid{list-style:none;margin:0;padding:0;display:grid;gap:14px;
         grid-template-columns:repeat(auto-fit,minmax(260px,1fr))}
.svc-card{background:var(--void2);border:1px solid var(--faint);
         border-radius:10px;padding:16px 18px;display:flex;
         flex-direction:column;gap:6px}
.svc-card-t{margin:0;color:var(--chalk);font-size:.94rem;font-weight:600;
           line-height:1.35}
.svc-card-p{margin:0;color:var(--dim);font-size:.84rem;line-height:1.55;flex:1}
.svc-card-fee{margin:2px 0 0;color:var(--tulsi);font-size:.8rem;font-weight:600}
.svc-card-ask{margin:2px 0 0;color:var(--hint);font-size:.8rem}
/* The card's own action — a real link, not a styled <div> pretending to
   be one, so it is keyboard-reachable and shows up in "open in new
   tab". Book cards call the existing [data-book] modal; the rest go to
   WhatsApp, because a price this page cannot confirm should never be
   typed as if it were final. */
.svc-card-cta{margin-top:8px;display:inline-flex;align-items:center;gap:6px;
             color:var(--haldi);font-size:.84rem;font-weight:600;
             text-decoration:none;background:none;border:0;padding:0;
             cursor:pointer;font-family:inherit;align-self:flex-start}
.svc-card-cta:hover{color:var(--lit)}
.svc-card-cta:focus-visible{outline:2px solid var(--haldi);outline-offset:3px}

/* ---------- NUMEROLOGY CARDS, redesigned 1 October 2026 ----------
   Abhishek shared a light/cream reference (numbered cards, an icon
   circle per card, a two-line "Service starts from ₹X onwards" price
   block, a pill CTA with a circular arrow) and asked for the
   STRUCTURE applied here, in the site's existing dark palette — not a
   switch to the reference's light theme. Group titles ("For you" /
   "Numbers & business") keep their original wording; the reference's
   descriptive subtitle under each group was not copied in, since
   that line of copy was never confirmed. */
.num-grid{gap:16px}
/* WHOLE-CARD CLICK + HOVER, 1 October 2026. Abhishek asked for the
   cards to react and for the whole card — not just the small "View
   Details" pill — to be clickable. Rather than wrapping the card in a
   second, bigger link (which would put TWO links to the same page on
   one card, confusing for a screen reader and for Tab order), the
   existing .num-card-cta anchor gets a ::after pseudo-element
   stretched to cover the whole card (position:absolute;inset:0,
   positioned against .num-card below via position:relative). That is
   the one link the card has; it is simply made as big as the card.
   Hovering or focusing anywhere on the card is hovering/focusing that
   same anchor, so the existing .num-card-cta:hover / :focus-visible
   rules (and the arrow-circle fill they already trigger) now fire from
   anywhere on the card, not just the pill — no new hover rule needed
   for the CTA itself, only the card-level lift below. Same pattern on
   .svc-pcard-cta further down for the Vastu photo cards. */
.num-card{background:var(--void2);border:1px solid var(--faint);
         border-radius:12px;padding:18px 18px 16px;display:flex;
         flex-direction:column;gap:8px;position:relative;
         transition:transform .22s ease,box-shadow .22s ease,
                    border-color .22s ease}
.num-card:hover,.num-card:focus-within{
  transform:translateY(-5px);border-color:var(--edge-lit);
  box-shadow:0 18px 36px rgba(2,10,15,.4)}
@media (prefers-reduced-motion:reduce){
  .num-card{transition:none}
  .num-card:hover,.num-card:focus-within{transform:none}
}
.num-card-top{display:flex;align-items:center;justify-content:space-between}
.num-card-no{font-family:var(--serif);font-size:.82rem;color:var(--dim);
            font-weight:400;letter-spacing:.02em}
.num-card-icon{width:40px;height:40px;border-radius:50%;flex:none;
              display:flex;align-items:center;justify-content:center;
              background:var(--void);border:1px solid var(--edge-lit)}
.num-card-icon svg{width:19px;height:19px;color:var(--haldi)}
.num-card-t{margin:2px 0 0;color:var(--chalk);font-size:.96rem;font-weight:600;
           line-height:1.3}
.num-card-p{margin:0;color:var(--dim);font-size:.83rem;line-height:1.55;flex:1}
.num-card-time{display:flex;align-items:center;gap:6px;margin:2px 0 0;
              color:var(--hint);font-size:.78rem;padding-top:10px;
              border-top:1px solid var(--faint)}
.num-card-time svg{width:14px;height:14px;flex:none;color:var(--hint)}
.num-card-foot{display:flex;align-items:flex-end;justify-content:space-between;
              gap:10px;margin-top:6px;flex-wrap:wrap}
.num-card-price{display:flex;flex-direction:column;gap:1px}
.num-card-price-label{font-size:.72rem;color:var(--dim)}
.num-card-price-amt{font-family:var(--serif);font-size:1.3rem;color:var(--haldi);
                    line-height:1.1}
.num-card-price-sub{font-size:.72rem;color:var(--dim)}
.num-card-cta{display:inline-flex;align-items:center;gap:8px;
             color:var(--chalk);font-size:.82rem;font-weight:600;
             text-decoration:none;white-space:nowrap;position:relative}
/* The stretched hit-area — see the comment above .num-card. z-index:1
   is only to sit above the icon/price siblings painted after it in
   source order; nothing in this card needs more than that. */
.num-card-cta::after{content:"";position:absolute;inset:0;z-index:1}
.num-card-cta:hover{color:var(--lit)}
.num-card-cta:hover .num-card-arrow{background:var(--haldi);border-color:var(--haldi);color:var(--ink)}
.num-card-cta:focus-visible{outline:2px solid var(--haldi);outline-offset:3px}
.num-card-arrow{width:30px;height:30px;border-radius:50%;flex:none;
               display:flex;align-items:center;justify-content:center;
               background:var(--void);border:1px solid var(--edge-lit);
               color:var(--chalk);transition:background .2s,border-color .2s,color .2s}
.num-card-arrow svg{width:14px;height:14px}
.num-group-head{display:flex;align-items:center;gap:12px;margin:0 0 14px}
.num-group-icon{width:38px;height:38px;border-radius:50%;flex:none;
               display:flex;align-items:center;justify-content:center;
               background:var(--void);border:1px solid var(--edge-lit)}
.num-group-icon svg{width:18px;height:18px;color:var(--haldi)}
.num-group-head .svc-group-title{margin:0}

/* ---------- VASTU SERVICES: photo-card grid ----------
   Third pass at this section in one day. First was an equal-size card
   grid; second (the compact-row version just above, in history but no
   longer in the markup) answered "too long" by combining three photos
   into one. This reference — a photo per service, 4-up grid, a "View
   all" pill per category — asks for MORE photography, not less, so the
   length problem is solved differently here: each category shows its
   first four services and the rest sit behind "View all", revealed by
   the tiny script at the bottom of the page rather than a page reload
   or a second URL.

   PHOTOGRAPHY, HONESTLY: this needs one photo per service to look like
   the reference — 15 for Vastu. Only one is real
   (img/svc/home-flats.webp, on the Home Vastu Consultation card). Every
   other card gets .svc-pcard-media--empty: a plain muted panel, no
   broken <img>, no invented stock photo standing in for a real one.
   Replace them one at a time as photos come in — each card's <img> (or
   lack of one) is independent of the others. */
.svc-cat{margin:0 0 36px}
.svc-cat:last-child{margin-bottom:0}
.svc-cat-head{display:flex;align-items:flex-end;justify-content:space-between;
             gap:20px;flex-wrap:wrap;margin:0 0 20px}
.svc-cat-eyebrow{display:block;font-size:.72rem;letter-spacing:.13em;
                 text-transform:uppercase;font-weight:600;color:var(--haldi);
                 margin-bottom:8px}
.svc-cat-h{font-family:var(--serif);font-weight:400;
          font-size:clamp(1.3rem,2.4vw,1.7rem);line-height:1.2;
          letter-spacing:-.01em;margin:0 0 8px;color:var(--chalk)}
.svc-cat-lede{margin:0;color:var(--dim);font-size:.86rem;line-height:1.55;
            max-width:52ch}
/* .svc-cat-viewall (the "View all N services" pill) left with the
   buttons it styled on 1 October 2026 — see the section's own comment
   above the markup for why. */

.svc-photo-grid{list-style:none;margin:0;padding:0;display:grid;gap:16px;
               grid-template-columns:repeat(4,1fr)}
@media (max-width:900px){.svc-photo-grid{grid-template-columns:repeat(2,1fr)}}
@media (max-width:560px){.svc-photo-grid{grid-template-columns:1fr}}
/* WHOLE-CARD CLICK + HOVER — same pattern as .num-card above:
   .svc-pcard-cta's ::after (below) stretches that one real link to
   cover the whole card, and the card itself lifts + gets a stronger
   shadow + border on hover/focus. overflow:hidden (already here, for
   the rounded corners) also clips the photo's zoom-on-hover. */
.svc-pcard{background:var(--void2);border:1px solid var(--faint);
          border-radius:12px;overflow:hidden;display:flex;flex-direction:column;
          position:relative;
          transition:transform .22s ease,box-shadow .22s ease,
                     border-color .22s ease}
.svc-pcard:hover,.svc-pcard:focus-within{
  transform:translateY(-5px);border-color:var(--edge-lit);
  box-shadow:0 18px 36px rgba(2,10,15,.4)}
@media (prefers-reduced-motion:reduce){
  .svc-pcard{transition:none}
  .svc-pcard:hover,.svc-pcard:focus-within{transform:none}
}
.svc-pcard-media{position:relative;aspect-ratio:4/3;background:var(--void);
                 overflow:hidden}
.svc-pcard-media img{display:block;width:100%;height:100%;object-fit:cover;
                     transition:transform .4s ease}
.svc-pcard:hover .svc-pcard-media img{transform:scale(1.07)}
@media (prefers-reduced-motion:reduce){.svc-pcard-media img{transition:none}}
.svc-pcard-icon{position:absolute;left:10px;bottom:10px;width:34px;height:34px;
               border-radius:50%;display:flex;align-items:center;justify-content:center;
               background:var(--void2);border:1px solid var(--edge-lit)}
.svc-pcard-icon svg{width:16px;height:16px;color:var(--haldi)}
/* min-height:245px is this body's own worst-case natural height —
   padding(30) + a 2-line title(~39) + a 6px gap + a 3-line
   description(~61) + a 6px gap + the foot's reserved 95px — the
   tallest any of these 15 cards' text actually runs to. Reserving it
   on EVERY card (not just the ones sharing a row with a taller one)
   is what makes height uniform across different ROWS of this grid,
   not just within one row: CSS Grid's align-items:stretch only
   equalises siblings in the SAME row, so Builder & Architect
   Partnership and Housing Society Vastu — alone together in this
   grid's second row — could still end up shorter than the row of
   four above them even after the foot fix, since nothing forced that
   second row as tall as the first. This min-height is the actual
   fix: every card now reaches the same height on its own, regardless
   of which row it's in or who else is in it. */
.svc-pcard-body{padding:14px 16px 16px;display:flex;flex-direction:column;gap:6px;flex:1;min-height:245px}
.svc-pcard-t{margin:0;color:var(--chalk);font-size:.94rem;font-weight:600;line-height:1.3}
.svc-pcard-p{margin:0;color:var(--dim);font-size:.82rem;line-height:1.55;flex:1}
/* min-height:95px is a "fee" card's own natural foot height — price
   box (~45px, its padding plus one text line) + this flex column's
   10px gap + the CTA button (~40px) — reserved here so an "ask" card's
   foot, which has nothing but the CTA, still occupies the same space.
   Without this, a card's natural height depended on which cards
   happened to land in its own CSS Grid row (align-items:stretch only
   equalises WITHIN a row): an "ask" card paired with "fee" row-mates
   looked fine, but a "fee" card that happened to share its row with a
   short "ask" card could get stretched well past its own content,
   dumping that extra height into .svc-pcard-p's flex:1 gap as a
   visibly empty band above the price box — reported 1 October 2026 on
   the Office Vastu card. Reserving this space on every foot makes
   every card's natural height the same regardless of row composition,
   so grid stretch becomes a no-op instead of the thing doing the
   work. */
.svc-pcard-foot{display:flex;flex-direction:column;align-items:stretch;
               justify-content:flex-end;gap:10px;margin-top:4px;min-height:95px}
/* PRICE BOX, simplified again 1 October 2026 — two rounds back it was
   an Online/On-site split with its own icon per column, echoing a
   reference Abhishek shared. He asked for that gone: no Online/On-site
   labels, no icons, one line. The seven Vastu services that do have
   two real prices now show only the lower (online) one here — "Starts
   from ₹X" — the on-site figure still lives on that service's own
   detail page, so nothing is lost, just not shown twice on the card.
   Briefly read "Rs. X" instead of "₹X" in this one box, at Abhishek's
   own request, then back to ₹ at his next one — the site has the
   rupee glyph and should use it, same as everywhere else on the page.

   The eight cards with no set price (Vastu Clarity Call and the rest)
   dropped their box entirely rather than keep an empty or "ask on
   WhatsApp" shell — "View Details" alone says enough; the honest
   price-not-set answer lives on the detail page, same as it did when
   this said "Ask on WhatsApp for pricing" out loud. */
.svc-price-box{background:var(--void);border:1px solid var(--faint);
               border-radius:9px;padding:11px 14px;text-align:center}
.svc-price-line{display:block;font-size:.86rem;font-weight:700;
                color:var(--tulsi)}

/* THE CTA IS NOW "VIEW DETAILS" EVERYWHERE, not "Book this" or "Ask on
   WhatsApp" — the card's job is to get someone to the service's own
   page, where the real action (book, or message on WhatsApp) lives
   next to the fuller write-up. One consistent label removes the need
   for a card to know, at a glance, which of two actions it should be
   driving toward. */
.svc-pcard-cta{align-self:stretch;display:flex;align-items:center;
              justify-content:center;gap:6px;padding:9px 14px;
              border-radius:8px;background:none;position:relative;
              border:1px solid var(--edge-lit);color:var(--chalk);
              font-size:.8rem;font-weight:600;cursor:pointer;
              text-decoration:none;white-space:nowrap}
/* The stretched hit-area — see the comment above .svc-pcard. */
.svc-pcard-cta::after{content:"";position:absolute;inset:0;z-index:1}
.svc-pcard-cta svg{width:14px;height:14px;flex:none}
.svc-pcard-cta:hover{border-color:var(--haldi);color:var(--lit);
                     background:rgba(53,166,233,.14)}
.svc-pcard-cta:focus-visible{outline:2px solid var(--haldi);outline-offset:3px}
.creds{flex:none;margin:0 0 var(--sec-gap)}
.creds-eyebrow{display:block;font-size:.72rem;letter-spacing:.13em;
               text-transform:uppercase;font-weight:600;color:var(--haldi);
               margin-bottom:10px}
.creds h2{font-family:var(--serif);font-weight:400;
          font-size:clamp(1.5rem,3.2vw,2.1rem);line-height:1.12;
          letter-spacing:-.015em;margin:0 0 22px;color:var(--chalk)}
/* Three now, not two, so the cap goes up and the minimum comes down —
   otherwise auto-fit puts two on a row and leaves the third stranded on
   its own, which reads as an afterthought rather than a set. 220px is
   the point below which the certificate lettering stops being legible
   at all, so the row drops to two and then one instead of shrinking
   past it. */
.creds-list{list-style:none;margin:0;padding:0;display:grid;gap:22px;
            grid-template-columns:repeat(auto-fit,minmax(220px,1fr));
            max-width:1040px}
/* NOT LINKS. The certificates used to open the full-size file in a new
   tab; they do not any more.

   The small versions are legible at the size they are shown, so the
   link was offering a bigger copy of something already readable — and
   an image that opens a raw .webp in a browser tab is a dead end with
   no way back except the back button. It also made the two cards the
   only clickable things in this band, which set an expectation the rest
   of the section could not meet.

   With the <a> gone there is nothing to hover and nothing to focus, so
   the border, radius and clipping move onto the <img> itself. */
/* CONTAIN, NOT COVER. A CERTIFICATE IS A DOCUMENT.

   This was height:190px + object-fit:cover, which was simply the wrong
   idea applied to the wrong content. cover fills the box by cropping,
   and it is right for the testimonial posters and the carousel
   photographs, where the subject is in the middle and the edges are
   scenery. A certificate has no scenery: the awarding body is along the
   top, the name is in the middle and the seal and signature are at the
   bottom, and cropping any of it removes the evidence the image is
   there to provide.

   It was worse here than usual because these two are nothing like each
   other — 900x1272 portrait and 1100x702 landscape. One box and cover
   meant the portrait lost its whole lower half while the landscape lost
   its sides.

   contain shows every document whole. The 4:3 box is a compromise that
   suits neither ratio perfectly and suits both adequately, which is the
   point: the two cards stay the same size, so the section reads as a
   set rather than as two images that happen to be near each other. The
   padding keeps the certificate borders off the card edge, and --void
   behind it is a step darker than the card so the document sits ON
   something rather than floating. */
.creds-list img{display:block;width:100%;height:auto;
                aspect-ratio:4/3;object-fit:contain;
                background:var(--void);padding:10px;
                border:1px solid var(--faint);border-radius:10px}
.creds-t{margin:10px 0 3px;color:var(--chalk);font-size:.92rem;font-weight:500;
         line-height:1.4}
.creds-m{margin:0;color:var(--dim);font-size:.78rem;line-height:1.6}

/* ---------- FAQ ----------
   Same eyebrow + serif heading as .voices and .creds. Three bands in a
   row, one typographic idea.

   The rows are separated by a hairline rather than boxed. Seven cards
   would out-weigh the testimonials directly above them, and this is
   reference material — people arrive at it with a question already in
   mind and scan for their own words.

   list-style:none on the summary is not optional: without it Safari and
   Firefox draw their own triangle IN ADDITION to the one below, and the
   two point different ways. */
/* margin-bottom 0, and that is not an oversight.
   .areas follows this now, and it opens with its own border-top plus
   clamp(26px,4svh,44px) of padding. Leaving a bottom margin here as
   well would stack two gaps and put 50-90px between the last answer and
   the rule above "What Acharya Gautam advises on". .areas supplies the
   separation, exactly as it did for .creds before the FAQ moved in
   between them. */
.faq{flex:none;margin:0}
.faq-eyebrow{display:block;font-size:.72rem;letter-spacing:.13em;
             text-transform:uppercase;font-weight:600;color:var(--haldi);
             margin-bottom:10px}
.faq h2{font-family:var(--serif);font-weight:400;
        font-size:clamp(1.5rem,3.2vw,2.1rem);line-height:1.12;
        letter-spacing:-.015em;margin:0 0 20px;color:var(--chalk)}
/* max-width:760px removed, 1 October 2026 (later again), at Abhishek's
   request — the FAQ list was the one block on this page narrower than
   its own .container, so it read as indented/squeezed next to every
   section above and below it, which all run the full 1180px width.
   No replacement cap: a details/summary row is a single line of text
   per question plus a short answer paragraph on open, so there's no
   line-length problem running it to 1180px the way there would be for
   a long block of prose. */
.faq-list{border-top:1px solid var(--faint)}
.faq details{border-bottom:1px solid var(--faint)}
.faq summary{
  list-style:none;cursor:pointer;position:relative;
  padding:15px 40px 15px 0;
  color:var(--chalk);font-size:.98rem;line-height:1.45;font-weight:500;
  transition:color .2s;
}
.faq summary::-webkit-details-marker{display:none}
.faq summary:hover{color:var(--lit)}
.faq summary:focus-visible{outline:3px solid var(--amber);outline-offset:2px}
/* The chevron is drawn, not a glyph, so it can rotate. 1px borders on a
   rotated square is the cheapest arrow there is and it stays crisp at
   any zoom. */
.faq summary::after{
  content:'';position:absolute;right:6px;top:50%;
  width:8px;height:8px;margin-top:-6px;
  border-right:1.5px solid var(--haldi);border-bottom:1.5px solid var(--haldi);
  transform:rotate(45deg);transition:transform .2s;
}
.faq details[open] summary::after{transform:rotate(-135deg);margin-top:-2px}
/* max-width:62ch REMOVED, 1 October 2026 (later again) — it capped
   the answer text at readable line-length back when .faq-list itself
   was only 760px wide, so the cap rarely even bound. Once .faq-list
   was widened to the page's full 1180px container (see the removed
   max-width on .faq-list above), 62ch (~570px at this font-size) left
   the text stuck against the left edge with a wide dead strip of
   empty space to its right — "align the content left to right" was
   the report. Dropped so the answer text uses the same width as its
   own summary line above it, consistent with the rest of the page. */
.faq details p{margin:0 0 16px;padding-right:40px;
               color:var(--dim);font-size:.92rem;line-height:1.7}
.faq details a{color:var(--haldi)}
@media (prefers-reduced-motion:reduce){
  .faq summary::after{transition:none}
}

/* ---------- below the fold threshold, let it breathe ---------- */
@media(max-width:900px){
  body{min-height:0;display:block}
  main{padding:20px 0 18px}
  /* Stacked below 900px — one column, portrait first so the greeting
     reads before the headline, same as the fold did before the 2-col
     restore. */
  .fold{grid-template-columns:minmax(0,1fr);gap:28px}
  .right{order:-1}
  /* THE INTERNAL SCROLL IS DESKTOP ONLY.

     Stacked, the card is not competing with a neighbouring column, so
     there is nothing to keep it aligned with — and a scroll box inside a
     scrolling page is genuinely unpleasant on a touch screen: the flick
     that was meant to move the page moves the fields instead, and you
     cannot tell which one you are about to get. Height goes back to
     auto, the fields flow, the page scrolls. One scroll, as it should
     be on a phone. */
  .card{height:auto;min-height:0}
  /* Reset every part of the desktop scroll box, not most of it. The
     padding and the reserved scrollbar gutter would otherwise leave a
     26px strip of dead space down the right of the form on a phone,
     holding a track for a scrollbar that is no longer there. */
  .form-body{overflow-y:visible;flex:none;min-height:auto;
             padding-right:0;scrollbar-gutter:auto;background:none}
  .submit-row{margin-top:2px}
  /* The photo is nudged down by .14 * --fig (transform, so it takes no
     room). In one column that pushed its bottom edge over the eyebrow and
     headline below it. Give the portrait that same amount of room back. */
  .portrait{--fig:min(538px,92.5vw);margin-bottom:calc(var(--fig) * .14 + 14px)}
  h1{font-size:clamp(2.4rem,8.6vw,3.3rem)}
  .intro{font-size:1rem}
}
/* Short laptops: trim the two tallest things so the fold still reads as
   one screen. These no longer have to make the form FIT beside the hero —
   the page is allowed to scroll now — they just stop the hero eating the
   whole viewport on a 1440x800. */
@media(min-width:901px) and (max-height:820px){
  .portrait{margin-bottom:12px;--fig:clamp(335px,16.25vw + 10svh,435px)}
  h1{font-size:clamp(2.1rem,3vw + 1svh,3.2rem);margin-bottom:14px}
  .intro{margin-bottom:16px}
  .tags{margin-bottom:18px}
}
/* Very wide screens size the type off vw and outrun the height they have
   to sit in. Cap the two vw-driven values so 1920 behaves like 1600. */
@media(min-width:1600px){
  /* Was a max-width cap on the img alone, which the halo could not see.
     Verified equivalent: at >=1600px wide, min(450px,36.25svh) is always
     at or below what the base clamp resolves to, so it binds
     identically — but now the halo scales with it. (450/36.25 are the
     old 360/29 * 1.25, same 25%-bigger pass as --fig's other values.) */
  .portrait{--fig:min(450px,36.25svh)}
  h1{font-size:clamp(2.3rem,2.6vw + .9svh,3.5rem)}
}
@media(prefers-reduced-motion:reduce){
  .social a{transition:none}
  .social a:hover,.social a:focus-visible{transform:none}
  /* Stilled, not removed — the wheel is part of the composition.
     The comment claiming this was here; the rule was not, so the wheel
     kept turning for anyone who had asked it to stop. */
  .portrait::before{animation:none}
  }

/* ============================================================
   SARTHI — the guided assistant.

   सारथी, the charioteer: the one who drives you there while you
   decide where you are going. That is the whole scope. It answers
   questions about the practice and takes an enquiry. It does NOT
   answer astrological questions, and there is no model behind it
   that could start.

   WHY IT IS NOT AN AI BOT. The site says, in four places, "he reads
   every message himself" and "no assistant reading a template back
   to you". A model that answered chart questions would contradict
   the one thing the practice sells. It would also need a key, and a
   key in browser JavaScript is public — anyone can spend it.

   WHY IT HAS NO DATA OF ITS OWN. Every category and service comes
   out of the real form's option lists, and every answer is written
   into the real form's fields. Sarthi is a second front end onto
   one form, not a second form. So there is one set of validation
   rules, one payload, one place services are defined — and the
   existing 51-test suite still covers the submission path, because
   it is the same path.
   ============================================================ */
/* WIDTH AND MIN-HEIGHT ARE EXPLICIT, AND THAT IS NOT TIDINESS.

   There is a global `button{ ... width:100% }` in this stylesheet. Any
   <button> that does not set its own width inherits it — which is how
   this launcher first rendered as a full-width bar across the foot of
   the page instead of a control in the corner. .sar-chip had the same
   fault and would have stacked one chip per line.

   Anchors are unaffected: the rule is `button{}`, so .watch-btn and
   .wedge-btn never had the problem. Only real <button>s do, and there
   are four of them here. */
.sarthi-open{
  position:fixed;right:var(--sar-gap-x);bottom:var(--sar-gap-y);
  z-index:70;display:grid;place-items:center;
  width:58px;height:58px;min-height:0;padding:0;
  box-sizing:border-box;
  border:1px solid var(--edge-lit);border-radius:50%;
  background:var(--void2);color:var(--chalk);
  cursor:pointer;box-shadow:0 12px 34px -18px rgba(0,0,0,.9);
  transition:border-color .2s,transform .2s,background .2s;
}
.sarthi-open:hover{border-color:var(--amber);transform:translateY(-2px)}
.sarthi-open:focus-visible{outline:3px solid var(--amber);outline-offset:3px}
/* 34px, not 23. The measurement, not a preference: rendered at 23px the
   face collapses into a smudge and the icon reads as a grey blob. */
.sarthi-open .si{width:34px;height:34px}
/* ============================================================
   CUSTOM PROPERTIES, NOT A DESCENDANT SELECTOR.

   This was `.si .si-line { fill: var(--chalk) }` and it did nothing:
   <use> clones its content into a SHADOW TREE, and a selector written
   outside cannot reach inside one. The paths fell back to the SVG
   default fill — black — which on a dark circle is a dark blob. That
   is what the screenshot showed.

   INHERITED properties do cross the boundary, and a custom property is
   inherited. So the colours are declared on .si out here and consumed
   as fill="var(--si-line)" on the paths in there. Hover just changes
   the variable.

   Anything added to that symbol later must paint from these two
   variables. A fill written directly onto a path will be unreachable
   from the stylesheet in exactly the same way.
   ============================================================ */
.si{--si-line:var(--chalk); --si-robe:var(--haldi)}
.sarthi-open:hover .si{--si-line:var(--lit)}
/* A label on hover for sighted users; aria-label carries the same words
   for everyone else. An icon alone in a circle is a convention, not an
   explanation. */
.sarthi-open::after{
  content:'Ask Sarthi';
  position:absolute;right:calc(100% + 10px);top:50%;transform:translateY(-50%);
  padding:7px 13px;border-radius:999px;white-space:nowrap;
  background:var(--void2);border:1px solid var(--faint);
  color:var(--chalk);font-family:var(--sans);font-size:.82rem;font-weight:600;
  opacity:0;pointer-events:none;transition:opacity .18s;
}
.sarthi-open:hover::after,
.sarthi-open:focus-visible::after{opacity:1}
/* No room for a floating label beside a 58px circle on a phone. */
@media (max-width:560px){ .sarthi-open::after{display:none} }
.sarthi-open[hidden]{display:none}

/* IT HAS TO SIT ABOVE THE PAGE, NOT IN IT.

   The panel was --void2 with an --edge-lit border, and so is every card
   on the page. Floating one over the enquiry card, the two merged: same
   surface, same border, and no way to tell where the page stopped and
   the assistant began.

   Three things separate it now, and each does a different job:

     1. A LIGHTER SURFACE. --void3 sits above --void2, so the panel
        reads as nearer the viewer than anything it covers. The message
        bubbles drop to --void2 in exchange, which keeps contrast
        inside the panel as well.

     2. A DARK HALO. The first shadow is a 1px ring of near-black. Against
        a card of the same tone a light border disappears; a dark one
        cannot, because nothing else on this page is that dark.

     3. TWO SHADOWS, NOT ONE. A tight one for the edge and a wide one for
        the lift. A single soft shadow at this size reads as a glow and
        does not separate anything. */
.sarthi{
  position:fixed;right:var(--sar-gap-x);bottom:var(--sar-gap-y);
  z-index:71;width:min(400px,calc(100vw - 28px));
  height:min(600px,calc(100svh - 100px));
  display:flex;flex-direction:column;
  background:var(--void3);
  border:1px solid var(--edge-lit);
  border-radius:16px;overflow:hidden;
  box-shadow:
    0 0 0 1px rgba(3,9,12,.9),
    0 18px 38px -14px rgba(0,0,0,.8),
    0 48px 96px -40px rgba(0,0,0,.95);
  opacity:0;visibility:hidden;transform:translateY(12px) scale(.98);
  transition:opacity .2s ease,visibility .2s,transform .22s cubic-bezier(.2,.8,.3,1);
}
.sarthi.is-open{opacity:1;visibility:visible;transform:none}
/* Full screen on a phone. A 400px panel floating over a 390px viewport
   is a panel with no page around it, and the keyboard then covers half
   of what is left. */
@media (max-width:560px){
  .sarthi{right:0;bottom:0;width:100vw;height:100svh;border-radius:0;border:0}
}

/* The whole bar closes the panel, so it says so with the cursor. */
.sarthi-top{
  flex:none;display:flex;align-items:center;gap:11px;
  padding:14px 14px 14px 18px;border-bottom:1px solid var(--faint);
  cursor:pointer;user-select:none;
  transition:background .2s;
}
.sarthi-top:hover{background:rgba(255,255,255,.03)}
/* 40px, up from 34. It holds a 30px figure now — the floor the render
   test set — and at 34px the circle had no room around it. */
.sarthi-mark{
  width:40px;height:40px;flex:none;border-radius:50%;
  display:grid;place-items:center;
  background:rgba(63,182,238,.14);border:1px solid rgba(63,182,238,.3);
  color:var(--haldi);
}
.sarthi-mark .si{width:30px;height:30px}
.sarthi-who{flex:1;min-width:0}
.sarthi-who b{display:block;color:var(--chalk);font-size:.95rem;font-weight:600}
/* States what it is on every screen, not only in the first message.
   Somebody who scrolls back up should not have to remember. */
.sarthi-who span{display:block;color:var(--hint);font-size:.74rem;margin-top:1px}
.sarthi-x{
  width:34px;height:34px;flex:none;min-height:0;padding:0;border-radius:50%;
  background:none;border:1px solid var(--edge-lit);color:var(--dim);
  display:grid;place-items:center;cursor:pointer;
  transition:border-color .2s,color .2s;
}
.sarthi-x:hover{border-color:var(--amber);color:var(--chalk)}
.sarthi-x:focus-visible{outline:3px solid var(--amber);outline-offset:2px}
.sarthi-x svg{width:15px;height:15px}

.sarthi-log{
  flex:1;min-height:0;overflow-y:auto;
  padding:16px 18px;display:flex;flex-direction:column;gap:10px;
  overscroll-behavior:contain;
  scrollbar-width:thin;scrollbar-color:var(--edge-lit) transparent;
}
.sarthi-log::-webkit-scrollbar{width:8px}
.sarthi-log::-webkit-scrollbar-thumb{background:var(--edge-lit);border-radius:99px}

.sar-msg{
  max-width:86%;padding:11px 14px;border-radius:14px;
  font-size:.9rem;line-height:1.6;white-space:pre-wrap;
}
.sar-msg.bot{align-self:flex-start;background:var(--void2);
             color:var(--dim);border-bottom-left-radius:5px}
.sar-msg.bot strong{color:var(--chalk);font-weight:600}
.sar-msg.me{align-self:flex-end;background:var(--amber);color:var(--on-fill);
            font-weight:500;border-bottom-right-radius:5px}
/* THE TYPING DOTS.

   Not decoration: they are what makes a pause readable as "more is
   coming" rather than as the panel having stalled. Remove them and the
   staged delivery just looks broken.

   Three dots on one delay each, offset so the wave reads left to right.
   Under prefers-reduced-motion the animation stops but the dots stay —
   the indicator is information, the movement is not. */
/* Announced, not shown. Without this rule the words "Sarthi is
   typing" render beside the dots as literal text — which is how a
   screen-reader-only label becomes a visible bug. The class was used
   before it existed. */
.sr-only{
  position:absolute;width:1px;height:1px;padding:0;margin:-1px;
  overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0;
}
/* THE ENTRANCE.

   Every arriving thing fades up 8px. Small on purpose: the message is
   the event, and a bubble that flies in from the edge makes the motion
   the event instead.

   .sar-enter is the from-state and .is-in the to-state, applied a frame
   apart. Both are needed — a transition with no starting state does not
   run, it just cuts.

   The delay is set per row in reveal(), so a list cascades and the eye
   is walked down it. transition-delay is cleared by the same rule
   finishing; it only affects the arrival. */
.sar-enter{opacity:0;transform:translateY(8px);
           transition:opacity .34s ease, transform .34s cubic-bezier(.2,.8,.3,1)}
.sar-enter.is-in{opacity:1;transform:none}
@media (prefers-reduced-motion:reduce){
  .sar-enter{opacity:1;transform:none;transition:none}
}
.sar-typing{display:flex;align-items:center;gap:4px;padding:14px}
.sar-typing i{
  width:6px;height:6px;border-radius:50%;background:var(--hint);
  animation:sarDot 1.15s ease-in-out infinite;
}
.sar-typing i:nth-child(2){animation-delay:.16s}
.sar-typing i:nth-child(3){animation-delay:.32s}
@keyframes sarDot{
  0%,70%,100%{opacity:.28;transform:translateY(0)}
  35%{opacity:1;transform:translateY(-3px)}
}
@media (prefers-reduced-motion:reduce){
  .sar-typing i{animation:none;opacity:.5}
}
.sar-note{align-self:flex-start;color:var(--hint);font-size:.78rem;
          line-height:1.5;max-width:90%;margin:-4px 0 2px}

.sar-chips{display:flex;flex-wrap:wrap;gap:8px;margin:2px 0 4px}
.sar-chip{
  /* width:auto beats the global button{width:100%}; without it every
     chip is its own full-width row and the option list reads as a
     stack of buttons rather than a set of choices. */
  width:auto;max-width:100%;
  padding:9px 15px;min-height:40px;box-sizing:border-box;
  border:1px solid var(--edge-lit);border-radius:999px;
  background:none;color:var(--soft);
  font-family:var(--sans);font-size:.85rem;font-weight:500;
  cursor:pointer;text-align:left;
  transition:border-color .2s,background .2s,color .2s;
}
.sar-chip:hover{border-color:var(--amber);background:rgba(53,166,233,.14);color:var(--lit)}
.sar-chip:focus-visible{outline:3px solid var(--amber);outline-offset:2px}
.sar-chip.ghost{border-style:dashed;color:var(--hint)}

.sarthi-ask{
  flex:none;display:flex;gap:9px;align-items:flex-end;
  padding:12px 14px;border-top:1px solid var(--faint);
}
.sarthi-ask input{
  flex:1;min-width:0;width:auto;margin:0;
  /* inherits the page's input styling; only the metrics differ */
  min-height:46px;font-size:.92rem;
}
.sarthi-send{
  width:46px;height:46px;flex:none;min-height:0;padding:0;
  border-radius:50%;border:0;background:var(--amber);color:var(--on-fill);
  display:grid;place-items:center;cursor:pointer;
  transition:filter .2s,opacity .2s;
}
.sarthi-send:hover{filter:brightness(1.08)}
.sarthi-send:disabled{opacity:.45;cursor:default}
.sarthi-send:focus-visible{outline:3px solid var(--haldi);outline-offset:2px}
.sarthi-send svg{width:19px;height:19px}
.sarthi-ask[hidden]{display:none}

/* ---- goal cards, recommendation card, suggestions ---- */

/* A PICK LIST — one column, one line each, a radio per row.

   This was a two-column grid of cards. Two problems, and the second is
   the one that matters:

     1. Long labels wrapped. "Relationship & marriage" broke over two
        lines while "Numerology" sat on one, so the rows were different
        heights and the column read as ragged rather than as a list.

     2. TWO COLUMNS IS NOT A LIST. A grid invites the eye to compare
        across as well as down, which is right for cards and wrong for
        "choose exactly one of these". One column, scanned top to
        bottom, is what a single choice looks like.

   The dot is not decoration either: a row of plain buttons gives no
   sign that picking one rules out the rest. */
.sar-chips.sar-pick{display:grid;grid-template-columns:minmax(0,1fr);gap:6px}
.sar-pick .sar-chip{
  width:100%;min-height:46px;border-radius:10px;
  display:flex;align-items:center;gap:11px;
  padding:10px 14px;line-height:1.3;
  /* One line, always. The panel is 400px and every label fits; if one
     ever does not, an ellipsis is tidier than a row twice the height of
     its neighbours. */
  white-space:nowrap;overflow:hidden;
}
.sar-pick .sar-lbl{overflow:hidden;text-overflow:ellipsis}
.sar-dot{
  flex:none;width:16px;height:16px;border-radius:50%;
  border:1.5px solid var(--edge-lit);
  display:grid;place-items:center;
  transition:border-color .18s;
}
.sar-dot::after{
  content:'';width:8px;height:8px;border-radius:50%;
  background:var(--amber);transform:scale(0);
  transition:transform .18s cubic-bezier(.2,.8,.3,1);
}
.sar-pick .sar-chip:hover .sar-dot{border-color:var(--amber)}
.sar-pick .sar-chip.is-on{border-color:var(--amber);
                          background:rgba(53,166,233,.14);color:var(--lit)}
.sar-pick .sar-chip.is-on .sar-dot{border-color:var(--amber)}
.sar-pick .sar-chip.is-on .sar-dot::after{transform:scale(1)}
/* Disabled the moment one is chosen, so a second click cannot land
   while the selection is being shown — but the chosen row must not grey
   out, because it is the answer. */
.sar-pick .sar-chip:disabled{cursor:default;opacity:.45}
.sar-pick .sar-chip.is-on:disabled{opacity:1}
@media (prefers-reduced-motion:reduce){
  .sar-dot,.sar-dot::after{transition:none}
}

/* THE RECOMMENDATION — brief §11.
   A description of a service and nothing else. No price: he does not
   quote one before he knows the question, and the figure is not
   Sarthi's to invent. */
.sar-card{
  align-self:flex-start;max-width:92%;
  /* Darker than the panel, like the bubbles — a card lighter than its
     container reads as floating a second time and the panel loses its
     own lift. */
  background:var(--void);border:1px solid var(--edge-lit);
  border-radius:12px;padding:14px 16px;
}
.sar-card-t{display:block;font-family:var(--serif);font-weight:400;
            font-size:1.06rem;color:var(--chalk);margin-bottom:7px}
.sar-card-w{margin:0 0 10px;color:var(--dim);font-size:.86rem;line-height:1.6}
.sar-card-l{margin:0;padding:0;list-style:none;display:grid;gap:6px}
.sar-card-l li{position:relative;padding-left:16px;
               color:var(--dim);font-size:.85rem;line-height:1.5}
.sar-card-l li::before{content:'';position:absolute;left:0;top:.55em;
  width:5px;height:5px;border-radius:50%;background:var(--tulsi)}
.sar-card-m{margin:11px 0 0;padding-top:10px;border-top:1px solid var(--faint);
            color:var(--hint);font-size:.76rem;line-height:1.5}

/* QUICK ACTIONS — brief §18. Rebuilt on every change of subject rather
   than toggled, so a stale action cannot survive one. */
/* Directly above the input, because that is what they are: things you
   could type. The old bar sat in the same place but held flow commands,
   which is why one of them jumped the conversation. */
.sar-quick{
  flex:none;display:flex;flex-wrap:wrap;gap:7px;
  padding:10px 14px 0;
}
.sar-quick[hidden]{display:none}
/* SAME FAILURE AS .dur-in, and worse. These are <button> elements with
   background:none — the pill outline is the entire affordance — and
   they sit on Sarthi's --void3 panel, where --faint measures 1.27:1
   against 1.63 on the page. The quietest surface carried the least
   visible control. --edge-lit is 3.66:1 there. */
.sar-q{
  width:auto;min-height:34px;padding:6px 13px;
  border:1px solid var(--edge-lit);border-radius:999px;background:none;
  color:var(--hint);font-family:var(--sans);font-size:.78rem;font-weight:500;
  cursor:pointer;transition:border-color .2s,color .2s;
}
.sar-q:hover{border-color:var(--amber);color:var(--chalk)}
.sar-q:focus-visible{outline:3px solid var(--amber);outline-offset:2px}

@media (prefers-reduced-motion:reduce){
  .sarthi,.sarthi-open,.sar-chip{transition:none}
  .sarthi-open:hover{transform:none}
}

/* ================= REVIEW YOUR BOOKING (14 October 2026) =================
   The step between the form and Cashfree, drawn inside the same modal with
   the same tokens: --void2 surfaces, --faint dividers, --edge-lit borders,
   --haldi/--amber accents. Cards stack in one column at every width, so
   nothing is clipped on a phone. */
.rv{display:flex;flex-direction:column;gap:12px;padding:4px 0 6px}
.rv-card{background:var(--void2);border:1px solid var(--faint);border-radius:12px;padding:14px 16px}
.rv-card-top{display:flex;align-items:center;justify-content:space-between;gap:12px;
             margin:0 0 8px}
.rv-h{margin:0;font-family:var(--sans);font-weight:600;font-size:.74rem;
      letter-spacing:.09em;text-transform:uppercase;color:var(--haldi)}
.rv-edit{width:auto;min-height:36px;padding:6px 14px;border-radius:8px;
         background:none;border:1px solid var(--edge-lit);color:var(--amber);
         font-weight:500;font-size:.84rem;
         transition:border-color .2s,color .2s,background .2s}
.rv-edit:hover{border-color:var(--amber);color:var(--haldi);background:rgba(53,166,233,.12)}
.rv-edit:focus-visible,.rv-back:focus-visible,.rv-pay:focus-visible{outline:3px solid var(--haldi);outline-offset:3px}
.rv-rows{margin:0;display:block}
.rv-row{display:flex;flex-direction:column;gap:2px;padding:9px 0;
        border-top:1px solid var(--faint);line-height:1.45}
.rv-row:first-child{border-top:0}
.rv-row dt{color:var(--dim);font-size:.8rem}
.rv-row dd{margin:0;color:var(--chalk);font-size:.96rem;overflow-wrap:anywhere}
.rv-disc dd{color:var(--tulsi)}
.rv-total{padding-top:12px;margin-top:2px;border-top:1px solid var(--edge-lit)}
.rv-total dt{color:var(--chalk);font-weight:600}
.rv-total dd{color:var(--haldi);font-weight:700;font-size:1.3rem}
.rv-none{margin:0;color:var(--dim);font-size:.9rem}
.rv-files{list-style:none;margin:0;padding:0}
.rv-file{display:grid;grid-template-columns:1fr auto;gap:2px 12px;padding:8px 0;
         border-top:1px solid var(--faint);font-size:.9rem}
.rv-file:first-child{border-top:0}
.rv-file-name{color:var(--chalk);overflow-wrap:anywhere}
.rv-file-meta{color:var(--dim);text-align:right}
.rv-file-st{grid-column:1/-1;font-size:.82rem}
.rv-file-st.ok{color:var(--tulsi)}.rv-file-st.wait{color:var(--dim)}.rv-file-st.bad{color:var(--alert)}
.rv-consent{list-style:none;margin:0;padding:0;font-size:.88rem;line-height:1.5;color:var(--dim)}
.rv-consent li{position:relative;padding:4px 0 4px 22px}
.rv-consent li::before{content:"";position:absolute;left:2px;top:.62em;width:10px;height:10px;
                       border-radius:50%;border:2px solid var(--edge-lit)}
.rv-consent .rv-ok::before{border-color:var(--tulsi);background:var(--tulsi)}
.rv-consent a{color:var(--amber)}
.rv-err{display:none;margin:0;font-size:.88rem;color:var(--alert)}
.rv-err.show{display:block}
.rv-actions{display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-top:2px}
.rv-back{background:none;color:var(--amber);border:1px solid var(--edge-lit);font-weight:500}
.rv-back:hover{border-color:var(--amber);color:var(--haldi);background:rgba(53,166,233,.12)}
.rv-note{margin-top:2px}
@media(max-width:520px){
  .rv-actions{grid-template-columns:1fr;gap:10px}
  .rv-pay{order:-1}
  .rv-card-top{align-items:flex-start}
}
@media(prefers-reduced-motion:reduce){.rv-edit,.rv-back{transition:none}}
