/*
 * Scott Aussie — component styles
 * Every text/background pair used here appears in the brand rules' computed contrast table.
 * Nothing is eyeballed (§Web non-negotiables #7).
 */

/* ============================================================
   1. Links — the underline is structural, not decorative
   WCAG 1.4.1: colour is never the only signal.
   ============================================================ */

/*
 * The persistent underline is required for links sitting INSIDE blocks of text —
 * WCAG 1.4.1, colour is never the only signal. It is not required, and looks wrong,
 * on navigation, the site title or the logo, where position and context already
 * identify the link. Those get an underline on hover instead.
 */
.wp-site-blocks a:where(:not(.wp-element-button):not(.wp-block-social-link-anchor):not(.wp-block-button__link)):where(
  :not(.wp-block-navigation-item__content):not(.wp-block-site-title a):not(.wp-block-site-logo a)
) {
  color: var(--sa-navy);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
}

.wp-block-site-title a,
.wp-block-site-logo a,
.wp-block-navigation .wp-block-navigation-item__content {
  text-decoration: none;
}

.wp-block-site-title a:hover,
.wp-block-navigation .wp-block-navigation-item__content:hover {
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 0.2em;
}

.wp-site-blocks a:where(:not(.wp-element-button):not(.wp-block-social-link-anchor):not(.wp-block-button__link)):hover {
  color: var(--sa-gold-deep);            /* 5.15:1 on white — PASS */
  text-decoration-thickness: 2px;
}

/* On navy backgrounds: white link, gold on hover (14.66:1 / 4.64:1) */
.has-primary-background-color a:where(:not(.wp-element-button):not(.wp-block-social-link-anchor)),
.sa-on-navy a:where(:not(.wp-element-button):not(.wp-block-social-link-anchor)) {
  color: var(--sa-white);
}
.has-primary-background-color a:where(:not(.wp-element-button):not(.wp-block-social-link-anchor)):hover,
.sa-on-navy a:where(:not(.wp-element-button):not(.wp-block-social-link-anchor)):hover {
  color: var(--sa-gold);
}

/* Never Accent Gold as inline link text on white — 3.16:1, fails.
   Brand rules call this "the most likely wrong guess in the whole palette". */


/* ============================================================
   2. Focus — one token, works on every background
   Gold ring: 3.16:1 on white, 4.64:1 on navy. Both clear the 3:1
   non-text threshold (WCAG 2.4.7 / 1.4.11).
   ============================================================ */

:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 3px solid var(--sa-gold);
  outline-offset: 2px;
  border-radius: 2px;
}

/* Never outline:none without a compliant replacement — §Web non-negotiables #1 */


/* ============================================================
   3. Buttons
   Primary  : navy fill, white text          → hover navy-deep
   Secondary: gold fill, NAVY text           → hover gold-LIGHT
   Ghost    : 2px navy border, navy text     → hover navy fill, white text

   The gold button gets LIGHTER on hover, never darker. Darkening moves the
   fill toward the navy text and collapses contrast:
     #A87B26 = 3.86:1 FAIL · #B8892B = 4.64:1 PASS · #C79A3D = 5.67:1 PASS
   ============================================================ */

.wp-block-button__link,
.wp-element-button {
  min-height: var(--sa-tap);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
  font-weight: 600;
  transition: background-color 0.15s ease, color 0.15s ease;
}

/* Secondary — gold */
.wp-block-button.is-style-sa-gold .wp-block-button__link {
  background-color: var(--sa-gold);
  color: var(--sa-navy);                 /* NEVER white on gold — 3.16:1 */
  border: none;
}
.wp-block-button.is-style-sa-gold .wp-block-button__link:hover,
.wp-block-button.is-style-sa-gold .wp-block-button__link:focus {
  background-color: var(--sa-gold-light);
  color: var(--sa-navy);
}

/* Ghost */
.wp-block-button.is-style-sa-ghost .wp-block-button__link {
  background-color: transparent;
  color: var(--sa-navy);
  border: 2px solid var(--sa-navy);
}
.wp-block-button.is-style-sa-ghost .wp-block-button__link:hover,
.wp-block-button.is-style-sa-ghost .wp-block-button__link:focus {
  background-color: var(--sa-navy);
  color: var(--sa-white);
}

/* Ghost on navy */
.has-primary-background-color .wp-block-button.is-style-sa-ghost .wp-block-button__link,
.sa-on-navy .wp-block-button.is-style-sa-ghost .wp-block-button__link {
  color: var(--sa-white);
  border-color: var(--sa-white);
}
.has-primary-background-color .wp-block-button.is-style-sa-ghost .wp-block-button__link:hover,
.sa-on-navy .wp-block-button.is-style-sa-ghost .wp-block-button__link:hover {
  background-color: var(--sa-white);
  color: var(--sa-navy);
}


/* ============================================================
   4. Eyebrow label
   ============================================================ */

.sa-eyebrow {
  font-size: var(--sa-size-eyebrow);
  font-weight: 600;
  line-height: 1.4;
  text-transform: uppercase;
  letter-spacing: 0.26em;
  color: var(--sa-gold-deep);            /* 5.15:1 on white */
  margin: 0 0 var(--sa-space-3);
}

/*
   NARROW ELEMENTS IN A SECTION MUST START WHERE THE WIDE ONES DO.

   Third instance of the same root cause as the card headings and the gold rule: core's
   constrained layout puts `margin-left/right: auto !important` on every section child,
   and `.sa-eyebrow` sets `margin: 0 0 …` with no `!important`, so it loses and centres.
   Measured on Home, Insights and For Operators — eyebrow at left=396 while its own
   heading sat at left=93. Body paragraphs did the same, landing at 201.

   Zeroing the margins is the WRONG fix, and it is the mistake the gold rule taught:
   the section's headings and grids are 1200px boxes auto-centred in a 1337px container,
   so the visual content column starts at 93 — not at the container edge. margin-left: 0
   would put these elements 68px to the LEFT of the heading they belong to.

   So they take the same offset the wide elements get: half the difference between the
   container and the wide size. Below 1200px that clamps to 0 and everything is flush,
   which is what the wide elements do too.
*/
.sa-section > .sa-eyebrow,
.sa-section > p,
.sa-section > ul,
.sa-section > ol,
.sa-section > blockquote,
.sa-section > .wp-block-separator,
/*
   The same applies OUTSIDE a section. Not every heading and paragraph on a page is
   wrapped in one — the home page's "Two audiences, one specialisation" and its
   supporting line sit directly in the post content — and scoping this to .sa-section
   first time round left those adrift by 108px: heading at 93, paragraph at 201. A
   narrow element auto-centres wherever core's constrained layout reaches it, so the
   correction has to reach just as far.
*/
.wp-block-post-content > .sa-eyebrow,
.wp-block-post-content > p,
.wp-block-post-content > ul,
.wp-block-post-content > ol,
.wp-block-post-content > blockquote,
.wp-block-post-content > figure.sa-media--16x9,
.wp-block-post-content > .wp-block-separator {
  margin-left: max(0px, calc((100% - var(--wp--style--global--wide-size, 1200px)) / 2)) !important;
  margin-right: auto !important;
}

/* Over a scrim, eyebrows are WHITE, never gold —
   gold reaches only 3.73:1 even at a 92% scrim. */
.wp-block-cover.sa-media .sa-eyebrow,
.sa-on-navy .sa-eyebrow { color: var(--sa-white); }


/* ============================================================
   5. Gold rule — the accent device
   Gold over photography is the 3px rule ONLY, never text.
   ============================================================ */

/*
   The gold rule is 54px wide, and core's constrained layout gives every child of a
   section `margin-left/right: auto !important`. A narrow element with two auto inline
   margins centres itself — so the rule has been sitting in the middle of left-aligned
   headings everywhere it appears inside a section, including the page heroes. Same
   root cause as the card-heading bug, different symptom: there it disabled flex
   stretch, here it simply centres.

   The class is doubled to beat core's :where() rule (zero specificity, injected
   inline) without depending on stylesheet order, and --centred is doubled to match so
   a deliberately centred rule still wins.
*/
/*
   PAINT the 54px, do not SIZE the element to it.

   A 54px-wide element inside a constrained section gets core's
   `margin-left/right: auto !important` and centres itself, so the rule sat in the
   middle of left-aligned headings everywhere — including the page heroes. Zeroing the
   margins fixed the centring and introduced a subtler error: the element then hugged
   the CONTAINER edge, about 40px left of where the heading text begins, because the
   heading is inside the narrower constrained content column.

   So the element keeps its auto margins and fills the content column exactly like the
   heading above it, and the gold is painted as a 54px background on the left. The rule
   now starts precisely where the heading starts, at any viewport width, with no
   dependency on the content-size token.
*/
.sa-rule {
  width: auto;
  height: 3px;
  border: 0;
  background-color: transparent;
  background-image: linear-gradient(var(--sa-gold), var(--sa-gold));
  background-repeat: no-repeat;
  background-size: 54px 3px;
  background-position: left center;
  margin-block: var(--sa-space-4);
}

.sa-rule--centred { background-position: center; }


/* ============================================================
   6. Stat component — the case-study numbers

   These are core/group blocks with a grid layout, so WordPress owns the
   columns and the gap. Nothing here re-declares the grid — that would fight
   the layout controls in the editor.
   ============================================================ */

.sa-stats { margin-block: var(--sa-space-6); }

.sa-stat {
  padding: var(--sa-space-5);
  background: var(--sa-neutral);
  border-top: 3px solid var(--sa-gold);
}

.sa-stat > * { margin-block: 0; }

.sa-stat__figure {
  font-size: clamp(36px, 2.2vw + 26px, 48px);
  font-weight: 600;
  line-height: 1.1;
  color: var(--sa-navy);                 /* 12.64:1 on #EEEEEE */
}

/* A stat whose "figure" is words rather than a number. Same tile, smaller type,
   so "City of Rockingham" does not sit at 48px next to a four-digit year. */
.sa-stat__figure--text {
  font-size: clamp(22px, 1.1vw + 18px, 28px) !important;
  line-height: 1.2;
}

.sa-stat__label {
  margin-top: var(--sa-space-2) !important;
  font-size: var(--sa-size-small);
  line-height: 1.5;
  color: var(--sa-navy);
}


/* ============================================================
   7. Quote component — core/quote, named testimonials only
   ============================================================ */

/*
   Even padding on all four sides.

   This was `padding: … 0 … var(--sa-space-5)` — zero on the right — which reads fine
   for a quote with only a gold left rule and no other edge. But the block also carries
   a 1px border top, right and bottom, so measured the text ran to within ONE pixel of
   the right-hand line while sitting 35px off the left. The asymmetry is invisible in
   the CSS and obvious on the page.
*/
blockquote.sa-quote {
  margin: var(--sa-space-6) 0;
  padding: var(--sa-space-5);
  border-left: 3px solid var(--sa-gold);
}

blockquote.sa-quote p {
  font-size: var(--sa-size-body-l);
  line-height: var(--sa-lh-body-l);
  color: var(--sa-navy);
}

blockquote.sa-quote cite {
  display: block;
  margin-top: var(--sa-space-4);
  font-size: var(--sa-size-small);
  font-style: normal;
  font-weight: 600;
  color: var(--sa-navy);
}

blockquote.sa-quote cite span {
  display: block;
  font-weight: 400;
  color: var(--sa-ui-grey);              /* 5.95:1 on white — meta text, in scope */
}


/* ============================================================
   7a. Post-template grids — the gap core forgets
   ============================================================ */

/*
   A core/post-template with a grid layout and no blockGap attribute computes to
   `gap: normal`, which for a grid container means ZERO. Featured images then touch
   edge to edge and, worse, each column's heading butts against its neighbour's — so a
   two-line title in the middle column and a four-line title on its right read as one
   run-on sentence. Andy hit exactly that on Start here: "A Critical Perspective on
   Western Australia's WAVES 2033 Strategy" and "How to Dodge the BS and Find a
   Marketing Partner…" interleaved line by line into nonsense.

   The .sa-cards grids never showed it because they declare their own gap, and .sa-news
   because this file sets one — which is why it looked like a problem with two pages
   rather than with every post-template on the site. One rule, applied wherever core
   leaves the gap unset.

   The column gap is larger than the row gap on purpose: adjacent columns of text need
   more separation than stacked blocks within one column, precisely because horizontal
   neighbours are what the eye joins into a single line.
*/
.wp-block-post-template.is-layout-grid {
  gap: var(--sa-space-5) var(--sa-space-6);
}

/*
   FOUR COLUMNS MAXIMUM on the full listings.

   `minimumColumnWidth` fills as many columns as fit, which on a wide monitor reached
   five — and a per-page count cannot divide evenly by both five and the three, two and
   one columns the same grid produces at narrower widths. Twelve per page is whole at
   1, 2, 3, 4 and 6; making five work as well would need a multiple of 60. So the cap
   is what makes the last row always full, rather than the count.

   Four is also about as many 16:9 cards as stay legible side by side.

   Scoped to .sa-list — the newspaper sections and the Start here band each carry their
   own column rules and must not be forced to four.
*/
@media (min-width: 1400px) {
  .wp-block-post-template.sa-list.is-layout-grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

/* ============================================================
   7b. Insights index — newspaper sections
   ============================================================ */

/*
   Lead plus two, done in CSS rather than in markup.

   Every item in a section is the same block structure, so the page stays editable in
   the Site Editor without collapsing. The grid gives the first child both columns'
   worth of height and the other two stack beside it; images are suppressed on the
   followers, which is what makes the lead read as the lead — and, usefully, means the
   six "10% series" articles no longer print the same photograph three times in a row.
*/
.sa-news .wp-block-post-template {
  display: grid;
  grid-template-columns: 1.6fr 1fr;
  gap: var(--sa-space-5) var(--sa-space-6);
  align-items: start;
  margin: var(--sa-space-5) 0 0;
  padding: 0;
  list-style: none;
}

.sa-news .wp-block-post-template > li:first-child { grid-row: span 2; }

.sa-news .wp-block-post-template > li:first-child .wp-block-post-title {
  font-size: var(--sa-size-h3);
  margin-block: var(--sa-space-3) var(--sa-space-2);
}

/* Followers are text-led. The image is the lead's job. */
.sa-news .wp-block-post-template > li:not(:first-child) .wp-block-post-featured-image { display: none; }

.sa-news .wp-block-post-template > li:not(:first-child) {
  border-top: 1px solid var(--sa-neutral);
  padding-top: var(--sa-space-4);
}

/* On a neutral band the hairline needs to be visible against the band, not the page. */
.sa-section--neutral .sa-news .wp-block-post-template > li:not(:first-child) {
  border-top-color: rgba(0, 35, 102, 0.18);
}

.sa-news .wp-block-post-title { margin-block: var(--sa-space-2); }
.sa-news .wp-block-post-title a { text-decoration: none; }
.sa-news .wp-block-post-title a:hover,
.sa-news .wp-block-post-title a:focus-visible { text-decoration: underline; }

.sa-news .wp-block-post-excerpt { margin-block: 0; }
.sa-news .wp-block-post-excerpt p { margin-block: 0; }

.sa-news .wp-block-post-featured-image {
  min-height: 0;      /* see the note on .sa-card — aspect-ratio loses to min-height:auto */
  overflow: hidden;
}

.sa-news__all { margin-top: var(--sa-space-5); font-weight: 500; }

/*
   The home page's "Worth reading" strip sits at the page's own measure.

   Its align:wide resolves to the post-content contentSize (90%), not the 1200px
   wide-size the rest of that page obeys — so at 1800px it ran 111..1674 while the
   headings, cards and stats ran 293..1493, and the discrepancy grows with the window.

   Scoped to this one wrapper rather than to .wp-block-query.alignwide generally:
   /insights/all/ and the archives are alignwide too and are MEANT to reach 90%, which
   is what lets category pages show more than three columns.
*/
.sa-latest-wrap {
  max-width: var(--wp--style--global--wide-size, 1200px) !important;
  margin-inline: auto !important;
}

/* Start here — three equal cards, image-led, above the sections. */
.sa-starthere .wp-block-post-template {
  margin: var(--sa-space-5) 0 0;
  padding: 0;
  list-style: none;
}

.sa-starthere .wp-block-post-featured-image { min-height: 0; overflow: hidden; }
.sa-starthere .wp-block-post-title { margin-block: var(--sa-space-3) var(--sa-space-2); }
.sa-starthere .wp-block-post-title a { text-decoration: none; }
.sa-starthere .wp-block-post-title a:hover,
.sa-starthere .wp-block-post-title a:focus-visible { text-decoration: underline; }

@media (max-width: 782px) {
  .sa-news .wp-block-post-template { grid-template-columns: 1fr; }
  .sa-news .wp-block-post-template > li:first-child { grid-row: auto; }
}

/* ============================================================
   8. Card component — core/group with grid layout
   ============================================================ */

.sa-card {
  display: flex;
  flex-direction: column;
  background: var(--sa-white);
  border: 1px solid var(--sa-neutral);
  border-top: 3px solid var(--sa-gold);
  padding: var(--sa-space-5);
}

.sa-card > :first-child { margin-top: 0; }
.sa-card > :last-child  { margin-bottom: 0; }

/*
   A CONSTRAINED GROUP INSIDE A FLEX COLUMN CENTRES ITS SHORT CHILDREN.

   satm_cards() emits each card as a core/group with constrained layout, so core
   adds (block-supports/layout.php):

     > :where(:not(.alignleft):not(.alignright):not(.alignfull)) {
         max-width: var(--wp--style--global--content-size);
         margin-left: auto !important; margin-right: auto !important; }

   and this file makes .sa-card a flex column. Per CSS Flexbox 8.3 a flex item is
   stretched to fill the cross axis only when NEITHER cross-axis margin is auto.
   Both are, so stretch never applies: every child shrink-to-fits its content and
   the auto margins then centre it.

   The result was alignment that tracked text length rather than intent. A heading
   short enough to sit on one line ("Websites", "Advertising") centred; one long
   enough to wrap filled the card and read as left-aligned. Every CTA link centred,
   because they are all short. Nothing here ever asked for centred anything.

   Zeroing the cross-axis margins restores stretch. The class is doubled because
   core's rule is injected inline and its :where() carries zero specificity — equal
   weight to a single .sa-card, so the winner would otherwise depend on load order.
*/
.sa-card.sa-card > * {
  margin-left: 0 !important;
  margin-right: 0 !important;
  max-width: none;
}
.sa-card__cta { margin-top: auto !important; padding-top: var(--sa-space-4); }

/* A card used inside a query loop has to fill its grid cell. Grid stretches the
   <li>, but the card is a child of the <li>, so without this a short excerpt
   leaves one card standing shorter than its neighbour and the row edge goes
   ragged. */
.wp-block-post-template > li > .sa-card { height: 100%; }

/*
   A featured image with an aspect ratio is a CROPPING BOX. Make it behave like one.

   core/post-featured-image already emits everything needed — aspect-ratio on the
   figure, object-fit:cover on the image — and it still broke out of the card.

   The cause is that flex and grid items get `min-height: auto`, which means they
   cannot shrink below their content's intrinsic height. That automatic minimum
   silently WINS over aspect-ratio. In a ~520px card the 16/9 box wants 292px; a
   2560x2458 photograph's intrinsic height at that width is 499px, so the figure
   grew to 499px and the image spilled over the title beneath it.

   It stayed invisible because every other featured image happened to be 1200x628.
   At ratio 1.91 the intrinsic height is 272px — twenty pixels UNDER the box — so
   the automatic minimum never engaged. The first genuinely non-16:9 photograph
   exposed it.

   min-height: 0 disables the automatic minimum; overflow: hidden is the belt to
   that brace and is what a cropping box should do anyway.
*/
.wp-block-post-template .wp-block-post-featured-image {
  min-height: 0;
  overflow: hidden;
}

.wp-block-post-template .wp-block-post-featured-image a,
.wp-block-post-template .wp-block-post-featured-image img {
  display: block;
  height: 100%;
  width: 100%;
}

.wp-block-post-template .wp-block-post-featured-image img { object-fit: cover; }

/* Inside a card the image must not be resized by flex distribution either —
   the aspect ratio governs its height, not the space left over. */
.sa-card > .wp-block-post-featured-image {
  flex: none;
  margin-bottom: var(--sa-space-4);
}

/* The "read the case study" link sits at the foot of the card, so the links line
   up across a row no matter how long each excerpt runs. core/post-excerpt emits
   the more-text as its own paragraph, which is what makes this possible. */
.sa-card .wp-block-post-excerpt {
  display: flex;
  flex-direction: column;
  flex: 1;
}

.sa-card .wp-block-post-excerpt__more-text {
  margin-top: auto;
  margin-bottom: 0;
  padding-top: var(--sa-space-4);
  font-weight: 500;
}

/* The result line under a card's client name. Reads as a tagline, not a heading,
   so the h3 stays scannable and the outline stays clean. */
.sa-card__tagline {
  margin-top: var(--sa-space-3) !important;
  margin-bottom: var(--sa-space-4) !important;
  font-size: var(--sa-size-body-l);
  line-height: 1.35;
  font-weight: 500;
  color: var(--sa-navy);
}


/* ============================================================
   9. Image slots — core/cover, reserve the space, never fill it

   The cover's overlay colour IS the brand scrim, so when Andy replaces the
   background image the 70%/85% navy is already configured beneath it.

   With no image the cover shows flat Neutral Grey at final dimensions, per
   brand rules §Image handling. A stock photo "for now" is never acceptable.
   ============================================================ */

.wp-block-cover.sa-media {
  min-height: 0;                          /* the aspect ratio governs, not minHeight */
  padding: clamp(24px, 5vw, 64px);
}

.sa-media--16x9 { aspect-ratio: 16 / 9; }
.sa-media--4x5  { aspect-ratio: 4 / 5; }
.sa-media--1x1  { aspect-ratio: 1 / 1; }
.sa-media--4x3  { aspect-ratio: 4 / 3; }
.sa-media--21x9 { aspect-ratio: 21 / 9; }

.wp-block-cover.sa-media .wp-block-cover__inner-container { width: 100%; }

/* With a photograph: white copy over the navy scrim. */
.wp-block-cover.sa-media :is(h1, h2, h3, p) { color: var(--sa-white); }

/*
 * Empty state — no photograph yet.
 *
 * Brand rules §Image handling: "a flat Neutral Grey #EEEEEE block at exact final
 * dimensions with the awaiting-tag visible". So the scrim is suppressed until
 * there is actually an image to scrim, and the copy flips to navy — 12.64:1 on
 * #EEEEEE, where white would have been 1.16:1 and unreadable.
 *
 * The moment Andy sets a background image, the overlay reappears at its configured
 * 70%/85% and the copy goes back to white. Nothing to remember, nothing to undo.
 */
.wp-block-cover.sa-media:not(:has(.wp-block-cover__image-background)):not(:has(video)) {
  background-color: var(--sa-neutral);
}

.wp-block-cover.sa-media:not(:has(.wp-block-cover__image-background)):not(:has(video))
  .wp-block-cover__background {
  display: none;
}

.wp-block-cover.sa-media:not(:has(.wp-block-cover__image-background)):not(:has(video))
  :is(h1, h2, h3, p):not(.sa-media__awaiting) {
  color: var(--sa-navy);
}

/*
 * The eyebrow stays navy here, NOT Gold Deep. The brand table computes
 * #8C6720 on #EEEEEE at 4.44:1 — a pass for large text and a fail for body, and an
 * 11px uppercase eyebrow is small text. Navy on Neutral Grey is 12.64:1.
 */
.wp-block-cover.sa-media:not(:has(.wp-block-cover__image-background)):not(:has(video))
  .sa-eyebrow {
  color: var(--sa-navy);
}

/* The awaiting tag. Deliberately visible — a placeholder that cannot be
   overlooked is the point. No page ships while one of these is present. */
.sa-media__awaiting {
  position: absolute;
  left: 0;
  bottom: 0;
  z-index: 2;
  max-width: 100%;
  margin: 0 !important;
  padding: var(--sa-space-2) var(--sa-space-3);
  background: var(--sa-navy);
  color: var(--sa-white) !important;
  font-size: 12px !important;
  font-weight: 600;
  letter-spacing: 0.04em;
  line-height: 1.4;
  text-transform: uppercase;
}

/*
   A gold rule sitting over a scrim stays a rule, never text.

   This block used to set `width: 54px; margin-inline: 0` to pull the rule left, and it
   never worked: core's constrained layout declares `margin-left/right: auto !important`
   on every child of the cover's inner container, and an un-flagged `margin-inline: 0`
   cannot beat it. Measured, the rule sat at x=348 with 309px of auto margin either side
   while the h1 began at x=38 — dead centre of every page hero on the site.

   Same fix as the section rule: let the element fill the content column so the auto
   margins are harmless, and paint the 54px of gold at its left edge.
*/
.wp-block-cover.sa-media .sa-rule {
  border: 0;
  width: auto;
  height: 3px;
  background-color: transparent;
  background-image: linear-gradient(var(--sa-gold), var(--sa-gold));
  background-repeat: no-repeat;
  background-size: 54px 3px;
  background-position: left center;
}


/* ============================================================
   9b. Marked notes — awaiting items, sequencing rules, build caveats
   ============================================================ */

.sa-notice {
  padding: var(--sa-space-4);
  border-left: 3px solid var(--sa-gold);
  background: var(--sa-neutral);
  margin-block: var(--sa-space-5);
}

.sa-notice > p { margin-block: 0; }

.sa-series-links { margin-top: var(--sa-space-3); }


/* ============================================================
   10. Form fields
   ============================================================ */

.sa-form { max-width: 640px; }

.sa-form__row { margin-bottom: var(--sa-space-4); }

.sa-form label {
  display: block;
  margin-bottom: var(--sa-space-2);
  font-weight: 500;
  color: var(--sa-navy);                 /* 14.66:1 */
}

.sa-form :is(input[type="text"], input[type="email"], input[type="tel"], select, textarea) {
  width: 100%;
  min-height: var(--sa-tap);
  padding: 12px var(--sa-space-3);
  font-family: var(--sa-font);
  font-size: var(--sa-size-body);
  color: var(--sa-navy);
  background: var(--sa-white);
  border: 1px solid var(--sa-ui-grey);   /* 5.95:1 — clears the 3:1 UI threshold */
  border-radius: var(--sa-radius);
}

/* Never Neutral Grey #EEEEEE for a form border — 1.16:1, invisible, fails 1.4.11 */

.sa-form :is(input, select, textarea):focus {
  border-color: var(--sa-navy);
  outline: 3px solid var(--sa-gold);
  outline-offset: 2px;
}

.sa-form__help {
  display: block;
  margin-top: var(--sa-space-2);
  font-size: var(--sa-size-small);
  color: var(--sa-ui-grey);
}

.sa-form__required { color: var(--sa-error); font-weight: 600; }

/* Errors carry an icon or text, never colour alone — WCAG 1.4.1 */
.sa-form__error {
  display: flex;
  gap: var(--sa-space-2);
  margin-top: var(--sa-space-2);
  color: var(--sa-error);
  font-size: var(--sa-size-small);
  font-weight: 500;
}
.sa-form__error::before { content: "⚠"; }

.sa-form__notice {
  padding: var(--sa-space-4);
  border-left: 3px solid var(--sa-gold);
  background: var(--sa-neutral);
  margin-bottom: var(--sa-space-5);
}

/* Honeypot — hidden from people, visible to bots */
.sa-form__hp {
  position: absolute !important;
  left: -9999px !important;
}

/* ---- Notice on a Neutral Grey section -----------------------------------
   .sa-form__notice paints itself Neutral Grey with a 3px gold left rule. Both
   fail inside .sa-section--neutral: the panel is the SAME #EEEEEE, so the notice
   has no edge at all, and Accent Gold on Neutral Grey is 2.72:1 — under even the
   3:1 non-text threshold. That exact pair was the defect found on the calculator
   on 10/08/2026. White fill fixes both at once: the notice separates from the
   band, and the gold rule rises to 3.16:1, which clears the graphics threshold.  */
.sa-section--neutral .sa-form__notice,
.sa-notify--on-neutral .sa-form__notice {
  background: var(--sa-white);
}

/* ---- Notice on a Neutral Grey section, part two -------------------------- */
/* (see .sa-section--neutral .sa-form__notice above)                           */


/* ============================================================
   11. Sections and rhythm
   ============================================================ */

.sa-section { padding-block: clamp(48px, 8vw, 96px); }
.sa-section--neutral { background: var(--sa-neutral); }
.sa-section--navy { background: var(--sa-navy); color: var(--sa-white); }
.sa-section--navy :is(h1, h2, h3, h4, p, li) { color: var(--sa-white); }

/* Keep body copy within a comfortable measure */
.sa-prose > p, .sa-prose > ul, .sa-prose > ol { max-width: var(--sa-measure); }


/* ============================================================
   12. Skip link
   ============================================================ */

.sa-skip-link {
  position: absolute;
  left: -9999px;
  z-index: 999;
  padding: var(--sa-space-3) var(--sa-space-4);
  background: var(--sa-navy);
  color: var(--sa-white);
  font-weight: 600;
  text-decoration: none;
}
.sa-skip-link:focus {
  left: var(--sa-space-3);
  top: var(--sa-space-3);
}


/* ============================================================
   13. Small screens — brief requires testing at 360px
   ============================================================ */

/*
 * A grid with an explicit columnCount renders repeat(N, minmax(0,1fr)) and does NOT
 * collapse — so two or three columns would survive down to 360px and be unreadable.
 * These override the generated rule at the point the columns stop working.
 */
@media (max-width: 900px) {
  .sa-stats.is-layout-grid,
  .sa-cards.is-layout-grid,
  .wp-block-post-template.is-layout-grid { grid-template-columns: repeat(2, minmax(0, 1fr)) !important; }
}

@media (max-width: 600px) {
  .sa-stats.is-layout-grid,
  .sa-cards.is-layout-grid,
  .wp-block-post-template.is-layout-grid { grid-template-columns: 1fr !important; }
}

@media (max-width: 480px) {
  .sa-quote { padding-left: var(--sa-space-4); }
  .wp-block-cover.sa-media { padding: var(--sa-space-4); }
}

@media (prefers-reduced-motion: reduce) {
  * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}


/* ============================================================
   14. Site header

   White background, navy text — the brief's "premium-restrained,
   dark-on-light" direction, with the gold CTA as the single accent.

   Navy on white is 14.66:1. The previous header used white text with no
   background colour on a white page: 1:1, and invisible.
   ============================================================ */

.sa-header {
  border-bottom: 1px solid var(--sa-neutral);
}

.sa-header__brand {
  gap: var(--sa-space-3);
  align-items: center;
}

.sa-header .wp-block-site-logo img {
  display: block;
  height: auto;
}

.sa-header .wp-block-site-title {
  margin: 0;
  font-size: var(--sa-size-small);
  font-weight: 600;
  line-height: 1.2;
  color: var(--sa-navy);
}

.sa-header__nav {
  gap: var(--sa-space-4);
  align-items: center;
}

.sa-header .wp-block-navigation {
  font-size: var(--sa-size-small);
}

/* The CTA is the only gold thing in the header — keep it compact. */
.sa-header .wp-block-button__link {
  padding: 10px 20px;
  font-size: var(--sa-size-small);
}

/*
 * Mobile overlay: navy background, white copy (14.66:1). Set on the navigation
 * block itself so it holds even if this stylesheet is not loaded.
 */
.sa-header .wp-block-navigation__responsive-container.is-menu-open {
  padding: var(--sa-space-6) var(--sa-space-4);
}

@media (max-width: 600px) {
  .sa-header__brand .wp-block-site-title { display: none; }   /* mark alone below 600px */
  .sa-header .wp-block-button__link { padding: 8px 16px; }
}


/* ============================================================
   15. One measure for the whole page

   Two different content widths were in play: the page template constrains
   post-content to 90%, while every .sa-section constrains its children to the
   theme content size (720px). So a button inside a section started hundreds of
   pixels further right than the same button outside one — which is exactly what
   "not as far left as the other buttons" looks like.

   Now everything shares the wide column, so headings, buttons and the alignwide
   grids all begin on the same left edge. Prose keeps a reading measure but is
   pinned to that edge rather than centred inside it, so it stays aligned.
   ============================================================ */

.entry-content.is-layout-constrained > :where(:not(.alignfull):not(.alignwide)),
.sa-section.is-layout-constrained > :where(:not(.alignfull):not(.alignwide)) {
  max-width: var(--wp--style--global--wide-size);
}

.entry-content.is-layout-constrained > :where(p, ul, ol, blockquote, .wp-block-quote),
.sa-section.is-layout-constrained > :where(p, ul, ol, blockquote, .wp-block-quote) {
  max-width: var(--sa-measure);       /* ~75 characters, per the brand rules */
  margin-inline: 0 auto;              /* left edge, not centred inside the column */
}


/* ============================================================
   16. Split rows and asides
   ============================================================ */

/* A portrait beside its copy. The photo column keeps its aspect ratio; the copy
   column starts at the top so the page opens with words, not a picture. */
.sa-split { gap: clamp(24px, 4vw, 56px); }

/* A filled slot rendered as a plain image rather than a scrimmed cover. */
.wp-block-image.sa-media { margin-block: 0; }
.wp-block-image.sa-media img {
  display: block;
  width: 100%;
  height: auto;
  object-fit: cover;
}
.sa-split > .wp-block-column > :first-child { margin-top: 0; }

/* ------------------------------------------------------------------
   Client logo on a case study.

   Sits on the page's white background, directly under the hero. Constrained by
   HEIGHT, not width: client logos arrive in wildly different proportions, and a
   width cap makes a wide wordmark tiny while a square mark stays huge. Capping
   height and letting width follow makes them read at a consistent visual weight.

   White background is deliberate and is the reason this is not in the navy hero:
   most logos are supplied in a dark-on-light version, which would disappear on
   navy. A logo that only exists as white-on-transparent will vanish here instead —
   flagged for Andy rather than solved by inventing a rule the brand guide
   does not contain.
   ------------------------------------------------------------------ */
/* The identity block: the client's mark and the client-and-dates line, paired on
   one row. Separately they were two small stacked fragments; together they are one
   object that says whose case study this is.

   Separated by SPACE, not by a rule. A 1px #EEEEEE hairline on white computes to
   1.05:1 — it is not visible, so it was decoration that decorated nothing. The
   brand palette has no line colour for this: Neutral Grey is scoped to section
   backgrounds and UI Grey to form borders, and the gold rule is already doing its
   job 150px above in the hero. Inventing a fourth would break the standing rule
   against unlisted brand values. */
.sa-client-id {
  display: flex;
  align-items: center;
  gap: clamp(16px, 3vw, 28px);
  flex-wrap: wrap;
  margin-bottom: var(--sa-space-7);
}

.sa-client-id .sa-client-logo { margin: 0; }
.sa-client-id .sa-eyebrow     { margin: 0 !important; }

.sa-client-logo { margin: 0 0 var(--sa-space-5); }

/*
   Sized by a fixed BOX, not by height alone.

   Client logos arrive at wildly different proportions — the three supplied here are
   1.00, 1.41 and 1.95. Capping only the height made the square Clubs WA mark render
   64x64 while a wordmark of the same height ran to 125px, so the square one looked
   half the size. A fixed height with object-fit lets each logo fill the box it can
   and keeps their visual weight comparable.
*/
.sa-client-logo__img {
  display: block;
  height: 96px;
  width: auto;
  max-width: 240px;
  object-fit: contain;
  object-position: left center;
}

@media (max-width: 600px) {
  .sa-client-logo__img { height: 64px; max-width: 180px; }
  .sa-client-id        { gap: var(--sa-space-3); }
}

/* An aside figure is deliberately modest — it is a footnote, not a hero. */
.sa-aside {
  max-width: 420px;
  margin-block: var(--sa-space-6);
}

/* Given a column of its own, the figure fills it — a 420px cap inside a 456px
   column leaves the picture short of the grid's right edge, which reads as a
   mistake rather than as restraint. The column width is already the restraint.
   Margins go too: the column gap is doing that job, and stray block margin
   would fight the vertical centring. */
.wp-block-column > .sa-aside {
  max-width: 100%;
  margin-block: 0;
}

.sa-aside img {
  display: block;
  width: 100%;
  height: auto;
  border-top: 3px solid var(--sa-gold);
}

.sa-aside figcaption {
  margin-top: var(--sa-space-2);
  font-size: var(--sa-size-small);
  line-height: 1.5;
  color: var(--sa-ui-grey);          /* 5.95:1 on white — meta text, in scope */
}

/* Columns stack on their own below 782px (core), but the gap wants tightening. */
@media (max-width: 781px) {
  .sa-split { gap: var(--sa-space-5); }
  .sa-split > .wp-block-column > .sa-media { max-width: 320px; }

  /* Stacked, the column is the full measure — wider than the limousine's 604px
     source, so filling it would upscale. Put the modest cap back. */
  .sa-split > .wp-block-column > .sa-aside { max-width: 420px; }
}


/* ============================================================
   17. Fluent Forms — the contact form

   The hand-built form was replaced with Fluent Forms so Andy can edit fields
   himself and connect whichever email platform he picks. Fluent ships its own
   look, so this maps the SAME values already computed for `.sa-form` above onto
   Fluent's class names. Nothing new is invented: the border, focus ring, tap
   target and error treatment are the ones already in the contrast table.

   Note Fluent emits `.ff-btn-submit { background-color: ; }` — an empty value,
   which is invalid CSS and simply drops, leaving its default blue. That is why
   the button is restyled here rather than through Fluent's own colour setting.
   ============================================================ */

.frm-fluent-form { max-width: 640px; }

.frm-fluent-form .ff-el-group { margin-bottom: var(--sa-space-4); }

.frm-fluent-form .ff-el-input--label label {
  display: block;
  margin-bottom: var(--sa-space-2);
  font-weight: 500;
  color: var(--sa-navy);                 /* 14.66:1 on white */
}

/* The required asterisk needs to be more than a red dot to a screen reader;
   Fluent already adds aria-required, so this is purely the visual cue. */
.frm-fluent-form .ff-el-is-required.asterisk-right label:after { color: var(--sa-error); }

.frm-fluent-form :is(input[type="text"], input[type="email"], input[type="tel"], select, textarea),
.frm-fluent-form .ff-el-form-control {
  width: 100%;
  min-height: var(--sa-tap);
  padding: 12px var(--sa-space-3);
  font-family: var(--sa-font);
  font-size: var(--sa-size-body);
  color: var(--sa-navy);
  background: var(--sa-white);
  border: 1px solid var(--sa-ui-grey);   /* 5.95:1 — clears the 3:1 UI threshold */
  border-radius: var(--sa-radius);
  box-shadow: none;
}

.frm-fluent-form textarea.ff-el-form-control { min-height: 8em; }

.frm-fluent-form .ff-el-form-control:focus {
  border-color: var(--sa-navy);
  outline: 3px solid var(--sa-gold);
  outline-offset: 2px;
  box-shadow: none;
}

.frm-fluent-form .ff-el-help-message {
  margin-top: var(--sa-space-2);
  font-size: var(--sa-size-small);
  color: var(--sa-ui-grey);              /* meta text — in scope for UI Grey */
}

/* Errors carry text, never colour alone — WCAG 1.4.1. Fluent already renders the
   message; the mark makes it legible without relying on the red. */
.frm-fluent-form .ff-el-is-error .ff-el-form-control { border-color: var(--sa-error); }

.frm-fluent-form .error.text-danger {
  display: flex;
  gap: var(--sa-space-2);
  margin-top: var(--sa-space-2);
  color: var(--sa-error);
  font-size: var(--sa-size-small);
  font-weight: 500;
}
.frm-fluent-form .error.text-danger::before { content: "⚠"; }

/* Submit button: the approved gold treatment. NAVY text on gold — white on gold
   is 3.16:1 and fails. Gold gets LIGHTER on hover, never darker: darkening moves
   the fill toward the navy text and collapses contrast to 3.86:1. */
.frm-fluent-form .ff-btn-submit,
.frm-fluent-form .ff-btn-submit:not(.ff_btn_no_style) {
  min-height: var(--sa-tap);
  padding: 12px var(--sa-space-5);
  font-family: var(--sa-font);
  font-size: var(--sa-size-body);
  font-weight: 600;
  color: var(--sa-navy);
  background-color: var(--sa-gold);      /* 4.64:1 with navy text — PASS */
  border: none;
  border-radius: var(--sa-radius);
  transition: background-color 0.15s ease;
}

.frm-fluent-form .ff-btn-submit:hover,
.frm-fluent-form .ff-btn-submit:focus,
.frm-fluent-form .ff-btn-submit:not(.ff_btn_no_style):hover {
  background-color: var(--sa-gold-light);
  color: var(--sa-navy);
}

.frm-fluent-form .ff-btn-submit:focus-visible {
  outline: 3px solid var(--sa-navy);
  outline-offset: 2px;
}

/* ---- Checkbox and consent -----------------------------------------------
   Fluent's structure is: .ff-el-group > (.ff-el-input--label + .ff-el-input--content
   > .ff-el-form-check > label > input + span). The first attempt styled a custom
   class on the OUTER group as a two-column grid, which cut across that structure
   and threw the field label into the middle of the page. The grid belongs on the
   inner label, which is the element that actually holds the box and the sentence.

   Grid rather than flex so a sentence wrapping to three lines hangs under itself
   instead of running back to the left margin under the checkbox.                */
.frm-fluent-form .ff-el-form-check-label {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--sa-space-3);
  align-items: start;
  margin-bottom: 0;
  font-weight: 400;                      /* it is a sentence, not a field name */
  color: var(--sa-navy);
  cursor: pointer;
}

.frm-fluent-form .ff-el-form-check-checkbox,
.frm-fluent-form input[type="checkbox"] {
  width: 22px;
  height: 22px;
  min-height: 0;                         /* the shared input rule sets 44px */
  margin: 3px 0 0;                       /* optical alignment to the first line */
  padding: 0;
  accent-color: var(--sa-navy);          /* 14.66:1 tick on white */
  flex: none;
}

.frm-fluent-form input[type="checkbox"]:focus-visible {
  outline: 3px solid var(--sa-gold);
  outline-offset: 2px;
}

/* A field whose label placement is "hidden" still renders the label, and Fluent's
   own class does not visually remove it. Take it out of the visual flow but leave
   it for assistive tech — the checkbox already carries the full sentence as its
   accessible name, so nothing is lost either way. */
.frm-fluent-form .ff-el-form-hidden > .ff-el-input--label {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* The confirmation message after submitting. */
.ff-message-success {
  padding: var(--sa-space-4);
  border-left: 3px solid var(--sa-gold);
  background: var(--sa-neutral);
  color: var(--sa-navy);                 /* 12.64:1 on #EEEEEE */
}

/* ============================================================
   18. Post meta — the date and by-line in the article hero

   Sits under the gold rule, over the 85% navy scrim, so it takes the same white
   the eyebrow and h1 take. Small and quiet: it is orientation, not content.
   ============================================================ */

.wp-block-cover.sa-media .sa-postmeta {
  gap: var(--sa-space-2);
  align-items: baseline;
  margin-top: var(--sa-space-3);
  font-size: var(--sa-size-small);
}

.wp-block-cover.sa-media .sa-postmeta :is(p, div, time, a) {
  margin: 0;
  color: var(--sa-white);                /* 14.66:1 on navy at 85% */
}

/* The author link keeps its underline — it is a link inside a line of text, and
   WCAG 1.4.1 does not exempt it for being small. */
.wp-block-cover.sa-media .sa-postmeta a { color: var(--sa-white); }

/* A post's categories become the hero eyebrow. core/post-terms renders links, and
   on the scrim they follow the eyebrow's white rather than the gold used on white. */
.wp-block-cover.sa-media .sa-eyebrow a {
  color: var(--sa-white);
  text-decoration: none;
}
.wp-block-cover.sa-media .sa-eyebrow a:hover { text-decoration: underline; }

/* ============================================================
   19. End-of-article calls to action

   Reuses .sa-card so the panel matches the cards on Insights, Our Work and the
   homepage rather than introducing a fourth treatment. Only the spacing and the
   max-width are new: these sit at the end of a column of prose, so they follow
   the reading measure rather than the wider card grid.
   ============================================================ */

/* Specificity has to match section 15, which gives every direct child of
   .entry-content the full wide column. These panels belong to the reading column
   instead, so they sit at the same measure as the prose and share its left edge. */
.entry-content > .sa-article-cta,
.entry-content > .sa-article-signup,
.sa-article-cta,
.sa-article-signup {
  margin-top: var(--sa-space-7);
  max-width: var(--sa-measure);
  margin-inline: 0 auto;              /* left edge, exactly like the paragraphs */
}

.sa-article-signup { margin-top: var(--sa-space-5); }

.sa-article-cta > :last-child,
.sa-article-signup > :last-child { margin-bottom: 0; }

/* The heading is a card heading, not a section heading — it should not compete
   with the h2s inside the article above it. */
.sa-article-cta h2,
.sa-article-signup h2 {
  font-size: var(--sa-size-h3);
  margin-top: var(--sa-space-2);
}

/* The form inside the signup panel is already styled by section 17; it only needs
   to stop being 640px wide inside a narrower card. */
.sa-article-signup .frm-fluent-form { max-width: 100%; }

/* ============================================================
   20. Comparison table

   Used on the Marketing Health Check to set the free scorecard against the paid
   audit. The rows the free column cannot answer are the argument, so they are
   styled to read as absences rather than as content.

   BORDERS ARE DECLARED IN FULL, NOT PATCHED.

   core/table ships `.wp-block-table td, th { border: 1px solid }` with NO colour,
   so every cell border falls back to currentColor — dark navy in the body, white in
   the header. Overriding only border-bottom and border-left left core owning the
   other two, which is why the verticals changed colour row by row, the gold edge
   survived only in the header, and the header cells sat a pixel smaller than the
   body. Core also adds a 3px rule under thead.

   So: reset all four on every cell, kill the thead rule, then declare only the
   lines the design actually wants. Two weights and no more — 1px for every
   horizontal separator, 3px gold for the single accent edge.

   A table is also the one element that reliably breaks a narrow layout, so per the
   site's own rule it scrolls inside its own container and never lets the page body
   scroll sideways.
   ============================================================ */

.wp-block-table.sa-compare {
  margin-block: var(--sa-space-6);
  overflow-x: auto;                      /* the table scrolls, the page never does */
  max-width: var(--wp--style--global--wide-size);
}

.wp-block-table.sa-compare table {
  width: 100%;
  min-width: 46rem;                      /* below this the columns become unreadable */
  border-collapse: collapse;
  font-size: var(--sa-size-small);
}

/* Every border is declared here, and nothing is left to core or the parent theme.
   Two weights only: 1px for horizontals, 3px gold for the single accent edge. */
.wp-block-table.sa-compare :is(th, td) { border: 0; }
.wp-block-table.sa-compare thead       { border-bottom: 0; }

.wp-block-table.sa-compare :is(th, td) {
  padding: var(--sa-space-3) var(--sa-space-4);
  text-align: left;
  vertical-align: top;
  border-bottom: 1px solid var(--sa-neutral);
}

/* The outer frame, so the table reads as one object rather than as loose rows. */
.wp-block-table.sa-compare table {
  border: 1px solid var(--sa-neutral);
}

.wp-block-table.sa-compare thead th {
  background: var(--sa-navy);
  color: var(--sa-white);                /* 14.66:1 */
  font-weight: 600;
  border-bottom: 0;
}

/* The row label column carries the area name. */
.wp-block-table.sa-compare tbody td:first-child {
  font-weight: 600;
  color: var(--sa-navy);
  white-space: nowrap;
}

/* The paid column is the one being sold. ONE gold edge, capped top and bottom so it
   reads as a panel rather than a stray line between two header cells. */
.wp-block-table.sa-compare :is(th, td):last-child {
  border-left: 3px solid var(--sa-gold);
}
.wp-block-table.sa-compare thead th:last-child {
  border-top: 3px solid var(--sa-gold);
}
.wp-block-table.sa-compare tbody tr:last-child td:last-child {
  border-bottom: 3px solid var(--sa-gold);
}

.wp-block-table.sa-compare tbody td:last-child {
  background: var(--sa-neutral);
  color: var(--sa-navy);                 /* 12.64:1 on #EEEEEE */
}

.wp-block-table.sa-compare em {
  color: var(--sa-ui-grey);              /* 5.95:1 on white */
  font-style: italic;
}

/* Close the table with the same 1px weight as every other separator, in navy so it
   reads as an end rather than as one more row division. A third border weight here
   was what made the bottom look heavier than the verticals. */
/* The final row just ends; the table's own 1px frame closes it. A heavier rule here
   was a third weight competing with the frame and the accent. */
.wp-block-table.sa-compare tbody tr:last-child :is(td) {
  border-bottom: 0;
  font-weight: 500;
}
.wp-block-table.sa-compare tbody tr:last-child td:last-child {
  border-bottom: 0;
}

/* ============================================================
   14. Profit Power-Up Calculator
   The one genuinely custom interactive widget on the site. Every colour and
   spacing step below is a token — the version this replaced used #0073aa
   (WordPress admin blue), #333 and #555, none of which are brand values.
   ============================================================ */

.sa-calc {
  border: 1px solid var(--sa-neutral);
  border-radius: var(--sa-radius);
  padding: var(--sa-space-5);
  margin-block: var(--sa-space-6);
}

.sa-calc__note {
  font-size: var(--sa-size-small);
  color: var(--sa-ui-grey);
  margin-block: 0 var(--sa-space-4);
}

/* The table is wide by nature. It scrolls inside its own box so the page body
   never scrolls sideways. */
.sa-calc__scroll {
  overflow-x: auto;
  margin-bottom: var(--sa-space-5);
}

.sa-calc table {
  width: 100%;
  min-width: 34rem;
  border-collapse: collapse;
  font-size: var(--sa-size-small);
}

.sa-calc th,
.sa-calc td {
  text-align: left;
  padding: var(--sa-space-2) var(--sa-space-3);
  border-bottom: 1px solid var(--sa-neutral);
  vertical-align: middle;
}

.sa-calc thead th {
  font-weight: 600;
  color: var(--sa-white);
  background: var(--sa-navy);
  border-bottom: 0;
}

.sa-calc tbody th {
  font-weight: 500;
  color: var(--sa-navy);
  white-space: nowrap;
}

.sa-calc input[type="number"] {
  width: 100%;
  min-width: 5.5rem;
  min-height: var(--sa-tap);
  padding: var(--sa-space-2);
  font: inherit;
  color: var(--sa-navy);
  background: var(--sa-white);
  border: 1px solid var(--sa-ui-grey);
  border-radius: var(--sa-radius);
}

.sa-calc input[type="number"]:focus-visible {
  outline: 3px solid var(--sa-gold);
  outline-offset: 2px;
}

/*
   The unit affix lives inside the field box.

   The wrapper takes over the border and the focus ring so the "$" and "%" sit within
   the same bordered box as the number they belong to, rather than floating above and
   below it on their own lines.

   :focus-within on the wrapper replaces :focus-visible on the input — the ring has to
   move with the border or keyboard focus would land on a borderless input and show
   nothing (WCAG 2.4.7). UI Grey on white is 5.95:1, inside its approved scope of form
   borders and muted text, and keeps the unit visually subordinate to the figure.
*/
.sa-calc__field {
  display: flex;
  align-items: center;
  background: var(--sa-white);
  border: 1px solid var(--sa-ui-grey);
  border-radius: var(--sa-radius);
}

.sa-calc__field:focus-within {
  outline: 3px solid var(--sa-gold);
  outline-offset: 2px;
}

.sa-calc__affix {
  flex: none;
  padding-inline: var(--sa-space-2);
  color: var(--sa-ui-grey);
  user-select: none;
}

/* The input inside the wrapper gives up its own border, radius and ring. */
.sa-calc__field input[type="number"] {
  min-width: 0;
  background: transparent;
  border: 0;
  border-radius: 0;
}

.sa-calc__field input[type="number"]:focus-visible { outline: none; }

/* A prefix owns the left padding, a suffix the right — otherwise the number sits a
   full padding step away from its own unit. */
.sa-calc__affix + input[type="number"] { padding-left: 0; }
.sa-calc__field input[type="number"]:has(+ .sa-calc__affix) { padding-right: 0; }

.sa-calc__help {
  display: block;
  font-weight: 400;
  font-size: var(--sa-size-small);
  color: var(--sa-ui-grey);
  white-space: normal;
}

.sa-calc__new {
  font-weight: 600;
  color: var(--sa-navy);
  white-space: nowrap;
}

/* Shown only when a target would push a percentage past 100. The old build
   clamped silently and displayed the clamped figure as if it were the answer. */
.sa-calc__capped {
  display: block;
  font-size: var(--sa-size-small);
  font-weight: 400;
  color: var(--sa-error);
}

/*
   `display: block` above silently beat the browser's own `[hidden] { display: none }`
   — a UA rule loses to any author declaration on a class — so the span the script
   emits with `hidden`, and unhides only when a percentage actually caps, was on
   screen permanently. Three rows carried a red "capped at 100%" against values of
   11.0% and 27.5%, which cap nothing.

   That is the 10/08 fix inverted rather than kept: the build before it capped in
   silence and showed the capped figure as the answer; this showed the warning
   whether or not it applied. A warning that is always on is not a warning.
*/
.sa-calc__capped[hidden] { display: none; }

.sa-calc__results {
  background: var(--sa-neutral);
  border-radius: var(--sa-radius);
  padding: var(--sa-space-4);
}

.sa-calc__figure {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--sa-space-2);
  padding-block: var(--sa-space-2);
  color: var(--sa-navy);
}

.sa-calc__figure + .sa-calc__figure {
  border-top: 1px solid var(--sa-white);
}

/*
 * Gold Deep, not Gold, for the rule on this panel.
 *
 * Accent Gold is 3.16:1 on white — fine — but only 2.72:1 on the Neutral Grey
 * this panel sits on, which is under the 3:1 floor for a non-text graphic. Gold
 * Deep is 4.44:1 there. This is exactly the case Gold Deep was added to the
 * palette for; measured, not eyeballed.
 */
.sa-calc__figure--total {
  font-size: var(--sa-size-body-l);
  font-weight: 600;
  border-top: 2px solid var(--sa-gold-deep) !important;
  padding-top: var(--sa-space-3);
  margin-top: var(--sa-space-2);
}

.sa-calc__insight {
  margin-top: var(--sa-space-4);
  padding-top: var(--sa-space-4);
  border-top: 1px solid var(--sa-white);
  color: var(--sa-navy);
  font-size: var(--sa-size-small);
}

.sa-calc__insight p { margin-block: 0 var(--sa-space-2); }
.sa-calc__insight p:last-child { margin-bottom: 0; }

@media (max-width: 600px) {
  .sa-calc { padding: var(--sa-space-3); }
}

/* ---- Calculator: the master control ----------------------------------
   One slider that moves all six levers at once. This is the article's whole
   argument made draggable — pull it to 10% and watch $100,000 become $177,000. */

.sa-calc__master {
  background: var(--sa-navy);
  color: var(--sa-white);
  border-radius: var(--sa-radius);
  padding: var(--sa-space-4);
  margin-bottom: var(--sa-space-5);
}

.sa-calc__master label {
  display: block;
  font-weight: 600;
  margin-bottom: var(--sa-space-2);
}

.sa-calc__master-value {
  color: var(--sa-gold);           /* 4.64:1 on navy — measured, PASS */
  font-variant-numeric: tabular-nums;
}

.sa-calc__master-row {
  display: flex;
  align-items: center;
  gap: var(--sa-space-3);
}

.sa-calc__master-row .sa-calc__scale {
  font-size: var(--sa-size-small);
  color: var(--sa-white);
  white-space: nowrap;
}

/* ---- Range inputs ---------------------------------------------------- */

.sa-calc input[type="range"] {
  flex: 1 1 auto;
  width: 100%;
  min-width: 7rem;
  min-height: var(--sa-tap);
  accent-color: var(--sa-gold);
  cursor: pointer;
  background: transparent;
}

.sa-calc input[type="range"]:focus-visible {
  outline: 3px solid var(--sa-gold);
  outline-offset: 2px;
}

.sa-calc__master input[type="range"] { accent-color: var(--sa-gold); }

.sa-calc__target {
  display: flex;
  align-items: center;
  gap: var(--sa-space-2);
  min-width: 11rem;
}

.sa-calc__target output {
  min-width: 3.5rem;
  text-align: right;
  font-weight: 600;
  color: var(--sa-navy);
  font-variant-numeric: tabular-nums;
}

/* ---- Proportional bar ------------------------------------------------- */

.sa-calc__bars {
  margin-top: var(--sa-space-4);
  padding-top: var(--sa-space-4);
  border-top: 1px solid var(--sa-white);
}

.sa-calc__bar-label {
  font-size: var(--sa-size-small);
  color: var(--sa-navy);
  margin-bottom: var(--sa-space-1);
}

.sa-calc__bar {
  height: 14px;
  background: var(--sa-white);
  border-radius: 2px;
  overflow: hidden;
  margin-bottom: var(--sa-space-3);
}

.sa-calc__bar span {
  display: block;
  height: 100%;
  width: 0;
  background: var(--sa-navy);
  transition: width 0.25s ease;
}

.sa-calc__bar--then span { background: var(--sa-gold-deep); }  /* 4.44:1 on neutral */

@media (prefers-reduced-motion: reduce) {
  .sa-calc__bar span { transition: none; }
}

/* ---- Reset ------------------------------------------------------------ */

.sa-calc__reset {
  margin-top: var(--sa-space-4);
  background: none;
  border: 2px solid var(--sa-navy);
  border-radius: var(--sa-radius);
  color: var(--sa-navy);
  font: inherit;
  font-size: var(--sa-size-small);
  font-weight: 600;
  min-height: var(--sa-tap);
  padding: var(--sa-space-2) var(--sa-space-4);
  cursor: pointer;
}

.sa-calc__reset:hover,
.sa-calc__reset:focus-visible {
  background: var(--sa-navy);
  color: var(--sa-white);
}

/*
   The service-page image sits at the TEXT measure, not the wide measure.

   These bands are core/image at align:wide, so they rendered 1203px while the body
   copy beneath them ran 984px (--sa-measure, 75ch) — about 110px proud on each side.
   Nothing else on the page reaches that far, so the photograph read as belonging to a
   different layout. Andy's call, 12/08/2026.

   The alignment rule above already gives this figure the same left edge as the
   paragraphs; this is only the width. 75ch is resolved against the figure's own font
   size, so the result is verified by measurement rather than assumed to match.
*/
.wp-block-post-content > figure.sa-media--16x9 {
  max-width: var(--sa-measure) !important;
}
