/* ============================================================
   BHARTIYA LAW — LIQUID GLASS
   The material layer. Loaded last; owns every translucent surface.
   ============================================================

   WHY THIS FILE USES `html` PREFIXES AND `!important`
   ---------------------------------------------------
   Neither is decoration. Three stylesheets already claim the same
   selectors, and two of them outrank a plain rule here:

     1. styles.css            — base
     2. enhancements.css      — sets `background: var(--glass-bg)
                                !important` and `border-radius: 18px
                                !important` on every card
     3. page-level <style>    — blog.php, index.php and the rest
                                declare card styles inside <body>,
                                which comes AFTER this file in
                                document order and therefore wins
                                every tie

   So a plain `.blog-card { background: … }` here loses twice over.
   That is precisely why the earlier version of this file looked
   like almost nothing had changed: the rules were being written,
   parsed and then discarded.

     · `html ` prefix  → beats the page-level <style> blocks
     · `!important`    → beats enhancements.css

   WHY NOT THE WebGL LIBRARY
   -------------------------
   @ybouane/liquidglass rasterises the DOM through html-to-image,
   uploads that raster to WebGL and refracts it. Fine for a static
   hero over a fixed background. Wrong here: the glass surfaces are
   a sticky navbar and scrolling cards, whose backdrop changes every
   frame — which that library handles only by re-capturing the whole
   page every frame. On a mid-range Android that is a stutter.

   THE FIVE LAYERS OF THE MATERIAL
   -------------------------------
     1. a colour wallpaper behind everything — glass with nothing
        behind it is just a pale rectangle
     2. blur + saturation + brightness  — refraction and bloom
     3. a translucent tint              — the pane itself
     4. a specular rim and sweep        — light catching the bevel
     5. layered shadow                  — thickness

   Everything is CSS. No JavaScript, no per-frame work: blur is
   composited on the GPU and the wallpaper is a static layer that
   is painted once and never repainted.
   ============================================================ */

:root {
    /* ── The dial. Lower these to soften the whole system. ── */
    /* Blur came DOWN from 34px, not up. Past roughly 24px the
       backdrop stops being a recognisable thing seen through glass
       and becomes fog — and fog is what made the panes read as
       flat paint. Real glass shows you what is behind it. */
    --glass-blur:        20px;
    --glass-blur-nav:    18px;
    --glass-saturate:    190%;
    --glass-bright:      1.12;

    /* Tint is a veil, not a fill — but it was set so thin that the
       panes stopped reading as panes at all. On a pale ground a 0.15
       veil over a blur is very nearly the ground, so a page of cards
       became one continuous wash with text floating on it. That is the
       "everything blends together" problem, and it is a legibility
       problem as much as a visual one: text needs a surface.

       0.34 still shows the backdrop moving behind it — the blur and
       the saturation boost do the work — while giving every pane a
       definite edge and something for type to sit on. */
    --lg-tint:           rgba(255, 255, 255, 0.34);
    --lg-tint-strong:    rgba(255, 255, 255, 0.46);
    --lg-tint-soft:      rgba(255, 255, 255, 0.20);
    --lg-tint-hover:     rgba(255, 255, 255, 0.50);

    /* The bevel. With the tint this low, the EDGE is what defines
       the pane — a bright hairline is now doing the work the fill
       used to do, which is exactly how the material is built. */
    --lg-rim:            rgba(255, 255, 255, 0.98);
    --lg-rim-soft:       rgba(255, 255, 255, 0.42);
    --lg-edge:           rgba(255, 255, 255, 0.30);
    --lg-edge-low:       rgba(11, 61, 46, 0.12);
    --lg-text:           #14211b;

    /* Three shadows: contact, mid, ambient. A single shadow always
       reads as a sticker rather than a floating pane. */
    --lg-shadow:
        0 1px 2px  rgba(11, 61, 46, 0.06),
        0 8px 24px rgba(11, 61, 46, 0.10),
        0 24px 56px rgba(11, 61, 46, 0.12);
    --lg-shadow-lift:
        0 2px 6px   rgba(11, 61, 46, 0.09),
        0 16px 36px rgba(11, 61, 46, 0.16),
        0 36px 84px rgba(11, 61, 46, 0.22);

    /* Large radii, and very slightly unequal corner to corner. A
       perfectly symmetrical rounded rectangle reads as a drawn shape;
       a few pixels of variation reads as something that set that way.

       Length radii, not percentages: a percentage radius is measured
       against the box, so past roughly 35% the corners meet and the
       pane collapses into an ellipse. */
    --lg-radius:      28px 24px 26px 24px / 24px 28px 24px 26px;
    --lg-radius-sm:   19px 17px 18px 17px / 17px 19px 17px 18px;
    --lg-radius-pill: 999px;
}

[data-theme="dark"] {
    /* Dark glass still needs more tint than light glass — a pane
       over a dark page has less to separate it from the ground —
       but far less than before, and the bright rim carries it. */
    /* Panes lift slightly off a dark ground rather than sitting flat
       on it: a touch of warmth in the fill, a brighter rim. Pure
       white at 7% over near-black reads grey and dead. */
    /* The dark ground is already dark, so a pane has to be LIGHTER
       than it to separate — and at 0.09 it barely was. */
    --lg-tint:        rgba(214, 240, 228, 0.14);
    --lg-tint-strong: rgba(214, 240, 228, 0.20);
    --lg-tint-soft:   rgba(214, 240, 228, 0.09);
    --lg-tint-hover:  rgba(214, 240, 228, 0.24);
    --lg-rim:         rgba(255, 255, 255, 0.72);
    --lg-rim-soft:    rgba(255, 255, 255, 0.16);
    --lg-edge:        rgba(180, 226, 206, 0.18);
    --lg-edge-low:    rgba(0, 0, 0, 0.42);
    --lg-text:        #eaf1ec;
    --lg-shadow:
        0 1px 2px   rgba(0, 0, 0, 0.34),
        0 8px 24px  rgba(0, 0, 0, 0.42),
        0 24px 56px rgba(0, 0, 0, 0.46);
    --lg-shadow-lift:
        0 2px 6px   rgba(0, 0, 0, 0.42),
        0 16px 36px rgba(0, 0, 0, 0.54),
        0 36px 84px rgba(0, 0, 0, 0.62);
}


/* ════════════════════════════════════════════════════════════
   1 · THE WALLPAPER
   The half that actually makes glass visible. Without colour
   behind them the panes have nothing to refract and vanish into
   the page — which is exactly what a white pane on a white page
   did before.

   `position: fixed` on a pseudo-element, never
   `background-attachment: fixed`, which forces a full repaint on
   every scroll frame on mobile. enhancements.css sets that on
   <body>; the override below is a real performance fix, not a
   cosmetic one.
   ════════════════════════════════════════════════════════════ */
html body {
    background: var(--light-bg) !important;
    background-attachment: scroll !important;
}
html[data-theme="dark"] body {
    background: var(--dark-bg) !important;
}

/* ── THE CANVAS ──────────────────────────────────────────────
   This is the layer that decides whether glass is visible at all.

   Glass is not a colour, it is a DISTORTION of whatever is behind it.
   Put a translucent pane over a flat cream page and there is nothing
   to distort — no colour shifts across the pane, the blur has nothing
   to smear, and the result is a pale rectangle with a fancy border.
   That is why the previous versions read as dull no matter how much
   the rim was tuned: the material was fine, the thing underneath it
   was empty.

   So the ground is now a proper mesh with real chroma — jade, aqua,
   sage, warm sand — in large overlapping pools. Behind glass those
   become the colour that bends and moves across each pane; in the
   open they stay soft enough to read text over.
   ──────────────────────────────────────────────────────────── */
html body::before {
    content: '';
    position: fixed;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    background-color: #F2F6F1;
    background-image:
        radial-gradient(58vw 52vw at  8%  -6%, rgba( 96, 178, 140, 0.68) 0%, transparent 64%),
        radial-gradient(50vw 46vw at 94%   6%, rgba(126, 178, 196, 0.62) 0%, transparent 66%),
        radial-gradient(54vw 48vw at 78%  52%, rgba(216, 190, 146, 0.72) 0%, transparent 64%),
        radial-gradient(48vw 56vw at -4%  56%, rgba(146, 196, 166, 0.60) 0%, transparent 66%),
        radial-gradient(60vw 44vw at 44% 100%, rgba(196, 172, 128, 0.62) 0%, transparent 66%),
        radial-gradient(38vw 34vw at 58%  28%, rgba(238, 243, 236, 0.85) 0%, transparent 62%),
        /* the grain — you do not see it, you see that the paper is
           not perfectly flat */
        repeating-linear-gradient( 28deg, rgba(60, 74, 62, 0.018) 0 2px, transparent 2px 7px),
        repeating-linear-gradient(-34deg, rgba(60, 74, 62, 0.014) 0 2px, transparent 2px 9px);
    background-size: auto;
    mask-image: none;
    -webkit-mask-image: none;
}
html[data-theme="dark"] body::before {
    background-color: #0D1411;
    background-image:
        radial-gradient(58vw 52vw at  8%  -6%, rgba( 26, 108, 82, 0.85) 0%, transparent 64%),
        radial-gradient(50vw 46vw at 94%   6%, rgba( 30,  76, 92, 0.78) 0%, transparent 66%),
        radial-gradient(54vw 48vw at 78%  52%, rgba( 18,  92, 68, 0.80) 0%, transparent 64%),
        radial-gradient(48vw 56vw at -4%  56%, rgba( 40, 132, 100, 0.55) 0%, transparent 66%),
        radial-gradient(60vw 44vw at 44% 100%, rgba(  6,  26, 20, 0.90) 0%, transparent 66%),
        radial-gradient(34vw 30vw at 60%  26%, rgba(193, 166, 123, 0.20) 0%, transparent 64%);
}

/* Opaque section grounds would cover the wallpaper completely. */
html .main-content, html .services-section, html .blog-section-wrap,
html .practice-grid, html .team-section, html .about-section,
html .contact-section, html .stats-section, html .why-choose-us,
html .related-posts, html .content-section, html .prac-section,
html main, html section, html .container {
    background-color: transparent !important;
}
/* …but the dark hero, header and footer keep their own ground. */
html .hero, html .page-hero, html .footer, html .blog-page-header,
html .cta-section {
    background-color: initial;
}

/* ── THE ANIMATION TAX ───────────────────────────────────────
   Several things on this site animated forever, and forever is a
   long time to pay for something nobody is looking at. What makes
   it expensive here rather than merely wasteful: almost every pane
   on the site has a backdrop-filter, and anything that changes
   underneath one forces that pane to re-filter its backdrop. One
   slow-moving layer in the background is not one layer's worth of
   work — it is every glass card on the page, every frame.

   1. THE LOADING BAR. `.loading-screen.hide` sets opacity and
      visibility but not `display`, and a `visibility: hidden`
      element is still in the layout tree. So `loadBar` — which
      animates `width` and `margin-left`, both layout properties —
      kept forcing layout every frame for the whole life of every
      page, invisibly, long after the loader was gone. It is now
      stopped when hidden, and while it IS visible it runs on
      transform, which needs no layout at all.

   2. BLURRED THINGS THAT ANIMATE `scale`. A blurred layer can be
      rasterised once and then moved around for free — but only if
      it is MOVED. Change its scale and the blur is recomputed at
      the new size every frame. Translating alone gives the same
      drift for none of the cost.

   3. THE TEAM CAROUSEL, which scrolled whether or not it was on
      screen. app.js now pauses it when it scrolls out of view.
   ──────────────────────────────────────────────────────────── */

html .loading-screen.hide,
html .loading-screen.hide * {
    animation: none !important;
}
html .loading-progress {
    /* The box stays put; the bar travels and stretches on the
       compositor instead. transform-origin: left so scaleX grows
       rightwards rather than out from the middle. */
    width: 100% !important;
    margin-left: 0 !important;
    transform-origin: left center;
    animation: lgLoadBar 1.4s ease-in-out infinite !important;
}
@keyframes lgLoadBar {
    0%   { transform: translateX(0)    scaleX(0.02); }
    50%  { transform: translateX(15%)  scaleX(0.70); }
    100% { transform: translateX(100%) scaleX(0.02); }
}

/* The 800px blob behind the hero animated translate AND scale
   together. Same drift, without re-blurring 640,000 pixels a frame. */
@keyframes lgHeroBlob {
    0%   { transform: translate3d(0, 0, 0); }
    100% { transform: translate3d(-120px, 80px, 0); }
}
html .hero::after {
    animation: lgHeroBlob 18s ease-in-out infinite alternate !important;
}

/* Paused by app.js when the carousel is not on screen. */
html .coriolis-track.is-offscreen { animation-play-state: paused !important; }


/* ── BUTTONS ─────────────────────────────────────────────────
   Solid forest green with white text for the primary action; warm
   beige with dark text and a brass hairline for the secondary. Both
   keep a soft shadow so they sit slightly above the paper.
   ──────────────────────────────────────────────────────────── */
html .btn-primary {
    background: var(--secondary-color) !important;
    background-size: auto !important;
    border: 1px solid var(--secondary-color) !important;
    /* Not a literal white. The forest green this sits on in light mode
       takes white at 8.6:1, but dark mode's accent is a bright mint
       where white measures 1.92:1 — --btn-ink is white on one and
       near-black on the other. */
    color: var(--btn-ink, #FFFFFF) !important;
    border-radius: 10px !important;
    box-shadow: 0 1px 2px  rgba(28, 28, 28, 0.06),
                0 6px 18px rgba(18, 87, 54, 0.18) !important;
    text-shadow: none !important;
}
html .btn-primary:hover {
    background: var(--accent-light) !important;
    border-color: var(--accent-light) !important;
    color: var(--btn-ink, #FFFFFF) !important;
    transform: translateY(-2px);
    box-shadow: 0 2px 4px  rgba(28, 28, 28, 0.08),
                0 12px 28px rgba(18, 87, 54, 0.26) !important;
}

html[data-theme="dark"] .btn-secondary {
    background: transparent !important;
    border: 1px solid var(--secondary-color) !important;
    color: var(--secondary-color) !important;
}
html[data-theme="dark"] .btn-secondary:hover {
    background: var(--secondary-color) !important;
    color: var(--btn-ink) !important;
    border-color: var(--secondary-color) !important;
}
html .btn-secondary {
    background: var(--beige, #EBE5D6) !important;
    border: 1px solid var(--gold) !important;
    color: var(--dark-text) !important;
    border-radius: 10px !important;
    box-shadow: 0 1px 2px rgba(28, 28, 28, 0.05) !important;
}
html .btn-secondary:hover {
    background: #E2DAC7 !important;
    border-color: var(--gold-dark) !important;
    color: var(--dark-text) !important;
    transform: translateY(-2px);
    box-shadow: 0 2px 4px  rgba(28, 28, 28, 0.07),
                0 10px 24px rgba(28, 28, 28, 0.08) !important;
}

/* The sweeping sheen belonged to the old gradient buttons. */
html .btn::before, html .btn::after { display: none !important; }

/* Brass is ornament: rules, hairlines, icon strokes. At 2.26:1 on the
   cream it is not a text colour and must never become one. */
html .section-header h2::after,
html .about-content h2::after,
html hr {
    background: var(--gold) !important;
    border-color: var(--gold) !important;
}

/* ── THE CALL TO ACTION ──────────────────────────────────────
   The section bands were removed because they drew a rectangle
   round content that was already reading fine — a box for its own
   sake. The CTA is the opposite case and the reason the rule has an
   exception: it is not part of the reading flow, it is the thing you
   are asked to do at the end of it. A panel here does not interrupt
   the page, it terminates it.

   So it stays dark in BOTH themes. On the cream it is the single
   deliberate dark mass on the page and the eye goes straight to it;
   in dark mode the ground is darker still (#0D1411), so the panel is
   lifted a couple of steps rather than sunk, and the brass rim is
   what makes the edge legible either way.

   Solid, not glass: at this size a backdrop-filter is a full-width
   blur of the wallpaper on every page, and the panel's whole job is
   to be opaque and final.
   ──────────────────────────────────────────────────────────── */
html .cta-section {
    position: relative;
    overflow: hidden;
    isolation: isolate;
    max-width: 1100px !important;
    margin: clamp(56px, 7vw, 88px) auto !important;
    padding: clamp(48px, 6.5vw, 76px) clamp(24px, 4vw, 48px) !important;
    text-align: center;
    border-radius: 28px !important;
    background:
        radial-gradient(120% 140% at 88% -10%, rgba(193, 166, 123, 0.20) 0%, transparent 58%),
        radial-gradient(110% 130% at 6% 108%, rgba(52, 150, 108, 0.16) 0%, transparent 60%),
        linear-gradient(142deg, #11402A 0%, #0C3021 52%, #0A2620 100%) !important;
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
    border: 1px solid rgba(193, 166, 123, 0.30) !important;
    box-shadow:
        0 22px 52px -18px rgba(12, 32, 24, 0.50),
        0 2px 0 rgba(255, 255, 255, 0.05) inset !important;
    color: #F3EFE6 !important;
}
/* In dark mode the page is darker than the panel, so the panel rises
   instead of sinking and the shadow stops doing any work. */
html[data-theme="dark"] .cta-section {
    background:
        radial-gradient(120% 140% at 88% -10%, rgba(212, 175, 55, 0.16) 0%, transparent 58%),
        radial-gradient(110% 130% at 6% 108%, rgba(52, 211, 153, 0.12) 0%, transparent 60%),
        linear-gradient(142deg, #1A3129 0%, #14261F 52%, #11201B 100%) !important;
    border-color: rgba(212, 175, 55, 0.26) !important;
    box-shadow:
        0 20px 46px -20px rgba(0, 0, 0, 0.60),
        0 2px 0 rgba(255, 255, 255, 0.04) inset !important;
}
/* A faint drafting grid, masked away at the edges so it never reaches
   the rim and turns into a visible texture seam. */
html .cta-section::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 0;
    background-image:
        linear-gradient(rgba(255, 255, 255, 0.035) 1px, transparent 1px),
        linear-gradient(90deg, rgba(255, 255, 255, 0.035) 1px, transparent 1px);
    background-size: 44px 44px;
    -webkit-mask-image: radial-gradient(ellipse at 50% 45%, #000 0%, transparent 78%);
    mask-image: radial-gradient(ellipse at 50% 45%, #000 0%, transparent 78%);
    pointer-events: none;
}
html .cta-section > * { position: relative; z-index: 1; }

html .cta-section h2 {
    color: #FBF8F1 !important;
    background: none !important;
    -webkit-text-fill-color: currentColor !important;
    margin: 0 0 14px !important;
    font-size: clamp(1.7rem, 3.2vw, 2.4rem) !important;
    line-height: 1.22;
}
/* The brass rule reads as ornament on cream and as ornament here too —
   on this ground it has the contrast to be seen, which it never quite
   had on the paper. */
html .cta-section h2::after {
    content: '';
    display: block;
    width: 68px;
    height: 2px;
    margin: 16px auto 0;
    border-radius: 2px;
    background: linear-gradient(90deg, transparent, var(--gold), transparent) !important;
    box-shadow: none !important;
}
html .cta-section p {
    color: rgba(243, 239, 230, 0.82) !important;
    max-width: 58ch;
    margin: 0 auto clamp(24px, 3vw, 34px) !important;
    font-size: clamp(1rem, 1.35vw, 1.1rem);
}
/* Forest green on forest green is not a button. On this panel the
   primary action takes the brass, with charcoal ink — 8.9:1 — and the
   panel's own green becomes the ground it sits on. */
html .cta-section .btn-primary,
html .cta-section .btn.btn-primary {
    background: linear-gradient(180deg, #D3BC95 0%, #C1A67B 100%) !important;
    background-color: #C1A67B !important;
    border: 1px solid rgba(255, 255, 255, 0.28) !important;
    color: #1C1C1C !important;
    box-shadow: 0 10px 24px -10px rgba(0, 0, 0, 0.55) !important;
}
html .cta-section .btn-primary:hover,
html .cta-section .btn.btn-primary:hover {
    background: linear-gradient(180deg, #E0CCAB 0%, #CDB48B 100%) !important;
    transform: translateY(-2px);
    box-shadow: 0 14px 30px -10px rgba(0, 0, 0, 0.55) !important;
}
html .cta-section .btn-secondary,
html .cta-section .btn:not(.btn-primary) {
    background: rgba(255, 255, 255, 0.07) !important;
    border: 1px solid rgba(243, 239, 230, 0.34) !important;
    color: #F3EFE6 !important;
}
html .cta-section a:focus-visible,
html .cta-section .btn:focus-visible {
    outline: 3px solid var(--gold);
    outline-offset: 3px;
}

@media (max-width: 640px) {
    html .cta-section {
        margin: clamp(40px, 9vw, 56px) 16px !important;
        padding: 44px 22px !important;
        border-radius: 22px !important;
    }
}


/* ── COLOUR, PLACED ──────────────────────────────────────────
   A cream page with charcoal text and nothing else is correct and
   dull. The colour goes in three places and no others, which is what
   keeps it from becoming noise:

     · section headings take the forest green (8.3:1 on the cream), so
       the eye lands on structure rather than on a wall of grey;
     · a brass rule sits under each one — ornament, at 2.3:1, which is
       exactly why it is a rule and never a word;
     · eyebrow labels and category chips take brass on a tinted ground
       dark enough to carry it.

   Body copy stays neutral charcoal. That contrast between a WARM
   ground and NEUTRAL text is deliberate: green-grey text on a
   green-tinted page is what made the type feel like it was dissolving
   into the background before. */
/* .cta-section h2 is deliberately NOT in this list — it sits on the
   dark panel above and takes cream there, not forest on forest. */
html .section-header h2,
html .about-content h2,
html .services-section h2,
html .blog-section-wrap h2 {
    color: var(--secondary-color) !important;
    background: none !important;
    -webkit-text-fill-color: currentColor !important;
}

html .section-header h2::after,
html .about-content h2::after {
    content: '';
    display: block;
    width: 68px;
    height: 2px;
    margin: 14px auto 0;
    border-radius: 2px;
    background: linear-gradient(90deg,
        rgba(193, 166, 123, 0) 0%,
        var(--gold) 28%,
        var(--gold) 72%,
        rgba(193, 166, 123, 0) 100%) !important;
}
html .about-content h2::after { margin-left: 0; margin-right: auto; }

/* Card titles: forest green rather than charcoal, so each card has a
   point of colour where the eye enters it. */
html .service-card h3,
html .practice-card h3,
html .blog-card h3,
html .related-card h3,
html .reason h3 {
    color: var(--secondary-color) !important;
}

/* Small uppercase labels — "Services at a glance", category chips —
   take brass on a ground tinted dark enough to hold it. */
html .filter-chip,
html .post-hero-cat,
html .blog-card-cat {
    background: rgba(18, 87, 54, 0.10) !important;
    border: 1px solid rgba(193, 166, 123, 0.45) !important;
    color: var(--secondary-color) !important;
}

/* The numbers on the stats strip are the one place a large brass
   figure works, because at that size 2.3:1 is decoration you read
   the LABEL of, and the label underneath is charcoal. */
html .stat .num,
html .stat-number {
    color: var(--gold-dark) !important;
}


/* ── REFRACTION ──────────────────────────────────────────────
   Real displacement refraction, on ONE element: the hero pane.

   Two things were learned the hard way here, and both are worth
   keeping written down.

   FIRST — the filter goes on the PANE, never on the rim pseudo.
   An element's "backdrop" is everything painted beneath it in the
   stacking context. The rim sits ABOVE the card's content, so the
   card's own heading and body text were part of the rim's backdrop,
   and the filter dutifully displaced them: every card rendered its
   text twice, once crisp and once smeared. On the pane itself the
   backdrop is only what is behind the card, so the text is painted
   afterwards and stays sharp while the colour behind it bends.

   SECOND — this is expensive, and it does not matter which filter
   primitive you use. An SVG filter used as a backdrop-filter re-runs
   every time the backdrop changes, which while scrolling means every
   frame. Measured on a 4x-throttled CPU across four seconds of
   scrolling: 1206ms of raster with feTurbulence, 1742ms with a
   pre-baked feImage map, against 0ms for a plain blur. There is no
   version of this that is cheap on nine cards at once.

   So it goes where it earns its cost — the one large pane at the top
   of the page, which is also the only place the effect is big enough
   to actually appreciate. The cards keep the blur and the lensed rim,
   which cost nothing per frame. Less is more, and here it is also
   the difference between a smooth page and a janky one.
   ──────────────────────────────────────────────────────────── */

/* ── SURVEY FIXES ────────────────────────────────────────────
   Found by measuring the CSS text colour, composited at its real
   alpha, against the MEDIAN rendered pixel of each element's box —
   which is the only method that works over glass and gradients,
   where there is no single background colour to look up.
   ──────────────────────────────────────────────────────────── */

/* The dark navbar was a mid-green (rgb 44,123,94) — light enough that
   gold on it measured 2.43:1 and the mint nav links 2.66:1. It is the
   bar at the top of every page, so this was the single worst offender
   on the site. Darkening it fixes the tagline, the wordmark and the
   links together: gold goes to 6.7:1, mint to 7.3:1. */
html[data-theme="dark"] .navbar::before {
    background: rgba(12, 28, 23, 0.86) !important;
}
html[data-theme="dark"] .firm-tagline { color: var(--gold-light) !important; }

/* Footer copy was white at 0.38 and 0.55 alpha — 3.2:1 and 4.3:1 on
   the footer's own ground. */
html .footer-copyright,
html .footer-legal-note {
    color: rgba(255, 255, 255, 0.80) !important;
}
html .footer-description {
    color: rgba(255, 255, 255, 0.82) !important;
}
/* The Bar Council line is the one piece of text on the site there is a
   professional obligation to make readable. It was gold at 0.7 alpha:
   2.88:1. Full-strength light gold takes it to 7:1. */
html .footer-disclaimer,
html .footer .disclaimer-note,
html .footer small {
    color: var(--gold-light) !important;
    opacity: 1 !important;
}


/* The filter chips took the mint accent on a tinted ground: 3.7:1 in
   dark. Light text on a darker chip is the readable way round. */
html[data-theme="dark"] .filter-chip {
    background: rgba(10, 24, 19, 0.55) !important;
    border-color: rgba(255, 255, 255, 0.16) !important;
    color: var(--light-text) !important;
}
html[data-theme="dark"] .filter-chip.active,
html[data-theme="dark"] .filter-chip:hover {
    background: var(--secondary-color) !important;
    color: var(--btn-ink) !important;
    border-color: var(--secondary-color) !important;
}
/* "FILTER" is a label, not decoration — it was 3.6:1. */
html .filter-bar-label { color: var(--gray-text) !important; }


/* The About block was a card wrapping a card — the whole section in
   one white panel, with the pull-quote in a second panel inside it.
   The outer one goes; the quote keeps its own, which is the one that
   is actually doing something. */
/* Its decorative corner glow was only ever invisible because the card
   clipped it. With the card gone it floats as a stray cream rectangle. */
html .about-glass-card::before,
html .about-glass-card::after { display: none !important; }

html .about-glass-card,
html .about-glass-wrap {
    background: none !important;
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
    border: 0 !important;
    box-shadow: none !important;
    border-radius: 0 !important;
}


/* ── PAGE RHYTHM ─────────────────────────────────────────────
   No section grounds. The alternating near-white bands were meant to
   read as full-bleed stripes running the width of the window; they do
   not, because these sections sit inside a max-width container, so
   what actually rendered was a pale rectangle with hard left and right
   edges floating in the middle of the page — a box around the content
   rather than a band behind it.

   Spacing does the same job without drawing anything. The eye reads a
   gap as a division perfectly well, and it cannot render wrong.
   ──────────────────────────────────────────────────────────── */
html .services-section,
html .stats-section,
html .blog-section-wrap,
html .why-choose-us,
html .coriolis-section,
html .about-glass-wrap {
    background: transparent !important;
    padding-top: clamp(54px, 7.5vw, 92px);
    padding-bottom: clamp(54px, 7.5vw, 92px);
}
html .services-section::before, html .stats-section::before,
html .blog-section-wrap::before, html .why-choose-us::before,
html .services-section::after, html .stats-section::after,
html .blog-section-wrap::after, html .why-choose-us::after {
    display: none !important;
}

/* ── THE HERO ────────────────────────────────────────────────
   No pane. The hero copy sits straight on the field, which is what
   makes the top of the page read as one continuous surface instead of
   a card dropped onto a backdrop — there is no edge anywhere between
   the header and the first section.

   This is also why the SVG displacement filters are gone from
   header.php: the hero panel was their only user, and they carried a
   10KB base64 noise map each, inlined into every page.
   ──────────────────────────────────────────────────────────── */
html .hero .hero-content {
    position: relative;
    max-width: 880px;
    margin: 0 auto;
    padding: clamp(10px, 2vw, 24px) clamp(16px, 3vw, 32px) clamp(14px, 2vw, 26px);
    background: none !important;
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
    border: 0 !important;
    border-radius: 0 !important;
    box-shadow: none !important;
}
html .hero .hero-content::after { display: none !important; }
html .hero .hero-content > * { position: relative; z-index: 2; }

/* ── THE BANDS ───────────────────────────────────────────────
   The hero used to be a dark slab in BOTH themes while everything
   around it followed the theme, which put two hard seams across a
   light page — pale header, dark block, pale body.

   It is now a monochromatic fade: one hue, top to bottom, ending on
   the page ground so there is no edge to see. Soft sage into the base
   in light; the page green into near-black in dark.
   ──────────────────────────────────────────────────────────── */
html .hero,
html .page-hero,
html .blog-page-header {
    /* Monochromatic, landing exactly on the page ground so the section
       has no edge. The canvas glows show through the tail of it. */
    /* Almost nothing. The mesh underneath IS the hero background now,
       and a wash laid over it flattens exactly the area the glass pane
       sits on — which is the one place the mesh needs to be richest. */
    background: linear-gradient(180deg,
        rgba(255, 255, 255, 0.16) 0%,
        rgba(255, 255, 255, 0) 100%) !important;
    color: var(--dark-text) !important;
}
html[data-theme="dark"] .hero,
html[data-theme="dark"] .page-hero,
html[data-theme="dark"] .blog-page-header {
    background: linear-gradient(180deg,
        rgba(6, 14, 11, 0.32) 0%,
        rgba(6, 14, 11, 0) 100%) !important;
    color: var(--light-text) !important;
}

/* The grid overlay on .page-hero is white hairlines — invisible on a
   light ground, so it inverts with the theme. At 4% it is texture,
   not decoration you are meant to notice. */
html .page-hero::before {
    background-image:
        linear-gradient(rgba(13, 20, 17, 0.04) 1px, transparent 1px),
        linear-gradient(90deg, rgba(13, 20, 17, 0.04) 1px, transparent 1px) !important;
}
html[data-theme="dark"] .page-hero::before {
    background-image:
        linear-gradient(rgba(237, 242, 240, 0.04) 1px, transparent 1px),
        linear-gradient(90deg, rgba(237, 242, 240, 0.04) 1px, transparent 1px) !important;
}

/* ── hero typography, per theme ──────────────────────────────── */
html .hero-title {
    background: none !important;
    -webkit-text-fill-color: currentColor !important;
    color: var(--primary-color) !important;
}
html[data-theme="dark"] .hero-title {
    color: var(--primary-color) !important;
}

html .page-hero h1,
html .blog-page-header h1 {
    color: var(--primary-color) !important;
    background: none !important;
    -webkit-text-fill-color: currentColor !important;
}

html .hero-subtitle,
html .page-hero p,
html .blog-page-header p {
    color: var(--gray-text) !important;
}

/* Gold is 2.1:1 on the light ground — ornament there, never text.
   On the dark ground it is 7.4:1, so it takes the eyebrow. */
html .hero-tagline-lead {
    color: var(--secondary-color) !important;
}
html[data-theme="dark"] .hero-tagline-lead {
    color: var(--gold) !important;
}

/* The hero's secondary button is the same object as everywhere else —
   it had its own transparent override from when the hero was a dark
   slab and beige would have looked pasted on. */
html .hero .btn-secondary {
    background-color: var(--beige, #EBE5D6) !important;
    border-color: var(--gold) !important;
    color: var(--dark-text) !important;
}
html .hero .btn-secondary:hover {
    background-color: #E2DAC7 !important;
    border-color: var(--gold-dark) !important;
    color: var(--dark-text) !important;
}
html[data-theme="dark"] .hero .btn-secondary {
    background-color: transparent !important;
    border-color: var(--secondary-color) !important;
    color: var(--secondary-color) !important;
}
html[data-theme="dark"] .hero .btn-secondary:hover {
    background-color: var(--secondary-color) !important;
    color: var(--btn-ink) !important;
}

/* The floating blob was built to glow against a dark slab; on a flat
   ground it reads as a smudge, so it goes. */
html .hero::after { display: none !important; }

/* ── THE SCALES ──────────────────────────────────────────────
   The watermark was sitting at top: -6px, which on a glyph this size
   put its optical centre straight through the title — a grey shape
   behind the words rather than an emblem above them. It belongs in
   the empty band between the header and the title, so it is lifted
   clear of the text entirely and given room to move without ever
   touching it.

   Two things move, and both are transforms, so the whole thing is one
   composited layer and costs nothing per frame: it rises and falls,
   and it rocks about the beam's fulcrum — which is what a pair of
   scales actually does, and why a rotation reads as weight settling
   rather than as a spinning decoration. transform-origin sits at the
   pivot (just under the top of the glyph), not at its centre, or the
   pans would swing the wrong way.

   It is also brass rather than green now. Forest green at 8% on a
   warm cream is a neutral grey blur; brass at 22% is a colour the
   page already uses for ornament, and it reads as an emblem.
   ──────────────────────────────────────────────────────────── */
/* The band the emblem lives in is RESERVED by the content's own top
   padding rather than carved out of the space above it with a negative
   offset. That was the bug: `top` is measured from the padding-box
   edge, which sits just under the sticky header, so any negative value
   pushed the glyph up behind the header — and the smaller the viewport,
   the worse it got. Positive offset inside a padding band that is
   always taller than the glyph means it can never reach the header
   above or the title below, at any width. */
html .hero .hero-content {
    padding-top: clamp(74px, 7.6vw, 124px) !important;
}
html .hero .hero-content::before {
    top: 2px !important;
    left: 50% !important;
    z-index: 0 !important;
    font-size: clamp(52px, 6.8vw, 102px) !important;
    line-height: 1 !important;
    color: var(--gold) !important;
    opacity: 0.22 !important;
    filter: none !important;
    transform-origin: 50% 26%;
    will-change: transform;
    animation: lgScales 7s ease-in-out infinite !important;
}
html[data-theme="dark"] .hero .hero-content::before {
    color: var(--gold) !important;
    opacity: 0.26 !important;
}
@keyframes lgScales {
    0%   { transform: translateX(-50%) translateY(0)     rotate(-5deg); }
    50%  { transform: translateX(-50%) translateY(-14px) rotate(5deg); }
    100% { transform: translateX(-50%) translateY(0)     rotate(-5deg); }
}
@media (prefers-reduced-motion: reduce) {
    html .hero .hero-content::before {
        animation: none !important;
        transform: translateX(-50%) !important;
    }
}

/* The footer keeps its own darker ground in both themes — a reader
   expects the page to end somewhere — but flat, not gradient-stacked. */
html .footer {
    background: #0D1411 !important;
    border-top: 1px solid var(--border-color) !important;
}
html .footer::before { display: none !important; }


/* ════════════════════════════════════════════════════════════
   2 · TWO MATERIALS, USED ON PURPOSE

   Glass was on every pane on the site, and that is what made it look
   odd rather than expensive. A refractive edge says "there is depth
   behind this" — which is true of a floating hero panel and a false
   promise on a card holding a portrait, where the rim just draws a
   grey frame around somebody's face.

   So there are two materials now:

     GLASS — the hero panel, the call to action, the search bar. Things
     that float over the page rather than sit in it. Three or four
     elements per page, never a grid of them.

     PAPER — everything that carries content: cards, forms, list panes,
     team photos. Warm white, one hairline border, one soft shadow.
     Quiet, legible, and it does not compete with what is printed on it.
   ════════════════════════════════════════════════════════════ */

/* ── PAPER ─────────────────────────────────────────────────── */
html .glass,
html .service-card, html .practice-card, html .blog-card,
html .sidebar-card, html .related-card, html .error-link-card,
html .team-card, html .team-full-card, html .testimonial-card,
html .contact-item, html .form,
html .coriolis-card,
html .reason, html .stat, html .prac-box, html .post-disclaimer,
html .post-nav-link, html .sw-update-toast-inner, html .no-blogs {
    background: var(--card-bg) !important;
    -webkit-backdrop-filter: none;
    backdrop-filter:         none;
    border: 1px solid var(--border-color) !important;
    border-radius: 18px !important;
    box-shadow:
        0 1px 2px  rgba(28, 28, 28, 0.04),
        0 6px 18px rgba(28, 28, 28, 0.06) !important;
    position: relative;
    overflow: hidden;
}
html[data-theme="dark"] .glass,
html[data-theme="dark"] .service-card, html[data-theme="dark"] .practice-card,
html[data-theme="dark"] .blog-card, html[data-theme="dark"] .sidebar-card,
html[data-theme="dark"] .related-card, html[data-theme="dark"] .error-link-card,
html[data-theme="dark"] .team-card, html[data-theme="dark"] .team-full-card,
html[data-theme="dark"] .testimonial-card, html[data-theme="dark"] .contact-item,
html[data-theme="dark"] .form,
html[data-theme="dark"] .coriolis-card,
html[data-theme="dark"] .reason, html[data-theme="dark"] .stat,
html[data-theme="dark"] .prac-box, html[data-theme="dark"] .post-disclaimer,
html[data-theme="dark"] .post-nav-link,
html[data-theme="dark"] .sw-update-toast-inner,
html[data-theme="dark"] .no-blogs {
    box-shadow:
        0 1px 2px  rgba(0, 0, 0, 0.28),
        0 6px 18px rgba(0, 0, 0, 0.34) !important;
}

/* No rim, no sweep on paper. Both are glass cues, and on an opaque
   card they read as a grey outline — most obviously around the team
   portraits, where the rim framed each face. */
html .glass::before,
html .service-card::before, html .practice-card::before, html .blog-card::before,
html .sidebar-card::before, html .related-card::before, html .error-link-card::before,
html .team-card::before, html .team-full-card::before, html .testimonial-card::before,
html .contact-item::before,
html .reason::before, html .stat::before, html .prac-box::before,
html .coriolis-card::before,
html .glass::after,
html .service-card::after, html .practice-card::after, html .blog-card::after,
html .sidebar-card::after, html .related-card::after, html .error-link-card::after,
html .team-card::after, html .team-full-card::after,
html .contact-item::after, html .form::after,
html .reason::after, html .stat::after,
html .post-nav-link::after, html .no-blogs::after {
    display: none !important;
}

/* The lift on hover stays — it is the cheapest way to say "this is a
   thing you can click" — but it is a lift now, not a change of
   material. */
html .service-card, html .practice-card, html .blog-card,
html .team-card, html .team-full-card, html .reason, html .stat,
html .error-link-card, html .related-card, html .coriolis-card {
    transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1),
                box-shadow 0.4s ease,
                border-color 0.4s ease;
}
html .service-card:hover, html .practice-card:hover, html .blog-card:hover,
html .team-card:hover, html .team-full-card:hover, html .reason:hover,
html .stat:hover, html .error-link-card:hover, html .related-card:hover {
    transform: translateY(-4px);
    border-color: var(--border-strong) !important;
    box-shadow:
        0 2px 4px   rgba(28, 28, 28, 0.06),
        0 14px 34px rgba(28, 28, 28, 0.11) !important;
}
html[data-theme="dark"] .service-card:hover, html[data-theme="dark"] .practice-card:hover,
html[data-theme="dark"] .blog-card:hover, html[data-theme="dark"] .team-card:hover,
html[data-theme="dark"] .team-full-card:hover, html[data-theme="dark"] .reason:hover,
html[data-theme="dark"] .stat:hover, html[data-theme="dark"] .error-link-card:hover,
html[data-theme="dark"] .related-card:hover {
    box-shadow:
        0 2px 4px   rgba(0, 0, 0, 0.34),
        0 14px 34px rgba(0, 0, 0, 0.46) !important;
}

/* A photo should meet the card edge, not a border inside a border. */
html .coriolis-card img, html .team-card img, html .team-full-card img,
html .blog-card img {
    border: 0 !important;
    border-radius: 0 !important;
}

/* ── GLASS ─────────────────────────────────────────────────── */
html .search-form, html .error-search {
    background: rgba(255, 255, 253, 0.55) !important;
    -webkit-backdrop-filter: blur(22px) saturate(170%);
    backdrop-filter:         blur(22px) saturate(170%);
    border: 1px solid rgba(255, 255, 255, 0.75) !important;
    border-radius: 999px !important;
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.9),
        0 2px 6px   rgba(28, 28, 28, 0.06),
        0 12px 30px rgba(28, 28, 28, 0.10) !important;
}
html[data-theme="dark"] .search-form,
html[data-theme="dark"] .error-search {
    background: rgba(35, 51, 44, 0.55) !important;
    border: 1px solid rgba(237, 242, 240, 0.14) !important;
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.14),
        0 2px 6px   rgba(0, 0, 0, 0.34),
        0 12px 30px rgba(0, 0, 0, 0.40) !important;
}

/* Content sits above the sweep. */
html .glass > *, html .service-card > *, html .practice-card > *,
html .sidebar-card > *, html .related-card > *, html .error-link-card > *,
html .team-card > *, html .team-full-card > *, html .testimonial-card > *,
html .contact-item > *, html .form > *, html .about-glass-card > *,
html .reason > *, html .stat > *, html .prac-box > *,
html .post-disclaimer > *, html .coriolis-card > *,
html .blog-card > .blog-card-link {
    position: relative;
    z-index: 1;
}

/* Text over glass has a busier backdrop than text over white, so
   the body colour is pushed to full strength rather than the muted
   grey the flat design used. */
html .service-card p, html .practice-card p, html .blog-card p,
html .team-card p, html .reason p, html .stat-label {
    color: var(--lg-text);
}


/* ════════════════════════════════════════════════════════════
   3 · MOTION
   transform and box-shadow only — both composited, so a hover
   never triggers layout or paint.

   The `transition` shorthand below is !important because
   enhancements.css marks its own transition important. That means
   it also replaces the page-level transitions, so `opacity` has to
   be listed here or the IntersectionObserver reveal on the blog
   grid would snap in with no fade at all.
   ════════════════════════════════════════════════════════════ */
html .service-card, html .practice-card, html .blog-card,
html .related-card, html .error-link-card, html .team-card,
html .team-full-card, html .reason, html .stat,
html .coriolis-card, html .post-nav-link {
    transition:
        opacity      .55s ease,
        transform    .42s cubic-bezier(0.22, 1, 0.36, 1),
        box-shadow   .42s cubic-bezier(0.22, 1, 0.36, 1),
        border-color .42s ease,
        background   .42s ease !important;
}

html .service-card:hover, html .practice-card:hover, html .blog-card:hover,
html .related-card:hover, html .error-link-card:hover, html .team-card:hover,
html .team-full-card:hover, html .reason:hover, html .coriolis-card:hover,
html .post-nav-link:hover {
    background: var(--lg-tint-hover) !important;
    border-color: rgba(15, 122, 87, 0.42) !important;
    box-shadow:
        inset 0 0 0 1px rgba(255, 255, 255, 0.42),
        inset 0 2px 1px -1px var(--lg-rim),
        var(--lg-shadow-lift) !important;
}
/* Kept separate from the block above: .blog-card carries the reveal
   transform, so lifting it must not fight the entrance animation. */
html .service-card:hover, html .practice-card:hover,
html .related-card:hover, html .error-link-card:hover,
html .team-card:hover, html .team-full-card:hover,
html .reason:hover, html .coriolis-card:hover {
    transform: translateY(-7px) !important;
}
html .blog-card.card-visible:hover,
html .blog-card.in-view:hover {
    transform: translateY(-9px) !important;
}


/* ════════════════════════════════════════════════════════════
   4 · NAVBAR
   The surface where glass earns its keep, because content visibly
   slides underneath it.

   THE BLUR IS ON A PSEUDO-ELEMENT, NOT ON .navbar ITSELF
   An element carrying `backdrop-filter` becomes a *backdrop root*:
   any descendant that also asks for a backdrop-filter can only
   sample what is painted inside that root, which for a navbar is
   nothing. The mobile dropdown menu is a descendant of .navbar and
   hangs BELOW it, over the page — so with the blur on .navbar the
   menu could never blur the page behind it. It would either be
   opaque or be a clear sheet with the article text legible through
   the nav labels.

   Moving the blur to `.navbar::before` — which covers exactly the
   bar and nothing else — leaves .navbar itself filter-free, so the
   dropdown gets its own working backdrop root. Same look, and the
   menu becomes real glass.
   ════════════════════════════════════════════════════════════ */
html .navbar {
    background: transparent !important;
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
    border: none !important;
    border-radius: 0 !important;
    box-shadow: 0 6px 32px rgba(11, 61, 46, 0.14) !important;
    /* styles.css already asks for `position: sticky; top: 0`, but
       enhancements.css later declares `.navbar { position: relative }`
       — one line, no !important, and the header stopped sticking. An
       earlier version of this file repeated the same mistake. A glass
       bar that scrolls away is pointless: the whole reason for the
       blur is content passing underneath it. */
    position: sticky !important;
    top: 0 !important;
    z-index: 1000 !important;
}
html[data-theme="dark"] .navbar {
    box-shadow: 0 6px 32px rgba(0, 0, 0, 0.55) !important;
}

html .navbar::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background: var(--lg-tint-strong);
    -webkit-backdrop-filter: blur(var(--glass-blur-nav)) saturate(var(--glass-saturate)) brightness(var(--glass-bright));
    backdrop-filter:         blur(var(--glass-blur-nav)) saturate(var(--glass-saturate)) brightness(var(--glass-bright));
    box-shadow:
        inset 0 -1px 0 0 var(--lg-edge-low),
        inset 0 1px 0 0 var(--lg-rim);
}
/* The bar's content has to sit above its own glass. */
html .navbar > * { position: relative; z-index: 1; }

/* Sticky filter bar on the blog gets the same treatment. */
html .filter-bar-wrap, html .blog-breadcrumb, html .post-breadcrumb {
    background: var(--lg-tint-soft) !important;
    -webkit-backdrop-filter: blur(24px) saturate(180%);
    backdrop-filter:         blur(24px) saturate(180%);
    border-radius: 0 !important;
    border-left: none !important;
    border-right: none !important;
    border-top: none !important;
}


/* ════════════════════════════════════════════════════════════
   5 · CONTROLS
   Pills, chips and buttons. iOS treats these as the same material
   as the panes, only smaller and rounder.
   ════════════════════════════════════════════════════════════ */
html .search-form, html .error-search {
    border-radius: var(--lg-radius-pill) !important;
    background: var(--lg-tint-strong) !important;
}

/* Only controls that sit on the page background get their own blur.
   Inline labels — category tags, count pills, expertise chips — sit
   INSIDE a pane that is already blurring. Nesting a second
   backdrop-filter there samples the parent's backdrop root instead
   of the page, which washes the label out and costs a compositing
   pass per tag. They keep their own flat colours. */
html .filter-chip, html .page-link, html .post-share a,
html .theme-toggle {
    -webkit-backdrop-filter: blur(18px) saturate(180%);
    backdrop-filter:         blur(18px) saturate(180%);
}

/* `.sidebar-btn` is deliberately absent from these lists. It is
   `btn btn-primary sidebar-btn` — a solid emerald button with white
   text. Giving it the pale tint overwrote the fill but not the
   label, so "Meet the team" and "Get in touch" turned white-on-white.
   It keeps its own colour and gets the bevel from .btn-primary. */
html .filter-chip:not(.active),
html .page-link:not(.current),
html .post-share a,
html .theme-toggle {
    background: var(--lg-tint) !important;
    border: 1px solid var(--lg-edge) !important;
    border-radius: var(--lg-radius-pill) !important;
    box-shadow:
        inset 0 1px 0 0 var(--lg-rim),
        0 2px 10px rgba(11, 61, 46, 0.10) !important;
}

/* Hover has to be restated here, and this is the bug behind
   "some buttons are not showing colours".

   `.page-link:hover` and `.post-share a:hover` fill with solid
   emerald and switch their label to white. Those rules are (0,2,0)
   and carry no !important, so the base rule above — (0,2,1) AND
   !important — kept its pale tint while the text still went white.
   White on near-white: the button appeared to vanish on hover.

   The fix is to own the hover rather than half-override it. */
html .page-link:not(.current):hover,
html .post-share a:hover {
    background: linear-gradient(135deg,
        rgba(18, 147, 106, 0.96), rgba(10, 82, 48, 0.96)) !important;
    border-color: rgba(10, 82, 48, 0.65) !important;
    color: #ffffff !important;
    transform: translateY(-2px);
    box-shadow:
        inset 0 1px 0 0 rgba(255, 255, 255, 0.30),
        0 8px 20px rgba(15, 122, 87, 0.34) !important;
}

/* Chips and the theme toggle brighten rather than fill — their own
   hover was always a light wash with dark text, and turning them
   emerald would make an unselected chip look selected. */
html .filter-chip:not(.active):hover,
html .theme-toggle:hover {
    background: var(--lg-tint-hover) !important;
    border-color: rgba(15, 122, 87, 0.40) !important;
    transform: translateY(-2px);
    box-shadow:
        inset 0 1px 0 0 rgba(255, 255, 255, 0.60),
        0 6px 18px rgba(11, 61, 46, 0.18) !important;
}

/* Tinted glass rather than a flat fill — the emerald reads through
   with a bevel on top. */
html .btn, html .btn-primary {
    border-radius: var(--lg-radius-pill) !important;
    position: relative;
    overflow: hidden;
}
html .btn-primary {
    box-shadow:
        inset 0 1px 0 0 rgba(255, 255, 255, 0.45),
        inset 0 -1px 0 0 rgba(0, 0, 0, 0.18),
        0 6px 22px rgba(15, 122, 87, 0.36),
        0 14px 40px rgba(15, 122, 87, 0.20) !important;
}
html .btn-primary::after {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: linear-gradient(
        155deg,
        rgba(255, 255, 255, 0.45) 0%,
        rgba(255, 255, 255, 0.12) 40%,
        rgba(255, 255, 255, 0.00) 66%);
}
html .btn-primary > * { position: relative; z-index: 1; }

/* Form fields as recessed glass — light comes from above, so the
   highlight goes on the bottom edge and the shadow on the top. */
html .form input, html .form select, html .form textarea,
html .form-group input, html .form-group select, html .form-group textarea,
html .search-input, html .error-search input {
    background: var(--lg-tint-soft) !important;
    -webkit-backdrop-filter: blur(16px) saturate(160%);
    backdrop-filter:         blur(16px) saturate(160%);
    border: 1px solid var(--lg-edge) !important;
    border-radius: 16px !important;
    box-shadow:
        inset 0 2px 4px rgba(11, 61, 46, 0.08),
        inset 0 -1px 0 0 rgba(255, 255, 255, 0.55) !important;
}
html .search-input { border: none !important; box-shadow: none !important; background: transparent !important; }
html[data-theme="dark"] .form input,
html[data-theme="dark"] .form select,
html[data-theme="dark"] .form textarea,
html[data-theme="dark"] .form-group input,
html[data-theme="dark"] .form-group select,
html[data-theme="dark"] .form-group textarea {
    box-shadow:
        inset 0 2px 4px rgba(0, 0, 0, 0.38),
        inset 0 -1px 0 0 rgba(255, 255, 255, 0.06) !important;
}


/* The wordmark had no dark-mode colour of its own: styles.css sets
   `.firm-name { color: var(--primary-color) }` and the dark theme
   keeps --primary-color at #0b3d2e. Very dark green on a very dark
   bar — the firm's own name was the least readable text on the
   page. */
html[data-theme="dark"] .firm-name {
    color: var(--light-text) !important;
}


/* ════════════════════════════════════════════════════════════
   5b · ICON TILES
   enhancements.css gives the practice and service icons a 56/64px
   tile filled with 15%-gold on white and shrinks the glyph to
   1.5rem. Against the old white page that read as a soft badge;
   against the emerald wallpaper it reads as a washed cream blob
   with a stamp-sized emoji in it.

   Rebuilt as the same material as everything else — an emerald
   glass square with a bright rim — and the glyph goes back up to a
   size you can actually see. The `!important` on font-size is not
   optional: enhancements.css marks its own important.
   ════════════════════════════════════════════════════════════ */
html .practice-icon, html .service-icon {
    background: linear-gradient(140deg,
        rgba(255, 255, 255, 0.70) 0%,
        rgba(18, 147, 106, 0.36) 52%,
        rgba(201, 162, 39, 0.30) 100%) !important;
    border: 1px solid rgba(255, 255, 255, 0.78) !important;
    box-shadow:
        inset 0 1.5px 0 0 rgba(255, 255, 255, 0.95),
        inset 0 -1px 0 0 rgba(11, 61, 46, 0.10),
        0 6px 18px rgba(11, 61, 46, 0.16) !important;
    -webkit-backdrop-filter: blur(14px) saturate(180%);
    backdrop-filter:         blur(14px) saturate(180%);
}
html .practice-icon {
    width: 62px !important;
    height: 62px !important;
    border-radius: 18px !important;
    font-size: 2rem !important;
}
html .service-icon {
    width: 70px !important;
    height: 70px !important;
    border-radius: 20px !important;
    font-size: 2.3rem !important;
}
/* The glyph is an emoji, so it paints in its own colours — a
   drop-shadow separates it from the tile instead of a text colour. */
html .practice-icon, html .service-icon {
    filter: drop-shadow(0 2px 5px rgba(11, 61, 46, 0.22));
    line-height: 1;
}
html .practice-card:hover .practice-icon,
html .service-card:hover .service-icon {
    box-shadow:
        inset 0 1.5px 0 0 rgba(255, 255, 255, 0.95),
        0 10px 26px rgba(15, 122, 87, 0.30) !important;
}

html[data-theme="dark"] .practice-icon,
html[data-theme="dark"] .service-icon {
    background: linear-gradient(140deg,
        rgba(255, 255, 255, 0.14) 0%,
        rgba(18, 147, 106, 0.28) 55%,
        rgba(201, 162, 39, 0.18) 100%) !important;
    border-color: rgba(255, 255, 255, 0.18) !important;
    box-shadow:
        inset 0 1px 0 0 rgba(255, 255, 255, 0.24),
        0 6px 18px rgba(0, 0, 0, 0.42) !important;
}

/* The related-posts strip on an article uses a flat wash behind its
   emoji; match it to the tiles so the page reads as one system. */
html .related-icon {
    background: linear-gradient(140deg,
        rgba(255, 255, 255, 0.42) 0%,
        rgba(18, 147, 106, 0.22) 60%,
        rgba(201, 162, 39, 0.16) 100%) !important;
}


/* ════════════════════════════════════════════════════════════
   6 · FOOTER
   Dark glass over the wallpaper rather than a solid slab, so the
   colour keeps running to the bottom of the page.
   ════════════════════════════════════════════════════════════ */
html .footer {
    background: linear-gradient(180deg,
        rgba(7, 39, 29, 0.82) 0%,
        rgba(6, 32, 26, 0.90) 100%) !important;
    -webkit-backdrop-filter: blur(28px) saturate(180%);
    backdrop-filter:         blur(28px) saturate(180%);
    box-shadow: inset 0 1px 0 0 rgba(255, 255, 255, 0.12) !important;
}


/* ════════════════════════════════════════════════════════════
   7 · CATEGORY TILES
   Most posts have no featured image, and an empty strip reads as a
   failed upload. Each category gets a generated tile instead: its
   initials over a hue derived from the category name (see
   blog_category_art() in includes/seo.php).

   The numerals use `background-clip: text` with a translucent white
   gradient, so the colour behind shows through the letterforms —
   the same trick the iOS lock screen uses for its clock.

   Selector weight note: blog.php declares
   `.blog-image:not(:has(img))`, which is (0,1,1). `html
   .blog-image.blog-image-art` is (0,2,1) and wins regardless of
   source order.
   ════════════════════════════════════════════════════════════ */
/* styles.css gives .blog-card `padding: 25px 20px` below 768px, which
   inset the artwork strip from the card edge and left it floating in
   the middle of a white margin on every phone. The card's own body
   supplies the padding it needs. */
html .blog-card { padding: 0 !important; }

html .blog-image.blog-image-art,
html[data-theme="dark"] .blog-image.blog-image-art {
    background: transparent !important;
    padding: 0;
}
html .blog-image.blog-image-art::before { display: none; }

html .cat-art {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 10px;
    width: 100%;
    height: 100%;
    min-height: 150px;
    overflow: hidden;
    isolation: isolate;
    /* Two stops of the same hue, 34deg apart, so the tile has a
       direction to it instead of reading as a flat swatch. */
    background:
        linear-gradient(152deg,
            hsl(var(--cat-h, 152) 64% 56%) 0%,
            hsl(calc(var(--cat-h, 152) + 34) 58% 38%) 100%);
}

/* A soft off-centre bloom, so no two corners are the same value. */
html .cat-art-glow {
    position: absolute;
    inset: -30%;
    z-index: 0;
    pointer-events: none;
    background:
        radial-gradient(42% 46% at 22% 18%, rgba(255, 255, 255, 0.42), transparent 62%),
        radial-gradient(46% 42% at 84% 74%, hsl(calc(var(--cat-h, 152) + 62) 84% 62% / 0.45), transparent 66%),
        radial-gradient(36% 40% at 74% 12%, rgba(255, 255, 255, 0.20), transparent 60%);
    transition: transform .7s cubic-bezier(0.22, 1, 0.36, 1);
}
/* The specular sweep, matching the panes. */
html .cat-art::after {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    background: linear-gradient(146deg,
        rgba(255, 255, 255, 0.34) 0%,
        rgba(255, 255, 255, 0.06) 30%,
        rgba(255, 255, 255, 0.00) 56%,
        rgba(0, 0, 0, 0.10) 100%);
}

html .cat-art-mono {
    position: relative;
    z-index: 2;
    font-family: 'Cormorant Garamond', 'Lora', Georgia, serif;
    font-size: clamp(2.9rem, 8vw, 3.9rem);
    font-weight: 700;
    line-height: 1;
    letter-spacing: .02em;
    /* Translucent fill clipped to the glyphs, so the tile's own
       colour comes through the letters. */
    background: linear-gradient(168deg,
        rgba(255, 255, 255, 0.98) 0%,
        rgba(255, 255, 255, 0.72) 46%,
        rgba(255, 255, 255, 0.92) 100%);
    -webkit-background-clip: text;
    background-clip: text;
    color: transparent;
    -webkit-text-fill-color: transparent;
    filter: drop-shadow(0 3px 14px rgba(0, 0, 0, 0.34));
    transition: transform .5s cubic-bezier(0.22, 1, 0.36, 1);
}

html .cat-art-name {
    position: relative;
    z-index: 2;
    max-width: 86%;
    text-align: center;
    font-size: .6rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .2em;
    text-indent: .2em;
    /* These tiles are generated per category, so the ground under the
       label can be anything the hue map produces — the amber ones put
       white at 3.1:1. Rather than pick a text colour per hue, the label
       carries its own dark plate: white is then safe on every tile,
       including whichever colour gets added next.

       A scrim on the tile itself was the first attempt and was worse —
       .cat-art::after is already the specular sweep, so it both
       clobbered that and inherited its `inset: 0`, stretching the
       gradient over the whole tile instead of the bottom edge. */
    color: #FFFFFF;
    background: rgba(0, 0, 0, 0.46);
    padding: 3px 9px;
    border-radius: 999px;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5);
    text-shadow: 0 1px 6px rgba(0, 0, 0, 0.32);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* If the post also carries an emoji icon, it rides in the corner
   rather than competing with the monogram for the centre. */
html .cat-art-emoji {
    position: absolute;
    top: 12px; right: 14px;
    z-index: 3;
    font-size: 1.3rem;
    line-height: 1;
    filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.35));
}

html .blog-card:hover .cat-art-mono { transform: scale(1.07); }
html .blog-card:hover .cat-art-glow { transform: translate3d(3%, -3%, 0) scale(1.1); }

/* The related-posts strip is shorter than a blog card. */
html .cat-art-sm { min-height: 116px; gap: 6px; }
html .cat-art-sm .cat-art-mono { font-size: 2.2rem; }
html .cat-art-sm .cat-art-name { font-size: .54rem; letter-spacing: .16em; }

html[data-theme="dark"] .cat-art {
    background: linear-gradient(152deg,
        hsl(var(--cat-h, 152) 56% 42%) 0%,
        hsl(calc(var(--cat-h, 152) + 34) 52% 24%) 100%);
}


/* ════════════════════════════════════════════════════════════
   7a · THE BLOG GRID
   blog.php sets `align-items: start` on the grid with the comment
   "each card takes its own natural height" — a deliberate masonry
   look. It reads as ragged rather than staggered, because the cards
   are all the same width and sit on a shared baseline at the top:
   the eye expects a row, and gets three boxes stopping at three
   different heights.

   `stretch` alone would only equalise each row. `grid-auto-rows: 1fr`
   equalises every row in the grid, so every card on the page is the
   same size. Nothing is clipped to achieve it — .blog-excerpt is
   already `flex: 1`, so the extra height goes into the gap above the
   footer and the footer stays pinned to the bottom.
   ════════════════════════════════════════════════════════════ */
html #masonryGrid {
    align-items: stretch !important;
}
html #masonryGrid > .blog-card { height: 100%; }

/* Equal rows are only worth having when there IS a row. Below 600px
   the grid is a single column, and forcing every card to the height
   of the tallest one just adds dead space to scroll past. */
@media (min-width: 601px) {
    html #masonryGrid { grid-auto-rows: 1fr; }
}

/* blog.php gives .blog-excerpt `flex: 1` so the footer is pushed to
   the bottom. That works when the card is its natural height. Once
   the card is stretched, the excerpt box grows past its own 3-line
   clamp — and `overflow: hidden` then cuts the fourth line through
   the middle of the letters instead of hiding it.

   The footer claims the slack with `margin-top: auto` instead, and
   the excerpt keeps the height its clamp gives it. */
html .blog-excerpt,
html .blog-excerpt.pretext-done {
    flex: 0 1 auto !important;
}
html .blog-card-footer { margin-top: auto; }


/* ════════════════════════════════════════════════════════════
   7b · THE ARTICLE PAGE
   `.blog-post-content` had no styling of its own at all — the
   article text sat directly on the page. On a plain white page
   that passed; on a colour wallpaper it does not, so the article
   becomes a pane like everything else. Long-form reading needs
   more tint than a card: text over a busy backdrop is where
   translucency stops being free.
   ════════════════════════════════════════════════════════════ */
html .blog-post-content {
    position: relative;
    background: rgba(255, 255, 255, 0.40) !important;
    -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate));
    backdrop-filter:         blur(var(--glass-blur)) saturate(var(--glass-saturate));
    border: 1px solid var(--lg-edge);
    border-radius: var(--lg-radius);
    box-shadow:
        inset 0 2px 1px -1px var(--lg-rim),
        var(--lg-shadow);
    padding: clamp(22px, 3.4vw, 46px);
}
html[data-theme="dark"] .blog-post-content {
    background: rgba(255, 255, 255, 0.10) !important;
}
html .post-featured-image,
html .post-featured-image img {
    border-radius: var(--lg-radius-sm);
    overflow: hidden;
}

@media (max-width: 768px) {
    html .blog-post-content { padding: 20px 16px; }
}


/* ════════════════════════════════════════════════════════════
   7c · THE CONTACT PAGE
   `.contact-info` and `.contact-form` are bare grid columns —
   no background, no padding, nothing. Treating them as panes put
   a border hard against the text and made the inner blocks look
   like they were bursting out of their container. The pane belongs
   one level down instead: each `.contact-item` is its own rounded
   tile, the way an iOS grouped list works, and the form is the
   pane on the other side.
   ════════════════════════════════════════════════════════════ */
html .contact-info, html .contact-form {
    background: transparent !important;
    border: none !important;
    box-shadow: none !important;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    padding: 0;
    overflow: visible;
}

html .contact-item {
    padding: 18px 22px !important;
    margin-bottom: 16px !important;
    border-radius: var(--lg-radius-sm) !important;
}
html .contact-item h4 { margin-bottom: 6px; }
html .contact-item:last-child { margin-bottom: 0 !important; }

html .form {
    padding: clamp(20px, 2.6vw, 32px) !important;
}


/* ════════════════════════════════════════════════════════════
   7d · THE DISCLAIMER MODAL
   Three separate faults met here.

   THE GREEN LINE DOWN THE RIGHT EDGE
   styles.css paints the modal's scrollbar thumb with
   `linear-gradient(180deg, #0f7a57, #12936a)` at 8px wide. The
   panel is capped at 85vh, so on a phone the text overflows by a
   little, the thumb fills almost the whole track, and an 8px
   emerald bar runs the full height hard against the rounded
   corner. It reads as a design element rather than a scrollbar.
   It is now a thin translucent overlay, inset from the edge.

   THE MURKY BROWN PANEL
   The backdrop is `rgba(0,0,0,0.8)` and I had put the panel in the
   generic material list at 34% white. 34% white over 80% black is
   mud, and the body text is #4a4238 — dark brown on dark grey.
   That is a contrast failure, not just an ugly one.

   The fix is both halves: the scrim lifts and blurs harder (so the
   page behind reads as soft colour rather than a blackout), and
   the panel goes to a genuinely light glass that dark text can sit
   on. More transparent AND more legible — the two are only in
   conflict when the thing behind is black.
   ════════════════════════════════════════════════════════════ */
html .disclaimer-modal {
    background: rgba(9, 38, 29, 0.30) !important;
    -webkit-backdrop-filter: blur(30px) saturate(170%) !important;
    backdrop-filter:         blur(30px) saturate(170%) !important;
}
html[data-theme="dark"] .disclaimer-modal {
    background: rgba(4, 14, 11, 0.62) !important;
}

html .disclaimer-modal-content {
    background: linear-gradient(150deg,
        rgba(255, 255, 255, 0.34) 0%,
        rgba(255, 255, 255, 0.22) 46%,
        rgba(232, 245, 239, 0.28) 100%) !important;
    -webkit-backdrop-filter: blur(26px) saturate(200%) brightness(1.14);
    backdrop-filter:         blur(26px) saturate(200%) brightness(1.14);
    border: 1px solid rgba(255, 255, 255, 0.34) !important;
    border-radius: var(--lg-radius) !important;
    box-shadow:
        inset 0 1.5px 0 0 rgba(255, 255, 255, 0.95),
        inset 0 -1px 0 0 rgba(11, 61, 46, 0.10),
        0 30px 90px rgba(0, 0, 0, 0.40) !important;
    padding: clamp(26px, 5vw, 42px) !important;
    /* Space for the scrollbar so it never touches the corner. */
    scrollbar-width: thin;
    scrollbar-color: rgba(11, 61, 46, 0.28) transparent;
}
html[data-theme="dark"] .disclaimer-modal-content {
    background: linear-gradient(150deg,
        rgba(255, 255, 255, 0.11) 0%,
        rgba(255, 255, 255, 0.06) 100%) !important;
    border-color: rgba(255, 255, 255, 0.18) !important;
    box-shadow:
        inset 0 1px 0 0 rgba(255, 255, 255, 0.22),
        0 30px 90px rgba(0, 0, 0, 0.62) !important;
    scrollbar-color: rgba(255, 255, 255, 0.26) transparent;
}

/* The emerald bar, replaced. `background-clip: padding-box` behind
   a transparent border is what insets the thumb from the edge —
   without it a narrow thumb still sits flush against the corner. */
html .disclaimer-modal-content::-webkit-scrollbar { width: 10px; }
html .disclaimer-modal-content::-webkit-scrollbar-track {
    background: transparent;
}
html .disclaimer-modal-content::-webkit-scrollbar-thumb {
    background: rgba(11, 61, 46, 0.26);
    border: 3px solid transparent;
    background-clip: padding-box;
    border-radius: 999px;
}
html .disclaimer-modal-content::-webkit-scrollbar-thumb:hover {
    background: rgba(11, 61, 46, 0.42);
    border: 3px solid transparent;
    background-clip: padding-box;
}
html[data-theme="dark"] .disclaimer-modal-content::-webkit-scrollbar-thumb {
    background: rgba(255, 255, 255, 0.24);
    border: 3px solid transparent;
    background-clip: padding-box;
}

/* The gold rule across the top was 4px of near-solid gold. On a
   glass panel that is the loudest thing on screen; 2px reads as a
   detail rather than a banner. */
html .disclaimer-modal-content::before {
    height: 2px !important;
    opacity: .85;
}

/* enhancements.css wraps the panel in a gold halo that pulses on a
   2.8s loop for as long as the modal is open. On a glass panel it
   reads as a warning glow. Kept as a static rim. */
html .disclaimer-modal-content::after {
    animation: none !important;
    opacity: 1 !important;
    inset: 0 !important;
    border-radius: inherit !important;
    box-shadow: none !important;
    padding: 1px;
    background: linear-gradient(138deg,
        rgba(255, 255, 255, 0.95) 0%,
        rgba(255, 255, 255, 0.40) 18%,
        rgba(255, 255, 255, 0.04) 46%,
        rgba(255, 255, 255, 0.00) 60%,
        rgba(255, 255, 255, 0.32) 84%,
        rgba(255, 255, 255, 0.75) 100%) !important;
    -webkit-mask:
        linear-gradient(#000 0 0) content-box,
        linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
    mask:
        linear-gradient(#000 0 0) content-box,
        linear-gradient(#000 0 0);
    mask-composite: exclude;
}
/* And the 56px grid it paints across the backdrop. */
html .disclaimer-modal::before { opacity: .45; }

/* Body copy at #4a4238 was the other half of the contrast problem. */
html .disclaimer-modal-content p { color: #2c3a33 !important; }
html[data-theme="dark"] .disclaimer-modal-content p { color: #cddbd3 !important; }

html .disclaimer-buttons { gap: 12px; }

html .btn-disclaimer-decline,
html .btn-disclaimer-accept {
    border-radius: var(--lg-radius-pill) !important;
    padding: 14px 30px !important;
    letter-spacing: .06em !important;
}

/* The decline button was a beige gradient left over from the old
   palette. As glass it stops competing with the accept button
   while staying clearly clickable. */
html .btn-disclaimer-decline {
    background: rgba(255, 255, 255, 0.42) !important;
    -webkit-backdrop-filter: blur(16px) saturate(170%);
    backdrop-filter:         blur(16px) saturate(170%);
    border: 1px solid rgba(11, 61, 46, 0.20) !important;
    color: #2c3a33 !important;
    box-shadow:
        inset 0 1px 0 0 rgba(255, 255, 255, 0.85),
        0 3px 12px rgba(11, 61, 46, 0.12) !important;
}
html .btn-disclaimer-decline:hover {
    background: rgba(255, 255, 255, 0.62) !important;
}
html[data-theme="dark"] .btn-disclaimer-decline {
    background: rgba(255, 255, 255, 0.10) !important;
    border-color: rgba(255, 255, 255, 0.20) !important;
    color: #e6efe9 !important;
    box-shadow: inset 0 1px 0 0 rgba(255, 255, 255, 0.16) !important;
}

html .btn-disclaimer-accept {
    border: 1px solid rgba(10, 82, 48, 0.55) !important;
    box-shadow:
        inset 0 1px 0 0 rgba(255, 255, 255, 0.35),
        0 8px 24px rgba(15, 122, 87, 0.38) !important;
}


/* ════════════════════════════════════════════════════════════
   7e · THE THEME SWITCH
   The new theme is revealed by a circle growing out of the toggle
   button. See the click handler in app.js for the geometry.

   The browser's default view transition is a crossfade of the two
   snapshots. A crossfade is exactly wrong here — mid-way through
   you get a washed-out average of light and dark, and the reveal
   edge disappears. So both default animations are switched off and
   the snapshots are stacked instead: old below, new above, and the
   new one is clipped to a growing circle.
   ════════════════════════════════════════════════════════════ */
/* The switch is a single disc moved by transform — no view
   transition, no snapshot layers. See the measurements in app.js for
   why. The pseudo-element rules that used to live here
   (::view-transition-old/new) are gone with the technique. */
.theme-disc {
    position: fixed;
    z-index: 2147483000;
    left: 0; top: 0;
    width: 200px;
    height: 200px;
    border-radius: 50%;
    pointer-events: none;
    transform: translate(-50%, -50%) scale(0.02);
    will-change: transform, opacity;
    /* backface-visibility keeps the layer on the compositor on the
       Android WebViews that still need the hint. */
    backface-visibility: hidden;
}

/* CLEAR WATER GLASS.
   The disc was a smoked pane at 0.90 alpha — it hid the page rather
   than showing it through. Clear glass shows you what is behind it;
   what makes it read as GLASS is not the fill but the edge, where
   the thickness bends light. So the fill drops to a wash and the
   work moves to the rim: a bright refracting edge, a band of the
   incoming theme's colour just inside it, and a specular highlight
   where the light lands.

   The fill still has to carry some weight. At the moment the disc
   covers the screen the theme changes behind it, and a fill of pure
   nothing would show that as a hard cut. Around 0.55 is the balance:
   the page is plainly legible through the disc as it passes, and the
   swap underneath reads as a dissolve rather than a jump.

   NOT backdrop-filter. A blur whose sampled area grows every frame
   re-evaluates over an area ending at full-screen — the one thing
   certain to stutter here. Translucency gives the same read for
   nothing.

   Every stop is a PERCENTAGE, so the rim keeps its proportion as the
   disc scales from 200px to full screen. A rim in pixels would grow
   from a hairline into a 60px band. */
/* The veil: a solid pane of the incoming theme's ground that fades
   up inside the disc over the last fifth of the sweep. See the note
   in app.js — clear glass cannot hide the swap, and this is what
   covers it without giving up the transparency everywhere else. */
.theme-veil {
    position: absolute;
    inset: 0;
    border-radius: 50%;
    opacity: 0;
    will-change: opacity;
}
.theme-disc[data-to="dark"] .theme-veil {
    background:
        radial-gradient(closest-side circle at 32% 28%, rgba(52, 196, 148, 0.30), transparent 66%),
        radial-gradient(closest-side circle at 74% 74%, rgba(34, 148, 166, 0.26), transparent 68%),
        #0c1613;
}
.theme-disc[data-to="light"] .theme-veil {
    background:
        radial-gradient(closest-side circle at 32% 28%, rgba(15, 122, 87, 0.20), transparent 66%),
        radial-gradient(closest-side circle at 74% 74%, rgba(201, 162, 39, 0.18), transparent 68%),
        #eef3ee;
}

.theme-disc::before,
.theme-disc::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: 50%;
    /* above the veil, so the rim still reads once it has frosted */
    z-index: 1;
}

/* The rim. Three stops inside one percent of the radius: a soft
   inner lift, a hard bright line, and a thin outer falloff — the
   look of a curved edge catching light, not a drawn border. */
.theme-disc::after {
    background:
        radial-gradient(closest-side circle,
            transparent 0 97.8%,
            rgba(255, 255, 255, 0.16) 98.4%,
            rgba(255, 255, 255, 0.55) 99.1%,
            rgba(255, 255, 255, 0.98) 99.6%,
            rgba(255, 255, 255, 0.42) 100%);
}

/* The specular: a highlight where the light lands, plus a faint
   counter-glow on the far side, which is what stops a translucent
   circle looking flat. */
.theme-disc::before {
    background:
        radial-gradient(closest-side circle at 30% 24%,
            rgba(255, 255, 255, 0.34), transparent 52%),
        radial-gradient(closest-side circle at 72% 78%,
            rgba(255, 255, 255, 0.12), transparent 46%);
}

.theme-disc[data-to="dark"] {
    background:
        /* colour gathering at the edge, the way it does in a lens */
        radial-gradient(closest-side circle,
            transparent 0 82%,
            rgba(34, 148, 166, 0.30) 94%,
            rgba(52, 196, 148, 0.44) 100%),
        radial-gradient(closest-side circle at 34% 30%, rgba(52, 196, 148, 0.20), transparent 66%),
        rgba(9, 22, 18, 0.55);
}
.theme-disc[data-to="light"] {
    background:
        radial-gradient(closest-side circle,
            transparent 0 82%,
            rgba(224, 194, 84, 0.26) 94%,
            rgba(255, 255, 255, 0.55) 100%),
        radial-gradient(closest-side circle at 34% 30%, rgba(63, 176, 137, 0.16), transparent 66%),
        rgba(242, 248, 243, 0.58);
}
.theme-disc[data-to="dark"]::before {
    background:
        radial-gradient(closest-side circle at 30% 24%,
            rgba(170, 255, 226, 0.24), transparent 52%),
        radial-gradient(closest-side circle at 72% 78%,
            rgba(120, 220, 255, 0.10), transparent 46%);
}

/* The button itself: a full turn and a pop. */
html .theme-toggle.is-switching {
    animation: theme-spin .72s cubic-bezier(0.34, 1.56, 0.64, 1);
}
@keyframes theme-spin {
    0%   { transform: rotate(0turn)   scale(1);    }
    45%  { transform: rotate(.5turn)  scale(1.18); }
    100% { transform: rotate(1turn)   scale(1);    }
}

@media (prefers-reduced-motion: reduce) {
    html .theme-toggle.is-switching { animation: none !important; }
    .theme-disc { display: none !important; }
}


/* ════════════════════════════════════════════════════════════
   8 · FALLBACKS AND OPT-OUTS
   ════════════════════════════════════════════════════════════ */

/* Without backdrop-filter these panes are simply see-through and
   the text over them fails contrast. That is an accessibility
   failure, not a cosmetic one — so fall back to solid surfaces. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    html .glass, html .navbar, html .search-form, html .filter-bar-wrap,
    html .service-card, html .practice-card, html .blog-card,
    html .sidebar-card, html .related-card, html .error-link-card,
    html .team-card, html .team-full-card, html .testimonial-card,
    html .contact-item, html .form, html .reason, html .stat,
    html .filter-chip:not(.active), html .page-link:not(.current),
    html .theme-toggle {
        background: var(--white-bg) !important;
    }
    html[data-theme="dark"] .glass, html[data-theme="dark"] .navbar,
    html[data-theme="dark"] .search-form, html[data-theme="dark"] .filter-bar-wrap,
    html[data-theme="dark"] .service-card, html[data-theme="dark"] .practice-card,
    html[data-theme="dark"] .blog-card, html[data-theme="dark"] .sidebar-card,
    html[data-theme="dark"] .related-card, html[data-theme="dark"] .error-link-card,
    html[data-theme="dark"] .team-card, html[data-theme="dark"] .team-full-card,
    html[data-theme="dark"] .testimonial-card, html[data-theme="dark"] .contact-item,
    html[data-theme="dark"] .form, html[data-theme="dark"] .reason,
    html[data-theme="dark"] .stat, html[data-theme="dark"] .theme-toggle {
        background: var(--card-bg) !important;
    }
    html body::before, html .navbar::before { display: none; }
}

/* macOS, Windows and iOS all expose a "reduce transparency"
   setting. Some readers genuinely cannot parse text over a busy
   backdrop. */
@media (prefers-reduced-transparency: reduce) {
    html .glass, html .navbar, html .search-form, html .filter-bar-wrap,
    html .service-card, html .practice-card, html .blog-card,
    html .sidebar-card, html .related-card, html .error-link-card,
    html .team-card, html .team-full-card, html .testimonial-card,
    html .contact-item, html .form, html .reason, html .stat,
    html .filter-chip:not(.active), html .page-link:not(.current),
    html .theme-toggle, html .form input, html .form select,
    html .form textarea {
        background: var(--white-bg) !important;
        -webkit-backdrop-filter: none !important;
        backdrop-filter: none !important;
    }
    html[data-theme="dark"] .glass, html[data-theme="dark"] .navbar,
    html[data-theme="dark"] .search-form, html[data-theme="dark"] .filter-bar-wrap,
    html[data-theme="dark"] .service-card, html[data-theme="dark"] .practice-card,
    html[data-theme="dark"] .blog-card, html[data-theme="dark"] .sidebar-card,
    html[data-theme="dark"] .related-card, html[data-theme="dark"] .error-link-card,
    html[data-theme="dark"] .team-card, html[data-theme="dark"] .team-full-card,
    html[data-theme="dark"] .testimonial-card, html[data-theme="dark"] .contact-item,
    html[data-theme="dark"] .form, html[data-theme="dark"] .reason,
    html[data-theme="dark"] .stat, html[data-theme="dark"] .theme-toggle,
    html[data-theme="dark"] .form input, html[data-theme="dark"] .form select,
    html[data-theme="dark"] .form textarea {
        background: var(--card-bg) !important;
    }
    html body::before, html .navbar::before,
    html .glass::before, html .service-card::before, html .practice-card::before,
    html .blog-card::before, html .sidebar-card::before, html .related-card::before,
    html .error-link-card::before, html .team-card::before,
    html .contact-item::before, html .form::before,
    html .btn-primary::after {
        display: none !important;
    }
    /* The tiles stay — they are the card's only artwork, and they
       are opaque, so transparency is not the issue here. */
}

/* A reduced-motion request is an accessibility need — for some
   people motion triggers nausea or migraine. !important is
   warranted: the reveal animations live in page-level <style>
   blocks that come after this file, so nothing weaker would win. */
@media (prefers-reduced-motion: reduce) {
    html .service-card, html .practice-card, html .blog-card,
    html .related-card, html .error-link-card, html .team-card,
    html .team-full-card, html .reason, html .stat, html .coriolis-card,
    html .service-card.reveal, html .practice-card.reveal,
    html .blog-card.reveal, html .related-card.reveal, html .team-card.reveal,
    html .reveal, html .reveal-left, html .reveal-right,
    html .blog-card.pre-view, html .blog-card.in-view,
    html .cat-art-mono, html .cat-art-glow, html .services-grid > * {
        transition: none !important;
        animation:  none !important;
    }
    html .service-card:hover, html .practice-card:hover, html .blog-card:hover,
    html .related-card:hover, html .error-link-card:hover, html .team-card:hover,
    html .team-full-card:hover, html .reason:hover, html .coriolis-card:hover,
    html .blog-card.card-visible:hover, html .blog-card.in-view:hover {
        transform: none !important;
    }
    /* Reveal elements start at opacity 0. With the transition
       removed they must be shown outright, or a reader who never
       triggers the observer sees nothing at all. */
    html .reveal, html .reveal-left, html .reveal-right,
    html .blog-card.pre-view, html .blog-card {
        opacity: 1 !important;
        transform: none !important;
    }
}

@media print {
    html body::before, html .navbar::before { display: none; }
    html .glass, html .navbar, html .service-card, html .practice-card,
    html .blog-card, html .sidebar-card, html .related-card,
    html .team-card, html .form {
        background: #fff !important;
        -webkit-backdrop-filter: none !important;
        backdrop-filter: none !important;
        box-shadow: none !important;
    }
}


/* ════════════════════════════════════════════════════════════
   9 · MOBILE
   An earlier version cut blur to 8px here, which — combined with a
   near-white tint on a near-white page — is exactly why nothing
   was visible on a phone. Blur stays high now; the saving comes
   from the wallpaper being a static layer that never repaints and
   from `background-attachment: scroll` above.
   ════════════════════════════════════════════════════════════ */
@media (max-width: 768px) {
    :root {
        --glass-blur:     26px;
        --glass-blur-nav: 24px;
        --lg-radius:      24px 21px 22px 21px / 21px 24px 21px 22px;
        --lg-radius-sm:   17px 15px 16px 15px / 15px 17px 15px 16px;
    }
    html .filter-chip, html .page-link, html .post-share a,
    html .theme-toggle {
        -webkit-backdrop-filter: blur(16px) saturate(180%);
        backdrop-filter:         blur(16px) saturate(180%);
    }

    /* ── THE MOBILE NAVIGATION PANEL ──────────────────────────
       enhancements.css declares `backdrop-filter: blur(20px)` on
       the dropdown and then sets `background: #ffffff !important`
       on the very next line. A fully opaque background makes the
       blur behind it literally invisible — there is nothing left to
       see through. That is why this one panel stayed flat white
       while the rest of the site went to glass.

       Borders and shadow are on `.active` only. The closed menu is
       `max-height: 0; overflow: hidden`, but neither borders nor
       box-shadow are clipped by overflow — on a zero-height box
       they still paint, as a stray line and a smudge across the
       page directly under the header.
       ───────────────────────────────────────────────────────── */
    /* CLOSED, the menu must vanish completely.
       `max-height: 0; overflow: hidden` collapses the CONTENT box,
       but enhancements.css also gives it `padding: 4px 0` — so the
       element is still 8px tall, and once it carries a translucent
       background and a blur that shows up as a mystery band running
       the full width right under the header. */
    html .nav-menu:not(.active) {
        padding: 0 !important;
        background: transparent !important;
        -webkit-backdrop-filter: none !important;
        backdrop-filter: none !important;
        border: none !important;
        box-shadow: none !important;
    }

    html .nav-menu {
        background: rgba(255, 255, 255, 0.30) !important;
        -webkit-backdrop-filter: blur(30px) saturate(200%) brightness(1.05) !important;
        backdrop-filter:         blur(30px) saturate(200%) brightness(1.05) !important;
        border-top: none !important;
        border-bottom: none !important;
        border-radius: 0 0 22px 22px;
        box-shadow: none !important;
    }
    html[data-theme="dark"] .nav-menu {
        background: rgba(255, 255, 255, 0.09) !important;
    }

    html .nav-menu.active {
        border-top: 1px solid rgba(255, 255, 255, 0.55) !important;
        box-shadow:
            inset 0 1px 0 0 rgba(255, 255, 255, 0.85),
            0 20px 46px rgba(11, 61, 46, 0.26) !important;
    }
    html[data-theme="dark"] .nav-menu.active {
        border-top-color: rgba(255, 255, 255, 0.16) !important;
        box-shadow:
            inset 0 1px 0 0 rgba(255, 255, 255, 0.16),
            0 20px 46px rgba(0, 0, 0, 0.60) !important;
    }

    /* Hairlines between items, light enough to read as glass
       rather than as table rules. */
    html .nav-menu li {
        border-bottom: 1px solid rgba(11, 61, 46, 0.10) !important;
    }
    html[data-theme="dark"] .nav-menu li {
        border-bottom-color: rgba(255, 255, 255, 0.08) !important;
    }
    html .nav-menu a:hover,
    html .nav-menu a:focus,
    html .nav-menu a.active {
        background: linear-gradient(90deg,
            rgba(255, 255, 255, 0.55), rgba(255, 255, 255, 0.00)) !important;
    }
    html[data-theme="dark"] .nav-menu a:hover,
    html[data-theme="dark"] .nav-menu a:focus,
    html[data-theme="dark"] .nav-menu a.active {
        background: linear-gradient(90deg,
            rgba(255, 255, 255, 0.12), rgba(255, 255, 255, 0.00)) !important;
    }

    /* The hamburger, to match the rest of the controls. */
    html .menu-toggle {
        background: var(--lg-tint) !important;
        -webkit-backdrop-filter: blur(16px) saturate(180%);
        backdrop-filter:         blur(16px) saturate(180%);
        border: 1px solid var(--lg-edge) !important;
        border-radius: 12px;
        box-shadow: inset 0 1px 0 0 var(--lg-rim) !important;
    }
    html .menu-toggle[aria-expanded="true"] {
        background: var(--lg-tint-hover) !important;
        border-color: rgba(15, 122, 87, 0.45) !important;
    }

    /* The header itself: a touch more tint on a phone, where the
       content sliding underneath is denser and the bar is thinner.
       On the pseudo-element, since that is where the glass lives. */
    html .navbar::before {
        background: rgba(255, 255, 255, 0.26);
    }
    html[data-theme="dark"] .navbar::before {
        background: rgba(255, 255, 255, 0.10);
    }
    /* Pull the colour pools tighter so they still read on a narrow
       viewport instead of washing into one flat tone. */
    /* A phone shows one narrow column, so pools that read as
       separate areas on a laptop overlap into a single muddle here —
       and the gold, which is an accent at desktop width, became half
       the screen. Same six brand colours, rearranged: emerald runs
       top-to-bottom as the spine, gold is one small pool in a corner,
       and a mint band sits behind the middle of the column where the
       cards actually are. */
    html body::before {
        background-image:
            radial-gradient(96vw 46vw at  -14%  -6%, rgba(15, 122, 87, 0.52), transparent 66%),
            radial-gradient(44vw 26vw at  108%   4%, rgba(201, 162, 39, 0.42), transparent 62%),
            radial-gradient(88vw 40vw at  112%  30%, rgba(18, 147, 106, 0.38), transparent 68%),
            radial-gradient(96vw 44vw at   50%  52%, rgba(63, 176, 137, 0.34), transparent 70%),
            radial-gradient(52vw 30vw at   -8%  74%, rgba(224, 194, 84, 0.26), transparent 66%),
            radial-gradient(104vw 52vw at  46% 106%, rgba(11, 61, 46, 0.48),  transparent 70%);
    }
    html[data-theme="dark"] body::before {
        background-image:
            radial-gradient(96vw 46vw at  -14%  -6%, rgba(52, 196, 148, 0.52), transparent 66%),
            radial-gradient(40vw 24vw at  108%   4%, rgba(224, 194, 84, 0.28), transparent 62%),
            radial-gradient(88vw 42vw at  112%  32%, rgba(34, 148, 166, 0.42), transparent 68%),
            radial-gradient(96vw 44vw at   50%  54%, rgba(28, 122, 96, 0.54), transparent 70%),
            radial-gradient(52vw 30vw at   -8%  76%, rgba(90, 206, 164, 0.26), transparent 66%),
            radial-gradient(104vw 54vw at  46% 108%, rgba(6, 30, 24, 0.74),   transparent 72%);
    }
}
