@import url('https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,400;9..144,600;9..144,700&family=Public+Sans:wght@400;500;700&display=swap');

/* ── Flex Theme — canonical tokens (runtime-overridable) ──────────────── */
:root {
  --flex-primary: #1F3A5F;
  --flex-accent:  #C97B2D;
  --flex-surface: #F9F7F4;
  --flex-ink:     #26221D;
  --flex-border:  #E3DED6;
  --flex-font-display: 'Fraunces', Georgia, serif;
  --flex-font-body:    'Public Sans', system-ui, sans-serif;
  --flex-base-size: 16px;
  --flex-radius:    0.5rem;
  --flex-radius-lg: 1rem;
  --flex-space-scale: 1;
  --flex-motion: 0.25s;
  --flex-card: #FFFFFF;
  --flex-primary-fg: #FFFFFF;
  --flex-accent-fg: #FFFFFF;

  /* ── Semantic aliases (all components read these) ── */
  --color-primary: var(--flex-primary);
  --color-primary-foreground: var(--flex-primary-fg, #FFFFFF);
  --color-accent: var(--flex-accent);
  --color-accent-foreground: var(--flex-accent-fg, #FFFFFF);
  --color-background: var(--flex-surface);
  --color-surface: var(--flex-card, #FFFFFF);
  --color-text: var(--flex-ink);
  --color-muted: color-mix(in srgb, var(--flex-ink) 62%, var(--flex-surface));
  --color-border: var(--flex-border);
  --color-footer-bg: color-mix(in srgb, var(--flex-ink) 92%, black);
  --color-footer-text: color-mix(in srgb, var(--flex-surface) 85%, white);
  --font-display: var(--flex-font-display);
  --font-body: var(--flex-font-body);
  --radius: var(--flex-radius);
  --radius-lg: var(--flex-radius-lg);
  --space-1: calc(0.5rem * var(--flex-space-scale));
  --space-2: calc(1rem * var(--flex-space-scale));
  --space-3: calc(1.75rem * var(--flex-space-scale));
  --space-4: calc(3rem * var(--flex-space-scale));
  --space-5: calc(5rem * var(--flex-space-scale));
  --text-sm: 0.875rem;
  --overlay-hero: linear-gradient(to right, rgba(20,18,15,0.72) 0%, rgba(20,18,15,0.40) 55%, rgba(20,18,15,0.12) 100%);
}

/* ── Base ── */
.flex-shell { font-family: var(--font-body); font-size: var(--flex-base-size); background: var(--color-background); color: var(--color-text); min-height: 100vh; display: flex; flex-direction: column; }
.flex-shell h1, .flex-shell h2, .flex-shell h3 { font-family: var(--font-display); line-height: 1.15; margin: 0; }
.flex-main { flex: 1; }
.flex-container { max-width: 72rem; margin-inline: auto; padding-inline: var(--space-2); width: 100%; }
.flex-section { padding-block: var(--space-4); }
.flex-section--tint { background: color-mix(in srgb, var(--color-primary) 6%, var(--color-background)); }
.flex-eyebrow { text-transform: uppercase; letter-spacing: 0.14em; font-size: var(--text-sm); font-weight: 700; color: var(--color-accent); }
.flex-headline { font-size: clamp(1.75rem, 4vw, 2.75rem); margin-top: var(--space-1); }
.flex-accent-text { color: var(--color-accent); font-style: italic; }
.flex-prose { line-height: 1.7; max-width: 46rem; }
.flex-prose a { color: var(--color-primary); }
/* #441 §7 — every multi-paragraph body on the site ran together: this class
   set only line-height and max-width, and the app bundle's Preflight zeroes
   `p`. Rhythm is derived from --space-*, so it scales with the density token
   the operator can actually reach. Descendants only — FeatureGrid and
   ServiceShowPage put .flex-prose ON a <p>, and margin on the class itself
   would move those. Must stay after the `.flex-shell h1,h2,h3 { margin: 0 }`
   rule above: equal specificity, source order decides.
   Physical properties (margin-bottom / margin-top), not the logical
   margin-block shorthand: matches the already-merged rich-text #446
   convention (`.ProseMirror p` etc.) and lets jsdom-based unit tests actually
   observe the rule (jsdom does not expand margin-block into computed
   physical margins). Still deliberately NOT #446's fixed `margin: 0 0 1rem`
   — flex-theme uses none of #446's classes and derives spacing from its own
   --space-* scale instead of a fixed 1rem, so it still respects the density
   token. Do not "harmonise" the two. For the p/ul/ol/blockquote/table rule
   specifically, top margin is left at its Preflight-zeroed default and only
   margin-bottom is set; the heading and list-item rules below it do set
   margin-top. */
.flex-prose p,
.flex-prose ul,
.flex-prose ol,
.flex-prose blockquote,
.flex-prose table { margin-bottom: var(--space-2); }
.flex-prose h2,
.flex-prose h3 { margin-top: var(--space-3); margin-bottom: var(--space-1); }
.flex-prose li + li { margin-top: calc(var(--space-1) * 0.5); }
.flex-prose > :first-child { margin-top: 0; }
.flex-prose > :last-child { margin-bottom: 0; }
.flex-card { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-lg); padding: var(--space-3); }
.flex-grid { display: grid; gap: var(--space-2); }
.flex-grid--2 { grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr)); }
.flex-grid--3 { grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); }

/* ── Buttons (shape variant via shell modifier) ── */
.flex-btn { display: inline-block; padding: 0.7rem 1.4rem; font-weight: 700; text-decoration: none; border: 1px solid transparent; transition: background var(--flex-motion), color var(--flex-motion); }
.flex-buttons-rounded .flex-btn { border-radius: var(--radius); }
.flex-buttons-square  .flex-btn { border-radius: 0; }
.flex-buttons-pill    .flex-btn { border-radius: 9999px; }
.flex-btn--primary { background: var(--color-primary); color: var(--color-primary-foreground); }
.flex-btn--primary:hover { background: color-mix(in srgb, var(--color-primary) 85%, white); }
.flex-btn--ghost { border-color: currentColor; color: inherit; }
.flex-btn--active, .flex-btn--active:hover { background: var(--color-primary); color: var(--color-primary-foreground); border-color: var(--color-primary); }
.flex-btn--disabled, .flex-btn--disabled:hover { opacity: 0.5; cursor: not-allowed; }

/* ── Blog pagination ── */
.flex-blog__pagination { justify-content: center; }

/* ── Header variants ── */
.flex-header { background: var(--color-surface); border-bottom: 1px solid var(--color-border); }
/* #450 item 1 — container-type/container-name turn this element into a
   query container so the mobile-nav collapse below binds to the header's
   OWN rendered inline-size, not the viewport (see the @container block's
   comment for what this does and does not fix). */
.flex-header__inner { display: flex; align-items: center; gap: var(--space-2); padding-block: var(--space-2); container-type: inline-size; container-name: flex-header; }
.flex-header--classic .flex-header__inner { justify-content: space-between; }
.flex-header--centered .flex-header__inner { flex-direction: column; }
.flex-header__brand { font-family: var(--font-display); font-size: 1.35rem; font-weight: 700; color: var(--color-text); text-decoration: none; }
/* #450 item 4 — sourced from tokens.branding.logo_height (renamed from
   tokens.header.logo_height, which collided with the unrelated
   variants.header layout variant) via tokensToCss.js's clampLogoHeight. */
.flex-header__brand img { max-height: var(--flex-logo-height, 3rem); width: auto; }
.flex-header__nav { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.flex-header__nav a { color: var(--color-text); text-decoration: none; font-weight: 500; }
.flex-header__nav a.is-active, .flex-header__nav a:hover { color: var(--color-primary); }
/* #441 §8 / #450 item 1 — the toggle is desktop-hidden; the block below is
   the theme's only header breakpoint.
   #450 item 1 specifically: this used to be `@media (max-width: 720px)`.
   720px was fitted to 413bbq, whose five links need 542px to sit on one
   row — a tenant with more or longer links could still wrap to two rows
   anywhere between 721px and their own overflow width, with no toggle
   available in that band (the pre-existing `flex-wrap: wrap` above was the
   only fallback there).
   This is now a CONTAINER query (`container-type: inline-size` on
   .flex-header__inner, above) instead of a viewport media query. That is a
   real, if partial, fix: it binds the collapse to the actual rendered width
   of the box that holds the nav, rather than to the browser viewport, which
   only usually happens to match it (this header has no max-width of its
   own below .flex-container's 72rem cap, but the two are NOT the same
   quantity, and only one of them is what the nav actually has to fit in).
   What it deliberately does NOT claim to fix: CSS has no primitive for
   "collapse when THIS nav's own links don't fit" independent of a static
   length — a container query still needs a fixed threshold, same as a
   media query did. True per-tenant content-adaptive collapse needs either
   JS-measured overflow (ResizeObserver comparing scrollWidth/clientWidth)
   or a configurable per-tenant token; neither is introduced here. 860px is
   therefore a deliberately generous, documented default (every known
   tenant's nav needs at most 542px) rather than the bare minimum any one
   tenant needs — so a tenant with a longer-than-413bbq nav has real
   headroom before this theme's guessed number becomes their problem again,
   without pretending the guess is gone. */
.flex-header__toggle { display: none; background: none; border: 0; padding: 0.25rem; color: var(--color-text); cursor: pointer; }
@container flex-header (max-width: 860px) {
  .flex-header__toggle { display: inline-flex; align-items: center; }
  .flex-header--classic .flex-header__inner { flex-wrap: wrap; }
  .flex-header__nav { display: none; flex-basis: 100%; flex-direction: column; gap: var(--space-1); padding-block: var(--space-2); }
  .flex-header__nav.is-open { display: flex; }
}

/* ── Hero variants ── */
.flex-hero { position: relative; color: #fff; }
.flex-hero--full_bleed_photo { min-height: 60vh; display: flex; align-items: center; background-size: cover; background-position: center; }
.flex-hero--full_bleed_photo::before { content: ''; position: absolute; inset: 0; background: var(--overlay-hero); }
.flex-hero--full_bleed_photo .flex-hero__content { position: relative; max-width: 36rem; padding-block: var(--space-5); }
.flex-hero--split { color: var(--color-text); }
.flex-hero--split .flex-hero__inner { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-4); align-items: center; padding-block: var(--space-4); }
.flex-hero--split img { width: 100%; border-radius: var(--radius-lg); object-fit: cover; }
.flex-hero--minimal { color: var(--color-text); background: color-mix(in srgb, var(--color-primary) 8%, var(--color-background)); text-align: center; }
.flex-hero--minimal .flex-hero__content { max-width: 42rem; margin-inline: auto; padding-block: var(--space-4); }
.flex-hero__headline { font-size: clamp(2rem, 5vw, 3.4rem); }
.flex-hero__body { margin-top: var(--space-2); line-height: 1.6; }
.flex-hero__actions { margin-top: var(--space-3); display: flex; gap: var(--space-1); justify-content: inherit; flex-wrap: wrap; }
@media (max-width: 720px) { .flex-hero--split .flex-hero__inner { grid-template-columns: 1fr; } }

/* ── Footer variants ── */
.flex-footer { background: var(--color-footer-bg); color: var(--color-footer-text); margin-top: auto; }
.flex-footer__inner { padding-block: var(--space-4); display: grid; gap: var(--space-3); }
.flex-footer--columns .flex-footer__inner { grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); }
.flex-footer--compact .flex-footer__inner { text-align: center; }
.flex-footer a { color: var(--color-footer-text); }
.flex-footer__attribution { grid-column: 1 / -1; text-align: center; font-size: var(--text-sm); opacity: 0.75; padding-top: var(--space-2); border-top: 1px solid color-mix(in srgb, var(--color-footer-text) 25%, transparent); }

/* ── Services index variants ── */
.flex-services--list .flex-section { padding-block: var(--space-2); }
