/* First Things First Accounting theme. Built by bin/build.php from assets/css/parts. Edit the parts, not this file. */

/* ==== 00-tokens.css ==== */
/* ==========================================================================
   First Things First Accounting — design tokens
   TIER: Premium · POSTURE: professional-editorial · COLOUR MODE: quiet luxury
   Colour derived from the client logo (cyan #18A8D8, 195°) deepened to 203°.
   Every ratio below was measured — see 01-brief/COLOUR-SYSTEM.md
   ========================================================================== */

:root{

  /* ---- Ground -------------------------------------------------------- */
  --ground:      #F6F8FA;
  --surface:     #FFFFFF;
  --tint:        #E9F0F6;
  --line:        #D7E0E9;
  --field:       #788B9C;   /* 3.30:1 page · 3.52:1 card · 3.06:1 tint */

  --navy:        #0A1C2B;
  --navy-2:      #13293B;

  /* RGB triplets so alpha can be composed without a second hex */
  --navy-rgb:    10 28 43;
  --paper-rgb:   246 248 250;

  /* ---- Type ---------------------------------------------------------- */
  --fg:          #16222E;   /* 15.15:1 page · 16.12:1 card · 14.02:1 tint */
  --fg-dim:      #4A5C6B;   /*  6.50:1 page ·  6.92:1 card ·  6.02:1 tint */
  --fg-mute:     #5C6E7E;   /*  4.95:1 page ·  5.27:1 card ·  4.58:1 tint */

  /* ---- The footer's blue ---------------------------------------------
     She asked for blue and gray from barbri.com (BRIEF.md), never black — and at
     --navy the footer read as black. barbri's own darkest is #001722 and their blue
     is #2A5488/#2F619A (hue 212-213), so the footer runs a gradient from a blue in
     that family down into --navy. --blue-deep is the LIGHTEST point, which is the
     one that has to carry the type: links 5.68:1 there and 8.41:1 at the navy end. */
  --blue-deep:   #153A5E;   /* hue 210, barbri's family. The footer's top stop. */

  --fg-on-dark:      #E8EEF4;  /* 14.80:1 on navy */
  --fg-dim-on-dark:  #A6B7C6;  /*  8.41:1 navy · 7.25:1 navy-2 */
  --fg-mute-on-dark: #8496A8;  /*  5.69:1 navy · 4.91:1 navy-2 */
  --fg-label-on-blue:#B6C4D2; /* the footer's column labels. The solid-navy mute (#8496A8)
                                 measured 4.33:1 on --blue-deep — under the floor — so the
                                 label keeps its hue and chroma and only gains lightness:
                                 6.57:1 on --blue-deep, 9.73:1 on --navy. */

  /* ---- Accent — quiet luxury: ink, never a large fill ----------------- */
  --accent:         #0D6CA6;  /* 5.31:1 page · 5.66:1 card · 4.92:1 tint */
  --accent-press:   #095480;  /* 8.10:1 card */
  --accent-on-dark: #45A6DF;  /* 6.40:1 navy · 5.52:1 navy-2 */
  --accent-on-scrim:#8ACBEF;  /* vs a white frame: 6.42:1 on the .86 band (the tick marks).
                                 On ANY .70 scrim — hero and closing CTA alike — it is
                                 3.64:1 against a pure-white frame: decorative rule only
                                 there (the hero hairline's centre), never text. The close
                                 eyebrow used it as text until verification round 1; it is
                                 --fg-mute-on-scrim now. */
  --fg-mute-on-scrim:#E0E7ED; /* label grey on a .70 scrim (hero facts, logo sub-line, closing
                                 eyebrow) over a pure-white frame —
                                 5.16:1 (the old #C9D4DE reached 4.28:1 there). A scrim-derived
                                 text step, not a palette colour; the solid-navy mute
                                 (#8496A8) is far under 3:1 on a scrim. */
  --on-accent:      #FFFFFF;  /* 5.66:1 on --accent */

  --ring-focus:         #0D6CA6;
  --ring-focus-on-dark: #6FBEEA;

  --scrim: 0.70;   /* Frame-independent. Navy @.70 over a PURE-WHITE frame = rgb(84,96,107):
                      #E8EEF4 = 5.51:1 · #E0E7ED = 5.16:1 · the 75% white button border =
                      4.45:1 (UI, needs 3). So her 10-15 clips can be any brightness and
                      every hero pair still passes. At the old .52 the 13px nav links
                      measured 4.03:1 over the lamp highlight of the v1 hero frame (peaks
                      were 214 under the h1, 213 under the nav). The v2 frame has no lamp;
                      the scrim stays at .70 for the clips. Measured, not guessed. */

  /* ---- Semantic — separate axis, never the accent -------------------- */
  --ok:#1B7A4B; --warn:#9A6410; --bad:#B23025;

  /* ---- Depth — three layers, negative spread, navy-tinted ------------ */
  --shadow-soft:  0 1px 1px  rgb(var(--navy-rgb) / .04),
                  0 12px 24px -12px rgb(var(--navy-rgb) / .09),
                  0 32px 64px -32px rgb(var(--navy-rgb) / .15);
  --shadow-float: 0 2px 4px  rgb(var(--navy-rgb) / .05),
                  0 24px 48px -16px rgb(var(--navy-rgb) / .13),
                  0 60px 120px -40px rgb(var(--navy-rgb) / .20);

  /* hairlines are rings, not borders */
  --hair:        0 0 0 1px rgb(var(--navy-rgb) / .09);
  --hair-strong: 0 0 0 1px rgb(var(--navy-rgb) / .16);
  --hair-inv:    0 0 0 1px rgb(255 255 255 / .12);

  /* ---- Type families ------------------------------------------------- */
  --font-display:'Gelasio', Georgia, 'Times New Roman', serif;   /* Georgia metrics */
  /* the '… Fallback' faces are Arial re-sized to the webfont's metrics (main.css), so the
     swap does not move the lead, the nav or the labels */
  --font-body:'Roboto', 'Roboto Fallback', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-label:'Montserrat', 'Montserrat Fallback', system-ui, sans-serif;   /* nav, buttons, labels */

  /* ---- Scale — neutral steps, never named after a tag ---------------- */
  --fs-01:2.5rem;     /* 40px @375 — hero. 'Clear numbers.' measures 271px, inside the
                         288px column at 320. H1 outranks H2 at every breakpoint. */
  --fs-02:1.875rem;   /* 30 */
  --fs-02b:1.625rem;  /* 26 — the step between section H2 and card H3: service detail titles */
  --fs-03:1.375rem;   /* 22 */
  --fs-04:1.125rem;   /* 18 */
  --fs-05:1.0625rem;  /* 17 */
  --fs-06:0.9375rem;  /* 15 */
  --fs-07:0.8125rem;  /* 13 */
  --fs-08:0.75rem;    /* 12 — the floor. Nothing functional goes under it */

  /* ---- Roles --------------------------------------------------------- */
  --t-hero:var(--fs-01);
  --t-section:var(--fs-02);
  --t-sub-lg:var(--fs-02b);  /* service detail + band titles, lead review quote */
  --t-sub:var(--fs-03);
  --t-quote:var(--fs-03);
  --t-card:var(--fs-04);
  --t-lead:var(--fs-04);
  --t-detail:1.125rem;       /* 18px, fixed at every width — detail prose must not share the
                                hero lead's 21/42 register (five roles were reading as one) */
  --t-body:var(--fs-05);
  --t-small:var(--fs-06);
  --t-label:var(--fs-07);
  --t-micro:var(--fs-08);    /* logo sub-line; hero fact labels on phones */

  --lh-display:1.1;     /* the reference runs 37.5/41.25 = 1.10 */
  --lh-sub:1.2;
  --lh-lead:2.0;        /* the reference runs 21/42 = 2.0 */
  --lh-body:1.65;
  --lh-detail:1.78;     /* 18 x 1.78 = 32.04px — the reference's detail prose runs 18/32 */
  --lh-label:1.3;       /* tracked uppercase labels were inheriting 1.65 and wrapping loose */
  --ls-display:-0.007em; /* the reference runs -0.25px on 37.5px = -0.0067em */
  --ls-display-lg:-0.02em; /* display sizes (>=26px): -1.04px on the 52px H2. Small serif keeps -0.007em */
  --ls-label:0.14em;
  --ls-label-tight:0.06em; /* phone fact labels: 'CONSULTATION' is 106px at 12px/.06em and must fit a 109px third at 375 (127.6px at 13/.14) */
  --ls-btn:0.055em;     /* the reference runs 1px on 18px */
  --t-btn:0.9375rem;    /* 15px on phones; the reference's 18px from 768 up */

  /* ---- Spacing — Premium lifts the section roles one step ------------ */
  --sp-1:0.25rem; --sp-2:0.5rem;  --sp-3:0.75rem; --sp-4:1rem;
  --sp-5:1.5rem;  --sp-6:2rem;    --sp-7:3rem;    --sp-8:4rem;
  --sp-9:5rem;    --sp-10:7rem;

  --space-section:    clamp(4.5rem, 9vw, 9rem);
  --space-section-lg: clamp(5.5rem, 12vw, 12rem);
  /* gaps INSIDE a section. 6vw against the 9vw section step: section boundary (2 x 9vw)
     : block gap = 3.0 at 375, 768 and 1280 — was 2.0, so services read as four sections */
  --space-block:      clamp(3rem, 6vw, 4.75rem);
  --space-section-sm: clamp(2.5rem, 5vw, 4rem);

  --gutter:1rem;
  --container:75rem;   /* 1200px */
  --measure:65ch;

  /* ---- Radius — one concentric scale, px (HOUSE-STYLE §1) ------------ */
  /* The reference keeps everything on a hairline radius — its buttons measure 4px and its
     paired photographs 5px. Ours had drifted to 18px on every panel and photograph, which
     reads softer and more consumer than the reference does. One radius now, 4px, on every
     rectangle: photographs, cards, panels and fields alike. Circles keep --r-pill.
     --r-sm and --r-lg had no users left and are gone. */
  --r-btn:4px;        /* the reference's button radius */
  --r-md:4px;         /* every rectangle: photographs, cards, panels, form fields */
  --r-pill:999px;
  --frame-pad:6px;

  --header-h:76px;      /* REFERENCE-SPEC: 96 -> 76 on scroll. This is the scrolled (solid) bar; it was 74 */
  --header-drop:10px;   /* over the hero the bar reads as 96px: its contents sit (96 - 76) / 2 lower — centre line 48px — and ride up on scroll */

  /* ---- Motion — two easings only ------------------------------------- */
  --ease-spring:cubic-bezier(.32,.72,0,1);    /* movement */
  --ease-expo:cubic-bezier(.16,1,.3,1);       /* opacity, hero sequence */
  --dur-fast:200ms;
  --dur-base:400ms;
  --dur-menu:480ms;     /* one menu link fading in; six links at 45ms steps end at 845ms */
  --dur-zoom:600ms;     /* image zoom on card hover — .8s read as lag behind the 400ms lift */
  --dur-reveal:900ms;
  --dur-stagger:620ms;  /* rows that arrive one after another use a SHORTER reveal, so the
                           steps between them are legible. At 900ms a 150ms step is 17% of the
                           animation and the four cards read as one slab; at 620ms it is 24%
                           and you can see them land in order. Last card: 450 + 620 = 1070ms,
                           inside the 1100ms house cap. */
  --dur-line:1000ms;    /* the process line drawing itself (was 1200 on `width`) */
  --dur-hero:1000ms;        /* rise + settle. Line 2: 80 + 1000 = 1080ms */
  --dur-drift:6.4s;     /* hero still drifting 1.06 -> 1. Equals HOLD in main.js, so the drift
                           lands as the slide hands over (was 9s against a 5.2s hold) */
  --dur-hero-fade:640ms;    /* lead, CTA, rule, facts. Last in: 460 + 640 = 1100ms — the cap */

  --grain-opacity:.038;

  color-scheme:light;
}


/* ==== 01-fonts.css ==== */
/* Faces from the prototype. Paths rewritten to the theme. */



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

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

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

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

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

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

@font-face{font-family:'Roboto Fallback';src:local('Arial'),local('ArialMT');
  size-adjust:99.48%;ascent-override:93.25%;descent-override:24.54%;line-gap-override:0%;}

@font-face{font-family:'Montserrat Fallback';src:local('Arial Bold'),local('Arial-BoldMT');
  font-weight:600 700;
  size-adjust:105.2%;ascent-override:92.01%;descent-override:23.86%;line-gap-override:0%;}


/* ==== 02-buttons.css ==== */
/*
 * Button and arrow link — ported from the prototype's main.css ("Island button" and
 * "Arrow link"), verbatim. WordPress's core/buttons is mapped onto .cmp-btn in
 * 03-core-buttons.css, so a button added in the editor looks the same.
 */

/* ---- Island button — pill, sentence case, arrow in its own capsule -------- */
.cmp-btn{position:relative;display:inline-flex;align-items:center;justify-content:center;gap:var(--sp-4);
  max-width:100%;min-width:0;flex-wrap:wrap;min-height:4rem;
  padding:1.125rem 3rem 1.125rem 1.75rem;border-radius:var(--r-btn);
  font-family:var(--font-label);font-weight:700;font-size:var(--t-btn);
  letter-spacing:var(--ls-btn);line-height:1.2;text-transform:uppercase;
  text-decoration:none;cursor:pointer;border:2px solid transparent;
  transition:transform var(--dur-fast) var(--ease-spring),
             background-color var(--dur-fast) var(--ease-expo),
             border-color var(--dur-fast) var(--ease-expo),
             color var(--dur-fast) var(--ease-expo);}
.cmp-btn__label{min-width:0;overflow-wrap:normal;} /* labels break between words, never inside one */
.cmp-btn__icon{position:absolute;right:1.125rem;top:50%;translate:0 -50%;
  inline-size:1.25rem;block-size:1.25rem;display:grid;place-items:center;
  transition:translate var(--dur-base) var(--ease-spring);}
.cmp-btn__icon svg{width:1.25rem;height:1.25rem;}
.cmp-btn:hover .cmp-btn__icon{translate:4px -50%;}
.cmp-btn:active{transform:scale(.985);}

.cmp-btn--solid{background:var(--accent);color:var(--on-accent);border-color:var(--accent);}
/* The reference's service-page button: filled, not outlined, at the full size. Navy
   rather than its black, and the same hover the header's filled button uses. */
.cmp-btn--fill{background:var(--navy);border-color:var(--navy);color:var(--fg-on-dark);}
.cmp-btn--fill:hover{background:var(--accent);border-color:var(--accent);color:var(--on-accent);}
/* The same button, drawn as an outline: for a second call to action further down a page,
   where a filled one would argue with the hero's. The base class alone is not this — its
   border is transparent, so `.cmp-btn` by itself renders as bare text. */
.cmp-btn--line{background:transparent;color:var(--navy);border-color:var(--navy);}
.cmp-btn--line:hover{background:var(--navy);border-color:var(--navy);color:var(--fg-on-dark);}

.cmp-btn--solid:hover{background:var(--accent-press);border-color:var(--accent-press);color:var(--on-accent);}

.cmp-btn--quiet{background:transparent;color:var(--accent);
  border-color:rgb(var(--navy-rgb) / .55);} /* composite vs ground 3.84:1 · card 3.91 · tint 3.75 (UI needs 3). Was .5 = 3.24 on the tint — it passed with no room for a tint nudge; .38 measured 2.36 */

.cmp-btn--quiet:hover{border-color:var(--accent);color:var(--accent-press);}

.cmp-btn--on-dark{background:transparent;color:var(--fg-on-dark);border-color:rgb(255 255 255 / .75);}

/* Hover is carried by the BORDER going to full white, not by the fill. Measured on the .70
   scrim over a pure-white frame, rgb(84,96,107): a white @.10 fill lifts the ground to
   rgb(101,112,121) and the 18px/700 label (under the 18.66px bold threshold, so 4.5 applies)
   drops to 4.33:1. At .06 the ground is rgb(94,106,116) and the label holds 4.77:1. The old
   hover also LOWERED the border from .75 to .70 (4.47 -> 4.13:1); now it rises to 6.44:1
   against the scrim, 5.57:1 against its own fill. On the .86 band the label is 8.3:1. */
.cmp-btn--on-dark:hover{background:rgb(255 255 255 / .06);border-color:rgb(255 255 255 / 1);color:var(--fg-on-dark);}

.cmp-btn--sm{min-height:2.75rem;padding:.75rem 1.5rem;font-size:var(--t-label);}

/* ---- Arrow link ---------------------------------------------------------- */


/* ==== 03-core-buttons.css ==== */
/*
 * Core's Button block, given the design's button.
 *
 * HAND-WRITTEN. The prototype's button is one element — <a class="cmp-btn"> — and the
 * importer puts that class on the block's WRAPPER, because core/button has nowhere else
 * to put it. Core then renders an <a class="wp-block-button__link"> inside, with its own
 * padding, background and radius, so every button was painted twice and stood 101px tall
 * against the design's 66px.
 *
 * The wrapper keeps the look (02-buttons.css, ported from the prototype) and gives up its
 * padding; the anchor takes that padding instead, so it fills the pill and the whole pill
 * is clickable — not just the words in the middle of it.
 */

.site-main .wp-block-button.cmp-btn{
	padding:0;
}

.site-main .wp-block-button.cmp-btn > .wp-block-button__link{
	/* Core's own button styling goes entirely; everything visible is the wrapper's. */
	all:unset;
	box-sizing:border-box;
	display:inline-flex;
	align-items:center;
	justify-content:center;
	gap:var(--sp-4);
	width:100%;
	min-width:0;
	max-width:100%;
	flex-wrap:wrap;
	padding:var(--btn-pad);
	border-radius:inherit;
	color:inherit;
	font:inherit;
	letter-spacing:inherit;
	text-transform:inherit;
	text-decoration:none;
	cursor:pointer;
}

/* The design's button padding, as a token, because the anchor carries it here and the
   prototype sets it on the button itself — at three widths (responsive.css). Restating
   only the base value pinned the link at 1.75rem where the design pays 3.375rem from
   768 up, and every button came out 34px narrower. All three live in 92-responsive.css's
   companion below, so the breakpoints stay in one place conceptually even though the
   token must be declared here.  */
:root{
	--btn-pad:1.125rem 3rem 1.125rem 1.75rem;
	--btn-pad-sm:.75rem 1.5rem;
}

/* The small header button pays less on each side, as the prototype's --sm does. */
.site-main .wp-block-button.cmp-btn--sm > .wp-block-button__link{
	padding:var(--btn-pad-sm);
}

/* A button block on its own still sits in the flow like the prototype's anchor. */
.site-main .wp-block-buttons > .wp-block-button.cmp-btn{
	display:inline-flex;
}

/* The arrow.
 *
 * In the prototype it is <svg><use href="#i-arrow"></svg> inside the label span. A
 * core/button keeps only inline text, and the importer drops <svg> from it, so the span
 * arrived empty: no arrow, and the button 38px narrower than the design. The same shape
 * is drawn here as a mask, which needs no markup at all and takes the button's own
 * colour — so it flips on a dark band exactly as the SVG did.
 */
.site-main .cmp-btn__icon{
	display:inline-block;
	inline-size:1.25rem;
	block-size:1.25rem;
	background-color:currentColor;
	-webkit-mask:var(--btn-arrow) center / contain no-repeat;
	mask:var(--btn-arrow) center / contain no-repeat;
}

:root{
	--btn-arrow:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath d='M3 10h14m0 0-5.5-5.5M17 10l-5.5 5.5' fill='none' stroke='%23000' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

/* ---- The arrow -------------------------------------------------------------
 * Every full-size button in the design carries the sprite's #i-arrow in a capsule at its
 * right-hand end. Core's Button block renders an <a> with the words and nothing else, so
 * those buttons lost their arrow while the button around them kept the space reserved for
 * it (.cmp-btn's 3rem of right-hand padding) — a button with a hole in it.
 *
 * Drawn as a masked pseudo-element on whatever carries .cmp-btn — the Button block's
 * wrapper, or a plain <a> where the design writes one (the owner band's "Meet the team"
 * sits in a paragraph, and a rule keyed to .wp-block-button missed it). Either way that
 * element is the one with position:relative. A mask, not a background image, so it takes currentColor and
 * turns white on the dark band exactly as the real icon does. The SVG is written with
 * SINGLE quotes: a double quote closes the CSS string and the whole declaration is
 * dropped, which shows up as a plain square or nothing at all.
 *
 * Not on a button that already has an icon of its own (the Steps block's link brings its
 * own SVG), and not on the header's small button — the design gives that one no arrow.
 */
.site-main .cmp-btn:not(.cmp-btn--sm):not(.cmp-btn--header):not(:has(svg))::after{
	content:"";
	position:absolute;
	right:1.125rem;
	top:50%;
	translate:0 -50%;
	inline-size:1.25rem;
	block-size:1.25rem;
	pointer-events:none;
	background:currentColor;
	-webkit-mask:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'><path d='M3 10h14m0 0-5.5-5.5M17 10l-5.5 5.5' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/></svg>") center / contain no-repeat;
	        mask:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'><path d='M3 10h14m0 0-5.5-5.5M17 10l-5.5 5.5' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/></svg>") center / contain no-repeat;
	transition:translate var(--dur-base) var(--ease-spring);
}

.site-main .cmp-btn:not(.cmp-btn--sm):not(.cmp-btn--header):not(:has(svg)):hover::after{
	translate:4px -50%;
}


/* ==== 05-reset.css ==== */
/*
 * Reset, grain and layout primitives — ported from the prototype's main.css, verbatim.
 * .cmp-wrap and .cmp-section are used by the header, the footer and the block styles
 * alike, so they are base, not a look.
 */

/* ---- Reset --------------------------------------------------------------- */
*,*::before,*::after{box-sizing:border-box;}
html{-webkit-text-size-adjust:100%;scroll-behavior:smooth;
  /* clip, not hidden: the closed mobile panel is a fixed box parked one screen to the right
     (child rects measured out to 610px at 320, 1506px at 768). `hidden` still leaves that
     area programmatically scrollable; `clip` makes it unreachable, so nothing that flips the
     panel's visibility mid-transition can ever add page width. Ignored before Safari 16,
     where body's `hidden` below still propagates to the viewport exactly as before. */
  overflow-x:clip;
  /* in-page anchors land clear of the fixed bar: 76 + 24 = 100px (they landed under it) */
  scroll-padding-top:calc(var(--header-h) + var(--sp-5));}
body{margin:0;background:var(--ground);color:var(--fg);
  font-family:var(--font-body);font-weight:400;font-size:var(--t-body);line-height:var(--lh-body);
  -webkit-font-smoothing:antialiased;overflow-x:hidden;overflow-x:clip; /* hidden is the pre-Safari-16 fallback; clip keeps <body> from becoming a scroll container now that <html> carries its own overflow */
  overflow-wrap:break-word;}
img,video,svg{display:block;max-width:100%;}
/* Every <img> now carries width/height attributes (no layout shift). The height attribute
   is a presentational hint, so without this a 1000x1250 anchor would render 1250px tall;
   the cover backgrounds set their own height:100% and out-rank it. */
img{height:auto;}
a{color:var(--accent);text-decoration-thickness:1px;text-underline-offset:3px;}
a:hover{color:var(--accent-press);}
button{font:inherit;}
h1,h2,h3,h4{font-family:var(--font-display);font-weight:400;margin:0;
  line-height:var(--lh-display);letter-spacing:var(--ls-display);text-wrap:balance;}
p{margin:0;text-wrap:pretty;}
ul,ol{margin:0;padding:0;list-style:none;}
figure,blockquote,dl,dd,fieldset{margin:0;}

:focus-visible{outline:3px solid var(--ring-focus);outline-offset:3px;border-radius:2px;}
/* Two-tone on dark grounds: a navy band hugging the element, then a white ring. The pair
   is 17.3:1 against itself, so it reads whatever frame, scrim or band edge sits behind it
   (the single light-blue ring measured 1.41:1 at the band's edge). Also the header while
   it floats over the hero, and the open mobile panel.
   RULE: every dark ground MUST carry .cmp-on-dark (today: hero, tax band, closing CTA,
   footer). Without it a block falls back to the default ring, --ring-focus on --navy =
   3.06:1 — two hundredths over the 3:1 floor — and its eyebrow / lead keep their
   light-ground inks. A new dark section without the class is a contrast bug. */
.cmp-on-dark :focus-visible,
.cmp-header:not(.is-stuck) :focus-visible,
.cmp-header.is-menu-open :focus-visible{outline:3px solid var(--surface);outline-offset:3px;
  box-shadow:0 0 0 3px var(--navy);}

.cmp-skip{position:absolute;left:var(--sp-4);top:-5rem;z-index:1000;
  background:var(--surface);color:var(--fg);padding:var(--sp-3) var(--sp-5);
  border-radius:var(--r-pill);box-shadow:var(--shadow-soft);
  transition:top var(--dur-fast) var(--ease-spring);}
.cmp-skip:focus{top:var(--sp-4);}
/* <main tabindex="-1"> so the skip link moves FOCUS, not just the scroll position. It is a
   landing spot, not a control, so it draws no ring. Relative: anchors the header sentinel. */
.cmp-main{position:relative;}
.cmp-main:focus{outline:none;}

/* Visually hidden, still read out — one utility instead of ad-hoc copies. */
.cmp-sprite{position:absolute;width:0;height:0;overflow:hidden;}  /* holds <symbol>s only */
.cmp-vh{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;}

/* Grid and flex children default to min-width:auto and refuse to shrink below
   min-content — that is what pushes a page wider than the viewport at 200%
   text zoom (WCAG 1.4.4). Opt every track child out. */
.cmp-services>*,.cmp-serve>*,.cmp-steps>*,.cmp-footer__grid>*,.cmp-owner>*,
.cmp-form__row>*,.cmp-cards>*,.cmp-reviews>*,.cmp-enquiry>*{min-width:0;}

/* ---- Grain — fixed layer, 3.8%, never on a scrolling element ------------- */
body::after{content:"";position:fixed;inset:0;z-index:60;pointer-events:none;
  opacity:var(--grain-opacity);
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");}
@media (forced-colors:active){body::after{display:none;}}

/* ---- Layout primitives --------------------------------------------------- */
.cmp-wrap{width:100%;max-width:var(--container);margin-inline:auto;
  padding-inline:var(--gutter);min-width:0;}
.cmp-section{padding-block:var(--space-section);}
.cmp-section--tint{background:var(--tint);}

/* ---- The three utilities the looks share ---------------------------------- */
.cmp-em{font-style:italic;}
.cmp-main{position:relative;}
.cmp-main:focus{outline:none;}
.cmp-sprite{position:absolute;width:0;height:0;overflow:hidden;}


/* ==== 10-header.css ==== */
/*
 * Header — ported from the prototype's main.css (the "Header" block), verbatim.
 * The markup in header.php and the walker in inc/chrome.php emit the same
 * .cmp- classes, so nothing here had to be rewritten. All width @media lives in
 * 92-responsive.css, as in the prototype.
 */

/* ==========================================================================
   Header — fixed, transparent over the hero, solid on scroll.
   She named this behaviour on davidfrenchcpa.com and noted that a nav which
   does not stay put was the thing she disliked, so it is fixed and never hides.
   ========================================================================== */
.cmp-header{position:fixed;inset:0 0 auto;z-index:100;max-width:100vw;isolation:isolate;
  background:transparent;color:var(--fg-on-dark);
  transition:background-color var(--dur-base) var(--ease-expo),
             box-shadow var(--dur-base) var(--ease-expo),
             color var(--dur-base) var(--ease-expo);}
/* REFERENCE-SPEC: 96px over the hero -> 76px on scroll. The BOX is always --header-h
   (76px); over the hero its contents sit --header-drop (10px) lower, so they centre on
   48px — the centre line of a 96px bar (measured: lockup 26-70) — and on scroll they ride
   up 10px to centre on 38px. The bar is transparent over the hero, so its box height is
   never seen there; only the centre line is. That is a transform on the compositor — the
   96 -> 76 shrink used to animate `height`, which is layout, for 400ms. (The box was 74px,
   2px under the spec; it is the spec's 76 now. Recorded in CONTEXT.md, Departures.) The offset is on the CONTENTS, not on the inner wrapper: a transformed
   wrapper would become the containing block of the fixed mobile panel inside it.
   min-height, not height: at 200% text size the desktop nav wraps onto more rows and the
   bar grows to hold them (with a fixed height the first row left the top of the screen). */
.cmp-header__inner{display:flex;align-items:center;gap:var(--sp-4);min-width:0;
  min-height:var(--header-h);padding-block:var(--sp-2);}
.cmp-header .cmp-logo,.cmp-header .cmp-burger{transform:translateY(var(--header-drop));
  transition:transform var(--dur-base) var(--ease-spring);}
.cmp-header.is-stuck .cmp-logo,.cmp-header.is-stuck .cmp-burger{transform:none;}
.cmp-header.is-stuck{background:var(--surface);color:var(--fg);
  box-shadow:0 1px 0 rgb(var(--navy-rgb) / .10),0 10px 30px -20px rgb(var(--navy-rgb) / .4);}
/* 1px marker 40px down the page. main.js watches it with an IntersectionObserver and flips
   .is-stuck when it leaves the viewport — no scroll listener. */
.cmp-header__sentinel{position:absolute;top:40px;left:0;width:1px;height:1px;pointer-events:none;}

/* The lockup keeps its words. With overflow-wrap:anywhere it shrank into a 64px column of
   single letters at 200% text size. Each line is now one unbroken line. From 1024 the
   lockup never shrinks — the nav wraps instead (responsive.css). Beside the burger, if the
   text is doubled and there is no room, it truncates with an ellipsis rather than pushing
   the menu button off the screen (the link keeps its full accessible name). */
.cmp-logo{display:flex;align-items:center;gap:.625rem;color:currentColor;
  text-decoration:none;position:relative;z-index:100;flex:0 1 auto;min-width:0;
  min-height:2.75rem;}
.cmp-logo__mark{width:2.25rem;height:2.25rem;flex:none;}
.cmp-logo__text{display:grid;gap:.15rem;min-width:0;}
.cmp-logo__name{font-family:var(--font-label);font-weight:600;font-size:var(--t-label);
  letter-spacing:.09em;text-transform:uppercase;line-height:1.15;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.cmp-logo__sub{font-family:var(--font-label);font-weight:400;font-size:var(--t-micro);
  letter-spacing:.17em;text-transform:uppercase;line-height:1.15;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
  color:var(--fg-mute-on-scrim);
  transition:color var(--dur-base) var(--ease-expo);} /* fades with the bar, like the name (which inherits the header's colour). A colour, not an opacity: .72 dropped it to 2.33:1 on a white hero frame. 5.16:1 on the scrim */
.cmp-header.is-stuck .cmp-logo__sub{color:var(--fg-dim);}          /* 6.92:1 on the white bar */
.cmp-footer .cmp-logo__sub{color:var(--fg-dim-on-dark);}           /* 8.41:1 on navy */

/* The panel scrolls. Measured at 667x375 (a phone on its side): "Book a call" sat at
   560px in a 371px viewport with the body locked and no overflow rule — unreachable.
   The top cap is a BORDER, not padding: borders sit outside the scroll area, so links
   scrolling up are clipped under the logo and the X instead of sliding through them.
   76px covers both states: the X spans 24-72 over the hero and 14-62 once scrolled.
   Closed, the panel is also `inert` (main.js, below 1024 only): visibility:hidden already
   keeps it out of the tab order, inert keeps it out even if a transition ever flips
   visibility early. */
.cmp-nav{position:fixed;inset:0;z-index:99;background:var(--navy);color:var(--fg-on-dark);
  border-top:var(--header-h) solid var(--navy);
  padding:var(--sp-6) var(--gutter) calc(var(--sp-8) + env(safe-area-inset-bottom));
  overflow-y:auto;overscroll-behavior:contain;-webkit-overflow-scrolling:touch;
  transform:translateX(100%);visibility:hidden;
  /* visibility flips instantly on open and waits out the slide on close. Transitioned
     together, the panel was still `hidden` on the frame the script moved focus into it,
     so focus() silently failed and never reached the first link. */
  transition:transform var(--dur-base) var(--ease-spring),visibility 0s var(--dur-base);}
.cmp-nav.is-open{transform:none;visibility:visible;transition-delay:0s;}
.cmp-nav__list{display:flex;flex-direction:column;align-items:flex-start;gap:var(--sp-5);}
.cmp-nav__link{font-family:var(--font-label);font-weight:600;font-size:var(--t-sub);
  line-height:var(--lh-label);letter-spacing:.04em;color:currentColor;text-decoration:none;position:relative;
  display:inline-flex;align-items:center;justify-content:flex-start;
  min-height:2.75rem;min-width:2.75rem;} /* 44px touch floor */
.cmp-nav__link::after{content:'';position:absolute;left:0;right:0;bottom:.25rem;height:1.5px;
  background:currentColor;transform:scaleX(0);transform-origin:left;
  transition:transform var(--dur-base) var(--ease-spring);}
.cmp-nav__link:hover::after,
.cmp-nav__link[aria-current='page']::after,
.cmp-nav__link[aria-current='location']::after{transform:scaleX(1);}

/* Services is a label rather than a link (inc/chrome.php): the landing page is out of
   the menu but the four service pages still hang under the word. It keeps the nav's
   type and height so the row does not shift, and loses the hover rule, which would
   promise a destination that is not there. The arrow beside it is the control. */
.cmp-nav__link--label{cursor:default;}

.cmp-nav__link--label::after{content:none;}
/* The service you are on, inside the dropdown: the label goes to full-strength
   ink and a short rule sits in the padding to its left. In the phone menu the
   panel is dark, so it takes the on-dark ink instead. */
.cmp-nav__sub a[aria-current='page']{color:var(--fg-on-dark);position:relative;}
.cmp-nav__sub a[aria-current='page']::before{content:'';position:absolute;
  left:calc(-1 * var(--sp-3));top:50%;width:.5rem;height:2px;
  background:var(--accent-on-dark);transform:translateY(-50%);}
/* Hover keeps the bar's own ink. The global a:hover (0,1,1) out-ranked color:currentColor
   on .cmp-nav__link and .cmp-logo (0,1,0), so over the hero and inside the navy panel a
   hovered link went --accent-press: measured 1.26:1 on the scrim over a white frame,
   2.13:1 on the panel — and on touch :hover sticks after the tap. currentColor here is
   --fg-on-dark: 5.51:1 over the hero (white frame), 14.80:1 on the panel. The underline
   drawing in is the hover cue on a dark ground. */
.cmp-nav__link:hover,.cmp-header .cmp-logo:hover{color:currentColor;}
/* On a white bar the blue hover stays (8.10:1 on --surface): the lockup once scrolled with
   the menu shut, and everything in the no-JS bar. The scrolled desktop nav row gets it in
   responsive.css (1024+) — NOT here: below 1024 these links only ever sit on the navy
   panel, and a tapped link keeps :hover while the panel slides shut, after main.js has
   already dropped .is-menu-open. */
.cmp-header.is-stuck:not(.is-menu-open) .cmp-logo:hover,
.no-js .cmp-header .cmp-nav__link:hover,
.no-js .cmp-header .cmp-logo:hover{color:var(--accent-press);}
.cmp-nav__cta{margin-top:var(--sp-6);}

/* Services, and the four pages under it. In the phone panel the four sit open beneath
   the word, indented, because a panel that has to be opened inside a panel is a trap on
   a touch screen. From 1024 they become a dropdown — see responsive.css. */
/* In the phone panel the group is a row — label plus chevron — with the list
   under it. The list used to be permanently open, which pushed Resources and
   Contact off the first screen and left no way to collapse it. It is closed
   now and the chevron opens it. */
.cmp-nav__group{display:grid;grid-template-columns:auto auto;
  justify-content:start;align-items:center;column-gap:var(--sp-3);}
.cmp-nav__more{display:grid;place-items:center;width:2.75rem;height:2.75rem;
  padding:0;background:none;border:0;color:currentColor;cursor:pointer;}
.cmp-nav__more svg{width:1.125rem;height:1.125rem;
  transition:transform var(--dur-base) var(--ease-spring);}
.cmp-nav__group.is-open .cmp-nav__more svg{transform:rotate(180deg);}
.cmp-nav__sub{grid-column:1 / -1;list-style:none;margin:0;
  padding:0 0 0 var(--sp-4);display:grid;
  overflow:hidden;max-height:0;visibility:hidden;
  transition:max-height var(--dur-base) var(--ease-expo),visibility 0s linear var(--dur-base);}
.cmp-nav__group.is-open .cmp-nav__sub{max-height:22rem;visibility:visible;
  transition-delay:0s;}
.cmp-nav__sub a{display:inline-flex;align-items:center;min-height:2.75rem;
  font-family:var(--font-label);font-weight:600;font-size:var(--t-small);
  letter-spacing:.06em;text-transform:uppercase;text-decoration:none;
  color:var(--fg-dim-on-dark);transition:color var(--dur-fast) var(--ease-expo);}
.cmp-nav__sub a:hover{color:var(--fg-on-dark);}

.cmp-header .cmp-btn--header{border-color:currentColor;color:currentColor;background:transparent;}
.cmp-header .cmp-btn--header:hover{background:rgb(255 255 255 / .06);border-color:rgb(255 255 255 / 1);} /* same cap as .cmp-btn--on-dark: at .12 the 13px/700 label measured 4.14:1 on a white frame; at .06 it is 4.77:1. The border steps from --fg-on-dark (5.51:1) to white (6.44:1) */
.cmp-header.is-stuck .cmp-btn--header{background:var(--navy);border-color:var(--navy);color:var(--fg-on-dark);}
.cmp-header.is-stuck .cmp-btn--header:hover{background:var(--accent);border-color:var(--accent);}

/* Menu open wins over .is-stuck, so these sit after it. Scrolled + open, the logo was
   rendering --fg on the navy panel (1.13:1). The class is the hook where :has()
   is not supported. */
.cmp-header:has(.cmp-nav.is-open),.cmp-header.is-menu-open{background:transparent;
  box-shadow:none;color:var(--fg-on-dark);}
.cmp-header:has(.cmp-nav.is-open) .cmp-btn--header,
.cmp-header.is-menu-open .cmp-btn--header{background:transparent;border-color:currentColor;color:currentColor;}
.cmp-header:has(.cmp-nav.is-open) .cmp-logo__sub,
.cmp-header.is-menu-open .cmp-logo__sub{color:var(--fg-mute-on-scrim);}  /* 13.9:1 on the navy panel */

.cmp-burger{display:block;margin-left:auto;background:none;border:0;color:currentColor;
  padding:var(--sp-3);cursor:pointer;position:relative;z-index:100;}
.cmp-burger svg{width:1.5rem;height:1.5rem;}
.cmp-burger__close{display:none;}
.cmp-burger[aria-expanded='true']{color:var(--fg-on-dark);}
.cmp-burger[aria-expanded='true'] .cmp-burger__open{display:none;}
.cmp-burger[aria-expanded='true'] .cmp-burger__close{display:block;}


/* ==== 11-footer.css ==== */
/*
 * Footer — ported from the prototype's main.css (the "Footer + giant wordmark"
 * block), verbatim. footer.php emits the same .cmp- classes.
 */

/* ==========================================================================
   Footer + giant wordmark
   ========================================================================== */
/* Blue at the top, settling into navy by the legal line — the blue she asked for
   (barbri), arriving where the eye lands coming off the page. Both ends measured:
   links #A6B7C6 5.68:1 on the blue and 8.41:1 on the navy. */
.cmp-footer{background:linear-gradient(180deg,var(--blue-deep) 0%,var(--navy) 62%);
  color:var(--fg-dim-on-dark);
  padding-block:var(--space-section) 0;overflow:hidden;} /* the section token, like every other band — it was the one section padded with a primitive (80px vs 115 at 1280) */
.cmp-footer__grid{display:grid;gap:var(--sp-8) var(--sp-7);}  /* 64px between ROWS, 48px between columns. One gap for both meant that wherever the
     four columns wrap — two-up on tablet, stacked on a phone — the rows sat as close as
     the columns and the groups ran together. */
.cmp-footer__title{font-family:var(--font-label);font-weight:600;font-size:var(--t-label);line-height:var(--lh-label);letter-spacing:var(--ls-label);
  text-transform:uppercase;color:var(--fg-label-on-blue);margin-bottom:var(--sp-5);}
.cmp-footer__list{display:grid;gap:var(--sp-1);min-width:0;}
.cmp-footer__list a{display:inline-flex;align-items:center;min-height:2.75rem;}
.cmp-footer a{color:var(--fg-dim-on-dark);text-decoration:none;}
.cmp-footer a:hover{color:var(--fg-on-dark);text-decoration:underline;}
.cmp-footer__list a{overflow-wrap:anywhere;}
.cmp-footer__blurb{font-size:var(--t-small);max-width:32ch;margin-top:var(--sp-4);}
.cmp-footer__list address{margin-top:0;font-style:normal;} /* <address> is italic by default and no Roboto italic is loaded — the browser was slanting the 400 */
.cmp-footer__logo{color:var(--fg-on-dark);margin-bottom:var(--sp-2);
  z-index:auto;} /* .cmp-logo's z-index:100 is for the header lockup (over the 99 menu panel). The footer is no stacking context, so the footer lockup was painting OVER the fixed call bar (90) as it scrolled under it — seen at 375 once the bar went solid */
.cmp-footer__bar{margin-top:var(--sp-8);padding-top:var(--sp-5);
  border-top:1px solid rgb(255 255 255 / .12);
  display:flex;flex-wrap:wrap;align-items:center; /* the 44px legal links were centring themselves while the © line sat at the top of the row */
  gap:var(--sp-4) var(--sp-6);justify-content:space-between;
  font-size:var(--t-label);color:var(--fg-mute-on-dark);}
.cmp-footer__legal{display:flex;flex-wrap:wrap;gap:var(--sp-5);}
.cmp-footer__legal a{display:inline-flex;align-items:center;min-height:2.75rem;}


/* ==== 20-widths.css ==== */
/*
 * Widths — the prototype's container model, applied to the blocks WordPress renders.
 *
 * The design has exactly one measure: .cmp-wrap, max-width var(--container) with
 * var(--gutter) inside it, which puts a section's first character at 152px at 1440 and
 * 32px below 1200. Every section is full width so its background reaches both edges,
 * and its contents sit in that one measure.
 *
 * Sections that carry their own .cmp-wrap element (the hero, the page headers, the
 * closing band) are already constrained by it; these rules give the same measure to the
 * sections whose container is WordPress's own — a Group or Cover set to Full width.
 *
 * All width @media lives in 92-responsive.css, so nothing here is breakpoint-specific.
 */

/* A section set to Full width: background edge to edge, no padding of its own. */
.site-main > .alignfull{
	max-width:none;
	margin-inline:0;
	padding-inline:0;
}

/* Its contents take the one measure. */
.site-main > .wp-block-group.alignfull > .wp-block-group__inner-container,
.site-main > .wp-block-cover.alignfull > .wp-block-cover__inner-container,
.site-main > .wp-block-columns.alignfull{
	width:100%;
	max-width:var(--container);
	margin-inline:auto;
	padding-inline:var(--gutter);
	min-width:0;
}

/* A section that carries its own .cmp-wrap already has the measure: the container above
   would apply it twice and indent the section by a second gutter. */
.site-main > .wp-block-group.alignfull > .wp-block-group__inner-container:has(> .cmp-wrap),
.site-main > .wp-block-cover.alignfull > .wp-block-cover__inner-container:has(> .cmp-wrap){
	max-width:none;
	padding-inline:0;
}

/* A Cover lays its contents out as a centred grid whose single track is sized to their
   content, so the text column came out as wide as its longest line — the home hero's
   heading measured 726px against the design's 1136. The track takes the full width and
   the container fills it; what the type does inside is then the design's business. */
.site-main > .wp-block-cover{
	grid-template-columns:minmax(0, 1fr);
	justify-content:stretch;
}

.site-main > .wp-block-cover > .wp-block-cover__inner-container{
	width:100%;
}

/* A block that is not full width still sits in the measure. */
.site-main > :not(.alignfull):not(.alignwide){
	width:100%;
	max-width:var(--container);
	margin-inline:auto;
	padding-inline:var(--gutter);
}

/* WordPress's own constrained layout: let the rules above decide the measure, so a Group
   inside a section does not re-centre its children on a narrower column. .cmp-wrap is
   exempt — it IS the measure, and this rule was cancelling it wherever a section carried
   its own wrap (the hero, the page headers, the closing band). */
.site-main :where(.is-layout-constrained) > :where(:not(.alignleft):not(.alignright):not(.alignfull):not(.cmp-wrap)){
	max-width:none;
	margin-inline:0;
}


/* ==== 30-text.css ==== */
/*
 * Type helpers — ported from the prototype's main.css ("Type helpers"), verbatim, plus
 * the mapping from WordPress's own heading and paragraph blocks onto them.
 *
 * In the prototype a section's heading carries .cmp-h2 and its opening paragraph
 * .cmp-lead. WordPress emits a bare <h2 class="wp-block-heading"> and <p>, so the
 * rules are attached by position inside .site-main instead — same result, nothing for
 * the client to remember.
 */

/* ---- Type helpers -------------------------------------------------------- */
.cmp-eyebrow{font-family:var(--font-label);font-weight:600;font-size:var(--t-label);
  line-height:var(--lh-label);letter-spacing:var(--ls-label);text-transform:uppercase;color:var(--accent);
  margin:0 0 var(--sp-4);display:flex;align-items:center;gap:var(--sp-4);}
.cmp-on-dark .cmp-eyebrow{color:var(--accent-on-dark);}   /* 6.40:1 on navy */
.cmp-hero .cmp-eyebrow{color:var(--accent-on-scrim);}    /* 5.23:1 on the scrim */

/* CONCEPT SPINE, appearance 1 — the line beside the eyebrow */
.cmp-eyebrow::after{content:'';flex:1 1 0;max-width:5rem;height:1px;
  background:currentColor;opacity:.5;}

.cmp-h2{font-size:var(--t-section);letter-spacing:var(--ls-display-lg);}
.cmp-lead{font-weight:300;font-size:var(--t-lead);line-height:var(--lh-lead);color:var(--fg-dim);max-width:54ch;}
.cmp-on-dark .cmp-lead{color:var(--fg-dim-on-dark);}
/* No runt last line. `pretty` has no line limit and always avoids a ONE-word
   last line, so it is the base everywhere. From 1024, where paragraphs are
   short enough, responsive.css upgrades the short blocks to `balance`, which
   evens every line and leaves no two-word runt either. Chrome stops balancing
   above six lines — on a phone these paragraphs run to nine, which is why the
   upgrade is behind the breakpoint rather than applied here. */
.cmp-lead, .cmp-hero__lead,
.cmp-offer__lead, .cmp-offer__text,
.cmp-split__lead, .cmp-split__text,
.cmp-band__text,
.cmp-team__text,
.cmp-also__text,
.cmp-svc__text, .cmp-serve__text,
.cmp-owner__lead,
.cmp-step__text,
.cmp-footer__blurb,
.cmp-acc__panel{text-wrap:pretty;}

.cmp-head{max-width:44rem;margin-bottom:var(--sp-8);} /* rem: display headings never sized in ch */
/* Nothing follows it on the Tax page, where the section is the heading and her
   intro alone: the 64px that spaces it off a list below would otherwise stack
   on top of the section's own padding and open a 190px hole. */
.cmp-head:last-child{margin-bottom:0;}
.cmp-head--center{margin-inline:auto;text-align:center;}
.cmp-head--center .cmp-lead{margin-inline:auto;}
.cmp-head--center .cmp-eyebrow{justify-content:center;}
.cmp-head--center .cmp-eyebrow::after{display:none;}
/* One rhythm everywhere: eyebrow -> H2 16 · H2 -> lead 24 · lead -> content 48+.
   The eyebrow belongs to its heading, so its gap is the tighter one. Measured: H2 -> lead
   was 0px in why-us, process and enquiry, 24px only inside .cmp-head. */
.cmp-h2 + .cmp-lead,.cmp-head .cmp-lead,.cmp-lead + .cmp-lead{margin-top:var(--sp-5);}
.cmp-em{font-style:italic;}   /* the one accent treatment per headline */

/* ---- WordPress's blocks, given the prototype's type ---------------------- */

/* These are DEFAULTS for a paragraph or list that carries no look of its own, so every
   selector sits inside :where() and weighs nothing. Written as `.site-main p` they
   out-ranked every ported .cmp- rule — the hero's lead took the reading measure instead
   of its own 624px, and the hero came out 190px narrower than the design. */

/* A section's first paragraph after its heading is the lead. */
:where(.site-main h2.wp-block-heading + p){font-family:var(--font-body);font-weight:300;
  font-size:var(--t-lead);line-height:var(--lh-lead);color:var(--muted);
  max-width:var(--measure-lead);margin-block:var(--sp-4) 0;text-wrap:pretty;}

/* Every other paragraph is body copy on the prototype's measure. */
:where(.site-main p){max-width:var(--measure);text-wrap:pretty;}
:where(.site-main .wp-block-columns p, .site-main .wp-block-column p){max-width:none;}

/* Lists: her service lists, set as the prototype sets them. */
:where(.site-main ul:not([class*="wp-block-"]):not(.cmp-footer__list),
       .site-main ol:not([class*="wp-block-"]):not(.cmp-footer__list)){padding-left:0;list-style:none;}


/* ==== 35-sections.css ==== */
/*
 * Section rhythm — the prototype's, ported.
 *
 * A section pays var(--space-section) top and bottom. Two plain sections in a row would
 * then put 259px between their contents at 1440 and 144px at 375 (measured across all ten
 * pages, 13 boundaries), so where both sides sit on the same ground with no edge between
 * them the second one stops paying and the gap is the single --space-section the scale
 * intends. A block with a background of its own is exempt: there the padding is not a gap
 * between sections, it is the air inside the coloured box.
 *
 * Widths are 20-widths.css; all width @media is 92-responsive.css.
 */

/* WordPress wraps a Group's children in an inner container, which would swallow the grid
   and the gap a look sets on the Group itself. A nested look group is therefore
   transparent; a top-level section keeps its container, because that is what carries the
   measure (20-widths.css). */
.site-main :where(.wp-block-group:not(.alignfull)) > .wp-block-group__inner-container{
	display:contents;
}

/* Two plain sections in a row: one gap, not two. */
.cmp-section:not(.cmp-section--tint) + .cmp-section:not(.cmp-section--tint),
.is-style-phero + .cmp-section:not(.cmp-section--tint){
	padding-top:0;
}

/* After a full-bleed band the page needs less air than between two blocks of text: the
   image has a hard edge, so a whole section's padding above the first line reads as a
   hole. Resources and Contact both open this way. */
.is-style-chero + .cmp-section{
	padding-top:calc(var(--space-section) * .55);
}

/* The About page opens on one block of her prose with no heading over it, the way the
   reference's "Our Story" does, so it is set a step up from body copy. */
.cmp-lead--story{
	font-size:var(--t-lead);
	line-height:1.7;
	color:var(--fg);
	max-width:60ch;
}

/* Core gives every Columns block a 1.75em bottom margin. The design never uses it — a
   grid's own gap does the spacing — and four team members inherited 119px of it between
   them. It is a default, declared in :where(), so this simply takes it back. */
.site-main .wp-block-columns{
	margin-bottom:0;
}

/* The questions block sits under the process block, which ends on her photograph. Flush
   against it the heading read as part of the picture. It takes the page's block gap.
   (Also set in the prototype's main.css, so a re-port keeps it.) */
.site-main .cmp-faq{
	margin-top:var(--space-block);
}


/* ==== 40-hero.css ==== */
/*
 * Home hero, and the facts row under it — ported from the prototype by tools/port-css.py.
 * Each look's own class becomes the block style WordPress prints;
 * inner BEM classes are the prototype's, kept by data-wp-class.
 *
 * GENERATED. Edits here are lost on the next port — anything written
 * against a plugin block's own markup belongs in 70- and up.
 */

/* 6.40:1 on navy */
.site-main .is-style-hero .cmp-eyebrow{color:var(--accent-on-scrim);}

/* No runt last line. `pretty` has no line limit and always avoids a ONE-word
   last line, so it is the base everywhere. From 1024, where paragraphs are
   short enough, responsive.css upgrades the short blocks to `balance`, which
   evens every line and leaves no two-word runt either. Chrome stops balancing
   above six lines — on a phone these paragraphs run to nine, which is why the
   upgrade is behind the breakpoint rather than applied here. */
.cmp-lead,
.cmp-hero__lead,
.cmp-offer__lead,
.cmp-offer__text,
.cmp-split__lead,
.cmp-split__text,
.cmp-band__text,
.cmp-team__text,
.cmp-also__text,
.cmp-svc__text,
.cmp-serve__text,
.cmp-owner__lead,
.site-main .arenex-steps__desc,
.cmp-footer__blurb,
.cmp-acc__panel{text-wrap:pretty;}

/* ==========================================================================
   Hero — full bleed, because she asked for a video hero with the nav over it.
   Premium lives in the type scale and the load sequence.
   ========================================================================== */
.site-main .is-style-hero{position:relative;min-height:min(94svh,940px);display:grid;align-items:center;
  isolation:isolate;overflow:hidden;
  background:var(--navy-2);}

/* the first painted frame is navy, not the grey page ground, while the image settles in */
.cmp-hero__media{position:absolute;inset:0;z-index:-2;overflow:hidden;
  contain:strict;}

/* 10-15 stacked slides cross-fading: nothing in here can affect layout or paint outside it */
.cmp-hero__media img,
.cmp-hero__media video{width:100%;height:100%;object-fit:cover;}

/* <picture> only swaps the 16:9 / 4:5 source — it must not become a box of its own, or
   the background <img>'s height:100% resolves against an inline wrapper. */
.cmp-hero__slide picture,
.site-main .is-style-owner picture,
.site-main .is-style-phero .arenex-split__figure picture{display:contents;}

/* Rotating industry frames — this is the hero she asked for: "still shots or
   video footage from 10 to 15 industries that I service... rotate on the home
   page", with pwc.com named as the reference. Each slide cross-fades and drifts
   slightly so stills read as footage. Her clips replace the <img> untouched. */
.cmp-hero__slide{position:absolute;inset:0;opacity:0;
  transition:opacity 1.6s var(--ease-expo);}

.cmp-hero__slide.is-live{opacity:1;}

.cmp-hero__slide img{width:100%;height:100%;object-fit:cover;
  transform:scale(1.06);transition:transform var(--dur-drift) linear;}

/* a constant drift, not a move with a start and an end — the one place linear is right */
.cmp-hero__slide.is-live img{transform:scale(1);}

.cmp-hero__slide video{transform:none;transition:none;}

/* footage already moves */

/* The hero is a STILL, deliberately. An ambient motion layer lived here — six light
   streaks running the boulevard and six office windows coming on and off, all on the
   compositor, no video. It was measured and accessible but it did not look good, so it
   came out. The whole thing is preserved in .v2-snap-round4 if it is ever wanted back;
   note that its geometry is tied to THIS crop (the boulevard converges at 51% of the
   rendered hero, not the 29% the source file shows) and the streaks are capped at .68
   because a brighter one behind the phone link measured 3.74:1. */

/* WCAG 2.2.2 — anything auto-playing beyond 5s needs a pause control.
   pwc.com puts theirs top-right; ours sits with the industry label. */
.cmp-hero__player[hidden]{display:none;}

.cmp-hero__player{position:absolute;right:var(--gutter);bottom:var(--sp-6);z-index:3;
  display:flex;align-items:center;gap:var(--sp-4);}

/* Two or more slides = the player is on screen, 44px tall, 32px off the bottom edge — the
   trust facts' own row. Pure CSS off the markup (no JS class), so nothing shifts when the
   script arrives: 32 + 44 + 24 = 100px keeps the facts clear of it. */
.site-main .is-style-hero:has(.cmp-hero__slide + .cmp-hero__slide) .cmp-hero__inner{
  padding-bottom:calc(var(--sp-6) + 2.75rem + var(--sp-5));}

/* The industry label is OFF by default (designer's call, 23 Sep): naming each frame put a
   tag on the hero, and one of the four is a city rather than an industry, so the set read
   oddly. The dots carry the names in their aria-labels, so nothing is lost to a screen
   reader. It comes back on phones once there are seven or more slides, where the dots no
   longer fit a row — see responsive.css. */
.cmp-hero__now{display:none;
  font-family:var(--font-label);font-weight:600;font-size:var(--t-label);
  line-height:var(--lh-label);letter-spacing:var(--ls-label);text-transform:uppercase;color:var(--fg-on-dark);}

/* 44x44 button, 28x2 bar drawn inside it (the button itself was 2px tall). Resting bar:
   white @.55 over the .70 scrim on a pure-white frame = 3.20:1 against that scrim (UI, needs 3). */
.cmp-hero__dots{display:flex;}

.cmp-hero__dot{position:relative;width:2.75rem;height:2.75rem;background:none;border:0;padding:0;
  cursor:pointer;}

.cmp-hero__dot::before{content:'';position:absolute;left:.5rem;right:.5rem;top:50%;height:2px;
  margin-top:-1px;background:rgb(255 255 255 / .55);
  transition:background var(--dur-fast) var(--ease-expo);}

.cmp-hero__dot:hover::before{background:rgb(255 255 255 / .8);}

.cmp-hero__dot[aria-current='true']::before{background:var(--fg-on-dark);}

/* Boundary at the button spec's .75: over the .70 scrim on a pure-white frame it is
   4.47:1 against the scrim outside it and 3.51:1 against its own .10 fill (UI, needs 3).
   At .5 it measured 2.92 / 2.30. Hover: the ring goes to full white (6.44:1 outside,
   3.86:1 against the .22 fill); the icon on that fill is 3.30:1. */
.cmp-hero__pause{width:2.75rem;height:2.75rem;display:grid;place-items:center;
  background:rgb(255 255 255 / .1);border:1.5px solid rgb(255 255 255 / .75);
  border-radius:var(--r-pill);color:var(--fg-on-dark);cursor:pointer;
  transition:background var(--dur-fast) var(--ease-expo),border-color var(--dur-fast) var(--ease-expo);}

.cmp-hero__pause:hover{background:rgb(255 255 255 / .22);border-color:rgb(255 255 255 / 1);}

.cmp-hero__pause svg{width:.875rem;height:.875rem;}

.cmp-hero__pause .i-play{display:none;}

.cmp-hero__pause[aria-pressed='true'] .i-play{display:block;}

.cmp-hero__pause[aria-pressed='true'] .i-pause{display:none;}

.site-main .is-style-hero .wp-block-cover__background{position:absolute;inset:0;z-index:-1;
  /* Uniform wash, as the reference does it.
     --scrim (.70) is the SAFE DEFAULT for a frame nobody has measured — it is computed
     against a pure-white worst case, so any clip she eventually sends passes on it:
       h1 / lead / nav / tel  --fg-on-dark   5.51:1
       trust labels           --fg-mute-on-scrim   5.16:1
       button border 75% white          4.45:1 (UI, needs 3)
     The frame in place now is KNOWN — Ontario at dusk, already dark — so .70 was simply
     burying it. Measured on this frame the whole hero still clears at .40; it runs at
     .56, which leaves the H1 at 4.7:1 against a 3.0 floor and lets the sunset and the
     window lights read. WHEN HER OWN CLIPS ARRIVE this override comes out and the hero
     goes back to var(--scrim), or each clip is measured the way this one was.
     No text in the hero carries an opacity — it would undo these numbers. */
  background:rgb(var(--navy-rgb) / .56);}

/* NEUTRAL BLACK, not navy — the reference's hero overlay is
                                     rgba(0,0,0,.82) at 80% opacity, and ours was tinting the
                                     whole frame blue on top of an already blue photograph.
                                     Same alpha, and it measures BETTER: the lead goes 4.58 ->
                                     5.63:1 because black is darker than navy at equal alpha. */
.cmp-hero__inner{padding-block:calc(var(--header-h) + 2 * var(--header-drop) + var(--sp-7)) var(--sp-7); /* 76 + 20 = the 96px the bar occupies over the hero */color:var(--fg-on-dark);
  position:relative;text-align:center;}

.cmp-hero__title{font-size:var(--t-hero);letter-spacing:var(--ls-display-lg);margin-inline:auto;}

/* No max-width here. The container is the measured constraint (1136px at 1280)
   and each statement holds one line inside it at 60px. A `ch` cap on a
   serif computes far narrower than the character count suggests — that is what
   broke the two-line shape the reference uses. custom-typography §0b. */
.cmp-hero__line{display:block;overflow:hidden;
  padding-bottom:.14em;margin-bottom:-.14em;}

/* descender room inside the mask */
/* 24px, not --t-lead's 21.
 *
 * Not a typographic whim: WCAG counts 24px as large text, which needs 3:1 rather than
 * 4.5:1. At 21px this one line was what pinned the hero's scrim — everything else had
 * room, and the lead did not, so the photograph had to stay dark for its sake. At 24px
 * the whole wash can come down by a third and the line is MORE legible, not less,
 * because it is bigger. The client asked for brighter photographs; this is what actually
 * bought them. */
/* 24px from 600 up. It was raised from 21px in round 1 because WCAG asks only 3:1 of
   text at 24px and 4.5:1 below it, and that single line was holding the whole hero
   photograph dark — at 24px the scrim could lighten and the picture open up.
   On a phone it is simply too big: 5 lines and 240px of a 358px column. Measured the
   background behind it there by sampling the rendered pixels with the text hidden —
   median 11.4:1, brightest 5% 4.97:1 — so 19px clears the stricter 4.5:1 it now has to
   meet, with margin. */
.cmp-hero__lead{font-weight:300;font-size:1.1875rem;line-height:1.65;
  color:var(--fg-on-dark);max-width:39rem;margin:var(--sp-5) auto 0;}

/* 39rem = 624px at 1280, where the first sentence measures 582px and the next word
     would need 647px — so it breaks after "businesses." and Inland Empire opens line two.
     Was 44rem, which left room for "Inland" to be dragged up. */
.cmp-hero__actions{display:flex;flex-direction:column;align-items:center;
  gap:var(--sp-5);margin-top:var(--sp-6);}

.cmp-hero__tel{font-family:var(--font-label);font-weight:600;font-size:var(--t-label);
  line-height:var(--lh-label);letter-spacing:var(--ls-label);text-transform:uppercase;
  color:var(--fg-on-dark);text-decoration:none;
  display:inline-flex;align-items:center;min-height:2.75rem;
  border-bottom:1.5px solid rgb(255 255 255 / .55); /* the underline is the link's only non-colour cue, so it is UI: 3.20:1 on the .70 scrim over a white frame (the dots' value). .45 measured 2.66 */
  transition:border-color var(--dur-fast) var(--ease-expo);}

.cmp-hero__tel:hover{border-color:var(--fg-on-dark);color:var(--fg-on-dark);}

/* Three-up at every width, as the reference keeps its logo row on one line. Stacked, the
   facts were a 215px column and the phone hero ran to 992px (1.22 screens).
   Flex, not a 3-col grid: `flex:1 1 0` gives equal thirds whenever the longest word fits
   (at 375 each third is 109px, 'CONSULTATION' is 106), a fact never shrinks below its
   longest word, and at 200% text zoom the facts wrap onto their own rows instead of
   breaking mid-word or pushing the page sideways.
   The labels are bottom-aligned in a two-line reserve, so the three values share one line
   even though 'Based in' is one line and its neighbours are two. Released at 768. */
.site-main .is-style-trust{display:flex;flex-wrap:wrap;justify-content:center;gap:var(--sp-5) var(--sp-2);
  margin-top:var(--sp-7);text-align:center;}

.cmp-trust__fact{flex:1 1 0;min-width:min-content;display:grid;gap:.5rem;align-content:start;}

.cmp-trust__fact :is(dt, .cmp-dt, .cmp-legal__term){font-family:var(--font-label);font-weight:600;font-size:var(--t-micro);
  line-height:var(--lh-label);letter-spacing:var(--ls-label-tight);text-transform:uppercase;color:var(--fg-mute-on-scrim);
  display:flex;align-items:flex-end;justify-content:center;min-height:calc(2em * var(--lh-label));}

.cmp-trust__fact :is(dd, .cmp-dd, .cmp-legal__def){margin:0;font-family:var(--font-display);font-size:var(--t-card);
  line-height:1.15;color:var(--fg-on-dark);letter-spacing:var(--ls-display);}

/* The hairline between the actions and the facts; its centre 4rem carries the accent. */
.cmp-hero__rule{width:min(100%,62rem);height:1px;background:rgb(255 255 255 / .22);
  margin:var(--sp-8) auto 0;position:relative;}

.cmp-hero__rule::after{content:'';position:absolute;left:50%;top:0;width:4rem;height:1px;
  transform:translateX(-50%);background:var(--accent-on-scrim);}

/* the bar is white here: the default ring, 5.66:1 */
.no-js .cmp-hero__inner{padding-top:var(--sp-8);}

/* ==========================================================================
   Conversion wrappers — added so the import keeps a link and an SVG that core
   blocks would otherwise flatten. Both are display:contents, so the prototype
   renders exactly as it did before they existed and WordPress gets a block it
   can hold: the scroll cue is a core/html block, the phone line a paragraph.
   ========================================================================== */
.cmp-down-wrap,
.cmp-icon-wrap,
.cmp-hero__frame{display:contents;}

.cmp-hero__tel-line,
.cmp-close__tel-line{display:contents;margin:0;}


/* ==== 41-chero.css ==== */
/*
 * Centred page header — ported from the prototype by tools/port-css.py.
 * Each look's own class becomes the block style WordPress prints;
 * inner BEM classes are the prototype's, kept by data-wp-class.
 *
 * GENERATED. Edits here are lost on the next port — anything written
 * against a plugin block's own markup belongs in 70- and up.
 */

/* focused only to place the reader, never drawn */

/* =================== CENTRED HERO (the reference's About) ================
   A photograph across the full width, a flat dark wash over it and one
   centred statement in white, with a rule dropping to the section below. The
   service pages keep the split hero; this one is for the pages that open on a
   statement rather than on a service. */
.site-main .is-style-chero{position:relative;isolation:isolate;width:100vw;
  margin-inline:calc(50% - 50vw);display:grid;align-items:center;
  min-height:clamp(26rem,60vh,38rem);
  padding-block:calc(var(--space-section) + var(--header-h)) var(--space-section);}

.site-main .is-style-chero .wp-block-cover__image-background{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:-2;}

/* Brand navy rather than plain black — see the note in 52-band.css. */
.site-main .is-style-chero .wp-block-cover__background{position:absolute;inset:0;z-index:-1;background:rgb(var(--navy-rgb) / .7);}

/* .7 is the reference's own wash. At .62 the white heading measured 4.5:1 on
     the Resources photograph — passing, but with nothing in hand. */
.cmp-chero__inner{text-align:center;display:grid;justify-items:center;gap:var(--sp-7);}

.cmp-chero__title{font-size:clamp(2.25rem,4.6vw,4rem);line-height:var(--lh-display);
  letter-spacing:var(--ls-display-lg);color:var(--fg-on-dark);margin:0;
  max-width:18ch;text-wrap:balance;}

/* The reference drops a thin arrow under the statement; it is a real link to
   the first section, so it works from the keyboard and is not just decoration. */
.cmp-chero__down{display:grid;place-items:center;width:2.75rem;height:2.75rem;
  color:var(--fg-on-dark);opacity:.85;}

.cmp-chero__down:hover{opacity:1;}

.cmp-chero__down svg{width:1.25rem;height:2rem;}

/* After a full-bleed band the page needs less air than between two blocks of
   text: the image has a hard edge, so a whole section's padding above the first
   line reads as a hole. Resources and Contact both open this way. */
.site-main .is-style-chero + .cmp-section{padding-top:calc(var(--space-section) * .55);}


/* ==== 42-cards.css ==== */
/*
 * Four photo cards — ported from the prototype by tools/port-css.py.
 * Each look's own class becomes the block style WordPress prints;
 * inner BEM classes are the prototype's, kept by data-wp-class.
 *
 * GENERATED. Edits here are lost on the next port — anything written
 * against a plugin block's own markup belongs in 70- and up.
 */

/* Grid and flex children default to min-width:auto and refuse to shrink below
   min-content — that is what pushes a page wider than the viewport at 200%
   text zoom (WCAG 1.4.4). Opt every track child out. */
.cmp-services>*,
.site-main .is-style-serve>*,
.site-main .arenex-steps__list>*,
.cmp-footer__grid>*,
.site-main .is-style-owner>*,
.cmp-form__row>*,
.site-main .is-style-cards>*,
.cmp-reviews>*,
.cmp-enquiry>*{min-width:0;}

.site-main .is-style-cards{display:grid;gap:var(--sp-5);}

.site-main .is-style-card{position:relative;display:flex;flex-direction:column;justify-content:flex-end;
  min-height:21rem;padding:var(--sp-5) var(--sp-5) var(--sp-6);border-radius:var(--r-md);
  overflow:hidden;isolation:isolate;color:var(--fg-on-dark);
  background:var(--navy-2); /* lazy image: until it lands the card is navy, so the white icon and title are never on a blank panel (7.25:1+ either way) */
  transition:transform var(--dur-base) var(--ease-spring),box-shadow var(--dur-base) var(--ease-expo);}

.cmp-card__bg{position:absolute;inset:0;z-index:-2;width:100%;height:100%;object-fit:cover;aspect-ratio:auto;
  transition:transform var(--dur-zoom) var(--ease-spring);}

/* Measured against a worst-case bright frame: the content band needs >=0.80 navy
   or 15px card text drops to 3.5:1. Held at 0.86 through 88%, then released so
   the photograph still reads at the top of the card. */
.site-main .is-style-card::before{position:absolute;inset:0;z-index:-1;
  /* Bottom-weighted, as the reference does it: the photograph is clear through the
     top half and only the type band is darkened. Measured against a white frame —
     the title sits where alpha is .95 and the icon where it is .88. */
  background:linear-gradient(to top,
    var(--navy) 0%,
    color-mix(in srgb, var(--navy) 96%, transparent) 22%,
    color-mix(in srgb, var(--navy) 62%, transparent) 40%,
    color-mix(in srgb, var(--navy) 12%, transparent) 62%,
    transparent 80%);}

/* RELEASED at the top for the natural photographs. The old ramp still had 72% navy at
   the middle of the card, which was fine over the dark warm frames it was tuned for and
   turned the pale daylight ones into a grey wash. The type band is untouched: the title
   still sits where the wash is .98 and the icon where it is .96, so both keep the 13:1
   they measured. */
.cmp-card__icon{width:2.125rem;height:2.125rem;color:var(--fg-on-dark);margin-bottom:var(--sp-5);}

.cmp-card__title{font-size:var(--t-card);text-wrap:balance;}

/* 21px @1280: 'Financial Management' holds one line in the 236px card column; it wrapped at 30 */
/* The whole card links to its page, as she asked, and the link lives IN the title so
   there is one link per card and its accessible name is the full service name
   ("Accounting" + the hidden " Services"). ::after stretches it back over the card. */
.cmp-card__title a{color:inherit;text-decoration:none;}

.cmp-card__title a::after{content:"";position:absolute;inset:0;z-index:2;}

.site-main .is-style-card:hover{transform:translateY(-4px);box-shadow:var(--shadow-float);}

.site-main .is-style-card:hover .cmp-card__bg{transform:scale(1.05);}

.site-main .is-style-card:has(.cmp-card__title a:focus-visible){outline:3px solid var(--ring-focus);outline-offset:4px;}

.cmp-card__title a:focus-visible{outline:none;}

/* Stagger — siblings in a row arrive one after another, and the step has to be big
   enough to SEE. nth-child, never an inline --i (kses strips it).
   Each staggered row also runs the shorter --dur-stagger, because a 150ms step against
   a 900ms reveal is 17% of the animation: the four cards overlapped so heavily they
   read as a single slab arriving. Every row below finishes inside the 1100ms cap. */
.js .site-main .is-style-cards .is-style-card.is-in,
.js .site-main .is-style-offer-item.is-in,
.js .cmp-serve__item.is-in,
.js .site-main .arenex-steps__step.is-in,
.js .cmp-faq__item.is-in,
.js .cmp-footer__grid > .cmp-anim.is-in{animation-duration:var(--dur-stagger);}

/* four service cards — 450 + 620 = 1070ms */
.js .site-main .is-style-cards .is-style-card:nth-child(2).is-in{animation-delay:150ms;}

.js .site-main .is-style-cards .is-style-card:nth-child(3).is-in{animation-delay:300ms;}

.js .site-main .is-style-cards .is-style-card:nth-child(4).is-in{animation-delay:450ms;}

/* ---- The title is sized by the CARD, not the window --------------------------
 *
 * Four passes at this went wrong because the card's width does not track the viewport:
 * the grid changes from one column to two to four, and the container caps at 1200, so
 * between 1024 and 1200 the card GROWS from 222px to 266px while the viewport steps put
 * the type DOWN. Every breakpoint value was right for one width and wrong beside it.
 *
 * The card is a container and the title is a share of it. "Financial Management" is the
 * longest of the four and measures 10.05x its own font size, so it fills the box at
 * 9.95cqi — 9.6 leaves a few pixels of slack at every card width. (cqi is 1% of the
 * container's CONTENT box, not the card's outer width, which is what caught the first
 * attempt at this.)
 *
 * Floor 18px so it stays readable on a phone, where the card is 173px and two long words
 * cannot fit at any size; cap 24px so it never outgrows the card on a tablet, where the
 * card is 406px and the share alone would give 36px.
 *
 * 4px off each side is 8px more for the words, and 20px still clears the rounded corner.
 */
.site-main .is-style-card{
	container-type:inline-size;
	padding-inline:var(--sp-4);
}

.cmp-card__title{
	font-size:clamp(1.125rem, 9.6cqi, 1.5rem);
}


/* ==== 43-svc.css ==== */
/*
 * Service detail blocks — ported from the prototype by tools/port-css.py.
 * Each look's own class becomes the block style WordPress prints;
 * inner BEM classes are the prototype's, kept by data-wp-class.
 *
 * GENERATED. Edits here are lost on the next port — anything written
 * against a plugin block's own markup belongs in 70- and up.
 */

/* FAILSAFE — needs no script. `.js` comes from the inline snippet in <head>; `.js-ready`
   is set by main.js the moment its reveal observers are wired. If that never happens,
   4s after first paint everything the script would have revealed is shown: the 26
   .cmp-anim blocks, the 4 float photographs, the process line and the phone call bar
   (measured with main.js blocked: 26 + 4 at opacity:0, the line at scaleX(0) and the bar
   parked, for good; with the failsafe all of them are in at 4.6s). When
   main.js does run — normally well inside the 4s — the selector stops matching, the
   pending animation is dropped and nothing here ever plays, so the scroll reveals are
   untouched (a plain timed reveal would replay the C05 bug: every block already shown
   before anyone scrolls to it). Not a motion effect: 1ms, so it sits outside the
   reduced-motion blocks and covers the call bar there too. */
.js:not(.js-ready) .cmp-anim:not(.is-in),
.js:not(.js-ready) .cmp-svc__float,
.js:not(.js-ready) .site-main .is-style-phero .arenex-split__body,
.js:not(.js-ready) .site-main .is-style-phero .arenex-split__figure,
.js:not(.js-ready) .site-main .is-style-phero .arenex-split__figure,
.js:not(.js-ready) .site-main .is-style-phero .arenex-split__figure img,
.js:not(.js-ready) .site-main .arenex-steps__list::before,
.js:not(.js-ready) .cmp-callbar{animation:cmp-failsafe 1ms 4s forwards;}

/* ==========================================================================
   Service detail blocks — the reference runs one expanded two-column block per
   service under the card grid: paired images, a filled circular icon above the
   title, a full paragraph, and a Learn more button. Sides alternate.
   ========================================================================== */
.site-main .is-style-svcs{display:grid;gap:calc(var(--space-block) + 1.5rem);margin-top:var(--space-block);}

/* +24px between the service blocks, so each one has room to read as its own section */
.site-main .is-style-svc,
.site-main .is-style-svc-flip{display:grid;gap:var(--sp-7);align-items:center;padding-block:var(--sp-6);}

/* 32px of its own air top and bottom, on top of the 100px between blocks: each one
     reads as its own section without the row turning into a list of gaps */
.site-main .is-style-svc>*,
.site-main .is-style-svc-flip>*{min-width:0;}

/* Paired images — ONE recipe for the three service blocks and the why-us block.
   Two equal-weight portrait photographs, as the reference runs them: both 4:5, same
   radius, no keyline. Every measure is a % of the FIGURE's own width W, so the pair is
   identical at every width: anchor .86W x 1.075W, float .62W x .775W, figure 1.195W
   tall (anchor + a 12% drop) -> float-over-anchor share = 65.4% everywhere (was 7-56%
   when px padding met % width). Built on aspect-ratio rather than % padding because
   % padding resolves against the grid cell, which breaks the share once max-width caps
   the figure (measured 55% at 768). At 1280 the figure is 631px against a 567px text
   column (was 50-58% of it). */
.site-main .is-style-pair{position:relative;aspect-ratio:1 / 1.195;
  max-width:32rem;}

/* stacked (<1024): a 704px column would make an 841px-tall pair at
                       768 — taller than the screen. 512 wide = 612 tall. Released at 1024. */
.cmp-svc__anchor{width:86%;aspect-ratio:4/5;object-fit:cover;
  border-radius:var(--r-md);box-shadow:var(--shadow-soft);
  background:var(--line);}

/* these photographs are pale: the not-yet-decoded frame is the pale line tone, not an empty shadowed box */
.cmp-svc__float{position:absolute;right:0;bottom:0;width:62%;
  aspect-ratio:4/5;object-fit:cover;border-radius:var(--r-md);box-shadow:var(--shadow-float);}

/* The signature slide-in. Hidden only under .js — with scripts off both photographs are
   simply there (they were missing: 4 images invisible with JS off). The float trails
   the block by 140ms so it reads as the second image arriving: 140 + 900 = 1040ms. */
.js .cmp-svc__float{opacity:0;transform:translateY(2rem);
  transition:opacity var(--dur-reveal) var(--ease-expo) 140ms,
             transform var(--dur-reveal) var(--ease-spring) 140ms;}

.site-main .is-style-pair.is-in .cmp-svc__float{opacity:1;transform:none;}

/* --flip mirrors the pair: anchor right, float bottom-left */
.site-main .is-style-svc-flip .cmp-svc__anchor{margin-left:auto;}

.site-main .is-style-svc-flip .cmp-svc__float{right:auto;left:0;}

/* filled circle, as the reference draws it — not an outlined one */
.cmp-svc__icon{width:4.125rem;height:4.125rem;border-radius:var(--r-pill);
  background:var(--navy);color:var(--fg-on-dark);
  display:grid;place-items:center;margin-bottom:var(--sp-5);
  box-shadow:var(--shadow-soft);}

.cmp-svc__icon svg{width:1.625rem;height:1.625rem;}

.cmp-svc__title{font-size:var(--t-sub-lg);letter-spacing:var(--ls-display-lg);margin-bottom:var(--sp-5);}

.cmp-svc__text{font-weight:300;font-size:var(--t-detail);line-height:var(--lh-detail);
  color:var(--fg-dim);max-width:34rem;margin-bottom:var(--sp-6);}

.cmp-svc__list{display:grid;gap:var(--sp-3);margin-bottom:var(--sp-7);}

.cmp-svc__list li{display:flex;gap:var(--sp-3);align-items:flex-start;
  font-size:var(--t-small);color:var(--fg-dim);min-width:0;}

/* The tick is drawn by CSS, so each item is plain text (a core List block in WordPress,
   not a repeater of inline SVGs — there were 16 copies). A mask filled with currentColor,
   so `color` still decides the ink: --accent here, --accent-on-scrim on the band. */
.cmp-svc__list li::before{content:'';flex:none;width:1.125rem;height:1.125rem;margin-top:.2rem;
  background:currentColor;color:var(--accent);
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath d='m4 10.5 4 4 8-9' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center/contain no-repeat;
  mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath d='m4 10.5 4 4 8-9' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center/contain no-repeat;}

/* On the home page this group followed the section's heading and lead, and paid 76px to
   clear them. On the Services page (round 2, 3 Oct 2026) it is the first thing under the
   page header, so that margin stacked on the section's own padding: 142px of nothing
   between the photograph above and the first service. The section's padding is the gap. */
.site-main .is-style-chero + .cmp-section > .wp-block-group__inner-container > .is-style-svcs{
	margin-top:0;
}


/* ==== 44-also.css ==== */
/*
 * Also on offer — ported from the prototype by tools/port-css.py.
 * Each look's own class becomes the block style WordPress prints;
 * inner BEM classes are the prototype's, kept by data-wp-class.
 *
 * GENERATED. Edits here are lost on the next port — anything written
 * against a plugin block's own markup belongs in 70- and up.
 */

/* ===================== HOME: HER OTHER TWO SERVICES ======================
   Accounts Receivable Management and the nationwide line have no page of
   their own, so they sit under the four that do, as a quieter pair: the same
   hairline and title size as every other list on the site, full width each,
   so they read as a footnote to the four rather than a fifth and sixth card. */
.site-main .is-style-also{list-style:none;margin:var(--sp-8) 0 0;padding:0;display:grid;gap:var(--sp-7);}

.cmp-also__item{border-top:1px solid var(--line);padding-top:var(--sp-5);}

.cmp-also__title{font-size:var(--t-card);margin:0 0 var(--sp-3);}

.cmp-also__text{font-weight:300;font-size:var(--t-detail);line-height:var(--lh-detail);
  color:var(--fg-dim);margin:0;max-width:48ch;}


/* ==== 45-owner.css ==== */
/*
 * Navy band with a photograph — ported from the prototype by tools/port-css.py.
 * Each look's own class becomes the block style WordPress prints;
 * inner BEM classes are the prototype's, kept by data-wp-class.
 *
 * GENERATED. Edits here are lost on the next port — anything written
 * against a plugin block's own markup belongs in 70- and up.
 */

/* ==========================================================================
   Owner band — full-bleed photograph, type over its left side
   The composition her own site runs as its hero. Same three-layer build as the
   old service band (image / scrim / inner), but the type sits left and the scrim
   is measured against this one known frame rather than a worst case.
   ========================================================================== */
/* Stacked, the type sits at the FOOT of the frame so her face keeps the top of it —
   align-content, not align-items, because the wrap is the only in-flow grid child.
   58rem because her head occupies the top 6-37% of the frame and the type block is
   ~540px: any shorter and the copy starts before her chin. A min-height rather than a
   top padding, so at 200% text the band grows with the copy instead of stranding it. */
.site-main .is-style-owner{position:relative;isolation:isolate;overflow:hidden;
  display:grid;align-content:end;
  min-height:58rem;
  padding-block:var(--space-block);
  color:var(--fg-on-dark);
  background:var(--navy-2);}

/* lazy image: until it lands the band is navy, not a grey wash */
.site-main .is-style-owner .wp-block-cover__image-background{position:absolute;inset:0;z-index:-2;width:100%;height:100%;object-fit:cover;
  object-position:50% 50%;}

/* the 4:5 phone frame is already centred on her */
/* Stacked (<1024) the type spans the full width, so the scrim runs top-to-bottom: she
   reads through .26 over the top third, and the ramp is finished by 36% — where the copy
   starts — not eased across the whole frame.
   .90 rather than .86 at the plateau: measured on the RENDERED pixels (375x928, glyphs
   blurred out at 24px so what is left is the ground the type actually sits on), .86 put
   the 18px/300 lead at 4.41:1 against the highlight on her shoulder — 2% under the 4.5
   floor. Checking the source frame had said 6.34:1, because a 10px blur on an 840px-wide
   file is a far coarser filter than 24px on a 375px render. The render is the authority. */
.site-main .is-style-owner .wp-block-cover__background{position:absolute;inset:0;z-index:-1;
  background:linear-gradient(180deg,
    rgb(var(--navy-rgb) / .26)  0%,
    rgb(var(--navy-rgb) / .30) 16%,
    rgb(var(--navy-rgb) / .62) 26%,
    rgb(var(--navy-rgb) / .90) 36%,
    rgb(var(--navy-rgb) / .94) 100%);}

/* neutral black, like the hero — navy was tinting her photograph */
.cmp-owner__body{max-width:34rem;}

.cmp-owner__lead{color:var(--fg-dim-on-dark);}

/* 5.19:1 on the .82 side, 6.34:1 on the .90 */
/* the quote — detail register (18/32), not a second lead */
.cmp-owner__quote{font-weight:300;font-size:var(--t-detail);line-height:var(--lh-detail);
  color:var(--fg-on-dark);max-width:44rem;margin-top:var(--sp-5);
  padding-left:var(--sp-4);border-left:2px solid var(--accent-on-scrim);}

.cmp-owner__credit{display:block;margin-top:var(--sp-2);font-family:var(--font-label);font-weight:600;
  font-size:var(--t-label);letter-spacing:var(--ls-label);text-transform:uppercase;
  color:var(--fg-mute-on-scrim);}

.cmp-owner__cta{margin-top:var(--sp-7);}


/* ==== 46-team.css ==== */
/*
 * The team — ported from the prototype by tools/port-css.py.
 * Each look's own class becomes the block style WordPress prints;
 * inner BEM classes are the prototype's, kept by data-wp-class.
 *
 * GENERATED. Edits here are lost on the next port — anything written
 * against a plugin block's own markup belongs in 70- and up.
 */

/* ========================= ABOUT: THE TEAM ===============================
   Her four people, each with a photograph and the bio she wrote. Two to a
   line, the photograph beside the bio. Two to a line was tried first: it put a
   536px slot under a 760px file, and Franz's and William's originals are only
   about 530px wide so there is nothing bigger to serve. At 288px the same file
   is two and a half times the slot and stays sharp. No job titles: she has not
   sent them. */
.site-main .is-style-team{list-style:none;margin:0;padding:0;display:grid;gap:var(--sp-8);}

/* Row gap is the space BETWEEN her paragraphs, so it stays at prose spacing;
   the column gap beside the photograph is set per width in responsive.css. */
.site-main .is-style-team-item{display:grid;gap:var(--sp-5);align-content:start;
  border-top:1px solid var(--line);padding-top:var(--sp-7);}

.site-main .is-style-team-item:first-child{border-top:0;padding-top:0;}

.site-main .is-style-team-photo{margin:0;overflow:hidden;}

.site-main .is-style-team-photo img{display:block;width:100%;height:auto;aspect-ratio:4/5;object-fit:cover;}

.cmp-team__name{font-size:var(--t-sub);margin:0;}

.cmp-team__text{font-weight:300;font-size:var(--t-body);line-height:var(--lh-detail);
  color:var(--fg-dim);margin:0;max-width:40rem;}


/* ==== 47-serve.css ==== */
/*
 * Who we serve — ported from the prototype by tools/port-css.py.
 * Each look's own class becomes the block style WordPress prints;
 * inner BEM classes are the prototype's, kept by data-wp-class.
 *
 * GENERATED. Edits here are lost on the next port — anything written
 * against a plugin block's own markup belongs in 70- and up.
 */

/* ==========================================================================
   Who we serve
   ========================================================================== */
/* Industry panels — solid navy cards, photograph on top. The photograph fills a 10:9
   box and dissolves into the panel over its last quarter, so there is no hard seam and
   no type ever sits on the picture: every pair below is measured on solid navy.
   `clip`, not `hidden` — `hidden` makes the panel a scroll container, which kills the
   automatic minimum size of the aspect-ratio box and clipped the copy at 200% text. */
.site-main .is-style-serve{display:grid;gap:var(--sp-5);counter-reset:serve;}

.cmp-serve__item{position:relative;overflow:clip;counter-increment:serve;
  display:flex;flex-direction:column;border-radius:var(--r-md);
  background:var(--navy);color:var(--fg-on-dark);box-shadow:var(--shadow-soft);
  transition:box-shadow var(--dur-base) var(--ease-expo),transform var(--dur-base) var(--ease-spring);}

.cmp-serve__item:hover{transform:translateY(-3px);box-shadow:var(--shadow-float);}

.cmp-serve__media{position:relative;overflow:clip;aspect-ratio:10/9;background:var(--navy-2);}

.cmp-serve__img{width:100%;height:100%;object-fit:cover;
  transition:transform var(--dur-zoom) var(--ease-spring);}

.cmp-serve__item:hover .cmp-serve__img{transform:scale(1.04);}

.cmp-serve__media::after{content:'';position:absolute;inset:auto 0 0;height:26%;
  background:linear-gradient(to top,var(--navy),rgb(var(--navy-rgb) / 0));}

.cmp-serve__body{flex:1;padding:var(--sp-4) var(--sp-6) var(--sp-7);}

/* The 01 / 02 / 03 index is gone (round 3, 12 Oct 2026: "why the numbers on who we
   serve — remove numbers"). It implied a ranking or a sequence, and these three are
   neither: they are the industries she works in, in no order. The rule under each title
   still carries the eye down, so the panel does not lose its structure.
   The counter itself stays defined above, so restoring this is uncommenting one rule. */

.cmp-serve__title{font-size:var(--t-card);margin-bottom:var(--sp-3);color:var(--fg-on-dark);}

/* The short rule above each title is gone too (round 3, 12 Oct 2026, straight after the
   numbers: "remove this as well"). It drew itself out on hover and was the panel's only
   motion cue, so the panels are now still on hover — worth knowing if she later asks why
   nothing happens when she points at one. Both rules are kept here, commented, so putting
   the cue back is uncommenting them.

.cmp-serve__title::before{content:'';display:block;width:2.75rem;height:2px;
  margin-bottom:var(--sp-4);background:var(--accent-on-dark);
  transform-origin:left;transform:scaleX(.18);
  transition:transform var(--dur-zoom) var(--ease-spring);}

.cmp-serve__item:hover .cmp-serve__title::before{transform:scaleX(1);}
*/

.cmp-serve__text{font-size:var(--t-small);color:var(--fg-dim-on-dark);}

/* three industry panels */
.js .cmp-serve__item:nth-child(2).is-in{animation-delay:150ms;}

.js .cmp-serve__item:nth-child(3).is-in{animation-delay:300ms;}

/* The home page staggers the middle panel; on a service page the row sits under a
   centred statement and the stagger reads as a mistake. */
.cmp-serve--flat .cmp-serve__item:nth-child(2){translate:none;}


/* ==== 48-res.css ==== */
/*
 * Resource links, and the pager under them — ported from the prototype by tools/port-css.py.
 * Each look's own class becomes the block style WordPress prints;
 * inner BEM classes are the prototype's, kept by data-wp-class.
 *
 * GENERATED. Edits here are lost on the next port — anything written
 * against a plugin block's own markup belongs in 70- and up.
 */

/* ============================== PAGER ===================================
   Sits under a paged list. The count line is a live region, so a screen
   reader hears the new range rather than being dropped silently onto
   different cards. Added by the script: with scripts off every card is
   visible and there is nothing here to render. */
.cmp-pager{display:grid;justify-items:center;gap:var(--sp-5);margin-top:var(--sp-8);}

.cmp-pager__status{margin:0;font-size:var(--t-small);color:var(--fg-mute);}

.cmp-pager__list{list-style:none;margin:0;padding:0;display:flex;flex-wrap:wrap;
  justify-content:center;gap:var(--sp-3);}

.cmp-pager__page{min-width:2.75rem;min-height:2.75rem;padding:0 var(--sp-3);
  display:grid;place-items:center;cursor:pointer;
  font-family:var(--font-label);font-size:var(--t-label);letter-spacing:var(--ls-label);
  color:var(--fg);background:var(--surface);border:1px solid var(--line);}

.cmp-pager__page:hover{border-color:var(--accent);color:var(--accent);}

.cmp-pager__page[aria-current='true']{background:var(--navy);border-color:var(--navy);
  color:var(--fg-on-dark);}

.site-main .is-style-res:focus{outline:none;}

/* ======================== RESOURCES: LINK CARDS ==========================
   Each card is one link straight out to IRS.gov or FTB.ca.gov, so the whole
   card is the <a> and its accessible name is the source, the title and her
   summary together — nothing here is a bare "click here" to a screen reader.
   Shaped to become a `resource` custom post type: the post title is the
   heading, and ACF carries the url, the source and the summary. */
.site-main .is-style-res{list-style:none;margin:0;padding:0;display:grid;gap:var(--sp-6);}

.cmp-res__item{display:grid;}

.cmp-res__link{display:grid;align-content:start;gap:var(--sp-3);height:100%;
  padding:var(--sp-6);background:var(--surface);border:1px solid var(--line);
  text-decoration:none;color:inherit;
  transition:border-color var(--dur-base) var(--ease-expo),
             box-shadow var(--dur-base) var(--ease-expo),
             transform var(--dur-base) var(--ease-spring);}

.cmp-res__link:hover{border-color:var(--accent);transform:translateY(-3px);
  box-shadow:0 14px 34px rgb(10 28 43 / .08);}

.cmp-res__source{font-family:var(--font-label);font-size:var(--t-label);
  letter-spacing:var(--ls-label);text-transform:uppercase;color:var(--accent);}

.cmp-res__title{font-size:var(--t-card);line-height:var(--lh-sub);margin:0;
  text-wrap:balance;}

.cmp-res__text{font-weight:300;font-size:var(--t-body);line-height:var(--lh-detail);
  color:var(--fg-dim);margin:0;}

/* Her own "Click Here" label, kept, with the outbound mark beside it. It sits
   at the foot of the card whatever length the summary runs to. */
.cmp-res__go{display:inline-flex;align-items:center;gap:var(--sp-3);
  margin-top:var(--sp-4);align-self:end;
  font-family:var(--font-label);font-size:var(--t-label);
  letter-spacing:var(--ls-label);text-transform:uppercase;color:var(--fg);}

.cmp-res__go svg{width:.875rem;height:.875rem;flex:none;
  transition:transform var(--dur-base) var(--ease-spring);}

.cmp-res__link:hover .cmp-res__go{color:var(--accent);}

.cmp-res__link:hover .cmp-res__go svg{transform:translate(2px,-2px);}

/* ---- Six, then the rest on a button ----------------------------------------
 *
 * She asked for the list to start at six (round 2, 3 Oct 2026). Every resource is in the
 * markup either way; these rules only apply under .js, so without the script the whole
 * list is there and the button is not.
 */
.js .cmp-res:not(.is-open) .cmp-res__item--extra{
	display:none;
}

.cmp-res__more{
	display:none;
	margin:var(--sp-8) 0 0;
	text-align:center;
}

.js .cmp-res__more{
	display:block;
}


/* ==== 49-quote.css ==== */
/*
 * Reviews — typographic first: the lead quote IS the section.
 *
 * The prototype ran its own fader (each quote in one grid cell, .is-live faded in by
 * main.js). The Testimonials block ships a scroll-snap slider that works without
 * JavaScript and is reachable by keyboard, so the BLOCK keeps the mechanism and this
 * style only does what the design does: the giant quote mark behind the type, the
 * display face at the measured size, and the caption. Porting the fader would have set
 * every quote to opacity 0 and waited for an .is-live class the block never adds.
 *
 * The design has no avatar and no stars, so both are off.
 */

.is-style-quote{
	position:relative;
	isolation:isolate;
}

/* The mark is the section's ground, not an ornament beside the text: set at 30rem it
   reads as a shape, not punctuation, and every quote lands on it. Navy at .07 over the
   tint composites to rgb(224,232,240) at its darkest — --fg measures 13.0:1 there and
   the caption's --fg-dim 5.58:1, so it can sit behind the type. It is drawn here rather
   than in the markup because it is decoration, not words. */
.is-style-quote .arenex-testimonials__inner{
	position:relative;
	isolation:isolate;
}

/* The marks sit beside the words, not above and below them.
   Her instruction, 21 Oct 2026: "I would like the quotes turned right side up and be next
   to the words instead of above and below." So each review is closed on both sides — an
   opening mark before the first word and a closing mark after the last, inline with the
   text and set tight against it, the way a quotation is punctuated rather than decorated.

   Inline, not display:block. A block mark is what put it on its own line above the review;
   inline makes it part of the first line, so the copy flows around it and the pair reads
   as one quotation however long the review runs.

   Sized at 1.6em rather than the old 4.5rem: a mark that leads a line of 27px type can be
   large, but one sitting inside the words has to stay punctuation or it reads as a glyph
   that wandered in. The accent colour is kept so the pair still registers.

   vertical-align and the small negative margins pull each mark against its word: a quote
   mark carries its own side bearing, which at this size leaves a visible gap that makes
   the mark look detached from the text it belongs to.

   aria-hidden is not available on a pseudo-element, but the block is a <blockquote> and a
   screen reader announces it as a quotation already, so the marks are decoration there. */
/* On the PARAGRAPH, not the blockquote. The block renders the review as one or more <p>
   inside .arenex-testimonials__quote, so a mark on the blockquote itself becomes a
   block-level sibling of those paragraphs — which is exactly the "above and below" she
   asked us to move away from. On the first and last paragraph they sit in the line with
   the words. */
.is-style-quote .arenex-testimonials__quote > p:first-child::before,
.is-style-quote .arenex-testimonials__quote > p:last-child::after{
	font-family:var(--font-display);
	font-size:1.6em;
	line-height:0;
	color:var(--accent);
	vertical-align:-0.28em;
}

.is-style-quote .arenex-testimonials__quote > p:first-child::before{
	content:"\201C";
	margin-right:.04em;
}

.is-style-quote .arenex-testimonials__quote > p:last-child::after{
	content:"\201D";
	margin-left:.04em;
}

/* Not in the design. */
.is-style-quote .arenex-testimonials__avatar,
.is-style-quote .arenex-testimonials__stars{
	display:none;
}

/* One review at a time, at the design's measure. The block's slider sizes its columns to
   show the next one peeking; the design shows a single quote across the measure, and at
   the block's own 480px column her longest review ran to 630px of type. */
.is-style-quote .arenex-testimonials__track{
	grid-auto-columns:100%;
}

.is-style-quote .arenex-testimonials__item{
	max-width:56rem;
	gap:var(--sp-6);
	background:none;
	padding:0;
	border:0;
}

/* At --t-sub-lg the longest of her three reviews ran eleven lines down half the page, so
   the size is stepped down and the measure widened. */
.is-style-quote .arenex-testimonials__quote{
	font-family:var(--font-display);
	font-weight:400;
	font-size:var(--t-quote);
	line-height:1.4;
	letter-spacing:var(--ls-display);
	color:var(--fg);
	margin:0;
	text-wrap:pretty;
	/* The parent holds a blockquote to the reading measure (736px); here the quote IS
	   the section and takes the item's own 56rem. */
	max-width:none;
}

.is-style-quote .arenex-testimonials__quote p{
	font-size:inherit;
	line-height:inherit;
	margin:0;
	max-width:none;
}

.is-style-quote .arenex-testimonials__who{
	margin-top:var(--sp-6);
	gap:.2rem;
}

.is-style-quote .arenex-testimonials__name{
	font-family:var(--font-label);
	font-weight:600;
	font-size:var(--t-small);
	letter-spacing:var(--ls-label-tight);
	color:var(--fg);
}

/* 6.02:1 on the tint, 5.58:1 where the mark is behind it. */
.is-style-quote .arenex-testimonials__detail{
	font-family:var(--font-body);
	font-size:var(--t-small);
	letter-spacing:normal;
	color:var(--fg-dim);
}

/* The Testimonials block pays its own --section-padding, and the section that holds it already
   pays --space-section: on the home page that put 260px of air inside the section on top
   of the section's own. The section owns the rhythm (35-sections.css), so the block's
   padding is off. */
.is-style-quote{
	padding-block:0;
}

/* ---- The review controls -----------------------------------------------------
 * The design: two round outlined buttons on the left, the dots pushed to the far right
 * (margin-left:auto). The block renders prev, dots, next in a row and styles them as
 * squares, so the pagination read as a different component altogether.
 *
 * The block's markup order is prev / dots / next; `order` puts both buttons first without
 * touching the DOM, so the tab order still follows the visual one.
 */
.site-main .is-style-quote .arenex-testimonials__nav{
	display:flex;
	align-items:center;
	gap:var(--sp-5);
}

.site-main .is-style-quote .arenex-testimonials__button{
	order:1;
	width:3rem;
	height:3rem;
	flex:none;
	display:grid;
	place-items:center;
	cursor:pointer;
	border:0;
	border-radius:var(--r-pill);
	background:transparent;
	color:var(--accent);
	/* 4.92:1 on the tint — UI needs 3. */
	box-shadow:0 0 0 1.5px currentColor inset;
	transition:background var(--dur-base) var(--ease-expo), color var(--dur-base) var(--ease-expo);
}

.site-main .is-style-quote .arenex-testimonials__button:hover{
	background:var(--accent);
	color:var(--on-accent);
}

.site-main .is-style-quote .arenex-testimonials__button-icon{
	width:1.125rem;
	height:1.125rem;
}

.site-main .is-style-quote .arenex-testimonials__dots{
	order:2;
	display:flex;
	gap:var(--sp-3);
	margin-left:auto;
}

.site-main .is-style-quote .arenex-testimonials__dot{
	width:2.75rem;
	height:2.75rem;
	display:grid;
	place-items:center;
	cursor:pointer;
	background:none;
	border:0;
}

.site-main .is-style-quote .arenex-testimonials__dot::before{
	content:"";
	width:.5rem;
	height:.5rem;
	border-radius:var(--r-pill);
	background:var(--fg-mute);
	transition:background var(--dur-base) var(--ease-expo), transform var(--dur-base) var(--ease-spring);
}

.site-main .is-style-quote .arenex-testimonials__dot[aria-current="true"]::before{
	background:var(--accent);
	transform:scale(1.5);
}

/* The block spaces its controls with a 24px margin; the design spaces the whole section
   on a 48px grid gap and gives the controls no margin of their own. */
.site-main .is-style-quote .arenex-testimonials__inner{
	display:grid;
	gap:var(--sp-7);
}

.site-main .is-style-quote .arenex-testimonials__nav{
	margin:0;
}

/* The block prints the reviewer, then the stars, then the quote, then the company. The
   design leads with the quote and signs it underneath — the quote IS the section, and a
   name above it reads like a heading for something that has not been said yet. `order`
   rearranges without touching the markup, so the reading order for a screen reader is
   still name-then-quote, which is the sensible one to hear. */
.site-main .is-style-quote .arenex-testimonials__item{
	gap:0;
}

.site-main .is-style-quote .arenex-testimonials__quote{
	order:1;
}

.site-main .is-style-quote .arenex-testimonials__who{
	order:2;
	margin-top:var(--sp-6);
}

/* The block pays 3.2px of padding-top on the company line to lift it off the name; the
   design spaces that pair with the grid gap alone, so the padding goes and the gap is
   the only thing between them. Three pixels per review, on every page that has one. */
.site-main .is-style-quote .arenex-testimonials__detail{
	order:3;
	margin-top:.2rem;
	padding:0;
}

/* On the home page the block's heading is there for a screen reader only — the giant
   quote mark is the section's title. A hidden heading still occupies a grid cell and
   still earns a 48px gap after it, which is where 99px of the section's extra height
   came from. Where the heading is hidden, the cell goes too; the service pages, whose
   heading is visible, are untouched. */
.site-main .is-style-quote .arenex-testimonials__head:has(.cmp-vh){
	display:none;
}

/* ---- The quote band as a page of its own ------------------------------------
 *
 * The reviews now live on their own page (round 2, 3 Oct 2026), where the band is the
 * first thing under the page header. Two things broke there.
 *
 * The big quotation mark is set at -.30em of a 456px glyph, so it begins 137px above the
 * section. On the home page the section paid a full --space-section above it and the mark
 * had room; under a page header the section pays .55 of that (35-sections.css), 66px, and
 * the mark ran up into the photograph. It gets the full padding back, and the mark sits
 * closer so it is inside the band either way.
 */
.site-main .is-style-chero + .cmp-section:has(.is-style-quote){
	padding-top:var(--space-section);
}



/* She asked to keep the arrows and have them say what they do.
 *
 * The base rule is display:grid with place-items:center, which is right for a lone icon
 * and wrong the moment there are two things in the button: the arrow and the word stacked
 * one above the other. A row, with the word beside the arrow.
 *
 * The aria-label already reads "Previous review" and still does, so a screen reader hears
 * the longer form and never hears the word twice.
 */
.site-main .is-style-quote .arenex-testimonials__button{
	display:inline-flex;
	flex-direction:row;
	align-items:center;
	justify-content:center;
	width:auto;
	height:2.75rem;
	padding-inline:var(--sp-5);
	gap:var(--sp-3);
	border:1px solid currentColor;
	border-radius:var(--r-pill);
	font-family:var(--font-label);
	font-weight:600;
	font-size:var(--t-label);
	letter-spacing:var(--ls-label);
	text-transform:uppercase;
	text-decoration:none;
	line-height:1;
}

.site-main .is-style-quote .arenex-testimonials__button-icon{
	width:1rem;
	height:1rem;
	flex:none;
}

.site-main .is-style-quote .arenex-testimonials__button[data-dir="prev"]::after{
	content:"Previous";
}

.site-main .is-style-quote .arenex-testimonials__button[data-dir="next"]::after{
	content:"Next";
}

/* The arrow leads on Next and follows on Previous, so each button reads in the direction
   it moves. */
.site-main .is-style-quote .arenex-testimonials__button[data-dir="next"]{
	flex-direction:row-reverse;
}

/* Nothing to go to: say so rather than offering a button that does nothing. */
.site-main .is-style-quote .arenex-testimonials__button[aria-disabled="true"]{
	opacity:.35;
	cursor:default;
}

/* A slide must never be wider than the track it sits in.
 *
 * The item is a flex child sized to its content, so on a phone the longest review set its
 * own width: 494px inside a 358px column, and the right-hand end of every line was cut
 * off. It fitted on desktop only because the track happened to be wider than the text
 * wanted. min() keeps the 56rem reading measure where there is room and clamps to the
 * track where there is not. */
.site-main .is-style-quote .arenex-testimonials__item{
	max-width:min(56rem, 100%);
	min-width:0;
}

/* Two labelled buttons and the dots do not fit one phone row: 494px of controls against
   358px. The dots move under the buttons rather than the buttons shrinking, because the
   words are the thing she asked for. */
@media (max-width:599px){
	.site-main .is-style-quote .arenex-testimonials__nav{
		flex-wrap:wrap;
		row-gap:var(--sp-4);
	}

	.site-main .is-style-quote .arenex-testimonials__dots{
		order:2;
		flex-basis:100%;
		justify-content:flex-start;
	}
}

/* Each slide is its own height, not the tallest one's.
 *
 * The track is a grid, so the slides were all stretched to the longest review and the
 * Previous/Next row sat under that — 150px of nothing below a short review. The track
 * follows the slide on screen instead (50-review-height.js); without the script it has no
 * height set and falls back to the tallest, exactly as before. */
.site-main .is-style-quote .arenex-testimonials__track{
	align-items:start;
	overflow-y:hidden;
}


/* ==== 50-split.css ==== */
/*
 * Full-width split — ported from the prototype by tools/port-css.py.
 * Each look's own class becomes the block style WordPress prints;
 * inner BEM classes are the prototype's, kept by data-wp-class.
 *
 * GENERATED. Edits here are lost on the next port — anything written
 * against a plugin block's own markup belongs in 70- and up.
 */

/* ==================== FULL-WIDTH SPLIT (her two tax blocks) ===============
   Her Tax page runs two solid full-width blocks, icon and heading over the
   copy on one side, and they alternate. Same shape here: one half carries the
   panel and the icon disc the process steps already use, the other half is a
   photograph filling its half edge to edge. --flip swaps the sides, which is
   what makes the pair read as a pair. Full-bleed, so it breaks the page column
   the way her blocks do. */
/* The band is boxed now, not full-bleed (70-arenex-split.css), so the grid takes the
   width it is given rather than reaching for the viewport. */
.site-main :is(.is-style-split-dark, .is-style-split-tint) > .arenex-split__grid{display:grid;width:100vw;margin-inline:calc(50% - 50vw);}
/* …except the contained ones, which take the width they are given (70-arenex-split.css). */
.site-main :is(.is-style-split-dark, .is-style-split-tint):not(.cmp-split--tall) > .arenex-split__grid{width:100%;margin-inline:0;}

/* 30rem is the measure for the half column this sits in from 1024, set in
   responsive.css. Stacked, the body is the full page width and 30rem left a
   third of it empty. */
.site-main .is-style-split-dark .arenex-split__body,
.site-main .is-style-split-tint .arenex-split__body{padding:var(--space-section) var(--sp-6);display:grid;
  align-content:center;justify-items:start;}

.cmp-split__icon{width:4.125rem;height:4.125rem;border-radius:var(--r-pill);flex:none;
  display:grid;place-items:center;background:var(--navy);color:var(--fg-on-dark);
  margin-bottom:var(--sp-6);}

.site-main .is-style-split-dark .cmp-split__icon{background:var(--surface);color:var(--navy);}

.cmp-split__icon svg{width:1.75rem;height:1.75rem;}

/* Her longest heading on the site sits here ("Experienced Tax and Accounting
   Professionals You Can Trust"): at the section size it ran four lines and
   pushed the list off the block. It takes the service-detail step instead. */
.cmp-split__title{font-size:var(--t-sub-lg);line-height:var(--lh-sub);
  letter-spacing:var(--ls-display);margin:0;max-width:22ch;text-wrap:balance;}

.cmp-split__lead{font-weight:400;font-size:var(--t-detail);line-height:1.6;
  color:var(--fg);margin:var(--sp-5) 0 0;max-width:46rem;}

.cmp-split__text{font-weight:300;font-size:var(--t-body);line-height:var(--lh-detail);
  color:var(--fg-dim);margin:var(--sp-5) 0 0;max-width:46rem;}

.site-main .is-style-split-dark{background:var(--navy);}

.site-main .is-style-split-dark .cmp-split__title{color:var(--fg-on-dark);}

.site-main .is-style-split-dark .cmp-split__lead{color:var(--fg-on-dark);}

.site-main .is-style-split-dark .cmp-split__text{color:var(--fg-dim-on-dark);}

.site-main .is-style-split-tint{background:var(--surface);}

.site-main .is-style-split-dark .arenex-split__figure,
.site-main .is-style-split-tint .arenex-split__figure{margin:0;}

.site-main .is-style-split-dark .arenex-split__figure img,
.site-main .is-style-split-tint .arenex-split__figure img{display:block;width:100%;height:100%;object-fit:cover;
  aspect-ratio:4/3;}

/* An upright picture: 4/3 would take the top off a portrait on a phone. */
.site-main .is-style-split-dark.cmp-split--tall .arenex-split__figure img{aspect-ratio:29/30;}

/* Her seven bullets, inside the panel. */
.cmp-split__list{list-style:none;margin:var(--sp-6) 0 0;padding:0;display:grid;
  gap:var(--sp-4);max-width:46rem;}

.cmp-split__list li{display:flex;gap:var(--sp-4);align-items:flex-start;
  font-weight:300;font-size:var(--t-body);line-height:1.5;color:var(--fg-dim);}

.cmp-split__list li::before{content:'';flex:none;width:1.125rem;height:1.125rem;
  margin-top:.22rem;background:currentColor;color:var(--accent);
  -webkit-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath d='m4 10.5 4 4 8-9' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center/contain no-repeat;
  mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath d='m4 10.5 4 4 8-9' fill='none' stroke='%23000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center/contain no-repeat;}

.site-main .is-style-split-dark .cmp-split__list li::before{color:var(--accent-on-dark);}


/* ==== 51-phero.css ==== */
/*
 * Service page header — ported from the prototype by tools/port-css.py.
 * Each look's own class becomes the block style WordPress prints;
 * inner BEM classes are the prototype's, kept by data-wp-class.
 *
 * GENERATED. Edits here are lost on the next port — anything written
 * against a plugin block's own markup belongs in 70- and up.
 */

/* ==================== ONE GAP BETWEEN SECTIONS ==========================
   Every section pays padding top and bottom, so two of them in a row put
   259px between their contents at 1440 and 144px at 375 — measured across all
   ten pages, 13 boundaries. Where both sides sit on the same ground with no
   edge between them, the second one stops paying and the gap is the single
   --space-section the scale intends.

   This does NOT apply to a block with a background of its own. On the dark
   bands, the owner block, the tinted quotes and the centred heroes, that
   padding is not a gap between sections at all — it is the air inside the
   coloured box, and removing it would put the type against the edge. */
.cmp-section:not(.cmp-section--tint) + .cmp-section:not(.cmp-section--tint),
.site-main .is-style-phero + .cmp-section:not(.cmp-section--tint){padding-top:0;}

/* the bar is in the flow above the hero, so no clearance is owed to it */


/* ======================= SERVICE PAGE: HERO ==============================
   The reference's service-page hero, and only what it holds: the serif title,
   one button, one photograph. Her sub-headline and intro are not lost — they
   open the section below, which is where the reference puts its first
   paragraph too.
   The photograph fills the right half and bleeds off the right edge from 1024
   (responsive.css); below that it is a plain 4:5 frame under the type. It
   arrives with the float's move, up and in, so the page opens the way the home
   page's pairs do — main.js reveals .cmp-phero__figure with the rest. */
.site-main .is-style-phero{padding-block:calc(var(--space-section) + var(--header-h)) var(--space-section);}

.site-main .is-style-phero .arenex-split__grid{display:grid;gap:var(--sp-8);}

/* The reference sets this title far above the page's own H1 step — 86px in a 472px
   column, so it breaks over three lines and behaves like a piece of art rather than a
   heading. Clamped rather than tokenised: it is this component's own size, used nowhere
   else, and the page's H2 scale is untouched by it. */
.cmp-phero__title{font-size:clamp(2.75rem,5.4vw,4.75rem);line-height:1.04;
  letter-spacing:var(--ls-display-lg);margin:0;}

/* The service name, drawn as an outline the way the reference draws its second line.
   Solid by default and on phones: a hairline outline at 44px is thin to read, and an
   engine without text-stroke would paint nothing at all if the fill were transparent
   here. responsive.css turns it into the outline from 768 up, behind @supports. */
.cmp-phero__em{display:block;font-style:normal;}

/* About opens on her own paragraph rather than a button: the hero body holds
   it, so it needs a measure and the quieter ink the leads use elsewhere. */
.cmp-phero__lead{font-weight:300;font-size:var(--t-body);line-height:var(--lh-detail);
  color:var(--fg-dim);margin:var(--sp-6) 0 0;max-width:46rem;text-wrap:pretty;}

/* 34rem is the measure for the 36rem column it sits in from 1024 (set in
     responsive.css). Stacked, the column is the full page width and 34rem left
     a third of it empty. */
.cmp-phero__actions{display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp-5);
  margin-top:var(--sp-7);}

.site-main .is-style-phero .arenex-split__figure{margin:0;overflow:hidden;}

.site-main .is-style-phero .arenex-split__figure img{width:100%;aspect-ratio:4/5;object-fit:cover;
  border-radius:var(--r-md);box-shadow:var(--shadow-soft);background:var(--line);}

/* Same reveal as .cmp-svc__float, same numbers: hidden only under .js, so with
   scripts off the photograph is simply there. */
/* The reference's reveal, taken from its own stylesheet rather than guessed. Its hero
   photograph is a column background with data-bg-animation="ro-reveal-from-bottom",
   and Nectar's JavaScript only adds classes — the motion is three CSS layers:

     wrap    translate3d(0,250px,0)            ->  translate3d(0,0,0)
     inner   rotate(25deg), origin left bottom ->  rotate(0), opacity 0 -> 1
     image   rotate(-25deg), same origin       ->  rotate(0)

   all on transform 2.3s cubic-bezier(0.2,0.65,0.3,1), the inner's opacity on .25s.
   The mask turns while the picture counter-turns inside it, so the photograph stays
   upright while its edge crosses the frame on the angle, and the whole thing rises
   250px. At rest every layer is 0, so it is a plain rectangle.
   Hidden only under .js: with scripts off the photograph is simply there. */
.site-main .is-style-phero .arenex-split__figure{overflow:hidden;width:100%;height:100%;}

/* The type beside it, on the reference's own column animation: fade-in-from-bottom,
   `translateY(50px)` with `data-delay="400"` on that column. Their end state is written
   inline by their script, so the duration is not in their CSS; 1s on the same curve as
   the photograph keeps the pair moving together, with the 400ms delay they set, so the
   words arrive while the frame is still rising. */
/* KEYFRAMES, not transitions. Measured: the page hero was the only reveal on the site
   built on transitions, and the only one that did not play. The hidden state painted, the
   transition property was applied (transform 2.3s, opacity .25s), .is-in went on — and the
   photograph still arrived finished. Screenshots at 300 / 700 / 1200 / 1900 / 2800ms were
   identical to the pixel.

   A transition only runs when the browser accepts that the old value was settled, and on
   a block that is above the fold the observer reports it in the same frame cluster as the
   first paint. Whether it animated was a race — which is what she reported twice: "it
   rolls in and sometimes it doesn't."

   A keyframe has no such precondition: it starts when the class lands. That is exactly
   why the rest of the site's reveals are keyframes, and the note in 90-motion.css says so
   in as many words. Same durations, same easings, same end state as before. */
.js .site-main .is-style-phero .arenex-split__body{opacity:0;}
.site-main .is-style-phero .arenex-split__body.is-in{
  animation:ftf-phero-body-y 1s cubic-bezier(.2,.65,.3,1) .4s backwards,
            ftf-phero-body-o .6s ease .4s backwards;
  opacity:1;}

@keyframes ftf-phero-body-y{from{transform:translateY(50px);}to{transform:none;}}
@keyframes ftf-phero-body-o{from{opacity:0;}to{opacity:1;}}

/* The photograph swings up from its bottom-left corner. It used to counter-rotate inside
   the frame, so the frame swung and the picture stayed upright, which reads as an overlay
   sweeping across a still image rather than the picture arriving. It moves with its frame
   now: one thing, in one motion. */
.js .site-main .is-style-phero .arenex-split__figure{opacity:0;transform-origin:left bottom;}
.site-main .is-style-phero .arenex-split__figure.is-in{
  animation:ftf-phero-fig-y 2.3s cubic-bezier(.2,.65,.3,1) backwards,
            ftf-phero-fig-o .25s ease backwards;
  opacity:1;}

@keyframes ftf-phero-fig-y{from{transform:rotate(25deg) translateZ(0);}to{transform:translate3d(0,0,0);}}
@keyframes ftf-phero-fig-o{from{opacity:0;}to{opacity:1;}}


/* ==== 52-band.css ==== */
/*
 * Full-bleed photo band — ported from the prototype by tools/port-css.py.
 * Each look's own class becomes the block style WordPress prints;
 * inner BEM classes are the prototype's, kept by data-wp-class.
 *
 * GENERATED. Edits here are lost on the next port — anything written
 * against a plugin block's own markup belongs in 70- and up.
 */

/* ======================= SERVICE PAGE: DARK BAND =========================
   The reference's dark band: one photograph across the full width at half
   black, the pictures on one side and the copy on the other. Built like
   .cmp-close — image, scrim, then the wrap on top — because that band already
   proved the stack. The pictures are the .cmp-svc pair, so they arrive with
   the same slide-in as everywhere else. */
.site-main .is-style-band{position:relative;isolation:isolate;overflow:hidden;
  padding-block:var(--space-section);}

.site-main .is-style-band .wp-block-cover__image-background{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;z-index:-2;}

/* Stacked, the type sits under the pictures and the frame is already dark: one even
   value does it. From 1024 the type moves beside the picture, over the lit meeting
   room, so responsive.css weights the scrim to that side instead of darkening the
   whole photograph — the picture is the point of the band. */
/* The scrim is the brand navy, not plain black: every band on the site is a photograph
   under a wash, and black read as a grey film over the picture rather than part of the
   palette. Same alpha, so the contrast figures hold (navy is luminance .012 against
   black’s 0). */
.site-main .is-style-band .wp-block-cover__background{position:absolute;inset:0;background:rgb(var(--navy-rgb) / .55);z-index:-1;}

.site-main .is-style-band-inner{display:grid;gap:var(--sp-8);}

/* Headings carry their own colour on the page, so on a dark band they have to be
   told again — inheriting from .cmp-on-dark is not enough. */
.cmp-band__title{font-size:var(--t-sub-lg);letter-spacing:var(--ls-display-lg);
  color:var(--fg-on-dark);margin:0 0 var(--sp-4);}

.cmp-band__sub{font-size:var(--t-sub);letter-spacing:var(--ls-display-lg);
  color:var(--fg-on-dark);margin:var(--sp-7) 0 var(--sp-4);}

/* White, held a step under the heading, rather than the page's blue-grey dim: on a
   photograph the blue-grey read as a different ink from the headings above it. .82
   composites to about 216 against these grounds, where the heading sits at 232, so
   the step is visible without the copy going grey. */
.cmp-band__text{font-weight:300;font-size:var(--t-detail);line-height:var(--lh-detail);
  color:rgb(255 255 255 / .82);margin:0;max-width:46ch;}

/* ---- The band is a colour, not a photograph ---------------------------------
 *
 * Round 2, 3 Oct 2026: "remove bg image and change with solid colour or gradient."
 *
 * The band held a wide photograph under a wash, with two more photographs inset on top of
 * it — three pictures competing in one section, and the backmost one only ever read as a
 * dark texture. The inset pair is the point of the band, so the backdrop steps back to
 * the brand's own dark.
 *
 * Done in CSS rather than by taking the image out of the three pages: the photograph
 * stays in the block, so putting it back is deleting this rule, and she still sees it in
 * the editor where she can swap it.
 *
 * The gradient is the footer's family — navy-2 into navy — on the diagonal, so the side
 * carrying the type is the darker end.
 */
.site-main .is-style-band .wp-block-cover__image-background{
	display:none;
}

.site-main .is-style-band{
	background:linear-gradient(145deg,
		var(--navy-2)  0%,
		var(--navy)   58%,
		#081621      100%);
}

/* The scrim weighted the wash towards the type because a photograph sat under it. With a
   flat ground there is nothing to weight, and the gradient above is the whole backdrop. */
.site-main .is-style-band .wp-block-cover__background{
	background:none;
}


/* ==== 53-offer.css ==== */
/*
 * Numbered service rows — ported from the prototype by tools/port-css.py.
 * Each look's own class becomes the block style WordPress prints;
 * inner BEM classes are the prototype's, kept by data-wp-class.
 *
 * GENERATED. Edits here are lost on the next port — anything written
 * against a plugin block's own markup belongs in 70- and up.
 */

/* Each of her services is a numbered row on a white panel, not a cell in a grid
   of text: the number and the title block hold the left, her paragraph gets a
   column of its own on the right. Three stacked paragraphs in one narrow cell
   read as one block of text — split across two columns, the bold line is
   plainly a sub-head and the paragraph is plainly the detail. */
.site-main .is-style-offer{list-style:none;margin:0;padding:0;display:grid;
  counter-reset:offer;background:var(--surface);border:1px solid var(--line);}

.site-main .is-style-offer-item{display:grid;gap:var(--sp-3) var(--sp-7);align-items:start;
  padding:var(--sp-6) var(--sp-6);}

.site-main .is-style-offer-item + .is-style-offer-item{border-top:1px solid var(--line);}

.site-main .is-style-offer-item::before{content:counter(offer, decimal-leading-zero);counter-increment:offer;
  font-family:var(--font-label);font-size:var(--t-label);letter-spacing:var(--ls-label);
  color:var(--accent);line-height:1;padding-top:.45rem;}

.site-main .is-style-offer-head{min-width:0;}

/* The title outranks her bold line instead of sitting level with it: 24px
   Gelasio over 18px Roboto 400 over 18px Roboto 300 dim — three clear ranks
   down the block. Fixed at every width for the same reason --t-detail is: the
   line under it never changes size, so the step must not either. --t-sub-lg
   reaches 40px from 1024 and swallowed the row. */
.cmp-offer__title{font-size:1.625rem;line-height:var(--lh-sub);margin:0;
  text-wrap:balance;}

/* two of Bookkeeping's nine run to two lines at this size; balanced, they split evenly instead of leaving one word alone */
/* Her bold line under each service title: Roboto 400 over the 300 of the
   paragraph, and the full-strength ink over the dim. Only two weights are
   loaded, so the step is weight plus colour rather than a synthetic bold. */
/* Her bold line is a deck, not a paragraph: same size as the prose under it but
   full-strength ink at 400 and set tight. At the 1.78 body leading a two-line
   deck read as a second paragraph and made the block look like three of them. */
.cmp-offer__lead{font-weight:400;font-size:var(--t-body);line-height:1.5;
  color:var(--fg);margin:var(--sp-3) 0 0;max-width:36ch;}

.cmp-offer__text{font-weight:300;font-size:var(--t-body);line-height:var(--lh-detail);
  color:var(--fg-dim);margin:0;max-width:50ch;}


/* ==== 54-svclist.css ==== */
/* ==========================================================================
   The list of services on a service page.  22 Oct 2026.
   --------------------------------------------------------------------------
   Replaces the four numbered boxes. Her instruction (Services Changes.docx):
   "Put the services a list (see sample)", with a photograph of the layout she
   wants — one row per service, the name in bold, a sentence under it, a hairline
   between rows.

   Her sample numbers its rows 01–07 and her note asks to see it both ways. The
   call settled it: no numbers, keep the rule. So the rule does the work the
   numbers were doing — it marks where one service ends and the next begins, and
   it is the same hairline the FAQ and the footer already use, so the page gains
   no new device.

   This is also why the boxes had to go rather than be restyled: her revised text
   runs to eight and nine services per page, not four. A 2x2 grid of nine items
   is not a grid.
   ========================================================================== */
/* A core Group in this theme renders an inner container, so a row is a GRANDCHILD of
   the list, not a child. Written out in full rather than as a descendant selector, so
   the paragraphs inside a row can never be mistaken for rows themselves. */
.site-main .is-style-svclist > .wp-block-group__inner-container{
	display:grid;
	grid-template-columns:minmax(0,1fr);
}

.site-main .is-style-svclist{
	margin-top:var(--space-block);
}

/* The rule sits ABOVE each row and the first row carries one too, so the list
   opens and closes on a line exactly as her sample does. box-shadow rather than
   border-top: a shadow does not add to the row's height, so the rhythm below is
   set by the padding alone. */
.site-main .is-style-svclist > .wp-block-group__inner-container > .wp-block-group{
	padding-block:var(--sp-5);
	box-shadow:0 -1px 0 rgb(var(--navy-rgb) / .14);
	min-width:0;
}

.site-main .is-style-svclist > .wp-block-group__inner-container > .wp-block-group:last-child{
	box-shadow:0 -1px 0 rgb(var(--navy-rgb) / .14),
	           0 1px 0 rgb(var(--navy-rgb) / .14);
}

/* Name and sentence share a row from 768 up (92-responsive.css); stacked below,
   because a 28ch name beside a 60ch sentence is unreadable on a phone. */
.cmp-svclist__name{
	font-family:var(--font-label);
	font-weight:600;
	font-size:var(--t-small);
	line-height:var(--lh-label);
	letter-spacing:.01em;
	color:var(--fg);
	margin:0 0 var(--sp-2);
}

.cmp-svclist__text{
	font-size:var(--t-body);
	line-height:var(--lh-body);
	color:var(--fg-dim);
	margin:0;
	max-width:62ch;
}


/* ==== 57-acc.css ==== */
/*
 * Questions — ported from the prototype by tools/port-css.py.
 * Each look's own class becomes the block style WordPress prints;
 * inner BEM classes are the prototype's, kept by data-wp-class.
 *
 * GENERATED. Edits here are lost on the next port — anything written
 * against a plugin block's own markup belongs in 70- and up.
 */

/* Four questions under the steps. A definition list, open — nothing to click, so the
   answers are there for a skimmer, a screen reader and a search engine alike. Same
   hairline as the steps above, so it reads as the same system one register quieter.
   Question: Montserrat 600 (a real face — no synthesised Roboto 600). */
.cmp-faq__title{font-size:var(--t-sub);letter-spacing:var(--ls-display-lg);margin-bottom:var(--sp-6);}

.site-main .is-style-faq{display:grid;gap:0 var(--sp-8);}

.cmp-faq__item{min-width:0;padding-block:var(--sp-5);box-shadow:0 -1px 0 rgb(var(--navy-rgb) / .12);}

.cmp-faq__item :is(dt, .cmp-dt, .cmp-legal__term){font-family:var(--font-label);font-weight:600;font-size:var(--t-small);
  line-height:var(--lh-label);letter-spacing:.02em;color:var(--fg);margin-bottom:var(--sp-3);}

.cmp-faq__item :is(dd, .cmp-dd, .cmp-legal__def){margin:0;font-size:var(--t-body);color:var(--fg-dim);max-width:58ch;}

/* four questions */
.js .cmp-faq__item:nth-child(2).is-in{animation-delay:120ms;}

.js .cmp-faq__item:nth-child(3).is-in{animation-delay:240ms;}

.js .cmp-faq__item:nth-child(4).is-in{animation-delay:360ms;}

.site-main .is-style-acc{border-top:1px solid var(--line);}

.cmp-acc__item{border-bottom:1px solid var(--line);}

.cmp-acc__item summary{display:flex;align-items:center;justify-content:space-between;
  gap:var(--sp-5);padding:var(--sp-5) 0;min-height:2.75rem;cursor:pointer;
  font-weight:500;font-size:var(--t-card);color:var(--fg);
  list-style:none;}

/* the default triangle, gone in every engine */
.cmp-acc__item summary::-webkit-details-marker{display:none;}

.cmp-acc__item summary::marker{content:'';}

.cmp-acc__icon{flex:none;width:1.25rem;height:1.25rem;color:var(--blue-deep);
  transition:transform var(--dur-fast) var(--ease-expo);}

.cmp-acc__icon svg{width:100%;height:100%;display:block;}

.cmp-acc__item[open] .cmp-acc__icon{transform:rotate(180deg);}

.cmp-acc__panel{margin:0;padding:0 0 var(--sp-6);max-width:70ch;
  font-weight:300;font-size:var(--t-detail);line-height:var(--lh-detail);color:var(--fg-dim);}

/* The questions sit under the process block, which ends on her photograph. Flush against
   it the heading read as part of the picture, so it gets the block gap the rest of the
   page uses. */
.cmp-faq{margin-top:var(--space-block);}

/* The FAQ page sets its twelve questions in three named groups. A group heading that
   follows an accordion needs the air a section gives a heading, or the next group reads
   as more of the last one; the first heading takes the lead paragraph's spacing instead. */
.cmp-faq__group{
	margin-top:var(--sp-9);
}

.cmp-head + .cmp-faq__group{
	margin-top:0;
}


/* ==== 60-process.css ==== */
/*
 * How it works — ported from the prototype by tools/port-css.py.
 * Each look's own class becomes the block style WordPress prints;
 * inner BEM classes are the prototype's, kept by data-wp-class.
 *
 * GENERATED. Edits here are lost on the next port — anything written
 * against a plugin block's own markup belongs in 70- and up.
 */

/* ==========================================================================
   Process — CONCEPT SPINE, appearance 2: one line drawn through the steps
   ========================================================================== */
/* Stacked at every width: intro, then the three steps, then the questions. Beside a
   sticky intro (.8fr / 2fr) each step measured 27ch with a one-word orphan — the measure
   rule out-ranks the sticky-intro pattern. Block gap, so the three read as one section. */
.site-main .is-style-process{display:grid;gap:var(--space-block);align-items:start;}

.cmp-process__intro{max-width:48rem;}

/* 768px: the new H2 holds two lines at 52px (measured 3 at 44rem) */
/* Photograph left, the three steps stacked down the right — the composition her own
   site uses for this section. The spine turns with it: it was a horizontal rule over a
   three-column row, and it is now a vertical line running down through the icon discs,
   drawn on reveal. Still scaleY on the compositor, not height. */
.cmp-how{display:grid;gap:var(--sp-8);align-items:start;}

.cmp-how__figure{margin:0;}

.cmp-how__figure img{width:100%;aspect-ratio:4/5;object-fit:cover;
  border-radius:var(--r-md);box-shadow:var(--shadow-float);background:var(--line);}

.site-main .arenex-steps__list{position:relative;display:grid;gap:var(--sp-7);counter-reset:step;
  list-style:none;padding:0;margin:0;}

/* the spine sits on the centre line of the 56px disc column */
.site-main .arenex-steps__list::before{content:'';position:absolute;left:1.75rem;top:1.75rem;bottom:1.75rem;
  width:1.5px;background:var(--line);transform-origin:top;
  transition:transform var(--dur-line) var(--ease-expo);}

.js .site-main .arenex-steps__list::before{transform:scaleY(0);}

.js .site-main .arenex-steps__list.is-in::before{transform:scaleY(1);}

.site-main .arenex-steps__step{position:relative;counter-increment:step;
  display:grid;grid-template-columns:3.5rem 1fr;column-gap:var(--sp-5);align-items:start;}

.site-main .arenex-steps__step>*{min-width:0;}

/* the same filled navy disc the services and the owner band use, one step smaller.
   It sits ON the spine, so it needs its own ground to break the line. */
.site-main .arenex-steps__num{grid-row:1 / span 3;width:3.5rem;height:3.5rem;border-radius:var(--r-pill);
  background:var(--navy);color:var(--fg-on-dark);box-shadow:var(--shadow-soft);
  display:grid;place-items:center;position:relative;z-index:1;}

.site-main .arenex-steps__num svg{width:1.375rem;height:1.375rem;}

/* 01 / 02 / 03 from a counter — the numbers follow the list, so reordering a step in
   the editor never leaves a hard-coded "02" behind. Label register, above the title. */
.site-main .arenex-steps__title{font-size:var(--t-card);margin:0 0 var(--sp-3);}

.site-main .arenex-steps__title::before{content:counter(step,decimal-leading-zero);
  display:block;margin-bottom:var(--sp-2);
  font-family:var(--font-label);font-weight:700;font-size:var(--t-label);
  letter-spacing:var(--ls-label);color:var(--accent);font-variant-numeric:tabular-nums;}

.site-main .arenex-steps__desc{font-size:var(--t-small);color:var(--fg-dim);margin:0;}

/* three process steps, following the spine as it draws */
.js .site-main .arenex-steps__step:nth-child(2).is-in{animation-delay:150ms;}

.js .site-main .arenex-steps__step:nth-child(3).is-in{animation-delay:300ms;}

/* ======================= SERVICE PAGE: ACCORDION =========================
   Six questions cost one screen instead of three. <details>/<summary> gives
   the open/close, the keyboard and the screen-reader semantics for free, and
   it still works with scripts off — the same reason the FAQ on the home page
   is a plain list rather than a scripted one. */
/* One panel at a time: the shared `name` makes the group exclusive, so opening one
   closes the last — the element does it, no script. A browser without it simply lets
   several stand open, which is the old behaviour and no worse. */
.cmp-how__action{margin-top:var(--sp-5);}


/* ==== 61-close.css ==== */
/*
 * Closing call to action — ported from the prototype by tools/port-css.py.
 * Each look's own class becomes the block style WordPress prints;
 * inner BEM classes are the prototype's, kept by data-wp-class.
 *
 * GENERATED. Edits here are lost on the next port — anything written
 * against a plugin block's own markup belongs in 70- and up.
 */

/* ==========================================================================
   Full-bleed service band — the reference's dark image row with large serif
   type set to one side. Used once, on the fourth service, so the alternating
   two-column rhythm above it has somewhere to land.
   ========================================================================== */

/* ==========================================================================
   Closing CTA — the reference's shape: eyebrow, one large centred serif
   statement, one button. Nothing else in the band.
   ========================================================================== */
.site-main .is-style-close{position:relative;isolation:isolate;overflow:hidden;color:var(--fg-on-dark);
  background:var(--navy-2);}

/* same first-frame rule as the hero and the band */
.site-main .is-style-close .wp-block-cover__image-background{position:absolute;inset:0;z-index:-2;width:100%;height:100%;object-fit:cover;}

/* Uniform, so the statement reads the same wherever it falls. .70 (was .78, which left
   22% of the photograph — a navy slab). Measured like the hero, against a PURE-WHITE frame
   — the image will be swapped in the WordPress media library one day and nobody will
   re-measure. Navy @.70 over white = rgb(84,96,107):
     eyebrow 13px  --fg-mute-on-scrim  5.16:1   (needs 4.5)
     title / tel   --fg-on-dark        5.51:1
     button border 75% white           4.47:1   (UI, needs 3)
   The eyebrow was --accent-on-scrim: 6.55:1 on the shipped frame (brightest pixel
   rgb(105,131,152)) but 3.64:1 on white — a pass that depended on the photograph. On the
   shipped frame the pairs now measure 9.29 / 9.92 / 7.30. */
.site-main .is-style-close .wp-block-cover__background{position:absolute;inset:0;z-index:-1;
  background:rgb(var(--navy-rgb) / .50);}

/* NEUTRAL BLACK, and much lighter. Navy @.70 was both
     tinting the photograph blue and burying it; the type had 11.6:1 it did not need. Black
     @.50 shows far more of the room and still measures H2 9.71:1, eyebrow 9.09:1, phone
     9.71:1, button border 7.19:1 — every one of them well clear. */
.cmp-close__inner{padding-block:var(--space-section-lg);text-align:center;}

.site-main .is-style-close .cmp-eyebrow{justify-content:center;color:var(--fg-mute-on-scrim);}

.site-main .is-style-close .cmp-eyebrow::after{display:none;}

.cmp-close__title{font-size:var(--t-section);letter-spacing:var(--ls-display-lg);max-width:24ch;margin:0 auto var(--sp-7);}

.cmp-close__actions{display:flex;flex-direction:column;align-items:center;gap:var(--sp-5);}

.cmp-close__tel{font-family:var(--font-label);font-weight:600;font-size:var(--t-label);
  line-height:var(--lh-label);letter-spacing:var(--ls-label);text-transform:uppercase;color:var(--fg-on-dark);
  text-decoration:none;display:inline-flex;align-items:center;min-height:2.75rem;
  border-bottom:1.5px solid rgb(255 255 255 / .55); /* 3.20:1 against a white frame under the .70 scrim — same cue, same value as the hero tel */
  transition:border-color var(--dur-fast) var(--ease-expo);}

.cmp-close__tel:hover{border-color:var(--fg-on-dark);color:var(--fg-on-dark);}


/* ==== 62-contact.css ==== */
/*
 * Enquiry form — ported from the prototype by tools/port-css.py.
 * Each look's own class becomes the block style WordPress prints;
 * inner BEM classes are the prototype's, kept by data-wp-class.
 *
 * GENERATED. Edits here are lost on the next port — anything written
 * against a plugin block's own markup belongs in 70- and up.
 */

/* ==========================================================================
   Enquiry form — fields, validation states
   ========================================================================== */
.cmp-form{display:grid;gap:var(--sp-5);}

.cmp-form__row{display:grid;gap:var(--sp-5);align-items:start;}

/* start: an error line under one field must not stretch its neighbour's input */
.cmp-field{display:grid;gap:var(--sp-2);min-width:0;}

.cmp-field__label{font-family:var(--font-label);font-weight:600;font-size:var(--t-small);
  letter-spacing:.02em;color:var(--fg);}

.cmp-field__req{color:var(--accent);}

.cmp-field__input{width:100%;font:inherit;font-size:var(--t-body);color:var(--fg);
  background:var(--surface);border:1.5px solid var(--field);border-radius:var(--r-md);
  min-height:3.25rem;padding:.75rem var(--sp-5);
  transition:border-color var(--dur-fast) var(--ease-expo);}

.cmp-field__input::placeholder{color:var(--fg-mute);}

/* A real ring. The old focus state was a 1.5px colour change plus a 1.25:1 halo; this is
   the page ring (--ring-focus, 5.66:1 on the white field, 5.31:1 on the ground) at 3px. */
.cmp-field__input:hover{border-color:var(--fg-dim);}

.cmp-field__input:focus-visible{border-color:var(--accent);
  outline:3px solid var(--ring-focus);outline-offset:2px;box-shadow:none;}

/* after :focus-visible so a focused invalid field keeps its red border. --bad on the white
   field 6.28:1 (UI, needs 3); the message on the page ground 5.90:1 (needs 4.5). */
.cmp-field__input[aria-invalid='true']{border-color:var(--bad);}

.cmp-field__error{font-size:var(--t-small);line-height:var(--lh-label);color:var(--bad);}

.cmp-form__note{font-size:var(--t-small);color:var(--fg-mute);}

/* 4.95:1 on the ground */
textarea.cmp-field__input{min-height:8rem;resize:vertical;padding-top:var(--sp-4);}

.cmp-field__hint{display:block;max-width:60ch;font-size:var(--t-label);line-height:var(--lh-label);color:var(--fg-mute);}

/* LOCKED: a single centred column at every width, as the approved v1 runs it — heading and
   lead centred, the form beneath at 44rem (704px, v1's measure), contact details under the
   form. One DOM order = one visual order = one focus order: head, form, details. No `order`
   anywhere (it was sending Tab from the closing phone link, past the form, to the details
   1070px further down, then back up to Name). The v2 two-column split at 1024+ is gone. */
.cmp-enquiry{display:grid;max-width:44rem;margin-inline:auto;}

.cmp-enquiry__head{text-align:center;margin-bottom:var(--sp-5);}

/* sp-5, not sp-7: the lead runs at --lh-lead 2.0, so there is already about
   20px of leading under its last line. At 48px the optical gap to the first
   label measured nearer 80. */
.cmp-enquiry__head .cmp-lead{margin-inline:auto;}

.cmp-enquiry__meta{display:flex;flex-wrap:wrap;justify-content:center;
  gap:0 var(--sp-7);margin-top:var(--sp-7);padding-top:var(--sp-5);
  box-shadow:0 -1px 0 rgb(var(--navy-rgb) / .12);
  font-size:var(--t-small);color:var(--fg-dim);text-align:center;}

/* One 44px row rhythm for links and plain lines alike: with 44px links beside 25px text
   lines and a fixed gap, the four lines sat 72 / 60 / 50px apart. */
.cmp-enquiry__item{display:flex;align-items:center;justify-content:center;min-height:2.75rem;min-width:0;}

/* Premium §6 kept inside the locked column: the phone number set as display type. It takes
   the first row under the hairline on its own, centred; email, address and hours follow. */
.cmp-enquiry__item--tel{flex:1 1 100%;}

.cmp-enquiry__tel{font-family:var(--font-display);font-size:var(--t-sub);
  letter-spacing:var(--ls-display);line-height:var(--lh-sub);}

/* 44px touch floor (the two links measured 19px tall). The underline is a text-decoration,
   not a border: a border would sit at the bottom of the 44px box, 12px under the words. */
.cmp-enquiry__meta a{display:inline-flex;align-items:center;min-height:2.75rem;max-width:100%;
  color:var(--fg);text-decoration:underline;text-decoration-thickness:1px;
  text-decoration-color:rgb(var(--navy-rgb) / .28);text-underline-offset:.3em;overflow-wrap:anywhere;
  transition:color var(--dur-fast) var(--ease-expo),text-decoration-color var(--dur-fast) var(--ease-expo);}

.cmp-enquiry__meta a:hover{text-decoration-color:var(--accent);color:var(--accent);}

/* Hours are unconfirmed (none are published on her site). The dashed rule marks the line
   as a placeholder at a glance, so it cannot be mistaken for a fact and shipped. */
.cmp-enquiry__hours[data-placeholder]{font-style:italic;
  text-decoration:underline dashed var(--field);text-decoration-thickness:1px;text-underline-offset:.3em;}


/* ==== 63-blog.css ==== */
/* Blog — the post cards (Blog page and "More articles" under a post), their page
   numbers, and the single post (inc/blog.php, inc/content/parts/blog-posts.php).

   Ported from R.E. Horner. Its four colour values and its radius and easing were that
   site's — navy and gold, a 14px radius, a single --ease — and none of those tokens exist
   here, so every one of them was falling through to its hard-coded fallback and the blog
   would have rendered in another client's palette. They are this site's tokens now. */

:root {
	--blog-link:  var(--accent);      /* titles, links, current page */
	--blog-line:  var(--line);        /* link underlines, list markers, dots */
	--blog-hover: var(--accent-press); /* a link under the pointer */
	--blog-text:  var(--fg-dim);      /* body copy and excerpts */
	--blog-muted: var(--fg-mute);     /* dates, reading time */
}

/* The four :hover rules below used to take --blog-line. On the site this came from that
   was a gold, which read as a hover. Here the line colour is a hairline grey, so every
   link would have faded to nearly invisible under the pointer — 1.2:1. They take the
   site's own pressed-link colour instead, 8.1:1. */

/* ---- Post cards ------------------------------------------------------------ */

.ftf-post-grid .wp-block-post {
	display: flex;
	flex-direction: column;
}
.ftf-post-grid .wp-block-post-featured-image {
	margin: 0;
	overflow: hidden;
	border-radius: var(--r-md);
}
.ftf-post-grid .wp-block-post-featured-image img {
	transition: transform .9s var(--ease-expo);
}
.ftf-post-grid .wp-block-post:hover .wp-block-post-featured-image img { transform: scale(1.03); }

.ftf-post-grid .wp-block-post-date {
	margin-top: 1.15rem;
	font-size: .85rem;
	color: var(--blog-muted);
}
.ftf-post-grid .wp-block-post-title {
	margin: .45rem 0 0;
	font-size: clamp(1.2rem, 1.6vw, 1.35rem);
	line-height: 1.25;
	text-wrap: balance;
}
.ftf-post-grid .wp-block-post-title a {
	color: var(--blog-link);
	text-decoration: none;
	transition: color .3s var(--ease-expo);
}
.ftf-post-grid .wp-block-post-title a:hover { color: var(--blog-hover); }

/* Title to excerpt: a clear step, smaller than the gap between cards. */
.ftf-post-grid .wp-block-post-excerpt { margin-top: .85rem; }
.ftf-post-grid .wp-block-post-excerpt__excerpt {
	margin: 0;
	color: var(--blog-text);
	line-height: 1.6;
}
.ftf-post-grid .wp-block-post-excerpt__more-text { margin: 1rem 0 0; }
.ftf-post-grid .wp-block-post-excerpt__more-link {
	font-weight: 500;
	color: var(--blog-link);
	text-decoration: none;
	border-bottom: 1.5px solid var(--blog-line);
	padding-bottom: 2px;
	transition: color .3s var(--ease-expo);
}
.ftf-post-grid .wp-block-post-excerpt__more-link:hover { color: var(--blog-hover); }

/* Three across on desktop, two on tablets, one on phones (core stacks below 600). */
@media (min-width: 601px) and (max-width: 960px) {
	.ftf-post-grid .wp-block-post-template.is-layout-grid { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }
}

/* ---- Page numbers ----------------------------------------------------------- */

.ftf-post-grid .wp-block-query-pagination {
	margin-top: clamp(2.75rem, 5vw, 4rem);
	gap: .6rem;
	align-items: center;
	justify-content: center;
}
.ftf-post-grid .wp-block-query-pagination-numbers {
	display: flex;
	gap: .6rem;
	margin: 0;
}
.ftf-post-grid .wp-block-query-pagination .page-numbers,
.ftf-post-grid .wp-block-query-pagination-previous,
.ftf-post-grid .wp-block-query-pagination-next {
	display: inline-flex;
	align-items: center;
	justify-content: center;
	gap: .5rem;
	min-width: 2.9rem;
	height: 2.9rem;
	margin: 0;
	padding: 0 1.15rem;
	border: 1px solid rgb(8 34 70 / .18);
	border-radius: 999px;
	font-size: 1rem;
	font-weight: 500;
	line-height: 1;
	color: var(--blog-link);
	text-decoration: none;
	transition: background-color .3s var(--ease-expo), border-color .3s var(--ease-expo), color .3s var(--ease-expo);
}
.ftf-post-grid .wp-block-query-pagination .page-numbers { padding: 0; }
.ftf-post-grid .wp-block-query-pagination a:hover { border-color: var(--blog-link); }
.ftf-post-grid .wp-block-query-pagination .page-numbers.current {
	background: var(--blog-link);
	border-color: var(--blog-link);
	color: #fff;
}
.ftf-post-grid .wp-block-query-pagination .page-numbers.dots { border-color: transparent; min-width: 1.5rem; }

/* ---- Single post ------------------------------------------------------------ */

.single-post .site-main > .container--content.section {
	max-width: calc(780px + 2 * var(--gutter));
	padding: clamp(3.5rem, 7vw, 6rem) var(--gutter) clamp(3.5rem, 6vw, 5.5rem);
}

.single-post .entry { margin-bottom: 0; }
.single-post .entry__title {
	margin-bottom: 1.35rem;
	font-size: clamp(2.2rem, 4.4vw, 3.4rem);
	line-height: 1.08;
	letter-spacing: -.025em;
	text-wrap: balance;
}

/* The line under the title: back to the blog, the date, the reading time. */
.ftf-entry-meta {
	display: flex;
	flex-wrap: wrap;
	align-items: center;
	gap: .35rem 1rem;
	margin: 0 0 clamp(1.8rem, 3.5vw, 2.6rem);
	font-size: .95rem;
	color: var(--blog-muted);
}
.ftf-entry-meta > :not(:first-child)::before {
	content: "";
	display: inline-block;
	width: 4px;
	height: 4px;
	margin-right: 1rem;
	border-radius: 50%;
	background: var(--blog-line);
	vertical-align: middle;
}
.ftf-entry-meta a {
	font-weight: 500;
	color: var(--blog-link);
	text-decoration: none;
	transition: color .3s var(--ease-expo);
}
.ftf-entry-meta a::before { content: "\2190\00a0"; }
.ftf-entry-meta a:hover { color: var(--blog-hover); }
@media (max-width: 600px) {
	.ftf-entry-meta { gap: .35rem .65rem; font-size: .86rem; }
	.ftf-entry-meta > :not(:first-child)::before { margin-right: .65rem; }
}

/* The date line sits inside the thumbnail wrapper, so the rounding moves to the image. */
.single-post .entry__thumb {
	overflow: visible;
	border-radius: 0;
	margin-bottom: clamp(2.4rem, 4.5vw, 3.4rem);
}
.single-post .entry__thumb img {
	display: block;
	width: 100%;
	height: auto;
	aspect-ratio: 16 / 9;
	object-fit: cover;
	border-radius: var(--r-md);
}

/* Reading type: body size a step up, a 70ch column, clear heading steps. */
.single-post .entry__content {
	font-size: 1.1rem;
	line-height: 1.75;
	color: var(--blog-text);
}
.single-post .entry__content > * { margin-block: 0; }
.single-post .entry__content > * + * { margin-top: 1.25em; }
.single-post .entry__content > p:first-child {
	font-size: 1.22rem;
	line-height: 1.65;
	color: var(--fg);
}
.single-post .entry__content h2 {
	font-size: clamp(1.45rem, 2.4vw, 1.8rem);
	line-height: 1.25;
	letter-spacing: -.015em;
	color: var(--blog-link);
	text-wrap: balance;
}
.single-post .entry__content h3 {
	font-size: 1.2rem;
	line-height: 1.35;
	color: var(--blog-link);
}
.single-post .entry__content > h2 { margin-top: 1.9em; }
.single-post .entry__content > h3 { margin-top: 1.7em; }
.single-post .entry__content > :is(h2, h3) + * { margin-top: .6em; }
.single-post .entry__content :is(ul, ol) { padding-left: 1.3em; }
.single-post .entry__content li + li { margin-top: .5em; }
.single-post .entry__content li::marker { color: var(--blog-line); }
.single-post .entry__content a {
	color: var(--blog-link);
	text-decoration: underline;
	text-decoration-color: var(--blog-line);
	text-decoration-thickness: 1.5px;
	text-underline-offset: 3px;
}
.single-post .entry__content strong { font-weight: 600; color: var(--fg); }
.single-post .entry__content hr {
	border: 0;
	border-top: 1px solid rgb(8 34 70 / .12);
	margin-block: 2.5em;
}
.single-post .entry__content img { height: auto; border-radius: var(--r-md); }

/* ---- After the article ------------------------------------------------------ */

.ftf-more-posts {
	background: #fff;
	padding: var(--space-section) var(--gutter);
}
.ftf-more-posts__inner {
	max-width: calc(var(--container) - 2 * var(--gutter));
	margin-inline: auto;
}
.ftf-more-posts__head {
	display: flex;
	flex-wrap: wrap;
	align-items: flex-end;
	justify-content: space-between;
	gap: 1rem 2rem;
	margin-bottom: clamp(2rem, 4vw, 3rem);
}
.ftf-more-posts__head h2 { margin: 0; }
.ftf-more-posts__all {
	font-weight: 500;
	color: var(--blog-link);
	text-decoration: none;
	border-bottom: 1.5px solid var(--blog-line);
	padding-bottom: 2px;
	transition: color .3s var(--ease-expo);
}
.ftf-more-posts__all:hover { color: var(--blog-hover); }

/* Two rules from the site this file was ported from are gone, not adapted.
 *
 * It styled the closing band as a Columns block with "is-style-cta" — that site's closing
 * card. This site's is a Cover with "is-style-close", which carries its own padding, so
 * the rules matched nothing and were only waiting to catch a future block of that name.
 *
 * And it zeroed the Blog band's top padding, because on that site the page header above it
 * paid the gap. This one does not, so the first row of cards sat flush against the header
 * photograph. The band takes the section rhythm below instead; that rule had the higher
 * specificity and was silently winning.
 */

/* ---- The Blog page's band --------------------------------------------------- */

/* The ported file styled the cards but never the section that holds them, so the band
   paid nothing top or bottom: the first row of cards sat flush against the page header
   above it and the closing band below, 0px on both sides. It takes the section rhythm
   every other band on the site takes. */
.site-main .ftf-blog-band{
	padding-block:var(--space-section);
}

/* Core gives the Post Template grid a blockGap of its own, which came out at 21px — tight
   against the 24px the site's other card grids use, and tighter still between rows, where
   a card's text runs right up to the next card's photograph. The house column gutter,
   with a clear step more between rows. */
.site-main .ftf-post-grid .wp-block-post-template{
	gap:var(--sp-8) var(--sp-5);
}


/* ==== 63-legal.css ==== */
/*
 * Legal pages — ported from the prototype by tools/port-css.py.
 * Each look's own class becomes the block style WordPress prints;
 * inner BEM classes are the prototype's, kept by data-wp-class.
 *
 * GENERATED. Edits here are lost on the next port — anything written
 * against a plugin block's own markup belongs in 70- and up.
 */

/* ============================ LEGAL PAGES ===============================
   Long-form prose and nothing else — no photograph, no band. One measure the
   whole way down, numbered headings that are findable at a glance, and the
   term/definition pairs she writes as "Identifiers: Name, email…" set as a
   real <dl> rather than a run-on sentence. */
.cmp-legal__head{margin-bottom:var(--sp-8);}

.cmp-legal__body{max-width:44rem;}

.cmp-legal__h2{font-size:var(--t-sub);line-height:var(--lh-sub);
  margin:var(--sp-8) 0 var(--sp-4);}

.cmp-legal__h2:first-child{margin-top:0;}

.cmp-legal__h3{font-family:var(--font-label);font-size:var(--t-label);
  letter-spacing:var(--ls-label);text-transform:uppercase;color:var(--fg-dim);
  margin:var(--sp-6) 0 var(--sp-3);}

.cmp-legal__text{font-weight:300;font-size:var(--t-body);line-height:var(--lh-detail);
  color:var(--fg-dim);margin:0 0 var(--sp-4);text-wrap:pretty;}

.cmp-legal__meta{font-family:var(--font-label);font-size:var(--t-label);
  letter-spacing:var(--ls-label);text-transform:uppercase;color:var(--fg-mute);
  margin:0 0 var(--sp-7);}

.cmp-legal__list{margin:0 0 var(--sp-5);padding-left:var(--sp-5);display:grid;gap:var(--sp-3);}

.cmp-legal__list li{font-weight:300;font-size:var(--t-body);line-height:var(--lh-detail);
  color:var(--fg-dim);}

.cmp-legal__defs{margin:0 0 var(--sp-5);display:grid;gap:var(--sp-4);}

.cmp-legal__row :is(dt, .cmp-dt, .cmp-legal__term){font-weight:400;font-size:var(--t-body);color:var(--fg);}

.cmp-legal__row :is(dd, .cmp-dd, .cmp-legal__def){margin:var(--sp-2) 0 0;font-weight:300;font-size:var(--t-body);
  line-height:var(--lh-detail);color:var(--fg-dim);overflow-wrap:anywhere;}

/* 44px touch floor, the same one the contact details use: these two sit in a
   list as standalone links, not inside a sentence, so the inline exemption in
   WCAG 2.5.8 does not cover them. They measured 24px. */
.cmp-legal__row :is(dd, .cmp-dd, .cmp-legal__def) a{display:inline-flex;align-items:center;min-height:2.75rem;
  max-width:100%;color:var(--fg);text-decoration:underline;text-underline-offset:.2em;}

.cmp-legal__row :is(dd, .cmp-dd, .cmp-legal__def) a:hover{color:var(--accent);}

/* Anything still waiting on her. Dashed, so it reads as unfinished at a
   glance and cannot be shipped by accident. */
.cmp-legal__todo{font-style:italic;color:var(--fg-mute);
  text-decoration:underline dashed var(--field);text-decoration-thickness:1px;
  text-underline-offset:.3em;}


/* ==== 70-arenex-split.css ==== */
/*
 * The Split block's frame, mapped onto the prototype's.
 *
 * HAND-WRITTEN — not produced by the porter, which regenerates 40–63 from the
 * prototype's own CSS and would overwrite anything added there. Everything in this file
 * is about the markup the PLUGIN renders (.arenex-split__*), which has no counterpart in
 * the prototype, so there is nothing for the porter to carry across.
 */

/* The block pays its own --section-padding; on the two bands the prototype's halves pay
   --space-section inside the body instead, so the block's outer padding is off.
   NOT the page hero: its padding-block IS the design's (--space-section plus the height
   of the fixed header it sits under), and zeroing it here took 264px off every service
   page's header. */
.is-style-split-dark,
.is-style-split-tint{
	padding-block:0;
}

/* The page hero: the design puts the text half on the container's edge and lets the
   photograph run past the right edge of the page. Constraining the whole grid cut the
   photograph short by 158px, so only the text half is aligned — at 1440 that is
   (1440 - 1200) / 2 + 32 = the section's own 152px, and 32px once the viewport is
   narrower than the container. */
/* The offset belongs to the GRID, not to the text column. Put inside the column it ate
   152px of the column's own 576px, so the heading wrapped where the design does not —
   237px of type became 316px. The grid stays full width, so the photograph still runs
   past the right edge. */
.is-style-phero > .arenex-split__grid{
	padding-inline-start:max(var(--gutter), calc((100vw - var(--container)) / 2 + var(--gutter)));
}

.is-style-phero .arenex-split__body{
	padding:0;
}

/* The band itself is full width; its two halves are the block's own grid, which the
   ported rules target (the porter maps .cmp-split onto it). The root must not also be a
   grid, or the halves are laid out twice. */
.is-style-split-dark,
.is-style-split-tint{
	display:block;
	width:100vw;
	margin-inline:calc(50% - 50vw);
}

.is-style-split-dark > .arenex-split__grid,
.is-style-split-tint > .arenex-split__grid{
	width:100%;
	margin-inline:0;
}

/* The page hero's reveal, finished by hand.
 *
 * The design has two elements — .cmp-phero__figure (the frame) and .cmp-phero__mask (the
 * clipped box inside it) — and the block has one: the figure IS both. The porter maps
 * both names onto it, so the rule that ENDS the reveal
 * (.cmp-phero__figure.is-in .cmp-phero__mask) came out as a descendant of itself and
 * could never match: the figure kept opacity 0 and the photograph was invisible.
 */
.site-main .is-style-phero .arenex-split__figure.is-in{
	opacity:1;
	transform:translate3d(0, 0, 0) rotate(0deg);
}


/* ---- Contained, and the words get the room ----------------------------------
 *
 * Round 2, 3 Oct 2026, about the TAX PREPARATION bands: "dont make it full width do boxed
 * section with gaps between row and columns", then "no box simple and text heading wide
 * and so image is not larger".
 *
 * Scoped with :not(.cmp-split--tall). The first pass changed the style itself, which also
 * caught the About page's "Over 20 years in Business" band — she never asked about that
 * one and it was better full-bleed. --tall is the class that marks it, and it is the only
 * band on the site that carries it.
 *
 * So: contained rather than full-bleed, one band rather than two floating panels, and the
 * split weighted to the words. At 1138 the two halves were 552px each and the panel paid
 * 72px of padding a side, leaving 409px for a 44px serif: the Tax heading ran to four
 * lines. The text side takes 7/12 now, which is 150px more.
 */
.site-main .is-style-split-dark:not(.cmp-split--tall),
.site-main .is-style-split-tint:not(.cmp-split--tall){
	width:100%;
	max-width:var(--container);
	margin-inline:auto;
	padding-inline:var(--gutter);
	background:none;
}

/* One band, not two panels: no gap, and the halves meet as they did before. */
.site-main :is(.is-style-split-dark, .is-style-split-tint):not(.cmp-split--tall) > .arenex-split__grid{
	gap:0;
	overflow:hidden;
}

.site-main .is-style-split-dark:not(.cmp-split--tall) .arenex-split__body{
	background:var(--navy);
}

.site-main .is-style-split-tint:not(.cmp-split--tall) .arenex-split__body{
	background:var(--tint);
}

/* A full --space-section was the padding of a band that ran to the window edges. Inside
   the measure it is simply a tall box, and it was eating the width the heading needed. */
.site-main :is(.is-style-split-dark, .is-style-split-tint):not(.cmp-split--tall) .arenex-split__body{
	padding-block:var(--sp-9);
}

/* Two contained bands in a row would otherwise touch. A full-bleed one still ends on its
   own colour, so it keeps the section rhythm and takes nothing extra. */
.site-main :is(.is-style-split-dark, .is-style-split-tint):not(.cmp-split--tall) + :is(.section, .cmp-section){
	margin-top:var(--sp-8);
}


/* ==== 71-arenex-steps.css ==== */
/*
 * The Steps block's frame, mapped onto the prototype's.
 *
 * HAND-WRITTEN — see the note in 70-arenex-split.css.
 *
 * The block nests its heading area inside the text column beside the list, and sets a
 * 7/5 grid with the photograph filling the column's height. The design runs the intro
 * full width ABOVE, then her photograph and the numbered steps side by side. The text
 * column is display:contents so the head, the list and the photograph become items of
 * one grid and can be placed where the design puts them.
 */

/* The block pays its own --section-padding on top of the section's: 260px of air. */
.is-style-process{
	padding-block:0;
}

.is-style-process .arenex-steps__inner{
	display:grid;
	gap:var(--space-block);
	grid-template-areas:
		"head"
		"media"
		"list";
}

.is-style-process .arenex-steps__text{
	display:contents;
}

/* The block's head wrapper is display:contents, so it could not be placed in the grid
   and its heading and lead were flowing into the columns on their own. */
.is-style-process .arenex-steps__head{
	display:block;
	grid-area:head;
	max-width:48rem;   /* 768px: the H2 holds two lines at 52px */
}

.is-style-process .arenex-steps__list{
	grid-area:list;
}

/* The block sets its own container width; the section it sits in already carries the
   measure, and the block's was 51px narrower at 768. */
.is-style-process .arenex-steps__inner{
	width:100%;
	max-width:none;
	padding-inline:0;
	margin-inline:0;
}

.is-style-process .arenex-steps__media{
	grid-area:media;
	margin:0;
	/* The block crops the photograph to 16/10 under 1024, which took her portrait from
	   880px to 408px and the section 710px short of the design. The photograph's own
	   4/5 decides its height. */
	aspect-ratio:auto;
}

/* Stacked, the photograph sets its own height from its 4/5 crop, so it is in the flow.
   The block positions it absolutely to fill the column, which is right from 1024 up
   (93-arenex-responsive.css) but left the figure with no height at all here. */
.is-style-process .arenex-steps__img{
	position:static;
	width:100%;
	height:auto;
	aspect-ratio:4/5;
	object-fit:cover;
	border-radius:var(--r-md);
	box-shadow:var(--shadow-float);
	background:var(--line);
}

/* One step. The block pays 24px top and bottom on each row and a 12px row gap inside it;
   the design spaces the steps with the list's own 64px gap and nothing else, so a row
   measured 187px against the design's 156px — 93px over three steps. */
.is-style-process .arenex-steps__step{
	padding-block:0;
	row-gap:0;
}

/* The step's type is the prototype's, ported (60-process.css) — not restated here. */

/* The prototype pays 48px between the intro and the photograph and 64px between the
   photograph and the steps. One grid has one row-gap, so it takes the smaller and the
   list makes up the difference. */
.is-style-process .arenex-steps__list{
	margin-top:calc(var(--sp-8) - var(--space-block));
}

/* The block rules a line above every row. The design has one continuous spine down the
   numbers and nothing across — the rules read as a table the page does not have. */
.is-style-process .arenex-steps__step{
	border-top:0;
	border-bottom:0;
}

/* The block pays 48px under its heading area on top of the grid's own row gap, so the
   intro sat 48px further from the steps than the design puts it. The grid decides the
   spacing here, as it does in the prototype. */
.is-style-process .arenex-steps__head{
	margin-bottom:0;
}

/* ---- The button under the steps -------------------------------------------
 * The four service pages end their process section with "Book a consultation"
 * (.cmp-how__action in the prototype — the home page has none). It is the Steps block's
 * own `link` field; inc/block-motion.php gives that link the .cmp-btn .cmp-btn--line
 * classes, so the whole button look and its responsive sizing come from 02-buttons.css.
 * All that is left is the arrow: the block draws it inline after the words, and the
 * design parks it in the right-hand capsule.
 *
 * The link is a grid item, so it took the cell: full width at 768 and 390 (704px against
 * the design's 362) and stretched to the row's height at 1440 (86px against 66). An
 * inline-flex button shrinks to its content only when the grid stops sizing it.
 */
.site-main .arenex-steps__link{
	justify-self:start;
	align-self:start;
	/* Stacked, the design puts 88px between the last step and the button; the block's own
	   row gap gives 64. From 1024 the two share a column of a two-column grid and
	   93-arenex-responsive.css sets the spacing there instead. */
	margin-top:2.5rem;
}

.site-main .arenex-steps__link > svg{
	position:absolute;
	right:1.125rem;
	top:50%;
	translate:0 -50%;
	inline-size:1.25rem;
	block-size:1.25rem;
	stroke-width:1.75;
	transition:translate var(--dur-base) var(--ease-spring);
}

.site-main .arenex-steps__link:hover > svg{
	translate:4px -50%;
}


/* ==== 72-core-accordion.css ==== */
/*
 * The core Accordion's own markup.
 *
 * HAND-WRITTEN — see the note in 70-arenex-split.css.
 *
 * The prototype used <details>/<summary>; core renders an <h3> holding a button, so the
 * ported summary rules matched nothing and each question came out 38px tall against the
 * design's 76px. These are the same declarations, on the elements WordPress prints.
 */
.is-style-acc .wp-block-accordion-heading{
	margin:0;
}

.is-style-acc .wp-block-accordion-heading__toggle{
	display:flex;
	align-items:center;
	justify-content:space-between;
	gap:var(--sp-5);
	width:100%;
	padding:var(--sp-5) 0;
	min-height:2.75rem;
	cursor:pointer;
	background:none;
	border:0;
	text-align:left;
	font-family:var(--font-body);
	font-weight:500;
	/* A step up from the body size: the questions are the section's headings, and at
	   --t-body they sat below their own answers, which run at --t-detail.
	   Taken down from 21px to 19px on 23 Oct 2026 — with thirty-one of them the page
	   runs long, and the weight does the work the extra two points were doing: 500
	   against the answers' 300 keeps the question clearly the heading of its pair. */
	font-size:1.1875rem;
	line-height:var(--lh-body);
	color:var(--fg);
}

/* The block draws its own chevron; it takes the prototype's size and colour, and turns
   the same way when the question is open. */
.is-style-acc .wp-block-accordion-heading__icon,
.is-style-acc .wp-block-accordion-heading svg{
	flex:none;
	width:1.25rem;
	height:1.25rem;
	color:var(--blue-deep);
	transition:transform var(--dur-fast) var(--ease-expo);
}

.is-style-acc .wp-block-accordion-item.is-open .wp-block-accordion-heading svg{
	transform:rotate(180deg);
}

.is-style-acc .wp-block-accordion-panel{
	padding:0;
}

/* ---- The reveal, driven from the block ---------------------------------------
 * The items used to carry .cmp-anim themselves, which Preact wiped on every toggle
 * (inc/block-motion.php has the full account). The class now sits on the Accordion
 * root, where nothing re-renders it, and the items animate from there. The stagger is
 * nth-child rather than a per-item class, so it survives a re-render too.
 *
 * Same keyframes, same guards and the same 4s failsafe as 90-motion.css: hidden only
 * under .js, shown again if the reveal script never wires up.
 */
.js .site-main .wp-block-accordion.cmp-anim > .wp-block-accordion-item{
	opacity:0;
}

.js .site-main .wp-block-accordion.cmp-anim.is-in > .wp-block-accordion-item{
	opacity:1;
	animation:cmp-in-y var(--dur-stagger) var(--ease-spring) backwards,
	          cmp-in-o var(--dur-stagger) var(--ease-expo) backwards;
}

.js .site-main .wp-block-accordion.cmp-anim.is-in > .wp-block-accordion-item:nth-child(2){ animation-delay:70ms; }
.js .site-main .wp-block-accordion.cmp-anim.is-in > .wp-block-accordion-item:nth-child(3){ animation-delay:140ms; }
.js .site-main .wp-block-accordion.cmp-anim.is-in > .wp-block-accordion-item:nth-child(4){ animation-delay:210ms; }
.js .site-main .wp-block-accordion.cmp-anim.is-in > .wp-block-accordion-item:nth-child(5){ animation-delay:280ms; }
.js .site-main .wp-block-accordion.cmp-anim.is-in > .wp-block-accordion-item:nth-child(n+6){ animation-delay:350ms; }

.js:not(.js-ready) .site-main .wp-block-accordion.cmp-anim:not(.is-in) > .wp-block-accordion-item{
	animation:cmp-failsafe 1ms 4s forwards;
}

@media (prefers-reduced-motion:reduce){
	.js .site-main .wp-block-accordion.cmp-anim > .wp-block-accordion-item,
	.js .site-main .wp-block-accordion.cmp-anim.is-in > .wp-block-accordion-item{
		opacity:1;
		animation:none;
	}
}

/* ---- The icon: a plus that becomes a minus  (round 3, 12 Oct 2026) -----------
 * "change to + -". It was a chevron that turned; core itself prints a "+" character and
 * swaps it for a "×", which is a third thing again. Neither is what she asked for, and
 * core gives no slot for an icon of our own — so the two bars are drawn on the icon span
 * as pseudo-elements.
 *
 * Why drawn rather than a mask: a plus and a minus are the SAME horizontal bar with a
 * vertical one over it, so the open state only has to scale the vertical bar away. One
 * element animating one property, and the horizontal bar never moves — which is what
 * makes it read as one control changing rather than two icons swapping.
 *
 * The "+" character core prints goes by making the span's text transparent, not
 * display:none — the span is what core sizes and positions, and hiding it moves the row.
 */
.site-main .is-style-acc .wp-block-accordion-heading__toggle-icon{
	position:relative;
	flex:none;
	width:1.25rem;
	height:1.25rem;
	color:transparent;
	font-size:0;
	line-height:0;
}

/* the bar that stays — this alone is the minus */
.site-main .is-style-acc .wp-block-accordion-heading__toggle-icon::before,
.site-main .is-style-acc .wp-block-accordion-heading__toggle-icon::after{
	content:"";
	position:absolute;
	top:50%;
	left:50%;
	width:0.875rem;
	height:1.5px;
	margin:-0.75px 0 0 -0.4375rem;
	border-radius:1px;
	background:var(--blue-deep);
	transition:transform var(--dur-fast) var(--ease-expo);
}

/* the bar that goes — stood on end, it makes the plus */
.site-main .is-style-acc .wp-block-accordion-heading__toggle-icon::after{
	transform:rotate(90deg);
}

.site-main .is-style-acc .wp-block-accordion-item.is-open .wp-block-accordion-heading__toggle-icon::after,
.site-main .is-style-acc [aria-expanded="true"] .wp-block-accordion-heading__toggle-icon::after{
	transform:rotate(90deg) scaleX(0);
}

/* Core turns the whole icon 45 degrees when an item opens — that is how its own "+"
   becomes a "×". Ours ends as a minus, so the span must not turn: left to core's rule the
   remaining bar came out as a diagonal stroke. The vertical bar scaling away above is the
   entire change. Four classes deep so it outranks core's own is-open rule. */
.site-main .is-style-acc .wp-block-accordion-item .wp-block-accordion-heading__toggle-icon,
.site-main .is-style-acc .wp-block-accordion-item.is-open .wp-block-accordion-heading__toggle-icon,
.site-main .is-style-acc .wp-block-accordion-item [aria-expanded="true"] .wp-block-accordion-heading__toggle-icon{
	transform:none;
}

/* the old chevron turned the whole icon; nothing should rotate now */
.site-main .is-style-acc .wp-block-accordion-item.is-open .wp-block-accordion-heading svg,
.site-main .is-style-acc .wp-block-accordion-heading svg{
	transform:none;
}

/* ---- Four categories, two to a row  (round 3, 12 Oct 2026) ------------------
 * The ask was two columns so the page does not scroll so far. The first reading of it
 * split the QUESTIONS across two columns, which put three of one category on the left
 * and two on the right and read as a broken list. What she meant was the CATEGORIES:
 * Getting started beside How we work, Taxes and deadlines beside Financial management.
 * Each category keeps its own questions in one column underneath its heading, so a
 * category still reads top to bottom as a list.
 *
 * Each heading and its accordion are wrapped in .cmp-faq__col by the section file, so a
 * category is one grid cell; the grid is set at 1024 up in 92-responsive.css, where every
 * width rule on this site lives. One column below that.
 *
 * align-items:start, so a short category does not stretch to its neighbour's height and
 * opening a question moves only what is under it, inside its own column.
 */
.cmp-faq__grid{
	display:grid;
	grid-template-columns:minmax(0,1fr);
	align-items:start;
	column-gap:var(--sp-8);
	row-gap:var(--sp-7);
}

.cmp-faq__col{min-width:0;}

/* The heading used to carry the gap between one category and the next (.cmp-faq__group,
   57-acc.css). The grid's row-gap does that now, so the heading only needs its own space
   above its first question. */
/* Smaller than a section heading, 22 Oct 2026: with thirty-one questions the page runs
   long, and she wants Taxes and Deadlines in view sooner. 24px against the questions'
   20px still reads as the group's name — the serif face carries the difference where two
   points of size alone would not — and the heading plus its gap gives back 28px a row.

   Worth knowing this is the smaller half of the saving. The larger one is structural:
   Getting Started runs 796px against How We Work's 545, and a grid row is as tall as its
   tallest cell, so 251px of empty column sits under How We Work before the second row can
   start. That is not something type size can reach. */
.cmp-faq__col .cmp-faq__title{
	font-size:1.5rem;
	margin-bottom:var(--sp-4);
}

/* ---- Less air between the questions  (round 3, tightened again 22 Oct 2026) ----
 * "less space between questions", asked twice. It went 24px to 16px in round 3; her new
 * document brings the page from twenty-three questions to thirty-one, so it goes to 12px.
 *
 * That is the floor. 12px above and below plus the 1px rule leaves 25px from one
 * question's baseline to the next, which is still a clear gap at 20px type. Taking it
 * lower makes the rules read as a table rather than a list of questions, and the tap
 * target drops under the 44px the rest of the site keeps.
 */
.is-style-acc .wp-block-accordion-heading__toggle{
	padding-block:var(--sp-3);
}

.is-style-acc .wp-block-accordion-panel .cmp-acc__panel{
	padding-bottom:var(--sp-5);
}


/* ==== 73-legal-prose.css ==== */
/*
 * The legal pages' prose.
 *
 * HAND-WRITTEN — 63-legal.css is regenerated from the prototype and cannot carry this,
 * because in the prototype there is no rule to port: the paragraphs simply have no
 * max-width of their own. .cmp-legal__body IS the measure (704px), and 30-text.css's
 * default then held every line to a second, narrower one inside it — the pages came out
 * 240px long.
 */
.cmp-legal__body p,
.cmp-legal__body li,
.cmp-legal__body dd,
.cmp-legal__body dt{
	max-width:none;
}

/* The legal pages' title.
 *
 * The prototype gives .cmp-h1 no rule of its own, so in the design it rendered at the
 * browser's 2em default (34px) while WordPress's own heading styles put it at --t-hero
 * (60px) — a 26px difference that pushed every section of a 3,100px page down by 28.
 * Neither was a decision: a legal page is not a hero, so both now take the section
 * scale. The same rule is in the prototype's main.css, so the two stay in step.
 */
.site-main .cmp-h1{
	font-family:var(--font-display);
	font-weight:400;
	font-size:var(--t-section);
	line-height:var(--lh-section);
	letter-spacing:var(--ls-display);
	color:var(--fg);
	margin:0;
	text-wrap:balance;
}


/* ==== 74-overlays.css ==== */
/*
 * Overlays, and what inherits a band's colour.
 *
 * HAND-WRITTEN. Three things the port cannot carry on its own:
 *
 * 1. THE PROTOTYPE STACKS WITH NEGATIVE z-index. Its bands put the photograph at -2 and
 *    the scrim at -1, both behind the text. A Cover block does the opposite: the
 *    photograph sits at 0 and core's own dim at 1. Porting the scrim's z-index:-1 put
 *    every dim BEHIND its photograph, so the heroes, the owner band and the closing band
 *    all lost their overlay and the type sat on a bright picture.
 *
 * 2. A CARD'S SCRIM IS A BARE DIV. It carries no words, so the importer leaves it out.
 *    The card draws it as ::before instead; the gradient itself is ported (42-cards.css).
 *
 * 3. HEADINGS DO NOT INHERIT. The parent theme colours every heading, so a white-on-navy
 *    band's title came out navy-on-navy — the four service cards were unreadable.
 */

/* ---- 1 · A Cover's own stacking, restored ------------------------------- */
.site-main .wp-block-cover > .wp-block-cover__image-background{
	z-index:0;
}

/* Core's own rule for a dim ratio is FOUR classes deep
   (.wp-block-cover.has-background-dim.has-background-dim-60 .wp-block-cover__background),
   so a three-class selector loses to it — which is why the owner band came right and the
   hero stayed at 0.6. This one is five. */
/* Core's winning rule is .wp-block-cover .wp-block-cover__background.has-background-dim
   .has-background-dim-60 — four classes, all of them on the SPAN except the first. The
   dim class sits on the span, never on the cover, so a selector qualifying the cover
   simply does not match and the weaker fallback was deciding it. This mirrors core's
   shape with .site-main in front. */
.site-main .wp-block-cover:not(.is-style-hero):not(.is-style-close) .wp-block-cover__background.has-background-dim,
.site-main .wp-block-cover:not(.is-style-hero):not(.is-style-close) > .wp-block-cover__background{
	z-index:1;
	/* The design's scrim IS this element's background — the exact black, or the owner
	   band's eight-stop gradient, both measured for contrast. WordPress ALSO applies its
	   dim ratio as opacity on top, so every overlay was being multiplied down: the hero's
	   measured 0.56 rendered at 0.56 x 0.6 = 0.34 and the type sat on a bright photo.
	   The ratio still decides the class WordPress writes; the colour decides the wash.

	   Except on the hero and the closing band: there the stops are written at full
	   strength and the dim ratio is deliberately left to set the level, so the client's
	   Overlay opacity slider works. See the note at the foot of this file. */
	opacity:1;
}

/* These two keep the stacking but NOT the opacity lock, so the slider drives them. */
.site-main .is-style-hero .wp-block-cover__background,
.site-main .is-style-close .wp-block-cover__background{
	z-index:1;
}

.site-main .wp-block-cover > .wp-block-cover__inner-container{
	position:relative;
	z-index:2;
}

/* ---- 2 · The card's scrim -------------------------------------------------- */
.site-main .is-style-card::before{
	content:"";
}

/* The scrim's own z-index is the prototype's -1, which puts it behind the photograph
   here rather than behind the words: in the design the photograph is at -2, and there is
   no -2 in a WordPress card. It goes between the two instead. */
.site-main .is-style-card::before{
	z-index:1;
}

/* Its photograph sits under the scrim, its words over both. */
.site-main .is-style-card > figure{
	z-index:0;
}

.site-main .is-style-card > :not(figure){
	position:relative;
	z-index:2;
}

/* …except the title, which carries the card's link.
   42-cards.css stretches that link over the whole card with ::after{inset:0}, but an
   absolute box resolves against its nearest POSITIONED ancestor — and the rule above had
   just made the heading one. So the hit area was the 234x25 heading, not the 266x336
   card, and only the word was clickable (round 3, 12 Oct 2026: "can we make it where we
   click anywhere on the service square").
   Static here, so the ::after resolves against the card. The stacking still works: the
   card is the positioned ancestor and its z-index:2 children sit above the scrim. */
.site-main .is-style-card > .cmp-card__title{
	position:static;
}

/* ---- 3 · Headings take the band's colour ----------------------------------- */
.site-main :is(.is-style-card, .is-style-hero, .is-style-chero, .is-style-owner,
               .is-style-band, .is-style-close, .is-style-split-dark, .cmp-on-dark)
          :is(h1, h2, h3, h4, h5, h6){
	color:inherit;
}

/* And the words INSIDE a heading. The accent word of the home hero is an <em>, which the
   theme colours navy on its own — on the navy hero that left "No surprises" invisible,
   navy on navy, while the rest of the line was white.
   :not([class]) matters: an inline word that carries its own class has its own treatment
   in the design, and forcing inherit on it flattened the page hero's outlined name back
   to solid navy. Only unclassed words take the line's colour; .cmp-em is named because
   it is the one classed exception that should. */
.site-main :is(h1, h2, h3, h4, h5, h6) :is(em, strong, i, b, span, a):not([class]),
.site-main .cmp-em{
	color:inherit;
}

/* ---- 4 · An eyebrow is a <span> in the design ------------------------------
 * WordPress has no inline block for it, so it arrives as a paragraph — and then took
 * 30-text.css's reading measure, which shrank it from the full 1136px to 569px and
 * stopped `text-align: center` from centring anything in the closing band.
 */
.site-main .cmp-eyebrow{
	max-width:none;
}

/* ---- 5 · A Cover's own padding ---------------------------------------------
 * Core pads a Cover by 1em all round. The design's bands pay their padding on the inner
 * container, so core's is 17px of extra height top and bottom on every photo band — the
 * hero, the closing call to action, the owner band. The measure is the inner
 * container's job (20-widths.css).
 */
/* :where() so this weighs nothing: it clears core's default, and any band that the
   design DOES pad — the owner band pays 76px at 1440 — keeps its own rule. Written at
   full weight it out-ranked the ported rules and flattened them. */
.site-main > :where(.wp-block-cover){
	padding:0;
}

/* ---- 3 · The hero and closing scrims: dark where the words are -------------
 * Client feedback: "the stock photos on the home page are very dark."
 *
 * She is right, and a flat wash was why. Measured across all four hero slides, the
 * brightest point in the heading's band is luminance 0.961 — nearly white — so a FLAT
 * scrim cannot come below 44% without the heading dropping under 3:1, and below 54% it
 * loses the 4.5:1 safety margin. There was almost nothing to give.
 *
 * A centre-weighted wash gives it back. The words occupy the middle of the frame (the
 * heading 11–89% across and 19–34% down, the lead, buttons and facts row below it), and
 * nothing sits in the top fifth or hard against the left and right edges. So the scrim
 * holds full strength through the middle and falls away towards the top and the corners:
 * the photograph reads brighter where the eye first lands, and every line of type keeps
 * the contrast it had.
 *
 * Not a top-to-bottom gradient: the facts row sits at 83–89%, so the bottom needs the
 * scrim as much as the middle does.
 */
.site-main .is-style-hero .wp-block-cover__background,
.site-main .is-style-close .wp-block-cover__background{
	/* Navy, not black. The stops keep their shape and their strength; only the colour
	   changes, so every contrast figure below still holds — navy is luminance .012 against
	   black's 0, which moves a ratio by less than a hundredth. */
	/* Stops at FULL strength, because WordPress's own Overlay opacity scales them (see
	   the rule below). At the shipped 60% these render as .60 / .58 / .46 / .26 / .16,
	   which is what the contrast was measured on. */
	background-image:radial-gradient(
		ellipse 78% 68% at 50% 58%,
		rgb(var(--navy-rgb) / 1) 0%,
		rgb(var(--navy-rgb) / .967) 42%,
		rgb(var(--navy-rgb) / .767) 68%,
		rgb(var(--navy-rgb) / .433) 86%,
		rgb(var(--navy-rgb) / .267) 100%
	);
}

/* Hand the Overlay opacity slider back on these two.
 *
 * The rule further up forces opacity:1 on every cover overlay, because the design's
 * scrim is the element's own background and WordPress was multiplying its dim ratio on
 * top — dimming every wash twice. That is still right for the owner band, whose scrim is
 * a measured eight-stop gradient that nobody should be sliding.
 *
 * On the hero and the closing band it took away a control the client actually wants. So
 * here the stops are full strength and the dim ratio is the only thing setting the
 * level: moving the slider now does exactly what it says, and the shipped 60% is the
 * value every contrast figure was measured at.
 *
 * The floor is worth knowing before anyone drags it: on the brightest of the four hero
 * slides the heading holds 3:1 down to about 40%, and loses its 4.5:1 margin below 50%.
 */


/* ==== 75-hero-slides.css ==== */
/*
 * The rotating home hero.
 *
 * HAND-WRITTEN. She asked for "still shots or video footage from 10 to 15 industries
 * that I service… rotate on the home page", with pwc.com as the reference. The frames are
 * a Gallery inside the Cover, so she adds an industry by adding a picture in the editor —
 * no custom block, and the Cover's own dim still sits over them.
 *
 * Stacking: the Cover's dim is at 1 (74-overlays.css), so the frames sit at 0 and the
 * words at 2. The Cover's inner container must NOT carry a z-index of its own, or the
 * gallery inside it cannot go behind the dim — a child cannot escape its parent's
 * stacking context.
 */

.site-main .is-style-hero > .wp-block-cover__inner-container{
	z-index:auto;
}

.site-main .wp-block-gallery.is-style-hero-slides{
	position:absolute;
	inset:0;
	z-index:0;
	margin:0;
	gap:0;
	overflow:hidden;
	/* Ten to fifteen stacked frames cross-fading: nothing in here can affect layout or
	   paint outside it. */
	contain:strict;
}

/* Every frame fills the hero and waits its turn. */
.site-main .wp-block-gallery.is-style-hero-slides figure.wp-block-image{
	position:absolute;
	inset:0;
	margin:0;
	width:100%;
	height:100%;
	opacity:0;
	transition:opacity 1.6s var(--ease-expo);
}

.site-main .wp-block-gallery.is-style-hero-slides figure.wp-block-image.is-live{
	opacity:1;
}

/* Before the script runs, the first frame is the one showing — so the hero is never
   blank, with or without JavaScript. */
.site-main .wp-block-gallery.is-style-hero-slides figure.wp-block-image:first-child{
	opacity:1;
}

/* A phone is served a portrait frame of the same scene, which means the <img> is wrapped
   in a <picture> (inc/hero-portrait.php). display:contents takes that wrapper out of the
   layout entirely, so the img stays a child of the absolutely positioned figure and its
   width:100%/height:100% still resolve against the hero rather than against the wrapper —
   without it the frame collapses to the picture's own intrinsic height. */
.site-main .wp-block-gallery.is-style-hero-slides figure.wp-block-image picture{
	display:contents;
}

.site-main .wp-block-gallery.is-style-hero-slides figure.wp-block-image img{
	width:100%;
	height:100%;
	object-fit:cover;
}

/* The words sit above the dim. */
.site-main .is-style-hero > .wp-block-cover__inner-container > .cmp-hero__inner{
	position:relative;
	z-index:2;
}

/* The caption carries the industry name for the label and the dots; it is not shown
   under the picture. */
.site-main .wp-block-gallery.is-style-hero-slides figcaption{
	position:absolute;
	width:1px;
	height:1px;
	margin:-1px;
	padding:0;
	overflow:hidden;
	clip-path:inset(50%);
	white-space:nowrap;
	border:0;
}

/* Room for the player.
 *
 * The design gives the hero extra bottom padding only when there is more than one frame
 * — .cmp-hero:has(.cmp-hero__slide + .cmp-hero__slide) — so a single-frame hero is not
 * left with a gap. WordPress's frames are gallery images, so that test never matched:
 * the hero came out 52px short and the player sat on the facts row. Same condition, on
 * the markup the Gallery renders. */
.site-main .is-style-hero:has(.is-style-hero-slides .wp-block-image + .wp-block-image) .cmp-hero__inner{
	padding-bottom:calc(var(--sp-6) + 2.75rem + var(--sp-5));
}

/* ---- The same band of frames on a compact header.  22 Oct 2026 ----------------
 * "Get rid of the picture on the testimonial page and put smaller versions of the 6
 * testimonial pictures" — so the Testimonials header runs her six client photographs
 * instead of one still. Same gallery, same script, nothing new to maintain.
 *
 * Only the stacking differs. The page hero puts its frames at 0 and its dim at 1; a
 * compact header isolates itself and runs its background at -2 and its dim at -1
 * (41-chero.css), so the frames have to sit at -2 to end up behind the scrim rather
 * than over the headline.
 */
/* The frames are absolute, so they fill their nearest POSITIONED ancestor. In a compact
   header that was the inner container, which is only as tall as the headline — the band
   measured 540px and the photographs 160px of it, sitting in a strip across the middle.
   Taking the inner container out of the positioning makes the header itself the
   containing block, which is what the page hero gets for free because its own inner
   container is full height. :has() so the four headers that still use a single still
   photograph are untouched. */
.site-main .is-style-chero:has(.is-style-hero-slides) > .wp-block-cover__inner-container{
	position:static;
	z-index:auto;
}

/* Taking the inner container out of the positioning also takes away the stacking context
   core gives it (position:relative, z-index:1), and the scrim sits at 1 — so the headline
   fell underneath it and read as a ghost. The words get the stacking context back on
   their own wrapper, where it costs the frames nothing. */
.site-main .is-style-chero:has(.is-style-hero-slides) .cmp-chero__inner{
	position:relative;
	z-index:2;
}

.site-main .is-style-chero .wp-block-gallery.is-style-hero-slides{
	z-index:-2;
}

/* ---- Where the crop falls on the Testimonials band.  23 Oct 2026 --------------
 * Her six client photographs are 3:2 and 2:1; the band is 1342 x 540, about 2.5:1.
 * object-fit:cover therefore drops 354px from the 3:2 frames — only 60% of their
 * height survives — and a centred crop takes half of that off the TOP, which is
 * precisely where the faces are. The first slide lost the woman's head.
 *
 * These are standing portraits: the heads sit near the top of the 3:2 frame, so the
 * window has to go most of the way up. At 30% two of the six still lost the top of a
 * head; at 15% only 53px comes off the top and every face is clear. The balance comes
 * off the floor, which carries nothing in any of the six.
 *
 * Not 0%: a frame pinned to the very top leaves no air above the heads and the group
 * reads as pressed against the edge.
 */
.site-main .is-style-chero .wp-block-gallery.is-style-hero-slides img{
	object-position:50% 15%;
}


/* ==== 76-fluentform.css ==== */
/*
 * The contact form, as Fluent Forms prints it.
 *
 * HAND-WRITTEN — see the note in 70-arenex-split.css.
 *
 * The prototype's form is hand-written markup (.cmp-field, .cmp-field__input,
 * .cmp-btn--fill) and 62-contact.css styles those classes. On the page the form is a
 * Fluent Forms block, which prints .ff-el-group / .ff-el-form-control / .ff-btn-submit
 * instead, so not one of those declarations matched and the form arrived in the plugin's
 * default grey. This is 62-contact.css again, on the elements the plugin prints.
 *
 * Scoped under .cmp-form (the wrapper keeps the prototype's class through data-wp-class)
 * so it can only ever reach this form, and every rule is a class deeper than the
 * plugin's own so it wins without !important.
 */

/* Three classes, not two: the plugin's own rules are .ff-default .ff-el-form-control,
   and being two classes like ours they were winning on order alone — its 11px padding and
   17px line-height survived, so every field came out 2px short of the design's. */

/* The sprite's #i-arrow, as a mask. The sprite itself cannot be reached from a
   pseudo-element, and the shape has to match the arrow on every other button exactly.
   The SVG is written with SINGLE quotes: double ones close the CSS string the url() is
   in, the whole declaration is dropped, mask-image computes to `none`, and the
   pseudo-element paints its background as a plain square. */
.site-main .cmp-form{
	--icon-arrow:url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'><path d='M3 10h14m0 0-5.5-5.5M17 10l-5.5 5.5' fill='none' stroke='black' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'/></svg>");
}

/* The plugin's own container margins: the section owns the rhythm. */
.site-main .cmp-form .frm-fluent-form,
.site-main .cmp-form fieldset{
	margin:0;
	padding:0;
	border:0;
}

/* One column by default; e-mail and telephone pair up at 600 (92-responsive.css), the
   same width the prototype's .cmp-form__row pairs at. */
.site-main .cmp-form fieldset{
	display:grid;
	grid-template-columns:minmax(0,1fr);
	gap:var(--sp-5);
	align-items:start;
}

/* Fluent Forms puts three hidden inputs at the top of the fieldset. As grid items they
   each took a row and a 24px gap — 72px of nothing above the first label. */
.site-main .cmp-form fieldset > input[type="hidden"]{
	display:none;
}

/* start: an error line under one field must not stretch its neighbour's input */
.site-main .cmp-form .ff-el-group{
	display:grid;
	gap:var(--sp-2);
	min-width:0;
	margin:0;
}

/* The plugin carries a clearfix: .ff-el-group::before and ::after. In a grid they are
   two more grid items — two zero-height rows, each still paying the 8px gap, so every
   field stood 16px taller than the design's. */
.site-main .cmp-form .ff-el-group::before,
.site-main .cmp-form .ff-el-group::after{
	content:none;
}

/* The label itself is inline, so the line box is the WRAPPER's: left at the body's 17px
   it stood 28px tall against the design's 25. Sized here, not only on the label. */
.site-main .cmp-form .ff-el-input--label{
	margin:0;
	font-size:var(--t-small);
	line-height:var(--lh-body);
}

.site-main .cmp-form .ff-el-input--label label{
	display:inline;
	font-family:var(--font-label);
	font-weight:600;
	font-size:var(--t-small);
	letter-spacing:.02em;
	line-height:var(--lh-body);
	color:var(--fg);
	margin:0;
	padding:0;
}

/* The plugin draws the required mark in its own red. The design marks it in the accent,
   and it is decoration for anyone reading — the label already carries aria-required. */
.site-main .cmp-form .ff-el-is-required.asterisk-right label::after{
	color:var(--accent);
	font-weight:600;
}

.site-main .cmp-form .ff-el-form-control{
	width:100%;
	font:inherit;
	font-size:var(--t-body);
	color:var(--fg);
	background:var(--surface);
	border:1.5px solid var(--field);
	border-radius:var(--r-md);
	min-height:3.25rem;
	padding:.75rem var(--sp-5);
	line-height:var(--lh-body);
	box-shadow:none;
	transition:border-color var(--dur-fast) var(--ease-expo);
}

.site-main .cmp-form .ff-el-form-control::placeholder{
	color:var(--fg-mute);
}

.site-main .cmp-form .ff-el-form-control:hover{
	border-color:var(--fg-dim);
}

/* A real ring: the page ring (--ring-focus, 5.66:1 on the white field) at 3px, not the
   plugin's 1px colour change. */
.site-main .cmp-form .ff-el-form-control:focus,
.site-main .cmp-form .ff-el-form-control:focus-visible{
	border-color:var(--accent);
	outline:3px solid var(--ring-focus);
	outline-offset:2px;
	box-shadow:none;
}

/* After :focus so a focused invalid field keeps its red border. */
.site-main .cmp-form .ff-el-form-control[aria-invalid="true"],
.site-main .cmp-form .ff-el-group.ff-el-is-error .ff-el-form-control{
	border-color:var(--bad);
}

/* The prototype's textarea is six rows (198px); the form gives it four, and a plugin
   field has no rows setting in its own editor. Six rows of --t-body at --lh-body, plus
   the padding and the border. */
.site-main .cmp-form textarea.ff-el-form-control{
	min-height:calc(6 * var(--t-body) * var(--lh-body) + 1.5rem + 3px);
	resize:vertical;
	padding-top:var(--sp-4);
}

.site-main .cmp-form .text-danger,
.site-main .cmp-form .error.text-danger{
	font-size:var(--t-small);
	line-height:var(--lh-label);
	color:var(--bad);
	margin:0;
}

/* ---- The submit button ---------------------------------------------------
 * .cmp-btn--fill, on the <button> the plugin prints. The prototype's arrow is a <span>
 * holding an SVG; the plugin gives us no slot for one, so it is drawn here as a masked
 * pseudo-element — a mask rather than a background image, so it takes currentColor and
 * turns white against the navy exactly as the real icon does.
 */
.site-main .cmp-form .ff_submit_btn_wrapper{
	margin:0;
	display:block;
}

.site-main .cmp-form .ff-btn-submit{
	position:relative;
	display:inline-flex;
	align-items:center;
	justify-content:center;
	gap:var(--sp-4);
	max-width:100%;
	min-width:0;
	min-height:4rem;
	padding:1.125rem 3rem 1.125rem 1.75rem;
	border-radius:var(--r-btn);
	font-family:var(--font-label);
	font-weight:700;
	font-size:var(--t-btn);
	letter-spacing:var(--ls-btn);
	line-height:1.2;
	text-transform:uppercase;
	text-decoration:none;
	cursor:pointer;
	background:var(--navy);
	border:2px solid var(--navy);
	color:var(--fg-on-dark);
	box-shadow:none;
	transition:transform var(--dur-fast) var(--ease-spring),
	           background-color var(--dur-fast) var(--ease-expo),
	           border-color var(--dur-fast) var(--ease-expo),
	           color var(--dur-fast) var(--ease-expo);
}

.site-main .cmp-form .ff-btn-submit::after{
	content:"";
	position:absolute;
	right:1.125rem;
	top:50%;
	translate:0 -50%;
	inline-size:1.25rem;
	block-size:1.25rem;
	background:currentColor;
	-webkit-mask:var(--icon-arrow) center / contain no-repeat;
	        mask:var(--icon-arrow) center / contain no-repeat;
	transition:translate var(--dur-base) var(--ease-spring);
}

.site-main .cmp-form .ff-btn-submit:hover{
	background:var(--accent);
	border-color:var(--accent);
	color:var(--on-accent);
}

.site-main .cmp-form .ff-btn-submit:hover::after{
	translate:4px -50%;
}

.site-main .cmp-form .ff-btn-submit:active{
	transform:scale(.985);
}

.site-main .cmp-form .ff-btn-submit:focus-visible{
	outline:3px solid var(--ring-focus);
	outline-offset:3px;
}

/* The plugin's success and failure messages, in the page's voice rather than its own. */
.site-main .cmp-form .ff-message-success{
	padding:var(--sp-5) var(--sp-6);
	border:1.5px solid var(--field);
	border-radius:var(--r-md);
	background:var(--surface);
	color:var(--fg);
	font-size:var(--t-body);
}

.site-main .cmp-form .ff-errors-in-stack .error{
	color:var(--bad);
	font-size:var(--t-small);
}

/* ---- The fields arrive one after another  (12 Oct 2026) ---------------------
 *
 * Every other block on the site reveals as it comes up the screen; the contact form
 * was the one thing that was simply there. Each field group now arrives like a card,
 * stepped 110ms apart (20-reveal.js adds .cmp-anim to the five .ff-el-group elements
 * — four fields and the submit — so the keyframes, the stagger, the reduced-motion
 * rules and the failsafe below are the site's own, not a second set).
 *
 * The hidden state has to be written in CSS, not added with the class: adding both at
 * once means the fields paint, disappear and come back. So the group starts at 0 here,
 * and .cmp-anim.is-in (90-motion.css) brings it in.
 *
 * :not(.is-in) matters: four classes deep, this rule out-ranks .js .cmp-anim.is-in
 * (three), so without it the fields were handed .is-in and stayed invisible. Written as
 * an exclusion it simply stops matching the moment the class lands, and the site's own
 * reveal takes over. */
.js .site-main .cmp-form .ff-el-group:not(.is-in){opacity:0;}

/* FAILSAFE, as 90-motion.css does it for .cmp-anim: if main.js never wires the
   observers, `js-ready` is never set and the fields are shown 4s after first paint.
   A form nobody can see is worse than one that does not animate. */
.js:not(.js-ready) .site-main .cmp-form .ff-el-group{animation:cmp-failsafe 1ms 4s forwards;}


/* ==== 77-heads.css ==== */
/*
 * Two section heads that are wider than the rest.
 *
 * HAND-WRITTEN — see the note in 70-arenex-split.css.
 *
 * The prototype keys these to the section's id:
 *     #what-we-do .cmp-head{max-width:50rem;}   #what-we-do .cmp-lead{max-width:70ch;}
 *     #team       .cmp-head{max-width:58rem;}   #team       .cmp-lead{max-width:80ch;}
 * The importer carried neither the id nor data-wp-name onto the block, so all four
 * matched nothing: the services and resources intros came out 704px against the design's
 * 800 and ran a line longer, and the team's the same. inc/block-anchors.php puts the
 * prototype's ids back (which also repairs the main menu's "Services" link), so these
 * are the design's own rules, unchanged.
 *
 * The one addition is .site-main, which is needed to out-rank core's constrained layout —
 * it caps every child of a constrained group at the content width. Core's own rule puts
 * everything after the layout class inside :where(), so one class is enough.
 */
.site-main #what-we-do .cmp-head{
	max-width:50rem;
}

.site-main #what-we-do .cmp-lead{
	max-width:70ch;
}

.site-main #team .cmp-head{
	max-width:58rem;
}

.site-main #team .cmp-lead{
	max-width:80ch;
}


/* ==== 78-person.css ==== */
/*
 * The team: the card grid, and one person's page.
 *
 * HAND-WRITTEN — see the note in 70-arenex-split.css.
 *
 * Her brief, from the David French site: the grid shows a photograph, the job title and
 * the name, and clicking through opens that person's page. The site's earlier team look
 * was a different thing — each person's photograph BESIDE their biography, stacked down
 * the page — so these are new classes rather than a reuse of that one. The old look is
 * untouched and still styles anything that carries it.
 *
 * Base is one column; the grid widens in 92-responsive.css, where every width query
 * lives.
 */

/* ---- 1 · The grid of people ------------------------------------------------ */
/* Gutters are the house card grid's (is-style-cards: 24px between columns), not a set of
   their own. Two four-across grids on the same site with different gutters read as a
   mistake, and at 48/64px the gap was a quarter of the card's own width — the row looked
   like four separate things rather than one team. A step more between rows than columns,
   so the two-up tablet layout still breaks into rows. */
.cmp-team{
	list-style:none;
	margin:0;
	padding:0;
	display:grid;
	gap:var(--sp-6) var(--sp-5);
}

.cmp-team__item{
	min-width:0;
}

/* The whole card is the link: a reader aiming for a small arrow on a phone misses it,
   and a screen reader gets one target with the person's name on it rather than three.
   The card is a filled panel, so it reads as something to press without an icon saying
   so — white on the page's #F6F8FA ground, with a hairline to hold its edge. */
.cmp-team__link{
	display:block;
	overflow:hidden;                 /* the photograph takes the card's corners */
	background:var(--surface);
	border-radius:var(--r-md);
	box-shadow:0 0 0 1px var(--line), var(--shadow-float);
	text-decoration:none;
	color:inherit;
	transition:transform var(--dur-base) var(--ease-spring),
	           box-shadow var(--dur-base) var(--ease-expo);
}

.cmp-team__link:hover,
.cmp-team__link:focus-visible{
	transform:translateY(-4px);
	box-shadow:0 0 0 1px var(--line), var(--shadow-lift, 0 12px 28px rgb(var(--navy-rgb) / .14));
}

.cmp-team__photo{
	display:block;
	width:100%;
	aspect-ratio:4 / 5;
	object-fit:cover;
	background:var(--line);
}

/* The words sit on the card's own ground, not the page's. */
.cmp-team__text{
	display:block;
	padding:var(--sp-5) var(--sp-5) var(--sp-6);
}

/* Title above the name, as the card she liked has it. */
.cmp-team__role{
	display:block;
	font-family:var(--font-label);
	font-weight:600;
	font-size:var(--t-label);
	line-height:var(--lh-label);
	letter-spacing:var(--ls-label);
	text-transform:uppercase;
	color:var(--accent);
	margin:0 0 var(--sp-3);
}

.cmp-team__name{
	display:block;
	font-family:var(--font-display);
	font-weight:400;
	font-size:var(--t-card);
	line-height:var(--lh-sub);
	letter-spacing:var(--ls-display);
	color:var(--fg);
	margin:0;
}

/* ---- 2 · One person's page ------------------------------------------------- */
.cmp-person__inner{
	display:grid;
	gap:var(--sp-8);
	align-items:start;
}

.cmp-person__figure{
	margin:0;
	min-width:0;
	/* Stacked, the portrait would otherwise run the full width — 640x800 on a tablet,
	   a whole screen of one face before a word of the biography. Capped until the two
	   columns take over at 1024. */
	max-width:22rem;
}

.cmp-person__photo{
	display:block;
	width:100%;
	aspect-ratio:4 / 5;
	object-fit:cover;
	border-radius:var(--r-md);
	background:var(--line);
	box-shadow:var(--shadow-float);
}

.cmp-person__body{
	min-width:0;
}

.cmp-person__role{
	margin-bottom:var(--sp-3);
}

.cmp-person__name{
	margin:0 0 var(--sp-6);
}

/* The reading measure the rest of the site uses for prose. */
.cmp-person__bio{
	max-width:62ch;
}

.cmp-person__bio p{
	font-size:var(--t-detail);
	line-height:var(--lh-detail);
	color:var(--fg-dim);
	margin:0 0 var(--sp-5);
}

.cmp-person__bio p:last-child{
	margin-bottom:0;
}

.cmp-person__back{
	margin:var(--sp-7) 0 0;
}

/* The band of everyone else. Its heading needs no bottom margin of its own — the
   section's grid already spaces it. */
.cmp-person__more .cmp-head{
	margin-bottom:var(--sp-8);
}

/* A tinted band is exempt from the section-rhythm collapse (35-sections.css) because its
   padding is air inside a coloured box, not a gap between sections. True — but the plain
   section above it still pays its own, so the biography sat 241px above "The rest of the
   team", twice the scale's gap. The band's own padding is the gap; this section owes only
   enough that the portrait — the taller of the two columns — does not touch the colour's
   edge. Guarded: with nobody else on the team the band is not rendered and this section is
   the last thing before the footer, where it needs its full padding back. */
.cmp-person:has(+ .cmp-person__more){
	/* .55 of a section — the ratio the design already uses wherever a full gap is too
	   much (35-sections.css). A flat 48px read as the portrait resting on the colour;
	   the full section padding on both sides read as 241px of nothing. */
	padding-bottom:calc(var(--space-section) * .55);
}


/* ==== 79-hidden.css ==== */
/*
 * Hiding a section without deleting it.
 *
 * A client asks for a section taken off the page and then wants it back a week later.
 * Deleting the block loses its words and its photograph; keeping two copies of the page
 * means every later fix has to be made twice. So: Advanced -> Additional CSS class ->
 * "cmp-off" on the section, and it leaves the front end. Clearing the field brings it
 * back exactly as it was.
 *
 * Not a block style: those are a single choice per block, so "Hidden" would replace the
 * look the section already carries (block-styles/core.php) and lose it on the way back.
 *
 * In the editor the section stays visible — faded, with a label — or she would have no
 * way to find it again and no way to switch it back on.
 */

/* Front end: gone, and gone from the accessibility tree with it. */
.site-main .cmp-off{
	display:none !important;
}

/* The editor keeps it on the canvas. .is-root-container is the editor's .site-main
   (EDITOR-PARITY), so this only ever applies inside the editor. */
.is-root-container .cmp-off{
	display:revert !important;
	opacity:.4;
	filter:grayscale(1);
	outline:2px dashed var(--line);
	outline-offset:4px;
	position:relative;
}

.is-root-container .cmp-off::after{
	content:"Hidden on the live site — clear the 'cmp-off' class under Advanced to show it again";
	position:absolute;
	inset-block-start:0;
	inset-inline-start:0;
	z-index:2;
	padding:var(--sp-2) var(--sp-4);
	background:var(--navy, #16222E);
	color:#fff;
	font-family:var(--font-label);
	font-size:.75rem;
	letter-spacing:var(--ls-label);
	text-transform:uppercase;
	pointer-events:none;
}


/* ==== 80-svc-solo.css ==== */
/* ==========================================================================
   Service band — ONE photograph, not a pair.  Round 3, 12 Oct 2026.
   --------------------------------------------------------------------------
   Her note on all three detail pages was the same: "just 1 main image proper
   size". The paired look (anchor + floating second photo, 43-svc.css) is still
   right on the Services page, where three blocks alternate down the page and the
   pair carries the rhythm — so that markup is untouched. The three detail pages
   now run a single photograph in the band's left column.

   Accounting keeps the laptop on the meeting table; Financial Management keeps
   the twelve-month forecast (her "don't like the middle picture" removed the
   whiteboard, and the forecast is the one that matches Accounting's laptop);
   Bookkeeping keeps the shelf of box files.
   ========================================================================== */

/* The two columns sit centred on each other, and the picture is held a little
   smaller than the column would allow.

   First pass ran it at the full 30rem — 600px of photograph against about 400px of
   copy — so the band's row was 600 tall, the text started at the top and left 200px
   of empty navy under it. Centring both columns fixes the gap; capping the width at
   28rem takes the row down to 560 so the two sides are closer in weight.

   Cropping it shorter with aspect-ratio was the other way to do that, and it is the
   wrong one here: these are 4:5 photographs composed to the edge — the box files run
   to the top of the bookkeeping frame and its new wooden floor to the bottom — so a
   centre crop takes the two things the picture is there for. Natural ratio, smaller
   box. */
.site-main .cmp-svc__solo{align-self:center;}

.site-main .cmp-svc__solo ~ .cmp-band__body{align-self:center;}

.cmp-svc__single{width:100%;max-width:28rem;margin-inline:auto;}

/* Radius and shadow on the IMG, not the figure: the figure does not clip, so a
   radius there leaves the photograph's own square corners sitting over it. */
.cmp-svc__single img{width:100%;border-radius:var(--r-md);
  box-shadow:var(--shadow-soft);background:var(--line);}


/* ==== 81-section-rhythm.css ==== */
/* ==========================================================================
   Where one full-bleed band meets the next.  12 Oct 2026.
   --------------------------------------------------------------------------
   On Tax Preparation the tinted split band runs straight into the navy closing
   CTA: no ground between them, so the page ends in one unbroken slab and the
   last list item reads as part of the CTA. Every other pair of bands on that
   page has 64px of ground between them (the split band carries it above
   itself), so the CTA is simply missing its share.

   Written as an adjacency rather than a margin on the band, so it applies only
   where a split actually meets the CTA — the service pages put a cover band in
   between and are untouched.
   ========================================================================== */
.site-main :is(.is-style-split-tint, .is-style-split-dark) + .is-style-close{
	margin-top:var(--sp-8);
}


/* ==== 82-contact-options.css ==== */
/* ==========================================================================
   Contact page — three alternatives for her to choose between.  13 Oct 2026.
   --------------------------------------------------------------------------
   Her note was "don't like this page at all" with nothing to go on, so rather
   than guess once these are three real pages she can open and compare. Same
   words, same photographs, same type as the rest of the site; only the
   arrangement changes.

   They live on their own preview pages (contact-option-1/2/3) and touch nothing
   the current contact page uses. Once she picks one, its markup moves into
   inc/content/sections/contact/ and the other two and this file go.

   Width rules are the exception to the house rule that every @media lives in
   92-responsive.css: these are throwaway, and keeping each option whole makes
   it far easier to delete the two she does not want.
   ========================================================================== */

/* ---------- shared by all three ---------- */
.cmp-opt__eyebrow{font-family:var(--font-label);font-weight:700;font-size:var(--t-label);
  letter-spacing:var(--ls-label);text-transform:uppercase;color:var(--accent-on-dark);
  margin:0 0 var(--sp-4);}
.cmp-opt__title{font-family:var(--font-display);font-size:clamp(2.25rem,4.4vw,3.25rem);
  line-height:var(--lh-display);letter-spacing:var(--ls-display-lg);color:var(--fg-on-dark);
  margin:0 0 var(--sp-4);}
.cmp-opt__lead{font-size:var(--t-detail);line-height:var(--lh-detail);
  color:var(--fg-dim-on-dark);margin:0;max-width:52ch;}

.cmp-opt__k{font-family:var(--font-label);font-weight:600;font-size:var(--t-micro);
  letter-spacing:var(--ls-label);text-transform:uppercase;color:var(--fg-mute-on-dark);
  margin:0 0 var(--sp-1);}
.cmp-opt__v{font-size:var(--t-body);line-height:1.5;color:var(--fg-on-dark);margin:0;}
.cmp-opt__v a{color:var(--fg-on-dark);text-decoration:none;}
.cmp-opt__v a:hover{text-decoration:underline;}

/* ---------- 1 · form and details side by side ---------- */
/* The header floats over the first section, so the eyebrow has to start below it or
   it is cut in half. --header-h is the bar's own height. */
.cmp-o1__strip{background:var(--navy);
  padding-block:calc(var(--header-h) + var(--sp-7)) var(--sp-9);}
.cmp-o1__body{background:var(--ground);}
.cmp-o1__row{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--sp-7);align-items:start;}
.cmp-o1__card{background:var(--surface);border-radius:var(--r-md);box-shadow:var(--shadow-soft);
  padding:var(--sp-7) var(--sp-6);}
.cmp-o1__card .cmp-h3{font-family:var(--font-display);font-size:var(--t-sub-lg);
  letter-spacing:var(--ls-display-lg);margin:0 0 var(--sp-2);}
.cmp-o1__note{font-size:var(--t-small);color:var(--fg-dim);margin:0 0 var(--sp-6);}
.cmp-o1__aside{background:var(--navy);border-radius:var(--r-md);box-shadow:var(--shadow-soft);
  padding:var(--sp-7) var(--sp-6);}
.cmp-o1__aside .cmp-opt__k{color:var(--fg-label-on-blue);font-size:var(--t-label);
  margin-bottom:var(--sp-5);}
.cmp-o1__item{margin:0 0 var(--sp-5);}
.cmp-o1__rule{height:1px;background:rgb(255 255 255 / .14);margin:var(--sp-6) 0;}
.cmp-o1__step{display:grid;grid-template-columns:1.75rem minmax(0,1fr);gap:var(--sp-3);
  align-items:start;margin:0 0 var(--sp-4);counter-increment:o1;}
.cmp-o1__steps{counter-reset:o1;}
.cmp-o1__step::before{content:counter(o1);width:1.75rem;height:1.75rem;border-radius:var(--r-pill);
  display:grid;place-items:center;background:rgb(255 255 255 / .10);color:var(--accent-on-dark);
  font-family:var(--font-label);font-weight:700;font-size:var(--t-micro);}
.cmp-o1__step span{font-size:var(--t-small);line-height:1.55;color:var(--fg-dim-on-dark);}
@media (min-width:900px){
  .cmp-o1__row{grid-template-columns:minmax(0,1.35fr) minmax(0,1fr);gap:var(--sp-8);}
}

/* ---------- 2 · form on the photograph ---------- */
/* Its own padding, not the section's: the card is the tallest thing in the band and a
   full section's worth underneath left a dead strip of navy above the footer. */
.cmp-o2{position:relative;background:var(--navy);overflow:hidden;
  padding-block:calc(var(--header-h) + var(--sp-7)) var(--sp-9);}
.cmp-o2::before{content:"";position:absolute;inset:0;opacity:.22;
  background-image:var(--o2-photo);background-size:cover;background-position:center;}
.cmp-o2::after{content:"";position:absolute;inset:0;
  background:linear-gradient(100deg, rgb(var(--navy-rgb) / .92) 38%, rgb(var(--navy-rgb) / .55) 100%);}
.cmp-o2 > .wp-block-group__inner-container{position:relative;z-index:1;}
.cmp-o2__row{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--sp-8);align-items:center;}
.cmp-o2__line{padding-block:var(--sp-5);box-shadow:0 -1px 0 rgb(255 255 255 / .14);margin:0;}
.cmp-o2__line:first-of-type{box-shadow:none;}
.cmp-o2__card{background:var(--surface);border-radius:var(--r-md);box-shadow:var(--shadow-float);
  padding:var(--sp-7) var(--sp-6);}
.cmp-o2__card .cmp-h3{font-family:var(--font-display);font-size:var(--t-sub);
  letter-spacing:var(--ls-display-lg);margin:0 0 var(--sp-2);}
@media (min-width:1024px){
  .cmp-o2__row{grid-template-columns:minmax(0,1fr) minmax(0,30rem);gap:var(--sp-9);}
}

/* ---------- 3 · three cards, then the form ---------- */
.cmp-o3__strip{background:var(--navy);
  padding-block:calc(var(--header-h) + var(--sp-7)) var(--sp-10);text-align:center;}
.cmp-o3__strip .cmp-opt__lead{margin-inline:auto;}
.cmp-o3__tiles{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--sp-5);
  margin-top:calc(var(--sp-9) * -1);position:relative;z-index:2;}
.cmp-o3__tile{background:var(--surface);border-radius:var(--r-md);box-shadow:var(--shadow-soft);
  padding:var(--sp-6) var(--sp-5);}
.cmp-o3__tile .cmp-opt__k{color:var(--fg-mute);}
.cmp-o3__tile .cmp-opt__v{color:var(--fg);}
.cmp-o3__tile .cmp-opt__v a{color:var(--fg);}
.cmp-o3__form{max-width:46rem;margin-inline:auto;}
.cmp-o3__form .cmp-h3{font-family:var(--font-display);font-size:var(--t-sub-lg);
  letter-spacing:var(--ls-display-lg);margin:0 0 var(--sp-3);text-align:center;}
.cmp-o3__note{font-size:var(--t-body);color:var(--fg-dim);margin:0 0 var(--sp-7);text-align:center;}
.cmp-o3__assure{background:var(--tint);padding-block:var(--sp-6);}
.cmp-o3__assure p{margin:0;text-align:center;font-family:var(--font-label);font-weight:600;
  font-size:var(--t-label);letter-spacing:var(--ls-label-tight);text-transform:uppercase;
  color:var(--fg-dim);}
@media (min-width:900px){
  .cmp-o3__tiles{grid-template-columns:repeat(3,minmax(0,1fr));}
}


/* ==== 90-motion.css ==== */
/*
 * Motion — ported from the prototype's main.css ("Motion"), verbatim, including the
 * reduced-motion branch. The reveal is driven by assets/js/motion.js, which adds
 * .is-in; without JavaScript every .cmp-anim is visible (the .no-js rules below).
 */

/* ==========================================================================
   Motion
   ========================================================================== */

/* 5h — the signature moment. CSS, not an observer: the first screen never
   waits on JavaScript. With JS off the page is simply there. */
@media (prefers-reduced-motion:no-preference){
  .cmp-hero__line > span{display:block;
    animation:cmp-rise var(--dur-hero) var(--ease-spring) both;}
  /* nth-child, not an inline --i: WordPress kses strips custom properties from style attributes */
  .cmp-hero__line:nth-child(2) > span{animation-delay:80ms;}
  .cmp-hero__media{animation:cmp-settle var(--dur-hero) var(--ease-expo) both;}
  /* Whole sequence lands inside 1100ms (it ran 1820): line 2 ends at 1080, facts at 1100. */
  .cmp-hero__lead,.cmp-hero__actions,.cmp-hero__rule,.cmp-trust{
    animation:cmp-fade var(--dur-hero-fade) var(--ease-expo) both;animation-delay:240ms;}
  .cmp-hero__actions{animation-delay:320ms;}
  .cmp-hero__rule{animation-delay:400ms;}
  .cmp-trust{animation-delay:460ms;}

  /* Mobile menu — links cascade in behind the panel: 140ms head start, 45ms steps.
     Explicit nth-child rules, no custom property. Last link lands at 365 + 480 = 845ms.
     Switched off from 1024 up in responsive.css, where the nav is a plain row. */
  .cmp-nav.is-open .cmp-nav__list > li{animation:cmp-fade var(--dur-menu) var(--ease-expo) both;}
  .cmp-nav.is-open .cmp-nav__list > li:nth-child(1){animation-delay:140ms;}
  .cmp-nav.is-open .cmp-nav__list > li:nth-child(2){animation-delay:185ms;}
  .cmp-nav.is-open .cmp-nav__list > li:nth-child(3){animation-delay:230ms;}
  .cmp-nav.is-open .cmp-nav__list > li:nth-child(4){animation-delay:275ms;}
  .cmp-nav.is-open .cmp-nav__list > li:nth-child(5){animation-delay:320ms;}
  .cmp-nav.is-open .cmp-nav__list > li:nth-child(6){animation-delay:365ms;}
}
@keyframes cmp-rise{from{transform:translateY(105%);}}
@keyframes cmp-settle{from{transform:scale(1.04);opacity:.001;}}
@keyframes cmp-fade{from{opacity:0;transform:translateY(14px);}}

/* 5i — below the fold. Transform and opacity only, no blur. The hidden state
   exists only under .js, so with scripts OFF nothing is ever hidden. With scripts on but
   main.js missing (404, blocked, or thrown before the observers are wired) the failsafe
   under this block takes over, so a failed script never leaves a blank section.
   A keyframe, not a transition: a transition on .cmp-anim out-ranked the cards' and
   panels' own hover transition (the lift ran 900ms and the shadow snapped). Two
   animations so the two-easings rule holds — spring moves, expo fades. Fill is
   `backwards` only: the hidden frame covers the stagger delay, and once it ends
   nothing is left filling, so :hover transforms are the element's own again. */
.js .cmp-anim{opacity:0;}
.js .cmp-anim.is-in{opacity:1;
  animation:cmp-in-y var(--dur-reveal) var(--ease-spring) backwards,
            cmp-in-o var(--dur-reveal) var(--ease-expo) backwards;}
@keyframes cmp-in-y{from{transform:translateY(28px);}}
@keyframes cmp-in-o{from{opacity:0;}}

/* FAILSAFE — needs no script. `.js` comes from the inline snippet in <head>; `.js-ready`
   is set by main.js the moment its reveal observers are wired. If that never happens,
   4s after first paint everything the script would have revealed is shown: the 26
   .cmp-anim blocks, the 4 float photographs, the process line and the phone call bar
   (measured with main.js blocked: 26 + 4 at opacity:0, the line at scaleX(0) and the bar
   parked, for good; with the failsafe all of them are in at 4.6s). When
   main.js does run — normally well inside the 4s — the selector stops matching, the
   pending animation is dropped and nothing here ever plays, so the scroll reveals are
   untouched (a plain timed reveal would replay the C05 bug: every block already shown
   before anyone scrolls to it). Not a motion effect: 1ms, so it sits outside the
   reduced-motion blocks and covers the call bar there too. */
.js:not(.js-ready) .cmp-anim:not(.is-in),
.js:not(.js-ready) .cmp-svc__float,
.js:not(.js-ready) .cmp-phero__body,
.js:not(.js-ready) .cmp-phero__figure,
.js:not(.js-ready) .cmp-phero__mask,
.js:not(.js-ready) .cmp-phero__mask img,
.js:not(.js-ready) .cmp-steps::before,
.js:not(.js-ready) .cmp-callbar{animation:cmp-failsafe 1ms 4s forwards;}
@keyframes cmp-failsafe{to{opacity:1;transform:none;visibility:visible;}}

/* Stagger — siblings in a row arrive one after another, and the step has to be big
   enough to SEE. nth-child, never an inline --i (kses strips it).
   Each staggered row also runs the shorter --dur-stagger, because a 150ms step against
   a 900ms reveal is 17% of the animation: the four cards overlapped so heavily they
   read as a single slab arriving. Every row below finishes inside the 1100ms cap. */
.js .cmp-cards .cmp-card.is-in,
.js .cmp-offer__item.is-in,
.js .cmp-serve__item.is-in,
.js .cmp-step.is-in,
.js .cmp-faq__item.is-in,
.js .cmp-footer__grid > .cmp-anim.is-in,
.js .cmp-team__item.is-in{animation-duration:var(--dur-stagger);}

/* four service cards — 450 + 620 = 1070ms */
.js .cmp-cards .cmp-card:nth-child(2).is-in{animation-delay:150ms;}
.js .cmp-cards .cmp-card:nth-child(3).is-in{animation-delay:300ms;}
.js .cmp-cards .cmp-card:nth-child(4).is-in{animation-delay:450ms;}
/* three industry panels */
.js .cmp-serve__item:nth-child(2).is-in{animation-delay:150ms;}
.js .cmp-serve__item:nth-child(3).is-in{animation-delay:300ms;}
/* three process steps, following the spine as it draws */
.js .cmp-step:nth-child(2).is-in{animation-delay:150ms;}
.js .cmp-step:nth-child(3).is-in{animation-delay:300ms;}
/* four questions */
.js .cmp-faq__item:nth-child(2).is-in{animation-delay:120ms;}
.js .cmp-faq__item:nth-child(3).is-in{animation-delay:240ms;}
.js .cmp-faq__item:nth-child(4).is-in{animation-delay:360ms;}
/* four team cards — the same step the service cards use, so the two rows read as one
   system. The team was never staggered: four portraits arriving together landed as a
   slab where every other row on the site comes in one at a time. */
.js .cmp-team__item:nth-child(2).is-in{animation-delay:150ms;}
.js .cmp-team__item:nth-child(3).is-in{animation-delay:300ms;}
.js .cmp-team__item:nth-child(4).is-in{animation-delay:450ms;}
/* the footer's four columns, left to right */
.js .cmp-footer__grid > .cmp-anim:nth-child(2).is-in{animation-delay:130ms;}
.js .cmp-footer__grid > .cmp-anim:nth-child(3).is-in{animation-delay:260ms;}
.js .cmp-footer__grid > .cmp-anim:nth-child(4).is-in{animation-delay:390ms;}

@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto;}
  *,*::before,*::after{animation-duration:.01ms !important;transition-duration:.01ms !important;}
  .js .cmp-anim,.js .cmp-svc__float{opacity:1 !important;
    transform:none !important;animation:none !important;}
  .cmp-steps::before{transform:none !important;}
}


/* ==== 92-responsive.css ==== */
/*
 * Responsive — the prototype's responsive.css, ported whole by
 * tools/port-css.py. EVERY width @media on this site lives here, as it does in
 * the prototype. GENERATED: plugin-frame breakpoints go in 93-.
 */

/* ==========================================================================
   First Things First Accounting — responsive
   This file contains @media blocks ONLY. House rule.
   Type steps are measured — see 01-brief/TYPE-SYSTEM.md.
   hero:body 375 40/17 = 2.35:1 · 1280 60/17 = 3.53:1 · 1600 64/17 = 3.76:1
   (Premium 6:1 floor waived — see CONTEXT.md departures)
   ========================================================================== */
@media (min-width:600px){

  /* The hero lead goes back to 24px here: the reason for that size is the contrast
     rule (40-hero.css), and from 600 the column is wide enough to carry it. */
.cmp-hero__lead{font-size:1.5rem;line-height:var(--lh-lead);}

  /* From 600 the number moves out of the flow and sits beside the title. */
.site-main .is-style-offer-item{grid-template-columns:2.75rem minmax(0,1fr);}
.site-main .is-style-offer-item::before{grid-column:1;grid-row:1;}
.site-main .is-style-offer-head{grid-column:2;}
.cmp-offer__text{grid-column:2;}
.site-main .is-style-also{grid-template-columns:1fr 1fr;gap:var(--sp-7) var(--sp-8);}
.site-main .is-style-res{grid-template-columns:1fr 1fr;}
.cmp-team{grid-template-columns:1fr 1fr;}

  /* Photograph beside the bio from 600; it holds a fixed column so all four
     pictures line up down the page whatever length the bio runs to. */
.site-main .is-style-team-item{grid-template-columns:11rem minmax(0,1fr);gap:var(--sp-5) var(--sp-6);align-items:start;}
.site-main .is-style-team-photo{grid-row:1 / span 4;}
:root{--gutter:1.5rem;}
.site-main .is-style-cards{grid-template-columns:repeat(2,1fr);}
.site-main .is-style-serve{grid-template-columns:repeat(2,1fr);}
.cmp-form__row{grid-template-columns:1fr 1fr;}

  /* The same pair on the Fluent Forms markup. The plugin gives every field its own
     .ff-el-group in one flat list, so the pair is made by placing those two groups in
     the fieldset's own grid rather than by a wrapper.
     .site-main is not decoration here: 76-fluentform.css sets the one-column default at
     `.site-main .cmp-form fieldset`, and written a class weaker these never applied at
     any width. The fieldset kept its single column, `grid-column:1 / -1` resolved to
     that one column, and only the telephone's `grid-column:2` created a second — an
     implicit, content-sized one. That is the 453px/227px pair in the screenshot. */
.site-main .cmp-form fieldset{grid-template-columns:repeat(2,minmax(0,1fr));}
.site-main .cmp-form .ff-el-group{grid-column:1 / -1;}
.site-main .cmp-form .ff-el-group:has(input[type="email"]){grid-column:1;}
.site-main .cmp-form .ff-el-group:has(input[type="tel"]){grid-column:2;}
.site-main .is-style-trust{gap:var(--sp-5) var(--sp-6);}
.cmp-trust__fact :is(dt, .cmp-dt, .cmp-legal__term){font-size:var(--t-label);letter-spacing:var(--ls-label);}
}
@media (min-width:768px){

  /* The service list: name on the left, sentence on the right, as her sample sets it.
     18rem holds the longest name she sent ("Establish & Monitor Key Performance
     Indicators") on two lines without stealing the sentence's measure. */
.site-main .is-style-svclist > .wp-block-group__inner-container > .wp-block-group > .wp-block-group__inner-container{display:grid;grid-template-columns:18rem minmax(0,1fr);gap:var(--sp-6);align-items:baseline;}
.cmp-svclist__name{margin-bottom:0;}


  /* The reference's outlined second line. @supports because without text-stroke a
     transparent fill leaves an invisible heading.
     :not(:only-child) because the outline only means anything against a solid line above
     it. She took "Small Business" off the four service headings (round 2, 3 Oct 2026),
     which left the em as the whole heading — a page title entirely in outline, which is
     hard to read and not what the reference does. Alone it is solid; paired, outlined. */
@supports (-webkit-text-stroke:1px currentColor){
.cmp-phero__title > .cmp-phero__em:not(:only-child){color:transparent;-webkit-text-stroke:1.5px var(--navy);}
}
:root{
    --fs-01:3.25rem;    /* 52 — measured: 'Clean books. Clear numbers.' needs 685px
                          of the 689px column at 56px, so 52 keeps it on one line
                          with room. Was 42, only 2px over the phone size. */
    --fs-02:2.625rem;   /* 42 */
    --fs-02b:1.875rem;  /* 30 */
    --fs-03:1.5625rem;  /* 25 */
    --fs-04:1.1875rem;  /* 19 */
    --fs-05:1.125rem;   /* 18 — body copy never stepped up: 17px at 375 and 17px
                           again in a 689px tablet column. */
    --gutter:2rem;
  }

  /* 768-1023: the pair was capped at 32rem, sitting in a 689px column with 177px
     of dead space to its right. It fills the column now. Filling it at the old
     proportions would make it 823px tall — which is what the cap was avoiding —
     so the anchor and float step down for this band and the box is squarer:
     689 wide gives 723 tall, against 612 before. */
  /* The cards are 2-up and ~332px wide here, against 236px in the 4-up desktop
     row, so the title has room the desktop size was never sized for. */
  /* The page-hero title is clamp(2.75rem, 5.4vw, 4.75rem). 5.4vw only reaches
     41px at 768, so it sat on the 44px floor — the phone size — until about
     815px wide. The floor is raised for this band: 52px at 768, growing to the
     55px the clamp already gives at 1023, so the step stays monotonic.
     Measured ceilings before wrap at 768: 72px for most, 69 for "Financial
     Management", 68 for "Dominique DelHomme". */
  /* Measures set for the half-columns these blocks occupy from 1024. Stacked at
     tablet they are full width, and 46ch of a 689px column reads as a fault
     rather than a measure. Widened to the top of the comfortable range, not
     removed — the cap is still doing its job. Audited across all ten pages at
     768: these four were the only text blocks materially short of their column
     that were not simply sitting in a grid cell. */
  /* The three steps: the title was at the 19px card size and the text at the
     15px small size — both set for the narrow desktop column beside her
     photograph, not for a 689px tablet row. */
.site-main .arenex-steps__title{font-size:var(--t-sub);}
.site-main .arenex-steps__desc{font-size:var(--t-body);}
.cmp-band__text{max-width:62ch;}
.cmp-lead{max-width:66ch;}
.cmp-chero__title{max-width:24ch;}
  /* 26ch is a measure for a heading in a full-bleed band, where the column was wider than
     the words needed. Boxed and weighted 7/12 (70-arenex-split.css), the column is 535px
     of usable width and 26ch capped the heading at 362px — it wrapped over four lines with
     173px of the column unused beside it. The column is the measure now. */
.cmp-split__title{max-width:none;}
.cmp-phero__title{font-size:clamp(3.25rem, 5.4vw, 4.75rem);}
.site-main .is-style-pair{max-width:none;aspect-ratio:1 / 1.05;}
.cmp-svc__anchor{width:78%;}
.cmp-svc__float{width:54%;}

  /* The paragraph and its list were running 76 characters a line in that column.
     The column stays full width; the prose does not. */
.cmp-svc__text,
.cmp-svc__list{max-width:58ch;}
.site-main .arenex-steps__list{gap:var(--sp-8);}
  /* the steps run DOWN the page now, beside her photograph — not a three-column row */
.cmp-trust__fact :is(dt, .cmp-dt, .cmp-legal__term){min-height:0;}
  /* every label is one line from 768 (213px thirds, longest label 190) */
  /* The air belongs ABOVE the hairline, not between the hairline and the facts:
     the rule reads as the lid on the group, so it should sit away from the phone
     link and close to what it introduces. 112 over, 40 under — was 64 over and
     120 under. Phones keep the base 64/48: this much is a far bigger share of a
     phone-height hero. */
.cmp-hero__rule{margin-top:calc(var(--sp-8) + 3rem);}
.site-main .is-style-trust{margin-top:2.5rem;}
:root{--t-btn:1.125rem;}
              /* 18px — the reference's button size */
.cmp-btn{padding:1.25rem 3.5rem 1.25rem 3.375rem;}
  /* the reference's 20px 56px 20px 54px */
.cmp-btn--sm{padding:.75rem 1.5rem;}
.cmp-footer__grid{grid-template-columns:repeat(2,1fr);}

  /* Owner band, tablet: the wide frame takes over from the phone's 4:5 crop (the <source>
     switches at the same 768). The column is still too narrow to put type beside her, so
     the stacked treatment holds — she keeps the top of the frame, the type keeps the foot.
     72% pulls the crop right so she is not cut at the shoulder. Measured on the rendered
     768x880: H2 7.56:1, lead 6.10:1, quote 10.58:1, credit 10.51:1, button 9.67:1. */
.site-main .is-style-owner{min-height:55rem;}
.site-main .is-style-owner .wp-block-cover__image-background{object-position:72% 50%;}
}
@media (min-width:1024px){

  /* The four FAQ categories, two to a row (round 3, 12 Oct 2026) — the categories, not
     the questions: each keeps its own list in one column. Set here rather than at 900,
     because the questions run at 20px from 1024 up and a narrower half column wraps most
     of them to three lines. */
.cmp-faq__grid{grid-template-columns:1fr 1fr;}

  /* Four people across, as the card row she liked runs. */
.cmp-team{grid-template-columns:repeat(4,1fr);}

  /* The photograph beside the biography. A fixed column, not a fraction: with 1fr the
     portrait grew with the viewport and a short bio left a tall gap beside it. */
.cmp-person__inner{grid-template-columns:26rem minmax(0,1fr);gap:var(--sp-9);}
.cmp-person__figure{max-width:none;}

:root{
    --fs-01:3rem;       /* 48 — above the 44px H2 */
    --fs-02:2.75rem;    /* 44 */
    --fs-02b:2.125rem;  /* 34 */
    --fs-03:1.6875rem;  /* 27 */
    --fs-04:1.25rem;    /* 20 */
    /* The tablet step sizes cascade up here too; desktop keeps what was approved. */
    --fs-05:1.0625rem;  /* 17 — back to the approved desktop body size. The 18px
                           step belongs to the 768-1023 band, where the columns
                           are wide and the type was still at the phone size. */
  }

  /* Header clearance grows with text size. At the default 16px this is exactly 96px
     (12.75 x 16 - 108 = 96); at 200% text the wrapped nav makes the bar ~340px and this
     gives 300, so the H1 never sits under it. */
.cmp-hero__inner{padding-top:calc(max(var(--header-h) + 2 * var(--header-drop), 12.75rem - 108px) + var(--sp-7) + 2.25rem);}
  /* +36px: the title was sitting close under the bar */
.site-main .is-style-trust{gap:var(--sp-5) var(--sp-8);}
.cmp-trust__fact :is(dd, .cmp-dd, .cmp-legal__def){font-size:var(--t-sub);}
.site-main .is-style-cards{grid-template-columns:repeat(4,1fr);}

  /* One 64px stagger: three equal 4:5 cards on one baseline read as the template row.
     The middle panel drops a step; the panels themselves are untouched. 32px gutters.
     The step is the `translate` property, not margin-top, and the row stretches: with
     align-items:start the two outer cards — the matched pair — ended 23px apart at 1280
     (645 vs 668: 'Online & service-based business' wraps to two lines, 'Logistics, shipping
     & trucking' holds one). Stretched, all three share one height and cards 1 and 3 share
     a bottom edge. `translate` is its own property, so the hover lift and the reveal (both
     `transform`) compose with it instead of overwriting it. It moves no layout, so the 64px
     the step needs is paid back as padding under the row. */
.site-main .is-style-serve{grid-template-columns:repeat(3,1fr);align-items:stretch;gap:var(--sp-6);
    padding-bottom:var(--sp-8);}
.cmp-serve__item:nth-child(2){translate:0 var(--sp-8);}

  /* Her photograph was a fixed 4:5 and taller than the three steps, which left a hole
     under step 3. Spreading the steps into that height (align-content:space-between) fixed
     the hole but pulled them so far apart they stopped reading as one sequence. So the
     PHOTOGRAPH follows the steps instead: the row stretches, the figure takes the column's
     full height and the picture covers it. The steps keep their own natural rhythm, the
     spine runs the full height, and there is no gap at either end. */
.cmp-how{grid-template-columns:.9fr 1.1fr;gap:var(--sp-9);align-items:stretch;}
.cmp-how__figure{height:100%;}
.cmp-how__figure img{height:100%;aspect-ratio:auto;object-fit:cover;}
.site-main .is-style-svc,
.site-main .is-style-svc-flip{grid-template-columns:1fr 1fr;gap:var(--sp-9);}
.site-main .is-style-svc-flip .is-style-pair{order:2;}
  /* stacked order stays image-then-text on phones */
  /* Owner band, desktop: the type moves off the foot and onto the LEFT of the frame —
     her own site's hero composition, with her face kept clear on the right.
     Scanned in 4% bands, the bright window behind the sofa peaks at L=0.771 between 44%
     and 60% of the frame, and her face sits at 64-79%. The 18px/300 lead needs .72 over
     that window, so the wash holds .76 across the type column and only then falls away —
     see the gradient below for how that falloff is shaped.
     The column is capped at 52% as well as 38rem: a bare rem becomes 76rem at 200% text
     and the column ran out to 95% of the frame, over her, where the lead measured 3.79:1.
     A percentage cannot grow with the text. */
.site-main .is-style-owner{min-height:clamp(34rem,46vw,44rem);align-content:center;}
.site-main .is-style-owner .wp-block-cover__image-background{object-position:50% 14%;}
  /* past 1.75:1 the frame crops vertically; 14% keeps her head in at 1920 */
  /* NEUTRAL BLACK AND SOFTER, matching the hero. Navy laid a blue cast over a photograph
     that is already cool, and black measures better at every alpha, so the peak could come
     down as well: the lead reads 5.83:1 at .76 where navy gave 5.19:1 at .82.
     NO EDGE. It used to fall from .82 to .32 across twelve per cent of
     the frame, which the eye reads as a cut rather than a gradient. The peak comes down
     from .84 to .76 — measured, the 18px/300 lead needs .72 over the window behind the
     sofa and gets 5.83:1 at .76 — and the falloff is spread over eight stops and forty-six
     per cent of the width instead of two stops and twelve. */
.site-main .is-style-owner .wp-block-cover__background{background:linear-gradient(90deg,
    rgb(var(--navy-rgb) / .76)   0%,
    rgb(var(--navy-rgb) / .76)  52%,
    rgb(var(--navy-rgb) / .68)  56%,
    rgb(var(--navy-rgb) / .56)  60%,
    rgb(var(--navy-rgb) / .42)  64%,
    rgb(var(--navy-rgb) / .28)  68%,
    rgb(var(--navy-rgb) / .16)  72%,
    rgb(var(--navy-rgb) / .08)  76%,
    rgb(var(--navy-rgb) / .03)  82%,
    rgb(var(--navy-rgb) / 0)    88%,
    rgb(var(--navy-rgb) / 0)   100%);}
.cmp-owner__body{max-width:min(38rem,52%);}
.site-main .is-style-pair{max-width:none;}
  /* the grid column is the constraint from here up */
.site-main .is-style-faq{grid-template-columns:1fr 1fr;}

  /* How it works: H2 left, lead right, on the reviews' 1.15 / .85 columns with the same
     80px gap — so the lead starts on the side-quote column's edge one section up. Stacked,
     the header filled the left 45% of the row (H2 ended at x=560 of 1280) over a full-width
     three-step row, and read as a two-column header with one column missing. Not centred:
     close and enquiry, directly below, are both centred stacks. `last baseline` sets the
     lead's last line on the H2's last baseline; `end` is the fallback (Safari < 16). */
.cmp-process__intro{max-width:none;display:grid;grid-template-columns:1fr 1fr;
    gap:var(--sp-9);align-items:end;align-items:last baseline;}
.cmp-process__intro > *{min-width:0;}
.cmp-process__intro .cmp-lead{margin-top:0;}

  /* Enquiry: no rules here. It is one centred 44rem column at every width (LOCKED; the
     1024+ two-column split was withdrawn in verification round 1 — see main.css). */
.cmp-reviews{grid-template-columns:1.15fr .85fr;gap:var(--sp-9);align-items:start;}

  /* Every column is exactly as wide as what it holds, and the room left over is shared
     out equally BETWEEN them (space-between), so the eye reads one gap repeated three
     times. They were fr grid tracks, and the brand and contact columns stretched well past
     their text: at 1265 that left ~165px after the brand blurb but ~50px between the link
     columns. Content width also means nothing wraps: 'Financial Management' (171px) and
     'info@firstthingsfirstaccounting.com' (272px) each keep one line.
     Flex, not a max-content grid, because a grid cannot wrap: at 1024 the four columns
     leave 4px spare, and any growth (enlarged text, a fallback font) would push the
     contact column out of the footer, which clips. A flex row drops it to a new line
     instead. The column gap is only the floor (32 here, 64 from 1280); the gap you
     actually see is the shared space: 49px at 1024, 113 at 1265. */
.cmp-footer__grid{display:flex;flex-wrap:wrap;justify-content:space-between;
    gap:var(--sp-8) var(--sp-6);}


  /* Service pages. The hero splits like the reference's, and the note blocks
     put the photograph opposite the text, alternating down the page. The figure
     keeps the pair's own proportions, so nothing here touches .cmp-svc. */
  /* The photograph takes the right half of the screen and runs off its edge, as the
     reference's does. It is out of flow, so the type column keeps the wrap's grid and
     the section's height is set by the type, not by a 4:5 frame. */
  /* The reference's hero exactly: the photograph runs from about a third of the way
     across to the right edge and the full height of the band, and the title crosses
     onto it. That is why this page's frame is sky-led — the type stays navy where it
     crosses, and the sky behind it measures far above the 4.5 it needs. */
.site-main .is-style-phero{position:relative;overflow:hidden;}
.site-main .is-style-phero .arenex-split__grid{grid-template-columns:minmax(0,1fr);align-items:center;min-height:34rem;}
.site-main .arenex-steps__title{font-size:var(--t-card);}
.site-main .arenex-steps__desc{font-size:var(--t-small);}
.site-main .is-style-phero .arenex-split__body{position:relative;z-index:1;max-width:36rem;}
.cmp-phero__lead{max-width:34rem;}
  /* the measure for the 36rem column */
.site-main .is-style-phero .arenex-split__figure{position:absolute;inset:0 0 0 auto;width:66vw;}
.site-main .is-style-phero .arenex-split__figure img{width:100%;height:100%;aspect-ratio:auto;object-position:30% 50%;
    border-radius:0;box-shadow:none;}

  /* A person, not a scene: the hero's height follows the copy beside it, so the
     slot can be anywhere from wide to nearly square and `cover` takes the
     difference off the top and bottom. Anchoring high means it comes off the
     floor, never off her head. */
.cmp-phero__figure--person img{object-position:50% 12%;}

  /* The title sits over the left edge of the picture. With the pale sky shots that
     edge was nearly the page colour and the outlined word read straight off it; the
     four scene photographs are not pale, so the section carries the same weighted
     scrim the dark bands use — full ground under the type, gone by the time it
     reaches the subject. It is painted on the section, not the figure, so the
     reveal animation slides the photograph up behind a scrim that does not move. */
.site-main .is-style-phero::after{content:"";position:absolute;inset:0;z-index:0;pointer-events:none;
    background:linear-gradient(90deg,
      rgb(246 248 250 / 1) 0%,
      rgb(246 248 250 / 1) 34%,
      rgb(246 248 250 / .86) 45%,
      rgb(246 248 250 / .42) 55%,
      rgb(246 248 250 / 0) 64%);}

  /* The band: pictures on the left, the copy on the right, as the reference runs it. */
  /* The service page's steps column ends with a button: it belongs under the steps, in the
     second column, and the photograph spans both rows so it still runs the full height of
     the column beside it. `span 2` rather than `1 / -1`, because the button's row is
     implicit and -1 only counts the explicit grid. Scoped with :has so the home page,
     which has no button, is untouched. */
  /* Two services to a line. One to a line left a third of every row empty and
     ran the nine-item list past 2000px; two halves the height and gives the
     paragraph a 54ch measure, which is inside the reading range. The number
     keeps its own rail so the block still has a spine to hang off. */
.site-main .is-style-offer{grid-template-columns:1fr 1fr;}
.site-main .is-style-offer-item{grid-template-columns:2.5rem minmax(0,1fr);
    padding:var(--sp-7);gap:var(--sp-4) var(--sp-5);}
.site-main .is-style-offer-head{grid-column:2;grid-row:1;}
.cmp-offer__text{grid-column:2;grid-row:2;max-width:56ch;}

  /* Hairlines: between the rows, and one down the middle. */
.site-main .is-style-offer-item + .is-style-offer-item{border-top:0;}
.site-main .is-style-offer-item:nth-child(n+3){border-top:1px solid var(--line);}
.site-main .is-style-offer-item:nth-child(even){border-left:1px solid var(--line);}

  /* An odd count leaves the last one alone beside an empty half, with a hairline
     running down the side of nothing. It takes the full width instead, and goes
     back to the title-beside-paragraph split so it reads as a row, not a
     stretched half. Bookkeeping's nine end this way. */
.site-main .is-style-offer .is-style-offer-item:last-child:nth-child(odd){
    grid-column:1 / -1;border-left:0;
    grid-template-columns:2.5rem minmax(0,20rem) minmax(0,1fr);}
.site-main .is-style-offer .is-style-offer-item:last-child:nth-child(odd)
    .cmp-offer__text{grid-column:3;grid-row:1;}
.cmp-how:has(.cmp-how__action) .cmp-how__figure{grid-row:1 / span 2;}
.cmp-how__action{grid-column:2;}


  /* The split becomes two halves, the photograph filling its half edge to edge
     and the panel padded to the page column so its type lines up with the
     sections above and below. --flip puts the picture on the other side. */
  /* Ten cards: three across, or the list runs five rows deep. */
.site-main .is-style-res{grid-template-columns:repeat(3,1fr);}
.site-main .is-style-team-item{grid-template-columns:18rem minmax(0,1fr);gap:var(--sp-5) var(--sp-8);}

  /* Short enough to balance from here: every line evened, so no last line is
     left with one or two words. Below this width the same paragraphs run to
     nine lines, past the point Chrome will balance, and keep `pretty`.
     --story is the one paragraph that is long at every width. */
.cmp-lead:not(.cmp-lead--story),
.cmp-hero__lead,
.cmp-offer__lead,
.cmp-offer__text,
.cmp-split__lead,
.cmp-split__text,
.cmp-band__text,
.cmp-team__text,
.cmp-also__text,
.cmp-svc__text,
.cmp-serve__text,
.cmp-owner__lead,
.site-main .arenex-steps__desc,
.cmp-acc__panel{text-wrap:balance;}
  /* Weighted to the words, not split down the middle: contained, a half-and-half band
     left the heading 409px at a laptop width and it wrapped over four lines. 7/12 gives
     it 150px more, and the photograph is still the larger thing on the page at 5/12. */
.site-main .is-style-split-dark > .arenex-split__grid,
.site-main .is-style-split-tint > .arenex-split__grid{grid-template-columns:7fr 5fr;align-items:stretch;min-height:34rem;}
  /* The mirrored band puts the photograph in column 1, so the weighting has to mirror too
     or the picture takes the 7 and the words the 5 — which is what happened: the body came
     out 473px and the heading wrapped over four lines again.
     The flip marker is on the GRID (arenex-split__grid--image-first), not on an ancestor.
     The .cmp-split--flip rules below are the prototype's ancestor class, which the block
     does not print; they have never matched anything here. */
.site-main .is-style-split-dark > .arenex-split__grid--image-first,
.site-main .is-style-split-tint > .arenex-split__grid--image-first{grid-template-columns:5fr 7fr;}
.site-main .is-style-split-dark .arenex-split__body,
.site-main .is-style-split-tint .arenex-split__body{padding-inline:clamp(var(--sp-7), 3.6vw, 4rem);}
.cmp-split__lead,
.cmp-split__text,
.cmp-split__list{max-width:34rem;}
  /* the half column's measure */
.site-main .is-style-split-dark .arenex-split__figure img,
.site-main .is-style-split-tint .arenex-split__figure img{height:100%;aspect-ratio:auto;}
.site-main .cmp-split--flip .is-style-split-dark .arenex-split__figure,
.site-main .cmp-split--flip .is-style-split-tint .arenex-split__figure{grid-column:1;grid-row:1;}
.site-main .cmp-split--flip .is-style-split-dark .arenex-split__body,
.site-main .cmp-split--flip .is-style-split-tint .arenex-split__body{grid-column:2;grid-row:1;}
.site-main .is-style-band-inner{grid-template-columns:1fr 1fr;gap:var(--sp-9);align-items:center;}

  /* Light over the pictures, heavy under the type. Navy rather than black, like every
     other scrim on the site (52-band.css): the stops and their strengths are the measured
     ones, only the hue changed, and navy is luminance .012 against black's 0. */
  /* The band's photograph is gone (52-band.css) and its backdrop is a flat gradient, so
     there is nothing left to weight a scrim against. Kept as a no-op rather than deleted:
     put the photograph back by removing the rules at the foot of 52-band.css, and this is
     the weighting it needs again. */
.site-main .is-style-band .wp-block-cover__background{background:none;}
}

/* ---- The desktop header row -------------------------------------------------
 *
 * The horizontal nav starts at 1200, not 1024.
 *
 * It used to start at 1024, which fitted while the row was five links and the button:
 * 846px of row against 710px of room at 1024 — already wrapping, and the comment below
 * records the logo sub-line and the CTA label wrapping there. Adding FAQ (revision 3)
 * made it six links, and the row no longer fits anywhere under 1200: at 1100 it is 60px
 * over, at 1024 it is 136px over, and the button dropped to a second line that took the
 * whole bar to 112px.
 *
 * Below 1200 the burger and its panel take over, which is the base state, so nothing in
 * here has to be undone — the rules simply do not apply. The container stops growing at
 * 1200, so the room above it is a constant 886px and this holds at every larger width.
 * -------------------------------------------------------------------------- */
@media (min-width:1200px){

.cmp-burger{display:none;}
.cmp-logo{flex-shrink:0;}
  /* the nav wraps before the lockup gives up a letter */
.cmp-callbar{display:none;}
.cmp-nav{position:static;inset:auto;background:none;color:inherit;padding:0;border:0;
    overflow:visible;transform:none;visibility:visible;margin-left:auto;z-index:auto;}

  /* 24px gaps from 1024: at 15/700 the row is 796px with 32px gaps against 781px of room
     at 1024 (the logo sub-line and the CTA label both wrapped). 32px returns at 1280. */
.cmp-nav__list{flex-direction:row;align-items:center;gap:var(--sp-5);
    flex-wrap:wrap;justify-content:flex-end;row-gap:var(--sp-2);}
  /* at 200% text the row wraps; the logo keeps its words */
.cmp-nav__list > li,
.cmp-nav.is-open .cmp-nav__list > li{animation:none;}
  /* the cascade is for the mobile panel only */
  /* The reference's nav register: 15px Montserrat 700 tracked 1.25px (.085em = 1.275px).
     At 13/600 the nav was the same size and weight as every eyebrow on the page. */
.cmp-nav__link{font-size:var(--t-small);font-weight:700;letter-spacing:.085em;text-transform:uppercase;}

  /* The row sits on the white bar once scrolled: the blue hover is 8.10:1 there. Over the
     hero the link keeps its own ink (main.css) — --accent-press measured 1.26:1 on the scrim. */
.cmp-header.is-stuck:not(.is-menu-open) .cmp-nav__link:hover{color:var(--accent-press);}
.cmp-nav__cta{margin-top:0;}

  /* The dropdown: it opens on hover, on keyboard focus, and on a click of the chevron,
     so a mouse, a keyboard and a touch screen each have a way in. The chevron is its own
     button, which leaves the Services link itself free to go to the section. */
.cmp-nav__group{position:relative;display:flex;align-items:center;gap:.125rem;grid-template-columns:none;}
.cmp-nav__more{display:inline-flex;align-items:center;justify-content:center;
    width:1.75rem;min-height:2.75rem;padding:0;border:0;background:none;color:inherit;cursor:pointer;}
.cmp-nav__more svg{width:.8rem;height:.8rem;transition:transform var(--dur-fast) var(--ease-expo);}
.cmp-nav__group.is-open .cmp-nav__more svg{transform:rotate(180deg);}

  /* The phone panel collapses the list with max-height; the desktop dropdown is
     an absolutely positioned panel and must undo that or it opens to nothing. */
.cmp-nav__sub{max-height:none;
    position:absolute;top:100%;left:calc(-1 * var(--sp-4));min-width:16.5rem;
    padding:var(--sp-4) var(--sp-3);background:var(--surface);border-radius:var(--r-md);
    box-shadow:var(--shadow-float);opacity:0;visibility:hidden;translate:0 .5rem;
    transition:opacity var(--dur-fast) var(--ease-expo),
               translate var(--dur-fast) var(--ease-expo),
               visibility 0s linear var(--dur-fast);}
.cmp-nav__group:hover .cmp-nav__sub,
.cmp-nav__group:focus-within .cmp-nav__sub,
.cmp-nav__group.is-open .cmp-nav__sub{opacity:1;visibility:visible;translate:0;transition-delay:0s;}
.cmp-nav__sub a{width:100%;padding:0 var(--sp-3);color:var(--fg);font-size:var(--t-label);}
.cmp-nav__sub a:hover{color:var(--accent);}

  /* The dropdown panel is white from here, so the marker flips to the page ink
     and the accent rule sits inside the panel's own padding. */
.cmp-nav__sub a[aria-current='page']{color:var(--accent);}
.cmp-nav__sub a[aria-current='page']::before{left:calc(-1 * var(--sp-3) + 2px);
    background:var(--accent);}
.cmp-header .cmp-nav{transform:translateY(var(--header-drop));transition:transform var(--dur-base) var(--ease-spring);}
  /* rides with the logo (a static row here, not the fixed panel) */
.cmp-header.is-stuck .cmp-nav{transform:none;}
}
@media (min-width:1280px){
:root{
    --fs-01:3.75rem;    /* 60 — 1.15x the 52px H2; still two lines in the 1136px column */
    --fs-02:3.25rem;    /* 52 */
    --fs-02b:2.5rem;    /* 40 */
    --fs-03:1.875rem;   /* 30 */
    --fs-04:1.3125rem;  /* 21 */
  }
/* The nav keeps the 1024 gap. It used to widen to 32px here, which fitted while the row
     was five items and the button: 846px of row against 886px of room. Adding FAQ (revision
     3) made it 894px and the button dropped onto a second line, taking the whole header to
     112px. The container stops growing at 1200, so that 886px never increases — 32px cannot
     come back at any width while there are six links. */
.cmp-nav__list{column-gap:var(--sp-5);}
.cmp-footer__grid{gap:var(--sp-9) var(--sp-8);}
}
@media (min-width:1600px){
:root{
    --fs-01:4rem;       /* 64 */
    --fs-02:3.625rem;   /* 58 */
    --fs-02b:2.75rem;   /* 44 */
    --fs-03:2rem;       /* 32 */
    --fs-04:1.375rem;   /* 22 */
    --t-card:1.3125rem; /* held at 21: the container stops at 1200, so the card column stays
                           218px and 'Financial Management' measures 221px at 22 — it wrapped */
  }
}


/* em, so this answers the reader's own text size, not the window: at a 32px default font it
   applies under 637px, where the doubled lockup (466px) cannot sit beside the menu button.
   The lockup text is decorative — .cmp-logo carries the accessible name. At the default
   16px it is 318px, so it never touches a 320px phone. (The old 13em version could not fire
   above a 208px window at any realistic text size.) */
@media (max-width:19.9em){
.cmp-logo__text{display:none;}
}
@media (max-width:1023px){

  /* Her photograph and the words become two blocks instead of one.
     Stacked, the scrim had to reach .90 by 36% of the height for the lead to
     clear 4.5:1 — which meant the portrait underneath it was not visible at
     all. Nothing is gained by keeping a picture no one can see behind type
     that is fighting it. The photograph gets its own frame, the copy sits on
     solid navy, and the scrim is not needed at either. */
.site-main .is-style-owner{min-height:0;padding-block:0;align-content:start;}
.site-main .is-style-owner .wp-block-cover__image-background{position:static;z-index:auto;width:100%;height:auto;
    /* She sits to the right of this frame, so a centred crop takes her out of it.
       72% keeps her in shot and the desk in the corner. */
    aspect-ratio:4/5;object-position:72% 30%;}
.site-main .is-style-owner .wp-block-cover__background{display:none;}
.site-main .is-style-owner>.cmp-wrap{padding-block:var(--space-block);}
.cmp-owner__body{max-width:none;}


  /* The fixed call bar (68px + safe area) is on screen below 1024 once the hero's own
     actions have scrolled away. Focused elements scroll clear of it, and the page ends 64px
     lower so the footer's last links are never under it. */
html{scroll-padding-bottom:7rem;}
body{padding-bottom:calc(var(--sp-8) + env(safe-area-inset-bottom));}
}


/* Phones: the four service cards run 2 x 2, so all four services are on one screen. Stacked
   they were four full-width 336px tiles — 1,450px of near-identical dark cards carrying an
   icon and two words each. 12px gutter; 4:5 like every other portrait on the page (165 x 207
   at 375, 138 x 173 at 320). Still whole-card links, far over the 44px floor.
   The track floor is max(8.5rem, 50% - 12px): the 50% term caps the row at two cards (three
   fitted at 568), and the rem term answers the reader's text size — at 200% text 8.5rem is
   272px, two no longer fit, and the cards fall back to one column instead of breaking
   'Bookkeeping' into three lines and clipping it (measured at 375 with the text doubled).
   For the same reason the 4:5 is a min-height (5/8 of the two-up row), not an aspect-ratio:
   a min-height grows with its text, an aspect-ratio box with overflow:hidden crops it.
   Contrast on the smaller card, against a pure-white frame: a two-line title starts 32% up
   the card at 320, where the scrim is navy @.88 -> 10.6:1; the icon tops out 55% up, @.55
   at worst -> 3.34:1 (UI, needs 3). 16px padding: 'Management' fits the 106px line at 320
   (scrollWidth = clientWidth on all four titles). */
@media (max-width:599px){
.site-main .is-style-cards{gap:var(--sp-3);
    grid-template-columns:repeat(auto-fit,minmax(min(100%,max(8.5rem,50% - var(--sp-3))),1fr));}
.site-main .is-style-card{min-height:calc((100vw - 2 * var(--gutter) - var(--sp-3)) * .625);padding:var(--sp-4);}
.cmp-card__icon{width:1.75rem;height:1.75rem;margin-bottom:var(--sp-3);}
}


/* Hero player goes full-width and centred on phones. The paired images keep their
   overlap here: it is sized in % of the figure and no tap target sits under it. */
@media (max-width:767px){

  /* The page hero's own opening. --space-section is 72px at this width, and with the 76px
     bar above it that put 148px over the heading — a third of a phone screen before the
     first word. The bar is already air; the hero only needs its own. Same rule as the
     prototype's responsive.css. */
.site-main .is-style-phero{padding-block-start:calc(var(--header-h) + var(--sp-7));}
.cmp-hero__player{left:var(--gutter);right:var(--gutter);justify-content:center;bottom:var(--sp-5);}

  /* Seven or more slides: 44px dots no longer fit one phone row (343 - 44 - 16 = 6 dots),
     so the industry label stands in for them. The pause control is always there. */
.cmp-hero__player--many .cmp-hero__dots{display:none;}
.cmp-hero__player--many .cmp-hero__now{display:block;}
}


/* At 320 the container is 288px and "BOOK A CONSULTATION" at 15px tracked needs
   307px with the arrow and padding — it wrapped the arrow onto a second line. */
@media (max-width:374px){
:root{--t-btn:0.875rem;}
.cmp-btn{padding:1.125rem 2.5rem 1.125rem 1.25rem;gap:var(--sp-3);}

  /* The lockup is 233.6px and the bar has 224 beside the burger at 320: the sub-line was
     wrapping under itself. .12em tracking (-11px) and a 12px gap bring it to 222 of 228. */
.cmp-header__inner{gap:var(--sp-3);}
.cmp-logo__sub{letter-spacing:.12em;}

  /* 83px thirds at 320: 'IN BUSINESS SINCE' takes three lines, so the reserve is three and
     the values still share one line (the first sat 15px low). */
.cmp-trust__fact :is(dt, .cmp-dt, .cmp-legal__term){min-height:calc(3em * var(--lh-label));}
}


/* iPhone SE 1 class (320 x 568). The gate is 375, but this is the smallest real screen: the
   hero button measured 520-584 there — 16px under the fold. Two cuts, both outside the
   locked hero shape (the statement keeps its lines, the lead keeps its 2.0 leading):
   the clearance above the H1 goes 48 -> 24px, and the H1 steps 40 -> 36px (4 lines x 39.6 =
   158 vs 176; still over the 30px H2). */
@media (max-width:359px){
:root{--fs-01:2.25rem;}
   /* 36 */
.cmp-hero__inner{padding-top:calc(var(--header-h) + 2 * var(--header-drop) + var(--sp-5));}
}


/* Forced colours repaint every background, which would blank the masked tick. Opt the tick
   out and give it the system text colour. */
@media (forced-colors:active){
.cmp-svc__list li::before{forced-color-adjust:none;background:CanvasText;}
}


/* ---- Facts row on a phone ------------------------------------------------
   Three across a 358px row gives each fact 114px: "In business since" breaks to two
   lines and so does "Ontario, California", and the row collides with the hero's player.
   Two per row gives each about 167px — every label sits on one line at the size it is
   meant to be read at — and the third centres under them. Nothing is hidden: all three
   facts are hers. */
@media (max-width:560px){
.cmp-trust__fact{flex:1 1 42%;}

  /* The two-line reserve exists to bottom-align three labels of different lengths across
     one row. Two per row, each label fits on one line, so the reserve is just a gap above
     the label — released here and taken back at 768 by the rule above. */
.cmp-trust__fact :is(dt, .cmp-dt, .cmp-legal__term){min-height:0;}
}


/* ---- Tablet: the reading sizes, up a step -------------------------------
   Between 768 and 1023 the column is wide but the type was still carrying its phone
   sizes, so the page read small for the space it had.

   The band is BOUNDED on purpose. A bump written as min-width:768 also applies at 1440
   unless every value is pinned back at 1024, and that has gone wrong twice on this build
   — desktop body text went 17 to 18px, and the step text 15 to 17px, both unnoticed until
   they were measured. A bounded band cannot leak. */
@media (min-width:768px) and (max-width:1023px){
.cmp-lead{font-size:1.3125rem;}
                    /* 21px */
.cmp-svc__text{font-size:1.1875rem;}
               /* 19px */
.cmp-svc__list{font-size:1.1875rem;}
               /* 19px */
.cmp-serve__title{font-size:1.3125rem;}
            /* 21px */
.cmp-serve__text{font-size:1rem;}
                  /* 16px */
.cmp-faq__item :is(dt, .cmp-dt, .cmp-legal__term){font-size:1rem;}
                 /* 16px */
.cmp-faq__item :is(dd, .cmp-dd, .cmp-legal__def){font-size:1.1875rem;}
            /* 19px */
.cmp-offer__text{font-size:1.1875rem;}
             /* 19px */
.cmp-also__text{font-size:1.1875rem;}
}


/* ==== 93-arenex-responsive.css ==== */
/*
 * Widths for the plugin blocks' own frames.
 *
 * HAND-WRITTEN, and deliberately separate from 92-responsive.css, which is regenerated
 * from the prototype's responsive.css every time a look changes — anything added there
 * is lost on the next port. These rules are about markup the plugin renders
 * (.arenex-steps__*), which the prototype has no counterpart for.
 *
 * It loads after 92 so it has the last word at the same breakpoints.
 */

@media (min-width: 1024px){

	/* The Steps block's frame: her photograph beside the steps, the intro full width
	   above them — the prototype's .cmp-how, .9fr 1.1fr with the photo stretched to the
	   column's height. */
	.site-main .is-style-process .arenex-steps__inner{
		grid-template-columns:.9fr 1.1fr;
		column-gap:var(--sp-9);
		grid-template-areas:
			"head head"
			"media list";
		align-items:stretch;
	}

	/* Side by side, the photograph stays in the flow: it is taller than the three steps
	   beside it (594px against 412px at 1440), and it is what stretches the row. Pulled
	   out of the flow it had no height of its own and the section came up 166px short. */
	/* The photograph's own 4/5 gives the row its height — it is taller than the three
	   steps beside it (594px against 412px at 1440) and is what stretches the row.
	   Stating the ratio on the FIGURE keeps that deterministic: height:100% on the image
	   inside a row the image itself sizes is circular, and it resolved differently
	   depending on whether the file had loaded when layout ran — 594px in one pass and
	   1500px in another, which is a 900px swing in the section. */
	.site-main .is-style-process .arenex-steps__media{
		height:auto;
		aspect-ratio:4/5;
	}

	.site-main .is-style-process .arenex-steps__img{
		position:static;
		width:100%;
		height:100%;
		aspect-ratio:auto;
		object-fit:cover;
	}

	/* The intro is itself two columns from 1024: the heading, and the lead beside it with
	   its last line on the heading's last baseline (`end` is the Safari < 16 fallback).
	   Even columns, not 1.15/.85: at 1.15/.85 the lead ran 400px and broke to three lines
	   while the heading beside it had room to spare. */
	.site-main .is-style-process .arenex-steps__head{
		max-width:none;
		display:grid;
		grid-template-columns:1fr 1fr;
		gap:var(--sp-9);
		align-items:end;
		align-items:last baseline;
	}

	.site-main .is-style-process .arenex-steps__head > *{min-width:0;}
	.site-main .is-style-process .arenex-steps__head > p{margin-top:0;}
}

/* The button's padding at the design's three widths (the prototype sets it on .cmp-btn;
   in WordPress the anchor inside carries it, through --btn-pad). */
@media (min-width: 768px){
	:root{ --btn-pad:1.25rem 3.5rem 1.25rem 3.375rem; --btn-pad-sm:.75rem 1.5rem; }
}

@media (max-width: 374px){
	:root{ --btn-pad:1.125rem 2.5rem 1.125rem 1.25rem; }
}

/* The mirrored band: photograph left, words right. The design does this with
   .cmp-split--flip; the block already marks the same thing as --image-first (the
   image_first field), but its own rule for it is scoped to two styles this site does not
   use, so the class was on the element doing nothing and About's portrait sat on the
   wrong side. */
@media (min-width: 1024px){
	.site-main .arenex-split__grid--image-first > .arenex-split__figure{
		grid-column:1;
		grid-row:1;
	}
	.site-main .arenex-split__grid--image-first > .arenex-split__body{
		grid-column:2;
		grid-row:1;
	}
}

/* The owner band's words, stacked under the photograph on a phone.
 *
 * The design pads a .cmp-wrap inside the band (.cmp-owner > .cmp-wrap). A Cover has no
 * such element — its inner container is WordPress's own — so the rule ported onto
 * nothing and the heading sat flush against the photograph above it and the section edge
 * below. This is that rule, on the element the Cover actually renders. */
@media (max-width: 1023px){
	.site-main .is-style-owner > .wp-block-cover__inner-container{
		padding-block:var(--space-block);
	}
}

/* The button under the steps, in the column the design puts it in.
 *
 * The prototype (responsive.css, the 1024 block):
 *     .cmp-how:has(.cmp-how__action) .cmp-how__figure{grid-row:1 / span 2;}
 *     .cmp-how__action{grid-column:2;}
 * — the photograph spans both rows, the steps take the first of the right-hand column
 * and the button the second. The Steps block dissolves .arenex-steps__text with
 * display:contents, so the head, the list and the link are all items of the same grid
 * and these are the same two rules on them. Added blind the link landed under the
 * photograph in column 1, on a row of its own, and the section stood 164px too tall.
 */
@media (min-width:1024px){
	.site-main .arenex-steps--list:has(.arenex-steps__link) .arenex-steps__media{
		grid-row:2 / span 2;
	}

	.site-main .arenex-steps--list .arenex-steps__link{
		grid-column:2;
	}

	/* Without this the list stretches to the photograph's height and its three rows are
	   pushed apart — 606px against the design's 412. */
	.site-main .arenex-steps--list:has(.arenex-steps__link) .arenex-steps__list{
		align-self:start;
	}

	/* The photograph spans rows 2 and 3, and a spanning item hands its extra height to
	   both tracks — so the button drifted 121px below the last step instead of the
	   design's 104, and adding a margin barely moved it because the margin was absorbed
	   by that same distribution. Naming the tracks settles it: the list's row takes its
	   own content, the button's row takes what the photograph leaves, and the button
	   sits at the top of it. The gap is then the row gap plus this margin, and nothing
	   else. */
	.site-main .arenex-steps--list:has(.arenex-steps__link) .arenex-steps__inner{
		grid-template-rows:auto max-content 1fr;
	}

	.site-main .arenex-steps--list .arenex-steps__link{
		margin-top:1.75rem;
	}
}

/* The page hero's gutters below the two-column breakpoint.
 *
 * At 1024 and up the photograph is absolutely positioned at 66vw and runs off the right
 * edge by design, so the grid pays a start offset only and stays full width (the note in
 * 70-arenex-split.css). Below that the photograph is back in flow under the text, and
 * with no end padding it ran to the viewport edge: 736px wide against the design's 704,
 * and at 4/5 that is 40px of extra height in the section at 768. Symmetric gutters here,
 * which is what .cmp-wrap gives the same element in the prototype. */
@media (max-width:1023px){
	.site-main .is-style-phero > .arenex-split__grid{
		max-width:var(--container);
		margin-inline:auto;
		padding-inline:var(--gutter);
	}
}

/* The section under the page hero keeps its top padding from 1024 up.
 *
 * 51-phero.css collapses it (the design's rule: two plain sections in a row do not pay
 * the gap twice — the first one's bottom padding is the whole gap). That holds while the
 * hero's bottom padding is visible air. From 1024 the photograph is positioned over the
 * whole hero with inset:0, so the hero's 115px sit behind it: measured, there were 0px
 * between the foot of the photograph and the cap-line of the heading below it. Mirrors
 * the same rule added to the prototype's responsive.css. */
@media (min-width:1024px){
	.site-main .is-style-phero + .cmp-section:not(.cmp-section--tint){
		/* Not the full section padding: the same .55 the design gives the section under a
		   full-bleed band (35-sections.css). The case is the same one — a hard photographic
		   edge above the first line — and at full strength the 120px below the photograph
		   read as a hole on all four service pages. */
		padding-top:calc(var(--space-section) * .55);
	}
}

