/* Self-hosted fonts (Google Fonts latin subsets, variable weight files), so the
   site makes no third-party request at all (DESIGN §10). */
@font-face {
  font-family: "Cormorant Garamond";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/assets/fonts/cormorant-garamond-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Cormorant Garamond";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/cormorant-garamond-italic-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Nunito Sans";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/assets/fonts/nunito-sans-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Tanisha Bhatia, practice website.
   Ported from the 12 Aug design-tool baseline (design-baseline/).
   Two rules that survive every design generation: no shadows, no gradients.
   Contrast: sage #7C826A fails 4.5:1 for small text on ivory, so anything
   small-and-sage uses --sage-deep #656B54 instead; #7C826A is reserved for
   fills under large text, marks, and decoration. */

:root {
  --ivory: #faf8f4;
  --stone: #ede8df;
  --taupe: #b6ab9a;
  --charcoal: #2e2e2e;
  --sage: #7c826a;
  --sage-deep: #656b54;
  --sage-hover: #585d48;
  /* Sage laid over ivory until it reads green without turning into a ground of
     its own: the Approach page's alternating band (owner, 15 Sep 2026).
     Measured on it: body 6.56:1, charcoal 11.42:1, sage-deep 4.67:1. */
  --sage-wash: #e9ede1;
  --body: #54524d;
  --field-border: #d9d2c6;
  /* Control boundaries need 3:1 (WCAG 1.4.11) and --field-border only manages
     1.6:1 on the ivory input fill, so inputs take this darker taupe instead:
     3.60:1 on ivory. --field-border stays for decorative outlines. */
  --input-border: #8c8172;
  --footer-body: #a9a397;
  --hairline: #e2ddd5;

  --serif: "Cormorant Garamond", Cormorant, "EB Garamond", Georgia, serif;
  --sans: "Nunito Sans", "Helvetica Neue", Arial, sans-serif;

  --container: 1180px;
  --narrow: 820px;
  --hpad: clamp(20px, 5vw, 40px);
  --section: clamp(56px, 8vw, 80px);

  /* An ivory site: never let a dark-mode phone draw dark form controls,
     scrollbars or a dark canvas behind the page. */
  color-scheme: light;
}

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

html {
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--ivory);
  color: var(--body);
  font-family: var(--sans);
  font-size: 18px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

h1,
h2,
h3 {
  margin: 0;
  color: var(--charcoal);
  font-family: var(--serif);
  font-weight: 500;
  line-height: 1.18;
  text-wrap: balance;
}

h1 {
  font-size: clamp(36px, 4.8vw, 52px);
  font-weight: 400;
}

.hero h1 {
  font-size: clamp(38px, 5vw, 58px);
}

/* The hero lead holds the baseline's 440px measure so its right edge sits
   under the h1 rather than running the full text column. */
.hero h1 + p {
  max-width: 440px;
}

h2 {
  font-size: clamp(30px, 3.6vw, 40px);
  font-weight: 400;
}

h3 {
  font-size: 24px;
}

p {
  margin: 0 0 22px;
}

p:last-child {
  margin-bottom: 0;
}

/* Let the browser rebalance the last lines of prose so a paragraph does not
   end on a single short word. */
p,
li,
dd {
  text-wrap: pretty;
}

/* Selection in the palette: the OS blue would be the only cold colour on the page. */
::selection {
  background: var(--sage-deep);
  color: var(--ivory);
}

/* One heading-to-paragraph gap for the whole site. Headings are reset to
   margin 0 above, so without this every h1/h2 followed by a paragraph sat at
   0px unless a component patched it (and six did, at 14–24px each). */
:is(h1, h2) + p {
  margin-top: 20px;
}

a {
  color: var(--sage-deep);
}

:focus-visible {
  outline: 2px solid var(--sage-deep);
  outline-offset: 2px;
}

.skip-link {
  position: fixed;
  z-index: 100;
  top: 8px;
  left: 8px;
  padding: 12px 16px;
  border-radius: 8px;
  background: var(--sage-deep);
  color: var(--ivory);
  text-decoration: none;
  transform: translateY(-200%);
}

.skip-link:focus {
  transform: translateY(0);
}

.container {
  width: min(var(--container), 100%);
  margin-inline: auto;
  padding-inline: var(--hpad);
}

.narrow {
  width: min(var(--narrow), 100%);
  margin-inline: auto;
  padding-inline: var(--hpad);
}

.section {
  padding-block: var(--section);
}

/* Two plain sections in a row sit 1.5 units apart (full bottom + half top);
   a section next to a band (hero, quote, CTA, footer) sits one unit from its
   edge. Without this every pair was 2 units (160px) apart on desktop. */
.section + .section {
  padding-top: calc(var(--section) * 0.5);
}

/* A full-bleed sage-wash band. It is a ground change, so it keeps the full
   unit of padding on both sides and gives the section after it the same. */
.section.wash {
  background: var(--sage-wash);
}

.section + .section.wash,
.section.wash + .section {
  padding-top: var(--section);
}

.eyebrow {
  margin: 0 0 14px;
  color: var(--sage-deep);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.24em;
  text-transform: uppercase;
}

.centered {
  text-align: center;
}

/* Keeps a hyphenated pair such as "10-minute" on one line. */
.nowrap {
  white-space: nowrap;
}

/* ---------- Buttons ---------- */

.button {
  display: inline-block;
  border: 0;
  border-radius: 8px;
  background: var(--sage-deep);
  color: var(--ivory);
  cursor: pointer;
  font-family: var(--sans);
  font-size: 15px;
  font-weight: 600;
  letter-spacing: 0.02em;
  line-height: 1.2;
  padding: 15px 30px;
  text-decoration: none;
  transition: background-color 150ms ease;
}

.button:hover {
  background: var(--sage-hover);
}

/* Quiet links sit beside, or stand in for, a 48px button and have to be as
   easy to hit, so the box grows to 48px and the taupe rule lives on a
   pseudo-element that stays 3px under the word instead of dropping to the
   bottom of the box. */
.link-quiet {
  align-items: center;
  color: var(--charcoal);
  display: inline-flex;
  min-height: 48px;
  position: relative;
  text-decoration: none;
}

.link-quiet::after {
  border-bottom: 1px solid var(--taupe);
  bottom: 12px;
  content: "";
  left: 0;
  position: absolute;
  right: 0;
  transition: border-color 150ms ease;
}

.link-quiet:hover::after {
  border-bottom-color: var(--sage-deep);
}

/* ---------- Header ---------- */

.site-header {
  position: sticky;
  z-index: 50;
  top: 0;
  border-bottom: 1px solid var(--hairline);
  background: rgba(250, 248, 244, 0.92);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
}

.header-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px 24px;
  padding-block: 16px;
}

.wordmark {
  color: var(--charcoal);
  font-family: var(--serif);
  font-size: 24px;
  font-weight: 400;
  /* Tight line box: on phones the wordmark is a row of its own. */
  line-height: 1.2;
  text-decoration: none;
  white-space: nowrap;
}

.wordmark .cred {
  color: var(--sage-deep);
  font-family: var(--sans);
  /* 12px is the site floor (DESIGN §3). */
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.18em;
  margin-left: 6px;
  text-transform: uppercase;
  vertical-align: 2px;
}

.nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px 26px;
}

.nav a {
  color: var(--body);
  /* 15px/500: the DESIGN §3 size, one step lighter than its 600 because six
     bold words in a row shout at 15px. */
  font-size: 15px;
  font-weight: 500;
  /* 15px × 1.65 line box + 24px block padding ≈ 49px: a full-height tap target. */
  padding-block: 12px;
  text-decoration: none;
  transition: color 150ms ease;
}

.nav a:hover {
  color: var(--charcoal);
}

/* The active-page underline is for the plain nav links. The CTA pill is never
   underlined: when Contact is the current page its "Get in touch" link carries
   aria-current, and this rule's specificity would otherwise override the pill's
   padding, drawing a stray rule beneath it. The underline's 1.5px comes out of
   the bottom padding so the active link keeps the same height as the rest. */
.nav a[aria-current="page"]:not(.nav-cta) {
  border-bottom: 1.5px solid var(--sage);
  color: var(--charcoal);
  padding-bottom: 10.5px;
}

.nav .nav-cta {
  border-bottom: 0;
  border-radius: 22px;
  background: var(--sage-deep);
  color: var(--ivory);
  font-size: 13px;
  font-weight: 600;
  /* The visible pill is the baseline's 41px (13px × 1.65 + 20px); the 48px
     tap target comes from the invisible ::after halo, not from a taller fill
     that would outweigh the wordmark. */
  padding: 10px 20px;
  position: relative;
  transition: background-color 150ms ease;
}

.nav .nav-cta::after {
  content: "";
  inset: -4px;
  position: absolute;
}

.nav .nav-cta:hover {
  background: var(--sage-hover);
  color: var(--ivory);
}

/* ---------- Hero (home) ---------- */

.hero {
  /* Inline-size container so the text panel can measure the page width in
     cqw below: 100vw would include the scrollbar and miss the grid by ~8px. */
  container-type: inline-size;
  display: grid;
  grid-template-columns: 1.05fr 0.95fr;
}

.hero-text {
  display: flex;
  flex-direction: column;
  justify-content: center;
  background: var(--stone);
  padding-block: var(--section);
  padding-inline: clamp(24px, 5vw, 56px);
  /* Once the window is wider than the container, the hero copy starts on the
     same x as the wordmark and every section below it (DESIGN §4). */
  padding-left: max(clamp(24px, 5vw, 56px), calc((100cqw - var(--container)) / 2 + var(--hpad)));
}

.hero-text-inner {
  max-width: 560px;
}

/* One practical line under the hero actions, in the footer's own words:
   who, where, and online. 15px is meta, above the 14px floor. */
.hero-facts {
  color: var(--body);
  font-size: 15px;
  line-height: 1.6;
  margin-top: 28px;
}

.hero-actions {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: 22px;
  margin-top: 34px;
}

.hero-image img {
  display: block;
  width: 100%;
  height: 100%;
  /* Capped near the text panel's own height so the image stops driving the
     grid on wide monitors and the h1 sits at the same y at 1920 as at 1440. */
  max-height: 480px;
  min-height: 420px;
  object-fit: cover;
  object-position: center 30%;
}

/* ---------- Hero puzzle (home) ---------- */

/* The baseline's animated puzzle, restored per DESIGN.md §9: pieces assemble on
   load (~2.5s), then eight of them take turns lifting out and easing back in on
   a 15s cycle, with one sage piece breathing between arrivals. Purely
   decorative and aria-hidden; frozen under reduced motion. */
.hero-puzzle {
  background: var(--ivory);
  min-height: clamp(340px, 42vw, 560px);
  overflow: hidden;
  position: relative;
}

/* The pieces are stroked ivory to draw the jigsaw seams, and that stroke also
   paints the puzzle's flat outer edge. With preserveAspectRatio="slice" the
   left/right edges land exactly on the panel (only top/bottom get cropped), so
   the outer stroke reads as a thin ivory rule at the seam with the stone
   hero-text panel. Bleeding the SVG a few px past the panel lets the panel's
   overflow:hidden clip that outer stroke, so each edge cuts through solid piece
   bodies instead of the stroke line. */
.hero-puzzle svg {
  position: absolute;
  inset: -6px;
  width: calc(100% + 12px);
  height: calc(100% + 12px);
}

.hero-puzzle path {
  animation: settle 0.8s cubic-bezier(0.22, 0.61, 0.36, 1) both;
  animation-delay: var(--d);
  opacity: 0;
  stroke: var(--ivory);
  stroke-width: 2.5;
  transform-box: fill-box;
  transform-origin: center;
}

@keyframes settle {
  from {
    opacity: 0;
    transform: translate(var(--dx), var(--dy)) rotate(var(--r, 0deg));
  }

  to {
    opacity: 1;
    transform: none;
  }
}

.hero-puzzle .refit {
  animation:
    settle 0.8s cubic-bezier(0.22, 0.61, 0.36, 1) both,
    refit 15s ease-in-out infinite;
  animation-delay: var(--d), var(--ld);
  animation-fill-mode: both, none;
}

@keyframes refit {
  0%,
  100% {
    transform: none;
    opacity: 1;
  }

  3% {
    transform: translate(calc(var(--dx) * 0.9), calc(var(--dy) * 0.9)) rotate(var(--r, 0deg));
    opacity: 0;
  }

  4.5% {
    transform: translate(calc(var(--dx) * 0.9), calc(var(--dy) * 0.9)) rotate(var(--r, 0deg));
    opacity: 0;
    animation-timing-function: cubic-bezier(0.22, 0.61, 0.36, 1);
  }

  11% {
    transform: none;
    opacity: 1;
  }
}

.hero-puzzle .breathe {
  animation:
    settle 0.8s cubic-bezier(0.22, 0.61, 0.36, 1) both,
    tint 12s ease-in-out 3s infinite;
  animation-delay: var(--d), 3s;
}

@keyframes tint {
  0%,
  100% {
    fill: #7c826a;
  }

  50% {
    fill: #9aa189;
  }
}

/* ---------- Cards ---------- */

/* Three fixed columns, one per audience: the row only ever scales with the
   window, it never rewraps into orphan rows (DESIGN.md §8). */
.card-grid {
  display: grid;
  gap: 24px;
  grid-template-columns: repeat(3, 1fr);
  margin-top: 44px;
}

/* Each card shares the row's two tracks (title, body) with its neighbours via
   subgrid: every title starts on the padding line and every paragraph starts
   on the same line as the others, with only the tallest title's height set
   aside rather than a fixed 2.5em. Without subgrid support the card falls
   back to its own auto rows, which only loses the paragraph alignment. */
.card {
  background: var(--stone);
  border-radius: 10px;
  display: grid;
  grid-row: span 2;
  grid-template-rows: subgrid;
  padding: 34px 30px;
  /* The subgrid would otherwise inherit the grid's 24px gap between title and body. */
  row-gap: 0;
}

.card h3 {
  font-size: 26px;
  margin-bottom: 12px;
}

.card p {
  font-size: 16px;
  margin: 0;
}

/* ---------- Quote band ---------- */

.quote-band {
  background: var(--sage);
  border-radius: 14px;
  padding: clamp(48px, 6vw, 72px) clamp(28px, 6vw, 96px);
}

.quote-band p {
  color: var(--ivory);
  font-family: var(--serif);
  font-size: clamp(24px, 3.4vw, 34px);
  font-style: italic;
  line-height: 1.4;
  margin: 0;
  margin-inline: auto;
  max-width: 760px;
  text-align: center;
  text-wrap: balance;
}

/* ---------- Split (about teaser, about page, contact) ---------- */

.split {
  display: grid;
  align-items: center;
  gap: clamp(32px, 5vw, 72px);
  /* Portrait 2 : prose 3; one column below 861px (DESIGN §8). */
  grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
}

.split.align-start {
  align-items: start;
}

/* The portraits are pre-cropped files (DESIGN §7): About 3:4, Home teaser 4:5,
   both cut from the original frame so nothing is thrown away in CSS. The img
   keeps width/height for layout stability; the ratio is the file's own. */
.portrait {
  border-radius: 10px;
  display: block;
  height: auto;
  width: 100%;
}

/* The teaser prose is short, so it sits vertically centred beside the 4:5
   frame (the split's default) rather than top-aligned above a gap. */
.split.teaser .portrait {
  max-width: 440px;
}

.sticky-col {
  position: sticky;
  top: 96px;
}

/* ---------- CTA band ---------- */

.cta-band {
  background: var(--stone);
  padding-block: var(--section);
  text-align: center;
}

.cta-band p {
  margin-inline: auto;
  max-width: 520px;
}

.cta-band .button {
  margin-top: 12px;
  padding: 15px 34px;
}

/* ---------- Approach page ---------- */

/* Stone callout naming the modalities, with the botanical line mark. */
.note-band {
  align-items: center;
  background: var(--stone);
  border-radius: 14px;
  display: flex;
  gap: clamp(20px, 3vw, 36px);
  padding: clamp(28px, 4vw, 40px) clamp(24px, 5vw, 56px);
}

.note-band .sprig {
  flex: none;
}

.note-band p {
  color: var(--charcoal);
  font-size: clamp(18px, 2vw, 21px);
  margin: 0;
  max-width: 620px;
}

/* Two-column sections: section heading and prose left, detail list right. */
.approach-cols {
  display: grid;
  gap: clamp(32px, 5vw, 80px);
  grid-template-columns: minmax(260px, 1fr) 1.8fr;
  align-items: start;
}

.col-head p {
  font-size: 17px;
}

/* Modalities as a definition table: term | hairline-ruled description rows. */
.modalities {
  margin: 0;
}

.modality {
  border-bottom: 1px solid var(--hairline);
  display: grid;
  gap: 16px clamp(20px, 3vw, 40px);
  grid-template-columns: minmax(150px, 190px) 1fr;
  padding-block: 24px;
}

.modality:first-child {
  border-top: 1px solid var(--hairline);
}

.modality dt {
  border-right: 1px solid var(--hairline);
  color: var(--charcoal);
  font-family: var(--serif);
  font-size: 23px;
  font-weight: 500;
  line-height: 1.25;
  padding-right: 18px;
}

.modality dd {
  font-size: 17px;
  margin: 0;
}

/* How therapy works: numbered rows sharing the modality table's rhythm. */
.how-item {
  border-bottom: 1px solid var(--hairline);
  display: grid;
  gap: 16px clamp(20px, 3vw, 40px);
  grid-template-columns: 56px 1fr;
  padding-block: 28px;
}

.how-item:first-child {
  border-top: 1px solid var(--hairline);
}

.how-item .num {
  color: var(--taupe);
  font-family: var(--serif);
  font-size: 30px;
  line-height: 1;
}

.how-item h3 {
  font-size: 26px;
  margin-bottom: 12px;
}

.how-item p {
  font-size: 17px;
}

/* "What happens next" strip (Home and Contact): three numbered steps on
   hairlines, the how-list's numeral and type on one row. Every sentence is
   hers, lifted from the Contact intro, the CTA band and the Approach steps. */
.steps-contact {
  margin-top: 72px;
}

.steps-contact h2 {
  font-size: clamp(28px, 3vw, 36px);
}

.steps-row {
  display: grid;
  gap: 32px 24px;
  grid-template-columns: repeat(3, 1fr);
  list-style: none;
  margin: 32px 0 0;
  padding: 0;
}

.steps-row li {
  border-top: 1px solid var(--hairline);
  padding-top: 20px;
}

.steps-row .num {
  color: var(--taupe);
  display: block;
  font-family: var(--serif);
  font-size: 30px;
  line-height: 1;
  margin-bottom: 14px;
}

.steps-row h3 {
  font-size: 24px;
  margin-bottom: 8px;
}

.steps-row p {
  font-size: 17px;
  margin: 0;
}

/* Closing card: stone by default, sage-wash on Approach so the page closes on
   the same green it opened its middle with. */
.begin-card {
  align-items: center;
  background: var(--stone);
  border-radius: 14px;
  display: flex;
  gap: clamp(24px, 4vw, 48px);
  padding: clamp(36px, 6vw, 64px);
}

.begin-card.wash-card {
  background: var(--sage-wash);
}

.begin-card .sprig {
  flex: none;
}

.begin-card p {
  max-width: 560px;
}

.begin-card .button {
  margin-top: 8px;
}

/* ---------- Intro block ---------- */

.intro-block {
  max-width: 640px;
}

.lead {
  color: var(--charcoal);
  font-family: var(--serif);
  font-size: 26px;
  line-height: 1.35;
}

/* ---------- Dotted item lists (service cards, qualifications) ---------- */

.dot-list {
  display: flex;
  flex-direction: column;
  font-size: 17px;
  list-style: none;
  margin: 0;
  padding: 0;
}

.dot-list li {
  padding-left: 18px;
  position: relative;
}

.dot-list li::before {
  background: var(--sage);
  border-radius: 50%;
  content: "";
  height: 5px;
  left: 0;
  position: absolute;
  top: 0.68em;
  width: 5px;
}

/* ---------- Service cards (services page) ---------- */

.service-grid {
  display: grid;
  gap: 20px;
  grid-template-columns: 1fr 1fr;
  margin-top: 44px;
}

/* Same subgrid treatment as .card: the two lists in a row start level even
   when one heading wraps and the other does not. */
.service-card {
  --card-fill: var(--stone);
  --card-title: var(--charcoal);
  --card-text: var(--body);
  --card-dot: var(--sage);
  background: var(--card-fill);
  border-radius: 10px;
  display: grid;
  grid-row: span 2;
  grid-template-rows: subgrid;
  padding: clamp(28px, 4vw, 36px) clamp(24px, 4vw, 32px);
  row-gap: 0;
}

.service-card h2 {
  color: var(--card-title);
  font-size: 26px;
  font-weight: 600;
  margin-bottom: 18px;
}

.service-card ul {
  color: var(--card-text);
  gap: 12px;
}

.service-card li::before {
  background: var(--card-dot);
}

/* The checkerboard is keyed on position, not a class, so the single column
   below 861px can re-alternate stone/sage/stone/sage instead of inheriting the
   desktop diagonal (stone/sage/sage/stone). Ivory heading (5.23:1) and stone
   items (4.55:1) on sage-deep; plain sage #7C826A would fail both. */
.service-card:nth-child(4n + 2),
.service-card:nth-child(4n + 3) {
  --card-fill: var(--sage-deep);
  --card-title: var(--ivory);
  --card-text: var(--stone);
  --card-dot: #d9d2c6;
}

/* ---------- Qualifications card (about page) ---------- */

.quals {
  background: var(--stone);
  border-radius: 10px;
  margin-top: 44px;
  padding: clamp(30px, 4vw, 40px) clamp(26px, 4vw, 36px);
}

/* Followed by a list, not a paragraph, so it carries the 20px gap itself. */
.quals h2 {
  font-size: 30px;
  margin-bottom: 20px;
}

.quals ul {
  gap: 14px;
}

/* The About page closes on one quiet line instead of the stone CTA band: the
   reader has just finished her story and needs a door, not a pitch
   (owner, 15 Sep 2026). */
.about-close {
  align-items: center;
  column-gap: 10px;
  display: flex;
  flex-wrap: wrap;
  margin: 40px 0 0;
}

/* ---------- FAQ ---------- */

/* Centred eyebrow + h1 above the accordion, per the baseline. The gap down to
   the content is the site-standard 44px used by every other page's title block
   (card grids, service grid, contact grid, qualifications), so page headers
   share one spacing rhythm. */
.faq-intro {
  margin-bottom: 44px;
}

/* The standfirst holds a 70-character measure inside the 820px column. */
.faq-intro p {
  margin-inline: auto;
  max-width: 560px;
}

/* Only the first group draws its own top rule: every later group sits on the
   hairline under the previous group's last answer, so there is one line
   between groups, not two with an empty 44px row between them. The group gap
   lives in the heading's top padding instead. */
.faq-group {
  border-top: 1px solid var(--hairline);
}

.faq-group + .faq-group {
  border-top: 0;
}

.faq-group > h2 {
  font-size: 30px;
  font-weight: 700;
  margin: 0;
  padding: 28px 4px 8px;
}

.faq-group + .faq-group > h2 {
  padding-top: 48px;
}

.faqs details {
  border-bottom: 1px solid var(--hairline);
}

.faqs summary {
  align-items: baseline;
  cursor: pointer;
  display: flex;
  gap: 24px;
  justify-content: space-between;
  list-style: none;
  padding: 26px 4px;
}

.faqs summary::-webkit-details-marker {
  display: none;
}

/* Questions are h3 beneath each category h2; the Cormorant 500 24px
   question look is set here, not by the h3 default. */
.faqs summary h3 {
  font-size: 24px;
  font-weight: 500;
  margin: 0;
}

/* Fixed 1em box: + and − have different advance widths, so without it the
   row's right edge shifted on every toggle. */
.faqs summary::after {
  color: var(--sage-deep);
  content: "+";
  flex: 0 0 auto;
  font-family: var(--sans);
  font-size: 26px;
  line-height: 1;
  text-align: center;
  width: 1em;
}

.faqs details[open] summary::after {
  content: "\2212";
}

/* Same 4px inset as the question above it, and a 600px measure: 17px Nunito
   runs ~70 characters there, 75 at the old 640px. */
.faqs .answer {
  font-size: 17px;
  max-width: 600px;
  padding: 0 4px 24px;
}

.faqs .answer p:last-child,
.faqs .answer ul:last-child {
  margin-bottom: 0;
}

/* The helpline list in the emergency answer takes the site's sage dot, not the
   UA's black disc. Styled here rather than with a class because the FAQPage
   JSON-LD mirrors this markup exactly (CLAUDE.md). */
.faqs .answer ul {
  list-style: none;
  margin: 0 0 22px;
  padding: 0;
}

.faqs .answer li {
  padding-left: 18px;
  position: relative;
}

.faqs .answer li + li {
  margin-top: 6px;
}

.faqs .answer li::before {
  background: var(--sage);
  border-radius: 50%;
  content: "";
  height: 5px;
  left: 0;
  position: absolute;
  top: 0.68em;
  width: 5px;
}

/* ---------- Contact ---------- */

.contact-grid {
  display: grid;
  gap: clamp(32px, 5vw, 64px);
  /* Form 3 : routes 2; one column below 861px (DESIGN §8). */
  grid-template-columns: minmax(0, 3fr) minmax(0, 2fr);
  margin-top: 44px;
}

/* Labels are quiet sage-deep (5.23:1 on ivory), not charcoal 700: a form on a
   therapy site should not shout its field names. */
.enquiry-form label {
  color: var(--sage-deep);
  display: block;
  font-size: 13px;
  font-weight: 400;
  letter-spacing: 0.06em;
  margin: 22px 0 8px;
  text-transform: uppercase;
}

.enquiry-form label:first-child {
  margin-top: 0;
}

/* The key to the asterisks, in the choice-hint voice. The asterisks are
   aria-hidden: each field's own `required` already announces itself. */
.required-key {
  color: var(--body);
  font-size: 15px;
  margin: 0;
}

/* Email and phone share a row; they stack below 768px (DESIGN §8). */
.field-pair {
  display: grid;
  gap: 14px;
  grid-template-columns: 1fr 1fr;
  margin-top: 22px;
}

/* White fill on the ivory page (DESIGN §6): the field reads as a field before
   its border does. Border #8C8172 measures 3.82:1 on white. Radios and
   checkboxes are excluded so the text-field padding never reaches them. */
.enquiry-form input:not([type="radio"], [type="checkbox"]),
.enquiry-form select,
.enquiry-form textarea {
  background: #fff;
  border: 1px solid var(--input-border);
  border-radius: 8px;
  color: var(--charcoal);
  font-family: var(--sans);
  font-size: 17px;
  min-height: 48px;
  padding: 12px 14px;
  width: 100%;
}

/* The only placeholder left is the textarea hint. It must read as a hint, not
   as typed text, so it sits between body and taupe: #76705F is 4.94:1 on white. */
.enquiry-form ::placeholder {
  color: #76705f;
  opacity: 1;
}

/* The browser's validation bubble disappears after a few seconds; an
   in-palette 2px rule stays on the field until it is fixed. Padding drops by
   the extra pixel so the box does not grow. */
.enquiry-form input:user-invalid,
.enquiry-form textarea:user-invalid {
  border-color: var(--sage-hover);
  border-width: 2px;
  padding: 11px 13px;
}

.enquiry-form textarea {
  min-height: 130px;
  resize: vertical;
}

/* Radio and checkbox groups. The legend takes the field-label voice; the
   choices themselves are plain body text. */
.choice-group {
  border: 0;
  margin: 22px 0 0;
  min-width: 0;
  padding: 0;
}

.enquiry-form legend {
  color: var(--sage-deep);
  font-size: 13px;
  letter-spacing: 0.06em;
  margin-bottom: 8px;
  padding: 0;
  text-transform: uppercase;
}

.enquiry-form label.choice {
  align-items: flex-start;
  color: var(--body);
  display: flex;
  font-size: 16px;
  gap: 12px;
  letter-spacing: normal;
  margin: 0;
  /* 16px × 1.65 line box + 22px padding ≈ 48px per choice row. */
  padding-block: 11px;
  text-transform: none;
}

/* One sentence under a legend, in the quiet label voice but sentence case so
   it reads as guidance rather than another field name. */
.choice-hint {
  color: var(--body);
  font-size: 15px;
  margin: 0 0 4px;
}

.enquiry-form .choice input {
  accent-color: var(--sage-deep);
  flex: none;
  height: 19px;
  margin: 3px 0 0;
  min-height: 0;
  width: 19px;
}

/* The two hand-offs sit on one row: the primary button composes an email, the
   quiet link the same message in WhatsApp. One button, no second pill. */
.form-actions {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: 8px 26px;
  margin-top: 26px;
}

.form-actions .button {
  margin-top: 0;
}

/* .link-quiet on a <button>: it has to carry form data, so it cannot be an
   anchor. Strip the control chrome and let the shared rule do the rest. */
button.link-quiet {
  background: none;
  border: 0;
  cursor: pointer;
  font-family: var(--sans);
  font-size: 16px;
  padding: 0;
}

/* Written by script.js once the enquiry is sent or fails. The paragraph stays
   in the tree while empty (it is a role="status" region and has to exist before
   it is filled to be announced); it only takes the stone panel once it has text. */
.form-feedback {
  font-size: 15px;
  margin: 0;
}

.form-feedback:not(:empty) {
  background: var(--stone);
  border-radius: 10px;
  margin-top: 16px;
  padding: 14px 18px;
}

/* Spam trap: off-screen for people, still filled in by bots. */
.form-trap {
  position: absolute;
  left: -10000px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.contact-cards {
  display: grid;
  gap: 18px;
  align-content: start;
}

.contact-card {
  background: var(--stone);
  border-radius: 10px;
  padding: 24px 28px;
}

.contact-card.outline {
  background: transparent;
  border: 1px solid var(--field-border);
}

.contact-card .label {
  color: var(--sage-deep);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.2em;
  margin-bottom: 6px;
  text-transform: uppercase;
}

.contact-card .value {
  color: var(--charcoal);
  font-family: var(--serif);
  font-size: 24px;
  font-weight: 500;
  /* Cormorant's default figures are old-style, so a phone number bounces
     between x-height and ascender; lining figures sit level like the email. */
  font-variant-numeric: lining-nums;
  line-height: 1.25;
  margin-bottom: 4px;
  /* The email carries a <wbr> after the @ so a narrow card breaks it there;
     anywhere-wrapping stays only as the last resort for a card narrower than
     "tanishabhatia.com" itself. */
  overflow-wrap: anywhere;
}

.contact-card .value a {
  color: inherit;
  text-decoration: none;
}

.contact-card .value a:hover {
  color: var(--sage-deep);
}

.hours-row {
  display: flex;
  font-size: 16px;
  justify-content: space-between;
  padding-block: 6px;
}

/* ---------- Footer ---------- */

.site-footer {
  background: var(--charcoal);
  color: var(--footer-body);
  font-size: 15px;
  padding-top: clamp(48px, 6vw, 72px);
}

/* The sage-deep focus ring is invisible on charcoal. */
.site-footer :focus-visible {
  outline-color: var(--ivory);
}

/* Minimal footer (owner, 15 Sep 2026): the practice line on the left, the links
   and the two ways to reach her as two wrapped rows on the right. The three
   labelled columns ran ~350px tall and pushed the emergency block off the
   fold; this is ~110px and the emergency text arrives sooner. */
.footer-top {
  display: flex;
  flex-wrap: wrap;
  gap: 16px clamp(32px, 6vw, 72px);
  justify-content: space-between;
  padding-bottom: 28px;
}

.footer-name {
  color: var(--ivory);
  font-family: var(--serif);
  font-size: 24px;
  margin-bottom: 6px;
}

.footer-practice {
  margin: 0;
}

.footer-ways {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  text-align: right;
}

/* Both rows wrap rather than shrink, and every link keeps its own 48px box:
   15px × 1.65 line box + 24px padding (DESIGN §10). */
.footer-nav,
.footer-reach {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  column-gap: 26px;
  margin: 0;
}

.footer-nav a,
.footer-reach a {
  display: inline-flex;
  align-items: center;
  min-height: 48px;
}

/* Links sit a step above footer body text: #CFCAC1 measures 8.32:1 on charcoal. */
.site-footer a {
  color: #cfcac1;
  text-decoration: none;
  transition: color 150ms ease;
}

.site-footer a:hover {
  color: var(--ivory);
}

.footer-urgent {
  border-top: 1px solid rgba(250, 248, 244, 0.16);
  padding-block: 24px 20px;
}

.footer-urgent-head {
  color: var(--ivory);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.2em;
  margin-bottom: 8px;
  text-transform: uppercase;
}

/* The one paragraph a distressed reader must be able to read: capped at ~70
   characters instead of running the full 1100px container. */
.footer-urgent p {
  color: #cfcac1;
  margin: 0;
  max-width: 640px;
}

/* The three helplines from the FAQ emergency answer, repeated in her words
   (owner decision, 9 Sep 2026). Each item is a 48px row; the numbers are
   ivory and underlined so they read as callable on the charcoal ground. They
   sit a step below the paragraph at the 14px meta floor (24 Sep 2026). */
.footer-helplines {
  column-gap: 32px;
  display: flex;
  flex-wrap: wrap;
  font-size: 14px;
  list-style: none;
  margin: 8px 0 0;
  padding: 0;
}

.footer-helplines li {
  align-items: center;
  color: #cfcac1;
  display: flex;
  min-height: 48px;
}

.footer-helplines a {
  color: var(--ivory);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.footer-bar {
  border-top: 1px solid rgba(250, 248, 244, 0.16);
  display: flex;
  flex-wrap: wrap;
  gap: 8px 24px;
  justify-content: space-between;
  font-size: 14px;
  padding-top: 20px;
  /* Clear the home indicator on phones with a bottom inset. */
  padding-bottom: max(20px, env(safe-area-inset-bottom));
}

/* ---------- WhatsApp button ---------- */

/* A plain wa.me link held in the corner of every page (owner, 25 Sep 2026):
   it opens her WhatsApp chat and nothing more, so it is not a chat widget
   (DESIGN §10). Sage-deep rather than WhatsApp green so it stays in the
   palette; the glyph is ivory at 5.23:1. 52px clears the 48px target. */
.whatsapp-float {
  align-items: center;
  background: var(--sage-deep);
  border-radius: 50%;
  bottom: max(16px, calc(env(safe-area-inset-bottom) + 8px));
  box-shadow: 0 2px 10px rgba(46, 46, 46, 0.18);
  color: var(--ivory);
  display: flex;
  height: 52px;
  justify-content: center;
  position: fixed;
  right: max(16px, calc(env(safe-area-inset-right) + 8px));
  width: 52px;
  z-index: 40;
}

.whatsapp-float:hover {
  background: var(--sage-hover);
}

/* ---------- Motion ---------- */

/* No page-entry animation: pages arrive still, so header, footer and
   container edges hold their place between pages (review R10, 9 Sep 2026). */
main {
  /* The skip link's target: keep the h1 clear of the sticky header. */
  scroll-margin-top: 96px;
}

/* ---------- Responsive ---------- */

/* Just above the un-stick point the 781px row has to hold the wordmark (266px)
   and the nav (372px of links and pill); 20px gaps leave 19px to spare where
   26px would wrap the nav under the wordmark inside a sticky header. */
@media (min-width: 861px) and (max-width: 1023px) {
  .nav {
    gap: 4px 20px;
  }

  /* Three columns here gave 244–290px cards at 20 characters per line. Two
     columns with the third card spanning both keeps every card above 380px;
     three columns return from 1024. */
  .card-grid {
    grid-template-columns: repeat(2, 1fr);
  }

  .card-grid .card:last-child {
    grid-column: 1 / -1;
  }
}

@media (max-width: 860px) {
  /* The header un-sticks and centres here rather than at 767px so there is no
     middle state where the nav wraps left-aligned under a sticky wordmark.
     A static header also stops a 170px sticky band covering a fifth of a
     phone screen. */
  .site-header {
    position: static;
  }

  .header-inner,
  .nav {
    justify-content: center;
    text-align: center;
  }

  /* Three centred rows on phones (wordmark, links, pill); tighter block
     padding and row gap keep the whole header near its old height even with
     full-height link targets. */
  .header-inner {
    gap: 8px 24px;
    padding-block: 12px;
  }

  /* 16px between links fits all five on one 320px row; the pill takes the
     next row on phones and rejoins the links once there is room. */
  .nav {
    gap: 4px 16px;
  }

  main {
    scroll-margin-top: 0;
  }

  .hero,
  .split,
  .card-grid,
  .contact-grid,
  .service-grid,
  .approach-cols,
  .steps-row {
    grid-template-columns: 1fr;
  }

  /* On phones the puzzle stops being a panel and becomes the ground of the
     hero copy (owner, 15 Sep 2026). The text panel and its inner wrapper
     dissolve (display: contents) so the eyebrow, headline, paragraph, actions
     and facts line are rows of one grid, and the puzzle spans only the first
     three rows: it ends exactly 18px under the paragraph, wherever that falls,
     and the actions and facts sit on plain stone below it. The band's
     vertical padding moves onto the first and last rows so the wash reaches
     the header rule. The pieces keep the desktop's settle and re-fit cycle
     (owner, 15 Sep 2026); reduced motion freezes them as everywhere else.
     Desktop keeps the animated panel unchanged. */
  .hero {
    background: var(--stone);
    padding-inline: clamp(24px, 5vw, 56px);
  }

  .hero-text,
  .hero-text-inner {
    display: contents;
  }

  /* The copy elements are grid items through display: contents but remain
     children of the inner wrapper, so they are addressed there. Every row sits
     in the one column explicitly: with the puzzle occupying column 1 of rows
     1 to 3, auto-placement would otherwise open a second column for the copy. */
  .hero-text-inner > * {
    grid-column: 1;
    max-width: 560px;
    position: relative;
    z-index: 1;
  }

  .hero .eyebrow {
    grid-row: 1;
    padding-top: var(--section);
  }

  .hero h1 {
    grid-row: 2;
  }

  .hero h1 + p {
    grid-row: 3;
    margin-bottom: 0;
    padding-bottom: 18px;
  }

  .hero-actions {
    grid-row: 4;
    margin-bottom: 0;
    margin-top: 16px;
  }

  /* The facts read as three centred lines under the stacked pair (owner,
     15 Sep 2026), with a looser leading than the desktop's single line. */
  /* 20px box gap plus the quiet link's 15px of tap-target slack puts the
     facts 35px under the link's text, the same step as paragraph to button. */
  .hero-facts {
    grid-row: 5;
    line-height: 1.75;
    margin-top: 20px;
    padding-bottom: var(--section);
    text-align: center;
  }

  .hero-puzzle {
    background: transparent;
    container-type: size;
    grid-column: 1;
    grid-row: 1 / 4;
    margin-inline: calc(-1 * clamp(24px, 5vw, 56px));
    min-height: 0;
    opacity: 0.5;
    pointer-events: none;
    z-index: 0;
  }

  /* The puzzle fills the wash: a square sized to the larger of the box's two
     dimensions (its viewBox is square), centred horizontally and hanging from
     the bottom, bled 6px past it so the outer stroke is clipped. The bottom
     row therefore always ends on the puzzle's own flat edge; the top row and
     side columns, which must be cut, dissolve into the stone through the mask
     below instead of ending on a hard line (owner, 15 Sep 2026). */
  .hero-puzzle svg {
    height: auto;
    inset: auto;
    bottom: -6px;
    left: 50%;
    transform: translateX(-50%);
    width: max(100cqw + 12px, 100cqh + 12px);
  }

  /* The puzzle was tinted for the desktop's ivory panel, where its palest
     piece is stone. On the stone band those pieces vanish, so on phones the
     tints are re-dealt (owner, 15 Sep 2026): stone pieces become ivory with
     stone seams, the taupe pieces take the lighter derived tint so nothing
     dark reads through the copy, three pieces behind the copy take the mid
     tints so the visible zone (rows 2 to 5, the outer columns in the fades)
     has the same variation as the panel, and the sage accent with its
     breathing moves one column right, from behind the headline into the
     right-hand fade. Paths are numbered row by row, five to a row. */
  .hero-puzzle path {
    stroke: var(--stone);
  }

  .hero-puzzle path[fill="#EDE8DF"] {
    fill: var(--ivory);
  }

  .hero-puzzle path[fill="#B6AB9A"] {
    fill: #d8cfbe;
  }

  .hero-puzzle path:nth-child(8) {
    fill: #c6cbb4;
  }

  .hero-puzzle path:nth-child(18) {
    fill: #d8cfbe;
  }

  .hero-puzzle path:nth-child(23) {
    fill: #e7e1d4;
  }

  .hero-puzzle .breathe {
    animation: settle 0.8s cubic-bezier(0.22, 0.61, 0.36, 1) both;
    animation-delay: var(--d);
    fill: #c6cbb4;
  }

  .hero-puzzle path:nth-child(15) {
    animation:
      settle 0.8s cubic-bezier(0.22, 0.61, 0.36, 1) both,
      tint 12s ease-in-out 3s infinite;
    animation-delay: var(--d), 3s;
    fill: #7c826a;
  }

  /* Three more pieces in the visible zone join the re-fit cycle, at delays
     that fall between the panel's own, so a lift is seen roughly every two
     to three seconds rather than mostly off in the faded edges. */
  .hero-puzzle path:nth-child(8),
  .hero-puzzle path:nth-child(13),
  .hero-puzzle path:nth-child(23) {
    animation:
      settle 0.8s cubic-bezier(0.22, 0.61, 0.36, 1) both,
      refit 15s ease-in-out infinite;
    animation-delay: var(--d), var(--ld);
    animation-fill-mode: both, none;
  }

  .hero-puzzle path:nth-child(8) {
    --ld: 3.5s;
  }

  .hero-puzzle path:nth-child(13) {
    --ld: 6.9s;
  }

  .hero-puzzle path:nth-child(23) {
    --ld: 10.3s;
  }

  /* Two gradients intersected: fully clear over the lower middle, fading to
     nothing at the top edge and both side edges. */
  .hero-puzzle {
    -webkit-mask-composite: source-in;
    -webkit-mask-image:
      linear-gradient(to bottom, transparent 0, #000 38%),
      linear-gradient(to right, transparent 0, #000 22%, #000 78%, transparent 100%);
    mask-composite: intersect;
    mask-image:
      linear-gradient(to bottom, transparent 0, #000 38%),
      linear-gradient(to right, transparent 0, #000 22%, #000 78%, transparent 100%);
  }

  /* One fact per line: the middle dots that join them on one desktop line
     are dropped and each span takes its own row. */
  .hero-facts span {
    display: block;
  }

  .hero-facts .sep {
    display: none;
  }

  .modality {
    grid-template-columns: 1fr;
    gap: 8px;
  }

  .modality dt {
    border-right: 0;
    padding-right: 0;
  }

  .note-band,
  .begin-card {
    flex-direction: column;
    align-items: flex-start;
  }

  /* Re-alternate the checkerboard for a single column. */
  .service-card:nth-child(4n + 3) {
    --card-fill: var(--stone);
    --card-title: var(--charcoal);
    --card-text: var(--body);
    --card-dot: var(--sage);
  }

  .service-card:nth-child(4n + 4) {
    --card-fill: var(--sage-deep);
    --card-title: var(--ivory);
    --card-text: var(--stone);
    --card-dot: #d9d2c6;
  }

  .sticky-col {
    position: static;
  }

  /* Stacked, the portrait sits centred over the prose instead of hugging the
     left edge, and About's frame keeps the teaser's 440px cap. */
  .split .portrait {
    margin-inline: auto;
    max-width: 440px;
  }
}

@media (max-width: 767px) {
  .field-pair {
    grid-template-columns: 1fr;
  }

  /* One left-aligned column: right-aligned link rows read as ragged once the
     footer is a single stack. */
  .footer-ways {
    align-items: flex-start;
    text-align: left;
  }

  .footer-nav,
  .footer-reach {
    justify-content: flex-start;
  }

  /* Five 15px links measure 260px; 12px gaps keep them on one 320px row
     (360px viewport) where 16px would push FAQ onto a third header row. */
  .nav {
    gap: 4px 12px;
  }

  /* Buttons go full-width on phones (DESIGN §6). */
  .button {
    display: block;
    text-align: center;
    width: 100%;
  }

  /* The hero pair stacks: the full-width button with the quiet link centred
     beneath it at the button's own 15px, so the two read as one control
     rather than a bar with a stray link under it (owner, 15 Sep 2026). */
  .hero-actions {
    align-items: stretch;
    flex-direction: column;
    gap: 6px;
  }

  .hero-actions .link-quiet {
    align-self: center;
    font-size: 15px;
  }

  .hero-image img {
    min-height: 320px;
  }

  /* Full-bleed: the band breaks out of its container's side padding, which is
     what the squared-off corners are for. */
  .quote-band {
    border-radius: 0;
    margin-inline: calc(var(--hpad) * -1);
  }
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  /* The puzzle renders complete and still. The refit and breathe pieces are
     listed by class so this override outranks their own animation rules
     (`.hero-puzzle .refit` is more specific than `.hero-puzzle path`). */
  .hero-puzzle path,
  .hero-puzzle .refit,
  .hero-puzzle .breathe {
    animation: none;
    opacity: 1;
    transform: none;
  }
}

/* ---------- Print ---------- */

@media print {
  .skip-link,
  .whatsapp-float,
  .nav,
  .hero-puzzle,
  .cta-band {
    display: none;
  }

  body,
  .section.wash {
    background: #fff;
  }

  .site-footer {
    background: #fff;
    color: var(--body);
  }

  .site-footer a,
  .footer-name,
  .footer-urgent-head,
  .footer-urgent p,
  .footer-helplines li {
    color: var(--charcoal);
  }
}
