/* ==========================================================================
   home.css — homepage-only sections. Not loaded by service or location pages.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Hero. Two paths split by urgency: call now (broken door) dominates,
   get a quote (planning) is subordinate. The scrim exists to keep white type
   at AA over the photograph; do not lighten it.
   -------------------------------------------------------------------------- */
.hero {
    position: relative;
    isolation: isolate;
    display: grid;
    align-items: center;
    min-height: min(76vh, 62rem);
    padding-block: var(--space-9) var(--space-8);
    color: var(--ink-on-dark);
}

/* IMG_1365 is the only true landscape single-subject photo in the gallery.
   Do not swap in IMG_1338 or IMG_1346: both are 6-panel collages and read as
   seams and competing horizons behind the headline. */
.hero::before {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -2;
    background: url("../images/gallery/IMG_1365.jpeg") center right / cover no-repeat;
}

/* Two-part scrim. The horizontal ramp holds the text column; the bottom
   vignette is what keeps the service links legible where the photo goes pale.
   Keeps white type above 4.5:1 across the whole photo. */
.hero::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: -1;
    background:
        linear-gradient(
            180deg,
            rgb(var(--scrim-rgb) / 0) 55%,
            rgb(var(--scrim-rgb) / 0.75) 100%
        ),
        linear-gradient(
            90deg,
            rgb(var(--scrim-rgb) / 0.86) 0%,
            rgb(var(--scrim-rgb) / 0.82) 62%,
            rgb(var(--scrim-rgb) / 0.60) 78%,
            rgb(var(--scrim-rgb) / 0.42) 100%
        );
}

/* Left-anchored, so the headline's left edge lines up with the logo and nav
   above it. Previously this element was the centred `.container` itself, which
   floated a left-ragged text block in the middle of the viewport. */
.hero__inner {
    max-width: 80ch;   /* headline measure, in characters */
    margin-right: auto;
}

/* First-load choreography. The hero is seen once per visit, so it earns an
   entrance. Built on @starting-style: the from-state exists only for the
   first render, so where it is unsupported the content is simply already
   there. Motion never gates the headline or the phone number. */
/* `.hero__services` is a sibling of `.hero__inner`, not a child, so it is named
   here to stay in the same entrance sequence. */
.hero__inner > *,
.hero__services {
    transition: opacity 480ms var(--ease-out),
                translate 480ms var(--ease-out);
}

@starting-style {
    .hero__inner > *,
    .hero__services {
        opacity: 0;
        translate: 0 12px;
    }
}

.hero__inner > *:nth-child(1) { transition-delay: 40ms; }
.hero__inner > *:nth-child(2) { transition-delay: 100ms; }
.hero__inner > *:nth-child(3) { transition-delay: 160ms; }
.hero__inner > *:nth-child(4) { transition-delay: 220ms; }
.hero__services { transition-delay: 280ms; }

.hero__eyebrow {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    margin-bottom: var(--space-5);
    padding: var(--space-2) var(--space-4);
    background: rgba(255, 255, 255, 0.12);
    border: 1px solid rgba(255, 255, 255, 0.28);
    border-radius: var(--radius-pill);
    font-family: var(--font-display);
    font-size: var(--text-sm);
    font-weight: 700;
    color: var(--ink-on-dark);
}

.hero__eyebrow svg {
    fill: var(--star);
}

.hero h1 {
    color: var(--ink-on-dark);
    margin-bottom: var(--space-5);
}

/* Only force the line break where the line provably fits. Below 720px the
   spans wrap naturally, because "GARAGE DOOR" set at the clamp minimum can
   exceed a 360px content column, and an overflowing headline is worse than an
   awkward break. */
.hero__line {
    display: inline;
}

@media (min-width: 720px) {
    .hero__line {
        display: block;
    }

    /* The spans are already their own lines here, so the mobile break is off. */
    .hero__br {
        display: none;
    }
}

/* The "Greater Toronto Area" lead-in sits smaller than the main line. */
.hero__line--sm {
    font-size: 0.7em;
}

/* The highlighted phrase is a <mark>; reset its default yellow highlight and
   carry the same blue accent the rest of the accent used. */
.hero h1 mark {
    display: block;
    background: none;
    font-size: 0.9em;
    color: var(--blue-on-scrim);   /* 6.6:1 on the scrim */
}

/* On the narrowest phones the two accent lines shrink further so the H1
   holds its shape without the long words forcing a wrap. */
@media (max-width: 375px) {
    .hero__line--sm {
        font-size: 0.5em;
    }

    .hero h1 mark {
        font-size: 0.8em;
    }
}

.hero__lead {
    margin-bottom: var(--space-6);
    font-size: var(--text-lg);
    color: var(--on-ink);
}

/* The urgency split. Call dominates by colour and size, not by isolation. */
.hero__paths {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
    align-items: center;
}

/* Both CTAs share a height so the row reads as one pair. Hierarchy comes from
   colour and type size, not from a height difference that looks accidental.
   The floor scales the pair together on large screens; the max() keeps it from
   dropping under the 48px control floor in the compressed tablet band. */
.hero__paths .btn {
    min-height: max(6rem, 48px);
}

.hero__paths .btn--outline {
    border-color: rgba(255, 255, 255, 0.45);
    color: var(--ink-on-dark);
    backdrop-filter: blur(2px);
}

.hero__paths .btn--outline:hover {
    background: rgba(255, 255, 255, 0.14);
    border-color: var(--ink-on-dark);
    color: var(--ink-on-dark);
}

/* --------------------------------------------------------------------------
   Service links. A quiet row, but every item is a real link to the page that
   treats that symptom. This is the shortest path from "my spring snapped" to
   the spring page, and it carries six internal links out of the hero.
   -------------------------------------------------------------------------- */
/* The chevrons cost ~19px per chip, which pushes six of them past the text
   column. Rather than cram them into one row, the label takes its own line and
   the chips wrap into tidy rows. */
.hero__services {
    display: block;
    margin-top: var(--space-7);
    padding-top: var(--space-5);
    border-top: 1px solid rgba(255, 255, 255, 0.16);
}

.hero__services-label {
    display: block;
    margin-bottom: var(--space-3);
    font-family: var(--font-display);
    font-size: var(--text-xs);
    font-weight: 700;
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    color: var(--on-ink-muted);
}

/* Uncapped: the row spans the container and the chips wrap where they wrap. */
.hero__services ul {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
    list-style: none;
}

/* These read as tags unless something says "this goes somewhere". The chevron
   says it. Enlarging them instead would put a third weight class in a hero
   that already has two calls to action. */
.hero__services a {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: 0.53em 0.8em;   /* em: chip padding tracks the chip's own size */
    border: 1px solid rgba(255, 255, 255, 0.34);
    border-radius: var(--radius-pill);
    background: rgba(255, 255, 255, 0.07);
    color: var(--on-ink);
    font-size: var(--text-sm);
    font-weight: 600;
    text-decoration: none;
    transition: background var(--dur) var(--ease-out),
                border-color var(--dur) var(--ease-out),
                color var(--dur) var(--ease-out),
                scale var(--dur-press) var(--ease-out);
}

.hero__services a svg {
    flex: none;
    opacity: 0.7;
    transition: translate var(--dur) var(--ease-out),
                opacity var(--dur) var(--ease-out);
}

.hero__services a:active {
    scale: 0.97;
}

@media (hover: hover) and (pointer: fine) {
    .hero__services a:hover {
        background: rgba(255, 255, 255, 0.18);
        border-color: rgba(255, 255, 255, 0.7);
        color: var(--ink-on-dark);
    }

    .hero__services a:hover svg {
        opacity: 1;
        translate: 2px 0;
    }
}

/* On the desktop layout (>=981px, this design's nav breakpoint) the six chips
   fit one row, so let them grow to fill it. Equal shares (`flex: 1 1 0`) look
   tidier but hand every chip the same width, narrower than "Track alignment"
   needs, so the label wraps. `1 0 auto` grows from each label's own width and
   never shrinks below it.

   This block must stay below `.hero__services a`: a media query adds no
   specificity, so from above it the `display` here loses to `inline-flex`. */
@media (min-width: 981px) {
    .hero__services li {
        flex: 1 0 auto;
    }

    .hero__services a {
        display: flex;
        justify-content: center;
    }
}

@media (max-width: 720px) {
    .hero {
        min-height: 0;
        padding-block: var(--space-7);
    }

    /* Photo detail is unreadable at this width; bias the scrim to solid so the
       type stays the subject. */
    .hero::after {
        background: linear-gradient(
            180deg,
            rgb(var(--scrim-rgb) / 0.90) 0%,
            rgb(var(--scrim-rgb) / 0.86) 60%,
            rgb(var(--scrim-rgb) / 0.94) 100%
        );
    }

    .hero__paths {
        flex-direction: column;
        align-items: stretch;
    }

    .hero__services {
        margin-top: var(--space-6);
    }
}

/* --------------------------------------------------------------------------
   Brand strip. One weight for every name: these are wordmarks we do not own,
   so they read as a list, not as forged logos.
   -------------------------------------------------------------------------- */
.brand-strip {
    padding-block: var(--space-6);
    background: var(--surface-raised);
    border-bottom: 1px solid var(--border);
}

.brand-strip p {
    margin-bottom: var(--space-4);
    font-family: var(--font-display);
    font-size: var(--text-sm);
    font-weight: 700;
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    color: var(--ink-muted);
    text-align: center;
}

.brand-strip ul {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--space-4) var(--space-8);
    list-style: none;
}

.brand-strip li {
    font-family: var(--font-display);
    font-size: var(--text-lg);
    font-weight: 700;
    letter-spacing: 0.01em;
    color: var(--ink-muted);
}

/* --------------------------------------------------------------------------
   Gallery preview
   -------------------------------------------------------------------------- */
.gallery-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(20rem, 100%), 1fr));
    gap: var(--space-4);
    margin-bottom: var(--space-6);
    list-style: none;
}

.gallery-grid button {
    display: block;
    width: 100%;
    padding: 0;
    background: none;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    overflow: hidden;
    cursor: pointer;
}

.gallery-grid img {
    width: 100%;
    aspect-ratio: 4 / 3;
    object-fit: cover;
    transition: scale var(--dur) var(--ease-out);
}

/* Touch devices fire :hover on tap, so a decorative hover must be gated. */
@media (hover: hover) and (pointer: fine) {
    .gallery-grid button:hover img {
        scale: 1.04;
    }
}

/* --------------------------------------------------------------------------
   Conversion bands.

   `.cta-band` sits directly after the reviews: proof, then the ask. It is the
   loudest thing between the hero and the form, on purpose.
   `.cta-inline` follows the gallery and is deliberately quiet. Two identical
   full-width CTAs in a row read as a template rather than an offer.
   -------------------------------------------------------------------------- */
/* Never `flex-wrap: wrap` here. Two side-by-side buttons are ~514px wide, so
   the pair only fits beside the headline past a 1080px viewport. Everything
   below that wrapped the actions onto their own line, where `space-between`
   has a single item to distribute and leaves the card's right half empty.
   The actions stack instead: one button wide, so the row always holds. */
.cta-band {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-5);
    margin-top: var(--space-7);
    padding: var(--space-6);
    background: var(--surface-raised);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow);
}

.cta-band__text {
    flex: 1 1 auto;
    min-width: 0;
    max-width: 46ch;
    margin: 0;
    font-family: var(--font-display);
    font-size: var(--text-lg);
    font-weight: 700;
    line-height: var(--leading-snug);
    color: var(--ink);
    text-wrap: balance;
}

/* Stacked and stretched: both buttons take the width of the wider one, so the
   pair reads as a single right-hand block rather than two ragged pills. */
.cta-band__actions {
    display: flex;
    flex: none;
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-3);
}

/* Inline padding is bought at the cost of the headline's column. */
.cta-band__actions .btn--emergency {
    padding-inline: 1.15em;
}

/* Between the phone and a roomy desktop the two columns compete. At 21px the
   button block is wider than the headline it is meant to answer, so the
   headline runs six ragged lines. Give the type back to the words. */
@media (max-width: 860px) {
    .cta-band__actions .btn--emergency {
        font-size: var(--text-base);
    }
}

.cta-inline {
    margin-top: var(--space-6);
    font-size: var(--text-lg);
    color: var(--ink-muted);
    text-align: center;
}

.cta-inline a {
    font-family: var(--font-display);
    font-weight: 700;
    color: var(--blue-text);
    text-underline-offset: 3px;
}

@media (max-width: 640px) {
    .cta-band {
        flex-direction: column;
        align-items: stretch;
        text-align: center;
    }


    /* `flex: 1 1 22rem` above sizes the text along the row axis. Once the
       direction flips, that basis becomes a 352px *height* and grow stretches
       it further, opening a void between the headline and the buttons.
       Column state sizes to content. */
    .cta-band__text {
        flex: 0 1 auto;
        margin-inline: auto;
    }

    .cta-band__actions .btn {
        width: 100%;
    }
}

/* 2rem of inline padding is a fifth of a 320px screen, and it is taken from
   the one line that must not wrap: the phone number. */
@media (max-width: 480px) {
    .cta-band {
        padding: var(--space-5) var(--space-4);
    }
}

/* --------------------------------------------------------------------------
   Proof panel. Client-owned photography only.
   -------------------------------------------------------------------------- */
.proof-photo {
    position: relative;
    border-radius: var(--radius-lg);
    overflow: hidden;
}

.proof-photo img {
    width: 100%;
    aspect-ratio: 4 / 3;
    object-fit: cover;
}

.proof-photo figcaption {
    padding: var(--space-5);
    background: var(--surface-ink);
    color: var(--on-ink-soft);
}

.proof-photo figcaption strong {
    display: block;
    margin-bottom: var(--space-2);
    font-family: var(--font-display);
    font-size: var(--text-lg);
    color: var(--ink-on-dark);
}

/* --------------------------------------------------------------------------
   Service list
   -------------------------------------------------------------------------- */
.service-list {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(28rem, 100%), 1fr));
    gap: var(--space-3);
    list-style: none;
}

.service-list a {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    height: 100%;
    padding: 0.94em 1.41em;
    background: var(--surface-raised);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    font-family: var(--font-display);
    font-weight: 600;
    color: var(--ink);
    text-decoration: none;
    transition: border-color var(--dur) var(--ease-out),
                background var(--dur) var(--ease-out);
}

.service-list a:hover {
    background: var(--blue-wash);
    border-color: var(--blue-fill);
    color: var(--blue-text);
}

.service-list svg {
    flex: none;
    color: var(--blue-text);
    transition: translate var(--dur) var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
    .service-list a:hover svg {
        translate: 3px 0;
    }
}

/* --------------------------------------------------------------------------
   Quote / contact
   -------------------------------------------------------------------------- */
.contact-methods {
    display: grid;
    gap: var(--space-3);
    list-style: none;
}

/* The contact band used to be --surface-ink, the exact colour of the footer
   directly beneath it, so the final call to action dissolved into the footer.
   It is a light band now: the dark footer terminates the page, and the orange
   CTA has somewhere to stand out against. */
.contact-section {
    background: var(--surface-raised);
    border-top: 1px solid var(--border);
}

.contact-section h2 {
    color: var(--ink);
}

.contact-section .split {
    row-gap:0.5em;
}

.contact-lead {
    color: var(--ink-body);
}

.contact-method {
    display: flex;
    align-items: center;
    gap: var(--space-4);
    padding: var(--space-4);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    color: var(--ink-body);
    font-style: normal;   /* <address> defaults to italic */
    text-decoration: none;
    transition: border-color var(--dur) var(--ease-out),
                background var(--dur) var(--ease-out),
                scale var(--dur-press) var(--ease-out);
}

a.contact-method:active {
    scale: 0.99;
}

@media (hover: hover) and (pointer: fine) {
    a.contact-method:hover {
        background: var(--blue-wash);
        border-color: var(--blue-fill);
        color: var(--ink);
    }
}

.contact-method svg {
    flex: none;
    color: var(--blue-text);
}

.contact-method__label {
    display: block;
    font-family: var(--font-display);
    font-size: var(--text-sm);
    font-weight: 700;
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    color: var(--ink-muted);
}

.contact-method__value {
    display: block;
    font-size: var(--text-lg);
    color: var(--ink);
}

/* --------------------------------------------------------------------------
   Proof band. Trust signals only, every one of them already stated elsewhere
   in the site's copy. Icons are inline SVG (never emoji), one stroke language.
   min(220px, 100%) keeps auto-fit from demanding a track wider than a narrow
   phone column and forcing a horizontal scrollbar.
   -------------------------------------------------------------------------- */
.trust-band {
    padding-block: var(--space-5);
    background: var(--surface-raised);
    border-bottom: 1px solid var(--border);
}

.trust-band ul {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(22rem, 100%), 1fr));
    gap: var(--space-4) var(--space-6);
    list-style: none;
}

.trust-band li {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    font-family: var(--font-display);
    font-size: var(--text-sm);
    font-weight: 600;
    color: var(--ink-body);
}

.trust-band li strong {
    font-weight: 700;
    color: var(--ink);
}

.trust-band__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: none;
    width: 4rem;
    height: 4rem;
    border-radius: var(--radius);
    background: var(--blue-wash);
    color: var(--blue-text);
}

.trust-band__icon svg {
    width: 2.2rem;
    height: 2.2rem;
}

/* --------------------------------------------------------------------------
   FAQ. Native <details>, so answers are readable with JS disabled and the
   disclosure is keyboard-operable for free. The chevron is a CSS-drawn caret,
   not an icon-font glyph; its rotation is neutralised under reduced-motion by
   the global rule in base.css.
   -------------------------------------------------------------------------- */
.faq {
    display: grid;
    gap: var(--space-3);
}

.faq__item {
    background: var(--surface-raised);
    border: 1px solid var(--border);
    border-radius: var(--radius);
}

.faq__item summary {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-4);
    padding: var(--space-4) var(--space-5);
    font-family: var(--font-display);
    font-size: var(--text-base);
    font-weight: 700;
    color: var(--ink);
    cursor: pointer;
    list-style: none;
    transition: background var(--dur) var(--ease-out),
                color var(--dur) var(--ease-out);
}

.faq__item summary::-webkit-details-marker {
    display: none;
}

.faq__item summary:hover {
    color: var(--blue-text);
}

/* Caret drawn from two borders. Rotates from pointing-down to pointing-up. */
.faq__item summary::after {
    content: "";
    flex: none;
    transition: transform var(--dur) var(--ease-out),
                margin-top var(--dur) var(--ease-out);
    width: 1rem;
    height: 1rem;
    margin-top: -0.4rem;
    border-right: 2px solid var(--blue-text);
    border-bottom: 2px solid var(--blue-text);
    transform: rotate(45deg);
    transition: transform var(--dur) var(--ease-out);
}

.faq__item[open] summary::after {
    margin-top: 0.3rem;
    transform: rotate(-135deg);
}

.faq__answer {
    padding: 0 var(--space-5) var(--space-5);
    color: var(--ink-body);
}

/* --------------------------------------------------------------------------
   Contact + footer text blocks. These carried inline styles; spacing belongs
   in the stylesheet so the rhythm stays on the scale.
   -------------------------------------------------------------------------- */
.contact-lead {
    margin-top: var(--space-4);
}

.contact-cta {
    margin-top: var(--space-6);
}

.footer-address {
    margin-top: var(--space-4);
}

.footer-address strong {
    color: var(--ink-on-dark);
}

/* The FAQ and the form are peers in one split. Neither header centres, or the
   two columns would read as two unrelated sections that happen to be adjacent. */
.quote-col .form-card {
    margin-top: 0;
}

@media (min-width: 900px) {
    #quote .section-header {
        margin-bottom: var(--space-6);
    }
}

/* --------------------------------------------------------------------------
   Door anatomy figure.

   This is a drawing, and it is styled as one. The gallery is where this shop's
   real work lives; nothing here should be mistakable for a photograph of it.
   -------------------------------------------------------------------------- */
.anatomy {
    margin: 0;
    border-radius: var(--radius-lg);
    overflow: hidden;
    background: var(--surface-ink);
    border: 1px solid var(--ink-border);
}

/* No crop. The opener rail runs to the right edge of the drawing, and `cover`
   was cutting it off. The intrinsic ratio is already 4:3. */
.anatomy img {
    display: block;
    width: 100%;
    height: auto;
}

.anatomy figcaption {
    padding: var(--space-4) var(--space-5);
    border-top: 1px solid var(--ink-border);
    font-size: var(--text-sm);
    color: var(--on-ink-muted);
    transition: color var(--dur) var(--ease-out);
}

/* Brighten the caption while a service is hovered (the spotlight is lit). */
.anatomy[data-part] figcaption {
    color: var(--on-ink);
}

/* Beside a figure the list runs in one column, so a row is a full-width target
   rather than a cramped two-up grid. */
.service-list--stacked {
    grid-template-columns: 1fr;
}

/* --------------------------------------------------------------------------
   Anatomy spotlight.

   Hovering (or focusing) a service row dims the drawing and lights the part
   that service touches. One image, one mask: eight generated variants would
   each redraw the scene slightly differently and jitter on swap.

   Every coordinate below was measured from the image's own pixels.
   -------------------------------------------------------------------------- */

/* Registered so the spotlight glides between parts instead of teleporting.
   Where @property is unsupported it simply snaps, which is still correct. */
@property --cx { syntax: "<percentage>"; inherits: true; initial-value: 50%; }
@property --cy { syntax: "<percentage>"; inherits: true; initial-value: 50%; }
@property --rx { syntax: "<percentage>"; inherits: true; initial-value: 20%; }
@property --ry { syntax: "<percentage>"; inherits: true; initial-value: 20%; }

.anatomy__stage {
    position: relative;
    --cx: 50%;
    --cy: 50%;
    --rx: 0%;    /* no hole: the dim is uniform until a part is picked */
    --ry: 0%;
    transition: --cx var(--dur-slow) var(--ease-out),
                --cy var(--dur-slow) var(--ease-out),
                --rx var(--dur-slow) var(--ease-out),
                --ry var(--dur-slow) var(--ease-out);
}

.anatomy__dim,
.anatomy__ring {
    position: absolute;
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--dur) var(--ease-out);
}

.anatomy__dim {
    inset: 0;
    background: rgb(var(--scrim-rgb) / 0.6);
    -webkit-mask-image: radial-gradient(ellipse var(--rx) var(--ry) at var(--cx) var(--cy),
                        transparent 70%, black 100%);
    mask-image: radial-gradient(ellipse var(--rx) var(--ry) at var(--cx) var(--cy),
                transparent 70%, black 100%);
}

.anatomy__ring {
    left: var(--cx);
    top: var(--cy);
    width: calc(var(--rx) * 1.6);
    height: calc(var(--ry) * 1.6);
    translate: -50% -50%;
    border: 1.5px solid var(--blue-on-scrim);
    border-radius: 50%;
}

/* `data-dim` is set while the pointer is anywhere over the service list, so
   crossing the gap between two rows never flashes the drawing back to full
   brightness. `data-part` only moves the spotlight. */
.anatomy[data-dim] .anatomy__dim { opacity: 1; }
.anatomy[data-part] .anatomy__ring { opacity: 0.75; }

/* Measured bounding boxes, converted to centre + radius. */
/* spring assembly measured at centre (31.5, 25.5), rx 15.5 ry 10.4; widened
   slightly so the oval clears both cable drums. */
.anatomy[data-part="spring"] .anatomy__stage { --cx: 31.5%; --cy: 25%;   --rx: 18%; --ry: 10.5%; }
.anatomy[data-part="cable"]  .anatomy__stage { --cx: 31.5%; --cy: 40%;   --rx: 19%; --ry: 22%; }
.anatomy[data-part="track"]  .anatomy__stage { --cx: 18.8%; --cy: 55%;   --rx: 9%;  --ry: 32%; }

/* the motor head and its ceiling brackets, not the whole rail */
.anatomy[data-part="opener"] .anatomy__stage { --cx: 79%;   --cy: 21%;   --rx: 12%; --ry: 13%; }

/* door + both tracks: measured bbox centre (32.8, 59.4), rx 17.2 ry 29.4 */
.anatomy[data-part="panels"] .anatomy__stage { --cx: 32.8%; --cy: 59.4%; --rx: 19%; --ry: 32%; }

.anatomy[data-part="sensor"] .anatomy__stage { --cx: 51.9%; --cy: 72%;   --rx: 8%;  --ry: 10%; }

/* No keypad is drawn. This marks the wall beside the opening where one mounts,
   and the caption says so rather than implying a part that is not there. */
.anatomy[data-part="keypad"] .anatomy__stage { --cx: 14%;   --cy: 36%;   --rx: 6%;  --ry: 8%; }

/* The rows that drive it get a matching resting cue. */
.service-list a[data-part]:hover,
.service-list a[data-part]:focus-visible {
    border-color: var(--blue-fill);
}

@media (prefers-reduced-motion: reduce) {
    .anatomy__stage { transition: none; }
}

/* --------------------------------------------------------------------------
   320px. The narrowest phone still in the wild.
   -------------------------------------------------------------------------- */
.nowrap {
    white-space: nowrap;
}

@media (max-width: 480px) {
    /* Three lines of eyebrow above the headline is not a badge, it is a
       paragraph wearing a pill. */
    .hero__eyebrow {
        align-items: flex-start;
        padding: var(--space-2) var(--space-3);
        font-size: var(--text-xs);
        line-height: 1.35;
    }

    .hero__eyebrow svg {
        margin-top: 0.15em;
    }

    .cta-inline a {
        display: inline-flex;
        align-items: center;
        padding-inline: var(--space-2);
    }
}

@media (max-width: 720px) {
    .footer-grid ul a,
    .footer-areas a {
        display: inline-flex;
        padding-block: var(--space-2);
    }
}
