/*
Theme Name: The Homeopathy Clinic
Theme URI: https://thehomeoclinic.com/
Author: Dr Sandeep Kumar Mishra
Description: Custom theme for The Homeopathy Clinic, Kanpur. Direction C. Mobile-first, one stylesheet, no icon fonts, no PHP sessions, PHP 7.4 compatible. Design system in BRAND.md; clinic facts in CLINIC-DATA.md, all wired to Appearance -> Customize.
Version: 0.11.3
Requires at least: 6.0
Tested up to: 6.8
Requires PHP: 7.4
License: GPL-2.0-or-later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: homeoclinic
*/

/* ==========================================================================
   1. TOKENS
   Every value here comes from BRAND.md. Nothing below this block may write a
   colour literal — the audit found three different teals, five radii and
   twelve type sizes on the live site, and one of each is the entire point.

   ONE scheme, light, defined once on the bare :root. It was three until 0.8.0,
   when the automatic prefers-color-scheme switch was removed — see the note
   below the token block for why. The [data-theme="dark"] set is still here but
   inert; nothing sets that attribute.
   ========================================================================== */

:root {
	--green:        #0E8A40;
	--green-text:   #0B6E33;
	--green-deep:   #073D1F;
	--green-soft:   #E0EEE2;
	--green-line:   #155A31;
	--leaf:         #7CBF3F;
	--leaf-bright:  #8FD44A;
	--orange:       #F7941E;
	--orange-hover: #E8871A;
	--orange-ink:   #1A1204;
	--orange-ink-2: #4E340D;
	--orange-text:  #A85A05;
	--paper:        #F2F4EF;
	--surface:      #FFFFFF;
	--surface-2:    #E7EBE2;
	--ink:          #0C1410;
	--ink-2:        #414C44;
	--ink-3:        #5A665C;
	--line:         #DDE2D8;
	--line-strong:  #C3CBBD;
	--on-green:     #F0F7EF;
	--on-green-2:   #9DC4A5;
	--wa:           #0E7440;
	--wa-hover:     #0B6134;
	--wa-ink:       #FFFFFF;

	/* Practo's blue, for the button that leaves for Practo. Their own Book
	   Appointment CTA measures #199FD9 with white text — read off the live page
	   on 2026-08-28, not taken from a palette site, which said #14BEF0. White on
	   #199FD9 is 3.0:1 and our text is 16.8px bold, which is not large text, so
	   the floor is 4.5:1 and their colour misses it. Same hue (198 degrees),
	   darkened until white clears the floor: 4.99:1. Precedent is WhatsApp —
	   BRAND.md keeps a brand colour but moves its luminance far enough to be
	   readable, and no further. */
	--practo:       #0D77A6;
	--practo-hover: #0A607F;
	--practo-ink:   #FFFFFF;

	--radius:    18px;
	--radius-in: 12px;
	--radius-vid:14px;
	--radius-pill: 999px;

	--shadow: 0 2px 3px rgba(12, 20, 16, .05), 0 14px 34px -18px rgba(12, 20, 16, .3);
	--shadow-lift: 0 6px 10px -8px rgba(12, 20, 16, .18), 0 22px 44px -22px rgba(12, 20, 16, .40);

	/* MOTION. Two curves and three durations, and every animated thing in the
	   theme uses one of them - the same argument as one green and two radii.
	   Mixed easing is why a site with animation on it can still feel cheap:
	   six components each easing differently read as six components, not as
	   one page.

	   --ease-out is the expensive one. It is fast at the start and takes a
	   long time to settle, which is how a heavy, well-damped object moves;
	   linear and ease-in-out both read as software. It is used for anything
	   that ARRIVES - reveals, entrances, the menu.

	   --ease is symmetrical and short, for things that respond to a finger or
	   a cursor and must not lag behind it.

	   Nothing here runs unless html carries .has-motion, which is set by four
	   lines in the <head> and only when the visitor has not asked their device
	   for reduced motion. See inc/assets.php. */
	--ease:      cubic-bezier(.4, 0, .2, 1);
	--ease-out:  cubic-bezier(.16, 1, .3, 1);
	--dur-fast:  .18s;
	--dur:       .32s;
	--dur-slow:  .7s;
	--stagger:   80ms;

	--pad-block: 60px;
	--wrap: 1140px;

	--sans: "Archivo", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
	--deva: "Noto Sans Devanagari", var(--sans);

	/* Light only, and say so. Without this the browser still darkens the things
	 * it owns rather than the page — scrollbars, form controls, the flash of
	 * background before CSS paints — on a phone set to dark mode. 0.8.0. */
	color-scheme: light;
}

/* The automatic dark scheme was REMOVED in 0.8.0 — 2026-09-03.
 *
 * It was never a decision the owner took. It was added because respecting
 * prefers-color-scheme is good practice, and the consequence was that the
 * first time he ever saw his own site he saw a near-black page, on a machine
 * set to dark mode, and said it was not the design he approved. He was right:
 * the mockups signed off on 20 August were the light palette below, and he had
 * never once been shown the dark one.
 *
 * A visitor's phone setting must not decide which of two designs a clinic
 * presents to a patient, when only one of them has been approved.
 *
 * The dark token values are NOT lost. They stay in BRAND.md with their
 * contrast audit, and the [data-theme="dark"] block below still applies them
 * if anything ever sets that attribute — nothing does today. To bring the
 * automatic switch back, wrap that block in
 * @media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { … } }
 * again, and re-check the header: on Elementor pages a builder stylesheet
 * repaints .site-head, so the header and body disagreed under dark mode.
 */

:root[data-theme="dark"] {
	--green:        #4FBF72;
	--green-text:   #6ACF89;
	--green-deep:   #06301A;
	--green-soft:   #15281A;
	--green-line:   #12522C;
	--leaf:         #9AD45E;
	--leaf-bright:  #A7E065;
	--orange:       #F9A63F;
	--orange-hover: #FBB65C;
	--orange-text:  #F0A64A;
	--paper:        #0A0F0C;
	--surface:      #121A14;
	--surface-2:    #18211A;
	--ink:          #E9EFE9;
	--ink-2:        #A8B5AA;
	--ink-3:        #8C9A8E;
	--line:         #202B23;
	--line-strong:  #314035;
	--on-green:     #EDF5EC;
	--on-green-2:   #8FB897;
	--wa:           #25B85F;
	--wa-hover:     #3ACB72;
	--wa-ink:       #08140C;
	--practo:       #38B6E8;
	--practo-hover: #55C4EF;
	--practo-ink:   #06131A;
}

@media (min-width: 900px) {
	:root { --pad-block: 96px; }
}

/* ==========================================================================
   2. RESET
   ========================================================================== */

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

html {
	-webkit-text-size-adjust: 100%;

	/* The header is sticky, so an in-page anchor otherwise lands with its
	   heading hidden underneath it. Clears the tallest header (94px) plus air.
	   Added 0.9.6, when the menu started shipping section anchors. */
	scroll-padding-top: 116px;
}

@media (prefers-reduced-motion: no-preference) {
	html { scroll-behavior: smooth; }
}

::selection {
	background: var(--leaf);
	color: var(--green-deep);
}

body {
	margin: 0;
	background: var(--paper);
	color: var(--ink);
	font-family: var(--sans);
	font-size: 16.5px;
	line-height: 1.55;
	-webkit-font-smoothing: antialiased;
	overflow-wrap: break-word;
}

/* body sets break-word so a long URL in an article cannot push the page
   sideways. Display headings are the exception: at 56px a split word reads as
   a fault, not as wrapping. Headings get enough room instead — see
   .booking-inner. */
h1, h2, h3 { overflow-wrap: normal; }

img, svg, iframe, video { max-width: 100%; }
img, iframe, video { height: auto; display: block; }

h1, h2, h3, h4, p, ul, ol, dl, figure, blockquote { margin: 0; }
ul, ol { padding: 0; list-style: none; }

a { color: inherit; }

button { font: inherit; color: inherit; }

table { border-collapse: collapse; width: 100%; }

/* BRAND.md: one focus ring, always visible. */
:focus-visible {
	outline: 3px solid var(--orange);
	outline-offset: 3px;
	border-radius: 2px;
}

/* Orange on orange is invisible. */
.on-orange :focus-visible { outline-color: var(--orange-ink); }

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

.screen-reader-text {
	position: absolute !important;
	width: 1px; height: 1px;
	padding: 0; margin: -1px;
	overflow: hidden;
	clip: rect(0 0 0 0);
	clip-path: inset(50%);
	white-space: nowrap;
	border: 0;
}

.skip-link {
	position: absolute;
	left: -9999px;
	z-index: 100;
	padding: 14px 20px;
	background: var(--orange);
	color: var(--orange-ink);
	font-weight: 800;
	text-decoration: none;
}
.skip-link:focus { left: 12px; top: 12px; }

/* ==========================================================================
   3. TYPE
   Archivo, worked hard. Headings are uppercase via text-transform, never typed
   capitals, so screen readers do not spell them out.
   ========================================================================== */

h1, h2, h3,
.stat-value, .step-num, .rating-value, .reviews-value,
.clinic-name, .btn, .eyebrow, .card-title {
	font-family: var(--sans);
	text-transform: uppercase;
	font-weight: 800;
	/* 104%, not 108%, and -.042em, not -.035em. Archivo's width axis pushed
	   out that far at display sizes reads as a sports wordmark; pulled back
	   towards normal width and tracked tighter it reads as a set headline.
	   The change is 4% of one axis and is invisible on a 1rem card title -
	   it only shows where the type is large, which is where it mattered. */
	font-stretch: 104%;
	letter-spacing: -.042em;
	line-height: 1.02;
}

h1 { font-size: clamp(2.6rem, 10.5vw, 5.4rem); }
h2 { font-size: clamp(2rem, 6.2vw, 3.5rem); }

/* Balance the lines rather than filling each one before moving to the next.
   Without it the homepage headline set as

       A
       HOMEOPATH
       YOU CAN
       SEE TODAY
       IN KANPUR.

   - a single letter alone on the widest line of type on the site. The browser
   does the work; where text-wrap is unsupported the heading simply wraps as
   before. */
h1, h2 { text-wrap: balance; }
.lede { text-wrap: pretty; }

/* The clamp floors (2.6rem / 2rem) stop the headings shrinking below roughly
   360px, which is where the Customizer's mobile preview and older Androids
   sit. Since headings no longer break mid-word, a long word — HOMEOPATHY,
   APPOINTMENT — would run past the edge instead of splitting. Drop the floor
   on the narrowest screens so the word shrinks to fit rather than overflowing. */
@media (max-width: 359px) {
	h1 { font-size: 2.05rem; }
	h2 { font-size: 1.7rem; }
}

h3 {
	font-size: 1.15rem;
	font-weight: 700;
	letter-spacing: -.018em;
	line-height: 1.2;
	text-transform: none;
}

.lede {
	font-size: 1.12rem;
	font-weight: 500;
	line-height: 1.5;
	text-transform: none;
	letter-spacing: 0;
	max-width: 46ch;
}

.eyebrow {
	display: flex;
	align-items: center;
	gap: 9px;
	font-size: .74rem;
	font-weight: 800;
	font-stretch: 100%;
	letter-spacing: .18em;
	line-height: 1.2;
	color: var(--green-text);
}

.post-meta,
.week-note,
.clinic-note,
.foot-note {
	font-size: .88rem;
	font-weight: 500;
	color: var(--ink-3);
	text-transform: none;
	letter-spacing: 0;
}

/* Devanagari has no case and must never be uppercased or letter-spaced. */
.hi {
	font-family: var(--deva);
	text-transform: none;
	letter-spacing: 0;
	line-height: 1.35;
}

/* ==========================================================================
   4. LAYOUT
   Spacing comes from gap, never per-element margins.
   ========================================================================== */

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

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

.sec-head {
	display: flex;
	flex-direction: column;
	gap: 14px;
	margin-bottom: 36px;
	max-width: 42ch;
}

.sec-foot {
	margin-top: 32px;
	color: var(--ink-2);
}

/* ---- Colour blocks. Each sets its own ground AND its own text tokens, so
   nothing inside ever needs to know which block it is in. ---- */

.on-green {
	background: var(--green-deep);
	color: var(--on-green);
}
.on-green .lede,
.on-green .sec-foot,
.on-green .post-meta { color: var(--on-green-2); }
.on-green .eyebrow { color: var(--leaf-bright); }
.on-green .leaf { background: var(--leaf-bright); }

.on-orange {
	background: var(--orange);
	color: var(--orange-ink);
}
.on-orange .lede,
.on-orange .sec-foot { color: var(--orange-ink-2); }
.on-orange .eyebrow { color: var(--orange-ink); }
.on-orange .leaf { background: var(--orange-ink); }

.on-tint { background: var(--surface-2); }

/* ==========================================================================
   5. THE LEAF
   BRAND.md's marker. This is why the theme needs no icon font at all: the
   525 KB icofont.woff2 is not replaced with something smaller, it is replaced
   with four lines of CSS.
   ========================================================================== */

.leaf {
	flex: none;
	width: 11px;
	height: 11px;
	background: var(--leaf);
	border-radius: 0 100% 0 100%;
	transform: rotate(-14deg);
}

/* ==========================================================================
   6. BUTTONS
   Every tap target clears 44px. 33 of 58 on the live site do not.
   ========================================================================== */

.btn {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: 10px;
	/* 56px, down from 60. Every target still clears 44px by 12px, and three
	   64px slabs stacked in the hero were most of what made the page read as
	   loud rather than expensive. Restraint is the whole difference. */
	min-height: 56px;
	padding: 0 24px;
	border: 2px solid transparent;
	border-radius: var(--radius-pill);
	background: var(--orange);
	color: var(--orange-ink);
	font-size: 1rem;
	font-weight: 800;
	font-stretch: 100%;
	letter-spacing: .015em;
	text-decoration: none;
	cursor: pointer;
	/* position/isolation are for the sheen below, not for layout. */
	position: relative;
	isolation: isolate;
	transition:
		background-color var(--dur-fast) var(--ease),
		border-color var(--dur-fast) var(--ease),
		color var(--dur-fast) var(--ease),
		transform var(--dur-fast) var(--ease),
		box-shadow var(--dur) var(--ease);
}

.btn:hover { background: var(--orange-hover); }

/* The sheen: a band of light that crosses the button once when the cursor
   arrives, and never again until it leaves and comes back.

   It is a moving BACKGROUND on a pseudo-element pinned to the button, not a
   moving element inside an overflow: hidden button - and that is deliberate.
   overflow: hidden would have clipped the label rather than let it overflow,
   and .call-bar .btn is explicitly allowed to shrink below its own content
   width at 320px, where clipping the word "WhatsApp" is exactly the failure
   that rule exists to avoid. A background is clipped to the border box for
   free, so nothing else has to change. */
.btn::after {
	content: "";
	position: absolute;
	inset: 0;
	z-index: -1;
	border-radius: inherit;
	pointer-events: none;
	background-image: linear-gradient(100deg, transparent 32%, rgba(255, 255, 255, .40) 50%, transparent 68%);
	background-repeat: no-repeat;
	background-size: 220% 100%;
	background-position: 260% 0;
	opacity: 0;
}

/* hover: hover, so a phone never fires it on tap - on a touch screen the
   :hover state sticks after the finger lifts, and a button that lights up and
   stays lit reads as broken. */
@media (hover: hover) {
	.btn:hover {
		transform: translateY(-2px);
		box-shadow: var(--shadow-lift);
	}

	.btn:hover::after { animation: hc-sheen .8s var(--ease-out) 1; }
}

/* Pressed, the button returns to the ground instead of pushing 1px below it.
   Against a 2px hover lift that reads as a real press; the old rule read as a
   twitch. */
.btn:active {
	transform: translateY(0);
	transition-duration: .05s;
}

.btn-sm {
	min-height: 50px;
	padding: 0 18px;
	font-size: .95rem;
}

.btn-lg { min-height: 60px; }

.btn-wa {
	background: var(--wa);
	color: var(--wa-ink);
}
.btn-wa:hover { background: var(--wa-hover); }

/* Online booking, in Practo's blue — the same reasoning as the WhatsApp
   button. A button that leaves for another service wears that service's
   colour, so the patient knows where the tap is taking them before it takes
   them there, and is not surprised by a Practo login screen.

   Shape and type stay ours. Practo's own button is a 4px rectangle in Lato
   700; imported wholesale into a page of pill buttons and Archivo it would
   read as a widget somebody pasted in, which is the look this rebuild exists
   to remove. Colour and wording carry the recognition; geometry stays with the
   design system. See BRAND.md, fourth correction, for the contrast working. */
.btn-book {
	background: var(--practo);
	color: var(--practo-ink);
}
.btn-book:hover { background: var(--practo-hover); }

/* On a deep-green ground the WhatsApp button loses its fill.
 *
 * Three filled, fully saturated buttons - WhatsApp green, orange, Practo blue
 * - sat in one hero at identical weight, and a row of three equal shouts has
 * no hierarchy in it at all. One of them had to step back, and the arithmetic
 * chose which: --wa (#0E7440) against the hero ground (#0A4926) is 1.5:1 of
 * surface contrast, so it was already the button nobody could see. It was
 * costing the page its calm and buying almost no visibility with it.
 *
 * Outlined, its label goes to full white - BETTER text contrast than the
 * filled version had - and the glyph keeps WhatsApp green, brightened to
 * #3DDC7F so it actually reads at 22px on this ground. BRAND.md's point
 * stands: the one colour on the site that is not ours is still there, still
 * scannable, just carried by the mark instead of by 300px of fill. Hovering
 * fills it in their green, which is where a filled state belongs.
 *
 * Filled everywhere else - on white, --wa is 4.6:1 and works exactly as it
 * always did. */
.on-green .btn-wa {
	background: transparent;
	border-color: rgba(255, 255, 255, .32);
	color: #FFFFFF;
}
.on-green .btn-wa .icon { color: #3DDC7F; }
.on-green .btn-wa:hover {
	background: var(--wa);
	border-color: var(--wa);
	color: var(--wa-ink);
}
.on-green .btn-wa:hover .icon { color: var(--wa-ink); }

.btn-ghost {
	background: transparent;
	border-color: var(--line-strong);
	color: var(--ink);
}
.btn-ghost:hover {
	background: var(--surface);
	border-color: var(--ink-3);
}
.on-green .btn-ghost {
	border-color: var(--green-line);
	color: var(--on-green);
}
.on-green .btn-ghost:hover {
	background: var(--green-line);
	border-color: var(--green-line);
}

/* Inside an orange block a plain orange button vanishes. */
.btn-on-orange.btn-call {
	background: var(--orange-ink);
	color: var(--orange);
}
.btn-on-orange.btn-call:hover { background: #000000; }

.actions {
	display: flex;
	flex-wrap: wrap;
	gap: 12px;
	margin-top: 26px;
}

.actions .btn { flex: 1 1 auto; }

@media (min-width: 560px) {
	.actions .btn { flex: 0 0 auto; }
}

.icon { flex: none; }

/* ==========================================================================
   7. HEADER
   ========================================================================== */

.site-head {
	position: sticky;
	top: 0;
	z-index: 40;
	background: var(--surface);
	border-bottom: 2px solid var(--line);
}

.head-row {
	display: flex;
	align-items: center;
	gap: 16px;
	min-height: 80px;
}

.brand {
	display: flex;
	align-items: center;
	gap: 15px;
	text-decoration: none;
	margin-right: auto;
}

/* One number drives the whole lockup: the mark box, and — through the name's
   em-based size below — the wordmark beside it. Change this and the two stay
   in proportion. The footer sets its own (see .foot-brand). */
/* 56 / 64, down from 62 / 76. At 76px in a 94px bar the mark filled 81% of
   the header's height, and a lockup with no air around it reads as cramped
   however good the mark is. The bar keeps its height; the logo gives some
   back. */
:root { --mark: 56px; }

@media (min-width: 900px) {
	:root { --mark: 64px; }
}

.brand-mark, .custom-logo-link { display: block; flex: none; }
.brand .mark, .custom-logo { display: block; width: var(--mark); height: var(--mark); }
.custom-logo { width: auto; max-width: 260px; height: var(--mark); }

/* A badge-shaped upload is treated as a mark — see homeoclinic_logo_mark().
   Square box, contain rather than cover, so a circular logo is never cropped
   into a square by the layout. */
.brand-mark.is-image .custom-logo {
	width: auto;
	max-width: 260px;
	height: var(--mark);
	object-fit: contain;
}

/* On the deep-green footer, a logo file exported on a white background would
   otherwise be a white rectangle sitting on green. Giving it a deliberate
   white plate with the brand's inner radius makes that read as a badge rather
   than a mistake — and it is harmless if the file is transparent. */
.on-green .brand-mark.is-image {
	background: #FFFFFF;
	border-radius: var(--radius-in);
	padding: 5px;
}

.brand-text {
	display: flex;
	flex-direction: column;
	gap: 3px;
}

.brand-name {
	font-weight: 800;
	font-stretch: 106%;
	font-size: 1.35rem;
	line-height: 1.05;
	letter-spacing: -.025em;
	text-transform: uppercase;
	color: var(--ink);
	/* The wordmark folds between words rather than being cut off. It is NOT
	   nowrap at any width: measured with the owner's logo, the name wanted
	   210.6px in 177.6 at exactly 900px and 262.4 in 244 at exactly 1100 -
	   the two band-start widths, where each band's type sizes meet the
	   narrowest row that band ever gets. Wrapping costs a second line in an
	   82-94px bar that has room for it; nowrap costs either an ellipsis
	   through the practice's name or, before the clip below existed, the
	   menu printed on top of it.
	   This does not fold the name when there is room: a flex item is laid out
	   at its max-content width - the whole line - and only wraps when the row
	   cannot give it that. */
	white-space: normal;
	/* body sets overflow-wrap: break-word so an article URL cannot push the
	   page sideways; the wordmark is the exception. It breaks between words,
	   never mid-word: "THE HOMEOPATH / Y" is a fault, not a wrap. */
	overflow-wrap: normal;
	/* The lockup may never paint outside its own box. See the note on
	   .brand-tagline below: an overflowing nowrap flex item is drawn OVER its
	   next sibling and adds nothing to scrollWidth, so the menu ends up
	   printed on top of the brand text while every check for horizontal page
	   overflow still reports a clean header. Clipping turns that silent
	   collision into a visible ellipsis on one line. */
	overflow: hidden;
	text-overflow: ellipsis;
}

/* Quieter than the name deliberately. At weight 700 in full green the
   tagline was the same visual weight as the practice name directly above it,
   so the lockup had two first lines and no second one. */
.brand-tagline {
	font-size: 0.74rem;
	font-weight: 600;
	letter-spacing: 0.09em;
	text-transform: uppercase;
	color: var(--green-text);
	opacity: .88;
	white-space: nowrap;
	/* Inert wherever the line is allowed to wrap (<=899px, and the footer);
	   the guarantee is for the nowrap case. */
	overflow: hidden;
	text-overflow: ellipsis;
}

/* Below the menu breakpoint the tagline WRAPS, and both flex items are told
   they may shrink.
   Found by rendering the header at 390px: nowrap plus a 43-character tagline
   plus the mark plus the menu button came to 455px of unshrinkable content in
   a 390px viewport, so the page scrolled sideways and the menu button was off
   the right-hand edge - unreachable. A flex item will not shrink below its
   content width without min-width: 0, which is why nothing else in the row
   gave way. The tagline is the owner's to type, so it can be any length: it
   has to be able to fold rather than push. */
@media (max-width: 899px) {
	.brand,
	.brand-text { min-width: 0; }

	/* The name is allowed to fold at every width (see .brand-name). It is the
	   site title, the owner can retype it in Site Identity at any length, and
	   nowrap on a flex item whose container has already given up all the room
	   it has is how a header pushes a page sideways. Folding is ugly; a
	   horizontal scrollbar on a phone is broken. */
	.brand-name { font-size: 1.15rem; }

	.brand-tagline {
		white-space: normal;
		font-size: 0.66rem;
		letter-spacing: 0.06em;
		line-height: 1.3;
	}
}

/* 320px - the width of the Customizer's own mobile preview, which is where
   the owner found this, and of the oldest phones still in use.
   The arithmetic at 320: 40px of wrap padding, a 56px mark, 15px beside it,
   16px before the menu button and the button's 50px leave 143px for a
   practice name that measures 155. So the name spilled, the row squeezed the
   text column to about 90px, the tagline broke into FIVE lines, and the page
   scrolled sideways. Everything in the lockup gives up a little - the same
   move the 900-1099px band already makes for the same reason - and the
   tagline survives rather than being hidden, because on a phone it is the
   only place the doctor's name appears above the fold. */
@media (max-width: 379px) {
	:root { --mark: 48px; }

	.brand { gap: 11px; }
	.head-row { gap: 10px; }

	/* The width axis, not just the size. Archivo is variable and the header
	   sets it at 106% everywhere else; measured at 320px the name wanted
	   170.1px in a 161px box, and pulling the axis back to its normal width
	   recovers about 6% of that - more than dropping a whole step of size
	   would, and without making the wordmark look shrunken beside the mark.
	   This is what a width axis is for. */
	.brand-name {
		font-size: 1rem;
		font-stretch: 100%;
	}

	.brand-tagline {
		font-size: 0.60rem;
		letter-spacing: 0.04em;
	}
}

@media (min-width: 900px) {
	/* The menu is five fixed links and must never wrap. Rendered at 1280 the
	   last two dropped onto a second line under the logo: the brand lockup
	   could not shrink (nowrap name, nowrap tagline, and no min-width: 0 above
	   this breakpoint), so the nav was the only flex item left to give - and it
	   gave by wrapping. Pin the nav at its own size; let the brand shrink. */
	.head-row { min-height: 94px; flex-wrap: nowrap; }
	.brand, .brand-text { min-width: 0; }
	.site-nav { flex: none; }
	.nav-list { flex-wrap: nowrap; }

	.brand-name { font-size: 1.62rem; }
	.brand { gap: 18px; }

	/* THE STRAP-LINE DOES NOT FIT BESIDE THE MENU, AT ANY WIDTH.
	   It is not a tuning problem, so do not reintroduce it at some wider
	   breakpoint - that is the bug this rule replaces.

	   The arithmetic, measured on the live site at 1440px. .wrap caps the row
	   at --wrap (1140px) minus 2x20px padding, so the header's content box is
	   1100px at 1440, at 1680 and at 2560 alike: NO media query above 1180px
	   buys the row a single extra pixel. Out of that 1100: the logo is 107.5
	   (the owner's upload is 1.68:1 at a 64px height, and .brand-mark allows
	   up to 260px), 18 beside it, two 16px row gaps, a five-item menu at
	   499.3 and the call button at 156.8. That leaves 286.5 for the brand
	   text. The strap-line - 43 characters of tracked-out uppercase - needs
	   362.2. It was over by 75.7px, and 59.7px of the doctor's name was being
	   printed underneath "Treatments".

	   Three of those five numbers are the owner's to change (the logo file's
	   aspect ratio, the site title, the menu items), so nothing tuned to fit
	   today stays fitting. The line is kept where it has room and does real
	   work: <900px, where the menu is a toggle and this is the only place the
	   doctor's name appears above the fold, and in the footer, where it
	   wraps. */
	.site-head .brand-tagline { display: none; }
}

/* There was a @media (min-width: 1320px) block here. It brought the
   strap-line back at >=1320 and bottom-aligned the menu and the call button
   to it, so that "Treatments" sat level with "MD (Hom.)" rather than above
   it. Both halves are gone: the strap-line never fitted in that band (the
   note in the >=900 block has the measurement), so the alignment it was
   correcting was alignment against a line that was overflowing its own box
   and printing itself under the menu. With one line in the lockup at every
   width >=900, the row's default centre alignment is right again. */

/* Between 900px and 1100px the menu has appeared but the row is not yet wide
   enough for the full-size lockup beside it: rendered at 1000px, the last
   menu item dropped onto a second line under the logo. Everything in the row
   gives up a little until there is room. */
/* max-width is .98, not 1099: a fractional viewport (a zoomed page, a hi-dpi
   laptop) can resolve to 1099.5, where "max-width: 1099px" is already false but
   "min-width: 1100px" is not yet true - a one-pixel dead zone in which the full
   lockup, the tagline and the full call button all come back at once and the
   name is clipped. The .98 closes it. The 1100 band below starts flush. */
@media (min-width: 900px) and (max-width: 1099.98px) {
	:root { --mark: 54px; }

	.brand-name { font-size: 1.3rem; }
	.brand { gap: 12px; }

	.head-row {
		gap: 10px;
		min-height: 82px;
	}

	.nav-list a {
		padding: 0 9px;
		font-size: .88rem;
	}

	/* No room for a full call button here without crushing the wordmark onto
	   two lines - which is the state this whole block exists to prevent.
	   Collapse it to the phone glyph, the same 50px square as the menu button:
	   the number is still one tap, the <span> label stays for screen readers,
	   and the full-width button is back at >=1100. */
	.head-action .btn-call {
		width: 50px;
		height: 50px;
		padding: 0;
		gap: 0;
		justify-content: center;
	}

	.head-action .btn-call span {
		position: absolute !important;
		width: 1px; height: 1px;
		padding: 0; margin: -1px;
		overflow: hidden;
		clip: rect(0 0 0 0);
		clip-path: inset(50%);
		white-space: nowrap;
		border: 0;
	}
}

/* 1100-1319: the menu is at full size but the row is not yet wide enough for
   the whole lockup AND the call button beside it - the band where the menu
   was wrapping under the logo on a typical 1280 laptop. Same move as the
   band above, gentler: the links tighten so the menu holds one line. */
@media (min-width: 1100px) and (max-width: 1319.98px) {
	.nav-list a { padding: 0 10px; font-size: .9rem; }
	.head-row { gap: 12px; }
}

.nav-toggle {
	display: none;
	align-items: center;
	justify-content: center;
	/* flex: none, or the row squeezes it. Once the brand lockup beside it was
	   allowed to shrink, the 50px button shrank too - measured at 41px in a
	   390px header, under the 44px floor this theme exists to enforce. A
	   width on a flex item is a suggestion until you say otherwise. */
	flex: none;
	width: 50px;
	height: 50px;
	padding: 0;
	background: none;
	border: 2px solid var(--line);
	border-radius: var(--radius-in);
	cursor: pointer;
}

.nav-list {
	display: flex;
	flex-wrap: wrap;
	gap: 4px;
}

.nav-list a {
	display: flex;
	align-items: center;
	min-height: 44px;
	padding: 0 13px;
	border-radius: var(--radius-in);
	font-size: .95rem;
	font-weight: 600;
	letter-spacing: -.005em;
	color: var(--ink-2);
	text-decoration: none;
	position: relative;
	transition: color var(--dur-fast) var(--ease), background-color var(--dur-fast) var(--ease);
}
.nav-list a:hover {
	background: var(--surface-2);
	color: var(--ink);
}

/* The underline sweeps out from the left rather than appearing. It is drawn
   in currentColor so it works on the white header and the deep-green one
   without a second rule, and it is permanently out on the current page -
   which is the first time this menu has marked where you are. */
.nav-list a::after {
	content: "";
	position: absolute;
	left: 13px;
	right: 13px;
	bottom: 7px;
	height: 2px;
	border-radius: 2px;
	background: currentColor;
	opacity: .5;
	transform: scaleX(0);
	transform-origin: left center;
	transition: transform var(--dur) var(--ease-out);
}

.nav-list a:hover::after,
.nav-list a:focus-visible::after,
.nav-list .current-menu-item > a::after,
.nav-list .current_page_item > a::after { transform: scaleX(1); }

.head-action { display: none; }

@media (min-width: 900px) {
	.head-action { display: block; flex: none; }
	.head-action .btn-call {
		padding: 9px 20px;
		font-size: 0.92rem;
		font-weight: 700;
		letter-spacing: 0.02em;
		box-shadow: 0 2px 8px rgba(247, 148, 30, 0.25);
		transition: transform 0.2s ease, box-shadow 0.2s ease;
	}
	.head-action .btn-call:hover {
		transform: translateY(-1px);
		box-shadow: 0 4px 14px rgba(247, 148, 30, 0.35);
	}
}

/* Below 900px the menu collapses — but only once the script has run, so a
   failed script leaves the menu visible rather than unreachable. */
@media (max-width: 899px) {
	.has-js-nav .nav-toggle { display: inline-flex; }

	.has-js-nav .site-nav {
		display: none;
		position: absolute;
		left: 0;
		right: 0;
		top: 100%;
		padding: 12px 20px 20px;
		background: var(--surface);
		border-bottom: 2px solid var(--line);
	}

	.has-js-nav .site-nav.is-open { display: block; }

	.has-js-nav .nav-list { flex-direction: column; gap: 2px; }
	.has-js-nav .nav-list a { min-height: 50px; }

	.site-head { position: static; }
	.has-js-nav .site-head { position: sticky; }
	.has-js-nav .head-row { position: relative; }
}

/* ---- The deep-green header ----------------------------------------------
   Appearance -> Customize -> Look and feel -> Deep green header. On by
   default; unticking it restores every rule above untouched.

   Why it is the default: the white bar met the dark-green hero at a 2px rule,
   so the first thing on the page was a seam - two components stacked rather
   than one page starting. Painting the bar in the hero's own top colour
   removes the seam, and on the inner pages it reads as a deliberate dark nav.
   It is also the direction the site was already signed off in: Direction C is
   full-bleed colour blocks, and the header is now one of them.

   Header text does not inherit .on-green - that class belongs to content
   blocks - so every token it needs is set explicitly here.
   ------------------------------------------------------------------------ */

.head-dark .site-head {
	background: linear-gradient(180deg, #0C512C 0%, #08421F 100%);
	border-bottom: 1px solid rgba(255, 255, 255, .10);
}

.head-dark .brand-name { color: #FFFFFF; }

.head-dark .brand-tagline {
	color: var(--leaf);
	opacity: 1;
}

/* The built-in mark is a mid-green badge (#0E8A40) and this ground is
   #0A4926: on its own it dissolves. A drop-shadow follows the SVG's actual
   silhouette rather than its box, so a zero-offset white one rims the badge
   and both leaves - a rim light, not a plate behind a circle, which would
   have clipped the two leaves that grow outside it. */
.head-dark .brand-mark:not(.is-image) .mark {
	filter:
		drop-shadow(0 0 .6px rgba(255, 255, 255, .60))
		drop-shadow(0 4px 12px rgba(0, 0, 0, .38));
}

/* An uploaded logo exported on white would be a white rectangle here. Same
   deliberate plate the footer already gives it. */
.head-dark .brand-mark.is-image {
	background: #FFFFFF;
	border-radius: var(--radius-in);
	padding: 5px;
}

.head-dark .nav-list a { color: rgba(240, 247, 239, .84); }

.head-dark .nav-list a:hover,
.head-dark .nav-list a:focus-visible {
	background: rgba(255, 255, 255, .11);
	color: #FFFFFF;
}

.head-dark .nav-list .current-menu-item > a,
.head-dark .nav-list .current_page_item > a { color: #FFFFFF; }

.head-dark .nav-toggle {
	border-color: rgba(255, 255, 255, .30);
	color: #FFFFFF;
}

@media (max-width: 899px) {
	.head-dark.has-js-nav .site-nav {
		background: #08421F;
		border-bottom-color: rgba(255, 255, 255, .10);
	}
}

/* ==========================================================================
   8. HERO
   ========================================================================== */

/* The hero was one flat fill of --green-deep across the whole width, which
   is what made a large, correctly-built block still read as a template: real
   surfaces have a light source. Three layers, all CSS, no image request:
   a leaf-coloured highlight where the light falls (top left), a green glow
   opposite it, and a gentle vertical shift down the whole panel. The token
   stays the middle of the range, so the block is still --green-deep. */
.hero.on-green {
	position: relative;
	overflow: hidden;
	background:
		radial-gradient(78% 62% at 6% -10%, rgba(124, 191, 63, .17), rgba(124, 191, 63, 0) 60%),
		radial-gradient(62% 72% at 106% 112%, rgba(14, 138, 64, .30), rgba(14, 138, 64, 0) 62%),
		linear-gradient(168deg, #0A4926 0%, var(--green-deep) 54%, #052E18 100%);
}

/* The brand leaf, enormous and almost invisible. Same four lines of CSS as
   the 11px marker in section 5 - one shape used at two sizes, which is what
   a mark is for. It sits behind the credential card on purpose: the card is
   frosted glass, and glass only reads as glass when there is something
   behind it to bend. */
.hero.on-green::before {
	content: "";
	position: absolute;
	top: -140px;
	right: -110px;
	width: 520px;
	height: 520px;
	background: var(--leaf);
	border-radius: 0 100% 0 100%;
	transform: rotate(-14deg);
	opacity: .055;
	pointer-events: none;
}

/* Grain. A gradient with nothing on it is a gradient; the same gradient with
   a film of noise over it is a surface, and that single difference is most of
   what separates a printed piece from a CSS fill. The browser generates it
   from ~300 bytes of inline SVG - no request, nothing to download, so it
   costs the load budget nothing. Soft-light keeps it as light and shade on
   the colour underneath rather than grey speckle laid on top. */
.hero.on-green::after {
	content: "";
	position: absolute;
	inset: 0;
	background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.8' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)'/%3E%3C/svg%3E");
	opacity: .30;
	mix-blend-mode: soft-light;
	pointer-events: none;
}

.hero > .wrap {
	position: relative;
	z-index: 1;
}

.hero-grid {
	display: grid;
	gap: 36px;
}

/* 1000px, not 900. At 900 the card column resolved to 313px, which is
   narrower than the card's own content needs - the fee label broke in the
   middle of the word "consultation". Below this the hero is one column and
   the card sits under the buttons at full width, where it has room. */
@media (min-width: 1000px) {
	.hero-grid {
		grid-template-columns: minmax(0, 1.22fr) minmax(330px, 0.78fr);
		/* Centred, and both alternatives were built and rejected in front of
		   a render at 1440. The headline sets on four lines, so the copy
		   column is 645px tall against a card of about 340: something has to
		   give up the difference.
		   `end` pushed the whole 300px of it into the top right corner, which
		   is the corner a reader arrives at second. Stretching the card to
		   645px and spreading its contents down that height read as an empty
		   panel, not a spacious one - 90px between a qualification and a row
		   of statistics is not composition, it is a gap. Centred, the space
		   splits either side of a card that is clearly its own object. */
		align-items: center;
		gap: 56px;
	}
}

.hero-copy { display: flex; flex-direction: column; gap: 18px; }

.hero-title {
	max-width: 18ch;
	line-height: .93;
	letter-spacing: -.05em;
}

/* Brighter than --on-green-2 and set narrower. The lede is the only sentence
   a visitor actually reads in the hero, and it was the dimmest thing in it. */
.hero .lede {
	max-width: 40ch;
	font-size: 1.15rem;
	color: rgba(240, 247, 239, .80);
}

/* Held below the global h1 ceiling because this heading does not have the
   width to itself - the credential card takes the other 40% of the row. At
   5.4rem it needed five lines and pushed the three buttons under the fold on
   a laptop, which is the one thing in the hero that has to be visible. */
@media (min-width: 900px) {
	.hero-title { font-size: clamp(3.3rem, 5.3vw, 4.5rem); }
}

/* Three buttons will not sit on one row without the phone number being
   clipped, so they wrap 2 + 1. Until 0.9.7 the pair was stretched to fill the
   row and Practo was stretched across the whole of the second one, which
   turned an accidental wrap into three equal-weight slabs - most of what made
   the hero read as a control panel.

   Now each takes its natural width and the row is capped so the wrap still
   falls after Call. What lands is a hierarchy: an outlined WhatsApp and a
   filled orange Call on the first line, Practo's blue on the second at its
   own width. Order is unchanged - WhatsApp, Call, Book. */
@media (min-width: 1000px) {
	.hero .actions {
		max-width: 560px;
		gap: 14px;
	}
	.hero .actions .btn { flex: 0 0 auto; }
}

.hero-jump {
	margin-top: 4px;
	font-weight: 600;
}
.hero-jump a {
	display: inline-flex;
	align-items: center;
	gap: 8px;
	min-height: 44px;
	color: var(--leaf-bright);
	text-underline-offset: 4px;
}

/* The credential card. 0.9.5 added it to fill the empty right half of the
   desktop hero; 0.9.6 finished it - see the notes on each rule. */
.hero-aside {
	display: flex;
	justify-content: center;
	width: 100%;
}

/* Pushed to the right edge of the wrap on desktop rather than floated in the
   middle of its column, so the composition has two edges instead of one edge
   and a drift. */
@media (min-width: 1000px) {
	.hero-aside { justify-content: flex-end; }
}

.hero-doctor-card {
	width: 100%;
	max-width: 440px;
	/* A flat 7% white wash had no light direction in it. A gradient across the
	   panel gives the glass a lit edge and a shaded one, which is the whole
	   reason to reach for glass rather than a lighter rectangle. */
	background: linear-gradient(158deg, rgba(255, 255, 255, .11) 0%, rgba(255, 255, 255, .045) 100%);
	backdrop-filter: blur(16px) saturate(120%);
	-webkit-backdrop-filter: blur(16px) saturate(120%);
	border: 1px solid rgba(255, 255, 255, 0.20);
	border-radius: var(--radius);
	padding: 28px 26px 26px;
	display: flex;
	flex-direction: column;
	/* space-between, with gap as the floor. Where the card is shorter than
	   the row - phones, and any desktop where the headline sets on fewer
	   lines - gap governs and the card is its natural height. Where the row
	   is taller, the three groups spread down it. */
	justify-content: space-between;
	gap: 26px;
	/* The inset hairline along the top edge is what makes a translucent panel
	   read as lit glass rather than as a lighter rectangle. */
	box-shadow:
		0 26px 60px -28px rgba(0, 0, 0, .65),
		0 0 90px -40px rgba(124, 191, 63, .45),
		inset 0 1px 0 rgba(255, 255, 255, .18);
}

.hero-doc-badge {
	display: flex;
	align-items: center;
	gap: 18px;
}

/* The photograph, once one is uploaded - and until then, the initials. What
   was here in 0.9.5 was an empty leaf-bright tile: the template asked
   homeoclinic_icon() for an icon called 'leaf', which does not exist, so it
   rendered nothing inside a coloured square. Both states are the same box, so
   uploading a photograph moves nothing else on the page.

   0.10.2 grew it from 68 to 96px (112 on desktop): at 68 the owner read the
   face as an avatar decoration rather than as *the* doctor, which is the one
   thing this card exists to show. */
.hero-doc-photo,
.hero-doc-mono {
	flex: none;
	width: 96px;
	height: 96px;
	border-radius: 50%;
}

@media (min-width: 1000px) {
	.hero-doc-photo,
	.hero-doc-mono {
		width: 112px;
		height: 112px;
	}
}

.hero-doc-photo {
	object-fit: cover;
	box-shadow: 0 0 0 3px rgba(143, 212, 74, .6), 0 8px 22px rgba(0, 0, 0, .34);
}

.hero-doc-mono {
	display: flex;
	align-items: center;
	justify-content: center;
	background: linear-gradient(150deg, var(--leaf-bright), var(--green));
	color: var(--green-deep);
	font-size: 1.32rem;
	font-weight: 800;
	font-stretch: 106%;
	letter-spacing: -.02em;
}

.hero-doc-titles {
	display: flex;
	flex-direction: column;
	gap: 3px;
}

.hero-doc-subtitle {
	font-size: 0.7rem;
	font-weight: 700;
	letter-spacing: 0.06em;
	text-transform: uppercase;
	color: var(--leaf-bright);
}

.hero-doc-name {
	font-size: 1.34rem;
	font-weight: 800;
	font-stretch: 104%;
	letter-spacing: -.02em;
	color: #FFFFFF;
	margin: 0;
	line-height: 1.16;
}

.hero-doc-qual {
	font-size: 0.92rem;
	font-weight: 600;
	color: var(--on-green-2);
	margin: 0;
}

/* Added 0.10.2: where he trained and the practice's certification, both
   already Customizer values and both a stronger signal than the pills below.
   Ticked, ruled off top and bottom, sitting between the face and the numbers
   so the card reads face -> credentials -> figures. The owner's note on 0.10.1
   was that the card "doesn't look convincing enough"; this is the substance
   that answers it. */
.hero-doc-creds {
	list-style: none;
	margin: 0;
	padding: 14px 2px;
	display: flex;
	flex-direction: column;
	gap: 9px;
	border-top: 1px solid rgba(255, 255, 255, .1);
	border-bottom: 1px solid rgba(255, 255, 255, .1);
}

.hero-doc-creds li {
	display: flex;
	align-items: flex-start;
	gap: 9px;
	font-size: 0.86rem;
	font-weight: 600;
	line-height: 1.3;
	color: rgba(240, 247, 239, .9);
}

.hero-doc-creds .icon {
	flex: none;
	margin-top: 1px;
	color: var(--leaf-bright);
}

.hero-doc-stats {
	display: grid;
	grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
	gap: 0;
	padding: 18px 4px;
	background: rgba(0, 0, 0, 0.26);
	border-radius: var(--radius-in);
	border: 1px solid rgba(255, 255, 255, 0.07);
	text-align: center;
}

.hero-stat-box {
	display: flex;
	flex-direction: column;
	gap: 3px;
	padding: 0 6px;
}

/* Hairlines rather than gaps. Three numbers separated by whitespace read as
   three unrelated facts; ruled apart they read as one row of credentials. */
.hero-stat-box + .hero-stat-box {
	border-left: 1px solid rgba(255, 255, 255, .10);
}

.stat-num {
	font-size: 1.42rem;
	font-weight: 800;
	font-stretch: 108%;
	letter-spacing: -.035em;
	color: #FFFFFF;
	line-height: 1.05;
}

.stat-txt {
	font-size: 0.67rem;
	font-weight: 600;
	text-transform: uppercase;
	letter-spacing: 0.07em;
	line-height: 1.25;
	color: var(--on-green-2);
	/* body sets break-word for long URLs in articles. A three-word label in a
	   90px column is not a long URL, and "CONSULTATI / ON FEE" is what
	   break-word does to it. */
	overflow-wrap: normal;
}

.hero-doc-footer {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
}

/* Outlined, not filled. Two filled pills under a filled stats plate gave the
   card three competing surfaces; the outline puts them where they belong, at
   the quiet end of the card. */
.hero-doc-pill {
	display: inline-block;
	font-size: 0.72rem;
	font-weight: 600;
	letter-spacing: .01em;
	padding: 6px 12px;
	border-radius: var(--radius-pill);
	border: 1px solid rgba(255, 255, 255, 0.18);
	color: var(--on-green-2);
}

.hero-doc-rating {
	display: flex;
	align-items: center;
	justify-content: space-between;
	padding-top: 12px;
	border-top: 1px solid rgba(255, 255, 255, 0.12);
}

.rating-val {
	font-size: 1.15rem;
	font-weight: 800;
	color: #F7941E;
}

.rating-note {
	font-size: 0.8rem;
	color: var(--on-green-2);
}

.hero-rating {
	display: flex;
	flex-direction: column;
	gap: 6px;
	padding: 26px 30px;
	border: 2px solid var(--green-line);
	border-radius: var(--radius);
	text-align: center;
}

.rating-value {
	font-size: clamp(4.4rem, 15vw, 7rem);
	font-weight: 900;
	font-stretch: 112%;
	letter-spacing: -.06em;
	line-height: 1;
}

.rating-stars, .reviews-stars {
	display: flex;
	justify-content: center;
	gap: 3px;
	color: var(--orange);
}

.rating-meta { font-size: .88rem; color: var(--on-green-2); }

/* ==========================================================================
   9. STATS
   ========================================================================== */

.stats-grid {
	display: grid;
	gap: 28px;
}

@media (min-width: 700px) {
	.stats-grid { grid-template-columns: repeat(3, 1fr); gap: 32px; }
}

.stat { display: flex; flex-direction: column; gap: 6px; }

.stat-value {
	font-size: clamp(2.6rem, 8vw, 3.6rem);
	font-weight: 900;
	font-stretch: 112%;
	letter-spacing: -.045em;
	line-height: 1;
}

.stat-label {
	font-size: .96rem;
	font-weight: 600;
	color: var(--orange-ink-2);
	text-transform: none;
	letter-spacing: 0;
	line-height: 1.35;
}

/* ==========================================================================
   10. CARDS
   ========================================================================== */

.card-grid {
	display: grid;
	gap: 16px;
}

@media (min-width: 640px) { .card-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px) { .card-grid { grid-template-columns: repeat(4, 1fr); } }

.card {
	display: flex;
	flex-direction: column;
	gap: 10px;
	padding: 22px;
	background: var(--surface);
	border: 2px solid var(--line);
	border-radius: var(--radius);
	transition:
		transform var(--dur) var(--ease),
		box-shadow var(--dur) var(--ease),
		border-color var(--dur) var(--ease);
}

.card-link {
	display: flex;
	flex-direction: column;
	gap: 10px;
	height: 100%;
	text-decoration: none;
}

.card p {
	color: var(--ink-2);
	font-size: .95rem;
	line-height: 1.5;
}

.card-more {
	display: inline-flex;
	align-items: center;
	gap: 7px;
	margin-top: auto;
	padding-top: 8px;
	color: var(--orange-text);
	font-weight: 700;
	font-size: .92rem;
}

.card-more .icon { transition: transform var(--dur) var(--ease-out); }

/* Only cards that are a link lift. A clinic card holds two buttons of its
   own, and moving a tap target 4px while a finger or cursor is travelling
   towards it is how a mis-tap happens - so those get the border and the
   shadow and stay exactly where they are. */
.card:has(.card-link):hover {
	border-color: var(--line-strong);
	box-shadow: var(--shadow-lift);
}

@media (hover: hover) {
	.card:has(.card-link):hover { transform: translateY(-4px); }
	.card:has(.card-link):hover .card-more .icon { transform: translateX(5px); }
}

.card.clinic:hover {
	border-color: var(--line-strong);
	box-shadow: var(--shadow);
}

.treatment h3::before {
	content: "";
	display: block;
	width: 11px;
	height: 11px;
	margin-bottom: 12px;
	background: var(--leaf);
	border-radius: 0 100% 0 100%;
	transform: rotate(-14deg);
	transition: transform var(--dur-slow) var(--ease-out), background-color var(--dur) var(--ease);
}

/* The leaf is the brand mark. On hover it opens - the same shape, larger and
   brighter - so the card acknowledges the cursor with the site's own
   vocabulary rather than with a generic glow. */
.treatment:hover h3::before {
	transform: rotate(-2deg) scale(1.45);
	background: var(--leaf-bright);
}

/* ==========================================================================
   11. STEPS
   ========================================================================== */

.step-grid { display: grid; gap: 30px; }

@media (min-width: 800px) {
	.step-grid { grid-template-columns: repeat(3, 1fr); gap: 40px; }
}

.step {
	display: flex;
	flex-direction: column;
	gap: 10px;
	padding-top: 22px;
	border-top: 2px solid var(--green-line);
}

.step-num {
	font-size: 3.4rem;
	font-weight: 900;
	font-stretch: 112%;
	letter-spacing: -.05em;
	line-height: 1;
	color: var(--leaf-bright);
}

.step p:not(.step-num) { color: var(--on-green-2); font-size: .96rem; }

/* ==========================================================================
   12. DOCTOR
   ========================================================================== */

.doctor-grid { display: grid; gap: 32px; }
.doctor-copy { display: flex; flex-direction: column; gap: 16px; max-width: 58ch; }

/* Only when a photograph has actually been uploaded - see doctor.php. The
   block is a single column until then, exactly as it was, rather than a
   two-column layout with an empty half. */
@media (min-width: 860px) {
	.doctor-grid.has-portrait {
		grid-template-columns: minmax(0, 300px) minmax(0, 1fr);
		align-items: start;
		gap: 44px;
	}
}

.doctor-figure { margin: 0; }

.doctor-portrait {
	width: 100%;
	border-radius: var(--radius);
	aspect-ratio: 4 / 5;
	object-fit: cover;
	box-shadow: var(--shadow);
}

.doctor-creds {
	font-weight: 700;
	color: var(--green-text);
}

.doctor p { color: var(--ink-2); }

/* ==========================================================================
   13. CLINICS AND HOURS
   ========================================================================== */

.clinics { gap: 16px; }

@media (min-width: 640px) { .clinics { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px) { .clinics { grid-template-columns: repeat(3, 1fr); } }

.clinic { gap: 14px; }

.clinic-head { display: flex; flex-direction: column; gap: 4px; }

.clinic-name {
	font-size: 1.5rem;
	font-weight: 800;
	font-stretch: 106%;
	letter-spacing: -.03em;
	line-height: 1.05;
}

.addr {
	font-style: normal;
	font-size: .95rem;
	line-height: 1.5;
	color: var(--ink-2);
}

/* Who may be seen at a clinic. Rendered only where a restriction exists, so
   most cards never show it.

   Deliberately quiet: a 2px rule and a tint, not a warning box. It has to be
   noticed by the one patient it applies to without shouting at the many it
   does not — a red-alert panel on a doctor's page reads as something being
   wrong with the clinic. The small orange label does the noticing; the body
   text stays the same weight as everything around it. Orange because it is
   the attention colour in BRAND.md, green being the identity colour. */
.clinic-access {
	padding: 11px 14px;
	border-left: 2px solid var(--orange);
	border-radius: 0 var(--radius-in) var(--radius-in) 0;
	background: var(--surface-2);
	color: var(--ink-2);
	font-size: .9rem;
	line-height: 1.5;
}

/* The label is --ink, not --orange-text. Measured: #A85A05 on the --surface-2
   tint is 4.21:1, and this is small text, so it misses the 4.5:1 floor
   BRAND.md sets. The orange stays as the 2px rule beside it, which is
   decoration and carries no text. Recorded in BRAND.md, third correction. */
.clinic-access-label {
	display: block;
	margin-bottom: 3px;
	font-size: .7rem;
	font-weight: 800;
	letter-spacing: .12em;
	text-transform: uppercase;
	color: var(--ink);
}

.clinic-hours {
	padding: 16px;
	background: var(--green-soft);
	border-radius: var(--radius-in);
}

.clinic-hours-title {
	display: flex;
	align-items: center;
	gap: 8px;
	margin-bottom: 10px;
	font-size: .78rem;
	font-weight: 800;
	letter-spacing: .12em;
	text-transform: uppercase;
	color: var(--green-text);
}

.hours { width: 100%; table-layout: fixed; }

.hours th, .hours td {
	padding: 5px 0;
	text-align: left;
	font-size: .93rem;
	vertical-align: top;
}

.hours th {
	width: 8.5em;
	font-weight: 700;
	color: var(--ink);
}

/* In a narrow clinic card the 8.5em day column left roughly 60px for the
   times, so "12:30 PM – 2:00 PM, 7:00 PM – 8:00 PM" came out one word per
   line. Stack instead. */
@media (max-width: 559px) {
	.hours th, .hours td { display: block; width: auto; }
	.hours th { padding-bottom: 0; }
	.hours td { padding-top: 1px; padding-bottom: 9px; }
}

.hours td { color: var(--ink-2); font-variant-numeric: tabular-nums; }

.hours .is-closed td { color: var(--ink-3); }

.hours .is-today th,
.hours .is-today td {
	color: var(--green-text);
	font-weight: 800;
}

.clinic-actions {
	display: flex;
	flex-wrap: wrap;
	gap: 8px;
	margin-top: auto;
	padding-top: 6px;
}

.clinic-actions .btn { flex: 1 1 auto; }

/* ---- The weekly schedule ---- */

.week { margin-top: 40px; }

.week-table {
	width: 100%;
	background: var(--surface);
	border: 2px solid var(--line);
	border-radius: var(--radius);
	overflow: hidden;
}

.week-table caption {
	padding: 20px 22px 6px;
	text-align: left;
	font-size: .78rem;
	font-weight: 800;
	letter-spacing: .18em;
	text-transform: uppercase;
	color: var(--green-text);
}

.week-table tr { border-top: 1px solid var(--line); }
.week-table tbody tr:first-child { border-top: 0; }

.week-table th, .week-table td {
	padding: 14px 22px;
	text-align: left;
	vertical-align: top;
}

.week-table th {
	width: 6.5em;
	font-weight: 800;
	text-transform: uppercase;
	letter-spacing: .04em;
}

.week-today {
	display: inline-block;
	margin-top: 4px;
	padding: 2px 8px;
	border-radius: var(--radius-pill);
	background: var(--orange);
	color: var(--orange-ink);
	font-size: .68rem;
	font-weight: 800;
	letter-spacing: .1em;
}

.week-slots { display: flex; flex-direction: column; gap: 7px; }

.week-slots li {
	display: flex;
	flex-wrap: wrap;
	gap: 4px 14px;
}

.week-time {
	font-weight: 700;
	font-variant-numeric: tabular-nums;
}

/* The min-width only exists to line the clinic names up in a column. On a
   phone it was forcing the table 341px wide inside a 282px page, which made
   the WHOLE PAGE scroll sideways. Alignment is worth nothing at that price. */
@media (min-width: 640px) {
	.week-time { min-width: 11.5em; }
}

.week-where { color: var(--ink-2); }

.week-closed { color: var(--ink-3); }

/* markToday() adds this class from the browser, after paint - the server
   cannot, because a cached page rendered on Monday would still claim Monday
   on Thursday. Without a transition the row therefore snaps green a beat
   after the page has settled, which reads as a glitch. With one, it reads as
   the page finding today. */
.week-table tr { transition: background-color .55s var(--ease-out); }
.week-table .is-today { background: var(--green-soft); }
.week-table .is-today .week-where { color: var(--ink); }

.week-note { margin-top: 14px; }

/* A restriction on who may attend a clinic, printed under the timetable that
   names it. Slightly louder than the generic "timings can change" note above
   it, because acting on it wrongly costs a patient a wasted journey. */
.week-access { color: var(--ink-2); }
.week-access strong { font-weight: 800; color: var(--ink); }

/* Below 560px a day label, a time range and a clinic name cannot share a row.
   Stack them — day above, times beneath — rather than let the table decide it
   needs more width than the screen has. thead is already screen-reader-only,
   so the row keeps its meaning when it stops looking like a table. */
@media (max-width: 559px) {
	.week-table caption { padding: 18px 16px 6px; }
	.week-table tbody tr { display: block; padding: 12px 16px; }
	.week-table tbody th,
	.week-table tbody td { display: block; width: auto; padding: 0; }
	.week-table tbody th { margin-bottom: 6px; }
	.week-slots li { gap: 2px 10px; }
}

/* ==========================================================================
   14. REVIEWS
   ========================================================================== */

/* 0.11.0 rebuild. Was one giant number, 5 hand-drawn stars and "from N reviews
   on Google" - which read as a single unverifiable boast and confused the
   owner ("what do you mean by Google reviews"). Now: a restrained average, an
   honest cross-platform sentence, and a row of chips that each link out to the
   platform they name. */
.reviews-inner {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 18px;
	text-align: center;
}

.reviews-title { max-width: 24ch; }

/* The average, its stars and its caption on one baseline-aligned row rather
   than stacked - stacked, the number dominated the section the way it used to
   dominate the page. */
.reviews-rating {
	display: flex;
	align-items: baseline;
	justify-content: center;
	flex-wrap: wrap;
	gap: 4px 12px;
}

.reviews-value {
	font-size: 2.6rem;
	font-weight: 900;
	font-stretch: 112%;
	letter-spacing: -.045em;
	line-height: 1;
}

/* Nudged onto the number's baseline. */
.reviews-rating .reviews-stars { align-self: center; }

.reviews-avg {
	font-size: .9rem;
	font-weight: 600;
	color: var(--ink-3);
	text-transform: uppercase;
	letter-spacing: .06em;
}

.reviews-headline {
	max-width: 44ch;
	font-size: 1.22rem;
	font-weight: 600;
	line-height: 1.45;
	color: var(--ink-2);
	text-wrap: balance;
}

/* A grid, not a wrapping flex row. Four chips of unequal width wrapped
   three-and-one and stranded the fourth, centred on its own line. The grid
   makes every chip in a row the same width and height, and the column count
   follows the number of platforms (data-count on the <ul>, set in the
   template) so 2, 3 or 4 each land as one even row instead of an orphan. */
.reviews-sources {
	list-style: none;
	margin: 4px 0 0;
	padding: 0;
	display: grid;
	grid-template-columns: repeat(2, minmax(0, 1fr));
	justify-content: center;
	align-items: stretch;
	gap: 12px;
	width: 100%;
	max-width: 620px;
}

/* The <li> is a bare grid cell; let its single child fill it so the chip -
   not just the text inside it - is the full width and height of the cell. */
.reviews-sources .rs { display: grid; }
.reviews-sources .rs-body { height: 100%; }

@media (min-width: 1000px) {
	.reviews-sources { grid-template-columns: repeat(4, minmax(0, 1fr)); max-width: 980px; }
	.reviews-sources[data-count="1"] { grid-template-columns: minmax(0, 320px); }
	.reviews-sources[data-count="2"] { grid-template-columns: repeat(2, minmax(0, 1fr)); max-width: 560px; }
	.reviews-sources[data-count="3"] { grid-template-columns: repeat(3, minmax(0, 1fr)); max-width: 760px; }
	.reviews-sources[data-count="5"] { grid-template-columns: repeat(3, minmax(0, 1fr)); max-width: 820px; }
}

/* On a phone, one column - the chips carry too much text to sit two-up. */
@media (max-width: 560px) {
	.reviews-sources,
	.reviews-sources[data-count] { grid-template-columns: 1fr; }
	.reviews-sources .rs-body { align-items: center; text-align: center; }
}

.reviews-sources .rs-body {
	display: flex;
	flex-direction: column;
	gap: 3px;
	min-height: 44px;
	justify-content: center;
	padding: 12px 18px;
	border: 2px solid var(--line);
	border-radius: var(--radius-in);
	background: var(--surface);
	text-decoration: none;
	transition:
		transform var(--dur) var(--ease),
		border-color var(--dur) var(--ease),
		box-shadow var(--dur) var(--ease);
}

a.rs-body:hover {
	border-color: var(--orange);
	transform: translateY(-2px);
	box-shadow: 0 10px 24px -14px rgba(0, 0, 0, .4);
}

a.rs-body:focus-visible {
	outline: 3px solid var(--orange);
	outline-offset: 2px;
}

.rs-name {
	font-size: .96rem;
	font-weight: 700;
	color: var(--ink);
}

.rs-figure {
	font-size: .82rem;
	font-weight: 600;
	color: var(--ink-2);
}

/* ==========================================================================
   15. VIDEOS
   ========================================================================== */

.video-grid { display: grid; gap: 16px; }

@media (min-width: 700px) { .video-grid { grid-template-columns: repeat(3, 1fr); } }

.video-facade {
	position: relative;
	display: block;
	width: 100%;
	padding: 0;
	background: var(--green-line);
	border: 0;
	border-radius: var(--radius-vid);
	overflow: hidden;
	cursor: pointer;
	aspect-ratio: 16 / 9;
}

.video-facade img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	transition: transform var(--dur-slow) var(--ease-out);
}

.video-play .icon { transition: transform var(--dur) var(--ease-out); }

@media (hover: hover) {
	.video-facade:hover img { transform: scale(1.05); }
	.video-facade:hover .video-play .icon { transform: scale(1.12); }
}

.video-play {
	position: absolute;
	inset: 0;
	display: flex;
	align-items: center;
	justify-content: center;
}

.video-play .icon {
	width: 64px;
	height: 64px;
	padding: 17px;
	background: var(--orange);
	color: var(--orange-ink);
	border-radius: 50%;
}

.video-frame {
	width: 100%;
	aspect-ratio: 16 / 9;
	border: 0;
	border-radius: var(--radius-vid);
}

/* ==========================================================================
   16. BOOKING
   ========================================================================== */

.booking-inner {
	display: flex;
	flex-direction: column;
	gap: 14px;
	max-width: 46rem;
}

/* Only the paragraph wants a reading measure. Capping the whole block at 40ch
   squeezed the h2 into a 378px box at 56px type, which broke "APPOINTMENT"
   across two lines mid-word on a 1280px desktop. */
.booking-inner > .lede { max-width: 40ch; }

/* .booking-email was here. Removed 2026-09-03 with the markup it styled - no
   patient has ever booked by email, so the address does not belong in the
   band where a patient decides to act. It is still in the footer. */

/* ==========================================================================
   17. PAGES, POSTS, PROSE
   ========================================================================== */

.page-head { padding-block: calc(var(--pad-block) * .7); }
.page-head .lede { margin-top: 14px; }
.page-head .post-meta { margin-bottom: 14px; }

.prose { max-width: 68ch; }

.prose > * + * { margin-top: 1.1em; }

.prose h2, .prose h3 {
	margin-top: 1.7em;
	line-height: 1.15;
}

.prose h2 { font-size: clamp(1.6rem, 4vw, 2.1rem); }

.prose p, .prose li { color: var(--ink-2); }

.prose ul, .prose ol {
	padding-left: 1.3em;
	list-style: revert;
}

.prose li + li { margin-top: .4em; }

.prose a {
	color: var(--green-text);
	text-underline-offset: 3px;
}

.prose img { border-radius: var(--radius-in); }

.prose blockquote {
	padding-left: 18px;
	border-left: 4px solid var(--leaf);
	font-size: 1.08rem;
}

.posts-grid { gap: 16px; }
@media (min-width: 640px) { .posts-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px) { .posts-grid { grid-template-columns: repeat(3, 1fr); } }

.post-card-media {
	margin: -22px -22px 4px;
	border-radius: var(--radius) var(--radius) 0 0;
	overflow: hidden;
}
.post-card-media img { width: 100%; aspect-ratio: 3 / 2; object-fit: cover; }

.post-image { border-radius: var(--radius); }

.post-nav-grid { display: grid; gap: 12px; }
@media (min-width: 700px) { .post-nav-grid { grid-template-columns: repeat(2, 1fr); } }

.post-nav-link {
	display: flex;
	flex-direction: column;
	gap: 5px;
	padding: 18px 20px;
	background: var(--surface);
	border: 2px solid var(--line);
	border-radius: var(--radius);
	text-decoration: none;
}
.post-nav-link span { font-size: .8rem; font-weight: 800; letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3); }
.post-nav-link strong { font-weight: 700; line-height: 1.3; }

.pagination { margin-top: 40px; }
.nav-links { display: flex; flex-wrap: wrap; gap: 8px; }
.nav-links .page-numbers {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	min-width: 50px;
	min-height: 50px;
	padding: 0 14px;
	background: var(--surface);
	border: 2px solid var(--line);
	border-radius: var(--radius-in);
	font-weight: 700;
	text-decoration: none;
}
.nav-links .page-numbers.current {
	background: var(--orange);
	border-color: var(--orange);
	color: var(--orange-ink);
}

/* The theme deliberately does not restyle page-builder content: an existing
   Elementor page must render on activation day exactly as it does now. */
.is-legacy-content .page-body .wrap { max-width: 100%; padding-inline: 0; }
.is-legacy-content .prose { max-width: none; }

/* ==========================================================================
   18. SEARCH FORM
   ========================================================================== */

.search-form {
	display: flex;
	gap: 8px;
	margin-top: 20px;
	max-width: 30rem;
}

.search-field {
	flex: 1 1 auto;
	min-height: 50px;
	padding: 0 16px;
	background: var(--surface);
	color: var(--ink);
	border: 2px solid var(--line-strong);
	border-radius: var(--radius-in);
	font: inherit;
	font-size: 1rem;
}

.search-submit { flex: none; }

/* ==========================================================================
   19. FOOTER AND CALL BAR
   ========================================================================== */

.site-foot { padding-block: 56px 0; }

.foot-grid {
	display: grid;
	gap: 32px;
}

@media (min-width: 800px) {
	/* minmax(0, ...), not a bare fr. A grid item's automatic minimum is its
	   max-content width, and the brand column holds the nowrap strap-line:
	   measured at 1440 the first column was 362.2px - the exact width of that
	   one line - instead of the 311.8px the 1.4fr asked for, so the lockup
	   was silently sizing the footer and stealing 50px from the other three
	   columns. The same automatic-minimum trap as min-width: 0 in flex. */
	.foot-grid { grid-template-columns: minmax(0, 1.4fr) repeat(3, minmax(0, 1fr)); gap: 40px; }
}

.foot-brand { display: flex; flex-direction: column; gap: 14px; }
.foot-brand .brand-mark .mark { width: 48px; height: 48px; }
.foot-brand .brand-mark.is-image .custom-logo { width: 48px; height: 48px; }
.foot-brand .brand-mark.is-image { align-self: flex-start; }
.foot-brand .brand-name { font-size: 1.1rem; }

/* The footer column is narrower than the strap-line, and it has vertical room
   the header bar has not: here the line folds instead of being clipped or
   forcing the column wider than its own grid track. */
.foot-brand .brand-tagline { white-space: normal; }

.foot-doctor { font-weight: 700; line-height: 1.4; }

/* Clinic certification. Built from the theme's own vocabulary — the micro-type
   used for column headings, the leaf marker, the pill radius — so it reads as
   part of the design rather than a badge pasted on. It sits below the doctor's
   name, not inside it: ISO 9001 certifies a quality-management system, MD
   (Hom.) is a medical degree, and running them together weakens the degree. */
.cert-badge {
	display: inline-flex;
	align-items: center;
	gap: 9px;
	margin-top: 16px;
	padding: 8px 16px;
	border: 1px solid var(--green-line);
	border-radius: var(--radius-pill);
	color: var(--leaf-bright);
	font-size: .72rem;
	font-weight: 800;
	letter-spacing: .16em;
	line-height: 1.3;
	text-transform: uppercase;
}

.cert-leaf {
	flex: none;
	width: 10px;
	height: 10px;
	background: var(--leaf-bright);
	border-radius: 0 100% 0 100%;
	transform: rotate(-14deg);
}
.foot-doctor span { font-weight: 400; color: var(--on-green-2); }

.foot-title {
	font-size: .74rem;
	font-weight: 800;
	letter-spacing: .18em;
	text-transform: uppercase;
	color: var(--leaf-bright);
	margin-bottom: 12px;
}

.foot-list { display: flex; flex-direction: column; gap: 2px; }

.foot-list a, .foot-list span {
	display: flex;
	align-items: center;
	gap: 9px;
	min-height: 44px;
	color: var(--on-green);
	text-decoration: none;
	font-size: .95rem;
}
.foot-list a:hover { color: var(--leaf-bright); text-decoration: underline; text-underline-offset: 3px; }

/* Social row in the footer brand column. Appearance -> Customize -> Clinic
   details -> Social media. Each is a 44px square - the BRAND.md tap-target
   floor - so it is a real target on a phone, not a 20px glyph. Hidden
   entirely by homeoclinic_social_nav() when no link is set. */
.foot-social {
	display: flex;
	flex-wrap: wrap;
	gap: 10px;
	margin-top: 20px;
	list-style: none;
}

.foot-social a {
	display: flex;
	align-items: center;
	justify-content: center;
	width: 44px;
	height: 44px;
	border: 1px solid var(--green-line);
	border-radius: var(--radius-in);
	color: var(--on-green);
	transition: color var(--dur-fast) var(--ease),
		background-color var(--dur-fast) var(--ease),
		border-color var(--dur-fast) var(--ease);
}

.foot-social a:hover,
.foot-social a:focus-visible {
	color: var(--green-deep);
	background: var(--leaf-bright);
	border-color: var(--leaf-bright);
}

/* Footer widgets.
   Widget titles inherited the 56px display heading — "ARCHIVES" and
   "CATEGORIES" rendered larger than anything else on the page. They are column
   headings, so they take the column-heading style.

   Two selectors, deliberately. Since WordPress 5.8 the widget screen is
   block-based, and block widgets emit <h2 class="wp-block-heading"> and ignore
   the before_title/after_title passed to register_sidebar entirely. So
   .widget-title alone matched nothing on a default install. The element
   selector catches block widgets; .widget-title catches classic ones, which is
   what the owner's site will have if the Classic Widgets plugin is active or
   the old widgets carried over from mexi. */
.foot-widgets h2,
.foot-widgets h3,
.widget-title {
	font-family: var(--sans);
	font-size: .74rem;
	font-weight: 800;
	line-height: 1.4;
	letter-spacing: .18em;
	text-transform: uppercase;
	color: var(--leaf-bright);
	margin-bottom: 12px;
}

.foot-widgets .widget + .widget { margin-top: 28px; }

.foot-widgets ul { display: flex; flex-direction: column; gap: 2px; }

.foot-widgets li a {
	display: flex;
	align-items: center;
	gap: 9px;
	min-height: 44px;
	color: var(--on-green);
	text-decoration: none;
	font-size: .95rem;
}

.foot-widgets li a:hover { color: var(--leaf-bright); text-decoration: underline; text-underline-offset: 3px; }

.foot-base {
	display: flex;
	flex-direction: column;
	gap: 12px;
	margin-top: 44px;
	padding-block: 22px 26px;
	border-top: 1px solid var(--green-line);
}

.foot-note, .foot-copy { color: var(--on-green-2); font-size: .85rem; max-width: 70ch; }

/* The fixed call bar. The audit found 0 WhatsApp links on the homepage; this
   puts one on every screen of every page, one tap from the thumb. */
.call-bar {
	position: fixed;
	left: 0; right: 0; bottom: 0;
	z-index: 50;
	display: flex;
	gap: 8px;
	padding: 10px 12px calc(10px + env(safe-area-inset-bottom));
	background: var(--surface);
	border-top: 2px solid var(--line);
}

/* min-width: 0 is load-bearing. A flex item defaults to min-width: auto, which
   means it cannot shrink below its own min-content width — so "WhatsApp" plus
   26px of padding either side pinned that button at 184px and "Call now" at
   132px. 132 + 184 + 8 gap + 24 bar padding = 348px, on a 320px screen. The bar
   is position: fixed, so the overflow never reached document.scrollWidth and a
   page-level overflow check reported all clear while the label was visibly
   clipped. */
.call-bar .btn {
	flex: 1 1 0;
	min-width: 0;
	min-height: 54px;
	font-size: 1rem;
}

/* Below 400px, trim the padding so the labels still fit inside the shrunk
   buttons rather than being cut off. */
@media (max-width: 400px) {
	.call-bar { gap: 6px; padding-left: 10px; padding-right: 10px; }
	.call-bar .btn { padding-left: 12px; padding-right: 12px; gap: 7px; font-size: .95rem; }
}

/* Room for the bar so it never covers the last line of the footer. */
body { padding-bottom: 84px; }

@media (min-width: 900px) {
	.call-bar { display: none; }
	body { padding-bottom: 0; }
}

.admin-bar .site-head { top: 32px; }
@media (max-width: 782px) { .admin-bar .site-head { top: 46px; } }

/* ==========================================================================
   20. MOTION

   THE CONTRACT, because getting this wrong hides the whole site.

   Nothing below hides an element unless <html> carries the has-motion class,
   and that class is added by four lines of inline script in the <head>
   (inc/assets.php) which run only when:

     - the owner has left "Gentle animations" ticked in Customize, AND
     - the visitor's device is NOT asking for reduced motion.

   The inline script also arms a 2.5-second failsafe: if assets/js/site.js has
   not marked itself ready by then - blocked, failed to download, threw - the
   class is removed and every revealed element is simply visible. So the three
   ways this could have blanked the page (no JavaScript, a broken script, an
   old browser) all end with the content on screen. That is the reason the
   class goes on in the head rather than being assumed: CSS that hides content
   must never be able to outlive the JavaScript that shows it again.

   The reduced-motion block in section 2 stays as the second line of defence -
   it neuters durations even if something here is ever gated wrongly.
   ========================================================================== */

/* -- Keyframes. Three, and only the leaf loops. ---------------------------- */

@keyframes hc-sheen {
	0%   { opacity: 0; background-position: 260% 0; }
	14%  { opacity: 1; }
	100% { opacity: 0; background-position: -160% 0; }
}

/* The brand leaf behind the credential card, drifting. 34 seconds for 20px:
   slow enough that it is never caught moving, present enough that the hero is
   not a still image. This is the only thing on the site that animates without
   being asked to, and it is one composited layer - no repaint, no layout. */
@keyframes hc-drift {
	0%, 100% { transform: rotate(-14deg) translate3d(0, 0, 0); }
	50%      { transform: rotate(-10.5deg) translate3d(-20px, 24px, 0); }
}

@keyframes hc-menu-in {
	from { opacity: 0; transform: translateY(-10px); }
	to   { opacity: 1; transform: none; }
}

/* -- The reveal engine ---------------------------------------------------- */

.has-motion [data-reveal] {
	opacity: 0;
	transform: translate3d(0, 24px, 0);
	transition:
		opacity var(--dur-slow) var(--ease-out),
		transform var(--dur-slow) var(--ease-out);
}

.has-motion [data-reveal="left"]  { transform: translate3d(-28px, 0, 0); }
.has-motion [data-reveal="right"] { transform: translate3d(28px, 0, 0); }

/* Rise and settle. Used once, on the credential card, because it is the one
   object on the page that should read as arriving rather than as scrolling
   into place. */
.has-motion [data-reveal="scale"] { transform: translate3d(0, 26px, 0) scale(.96); }

.has-motion [data-reveal].is-in {
	opacity: 1;
	transform: none;
}

/* -- Groups: one observer, children staggered ----------------------------- *
 * The stagger is in CSS rather than in JavaScript on purpose. Setting
 * style.transitionDelay on every child means touching the DOM once per card;
 * nth-child costs nothing and cannot go wrong. Seven steps covers every grid
 * in the theme (four treatments, three stats, three steps, three clinics);
 * anything beyond that lands together, which is what you want anyway - a
 * ninth item arriving 640ms late reads as a stall, not as choreography.
 * ------------------------------------------------------------------------- */

.has-motion [data-reveal-group] > * {
	opacity: 0;
	transform: translate3d(0, 24px, 0);
	transition:
		opacity var(--dur-slow) var(--ease-out),
		transform var(--dur-slow) var(--ease-out);
}

.has-motion [data-reveal-group].is-in > * {
	opacity: 1;
	transform: none;
}

.has-motion [data-reveal-group].is-in > *:nth-child(1) { transition-delay: 0ms; }
.has-motion [data-reveal-group].is-in > *:nth-child(2) { transition-delay: calc(var(--stagger) * 1); }
.has-motion [data-reveal-group].is-in > *:nth-child(3) { transition-delay: calc(var(--stagger) * 2); }
.has-motion [data-reveal-group].is-in > *:nth-child(4) { transition-delay: calc(var(--stagger) * 3); }
.has-motion [data-reveal-group].is-in > *:nth-child(5) { transition-delay: calc(var(--stagger) * 4); }
.has-motion [data-reveal-group].is-in > *:nth-child(6) { transition-delay: calc(var(--stagger) * 5); }
.has-motion [data-reveal-group].is-in > *:nth-child(n+7) { transition-delay: calc(var(--stagger) * 6); }

/* -- The hero, on arrival ------------------------------------------------- *
 * Above the fold, so this is not a scroll effect - it is the first thing the
 * visitor sees, and it is the only place in the theme where the timing is
 * tuned by hand. The copy column runs its own stagger; the credential card
 * waits for it and then rises, so the eye reads the sentence before it reads
 * the doctor's credentials rather than being offered both at once.
 * ------------------------------------------------------------------------- */

.has-motion .hero-copy > * { transform: translate3d(0, 18px, 0); }

.has-motion .hero-aside [data-reveal] { transition-delay: 260ms; }

/* The leaf drifts only once the hero has finished arriving - starting a 34s
   ambient loop while three other things are still moving is noise. */
.has-motion .hero.on-green::before {
	animation: hc-drift 34s var(--ease) infinite;
	animation-delay: 1.2s;
}

/* -- The header, once the page has moved ---------------------------------- *
 * A sticky bar that looks identical whether it is sitting in the layout or
 * floating over the content has no depth in it. Past 24px it tightens and
 * lifts off the page. Nothing reflows below it: the row's own height is the
 * only animated length, and the logo scales rather than resizing.
 * ------------------------------------------------------------------------- */

.site-head { transition: box-shadow var(--dur) var(--ease); }

.is-stuck .site-head { box-shadow: 0 14px 34px -22px rgba(7, 61, 31, .55); }
.is-stuck.head-dark .site-head { box-shadow: 0 16px 36px -20px rgba(0, 0, 0, .55); }

@media (min-width: 900px) {
	.head-row { transition: min-height var(--dur) var(--ease); }

	.brand-mark .mark,
	.brand-mark .custom-logo { transition: transform var(--dur) var(--ease); }

	.is-stuck .head-row { min-height: 76px; }

	.is-stuck .brand-mark .mark,
	.is-stuck .brand-mark .custom-logo { transform: scale(.87); }
}

/* -- The mobile menu ------------------------------------------------------ */

@media (max-width: 899px) {
	.has-motion .has-js-nav .site-nav.is-open {
		animation: hc-menu-in var(--dur) var(--ease-out) 1;
	}
}

/* -- Counting numbers ----------------------------------------------------- *
 * site.js counts the statistics up from zero when the band comes into view.
 * Proportional digits change width as they go, so a number counting to 25,000
 * makes the whole row shuffle sideways while it runs. Tabular figures are all
 * one width, which is what they are for. Set permanently, not only while
 * counting, so the layout is identical before, during and after.
 * ------------------------------------------------------------------------- */

.stat-value,
.stat-num,
.reviews-value,
.rating-value { font-variant-numeric: tabular-nums; }

/* -- The jump link's arrow ------------------------------------------------ */

.hero-jump .icon { transition: transform var(--dur) var(--ease-out); }

@media (hover: hover) {
	.hero-jump a:hover .icon { transform: translateX(6px); }
}

/* -- The credential card, on hover ---------------------------------------- *
 * It is glass. Glass catches more light when you lean towards it. Desktop
 * only: below 1000px the card is a full-width panel under the buttons, and a
 * full-width panel that lifts reads as the page wobbling.
 * ------------------------------------------------------------------------- */

.hero-doctor-card {
	transition:
		transform var(--dur-slow) var(--ease-out),
		box-shadow var(--dur-slow) var(--ease-out);
}

@media (hover: hover) and (min-width: 1000px) {
	.hero-doctor-card:hover {
		transform: translateY(-5px);
		box-shadow:
			0 34px 70px -30px rgba(0, 0, 0, .70),
			0 0 110px -38px rgba(124, 191, 63, .58),
			inset 0 1px 0 rgba(255, 255, 255, .26);
	}
}
