/* Shared design system for SiteTech subpages (About, Pricing, Portfolio, Contact).
   The home page (index.html) keeps its own cinematic WebGL styles; these pages
   reuse the same palette/type but stay lightweight and responsive by default.
   Font is loaded via <link> in each page's <head>, not @import here — @import
   inside CSS delays font discovery until this file is fetched and parsed. */

/* ---------- self-hosted fonts (SIL Open Font License) ----------
   Italiana 400 (h1 and the logo only) and the Geist variable file, served
   from this origin instead of fonts.googleapis.com: one fewer DNS+TLS
   handshake on the critical path, no third-party request, and the display
   face can be preloaded from each page's <head>. Files under assets/fonts/. */
@font-face {
    /* Geist, SIL Open Font License 1.1 — see licences/geist-OFL-1.1.txt and
       design-references/asset-provenance.md. Variable file: one request covers
       every weight, and it is smaller than the two static weights we use
       (69,652 B against 91,616 B). Subsetted to Latin plus the punctuation this
       site actually renders: 69,652 -> 32,024 B, with all 95 distinct characters
       used across every EN and FR page verified present in the cmap — French
       accents, em and en dash, the arrow and the dollar sign included. The
       wght 100-900 axis survives subsetting. */
    font-family: 'Geist';
    font-style: normal;
    font-weight: 100 900;
    font-display: swap;
    src: url(assets/fonts/geist-variable.woff2) format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+20AC, U+2122, U+2190-2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
    font-family: 'Italiana';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url(assets/fonts/italiana-400.woff2) format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* Design tokens live in tokens.css, loaded before this file on every page. */

* { margin: 0; padding: 0; box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
    background: var(--bg);
    color: var(--fg);
    font-family: 'Geist', system-ui, sans-serif;
    font-weight: 400;
    font-size: 16px;
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
}

/* Italiana is the display face and now appears in exactly two places: the h1 of
   a page, and the logo (which is an SVG and carries its own outlines). Every
   other heading is Geist. Scoped 7 Sep 2026 — it was on h1/h2/h3/.serif plus
   five components, which is what made the pages read as one texture. */
h1, .serif {
    font-family: 'Italiana', serif;
    font-weight: 400;
    color: var(--fg-title);
    letter-spacing: 0.5px;
}
h2, h3 {
    font-family: 'Geist', system-ui, sans-serif;
    font-weight: 500;
    color: var(--fg-title);
    letter-spacing: -0.02em;
}
h1 { letter-spacing: -0.02em; }

/* Measure. Body prose caps at 68ch; headings want a much shorter line or a
   large h1 runs the full container and undoes the grouping. Both in ch so they
   stay correct if the size changes. */
main p, main li, main summary, main dd { max-width: 46ch; }
main h1 { max-width: 14ch; }
main h2, main h3 { max-width: 20ch; }

/* Grouping. The gap from a heading to its own paragraph was 12px while the
   line-gap INSIDE a paragraph was 22.4px — the lines looked further apart than
   the heading was from its content, so nothing grouped. */
main h2 + p, main h3 + p, main h2 + ul, main h3 + ul,
main h2 + div, main h3 + div { margin-top: 24px; }

a { color: inherit; }

.container {
    width: 100%;
    max-width: 1180px;
    margin: 0 auto;
    padding: 0 32px;
}

/* ---------- header / nav ---------- */

/* The right-hand cluster of the header. Was an inline style repeated on every
   subpage and a class defined only in the old home.css; when index.html adopted
   the shared header the class had nowhere to resolve, so the group stopped being
   a flex row and the hamburger wrapped onto a second line at 900px. */
.header-actions {
    display: flex;
    align-items: center;
    gap: 16px;
}

.site-header {
    position: sticky;
    top: 0;
    z-index: 100;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 22px 40px;
    background: rgba(5, 7, 13, 0.75);
    backdrop-filter: blur(10px);
    border-bottom: 1px solid var(--border-soft);
}

.site-header .brand {
    display: flex;
    align-items: center;
    text-decoration: none;
    color: var(--fg);
}
.brand-logo { display: block; height: 34px; width: auto; }

.site-nav {
    display: flex;
    align-items: center;
    gap: 28px;
}

.site-nav a {
    text-decoration: none;
    color: var(--fg-muted);
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 2px;
    font-weight: 500;
    transition: color 0.25s;
}

.site-nav a:hover,
.site-nav a[aria-current="page"] { color: var(--fg); }

.contact-btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 10px 24px;
    background: var(--fg);
    color: var(--bg);
    text-decoration: none;
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 1px;
    font-weight: 600;
    border-radius: 20px;
    transition: transform 0.3s, background 0.3s;
    white-space: nowrap;
}
.contact-btn:hover { transform: scale(1.05); background: var(--fg-title); }

.phone-link {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: var(--fg);
    text-decoration: none;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.5px;
    white-space: nowrap;
    transition: color 0.2s;
}
.phone-link svg { width: 15px; height: 15px; fill: currentColor; flex-shrink: 0; }
.phone-link:hover { color: var(--cyan); }

.lang-toggle {
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 1px;
    color: var(--fg-muted);
    text-decoration: none;
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 8px 16px;
    transition: color 0.2s, border-color 0.2s;
    white-space: nowrap;
}
.lang-toggle:hover { color: var(--fg); border-color: var(--cyan); }

.nav-toggle {
    display: none;
    flex-direction: column;
    gap: 5px;
    background: none;
    border: none;
    cursor: pointer;
    padding: 6px;
    z-index: 110;
}
.nav-toggle span {
    width: 22px; height: 1.5px;
    background: var(--fg);
    transition: transform 0.3s, opacity 0.3s;
}
.nav-toggle.open span:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
.nav-toggle.open span:nth-child(2) { opacity: 0; }
.nav-toggle.open span:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }

/* Desktop-only page-preview menu, mirroring the mobile off-canvas panel so
   desktop visitors get the same at-a-glance list of every page. Mobile
   already has .nav-toggle above for this job, so this hides <=720px. */
.mobile-nav-toggle {
    display: flex;
    flex-direction: column;
    gap: 5px;
    background: none;
    border: none;
    cursor: pointer;
    padding: 6px;
    z-index: 110;
}
.mobile-nav-toggle span {
    width: 22px; height: 1.5px;
    background: var(--fg);
    transition: transform 0.3s, opacity 0.3s;
}
.mobile-nav-toggle.open span:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
.mobile-nav-toggle.open span:nth-child(2) { opacity: 0; }
.mobile-nav-toggle.open span:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }

.mobile-nav-panel {
    position: fixed;
    top: 0; right: 0;
    height: 100vh;
    width: 78vw;
    max-width: 320px;
    background: var(--bg-deep);
    border-left: 1px solid var(--border);
    z-index: 130;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 28px;
    padding: 40px;
    transform: translateX(100%);
    /* Same closed-state rule as .site-nav (see the 900px block): out of layout, out of the tab order. */
    visibility: hidden;
    transition: transform 0.35s cubic-bezier(0.16, 1, 0.3, 1), visibility 0s linear 0.35s;
}
.mobile-nav-panel.open { transform: translateX(0); visibility: visible; transition-delay: 0s; }
.mobile-nav-panel a {
    color: var(--fg);
    text-decoration: none;
    font-size: 15px;
    text-transform: uppercase;
    letter-spacing: 2px;
}

/* ---------- footer ---------- */

.site-footer {
    border-top: 1px solid var(--border-soft);
    padding: 48px 40px 32px;
    /* 80, not 120: measured 18 Sep 2026. The gap from the last text to this rule was 220 px on
       every page at 390 and 1440 (100 px of section padding plus this margin), and 26.1% of the
       viewport on a phone against 24.4% on desktop - the same proportion, so nothing here scales
       wrong. Reduced site-wide to close it by a fifth. The ten inline padding-bottom:100px styles
       on the closing sections are deliberately NOT touched yet; see the ledger. */
    margin-top: 80px;
}
.site-footer .footer-inner {
    max-width: 1180px;
    margin: 0 auto;
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 24px;
}
.site-footer .brand {
    display: flex;
    align-items: center;
}
.site-footer .brand .brand-logo { height: 28px; }
.site-footer .footer-nav {
    display: flex;
    gap: 24px;
    flex-wrap: wrap;
}
.site-footer .footer-nav a {
    text-decoration: none;
    color: var(--fg-faint);
    font-size: 12px;
    letter-spacing: 0.5px;
    transition: color 0.25s;
}
.site-footer .footer-nav a:hover { color: var(--fg); }
.site-footer .brand-sub {
    margin-top: 6px;
    font-size: 11px;
    color: var(--fg-faint);
    letter-spacing: 0.5px;
}
.site-footer .footer-business {
    display: flex;
    flex-direction: column;
    gap: 4px;
    font-size: 12px;
    color: var(--fg-faint);
}
.site-footer .copyright {
    color: var(--fg-faint);
    font-size: 11px;
    letter-spacing: 0.5px;
    width: 100%;
    margin-top: 24px;
}

/* ---------- page hero ---------- */

.page-hero {
    padding: 120px 40px 60px;
    max-width: 1180px;
    margin: 0 auto;
}
.page-hero h1 {
    font-size: 72px;
    line-height: 1.05;
    margin-bottom: 20px;
}
.page-hero p {
    font-size: 17px;
    color: var(--fg-muted);
    max-width: 46ch;
}
/* pricing: the short deposit line under the h1; the full terms sit at #terms after the FAQ */
.page-hero .deposit-line { max-width: 64ch; }
.page-hero .deposit-line strong { color: var(--fg-title); font-weight: 500; }
.page-hero .deposit-line a { color: var(--cyan); text-decoration: underline; text-underline-offset: 3px; }
#terms .price-terms { margin-left: 0; text-align: left; }
.eyebrow {
    display: inline-block;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 3px;
    color: var(--cyan);
    margin-bottom: 18px;
}

/* ---------- sections / cards ---------- */

section.page-section {
    padding: 60px 40px;
    max-width: 1180px;
    margin: 0 auto;
}
/* The closing section on every page that ends in one. Until 18 Sep 2026 this was ten inline
   padding-bottom:100px attributes on the <section>, which no stylesheet rule could override, and the
   three form pages carried none at all - so they ended 60 px tighter at 390 and 40 px at 1440, measured
   from the last element bottom edge. One value in one place now. It is section.page-closing, not a bare
   .page-closing, because section.page-section is a type+class selector and a bare class would lose to
   it; for the same reason the rule is repeated inside the 720 px media query below. */
section.page-closing { padding-bottom: 100px; }
section.page-section h2 {
    font-size: 42px;
    margin-bottom: 16px;
}
section.page-section > p.lede {
    color: var(--fg-muted);
    max-width: 46ch;
    margin-bottom: 48px;
}

/* The reach map on the About page (Albert, 17 Sep 2026): Canada in the navy token, New Brunswick in
   the brand cyan (the token is named --cyan and holds #22d3ee, the same cyan as the dash fills and the
   travelling light; there is no other cyan token). Strokes do not scale with the map so PEI keeps a
   1 px edge at 390, where it is 12 x 5 px. The label text is in viewBox units: 34 reads 24 px at 1440
   and 12 px at 390. Decorative: the SVG is aria-hidden, the sentence carries the meaning. */
.reach-map { max-width: 720px; margin: 0 auto; }
.reach-map svg { display: block; width: 100%; height: auto; }
.reach-map path { fill: var(--blue-dim); stroke: var(--border); stroke-width: 1; stroke-linejoin: round; vector-effect: non-scaling-stroke; }
.reach-map path.nb { fill: var(--cyan); stroke: var(--cyan); }
.reach-map .nb-label line { stroke: var(--cyan); stroke-width: 1.5; vector-effect: non-scaling-stroke; }
.reach-map .nb-label text { fill: var(--cyan); font-family: 'Geist', system-ui, sans-serif; font-weight: 600; font-size: 34px; letter-spacing: 2px; }
.reach-line { text-align: center; color: var(--fg-title); font-size: 18px; line-height: 1.5; margin: 28px auto 0; max-width: 40ch; }

/* The homepage's former closing CTA, on About since 17 Sep 2026 (moved from home.css with it). */
.hero-cta {
    display: flex;
    align-items: center;
    gap: 18px;
    flex-wrap: wrap;
    margin-bottom: 26px;
}
.hero-cta-sub {
    font-size: 13px;
    color: var(--fg-muted);
    letter-spacing: 0.4px;
}
/* Used on About (EN and FR) only: the line under the About closing CTA that points at the case
   study. It was written for the homepage closing block, which was removed on 18 Sep 2026 at
   Albert's request (the homepage now has no in-content route to the case study, deliberately). */
.closing-proof {
    margin-top: 14px;
    font-size: 14px;
}
.closing-proof a {
    color: var(--cyan);
    text-decoration: none;
    border-bottom: 1px solid rgba(34, 211, 238, 0.35);
    padding-bottom: 1px;
}
.closing-proof a:hover,
.closing-proof a:focus-visible {
    border-bottom-color: var(--cyan);
}
.about-closing .hero-cta { justify-content: center; }

.card {
    background: var(--bg-raised);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 32px;
}

.contact-grid {
    display: grid;
    grid-template-columns: 1fr 1.4fr;
    gap: 60px;
    align-items: start;
}

.grid {
    display: grid;
    gap: 24px;
}
.grid-3 { grid-template-columns: repeat(3, 1fr); }
.grid-2 { grid-template-columns: repeat(2, 1fr); }

/* ---------- stat banner ---------- */

.stat-banner {
    display: flex;
    align-items: center;
    gap: 24px;
    background: linear-gradient(120deg, rgba(34,211,238,0.12), rgba(37,99,235,0.16));
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 26px 30px;
    margin-top: 32px;
}
.stat-banner .stat-number {
    font-family: 'Geist', system-ui, sans-serif;
    font-size: 52px;
    color: var(--fg-title);
    line-height: 1;
    white-space: nowrap;
}
.stat-banner p {
    color: var(--fg-muted);
    font-size: 15px;
    margin: 0;
    max-width: 480px;
}
/* the visible citation under the stat banner: the figure changes monthly, so the page states its date */
.page-hero .stat-source {
    color: var(--fg-faint);
    font-size: 12px;
    margin-top: 12px;
    max-width: 560px;
}

/* ---------- tier tags & checklists ---------- */

.tier-tags {
    display: flex;
    gap: 8px;
    margin-bottom: 16px;
    flex-wrap: wrap;
}
.tier-tag {
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 1px;
    padding: 4px 10px;
    border-radius: 12px;
    border: 1px solid var(--border);
    color: var(--fg-faint);
}
.tier-tag.active { border-color: var(--blue); color: var(--cyan); }

.check-list {
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 8px;
    color: var(--fg-muted);
    font-size: 15px;
}
.check-list li::before { content: "\2713"; color: var(--blue); margin-right: 8px; }

/* ---------- feature checkbox form ---------- */

/* The label rule above this file's forms is uppercase with 1.5px tracking. That is
   for short field names; anything that reads as a sentence stays sentence case
   (Albert, 13 Sep 2026): the option rows here, and any label carrying .sentence. */
label.sentence {
    text-transform: none;
    letter-spacing: 0;
    font-size: 15px;
    color: var(--fg-muted);
}
.feature-check {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 10px 0;
    border-bottom: 1px solid var(--border-soft);
    font-size: 15px;
    color: var(--fg-muted);
    text-transform: none;
    letter-spacing: 0;
    cursor: pointer;
}
.feature-check input[type="checkbox"] {
    appearance: none;
    -webkit-appearance: none;
    margin-top: 2px;
    width: 18px;
    height: 18px;
    flex-shrink: 0;
    border: 1.5px solid var(--border);
    border-radius: 4px;
    background: var(--bg-raised);
    cursor: pointer;
    position: relative;
    transition: border-color 0.2s, background 0.2s;
}
.feature-check input[type="checkbox"]:checked {
    background: linear-gradient(120deg, var(--cyan), var(--blue));
    border-color: transparent;
}
.feature-check input[type="checkbox"]:checked::after {
    content: "";
    position: absolute;
    left: 6px;
    top: 2px;
    width: 4px;
    height: 8px;
    border: solid var(--bg);
    border-width: 0 2px 2px 0;
    transform: rotate(45deg);
}
.feature-check input[type="checkbox"]:focus-visible {
    outline: 2px solid var(--blue);
    outline-offset: 2px;
}
.feature-check span { color: var(--fg); }

/* ---------- buttons ---------- */

.btn {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    padding: 14px 30px;
    border-radius: 24px;
    text-decoration: none;
    font-size: 12px;
    text-transform: uppercase;
    letter-spacing: 1.5px;
    font-weight: 600;
    transition: transform 0.25s, opacity 0.25s;
}
.btn:hover { transform: scale(1.03); }
.btn-primary {
    background: linear-gradient(120deg, var(--cyan), var(--blue));
    color: var(--bg);
}
.btn-ghost {
    background: transparent;
    border: 1px solid var(--border);
    color: var(--fg);
}

/* ---------- pricing ---------- */

.price-terms {
    max-width: 46ch;
    margin: 28px auto 0;
    text-align: center;
    font-size: 16px;
    line-height: 1.6;
    color: var(--fg-muted);
}
.price-terms strong { color: var(--fg-title); }

.price-card {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 18px;
}
.price-card.featured {
    border-color: var(--cyan);
    box-shadow: 0 0 0 1px var(--cyan) inset;
}
/* Two soft lights tracking the featured card's border. The wrapper is painted as a ring
   only: it is padded by the border width and masked with two stacked layers composited
   `exclude`, so the content box is punched out and just the 2px rim survives. The lights
   themselves are large radial gradients riding the rounded border box via offset-path,
   half a lap apart, in the two brand colours. */
.price-card.featured .border-glow {
    position: absolute;
    inset: 0;
    border-radius: inherit;
    padding: 5px;   /* the rim the lights show through: 2 px until 17 Sep 2026 (Albert: thin, not dim) */
    overflow: hidden;
    pointer-events: none;
    z-index: 0;
    -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
    mask-composite: exclude;
}
.price-card.featured .border-glow i {
    position: absolute;
    width: 300px;
    height: 300px;
    margin: -150px 0 0 -150px;
    border-radius: 50%;
    offset-path: border-box;
    offset-distance: 0%;
    offset-rotate: 0deg;
    animation: border-glow-orbit 7s linear infinite;
}
.price-card.featured .border-glow i:first-child {
    background: radial-gradient(circle, var(--cyan) 0%, var(--cyan) 6%, rgba(34, 211, 238, 0.55) 20%, rgba(34, 211, 238, 0) 58%);
}
.price-card.featured .border-glow i:last-child {
    background: radial-gradient(circle, var(--blue) 0%, var(--blue) 6%, rgba(37, 99, 235, 0.55) 20%, rgba(37, 99, 235, 0) 58%);
    animation-delay: -3.5s;
}
@keyframes border-glow-orbit {
    to { offset-distance: 100%; }
}
/* The glow (Albert, 17 Sep 2026, 23:25). Measured first: the light's peak was already the full brand
   cyan (luminance 0.53, 10.6:1 against the card), so opacity had nothing to give; the ring mask let
   it paint a 2 px rim and nothing else. Two changes: the rim is 5 px, and two blurred discs ride the
   same path under the rim, drawn as the card's own pseudo-elements at z-index -1 inside an isolated
   stacking context, so they paint over the card's background, under its content, and past its edge
   onto the page. Measured at 1440: reach 36 px outward and 20 px inward; at 390 (same values, one
   rule): 48 outward, 26 inward. The phone value is Albert's call on the preview. */
.price-card.featured { isolation: isolate; }
.price-card.featured::before,
.price-card.featured::after {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    width: 240px;
    height: 240px;
    margin: -120px 0 0 -120px;
    border-radius: 50%;
    offset-path: border-box;
    offset-rotate: 0deg;
    animation: border-glow-orbit 7s linear infinite;
    pointer-events: none;
    z-index: -1;
    filter: blur(16px);
    opacity: 0.7;
}
.price-card.featured::before {
    background: radial-gradient(circle, var(--cyan) 0%, rgba(34, 211, 238, 0) 45%);
}
.price-card.featured::after {
    background: radial-gradient(circle, var(--blue) 0%, rgba(37, 99, 235, 0) 45%);
    animation-delay: -3.5s;
}
/* The card keeps its static copper rim where the lights cannot ride: without offset-path
   the two gradients would stack in one corner, which reads as a blotch rather than a rim. */
@supports not (offset-path: border-box) {
    .price-card.featured .border-glow,
    .price-card.featured::before,
    .price-card.featured::after { display: none; }
}
@media (prefers-reduced-motion: reduce) {
    .price-card.featured .border-glow i,
    .price-card.featured::before,
    .price-card.featured::after { animation: none; }
    .price-card.featured .border-glow i:last-child,
    .price-card.featured::after { offset-distance: 50%; }
}
.popular-badge {
    position: absolute;
    top: -13px;
    left: 50%;
    transform: translateX(-50%);
    background: linear-gradient(120deg, var(--cyan), var(--blue));
    color: var(--bg);
    font-size: 10px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 1px;
    padding: 5px 14px;
    border-radius: 12px;
    white-space: nowrap;
}
.price-card .tier-includes {
    color: var(--fg-title);
    font-size: 13px;
    font-weight: 600;
}
.price-card .price {
    font-family: 'Geist', system-ui, sans-serif;
    font-size: 44px;
    color: var(--fg-title);
}
.price-card .price span {
    display: block;
    margin-top: 4px;
    font-family: 'Geist', system-ui, sans-serif;
    font-size: 13px;
    color: var(--fg-faint);
}
.price-card ul {
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: 10px;
    color: var(--fg-muted);
    font-size: 15px;
}
.price-card ul li::before {
    /* a short teal rule, drawn, not the em dash character (copy rule, 13 Sep 2026) */
    content: "";
    display: inline-block;
    width: 12px;
    height: 1px;
    background: var(--blue);
    vertical-align: middle;
    margin-right: 8px;
}

/* ---------- FAQ ---------- */

.faq-item {
    border-bottom: 1px solid var(--border-soft);
    padding: 22px 0;
}
.faq-item summary {
    cursor: pointer;
    font-size: 16px;
    color: var(--fg-title);
    list-style: none;
}
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary::after {
    content: "+";
    float: right;
    color: var(--cyan);
}
.faq-item[open] summary::after { content: "\2212"; }
.faq-item p {
    margin-top: 12px;
    color: var(--fg-muted);
    font-size: 16px;
    max-width: 46ch;
}

/* ---------- testimonials ---------- */

.testimonial p.quote {
    font-family: 'Geist', system-ui, sans-serif;
    font-size: 22px;
    color: var(--fg-title);
    margin-bottom: 18px;
}
.testimonial .who {
    color: var(--fg-faint);
    font-size: 13px;
}

/* ---------- contact form ---------- */

.form-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 18px;
}
.form-grid .full { grid-column: 1 / -1; }
label {
    display: block;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 1.5px;
    color: var(--fg-faint);
    margin-bottom: 8px;
}
input, textarea {
    width: 100%;
    background: var(--bg-raised);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 13px 16px;
    color: var(--fg);
    font-family: 'Geist', system-ui, sans-serif;
    font-size: 16px;
}
input:focus, textarea:focus {
    outline: none;
    border-color: var(--cyan);
}
textarea { resize: vertical; min-height: 120px; }
.form-status {
    margin-top: 16px;
    font-size: 13px;
    color: var(--blue);
    display: none;
}
.form-status.visible { display: block; }
.form-status.success { color: var(--success); }
.form-status.error { color: var(--error); }
.st-honeypot-field {
    position: absolute;
    left: -9999px;
    width: 1px;
    height: 1px;
    overflow: hidden;
}

.contact-detail { margin-bottom: 28px; }
.contact-detail .label {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 1.5px;
    color: var(--fg-faint);
    margin-bottom: 6px;
}
.contact-detail .value { font-size: 16px; color: var(--fg-title); }

/* ---------- before/after comparison (case-study pages) ---------- */

.compare {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 32px;
}

.compare-item { margin: 0; }

.compare-item img {
    display: block;
    width: 100%;
    height: auto;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    background: var(--bg-raised);
}

.compare-item figcaption {
    margin-top: 10px;
    font-size: 15px;
    letter-spacing: 0.5px;
    color: var(--fg-muted);
}

/* The phone shots are 390px wide against 1440px desktop ones; capping them
   keeps a portrait screenshot from towering over the pair above it. */
.compare-phone img {
    max-width: 300px;
    margin: 0 auto;
}
.compare-phone figcaption { text-align: center; }

.compare-links {
    margin-top: 22px;
    font-size: 15px;
    color: var(--fg-muted);
}
.compare-links a { color: var(--cyan); }  /* teal on the page background fails 4.5:1; cyan clears it */

.compare-facts {
    margin: 16px 0 0;
    padding-left: 20px;
    color: var(--fg-muted);
}
.compare-facts li { margin-bottom: 10px; }

/* ---------- responsive ---------- */

@media (max-width: 900px) {
    .grid-3 { grid-template-columns: 1fr 1fr; }
    .page-hero h1 { font-size: 52px; }

    /* The header collapses here, not at 720px. The desktop header needs about
       800px (brand, four links, phone, FR, Contact, two toggles) and collided
       with itself at 768px: "Work" touched the phone number and the right
       group overflowed the viewport by 5px. */
    .site-header { padding: 18px 20px; }
    .brand-logo { height: 28px; }
    .site-nav {
        position: fixed;
        top: 0; right: 0;
        height: 100vh;
        width: 78vw;
        max-width: 320px;
        background: var(--bg-deep);
        border-left: 1px solid var(--border);
        flex-direction: column;
        align-items: flex-start;
        justify-content: center;
        gap: 28px;
        padding: 40px;
        transform: translateX(100%);
        /* Closed state leaves layout and the tab order.
           `display: none`, not `visibility: hidden`, and the difference is
           measurable. `.site-header` sets `backdrop-filter: blur(10px)` (see
           the .site-header rule), and backdrop-filter creates a CONTAINING
           BLOCK for `position: fixed` descendants. So this element is not
           viewport-fixed at all - it resolves against the header and
           contributes to document scroll overflow like any ordinary box. With
           `visibility: hidden` it panned 320px sideways on all 13 subpages at
           768 and 900 in a desktop (non-touch) window. No ancestor overflow
           rule can clear that: `overflow-x: clip` on `html` was tried and
           measured, and did nothing. The proof of the mechanism is
           `.mobile-nav-panel`, an identical 320px off-canvas drawer that sits
           at body level, is genuinely viewport-fixed, and contributes zero pan.
           `display: none` removes the box from layout entirely, which fixes the
           pan and takes the links out of the tab order in the same line.
           `allow-discrete` plus `@starting-style` keep the slide animation. */
        display: none;
        transition: transform 0.35s cubic-bezier(0.16, 1, 0.3, 1),
                    display 0.35s allow-discrete;
    }
    .site-nav.open { display: flex; transform: translateX(0); }
    @starting-style { .site-nav.open { transform: translateX(100%); } }
    .site-nav a { font-size: 14px; display: block; padding: 10px 0; }
    .nav-toggle { display: flex; padding: 11px; }
    .mobile-nav-toggle { display: none; }
    .phone-link .phone-text { display: none; }
}

@media (max-width: 720px) {
    .page-hero { padding: 100px 20px 40px; }
    .page-hero h1 { font-size: 40px; }
    section.page-section { padding: 40px 20px; }
    section.page-closing { padding-bottom: 100px; }
    section.page-section h2 { font-size: 30px; }

    .grid-3, .grid-2, .contact-grid, .compare { grid-template-columns: 1fr; }
    .compare { gap: 24px; }
    .form-grid { grid-template-columns: 1fr; }
    .stat-banner { flex-direction: column; align-items: flex-start; gap: 12px; padding: 22px; }
    .stat-banner .stat-number { font-size: 40px; }

    /* iOS Safari auto-zooms on focus into inputs smaller than 16px */
    input, textarea { font-size: 16px; }

    .btn, .contact-btn { padding-top: 13px; padding-bottom: 13px; }

    .site-footer .footer-inner { flex-direction: column; }
    /* French nav labels run ~40% longer than English: "Accueil / A propos / Tarifs /
       Realisations / Contact" measures 345 px against English's 285. At a 310 px column
       (390 viewport) the FR nav therefore wrapped to a second line, and because `gap`
       sets the ROW gap too, that cost 43 px rather than 19 - the FR footer stood at
       285 px against English's 241. Measured 18 Sep 2026 in BOTH languages; the original
       17 Sep measurement was English-only and could not see it.
       Dropping the 0.5 px letter-spacing and tightening the column gap puts FR on one
       line with 17 px of slack. row-gap 6 is the safety net: if a future label does push
       it to two lines, that costs 6 px instead of 24. Desktop is untouched. */
    .site-footer .footer-nav { column-gap: 16px; row-gap: 6px; }
    .site-footer .footer-nav a { letter-spacing: 0; }
}

* { -webkit-tap-highlight-color: transparent; }

/* ---------- before / after project rows (portfolio) ---------- */
/* One project per row, two columns: previously | now. Each column is a
   light-sweep loop as header, the screenshot, then one plain text anchor.
   The loops are decoration (alt=""), so an sr-only heading names each
   column for the accessibility tree. Stacks below 720px. */

.sr-only {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

.ba-project {
    background: var(--bg-raised);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 32px;
    margin-bottom: 24px;
}
.ba-project > .tag {
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 2px;
    color: var(--cyan);
    display: block;
    margin-bottom: 8px;
}
.ba-project > h2 { font-size: 28px; margin-bottom: 10px; }
.ba-project > p {
    color: var(--fg-muted);
    font-size: 15px;
    max-width: 46ch;
    margin-bottom: 28px;
}

.ba-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 24px;
}
.ba-col { display: flex; flex-direction: column; }

/* Light-sweep loop: decorative header above the screenshot. */
.sweep {
    display: block;
    width: 100%;
    height: auto;
    margin-bottom: 10px;
}
@media (prefers-reduced-motion: reduce) { .sweep--anim  { display: none; } }
@media (prefers-reduced-motion: no-preference) { .sweep--still { display: none; } }

.ba-shot {
    display: block;
    width: 100%;
    height: auto;
    border: 1px solid var(--border-soft);
    border-radius: 10px;
}

.ba-link {
    display: inline-block;
    margin-top: 12px;
    color: var(--cyan);
    font-size: 13px;
    font-weight: 600;
    text-decoration: none;
}
.ba-link:hover { text-decoration: underline; }

.ba-case-link {
    display: inline-block;
    margin-top: 24px;
    color: var(--cyan);
    font-size: 13px;
    font-weight: 600;
    text-decoration: none;
}
.ba-case-link:hover { text-decoration: underline; }

@media (max-width: 720px) {
    .ba-project { padding: 22px; }
    .ba-project > h2 { font-size: 24px; }
    .ba-grid { grid-template-columns: 1fr; gap: 32px; }
}

/* Links that belong in the mobile drawer but not the desktop bar. The drawer is
   now the ONLY drawer — the duplicate .mobile-nav-panel was removed 7 Sep 2026 —
   so it has to carry Get a Quote and Contact, which the desktop header serves
   with the Contact button and the page CTAs instead. */
.nav-drawer-only { display: none; }
@media (max-width: 900px) { .nav-drawer-only { display: block; } }

/* ---------- custom package stepper (custom-package.html, 13 Sep 2026) ----------
   One step at a time when the script runs; one long form when it does not. The
   option rows reuse .feature-check; the radio rules mirror the checkbox ones. */

.stepper { scroll-margin-top: 90px; }
.stepper fieldset { border: 0; padding: 0; margin: 0; min-width: 0; }
.stepper legend { padding: 0; }
.stepper .step + .step { margin-top: 40px; }
.stepper.js .step + .step { margin-top: 0; }
.stepper.js .step:not(.is-active) { display: none; }
.stepper .step-title { font-size: 28px; margin-bottom: 8px; }
.stepper .step-title:focus { outline: none; }
.stepper .step-row { margin-top: 24px; }
.stepper .step-row h3 { font-size: 17px; margin-bottom: 4px; }
.stepper .step-hint { color: var(--fg-muted); font-size: 15px; margin-bottom: 8px; max-width: 60ch; }
.stepper .step-progress {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 1.5px;
    color: var(--fg-faint);
    margin-bottom: 14px;
}
.stepper:not(.js) .step-progress,
.stepper:not(.js) .step-nav,
.stepper:not(.js) .summary-wrap { display: none; }
.stepper .feature-check { min-height: 44px; align-items: center; }
.stepper .feature-check[hidden] { display: none; }
.stepper .feature-check small { display: block; color: var(--fg-faint); font-size: 13px; margin-top: 2px; }
.stepper .feature-check input[type="radio"] {
    appearance: none;
    -webkit-appearance: none;
    width: 18px;
    height: 18px;
    flex-shrink: 0;
    border: 1.5px solid var(--border);
    border-radius: 50%;
    background: var(--bg-raised);
    cursor: pointer;
    position: relative;
    transition: border-color 0.2s, background 0.2s;
}
.stepper .feature-check input[type="radio"]:checked {
    background: linear-gradient(120deg, var(--cyan), var(--blue));
    border-color: transparent;
}
.stepper .feature-check input[type="radio"]:checked::after {
    content: "";
    position: absolute;
    left: 5px;
    top: 5px;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--bg);
}
.stepper .feature-check input[type="radio"]:focus-visible {
    outline: 2px solid var(--blue);
    outline-offset: 2px;
}
.stepper .step-nav { display: flex; justify-content: space-between; gap: 12px; margin-top: 28px; }
.stepper .step-nav .btn { cursor: pointer; font-family: inherit; }
.stepper .step-nav .btn-primary { border: none; margin-left: auto; }
.stepper .step-nav .btn[hidden] { display: none; } /* .btn sets display, which beats the hidden attribute */
.stepper .summary { margin: 0 0 24px; }
.stepper .summary div { padding: 10px 0; border-bottom: 1px solid var(--border-soft); }
.stepper .summary dt {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 1.5px;
    color: var(--fg-faint);
    margin-bottom: 4px;
}
.stepper .summary dd { margin: 0; color: var(--fg); font-size: 15px; display: flex; flex-wrap: wrap; align-items: center; gap: 4px 16px; }
.stepper .summary dd ul { margin: 0; padding: 0; list-style: none; }
.stepper .summary-change {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    padding: 0;
    background: none;
    border: 0;
    color: var(--cyan);
    font-family: inherit;
    font-size: 13px;
    text-decoration: underline;
    text-underline-offset: 3px;
    cursor: pointer;
}
.stepper .summary-change:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; }
@media (max-width: 720px) {
    .stepper .step-title { font-size: 24px; }
}
