/* sections/tokens.css */
/* CMS global design tokens — the single source of truth for section sizing.
 *
 * This is layer 1 of the scoped-component model (layer 2 = per-type section.css,
 * layer 3 = inline --section-* instance overrides). It is emitted FIRST in the
 * /cms-sections.css bundle, so it loads on the live marketing shell, spawn
 * detail pages, and the editor canvas alike — change a value here and every
 * section that reads the token re-sizes everywhere at once.
 *
 * Colour tokens are NOT here — they are tenant-specific and come from the
 * DB-driven /brand.css (--mkt-color-1..30). These are the non-colour globals.
 *
 * RULE: this file may only declare :root custom properties (enforced by
 * TestTokensFileIsRootOnly). Sections consume them with a literal fallback:
 *   padding: var(--cms-space-xl, 3rem);
 * so a section still renders sanely if the bundle ever fails to load, and the
 * fallback documents the token's current value inline.
 *
 * Values below match the literals currently hard-coded across sections.css and
 * the block templates, so introducing the layer is visually neutral — nothing
 * moves until you deliberately change a token.
 */
:root {
    /* --- Spacing scale (t-shirt sizes) ------------------------------------ */
    --cms-space-3xs: 0.25rem;
    --cms-space-2xs: 0.5rem;
    --cms-space-xs: 0.75rem;
    --cms-space-sm: 1rem;
    --cms-space-md: 1.5rem;
    --cms-space-lg: 2rem;
    --cms-space-xl: 3rem;
    --cms-space-2xl: 4rem;

    /* --- Section rhythm --------------------------------------------------- */
    --cms-section-padding-y: var(--cms-space-xl);   /* .section vertical padding */
    --cms-container-max: 1200px;                    /* .container max width */
    --cms-container-pad-x: var(--cms-space-sm);     /* .container side padding */

    /* --- Corner radius ---------------------------------------------------- */
    --cms-radius-sm: 4px;
    --cms-radius-md: 8px;
    --cms-radius-lg: 12px;
    --cms-radius-pill: 999px;

    /* --- Type scale ------------------------------------------------------- */
    --cms-font-h1: 2.5rem;
    --cms-font-h2: 2rem;
    --cms-font-h3: 1.5rem;
    --cms-text-lead: 1.25rem;   /* .subtitle / intro */
    --cms-text-body: 1rem;
    --cms-text-sm: 0.9rem;
    --cms-line-body: 1.6;
    --cms-weight-bold: 700;
    --cms-weight-semibold: 600;
}

/* sections/prose.css */
/* Author prose helpers (global layer 1b).
 *
 * The one thing an author can do to a single line of typed prose that the
 * per-field alignment controls cannot: align it against the run of text
 * around it. Typed as <span class="center">…</span> in any prose field.
 *
 * span, not div or p: a prose field renders inside a <p>, and a block-level
 * element there is invalid nesting that closes the paragraph early, ending
 * the parent's alignment mid-block. A span carries display:block instead,
 * which is valid inside a <p> and lays out the same.
 *
 * text-align-last is set alongside text-align on purpose. It inherits, so a
 * one-line span inside a justified parent would otherwise take the parent's
 * text-align-last — and for a single line, the only line IS the last line,
 * so the parent's value would win and the span would not move at all.
 *
 * The class values are whitelisted in textBlockSanitizer (block_rendering.go);
 * anything outside that fixed set has its class attribute stripped.
 */
.section span.center,
.section span.left,
.section span.right {
    display: block;
}

.section span.center { text-align: center; text-align-last: center; }
.section span.left   { text-align: left;   text-align-last: left; }
.section span.right  { text-align: right;  text-align-last: right; }

/* sections/chrome.css */
/* Shared section chrome (global layer 1c).
 *
 * The disclosure-list treatment: .cms-faq / .cms-faq-item / .cms-faq-answer.
 * Since 2026-09-06 there is only ONE template rendering this markup -- the List
 * section, which faq / price_list / services_grid are all routed through -- but
 * the rules stay here rather than moving into sections/list/section.css: they
 * are the shared vocabulary the marker and frame modifiers are written against,
 * and a scoped per-type file cannot host classes another type may come to wear.
 * They are classes rather than custom properties, so tokens.css cannot host them
 * either. Hence a global layer,
 * scoped under .section exactly like prose.css, and emitted before the
 * per-type bundle so a section.css can still override it.
 *
 * Moved here from pkg/hygieneWebSite/static/css/sections.css on 2026-09-04.
 * It was host-owned, which meant the FAQ block's appearance shipped with the
 * hygiene site rather than with the CMS, while the Services accordion that
 * reuses the same classes was already a scoped component.
 *
 * Load order note: /static/css/sections.css links before /cms-sections.css on
 * all three surfaces (live shell, spawn detail, editor canvas), so these rules
 * land later in the cascade than they did before the move. Nothing depends on
 * that -- the overrides below are separated by specificity, not by file order.
 *
 * The class names still say "faq" because the markup and the per-item colour
 * custom properties (--faq-question-override / --faq-answer-override) do; a
 * rename is a bigger change than this move and would touch stored page data.
 *
 * --- The modifier vocabulary (2026-09-04) -------------------------------
 *
 * A disclosure list is BASE + optional modifiers on the .cms-faq wrapper:
 *
 *   frame     (nothing)          boxed rows: bordered, rounded, gapped
 *             .list-frame-flat   stacked rows: one rule between, no tint
 *   marker    (nothing)          rotating chevron
 *             .list-marker-plus  + / - swap
 *   height    (nothing)          auto -- the row is whatever its content makes it
 *             .list-h-small|medium|large   collapsed row only
 *
 * Alternating rows are NOT a modifier here. The base and alternate colours are
 * resolved per row by the renderer (listRowStyle / serviceStyle) and emitted
 * inline, because a section-wide colour has to be inline too and would beat any
 * nth-child rule this file could write.
 *
 * A row with nothing to expand is a <div class="cms-faq-item"> holding a
 * <div class="cms-faq-row"> instead of a <details>/<summary> pair. It is styled
 * by the same rules -- every selector that shapes a summary lists .cms-faq-row
 * beside it -- so a list mixing the two still lines up.
 *
 * The base IS the boxed/chevron look the FAQ block has always had, so a block
 * that emits no modifier renders exactly as before -- that is what makes the
 * vocabulary safe to introduce ahead of the fields that will drive it. The
 * flat/plus modifiers are the Services accordion's look, expressed once here
 * instead of as a services-only override, so either block can wear either.
 *
 * ORDER MATTERS within this file: the height rules must come last. They set
 * the summary's padding at (0,3,1), exactly the same specificity as the flat
 * frame's summary rule, so the cascade is decided by which one is written
 * later -- move them up and Small/Medium/Large silently stop working on a
 * flat list.
 */

/* --- Base: boxed rows, rotating chevron -------------------------------- */

.section .cms-faq {
    margin-top: var(--cms-space-md, 1.5rem);
}

/* --list-band is read here as well as on a flat list's summary, so the ONE
 * property stripes either frame -- see the alternating-rows block below. It is
 * unset on a boxed list unless a row carries its own colour, in which case the
 * fallback never applies. */
.section .cms-faq-item {
    border: 1px solid var(--table-border, #e0e0e0);
    border-radius: var(--cms-radius-md, 8px);
    margin-bottom: var(--cms-space-xs, 0.75rem);
    overflow: hidden;
    background: var(--list-band, var(--soft-background, #f5f5f5));
}

.section .cms-faq-item > summary,
.section .cms-faq-item > .cms-faq-row {
    padding: var(--cms-space-sm, 1rem) 1.25rem;
    cursor: pointer;
    font-weight: var(--cms-weight-semibold, 600);
    list-style: none;
    display: flex;
    justify-content: space-between;
    align-items: center;
    color: var(--faq-question-override, var(--section-heading));
}

.section .cms-faq-item > summary::-webkit-details-marker {
    display: none;
}

/* A row with nothing to expand. The block renders a <div class="cms-faq-row">
 * in place of the <summary>, and no <details> at all -- so it carries no
 * marker, cannot be opened, and is not announced as expandable. It shares every
 * rule that shapes a summary (see the selector lists above) so a mixed list
 * still lines up; only the pointer differs, because there is nothing to click.
 */
.section .cms-faq-item > .cms-faq-row {
    cursor: default;
}

/* The marker glyph is supplied HERE, not by the block's markup. The FAQ
 * template used to type a literal "\25BC" into the span, which the plus
 * modifier could not remove -- it only adds a ::before, so a boxed FAQ set to
 * Plus / minus rendered "+\25BC", both markers at once. Either block can wear
 * either marker, so the glyph belongs to the vocabulary: the span is empty in
 * every template and each marker owns its own content. */
.section .cms-faq-arrow {
    transition: transform 0.2s;
}

.section .cms-faq-arrow::before {
    content: "\25BC"; /* down chevron */
}

.section .cms-faq-item[open] .cms-faq-arrow {
    transform: rotate(180deg);
}

/* --list-expanded is the open panel's own background, set inline per item so
 * the collapsed header and the open body can carry different colours. Unset it
 * is transparent, which shows the item's background (or the section) through
 * the panel -- the behaviour every list has had. */
.section .cms-faq-answer {
    padding: var(--cms-space-sm, 1rem) 1.25rem;
    line-height: var(--cms-line-body, 1.6);
    color: var(--faq-answer-override, var(--section-text));
    background: var(--list-expanded, transparent);
}

/* --- Frame: flat ------------------------------------------------------- */

/* Rows butt together separated by a single rule, with a tinted header band and
 * no border, radius or gap. Colours are color-mix tints of the section's own
 * heading slot rather than fixed values, so the list re-tints with the block's
 * palette and the accessibility schemes -- which repaint --section-* wholesale
 * -- carry it with them.
 *
 * THE FRAME NO LONGER PAINTS A BAND (2026-09-06). It used to set --list-band to
 * 8% of the section's heading colour, which made Row Style a secret colour
 * control: choosing "Flat rows" tinted every row with a colour no field named,
 * changed or turned off. The live FAQ page ended up setting Alternate Row
 * Background to the SECTION's own colour purely to cancel it -- picking a colour
 * to mean "no colour". The tint is reproducible honestly as Every Row →
 * Background + Transparency, so the frame is now shape alone: rules, gaps,
 * corners, padding.
 *
 * --list-band survives as the carrier a ROW paints itself with. It is declared
 * nowhere and read on the summary, so an unset value computes to transparent;
 * a per-row or section-wide Background is emitted inline on the <details> by
 * listRowStyle and inherits down to its header, which is the hand-off that stops
 * a band tint painting over the colour the author picked.
 */
.section .cms-faq.list-frame-flat {
    --list-rule: color-mix(in srgb, var(--section-heading, #333) 35%, transparent);
}

.section .list-frame-flat .cms-faq-item {
    border: 0;
    border-top: 1px solid var(--list-rule);
    border-radius: 0;
    margin: 0;
    background: transparent;
}

.section .list-frame-flat .cms-faq-item:last-child {
    border-bottom: 1px solid var(--list-rule);
}

.section .list-frame-flat .cms-faq-item > summary,
.section .list-frame-flat .cms-faq-item > .cms-faq-row {
    padding: var(--cms-space-md, 1.5rem) var(--cms-space-sm, 1rem);
    background: var(--list-band);
    font-size: var(--cms-text-lead, 1.25rem);
}

.section .list-frame-flat .cms-faq-answer {
    padding: var(--cms-space-md, 1.5rem) var(--cms-space-sm, 1rem);
}

/* --- Marker: plus/minus ------------------------------------------------ */

/* A glyph swap rather than a rotation, so the chevron's transform is turned
 * off as well -- left on, the "-" would spin on open. */
.section .list-marker-plus .cms-faq-arrow::before {
    content: "+";
    font-size: var(--cms-font-h3, 1.5rem);
    line-height: 1;
}

.section .list-marker-plus .cms-faq-item[open] .cms-faq-arrow::before {
    content: "\2212"; /* minus sign */
}

.section .list-marker-plus .cms-faq-item[open] .cms-faq-arrow {
    transform: none;
}

/* --- Height: the collapsed row ----------------------------------------- */

/* Applies to the summary only, so an open body is never padded out to match a
 * tall collapsed row. Auto is the absence of these classes: no rule, the row is
 * whatever its padding and one line of text make it.
 *
 * Each step sets vertical padding AS WELL AS a floor, because a min-height
 * alone cannot shrink a row below the padding it already carries -- set only
 * min-height and Small appears to do nothing. The summary is a flex row with
 * align-items:center, so the label and the marker stay centred at every height.
 *
 * These must stay the last rules in the file -- see the header note.
 */

.section .list-h-small .cms-faq-item > summary,
.section .list-h-small .cms-faq-item > .cms-faq-row {
    padding-top: var(--cms-space-2xs, 0.5rem);
    padding-bottom: var(--cms-space-2xs, 0.5rem);
    min-height: 40px;
}

.section .list-h-medium .cms-faq-item > summary,
.section .list-h-medium .cms-faq-item > .cms-faq-row {
    padding-top: var(--cms-space-sm, 1rem);
    padding-bottom: var(--cms-space-sm, 1rem);
    min-height: 64px;
}

.section .list-h-large .cms-faq-item > summary,
.section .list-h-large .cms-faq-item > .cms-faq-row {
    padding-top: var(--cms-space-lg, 2rem);
    padding-bottom: var(--cms-space-lg, 2rem);
    min-height: 104px;
}

/* sections/cards/section.css */
/* Section: cards — scoped component styles.
 *
 * Every selector in this file must live under [data-section-type="cards"];
 * cross-section styling is forbidden (enforced by TestSectionCSSScoped).
 *
 * Scope note: only the in-flow card picture (Picture Position = Above / Below /
 * Left / Right) lives here. The card's own chrome — surface, border, radius,
 * padding, the .card-grid layout and the fixed cards-per-line maths — is still
 * in the host sections.css, which is why the rules below read --card-pad and
 * --card-radius from it rather than restating either value.
 *
 * Nothing here matches a card that has no picture placement: the renderer only
 * emits .card--img / .card--img-<pos> when a picture is actually placed, so a
 * card using the original background picture (or none at all) renders exactly
 * as it did before this file existed.
 */

[data-section-type="cards"] .card--img {
    display: flex;
}

[data-section-type="cards"] .card--img-above { flex-direction: column; }
[data-section-type="cards"] .card--img-below { flex-direction: column-reverse; }
[data-section-type="cards"] .card--img-left { flex-direction: row; }
[data-section-type="cards"] .card--img-right { flex-direction: row-reverse; }

/* The content column must be allowed to shrink: a flex item's default
   min-width:auto would let a long unbroken word push the picture out of the
   card in the side-by-side placements. */
[data-section-type="cards"] .card--img > .card-content {
    flex: 1 1 auto;
    min-width: 0;
}

/* The picture is pulled back out through the card's own padding and then held
   off the edge by --card-img-inset, so a hairline of card surface frames it.
   Deliberately an inset rather than a full bleed: a bleed would need
   overflow:hidden on .card — a property change landing on every card in the
   system — and rounded-corner clipping is where browsers leave an antialiasing
   seam. The inset sidesteps both. --card-pad is declared alongside the padding
   it mirrors in the host sections.css; the literal fallback keeps this correct
   if the bundle loads without it. */
[data-section-type="cards"] .card--img > .card-image {
    margin: calc(var(--card-img-inset, 2px) - var(--card-pad, 1.5rem));
    overflow: hidden;
    /* Concentric with the card: an 8px card inset by 2px wants ~6px. Follows
       --card-radius down to 0 so the Square Corners toggle still governs the
       picture; max() stops a large inset producing a negative radius. */
    border-radius: max(0px, calc(var(--card-radius, 8px) - var(--card-img-inset, 2px)));
}

/* Only the edge facing the text becomes a real gap; the other three keep the
   hairline inset above. */
[data-section-type="cards"] .card--img-above > .card-image { margin-bottom: var(--cms-space-sm, 1rem); }
[data-section-type="cards"] .card--img-below > .card-image { margin-top: var(--cms-space-sm, 1rem); }
[data-section-type="cards"] .card--img-left > .card-image { margin-right: var(--cms-space-md, 1.5rem); }
[data-section-type="cards"] .card--img-right > .card-image { margin-left: var(--cms-space-md, 1.5rem); }

/* <picture> is inline and auto-height by default, so height:100% on the img
   would resolve against nothing — the same trap split_content hit. */
[data-section-type="cards"] .card--img > .card-image picture {
    display: block;
    width: 100%;
    height: 100%;
}

[data-section-type="cards"] .card--img > .card-image img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* Above/Below: a fixed aspect ratio is what makes a row of cards line up no
   matter what shape the uploaded photos are — the whole point of putting the
   picture inside the card rather than in a picture section above it. */
[data-section-type="cards"] .card--img-above > .card-image,
[data-section-type="cards"] .card--img-below > .card-image {
    aspect-ratio: 4 / 3;
}

/* Left/Right: the picture takes a share of the width and stretches to the
   card's height instead, so cards in the row still finish level. */
[data-section-type="cards"] .card--img-left > .card-image,
[data-section-type="cards"] .card--img-right > .card-image {
    flex: 0 0 40%;
    align-self: stretch;
}

/* Side-by-side needs width to work in. The card grid is already 1-up here, so
   stacking the picture above the text is the only sane reading of Left/Right
   on a phone. */
@media (max-width: 768px) {
    [data-section-type="cards"] .card--img-left,
    [data-section-type="cards"] .card--img-right {
        flex-direction: column;
    }

    [data-section-type="cards"] .card--img-left > .card-image,
    [data-section-type="cards"] .card--img-right > .card-image {
        flex-basis: auto;
        aspect-ratio: 4 / 3;
        margin-right: calc(var(--card-img-inset, 2px) - var(--card-pad, 1.5rem));
        margin-left: calc(var(--card-img-inset, 2px) - var(--card-pad, 1.5rem));
        margin-bottom: var(--cms-space-sm, 1rem);
    }
}
/* sections/list/section.css */
/* Section: list (List) — scoped component styles.
 *
 * Every selector in this file must live under [data-section-type="list"];
 * cross-section styling is forbidden (enforced by TestSectionCSSScoped).
 *
 * The List renders the shared disclosure-list chrome from sections/chrome.css
 * and adds three things of its own:
 *
 *   1. The row's own label span.
 *
 *   2. The spacing of a list typed into a row body -- what the Services
 *      accordion gave its "what's included" lines.
 *
 * The flat frame's band used to be overridden here. It is gone from
 * sections/chrome.css itself now (2026-09-06), so there is nothing left to
 * override: a row is painted only by Every Row / Alternate Rows / This Row Only.
 *
 * The cards layout needs no colour mapping either. listRowStyle emits the card
 * carriers (--card-heading-override / --card-text-override) alongside the list
 * ones, because it serves both layouts since serviceStyle was folded into it.
 */

/* 1. The row: label left, marker hard right.
 *
 * The summary is already a flex space-between from chrome.css, so the label
 * taking the free space is what keeps the marker pinned to the right edge
 * whatever the label's length. A price, where a row has one, is words inside
 * the label like any other -- there is no price field.
 */
[data-section-type="list"] .cms-list-label {
    flex: 1 1 auto;
}

/* An author's "what's included" lines are typed straight into the body as a
 * list. The extra breathing room is what the Services accordion gives them.
 */
[data-section-type="list"] .cms-faq-answer ul {
    list-style: none;
    margin: 0;
    padding: 0;
}

[data-section-type="list"] .cms-faq-answer ul li {
    margin-bottom: var(--cms-space-2xs, 0.5rem);
}
/* sections/picture/section.css */
/* Section: picture — scoped component styles.
 *
 * Every selector in this file must live under [data-section-type="picture"];
 * cross-section styling is forbidden (enforced by TestSectionCSSScoped).
 *
 * Scope note: only the grid layout has been lifted so far. The picture template
 * still carries ~25 inline style attributes across its three layout branches
 * (single-standard centred, single side-by-side, multi-image grid) — converting
 * those is the rest of the picture conversion, tracked in
 * FINDINGS_scoped_component_conversion_2026-07-12.md §3.
 *
 * The grid was an unscoped <style> block emitted once per picture instance,
 * declaring a global `.cms-picture-grid` rule mid-page. It needed `!important`
 * to beat the inline `grid-template-columns` the template wrote on the same
 * element; now the column count and gap arrive as the instance custom
 * properties --pic-cols / --pic-gap and the component owns the layout, so the
 * mobile override wins on source order alone.
 */

[data-section-type="picture"] .cms-picture-grid { display: grid; grid-template-columns: var(--pic-cols, 1fr); gap: var(--pic-gap, var(--cms-space-md, 1.5rem)); }

@media (max-width: 768px) {
    [data-section-type="picture"] .cms-picture-grid { grid-template-columns: 1fr; }
}
/* sections/split_content/section.css */
/* Section: split_content — scoped component styles.
 *
 * Every selector in this file must live under [data-section-type="split_content"];
 * cross-section styling is forbidden (enforced by TestSectionCSSScoped). These
 * rules were previously emitted as an UNSCOPED <style> block inside the block
 * template, duplicated once per instance — see FINDINGS_scoped_component_
 * conversion_2026-07-12.md §4. They now ship once per page in /cms-sections.css.
 */

/* z-index 2 matches what the host stylesheet gives `.section-media > .container`.
 * Split Content is the only section component whose top-level child is NOT a
 * .container (its 50/50 grid is full-bleed by design), so that host rule never
 * reached it: setting a Background Type of Image/Video on a split section put
 * the absolutely-positioned .media-bg over the whole grid and the image column,
 * text and buttons all vanished underneath it. */
[data-section-type="split_content"] .split-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0; align-items: stretch; position: relative; z-index: 2; }
[data-section-type="split_content"] .split-grid--right .split-image { order: 2; }
[data-section-type="split_content"] .split-grid--right .split-body { order: 1; }
/* The image column must fit inside the row, never grow it and never crop it.
 * The <img> is wrapped in a <picture>, so `height: 100%` on the img resolves
 * against that wrapper — inline and auto-height by default, which made the img
 * fall back to its natural height and spill out of a fixed-height section.
 * Making .split-image a grid container stretches the picture to the row height,
 * giving the img a definite box to fit into. `object-fit: contain` scales the
 * whole image down to that box: a fixed section height must never cut anything
 * off the picture, so a mismatched aspect ratio letterboxes (the section
 * background shows through) rather than cropping. In Auto mode nothing has a
 * definite height, so the img keeps its natural size and sets the row height
 * exactly as before.
 *
 * Letterboxing is the safe default, not always the wanted one: two sections set
 * to the same height look like different heights when their pictures have
 * different aspect ratios, which is the single most common "why does that one
 * look wrong" report from authors. The Crop Image to Fit toggle opts a section
 * out -- see .split-image-fill below. */
[data-section-type="split_content"] .split-image { display: grid; overflow: hidden; }
[data-section-type="split_content"] .split-image picture { display: block; height: 100%; min-height: 0; }
[data-section-type="split_content"] .split-image img { width: 100%; height: 100%; object-fit: contain; display: block; }
[data-section-type="split_content"] .split-body { padding: var(--cms-space-xl, 3rem); display: flex; flex-direction: column; justify-content: center; overflow: auto; }

/* Don't manufacture overflow. The body scrolls only when the text genuinely
 * does not fit, so every wasted pixel inside it is a scrollbar the author did
 * not earn: a trailing <ul>/<p> margin adds 16px of dead space below the last
 * line, and 3rem top+bottom padding is 96px of a 300px Small section. Trimming
 * the trailing margin and tightening the vertical padding on fixed-height
 * sections is the difference between a scrollbar and a comfortable fit for
 * ordinary heading + paragraph + short-list content. Auto sections keep the
 * full 3rem — they have no ceiling to run out of. */
/* Content Colour has to be set on the body, not left to inherit. The host
 * stylesheet colours headings (--section-heading) and <ul>/<ol>
 * (--section-text) by element, but the Content field renders as a bare
 * <div class="split-text"> — no rule matched it, so it inherited the global
 * body text colour and quietly ignored the section's Content Colour. Setting it
 * here also covers any loose markup the author types into the field. */
[data-section-type="split_content"] .split-body { color: var(--section-text); }
[data-section-type="split_content"] .split-body > :first-child { margin-top: 0; }
[data-section-type="split_content"] .split-body > :last-child { margin-bottom: 0; }
[data-section-type="split_content"] .split-h-small .split-body,
[data-section-type="split_content"] .split-h-medium .split-body,
[data-section-type="split_content"] .split-h-large .split-body,
[data-section-type="split_content"] .split-h-xlarge .split-body { padding-top: var(--cms-space-lg, 2rem); padding-bottom: var(--cms-space-lg, 2rem); }
/* With a fixed section height the body can overflow. `safe center` keeps the
 * start of the content reachable when it does (plain `center` in a scroll
 * container puts the first line above the scrollable area). Browsers without
 * `safe` drop the declaration and fall back to the line above. */
[data-section-type="split_content"] .split-body { justify-content: safe center; }
[data-section-type="split_content"] .split-list { margin: var(--cms-space-sm, 1rem) 0; padding-left: var(--cms-space-md, 1.5rem); }
[data-section-type="split_content"] .split-list li { margin-bottom: var(--cms-space-2xs, 0.5rem); }

/* Fixed section heights (split_height field). Auto is the default: no rule, the
 * grid takes its height from the body content. These are real heights, not
 * floors: several split_content sections set to the same size must line up
 * regardless of how much text each one carries, so content does NOT grow the
 * section — long text scrolls inside .split-body instead. `min-height: 0`
 * stops the grid items from forcing the track taller. */
[data-section-type="split_content"] .split-grid.split-h-small { height: 300px; min-height: 0; }
[data-section-type="split_content"] .split-grid.split-h-medium { height: 450px; min-height: 0; }
[data-section-type="split_content"] .split-grid.split-h-large { height: 650px; min-height: 0; }
[data-section-type="split_content"] .split-grid.split-h-xlarge { height: 850px; min-height: 0; }

/* Crop Image to Fit (image_fill toggle). Swaps the letterbox fit for a centre
 * crop so the picture fills the image column edge to edge, making every section
 * of a given height frame identically whatever was uploaded. Scoped to the
 * fixed-height classes on purpose: Auto height has no class for these selectors
 * to match, so the toggle is structurally inert there rather than inert by
 * promise. The <=768px block below drops the fixed heights, at which point the
 * img has no definite box, keeps its natural aspect and there is nothing to
 * crop -- stacked layouts need no special case. Cropping is centred, so a
 * picture whose subject sits near an edge can lose it; that is the trade the
 * author accepts by switching the toggle on. */
[data-section-type="split_content"].split-image-fill .split-h-small .split-image img,
[data-section-type="split_content"].split-image-fill .split-h-medium .split-image img,
[data-section-type="split_content"].split-image-fill .split-h-large .split-image img,
[data-section-type="split_content"].split-image-fill .split-h-xlarge .split-image img { object-fit: cover; }

/* Empty-image placeholder shown in the editor canvas before an image is picked.
 * Was an inline style attribute on the div; same values, now part of the component. */
[data-section-type="split_content"] .split-image-placeholder { background: var(--soft-background, #f0f0f0); height: 100%; min-height: 300px; display: flex; align-items: center; justify-content: center; color: var(--secondary-text, #999); }

@media (max-width: 768px) {
    [data-section-type="split_content"] .split-grid { grid-template-columns: 1fr; }
    [data-section-type="split_content"] .split-grid--right .split-image { order: 0; }
    /* Stacked: a fixed grid height would stretch the image to the full figure,
       so heights fall back to auto on narrow screens. */
    [data-section-type="split_content"] .split-grid.split-h-small,
    [data-section-type="split_content"] .split-grid.split-h-medium,
    [data-section-type="split_content"] .split-grid.split-h-large,
    [data-section-type="split_content"] .split-grid.split-h-xlarge { height: auto; min-height: 0; }
    /* No fixed height to overflow once stacked. */
    [data-section-type="split_content"] .split-body { overflow: visible; }
}

/* Full-bleed image (full_bleed toggle). Every .section carries vertical padding
 * from the global rhythm (3rem, 4rem at >=1200px), so the picture is always
 * framed by a band of section background top and bottom no matter what height
 * or aspect ratio it has. This drops that padding on the section itself — the
 * image then touches the top and bottom edges and neighbouring sections butt
 * straight up against each other. .split-body keeps its own padding, so the
 * text is still inset. Specificity (0,2,0) beats the .section (0,1,0) rule in
 * the >=1200px media block; media queries add none of their own. */
[data-section-type="split_content"].split-full-bleed { padding-top: 0; padding-bottom: 0; }

/* Full-width (span) modes — image_position "span-left" / "span-right".
 * The picture stops being a column and becomes the section's own backdrop:
 * .split-image goes out of flow and covers the whole section, padding included,
 * so it runs edge to edge whatever the section rhythm is. The text becomes a
 * panel floating over one side, which is the only place in this component where
 * the image is CROPPED (object-fit: cover) rather than fitted — a backdrop with
 * letterbox bars would defeat the point. The section's vertical padding is what
 * keeps the panel off the top and bottom edges, so Full-Bleed Image tightens
 * this layout rather than changing what the picture does. Auto height works:
 * with the image out of flow the row height comes from the panel. */
[data-section-type="split_content"].split-span { position: relative; overflow: hidden; }
[data-section-type="split_content"].split-span .split-image { position: absolute; inset: 0; z-index: 0; }
[data-section-type="split_content"].split-span .split-image img { width: 100%; height: 100%; object-fit: cover; }
[data-section-type="split_content"].split-span .split-image-placeholder { height: 100%; min-height: 0; }
/* Span mode puts the grid back to static so .split-image's `inset: 0` resolves
 * against the SECTION (covering its padding bands, edge to edge) instead of the
 * grid's padded box. Nothing is buried by that: the backdrop sits at z-index 0
 * and the panel below lifts itself to 1. */
[data-section-type="split_content"].split-span .split-grid { display: flex; align-items: center; position: static; z-index: auto; padding: 0 var(--cms-space-xl, 3rem); }
/* Panel colour defaults to the section background; the Text Panel Transparency
 * slider replaces it with a color-mix via the inline --split-panel-bg. */
/* The panel must be positioned too. An absolutely-positioned element paints
 * above in-flow block descendants of the same stacking context even at z-index
 * 0, so a static .split-body ends up UNDER the backdrop and disappears. */
[data-section-type="split_content"].split-span .split-body { position: relative; z-index: 1; width: min(46%, 620px); background: var(--split-panel-bg, var(--section-bg)); overflow: visible; }
[data-section-type="split_content"].split-span--right .split-body { margin-left: auto; }

@media (max-width: 768px) {
    /* Stacked: the panel spans the width and the picture stays behind it. */
    [data-section-type="split_content"].split-span .split-grid { padding: 0 var(--cms-space-sm, 1rem); }
    [data-section-type="split_content"].split-span .split-body { width: 100%; }
}

/* sections/testimonial_carousel/section.css */
/* Section: testimonial_carousel — scoped component styles.
 *
 * Every selector in this file must live under
 * [data-section-type="testimonial_carousel"]; cross-section styling is
 * forbidden (enforced by TestSectionCSSScoped).
 *
 * Lifted verbatim from 11 inline style attributes in the block template. The
 * one behavioural change is that the visible slide and the current dot are now
 * the `is-active` class rather than inline `display` / `background`, so
 * section.js toggles a class instead of writing style attributes.
 */

[data-section-type="testimonial_carousel"] .cms-testimonial-heading { text-align: center; }

[data-section-type="testimonial_carousel"] .cms-testimonial-carousel { position: relative; max-width: 800px; margin: var(--cms-space-lg, 2rem) auto; overflow: hidden; }

[data-section-type="testimonial_carousel"] .cms-testimonial-slide { display: none; text-align: center; padding: var(--cms-space-lg, 2rem); }
[data-section-type="testimonial_carousel"] .cms-testimonial-slide.is-active { display: block; }

[data-section-type="testimonial_carousel"] .cms-testimonial-slide blockquote { font-size: var(--cms-text-lead, 1.25rem); font-style: italic; line-height: var(--cms-line-body, 1.6); margin: 0 0 var(--cms-space-md, 1.5rem) 0; color: var(--body-text, #333); }

[data-section-type="testimonial_carousel"] .cms-testimonial-author { font-weight: var(--cms-weight-semibold, 600); color: var(--button-background-color, #7a9579); }

[data-section-type="testimonial_carousel"] .cms-testimonial-source { font-size: var(--cms-text-sm, 0.9rem); color: var(--secondary-text, #666); margin-top: var(--cms-space-3xs, 0.25rem); }

[data-section-type="testimonial_carousel"] .cms-carousel-prev,
[data-section-type="testimonial_carousel"] .cms-carousel-next { position: absolute; top: 50%; transform: translateY(-50%); background: var(--button-background-color, #7a9579); color: white; border: none; width: 40px; height: 40px; border-radius: 50%; cursor: pointer; font-size: var(--cms-text-lead, 1.25rem); }
[data-section-type="testimonial_carousel"] .cms-carousel-prev { left: 0; }
[data-section-type="testimonial_carousel"] .cms-carousel-next { right: 0; }

[data-section-type="testimonial_carousel"] .cms-carousel-dots { display: flex; justify-content: center; gap: var(--cms-space-2xs, 0.5rem); margin-top: var(--cms-space-sm, 1rem); }

/* The dots are <button>s, not <span>s (2026-08-22): they were click-only, so a
   keyboard user could step through with prev/next but never jump to a given
   testimonial. Padding/border are zeroed so the element stays the same 10px
   circle it has always been. */
[data-section-type="testimonial_carousel"] .cms-carousel-dot { width: 10px; height: 10px; padding: 0; border: none; border-radius: 50%; background: #ccc; cursor: pointer; }
[data-section-type="testimonial_carousel"] .cms-carousel-dot.is-active { background: var(--button-background-color, #7a9579); }
[data-section-type="testimonial_carousel"] .cms-carousel-dot:focus-visible { outline: 3px solid currentColor; outline-offset: 2px; }
[data-section-type="testimonial_carousel"] .cms-carousel-prev:focus-visible,
[data-section-type="testimonial_carousel"] .cms-carousel-next:focus-visible { outline: 3px solid currentColor; outline-offset: 2px; }
/* sections/text/section.css */
/* Section: text — scoped component styles.
 *
 * Every selector in this file must live under [data-section-type="text"];
 * cross-section styling is forbidden (enforced by TestSectionCSSScoped).
 * The text section currently needs no rules beyond the shared .section
 * foundation in sections.css — .cms-text-content is an unstyled hook. Add
 * text-specific rules here, never to the per-host sections.css copies.
 */
/* sections/video/section.css */
/* Section: video — scoped component styles.
 *
 * Every selector in this file must live under [data-section-type="video"];
 * cross-section styling is forbidden (enforced by TestSectionCSSScoped).
 *
 * The video block had no per-instance <style> block — it carried 18 inline
 * style attributes instead, which is the same problem wearing different
 * clothes: layout constants duplicated into every rendered instance, invisible
 * to any stylesheet, and unreachable from an accessibility scheme. All of them
 * are here now except the two sanctioned carriers (the section tag's
 * sectionStyle, and the two instance custom properties below).
 *
 * Instance variation, per the scoped-component model:
 *   --vid-max-w  the size field's max width (small/medium/large/full)
 *   --vid-basis  the side-by-side column's flex-basis for that same size
 *
 * The centred and side-by-side branches keep their own margins deliberately —
 * they were 1rem and 0.5rem respectively before the conversion, and this is a
 * lift, not a redesign.
 */

[data-section-type="video"] .cms-video-centre { text-align: center; }
[data-section-type="video"] .cms-video-centre .video-container { max-width: var(--vid-max-w, 600px); margin: 0 auto; }
[data-section-type="video"] .cms-video-centre .cms-video-more { margin-top: var(--cms-space-sm, 1rem); }
[data-section-type="video"] .video-description { margin-top: var(--cms-space-sm, 1rem); }

[data-section-type="video"] .video-container video { width: 100%; border-radius: var(--cms-radius-md, 8px); }

[data-section-type="video"] .cms-video-split { display: flex; gap: var(--cms-space-lg, 2rem); align-items: flex-start; flex-wrap: wrap; }
[data-section-type="video"] .cms-video-side { flex: 1 1 var(--vid-basis, 400px); max-width: var(--vid-max-w, 600px); }
[data-section-type="video"] .cms-video-side .cms-video-more { margin-top: var(--cms-space-2xs, 0.5rem); }
[data-section-type="video"] .cms-video-description { flex: 1 1 250px; }
[data-section-type="video"] .cms-video-description p { margin: 0; line-height: var(--cms-line-body, 1.6); }
