/**
 * The site rail, a fixed slate column down the right of the homepage holding the
 * scroll-built three.js house, plus the "Plan your extension" panel that
 * controls it.
 *
 * The rail is a layout element, not a backdrop: the page content is inset to
 * the left of it (`.has-rail main { padding-right }`) so nothing is ever in
 * front of the canvas. That is what lets the model be lit and coloured properly
 * — when it sat behind the page its palette was capped by the contrast the body
 * copy needed in front of it, and it read as a model left in shadow.
 *
 * `has-rail` is set on <html> before first paint by the inline test in
 * index.html, and removed again by extension-3d.js if the scene can't run.
 * The width threshold below must match MIN_WIDTH in extension-3d.js.
 */

:root {
    --rail-w: clamp(360px, 30vw, 560px);
}

/* Everything full-width on the page is inset by the rail's width — the footer
   included, or it would run underneath it. */
.has-rail main,
.has-rail #footer-include { padding-right: var(--rail-w); }

.site-rail { display: none; }

.has-rail .site-rail {
    display: block;
    position: fixed;
    top: var(--header-h);
    right: 0;
    bottom: 0;
    width: var(--rail-w);
    z-index: 3;
    /* Scenery, never a control — clicks and scrolls pass straight through. */
    pointer-events: none;
    overflow: hidden;
    border-left: 1px solid var(--slate-700);
    background:
        radial-gradient(120% 60% at 78% 18%, rgba(140, 150, 158, 0.30) 0%, rgba(140, 150, 158, 0) 62%),
        linear-gradient(to bottom, var(--slate-900) 0%, var(--slate-800) 46%, #14181b 100%);
}

/* The canvas fades up once the first frame is on screen, so the rail never
   flashes an empty box while three.js is still parsing. */
.site-rail canvas {
    display: block;
    width: 100%;
    height: 100%;
    opacity: 0;
    transition: opacity 700ms var(--ease);
}
.site-rail.is-ready canvas { opacity: 1; }

/* Keep the back-to-top button clear of the rail. */
.has-rail .back-to-top { right: calc(var(--rail-w) + 24px); }

/* ── Background layer (narrow screens) ────────────────────────────────────── */
/* Too narrow for a column, so the house goes behind the page instead: fixed at
   z-index -1, above the page background and below all content, never taking
   pointer events.
 *
 * The opacity is a MEASURED CEILING, not a taste call — body copy sits directly
 * on top of this. See "The background layer's contrast ceiling" in CLAUDE.md
 * before touching it or the palette in extension-3d.js. */
.site-bg { display: none; }

.has-bg .site-bg {
    display: block;
    position: fixed;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    opacity: 0;
    transition: opacity 700ms var(--ease);
    /* A real sky for the house to stand in. This used to sit within a few
       percent of --paper, from back when the copy bands were translucent and
       anything here bled through behind body text. The bands are fully opaque
       now, so nothing is laid over this and it has no contrast ceiling — and
       near-paper was the other half of why the phone version looked bleached:
       a pale model against a white sky has nothing to read against.
       The horizon band is matched to the scene's own fog colour so the far end
       of the terrace dissolves into it rather than stopping on a silhouette. */
    background: linear-gradient(to bottom, #9db7d1 0%, #c3cedb 42%, #dcdfda 74%, #d3d3ca 100%);
}
.has-bg .site-bg.is-ready { opacity: var(--bg-opacity); }
.site-bg canvas { display: block; width: 100%; height: 100%; }

/* Full strength. That is only safe because no body copy is ever laid over it:
   the bands that carry text keep a solid background of their own (below), and
   the scene shows through the deliberate window at the planner. Fading it
   instead is what made the old background version look like a model in shadow —
   measured, the darkest rendered pixel would have to be about sRGB 180 before
   muted text cleared 4.5:1 at even 30% opacity, and a house that pale has no
   colour left in it. */
:root { --bg-opacity: 1; }

/* Every band that carries copy is fully opaque. That is the whole design: the
   house is never behind text, so it never has to be faded, and it keeps its
   colour. Letting it show through the bands was tried and measured — with the
   scene at full richness its darkest rendered pixel is rgb(17,19,22), and even
   10% show-through puts --stone-600 at ~4.4:1, under the line. Fading the scene
   until that passes is the washed-out version this replaced. So it gets windows
   of its own instead: the showcase, and the planner. */
/* LIGHT bands stay fully opaque. That direction is the measured failure: dark
   copy on a light band needs the band to stay light, and the scene's darkest
   pixels drag it down fast (see the table in CLAUDE.md). */
.has-bg main > section { background-color: var(--paper); }
.has-bg main > section.section--stone { background-color: var(--stone-50); }

/* DARK bands are a different problem and can carry the scene. White text on a
   heavily scrimmed near-black composite is the forgiving direction: measured
   against the brightest pixel the scene renders, the worst case here is still
   about 8:1 for white and 5:1 for --brick-pale, where the light bands could not
   clear 4.5:1 at even 12% show-through. So every dark band on the page becomes
   a window onto the house instead of hiding it.
   Re-measure with scratchpad bg-contrast.js if these alphas change. */
.has-bg main > section.trust-strip,
.has-bg main > section.section--dark { background-color: rgba(34, 39, 43, 0.80); }
.has-bg main > section.cta-band { background-color: rgba(27, 31, 35, 0.78); }
.has-bg .site-footer { background-color: rgba(27, 31, 35, 0.86); }

/* The showcase is a clear window onto the scene: nothing over it but the stage
   readout, on its own card at the foot of the screen. Class-scoped so it beats
   the band rule above without reaching for an id. */
.build-showcase { display: none; }
.has-bg main > section.build-showcase {
    display: flex;
    align-items: flex-end;
    min-height: 100vh;
    padding-block: 0 clamp(20px, 5vh, 44px);
    background: transparent;
}
.has-bg .showcase-slot .planner-panel {
    background: var(--paper);
    border: 1px solid var(--stone-200);
    padding: clamp(18px, 4.5vw, 26px);
}
.has-bg .showcase-slot .planner-stage-note { min-height: 0; }

/* …and the planner is the window — the id keeps it ahead of the band rules
   above, which is where the white-on-paper bug came from the first time: a
   `:not(#planner)` in that selector carried id specificity and beat the dark band. */

/* …and the planner is the window: a clear screen of the finished house, then
   the copy on its own card. The lead-in is the whole point — on a phone the
   card is nearly full width, so without it the scene shows only as slivers
   down the sides. */
.has-bg main > section#planner {
    background: transparent;
    padding-top: 88vh;
}
.has-bg #planner .planner-copy {
    background: var(--paper);
    padding: clamp(20px, 5vw, 32px);
    border: 1px solid var(--stone-200);
}

/* Between 1200px and the point the content column is comfortable again, the
   page's four-across grids have too little room beside the rail. */
@media (min-width: 1200px) and (max-width: 1559px) {
    .has-rail .trust-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .has-rail .trust-item:nth-child(-n+2) { border-top: 0; }
    .has-rail .trust-item:nth-child(odd) { border-left: 0; padding-left: 0; }
    .has-rail .services-layout { grid-template-columns: 1fr; gap: 40px; }
    .has-rail .process-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .has-rail .split { grid-template-columns: 1fr; }
    .has-rail .footer-main { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ── Planner panel ────────────────────────────────────────────────────────── */
/* With the rail running the copy is on its own; without it the section falls
   back to two columns, copy beside a photo. */
.planner-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: clamp(28px, 4vw, 60px);
    align-items: center;
}
/* Single column, but not a full-width one — the option rows would stretch the
   floor-area figure right away from the option it belongs to. */
.has-rail .planner-layout { grid-template-columns: minmax(0, 1fr); }
.has-rail .planner-copy { max-width: 680px; }

.planner-head { margin-bottom: 26px; }
.planner-head h2 { margin-bottom: 12px; }
.planner-head p { font-size: 1rem; line-height: 1.7; color: var(--ink-soft); }

.planner-panel[hidden] { display: none; }

/* ── Build stage readout ──────────────────────────────────────────────────── */
.planner-stage-index {
    display: block;
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--brick-dark);
    margin-bottom: 10px;
}
.planner-stage-name {
    font-family: var(--font-display);
    font-size: clamp(1.375rem, 1.1rem + 1.1vw, 1.875rem);
    font-weight: 700;
    letter-spacing: -0.02em;
    line-height: 1.15;
    color: var(--slate-800);
    margin-bottom: 10px;
}
.planner-stage-note {
    font-size: 0.9375rem;
    line-height: 1.7;
    color: var(--ink-soft);
    min-height: 3.4em;
}

.planner-bar-track {
    height: 3px;
    background: var(--stone-200);
    margin-top: 26px;
    overflow: hidden;
}
.planner-bar {
    height: 100%;
    width: 0;
    background: var(--brick);
    transition: width 90ms linear;
}
.planner-bar-hint {
    margin-top: 12px;
    font-size: 0.8125rem;
    letter-spacing: 0.04em;
    color: var(--stone-600);
}

/* ── Options ──────────────────────────────────────────────────────────────── */
.planner-options {
    display: grid;
    gap: 0;
    border-top: 1px solid var(--stone-200);
}

.planner-option {
    display: grid;
    grid-template-columns: 22px minmax(0, 1fr) auto;
    align-items: center;
    gap: 14px;
    width: 100%;
    padding: 14px 4px;
    border-bottom: 1px solid var(--stone-200);
    text-align: left;
    color: var(--ink);
    transition: background-color var(--t), padding-left var(--t);
}
.planner-option:hover { background: var(--stone-50); padding-left: 10px; }

/* Square indicator — filled gold when the option is on. */
.planner-tick {
    width: 20px;
    height: 20px;
    border: 1.5px solid var(--stone-300);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: transparent;
    transition: background-color var(--t), border-color var(--t), color var(--t);
}
.planner-tick .icon { width: 13px; height: 13px; stroke-width: 3; }
.planner-option[aria-pressed="true"] .planner-tick {
    background: var(--brick-warm);
    border-color: var(--brick-warm);
    color: var(--slate-900);
}

.planner-option h3 { font-size: 0.9375rem; margin-bottom: 2px; }
.planner-option p { font-size: 0.8125rem; line-height: 1.5; color: var(--ink-soft); }
.planner-option .planner-gain {
    font-family: var(--font-display);
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--stone-600);
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

/* ── Running total ────────────────────────────────────────────────────────── */
.planner-total {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 20px;
    flex-wrap: wrap;
    margin-top: 20px;
    padding: 16px 20px;
    background: var(--slate-800);
    color: #fff;
}
.planner-total-label {
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--brick-pale);
}
.planner-total-value {
    font-family: var(--font-display);
    font-size: clamp(1.5rem, 1.2rem + 1.2vw, 2.125rem);
    font-weight: 700;
    line-height: 1;
    letter-spacing: -0.02em;
    color: #fff;
    font-variant-numeric: tabular-nums;
}

.planner-note {
    margin-top: 14px;
    font-size: 0.8125rem;
    line-height: 1.6;
    color: var(--stone-600);
}

.planner-actions { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 18px; }

/* ── Photo fallback (no WebGL or reduced motion) ──────────────────────────── */
.planner-fallback {
    position: relative;
    background: var(--stone-50);
    border: 1px solid var(--stone-200);
}
.planner-fallback[hidden] { display: none; }
.planner-fallback img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }
.planner-fallback figcaption {
    padding: 14px 18px;
    font-size: 0.8125rem;
    color: var(--stone-600);
    border-top: 1px solid var(--stone-200);
}
/* Corner tick marks — reads as a drawing sheet rather than a widget. */
.planner-fallback::before,
.planner-fallback::after {
    content: '';
    position: absolute;
    width: 26px;
    height: 26px;
    pointer-events: none;
    z-index: 1;
}
.planner-fallback::before {
    top: -1px; left: -1px;
    border-top: 2px solid var(--brick);
    border-left: 2px solid var(--brick);
}
.planner-fallback::after {
    bottom: -1px; right: -1px;
    border-bottom: 2px solid var(--brick);
    border-right: 2px solid var(--brick);
}

/* ── Narrow ───────────────────────────────────────────────────────────────── */
@media (max-width: 899px) {
    .planner-layout { grid-template-columns: 1fr; gap: 26px; }
    .planner-stage-note { min-height: 0; }
}

@media (max-width: 767px) {
    .planner-option { grid-template-columns: 20px minmax(0, 1fr); padding: 12px 2px; }
    .planner-option .planner-gain { grid-column: 2; margin-top: 3px; }
    .planner-actions .btn { width: 100%; }
    .planner-total { padding: 14px 16px; }
}
