/* J7 Creations - Main Stylesheet */

/* ---------------------------------------------------------------------------
   DESIGN TOKENS

   Every colour, space and type size on the site should come from here. If you
   find yourself writing a literal hex or px value in a page, add a token
   instead — that is what keeps the two themes correct and the pages
   consistent.

   Both themes define the SAME set of names. A token that exists in one theme
   and not the other is how light mode broke last time: hardcoded colours kept
   their dark-theme value on a light background and dropped to ~2:1 contrast.

   The Atomik Menace site keeps a pinned copy of this file as its base.css and
   loads its own tokens after it. A colour, blur, radius, font or image typed
   straight into a rule below would show up on that site in J7's look.
   --------------------------------------------------------------------------- */

/* EDIT HERE: the site's colours, spacing and type sizes. :root below is the
   dark theme; [data-theme="light"] further down is the light theme. Both use
   the same names, so a new name must be added to both. Run
   python scripts/stamp-assets.py after editing this file. */
:root {
    /* Surfaces */
    --color-bg-dark: #1a1a1a;
    --color-bg-darker: #0f0f0f;
    --color-card-bg: #252525;
    --color-input-bg: #333333;
    --color-border: #444444;

    /* Text */
    --color-text-white: #ffffff;
    --color-text-gray: #cfcfcf;
    --color-text-muted: #bcbcbc;

    /* Brand — one purple and one teal, not four and three.
       --color-accent is the interactive/brand colour; --color-success is the
       "included / no fee / confirmed" colour. */
    /* As close to the Covenant violet as a dark card allows. The card floor
       is grey ~34 where the wallpaper is brightest behind it, so anything
       below about 0.245 relative luminance drops the inline links under
       4.5:1. #4c1d95 itself measures 1.6:1 here — invisible. */
    --color-accent: #9b78f5;
    --color-accent-strong: #5b21b6;
    --color-success: #7fe6c3;
    --color-gradient-start: #6d28d9;
    --color-gradient-mid: #3db896;
    --color-gradient-end: #e85d6f;

    /* Translucent brand washes, used for panels and callouts */
    --wash-accent: rgba(123, 92, 184, 0.15);
    --wash-accent-strong: rgba(123, 92, 184, 0.22);
    --wash-success: rgba(61, 184, 150, 0.14);

    /* Panels that sit on the photographic body background. These carry a
       scrim so text on them stays readable over the logo image. */
    --panel-bg: rgba(26, 26, 26, 0.46);
    --panel-bg-solid: #202020;
    --panel-border: rgba(255, 255, 255, 0.10);

    --shadow-color: rgba(0, 0, 0, 0.4);
    --shadow-card: 0 2px 10px rgba(0, 0, 0, 0.35);

    /* Spacing — 3xs..xl. The old set was missing 0.75/1.5/3rem, which are the
       three values the pages actually used most. */
    --spacing-3xs: 0.25rem;
    --spacing-2xs: 0.5rem;
    --spacing-xs: 0.5rem;
    --spacing-s: 0.75rem;
    --spacing-sm: 1rem;
    --spacing-m: 1.5rem;
    --spacing-md: 2rem;
    --spacing-l: 3rem;
    --spacing-lg: 4rem;
    --spacing-xl: 6rem;

    /* Type scale — a real ratio, replacing nine ad-hoc sizes crammed into a
       0.4rem band (0.85/0.9/0.95/1/1.05/1.1...). */
    --text-xs: 0.8125rem;
    --text-sm: 0.9375rem;
    --text-base: 1rem;
    --text-lg: 1.125rem;
    --text-xl: 1.375rem;
    --text-2xl: 1.75rem;
    --text-3xl: 2.25rem;
    --text-4xl: 3rem;

    --radius: 8px;
    --radius-sm: 4px;
    --radius-lg: 12px;

    /* Type. The display face is for big headings (h1, h2, .display). J7 uses
       one family for both; a second brand can set its own. */
    --font-body: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
                 'Helvetica Neue', Arial, sans-serif;
    --font-display: var(--font-body);

    /* The wallpaper the whole site floats on, the scrim over it, and the fade
       behind the navbar. */
    --wallpaper: url('/assets/images/j7-wall.fd59da6c.jpg');
    --wallpaper-small: url('/assets/images/j7-wall-sm.faab30a7.jpg');
    --wallpaper-scrim: rgba(12, 12, 14, 0.35);
    --nav-fade: linear-gradient(to bottom,
        rgba(10, 10, 12, 0.80) 0%,
        rgba(10, 10, 12, 0.62) 55%,
        rgba(10, 10, 12, 0) 100%);

    /* Glass cards, inputs and menus. The theme-specific rules further down
       stay separate, so the light theme's values are here too, as the
       *-light names, and each light rule reads its own. */
    --glass-blur: blur(10px);
    --card-bg: rgba(26, 26, 26, 0.48);
    --card-bg-soft: rgba(26, 26, 26, 0.40);
    --card-border: rgba(255, 255, 255, 0.15);
    --card-hover-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
    --card-bg-light: rgba(255, 255, 255, 0.29);
    --card-bg-soft-light: rgba(255, 255, 255, 0.27);
    --card-border-light: rgba(0, 0, 0, 0.3);
    --card-hover-shadow-light: 0 8px 24px rgba(0, 0, 0, 0.15);
    --input-blur: blur(5px);
    --input-bg: rgba(26, 26, 26, 0.7);
    --input-border: rgba(255, 255, 255, 0.2);
    --input-bg-light: rgba(255, 255, 255, 0.54);
    --input-text-light: #000000;
    --control-border-light: rgba(0, 0, 0, 0.18);
    --control-text-light: #101010;
    --menu-bg: rgba(16, 16, 18, 0.92);
    --menu-border: rgba(255, 255, 255, 0.14);
    --menu-text: #ffffff;
    --portfolio-border-light: rgba(255, 255, 255, 0.6);
    --breadcrumb-bg-light: rgba(255, 255, 255, 0.32);
    --result-bg-light: rgba(255, 255, 255, 0.24);
    --footer-bg-light: rgba(255, 255, 255, 0.94);
    --float-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
    --float-shadow-light: 0 4px 12px rgba(0, 0, 0, 0.2);
    --toggle-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);

    /* Text inside a light-theme glass card, read by the card-scoped rule
       just after the light theme below. */
    --glass-ink: #101010;
    --glass-ink-gray: #33333a;
    --glass-ink-muted: #3a3a44;
    --glass-accent: #4c1d95;
    --glass-accent-strong: #3b1478;
    --glass-success: #0d4030;
    --glass-line: rgba(0, 0, 0, 0.16);

    /* Brand touches outside the palette above: text and icons on an accent
       button, the accent as "r, g, b" for its glows, the theme button's
       gradient, and the link colour in the price calculator's result. */
    --on-accent: #ffffff;
    --accent-rgb: 107, 76, 154;
    --toggle-gradient: linear-gradient(135deg, #6b4c9a, #c43d4e);
    --result-accent: #b9a2ff;

    /* The navbar is fixed and 90px tall, so a jump to #contact scrolls the
       section's top edge to y=0 — underneath the bar. Every anchor target
       needs to stop short by at least the bar's height. */
    --nav-offset: 6.5rem;
}

/* scroll-margin only affects where a fragment jump or scrollIntoView comes to
   rest, so applying it to every id is safe and catches targets added later.
   It also keeps an invalid form field from landing under the bar on submit. */
[id] {
    scroll-margin-top: var(--nav-offset);
}

[data-theme="light"] {
    /* Light mode keeps the same dark wallpaper and scrim as dark mode. Only
       the cards change: they become light frosted glass that the content sits
       on. So the page-level text tokens stay LIGHT here, because anything not
       on a card (section titles, the footer note) is still on dark artwork.
       Card-scoped overrides further down flip the text to dark inside glass. */
    /* Both of these are only ever seen through the wallpaper, or used as a
       card surface. Making them glass converts the cards that set
       `background: var(--color-bg-dark)` inline, which a stylesheet rule
       could not override. */
    --color-bg-dark: rgba(255, 255, 255, 0.29);
    --color-bg-darker: rgba(255, 255, 255, 0.32);
    --color-card-bg: rgba(255, 255, 255, 0.29);
    --color-input-bg: rgba(255, 255, 255, 0.24);
    --color-border: rgba(0, 0, 0, 0.14);

    --color-text-white: #ffffff;
    --color-text-gray: #d6d6d6;
    --color-text-muted: #c2c2c2;

    --color-accent: #c4b0ff;
    --color-accent-strong: #6d28d9;
    --color-success: #8fecd0;

    --wash-accent: rgba(155, 127, 212, 0.16);
    --wash-accent-strong: rgba(155, 127, 212, 0.24);
    --wash-success: rgba(111, 216, 180, 0.14);

    /* The frosted glass itself */
    --panel-bg: rgba(255, 255, 255, 0.29);
    --panel-bg-solid: rgba(255, 255, 255, 0.34);

    /* Frosted glass over a near-black photograph.
       Measured from the wallpaper itself: after the body::after scrim, the
       blurred backdrop sits between grey 5 and grey 40. A white wash bright
       enough to carry dark text therefore has to be nearly opaque, which is
       why thinning it alone just makes the cards dim rather than clear.
       contrast() below 1 pulls the backdrop toward mid-grey. That is an
       ADDITIVE transfer, unlike brightness(), which multiplies and so cannot
       lift black at all — it brings the artwork UP into view instead of
       covering it over.
       Keep contrast() as HIGH as the text floor allows. Every step down
       flattens the artwork as well as lifting it, and past about 0.4 the
       card stops showing the mark at all — it just looks like a paler panel,
       which defeats the point of thinning the wash. 0.5 leaves roughly 25
       levels of the logo visible through the glass; 0.34 left about 14. */
    --glass-filter: blur(14px) contrast(0.5) brightness(2) saturate(1.8);
    --glass-filter-dense: blur(16px) contrast(0.5) brightness(2) saturate(1.8);
    --panel-border: rgba(255, 255, 255, 0.55);

    --shadow-color: rgba(0, 0, 0, 0.35);
    --shadow-card: 0 4px 18px rgba(0, 0, 0, 0.28);
}

/* Inside a light-mode glass card, text flips to dark. Custom properties
   inherit, so redefining them on the card cascades to everything within it —
   no per-element overrides needed. */
[data-theme="light"] .panel,
[data-theme="light"] .service-card,
[data-theme="light"] .capability-column,
[data-theme="light"] .advantage-item,
[data-theme="light"] .why-item,
[data-theme="light"] .callout,
[data-theme="light"] .cta-box,
[data-theme="light"] .result-panel,
[data-theme="light"] .hero-container,
[data-theme="light"] .contact-form,
[data-theme="light"] .contact-direct,
[data-theme="light"] .footer .container,
[data-theme="light"] .breadcrumb,
[data-theme="light"] .portfolio-item,
[data-theme="light"] .form-group,
/* Catches the inline-styled CTA and callout boxes scattered through the
   service pages. They take their surface from --color-bg-dark, which is glass
   in light mode, so their text has to flip too. Matching the inline style is
   more reliable than maintaining a list of anonymous divs. */
[data-theme="light"] [style*="var(--color-bg-dark)"],
[data-theme="light"] [style*="var(--panel-bg)"] {
    --color-text-white: var(--glass-ink);
    --color-text-gray: var(--glass-ink-gray);
    --color-text-muted: var(--glass-ink-muted);
    --color-accent: var(--glass-accent);
    --color-accent-strong: var(--glass-accent-strong);
    --color-success: var(--glass-success);
    --color-border: var(--glass-line);
    color: var(--color-text-white);
}

/* Reset & Base */
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

html {
    scroll-behavior: smooth;
    /* 17px instead of the 16px default. Type, spacing and radii are all in
       rem, so one change scales the whole page by ~6% rather than leaving
       larger text crammed into unchanged boxes. */
    font-size: 106.25%;
}

body {
    /* 'Inter' was listed here for months but never actually loaded — no font
       link, no @font-face — so every visitor has always seen the system face.
       Leading with the system stack makes the declaration honest and costs no
       download, which matters on rural connections. To use Inter for real,
       self-host the woff2 and add an @font-face rule; do not hotlink Google
       Fonts (extra origin, and the CSP would need widening). */
    font-family: var(--font-body);
    background-color: var(--color-bg-dark);
    color: var(--color-text-white);
    line-height: 1.6;
    font-weight: 600;
    /* Space for the fixed navbar. Measured at 82px with the 17px root size;
       84 leaves a hair of clearance rather than clipping the first heading. */
    padding-top: 84px;
}

.container {
    max-width: 1200px;
    margin: 0 auto;
    padding: 0 var(--spacing-md);
}

/* Typography */
h1, h2, h3, h4 {
    font-weight: 800;
    line-height: 1.2;
    margin-bottom: var(--spacing-sm);
}

h1 { font-size: 3rem; }
h2 { font-size: 2.5rem; }
h3 { font-size: 1.5rem; }
h4 { font-size: 1.25rem; }

p {
    margin-bottom: var(--spacing-sm);
    color: var(--color-text-gray);
}

a {
    color: var(--color-accent);
    text-decoration: none;
    transition: color 0.3s ease;
}

a:not(.btn):hover {
    color: var(--color-gradient-mid);
}

/* Buttons */
.btn {
    display: inline-block;
    padding: 0.75rem 2rem;
    border-radius: var(--radius-sm);
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    transition: all 0.3s ease;
    cursor: pointer;
    border: none;
}

.btn-primary {
    background: linear-gradient(135deg, var(--color-gradient-start), var(--color-gradient-end));
    color: var(--on-accent);
}

.btn-primary:hover {
    transform: translateY(-2px);
    box-shadow: 0 4px 12px rgba(var(--accent-rgb), 0.4);
}

.btn-secondary {
    background: transparent;
    border: 2px solid var(--color-accent);
    color: var(--color-text-white);
}

.btn-secondary:hover {
    background: var(--color-accent);
}

/* Big headings use the display face (--font-display). */
h1, h2, .display {
    font-family: var(--font-display);
}

/* Navigation */
.navbar {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    /* No surface: the wallpaper runs straight through the bar. The nav keeps
       its dark-theme treatment in BOTH themes — it is over artwork, never
       over a card, so light text is what reads there. That is also why the
       navbar is deliberately absent from the light-mode card scope and the
       light glass rules below; adding it back would flip this text dark and
       drop it to ~1.6:1 against the wallpaper.
       Not a panel, a fade: the bar has no edge, it just darkens toward the
       top of the viewport and dissolves. That keeps the wallpaper visible
       through it while stopping page content from colliding with the nav
       links as it scrolls past. A hard border would put the edge back. */
    background: var(--nav-fade);
    padding: var(--spacing-sm) 0 calc(var(--spacing-sm) + 0.5rem);
    z-index: 1000;
    border-bottom: none;
}

.nav-container {
    max-width: 1200px;
    margin: 0 auto;
    padding: 0 var(--spacing-md);
    display: flex;
    justify-content: space-between;
    align-items: center;
    position: relative;
}

/* Theme Toggle */
.theme-toggle {
    background: var(--toggle-gradient) !important;
    border: 2px solid var(--on-accent) !important;
    border-radius: 50%;
    width: 40px;
    height: 40px;
    cursor: pointer;
    display: flex !important;
    align-items: center;
    justify-content: center;
    margin-left: var(--spacing-sm);
    transition: all 0.3s ease;
    flex-shrink: 0;
    font-size: 20px;
    line-height: 1;
    box-shadow: var(--toggle-shadow);
}

.theme-toggle:hover {
    transform: scale(1.1);
    box-shadow: 0 4px 12px rgba(var(--accent-rgb), 0.5);
}

/* Line icons rather than emoji — emoji render differently per platform and
   cannot inherit colour. The markup ships both; CSS shows one per theme. */
.theme-toggle svg {
    width: 20px;
    height: 20px;
    display: block;
    fill: none;
    stroke: var(--on-accent);
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.theme-toggle .sun-icon,
[data-theme="light"] .theme-toggle .moon-icon {
    display: none;
}

[data-theme="light"] .theme-toggle .sun-icon {
    display: block;
}

.nav-logo img {
    height: 40px;
    width: auto;
}

/* Home belongs with the logo, not in the right-hand group. The auto margin
   soaks up the container's free space, so justify-content: space-between has
   none left to distribute and the pair stays flush left while everything
   else is pushed to the right edge. */
.nav-home {
    margin-left: var(--spacing-s);
    margin-right: auto;
    white-space: nowrap;
}

/* The theme toggle is a sibling of the menu, not a child of it, because on
   mobile .nav-menu collapses to max-height:0 with overflow:hidden and nothing
   inside it can sit beside the hamburger. Ordering keeps the desktop row
   looking the same: menu first, toggle last. */
.nav-menu     { order: 1; }
.theme-toggle { order: 2; }
.nav-toggle   { order: 3; }

.nav-menu {
    display: flex;
    list-style: none;
    gap: var(--spacing-md);
}

.nav-link {
    color: var(--color-text-white);
    font-weight: 600;
}

.nav-link:hover {
    color: var(--color-accent);
}

.nav-cta {
    /* A filled button needs its own foreground: inheriting --color-text-white
       gave 3.29:1 in dark and 2.35:1 in light, because the text colour flips
       with the theme while the accent fill does not flip far enough. */
    background: var(--color-accent-strong);
    color: var(--on-accent);
    padding: 0.5rem 1.5rem;
    border-radius: var(--radius-sm);
}

.nav-cta:hover {
    background: var(--color-accent);
    color: var(--on-accent);
}

.nav-toggle {
    display: none;
    background: none;
    border: none;
    cursor: pointer;
}

.hamburger {
    display: block;
    width: 25px;
    height: 3px;
    background: var(--color-text-white);
    position: relative;
}

.hamburger::before,
.hamburger::after {
    content: '';
    position: absolute;
    width: 25px;
    height: 3px;
    background: var(--color-text-white);
}

.hamburger::before { top: -8px; }
.hamburger::after { top: 8px; }

/* Hero Section */
.hero {
    padding: var(--spacing-xl) 0;
    background: transparent;
    text-align: center;
    position: relative;
    min-height: 600px;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Fixed Logo Background - stays centered while scrolling on ALL pages */
body::before {
    /* The logo used as a fixed wallpaper: it stays centred while the page
       scrolls in front of it. background-attachment: fixed is what pins it;
       cover keeps it filling the viewport at any aspect ratio. */
    content: '';
    position: fixed;
    inset: 0;
    background-image: var(--wallpaper);
    background-position: center center;
    background-repeat: no-repeat;
    background-size: cover;
    background-attachment: fixed;
    z-index: -2;
    pointer-events: none;
}

/* Scrim between wallpaper and content. Without it, text crossing the bright
   metallic monogram drops well below readable contrast — the wallpaper is a
   photograph, so contrast varies pixel to pixel and cannot be relied on. */
body::after {
    content: '';
    position: fixed;
    inset: 0;
    background: var(--wallpaper-scrim);
    z-index: -1;
    pointer-events: none;
}

/* Phones get a smaller rendition, and fixed attachment is unreliable on iOS,
   so it scrolls with the page there instead of juddering. */
@media (max-width: 768px) {
    :root { --nav-offset: 5rem; }

    body::before {
        background-image: var(--wallpaper-small);
        background-attachment: scroll;
    }
}

.hero-container {
    max-width: 800px;
    margin: 0 auto;
    padding: 0 var(--spacing-md);
    position: relative;
    z-index: 1;
    /* Tokens, not literals: this panel used to stay 60% near-black in light
       mode while its text flipped to dark, giving 1.53:1 on the subtitle. */
    background: var(--panel-bg);
    backdrop-filter: var(--glass-blur);
    border-radius: var(--radius-lg);
    padding: 3rem 2rem;
    border: 1px solid var(--panel-border);
}

.hero-title {
    font-size: 3.5rem;
    margin-bottom: var(--spacing-md);
    background: linear-gradient(135deg, var(--color-gradient-start), var(--color-gradient-mid), var(--color-gradient-end));
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
}

.hero-subtitle {
    font-size: 1.25rem;
    margin-bottom: var(--spacing-lg);
    color: var(--color-text-gray);
}

.hero-cta {
    display: flex;
    gap: var(--spacing-md);
    justify-content: center;
}

/* Services Section */
.services {
    padding: var(--spacing-xl) 0;
    background: transparent;
}

.section-title {
    text-align: center;
    margin-bottom: var(--spacing-lg);
    position: relative;
    z-index: 1;
}

.services-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: var(--spacing-md);
}

.service-card {
    background: var(--card-bg);
    backdrop-filter: var(--glass-blur);
    padding: var(--spacing-md);
    border-radius: var(--radius);
    border: 1px solid var(--card-border);
    transition: transform 0.3s ease;
}

[data-theme="light"] .service-card {
    background: var(--card-bg-light);
    backdrop-filter: var(--glass-filter);
    border: 2px solid var(--card-border-light);
}

.service-card:hover {
    transform: translateY(-6px);
    box-shadow: var(--card-hover-shadow);
    border-color: var(--color-accent);
}

[data-theme="light"] .service-card:hover {
    box-shadow: var(--card-hover-shadow-light);
}

.service-desc {
    margin-bottom: var(--spacing-xs);
}

.service-audience {
    font-style: italic;
    margin-bottom: var(--spacing-sm);
}

.service-link {
    font-weight: 600;
}

/* Capabilities Section */
.capabilities {
    padding: var(--spacing-xl) 0;
    background: transparent;
}

.capabilities-table {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
    gap: var(--spacing-md);
}

.capability-column {
    background: var(--card-bg);
    backdrop-filter: var(--glass-blur);
    padding: var(--spacing-md);
    border-radius: var(--radius);
    border: 1px solid var(--card-border);
}

[data-theme="light"] .capability-column {
    background: var(--card-bg-light);
    backdrop-filter: var(--glass-filter);
    border: 2px solid var(--card-border-light);
}

.capability-column h3 {
    color: var(--color-accent);
    margin-bottom: var(--spacing-sm);
}

.capability-column:hover,
.capability-card:hover {
    transform: translateY(-4px);
    box-shadow: var(--card-hover-shadow);
    border-color: var(--color-accent);
}

[data-theme="light"] .capability-column:hover,
[data-theme="light"] .capability-card:hover {
    box-shadow: var(--card-hover-shadow-light);
}

.capability-column ul {
    list-style: none;
}

.capability-column li {
    padding: var(--spacing-xs) 0;
    color: var(--color-text-gray);
}

/* Advantage Section */
.advantage {
    padding: var(--spacing-xl) 0;
    background: transparent;
}

.advantage-intro {
    text-align: center;
    font-size: 1.25rem;
    margin-bottom: var(--spacing-lg);
    color: var(--color-text-white);
}

.advantage-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: var(--spacing-md);
}

.advantage-item {
    background: var(--card-bg-soft);
    backdrop-filter: var(--glass-blur);
    padding: var(--spacing-md);
    border-radius: var(--radius);
    border-left: 4px solid var(--color-accent);
}

[data-theme="light"] .advantage-item {
    background: var(--card-bg-soft-light);
    backdrop-filter: var(--glass-filter);
    border-left: 4px solid var(--color-accent);
    border: 2px solid var(--card-border-light);
}

.advantage-item h3 {
    color: var(--color-accent);
    margin-bottom: var(--spacing-xs);
}

/* Portfolio Section */
.portfolio {
    padding: var(--spacing-xl) 0;
    background: transparent;
}

.portfolio-tabs {
    display: flex;
    gap: var(--spacing-sm);
    justify-content: center;
    margin-bottom: var(--spacing-lg);
    flex-wrap: wrap;
}

.tab-btn {
    background: transparent;
    border: 2px solid var(--color-border);
    color: var(--color-text-white);
    padding: 0.5rem 1.5rem;
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: all 0.3s ease;
}

.tab-btn:hover,
.tab-btn.active {
    /* Filled accent buttons need an explicit foreground. Inheriting the themed
       text colour gives 3.29:1 in dark and 2.35:1 in light — the same defect
       that affected .nav-cta and .skip-link. */
    border-color: var(--color-accent-strong);
    background: var(--color-accent-strong);
    color: var(--on-accent);
}

.portfolio-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: var(--spacing-md);
}

.portfolio-item {
    background: var(--color-bg-dark);
    border-radius: var(--radius);
    overflow: hidden;
    border: 1px solid var(--color-border);
}

.portfolio-img {
    width: 100%;
    height: 200px;
    object-fit: cover;
}

.portfolio-item h4 {
    padding: var(--spacing-sm);
    font-size: 1rem;
}

.portfolio-cta {
    text-align: center;
    margin-top: var(--spacing-lg);
}

/* Why J7 Section */
.why-j7 {
    padding: var(--spacing-xl) 0;
    background: transparent;
}

.why-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: var(--spacing-md);
}

.why-item {
    background: var(--card-bg-soft);
    backdrop-filter: var(--glass-blur);
    padding: var(--spacing-md);
    border-radius: var(--radius);
    border: 1px solid var(--panel-border);
}

[data-theme="light"] .why-item {
    background: var(--card-bg-soft-light);
    backdrop-filter: var(--glass-filter);
    border: 2px solid var(--card-border-light);
}

.why-item h3 {
    color: var(--color-accent);
    margin-bottom: var(--spacing-xs);
}

/* Contact Section */
.contact {
    padding: var(--spacing-xl) 0;
    background: transparent;
}

.contact-intro {
    text-align: center;
    margin-bottom: var(--spacing-lg);
}

.contact-form {
    max-width: 600px;
    margin: 0 auto var(--spacing-lg);
}

.form-group {
    margin-bottom: var(--spacing-md);
}

.form-group label {
    display: block;
    margin-bottom: var(--spacing-xs);
    font-weight: 600;
}

.form-group input,
.form-group select,
.form-group textarea {
    width: 100%;
    padding: 0.75rem;
    background: var(--input-bg);
    backdrop-filter: var(--input-blur);
    border: 1px solid var(--input-border);
    border-radius: var(--radius-sm);
    color: var(--color-text-white);
    font-family: inherit;
    font-size: 1rem;
}

[data-theme="light"] .form-group input,
[data-theme="light"] .form-group select,
[data-theme="light"] .form-group textarea {
    background: var(--input-bg-light);
    backdrop-filter: var(--glass-filter);
    -webkit-backdrop-filter: var(--glass-filter);
    border: 2px solid var(--card-border-light);
    color: var(--input-text-light);
    font-weight: 600;
}

.form-group input:focus,
.form-group select:focus,
.form-group textarea:focus {
    outline: none;
    border-color: var(--color-accent);
}

.contact-direct {
    text-align: center;
    padding: var(--spacing-md);
    background: var(--card-bg-soft);
    backdrop-filter: var(--glass-blur);
    border-radius: var(--radius);
    border: 1px solid var(--panel-border);
}

[data-theme="light"] .contact-direct {
    background: var(--card-bg-soft-light);
    backdrop-filter: var(--glass-filter);
    border: 2px solid var(--card-border-light);
}

.contact-area {
    margin-top: var(--spacing-sm);
    font-size: 0.9rem;
}

/* Footer */
.footer {
    padding: var(--spacing-md) 0;
    background: transparent;
    border-top: 1px solid var(--panel-border);
    text-align: center;
}

/* Back to Top Button */
.back-to-top {
    position: fixed;
    bottom: 2rem;
    right: 2rem;
    width: 50px;
    height: 50px;
    background: linear-gradient(135deg, var(--color-gradient-start), var(--color-gradient-mid));
    color: white;
    border: none;
    border-radius: 50%;
    font-size: 1.5rem;
    cursor: pointer;
    box-shadow: var(--float-shadow);
    opacity: 0;
    visibility: hidden;
    transition: all 0.3s ease;
    z-index: 999;
}

.back-to-top.visible {
    opacity: 1;
    visibility: visible;
}

.back-to-top:hover {
    transform: translateY(-4px);
    box-shadow: 0 6px 16px rgba(var(--accent-rgb), 0.4);
}

[data-theme="light"] .back-to-top {
    box-shadow: var(--float-shadow-light);
}

[data-theme="light"] .back-to-top:hover {
    box-shadow: 0 6px 16px rgba(var(--accent-rgb), 0.3);
}

/* Responsive */
@media (max-width: 768px) {
    h1 { font-size: 2rem; }
    h2 { font-size: 1.75rem; }
    h3 { font-size: 1.25rem; }
    
    /* Mobile Navigation */
    .nav-menu {
        position: fixed;
        top: 84px;
        left: 0;
        right: 0;
        background: var(--color-bg-darker);
        flex-direction: column;
        padding: var(--spacing-md);
        border-bottom: 1px solid var(--color-border);
        box-shadow: 0 4px 6px var(--shadow-color);
        max-height: 0;
        overflow: hidden;
        transition: max-height 0.3s ease;
    }
    
    .nav-menu.active {
        display: flex;
        max-height: 400px;
    }
    
    .nav-menu li {
        margin: var(--spacing-xs) 0;
    }
    
    .nav-toggle {
        display: block;
        z-index: 1001;
    }
    
    /* Hero Section Mobile */
    .hero {
        padding: var(--spacing-lg) 0;
        min-height: auto;
    }
    
    .hero-title {
        font-size: 2rem;
        margin-bottom: var(--spacing-sm);
    }
    
    .hero-subtitle {
        font-size: 1rem;
        margin-bottom: var(--spacing-md);
    }
    
    .hero-cta {
        flex-direction: column;
        gap: var(--spacing-sm);
        align-items: center;
    }
    
    .hero-cta .btn {
        width: 100%;
        max-width: 300px;
        text-align: center;
    }
    
    /* Services Grid */
    .services-grid {
        grid-template-columns: 1fr;
        gap: var(--spacing-md);
    }
    
    .service-card {
        padding: var(--spacing-md);
    }
    
    /* Capabilities Table */
    .capabilities-table {
        flex-direction: column;
        gap: var(--spacing-md);
    }
    
    .capability-column {
        padding: var(--spacing-md);
    }
    
    /* Advantage Grid */
    .advantage-grid {
        grid-template-columns: 1fr;
        gap: var(--spacing-md);
    }
    
    .advantage-item {
        padding: var(--spacing-md);
    }
    
    /* Portfolio Tabs */
    .portfolio-tabs {
        flex-wrap: wrap;
        justify-content: center;
        gap: var(--spacing-xs);
    }
    
    .tab-btn {
        padding: 0.5rem 1rem;
        font-size: 0.9rem;
    }
    
    .portfolio-grid {
        grid-template-columns: 1fr;
        gap: var(--spacing-md);
    }
    
    /* Why Grid */
    .why-grid {
        grid-template-columns: 1fr;
        gap: var(--spacing-md);
    }
    
    /* Contact Form */
    .contact-form {
        padding: 0 var(--spacing-sm);
    }
    
    .form-group input,
    .form-group select,
    .form-group textarea {
        font-size: 16px; /* Prevents zoom on iOS */
    }
    
    /* Buttons */
    .btn {
        padding: 0.75rem 1.5rem;
        font-size: 0.9rem;
    }
    
    /* Section Padding */
    .services,
    .capabilities,
    .advantage,
    .portfolio,
    .why-j7,
    .contact {
        padding: var(--spacing-lg) 0;
    }
    
    /* Container */
    .container {
        padding: 0 var(--spacing-sm);
    }
}

/* ---------------------------------------------------------------------------
   COMPONENTS

   These replace the inline style attributes that previously did most of the
   design work. Adding a variant here is always better than writing style=""
   in a page: inline colours cannot respond to the theme, which is what made
   light mode unreadable.
   --------------------------------------------------------------------------- */

/* Panel — the standard bordered surface. Use .panel--accent to emphasise,
   .panel--flush for one with no padding (media cards). */
.panel {
    padding: var(--spacing-m);
    background: var(--panel-bg);
    border: 1px solid var(--panel-border);
    border-radius: var(--radius);
    backdrop-filter: var(--glass-blur);
}

.panel--accent {
    border: 2px solid var(--color-accent);
}

.panel--wash {
    background: linear-gradient(135deg, var(--wash-accent), var(--wash-success));
    border: 2px solid var(--color-accent);
}

.panel--roomy { padding: var(--spacing-md); }
.panel--flush { padding: 0; overflow: hidden; }
.panel--center { text-align: center; }

/* Stack — vertical rhythm without per-element margins */
.stack > * + * { margin-top: var(--spacing-sm); }
.stack-s > * + * { margin-top: var(--spacing-2xs); }
.stack-l > * + * { margin-top: var(--spacing-m); }

/* Text helpers */
.text-muted { color: var(--color-text-gray); }
.text-small { font-size: var(--text-sm); }
.text-fine  { font-size: var(--text-xs); color: var(--color-text-gray); }
.text-accent { color: var(--color-accent); }
.text-success { color: var(--color-success); }
.text-lead  { font-size: var(--text-lg); }
.note { margin-top: var(--spacing-sm); font-size: var(--text-sm); color: var(--color-text-gray); }

/* Card heading used inside panels */
.panel-title {
    color: var(--color-accent);
    margin-bottom: var(--spacing-sm);
    font-size: var(--text-xl);
}

/* Form controls — the estimator inputs previously re-declared this inline
   16 times, bypassing the light-theme override and the iOS zoom fix. */
.form-control {
    width: 100%;
    padding: var(--spacing-s);
    background: var(--color-input-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    color: var(--color-text-white);
    font-size: 16px; /* below 16px iOS zooms the page on focus */
    font-family: inherit;
}

.form-control:focus-visible {
    outline: 2px solid var(--color-accent);
    outline-offset: 2px;
}

.field-label {
    display: block;
    margin-bottom: var(--spacing-2xs);
    font-weight: 600;
}

.field-hint {
    margin-top: var(--spacing-2xs);
    color: var(--color-text-gray);
    font-size: var(--text-sm);
}

/* Grids */
.grid { display: grid; gap: var(--spacing-m); }
.grid--auto   { grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr)); }
.grid--narrow { grid-template-columns: repeat(auto-fit, minmax(min(200px, 100%), 1fr)); }
.grid--wide   { grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr)); }

/* Breadcrumb — was 12 inline styles repeated across three pages */
.breadcrumb {
    padding: var(--spacing-sm) 0;
    background: var(--panel-bg);
    backdrop-filter: var(--glass-blur);
    margin-bottom: var(--spacing-md);
    font-size: var(--text-sm);
}
.breadcrumb a { color: var(--color-accent); text-decoration: none; }
.breadcrumb a:hover { text-decoration: underline; }
.breadcrumb .sep { margin: 0 var(--spacing-2xs); color: var(--color-text-gray); }
.breadcrumb .current { color: var(--color-text-white); }

/* Estimator result panel */
.result-panel {
    padding: var(--spacing-m);
    background: linear-gradient(135deg, var(--wash-accent), var(--wash-success));
    border-radius: var(--radius);
    border: 1px solid var(--color-accent);
}
.result-figure { font-size: var(--text-xl); font-weight: 700; }
.result-total  { font-size: var(--text-2xl); font-weight: 700; color: var(--color-accent); }
.result-label  { color: var(--color-text-gray); font-size: var(--text-sm); }

/* Callout — for the "equipment priced separately" style notices */
.callout {
    padding: var(--spacing-md);
    border-radius: var(--radius);
    border: 2px solid var(--color-accent);
    background: linear-gradient(135deg, var(--wash-accent), var(--wash-success));
    margin-bottom: var(--spacing-l);
}
.callout--success { border-color: var(--color-success); background: var(--wash-success); }

/* Final call-to-action block, previously built six different ways */
.cta-box {
    padding: var(--spacing-md);
    background: var(--panel-bg);
    border: 2px solid var(--color-accent);
    border-radius: var(--radius);
    text-align: center;
    margin-top: var(--spacing-l);
}

/* Accessibility ---------------------------------------------------------- */

.skip-link {
    position: absolute;
    left: -9999px;
    top: 0;
    background: var(--color-accent-strong);
    color: var(--on-accent);
    padding: var(--spacing-2xs) var(--spacing-sm);
    z-index: 1000;
    border-radius: 0 0 var(--radius-sm) 0;
}
.skip-link:focus {
    left: 0;
}

:where(a, button, input, select, textarea, [tabindex]):focus-visible {
    outline: 2px solid var(--color-accent);
    outline-offset: 2px;
    border-radius: 2px;
}

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

/* ---------------------------------------------------------------------------
   NAV SUBMENU
   The three service pages carry all the detailed pricing but were previously
   unreachable from the nav — "Services" only jumped to a homepage section.
   --------------------------------------------------------------------------- */

.has-submenu { position: relative; }

.submenu-toggle {
    background: none;
    border: none;
    cursor: pointer;
    font: inherit;
    color: var(--color-text-white);
    font-weight: 600;
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0;
}

.submenu-toggle .caret {
    border-left: 4px solid transparent;
    border-right: 4px solid transparent;
    border-top: 5px solid currentColor;
    transition: transform 0.2s ease;
}

.submenu-toggle[aria-expanded="true"] .caret { transform: rotate(180deg); }
.submenu-toggle:hover { color: var(--color-accent); }

.submenu {
    position: absolute;
    /* Flush to the trigger on purpose. An offset here leaves a dead zone the
       mouse has to cross, hover is lost on the way down, and the menu closes
       before you can click anything in it. Spacing lives inside the panel. */
    top: 100%;
    left: 0;
    min-width: 250px;
    background: var(--menu-bg);
    backdrop-filter: var(--glass-blur);
    -webkit-backdrop-filter: var(--glass-blur);
    color: var(--menu-text);
    border: 1px solid var(--menu-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-card);
    padding: 0.5rem 0;
    /* Transparent border, not margin: it reads as a gap but is still part of
       the element, so the pointer never leaves the menu on the way in. */
    border-top: 0.5rem solid transparent;
    background-clip: padding-box;
    list-style: none;
    display: none;
    z-index: 1001;
}

.submenu li { margin: 0; }

.submenu a {
    display: block;
    padding: 0.6rem 1.1rem;
    color: var(--color-text-white);
    white-space: nowrap;
}

.submenu a:hover,
.submenu a:focus-visible {
    background: var(--wash-accent);
    color: var(--color-accent);
}

/* Open on hover for pointers, and on click/focus for keyboard and touch */
.has-submenu:hover .submenu,
.has-submenu:focus-within .submenu,
.submenu-toggle[aria-expanded="true"] + .submenu { display: block; }


@media (max-width: 768px) {
    /* No hover on touch: the submenu becomes a nested list, always open,
       so every service page is one tap away once the menu is expanded. */
    .submenu {
        position: static;
        display: block;
        min-width: 0;
        border: none;
        box-shadow: none;
        background: transparent;
        padding: 0 0 0 1rem;
    }
    .submenu a { padding: 0.5rem 0; }
    .submenu-toggle .caret { display: none; }
    .submenu-toggle { cursor: default; }
}

/* Cross-links between service pages — there were none, and one page told the
   reader in plain text to "see the Field Installation page" with no link. */
.related-services { padding: var(--spacing-lg) 0; }

.related-link {
    display: block;
    color: inherit;
    transition: transform 0.2s ease, border-color 0.2s ease;
}

.related-link:hover,
.related-link:focus-visible {
    transform: translateY(-3px);
    border-color: var(--color-accent);
}

.related-link .panel-title { margin-bottom: var(--spacing-2xs); }

/* The service-area map was a fixed 500px with no mobile reduction — half a
   phone screen of embedded map sitting between the visitor and the form. */
.service-map { width: 100%; border: 0; display: block; border-radius: var(--radius); }

@media (max-width: 768px) {
    .service-map { height: 300px !important; }
}

/* ---------------------------------------------------------------------------
   FIXES FOUND IN VISUAL REVIEW
   --------------------------------------------------------------------------- */

/* js/app.js sets display:flex on every .portfolio-item so the grid lays out.
   The homepage carousel cards never declared a direction, so they defaulted to
   row: image, heading and caption sat side by side inside a 350px card and the
   captions wrapped to one or two words per line. */
.portfolio-item {
    flex-direction: column;
}

/* Four service cards in a three-column grid left one stranded on its own row
   with a large empty gap beside it. Two rows of two reads as deliberate. */
@media (min-width: 900px) {
    .services-grid {
        grid-template-columns: repeat(2, 1fr);
    }
}

/* The embedded map is a bright light-mode tile set sitting on a dark page,
   directly above the contact form - the highest-contrast thing on the screen.
   Ease it back so it stops shouting, and let it come forward on hover. */
.service-map {
    filter: saturate(0.85) brightness(0.92);
    transition: filter 0.3s ease;
}
.service-map:hover { filter: none; }

[data-theme="light"] .service-map { filter: none; }

/* Sections stay transparent — the wallpaper is meant to show between content.
   The blocks that need a readable surface get their own card below, rather
   than the whole section becoming one slab. */
.footer {
    border-top: 1px solid var(--panel-border);
}

/* The form and the contact details carry the accent-coloured email and phone
   links, which sit at 2.79:1 on bare wallpaper. They get a card each. */
.contact-form,
.contact-direct,
.footer .container {
    background: var(--panel-bg);
    backdrop-filter: var(--glass-blur);
    -webkit-backdrop-filter: var(--glass-blur);
    border: 1px solid var(--panel-border);
    border-radius: var(--radius);
    padding: var(--spacing-md);
}

.footer .container {
    padding: var(--spacing-m) var(--spacing-md);
}

/* ---------------------------------------------------------------------------
   LIGHT MODE: FROSTED GLASS CARDS OVER THE DARK WALLPAPER

   Light mode is not an inverted page. The wallpaper and scrim stay exactly as
   they are in dark mode; what changes is that content sits on translucent
   white glass instead of dark panels. The blur is what makes it read as glass
   rather than a flat white box — the artwork stays visible through it.
   --------------------------------------------------------------------------- */

[data-theme="light"] .panel,
[data-theme="light"] .service-card,
[data-theme="light"] .capability-column,
[data-theme="light"] .advantage-item,
[data-theme="light"] .why-item,
[data-theme="light"] .cta-box,
[data-theme="light"] .hero-container,
[data-theme="light"] .portfolio-item {
    background: var(--card-bg-light);
    backdrop-filter: var(--glass-filter);
    -webkit-backdrop-filter: var(--glass-filter);
    border-color: var(--portfolio-border-light);
    box-shadow: var(--shadow-card);
}

/* Slightly denser where a visitor reads carefully or types */
[data-theme="light"] .contact-form,
[data-theme="light"] .contact-direct,
[data-theme="light"] .footer .container,
[data-theme="light"] .breadcrumb {
    background: var(--breadcrumb-bg-light);
    backdrop-filter: var(--glass-filter-dense);
    -webkit-backdrop-filter: var(--glass-filter-dense);
}

[data-theme="light"] .form-control {
    background: var(--card-bg-soft-light);
    backdrop-filter: var(--glass-filter);
    -webkit-backdrop-filter: var(--glass-filter);
    border-color: var(--control-border-light);
    color: var(--control-text-light);
}

/* Callouts keep their brand tint but on a light base so they still read */
[data-theme="light"] .callout,
[data-theme="light"] .result-panel {
    background: var(--result-bg-light);
    backdrop-filter: var(--glass-filter);
    -webkit-backdrop-filter: var(--glass-filter);
}

/* The CTA and callout boxes on the service pages take their surface from a
   token in an inline style, so no class rule reaches them. Without the lift
   they would be a 29% wash straight onto near-black artwork. */
[data-theme="light"] [style*="var(--color-bg-dark)"],
[data-theme="light"] [style*="var(--color-bg-darker)"],
[data-theme="light"] [style*="var(--color-card-bg)"],
[data-theme="light"] [style*="var(--panel-bg)"] {
    backdrop-filter: var(--glass-filter);
    -webkit-backdrop-filter: var(--glass-filter);
    border-radius: var(--radius);
}

/* Where backdrop-filter is unsupported, fall back to a more opaque card so
   text never lands on bare artwork. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    [data-theme="light"] .panel,
    [data-theme="light"] .service-card,
    [data-theme="light"] .capability-column,
    [data-theme="light"] .advantage-item,
    [data-theme="light"] .cta-box,
    [data-theme="light"] .hero-container,
    [data-theme="light"] .portfolio-item,
    [data-theme="light"] .contact,
    [data-theme="light"] .footer {
        background: var(--footer-bg-light);
    }
}


/* The service-area section is transparent; the cards inside it carry their
   own surface. A full-width band here swallowed the wallpaper. */

/* Controls with a filled background and white text need a fill that stays
   dark in BOTH themes. The theme tokens cannot serve this: light mode's accent
   is deliberately light so it reads on the dark wallpaper, which leaves white
   text on light purple at ~2.5:1. */
:root, [data-theme="light"] {
    --color-control-fill: #4c1d95;
}

/* The estimator result panel carries a brand wash on top of the card, so it
   sits lighter than a plain panel and the deepened violet drops to 4.04:1 on
   it. This one surface keeps a lighter accent. The light-mode rule below is
   explicit so the deep purple is never at the mercy of source order. */
.result-panel { --color-accent: var(--result-accent); }
[data-theme="light"] .result-panel { --color-accent: var(--glass-accent); }

/* The arrows set `background: var(--color-accent)` inline. Redefining the
   token on the element is cleaner than an !important override. */
button[onclick^="scrollPortfolio"] {
    --color-accent: var(--color-control-fill);
    color: var(--on-accent);
}

/* Readable by a screen reader, invisible on screen. For inputs whose purpose
   is obvious from the copy around them but which still need a real label. */
.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
}

.skip-link {
    background: var(--color-control-fill);
    color: var(--on-accent);
}

/* Active filter tab is a filled control with white text, so it needs the
   theme-independent fill for the same reason the arrows do. */
.tab-btn.active {
    background: var(--color-control-fill);
    border-color: var(--color-control-fill);
    color: var(--on-accent);
}

/* A violet link on a green wash is inherently low-contrast — the two sit at
   similar luminance. Inside a tinted callout, links take the body colour and
   lean on an underline to read as links. */
/* The links carry an inline `color: var(--color-accent)`, which beats any
   stylesheet rule — so redefine the token on the container instead. */
[style*="var(--wash-success)"],
[style*="var(--wash-accent)"] {
    --color-accent: var(--color-text-white);
}

[style*="var(--wash-success)"] a,
[style*="var(--wash-accent)"] a {
    text-decoration: underline;
    text-underline-offset: 2px;
}

/* ---------------------------------------------------------------------------
   FAQ ACCORDION
   <details> does the open/close natively — no JavaScript, works with the
   keyboard for free, and the answers are in the DOM for search engines whether
   or not anyone expands them.
   --------------------------------------------------------------------------- */
.faq-item {
    margin-bottom: var(--spacing-s);
}

.faq-item summary {
    cursor: pointer;
    font-weight: 700;
    font-size: var(--text-lg);
    list-style: none;
    display: flex;
    align-items: flex-start;
    gap: 0.75rem;
}

/* Hide the default disclosure triangle in both engines, then draw our own so
   it can be positioned and coloured. */
.faq-item summary::-webkit-details-marker { display: none; }

.faq-item summary::before {
    content: '+';
    color: var(--color-accent);
    font-weight: 700;
    line-height: 1.2;
    flex-shrink: 0;
}

.faq-item[open] summary::before { content: '−'; }

.faq-item[open] summary { margin-bottom: var(--spacing-2xs); }

.faq-item p {
    color: var(--color-text-gray);
    padding-left: 1.6rem;
}

/* A hairline above the FAQ entry so it reads as a different kind of thing to
   the service links above it. */
.submenu-sep {
    border-top: 1px solid var(--panel-border);
    margin-top: 0.35rem;
    padding-top: 0.35rem;
}

/* The question sits under the section heading rather than replacing it: the
   section is still Services, and the question is how you find your way into it.
   A styled paragraph, not a heading — it introduces the cards, it does not
   contain them, and making it an h3 would misdescribe the structure.
   It sits on bare wallpaper, so it takes the page-level text colour, which is
   light in both themes. */
.section-question {
    text-align: center;
    font-size: var(--text-xl);
    font-weight: 700;
    color: var(--color-text-white);
    margin-bottom: var(--spacing-2xs);
}

/* ---------------------------------------------------------------------------
   SERVICE CARDS: QUESTION FIRST
   Each card opens with the problem in the customer's words, then answers it
   with the service. The two used to be separate sections saying the same thing
   in two different voices.
   --------------------------------------------------------------------------- */
.service-question {
    color: var(--color-accent);
    font-size: var(--text-lg);
    font-weight: 800;
    line-height: 1.3;
    margin-bottom: var(--spacing-3xs);
}

.service-symptom {
    color: var(--color-text-muted);
    font-style: italic;
    font-size: var(--text-sm);
    padding-bottom: var(--spacing-s);
    margin-bottom: var(--spacing-s);
    border-bottom: 1px solid var(--panel-border);
}

/* The service name is the answer, so it steps back from the question above it
   rather than competing with it. */
.service-card h3 {
    font-size: var(--text-xl);
}

/* ---------------------------------------------------------------------------
   PRINT WEIGHT HELPER
   --------------------------------------------------------------------------- */
.weight-helper {
    border: 1px solid var(--panel-border);
    border-radius: var(--radius);
    padding: var(--spacing-m);
    margin-bottom: var(--spacing-m);
    background: var(--wash-accent);
}

.wh-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-bottom: var(--spacing-m);
}

.wh-tab {
    flex: 1 1 auto;
    padding: 0.6rem 1rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--color-text-white);
    font: inherit;
    font-weight: 600;
    cursor: pointer;
}

.wh-tab.active {
    background: var(--color-control-fill);
    border-color: var(--color-control-fill);
    color: var(--on-accent);
}

.wh-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: var(--spacing-sm);
    margin-bottom: var(--spacing-sm);
}

.wh-dims {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 0.5rem;
}

.wh-mesh,
.wh-result {
    margin-top: var(--spacing-sm);
    padding: var(--spacing-sm);
    border-radius: var(--radius-sm);
    background: var(--wash-success);
    border: 1px solid var(--color-border);
}

.wh-result strong { font-size: var(--text-lg); }

/* .form-control sets width:100%, which in a flex row makes the unit dropdown
   claim the whole line and squeeze the number beside it down to 28px. The
   dropdown only needs to be as wide as the word "grams". */
#weight-unit {
    flex: 0 0 auto;
    width: auto;
}

/* Intake questions on the contact form. Two columns on anything wide enough,
   one on a phone — a five-field grid that reflows to a single column is much
   less daunting than five full-width rows. */
.intake-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
    gap: var(--spacing-sm);
}

/* ---------------------------------------------------------------------------
   The site assistant
   ---------------------------------------------------------------------------
   Built by js/chat.js, so there is no markup for it in any page. It uses the
   frosted .panel treatment, which is what carries the design in both themes:
   the wallpaper stays dark, the card floats over it.

   The launcher owns the bottom-right corner, so .back-to-top stacks above it
   rather than underneath. */

.chat-root {
    position: fixed;
    bottom: 2rem;
    right: 2rem;
    z-index: 1000;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: var(--spacing-2xs);
}

.chat-launcher {
    display: inline-flex;
    align-items: center;
    gap: var(--spacing-2xs);
    padding: var(--spacing-2xs) var(--spacing-sm);
    background: linear-gradient(135deg, var(--color-gradient-start), var(--color-gradient-mid));
    color: var(--on-accent);
    border: none;
    border-radius: 999px;
    font-size: var(--text-sm);
    font-weight: 600;
    cursor: pointer;
    box-shadow: 0 4px 12px var(--shadow-color);
    transition: transform 0.3s ease, box-shadow 0.3s ease;
}

.chat-launcher:hover {
    transform: translateY(-2px);
    box-shadow: 0 6px 16px var(--shadow-color);
}

.chat-launcher__icon { font-size: var(--text-lg); line-height: 1; }

/* [hidden] is a UA rule at element specificity, so a class that sets display
   silently beats it and the panel is open from the first paint. */
.chat-panel[hidden] { display: none; }

.chat-panel {
    width: min(23rem, calc(100vw - 2rem));
    max-height: min(32rem, calc(100vh - 8rem));
    display: flex;
    flex-direction: column;
    padding: 0;
    overflow: hidden;
    background: var(--panel-bg-solid);
    box-shadow: 0 12px 32px var(--shadow-color);
}

.chat-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--spacing-2xs);
    padding: var(--spacing-s) var(--spacing-sm);
    border-bottom: 1px solid var(--panel-border);
}

.chat-note a {
    color: var(--color-accent);
    text-decoration: underline;
}

.chat-note {
    margin: var(--spacing-3xs) 0 0;
    font-size: var(--text-xs);
    /* --color-text-muted is the faintest token, and this is the smallest type
       in the widget. Over frosted glass that pairing is the first thing to
       fail a contrast check, so the note takes the stronger grey. */
    color: var(--color-text-gray);
}

.chat-close {
    background: none;
    border: none;
    color: var(--color-text-gray);
    font-size: var(--text-xl);
    line-height: 1;
    cursor: pointer;
    padding: 0 var(--spacing-3xs);
}

.chat-close:hover { color: var(--color-text-white); }

.chat-log {
    flex: 1 1 auto;
    overflow-y: auto;
    padding: var(--spacing-sm);
    display: flex;
    flex-direction: column;
    gap: var(--spacing-2xs);
}

.chat-msg { display: flex; flex-direction: column; max-width: 90%; }
.chat-msg--user { align-self: flex-end; align-items: flex-end; }
.chat-msg--assistant { align-self: flex-start; }

.chat-bubble {
    padding: var(--spacing-2xs) var(--spacing-s);
    border-radius: var(--radius);
    font-size: var(--text-sm);
    line-height: 1.5;
    white-space: pre-wrap;
    background: var(--color-input-bg);
    color: var(--color-text-gray);
}

.chat-msg--user .chat-bubble {
    background: var(--wash-accent-strong);
    color: var(--color-text-white);
}

.chat-bubble--error {
    background: var(--wash-accent);
    border: 1px solid var(--color-accent);
}

.chat-handoff {
    margin-top: var(--spacing-2xs);
    align-self: flex-start;
    font-size: var(--text-sm);
}

/* The send card: the contact form's essentials inside the chat, so a
   conversation that ends in "yes, send it" is sent from where it happened.
   Inputs reuse .chat-input, so both themes are already right. */
.chat-msg--wide { align-self: stretch; max-width: 100%; }

.chat-send-card {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-3xs);
    margin-top: var(--spacing-2xs);
    padding: var(--spacing-s);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-card-bg);
}

.chat-send-card__title { margin: 0; font-weight: 700; color: var(--color-text-white); }

.chat-send-card__hint,
.chat-send-card__small { margin: 0; font-size: var(--text-sm); color: var(--color-text-gray); }

.chat-send-card__small a { color: var(--color-accent); }

.chat-send-card__label {
    margin-top: var(--spacing-3xs);
    font-size: var(--text-sm);
    color: var(--color-text-white);
}

.chat-send-card__optional { color: var(--color-text-gray); }

.chat-send-card .chat-input { width: 100%; font-family: inherit; }

.chat-send-card__message { resize: vertical; line-height: 1.4; }

.chat-send-card__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--spacing-2xs);
    margin-top: var(--spacing-2xs);
}

.chat-send-card__cancel {
    background: none;
    border: none;
    padding: var(--spacing-3xs);
    color: var(--color-text-gray);
    font-size: var(--text-sm);
    text-decoration: underline;
    cursor: pointer;
}

.chat-send-card__status { margin: 0; font-size: var(--text-sm); color: var(--color-text-white); }
.chat-send-card__status:empty { display: none; }

.chat-sent { border: 1px solid var(--color-accent); color: var(--color-text-white); }

/* Tap-to-answer choices under a question. Pill-shaped so they read as
   buttons, quieter than Send so they do not compete with it. The suggested
   answer carries the accent border, bold text and a small label - not a
   tinted background, which over the light theme's frosted panel dropped
   its text to 3:1. Everything sits on the same fill as the other chips. */
.chat-choices {
    display: flex;
    flex-wrap: wrap;
    gap: var(--spacing-3xs);
    margin-top: var(--spacing-2xs);
}

.chat-choice {
    padding: var(--spacing-3xs) var(--spacing-s);
    background: var(--color-input-bg);
    color: var(--color-text-white);
    border: 1px solid var(--color-border);
    border-radius: 999px;
    font-size: var(--text-sm);
    line-height: 1.4;
    cursor: pointer;
}

.chat-choice:hover,
.chat-choice:focus-visible {
    border-color: var(--color-accent);
}

.chat-choice--suggested {
    border-color: var(--color-accent);
    font-weight: 600;
}

.chat-choice__tag {
    margin-left: var(--spacing-3xs);
    font-size: var(--text-xs);
    font-weight: 400;
    color: inherit;
}

/* Three dots while the answer is on its way. Reduced-motion visitors get a
   static row rather than nothing, so the wait is still visible. */
.chat-bubble--typing { display: flex; gap: 0.25rem; align-items: center; }

.chat-bubble--typing span {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--color-text-muted);
    animation: chat-blink 1.2s infinite ease-in-out;
}

.chat-bubble--typing span:nth-child(2) { animation-delay: 0.2s; }
.chat-bubble--typing span:nth-child(3) { animation-delay: 0.4s; }

@keyframes chat-blink {
    0%, 80%, 100% { opacity: 0.3; }
    40% { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
    .chat-bubble--typing span { animation: none; opacity: 0.6; }
    .chat-launcher { transition: none; }
}

.chat-form {
    display: flex;
    gap: var(--spacing-2xs);
    padding: var(--spacing-2xs) var(--spacing-sm) var(--spacing-sm);
}

.chat-input {
    flex: 1 1 auto;
    min-width: 0;
    padding: var(--spacing-2xs) var(--spacing-s);
    background: var(--color-input-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    color: var(--color-text-white);
    font-size: var(--text-sm);
}

.chat-input:focus {
    outline: 2px solid var(--color-accent);
    outline-offset: 1px;
}

.chat-send { flex: 0 0 auto; font-size: var(--text-sm); }

/* On a phone the panel is the screen, not a card floating in the corner. */
@media (max-width: 600px) {
    .chat-root { bottom: 1rem; right: 1rem; left: 1rem; align-items: stretch; }
    .chat-launcher { align-self: flex-end; }
    .chat-panel { width: 100%; max-height: calc(100vh - 6rem); }
}

/* The launcher sits where back-to-top used to. Move it up rather than let the
   two overlap — the launcher is always visible, back-to-top only sometimes. */
.back-to-top { bottom: 6rem; }

@media (max-width: 600px) {
    .back-to-top { bottom: 5rem; }
}
