/*
Theme Name: SpeechRight
Theme URI: https://www.speechright.co.uk/
Author: Floom Digital
Author URI: https://floomdigital.co.uk/
Description: Block theme for SpeechRight, an independent speech and language therapy practice in Nottingham. Full Site Editing, WCAG 2.2 AA, light/dark themes with device auto-detection. Built on the SpeechRight Design System tokens.
Version: 1.0.0
Requires at least: 6.5
Tested up to: 7.1
Requires PHP: 8.0
License: GNU General Public License v2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: speechright
Tags: full-site-editing, block-patterns, accessibility-ready, one-column, editor-style, block-styles, wide-blocks

SpeechRight WordPress theme, (C) 2026 Floom Digital
SpeechRight is distributed under the terms of the GNU GPL version 2 or later.

This theme bundles the following third-party resources:

Fredoka, Nunito Sans — assets/fonts/
  Copyright the Fredoka and Nunito Sans project authors
  SIL Open Font License 1.1, https://scripts.sil.org/OFL
  Source: https://fonts.google.com/

Lucide icons — inlined as CSS masks in assets/tokens/icons.css
  Copyright (c) 2022 Lucide Contributors
  ISC License, https://github.com/lucide-icons/lucide/blob/main/LICENSE

SpeechRight logo, wordmark and photography — assets/img/
  Copyright SpeechRight. All rights reserved. NOT covered by this theme's
  licence; they are the client's property and are bundled for their own site.
*/

/* ─────────────────────────────────────────────────────────────────────────────
   HOW THIS FILE IS ORGANISED

   The section numbering mirrors the SpeechRight design's own stylesheet, so a
   rule can be traced back to the design it came from. Where a rule differs, it
   is because WordPress emits different markup from the static preview — those
   places are commented.

    1. Document furniture            10. Lists, hours, checklists
    2. Section bands                 11. Accordion
    3. Utility bar                   12. Forms and contact
    4. Header                        13. Theme switch
    5. Buttons                       14. Address and clinic
    6. Cards, downloads, quotes      15. Footer
    7. Hero and home sections        16. Sticky mobile CTA
    8. About                         17. Prose and notes
    9. Images                        18. Icons
                                     19. Editor-only corrections

   Colour, type, spacing, radii, shadows and motion come from the design tokens
   in assets/tokens/, enqueued ahead of this file. Never hard-code a value —
   always use var(--*).
   ───────────────────────────────────────────────────────────────────────────── */


/* ═══════════════════════════════════════════════════════════════════════════
   1. DOCUMENT FURNITURE
   ═══════════════════════════════════════════════════════════════════════════ */

/* Skip link — the first tab stop on every page (WCAG 2.4.1). WordPress outputs
   this itself for block themes, so the theme styles core's rather than adding a
   second one: two skip links is two tab stops doing the same job. */
.skip-link.screen-reader-text:focus{position:fixed;left:0;top:0;z-index:200;
  width:auto;height:auto;clip:auto;clip-path:none;overflow:visible;
  padding:12px 20px;border-radius:0 0 var(--radius-md) 0;
  background:var(--action-primary);color:var(--text-on-brand);
  font:var(--weight-semibold) var(--text-base)/1 var(--font-display);
  text-decoration:none}

/* Anchor jumps use ONE mechanism. scroll-padding-top (on the scrollport) and
   scroll-margin-top (on the target) are additive, not alternatives — setting
   both doubles the offset. scroll-padding-top is the one to keep: it also
   covers focus-driven scrolling, which :target does not (WCAG 2.4.11).

   The value is measured, not guessed: this header's compressed height changes
   with the breakpoint and with whether the six nav items wrap, so any fixed
   number is wrong at some width. theme-toggle.js publishes the live height as
   --sr-header-h; the fallback covers the moment before the first measurement. */
html{scroll-padding-top:calc(var(--sr-header-h,88px) + var(--space-4))}
@media (prefers-reduced-motion:no-preference){html{scroll-behavior:smooth}}


/* ═══════════════════════════════════════════════════════════════════════════
   2. SECTION BANDS — the page's colour system

   WHY THESE ARE CONSTANTS, NOT RAMP STEPS. The design system's dark theme
   remaps the ramps: 50–200 become dark tints and 500–900 become light
   foregrounds. That is correct for components (a chip written green-50 /
   green-700 adapts for free) but it makes a raw step useless as a section
   background — a 50-step reads near-white in light and near-black in dark,
   which is exactly the "plain white or grey" problem. So section fields are
   declared here as constants with an explicit value per theme, the same pattern
   the design system uses for --band-ink-bg and --band-brand-bg.

   Two weights: TINT is unmistakably coloured but quiet enough for long copy and
   carries dark text; SOLID is a full brand field carrying light or ink text
   depending on the hue. Alternating them is what stops a heavily coloured page
   becoming garish, and means no two full-strength fields ever touch.
   Every pair was contrast-checked in both themes; the lowest is 5.2:1.
   ═══════════════════════════════════════════════════════════════════════════ */

:root{
--sr-tint-green:#DCEBC6;--sr-tint-green-edge:#C2DDA0;
--sr-tint-sky:#CDEFFB;--sr-tint-sky-edge:#A2E1F8;
--sr-tint-yellow:#FFF0B3;--sr-tint-yellow-edge:#FFE375;
--sr-on-tint:#2C2C2A;--sr-on-tint-heading:#111111;--sr-on-tint-muted:#4A4A47;
/* The green field carries WHITE copy, so it is green-600 #578026, not the logo
   green #6C9D30. This is the design system's most important rule: #6C9D30 with
   white measures 3.2:1 and fails AA for body copy, while #578026 measures 4.6:1
   and passes. #6C9D30 remains the brand colour everywhere it carries no white
   text — the logo, the tints, the icon chips. Like the deep field it is
   CONSTANT across themes: green does not darken for dark mode, only light and
   bright colours do.
   There is no muted variant. On #578026 nothing but pure white clears 4.5:1 —
   even green-50 only reaches 4.1:1 — which is the right answer anyway: muted
   text on a saturated background is what reads badly. */
--sr-solid-green:#578026;--sr-on-solid-green:#FFFFFF;--sr-on-solid-green-muted:#FFFFFF;
--sr-solid-sky:#3FBFEE;--sr-on-solid-sky:#0D2C39;--sr-on-solid-sky-muted:#173F4F;
--sr-solid-yellow:#FECE00;--sr-on-solid-yellow:#241D00;--sr-on-solid-yellow-muted:#3A2F00;
/* Deep green is likewise constant — green-700, which carries white at 6.3:1. */
--sr-solid-deep:#44631E;--sr-on-solid-deep:#FFFFFF;--sr-on-solid-deep-muted:#E6F0D6;
--sr-footer-bg:#2E4A16;
/* Cards that sit ON a coloured band. */
--sr-oncolour-card:#FFFFFF;--sr-oncolour-edge:rgba(17,17,17,.09);
--sr-oncolour-fg:#3B3B3A;--sr-oncolour-heading:#111111;
--radius-bubble-xl:64px 64px 64px 16px;
}
[data-theme="dark"]{
--sr-tint-green:#2A3F1B;--sr-tint-green-edge:#3E5A28;
--sr-tint-sky:#102F3D;--sr-tint-sky-edge:#1C5268;
--sr-tint-yellow:#332A0A;--sr-tint-yellow-edge:#514115;
--sr-on-tint:#DCDCD8;--sr-on-tint-heading:#F7F7F5;--sr-on-tint-muted:#B9B9B4;
/* Bright sky and bright yellow DO darken — they are light colours. Brand green
   and deep green are deliberately absent: they keep their light-theme value,
   because the brand colour is the brand colour. */
--sr-solid-sky:#12688A;--sr-on-solid-sky:#EAF7FC;--sr-on-solid-sky-muted:#C4E6F3;
--sr-solid-yellow:#6B5300;--sr-on-solid-yellow:#FFF3C7;--sr-on-solid-yellow-muted:#EBD79A;
--sr-oncolour-card:rgba(255,255,255,.07);--sr-oncolour-edge:rgba(255,255,255,.15);
--sr-oncolour-fg:#DCDCD8;--sr-oncolour-heading:#F7F7F5;
}
@media (prefers-color-scheme:dark){:root:not([data-theme="light"]){
--sr-tint-green:#2A3F1B;--sr-tint-green-edge:#3E5A28;
--sr-tint-sky:#102F3D;--sr-tint-sky-edge:#1C5268;
--sr-tint-yellow:#332A0A;--sr-tint-yellow-edge:#514115;
--sr-on-tint:#DCDCD8;--sr-on-tint-heading:#F7F7F5;--sr-on-tint-muted:#B9B9B4;
--sr-solid-sky:#12688A;--sr-on-solid-sky:#EAF7FC;--sr-on-solid-sky-muted:#C4E6F3;
--sr-solid-yellow:#6B5300;--sr-on-solid-yellow:#FFF3C7;--sr-on-solid-yellow-muted:#EBD79A;
--sr-oncolour-card:rgba(255,255,255,.07);--sr-oncolour-edge:rgba(255,255,255,.15);
--sr-oncolour-fg:#DCDCD8;--sr-oncolour-heading:#F7F7F5;
}}

/* Bands butt directly against one another — the colour rhythm depends on it,
   and a gap between two fields reads as a mistake. WordPress's flow layout puts
   24px of blockGap between top-level blocks, so the sections opt out. The
   selectors are class-based, which beats core's :where()-wrapped rule.

   `.is-root-container` is the editor canvas's own wrapper. The page editor has
   no template around the content, so `.sr-main` is not there — without it these
   rules would apply on the front end and not while editing, and the preview
   would be a different page. It never exists on the front end. */
:is(.sr-hero,.sr-section,.sr-utility-bar,.sr-header,.sr-footer){margin-block:0}
:is(.sr-main,.is-root-container) > *{margin-block:0}

/* The theme's own layout wrappers space their children with gap. WordPress's
   flow layout also puts a blockGap margin between siblings, so without this the
   two stack and every one of these boxes is a row-gap taller than the design —
   it was adding 24px to the header alone. */
:is(.sr-header__inner,.sr-utility-bar__inner,.sr-footer__inner,.sr-footer__cols,
   .sr-header__actions,.sr-hero__inner,.sr-services,.sr-services__item,
   .sr-reasons,.sr-reasons__item,.sr-convo,.sr-convo__item,.sr-about__top,
   .sr-about__body,.sr-about__foot,.sr-about__lockup,.sr-signature,
   .sr-showcase__panel,.sr-showcase__card,.sr-contact,.sr-contact__notes,
   .sr-grid,.sr-downloads,.sr-faq,.sr-address,:is(.sr-checklist,.is-style-sr-checklist),:is(.sr-strip,.is-style-sr-strip),
   :is(.sr-panel,.is-style-sr-panel),.sr-accreditations,.sr-form,.sr-field) > *{margin-block:0}

.sr-section{padding-block:var(--section-y)}
.sr-section--lg{padding-block:var(--section-y-lg)}
.sr-section--tight{padding-block:var(--space-12)}

/* TINT bands — coloured, dark text, safe for long copy. */
.sr-tint{background:var(--sr-tint-green);color:var(--sr-on-tint)}
.sr-tint--sky{background:var(--sr-tint-sky)}
.sr-tint--yellow{background:var(--sr-tint-yellow)}
.sr-tint :is(h1,h2,h3,h4){color:var(--sr-on-tint-heading)}
.sr-tint :is(p,li,dd){color:var(--sr-on-tint)}
.sr-tint :is(:is(.sr-lead,.is-style-sr-lead),.sr-hint){color:var(--sr-on-tint-muted)}
.sr-tint :is(.sr-eyebrow,.is-style-sr-eyebrow){color:var(--sr-on-tint-heading)}

/* SOLID bands — full brand field. */
.sr-solid{background:var(--sr-solid-green);color:var(--sr-on-solid-green)}
.sr-solid :is(h1,h2,h3,h4,:is(.sr-eyebrow,.is-style-sr-eyebrow),p,li,dd){color:var(--sr-on-solid-green)}
.sr-solid :is(.sr-lead,.is-style-sr-lead){color:var(--sr-on-solid-green-muted)}
/* Body copy directly on a saturated field carries a little more weight than it
   would on white — a saturated background visually thins a typeface. Cards
   reset this; see §6. */
.sr-solid > * :is(p,li){font-weight:var(--weight-medium)}

.sr-solid--sky{background:var(--sr-solid-sky);color:var(--sr-on-solid-sky)}
.sr-solid--sky :is(h1,h2,h3,h4,:is(.sr-eyebrow,.is-style-sr-eyebrow),p,li,dd){color:var(--sr-on-solid-sky)}
.sr-solid--sky :is(.sr-lead,.is-style-sr-lead){color:var(--sr-on-solid-sky-muted)}
.sr-solid--yellow{background:var(--sr-solid-yellow);color:var(--sr-on-solid-yellow)}
.sr-solid--yellow :is(h1,h2,h3,h4,:is(.sr-eyebrow,.is-style-sr-eyebrow),p,li,dd){color:var(--sr-on-solid-yellow)}
.sr-solid--yellow :is(.sr-lead,.is-style-sr-lead){color:var(--sr-on-solid-yellow-muted)}
.sr-solid--deep{background:var(--sr-solid-deep);color:var(--sr-on-solid-deep)}
.sr-solid--deep :is(h1,h2,h3,h4,:is(.sr-eyebrow,.is-style-sr-eyebrow),p,li,dd){color:var(--sr-on-solid-deep)}
.sr-solid--deep :is(.sr-lead,.is-style-sr-lead){color:var(--sr-on-solid-deep-muted)}

/* Links on any coloured band: inherit the band's foreground and underline, so
   they stay identifiable without relying on colour (WCAG 1.4.1). */
:is(.sr-tint,.sr-solid) a:not(.wp-block-button__link):not(.sr-btn){
  color:inherit;text-decoration:underline;text-decoration-thickness:2px;
  text-underline-offset:3px}
:is(.sr-tint,.sr-solid) a:hover:not(.wp-block-button__link):not(.sr-btn){
  text-decoration-thickness:3px}
:is(.sr-tint,.sr-solid) :focus-visible{
  box-shadow:0 0 0 2px currentColor,0 0 0 5px var(--sr-oncolour-card)}

/* Cards on the green fields. The green fields are constant across themes, so
   their cards cannot inherit the global card token: the dark-theme default is a
   7% white wash, which over a mid-tone green goes muddy and drops its text to
   about 4.2:1. They get an OPAQUE card instead — white in light, near-black in
   dark — so the card follows the page theme while still separating cleanly from
   the green. --surface-card is lifted one step above the card colour so form
   inputs inside a card stay distinguishable from it. */
[data-theme="dark"] .sr-solid:not(.sr-solid--sky):not(.sr-solid--yellow),
[data-theme="dark"] .sr-solid--deep{
--sr-oncolour-card:#1C1C19;--sr-oncolour-edge:rgba(255,255,255,.18);
--sr-oncolour-fg:#DCDCD8;--sr-oncolour-heading:#F7F7F5;--surface-card:#262622}
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]) .sr-solid:not(.sr-solid--sky):not(.sr-solid--yellow),
  :root:not([data-theme="light"]) .sr-solid--deep{
  --sr-oncolour-card:#1C1C19;--sr-oncolour-edge:rgba(255,255,255,.18);
  --sr-oncolour-fg:#DCDCD8;--sr-oncolour-heading:#F7F7F5;--surface-card:#262622}
}

/* THE APPROVED PAGE RENDERS THESE AT FULL WIDTH.
   The design declares narrower measures — .sr-section-head 720px, .sr-convo
   920px, .sr-contact 1000px — but its own layout shim writes
   `:where(.is-layout-constrained) > :not(.alignwide):not(.alignfull)...`, and
   those :not() tests sit OUTSIDE the :where(), so the selector scores 0,4,0 and
   overrides all three. WordPress's real layout CSS wraps the :not()s in a
   second :where(), scores 0,0,0, and lets them through — which is why the build
   was narrower than the design everywhere a section head or the testimonial
   column appeared.
   Matching what the client approved means reproducing the full-width render.
   Delete this rule to get the narrower measures the stylesheet asks for. */
.is-layout-constrained > :is(.sr-section-head,.sr-convo,.sr-contact){max-width:var(--layout-max)}

/* COLUMN WIDTHS.
   The design's preview gives every core/column `flex:1 1 min(340px,100%)`, so a
   declared width acts as a starting basis that still grows into the free space.
   WordPress treats a declared width as a fixed basis and lets only the
   undeclared columns grow — same markup, different column widths, and text that
   wraps to a different number of lines. Three sections showed it: the services
   standfirst, the careers copy and the resources signpost.
   The declared widths in the patterns are left exactly as the design wrote
   them; this rule reproduces the flex behaviour they were authored against. */
/* The design's default column gap. Written with :where() so a block that
   declares its own blockGap — the careers and resources signposts both do —
   still wins; a plain class here would out-specify core's per-container rule
   and quietly flatten every gap to this default. */
:where(:is(.sr-main,.is-root-container) .wp-block-columns){gap:var(--space-10)}
:is(.sr-main,.is-root-container) .wp-block-columns > .wp-block-column{flex-grow:1;flex-shrink:1;
  flex-basis:min(340px,100%)}
/* The design tops-aligns columns; core forces align-items:normal !important on
   the container, so it is done per column — leaving any column that carries an
   explicit vertical alignment (the split section head) alone. */
:is(.sr-main,.is-root-container) .wp-block-columns > .wp-block-column:not([class*="vertically-aligned"]){
  align-self:flex-start}
/* core sets flex-grow:0 on any column with a declared width; the preview lets
   them grow, so the width acts as a starting basis rather than a cap. */
:is(.sr-main,.is-root-container) .wp-block-columns > .wp-block-column[style*="flex-basis"]{flex-grow:1}

:is(.sr-narrow,.is-style-sr-narrow){max-width:var(--layout-narrow)}
:is(.sr-center,.is-style-sr-center){text-align:center;margin-inline:auto}
:is(.sr-lead,.is-style-sr-lead){font:var(--type-lead);color:var(--text-muted);max-width:64ch}
:is(.sr-center,.is-style-sr-center) :is(.sr-lead,.is-style-sr-lead){margin-inline:auto}
/* --type-eyebrow is 13px. The design's readme says "nothing is below 15px",
   which its own token contradicts; the stylesheet is the artefact, so the token
   wins and the readme's claim is the thing that is wrong. An eyebrow is a label
   above a heading that repeats its sense, not a run of body copy, and WCAG sets
   no minimum type size — so this is a legibility judgement, not a conformance
   one. Raise it here if the client would rather have the larger label. */
:is(.sr-eyebrow,.is-style-sr-eyebrow){font:var(--type-eyebrow);letter-spacing:var(--tracking-caps);
  text-transform:uppercase;color:var(--green-700);margin:0 0 var(--space-3)}
/* The design's flow shim spaces these at 16px, where WordPress would use the
   24px blockGap. Declared as a grid gap so the rhythm is explicit rather than
   inherited from a global that other sections rely on. */
.sr-section-head{max-width:var(--layout-narrow);margin-bottom:var(--space-12);
  display:grid;gap:var(--space-4)}
.sr-section-head > *{margin-block:0}
.sr-section-head.sr-center{margin-inline:auto}
/* Split section head: heading left, lead right, for a section that opens with a
   statement rather than a centred title. */
.wp-block-columns.sr-section-head--split{margin-bottom:var(--space-12);
  gap:var(--space-8) var(--space-16);align-items:flex-end}
.sr-section-head--split h2{margin:0}
:is(.sr-statement,.is-style-sr-statement){margin:0 0 var(--space-6);
  font:600 var(--text-2xl)/var(--leading-snug) var(--font-display);
  color:var(--sr-on-tint-heading);text-wrap:balance}


/* ═══════════════════════════════════════════════════════════════════════════
   3. UTILITY BAR

   Phone, opening hours and a message link through to Contact Us — the email
   address is deliberately absent (client amend). It sits OUTSIDE the sticky
   header, in its own template part, so it scrolls away naturally rather than
   having to be collapsed: an animated collapse inside a sticky element is what
   makes a header feel jumpy.
   ═══════════════════════════════════════════════════════════════════════════ */

.sr-utility-bar{background:var(--sr-footer-bg);color:var(--on-ink-body);
  padding-inline:clamp(16px,4vw,48px);--on-ink-muted:#C4C4C0}
.sr-utility-bar__inner{max-width:var(--layout-max);margin-inline:auto;
  display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;
  gap:var(--space-2) var(--space-6);min-height:44px;padding-block:var(--space-1)}
.sr-utility-bar p{margin:0}
.sr-utility-link{display:inline-flex;align-items:center;gap:var(--space-2);
  min-height:var(--tap-min);padding-inline:var(--space-1);
  font:var(--type-label);color:var(--on-ink-heading);border-radius:var(--radius-xs)}
.sr-utility-link a{color:inherit;text-decoration:none}
.sr-utility-link:hover,.sr-utility-link:hover a{color:var(--yellow-300);
  text-decoration:underline;text-decoration-thickness:2px;text-underline-offset:3px}
.sr-utility-note{display:inline-flex;align-items:center;gap:var(--space-2);
  font:var(--type-small);color:var(--on-ink-muted);min-height:24px}
/* Section 18 hangs a paragraph's icon off an absolutely positioned ::before,
   pinned to the paragraph's own box. In this bar the note and the links have
   different boxes — 24px against the links' 44px tap target — so an absolute
   icon lands at a different height in each, and above its own label. These
   make the icon an ordinary flex item in the row instead, at one size, so
   every icon centres on its own text and on the others. The [class*=] is
   needed to out-specify the section 18 rules, not for its own sake. */
.sr-utility-note[class*="sr-i--"]{padding-inline-start:0}
.sr-utility-link[class*="sr-i--"]{padding-inline-start:var(--space-1)}
:is(.sr-utility-note,.sr-utility-link)[class*="sr-i--"]::before{position:static;
  --sr-i-size:16px}
.sr-utility-bar :focus-visible{box-shadow:0 0 0 2px var(--sr-footer-bg),0 0 0 5px var(--sky-300)}
/* THE BAR IS ONE LINE OR IT IS NOT A BAR.

   All three items need about 650px of the 1200 to sit in a row. Below that they
   wrapped, and the strip above a sticky header went from 44px to 84px and then
   to 104px between 480 and 620 — a fifth of a phone screen, spent on a strip
   that exists to be glanceable. What the client saw as "Send us a message drops
   onto its own line" was the same thing at the width they happened to be at.

   So the bar sheds items rather than wrapping, and it sheds the ones that are
   said again elsewhere on the same screen:

   · Send us a message goes first. The header carries a Contact Us button at
     every width, and on a phone the sticky Contact Us bar is pinned to the
     bottom of the viewport — three routes to one form is two too many.
   · The hours go next, at the width where they stop fitting beside the number.
     They are in the footer and in Our Clinic, neither of which is far.

   What survives to the narrowest screen is the telephone number, which is the
   one thing here that is not on the page anywhere else above the fold and the
   only one that is a tap away from doing something. */
@media (max-width:959px){
  .sr-utility-bar .sr-utility-link.sr-i--mail{display:none}
}
@media (max-width:519px){
  .sr-utility-bar__inner{justify-content:center}
  .sr-utility-bar .sr-utility-note.sr-i--clock{display:none}
}


/* ═══════════════════════════════════════════════════════════════════════════
   4. HEADER

   Two states, one grid. Unscrolled, the logo is large and centred with the nav
   spanning the container beneath it (client amend: "logo bigger and more
   central"). Scrolled, the whole thing compresses into a single row — logo
   small and left, nav centred, actions right — so the sticky bar costs as
   little vertical space as possible. Only the logo size and the padding
   animate; the reflow itself is instant, which reads as a snap-to-compact.

   The sticky element is the header template part's own <header>. It contains
   nothing but .sr-header__inner, so it has the whole page to travel over — a
   sticky box can only move within its containing block, which is why the
   utility bar had to come out of it.
   ═══════════════════════════════════════════════════════════════════════════ */

.sr-header{position:sticky;top:0;z-index:50;background:var(--surface-page);
  border-bottom:1px solid transparent;transition:var(--transition-control);
  padding-inline:clamp(16px,4vw,48px)}
.sr-scrolled .sr-header{background:var(--surface-glass);
  -webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);
  border-bottom-color:var(--border-subtle);box-shadow:var(--shadow-sm)}

.sr-header__inner{max-width:var(--layout-max);margin-inline:auto;
  display:grid;justify-items:center;gap:var(--space-4);
  padding-block:var(--space-6);
  transition:padding var(--duration-base) var(--ease-standard)}
.sr-header__brand{display:inline-flex;border-radius:var(--radius-xs);margin:0}
/* WHY object-fit IS HERE.

   The brand is the flex item that absorbs whatever the toggle and the actions
   leave — at 360px that is about 90px. With a fixed height AND max-width:100%
   the image then has two independent constraints and the browser stops keeping
   the aspect ratio: the wordmark rendered at 2.07 against its natural 3.86,
   squashed to two thirds of its width.

   `contain` makes the width the binding constraint and the drawing scale to
   it. Above about 440px the box is not clamped, the image fills it exactly,
   and this changes nothing. */
.sr-header__brand img{height:88px;width:auto;object-fit:contain;object-position:left center;transition:height var(--duration-base) var(--ease-standard)}

/* core/navigation renders a <ul class="wp-block-navigation__container"> and
   wraps each link's text in .wp-block-navigation-item__content, so the design's
   `.sr-nav a` rules are applied to that class. */
.sr-nav ul{list-style:none;display:flex;flex-wrap:wrap;justify-content:center;
  gap:var(--space-2) var(--space-6);margin:0;padding:0}
.sr-nav li{margin:0}
.sr-nav .wp-block-navigation-item__content{display:inline-flex;align-items:center;
  min-height:var(--tap-min);padding-inline:var(--space-1);
  font:var(--weight-semibold) var(--text-base)/1 var(--font-display);
  color:var(--text-body);text-decoration:none;border-radius:var(--radius-xs);
  white-space:nowrap;transition:var(--transition-control)}
/* The hover is an inset underline rather than a border, so it costs no layout
   and cannot shift the row. Colour is never the only signal: the current page
   keeps the same underline in a stronger green. */
.sr-nav .wp-block-navigation-item__content:hover{color:var(--green-700);
  box-shadow:inset 0 -3px 0 var(--green-300)}
/* Both markers get the same treatment: aria-current="page" for the page being
   viewed, set by inc/navigation.php, and aria-current="location" for the
   section of the front page in view, set by the scroll-spy. Colour is never
   the only signal — the underline carries it for anyone who cannot see the
   green, and it is a box-shadow so marking an item cannot shift the row. */
.sr-nav .current-menu-item > .wp-block-navigation-item__content,
.sr-nav .wp-block-navigation-item__content[aria-current]:not([aria-current="false"]){
  color:var(--green-700);box-shadow:inset 0 -3px 0 var(--action-primary)}
/* The marker and the focus ring are both box-shadow, and a box-shadow does not
   accumulate across rules — the more specific one replaces the other outright.
   So marking an item removed its focus ring, and the current item was the one
   place keyboard focus became invisible (WCAG 2.4.7). It was latent until the
   markers were actually being set. Both, explicitly. */
.sr-nav .current-menu-item > .wp-block-navigation-item__content:focus-visible,
.sr-nav .wp-block-navigation-item__content[aria-current]:not([aria-current="false"]):focus-visible{
  box-shadow:var(--focus-ring),inset 0 -3px 0 var(--action-primary)}
.sr-header__actions{display:flex;align-items:center;gap:var(--space-3)}
.sr-header__actions .wp-block-buttons{margin:0}

/* core/navigation's own overlay toggle, given the design's nav-toggle look.
   Deliberately no `display` here: core hides the toggle above 600px with
   `.wp-block-navigation__responsive-container-open:not(.always-shown)
   {display:none}`, and this stylesheet loads after core's, so setting display
   would drag the hamburger onto the desktop header. Style the appearance and
   leave the visibility to the block. */
.sr-nav .wp-block-navigation__responsive-container-open,
.sr-nav .wp-block-navigation__responsive-container-close{
  align-items:center;justify-content:center;
  width:var(--control-h-md);height:var(--control-h-md);padding:0;
  border:1px solid var(--border-subtle);border-radius:var(--radius-pill);
  background:var(--surface-sunken);color:var(--text-heading);
  transition:var(--transition-control)}
.sr-nav .wp-block-navigation__responsive-container-open:hover{
  background:var(--surface-card);color:var(--green-700);border-color:var(--green-200)}

/* THE OVERLAY FOLLOWS THE THEME.

   core/navigation paints the open overlay #fff on #000, as two flat values
   rather than anything a theme can hook — so on a phone in dark mode the menu
   opened as a white sheet over a dark site. These are the same weight as core's
   and load after them. The surface is the page's own, so the menu reads as the
   page arriving rather than as a different site.

   The toggle and the close button are the same control in two states and are
   styled together above; only `display` is set here, because core owns when
   each is shown. The close button was `display:block`, which left the centring
   already declared on it doing nothing and the cross sitting a pixel from the
   left edge of a 44px target. */
/* The selector is long because core's is. The rule being beaten is

     .wp-block-navigation:not(.has-background)
       .wp-block-navigation__responsive-container.is-menu-open:not(
       .disable-default-overlay){background-color:#fff}

   which scores 0,5,0 — five classes, two of them inside :not(). Anything
   shorter loses and the menu stays white. `:not(.has-background)` is carried
   over so this handles the same case core does: a nav that has been given its
   own background colour keeps it. */
.sr-header .wp-block-navigation.sr-nav:not(.has-background)
  .wp-block-navigation__responsive-container.is-menu-open{
  background-color:var(--surface-page);color:var(--text-body)}
.sr-nav .wp-block-navigation__responsive-container.is-menu-open
  .wp-block-navigation__responsive-container-close{display:flex}

/* WHY THE STICKY CTA HAS TO BE TOLD TO GO.

   The overlay asks for z-index 100000, and gets it — inside the header, which
   is position:sticky with a z-index of its own and therefore a stacking context
   the overlay cannot climb out of. Against the sticky Contact Us bar, which is
   z-index 60 in the root context, the whole header stacks at 50 and loses. So a
   green button floated over an open menu, on top of the very item it duplicates.

   Raising the header's z-index would fix this one case and start an argument
   with everything else that stacks. core/navigation puts `has-modal-open` on
   <html> for exactly this, so the page can stand down while a modal is open. */
html.has-modal-open .sr-sticky-cta{display:none}

/* WHERE THE HAMBURGER STARTS.

   core/navigation only has three settings — always, mobile, never — and its
   "mobile" is hard-coded to 600px. This header needs a wider one: below 960px
   its grid stops putting the nav and the Contact Us button on one row, so
   between 600 and 960 the button dropped to a line of its own (header 199px to
   259px) and by 640 the six nav items wrapped to two rows (287px). A quarter
   of a phone screen of sticky chrome, on the widths a tablet actually uses.

   960px is not a new number: it is the width at which the header's own
   one-row layout below already stops. These three rules are core's own, at
   the theme's breakpoint rather than core's — the menu hidden, the toggle
   shown, the close button back inside the open overlay. Everything about how
   the overlay itself looks and behaves is still core's. */
@media (min-width:600px) and (max-width:959px){
  .sr-nav .wp-block-navigation__responsive-container:not(.hidden-by-default):not(.is-menu-open){
    display:none}
  .sr-nav .wp-block-navigation__responsive-container-open:not(.always-shown){display:flex}
  .sr-nav .wp-block-navigation__responsive-container.is-menu-open
    .wp-block-navigation__responsive-container-close{display:flex}
}

/* Compress on scroll at EVERY width. A 260px sticky header is half a phone
   screen, so the collapse cannot be desktop-only: shrink the logo and cut the
   padding first, then reflow to a single row once there is room for one. */
.sr-scrolled .sr-header__inner{gap:var(--space-3);padding-block:var(--space-3)}
.sr-scrolled .sr-header__brand img{height:44px}

@media (max-width:959px){
  /* Flex, not grid, at these widths. core/navigation renders its overlay toggle
     inside the nav element rather than inside the actions group, so nav and
     actions are two separate boxes that have to sit side by side — put both in
     one grid cell and the hamburger lands underneath the theme switch.
     Order matches the design's cluster: toggle, Contact Us, theme switch. */
  .sr-header__inner{display:flex;flex-wrap:nowrap;align-items:center;
    gap:var(--space-2);column-gap:var(--space-4)}
  .sr-header__brand{flex:1 1 auto;min-width:0;order:0}
  .sr-nav{flex:none;order:1}
  .sr-header__actions{flex:none;order:2}
}
/* The sizes below are the phone's. Between 640 and 960 the row has room for
   the full logo, so only the layout above is shared. */
@media (max-width:639px){
  .sr-header__brand img{height:52px}
  .sr-scrolled .sr-header__brand img{height:40px}
  /* The CTA tightens rather than losing its label — the visible text is the
     button's accessible name, so it stays real text at every width. */
  .sr-header__actions .wp-block-button__link{padding-inline:var(--space-4);
    font-size:var(--text-sm)}
}
@media (max-width:399px){
  .sr-header__brand img{height:44px}
  .sr-header__actions{gap:var(--space-2)}
  /* The brand is the flex item that gives way, so every pixel the row spares is
     a pixel of logo. Tightening the two gaps and the button's own padding takes
     it from 91px to 115px — without dropping a control or shortening the CTA,
     whose visible text is its accessible name. */
  .sr-header__inner{column-gap:var(--space-2)}
  .sr-header__actions .wp-block-button__link{padding-inline:var(--space-3)}
}
/* Between 640 and 960 the nav used to stay inline and was given a horizontal
   scroller when the header compressed. It is an overlay at those widths now,
   so there is no row to scroll and those rules have gone. */
@media (min-width:960px){
  .sr-header__inner{grid-template-columns:1fr auto;
    grid-template-areas:"brand brand" "nav actions";align-items:center}
  .sr-header__brand{grid-area:brand;justify-self:center}
  .sr-nav{grid-area:nav;justify-self:stretch;min-width:0}
  .sr-nav ul{justify-content:flex-start;
    gap:var(--space-2) clamp(var(--space-4),2.4vw,var(--space-8))}
  .sr-header__actions{grid-area:actions;justify-self:end}
  /* Compressed: one row — brand left, nav centred, actions right. */
  .sr-scrolled .sr-header__inner{grid-template-columns:auto 1fr auto;
    grid-template-areas:"brand nav actions";gap:var(--space-8);
    padding-block:var(--space-3)}
  .sr-scrolled .sr-header__brand{justify-self:start}
  .sr-scrolled .sr-header__brand img{height:46px}
  .sr-scrolled .sr-nav{justify-self:center}
  .sr-scrolled .sr-nav ul{justify-content:center}
}

/* The colour lockup has a solid black wordmark, so dark surfaces use a DERIVED
   dark-surface variant — not the flat white knockout, which recolours every
   pixel and throws the coloured bubble mark away. Both selectors are needed:
   the attribute covers a pinned choice, the media query covers a device already
   set to dark, which is the more common first visit.
   The :is() prefix is not decoration — core ships .wp-block-site-logo img
   {display:block}, which outranks a lone .sr-logo--dark. */
:is(.sr-header,.sr-footer,.sr-about__lockup,.wp-block-site-logo) .sr-logo--dark{display:none}
[data-theme="dark"] :is(.sr-header,.sr-footer,.sr-about__lockup,.wp-block-site-logo) .sr-logo--light{display:none}
[data-theme="dark"] :is(.sr-header,.sr-footer,.sr-about__lockup,.wp-block-site-logo) .sr-logo--dark{display:block}
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]) :is(.sr-header,.sr-footer,.sr-about__lockup,.wp-block-site-logo) .sr-logo--light{display:none}
  :root:not([data-theme="light"]) :is(.sr-header,.sr-footer,.sr-about__lockup,.wp-block-site-logo) .sr-logo--dark{display:block}
}


/* ═══════════════════════════════════════════════════════════════════════════
   5. BUTTONS — registered as core/button block styles (see functions.php)

   Filled green uses --action-primary (green-600), which measures 4.7:1 with
   white. Sky and yellow fills carry a darker hairline for 1.4.11 Non-text
   Contrast.
   ═══════════════════════════════════════════════════════════════════════════ */

.wp-block-buttons{display:flex;flex-wrap:wrap;gap:var(--space-3);margin:0}
.wp-block-button{margin:0}
.sr-btn,.wp-block-button__link,.wp-element-button{display:inline-flex;
  align-items:center;justify-content:center;gap:var(--space-2);
  min-height:var(--control-h-md);padding:var(--space-3) var(--space-6);
  border:1.5px solid transparent;border-radius:var(--radius-md);
  background:var(--action-primary);color:var(--text-on-brand);
  font:var(--weight-semibold) var(--text-base)/1.2 var(--font-display);
  text-decoration:none;cursor:pointer;transition:var(--transition-control)}
.sr-btn:hover,.wp-block-button__link:hover{background:var(--action-primary-hover);
  color:var(--text-on-brand);transform:var(--lift-hover);text-decoration:none}
.sr-btn:active,.wp-block-button__link:active{background:var(--action-primary-active);
  transform:var(--press-active)}
.sr-btn--lg,.sr-btn--lg .wp-block-button__link{min-height:var(--control-h-lg);
  padding-inline:var(--space-8);font-size:var(--text-md)}
.sr-btn--sm,.sr-btn--sm .wp-block-button__link{min-height:var(--control-h-sm);
  padding:var(--space-2) var(--space-4);font-size:var(--text-sm)}

.is-style-sr-secondary .wp-block-button__link{background:var(--action-secondary);
  border-color:var(--action-secondary-edge);color:var(--text-on-secondary)}
.is-style-sr-secondary .wp-block-button__link:hover{background:var(--action-secondary-hover);
  color:var(--text-on-secondary)}
.is-style-sr-accent .wp-block-button__link{background:var(--action-accent);
  border-color:var(--action-accent-edge);color:var(--text-on-accent)}
.is-style-sr-accent .wp-block-button__link:hover{background:var(--action-accent-hover);
  color:var(--text-on-accent)}
.is-style-sr-outline .wp-block-button__link{background:transparent;
  border-color:var(--border-brand);color:var(--text-link-hover)}
.is-style-sr-outline .wp-block-button__link:hover{background:var(--green-50);
  color:var(--green-800)}

/* Buttons sitting ON a saturated band cannot use the surface-tuned link
   colours: green-700 on bright sky measures 3.2:1 in light and 4.12:1 in dark,
   both under the 4.5:1 that 17px/600 needs. On a solid band they take the
   band's own foreground, which is the pair that was measured for it. */
.sr-solid .is-style-sr-outline .wp-block-button__link{background:transparent;
  border-color:currentColor;color:var(--sr-on-solid-green)}
.sr-solid .is-style-sr-outline .wp-block-button__link:hover{
  background:var(--sr-oncolour-card);color:var(--sr-oncolour-heading);
  border-color:var(--sr-oncolour-card)}
.sr-solid--sky .is-style-sr-outline .wp-block-button__link{color:var(--sr-on-solid-sky)}
.sr-solid--yellow .is-style-sr-outline .wp-block-button__link{color:var(--sr-on-solid-yellow)}
.sr-solid--deep .is-style-sr-outline .wp-block-button__link{color:var(--sr-on-solid-deep)}
/* A filled button on a saturated band needs a hairline: green-600 on bright sky
   is a 2.12:1 boundary, under the 3:1 that 1.4.11 wants for a control edge. */
.sr-solid .wp-block-button:not(.is-style-sr-outline) .wp-block-button__link{border-color:var(--sr-on-solid-green)}
.sr-solid--sky .wp-block-button:not(.is-style-sr-outline) .wp-block-button__link{border-color:var(--sr-on-solid-sky)}
.sr-solid--yellow .wp-block-button:not(.is-style-sr-outline) .wp-block-button__link{border-color:var(--sr-on-solid-yellow)}
.sr-solid--deep .wp-block-button:not(.is-style-sr-outline) .wp-block-button__link{border-color:var(--sr-on-solid-deep)}
/* A filled green button directly ON the green field would be the same colour as
   the field, so it flips to a white fill with green text. Buttons inside a card
   are reset by the card rule below. */
.sr-solid:not(.sr-solid--sky):not(.sr-solid--yellow) > * .wp-block-button:not(.is-style-sr-outline) .wp-block-button__link{
  background:#FFFFFF;color:#3C5A1B;border-color:transparent}
.sr-solid:not(.sr-solid--sky):not(.sr-solid--yellow) > * .wp-block-button:not(.is-style-sr-outline) .wp-block-button__link:hover{
  background:#F2F7EA;color:#2F4715}
/* A button inside a card takes the card's colours, not the band's — the band's
   white foreground would be white text on a white card. */
:is(:is(.sr-oncolour,.is-style-sr-oncolour),:is(.sr-card,.is-style-sr-card),.sr-showcase__card,:is(.sr-strip,.is-style-sr-strip),:is(.sr-panel,.is-style-sr-panel)) .is-style-sr-outline .wp-block-button__link{
  color:var(--text-link);border-color:var(--border-brand);background:transparent}
:is(:is(.sr-oncolour,.is-style-sr-oncolour),:is(.sr-card,.is-style-sr-card),.sr-showcase__card,:is(.sr-strip,.is-style-sr-strip),:is(.sr-panel,.is-style-sr-panel)) .is-style-sr-outline .wp-block-button__link:hover{
  background:var(--green-50);color:var(--text-link-hover);border-color:var(--border-brand)}
:is(:is(.sr-oncolour,.is-style-sr-oncolour),:is(.sr-card,.is-style-sr-card),.sr-showcase__card,:is(.sr-strip,.is-style-sr-strip),:is(.sr-panel,.is-style-sr-panel)) .wp-block-button:not(.is-style-sr-outline) .wp-block-button__link{
  background:var(--action-primary);color:var(--text-on-brand);border-color:transparent}


/* ═══════════════════════════════════════════════════════════════════════════
   6. CARDS, DOWNLOADS AND QUOTES — 1px border AND shadow-sm.
      No coloured left-border accents.
   ═══════════════════════════════════════════════════════════════════════════ */

/* The card grid's columns live here rather than on a block layout attribute,
   so the Card grid block carries no layout of its own to be half-undone from
   the sidebar. 320px is the design's own minimum column. */
.sr-grid{display:grid;gap:var(--space-6);
  grid-template-columns:repeat(auto-fill,minmax(min(320px,100%),1fr))}
:is(.sr-card,.is-style-sr-card){display:flex;flex-direction:column;gap:var(--space-3);height:100%;
  padding:var(--space-8);background:var(--surface-card);
  border:1px solid var(--border-subtle);border-radius:var(--radius-lg);
  box-shadow:var(--shadow-sm);transition:var(--transition-control)}
:is(.sr-card,.is-style-sr-card) > *{margin:0}
:is(.sr-card,.is-style-sr-card) :is(h2,h3,h4){margin:0;font-size:var(--text-lg)}
:is(.sr-card,.is-style-sr-card) p{margin:0;font:var(--type-body);color:var(--text-muted)}
:is(.sr-card,.is-style-sr-card) ul{margin-top:auto}
:is(.sr-card__title,.is-style-sr-card-title){margin:0;
  font:var(--weight-semibold) var(--text-lg)/var(--leading-snug) var(--font-display);
  color:var(--text-heading)}
:is(.sr-card__meta,.is-style-sr-card-meta){font:var(--type-small);color:var(--text-subtle)}
a.sr-card,.sr-card--link{text-decoration:none;color:inherit}
a.sr-card:hover,.sr-card--link:hover{box-shadow:var(--shadow-md);
  transform:var(--lift-hover);border-color:var(--green-200)}
a.sr-card:hover :is(h2,h3,:is(.sr-card__title,.is-style-sr-card-title)),
.sr-card--link:hover :is(h2,h3,:is(.sr-card__title,.is-style-sr-card-title)){color:var(--green-700)}

/* Cards on a SOLID band.
   Done by REDEFINING the band's foreground tokens inside the card rather than
   by restating a colour on every element. The band sets `.sr-solid p,li,dd
   {color:var(--sr-on-solid-green)}` and `.sr-solid a{color:inherit}`; if a card
   only overrides `p`, then `li` and any anchor keep the band's white and vanish
   on a white card. Re-pointing the token fixes every element the band styles at
   once, including ones added later. The :is() also out-specifies the band's
   :not() chain on anchors. */
.sr-solid :is(:is(.sr-card,.is-style-sr-card),:is(.sr-oncolour,.is-style-sr-oncolour),.sr-sheet,:is(.sr-strip,.is-style-sr-strip),:is(.sr-panel,.is-style-sr-panel),.sr-showcase__card,.sr-services__item,.wp-block-file,.wp-block-details,.sr-convo__item blockquote){
  --sr-on-solid-green:var(--sr-oncolour-fg);--sr-on-solid-sky:var(--sr-oncolour-fg);
  --sr-on-solid-yellow:var(--sr-oncolour-fg);--sr-on-solid-deep:var(--sr-oncolour-fg);
  color:var(--sr-oncolour-fg)}
.sr-solid :is(:is(.sr-card,.is-style-sr-card),:is(.sr-oncolour,.is-style-sr-oncolour),.sr-sheet,:is(.sr-strip,.is-style-sr-strip),:is(.sr-panel,.is-style-sr-panel),.sr-showcase__card,.sr-services__item,.wp-block-file,.wp-block-details,.sr-convo__item blockquote) :is(h2,h3,h4,:is(.sr-card__title,.is-style-sr-card-title),:is(.sr-eyebrow,.is-style-sr-eyebrow)){
  color:var(--sr-oncolour-heading)}
.sr-solid :is(:is(.sr-card,.is-style-sr-card),:is(.sr-oncolour,.is-style-sr-oncolour),.sr-sheet,:is(.sr-strip,.is-style-sr-strip),:is(.sr-panel,.is-style-sr-panel),.sr-showcase__card,.sr-services__item,.wp-block-file,.wp-block-details,.sr-convo__item blockquote) :is(p,li){
  font-weight:var(--weight-regular);color:var(--sr-oncolour-fg)}
.sr-solid :is(:is(.sr-card,.is-style-sr-card),:is(.sr-oncolour,.is-style-sr-oncolour),.sr-sheet,:is(.sr-strip,.is-style-sr-strip),:is(.sr-panel,.is-style-sr-panel),.sr-showcase__card,.sr-services__item,.wp-block-file) a:not(.wp-block-button__link):not(.sr-btn){
  color:var(--text-link);text-decoration:underline;text-decoration-thickness:1px}
.sr-solid :is(:is(.sr-card,.is-style-sr-card),:is(.sr-oncolour,.is-style-sr-oncolour),.sr-sheet,:is(.sr-strip,.is-style-sr-strip),:is(.sr-panel,.is-style-sr-panel),.sr-showcase__card,.sr-services__item,.wp-block-file) a:hover:not(.wp-block-button__link):not(.sr-btn){
  color:var(--text-link-hover);text-decoration-thickness:2px}
.sr-solid :is(.sr-card,.is-style-sr-card){background:var(--sr-oncolour-card);border-color:var(--sr-oncolour-edge)}
.sr-solid .sr-card--link:hover,.sr-solid a.sr-card:hover{
  border-color:var(--sr-oncolour-edge);box-shadow:var(--shadow-md)}

:is(.sr-oncolour,.is-style-sr-oncolour){background:var(--sr-oncolour-card);border:1px solid var(--sr-oncolour-edge);
  border-radius:var(--radius-xl);color:var(--sr-oncolour-fg)}
:is(.sr-oncolour,.is-style-sr-oncolour) :is(h2,h3,h4){color:var(--sr-oncolour-heading)}
:is(.sr-oncolour,.is-style-sr-oncolour) p{color:var(--sr-oncolour-fg)}
/* Panel — a card on a coloured band with the card's own padding. */
:is(.sr-panel,.is-style-sr-panel){display:grid;gap:var(--space-5);padding:var(--space-8);
  border-radius:var(--radius-xl);background:var(--sr-oncolour-card);
  border:1px solid var(--sr-oncolour-edge)}
:is(.sr-panel,.is-style-sr-panel) > *{margin:0}

/* Downloads. core/file renders .wp-block-file with the label anchor and the
   download button as siblings, so the design's .sr-download card is applied to
   that. The format and size are part of each link's accessible name, not
   decoration: a screen reader user should know a press starts a download, and
   what it costs on mobile data, before committing (WCAG 2.4.4). */
.sr-downloads{display:grid;gap:var(--space-4);margin:0;padding:0;list-style:none}
.sr-downloads .wp-block-file{display:flex;flex-wrap:wrap;gap:var(--space-4) var(--space-6);
  align-items:center;justify-content:space-between;margin:0;padding:var(--space-6);
  border-radius:var(--radius-lg);background:var(--surface-card);
  border:1px solid var(--border-subtle);box-shadow:var(--shadow-xs);
  transition:var(--transition-control)}
.sr-downloads .wp-block-file:hover{box-shadow:var(--shadow-sm);border-color:var(--green-200)}
.sr-downloads .wp-block-file > a:first-child{
  font:600 var(--text-lg)/var(--leading-snug) var(--font-display);
  color:var(--text-heading);text-decoration:none}
.sr-downloads .wp-block-file__button{background:transparent;
  color:var(--text-link-hover);border:1.5px solid var(--border-brand);
  border-radius:var(--radius-md);padding:var(--space-3) var(--space-6);
  min-height:var(--control-h-md);display:inline-flex;align-items:center;
  font:var(--weight-semibold) var(--text-base)/1.2 var(--font-display)}
.sr-downloads .wp-block-file__button:hover{background:var(--green-50);color:var(--green-800)}
.sr-solid .sr-downloads .wp-block-file{background:var(--sr-oncolour-card);
  border-color:var(--sr-oncolour-edge)}


/* ═══════════════════════════════════════════════════════════════════════════
   7. HERO AND THE HOME SECTIONS
   ═══════════════════════════════════════════════════════════════════════════ */

/* HERO — asymmetric editorial, not a centred banner. The display line runs
   large and tight; the tagline sits in a real speech bubble, because the
   tagline is the practice speaking. The photo is cropped to an oversized
   bubble — the brand's signature shape at scale. */
.sr-hero{padding-block:var(--space-16) var(--section-y);overflow:hidden}
.sr-hero__inner{max-width:var(--layout-max);margin-inline:auto;display:grid;
  gap:var(--space-12) var(--space-16);align-items:center}
@media (min-width:900px){
  .sr-hero__inner{grid-template-columns:minmax(0,1.05fr) minmax(0,.95fr)}
}
.sr-hero h1{font:600 var(--text-6xl)/1.02 var(--font-display);
  letter-spacing:var(--tracking-tight);margin:0 0 var(--space-6);text-wrap:balance}
/* The emphasis is green text over a yellow pill drawn behind it — a
   hand-drawn-feeling underline rather than a border, and not colour carrying
   meaning on its own. */
.sr-hero h1 em{font-style:normal;color:var(--green-600);position:relative;
  white-space:nowrap;isolation:isolate}
.sr-hero h1 em::after{content:"";position:absolute;left:0;right:0;bottom:-.06em;
  height:.28em;border-radius:var(--radius-pill);background:var(--yellow-300);z-index:-1}
.sr-hero__tagline{display:inline-block;margin:0 0 var(--space-6);
  padding:var(--space-4) var(--space-6);border-radius:var(--radius-bubble);
  background:var(--sr-oncolour-card);border:1px solid var(--sr-oncolour-edge);
  font:var(--weight-medium) var(--text-md)/1.4 var(--font-display);
  color:var(--sr-oncolour-heading)}
.sr-hero__actions{display:flex;flex-wrap:wrap;gap:var(--space-3);margin-top:var(--space-8)}
/* A run of copy followed by its actions. The hero names its own row and sets
   this distance on it; the signpost on the home page and the closing CTA on
   every inner page are the same shape without a class, and were sitting flush
   against the paragraph above them. Core's .wp-block-buttons{margin:0} is what
   they were getting instead — right for a row of buttons inside a layout that
   spaces its own children, wrong directly under a sentence. */
:is(.sr-main,.is-root-container) p + .wp-block-buttons{margin-top:var(--space-8)}
.sr-hero__figure{position:relative;margin:0}
.sr-hero__figure img{display:block;border-radius:var(--radius-bubble-xl);
  width:100%;height:420px;object-fit:cover}
@media (max-width:559px){.sr-hero__figure img{height:300px}}

/* SERVICE TILES — the nine services on the solid green band. White cards on a
   full brand field: the colour comes from the band, the tiles stay legible for
   long copy, and a two-line title beside a five-line description never leaves a
   ragged row. */
.sr-services{display:grid;
  grid-template-columns:repeat(auto-fill,minmax(min(330px,100%),1fr));
  gap:var(--space-5);margin:0;padding:0;list-style:none}
.sr-services__item{margin:0;display:grid;gap:var(--space-4);align-content:start;
  padding:var(--space-8);border-radius:var(--radius-xl);
  background:var(--sr-oncolour-card);border:1px solid var(--sr-oncolour-edge)}
.sr-services__item > *{margin:0}
.sr-services__item h3{margin:0;
  font:600 var(--text-lg)/var(--leading-snug) var(--font-display);
  color:var(--sr-oncolour-heading);text-wrap:balance}
.sr-services__item p{margin:0;font:var(--type-body);color:var(--sr-oncolour-fg)}
/* The chip is the icon block itself: it sets its own box, and the three brand
   tints cycle in CSS so reordering or removing a tile keeps the sequence. */
.sr-services__item .sr-icon{width:52px;height:52px;border-radius:var(--radius-lg);
  background:var(--sr-tint-green);color:var(--sr-on-tint-heading);--sr-i-size:26px}
.sr-services__item:nth-child(3n+2) .sr-icon{background:var(--sr-tint-sky)}
.sr-services__item:nth-child(3n+3) .sr-icon{background:var(--sr-tint-yellow)}

/* REASONS — the eight reasons on the sky tint. Chrome-free: a white chip, a
   short title, a line of copy. */
.sr-reasons{display:grid;
  grid-template-columns:repeat(auto-fill,minmax(min(250px,100%),1fr));
  gap:var(--space-10) var(--space-8);margin:0;padding:0;list-style:none}
.sr-reasons__item{margin:0;display:grid;gap:var(--space-3);align-content:start}
.sr-reasons__item > *{margin:0}
.sr-reasons__item h3{margin:0;
  font:600 var(--text-md)/var(--leading-snug) var(--font-display);text-wrap:balance}
.sr-reasons__item p{margin:0;font:var(--type-small)}
.sr-reasons__item .sr-icon{width:48px;height:48px;border-radius:var(--radius-pill);
  background:var(--sr-oncolour-card);border:1px solid var(--sr-oncolour-edge);
  color:var(--sr-oncolour-heading);--sr-i-size:24px}

/* CONVERSATION — testimonials as a dialogue. This is where the bubble radius
   earns its place: quotes alternate side and tail direction so the column reads
   as people talking, which is the practice's whole subject. */
.sr-convo{display:grid;gap:var(--space-8);max-width:920px;margin-inline:auto;
  padding:0;list-style:none}
.sr-convo__item{margin:0;display:grid;gap:var(--space-3);
  max-width:min(600px,94%);justify-items:start}
.sr-convo__item:nth-child(even){margin-inline-start:auto;justify-items:end;text-align:right}
.sr-convo__item blockquote{margin:0;padding:var(--space-6) var(--space-8);
  border-radius:var(--radius-bubble);background:var(--sr-oncolour-card);
  border:1px solid var(--sr-oncolour-edge);font:var(--type-lead);
  color:var(--sr-oncolour-fg);border-left:1px solid var(--sr-oncolour-edge)}
.sr-convo__item blockquote p{margin:0;font:inherit;color:inherit}
.sr-convo__item:nth-child(even) blockquote{border-radius:var(--radius-bubble-alt)}
/* The trailing margin is the design's: its .sr-convo__by rule never resets the
   base paragraph margin, so each attribution carries 16px beneath it and the
   dialogue sits looser than the declared 12px gap suggests. Reproduced because
   it is what the approved page shows. */
.sr-convo__by{display:flex;align-items:center;gap:var(--space-2);
  font:var(--type-label);padding-inline:var(--space-4)}
/* Doubled class to out-specify core's `:root :where(.is-layout-flow) >
   :last-child { margin-block-end:0 }`. */
.sr-convo__by.sr-convo__by{margin:0 0 var(--space-4)}

/* CLINIC — a deep brand-green field carrying the copy and the photographs as
   cards, rather than a photograph used as a background. A photograph behind
   text needs a scrim, and a scrim is just grey. */
.sr-showcase__panel{display:grid;gap:var(--space-8);
  grid-template-columns:repeat(auto-fit,minmax(min(320px,100%),1fr));align-items:start}
.sr-showcase__card{padding:var(--space-10);border-radius:var(--radius-xl);
  background:var(--sr-oncolour-card);border:1px solid var(--sr-oncolour-edge);
  color:var(--sr-oncolour-fg);display:grid;gap:var(--space-5);align-content:start}
.sr-showcase__card > *{margin:0}
.sr-showcase__card :is(h2,h3,:is(.sr-eyebrow,.is-style-sr-eyebrow)){color:var(--sr-oncolour-heading)}
.sr-showcase__card :is(p,li){color:var(--sr-oncolour-fg)}
.sr-showcase__card .sr-hours dt{color:var(--sr-oncolour-heading)}
.sr-showcase__card .sr-hours dd{color:var(--sr-oncolour-fg)}
.sr-showcase__card .sr-hours div{border-bottom-color:var(--sr-oncolour-edge)}
.sr-clinic-gallery img{width:100%;aspect-ratio:4/3;object-fit:cover;
  border-radius:var(--radius-lg)}

/* FEES — a quiet single strip, for a section that answers one question. */
:is(.sr-strip,.is-style-sr-strip){display:grid;gap:var(--space-5) var(--space-8);
  grid-template-columns:auto minmax(0,1fr);align-items:start;
  max-width:var(--layout-max);padding:var(--space-10);
  background:var(--sr-oncolour-card);border:1px solid var(--sr-oncolour-edge);
  border-radius:var(--radius-xl)}
:is(.sr-strip,.is-style-sr-strip) h2{margin:0 0 var(--space-3);font:var(--type-h4);color:var(--sr-oncolour-heading)}
:is(.sr-strip,.is-style-sr-strip) p{margin:0;font:var(--type-body);color:var(--sr-oncolour-fg);max-width:72ch}
:is(.sr-strip,.is-style-sr-strip) .sr-icon{width:56px;height:56px;border-radius:var(--radius-lg);
  background:var(--sr-tint-yellow);color:var(--sr-on-tint-heading);--sr-i-size:28px}
@media (max-width:559px){:is(.sr-strip,.is-style-sr-strip){grid-template-columns:1fr;padding:var(--space-6)}}


/* ═══════════════════════════════════════════════════════════════════════════
   8. ABOUT — editorial statement, lockup and signature

   Intro and photograph side by side, then the remaining copy running full width
   beneath in two readable measures — five paragraphs is too long for a single
   column beside an image strip.
   ═══════════════════════════════════════════════════════════════════════════ */

.sr-about__top{display:grid;gap:var(--space-10) var(--space-16);align-items:center}
@media (min-width:900px){
  .sr-about__top{grid-template-columns:minmax(0,1.05fr) minmax(0,.95fr)}
}
.sr-about__figure{margin:0}
.sr-about__figure img{display:block;height:clamp(280px,38vw,420px);width:100%;
  object-fit:cover;border-radius:var(--radius-bubble-xl)}
.sr-about__body{display:grid;gap:var(--space-6) var(--space-12);
  grid-template-columns:repeat(auto-fit,minmax(min(340px,100%),1fr));
  margin-top:var(--space-12)}
.sr-about__body p{margin:0;font:var(--type-body)}
.sr-about__foot{display:flex;flex-wrap:wrap;align-items:center;
  justify-content:space-between;gap:var(--space-10);margin-top:var(--space-12);
  padding-top:var(--space-10);border-top:1px solid currentColor}
.sr-about__lockup{display:grid;gap:var(--space-4);justify-items:start}
.sr-about__lockup img{width:100%;max-width:260px;height:auto}
.sr-brand-lockup{margin:0}
/* No rule above the signature, and no extra spacing. The design's stylesheet
   declares a border-top and padding here, but its own markup cancels them with
   an inline `style="margin:0;padding:0;border:0"` — so the approved page shows
   the lockup and the signature as one quiet stack, with the only rule on the
   whole foot row above. The markup is what was signed off, so it wins. */
.sr-signature{display:grid;gap:var(--space-2);margin:0;padding:0;border:0}
.sr-signature img{width:180px;height:auto;max-width:100%}
.sr-signature p{margin:0;font:var(--type-small);color:var(--text-subtle)}
/* The signature inverts on any dark surface, as the design does.
   The design's note calls the asset "black ink on transparent"; it is actually
   sky blue #4AC0EC, so the inversion lands on #FF651E rather than white — but
   that IS the approved page: the design renders an orange signature in dark and
   a blue one in light. It measures 4.8:1 on the dark yellow field — better than the
   1.8:1 the blue manages on the light one — and it is decorative in any case (alt=""), with the name set as real text beneath.
   BOTH selectors are required: the attribute covers a pinned choice, the media
   query covers a device already set to dark, which is the more common first
   visit. */
[data-theme="dark"] .sr-signature img{filter:invert(1) brightness(1.6)}
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]) .sr-signature img{filter:invert(1) brightness(1.6)}
}

/* Accreditation logo row (RCSLT, HCPC, ASLTIP, DBS). Sized by width, not
   height: a height-only rule with width:auto lays the element out 0px wide
   before the intrinsic size is known. */
/* The four mark files carry their own opaque #F5F8FB background — they are the
   client's originals and cannot be knocked out without damaging the marks. Left
   bare they read as four ragged white rectangles on the yellow band, so each
   gets the same plaque in that colour: the background then looks deliberate,
   and the marks stay legible on the dark theme as well. */
/* The class is doubled so the gap beats core's per-container blockGap rule,
   which is what was pushing the row past the container and wrapping the marks
   onto their own line. */
/* Bare, as the design has them. The four files carry their own opaque #F5F8FB
   background — they are the client's originals — so they read as light plaques
   on the yellow band in the design too; a border and padding of our own only
   drew attention to it. The doubled class beats core's per-container blockGap,
   which was otherwise wide enough to wrap the row onto its own line. */
.sr-accreditations.sr-accreditations{display:flex;flex-wrap:wrap;align-items:center;
  gap:var(--space-5);margin-top:var(--space-8);padding:0;list-style:none}
.sr-accreditations figure{margin:0;display:flex;align-items:center;justify-content:center}
.sr-accreditations img{width:112px;height:auto;max-width:100%;display:block}


/* ═══════════════════════════════════════════════════════════════════════════
   9. IMAGES

   core/image does not write width and height attributes for an image with no
   media-library attachment, so the brand assets declare their proportions here.
   Without it the page reflows as each one decodes (Cumulative Layout Shift).
   The photographs get theirs injected at render time — see functions.php.
   ═══════════════════════════════════════════════════════════════════════════ */

.sr-brand-lockup img{aspect-ratio:325/114}
.sr-signature img{aspect-ratio:182/33}
.sr-accreditations img{aspect-ratio:197/119}


/* ═══════════════════════════════════════════════════════════════════════════
   10. LISTS, HOURS, CHECKLISTS
   ═══════════════════════════════════════════════════════════════════════════ */

/* Checklists stay a real core/list, so the markup keeps <ul>/<li> semantics and
   a screen reader still announces "list, 7 items". The tick is drawn on each
   li::before from --sr-i-url, which the <ul> sets by carrying an sr-i--* class:
   the icon name inherits down, the list structure is untouched, and adding or
   removing an item is an ordinary list edit. */
:is(.sr-checklist,.is-style-sr-checklist){list-style:none;margin:0;padding:0;display:grid;gap:var(--space-3)}
:is(.sr-checklist,.is-style-sr-checklist)::before{display:none}
:is(.sr-checklist,.is-style-sr-checklist) li{display:flex;gap:var(--space-3);margin:0;font:var(--type-body)}
:is(.sr-checklist,.is-style-sr-checklist) li::before{content:"";display:inline-block;flex:none;
  width:20px;height:20px;margin-top:3px;background:currentColor;color:var(--green-600);
  -webkit-mask:var(--sr-i-url) center/contain no-repeat;
  mask:var(--sr-i-url) center/contain no-repeat}
:is(.sr-tint,.sr-solid) :is(.sr-checklist,.is-style-sr-checklist) li::before{color:currentColor}
.sr-solid :is(:is(.sr-card,.is-style-sr-card),:is(.sr-oncolour,.is-style-sr-oncolour),:is(.sr-panel,.is-style-sr-panel),.sr-showcase__card) :is(.sr-checklist,.is-style-sr-checklist) li::before{
  color:var(--text-link)}

/* The rows. The editor renders this block through serverSideRender, so the
   canvas gets this same markup and these same rules; the day-by-day controls
   are in the sidebar. */
.sr-hours{margin:0;display:grid;gap:0}
.sr-hours div{display:flex;justify-content:space-between;
  gap:var(--space-6);padding-block:var(--space-3);
  border-bottom:1px solid var(--border-subtle)}
.sr-hours div:last-child{border-bottom:0}
.sr-hours dt{font:var(--type-label);color:var(--text-body);margin:0}
.sr-hours dd{margin:0;font:var(--type-body);color:var(--text-muted);
  font-variant-numeric:tabular-nums}


/* ═══════════════════════════════════════════════════════════════════════════
   11. ACCORDION — core/details. Native disclosure, keyboard operable, and it
       announces its own expanded state without any ARIA of ours.
   ═══════════════════════════════════════════════════════════════════════════ */

:root{--sr-chevron:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="black" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>')}
.sr-faq{display:grid;gap:var(--space-3)}
.wp-block-details{background:var(--surface-card);border:1px solid var(--border-subtle);
  border-radius:var(--radius-lg);box-shadow:var(--shadow-xs);padding:0;overflow:hidden;
  margin:0}
.wp-block-details summary{display:flex;align-items:flex-start;gap:var(--space-4);
  padding:var(--space-5) var(--space-6);min-height:var(--tap-min);cursor:pointer;
  font:var(--weight-semibold) var(--text-lg)/1.35 var(--font-display);
  color:var(--text-heading);list-style:none;transition:var(--transition-control)}
.wp-block-details summary::-webkit-details-marker{display:none}
.wp-block-details summary::after{content:"";flex:none;width:20px;height:20px;
  margin-left:auto;background:currentColor;
  transition:transform var(--duration-base) var(--ease-standard);
  -webkit-mask:var(--sr-chevron) center/contain no-repeat;
  mask:var(--sr-chevron) center/contain no-repeat}
.wp-block-details[open] summary::after{transform:rotate(180deg)}
.wp-block-details summary:hover{background:var(--green-50);color:var(--green-800)}
.wp-block-details[open] summary{border-bottom:1px solid var(--border-subtle)}
.wp-block-details > :not(summary){padding-inline:var(--space-6);color:var(--text-muted)}
.wp-block-details > :not(summary):first-of-type{padding-top:var(--space-5)}
.wp-block-details > :not(summary):last-child{padding-bottom:var(--space-6);margin-bottom:0}


/* ═══════════════════════════════════════════════════════════════════════════
   12. FORMS AND CONTACT — 1.5px borders, 44px targets, sky focus ring,
       a visible error pattern that never relies on colour alone.

   The form is Contact Form 7; its field markup carries the sr-* classes below,
   set in inc/contact-form.php. Everything CF7 does not supply is there:
   a visible <label> for every field tied by for/id (3.3.2), autocomplete on
   name, email and telephone (1.3.5), required marked in text as well as with an
   aria-hidden asterisk, and errors announced in CF7's live region rather than
   signalled by a red border alone (1.4.1, 3.3.1).
   ═══════════════════════════════════════════════════════════════════════════ */

/* The form IS the section, not a column beside it. Seven fields stacked in a
   half-width column made a tall thin form against a short block of text; the
   full measure lets the fields pair up, which roughly halves its height. */
.sr-contact{max-width:1000px;margin-inline:auto;display:grid;gap:var(--space-8)}
.sr-form{display:grid;gap:var(--space-5);padding:var(--space-10)}
.sr-form .wpcf7-form{display:grid;gap:var(--space-5)}
.sr-form__row{display:grid;gap:var(--space-5);
  grid-template-columns:repeat(auto-fit,minmax(min(240px,100%),1fr))}
.sr-form__row--3{grid-template-columns:repeat(auto-fit,minmax(min(200px,100%),1fr))}
.sr-field{display:grid;gap:var(--space-2)}
.sr-label{font:var(--type-label);color:var(--sr-oncolour-heading)}
.sr-req{color:var(--coral-600)}
.sr-hint{font:var(--type-small);color:var(--text-subtle);margin:0}
.sr-input,.sr-select,.sr-textarea{width:100%;min-height:var(--control-h-md);
  padding:var(--space-3) var(--space-4);background:var(--surface-card);
  color:var(--text-body);border:1.5px solid var(--border-default);
  border-radius:var(--radius-sm);font:var(--type-body);
  transition:var(--transition-control)}
/* Contact Form 7 renders the textarea with rows="10", so its intrinsic height
   is ~306px; the design's is a bare textarea sized by min-height alone. Pin the
   height so the two agree, and keep it resizable. */
.sr-textarea{min-height:140px;height:140px;resize:vertical}
.sr-input:hover,.sr-select:hover,.sr-textarea:hover{border-color:var(--border-strong)}
.sr-input:focus-visible,.sr-select:focus-visible,.sr-textarea:focus-visible{
  border-color:var(--border-brand);box-shadow:var(--focus-ring);outline:none}
.sr-input::placeholder,.sr-textarea::placeholder{color:var(--text-subtle)}
.sr-select{appearance:none;padding-right:var(--space-10);
  background-image:var(--sr-chevron);background-repeat:no-repeat;
  background-position:right var(--space-4) center;background-size:18px}
.sr-check{display:flex;gap:var(--space-3);align-items:flex-start;
  padding:var(--space-3);margin-inline:calc(var(--space-3) * -1);
  border-radius:var(--radius-sm);min-height:var(--tap-min);cursor:pointer}
.sr-check:hover{background:var(--green-50)}
.sr-check input{width:22px;height:22px;flex:none;margin:2px 0 0;
  accent-color:var(--action-primary)}
.sr-check span{font:var(--type-small);color:var(--text-muted)}
.sr-form .wpcf7-acceptance .wpcf7-list-item{margin:0}
.sr-form .wpcf7-acceptance label{display:flex;gap:var(--space-3);align-items:flex-start}

/* ── Query loops ────────────────────────────────────────────────────────────
   Two layouts for the same query — a grid of cards, and ruled rows. The cards
   reuse .sr-card, so a post card and a Resources card are the same box from the
   same rule; only the contents differ.

   core/post-template renders a <ul> of <li>, so the grid's items are the list
   items and the card inside each one fills its row with height:100%. */
.sr-posts{list-style:none;margin:0;padding:0}
.sr-posts > li{margin:0}
.sr-post-thumb img{border-radius:var(--radius-md);width:100%;height:auto;display:block}
.sr-posts .wp-block-post-title{margin:0;font-size:var(--text-lg);
  font-family:var(--font-display);font-weight:var(--weight-semibold);
  line-height:var(--leading-snug)}
.sr-posts .wp-block-post-title a{color:inherit;text-decoration:none}
.sr-posts .wp-block-post-title a:hover{color:var(--green-700);text-decoration:underline;
  text-decoration-thickness:2px;text-underline-offset:3px}
.sr-posts .wp-block-post-excerpt__excerpt{margin:0}
.sr-posts .wp-block-post-excerpt__more-link{display:inline-block;margin-top:var(--space-2);
  font:var(--type-label);color:var(--text-link)}
/* Cards in a row are the same height, so a post with no image — or a short
   excerpt — leaves space under its text. Letting the excerpt grow and pushing
   the link to the foot puts every "Read this" on the same line, which makes
   the even height read as a decision rather than a gap. */
.sr-card .wp-block-post-excerpt{display:flex;flex-direction:column;flex:1 1 auto}
.sr-card .wp-block-post-excerpt__more-link{margin-top:auto;padding-top:var(--space-3)}

/* Rows. The rule between them is the separator; the last one does not need a
   line above the pagination. */
/* A double hyphen cannot be used in a dynamic block's className — see
   docs/editor-parity.md — so this modifier is a single hyphen. */
.sr-posts-list > li{padding-block:var(--space-6);
  border-bottom:1px solid var(--border-subtle)}
.sr-posts-list > li:last-child{border-bottom:0}
.sr-posts-list .wp-block-post-excerpt__excerpt{max-width:68ch}
.sr-post-row{display:grid;gap:var(--space-2)}
.sr-post-row > *{margin:0}

/* Pagination — the same control manners as everything else that is clickable. */
.wp-block-query-pagination{margin-top:var(--space-10);gap:var(--space-2)}
.wp-block-query-pagination :is(a,span.current){display:inline-flex;align-items:center;
  justify-content:center;min-height:var(--tap-min);min-width:var(--tap-min);
  padding-inline:var(--space-3);border-radius:var(--radius-sm);
  font:var(--type-label);color:var(--text-link);text-decoration:none}
.wp-block-query-pagination a:hover{background:var(--green-50);color:var(--green-800)}
.wp-block-query-pagination span.current{background:var(--action-primary);
  color:var(--text-on-brand)}

/* ── Comments ───────────────────────────────────────────────────────────────
   Core's comment blocks bring their own bare inputs. The site already has one
   form and one set of field manners; a second set on a post would read as a
   different site. These give core's fields the contact form's, so the two
   agree without the comment form having to be rebuilt block by block.

   Discussion is closed on this site by default — see docs/before-launch.md —
   so this styles something that is usually not on the page. It is here so that
   a post with comments open is not the one page nobody looked at. */
.sr-comments :is(input[type="text"],input[type="email"],input[type="url"],textarea){
  width:100%;min-height:var(--control-h-md);
  padding:var(--space-3) var(--space-4);background:var(--surface-card);
  color:var(--text-body);border:1.5px solid var(--border-default);
  border-radius:var(--radius-sm);font:var(--type-body);
  transition:var(--transition-control)}
.sr-comments textarea{min-height:140px;resize:vertical}
.sr-comments :is(input,textarea):hover{border-color:var(--border-strong)}
.sr-comments :is(input,textarea):focus-visible{border-color:var(--border-brand);
  box-shadow:var(--focus-ring);outline:none}
.sr-comments label{font:var(--type-label);color:var(--text-body)}
.sr-comments .comment-form-cookies-consent{display:flex;gap:var(--space-3);
  align-items:flex-start}
.sr-comments .comment-form-cookies-consent input{width:22px;height:22px;flex:none;
  margin:2px 0 0;accent-color:var(--action-primary)}
.sr-comments .comment-form-cookies-consent label{font:var(--type-small);color:var(--text-muted)}
.sr-comment{padding-block:var(--space-6);border-bottom:1px solid var(--border-subtle)}
.sr-comment__head{align-items:center;gap:var(--space-3);margin-bottom:var(--space-3)}
.sr-comment__head img{border-radius:var(--radius-pill)}
.sr-form__actions{display:flex;flex-wrap:wrap;align-items:center;
  justify-content:space-between;gap:var(--space-4)}
.sr-form__note{font:var(--type-small);color:var(--text-subtle);margin:0;flex:1 1 260px}
.sr-form .wpcf7-submit{display:inline-flex;align-items:center;justify-content:center;
  gap:var(--space-2);min-height:var(--control-h-lg);padding-inline:var(--space-8);
  background:var(--action-primary);color:var(--text-on-brand);
  border:1.5px solid transparent;border-radius:var(--radius-md);
  font:var(--weight-semibold) var(--text-md)/1.2 var(--font-display);cursor:pointer;
  transition:var(--transition-control)}
.sr-form .wpcf7-submit:hover{background:var(--action-primary-hover);transform:var(--lift-hover)}

/* CF7 messaging. Never colour alone: each message carries words, and the
   visible banner is aria-hidden because CF7 announces through its own
   visually-hidden live region — so nothing is read out twice. */
.wpcf7 form .wpcf7-response-output{margin:var(--space-4) 0 0;
  padding:var(--space-4) var(--space-5);border-width:1.5px;border-style:solid;
  border-radius:var(--radius-sm);font:var(--type-label)}
.wpcf7 form.sent .wpcf7-response-output{background:var(--status-success-bg);
  border-color:var(--status-success);color:var(--status-success)}
.wpcf7 form.invalid .wpcf7-response-output,
.wpcf7 form.unaccepted .wpcf7-response-output,
.wpcf7 form.failed .wpcf7-response-output,
.wpcf7 form.spam .wpcf7-response-output{background:var(--status-error-bg);
  border-color:var(--status-error);color:var(--status-error)}
.wpcf7-not-valid-tip{display:flex;gap:var(--space-2);align-items:flex-start;
  margin-top:var(--space-2);color:var(--status-error);font:var(--type-small);
  font-weight:var(--weight-semibold)}
.wpcf7-not-valid{border-color:var(--status-error) !important}
/* The honeypot must never reach a keyboard or a screen reader. */
.sr-hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}

.sr-contact__notes{display:grid;gap:var(--space-4) var(--space-8);
  grid-template-columns:repeat(auto-fit,minmax(min(300px,100%),1fr));
  margin:0;padding:0;list-style:none}
/* Block, not flex: the second note is a sentence with a telephone link inside
   it, and flex would make each run a separate item — breaking the sentence into
   columns and wrapping the number in the middle. */
.sr-contact__notes p{display:block;margin:0;font:var(--type-small);
  position:relative;padding-inline-start:calc(var(--sr-i-size) + var(--space-3))}
.sr-contact__notes p::before{position:absolute;inset-inline-start:0;top:2px}


/* ═══════════════════════════════════════════════════════════════════════════
   13. THEME SWITCH — one button that flips between light and dark

   The icon shown is the theme the press will move TO, matching the button's
   accessible name, so a screen reader user is never told "dark theme" while
   looking at the dark theme.
   ═══════════════════════════════════════════════════════════════════════════ */

.sr-theme-switch{display:inline-flex;align-items:center;justify-content:center;
  width:var(--control-h-md);height:var(--control-h-md);padding:0;
  border:1px solid var(--border-subtle);border-radius:var(--radius-pill);
  background:var(--surface-sunken);color:var(--text-muted);cursor:pointer;
  transition:var(--transition-control)}
.sr-theme-switch:hover{background:var(--surface-card);color:var(--green-700);
  border-color:var(--green-200);transform:var(--lift-hover)}
.sr-theme-switch:active{transform:var(--press-active)}
.sr-theme-switch > span{--sr-i-size:20px}
.sr-theme-switch .sr-theme-switch__moon{display:block}
.sr-theme-switch .sr-theme-switch__sun{display:none}
[data-theme="dark"] .sr-theme-switch .sr-theme-switch__moon{display:none}
[data-theme="dark"] .sr-theme-switch .sr-theme-switch__sun{display:block}
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]) .sr-theme-switch .sr-theme-switch__moon{display:none}
  :root:not([data-theme="light"]) .sr-theme-switch .sr-theme-switch__sun{display:block}
}


/* ═══════════════════════════════════════════════════════════════════════════
   14. ADDRESS

   Rows are paragraphs rather than a list, because each line carries a DIFFERENT
   icon and core/list-item does not support a per-item class.
   ═══════════════════════════════════════════════════════════════════════════ */

.sr-address{display:grid;gap:var(--space-3);margin:0;padding:0;
  font:var(--type-body);font-style:normal}
.sr-address p{display:flex;gap:var(--space-3);margin:0;align-items:flex-start}
.sr-address p::before{margin-top:4px;color:var(--green-600)}
:is(.sr-solid,.sr-tint,.sr-showcase__card) .sr-address p::before{color:currentColor}
.sr-address a{color:inherit}


/* ═══════════════════════════════════════════════════════════════════════════
   15. FOOTER

   The footer and utility bar sit on brand green rather than the near-black ink
   band, so the muted foreground had to be re-measured: --on-ink-muted #9D9D9C
   was tuned against #22221F and only reaches 3.67:1 on #2E4A16. Both scope a
   lighter value that clears 4.5:1 at 15px.
   ═══════════════════════════════════════════════════════════════════════════ */

.sr-footer{background:var(--sr-footer-bg);color:var(--on-ink-body);
  padding-block:var(--space-16) var(--space-8);
  padding-inline:clamp(16px,4vw,48px);--on-ink-muted:#C4C4C0}
.sr-footer__inner{max-width:var(--layout-max);margin-inline:auto}
.sr-footer__cols{display:grid;gap:var(--space-10);
  grid-template-columns:repeat(auto-fit,minmax(min(220px,100%),1fr));
  padding-bottom:var(--space-12)}
.sr-footer__logo img{height:64px;width:auto;margin-bottom:var(--space-4)}
.sr-footer :is(h2,h3){font:var(--type-label);color:var(--on-ink-heading);
  margin:0 0 var(--space-4);text-transform:none}
.sr-footer p{font:var(--type-small);color:var(--on-ink-muted);max-width:36ch}
.sr-footer ul{list-style:none;margin:0;padding:0;display:grid;gap:var(--space-1)}
.sr-footer li{margin:0}
.sr-footer a{display:inline-flex;align-items:center;min-height:var(--tap-min);
  font:var(--type-small);color:var(--on-ink-body);text-decoration:none;
  border-radius:var(--radius-xs)}
.sr-footer a:hover{color:var(--neutral-0);text-decoration:underline;
  text-decoration-thickness:2px;text-underline-offset:3px}
.sr-footer .sr-address{font:var(--type-small);color:var(--on-ink-body)}
.sr-footer .sr-address p{max-width:none;color:var(--on-ink-body)}
.sr-footer .sr-address p::before{color:var(--yellow-300)}
.sr-footer .sr-footer__brand p::before{color:var(--yellow-300)}
/* A social link carries its mark INSIDE the anchor, not beside it. On the
   paragraph the icon sat outside the link — a logo the visitor aims at and
   misses, and 20px of the row that looked clickable and was not. On the anchor
   the two are one control, and the 44px tap target every footer link has
   covers both.

   It also fixes where the mark sat. Section 18 hangs a paragraph's icon near
   the paragraph's top, which is right for several lines of copy and wrong for
   a one-line link whose text is centred in a 44px anchor — it left the mark
   floating nine pixels above the word. As part of the link it simply shares
   the line. */
/* The standfirst above it is body copy, and a link tucked straight under a
   paragraph reads as part of it. Its own space, and no bottom margin because
   it is the last thing in the column. */
.sr-social{margin:var(--space-5) 0 0}
.sr-footer__bar{border-top:1px solid var(--on-ink-border);padding-top:var(--space-6);
  display:flex;flex-wrap:wrap;justify-content:space-between;gap:var(--space-4);
  font:var(--type-small);color:var(--on-ink-muted)}
.sr-footer__bar p{margin:0}
.sr-footer__bar ul{display:flex;flex-wrap:wrap;gap:var(--space-6)}
.sr-footer :focus-visible{box-shadow:0 0 0 2px var(--sr-footer-bg),0 0 0 5px var(--sky-300)}
/* The footer is the brand band in both themes, so it always shows the
   dark-surface lockup, whatever the page theme is. */
.sr-footer .wp-block-site-logo .sr-logo--light{display:none}
.sr-footer .wp-block-site-logo .sr-logo--dark{display:block}


/* ═══════════════════════════════════════════════════════════════════════════
   16. STICKY MOBILE CTA — the one permitted fixed element besides the header
   ═══════════════════════════════════════════════════════════════════════════ */

.sr-sticky-cta{position:fixed;inset-inline:0;bottom:0;z-index:60;display:none;
  padding:var(--space-3) var(--space-4)
    calc(var(--space-3) + env(safe-area-inset-bottom,0px));
  background:var(--surface-glass);
  -webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);
  border-top:1px solid var(--border-subtle)}
.sr-sticky-cta .wp-block-buttons,.sr-sticky-cta .wp-block-button{width:100%}
.sr-sticky-cta .wp-block-button__link{width:100%}
@media (max-width:719px){.sr-sticky-cta{display:block}body{padding-bottom:76px}}


/* ═══════════════════════════════════════════════════════════════════════════
   17. PROSE AND NOTES (policies, long-form)

   Policy text sits on the page surface deliberately. It is the longest
   continuous reading on the site and it is legal content; a tint behind it buys
   nothing.
   ═══════════════════════════════════════════════════════════════════════════ */

:is(.sr-prose,.is-style-sr-prose){max-width:var(--layout-narrow)}
:is(.sr-prose,.is-style-sr-prose) h2{margin-top:var(--space-12)}
:is(.sr-prose,.is-style-sr-prose) h3{margin-top:var(--space-8);font-size:var(--text-xl)}
:is(.sr-prose,.is-style-sr-prose) > :first-child{margin-top:0}
:is(.sr-note,.is-style-sr-note){display:flex;gap:var(--space-3);padding:var(--space-5) var(--space-6);
  border-radius:var(--radius-lg);background:var(--status-info-bg);
  color:var(--sky-800);font:var(--type-small)}
:is(.sr-note,.is-style-sr-note)::before{flex:none;margin-top:2px}
:is(.sr-note,.is-style-sr-note) strong{color:var(--sky-800)}
.sr-note--warning{background:var(--status-warning-bg);color:var(--yellow-800)}
.sr-note--warning strong{color:var(--yellow-800)}


/* ═══════════════════════════════════════════════════════════════════════════
   18. ICONS — Lucide, 2px stroke, round caps, 24px grid. Always paired with a
       label; an icon-only control carries an accessible name. Never emoji.

   Drawn as CSS masks rather than inline SVG or an icon font: they take
   currentColor, so an icon adapts to whichever band it lands on, and there is
   no third-party request. The glyphs are in assets/tokens/icons.css.
   ═══════════════════════════════════════════════════════════════════════════ */

.sr-icon,[class*="sr-i--"]{--sr-i-size:20px}
/* A chip: the icon block sizes its own box, and the contexts above give it the
   chip's fill. Standalone chips use these variants. */
.sr-icon{display:inline-flex;align-items:center;justify-content:center;flex:none}
.sr-icon--green,.sr-icon--sky,.sr-icon--yellow{display:flex;width:56px;height:56px;
  border-radius:var(--radius-lg);--sr-i-size:28px}
.sr-icon--green{background:var(--green-50);color:var(--green-700)}
.sr-icon--sky{background:var(--sky-50);color:var(--sky-700)}
.sr-icon--yellow{background:var(--yellow-50);color:var(--yellow-700)}
.sr-icon--plain{width:auto;height:auto;background:none;border-radius:0;color:inherit}
.sr-icon--sm{width:48px;height:48px;--sr-i-size:24px}
.sr-icon--round{border-radius:var(--radius-pill)}
.sr-solid :is(:is(.sr-card,.is-style-sr-card),:is(.sr-oncolour,.is-style-sr-oncolour)) .sr-icon--green{background:var(--green-50);color:var(--green-700)}
/* An icon on a paragraph is set as a hanging indent, not a flex row. Flex would
   make every inline child — the text either side of a link, the link itself — a
   separate flex item, which breaks a sentence into fragments and wraps a phone
   number mid-number. The gutter keeps the copy as ordinary inline text. */
:is(p,li,dt,dd)[class*="sr-i--"]{position:relative;
  padding-inline-start:calc(var(--sr-i-size) + var(--space-3))}
:is(p,li,dt,dd)[class*="sr-i--"]::before{position:absolute;
  inset-inline-start:0;top:.18em}
/* Links and summaries hold a single run of text, so a flex row is right there. */
:is(a,summary)[class*="sr-i--"]{display:inline-flex;gap:var(--space-3);
  align-items:flex-start}
.sr-hint::before{--sr-i-size:16px}


/* ═══════════════════════════════════════════════════════════════════════════
   19. EDITOR-ONLY CORRECTIONS

   The editor canvas has no sticky header and no scroll state, so a couple of
   rules need neutralising there. Loaded via add_editor_style.
   ═══════════════════════════════════════════════════════════════════════════ */

.editor-styles-wrapper .sr-header{position:static}
.editor-styles-wrapper .sr-sticky-cta{position:static;display:block}
.editor-styles-wrapper body{padding-bottom:0}

/* ── What the canvas still does differently ─────────────────────────────────
   The markup is now the same in both: every block of this theme's own builds
   its children with useInnerBlocksProps, so the canvas has no wrapper divs the
   front end lacks and the DOM the selectors above were written against is the
   DOM they meet. See docs/editor-parity.md.

   One difference is left, and it cannot be fixed in the markup. WordPress
   loads core's layout CSS into the canvas prefixed with `.editor-styles-wrapper`,
   which scores it 0,2,0 — while on the front end the same rules are wrapped in
   :where() and score 0,0,0. A single-class rule in this stylesheet therefore
   wins on the page and loses in the editor, silently. The rules below carry
   the same prefix so the theme keeps its own values in both.

   Every value here is one the front end already renders. Nothing below is a
   design decision, and nothing below should ever set something the stylesheet
   above does not. `node qa/editor-parity.mjs` is what proves that.
   ─────────────────────────────────────────────────────────────────────────── */

/* Declared margins that core's prefixed reset flattens. Placed before the
   container resets, mirroring the order of the originals, so a section head
   still zeroes its own children and nothing else does. */
.editor-styles-wrapper :is(.sr-eyebrow,.is-style-sr-eyebrow){margin:0 0 var(--space-3)}
.editor-styles-wrapper .sr-convo__by.sr-convo__by{margin:0 0 var(--space-4)}

/* The container resets, at the canvas's weight. */
.editor-styles-wrapper :is(.sr-header__inner,.sr-utility-bar__inner,.sr-footer__inner,.sr-footer__cols,
   .sr-header__actions,.sr-hero__inner,.sr-services,.sr-services__item,
   .sr-reasons,.sr-reasons__item,.sr-convo,.sr-convo__item,.sr-about__top,
   .sr-about__body,.sr-about__foot,.sr-about__lockup,.sr-signature,
   .sr-showcase__panel,.sr-showcase__card,.sr-contact,.sr-contact__notes,
   .sr-grid,.sr-downloads,.sr-faq,.sr-address,:is(.sr-checklist,.is-style-sr-checklist),
   :is(.sr-strip,.is-style-sr-strip),:is(.sr-panel,.is-style-sr-panel),
   .sr-accreditations,.sr-form,.sr-field,.sr-section-head) > *{margin-block:0}
.editor-styles-wrapper :is(.sr-card,.is-style-sr-card,.sr-panel,.is-style-sr-panel,
   .sr-showcase__card,.sr-services__item,.sr-reasons__item) > *{margin:0}
.editor-styles-wrapper :is(.sr-prose,.is-style-sr-prose) > :first-child{margin-top:0}
/* A card pushes its list to its foot with an auto top margin; the reset above
   would flatten it. */
.editor-styles-wrapper :is(.sr-card,.is-style-sr-card) > ul{margin-top:auto}
/* The button carries a 1.5px transparent border so that outlining it does not
   move it. In the canvas the label is a contenteditable div rather than an
   anchor and the border is lost, which makes every button 3px narrower. */
.editor-styles-wrapper :is(.sr-btn,.wp-block-button__link,.wp-element-button){border-width:1.5px;border-style:solid}

/* The theme's own measures and band spacing, at the canvas's weight. */
.editor-styles-wrapper :is(.sr-hero,.sr-section,.sr-utility-bar,.sr-header,.sr-footer){margin-block:0}
.editor-styles-wrapper :is(.sr-main,.is-root-container) > *{margin-block:0}
.editor-styles-wrapper :is(.sr-narrow,.is-style-sr-narrow){max-width:var(--layout-narrow)}
.editor-styles-wrapper :is(.sr-prose,.is-style-sr-prose){max-width:var(--layout-narrow)}
.editor-styles-wrapper .sr-section-head{margin-bottom:var(--space-12)}
.editor-styles-wrapper .wp-block-columns.sr-section-head--split{margin-bottom:var(--space-12)}

/* Component spacing, restated at the canvas's weight. Each of these is a value
   the stylesheet above already declares; core's blockGap and its
   last-child margin reset outrank the original only inside the editor. */
/* Only these three opt out of blockGap on the front end; the rest of a
   section's children keep it, so this is a list and not a blanket. */
.editor-styles-wrapper :is(.sr-services,.sr-reasons,.sr-downloads){margin-block-start:0}
.editor-styles-wrapper :is(.sr-statement,.is-style-sr-statement){margin:0 0 var(--space-6)}
.editor-styles-wrapper .sr-hero__tagline{margin:0 0 var(--space-6)}
.editor-styles-wrapper .sr-hero__actions{gap:var(--space-3);margin-top:var(--space-8)}
.editor-styles-wrapper p + .wp-block-buttons{margin-top:var(--space-8)}
.editor-styles-wrapper .sr-about__body{gap:var(--space-6) var(--space-12);margin-top:var(--space-12)}
.editor-styles-wrapper .sr-about__foot{gap:var(--space-10);margin-top:var(--space-12)}
.editor-styles-wrapper .sr-accreditations.sr-accreditations{gap:var(--space-5);margin-top:var(--space-8)}

/* Narrow-screen rhythm. The design ships these as one block at 719px, after
   its 639px and 399px logo rules — which means the wider query wins and the
   logo never actually reaches its smaller sizes. The intended progression is
   88 → 64 → 52 → 44, so the logo step is placed here in width order and the
   spacing rules follow the design as written. */
@media (max-width:719px){
  .sr-section{padding-block:var(--space-16)}
  .sr-section--lg{padding-block:var(--space-20)}
  :is(.sr-card,.is-style-sr-card){padding:var(--space-6)}
  .sr-services__item{padding:var(--space-6)}
  .sr-showcase__card{padding:var(--space-8)}
  .sr-form{padding:var(--space-6)}
}
@media (min-width:640px) and (max-width:719px){
  .sr-header__brand img{height:64px}
}

@media print{
  .sr-utility-bar,.sr-header__actions,.sr-sticky-cta,.sr-theme-switch{display:none}
}

/* Used for one frame when an in-page link is clicked, so the header's final
   compressed height can be measured before the browser computes the jump. */
.sr-header--instant,.sr-header--instant *{transition:none !important}

/* The Opening hours block's editor UI. The front end is a plain <dl>; this is
   the paired day/time inputs the client types into. */
/* The hours controls live in the sidebar, so they are laid out there rather
   than in the canvas — the canvas renders the block's real output. */
.sr-hours__row-edit{display:grid;gap:var(--space-2);margin-bottom:var(--space-4)}
/* serverSideRender needs an element to hang the block props on. Neither
   wrapper exists on the front end, so neither may generate a box between the
   section and the thing it is previewing. */
.editor-styles-wrapper :is(.sr-hours-preview,.sr-contact-form-preview){display:contents}
/* Contact Form 7 injects its spinner with JavaScript, which the canvas does
   not run — leaving the submit cell 72px narrower in the editor than on the
   page, and the note beside it correspondingly wider. The spinner is
   visibility:hidden until a submission, so the front end shows empty space
   there too: 24px wide with 24px either side. The space is reserved rather
   than the element faked, so the row breaks at the same point in both.
   The plugin's own stylesheet is loaded into the canvas by
   inc/contact-form.php, which is what hides its response output. */
.editor-styles-wrapper .wpcf7-submit.has-spinner{margin-inline-end:72px}
