@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);
  }
}
.article-section {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  padding-top: 0;
  /* padding-bottom is inherited from section {} in base.scss */
}

/* Header clearance is no longer this section's job — the always-emitted
   .header spacer handles it, and base.scss suppresses that spacer only when an
   .article-image is present. Re-adding a padding-top here would double-clear.
   It also used to pad imageless article sections placed mid-page, where no
   clearance is wanted. */
.article-section .article-image-wrapper {
  position: relative;
  width: 100vw;
  height: 100vh;
  margin-left: calc(50% - 50vw);
}

.article-section .article-image {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: center;
  display: block;
}

/* Left/right text alignment — inset to the article content column edge.
   max() keeps a minimum 2rem gutter on narrow viewports. */
.article-section .image-overlay.left,
.article-section .image-overlay.right {
  box-sizing: border-box;
  padding-left: max(5rem, (100% - var(--article-content-width)) / 2);
  padding-right: max(5rem, (100% - var(--article-content-width)) / 2);
}

/* ── Overlay mode: show/hide ──────────────────────────────────────────────── */
.article-image-wrapper.mode-panel .article-text-outer {
  display: none;
}

.article-image-wrapper.mode-text .image-overlay {
  display: none;
}

.article-image-wrapper.mode-none .image-overlay,
.article-image-wrapper.mode-none .article-text-outer {
  display: none;
}

/* ── Text overlay: position anchor ───────────────────────────────────────── */
/* Article image always sits behind the fixed header, so pos-top always
   includes the header-height offset (no has-header JS needed). */
.article-text-outer {
  position: absolute;
  left: 0;
  width: 100%;
  box-sizing: border-box;
  padding-left: max(5rem, (100% - var(--article-content-width)) / 2);
  padding-right: max(5rem, (100% - var(--article-content-width)) / 2);
}

.article-text-outer.pos-top {
  top: calc(var(--header-height) + 10rem);
}

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

.article-text-outer.pos-bottom {
  bottom: 10rem;
  top: auto;
}

/* ── Text overlay: inner ─────────────────────────────────────────────────── */
.article-text-content {
  font-family: "Roboto", sans-serif;
  font-size: 4.6rem;
  line-height: 5.5rem;
  font-weight: var(--image-overlay-font-weight);
  margin: 0;
}

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

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

.article-wrapper {
  width: 100%;
  max-width: var(--article-content-width);
  box-sizing: border-box;
  display: flex;
  flex-wrap: wrap;
}

.article-wrapper img {
  width: 100%;
  height: auto;
  margin-bottom: var(--space-md);
  margin-top: var(--space-md);
}

/* Bare video/YouTube embeds inserted by the rich-text editor carry native
   width/height attributes and no wrapper — force them to fill the column. */
.article-wrapper iframe,
.article-wrapper video {
  width: 100%;
  height: auto;
  aspect-ratio: 16/9;
  margin-bottom: var(--space-md);
  margin-top: var(--space-md);
}

.iframe {
  padding-top: 56.25%;
  position: relative;
  overflow: hidden;
  margin-bottom: var(--space-md);
  margin-top: var(--space-md);
}

.iframe iframe {
  border: 0;
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

.article-heading,
.article-lead,
.article-body {
  width: 100%;
}

.article-headline {
  font-size: var(--article-headline-font-size);
  line-height: var(--article-headline-line-height);
  font-weight: 700;
  color: var(--brand-heading);
  font-family: var(--brand-font-heading);
  margin-top: calc(10rem - (var(--article-headline-line-height) - var(--article-headline-font-size)) / 2);
  margin-bottom: calc(var(--space-md) - (var(--article-headline-line-height) - var(--article-headline-font-size)) / 2 - (var(--article-lead-line-height) - var(--article-lead-font-size)) / 2);
}

.article-lead {
  font-size: var(--article-lead-font-size);
  line-height: var(--article-lead-line-height);
  font-weight: 700;
  color: var(--brand-text);
  /* Author/Published follow with tight (1.0) line-height, so only remove lead's own half-leading */
  margin-bottom: calc(var(--space-md) - (var(--article-lead-line-height) - var(--article-lead-font-size)) / 2);
}

.article-author,
.article-published {
  width: 100%;
  font-size: var(--article-body-font-size);
  line-height: var(--article-body-font-size); /* tight 1.0 — matches IDML spec */
  color: var(--brand-text);
}

.article-author {
  margin-bottom: 1.2rem; /* 12px gap to Published line */
}

.article-published {
  /* Remove body's half-leading from the gap to maintain --space-md visual rhythm */
  margin-bottom: calc(var(--space-md) - (var(--article-body-line-height) - var(--article-body-font-size)) / 2);
}

.article-body {
  font-size: var(--article-body-font-size);
  line-height: var(--article-body-line-height);
  color: var(--brand-text);
}

@media only screen and (max-width: 768px) {
  .article-wrapper {
    padding: 0 5rem;
  }
}
/* 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;
  }
}

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