/* ============================================================
   ARECH Concrete CMS theme — main stylesheet.

   Port of the Astro design-system-v1.md tokens into a Concrete
   theme. Load order:
     1. :root design tokens (mirrors site/src/styles/tokens.css)
     2. @font-face self-host block (mirrors global.css)
     3. Base resets
     4. Layout helpers (container, section padding, grid)
     5. Chrome (site-header / site-footer / buttons / skip-link)
     6. Page templates (default.php / view.php / empty.php classes)
     7. prefers-reduced-motion override

   Any token-level change must update content/documents/design-
   system-v1.md and site/src/styles/tokens.css in the same commit
   so the Astro design reference and the Concrete theme stay in
   lockstep.
   ============================================================ */

/* ============================================================
   1. Design tokens — runtime CSS custom properties.
   Mirror of site/src/styles/tokens.css.
   ============================================================ */

:root {
    /* Colors — dark theme */
    --orange: #e8651a;
    --orange-bright: #ff7a2f;
    --orange-dim: #c4510e;
    --brand-yellow: #feb105;
    --dark: #0d0d0f;
    --dark-2: #141416;
    --dark-3: #1c1c20;
    --dark-4: #252529;
    --white: #ffffff;
    --off-white: #f5f4f0;
    --light: #b0b0ba;
    --muted: #6b6b75;
    --muted-accessible: #909099;

    /* Colors — LIGHT body palette (paper / ink) */
    --paper-0: #ffffff;
    --paper-1: #f5f4f0;
    --paper-2: #edece7;
    --paper-3: #e4e2dc;
    --paper-4: #dad8d2;
    --ink-1: #0a0a0b;
    --ink-2: #2a2a2d;
    --ink-3: #54545a;
    --ink-4: #5f5f69;
    --orange-link: #b84a0c;
    --orange-text: #8c3504;
    --hairline: rgba(10, 10, 11, 0.1);
    --hairline-strong: rgba(10, 10, 11, 0.18);

    /* Spacing scale — 4 px base, 11 steps */
    --space-1: 4px;
    --space-2: 8px;
    --space-3: 12px;
    --space-4: 16px;
    --space-5: 24px;
    --space-6: 32px;
    --space-7: 48px;
    --space-8: 64px;
    --space-9: 96px;
    --space-10: 128px;
    --space-11: 160px;

    /* Containers — responsive_manual_en_0.1 §2: single uniform container,
       NO wide tier. --container = 1140 at XL (1024–1439), steps to 1200 at
       2XL (≥1440) via the media query below. Applied identically to every
       section so all content shares one left edge. */
    --container-narrow: 720px;
    --container: 1140px;

    /* Container horizontal padding (responsive — see media queries below) */
    --container-px: 16px;

    /* Content measure cap — one-off layout width kept as a design token
       (S72: de-magic-numbered from hero_impact). The FAQ reading column uses
       the existing --container-narrow token, per the prototype. */
    --measure-hero:  1100px;  /* hero content cap */

    /* Corner radius scale (S72: --radius-md 6px is the rounded-corner CEILING
       per user pref — nothing rounder except intentional pills). */
    --radius-xs:   2px;
    --radius-sm:   4px;
    --radius-md:   6px;
    --radius-pill: 999px;

    /* Motion — durations + easings + stagger */
    --motion-instant: 0ms;
    --motion-fast: 150ms;
    --motion-normal: 250ms;
    --motion-slow: 400ms;
    --motion-slower: 600ms;
    --motion-reveal: 800ms;
    --motion-cinematic: 1200ms;
    --motion-ambient-fast: 20s;
    --motion-ambient-slow: 30s;
    --ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
    --ease-decelerate: cubic-bezier(0, 0, 0.2, 1);
    --ease-accelerate: cubic-bezier(0.4, 0, 1, 1);
    --ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);
    --ease-linear: linear;
    --stagger-1: 0ms;
    --stagger-2: 100ms;
    --stagger-3: 200ms;
    --stagger-4: 300ms;
    --stagger-5: 400ms;

    /* Font stacks */
    --font-display: 'Geist', system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
    --font-headline: 'General Sans', 'Inter', system-ui, sans-serif;
    --font-body: 'DM Sans', system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
    --font-mono: 'DM Mono', 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace;

    /* Chrome heights — used to offset main below the sticky header */
    --header-height: 72px;
}

/* responsive_manual_en_0.1 §1–§2 — min-width only; gutter 16→20→24→32→40;
   container steps 1140 → 1200 at the 2XL breakpoint (≥1440). */
@media (min-width: 680px)  { :root { --container-px: 20px; } }
@media (min-width: 768px)  { :root { --container-px: 24px; } }
@media (min-width: 1024px) { :root { --container-px: 32px; --header-height: 80px; } }
@media (min-width: 1440px) { :root { --container-px: 40px; --container: 1200px; } }

/* ============================================================
   2. @font-face — self-hosted woff2 (mirror of global.css block).
   Files live under <theme>/fonts/<family>/<weight>.woff2.
   size-adjust + ascent/descent/line-gap-override descriptors lock
   the line-box dimensions to match the system-ui fallback so the
   swap from fallback → web font does not spike CLS.
   ============================================================ */

/* Geist — Display */
@font-face {
    font-family: 'Geist';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('../fonts/geist/400-regular.woff2') format('woff2');
    size-adjust: 100%;
    ascent-override: 95%;
    descent-override: 22%;
    line-gap-override: 0%;
}
@font-face {
    font-family: 'Geist';
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url('../fonts/geist/500-medium.woff2') format('woff2');
    size-adjust: 100%;
    ascent-override: 95%;
    descent-override: 22%;
    line-gap-override: 0%;
}
@font-face {
    font-family: 'Geist';
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url('../fonts/geist/700-bold.woff2') format('woff2');
    size-adjust: 100%;
    ascent-override: 95%;
    descent-override: 22%;
    line-gap-override: 0%;
}
@font-face {
    font-family: 'Geist';
    font-style: normal;
    font-weight: 900;
    font-display: swap;
    src: url('../fonts/geist/900-black.woff2') format('woff2');
    size-adjust: 100%;
    ascent-override: 95%;
    descent-override: 22%;
    line-gap-override: 0%;
}

/* General Sans — Headline */
@font-face {
    font-family: 'General Sans';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('../fonts/general-sans/400-regular.woff2') format('woff2');
    size-adjust: 100%;
    ascent-override: 95%;
    descent-override: 22%;
    line-gap-override: 0%;
}
@font-face {
    font-family: 'General Sans';
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url('../fonts/general-sans/500-medium.woff2') format('woff2');
    size-adjust: 100%;
    ascent-override: 95%;
    descent-override: 22%;
    line-gap-override: 0%;
}
@font-face {
    font-family: 'General Sans';
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url('../fonts/general-sans/600-semibold.woff2') format('woff2');
    size-adjust: 100%;
    ascent-override: 95%;
    descent-override: 22%;
    line-gap-override: 0%;
}
@font-face {
    font-family: 'General Sans';
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url('../fonts/general-sans/700-bold.woff2') format('woff2');
    size-adjust: 100%;
    ascent-override: 95%;
    descent-override: 22%;
    line-gap-override: 0%;
}

/* DM Sans — Body */
@font-face {
    font-family: 'DM Sans';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('../fonts/dm-sans/400-regular.woff2') format('woff2');
    size-adjust: 100%;
    ascent-override: 95%;
    descent-override: 22%;
    line-gap-override: 0%;
}
@font-face {
    font-family: 'DM Sans';
    font-style: italic;
    font-weight: 400;
    font-display: swap;
    src: url('../fonts/dm-sans/400-italic.woff2') format('woff2');
    size-adjust: 100%;
    ascent-override: 95%;
    descent-override: 22%;
    line-gap-override: 0%;
}
@font-face {
    font-family: 'DM Sans';
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url('../fonts/dm-sans/500-medium.woff2') format('woff2');
    size-adjust: 100%;
    ascent-override: 95%;
    descent-override: 22%;
    line-gap-override: 0%;
}
@font-face {
    font-family: 'DM Sans';
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url('../fonts/dm-sans/600-semibold.woff2') format('woff2');
    size-adjust: 100%;
    ascent-override: 95%;
    descent-override: 22%;
    line-gap-override: 0%;
}
@font-face {
    font-family: 'DM Sans';
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url('../fonts/dm-sans/700-bold.woff2') format('woff2');
    size-adjust: 100%;
    ascent-override: 95%;
    descent-override: 22%;
    line-gap-override: 0%;
}

/* DM Mono — Eyebrows / captions */
@font-face {
    font-family: 'DM Mono';
    font-style: normal;
    font-weight: 300;
    font-display: swap;
    src: url('../fonts/dm-mono/300-light.woff2') format('woff2');
    size-adjust: 100%;
    ascent-override: 95%;
    descent-override: 22%;
    line-gap-override: 0%;
}
@font-face {
    font-family: 'DM Mono';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('../fonts/dm-mono/400-regular.woff2') format('woff2');
    size-adjust: 100%;
    ascent-override: 95%;
    descent-override: 22%;
    line-gap-override: 0%;
}
@font-face {
    font-family: 'DM Mono';
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url('../fonts/dm-mono/500-medium.woff2') format('woff2');
    size-adjust: 100%;
    ascent-override: 95%;
    descent-override: 22%;
    line-gap-override: 0%;
}

/* ============================================================
   3. Base resets.
   ============================================================ */

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

html {
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
    scroll-behavior: smooth;
    scroll-padding-top: calc(var(--header-height) + 16px);
}

body {
    margin: 0;
    font-family: var(--font-body);
    font-size: 16px;
    font-weight: 400;
    line-height: 1.65;
    color: var(--off-white);
    background-color: var(--dark);
    min-height: 100vh;
    overflow-x: hidden;
}

h1, h2, h3, h4, h5, h6 {
    margin: 0;
    font-family: var(--font-headline);
    line-height: 1.2;
    color: var(--off-white);
}

h1 {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: clamp(48px, 6vw, 88px);
    line-height: 1.05;
    letter-spacing: -0.015em;
}
h2 {
    font-weight: 600;
    font-size: clamp(42px, 5vw, 72px);
    line-height: 1.1;
    letter-spacing: -0.01em;
}
h3 {
    font-weight: 600;
    font-size: clamp(28px, 3vw, 36px);
    line-height: 1.2;
    letter-spacing: -0.005em;
}
h4 {
    font-weight: 500;
    font-size: 20px;
    line-height: 1.3;
}
h5 {
    font-weight: 600;
    font-size: 16px;
    line-height: 1.4;
    letter-spacing: 0.02em;
}

p { margin: 0 0 var(--space-4); }
p:last-child { margin-bottom: 0; }

a {
    color: var(--orange);
    text-decoration: none;
    transition: color var(--motion-fast) var(--ease-standard);
}
a:hover { color: var(--orange-bright); }

img, svg, video {
    display: block;
    max-width: 100%;
    height: auto;
}

button {
    font-family: inherit;
    font-size: inherit;
    border: none;
    background: transparent;
    cursor: pointer;
    color: inherit;
}

:focus-visible {
    outline: 2px solid var(--orange);
    outline-offset: 2px;
    border-radius: var(--radius-xs);
}

/* Eyebrow + lead helpers (theme block classes) */
.eyebrow {
    font-family: var(--font-mono);
    font-size: 11px;
    font-weight: 500;
    line-height: 1;
    letter-spacing: 0.2em;
    text-transform: uppercase;
    color: var(--orange);
    display: inline-block;
    margin-bottom: var(--space-4);
}
.lead {
    font-size: 20px;
    line-height: 1.55;
    color: var(--light);
    max-width: 65ch;
}

/* ============================================================
   4. Layout helpers — container + section padding + grid.
   ============================================================ */

/* ---- CANONICAL CONTAINER BOX (S72) ---------------------------------------
   Every section's content must land at left edge (vp − --container)/2 with a
   content width of --container, capped by --container-px gutters. With the
   global border-box reset there are exactly TWO correct source forms, keyed
   strictly to DOM structure — never mix them within one structural case:

     • MULTI-ELEMENT (band + __inner): gutter on the band
       (`padding-inline: var(--container-px)`), inner is
       `max-width: var(--container); margin-inline: auto;` with NO inner
       padding. → all .arech-* blocks. (Scroll containers like
       .arech-sst__inner are a documented exception — gutter stays on inner.)

     • SINGLE-ELEMENT (no inner wrapper — e.g. native content safety-net):
       `max-width: calc(var(--container) + 2 * var(--container-px));
        padding-inline: var(--container-px); margin-inline: auto;`
       The +2·gutter offsets the border-box-absorbed padding so the content
       edge still equals (vp − --container)/2.

   APPLIED (S72, user-approved): `.container` is single-element, so it uses the
   calc() form (content + both gutters). This lands its content at the SAME left
   edge and width as the section blocks, aligning navbar / footer / hero / cta
   with section content per the locked responsive standard ("navbar, footer cap
   identically"). Previously it was 2·--container-px narrower + inset one gutter.
   ------------------------------------------------------------------------- */
.container {
    max-width: calc(var(--container) + 2 * var(--container-px));
    margin-inline: auto;
    padding-inline: var(--container-px);
}
.container--narrow { max-width: var(--container-narrow); }

/* Section padding presets — DS § 7.
   Modest = content sections. Premium = hero / CTA / showcase. */
.section-modest  { padding-block: 60px; }
.section-premium { padding-block: 80px; }
@media (min-width: 480px) {
    .section-modest  { padding-block: 60px; }
    .section-premium { padding-block: 100px; }
}
@media (min-width: 768px) {
    .section-modest  { padding-block: 80px; }
    .section-premium { padding-block: 120px; }
}
@media (min-width: 1024px) {
    .section-modest  { padding-block: 120px; }
    .section-premium { padding-block: 160px; }
}

.section-dark  { background-color: var(--dark); color: var(--off-white); }
.section-paper { background-color: var(--paper-1); color: var(--ink-2); }
.section-paper h1, .section-paper h2, .section-paper h3,
.section-paper h4, .section-paper h5, .section-paper h6 { color: var(--ink-1); }
.section-paper a { color: var(--orange-link); }
.section-paper a:hover { color: var(--orange-text); }

/* ============================================================
   5. Chrome — skip-link, site-header, site-footer, buttons.
   ============================================================ */

.skip-link {
    position: absolute;
    top: -40px;
    left: var(--space-4);
    background: var(--orange);
    color: var(--white);
    padding: var(--space-2) var(--space-4);
    z-index: 1000;
    transition: top var(--motion-fast) var(--ease-standard);
}
.skip-link:focus { top: var(--space-2); color: var(--white); }

/* --- Site header --- */
.site-header {
    position: sticky;
    top: 0;
    z-index: 100;
    background-color: rgba(13, 13, 15, 0.85);
    backdrop-filter: saturate(180%) blur(12px);
    -webkit-backdrop-filter: saturate(180%) blur(12px);
    border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
.site-header__inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-5);
    min-height: var(--header-height);
}
.site-logo {
    display: inline-flex;
    align-items: center;
    color: var(--off-white);
    flex-shrink: 0;
}
.site-logo__mark {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: 22px;
    letter-spacing: 0.04em;
    color: var(--brand-yellow);
}
.site-logo--footer .site-logo__mark { font-size: 26px; }

.site-nav {
    display: none;
    flex: 1;
    justify-content: center;
}
.site-nav ul {
    display: flex;
    list-style: none;
    margin: 0;
    padding: 0;
    gap: var(--space-6);
}
.site-nav a {
    font-family: var(--font-headline);
    font-weight: 500;
    font-size: 15px;
    color: var(--off-white);
    padding: var(--space-3) 0;
    transition: color var(--motion-fast) var(--ease-standard);
}
.site-nav a:hover { color: var(--orange-bright); }
.site-nav .nav-selected a,
.site-nav .nav-path-selected > a { color: var(--orange); }

.site-header__cta { display: none; }
@media (min-width: 1024px) {
    .site-nav,
    .site-header__cta { display: flex; }
}

.site-header__burger {
    display: inline-flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: 5px;
    width: 44px;
    height: 44px;
    margin-inline-start: auto;
}
.site-header__burger span {
    display: block;
    width: 22px;
    height: 2px;
    background-color: var(--off-white);
    border-radius: var(--radius-xs);
    transition: transform var(--motion-fast) var(--ease-standard),
                opacity var(--motion-fast) var(--ease-standard);
}
.site-header__burger[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.site-header__burger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.site-header__burger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
@media (min-width: 1024px) {
    .site-header__burger { display: none; }
}

/* S55 H1 fix — `display: flex` was overriding the `hidden` HTML attribute on
   the mobile drawer, leaving it permanently visible. The HTML attribute
   `hidden` defaults to `display: none` BUT any explicit `display:` declaration
   wins. Two-step fix: (1) global guard for `[hidden]` so it always collapses,
   (2) scope the drawer's flex layout to the non-hidden state. */
[hidden] { display: none !important; }
.site-nav-mobile:not([hidden]) {
    background-color: var(--dark-2);
    border-top: 1px solid rgba(255, 255, 255, 0.08);
    padding: var(--space-6) var(--container-px);
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}
.site-nav-mobile ul {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}
.site-nav-mobile a {
    font-family: var(--font-headline);
    font-weight: 500;
    font-size: 17px;
    color: var(--off-white);
    display: block;
    padding: var(--space-3) 0;
    border-bottom: 1px solid rgba(255, 255, 255, 0.06);
}

/* --- Buttons --- */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-2);
    font-family: var(--font-headline);
    font-weight: 600;
    font-size: 15px;
    line-height: 1;
    padding: 12px 24px;
    border-radius: var(--radius-pill);
    cursor: pointer;
    transition:
        background-color var(--motion-fast) var(--ease-standard),
        color var(--motion-fast) var(--ease-standard),
        transform var(--motion-fast) var(--ease-standard);
    min-height: 44px;
    text-align: center;
    white-space: nowrap;
}
.btn--primary {
    background-color: var(--orange);
    color: var(--white);
}
.btn--primary:hover {
    background-color: var(--orange-bright);
    color: var(--white);
    transform: translateY(-1px);
}
.btn--primary:active {
    background-color: var(--orange-dim);
    transform: translateY(0);
}
.btn--secondary {
    background-color: transparent;
    color: var(--off-white);
    box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.2);
}
.btn--secondary:hover {
    color: var(--orange-bright);
    box-shadow: inset 0 0 0 1px var(--orange-bright);
}
.btn--block { width: 100%; }

/* --- Main shell --- */
.site-main { display: block; min-height: 50vh; }

/* --- Site footer --- */
.site-footer {
    background-color: var(--dark-2);
    color: var(--light);
    border-top: 1px solid rgba(255, 255, 255, 0.08);
    padding-block: var(--space-9) var(--space-6);
    margin-top: var(--space-10);
}
.site-footer__inner {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-8);
}
@media (min-width: 768px) {
    .site-footer__inner {
        grid-template-columns: 1.4fr 1fr 1fr 1.4fr;
        gap: var(--space-7);
    }
}
.site-footer__heading {
    font-family: var(--font-headline);
    font-weight: 600;
    font-size: 16px;
    color: var(--off-white);
    margin-bottom: var(--space-4);
    letter-spacing: 0.01em;
}
.site-footer__col ul {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
}
.site-footer__col a {
    color: var(--light);
    font-size: 14px;
    transition: color var(--motion-fast) var(--ease-standard);
}
.site-footer__col a:hover { color: var(--orange-bright); }
.site-footer__tagline {
    font-family: var(--font-mono);
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 0.15em;
    color: var(--muted-accessible);
    margin-top: var(--space-3);
}
.site-footer__certs {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    margin-top: var(--space-5);
    list-style: none;
    padding: 0;
}
.site-footer__certs li {
    font-family: var(--font-mono);
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 0.1em;
    color: var(--off-white);
    padding: 4px 10px;
    border: 1px solid rgba(255, 255, 255, 0.18);
    border-radius: var(--radius-sm);
}
.site-footer__address {
    font-style: normal;
    font-size: 14px;
    line-height: 1.6;
    color: var(--light);
}
.site-footer__address strong { color: var(--off-white); }
.site-footer__contact {
    margin-top: var(--space-4);
}
.site-footer__base {
    margin-top: var(--space-8);
    padding-top: var(--space-5);
    border-top: 1px solid rgba(255, 255, 255, 0.06);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
}
.site-footer__copy {
    margin: 0;
    font-size: 13px;
    color: var(--muted-accessible);
}

/* === BEGIN STEP 1 GAP-FIX === */

/* ============================================================
   § 5b. Global Layout Gap-Fixes (S68 Step 1)
   Five additive patches: GAP-1 .legal-hero pattern, GAP-2 touch
   target 44x44 enforcement, GAP-3 cascade layer declaration,
   GAP-4 grid utilities, GAP-5 .lead fluid clamp.
   No tokens introduced — all values resolve to :root tokens
   declared in § 1 and design-system-v1.md sections referenced
   inline below.
   ============================================================ */

/* ---------- GAP-3: Cascade layer order (DS § 9, system hygiene)
   Declared layer-only (no rules yet). Future polish CSS opts into
   a named layer; critical UX rules (focus-visible, touch targets,
   skip-link) stay unlayered so Concrete-injected admin CSS in
   later cascade positions cannot win against them.
   `overrides` is last and reserved for the rare `!important`. */
@layer reset, tokens, base, layout, components, prose, utilities, overrides;

/* ---------- GAP-2: Touch target 44x44 enforcement (DS § 8)
   Unlayered on purpose. WCAG 2.5.5 + DS § 8 hard floor.
   `:where()` keeps specificity at 0,0,0 so inline-prose anchors
   inside `.prose p a` (which only need their normal text hit-area)
   are NOT inflated, only navigation / footer / dialog controls
   and form fields receive the floor. */
:where(.site-nav a,
       .site-nav-mobile a,
       .site-footer__col a,
       .site-footer__base a,
       [role="button"]:not(.btn),
       button:not(.btn):not(.btn-toggle):not([aria-label-hidden])) {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
}

:where(input[type="text"],
       input[type="email"],
       input[type="tel"],
       input[type="url"],
       input[type="search"],
       input[type="number"],
       input[type="password"],
       select,
       textarea) {
    min-height: 44px;
    padding-block: var(--space-2);
    padding-inline: var(--space-3);
    font: inherit;
}

/* Icon-only buttons — wrap in 44x44 hit area. Use :has() so any
   <button> that contains ONLY an <svg> (no text node sibling) is
   given the floor. Falls back gracefully: pre-:has() browsers
   keep the button at intrinsic size — visual still readable, only
   tap-area shrinks. */
:where(button, a):has(> svg:only-child) {
    min-width: 44px;
    min-height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

@layer layout {
    /* ---------- GAP-1: .legal-hero pattern (DS § 3 H1 subpage / § 7 premium padding)
       S66 compose used `<div class="legal-hero">` on legal pages
       (cookie / privacy / terms), sitemap, products hub, contact,
       and 4 list pages. Mirrors the `subpage-header-explore` v1
       proto: eyebrow + h1 (max 22ch) + lead (max 65ch) + optional
       meta row, on a premium-padded full-bleed band centred via
       --container. */
    .legal-hero {
        padding-block: var(--space-9);
        padding-inline: var(--container-px);
        background-color: var(--dark);
        color: var(--off-white);
    }
    .legal-hero__inner {
        max-width: var(--container);
        margin-inline: auto;
    }
    .legal-hero .eyebrow { margin-bottom: var(--space-5); }

    .legal-hero h1,
    .legal-hero .legal-hero__h1 {
        font-family: var(--font-headline);
        font-weight: 600;
        font-size: clamp(40px, 5vw, 64px);
        line-height: 1.05;
        letter-spacing: -0.015em;
        color: var(--off-white);
        max-width: 22ch;
        margin-block-end: var(--space-5);
    }
    .legal-hero h1 .accent,
    .legal-hero__h1 .accent { color: var(--orange); }

    .legal-hero .lead,
    .legal-hero__lead {
        max-width: 65ch;
        margin-block-end: var(--space-6);
    }

    /* Optional meta strip (last-updated, jurisdiction, etc.).
       Renders inline below the lead, hairline-separated. */
    .legal-hero__meta {
        display: flex;
        flex-wrap: wrap;
        gap: var(--space-2) var(--space-5);
        padding-block-start: var(--space-5);
        border-block-start: 1px solid rgba(255, 255, 255, 0.08);
        font-family: var(--font-mono);
        font-size: 12px;
        letter-spacing: 0.15em;
        text-transform: uppercase;
        color: var(--muted-accessible);
    }
    .legal-hero__meta > * + *::before {
        content: "·";
        margin-inline-end: var(--space-3);
        color: var(--muted);
    }

    /* Premium scale-up on >= md (DS § 7 premium ladder). */
    @media (min-width: 768px) {
        .legal-hero { padding-block: var(--space-10); }
    }
    @media (min-width: 1024px) {
        .legal-hero { padding-block: var(--space-11); }
    }

    /* LIGHT-paper variant — when legal-hero lives inside a
       paper section, swap text + accent colours to satisfy
       DS § 1.B LIGHT-Rule-7 (link-and-accent role split). */
    .section-paper .legal-hero,
    .legal-hero.section-paper {
        background-color: var(--paper-1);
        color: var(--ink-2);
    }
    .section-paper .legal-hero h1,
    .legal-hero.section-paper h1 { color: var(--ink-1); }
    .section-paper .legal-hero__meta,
    .legal-hero.section-paper .legal-hero__meta {
        color: var(--ink-3);
        border-block-start-color: var(--hairline);
    }
}

@layer utilities {
    /* ---------- GAP-4: Grid utilities (DS § 9.5 column progression)
       Mobile-first 1-col base; container queries gate breakpoint
       upgrades against the grid's nearest sized ancestor where
       the consumer opts in via `.grid--cq`. Default modifiers
       still use min-width media queries (DS § 5 viewport bps) so
       legacy block templates without container-type continue to
       respond by viewport. */
    .grid {
        display: grid;
        gap: var(--space-5);
        grid-template-columns: 1fr;
    }
    .grid--gap-sm { gap: var(--space-4); }
    .grid--gap-lg { gap: var(--space-7); }

    /* Viewport-anchored progressions (default behaviour).
       Ladder anchored to manual breakpoints: 2-col @MD 680,
       3-col @XL 1024, 4-col @2XL 1440. (1140 was illegal.) */
    @media (min-width: 680px) {
        .grid--2-col-md { grid-template-columns: repeat(2, minmax(0, 1fr)); }
        .grid--3-col-lg { grid-template-columns: repeat(2, minmax(0, 1fr)); }
        .grid--3-col-xl { grid-template-columns: repeat(2, minmax(0, 1fr)); }
        .grid--4-col-xl { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    }
    @media (min-width: 1024px) {
        .grid--2-col-lg { grid-template-columns: repeat(2, minmax(0, 1fr)); }
        .grid--3-col-lg { grid-template-columns: repeat(3, minmax(0, 1fr)); }
        .grid--3-col-xl { grid-template-columns: repeat(3, minmax(0, 1fr)); }
        .grid--4-col-xl { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    }
    @media (min-width: 1440px) {
        .grid--4-col-xl { grid-template-columns: repeat(4, minmax(0, 1fr)); }
    }

    /* Opt-in container-query mode: parent declares
       `container-type: inline-size` and adds `.grid--cq` to the
       grid. Same breakpoints, evaluated against container width. */
    .grid--cq-host { container-type: inline-size; }
    @container (min-width: 680px) {
        .grid--cq.grid--2-col-md,
        .grid--cq.grid--3-col-lg,
        .grid--cq.grid--3-col-xl,
        .grid--cq.grid--4-col-xl { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    }
    @container (min-width: 1024px) {
        .grid--cq.grid--2-col-lg,
        .grid--cq.grid--3-col-lg { grid-template-columns: repeat(3, minmax(0, 1fr)); }
        .grid--cq.grid--3-col-xl { grid-template-columns: repeat(3, minmax(0, 1fr)); }
        .grid--cq.grid--4-col-xl { grid-template-columns: repeat(3, minmax(0, 1fr)); }
    }
    @container (min-width: 1440px) {
        .grid--cq.grid--4-col-xl { grid-template-columns: repeat(4, minmax(0, 1fr)); }
    }

    /* ---------- GAP-5: .lead fluid clamp (DS § 3 fluid typography)
       Overrides the legacy hardcoded 20px in § 3 of main.css.
       Placed in @layer utilities so it wins over the unlayered
       baseline `.lead` rule (layered rules beat unlayered when
       layers are declared — but layered rules lose to unlayered
       only when specificity ties; here we add `:where()` to keep
       specificity at the same 0,0,1,0 floor so the override is
       deterministic). */
    :where(.lead) {
        font-size: clamp(18px, 1.5vw, 22px);
        line-height: 1.55;
        color: var(--light);
        max-width: 65ch;
    }
    .section-paper :where(.lead) { color: var(--ink-3); }
}

/* ---------- Reduced-motion branch (DS § 10 mandate)
   The patches above declare zero animations or transitions, so
   this branch is a defence-in-depth no-op: any future polish
   added inside @layer components / utilities that introduces
   motion is covered by the global rule in § 7. Documented here
   so a future editor knows reduced-motion was considered. */
@media (prefers-reduced-motion: reduce) {
    /* No new motion introduced by § 5b — global § 7 rule covers
       any future additions. Intentionally empty. */
}

/* === END STEP 1 GAP-FIX === */

/* ============================================================
   6. Page templates — default.php / view.php / empty.php.
   ============================================================ */

.page-default__hero { padding-block: var(--space-9) var(--space-6); }
/* S55 M2 — Main no longer adds its own padding-block. Each block in
   Main now paints its own background to viewport edges and owns its
   vertical rhythm via the block's own padding-block declaration. A
   wrapper padding here would split adjacent full-bleed bands with a
   gap of the body background (--dark) and break the visual flow. */
.page-default__body { padding-block: 0; }
.page-default__cta  { padding-block: var(--space-9); }

/* S69 SAFETY NET — raw native content blocks dropped straight into Main
   (e.g. About page sections: bare <blockquote>/<p> with no .arech-prose
   wrapper) would otherwise render full-bleed at left:0, misaligned from
   every styled section. Give any Main child that ISN'T one of our own
   self-containing blocks the same centred --container grid + padding, so
   every section starts at the one shared left edge. Our blocks (.arech-*,
   .legal-section, .arech-prose, .container) opt OUT — they manage their
   own width. This makes alignment the DEFAULT, not something each block
   must remember to add. */
.page-default__body > :not([class*="arech-"]):not(.legal-section):not(.container):not(.ccm-block-styles):not(script):not(style) {
    /* Concrete drops native content as a FLAT run of bare <p>/<h2>/<h3>/<ul>/
       <blockquote> siblings straight into Main (no section wrapper). Centre
       EACH one itself on the shared --container column with the standard
       gutter, so they line up with every styled section at the one left edge.
       (Not display:grid here — these elements have no child wrapper to place;
       they ARE the content, so they get the max-width + auto margins.) */
    /* Prototype .container formula: max-width = content + both gutters, with
       the gutter as padding. At desktop the text lands exactly where the
       custom blocks' text lands (gutter is absorbed, not added); at mobile
       the padding gives the edge breathing room. */
    max-width: calc(var(--container) + 2 * var(--container-px));
    margin-inline: auto;
    padding-inline: var(--container-px);
    box-sizing: border-box;
}
/* Bare <ul>/<ol> carry the browser's default list indent (~40px
   padding-inline-start) which pushes them past the shared left edge.
   Move the markers inside so the list box aligns with the paragraphs. */
.page-default__body > ul:not([class*="arech-"]),
.page-default__body > ol:not([class*="arech-"]) {
    /* Same content box as the paragraphs (max-width var(--container),
       centered, standard gutter — inherited from the safety-net rule above).
       The default list indent is moved inside so the list TEXT lines up with
       paragraph text rather than hanging 40px further right. */
    list-style-position: inside;
    padding-inline: var(--container-px);
}
@media (min-width: 768px) {
    .page-default__body > :not([class*="arech-"]):not(.legal-section):not(.container):not(.ccm-block-styles):not(script):not(style):where(p, blockquote, li) {
        text-align: justify;
        text-justify: inter-word;
        hyphens: auto;
    }
}

.page-view { padding-block: var(--space-8); }
.page-view__body { max-width: var(--container-narrow); margin-inline: auto; }

/* System pages (login, error, password recovery) — empty.php */
.is-system-page {
    background:
        radial-gradient(ellipse 80% 60% at 50% 0%, rgba(232, 101, 26, 0.08), transparent 60%),
        var(--dark);
    min-height: 100vh;
    display: grid;
    place-items: center;
}
.system-shell {
    width: 100%;
    padding: var(--space-7) var(--container-px);
}
.system-shell__inner {
    max-width: 480px;
    margin-inline: auto;
    padding: var(--space-7);
    background-color: var(--dark-2);
    border: 1px solid rgba(255, 255, 255, 0.08);
    border-radius: var(--radius-md);
}

/* ============================================================
   7. prefers-reduced-motion — kills all animation.
   ============================================================ */

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* ============================================================
   7b. Prose typography port (S55 M3) — long-form text styling
   for native Concrete `content` blocks dropped on a page with
   class hooks .arech-prose / .arech-eyebrow / .arech-pullquote
   / .arech-accent / .arech-address-card and the section flavour
   classes .arech-section-who (dark band) / .arech-section-addresses
   (paper band).

   Why UNLAYERED: the global resets at section 3 (h2 / h4 / p /
   a) sit unlayered. To override them on prose surfaces without
   bumping specificity, these rules also sit unlayered and rely
   on the descendant-selector specificity boost (.arech-prose h2
   = 0,1,1 vs the bare h2 = 0,0,1). Adding a cascade layer would
   demote these below the global resets per CSS Cascade L5 and
   they would never paint.

   Tokens referenced (all from section 1 above + DS § 1, 2, 4, 10):
     palette  — --orange, --off-white, --ink-1..3, --dark, --paper-1,
                --paper-2, --hairline
     space    — --space-3..9, --container-px, --container-narrow,
                --container, --radius-md (via fallback 4px)
     type     — --font-display, --font-body, --font-mono
     motion   — --motion-fast, --ease-standard
   ============================================================ */

/* Prose band — full-bleed surface that hosts the long-form HTML
   typed into a native Concrete content block. Block paints its
   own background to viewport edges; the .prose-body child centres
   on a reading width. */
.arech-prose {
    /* S69 ROOT-CAUSE FIX — content-grid: the band paints full-bleed, but a
       centred --container column holds all content, and every child is
       anchored to that column-edge (left). This is the CSS equivalent of
       the prototype <section><div class="container"> wrapper and is what
       makes the WHO-WE-ARE / ADDRESSES sections line up with the custom
       blocks (which all centre at var(--container)). */
    display: grid;
    grid-template-columns:
        [full-start] minmax(var(--container-px), 1fr)
        [content-start] minmax(0, var(--container)) [content-end]
        minmax(var(--container-px), 1fr) [full-end];
    padding-block: var(--space-9);
    font-family: var(--font-body);
    font-size: clamp(17px, 1.4vw, 19px);
    line-height: 1.65;
    color: inherit;
    container-type: inline-size;
}
.arech-prose > * { grid-column: content; }
@media (min-width: 768px)  { .arech-prose { padding-block: var(--space-10); } }
@media (min-width: 1024px) { .arech-prose { padding-block: var(--space-11); } }

/* Body — fills the content column (S69: no longer a narrow 720px column
   that wasted the right half of the band). The prose paragraphs cap their
   own line length via `.arech-prose p { max-width: 60ch }`, so the body can
   span the full --container width and still read comfortably. */
.arech-prose__inner,
.arech-prose .prose-body {
    max-width: none;
    margin-inline: 0;
}

/* S69 FILL-WIDTH — prototype `.section-who .layout` is a 2-column grid at
   >=1024px: heading column (eyebrow + h2) on the left, body paragraphs on
   the right, both filling the section width; the pullquote spans full-width
   underneath. This replaces the flat single-column stack that left the
   right half of the band empty and made the page a long "sausage".
   (prototype index.html L896-907, L1691-1714.) */
@media (min-width: 1024px) {
    /* 2-col split. CRITICAL: NO column-gap on the outer grid — a column-gap
       inflates the side gutter tracks and shifts content-start inward, so the
       section would no longer start at the same x as every other section
       (the 641-vs-673 bug). Side gutters stay pure minmax; the visual gap
       between the two content halves is a padding on the body column. */
    .arech-prose.arech-section-who {
        column-gap: 0;
        row-gap: var(--space-7);
        align-items: end;
        grid-template-columns:
            [full-start] minmax(var(--container-px), 1fr)
            [content-start] minmax(0, calc(var(--container) / 2)) [col-mid] minmax(0, calc(var(--container) / 2)) [content-end]
            minmax(var(--container-px), 1fr) [full-end];
    }
    .arech-prose.arech-section-who > .arech-eyebrow { grid-column: content; grid-row: 1; align-self: start; }
    .arech-prose.arech-section-who > h2 {
        grid-column: content-start / col-mid;
        grid-row: 2;
        margin-block-end: 0;
    }
    .arech-prose.arech-section-who > .prose-body {
        grid-column: col-mid / content-end;
        grid-row: 2;
        padding-inline-start: var(--space-8);
    }
    .arech-prose.arech-section-who > .arech-pullquote { grid-column: content; grid-row: 3; }
}

/* Section-flavour wrappers — `.arech-section-who` (dark) +
   `.arech-section-addresses` (paper). Provide the full-bleed
   surface paint that the unwrapped Main area now allows. */
.arech-prose.arech-section-who {
    background-color: var(--dark);
    color: var(--off-white);
}
.arech-prose.arech-section-addresses {
    background-color: var(--paper-1);
    color: var(--ink-1);
}

/* ============================================================
   S69 — `.legal-section` fill-width adoption.
   `.legal-section` is the bare wrapper emitted by the S66 compose
   scripts (legal pages, list pages, products hub, contact, sitemap).
   It had ZERO rules in main.css, so those sections rendered as an
   unstyled flush-left sausage. Give it the SAME centred content-column
   grid + fill-width body as `.arech-prose`, so every one of those pages
   inherits the uniform layout with no compose-script edits. */
.legal-section {
    display: grid;
    grid-template-columns:
        [full-start] minmax(var(--container-px), 1fr)
        [content-start] minmax(0, var(--container)) [content-end]
        minmax(var(--container-px), 1fr) [full-end];
    padding-block: var(--space-8);
}
@media (min-width: 768px)  { .legal-section { padding-block: var(--space-9); } }
@media (min-width: 1024px) { .legal-section { padding-block: var(--space-10); } }
.legal-section > * { grid-column: content; max-width: none; }
.legal-section > h2 {
    font-family: var(--font-display);
    font-weight: 700;
    font-size: clamp(28px, 3.4vw, 44px);
    line-height: 1.1;
    letter-spacing: -0.01em;
    margin: 0 0 var(--space-5);
}
.legal-section :where(p, li) { max-width: none; }
@media (min-width: 768px) {
    .legal-section :where(p, li) {
        text-align: justify;
        text-justify: inter-word;
        hyphens: auto;
    }
}
.legal-section p + p,
.legal-section ul,
.legal-section ol { margin-block-start: var(--space-4); }

/* Heading inside prose — display-font H2 anchored to the DS
   type scale. Defeats the global `h2 { color: var(--off-white); }`
   via descendant-selector specificity, then inherits theme colour
   from the section-flavour wrapper. */
.arech-prose h2 {
    font-family: var(--font-display);
    font-weight: 700;
    /* S55 D3 — H2 clamp aligned to prototype global h2 rule
       (`clamp(42px, 5vw, 72px)` in prototypes/homepage/index.html L391-398).
       Previous `clamp(32px, 5vw, 60px)` was two scale steps too small. */
    font-size: clamp(42px, 5vw, 72px);
    line-height: 1.05;
    letter-spacing: -0.01em;
    color: inherit;
    margin: 0 0 var(--space-5);
    /* S56 P4 — soft cap raised from 42ch to 64ch. 42ch forced "ARECH is
       a factory-direct LED display manufacturer based in Shenzhen."
       (60+ chars) to wrap on 2 narrow lines that didn't match the
       prototype's wider reading column. 64ch holds the long headline
       on 2 well-balanced lines at typical reading widths. */
    max-width: min(64ch, 100%);
}
.arech-prose h3 {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: clamp(22px, 2.6vw, 30px);
    line-height: 1.2;
    color: inherit;
    margin: var(--space-6) 0 var(--space-3);
    /* S55 D1 polish — same family of cap bug, same soft-cap fix. */
    max-width: min(48ch, 100%);
}

/* Paragraphs — token-driven rhythm.
   S69 FILL-WIDTH: default prose body spans the full content column instead
   of a narrow 60ch reading strip (which left the right half of the band
   empty and lengthened the page into a "sausage"). At >=768px the body is
   justified (flush left+right) so it fills to the right edge; on phones it
   stays ragged-right to avoid inter-word rivers. The 2-col `--split` shape
   (short title+text) and the FAQ narrow column are unaffected — they set
   their own widths. Genuine reading pages opt back into a measure with the
   `.arech-prose--measure` modifier below. */
.arech-prose p {
    margin: 0;
    max-width: none;
}
@media (min-width: 768px) {
    .arech-prose p,
    .arech-prose li {
        text-align: justify;
        text-justify: inter-word;
        hyphens: auto;
    }
}
.arech-prose p + p {
    margin-block-start: var(--space-4);
}
/* Opt-in comfortable reading measure (long legal terms body etc.) — keeps a
   60ch column and left-aligned text where justify-fill is not wanted. */
.arech-prose--measure :where(p, li) {
    max-width: 65ch;
    text-align: start;
}
/* --split body fills its column half (no inner reading cap). */
.arech-prose--split > .prose-body :where(p, li) { max-width: none; }

/* Inline emphasis. */
.arech-prose strong {
    color: inherit;
    font-weight: 600;
}
.arech-prose em {
    font-style: italic;
}

/* Inline link — orange brand colour with offset underline.
   Section-flavour resolves to the contextually correct link
   colour (orange on dark / orange-link on paper). */
.arech-prose a {
    color: var(--orange);
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 4px;
    transition: color var(--motion-fast) var(--ease-standard);
}
.arech-prose.arech-section-addresses a {
    color: var(--orange-link);
}
.arech-prose a:hover {
    color: var(--orange-bright);
}
.arech-prose.arech-section-addresses a:hover {
    color: var(--orange-text);
}

/* Eyebrow — small uppercase mono label above an H2. */
.arech-eyebrow {
    font-family: var(--font-mono);
    font-size: 12px;
    font-weight: 500;
    line-height: 1;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--orange);
    margin: 0 0 var(--space-3);
    display: block;
}
.arech-prose.arech-section-addresses .arech-eyebrow {
    color: var(--orange-link);
}

/* Pullquote — italic motto with orange left border. Logical
   property `border-inline-start` keeps the rule future-proof
   for an eventual RTL flip. */
.arech-pullquote {
    font-family: var(--font-body);
    font-size: clamp(22px, 2.4vw, 32px);
    line-height: 1.3;
    font-style: italic;
    color: var(--orange);
    border-inline-start: 3px solid var(--orange);
    padding-inline-start: var(--space-5);
    margin: var(--space-6) 0 0;
    max-width: 32ch;
}

/* Accent — inline orange highlight on a word inside a heading
   or paragraph (e.g. <h2>Where to <span class="arech-accent">find us</span></h2>). */
.arech-accent {
    color: var(--orange);
}
.arech-prose.arech-section-addresses .arech-accent {
    color: var(--orange-link);
}

/* Address card — formatted address block. `<address>` element
   default italic stripped; bordered card with hairline tint of
   the current text colour so the card adapts to both dark and
   paper bands without separate rules. */
.arech-address-card,
.arech-prose address {
    font-style: normal;
    font-family: var(--font-body);
    font-size: clamp(16px, 1.2vw, 18px);
    line-height: 1.55;
    padding: var(--space-6);
    /* S56 P5 — border lifted from currentColor 14% to 28% +
       stronger fill bg-tint so the card reads as a distinct surface
       (was nearly invisible on paper-1 ivory). Plus border-radius
       bumped from 4px to var(--space-2) for visual weight. */
    border: 1px solid color-mix(in oklch, currentColor 28%, transparent);
    background-color: color-mix(in oklch, currentColor 4%, transparent);
    border-radius: var(--space-2);
    display: inline-block;
    max-width: 36ch;
    margin: var(--space-5) 0 0;
}
.arech-address-card strong:first-child,
.arech-prose address strong:first-child {
    display: block;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    margin-bottom: var(--space-2);
}

/* :has() polish — when a prose band hosts MULTIPLE address
   cards (e.g. Section 8 "Where to Find Us" with HQ + factory),
   switch the inner container to a flex grid so the cards sit
   side-by-side on wider surfaces without a separate wrapper. */
.arech-prose:has(.arech-address-card + .arech-address-card) .prose-body,
.arech-prose:has(address + address) .prose-body {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-5);
    max-width: var(--container);
}
.arech-prose:has(.arech-address-card + .arech-address-card) .prose-body > p,
.arech-prose:has(address + address) .prose-body > p {
    flex-basis: 100%;
}

/* Container-query refinement — narrow surfaces (rare for prose
   but possible when embedded inside a card slot) collapse the
   H2 max-width so it doesn't run flush against the box edge. */
@container (max-width: 480px) {
    .arech-prose h2 { max-width: none; }
    .arech-pullquote { font-size: clamp(20px, 5vw, 24px); }
}

/* ============================================================
   8. Concrete editor compatibility — ccm-edit-mode tweaks.
   Concrete adds .ccm-edit-mode on <body> when in editor; tighten
   the sticky header so blocks below remain reachable.
   ============================================================ */

.ccm-edit-mode .site-header {
    position: relative;
    background-color: var(--dark);
}

/* S56 — Concrete admin toolbar coexistence.
   Concrete injects <div id="ccm-toolbar"> position:fixed top:0 ~48px
   when admin is logged in. It overlays our sticky .site-header.
   `padding-top` on body does NOT help — `position: sticky` ignores
   parent padding and snaps to viewport top:0. Must shift the sticky
   header's own top offset.
   Multiple selectors + !important: defensive against unknown class
   variants Concrete may use (race condition between JS-added body
   class and CSS load). */
body:has(#ccm-toolbar):not(.ccm-edit-mode) .site-header,
body.ccm-toolbar-visible:not(.ccm-edit-mode) .site-header,
body.ccm-page:has(#ccm-toolbar):not(.ccm-edit-mode) .site-header {
    top: 48px !important;
}

/* Prose padding-block shrink in edit mode so the placeholder
   bands don't dominate the editor canvas. */
.ccm-edit-mode .arech-prose {
    padding-block: var(--space-6);
}

/* ============================================================
   S53 product family pages — anchor offset compensation.
   The sticky-tabs strip (~48-60px) sits below the site-header
   (--header-height). Without extra scroll-margin, anchor jumps
   land at the top of the sticky-tabs strip, hiding the target
   section's heading underneath it. Add the strip height to the
   existing scroll-padding so each anchored section lands flush
   below the strip.
   ============================================================ */

.arech-product-family-page .arech-section-anchor {
    scroll-margin-top: calc(var(--header-height) + 64px);
}
/* S69 — product-family sections that hold BARE native content (no custom
   block child) get the shared centered container as a GRID on the anchor
   itself, with children placed on the content column. Anchors that contain a
   custom block (.arech-*) are left untouched (the block self-centres).
   `:has()` lets us target only the native-content anchors. */
.arech-product-family-page .arech-section-anchor:not(:has(> [class*="arech-"])) {
    display: grid;
    grid-template-columns:
        [full-start] minmax(var(--container-px), 1fr)
        [content-start] minmax(0, var(--container)) [content-end]
        minmax(var(--container-px), 1fr) [full-end];
}
.arech-product-family-page .arech-section-anchor:not(:has(> [class*="arech-"])) > * {
    grid-column: content;
    max-width: none;
}
@media (min-width: 768px) {
    .arech-product-family-page .arech-section-anchor:not(:has(> [class*="arech-"])) > :where(p, blockquote, li) {
        text-align: justify;
        text-justify: inter-word;
        hyphens: auto;
    }
}

/* ============================================================
   === Ambient v1.4 port (S55) ===
   Port of the signature visual moves from
   prototypes/homepage/index.html (v1.4 lock, 2026-05-19) into
   the live Concrete theme. Five patterns ported here, scoped
   to a single cascade layer so blocks + page templates can
   opt in without specificity wars with per-block view.css.

   Layer order: theme defaults sit unlayered (winning over
   layered rules); ambient lives in @layer theme.ambient so any
   per-block view.css (also unlayered) overrides it without
   needing higher specificity. Promote individual rules out of
   the layer if a block needs to inherit them as a baseline.

   Tokens used:
     palette  — --orange, --orange-bright, --orange-dim,
                --paper-1, --paper-2, --ink-1..4,
                --hairline, --hairline-strong, --dark, --dark-2
     motion   — --motion-fast/normal/slow/reveal,
                --motion-ambient-fast/slow,
                --ease-standard/linear/decelerate,
                --stagger-1..5
     space    — --space-3..9
     chrome   — --header-height, --container, --container-px

   Local-only tokens (declared once below): --grid-hero,
   --scan-intensity, --paper-grain-opacity.
   ============================================================ */

@layer theme.ambient {

    /* -------------------------------------------------------
       Local custom properties — kept inside the layer so they
       do not leak into block authoring globally; consumers
       override via inline style or descendant rules.
       ------------------------------------------------------- */
    :root {
        --grid-hero: 80px;
        --scan-intensity: 0.18;       /* hero LED matrix peak opacity */
        --paper-grain-opacity: 0.06;  /* section-premium texture strength */
        --ticker-duration: var(--motion-ambient-slow);
    }

    /* =========================================================
       1) HERO LED MATRIX SCAN
       Prototype ref: lines 665-712 (.hero-led-bg), 697-700
       (@keyframes ledFlicker), 715-734 (.hero-grid + gridMove),
       737-743 (.hero-glow). Hero block already ships its own
       view.css (arech_hero_impact/view.css) with a perspective
       grid + JS-populated dots — these theme-level classes are
       the SIBLING fallback for any other block (or a content
       block on a non-impact page) that wants the same ambient
       LED scan without a custom block. Generic class names so
       they can be applied as wrapper utilities.
       ========================================================= */

    .ambient-led-bg {
        position: absolute;
        inset: 0 0 0 auto;
        width: 55%;
        z-index: -3;
        pointer-events: none;
        opacity: 0;
        transform: perspective(800px) rotateY(-8deg);
        transform-origin: right center;
        transition: opacity var(--motion-reveal) var(--ease-standard);
        /* Radial-gradient dot grid: cheaper than 800 DOM nodes,
           composites on the GPU as a single layer. */
        background-image:
            radial-gradient(
                circle at center,
                var(--orange) 0,
                var(--orange) 1.5px,
                transparent 2px
            );
        background-size: 18px 18px;
        background-repeat: repeat;
        -webkit-mask-image:
            linear-gradient(to left, black 50%, transparent 100%),
            linear-gradient(to top, black 60%, transparent 100%);
        mask-image:
            linear-gradient(to left, black 50%, transparent 100%),
            linear-gradient(to top, black 60%, transparent 100%);
        -webkit-mask-composite: source-in;
        mask-composite: intersect;
    }
    .ambient-led-bg.is-visible { opacity: var(--scan-intensity); }

    /* Scan line — translates top-to-bottom across the matrix.
       Composite-only: translate3d + opacity, no layout reads. */
    .ambient-led-bg::after {
        content: '';
        position: absolute;
        inset-inline: 0;
        block-size: 25%;
        background: linear-gradient(
            to bottom,
            transparent 0%,
            color-mix(in oklch, var(--orange) 35%, transparent) 50%,
            transparent 100%
        );
        opacity: 0.6;
        transform: translate3d(0, -100%, 0);
        animation: ambientLedScan 7s var(--ease-standard) infinite;
        will-change: transform;
        pointer-events: none;
    }
    @keyframes ambientLedScan {
        0%   { transform: translate3d(0, -100%, 0); opacity: 0; }
        20%  { opacity: 0.6; }
        80%  { opacity: 0.6; }
        100% { transform: translate3d(0, 400%, 0); opacity: 0; }
    }

    /* Ambient grid drift overlay — for any dark hero/section. */
    .ambient-grid {
        position: absolute;
        inset: calc(-1 * var(--grid-hero)) 0 0 0;
        z-index: -2;
        pointer-events: none;
        background-image:
            linear-gradient(rgba(232, 101, 26, 0.07) 1px, transparent 1px),
            linear-gradient(90deg, rgba(232, 101, 26, 0.07) 1px, transparent 1px);
        background-size: var(--grid-hero) var(--grid-hero);
        animation: ambientGridMove var(--motion-ambient-fast) var(--ease-linear) infinite;
        will-change: transform;
    }
    @keyframes ambientGridMove {
        0%   { transform: translate3d(0, 0, 0); }
        100% { transform: translate3d(0, var(--grid-hero), 0); }
    }

    /* Radial glow halo. */
    .ambient-glow {
        position: absolute;
        inset: 0;
        z-index: -1;
        pointer-events: none;
        background: radial-gradient(
            ellipse 80% 60% at 60% 40%,
            color-mix(in oklch, var(--orange) 12%, transparent) 0%,
            transparent 60%
        );
    }

    /* Container queries — when the ambient layer is dropped
       into a narrow block (e.g. a card carousel cell), tone
       down the scan so it does not dominate small surfaces. */
    @container (max-width: 480px) {
        .ambient-led-bg.is-visible { opacity: calc(var(--scan-intensity) * 0.55); }
    }

    /* =========================================================
       2) SECTION-PREMIUM PAPER TEXTURE
       Prototype ref: .section-premium padding ladder (lines
       367-372) — port adds a subtle SVG fractal grain + a
       decorative cardboard-tape strip via ::before. Class
       name reused so existing .section-premium markup gains
       the texture automatically.

       The grain is a 90-byte inline SVG (fractal turbulence),
       repeated as a 200x200 tile — total cost on main.css is
       ~0.6 KB pre-gzip. Toned to --paper-grain-opacity (6%).
       ========================================================= */

    .section-premium {
        position: relative;
        isolation: isolate;
    }
    .section-premium.section-paper::before {
        content: '';
        position: absolute;
        inset: 0;
        z-index: -1;
        pointer-events: none;
        background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0.04 0 0 0 0 0.04 0 0 0 0 0.04 0 0 0 0.55 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
        background-size: 200px 200px;
        opacity: var(--paper-grain-opacity);
        mix-blend-mode: multiply;
    }

    /* Cardboard tape strip — diagonal accent in the top-start
       corner. Uses logical properties so a future RTL flip
       does not need a separate rule. */
    .section-premium.section-paper.has-tape::after {
        content: '';
        position: absolute;
        inset-block-start: var(--space-5);
        inset-inline-start: calc(-1 * var(--space-6));
        inline-size: 180px;
        block-size: 28px;
        background: color-mix(in oklch, var(--orange) 35%, var(--paper-2));
        opacity: 0.55;
        transform: rotate(-8deg);
        box-shadow:
            0 1px 0 var(--hairline),
            inset 0 0 0 1px color-mix(in oklch, var(--orange) 18%, transparent);
        pointer-events: none;
        z-index: 0;
    }

    /* Dark variant — paper grain hidden, faint gradient wash
       instead, so the same .section-premium markup works in
       both .section-paper and .section-dark contexts. */
    .section-premium.section-dark::before {
        content: '';
        position: absolute;
        inset: 0;
        z-index: -1;
        pointer-events: none;
        background:
            radial-gradient(
                ellipse 60% 40% at 50% 0%,
                color-mix(in oklch, var(--orange) 8%, transparent),
                transparent 60%
            );
    }

    /* =========================================================
       3) STICKY HORIZONTAL NAV (autonav surface)
       Prototype ref: lines 542-648 (.site-header / .nav-inner /
       .nav-links / .nav-toggle). The theme already has
       .site-header rules unlayered (lines 473-583 above), so
       this layer ADDS the polish: scrolled-state contrast bump,
       active-link underline animation, focus ring inset.

       Concrete native autonav renders <ul><li><a>; this layer
       targets that DOM directly without DOM changes — applied
       inside .site-nav so it only affects the chrome nav.
       ========================================================= */

    .site-header {
        transition:
            background-color var(--motion-normal) var(--ease-standard),
            border-color var(--motion-normal) var(--ease-standard);
    }
    .site-header.is-scrolled {
        background-color: color-mix(in oklch, var(--dark) 97%, transparent);
        border-bottom-color: rgba(255, 255, 255, 0.12);
    }

    /* Active + hover underline — uses transform scale so it
       composites; no layout work on hover. */
    .site-nav a {
        position: relative;
    }
    .site-nav a::after {
        content: '';
        position: absolute;
        inset-inline: 0;
        inset-block-end: 4px;
        block-size: 2px;
        background: var(--orange);
        transform: scaleX(0);
        transform-origin: left center;
        transition: transform var(--motion-fast) var(--ease-standard);
    }
    .site-nav a:hover::after,
    .site-nav a:focus-visible::after,
    .site-nav .nav-selected > a::after,
    .site-nav .nav-path-selected > a::after {
        transform: scaleX(1);
    }

    /* :has() polish — when the header contains a focused
       interactive element, lift contrast so it cannot blend
       into a scroll-darkened page background. */
    .site-header:has(:focus-visible) {
        background-color: color-mix(in oklch, var(--dark) 92%, transparent);
    }

    /* =========================================================
       4) TRUST-BAR TICKER MARQUEE
       Prototype ref: lines 851-892 (.trust-bar / .trust-track /
       .trust-item / trustScroll keyframes).
       No custom block exists yet for this (no arech_trust_bar_
       ticker in /blocks). Until a custom block is built, an
       operator can drop a Concrete `content` block onto a page
       and add this exact markup in the HTML editor:

         <div class="ambient-ticker">
           <div class="ambient-ticker__track">
             <span class="ambient-ticker__item">100,000+ hours</span>
             <span class="ambient-ticker__item">CE / FCC / RoHS / ISO</span>
             ...repeat list ONCE more so 50% translate loops
             without a visible seam...
           </div>
         </div>

       The 50% translate trick requires the inner list to be
       duplicated; without that the scroll jumps back visibly.
       ========================================================= */

    .ambient-ticker {
        position: relative;
        overflow: hidden;
        background-color: var(--dark-3);
        border-block: 1px solid var(--hairline-strong);
        padding-block: var(--space-5);
    }
    .ambient-ticker__track {
        display: inline-flex;
        inline-size: max-content;
        gap: 0;
        animation: ambientTickerScroll var(--ticker-duration) var(--ease-linear) infinite;
        will-change: transform;
    }
    .ambient-ticker:hover .ambient-ticker__track,
    .ambient-ticker:focus-within .ambient-ticker__track {
        animation-play-state: paused;
    }
    .ambient-ticker__item {
        display: inline-flex;
        align-items: center;
        gap: var(--space-3);
        padding-inline: var(--space-7);
        font-family: var(--font-mono);
        font-size: 11px;
        font-weight: 500;
        letter-spacing: 0.15em;
        text-transform: uppercase;
        color: var(--light);
        border-inline-end: 1px solid rgba(255, 255, 255, 0.05);
        white-space: nowrap;
    }
    .ambient-ticker__item .glyph { color: var(--orange); font-size: 12px; }
    @keyframes ambientTickerScroll {
        0%   { transform: translate3d(0, 0, 0); }
        100% { transform: translate3d(-50%, 0, 0); }
    }

    /* =========================================================
       5) SCROLL-REVEAL PATTERNS
       Prototype ref: lines 447-463 (.reveal / .reveal-delay-1..5
       / .reveal.visible). Modern browsers get a pure-CSS
       `animation-timeline: view()` path (no JS observer); older
       browsers fall back to the existing JS pattern (theme
       interaction-engineer ships the IntersectionObserver that
       adds `.is-in` and the legacy `.visible` class).

       Both class names supported: `.reveal` (prototype) and
       `.arech-reveal` (block view.css convention). Single rule.
       ========================================================= */

    .reveal,
    .arech-reveal {
        opacity: 0;
        transform: translate3d(0, 32px, 0);
        transition:
            opacity var(--motion-reveal) var(--ease-decelerate),
            transform var(--motion-reveal) var(--ease-decelerate);
    }
    .reveal.visible,
    .reveal.is-in,
    .arech-reveal.visible,
    .arech-reveal.is-in {
        opacity: 1;
        transform: translate3d(0, 0, 0);
    }
    :is(.reveal, .arech-reveal).reveal-delay-1,
    :is(.reveal, .arech-reveal).arech-reveal--s1 { transition-delay: var(--stagger-1); }
    :is(.reveal, .arech-reveal).reveal-delay-2,
    :is(.reveal, .arech-reveal).arech-reveal--s2 { transition-delay: var(--stagger-2); }
    :is(.reveal, .arech-reveal).reveal-delay-3,
    :is(.reveal, .arech-reveal).arech-reveal--s3 { transition-delay: var(--stagger-3); }
    :is(.reveal, .arech-reveal).reveal-delay-4,
    :is(.reveal, .arech-reveal).arech-reveal--s4 { transition-delay: var(--stagger-4); }
    :is(.reveal, .arech-reveal).reveal-delay-5,
    :is(.reveal, .arech-reveal).arech-reveal--s5 { transition-delay: var(--stagger-5); }

    /* CSS-only progressive enhancement — when the browser
       supports scroll-driven animations (Chromium 115+, Safari
       TP), use view() so reveals work even with JS disabled.
       Older browsers (Firefox stable as of 2026-05) keep the
       JS-driven `.visible` / `.is-in` path above. */
    @supports (animation-timeline: view()) {
        @media (prefers-reduced-motion: no-preference) {
            .reveal:not(.is-in):not(.visible),
            .arech-reveal:not(.is-in):not(.visible) {
                animation: ambientFadeUp linear forwards;
                animation-timeline: view();
                animation-range: entry 0% entry 60%;
            }
            @keyframes ambientFadeUp {
                from { opacity: 0; transform: translate3d(0, 32px, 0); }
                to   { opacity: 1; transform: translate3d(0, 0, 0); }
            }
        }
    }

    /* =========================================================
       Reduced-motion gate — required for every animated rule
       above. Collapses to instant final state, ≤ 50ms.
       ========================================================= */
    @media (prefers-reduced-motion: reduce) {
        .ambient-led-bg::after,
        .ambient-grid,
        .ambient-ticker__track {
            animation: none !important;
        }
        .ambient-led-bg.is-visible {
            opacity: calc(var(--scan-intensity) * 0.4);
        }
        .reveal, .arech-reveal,
        .reveal.visible, .reveal.is-in,
        .arech-reveal.visible, .arech-reveal.is-in {
            opacity: 1;
            transform: none;
            transition-duration: 50ms;
        }
        .site-nav a::after {
            transition-duration: 50ms;
        }
    }

} /* end @layer theme.ambient */

/* S69 large-desktop container step (1440-1600 rule) */
/* responsive_manual_en_0.1 (locked 2026-06-01): single uniform container, NO wide tier. --container = 1140 (XL 1024–1439) stepping to 1200 (2XL ≥1440), applied identically to every section. The old section-based 2-tier (1200/1440) is retired. */
