@charset "UTF-8";
/* Roboto — the family every token in variables.scss already names
   (--brand-font-body, and the hero's pinned family). It was never actually
   loaded: no @font-face and no font <link> anywhere, so the whole template was
   relying on Roboto happening to be installed on the viewer's machine. Where it
   is not — a stock Mac, most Windows installs — everything silently fell back to
   the generic sans, about 12% wider at 46px, which changed the hero's line
   breaks and pushed copy into the three-line clamp.

   Must stay the FIRST rule in the compiled sheet: a CSS @import is only valid
   before any other rule, and 'base/reset' is first in the publish-generated
   main.scss import list. Weights 400 and 700 are what the brief specifies
   ("Roboto Regular/Bold"). 300 is kept because the older
   css/fonts/roboto.css loaded it for body copy.

   Self-hosting would be faster and avoids the Google Fonts privacy question for
   EU visitors — worth doing before real tenants, but this keeps the existing
   product precedent (chris/simon load Roboto the same way). */
@import url("https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;700&display=swap");
/* http://meyerweb.com/eric/tools/css/reset/
   v2.0 | 20110126
   License: none (public domain)
*/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
  margin: 0;
  padding: 0;
  border: 0;
  font-size: 100%;
  vertical-align: baseline;
}

/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
  display: block;
}

body {
  line-height: 1;
}

ol, ul {
  list-style: none;
}

blockquote, q {
  quotes: none;
}

blockquote:before, blockquote:after,
q:before, q:after {
  content: "";
  content: none;
}

table {
  border-collapse: collapse;
  border-spacing: 0;
}

/* Modern additions */
*, *::before, *::after {
  box-sizing: border-box;
}

input, button, textarea, select {
  font: inherit;
}

img, picture, video, canvas, svg {
  display: block;
  max-width: 100%;
}

a {
  text-decoration: none;
  color: var(--link-color);
}

a:hover {
  color: var(--link-hover-color);
}

:root {
  /* ============================================================
     TIER 0 — BRAND TOKENS
     ============================================================
     Start here. These ~15 variables define the overall look of
     your site. All component variables further down inherit from
     these. Changing a brand token cascades through the entire
     design automatically.

     NOTE (AI design assistant): to let the AI assistant set one of these tokens,
     it must ALSO be added to DesignAssistantService.ALLOWED_TOKENS + SYSTEM_PROMPT
     (Java) and AiDesignDrawer.tsx BASELINE_TOKENS (React). See
     docs/ai/ai-design-assistant-handoff.md -> "EXECUTION CONSTRAINT".
     ============================================================ */
  /* --- Brand Colours ---
     --brand-primary  : Main background colour for the header and footer.
                        Change this one value to set the signature colour
                        for the top and bottom of every page.
     --brand-accent   : Used for hover states and active navigation links.
                        Choose a colour that stands out against brand-primary.
     --brand-text     : All body text, footer links, and navigation links.
     --brand-heading  : Heading colour across all sections. Defaults to
                        brand-text so headings and body stay in harmony.
     --brand-surface  : Background for dropdown menus. Defaults to white.
     --brand-border   : The subtle dividing lines between sections.
                        The header has its own --header-border-bottom override
                        because it uses a stronger solid line by default. */
  --brand-primary: rgba(255,255,255, 0.8);
  --brand-accent: var(--brand-text);
  --brand-text: rgb(0, 0, 0);
  --brand-heading: var(--brand-text);
  --brand-surface: white;
  --brand-border: rgba(0, 0, 0, 0.25);
  /* --- Links ---
     Colour of inline body and article links (navigation and footer links
     have their own controls further down). Defaults to brand-text so links
     match body copy until you choose to set them apart; hover defaults to
     brand-accent, consistent with the rest of the site's hover colour. */
  --link-color: var(--brand-text);
  --link-hover-color: var(--brand-accent);
  /* --- Typography ---
     Font families are selected in the Designer panel. The CMS loads
     the font files automatically — just set the name here.
     --brand-font-body    : Font used for all body text, navigation, and footers.
     --brand-font-heading : Font used for section headings and article titles.
                            Defaults to the body font. Set a different typeface
                            here to create a heading/body contrast. */
  --brand-font-body: "Roboto", sans-serif;
  --brand-font-heading: var(--brand-font-body);
  /* --- Spacing Scale ---
     Controls the overall density and rhythm of the layout.
     The Designer panel offers Compact / Default / Spacious presets that
     override all four values at once. You can also set them individually.

     Default values (1rem = 10px):
       --space-xs : 2rem  — icon gaps, tight inner padding
       --space-sm : 3rem  — component padding, column gaps
       --space-md : 5rem  — main rhythm unit: section spacing, article gaps
       --space-lg : 8rem  — large structural spacing (reserved for future use) */
  --space-xs: 2rem;
  --space-sm: 3rem;
  --space-md: 5rem;
  --space-lg: 8rem;
  /* --- Shape ---
     --brand-border-radius : Corner radius applied to dropdowns and interactive
                             elements. 0 = sharp corners, 4px = subtle softness,
                             12px = fully rounded. */
  --brand-border-radius: 0;
  /* ============================================================
     TIER 1 — COMPONENT VARIABLES
     ============================================================
     These control individual sections and components. By default
     they inherit from the Tier 0 brand tokens above. You can
     override any individual variable here for fine-tuned control
     without affecting the rest of the site.
     ============================================================ */
  /* --- Drop Shadows ---
     One ramp, two orientations. The shadow starts at --shadow-color flush
     against the panel edge (immediately below the black rule where one exists)
     and eases to zero at --shadow-depth.

     The ramp lives in --shadow-stops as a bare stop list so both orientations
     share one curve and cannot drift apart. (Until 2026-08-24 a third consumer
     read it: a radial corner where the dropdown's bottom and right fades met.
     The panel now runs to the bottom of the viewport, so it has no lower edge
     and no corner — see header.md.)

     The falloff is EASED, not linear (2026-08-24, designer asked for a more
     gradual fade). Two things were wrong with the 5px linear ramp: it was
     simply too tight, and a linear ramp meets zero with a derivative kink that
     the eye reads as a faint terminating edge — the exact artefact the fade
     exists to avoid, and it grows *more* obvious as the ramp lengthens. These
     stops fall fast and then flatten, so the tail reaches zero with almost no
     slope.

     Alphas are fractions of --shadow-color via color-mix, not hardcoded rgba,
     so that one token still sets strength and hue for the whole system.
     color-mix against `transparent` interpolates premultiplied, so the stops
     stay pure black and only alpha moves. Dart-sass does not parse custom
     property values at all, so this passes through the compile verbatim.

     These are gradients, not box-shadows, on purpose: a box-shadow's blur is
     Gaussian, so it never actually reads full strength at the edge, it bleeds
     back over the rule, and it wraps the corners. Consumers must give the
     pseudo-element `pointer-events: none` — these bands sit above page content,
     and at 12px they overlap appreciably more of it than at 5px. */
  --shadow-depth: 1.2rem;
  --shadow-color: rgba(0, 0, 0, 0.25);
  --shadow-stops: var(--shadow-color) 0%,
                           color-mix(in srgb, var(--shadow-color) 72%, transparent) 16.7%,
                           color-mix(in srgb, var(--shadow-color) 50%, transparent) 33.3%,
                           color-mix(in srgb, var(--shadow-color) 32%, transparent) 50%,
                           color-mix(in srgb, var(--shadow-color) 18%, transparent) 66.7%,
                           color-mix(in srgb, var(--shadow-color) 8%, transparent) 83.3%,
                           color-mix(in srgb, var(--shadow-color) 3%, transparent) 91.7%,
                           rgba(0, 0, 0, 0) 100%;
  --shadow-fade-down: linear-gradient(to bottom, var(--shadow-stops));
  --shadow-fade-right: linear-gradient(to right, var(--shadow-stops));
  /* --- Global Text & Layout ---
     Base font and colour settings used throughout. --color is the
     root text colour — it inherits from --brand-text. --font-family
     inherits from --brand-font-body. */
  --content-width: 140rem;
  --primary-color: var(--brand-primary);
  --text-color: var(--brand-text);
  --bold: 700;
  --font-family: var(--brand-font-body);
  --font-size: 1.6rem;
  --line-height: 2.4rem;
  --color: var(--brand-text);
  --headline-font-size: clamp(2rem, 4vw, 3.6rem);
  --headline-line-height: clamp(2.4rem, 4vw, 4.2rem);
  --teaser-font-size: var(--font-size);
  --teaser-line-height: var(--line-height);
  --image-overlay-text-color: white;
  /* --- Sections ---
     Spacing below each section and the divider line between them.
     Both spacing values inherit from --space-md, so adjusting the
     spacing scale preset updates all section rhythm at once. */
  --section-padding-top: var(--space-md);
  --section-padding-bottom: var(--space-md);
  --section-border-bottom: 1px solid var(--brand-border);
  --section-heading-margin-bottom: var(--space-md);
  /* Section backgrounds — set --section-alt-background-color to a colour
     (e.g. #f5f5f5) to enable alternating white/grey bands across content
     sections. Both default to transparent (no fill). */
  --section-background-color: transparent;
  --section-alt-background-color: transparent;
  /* --- Header ---
     The fixed navigation bar at the top of every page.
     --header-background-color inherits from --brand-primary, so it matches
     the footer by default. Override here to give the header its own colour.
     --header-border-bottom is kept as a solid line, independent of
     --brand-border, because the header needs a stronger visual divide.
     To soften it to match the section dividers, set:
       --header-border-bottom: 1px solid var(--brand-border) */
  --header-background-color: var(--brand-primary);
  /* Header-icon contrast. Icons are black SVGs by default (filter: none). On a
     dark header, set this to `brightness(0) invert(1)` to render them white.
     This is a plain token the AI sets with the palette (and the manual editor
     can override) — there is no automatic luminance flip by design. */
  --header-icon-filter: none;
  /* Header-logo contrast. The logo is the customer's uploaded image, so unlike
     the monochrome icons an invert filter only makes sense for a MONOCHROME
     logo (it would flatten a colour logo). Defaults to none; set to
     `brightness(0) invert(1)` to flip a black logo white on a dark header. */
  --header-logo-filter: none;
  --header-height: 10rem;
  --header-mobile-height: 8rem;
  --header-padding: 0 5rem;
  --header-mobile-padding: 0 2rem;
  --header-icons-width: auto;
  --header-icons-height: 1.6rem;
  --header-icons-padding: 0 5rem;
  /* Gap between individual icons. The distance from the icons to the header
     edges is --header-padding / --header-mobile-padding, not a gap. */
  --header-icons-gap: var(--space-sm);
  --header-icons-mobile-gap: var(--space-xs);
  --header-icons-mobile-padding: 0 3rem;
  --header-border-bottom: 1px solid #000000;
  --header-icons-box-width: 9rem;
  /* Rendered logo height; --header-logo-max-height is the ceiling the customer's
     uploaded image is never allowed to exceed. */
  --header-logo-height: 5rem;
  --header-logo-mobile-height: 3.33rem;
  --header-logo-max-height: 5rem;
  /* --- Search Box --- */
  --search-box-background-color: rgba(255, 255, 255, 1);
  --search-box-height: 6rem;
  --search-box-padding: 0 5rem;
  --search-box-mobile-padding: 0 2rem;
  /* --- Navigation ---
     Desktop dropdown and mobile hamburger menu.
     Link colours inherit from --brand-text; hover colour from --brand-accent.
     Dropdown background inherits from --brand-surface.
     The panel's edge shadow now comes from --shadow-fade-right (see Drop
     Shadows above), not from --nav-dropdown-shadow. */
  /* Desktop dropdown geometry. The panel width is not set anywhere — it falls
     out of these three values as levels open:
       1 level  = 5 + 25 + 5              = 35rem (350px)
       2 levels = 5 + 25 + 5 + 25 + 5     = 65rem (650px)
       3 levels = 5 + 25 + 5 + 25 + 5 + 25 + 5 = 95rem (950px)
     --nav-line-height doubles as the descriptor height (250 x 20px).
     --nav-panel-padding is the left/right/bottom gutter. The TOP gutter is
     calc(--header-height + --nav-panel-padding) in _headers.scss: the panel
     starts at the page top and runs under the header, so its top gutter is
     measured from the header's lower edge, not from the panel's own. */
  --nav-link-width: 25rem;
  --nav-panel-padding: var(--space-md);
  --nav-column-gap: var(--space-md);
  --nav-item-gap: var(--space-xs);
  --nav-font-size: 1.4rem;
  --nav-line-height: 2rem;
  --nav-mobile-font-size: 1.6rem;
  --nav-mobile-line-height: 2rem;
  /* Mobile panel: 50px above the first row, 20px down each side. Descriptors
     are full width minus the side gutters (440 - 40 = 400px portrait,
     956 - 40 = 916px landscape) — no width is declared for them. */
  --nav-mobile-top-gutter: var(--space-md);
  --nav-mobile-gutter: var(--space-xs);
  /* One width for every nav arrow — the forward arrows and the mobile back
     arrow are the same glyph at the same size. */
  --nav-arrow-width: 1.2rem;
  /* Forward arrows rest at 25% black and go solid on the selected item. */
  --nav-arrow-opacity: 0.25;
  --nav-arrow-opacity-selected: 1;
  --nav-link-color: var(--color);
  --nav-link-hover-color: var(--brand-accent);
  --nav-dropdown-background: var(--brand-surface);
  --nav-dropdown-border: none;
  /* All-round panel glow, superseded 2026-08-04 by the 5px linear edge fade on
     the panel's far right edge. Kept as a live token, still read by
     .dropdown-panel and .search-autocomplete — set it back to
     `0px 8px 16px rgba(0,0,0,0.4)` to restore the previous look. */
  --nav-dropdown-shadow: none;
  --nav-dropdown-padding-top: 11rem;
  --nav-dropdown-min-height: 300px;
  --nav-mobile-controls-background: var(--brand-surface);
  --nav-mobile-controls-border: 1px solid black;
  /* --- Footer ---
     Background inherits from --brand-primary by default, matching the header.
     Override --footer-background-color to give the footer its own colour.
     Footer LINK colour tracks --footer-text-color (below) so links and body text
     flip together when the footer goes dark; hover stays --brand-accent. */
  --footer-background-color: var(--brand-primary);
  --footer-link-color: var(--footer-text-color);
  --footer-link-hover-color: var(--brand-accent);
  /* Footer text colour — drives BOTH the .footer-text block (company address /
     headline) AND the footer links (via --footer-link-color above). Default
     matches brand-text; set light (e.g. white) for a dark footer. The AI's
     one-action contrast contract sets this whenever it darkens the footer, so
     links and address stay legible together. */
  --footer-text-color: var(--brand-text);
  /* --- Hero Carousel ---
     Swiper pagination dots and navigation arrow positioning.
     Bullet colours are intentionally neutral by default (grey inactive,
     black active, white borders) — they sit over full-bleed images and
     must remain legible regardless of the brand palette. Override if needed. */
  /* 12px is the designer's 2026-08-30 hero ruling, applied to *every* carousel
     on purpose: one indicator size across hero, teaser and testimonial until the
     designer asks for different ones (Alex, 2026-08-30). Split into per-component
     tokens only when that happens. */
  --hero-pagination-bullet-size: 12px;
  --hero-navigation-button-size: 40px;
  --hero-navigation-position: 50px;
  /* ⚠️ Two sets of bullet *colour* styling live here, and they are NOT
     interchangeable. The four tokens below feed the *unscoped*
     `.swiper-pagination-bullet` rule in _heroes.scss, which — despite the
     --hero- prefix — actually styles the teaser and testimonial carousels.
     Leave them alone unless you mean to restyle those. The hero's own colours
     use the brief-specific set further down. Size and stroke width are
     deliberately shared by both. (The misnamed prefix is pre-existing; see
     "Known smells".)

     Aligned to the hero's language 2026-08-30 (Alex): white centre with a black
     ring unselected, solid black selected. The old grey-on-white-ring pair read
     as an ~8px grey dot on a white page — the 2px white border is invisible
     there, so only the centre showed — against the hero's 12px. Both now occupy
     the full 12px.

     The selected state is deliberately NOT a 1:1 copy of the hero's, which
     carries a *white* ring. That ring exists so a black disc survives dark
     photography; on a white page it is invisible, which would shrink the
     selected dot to 10px next to 12px unselected rings and make the selected
     state read as the smaller one. Solid black is the right translation.

     Assumes a light section background. --section-alt-background-color is
     transparent by default and documented for light bands (#f5f5f5); revisit
     only if a tenant sets a dark one. */
  --hero-pagination-bullet-spacing: 6px;
  --hero-pagination-bullet-color: #ffffff;
  --hero-pagination-bullet-border-color: #000000;
  --hero-pagination-bullet-active-color: #000000;
  --hero-pagination-bullet-active-border-color: #000000;
  /* --- Hero layout & typography (designer brief, 1 July 2026) ---
     Desktop values; _heroes.scss redefines these per viewport. The text
     column is deliberately narrower than --content-width: the brief puts
     hero headlines in a 780px column centred in the viewport, not in the
     1400px section column the rest of the page uses. */
  /* The masthead the hero measures its top offsets from. The header switches
     to --header-mobile-height at the mobile breakpoints but --header-height
     itself is never redefined, so the hero needs its own alias to track it —
     otherwise mobile offsets are computed against the desktop header. */
  --hero-masthead-height: var(--header-height);
  --hero-text-content-width: 78rem; /* 780px — desktop text column */
  /* Safety gutter on screens narrower than the text column. Must stay below
     (viewport - text column) / 2 or it, not the column, sets the text width —
     at the brief's 440px portrait viewport that ceiling is 2rem. */
  --hero-gutter: 5rem;
  --hero-text-offset: 10rem; /* 100px from masthead / panel top */
  --hero-image-headline-size: 4.6rem; /* 46px */
  --hero-image-headline-line-height: 1.2;
  --hero-panel-height: 13%; /* % of hero depth */
  --hero-panel-headline-size: 3.2rem; /* 32px */
  --hero-panel-opacity: 0.6;
  /* Hero pagination bullets — designer ruling, 2026-08-30. Separate from the
     teaser bullet tokens above; changing these does not touch the teaser or
     testimonial carousels.

     The ruling confirmed both deviations we shipped on 26 Aug and asked for a
     third change: the fill is opaque (the "50% opacity" in every earlier
     revision's prose is withdrawn), the selected slide inverts the disc rather
     than carrying a 7px pupil, and the indicator drops from 14px to 12px.
     Translucency is gone for good — any translucent fill takes its colour from
     the photograph behind it, so the two states invert depending on the picture. */
  --hero-pagination-offset: 50px; /* below the masthead */
  /* Diameter is --hero-pagination-bullet-size above (shared with the teaser and
     testimonial carousels); 1px stroke + 10px centre. */
  --hero-pagination-bullet-gap: 20px; /* ⇒ 32px pitch */
  --hero-pagination-bullet-fill: #ffffff;
  --hero-pagination-bullet-stroke: #000000;
  --hero-pagination-bullet-stroke-width: 1px;
  /* Selected state inverts the disc: white stroke, black centre. The white
     stroke is what keeps it visible on dark imagery. */
  --hero-pagination-bullet-active-fill: #000000;
  --hero-pagination-bullet-active-stroke: #ffffff;
  /* Headline scrim — the "White + Gradient" / "Black + Gradient" options in the
     Text color group. A gradient between the picture and the type so the headline
     stays legible over a photograph the site owner chose.

     These are the SMALLEST values that clear the 3:1 WCAG large-text minimum,
     measured on rendered pixels, not picked by eye. The floors are 41.6% (black,
     behind white type) and 34.9% (white, behind black type); the few extra points
     are margin for JPEG noise and for a photograph other than the one tested.
     Contrast at these values: 3.32:1 and 3.66:1. Working:
     docs/ai/briefs/2026-07-01-hero-image-movie.md.

     Change the alpha here if the designer wants a different strength — nothing
     else needs touching. Below ~42% / ~35% the headline stops passing. */
  --hero-scrim-dark: rgba(0, 0, 0, 0.45);
  --hero-scrim-light: rgba(255, 255, 255, 0.40);
  /* The scrim is sized to the headline, not to the slide. It must not run under
     the masthead: --header-background-color is rgba(255,255,255,0.8), so a scrim
     behind it shows through and tints the header (dark type turned it beige —
     Alex, 2026-08-30). It starts at the foot of the masthead instead.

     Height = offset from the masthead + the headline block + a fade that
     finishes just after the type. Driving it from the same tokens as the
     headline keeps it correct at every breakpoint with no per-tier overrides. */
  --hero-image-headline-lines: 3; /* must match the line clamp */
  --hero-scrim-text-height: calc(var(--hero-image-headline-size) *
                                        var(--hero-image-headline-line-height) *
                                        var(--hero-image-headline-lines));
  --hero-scrim-fade: calc(var(--hero-image-headline-size) * 2);
  /* --- Image Overlay ---
     The text panel that appears over hero and teaser images.
     The variant classes (.hero-top-left, .hero-center, .hero-top-banner,
     .hero-vertical) in the hero SCSS override these defaults to create
     layout presets. Edit those classes to adjust the presets. */
  /* Positioning */
  --image-overlay-position: absolute;
  --image-overlay-top: auto;
  --image-overlay-right: auto;
  --image-overlay-bottom: 0;
  --image-overlay-left: 0;
  --image-overlay-width: 100%;
  --image-overlay-height: clamp(5%, 8vw, 13%);
  /* Visual style */
  --image-overlay-background-color: rgba(0,0,0,0.6);
  --image-overlay-border-radius: 0;
  --image-overlay-padding: 0;
  --image-overlay-margin: 0;
  /* Flexbox layout */
  --image-overlay-display: flex;
  --image-overlay-align-items: center;
  --image-overlay-justify-content: center;
  --image-overlay-flex-direction: row;
  /* Text style */
  --image-overlay-font-weight: 700;
  --image-overlay-text-align: center;
  --image-overlay-text-transform: none;
  --image-overlay-letter-spacing: normal;
  --image-overlay-text-shadow: none;
  /* --- Teasers, Features & Spotlight — shared typography defaults ---
     These are the shared defaults. All three section types inherit from them.
     To override a specific section, change its per-section variable below
     — the shared default is unaffected. */
  --teaser-headline-font-size: var(--font-size);
  --teaser-headline-line-height: var(--line-height);
  /* --- Teasers section — per-section overrides ---
     Change these to restyle only the teasers carousel section. */
  --teasers-section-font-size: var(--teaser-font-size);
  --teasers-section-line-height: var(--teaser-line-height);
  --teasers-section-headline-font-size: var(--teaser-headline-font-size);
  --teasers-section-headline-line-height: var(--teaser-headline-line-height);
  /* --- Feature section — per-section overrides ---
     Change these to restyle only the feature block section. */
  --feature-section-font-size: var(--teaser-font-size);
  --feature-section-line-height: var(--teaser-line-height);
  --feature-section-headline-font-size: var(--teaser-headline-font-size);
  --feature-section-headline-line-height: var(--teaser-headline-line-height);
  /* --- Spotlight section — per-section overrides ---
     Change these to restyle only the spotlight section. */
  --spotlight-section-font-size: var(--teaser-font-size);
  --spotlight-section-line-height: var(--teaser-line-height);
  --spotlight-section-headline-font-size: var(--teaser-headline-font-size);
  --spotlight-section-headline-line-height: var(--teaser-headline-line-height);
  /* --- Testimonials section — per-section overrides ---
     Change these to restyle only the testimonials section. */
  --testimonials-avatar-size: 9rem;
  --testimonials-quote-mark-size: 8rem;
  --testimonials-section-font-size: var(--teaser-font-size);
  --testimonials-section-line-height: var(--teaser-line-height);
  --testimonials-section-headline-font-size: var(--teaser-headline-font-size);
  --testimonials-section-headline-line-height: var(--teaser-headline-line-height);
  --teaser-gap: 4rem;
  --image-margin-bottom: var(--space-sm);
  /* --- Article --- */
  --article-content-width: 78rem;
  --article-content-gap: var(--space-md);
  --article-headline-font-size: 3.6rem;
  --article-headline-line-height: 4.3rem;
  --article-lead-font-size: 2.6rem;
  --article-lead-line-height: 3.1rem;
  --article-body-font-size: 1.8rem;
  --article-body-line-height: 2.7rem;
  /* --- Gallery Lightbox ---
     The lightbox overlay appears full-screen over all content and must
     remain dark and legible regardless of the brand colour palette.
     These variables are intentionally NOT wired to --brand-primary or
     --brand-surface — the lightbox always needs a dark background. */
  --lightbox-text-color: #fff;
  --lightbox-nav-bg: rgba(0, 0, 0, 0.7);
  --lightbox-nav-hover-bg: rgba(0, 0, 0, 0.9);
}

/* 1rem = 10px */
html {
  font-size: 62.5%;
  position: relative;
  min-height: 100%;
}

body {
  font-family: var(--font-family);
  font-size: var(--font-size);
  line-height: var(--line-height);
  color: var(--color);
  position: relative;
}

.container {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  min-height: 100vh;
}

/* SECTIONS */
section {
  width: 100%;
  scroll-margin-top: 8rem;
  padding-top: var(--section-padding-top);
  padding-bottom: var(--section-padding-bottom);
  border-bottom: var(--section-border-bottom);
  position: relative;
  background-color: var(--section-background-color);
}

/* Even-positioned sections get the alternate background when set */
section:nth-child(even) {
  background-color: var(--section-alt-background-color);
}

/* Header sits flush — no top/bottom padding, no border */
.container > section:first-child {
  padding-top: 0;
  padding-bottom: 0;
}

.section-heading {
  font-size: var(--headline-font-size);
  line-height: var(--headline-line-height);
  font-weight: bold;
  color: var(--brand-heading);
  font-family: var(--brand-font-heading);
  /* Modern approach with fallback */
  leading-trim: both;
  text-edge: cap alphabetic;
  /* Fallback for browsers without leading-trim support */
  margin-top: 0;
  margin-bottom: 4.1rem;
}

/* Only apply negative margin if leading-trim isn't supported */
@supports not (leading-trim: both) {
  .section-heading {
    margin-top: -0.8rem;
  }
}
/* Centre the heading within the gallery section without affecting vertical margins */
.gallery-section .section-heading {
  margin-left: auto;
  margin-right: auto;
}

/* Spacer div that compensates for the fixed header on non-hero pages */
.header {
  width: 100%;
  height: var(--header-height);
}

/* The spacer yields when the page opens hero-like — the frosted header is
   designed to overlay a hero image or a full-bleed article image.
   The `main >` variants match the same shape under an engine that wraps the
   page composition in <main>; they are inert here but keep the whole decision
   inside this stylesheet, so the file ports verbatim. */
.header-section:has(+ .hero-section) .header,
.header-section:has(+ .article-section .article-image) .header,
.header-section:has(+ main > .hero-section) .header,
.header-section:has(+ main > .article-section:first-child .article-image) .header {
  display: none;
}

.image-overlay {
  position: var(--image-overlay-position);
  top: var(--image-overlay-top);
  right: var(--image-overlay-right);
  bottom: var(--image-overlay-bottom);
  left: var(--image-overlay-left);
  width: var(--image-overlay-width);
  height: var(--image-overlay-height);
  background-color: var(--image-overlay-background-color);
  border-radius: var(--image-overlay-border-radius);
  padding: var(--image-overlay-padding);
  margin: var(--image-overlay-margin);
  display: var(--image-overlay-display);
  align-items: var(--image-overlay-align-items);
  justify-content: var(--image-overlay-justify-content);
  flex-direction: var(--image-overlay-flex-direction);
}

.image-overlay.left {
  justify-content: flex-start;
}

.image-overlay.right {
  justify-content: flex-end;
}

.image-overlay-text {
  font-size: var(--headline-font-size);
  line-height: var(--headline-line-height);
  color: var(--image-overlay-text-color);
  font-weight: var(--image-overlay-font-weight);
  text-align: var(--image-overlay-text-align);
  text-transform: var(--image-overlay-text-transform);
  letter-spacing: var(--image-overlay-letter-spacing);
  text-shadow: var(--image-overlay-text-shadow);
}

.image-wrapper {
  position: relative;
}

.image-wrapper:not(:last-child) {
  margin-bottom: var(--image-margin-bottom);
}

@media only screen and (max-width: 760px) {
  .section-heading {
    margin-top: 0;
  }
}
/* Same breakpoint as _headers.scss — the spacer has to track the shorter mobile
   header, or non-hero pages open with 2rem of dead space above the content. */
@media (max-width: 769px), (orientation: landscape) and (max-height: 500px) {
  .header {
    height: var(--header-mobile-height);
  }
}
/* This is a rule that adds margins on the left and right 
when the content is less than the max-width prescribed */
@media only screen and (max-width: 1500px) {
  section:not(.hero-section):not(.footer-section):not(.article-section) {
    padding-right: 5rem;
    padding-left: 5rem;
  }
}
/* POWERED BY WEBPUZZLE BADGE */
.powered-by-webpuzzle {
  display: flex;
  justify-content: center;
  padding-top: var(--space-md);
  padding-bottom: var(--space-md);
}

.powered-by-webpuzzle img {
  height: var(--header-logo-max-height);
  width: auto;
}

/* HEADER - Desktop First */
.site-header {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: var(--header-height);
  padding: var(--header-padding);
  display: flex;
  justify-content: space-between;
  align-items: center;
  background-color: var(--header-background-color);
  border-bottom: var(--header-border-bottom);
  z-index: 100;
  box-sizing: border-box;
}

/* Drop shadow below the header's black rule.
   `position: fixed` + `top: var(--header-height)`, not `absolute` + `top: 100%`:
   an absolutely positioned child resolves its offsets against the PADDING box,
   which sits 1px inside the bottom border, so `top: 100%` would paint over the
   rule instead of starting below it. --header-height is the border-box height
   (box-sizing: border-box) measured from the viewport top, so this lands exactly
   on the outer edge. Same reason .search-box repeats the token in the media
   query — the mobile override below must follow. */
.site-header::after {
  content: "";
  position: fixed;
  top: var(--header-height);
  left: 0;
  right: 0;
  height: var(--shadow-depth);
  background: var(--shadow-fade-down);
  pointer-events: none;
}

/* Both icon groups flex equally so the logo stays centred regardless of how
   many icons each side renders (tier/config dependent). */
.header-icons {
  flex: 1;
  display: flex;
  gap: var(--header-icons-gap);
  justify-content: flex-start;
  align-items: center;
}

.header-icons.right {
  justify-content: flex-end;
}

.header-icons button {
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
}

.header-icons img {
  width: var(--header-icons-width);
  height: var(--header-icons-height);
  cursor: pointer;
  filter: var(--header-icon-filter);
}

/* Centred against the header as a whole: both .header-icons groups are
   `flex: 1` (basis 0), so they always take equal width and the logo sits on the
   header's true centre line regardless of icon count. */
.site-logo {
  display: flex;
  align-items: center;
  justify-content: center;
}

.site-logo a {
  display: flex;
  align-items: center;
}

.site-logo a img {
  display: block;
  height: var(--header-logo-height);
  max-height: var(--header-logo-max-height);
  width: auto;
  cursor: pointer;
  filter: var(--header-logo-filter);
}

/* NAVIGATION CONTROLS - Desktop */
.mobile-nav-controls {
  display: none;
  gap: 2rem;
  align-items: center;
  margin-top: 4rem;
  margin-bottom: 2rem;
  padding: 2rem;
  background-color: var(--nav-mobile-controls-background);
  width: 100%;
  box-sizing: border-box;
  z-index: 51;
}

.mobile-nav-controls.active {
  display: flex;
}

.mobile-nav-controls button {
  background: none;
  border: none;
  cursor: pointer;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
}

.mobile-back {
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease;
}

.mobile-back.visible {
  opacity: 1;
  pointer-events: auto;
}

/* Back arrows are always solid black — unlike the forward arrows they have no
   resting/selected distinction.
   Don't reintroduce a `.mobile-nav-controls img` sizing rule: at (0,1,1) it
   out-specifies this one and silently forced the arrow to --header-icons-height
   (1.6rem) with width:auto, so it rendered wider than the forward arrows. */
.mobile-back-arrow {
  width: var(--nav-arrow-width);
  cursor: pointer;
  opacity: 1;
}

#close {
  display: none;
}

/* NAVIGATION - Desktop
   Starts at the page top, not below the header, so the panel runs *under* the
   header and shows through it — --header-background-color is
   rgba(255,255,255,0.8), so the bar reads pure white over the panel and grey
   over page content. That contrast is the middle layer becoming visible through
   the top one, and it only exists because the header is translucent.

   `fixed`, not `absolute`: the header is fixed, and an absolute nav drifts by
   exactly the scroll offset (measured: scroll 200px -> panel sits 200px above
   the header's lower edge). That was survivable while the panel merely sat
   below the header; now that it tucks underneath, the two must stay registered
   or the tuck comes apart. Mobile already used fixed for the same reason. */
.main-navigation {
  display: none;
  position: fixed;
  top: 0;
  left: 0;
  width: auto;
  height: auto;
  z-index: 99;
  margin-top: 0;
  background: transparent;
}

/* Width is deliberately `auto` — the panel grows 350 -> 650 -> 950px purely
   from the gutter + column + gap tokens as each level opens (see variables.scss). */
.dropdown-panel {
  display: none;
  /* The 50px top gutter is measured from the HEADER's lower edge, not from the
     panel's own top — the panel now starts at y=0 and its first 100px are hidden
     behind the header, so a plain 50px would put the first descriptor under the
     bar. Adding --header-height keeps the first row exactly --nav-panel-padding
     below the header, identical to before this change (verified: 50px).
     Left/right stay --nav-panel-padding, so the 350/650/950 width arithmetic
     below is untouched. */
  padding: calc(var(--header-height) + var(--nav-panel-padding)) var(--nav-panel-padding) var(--nav-panel-padding);
  background-color: var(--nav-dropdown-background);
  border-bottom: var(--nav-dropdown-border);
  box-shadow: var(--nav-dropdown-shadow);
  /* Fill the viewport height regardless of how many links a level holds
     (2026-08-24, designer). min-height, NOT height: a menu longer than the
     viewport must still be allowed to grow — .main-navigation is `fixed` and
     nothing here scrolls, so a hard 100vh would spill the overflowing links out
     over page content with no white behind them. With min-height the panel just
     extends below the fold: those links are still unreachable, but that is a
     pre-existing desktop limitation (see Known smells in header.md), not one
     this rule introduces. The mobile block resets this — see min-height: 0 there. */
  min-height: 100vh;
  height: auto;
  flex-direction: row;
  align-items: flex-start;
  justify-content: flex-start;
  flex-wrap: nowrap;
  gap: var(--nav-column-gap);
  box-sizing: border-box;
  width: auto;
  position: relative;
  z-index: 50;
  margin-top: 0;
}

/* Drop shadow on the panel's far right edge — the panel is one growing box
   (350 -> 650 -> 950px), so `left: 100%` tracks the outermost open column with
   no per-level rule. No black rule on this edge, so the fade starts flush at
   25%. The panel has no border, so its padding box and border box coincide and
   `left: 100%` is the true outer edge. Desktop only: the mobile nav is a
   full-width overlay with no free vertical edge (suppressed below). */
.dropdown-panel::after {
  content: "";
  position: absolute;
  left: 100%;
  top: 0;
  bottom: 0;
  width: var(--shadow-depth);
  background: var(--shadow-fade-right);
  pointer-events: none;
}

/* The panel's lower edge carries no fade. It reaches the bottom of the viewport
   (min-height: 100vh, 2026-08-24), so there is no visible lower edge to soften —
   the same reason mobile has never had one. The corner treatment went with it:
   with no bottom band there is no corner where two bands meet.

   This deleted `.dropdown-panel::before`, a linear+radial pair that fell to 0 at
   --shadow-depth from the panel's bottom and bottom-right corner. Restoring it
   only makes sense alongside a content-height panel; the tuning that was hard to
   get right is on record in header.md (the corner needs `farthest-side` — both
   other extent keywords are wrong, in opposite directions). */
.main, .submenu, .submenu-3 {
  display: none;
  list-style: none;
  margin: 0;
  padding: 0;
  flex-direction: column;
  align-items: flex-start;
  justify-content: flex-start;
  gap: var(--nav-item-gap);
  z-index: 1;
  background-color: var(--nav-dropdown-background);
  transition: transform 0.3s ease;
  flex: 0 0 var(--nav-link-width);
  width: var(--nav-link-width);
}

.main.hidden {
  transform: translateX(-100%);
}

/* All three levels, not just .menu-item — without a full-width <li> the column
   collapses to text width and the arrow can't right-align in the 250px field. */
.menu-item, .submenu-item, .submenu-3-item {
  width: 100%;
  text-align: left;
  margin: 0;
  padding: 0;
}

.menu-item:last-child {
  margin-bottom: 0;
}

/* The "descriptor field": 250 x 20px, arrow right-aligned inside it.
   min-height, not height — a long label wraps and the field grows in exact
   20px steps (line-height == field height), so the vertical rhythm survives. */
.link {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--nav-item-gap);
  width: 100%;
  min-height: var(--nav-line-height);
  padding: 0;
  overflow-wrap: anywhere;
  font-family: var(--font-family);
  font-size: var(--nav-font-size);
  line-height: var(--nav-line-height);
  font-weight: normal;
  opacity: 1;
  color: var(--nav-link-color);
  text-decoration: none;
  text-align: left;
  box-sizing: border-box;
}

.link span {
  min-width: 0;
}

/* Parent item with no page of its own — the click is cancelled in header.js, so
   don't offer a pointer. .no-target is set there (it also catches the published
   "https://#" form); the attribute selector covers edit mode before JS runs. */
.link.no-target,
.link[href="#"] {
  cursor: default;
}

.link .arrow {
  margin-left: auto;
  width: var(--nav-arrow-width);
  flex-shrink: 0;
  display: block;
  opacity: var(--nav-arrow-opacity);
}

.link:hover .arrow,
.link.open .arrow {
  opacity: var(--nav-arrow-opacity-selected);
}

.link:active,
.link:focus {
  font-weight: normal;
}

/* .open is set by header.js on the item whose submenu column is showing, so the
   trail through the levels stays bold once the pointer moves into that column. */
.link:hover,
.link.open {
  font-weight: var(--bold);
  color: var(--nav-link-hover-color);
}

.header-text {
  font-size: var(--nav-mobile-font-size);
  font-weight: 700;
  font-family: var(--font-family);
}

.submenu.active {
  display: flex;
}

/* Arrow utilities using Unicode */
.arrow-left::before {
  content: "←";
  font-size: inherit;
}

.arrow-right::before {
  content: "→";
  font-size: inherit;
}

/* For buttons or clickable arrows */
.arrow-btn {
  background: none;
  border: none;
  cursor: pointer;
  font-size: 1.5rem;
  padding: 0.5rem;
}

/* SEARCH BOX */
.search-box {
  display: none;
  position: fixed;
  top: var(--header-height);
  left: 0;
  width: 100%;
  height: var(--search-box-height);
  background-color: var(--search-box-background-color);
  border-bottom: var(--header-border-bottom);
  z-index: 98;
  padding: var(--search-box-padding);
  box-sizing: border-box;
  align-items: center;
  justify-content: space-between;
}

.search-box.active {
  display: flex;
}

/* The search box is a second fixed bar with the same 1px #000 rule, sitting
   directly under the header. Its own fade goes below it, at header + box height.
   The box is display:none until opened, which takes this pseudo-element with it,
   so no `.active` qualifier is needed here. */
.search-box::after {
  content: "";
  position: fixed;
  top: calc(var(--header-height) + var(--search-box-height));
  left: 0;
  right: 0;
  height: var(--shadow-depth);
  background: var(--shadow-fade-down);
  pointer-events: none;
}

/* No shadow BETWEEN the two bars (2026-08-24, designer). While search is open the
   header and the search box read as one surface, so only the lower edge of the
   pair casts — the header's own fade is suppressed and .search-box::after above
   is the only horizontal band left.

   This reverses the 2026-08-04 call, which deliberately let the header fade land
   on the search box on the grounds that the header floats higher (z 100 vs 98).
   That is still true and is still why the fade *would* paint there; it just is
   not what the design wants.

   `:has(~ ...)` rather than `:has(+ ...)`: the search box is the header's next
   element sibling today (comment and whitespace nodes do not affect either
   combinator), but the general form also survives a wrapper being introduced
   between them. Specificity (0,2,1) beats the base rule's (0,1,1), and the
   mobile override only restates `top`, so it cannot resurrect the band. */
.site-header:has(~ .search-box.active)::after {
  display: none;
}

/* ...and none between the search box and the autocomplete either (2026-08-24).
   Same reasoning one level down: the autocomplete is fixed at exactly this
   fade's `top`, so the band painted straight onto it.

   Suppressing this was only safe once the autocomplete became full-height. While
   it stopped at max-height: 30rem it had a real lower edge, and removing this
   fade would have left the assembly with no bottom shadow at all — the
   autocomplete cannot cast its own (see below). Now header + search box +
   autocomplete reach the viewport floor as one surface, so there is no edge left
   to cast and no shadow is the right answer, exactly as for the full-height
   dropdown panel.

   The autocomplete is a descendant of .search-box, not a sibling, so this is a
   plain :has() descendant test. */
.search-box:has(.search-autocomplete.visible)::after {
  display: none;
}

.search-box input {
  flex: 1;
  height: auto;
  border: none;
  background: var(--search-box-background-color);
  outline: none;
  padding: 0;
  font-size: var(--font-size);
  color: inherit;
  margin-right: 1rem;
  line-height: 1.6rem;
}

/* Hide browser's default search clear button */
.search-box input::-webkit-search-cancel-button {
  -webkit-appearance: none;
  appearance: none;
}

.search-box input::-ms-clear {
  display: none;
}

.search-box input::placeholder {
  color: inherit;
  opacity: 0.7;
}

.search-box .search-icon {
  width: var(--header-icons-width);
  height: var(--header-icons-height);
  cursor: pointer;
  flex-shrink: 0;
}

/* Search wrapper — Vue mount point; fills the padded search-box area */
.search-box .search-wrapper {
  flex: 1;
  display: flex;
  align-items: center;
  height: 100%;
}

/* Autocomplete dropdown — fixed-position panel below the search box */
.search-autocomplete {
  display: none;
  position: fixed;
  top: calc(var(--header-height) + var(--search-box-height));
  left: 0;
  width: 100%;
  /* Fills to the viewport floor, like the dropdown panel (2026-08-24, designer).
     `bottom: 0` rather than a height calc: `top` is already restated at the mobile
     breakpoint, so the height follows both breakpoints with no duplication — the
     restatement .site-header::after needs is avoided here. This replaced
     max-height: var(--search-autocomplete-max-height) (30rem), which had to go
     outright: a max-height would cap the box and defeat `bottom`. The token had
     no other consumer and was removed with it.

     Unlike .dropdown-panel this takes a definite height, not min-height — it was
     always a scroller (overflow-y: auto below), so long result lists scroll here
     instead of running off the bottom. */
  bottom: 0;
  overflow-y: auto;
  background-color: var(--nav-dropdown-background);
  box-shadow: var(--nav-dropdown-shadow);
  list-style: none;
  margin: 0;
  /* Menu geometry (2026-08-24, designer: "same as menus, only without the
     arrows"). 50px gutters all round like .dropdown-panel, replacing 2rem/5rem.
     The type already matched — --nav-font-size / --nav-line-height — so what was
     off was the rhythm and the gutters. */
  padding: var(--nav-panel-padding);
  box-sizing: border-box;
  z-index: 97;
}

/* Flex column so the 20px item rhythm comes from `gap`, exactly as the menu
   columns do, instead of per-item padding. .visible must therefore switch to
   flex, not block. */
.search-autocomplete.visible {
  display: flex;
  flex-direction: column;
  gap: var(--nav-item-gap);
}

.autocomplete-section,
.search-autocomplete .autocomplete-section > ul {
  display: flex;
  flex-direction: column;
  gap: var(--nav-item-gap);
  list-style: none;
  margin: 0;
  padding: 0;
}

/* Deliberately NOT menu-descriptor styling: this is a section heading, not a
   link. The menu has no equivalent, so "same as menus" does not reach it. Sits
   on the same 20px rhythm as everything else — its old vertical padding is gone
   because the parent `gap` owns the spacing now. */
.autocomplete-label {
  display: flex;
  align-items: center;
  min-height: var(--nav-line-height);
  /* Explicit line-height, not just min-height: the panel inherits 24px from the
     body, which beats a 20px min-height and pushed the label off the 20px grid
     (measured: label 24px, article-to-tag gap 64px instead of 60px). The items
     escape this only because they set line-height themselves. Same rule the menu
     descriptors rely on — line-height equal to the field height is what keeps the
     rhythm. */
  line-height: var(--nav-line-height);
  font-size: 1.2rem;
  font-weight: var(--bold);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--color);
  opacity: 0.5;
  padding: 0;
}

/* Mirrors .link: same 250x20 descriptor field and wrap behaviour, minus the
   arrow and its `justify-content: space-between`. min-height, not height, so a
   long headline wraps in exact 20px steps and the rhythm survives — the same
   reason the menu uses it. */
.search-autocomplete .autocomplete-item {
  display: flex;
  align-items: center;
  min-height: var(--nav-line-height);
  padding: 0;
  overflow-wrap: anywhere;
  font-family: var(--font-family);
  font-size: var(--nav-font-size);
  line-height: var(--nav-line-height);
  font-weight: normal;
  list-style: none;
  cursor: pointer;
  color: var(--nav-link-color);
}

.search-autocomplete .autocomplete-item:hover {
  color: var(--nav-link-hover-color);
  font-weight: var(--bold);
}

.header-icons #search-close {
  display: none;
}

.header-icons.search-active #search {
  display: none !important;
}

.header-icons.search-active #search-close {
  display: block !important;
}

/* Hide navigation when search is active */
.search-box.active ~ .main-navigation {
  display: none !important;
}

/* MOBILE STYLES
   The orientation clause catches landscape phones (e.g. 956 x 440), which are
   wider than 769px and would otherwise get the desktop hover dropdown. Keep it
   in sync with isMobile() in templates/js/header.js — the JS decides
   click-vs-hover, so the two must agree or the menu half-works. */
@media (max-width: 769px), (orientation: landscape) and (max-height: 500px) {
  .site-header {
    height: var(--header-mobile-height);
    padding: var(--header-mobile-padding);
    margin-bottom: 0;
  }
  /* The fade is anchored to the header's outer edge in viewport coordinates,
     so it does not follow the height token automatically — restate it. */
  .site-header::after {
    top: var(--header-mobile-height);
  }
  .header-icons {
    gap: var(--header-icons-mobile-gap);
  }
  .site-logo a img {
    height: var(--header-logo-mobile-height);
  }
  .main-navigation {
    display: none;
    position: fixed;
    width: 100%;
    top: 0;
    left: 0;
    margin-top: var(--header-mobile-height);
    height: calc(100vh - var(--header-mobile-height));
    background-color: var(--search-box-background-color);
    z-index: 50;
    border: none;
    font-size: var(--nav-mobile-font-size);
    line-height: var(--nav-mobile-line-height);
    /* Gutters live here, not on the children, so the heading row and the
       descriptors share one left edge. Landscape phones are short — the panel
       scrolls rather than clipping the tail of a long menu. */
    padding: var(--nav-mobile-top-gutter) var(--nav-mobile-gutter) var(--nav-mobile-gutter);
    box-sizing: border-box;
    overflow-y: auto;
  }
  /* Heading row: same 20px-tall descriptor slot as a menu item, with the back
     arrow 20px to its left, then 20px down to the first descriptor. */
  .mobile-nav-controls {
    display: none;
    gap: var(--nav-item-gap);
    align-items: center;
    min-height: var(--nav-mobile-line-height);
    margin: 0 0 var(--nav-item-gap);
    padding: 0;
    background-color: var(--nav-mobile-controls-background);
    width: 100%;
    border: none;
    box-sizing: border-box;
    z-index: 51;
    position: relative;
  }
  .dropdown-panel {
    display: flex;
    flex-direction: row;
    align-items: flex-start;
    justify-content: flex-start;
    flex-wrap: nowrap;
    gap: 2rem;
    border: none;
    box-sizing: border-box;
    height: auto;
    /* Desktop fills the viewport; here the nav itself is the full-height
       scroller and the panel must stay content-sized inside it. */
    min-height: 0;
    width: 100%;
    padding: 0;
    position: relative;
    z-index: 50;
    margin-top: 0;
    background-color: var(--nav-dropdown-background);
    box-shadow: none;
  }
  /* Full-width overlay inside a scrolling panel — no free vertical edge to
     fade. (The lower-edge fade is gone at every width since 2026-08-24.) */
  .dropdown-panel::after {
    display: none;
  }
  .mobile-nav-controls.active + .dropdown-panel {
    margin-top: 0;
  }
  /* Mobile shows one full-width column at a time — only the desktop 250px
     column width is reset; the 20px item gap carries over. */
  .main, .submenu, .submenu-3 {
    flex: 0 0 auto;
    width: 100% !important;
  }
  .menu-item, .submenu-item, .submenu-3-item {
    width: 100%;
    text-align: left;
  }
  .menu-item:last-child {
    margin-bottom: 0;
  }
  .link {
    display: flex;
    justify-content: space-between;
    align-items: center;
    min-height: var(--nav-mobile-line-height);
    padding: 0;
    font-size: var(--nav-mobile-font-size);
    line-height: var(--nav-mobile-line-height);
    color: var(--nav-link-color);
    text-decoration: none;
    text-align: left;
  }
  /* SEARCH BOX */
  .search-box {
    top: var(--header-mobile-height);
    padding: var(--search-box-mobile-padding);
  }
  .search-box::after {
    top: calc(var(--header-mobile-height) + var(--search-box-height));
  }
  .search-autocomplete {
    top: calc(var(--header-mobile-height) + var(--search-box-height));
    /* Mobile menu gutters, matching .main-navigation's
       --nav-mobile-top-gutter / --nav-mobile-gutter, rather than the search box's
       own `0 2rem` — the list is formatted as a menu at both widths now, and the
       old value gave it no top gutter at all. */
    padding: var(--nav-mobile-top-gutter) var(--nav-mobile-gutter) var(--nav-mobile-gutter);
  }
}
/* Hero is full-bleed — no top padding from the global section rule */
.hero-section {
  padding-top: 0;
  padding-bottom: 0;
}

/* Over-riding Swiper styles */
/* dvh, not vh: the brief's "full screen depth" means the screen the visitor
   actually sees. vh is the *largest* viewport — with the mobile URL bar shown
   it overshoots, hiding the panel below the fold until the page is scrolled.
   The vh line stays as the fallback for browsers without dvh. */
.hero-section .swiper {
  width: 100%;
  height: 100vh;
  height: 100dvh;
  position: relative;
  overflow: hidden;
}

.hero-section .swiper-slide {
  display: flex;
  justify-content: center;
  align-items: center;
  position: relative;
}

.hero-section .swiper-slide picture,
.hero-section .swiper-slide picture img,
.hero-section .swiper-slide video,
.hero-section .swiper-slide iframe {
  width: 100%;
  height: 100%; /* Ensure the image takes up the full height of the container */
  display: block;
  object-fit: cover; /* Ensure the image covers the entire container */
  object-position: top; /* Align the image to the top of the container */
}

.hero-top-left {
  --image-overlay-top: 20px;
  --image-overlay-left: 20px;
  --image-overlay-bottom: auto;
  --image-overlay-width: auto;
  --image-overlay-height: auto;
  --image-overlay-padding: 15px 25px;
  --image-overlay-border-radius: 8px;
}

.hero-center {
  --image-overlay-top: 50%;
  --image-overlay-left: 50%;
  --image-overlay-bottom: auto;
  --image-overlay-width: auto;
  --image-overlay-height: auto;
  --image-overlay-padding: 30px 50px;
  --image-overlay-border-radius: 12px;
  transform: translate(-50%, -50%);
}

.hero-top-banner {
  --image-overlay-top: 0;
  --image-overlay-bottom: auto;
  --image-overlay-height: 80px;
  --image-overlay-background-color: rgba(0,0,0,0.8);
}

.hero-vertical {
  --image-overlay-right: 20px;
  --image-overlay-left: auto;
  --image-overlay-top: 20px;
  --image-overlay-bottom: 20px;
  --image-overlay-width: 200px;
  --image-overlay-height: auto;
  --image-overlay-flex-direction: column;
  --image-overlay-text-transform: uppercase;
  --image-overlay-letter-spacing: 2px;
}

.hero-section .swiper-pagination {
  left: 50% !important;
  transform: translateX(-50%) !important;
  width: max-content !important;
  text-align: center !important;
  top: 110px !important; /* superseded below — kept as the no-header fallback */
}

/* Indicators sit a fixed distance below the masthead, so the offset has to be
   measured from the header rather than the top of the viewport. */
.hero-section.has-header .swiper-pagination {
  top: calc(var(--hero-masthead-height) + var(--hero-pagination-offset)) !important;
}

/* Swiper sets .swiper-pagination-lock when there are too few slides to scroll.
   The brief only shows indicators when a carousel is actually in use. */
.hero-section .swiper-pagination-lock {
  display: none !important;
}

/* Hero pagination bullets: 12px opaque white disc with a 1px black stroke; the
   selected slide inverts it. Scoped to .hero-section on purpose — the unscoped
   bullet rules further down keep their own colours and 2px stroke for the teaser
   and testimonial carousels, but share the 12px size token. */
.hero-section .swiper-pagination-bullet {
  box-sizing: border-box !important; /* Swiper resets to content-box; without
   this the stroke makes it 14px */
  width: var(--hero-pagination-bullet-size) !important;
  height: var(--hero-pagination-bullet-size) !important;
  background: var(--hero-pagination-bullet-fill) !important;
  border: var(--hero-pagination-bullet-stroke-width) solid var(--hero-pagination-bullet-stroke) !important;
  opacity: 1 !important;
  position: relative;
  margin: 0 calc(var(--hero-pagination-bullet-gap) / 2) !important;
}

/* Selected inverts the disc rather than adding a centre dot — proposed 26 Aug,
   ratified by the designer on 2026-08-30, which also withdrew the 7px pupil.

   Inverting — black fill, white stroke — survives any backdrop, which a plain
   black fill does not: tested over the hero's own dark car body, a black disc
   with a black stroke disappeared entirely, while the white stroke keeps it
   legible. On pale imagery the white stroke is invisible and it simply reads as
   a solid black dot. */
.hero-section .swiper-pagination-bullet-active {
  background: var(--hero-pagination-bullet-active-fill) !important;
  border: var(--hero-pagination-bullet-stroke-width) solid var(--hero-pagination-bullet-active-stroke) !important;
}

/* Teaser and testimonial bullets. Stroke width is shared with the hero so the
   two read as one family — at 2px the ring was visibly heavier than the hero's.
   box-sizing is belt-and-braces: reset.scss already applies border-box globally
   and these measured 12px before it was added, so unlike the hero rule this is
   not correcting an actual Swiper override — it just keeps the two bullet rules
   symmetrical if Swiper's CSS ever changes. */
.swiper-pagination-bullet {
  box-sizing: border-box !important;
  background: var(--hero-pagination-bullet-color) !important;
  border: var(--hero-pagination-bullet-stroke-width) solid var(--hero-pagination-bullet-border-color) !important;
  opacity: 1 !important;
  width: var(--hero-pagination-bullet-size) !important;
  height: var(--hero-pagination-bullet-size) !important;
  margin: 0 var(--hero-pagination-bullet-spacing) !important;
  transition: background 0.3s, border 0.3s;
}

.swiper-pagination-bullet-active {
  background: var(--hero-pagination-bullet-active-color) !important;
  border: var(--hero-pagination-bullet-stroke-width) solid var(--hero-pagination-bullet-active-border-color) !important;
}

.hero-section .swiper-button-next,
.hero-section .swiper-button-prev {
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
  width: var(--hero-navigation-button-size);
  height: var(--hero-navigation-button-size);
  opacity: 1;
}

.hero-section .swiper-button-next {
  right: var(--hero-navigation-position);
}

.hero-section .swiper-button-prev {
  left: var(--hero-navigation-position);
}

/* Stop the default arrows from showing */
.hero-section .swiper-button-next::after,
.hero-section .swiper-button-prev::after {
  display: none;
}

/* ── Tinted panel over the lower part of the hero ─────────────────────────
   The panel is a full-bleed band; its headline sits in the same centred
   column as the image headline ("full width in the default 780px text
   content area"). This replaces the earlier inset-to-content-edge padding,
   which measured against the 1400px section column rather than 780px.
   box-sizing: border-box is required because Swiper overrides the global
   reset to content-box inside the swiper; without it the padding adds to
   width: 100% and pushes the element past the viewport edge. */
.hero-section .image-overlay {
  box-sizing: border-box;
  height: var(--hero-panel-height);
  background-color: rgba(0, 0, 0, var(--hero-panel-opacity));
  padding-left: var(--hero-gutter);
  padding-right: var(--hero-gutter);
}

/* The column stays centred regardless of text alignment — base.scss moves it
   with justify-content, which would drag the whole 780px block to the edge. */
.hero-section .image-overlay.left,
.hero-section .image-overlay.right {
  justify-content: center;
}

/* Panel colour. Black is the default and preserves current behaviour; the
   white variant is styled ready for a "Panel colour" config option, which is
   a separate gated DB change. Headline colour follows the panel so the pair
   can't be configured into an illegible combination. */
.hero-section .image-overlay.panel-black {
  background-color: rgba(0, 0, 0, var(--hero-panel-opacity));
}

.hero-section .image-overlay.panel-white {
  background-color: rgba(255, 255, 255, var(--hero-panel-opacity));
}

.hero-section .image-overlay.panel-white .image-overlay-text {
  color: #000000;
}

/* A <div>, not a <p>: the panel headline binds to the Lead field, which is a
   rich-text (textarea) field the editor wraps in <p>. A <p> cannot contain a
   <p> — the parser closes the styled one and orphans the text into a bare,
   unstyled paragraph, which reads as "the panel is empty". */
.hero-section .image-overlay-text {
  box-sizing: border-box;
  width: 100%;
  max-width: var(--hero-text-content-width);
  /* Pinned to Roboto to match .hero-text-content — the brief specifies one
     face for both hero headlines, and the base rule would otherwise leave this
     one on the tenant's brand body font. Alex ruled 2026-08-26: pin for now.
     Revisit if hero type should follow the brand font instead. */
  font-family: "Roboto", sans-serif;
  font-size: var(--hero-panel-headline-size);
  line-height: 1.2;
  margin: 0;
}

/* Strip the editor-injected paragraph's default margins so the headline stays
   optically centred in the panel depth. */
.hero-section .image-overlay-text > p {
  margin: 0;
}

/* The brief specifies the panel headline as a single line, and the panel is a
   fixed % of hero depth — so copy long enough to wrap would spill out of the
   band top and bottom. Hold it to one line and ellipsize instead: the panel
   keeps its geometry and an over-long headline degrades visibly rather than
   breaking the layout. overflow on the panel is the backstop. */
.hero-section .image-overlay {
  overflow: hidden;
}

.hero-section .image-overlay-text,
.hero-section .image-overlay-text > p {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* "Text align" writes .left / .right onto .image-overlay. Inside the hero it
   aligns the headline within the centred column instead of moving the column. */
.hero-section .image-overlay .image-overlay-text {
  text-align: center;
}

.hero-section .image-overlay.left .image-overlay-text {
  text-align: left;
}

.hero-section .image-overlay.right .image-overlay-text {
  text-align: right;
}

@media only screen and (max-width: 768px) {
  .hero-section .swiper-button-next,
  .hero-section .swiper-button-prev {
    display: none;
  }
}
/* ── Overlay mode: show/hide based on active mode ─────────────────────── */
/* mode-text-panel (image headline + panel together) deliberately has no rule:
   both overlays are visible by default, so the combined variant is the
   absence of a hiding rule. Don't "complete the set" by adding one. */
.swiper-slide.mode-panel .hero-text-outer {
  display: none;
}

.swiper-slide.mode-text .image-overlay {
  display: none;
}

.swiper-slide.mode-none .image-overlay,
.swiper-slide.mode-none .hero-text-outer {
  display: none;
}

/* ── Text overlay outer — position anchor ─────────────────────────────── */
/* box-sizing: border-box required: Swiper overrides the global reset to
   content-box inside the slider, so padding would exceed width:100% otherwise.
   Mirrors the same padding logic used for .image-overlay.left/.right above. */
/* Flex centring places the text column in the middle of the viewport;
   --hero-gutter is the safety gutter on screens narrower than the column. */
.hero-text-outer {
  position: absolute;
  left: 0;
  width: 100%;
  box-sizing: border-box;
  padding-left: var(--hero-gutter);
  padding-right: var(--hero-gutter);
  display: flex;
  justify-content: center;
}

/* Vertical positions. The top offset is measured from the masthead; the
   bottom offset is measured from the panel — not the image edge — whenever a
   panel is showing, per the brief's "finish Npx above the bottom of the image
   or tinted panels over images (if used)". */
.hero-text-outer.pos-top {
  top: var(--hero-text-offset);
}

.hero-section.has-header .hero-text-outer.pos-top {
  top: calc(var(--hero-masthead-height) + var(--hero-text-offset));
}

.hero-text-outer.pos-middle {
  top: 50%;
  transform: translateY(-50%);
}

.hero-text-outer.pos-bottom {
  bottom: var(--hero-text-offset);
  top: auto;
}

.swiper-slide.mode-text-panel .hero-text-outer.pos-bottom {
  bottom: calc(var(--hero-panel-height) + var(--hero-text-offset));
}

/* ── Headline scrim ───────────────────────────────────────────────────────
   The "White + Gradient" / "Black + Gradient" options in the Text color group.
   A gradient laid between the picture and the type.

   Why it exists: on a real photograph both type colours can fail at once. The
   hero's own image holds a pure-white wall and a near-black car under one
   headline, so white and black each measure 1.00:1 against a 3:1 minimum. No
   colour choice fixes that, because the failure is the tonal range within a
   single headline. Rather than force a treatment, the two gradient options put
   it in the editor's hands. Strength lives in --hero-scrim-* in variables.scss.

   Only renders when an image headline is shown (Alex, 2026-08-30) — the marker
   class rides on .hero-text-overlay, which only exists on a slide with a
   headline, so mode-none and panel-only slides are untouched by construction.

   :has() is load-bearing: the marker lands on .hero-text-overlay
   (data-css-marker="text-color") but the gradient must span the whole slide,
   and .hero-text-outer is only as tall as the headline itself. */
.hero-section .swiper-slide:has(.hero-text-overlay.has-gradient) {
  --hero-scrim: var(--hero-scrim-dark);
  --hero-scrim-nil: rgba(0, 0, 0, 0);
  --hero-scrim-dir: to bottom;
}

/* Black type needs a light scrim. The zero-alpha stop must be the SAME hue —
   the keyword `transparent` is rgba(0,0,0,0), which fades a white scrim through
   grey. */
.hero-section .swiper-slide:has(.hero-text-overlay.color-black.has-gradient) {
  --hero-scrim: var(--hero-scrim-light);
  --hero-scrim-nil: rgba(255, 255, 255, 0);
}

/* Direction follows the headline. */
.hero-section .swiper-slide:has(.pos-bottom > .hero-text-overlay.has-gradient) {
  --hero-scrim-dir: to top;
}

.hero-section .swiper-slide:has(.hero-text-overlay.has-gradient)::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  z-index: 1;
  pointer-events: none;
}

/* Headline at the top: the scrim begins at the foot of the masthead, never at
   the top of the slide — the header is 80% white and a scrim behind it tints it.
   It runs solid down through the headline, then fades out just below it. */
.hero-section .swiper-slide:has(.pos-top > .hero-text-overlay.has-gradient)::before {
  top: 0;
  height: calc(var(--hero-text-offset) + var(--hero-scrim-text-height) + var(--hero-scrim-fade));
  background: linear-gradient(to bottom, var(--hero-scrim) 0, var(--hero-scrim) calc(var(--hero-text-offset) + var(--hero-scrim-text-height)), var(--hero-scrim-nil) 100%);
}

.hero-section.has-header .swiper-slide:has(.pos-top > .hero-text-overlay.has-gradient)::before {
  top: var(--hero-masthead-height);
}

/* Headline at the bottom: anchored to the foot of the slide and fading upwards.
   With a panel showing, the headline sits above it, so the scrim has to be
   taller by the panel's depth to still clear the type. */
.hero-section .swiper-slide:has(.pos-bottom > .hero-text-overlay.has-gradient)::before {
  bottom: 0;
  height: calc(var(--hero-text-offset) + var(--hero-scrim-text-height) + var(--hero-scrim-fade));
  background: linear-gradient(to top, var(--hero-scrim) 0, var(--hero-scrim) calc(var(--hero-text-offset) + var(--hero-scrim-text-height)), var(--hero-scrim-nil) 100%);
}

.hero-section .swiper-slide.mode-text-panel:has(.pos-bottom > .hero-text-overlay.has-gradient)::before {
  height: calc(var(--hero-panel-height) + var(--hero-text-offset) + var(--hero-scrim-text-height) + var(--hero-scrim-fade));
  background: linear-gradient(to top, var(--hero-scrim) 0, var(--hero-scrim) calc(var(--hero-panel-height) + var(--hero-text-offset) + var(--hero-scrim-text-height)), var(--hero-scrim-nil) 100%);
}

/* Centred headline: a band centred on the type, fading both ways. */
.hero-section .swiper-slide:has(.pos-middle > .hero-text-overlay.has-gradient)::before {
  top: 50%;
  transform: translateY(-50%);
  height: calc(var(--hero-scrim-text-height) + var(--hero-scrim-fade) * 2);
  background: linear-gradient(to bottom, var(--hero-scrim-nil) 0, var(--hero-scrim) var(--hero-scrim-fade), var(--hero-scrim) calc(100% - var(--hero-scrim-fade)), var(--hero-scrim-nil) 100%);
}

/* Type and panel sit above the scrim — the panel keeps its own 60% and must not
   be tinted twice by a pos-bottom gradient running up through it. */
.hero-section .hero-text-outer,
.hero-section .image-overlay {
  z-index: 2;
}

/* ── Text overlay inner ────────────────────────────────────────────────── */
.hero-text-overlay {
  width: 100%;
  max-width: var(--hero-text-content-width);
}

/* "Up to three lines" is a hard cap (designer, 2026-08-26): a fourth line would
   push a pos-bottom headline past its offset and, with a panel showing, into
   the panel. Clamp and ellipsize rather than let the layout drift. */
.hero-text-content {
  font-family: "Roboto", sans-serif;
  font-size: var(--hero-image-headline-size);
  line-height: var(--hero-image-headline-line-height);
  font-weight: var(--image-overlay-font-weight);
  margin: 0;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: var(--hero-image-headline-lines);
  line-clamp: var(--hero-image-headline-lines);
  overflow: hidden;
}

.hero-text-overlay.color-white .hero-text-content {
  color: #ffffff;
}

.hero-text-overlay.color-black .hero-text-content {
  color: #000000;
}

/* ── Viewport overrides ───────────────────────────────────────────────────
   Same breakpoint pair base.scss already uses for the header spacer, so the
   hero and the masthead switch together rather than drifting apart. Mobile
   portrait is width-driven; mobile landscape is height-driven, because the
   brief's 956x440 landscape phone is wider than the portrait breakpoint but
   still needs mobile typography.

   ⚠️ The 769px value is NOT free to change here. It is duplicated in
   base.scss, _headers.scss and — critically — isMobile() in js/header.js,
   which decides click-vs-hover menus. Moving the hero's copy alone desyncs
   --hero-masthead-height from the real masthead and reintroduces the offset
   bug found 2026-08-16. Renormalising it is a site-wide job; see "Known
   smells" in components/hero.md.

   ── Tablet tier ──
   Answers the designer's unanswered "intermediate viewports" query by applying
   a standard 1024px breakpoint (Alex, 2026-08-30 — the designer does not work
   in breakpoints, so this is ours, not his). Bounded at the bottom by 770px so
   it butts exactly against the mobile switch above with no gap.

   These values are LINEARLY INTERPOLATED between the designer's own 440px and
   1920px designs, evaluated at the 896px midpoint of the range — they are not
   drawn anywhere. Evidence they are needed: at an 800px viewport the desktop
   tier put a 46px headline in a column the 5rem gutters cap to 685px, and the
   brief's own sample copy overflowed the three-line clamp and ellipsised.

   Deliberately does NOT set --hero-masthead-height: above 769px the real
   masthead is the desktop one, so the hero must keep inheriting it. */
@media (min-width: 770px) and (max-width: 1023.98px) {
  .hero-section {
    --hero-text-content-width: 52rem; /* 520px — 400→780 interpolated */
    --hero-text-offset: 8rem; /* 80px  — 70→100 */
    --hero-image-headline-size: 3.2rem; /* 32px  — 24→46 */
    --hero-panel-height: 12%; /*       — 11→13 */
    --hero-panel-headline-size: 2.4rem; /* 24px  — 20→32 */
    --hero-pagination-offset: 40px; /*       — 30→50 */
  }
}
@media (max-width: 769px) {
  .hero-section {
    --hero-masthead-height: var(--header-mobile-height);
    --hero-text-content-width: 40rem; /* 400px */
    /* 20px, per the artwork: at the brief's 440px viewport the desktop 5rem
       gutter would cap the column at 340px and the 400px width never applies. */
    --hero-gutter: 2rem; /* 20px */
    --hero-text-offset: 7rem; /* 70px */
    --hero-image-headline-size: 2.4rem; /* 24px */
    --hero-panel-height: 11%;
    --hero-panel-headline-size: 2rem; /* 20px */
    --hero-pagination-offset: 30px;
  }
}
@media (orientation: landscape) and (max-height: 500px) {
  .hero-section {
    --hero-masthead-height: var(--header-mobile-height);
    --hero-text-content-width: 40rem; /* 400px */
    --hero-text-offset: 6rem; /* 60px */
    --hero-image-headline-size: 2.4rem; /* 24px */
    --hero-panel-height: 18%;
    --hero-panel-headline-size: 2rem; /* 20px */
    --hero-pagination-offset: 30px;
  }
}
/* FOOTER */
.footer-section {
  background-color: var(--footer-background-color);
  padding-top: 0;
  padding-bottom: 0;
  border-bottom: none;
}

footer {
  position: relative;
  bottom: 0;
  left: 0;
  width: 100%;
  background-color: var(--footer-background-color);
  padding: 5rem;
  font-size: var(--font-size);
  box-sizing: border-box;
  display: flex;
  gap: 4rem;
}

.footer-menu {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-start;
  gap: 5rem;
  width: 67%;
}

.footer-links {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  flex: 0 0 auto;
  max-width: 17rem;
}

.footer-links a {
  color: var(--footer-link-color);
  text-decoration: none;
}

.footer-links a:hover {
  color: var(--footer-link-hover-color);
}

.footer-links-heading {
  color: var(--footer-link-color);
  font-weight: bold;
}

.footer-text {
  display: flex;
  justify-content: flex-end;
  width: 33%;
}
.footer-text .headline {
  font-weight: 700;
  color: var(--footer-text-color);
  font-family: var(--brand-font-heading);
}

.footer-text-content {
  text-align: left;
  color: var(--footer-text-color);
}

/* MOBILE STYLES */
@media (max-width: 769px) {
  footer {
    padding: 5rem;
  }
}
.feature-section .content,
.feature-section .section-heading {
  max-width: var(--content-width);
  margin-left: auto;
  margin-right: auto;
}

.feature-section .text-wrapper .text {
  font-size: var(--feature-section-font-size);
  line-height: var(--feature-section-line-height);
  color: var(--brand-text);
  gap: 3rem;
}

.one-column {
  column-count: 1;
}

.two-columns {
  column-count: 2;
}

.three-columns {
  column-count: 3;
}

.feature-section .text-wrapper .headline {
  font-size: var(--feature-section-headline-font-size);
  line-height: var(--feature-section-headline-line-height);
  font-weight: bold;
  color: var(--brand-heading);
  font-family: var(--brand-font-heading);
}

/* Image overlay styles are inherited from base.scss */
/* Correction to the main styles for the smallest screens */
@media only screen and (max-width: 768px) {
  .feature-section .image-overlay-text {
    font-size: 1.6rem;
  }
}
/* ── Spotlight ─────────────────────────────────────────────────────────────── */
/* Text left, image right. Add class 'reversed' to section for image left, text right. */
.spotlight-section .section-heading {
  max-width: var(--content-width);
  margin-left: auto;
  margin-right: auto;
}

/* `.content` is the flex layout wrapper (a <div>, not a link — only the image
   is linked, so the editable Body can hold inline links without nesting <a>).
   Direct-child scoping kept as a guard against any nested `.content`. */
.spotlight-section > .content {
  display: flex;
  align-items: flex-start;
  gap: var(--teaser-gap);
  max-width: var(--content-width);
  margin-left: auto;
  margin-right: auto;
}

.spotlight-section .text-item {
  flex: 1.2;
}

.spotlight-section .image-item {
  flex: 1;
}

.spotlight-section .image-item img {
  width: 100%;
  aspect-ratio: 4/3;
  object-fit: cover;
  display: block;
}

.spotlight-section .text-item .headline {
  font-size: var(--spotlight-section-headline-font-size);
  line-height: var(--spotlight-section-headline-line-height);
  font-weight: bold;
  color: var(--brand-heading);
  font-family: var(--brand-font-heading);
}

.spotlight-section .text-item .text {
  font-size: var(--spotlight-section-font-size);
  line-height: var(--spotlight-section-line-height);
  /* Pinned to --brand-text for consistency with every other section's body text;
     previously had no colour rule and fell through to the cascade. */
  color: var(--brand-text);
}

.spotlight-section.reversed > .content {
  flex-direction: row-reverse;
}

@media only screen and (max-width: 768px) {
  .spotlight-section > .content,
  .spotlight-section.reversed > .content {
    flex-direction: column;
  }
}
/* Over-riding Swiper styles */
.teasers-section .swiper {
  max-width: var(--content-width);
}

.teasers-section .swiper-wrapper {
  gap: var(--teaser-gap);
}

.teasers-section .swiper-slide {
  margin-right: 0 !important;
}

.teasers-section .swiper-wrapper.no-carousel {
  display: flex !important;
  flex-wrap: wrap !important;
  transform: none !important;
  transition: none !important;
  width: 100% !important;
  height: auto !important;
  gap: var(--teaser-gap);
}

.teasers-section .swiper-slide.no-carousel {
  width: auto !important;
  height: auto !important;
  transform: none !important;
  min-width: 250px; /* Minimum width before wrapping */
}

.teasers-section .swiper-slide.no-carousel.four {
  flex: 0 1 calc(25% - var(--teaser-gap)) !important; /* 4 items per row minus gap */
}

.teasers-section .swiper-slide.no-carousel.three {
  flex: 0 1 calc(33.33% - var(--teaser-gap)) !important; /* 3 items per row minus gap */
}

.teasers-section .swiper-slide.no-carousel.two {
  flex: 0 1 calc(50% - var(--teaser-gap)) !important; /* 2 items per row minus gap */
}

/* Pagination is hidden on desktop; shown on mobile via the media query below */
.teasers-section .swiper-pagination {
  display: none;
  left: 50% !important;
  transform: translateX(-50%) !important;
  width: max-content !important;
  text-align: center !important;
  top: 10px !important;
}

/* No-carousel sections have Swiper disabled, so the pagination dots are dead
   controls. Hide them outright — otherwise the mobile media query below forces
   them visible. (Pagination is a following sibling of the .swiper-wrapper.) */
.teasers-section .swiper-wrapper.no-carousel ~ .swiper-pagination {
  display: none !important;
}

.teasers-section .swiper-button-next,
.teasers-section .swiper-button-prev {
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
  width: 40px;
  height: 40px;
  opacity: 1;
}

.teasers-section .swiper-button-next {
  right: 40px;
}

.teasers-section .swiper-button-prev {
  left: 40px;
}

/* Stop the default arrows from showing */
.teasers-section .swiper-button-next::after,
.teasers-section .swiper-button-prev::after {
  display: none;
}

/* Text styles */
.teasers-section {
  font-size: var(--teasers-section-font-size);
  line-height: var(--teasers-section-line-height);
}

.teasers-section .headline {
  font-size: var(--teasers-section-headline-font-size);
  line-height: var(--teasers-section-headline-line-height);
  font-weight: var(--bold);
  color: var(--brand-heading);
  font-family: var(--brand-font-heading);
}

/* Teaser lead/body (promo + article teasers). Pinned to --brand-text so it stays
   consistent with every other section's body text. The promo/article teaser card
   is wrapped in <a> (section-link fix), so WITHOUT this it inherits the global
   a{color:var(--link-color)} and renders in the link colour — the cause of the
   "Articles/Promotions came out a different colour" bug. Over-image text uses
   .image-overlay-text below (its own token), not this. */
.teasers-section .text {
  color: var(--brand-text);
}

.teasers-section .image-overlay-text {
  font-size: var(--teasers-section-font-size);
  line-height: var(--teasers-section-line-height);
  color: var(--image-overlay-text-color);
  font-weight: var(--bold);
  text-align: center;
}

@media only screen and (max-width: 768px) {
  .teasers-section .item {
    display: flex;
    flex-direction: column;
  }
  .teasers-section .swiper-button-next,
  .teasers-section .swiper-button-prev {
    display: none;
  }
  .teasers-section .swiper-pagination {
    display: block;
    position: relative;
    margin-top: 2rem;
    z-index: 10;
    margin-bottom: 5px;
  }
  /* No-carousel (few items): Swiper is disabled, so the static flex grid above
     applies. Collapse to one full-width column on mobile so the cards keep the
     section's equal left/right margins instead of sitting in a narrow
     min-width:250px column pinned to the left with a big right-hand gap. */
  .teasers-section .swiper-slide.no-carousel,
  .teasers-section .swiper-slide.no-carousel.two,
  .teasers-section .swiper-slide.no-carousel.three,
  .teasers-section .swiper-slide.no-carousel.four {
    flex: 0 0 100% !important;
    min-width: 0 !important;
  }
}
/* ── Testimonials ──────────────────────────────────────────────────────────── */
.testimonials-section .swiper {
  max-width: var(--content-width);
}

.testimonials-section .swiper-wrapper {
  gap: var(--teaser-gap);
}

.testimonials-section .swiper-slide {
  margin-right: 0 !important;
}

.testimonials-section .swiper-wrapper.no-carousel {
  display: flex !important;
  flex-wrap: wrap !important;
  transform: none !important;
  transition: none !important;
  width: 100% !important;
  height: auto !important;
  gap: var(--teaser-gap);
}

.testimonials-section .swiper-slide.no-carousel {
  width: auto !important;
  height: auto !important;
  transform: none !important;
  min-width: 250px;
}

.testimonials-section .swiper-slide.no-carousel.four {
  flex: 0 1 calc(25% - var(--teaser-gap)) !important;
}

.testimonials-section .swiper-slide.no-carousel.three {
  flex: 0 1 calc(33.33% - var(--teaser-gap)) !important;
}

.testimonials-section .swiper-slide.no-carousel.two {
  flex: 0 1 calc(50% - var(--teaser-gap)) !important;
}

.testimonials-section .swiper-pagination {
  display: none;
  left: 50% !important;
  transform: translateX(-50%) !important;
  width: max-content !important;
  text-align: center !important;
  top: 10px !important;
}

/* Same as teasers: hide the dead pagination dots when Swiper is disabled. */
.testimonials-section .swiper-wrapper.no-carousel ~ .swiper-pagination {
  display: none !important;
}

.testimonials-section .swiper-button-next,
.testimonials-section .swiper-button-prev {
  background-size: contain;
  background-repeat: no-repeat;
  background-position: center;
  width: 40px;
  height: 40px;
  opacity: 1;
}

.testimonials-section .swiper-button-next {
  right: 0;
}

.testimonials-section .swiper-button-prev {
  left: 0;
}

.testimonials-section .swiper-button-next::after,
.testimonials-section .swiper-button-prev::after {
  display: none;
}

/* Card layout */
.testimonials-section .item {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

/* Avatar — Style A: Portraits (default) */
.testimonials-section .avatar-wrapper {
  width: var(--testimonials-avatar-size);
  height: var(--testimonials-avatar-size);
  border-radius: 50%;
  overflow: hidden;
  background-color: var(--brand-border); /* grey circle when no image uploaded */
  flex-shrink: 0;
  margin-bottom: var(--space-xs);
}

.testimonials-section .avatar {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Quote text */
.testimonials-section .quote {
  font-style: italic;
  font-size: var(--testimonials-section-font-size);
  line-height: var(--testimonials-section-line-height);
  color: var(--brand-text);
  margin-bottom: var(--space-xs);
}

/* Attribution */
.testimonials-section .attribution {
  font-size: var(--testimonials-section-headline-font-size);
  line-height: var(--testimonials-section-headline-line-height);
  font-weight: var(--bold);
  color: var(--brand-heading);
  font-family: var(--brand-font-heading);
}

/* Style B: Quotes only */
.testimonials-section.quotes-only .avatar-wrapper {
  display: none;
}

.testimonials-section.quotes-only .quote::before {
  content: "“";
  display: block;
  font-size: var(--testimonials-quote-mark-size);
  line-height: 1;
  color: var(--brand-text);
  margin-bottom: var(--space-xs);
  font-family: var(--brand-font-heading);
}

.testimonials-section.quotes-only .attribution {
  padding-top: var(--space-xs);
  border-top: 1px solid var(--brand-border);
  width: 100%;
}

@media only screen and (max-width: 768px) {
  .testimonials-section .swiper-button-next,
  .testimonials-section .swiper-button-prev {
    display: none;
  }
  .testimonials-section .swiper-pagination {
    display: block;
    position: relative;
    margin-top: 2rem;
    z-index: 10;
    margin-bottom: 5px;
  }
  /* Same no-carousel mobile collapse as the teasers section above. */
  .testimonials-section .swiper-slide.no-carousel,
  .testimonials-section .swiper-slide.no-carousel.two,
  .testimonials-section .swiper-slide.no-carousel.three,
  .testimonials-section .swiper-slide.no-carousel.four {
    flex: 0 0 100% !important;
    min-width: 0 !important;
  }
}
/* Center the gallery content within a section - specific handling not to interfere with the Isotope plug-in */
.gallery-section .section-heading {
  max-width: var(--content-width);
}

.gallery-center-wrapper {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  width: 100%;
  max-width: var(--content-width);
  margin: 0 auto;
}

/* Ensure masonry container behaves normally */
.masonry {
  /* Don't add flex or grid here - let Isotope handle positioning */
  width: 100%;
  margin: 0;
}

.item-sizer,
.gallery-item {
  box-sizing: border-box;
  width: calc(25% - 5px);
  margin-bottom: 0;
  cursor: pointer;
}

@media only screen and (max-width: 1024px) {
  .item-sizer,
  .gallery-item {
    width: calc(33.333% - 5px);
  }
}
@media only screen and (max-width: 768px) {
  .content-wrapper {
    margin: auto;
    max-width: var(--content-width);
  }
  .item-sizer,
  .gallery-item {
    width: calc(50% - 5px);
  }
}
@media only screen and (max-width: 480px) {
  .item-sizer,
  .gallery-item {
    width: 100%;
  }
}
.item-sizer img,
.gallery-item img {
  width: 100%;
  height: auto;
  display: block;
  object-fit: cover;
}

.item-sizer .caption,
.gallery-item .caption {
  display: none;
}

.gallery-image::-webkit-scrollbar {
  width: 0px;
  background: transparent; /* make scrollbar transparent */
}

.gallery-image {
  box-sizing: border-box;
  max-height: 100vh;
  overflow: auto;
}

.gallery-image .cap {
  color: var(--lightbox-text-color);
  margin: auto;
  max-width: 80%;
  width: 60rem;
}

.gallery-image .cap h4 {
  margin: 1.5rem auto 1rem auto;
}

.gallery-image img {
  display: block;
  max-height: calc(100vh - 20rem);
  max-width: 100%;
  margin: auto;
}

.basicLightbox .gallery-close {
  color: var(--lightbox-text-color);
  cursor: pointer;
  font-size: 3rem;
  position: fixed;
  right: 2rem;
  top: 2rem;
  z-index: 2;
}

.basicLightbox .gallery-close:after {
  content: "✕";
}

.basicLightbox .gallery-prev,
.basicLightbox .gallery-next {
  color: var(--lightbox-text-color);
  cursor: pointer;
  font-size: 5rem;
  position: fixed;
  right: 2rem;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
}

.basicLightbox .gallery-prev {
  left: 2rem;
}

.basicLightbox .gallery-prev:after {
  content: "❮";
}

.basicLightbox .gallery-next:after {
  content: "❯";
}

/* SimpleLightbox Navigation Arrow Centering - Z-INDEX FIXED */
/* Target the actual SimpleLightbox wrapper and controls */
.sl-wrapper {
  z-index: 9999 !important;
}

.sl-wrapper .sl-close,
.sl-wrapper .sl-counter,
.sl-wrapper .sl-navigation,
.sl-wrapper .sl-prev,
.sl-wrapper .sl-next {
  z-index: 10000 !important;
}

/* Style the navigation buttons */
.sl-wrapper .sl-prev,
.sl-wrapper .sl-next {
  position: fixed !important;
  top: 50% !important;
  transform: translateY(-50%) !important;
  width: 52px !important;
  height: 52px !important;
  padding: 0 0 4px 0 !important;
  background: var(--lightbox-nav-bg) !important;
  border: none !important;
  border-radius: 50% !important;
  color: var(--lightbox-text-color) !important;
  font-size: 28px !important;
  font-weight: normal !important;
  cursor: pointer !important;
  text-decoration: none !important;
  display: flex !important;
  align-items: center !important;
  justify-content: center !important;
  line-height: 1 !important;
  transition: background-color 0.3s ease !important;
  pointer-events: auto !important;
}

.sl-wrapper .sl-prev:hover,
.sl-wrapper .sl-next:hover {
  background: var(--lightbox-nav-hover-bg) !important;
}

.sl-wrapper .sl-prev {
  left: 30px !important;
}

.sl-wrapper .sl-next {
  right: 30px !important;
}

/* Ensure the navigation container is visible and clickable */
.sl-wrapper .sl-navigation {
  display: block !important;
  z-index: 10000 !important;
  pointer-events: auto !important;
}

/* Remove any conflicting styles */
.sl-navigation button {
  display: none;
}

/* Hide navigation arrows on mobile devices */
@media only screen and (max-width: 768px) {
  .sl-wrapper .sl-prev,
  .sl-wrapper .sl-next {
    display: none !important;
  }
  .sl-wrapper .sl-navigation {
    display: none !important;
  }
}
/* Remove any conflicting styles */
.sl-navigation button {
  display: none;
}

.social-links-section {
  display: flex;
  justify-content: center;
  align-items: center;
}

.social-links-section img {
  height: 3rem;
}

.social-links-section .content {
  max-width: var(--content-width);
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 2rem;
}

/*# sourceMappingURL=main-6225.css.map */
