/* ============================================================
   KM Digital Solutions - Component styles (2026-07 retheme)
   Consumes the semantic tokens defined in style.css. Section
   order mirrors the homepage.
   ============================================================ */

/* Legacy variable bridge: old token names still referenced by
   not-yet-rebuilt templates resolve to on-brand values instead of
   breaking. Remove once every template is confirmed migrated. */
:root {
    --primary: var(--brand-granite);
    --primary-light: var(--brand-granite);
    --secondary: var(--color-accent-ink);
    --accent: var(--brand-terracotta);
    --bg: var(--color-canvas);
    --bg-card: var(--color-surface);
    --bg-subtle: var(--color-surface-soft);
    --text: var(--color-ink);
    --text-muted: var(--color-ink-soft);
    --border: var(--color-border);
    --font-heading: var(--font-sans);
    --font-body: var(--font-sans);
}

[hidden] {
    display: none !important;
}

/* ============================================================
   Hero
   ============================================================ */
.hero {
    padding-block: clamp(2.5rem, 6vw, 4.5rem) clamp(2.5rem, 5vw, 4rem);
}

.hero__layout {
    display: grid;
    grid-template-columns: 1.1fr 0.9fr;
    gap: clamp(2rem, 5vw, 4rem);
    align-items: center;
}

.hero__title {
    font-size: clamp(2.4rem, 5vw, 3.6rem);
    margin-top: 1.1rem;
}

.hero__title-accent {
    color: var(--color-accent); /* display-size text: 3.2:1 passes large-text AA */
}

.hero__description {
    margin-top: 1.25rem;
    font-size: clamp(1.05rem, 1.6vw, 1.1875rem);
    line-height: 1.6;
    color: var(--color-ink-soft);
    max-width: 34em;
}

.hero__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin-top: 1.75rem;
}

.hero__trustline {
    margin-top: 1.5rem;
    font-size: 0.8125rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--color-ink-soft);
}

.hero__visual {
    display: block;
}

.hero__panel {
    background: var(--color-panel);
    border-radius: var(--radius-lg);
    padding: clamp(1.5rem, 3vw, 2rem);
    box-shadow: var(--shadow-md);
}

.hero__panel-title {
    font-size: 0.75rem;
    font-weight: 500;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--brand-cream);
    opacity: 0.7;
}

.hero__ledger {
    list-style: none;
    margin-top: 1rem;
}

.hero__ledger li {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    padding-block: 0.7rem;
    border-bottom: 1px solid rgba(242, 237, 225, 0.14);
}

.hero__ledger li:last-child {
    border-bottom: 0;
}

.hero__ledger-label {
    color: var(--brand-cream);
    font-size: 0.9375rem;
    font-weight: 500;
}

.hero__ledger-value {
    color: var(--brand-cream);
    opacity: 0.75;
    font-size: 0.8125rem;
    text-align: right;
}

.hero__panel-note {
    margin-top: 1rem;
    font-size: 0.8125rem;
    line-height: 1.5;
    color: var(--brand-cream);
    opacity: 0.8;
}

@media (max-width: 991px) {
    .hero__layout {
        grid-template-columns: 1fr;
    }

    .hero__visual {
        display: none;
    }
}

/* ============================================================
   Trust / Founders
   ============================================================ */
.founders {
    list-style: none;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem;
    max-width: 52rem;
}

.founder-chip {
    width: 100%;
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 1rem 1.15rem;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    cursor: pointer;
    text-align: left;
    font-family: var(--font-sans);
    transition: border-color 0.2s var(--ease), box-shadow 0.2s var(--ease);
}

.founder-chip:hover {
    border-color: var(--color-border-strong);
    box-shadow: var(--shadow-md);
}

.founder-chip__avatar {
    flex: 0 0 3.25rem;
    width: 3.25rem;
    height: 3.25rem;
    border-radius: 50%;
    overflow: hidden;
}

.founder-chip__avatar svg,
.founder-chip__avatar img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.founder-chip__meta {
    display: grid;
    gap: 0.15rem;
    min-width: 0;
}

.founder-chip__name {
    font-weight: 600;
    font-size: 1rem;
    color: var(--color-ink);
}

.founder-chip__role {
    font-size: 0.8125rem;
    color: var(--color-ink-soft);
}

.founder-chip__cue {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-family: var(--font-mono);
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--color-accent-ink);
    white-space: nowrap;
}

.trust__points {
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem;
    margin-top: 1.75rem;
}

.trust__point {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.45rem 0.9rem;
    font-size: 0.875rem;
    color: var(--color-ink);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-pill);
}

.trust__point svg {
    color: var(--color-accent);
    flex: 0 0 auto;
}

@media (max-width: 640px) {
    .founders {
        grid-template-columns: 1fr;
    }

    .founder-chip__cue {
        display: none;
    }
}

/* Founder modal */
.founder-modal {
    position: fixed;
    inset: 0;
    z-index: 200;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
}

.founder-modal__backdrop {
    position: absolute;
    inset: 0;
    background: rgba(47, 62, 81, 0.5);
}

.founder-modal__panel {
    position: relative;
    width: min(28rem, 100%);
    max-height: calc(100dvh - 2rem);
    overflow-y: auto;
    background: var(--color-surface);
    border-radius: var(--radius-lg);
    border: 1px solid var(--color-border);
    box-shadow: var(--shadow-md);
    padding: clamp(1.5rem, 4vw, 2rem);
}

.founder-modal__close {
    position: absolute;
    top: 0.9rem;
    right: 0.9rem;
    width: 2.5rem;
    height: 2.5rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    color: var(--color-ink);
    cursor: pointer;
}

.founder-modal__close:hover {
    border-color: var(--color-border-strong);
}

.founder-modal__head {
    display: flex;
    align-items: center;
    gap: 1rem;
}

.founder-modal__avatar {
    flex: 0 0 4rem;
    width: 4rem;
    height: 4rem;
    border-radius: 50%;
    overflow: hidden;
}

.founder-modal__name {
    font-size: 1.25rem;
}

.founder-modal__role {
    font-size: 0.875rem;
    color: var(--color-ink-soft);
}

.founder-modal__desc {
    margin-top: 1rem;
    color: var(--color-ink-soft);
    line-height: 1.6;
}

.founder-modal__contacts {
    display: grid;
    gap: 0.5rem;
    margin-top: 1.25rem;
}

.founder-modal__contact {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    padding: 0.7rem 0.9rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    text-decoration: none;
    color: var(--color-ink);
    font-size: 0.9375rem;
    transition: border-color 0.2s var(--ease), background-color 0.2s var(--ease);
}

.founder-modal__contact:hover {
    background: var(--color-surface-soft);
    border-color: var(--color-border-strong);
    color: var(--color-ink);
}

.founder-modal__contact svg {
    color: var(--color-accent-ink);
    flex: 0 0 auto;
}

/* ============================================================
   Entry Paths
   ============================================================ */
.path-card {
    display: grid;
    gap: 0.7rem;
    align-content: start;
}

.path-card__kicker {
    font-size: 0.75rem;
    font-weight: 500;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--color-accent-ink);
}

.path-card__link,
.service-tile__link,
.case-card__link {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    margin-top: 0.4rem;
    font-size: 0.9375rem;
    font-weight: 500;
    color: var(--color-accent-ink);
    text-decoration: none;
}

.path-card__link:hover,
.service-tile__link:hover,
.case-card__link:hover {
    color: var(--color-accent-ink);
    text-decoration: underline;
    text-decoration-color: var(--color-accent);
    text-underline-offset: 0.25em;
}

/* ============================================================
   Journey
   ------------------------------------------------------------
   The four-up card grid that used to live here belonged to an
   earlier journey markup (.journey__num / .journey__question /
   .journey__cta) that no template renders any more. P3 removed
   it: every journey rule now lives in ONE place, the
   ".journey--project" system further down this file. Keeping a
   second, weaker .journey__stages ruleset here only made the
   cascade harder to read.
   ============================================================ */

/* ============================================================
   Case Studies
   ============================================================ */
.case-studies__leads {
    align-items: stretch;
}

.case-card {
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.case-card__shot {
    display: block;
    border-bottom: 1px solid var(--color-border);
}

.case-card__shot img {
    width: 100%;
    aspect-ratio: 16 / 10;
    object-fit: cover;
    object-position: top;
}

.case-card__body {
    padding: clamp(1.25rem, 3vw, 1.75rem);
    display: grid;
    gap: 0.7rem;
    align-content: start;
}

.case-card__kicker {
    font-size: 0.75rem;
    font-weight: 500;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--color-ink-soft);
}

.case-card__stats {
    display: flex;
    gap: 2rem;
    margin-top: 0.5rem;
}

.case-card__stat {
    display: grid;
    gap: 0.2rem;
}

.stat-figure {
    font-size: clamp(1.75rem, 3vw, 2.25rem);
    font-weight: 600;
    color: var(--color-accent); /* large numerals: non-text/large AA */
    line-height: 1.1;
}

.case-card__stat-label {
    font-size: 0.8125rem;
    color: var(--color-ink-soft);
}

.recent-builds {
    margin-top: clamp(2rem, 4vw, 3rem);
}

.recent-builds__row {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 1rem;
}

.recent-builds__item {
    display: block;
    overflow: hidden;
    text-decoration: none;
}

.recent-builds__item img {
    width: 100%;
    aspect-ratio: 16 / 10;
    object-fit: cover;
    object-position: top;
    border-bottom: 1px solid var(--color-border);
}

.recent-builds__meta {
    display: grid;
    gap: 0.1rem;
    padding: 0.8rem 1rem;
}

.recent-builds__client {
    font-weight: 600;
    font-size: 0.9375rem;
    color: var(--color-ink);
}

@media (max-width: 900px) {
    .recent-builds__row {
        grid-template-columns: 1fr;
        gap: 0.6rem;
    }

    /* Compact horizontal rows on mobile: thumbnail left, meta right. */
    .recent-builds__item {
        display: flex;
        align-items: stretch;
    }

    .recent-builds__item img {
        width: 38%;
        min-width: 7rem;
        aspect-ratio: 4 / 3;
        border-bottom: 0;
        border-right: 1px solid var(--color-border);
    }

    .recent-builds__meta {
        align-content: center;
        padding: 0.7rem 0.9rem;
    }
}

/* ============================================================
   Flagship (five-day websites)
   ============================================================ */
.flagship__inner {
    display: grid;
    grid-template-columns: 1.5fr 1fr;
    overflow: hidden;
}

.flagship__main {
    padding: clamp(1.5rem, 4vw, 2.5rem);
    display: grid;
    gap: 1rem;
    align-content: start;
    justify-items: start;
}

.flagship__conditions {
    padding: clamp(1.5rem, 4vw, 2.5rem);
    background: var(--color-surface-soft);
    border-left: 1px solid var(--color-border);
    display: grid;
    gap: 1rem;
    align-content: start;
}

.flagship__terms {
    list-style: none;
    display: grid;
    gap: 0.75rem;
    color: var(--color-ink-soft);
}

.flagship__terms li {
    padding-left: 1.1rem;
    position: relative;
}

.flagship__terms li::before {
    content: '';
    position: absolute;
    left: 0;
    top: 0.5em;
    width: 0.45rem;
    height: 2px;
    background: var(--color-accent);
}

.flagship__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin-top: 0.25rem;
}

.check-list {
    list-style: none;
    display: grid;
    gap: 0.6rem;
}

.check-list li {
    display: flex;
    align-items: flex-start;
    gap: 0.55rem;
    font-size: 0.9375rem;
    color: var(--color-ink);
}

.check-list svg {
    color: var(--color-accent);
    flex: 0 0 auto;
    margin-top: 0.15rem;
}

.check-list--two-col {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.6rem 1.25rem;
}

@media (max-width: 900px) {
    .flagship__inner {
        grid-template-columns: 1fr;
    }

    .flagship__conditions {
        border-left: 0;
        border-top: 1px solid var(--color-border);
    }

    .check-list--two-col {
        grid-template-columns: 1fr;
    }
}

/* ============================================================
   Services
   ============================================================ */
.services__group-label {
    font-size: 0.75rem;
    font-weight: 500;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--color-ink-soft);
    margin-bottom: 1rem;
}

.services__grid {
    margin-bottom: clamp(1.75rem, 4vw, 2.5rem);
}

.services__grid--systems {
    max-width: 52rem;
}

.service-tile {
    display: grid;
    gap: 0.6rem;
    align-content: start;
}

.service-tile__icon {
    width: 2.75rem;
    height: 2.75rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-md);
    background: var(--color-accent-soft);
    color: var(--color-accent-ink);
}

@media (max-width: 640px) {
    /* Phones: the homepage services grid collapses to a scannable
       list (icon + name + link). Outcomes live on the service pages
       and the services index. */
    .services .service-tile.card--pad {
        display: grid;
        grid-template-columns: auto 1fr;
        align-items: center;
        column-gap: 0.8rem;
        row-gap: 0.1rem;
        padding: 0.8rem 1rem;
    }

    .services .service-tile__icon {
        width: 2.25rem;
        height: 2.25rem;
        grid-row: span 2;
    }

    .services .service-tile h4 {
        font-size: 1rem;
    }

    .services .service-tile p {
        display: none;
    }

    .services .service-tile__link {
        margin-top: 0;
        font-size: 0.875rem;
    }

    .services__grid {
        gap: 0.5rem;
        margin-bottom: 1.5rem;
    }
}

/* ============================================================
   Systems (granite panel)
   ============================================================ */
.eyebrow--inverse {
    color: var(--brand-cream);
    opacity: 0.85;
}

.eyebrow--inverse::before {
    background: var(--brand-cream);
}

.section--panel .section-header p {
    color: var(--brand-cream);
    opacity: 0.85;
}

.systems__builds {
    margin-top: 0.5rem;
}

.systems__build {
    background: var(--color-panel-raise);
    border: 1px solid rgba(242, 237, 225, 0.14);
    border-radius: var(--radius-lg);
    padding: clamp(1.25rem, 3vw, 1.75rem);
    display: grid;
    gap: 0.8rem;
    align-content: start;
}

.systems__build p {
    font-size: 0.9575rem;
    line-height: 1.6;
    opacity: 0.92;
}

.systems__build-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
}

.systems__chip {
    background: rgba(242, 237, 225, 0.12);
    border-color: rgba(242, 237, 225, 0.3);
    color: var(--brand-cream);
}

.systems__build-note {
    font-size: 0.875rem;
    opacity: 0.75;
}

.systems__cta {
    margin-top: clamp(1.75rem, 4vw, 2.5rem);
    display: grid;
    gap: 1.1rem;
    justify-items: start;
    max-width: 46em;
}

.systems__cta-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
}

.btn--outline-inverse {
    border-color: rgba(242, 237, 225, 0.55);
    color: var(--brand-cream);
}

.btn--outline-inverse:hover {
    background: var(--brand-cream);
    border-color: var(--brand-cream);
    color: var(--brand-granite);
}

/* ============================================================
   Estimator (pricing calculator)
   ============================================================ */
.pricing-calc {
    padding-block: var(--section-pad);
}

.pricing-calc__form {
    padding: clamp(1.25rem, 3vw, 2rem);
    display: grid;
    gap: 1.5rem;
}

/* Grid items may never force the form wider than its container. */
.pricing-calc__form > * {
    min-width: 0;
}

.calc-goals__label {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    font-weight: 600;
    margin-bottom: 1rem;
}

.calc-goals__step {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.6rem;
    height: 1.6rem;
    border-radius: 50%;
    background: var(--brand-granite);
    color: var(--brand-cream);
    font-family: var(--font-mono);
    font-size: 0.8125rem;
}

.calc-goals__options {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 0.75rem;
}

.calc-goal {
    display: grid;
    gap: 0.3rem;
    justify-items: start;
    text-align: left;
    padding: 1rem;
    background: var(--color-surface);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-md);
    cursor: pointer;
    font-family: var(--font-sans);
    transition: border-color 0.2s var(--ease), background-color 0.2s var(--ease);
}

.calc-goal:hover {
    border-color: var(--brand-granite);
}

.calc-goal[aria-pressed='true'] {
    border-color: var(--brand-granite);
    background: var(--color-surface-soft);
    box-shadow: inset 0 0 0 1px var(--brand-granite);
}

.calc-goal__icon {
    color: var(--color-accent-ink);
}

.calc-goal[aria-pressed='true'] .calc-goal__icon {
    color: var(--color-accent);
}

.calc-goal__label {
    font-weight: 600;
    font-size: 0.9375rem;
    color: var(--color-ink);
}

.calc-goal__sub {
    font-size: 0.8125rem;
    color: var(--color-ink-soft);
}

.calc-services__hint {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    font-weight: 600;
    margin-bottom: 0.75rem;
}

.calc-services__hint > span {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.35rem 0.6rem;
    min-width: 0;
}

.calc-services__all {
    background: none;
    border: 0;
    font-family: var(--font-sans);
    font-size: 0.875rem;
    color: var(--color-accent-ink);
    text-decoration: underline;
    text-underline-offset: 0.2em;
    cursor: pointer;
}

.calc-group {
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-surface);
    margin-bottom: 0.6rem;
}

.calc-group[open] {
    border-color: var(--color-border-strong);
}

.calc-group__summary {
    list-style: none;
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.9rem 1.1rem;
    cursor: pointer;
}

.calc-group__summary::-webkit-details-marker {
    display: none;
}

.calc-group__name {
    font-weight: 500;
    font-size: 0.9575rem;
    display: flex;
    align-items: center;
    gap: 0.6rem;
    flex-wrap: wrap;
}

.pricing-calc__billing {
    font-family: var(--font-mono);
    font-size: 0.6875rem;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--color-ink-soft);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-pill);
    padding: 0.1rem 0.5rem;
}

.calc-group__state {
    margin-left: auto;
    font-family: var(--font-mono);
    font-size: 0.75rem;
    color: var(--color-ink-soft);
    text-align: right;
}

.calc-group__state[data-selected='true'] {
    color: var(--color-accent-ink);
    font-weight: 600;
}

.calc-group__chevron {
    color: var(--color-ink-soft);
    transition: transform 0.2s var(--ease);
}

.calc-group[open] .calc-group__chevron {
    transform: rotate(180deg);
}

.calc-group__body {
    padding: 0 1.1rem 1.1rem;
    display: grid;
    gap: 0.75rem;
}

.pricing-calc__info {
    justify-self: start;
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    background: none;
    border: 0;
    cursor: pointer;
    font-family: var(--font-sans);
    font-size: 0.8125rem;
    color: var(--color-accent-ink);
}

.pricing-calc__info-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.1rem;
    height: 1.1rem;
    border-radius: 50%;
    border: 1px solid currentColor;
    font-family: var(--font-mono);
    font-size: 0.6875rem;
}

.pricing-calc__info-label {
    text-decoration: underline;
    text-underline-offset: 0.2em;
}

.pricing-calc__options {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(11.5rem, 1fr));
    gap: 0.5rem;
}

.pricing-calc__radio input {
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
}

.pricing-calc__radio-box {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    padding: 0.65rem 0.85rem;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-sm);
    font-size: 0.875rem;
    color: var(--color-ink);
    cursor: pointer;
    transition: background-color 0.15s var(--ease), border-color 0.15s var(--ease), color 0.15s var(--ease);
}

.pricing-calc__radio input:checked + .pricing-calc__radio-box {
    background: var(--brand-granite);
    border-color: var(--brand-granite);
    color: var(--brand-cream);
}

.pricing-calc__radio input:focus-visible + .pricing-calc__radio-box {
    outline: 2px solid var(--color-focus);
    outline-offset: 2px;
}

.pricing-calc__radio-box strong {
    font-family: var(--font-mono);
    font-weight: 600;
    font-size: 0.9375rem;
}

.pricing-calc__includes {
    font-size: 0.6875rem;
    opacity: 0.85;
}

.pricing-calc__included-note {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.8125rem;
    color: var(--color-accent-ink);
    background: var(--color-accent-soft);
    border-radius: var(--radius-sm);
    padding: 0.5rem 0.75rem;
}

/* Sticky, fully opaque total bar */
.pricing-calc__total-bar {
    position: sticky;
    bottom: 0;
    z-index: 5;
    background: var(--color-surface);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-md);
    padding: 0.9rem 1.1rem calc(0.9rem + env(safe-area-inset-bottom, 0px));
}

.pricing-calc__total-inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
}

.pricing-calc__summary {
    flex: 1 1 100%;
    font-size: 0.8125rem;
    color: var(--color-ink-soft);
}

.pricing-calc__total-nums {
    display: flex;
    align-items: baseline;
    gap: 1.25rem;
    flex-wrap: wrap;
}

.pricing-calc__total-monthly,
.pricing-calc__total-onceoff {
    font-family: var(--font-mono);
    font-weight: 600;
    font-size: 1.05rem;
    color: var(--color-ink);
}

.pricing-calc__total-monthly small,
.pricing-calc__total-onceoff small {
    display: block;
    font-family: var(--font-sans);
    font-weight: 400;
    font-size: 0.75rem;
    color: var(--color-ink-soft);
}

.pricing-calc__zero-note {
    flex: 1 1 100%;
    font-size: 0.875rem;
    color: var(--color-ink-soft);
}

.pricing-calc__bar-actions {
    margin-left: auto;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
}

.pricing-calc__cta-btn[aria-disabled='true'] {
    opacity: 0.55;
    cursor: not-allowed;
}

.form-group__legend {
    display: block;
    font-size: 0.875rem;
    font-weight: 500;
    margin-bottom: 0.5rem;
    color: var(--color-ink);
    padding: 0;
}

.pricing-calc__disclaimer {
    margin-top: 1.25rem;
    font-size: 0.875rem;
    color: var(--color-ink-soft);
    max-width: 52em;
}

@media (max-width: 900px) {
    .calc-goals__options {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (max-width: 560px) {
    /* Keep goals two-up on phones: halves the step-1 height. */
    .calc-goals__options {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 0.5rem;
    }

    .calc-goal {
        padding: 0.75rem;
    }

    .calc-goal__sub {
        display: none;
    }

    .pricing-calc__total-inner {
        align-items: stretch;
        flex-direction: column;
    }

    .pricing-calc__bar-actions {
        margin-left: 0;
        flex-direction: column;
        align-items: stretch;
    }

    .pricing-calc__total-inner .btn {
        width: 100%;
    }

    /* A sticky multi-row total obscures the final calculator options on a
       390px viewport. Keep the summary in normal flow on phones. */
    .pricing-calc__total-bar {
        position: static;
    }
}

/* ============================================================
   Testimonials
   ============================================================ */
.testimonials-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem;
}

.testimonial-card__top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    flex-wrap: wrap;
}

.testimonial-card__stars {
    display: inline-flex;
    gap: 0.15rem;
}

.testimonial-card__stars .star {
    fill: var(--color-border);
}

.testimonial-card__stars .star.is-on {
    fill: var(--color-accent);
}

.testimonial-card__source {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    font-family: var(--font-mono);
    font-size: 0.6875rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--color-ink-soft);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-pill);
    padding: 0.2rem 0.6rem;
    margin-left: auto;
}

.testimonial-card__source--google {
    color: var(--color-accent-ink);
    border-color: var(--color-accent-soft);
    background: var(--color-accent-soft);
}

.testimonial-card__quote {
    margin-top: 0.9rem;
    font-size: 0.9575rem;
    line-height: 1.65;
    color: var(--color-ink);
}

.testimonial-card__author-block {
    margin-top: 1rem;
    display: grid;
    gap: 0.1rem;
}

.testimonial-card__author {
    font-weight: 600;
    font-size: 0.9375rem;
}

.testimonial-card__role {
    font-size: 0.8125rem;
    color: var(--color-ink-soft);
}

.testimonials-cta {
    margin-top: 1.75rem;
}

.testimonials-cta__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
}

@media (max-width: 768px) {
    .testimonials-grid {
        grid-template-columns: 1fr;
    }
}

/* ============================================================
   Process + FAQ
   ============================================================ */
.process-steps {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 1rem;
}

.process-step {
    display: grid;
    gap: 0.5rem;
    align-content: start;
}

.process-step__number {
    font-size: 0.8125rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    color: var(--color-accent-ink);
}

.service-fine-print {
    margin-top: 1.5rem;
    max-width: 52em;
}

@media (max-width: 991px) {
    .process-steps {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (max-width: 560px) {
    .process-steps {
        grid-template-columns: 1fr;
    }
}

.faq {
    margin-top: clamp(2rem, 5vw, 3rem);
    max-width: 46rem;
}

.faq__item {
    border-bottom: 1px solid var(--color-border);
}

.faq__question {
    list-style: none;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding-block: 1rem;
    font-weight: 500;
    cursor: pointer;
    color: var(--color-ink);
}

.faq__question::-webkit-details-marker {
    display: none;
}

.faq__chevron {
    flex: 0 0 auto;
    color: var(--color-ink-soft);
    transition: transform 0.2s var(--ease);
}

.faq__item[open] .faq__chevron {
    transform: rotate(180deg);
}

.faq__answer {
    padding-bottom: 1.1rem;
    color: var(--color-ink-soft);
    line-height: 1.65;
    max-width: 60ch;
}

/* ============================================================
   CTA section (tabs, booking, forms)
   ============================================================ */
.cta-section {
    padding-block: var(--section-pad);
}

.cta-section__inner {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    padding: clamp(1.5rem, 4vw, 2.5rem);
}

.cta-section__inner > p {
    color: var(--color-ink-soft);
    max-width: 44em;
    margin-top: 0.5rem;
}

.cta-tabs {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-top: 1.5rem;
}

.cta-tab {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.65rem 1.1rem;
    font-family: var(--font-sans);
    font-size: 0.9375rem;
    font-weight: 500;
    color: var(--color-ink);
    background: var(--color-surface);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-pill);
    cursor: pointer;
    transition: background-color 0.2s var(--ease), color 0.2s var(--ease), border-color 0.2s var(--ease);
}

.cta-tab:hover {
    border-color: var(--brand-granite);
}

.cta-tab--active {
    background: var(--brand-granite);
    border-color: var(--brand-granite);
    color: var(--brand-cream);
}

.cta-panel {
    display: none;
    margin-top: 1.75rem;
}

.cta-panel--active {
    display: block;
}

.cta-panel__content h3 {
    margin-bottom: 0.4rem;
}

.cta-panel__content > p {
    color: var(--color-ink-soft);
    margin-bottom: 1.25rem;
}

/* Booking widget */
.booking-widget {
    display: grid;
    gap: 1.5rem;
}

.booking-widget__calendar {
    max-width: 24rem;
}

.booking-cal__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 0.75rem;
}

.booking-cal__month {
    font-weight: 600;
}

.booking-cal__nav {
    width: 2.25rem;
    height: 2.25rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--color-surface);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-sm);
    color: var(--color-ink);
    cursor: pointer;
}

.booking-cal__nav:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

.booking-cal__days {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 0.25rem;
    font-family: var(--font-mono);
    font-size: 0.6875rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-ink-soft);
    text-align: center;
    margin-bottom: 0.35rem;
}

.booking-cal__grid {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 0.25rem;
}

.booking-cal__day {
    aspect-ratio: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 0.875rem;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    color: var(--color-ink);
    cursor: pointer;
}

.booking-cal__day:hover:not(:disabled) {
    border-color: var(--brand-granite);
}

.booking-cal__day:disabled {
    color: var(--color-ink-soft);
    opacity: 0.45;
    cursor: not-allowed;
    background: transparent;
}

.booking-cal__day--selected {
    background: var(--brand-granite);
    border-color: var(--brand-granite);
    color: var(--brand-cream);
}

.booking-cal__day--empty {
    visibility: hidden;
}

.booking-times__grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(6.5rem, 1fr));
    gap: 0.5rem;
    max-width: 30rem;
}

.booking-time {
    padding: 0.55rem 0.5rem;
    font-family: var(--font-mono);
    font-size: 0.875rem;
    text-align: center;
    background: var(--color-surface);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-sm);
    color: var(--color-ink);
    cursor: pointer;
}

.booking-time:hover {
    border-color: var(--brand-granite);
}

.booking-time--selected {
    background: var(--brand-granite);
    border-color: var(--brand-granite);
    color: var(--brand-cream);
}

.booking-widget__times h4 {
    margin-bottom: 0.6rem;
}

.booking-service-banner,
.enquiry-calc-summary {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0.7rem 0.9rem;
    background: var(--color-accent-soft);
    border-radius: var(--radius-md);
    font-size: 0.9375rem;
    color: var(--color-ink);
    margin-bottom: 1rem;
}

.booking-service-banner svg,
.enquiry-calc-summary__icon svg {
    color: var(--color-accent-ink);
    flex: 0 0 auto;
}

.enquiry-calc-summary__text {
    display: grid;
    gap: 0.05rem;
}

.enquiry-calc-summary__text span {
    font-size: 0.875rem;
    color: var(--color-ink-soft);
}

.enquiry-calc-summary__edit {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    background: none;
    border: 0;
    font-family: var(--font-sans);
    font-size: 0.8125rem;
    color: var(--color-accent-ink);
    text-decoration: underline;
    text-underline-offset: 0.2em;
    cursor: pointer;
}

.booking-widget__selected {
    font-weight: 600;
    margin-bottom: 0.75rem;
}

/* Forms shared */
.cta-form,
.booking-widget__form,
.booking-callback__form {
    display: grid;
    gap: 1rem;
    max-width: 44rem;
}

.cta-form__row {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem;
}

.form-group {
    display: grid;
    gap: 0.35rem;
    align-content: start;
}

.service-selector {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.5rem;
}

.service-selector--compact {
    grid-template-columns: repeat(3, minmax(0, 1fr));
}

.service-select-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.service-chip {
    display: block;
    width: 100%;
    margin-bottom: 0;
}

.service-chip input {
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
}

.service-chip__label {
    display: block;
    padding: 0.55rem 0.85rem;
    font-size: 0.875rem;
    font-weight: 400;
    color: var(--color-ink);
    background: var(--color-surface);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: background-color 0.15s var(--ease), color 0.15s var(--ease), border-color 0.15s var(--ease);
}

.service-chip input:checked + .service-chip__label {
    background: var(--brand-granite);
    border-color: var(--brand-granite);
    color: var(--brand-cream);
}

.service-chip input:focus-visible + .service-chip__label {
    outline: 2px solid var(--color-focus);
    outline-offset: 2px;
}

.form-consent {
    font-size: 0.8125rem;
    color: var(--color-ink-soft);
    max-width: 52em;
}

.form-consent a {
    color: var(--color-accent-ink);
}

/* Success / error states */
.booking-widget__success,
.enquiry-success {
    display: grid;
    gap: 0.6rem;
    justify-items: start;
    padding: 1.5rem;
    background: var(--color-surface-soft);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    max-width: 34rem;
}

.booking-widget__success svg,
.enquiry-success svg {
    color: var(--color-accent);
}

.form-error-box {
    padding: 0.8rem 1rem;
    background: var(--color-surface);
    border: 1px solid var(--color-error);
    border-radius: var(--radius-md);
    color: var(--color-error);
    font-size: 0.9375rem;
}

.cta-phone-numbers {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
}

.booking-fallback {
    margin-top: 1.25rem;
    font-size: 0.875rem;
    color: var(--color-ink-soft);
}

@media (max-width: 768px) {
    .cta-form__row,
    .service-selector,
    .service-selector--compact {
        grid-template-columns: 1fr;
    }
}

/* ============================================================
   Service pages / generic page headers
   ============================================================ */
.service-hero__inner {
    max-width: 50rem;
    display: grid;
    gap: 1.1rem;
    justify-items: start;
}

.service-hero__meta {
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: 1.25rem;
    font-size: 0.9375rem;
    color: var(--color-ink-soft);
}

.service-hero__meta li {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
}

.service-hero__meta svg {
    color: var(--color-accent-ink);
}

.service-hero__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
}

.service-price {
    font-size: 1.15rem;
    font-weight: 600;
    color: var(--color-ink);
}

.page-header {
    padding-block: clamp(2.5rem, 6vw, 4rem) 0;
}

.page-header h1 {
    margin-bottom: 0.5rem;
}

.services-index__second {
    margin-top: clamp(2.5rem, 6vw, 4rem);
}

/* ============================================================
   Modals (review + calculator info) and sticky review button
   ============================================================ */
.review-sticky-btn {
    position: fixed;
    bottom: 1.1rem;
    left: 1.1rem;
    z-index: 80;
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.6rem 1rem;
    background: var(--color-surface);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-pill);
    box-shadow: var(--shadow-md);
    font-family: var(--font-sans);
    font-size: 0.8125rem;
    font-weight: 500;
    color: var(--color-ink);
    cursor: pointer;
}

.review-sticky-btn__icon {
    color: var(--color-accent);
}

.review-modal,
.calc-info-modal {
    position: fixed;
    inset: 0;
    z-index: 200;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
}

.review-modal__backdrop,
.calc-info-modal__backdrop {
    position: absolute;
    inset: 0;
    background: rgba(47, 62, 81, 0.5);
}

.review-modal__panel,
.calc-info-modal__panel {
    position: relative;
    width: min(34rem, 100%);
    max-height: calc(100dvh - 2rem);
    overflow-y: auto;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
    padding: clamp(1.5rem, 4vw, 2rem);
}

.review-modal__close,
.calc-info-modal__close {
    position: absolute;
    top: 0.9rem;
    right: 0.9rem;
    width: 2.5rem;
    height: 2.5rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    color: var(--color-ink);
    cursor: pointer;
}

.review-modal__intro,
.calc-info-modal__desc {
    color: var(--color-ink-soft);
    margin-top: 0.4rem;
}

.review-modal__google-cta {
    display: flex;
    align-items: center;
    gap: 0.8rem;
    margin-top: 1.25rem;
    padding: 0.9rem 1rem;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-md);
    text-decoration: none;
    color: var(--color-ink);
}

.review-modal__google-cta:hover {
    background: var(--color-surface-soft);
    color: var(--color-ink);
}

.review-modal__google-cta-text {
    display: grid;
    gap: 0.1rem;
}

.review-modal__google-cta-text small {
    color: var(--color-ink-soft);
}

.review-modal__google-cta-arrow {
    margin-left: auto;
    color: var(--color-ink-soft);
}

.review-modal__list {
    display: grid;
    gap: 0.75rem;
    margin-top: 1.25rem;
}

.review-modal__card {
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    padding: 1rem 1.1rem;
    display: grid;
    gap: 0.6rem;
}

.review-modal__card-stars {
    display: inline-flex;
    gap: 0.15rem;
    color: var(--color-accent);
}

.review-modal__card-quote {
    font-size: 0.9375rem;
    line-height: 1.6;
}

.review-modal__card-meta {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
}

.review-modal__card-author {
    font-weight: 600;
    font-size: 0.9375rem;
}

.review-modal__card-role {
    font-size: 0.8125rem;
    color: var(--color-ink-soft);
}

.review-modal__card-badge {
    font-family: var(--font-mono);
    font-size: 0.6875rem;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--color-ink-soft);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-pill);
    padding: 0.2rem 0.6rem;
    white-space: nowrap;
}

.review-modal__card--google .review-modal__card-badge {
    color: var(--color-accent-ink);
    background: var(--color-accent-soft);
    border-color: var(--color-accent-soft);
}

.calc-info-modal__eyebrow {
    font-family: var(--font-mono);
    font-size: 0.75rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--color-accent-ink);
}

.calc-info-modal__title {
    margin-top: 0.4rem;
}

.calc-info-modal__includes-wrap {
    margin-top: 1rem;
}

.calc-info-modal__includes-title {
    font-size: 0.875rem;
    margin-bottom: 0.5rem;
}

.calc-info-modal__includes {
    list-style: none;
    display: grid;
    gap: 0.4rem;
}

.calc-info-modal__includes li {
    position: relative;
    padding-left: 1.1rem;
    font-size: 0.9375rem;
    color: var(--color-ink-soft);
}

.calc-info-modal__includes li::before {
    content: '';
    position: absolute;
    left: 0;
    top: 0.55em;
    width: 0.45rem;
    height: 2px;
    background: var(--color-accent);
}

.calc-info-modal__note {
    margin-top: 1rem;
    font-size: 0.875rem;
    color: var(--color-ink-soft);
}

.calc-info-modal__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin-top: 1.25rem;
}

/* ============================================================
   Blog archive / single post / 404 / landing
   ============================================================ */
.blog-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 1rem;
}

.blog-card {
    overflow: hidden;
    display: flex;
    flex-direction: column;
}

.blog-card__image img {
    width: 100%;
    aspect-ratio: 16 / 9;
    object-fit: cover;
    border-bottom: 1px solid var(--color-border);
}

.blog-card__body {
    padding: 1.1rem 1.25rem 1.35rem;
    display: grid;
    gap: 0.5rem;
    align-content: start;
}

.blog-card__category {
    font-family: var(--font-mono);
    font-size: 0.6875rem;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--color-accent-ink);
    text-decoration: none;
}

.blog-card__title {
    font-size: 1.1rem;
}

.blog-card__title a {
    text-decoration: none;
}

.blog-card__title a:hover {
    color: var(--color-accent-ink);
}

.blog-card__excerpt {
    font-size: 0.9375rem;
    color: var(--color-ink-soft);
}

.blog-pagination {
    text-align: center;
    margin-top: 3rem;
}

.blog-pagination .page-numbers {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 2.4rem;
    height: 2.4rem;
    padding-inline: 0.6rem;
    margin-inline: 0.15rem;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-sm);
    text-decoration: none;
    font-size: 0.9375rem;
}

.blog-pagination .page-numbers.current {
    background: var(--brand-granite);
    border-color: var(--brand-granite);
    color: var(--brand-cream);
}

.blog-empty {
    text-align: center;
    padding: 4rem 0;
}

.single-post__header {
    padding-block: clamp(2.5rem, 6vw, 4rem) 1.5rem;
}

.single-post__header .container {
    max-width: 48rem;
}

.post-meta {
    margin-top: 1rem;
    font-size: 0.9375rem;
}

.single-post__hero {
    max-width: 48rem;
    margin-bottom: 3rem;
}

.single-post__hero img {
    width: 100%;
    max-height: 500px;
    object-fit: cover;
    border-radius: var(--radius-lg);
    border: 1px solid var(--color-border);
}

.single-post__content .container {
    max-width: 48rem;
}

.post-nav-wrap {
    max-width: 48rem;
    margin-block: 3rem;
}

.post-nav {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    padding-top: 2rem;
    border-top: 1px solid var(--color-border);
}

.post-nav__next {
    margin-left: auto;
}

.error-404__code {
    font-size: clamp(4rem, 12vw, 7rem);
    font-weight: 600;
    color: var(--color-accent);
    line-height: 1;
}

.error-404__text {
    max-width: 34em;
    margin: 1rem auto 2rem;
}

.error-404 h2 {
    margin-top: 1rem;
}

.landing-hero {
    padding: clamp(2.5rem, 7vw, 5rem) var(--container-pad);
}

.landing-hero__inner {
    max-width: 44rem;
    margin-inline: auto;
    text-align: center;
}

.landing-hero__sub {
    margin: 1rem auto 0;
    color: var(--color-ink-soft);
    font-size: 1.125rem;
}

.landing-form {
    margin-top: 2rem;
    text-align: left;
}

.landing-footnote {
    text-align: center;
    padding: 2rem;
    font-size: 0.75rem;
    color: var(--color-ink-soft);
}

@media (max-width: 900px) {
    .blog-grid {
        grid-template-columns: 1fr;
    }
}

/* ============================================================
   Inline currency switcher (hydrated by currency-render.js)
   ============================================================ */
.km-inline-currency-switcher {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.8125rem;
    color: var(--color-ink-soft);
}

.km-inline-currency-switcher select,
.km-inline-currency-switcher button {
    font-family: var(--font-sans);
    font-size: 0.8125rem;
    padding: 0.3rem 0.55rem;
    width: auto;
}

/* ============================================================
   Systems-first homepage redesign (2026-08)
   ============================================================ */

/* Hero: readable business map over the brand-coloured particle field. */
.hero--systems {
    position: relative;
    min-height: min(50rem, calc(100svh - var(--header-h)));
    display: flex;
    align-items: center;
    overflow: clip;
    padding-block: clamp(3rem, 6vw, 5.5rem);
    border-bottom: 1px solid var(--color-border);
}

.hero__particles,
.hero__wash {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
}

.hero__particles {
    z-index: 0;
}

.hero__wash {
    inset: auto -8rem -13rem auto;
    width: min(42vw, 38rem);
    height: min(42vw, 38rem);
    border-radius: 50%;
    background: var(--color-accent-soft);
    opacity: 0.62;
    filter: blur(2px);
}

.hero__container {
    position: relative;
    z-index: 1;
}

.hero--systems .hero__layout {
    grid-template-columns: minmax(0, 0.92fr) minmax(32rem, 1.08fr);
    gap: clamp(2.5rem, 5vw, 5rem);
}

.hero--systems .hero__title {
    max-width: 12.5em;
    font-size: clamp(2.75rem, 5vw, 4.65rem);
    line-height: 1.02;
    letter-spacing: -0.045em;
}

.hero--systems .hero__description {
    max-width: 39rem;
}

.hero--systems .hero__trustline {
    max-width: 44rem;
}

.hero-blueprint {
    overflow: hidden;
    background: var(--color-surface);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-lg);
    box-shadow: 0 1.5rem 3.75rem rgba(47, 62, 81, 0.15);
}

/* The hero's terminal chrome lives in the shared .terminal-bar block near
   the end of this file (P5 "TERMINAL CHROME"). P6 deleted the private
   .hero-blueprint__bar / __dots / __title / __status copies, which were
   declaration-identical to it, and pointed section-hero.php at the shared
   classes instead. The hero's two responsive overrides are re-scoped to
   .hero-blueprint and live in the <= 760px block below. */

.hero-map {
    position: relative;
    height: clamp(23rem, 34vw, 27rem);
    background: var(--color-surface-soft);
}

.hero-map__lines {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
}

.hero-map__lines path {
    fill: none;
    stroke: var(--color-border-strong);
    stroke-width: 1.2;
    stroke-dasharray: 4 5;
    vector-effect: non-scaling-stroke;
}

.hero-node {
    position: absolute;
    z-index: 1;
    min-width: 8.4rem;
    display: flex;
    align-items: center;
    gap: 0.55rem;
    padding: 0.65rem 0.75rem;
    color: var(--color-ink);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    text-decoration: none;
    transition: transform 0.25s var(--ease), border-color 0.25s var(--ease), box-shadow 0.25s var(--ease);
}

a.hero-node:hover {
    color: var(--color-ink);
    border-color: var(--color-border-strong);
    box-shadow: var(--shadow-md);
    transform: translateY(-2px);
}

.hero-node__icon {
    flex: 0 0 1.8rem;
    width: 1.8rem;
    height: 1.8rem;
    display: grid;
    place-items: center;
    color: var(--color-accent-ink);
    background: var(--color-accent-soft);
    border-radius: var(--radius-sm);
}

.hero-node__icon svg,
.app-pattern__icon svg {
    width: 1.15rem;
    height: 1.15rem;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.6;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.hero-node strong,
.hero-node small {
    display: block;
    line-height: 1.22;
}

.hero-node strong {
    font-size: 0.8125rem;
}

.hero-node small {
    margin-top: 0.12rem;
    font-size: 0.6875rem;
    color: var(--color-ink-soft);
}

.hero-node--docs { top: 9%; left: 4%; }
.hero-node--crm { top: 7%; right: 4%; }
.hero-node--email { right: 2.5%; bottom: 18%; }
.hero-node--data { left: 50%; bottom: 3%; transform: translateX(-50%); }
.hero-node--team { left: 2.5%; bottom: 20%; }

a.hero-node--data:hover {
    transform: translateX(-50%) translateY(-2px);
}

.hero-node--core {
    top: 50%;
    left: 50%;
    width: 11.5rem;
    min-height: 6.5rem;
    display: grid;
    justify-items: center;
    align-content: center;
    gap: 0.3rem;
    text-align: center;
    color: var(--brand-cream);
    background: var(--brand-granite);
    border-color: var(--brand-granite);
    transform: translate(-50%, -50%);
    box-shadow: 0 0.8rem 2rem rgba(47, 62, 81, 0.2);
}

.hero-node--core .mono {
    font-size: 0.6875rem;
    letter-spacing: 0.12em;
    opacity: 0.68;
}

.hero-node--core strong {
    max-width: 9rem;
    font-size: 1rem;
}

.hero-node__pulse {
    width: 0.55rem;
    height: 0.55rem;
    border-radius: 50%;
    background: var(--brand-terracotta);
    box-shadow: 0 0 0 0.35rem rgba(200, 106, 74, 0.18);
}

.hero-blueprint__note {
    padding: 0.85rem 1rem;
    font-size: 0.8125rem;
    color: var(--color-ink-soft);
    background: var(--color-surface);
    border-top: 1px solid var(--color-border);
}

/* Primary systems section. */
.systems--primary {
    position: relative;
    overflow: clip;
}

.systems__heading,
.services__heading {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: end;
    gap: 2rem;
    margin-bottom: clamp(2.25rem, 5vw, 3.75rem);
}

.systems__heading .section-header,
.services__heading .section-header {
    margin-bottom: 0;
}

.systems__text-link,
.services__all-link {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    padding-bottom: 0.25rem;
    font-size: 0.875rem;
    font-weight: 600;
    text-decoration: none;
    border-bottom: 1px solid currentColor;
}

.systems__text-link {
    color: var(--brand-cream);
}

.systems__text-link:hover {
    color: #FFFFFF;
}

.systems__decision-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem;
}

/* P7: align-content is start, not end. With balanced copy the two cards
   are the same height anyway, and `end` left a ragged gap above the
   kicker that read as a layout bug. Border is 2px on BOTH cards: the
   accent card used to carry a 3px inset box-shadow bar on top of a 1px
   border, which made the pair geometrically unequal. Matching the
   border-WIDTH and varying only the colour keeps the two boxes
   identical to the pixel at every width. */
.systems__decision-card {
    min-height: 14rem;
    display: grid;
    align-content: start;
    gap: 0.7rem;
    padding: clamp(1.35rem, 3vw, 2rem);
    background: var(--color-panel-raise);
    border: 2px solid rgba(242, 237, 225, 0.16);
    border-radius: var(--radius-lg);
}

.systems__decision-card--accent {
    border-color: var(--brand-terracotta);
}

.systems__decision-num {
    font-size: 0.6875rem;
    letter-spacing: 0.1em;
    color: var(--brand-cream);
    opacity: 0.68;
}

/* P7: the inert `max-width: 36rem` is gone. The card is a half-width
   grid track, so the cap never applied and it hid the fact that the two
   paragraphs were free to run to different lengths. */
.systems__decision-card p {
    color: var(--brand-cream);
    opacity: 0.84;
}

.systems__patterns {
    margin-top: clamp(3rem, 6vw, 5rem);
}

.systems__patterns-head {
    display: flex;
    align-items: end;
    justify-content: space-between;
    gap: 2rem;
    margin-bottom: 1rem;
}

.systems__patterns-head .mono,
.systems__proof-intro > .mono {
    display: block;
    margin-bottom: 0.4rem;
    font-size: 0.6875rem;
    letter-spacing: 0.11em;
    color: var(--brand-cream);
    opacity: 0.65;
}

/* P7: 3 x 2 instead of one 5-wide row (the sixth archetype, DDMRP,
   arrived and a 6-across row is unreadable). `grid-auto-rows: 1fr`
   makes both rows the same height, so all six faces align whatever the
   titles wrap to. NOTE: .services__rail is NOT in this selector and
   must stay out of it, or the homepage service tiles change with it. */
.systems__rail {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    grid-auto-rows: 1fr;
    gap: 0.75rem;
}

/* P7: the face is a <button> that opens the blueprint modal, so the UA
   button styles are reset here (font, background, border, alignment).
   The 18.5rem min-height went with the description paragraph, which
   moved into the modal; equal heights now come from the rail's
   grid-auto-rows. Hover, focus ring, title and the "View blueprint"
   affordance live in the P7 block at the end of this file. */
.app-pattern {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    width: 100%;
    padding: 1.15rem;
    font: inherit;
    text-align: left;
    color: var(--color-ink);
    background: var(--brand-cream);
    border: 1px solid rgba(242, 237, 225, 0.28);
    border-radius: var(--radius-md);
    cursor: pointer;
}

.app-pattern__icon {
    width: 2.6rem;
    height: 2.6rem;
    display: grid;
    place-items: center;
    color: var(--color-accent-ink);
    background: var(--color-accent-soft);
    border-radius: var(--radius-md);
}

/* P7: the pinning is gone (`margin-top: auto` + `padding-top: 2rem`
   used to shove this label to the bottom of a tall card). Content now
   flows top-down from the icon, and the label is held to ONE line so
   the six titles start at the same y. */
.app-pattern__meta {
    margin-top: 0.85rem;
    font-size: 0.625rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    white-space: nowrap;
    color: var(--color-ink-soft);
}

/* P7: `.section--panel .app-pattern h3` and `... p` were deleted here.
   A <button> may not contain an <h3>, so the title is a
   .app-pattern__title span, and the description paragraph moved into
   the modal. Both replacements are in the P7 block at the end of this
   file. */

.systems__proof {
    display: grid;
    grid-template-columns: 1.25fr 0.75fr;
    gap: clamp(2rem, 5vw, 4rem);
    align-items: end;
    margin-top: clamp(3rem, 6vw, 5rem);
    padding-top: 2rem;
    border-top: 1px solid rgba(242, 237, 225, 0.18);
}

.systems__proof-intro p {
    max-width: 42rem;
    margin-top: 0.6rem;
    font-size: 0.9375rem;
    opacity: 0.8;
}

.systems__proof-builds {
    display: grid;
    gap: 0.65rem;
}

.systems__proof-builds p {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding-block: 0.65rem;
    border-bottom: 1px solid rgba(242, 237, 225, 0.15);
}

.systems__proof-builds strong {
    font-size: 0.875rem;
}

/* Two primary paths. */
.paths--split {
    background: var(--color-canvas);
}

.paths__intro {
    max-width: 56rem;
    display: grid;
    gap: 0.9rem;
    margin-bottom: clamp(2rem, 5vw, 3.5rem);
}

.paths__intro p {
    max-width: 46rem;
    color: var(--color-ink-soft);
}

.paths--split .paths__grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem;
}

.paths--split .path-card {
    position: relative;
    min-height: 29rem;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 1rem;
    overflow: hidden;
    padding: clamp(1.5rem, 4vw, 2.5rem);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
}

.path-card--systems {
    color: var(--brand-cream);
    background: var(--brand-granite);
    border-color: var(--brand-granite);
}

.path-card--services {
    color: var(--color-ink);
    background: var(--color-surface);
}

.path-card__topline {
    width: 100%;
    display: flex;
    justify-content: space-between;
    align-items: start;
    gap: 1rem;
}

.path-card__mark {
    font-family: var(--font-mono);
    font-size: clamp(4.5rem, 8vw, 7rem);
    font-weight: 700;
    line-height: 0.8;
    opacity: 0.12;
}

.path-card--systems .path-card__kicker,
.path-card--systems h3,
.path-card--systems p,
.path-card--systems .path-card__link {
    color: var(--brand-cream);
}

.paths--split .path-card h3 {
    max-width: 16em;
    margin-top: auto;
    font-size: clamp(1.65rem, 3vw, 2.35rem);
}

.paths--split .path-card p {
    max-width: 35rem;
    font-size: 0.975rem;
    line-height: 1.6;
    opacity: 0.86;
}

.path-card__tags {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    list-style: none;
}

.path-card__tags li {
    padding: 0.3rem 0.65rem;
    font-family: var(--font-mono);
    font-size: 0.6875rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-pill);
}

.path-card--systems .path-card__tags li {
    border-color: rgba(242, 237, 225, 0.25);
}

.paths--split .path-card__link {
    margin-top: 0.5rem;
    font-weight: 600;
}

/* Editorial digital-services rail. */
.services--presence {
    background: var(--color-surface-soft);
    border-block: 1px solid var(--color-border);
}

.services__all-link {
    color: var(--color-ink);
}

.services__rail {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 0.75rem;
}

.service-tile--editorial {
    min-height: 19rem;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    padding: 1.2rem;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-top: 3px solid var(--brand-terracotta);
    border-radius: var(--radius-md);
    transition: transform 0.25s var(--ease), border-color 0.25s var(--ease), box-shadow 0.25s var(--ease);
}

.service-tile--editorial:hover {
    transform: translateY(-3px);
    border-color: var(--color-border-strong);
    box-shadow: var(--shadow-md);
}

.service-tile__topline {
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: auto;
    padding-bottom: 2rem;
}

.service-tile--editorial .service-tile__icon svg {
    width: 1.3rem;
    height: 1.3rem;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.55;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.service-tile__index {
    font-size: 0.6875rem;
    letter-spacing: 0.1em;
    color: var(--color-ink-soft);
}

.service-tile--editorial h3 {
    font-size: 1.2rem;
}

.service-tile--editorial > p {
    margin-top: 0.55rem;
    font-size: 0.875rem;
    line-height: 1.55;
    color: var(--color-ink-soft);
}

.service-tile--editorial .service-tile__link {
    margin-top: 1.2rem;
    min-height: 2.75rem;
    align-items: center;
}

/* ============================================================
   JOURNEY TIMELINE (P3, 2026-08-17)
   ------------------------------------------------------------
   Every journey rule lives in this one block: base, the two
   breakpoints and the reduced-motion neutralisation. Nothing
   journey-related is left in the shared responsive blocks
   further down, so the cascade for this section reads top to
   bottom in one place.

   LAYOUT
     >= 1024px  two columns: sticky stage marker | timeline
     761-1023   marker hidden, mono progress chip above the
                timeline, timeline full width
     <= 760px   plain stacked timeline. No horizontal rail,
                nothing sticky, nothing hidden.

   THE CONNECTOR
     .journey__spine::before is the 2px granite track. The SVG
     line on top of it is the terracotta progress overlay. The
     line carries pathLength="1", so its length is normalised
     and stroke-dasharray: 1 makes one dash cover the whole
     line. js/journey-map.js publishes --journey-dash on the
     section root:
         1 = undrawn      0 = fully drawn
     which is exactly (1 - scroll progress through the spine).
     No real path length is ever measured, in CSS or in JS.

     The script publishes NOTHING at <= 760px or under
     prefers-reduced-motion; both cases below hard-set
     stroke-dashoffset: 0, so the connector renders pre-drawn
     and no per-scroll SVG write ever happens.

   MOTION BUDGET
     Cards enter once, alternating slide-left / slide-right (the
     P1 utilities, 450ms). Active state is colour and weight
     only: no transform, so it can never fight the entrance
     transform. overflow-x: clip on the section means a
     horizontal entrance can never produce a scrollbar.
   ============================================================ */
.journey--project {
    /* clip, NOT hidden: overflow-x: hidden would turn the section into a
       scroll container and break the sticky compass inside it. */
    overflow-x: clip;
    scroll-margin-top: var(--header-h);

    --journey-track-x: 2.25rem;   /* centre line of the track */
    --journey-track-w: 2px;
    --journey-gutter: 4.75rem;    /* card inset, clears the track and dot */
    --journey-card-pad: clamp(1.4rem, 3vw, 2.1rem);
    --journey-dot: 0.875rem;
}

.journey__header {
    max-width: 52rem;
}

.journey__layout {
    display: grid;
    grid-template-columns: minmax(15rem, 0.62fr) minmax(0, 1.38fr);
    gap: clamp(2rem, 6vw, 5rem);
    align-items: start;
}

/* ---- Sticky stage marker (desktop) ---- */
.journey__compass {
    position: sticky;
    top: calc(var(--header-h) + 1.5rem);
}

.journey__compass-card {
    padding: 1.5rem;
    color: var(--brand-cream);
    background: var(--brand-granite);
    border-radius: var(--radius-lg);
}

.journey__compass-label,
.journey__compass-num {
    font-size: 0.6875rem;
    letter-spacing: 0.11em;
    opacity: 0.65;
}

.journey__compass-num {
    margin-top: 2.5rem;
}

.journey__compass h3 {
    margin-top: 0.35rem;
    font-size: clamp(1.8rem, 3vw, 2.5rem);
    color: var(--brand-cream);
}

.journey__progress {
    height: 2px;
    margin-top: 1.5rem;
    overflow: hidden;
    background: rgba(242, 237, 225, 0.2);
}

.journey__progress span {
    display: block;
    width: 100%;
    height: 100%;
    background: var(--brand-terracotta);
    transform: scaleX(0);
    transform-origin: left center;
    transition: transform 0.45s var(--ease);
}

.journey__nav {
    display: grid;
    gap: 0.2rem;
    margin-top: 1.25rem;
    list-style: none;
}

.journey__nav a {
    position: relative;
    display: block;
    padding: 0.45rem 0.45rem 0.45rem 1rem;
    font-size: 0.8125rem;
    color: var(--brand-cream);
    opacity: 0.48;
    text-decoration: none;
    transition: opacity 0.25s var(--ease);
}

.journey__nav a::before {
    content: '';
    position: absolute;
    left: 0;
    top: 50%;
    width: 0.34rem;
    height: 0.34rem;
    border-radius: 50%;
    background: currentColor;
    transform: translateY(-50%);
}

.journey__nav a:hover,
.journey__nav a:focus-visible {
    opacity: 0.85;
}

.journey__nav a[aria-current='step'] {
    opacity: 1;
}

/* ---- Timeline column ---- */
.journey__timeline {
    min-width: 0;
}

/* Tablet-band readout. Hidden here, switched on between 761 and 1023px,
   where the sticky marker is gone. Fed by the same script hooks. */
.journey__chip {
    display: none;
    align-items: center;
    gap: 0.85rem;
    margin-bottom: 1.5rem;
    padding: 0.5rem 0.95rem;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-pill);
}

.journey__chip-count {
    font-size: 0.6875rem;
    letter-spacing: 0.11em;
    color: var(--color-accent-ink);
}

.journey__chip-name {
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--color-ink);
}

.journey__progress--chip {
    flex: 1 1 auto;
    min-width: 3rem;
    margin-top: 0;
    background: var(--color-border);
}

/* ---- Track, connector, dots ---- */
.journey__spine {
    position: relative;
}

.journey__spine::before {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    left: var(--journey-track-x);
    width: var(--journey-track-w);
    margin-left: calc(var(--journey-track-w) / -2);
    background: var(--color-border);
}

.journey__connector {
    position: absolute;
    top: 0;
    left: var(--journey-track-x);
    width: var(--journey-track-w);
    height: 100%;
    margin-left: calc(var(--journey-track-w) / -2);
    pointer-events: none;
}

/* NEVER add vector-effect: non-scaling-stroke here. It makes the browser
   stroke in screen space, which throws away the pathLength="1"
   normalisation: stroke-dasharray: 1 then means a one-user-unit dash
   pattern and the connector renders as a dashed line instead of one
   drawn segment. It is not needed either. The viewBox is 2 units wide in
   a 2px-wide box, so the x scale is exactly 1, and a vertical line's
   stroke width is measured along x. 2 units = 2 CSS px, at any height. */
.journey__connector line {
    stroke: var(--brand-terracotta);
    stroke-width: var(--journey-track-w);
    stroke-dasharray: 1;
    stroke-dashoffset: var(--journey-dash, 1);
}

.journey--project .journey__stages {
    display: grid;
    grid-template-columns: 1fr;
    gap: clamp(1rem, 2.4vw, 1.6rem);
    list-style: none;
}

/* scroll-margin-top governs NATIVE anchor scrolling: a #journey-step-N URL,
   or a compass click with JS off. (With JS on, js/navigation.js intercepts
   every a[href^="#"] and scrolls to top minus header height instead, which
   ignores scroll-margin entirely. That file is theme-wide and was out of
   this phase's scope.)
   The max() floor clears the sticky header. The 28vh term lands the stage
   near the same reading line the script measures against, 48% of the
   viewport, so the marker names the stage you asked for rather than the
   one that ends up across the middle of the screen. */
.journey--project .journey__stage {
    position: relative;
    padding-left: var(--journey-gutter);
    scroll-margin-top: max(calc(var(--header-h) + 1.5rem), 28vh);
}

.journey__dot {
    position: absolute;
    top: calc(var(--journey-card-pad) + 0.4rem);
    left: var(--journey-track-x);
    width: var(--journey-dot);
    height: var(--journey-dot);
    margin-left: calc(var(--journey-dot) / -2);
    background: var(--color-surface);
    border: 2px solid var(--color-border-strong);
    border-radius: 50%;
    transition: background-color 0.35s var(--ease), border-color 0.35s var(--ease), box-shadow 0.35s var(--ease);
}

.journey__stage.is-active .journey__dot {
    background: var(--brand-terracotta);
    border-color: var(--brand-terracotta);
    box-shadow: 0 0 0 4px var(--color-accent-soft);
}

/* The reveal wrapper carries the entrance so the dot, which is a sibling
   of it inside the non-transformed <li>, stays welded to the track. */
.journey__stage-reveal {
    min-width: 0;
}

.journey__card {
    display: grid;
    gap: 0.9rem;
    padding: var(--journey-card-pad);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    opacity: 0.62;
    transition: opacity 0.35s var(--ease), border-color 0.35s var(--ease), box-shadow 0.35s var(--ease);
}

.journey__stage.is-active .journey__card {
    opacity: 1;
    border-color: var(--color-border-strong);
    box-shadow: var(--shadow-md);
}

.journey__card-head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.7rem;
}

.journey__stage-num {
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.12em;
    color: var(--color-ink-soft);
    transition: color 0.35s var(--ease);
}

/* Small text, so the accent INK (#8B584D), never display terracotta. */
.journey__stage.is-active .journey__stage-num {
    color: var(--color-accent-ink);
}

.journey__stage-kicker {
    font-size: 0.6875rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--color-ink-soft);
}

.journey__stage-copy {
    max-width: 39rem;
}

.journey__stage-copy h3 {
    font-size: clamp(1.45rem, 2.4vw, 2rem);
}

.journey__stage-copy > p:not(.journey__output) {
    margin-top: 0.75rem;
    color: var(--color-ink-soft);
}

.journey__output {
    display: grid;
    gap: 0.15rem;
    margin-top: 1.5rem;
    padding-top: 0.9rem;
    border-top: 1px solid var(--color-border);
}

.journey__output span {
    font-family: var(--font-mono);
    font-size: 0.625rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--color-ink-soft);
}

.journey__output strong {
    font-size: 0.9375rem;
}

.journey__close {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 2rem;
    margin-top: clamp(2rem, 5vw, 3.5rem);
    padding: 1.25rem 1.5rem;
    background: var(--color-accent-soft);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
}

.journey__close p {
    max-width: 43rem;
}

/* Tablet band: the sticky marker cannot earn its column width any more,
   so it goes and the chip takes over the same information. */
@media (max-width: 1023px) {
    /* position: static as well as display: none, so a QA sweep for sticky
       positioning inside this section returns nothing at all below 1024px
       rather than a hidden element that still computes to sticky. */
    .journey__compass {
        display: none;
        position: static;
    }

    .journey__layout {
        display: block;
    }

    .journey__chip {
        display: flex;
    }
}

/* Phones: one plain column. No rail, no sticky anything, no dimming.
   The connector is pre-drawn and the script never writes to it. */
@media (max-width: 760px) {
    .journey--project {
        --journey-track-x: 1.25rem;
        --journey-gutter: 2.85rem;
        --journey-dot: 0.75rem;
    }

    .journey__chip {
        display: none;
    }

    .journey__connector line {
        stroke-dashoffset: 0;
    }

    .journey__card {
        opacity: 1;
    }

    .journey__dot {
        top: calc(var(--journey-card-pad) + 0.3rem);
    }

    .journey__close {
        align-items: flex-start;
        flex-direction: column;
    }
}

/* Reduced motion: the connector is drawn, the progress bar jumps instead
   of sliding, and every state transition in the section is off. The
   script skips all draw work, so nothing here has to fight an inline
   style. Colour and weight changes still communicate the active stage. */
@media (prefers-reduced-motion: reduce) {
    .journey__connector line {
        stroke-dashoffset: 0;
    }

    .journey__progress span,
    .journey__nav a,
    .journey--project .journey__stage,
    .journey__card,
    .journey__dot,
    .journey__stage-num {
        transition: none;
    }
}

/* Founder cards with real supplied portraits. */
.trust--founders {
    background: var(--color-canvas);
}

.trust__layout {
    display: grid;
    grid-template-columns: minmax(17rem, 0.7fr) minmax(0, 1.3fr);
    gap: clamp(2.5rem, 7vw, 6rem);
    align-items: center;
}

.trust__intro {
    display: grid;
    gap: 1rem;
}

.trust__intro > p {
    color: var(--color-ink-soft);
}

.trust__intro .trust__points {
    display: grid;
    margin-top: 0.5rem;
}

.trust__intro .trust__point {
    padding: 0;
    background: transparent;
    border: 0;
    border-radius: 0;
}

.trust__response {
    padding-top: 0.75rem;
    font-size: 0.75rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    border-top: 1px solid var(--color-border);
}

.trust--founders .founders {
    max-width: none;
    align-items: stretch;
}

.founder-card {
    width: 100%;
    height: 100%;
    display: grid;
    grid-template-rows: auto 1fr;
    overflow: hidden;
    padding: 0;
    text-align: left;
    font-family: var(--font-sans);
    color: var(--color-ink);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    cursor: pointer;
    transition: transform 0.25s var(--ease), border-color 0.25s var(--ease), box-shadow 0.25s var(--ease);
}

.founder-card:hover {
    transform: translateY(-3px);
    border-color: var(--color-border-strong);
    box-shadow: var(--shadow-md);
}

.founder-card__portrait {
    position: relative;
    display: block;
    overflow: hidden;
    aspect-ratio: 4 / 5;
    background: var(--color-accent-soft);
}

.founder-card__portrait img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center top;
    transition: transform 0.5s var(--ease);
}

.founder-card:hover .founder-card__portrait img {
    transform: scale(1.025);
}

.founder-card__status {
    position: absolute;
    left: 0.75rem;
    bottom: 0.75rem;
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.35rem 0.6rem;
    font-size: 0.625rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--brand-cream);
    background: var(--brand-granite);
    border-radius: var(--radius-pill);
}

.founder-card__status i {
    width: 0.4rem;
    height: 0.4rem;
    border-radius: 50%;
    background: var(--brand-terracotta);
}

.founder-card__body {
    display: grid;
    align-content: start;
    padding: 1rem;
}

.founder-card__name {
    font-size: 1.15rem;
    font-weight: 650;
}

.founder-card__role {
    margin-top: 0.25rem;
    font-size: 0.8125rem;
    line-height: 1.4;
    color: var(--color-ink-soft);
}

.founder-card__cue {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    margin-top: 1rem;
    font-size: 0.8125rem;
    font-weight: 600;
    color: var(--color-accent-ink);
}

.founder-modal__avatar img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* Dedicated Systems & Apps landing page. */
.systems-page-hero {
    padding-block: clamp(3.5rem, 8vw, 7rem);
}

.systems-page-hero__grid {
    display: grid;
    grid-template-columns: minmax(0, 1.12fr) minmax(20rem, 0.88fr);
    gap: clamp(2.5rem, 7vw, 6rem);
    align-items: center;
}

.systems-page-hero__copy h1 {
    max-width: 13em;
    margin-top: 1rem;
    font-size: clamp(2.6rem, 5.5vw, 4.8rem);
    line-height: 1.03;
    letter-spacing: -0.045em;
}

.systems-page-hero__copy .lead {
    margin-top: 1.25rem;
}

.systems-page-hero__brief {
    padding: clamp(1.5rem, 4vw, 2.25rem);
    color: var(--brand-cream);
    background: var(--brand-granite);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
}

.systems-page-hero__brief > .mono {
    font-size: 0.6875rem;
    letter-spacing: 0.1em;
    opacity: 0.65;
}

.systems-page-hero__brief > p {
    margin-top: 1.5rem;
    font-size: clamp(1.25rem, 2.5vw, 1.7rem);
    line-height: 1.4;
}

.systems-page-hero__brief ul {
    display: grid;
    gap: 0.75rem;
    margin-top: 2rem;
    list-style: none;
}

.systems-page-hero__brief li {
    display: flex;
    gap: 0.8rem;
    padding-top: 0.75rem;
    font-size: 0.875rem;
    border-top: 1px solid rgba(242, 237, 225, 0.16);
}

.systems-page-hero__brief li span {
    font-family: var(--font-mono);
    opacity: 0.55;
}

.systems-page-possibilities__grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 1px;
    overflow: hidden;
    background: rgba(242, 237, 225, 0.18);
    border: 1px solid rgba(242, 237, 225, 0.18);
    border-radius: var(--radius-lg);
}

.systems-page-example {
    min-height: 16rem;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    padding: 1.5rem;
    background: var(--color-panel);
}

.systems-page-example__num,
.systems-page-example__label {
    font-size: 0.65rem;
    letter-spacing: 0.09em;
    color: var(--brand-cream);
    opacity: 0.58;
}

.systems-page-example__label {
    margin-top: auto;
    padding-top: 2rem;
    text-transform: uppercase;
}

.systems-page-example h3 {
    margin-top: 0.5rem;
}

.systems-page-example p {
    margin-top: 0.6rem;
    font-size: 0.875rem;
    opacity: 0.78;
}

.systems-page-connections__layout {
    display: grid;
    grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
    gap: clamp(2.5rem, 7vw, 6rem);
    align-items: start;
}

.systems-page-connections__list {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.75rem;
    list-style: none;
}

.systems-page-connections__list li {
    min-height: 8.5rem;
    display: grid;
    align-content: end;
    gap: 0.35rem;
    padding: 1rem;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
}

.systems-page-connections__list span {
    font-size: 0.8125rem;
    color: var(--color-ink-soft);
}

.systems-page-choice__grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem;
}

.systems-page-choice__grid article {
    display: grid;
    justify-items: start;
    gap: 1rem;
}

.services-systems-bridge__inner {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 3rem;
}

.services-systems-bridge__inner > div {
    max-width: 48rem;
}

.services-systems-bridge__inner h2 {
    margin-top: 0.8rem;
}

.services-systems-bridge__inner p {
    margin-top: 0.65rem;
    opacity: 0.82;
}

/* Side-origin reveal for the paired path cards.
   The systems decision cards used to share this rule. Since P2 they carry
   the canonical [data-animate="slide-left"] / "slide-right" utilities
   instead, so the group-based version is scoped to .paths__grid only and
   there is exactly one side-entrance mechanism in the codebase. */
.paths__grid[data-animate-group] > *:first-child {
    transform: translateX(-1.1rem);
}

.paths__grid[data-animate-group] > *:last-child {
    transform: translateX(1.1rem);
}

.paths__grid[data-animate-group].is-visible > * {
    transform: none;
}

/* Responsive rails and compact layouts. */
@media (max-width: 1080px) {
    .hero--systems .hero__layout {
        grid-template-columns: minmax(0, 0.9fr) minmax(28rem, 1.1fr);
        gap: 2rem;
    }

    /* P7: .systems__rail left this shared selector. Its base layout is
       3 x 2 now, so the override was a no-op for the app-pattern cards
       and only the services rail still needs the 4 -> 3 step down.
       Splitting it keeps a systems-side change from leaking into the
       service tiles. The `.app-pattern { min-height: 16rem }` rule that
       sat here went with the description paragraph and the swipe-rail
       card size; equal heights come from grid-auto-rows now. */
    .services__rail {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}

@media (max-width: 900px) {
    .hero--systems {
        min-height: auto;
    }

    .hero--systems .hero__layout,
    .systems-page-hero__grid,
    .systems-page-connections__layout,
    .trust__layout {
        grid-template-columns: 1fr;
    }

    .hero--systems .hero__visual {
        display: block;
    }

    .hero-map {
        height: 25rem;
    }

    .systems__proof {
        grid-template-columns: 1fr;
    }

    .trust__layout {
        align-items: start;
    }

    .trust__intro {
        max-width: 42rem;
    }

    .systems-page-possibilities__grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (max-width: 760px) {
    .hero--systems {
        padding-block: 2.4rem 3.25rem;
    }

    .hero--systems .hero__title {
        font-size: clamp(2.45rem, 11vw, 3.5rem);
    }

    .hero--systems .hero__actions .btn {
        width: 100%;
    }

    /* Hero-only overrides of the SHARED .terminal-bar (P6 migration).
       Scoped to .hero-blueprint so the /systems/ brief terminal keeps its
       title at this width; the two-class selectors also outrank the base
       .terminal-bar rules regardless of where they sit in the file. */
    .hero-blueprint .terminal-bar__title {
        display: none;
    }

    .hero-blueprint .terminal-bar {
        grid-template-columns: 1fr auto;
    }

    .hero-map {
        height: 22.5rem;
    }

    .hero-node {
        min-width: 6.6rem;
        gap: 0.4rem;
        padding: 0.5rem;
    }

    .hero-node__icon {
        flex-basis: 1.45rem;
        width: 1.45rem;
        height: 1.45rem;
    }

    .hero-node__icon svg {
        width: 0.95rem;
        height: 0.95rem;
    }

    .hero-node strong {
        font-size: 0.7rem;
    }

    .hero-node small {
        font-size: 0.6rem;
    }

    .hero-node--docs { top: 7%; left: 2%; }
    .hero-node--crm { top: 6%; right: 2%; }
    .hero-node--email { right: 1.5%; bottom: 18%; }
    .hero-node--team { left: 1.5%; bottom: 20%; }
    .hero-node--data { bottom: 2%; }

    .hero-node--core {
        width: 8.5rem;
        min-height: 5.8rem;
    }

    .hero-node--core strong {
        font-size: 0.82rem;
    }

    .systems__heading,
    .services__heading {
        grid-template-columns: 1fr;
        align-items: start;
        gap: 1rem;
    }

    .systems__decision-grid {
        grid-template-columns: 1fr;
    }

    .systems__decision-card {
        min-height: 12.5rem;
    }

    /* The .mobile-rail ruleset that used to sit here is GONE. P2 de-railed
       systems, services, case studies and founders; P3 de-railed the journey
       stages and the two path cards, which were the last two users. The
       class now has zero occurrences in template-parts, so the pattern is
       retired site-wide per PLAN.md section 5. Do not reintroduce it: a
       horizontal swipe rail hides content behind a gesture nobody is told
       about, and it is the fastest route to a horizontal scrollbar.

       REVERSAL 2026-08-18 (Milan, design review): rails are BACK as
       `.km-rail` (P8 block at the end of this file) with mandatory visible
       affordances - next-card peek + visible thin scrollbar. The 2026-08
       retirement stands as a warning about the OLD pattern (no affordance,
       hidden scrollbar, 85% cards, swipe-label crutch), not a ban. */

    /* De-railed mobile layouts (P2). The app-pattern cards become a
       compact two-up grid and the service tiles a plain vertical list.
       Both drop the tall desktop min-height, which only existed to give
       the swipe rail a consistent card size.
       P8: both grid-template-columns declarations below are now INERT -
       `.km-rail` makes these two wrappers flex containers at this width.
       They are left in place (like the P7 decision-grid override) because
       they are the correct fallback the moment `.km-rail` is removed from
       the markup; the P8 block owns the live layout. */
    .systems__rail {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 0.6rem;
    }

    .services__rail {
        grid-template-columns: 1fr;
        gap: 0.6rem;
    }

    .app-pattern {
        min-height: 0;
        padding: 0.85rem;
    }

    .app-pattern__icon {
        width: 2.2rem;
        height: 2.2rem;
    }

    .app-pattern__meta {
        padding-top: 1.1rem;
        font-size: 0.5625rem;
    }

    /* P8: deleted inert app-pattern h3/p rules (G7 ruling). */

    .service-tile--editorial {
        min-height: 0;
        padding: 1.1rem;
    }

    .service-tile__topline {
        padding-bottom: 1rem;
    }

    .service-tile--editorial .service-tile__link {
        margin-top: 0.9rem;
    }

    /* De-railed in P3 under the G2 ruling. The two path cards were the
       last horizontal swipe on the homepage; they now stack, like every
       other card group below 760px. The tall min-height went with the
       rail: it only existed to keep the swipe cards a uniform size. */
    .paths--split .paths__grid {
        grid-template-columns: 1fr;
        gap: 0.75rem;
    }

    .paths--split .path-card {
        min-height: 0;
    }

    /* Journey rules are NOT here. The whole journey system, including its
       1023px and 760px behaviour, lives in one block further up the file. */

    .services-systems-bridge__inner {
        align-items: flex-start;
        flex-direction: column;
    }

    .trust--founders .founders {
        max-width: none;
    }

    /* width:100% is load-bearing. Without it the aspect-ratio box resolves
       its WIDTH from the clamped max-height, so the portrait sat 28px
       narrower than its card and left a white gutter down the right edge.
       Explicit width wins over aspect-ratio; max-height then crops through
       object-fit: cover instead of shrinking the box. */
    .founder-card__portrait {
        width: 100%;
        max-height: 24rem;
    }

    .systems-page-possibilities__grid,
    .systems-page-connections__list,
    .systems-page-choice__grid {
        grid-template-columns: 1fr;
    }

    .systems-page-example {
        min-height: 13rem;
    }
}

@media (max-width: 430px) {
    .hero-map {
        height: 21rem;
    }

    .hero-node--core {
        width: 7.6rem;
    }

    .hero-node--data {
        min-width: 6.1rem;
    }

    .hero-blueprint__note {
        font-size: 0.75rem;
    }
}

/* Journey is absent here on purpose: its reduced-motion block sits inside
   the journey system further up, next to the rules it neutralises. */
@media (prefers-reduced-motion: reduce) {
    .hero-node,
    .founder-card,
    .founder-card__portrait img,
    .service-tile--editorial {
        transition: none;
    }
}

/* ============================================================
   P1 FOUNDATION UTILITIES (shipped 2026-08-17, applied in P2/P3)
   ------------------------------------------------------------
   Technical-surface textures and directional reveal variants.
   Both are now in service: P2 put the inverse dot-grid on the
   systems panel and the side entrances on its decision cards,
   P3 put the dot-grid on the journey section and the alternating
   side entrances on the journey timeline cards.

   USAGE
     .bg-dotgrid            cream / light surfaces (granite dots)
     .bg-dotgrid--inverse   granite panels (cream dots)
     .bg-graph              graph-paper ruling, same two contexts
     [data-animate="slide-left"]  enters from the left
     [data-animate="slide-right"] enters from the right

   RULES
     - Pure CSS tiles, no images, no extra requests.
     - Dot / rule opacity stays at or below 6 per cent: texture must
       never compete with type. Never place on hero, forms, FAQ or
       legal pages (see PLAN.md section 5).
     - The reveal variants are driven by the SAME .is-visible toggle
       that js/reveal.js already sets. reveal.js is not modified.
     - prefers-reduced-motion neutralises the transforms, matching the
       existing pattern in style.css.
   ============================================================ */

.bg-dotgrid,
.bg-graph {
    --km-tex-ink: 47, 62, 81;   /* Blue Granite, for cream surfaces */
    --km-tex-alpha: 0.06;
    --km-tex-size: 22px;
    position: relative;
    background-repeat: repeat;
}

.bg-dotgrid--inverse,
.bg-graph--inverse {
    --km-tex-ink: 242, 237, 225; /* Cannoli Cream, for granite panels */
    --km-tex-alpha: 0.055;
}

.bg-dotgrid {
    background-image: radial-gradient(
        circle at 1px 1px,
        rgba(var(--km-tex-ink), var(--km-tex-alpha)) 1px,
        transparent 0
    );
    background-size: var(--km-tex-size) var(--km-tex-size);
}

.bg-graph {
    background-image:
        linear-gradient(to right, rgba(var(--km-tex-ink), var(--km-tex-alpha)) 1px, transparent 1px),
        linear-gradient(to bottom, rgba(var(--km-tex-ink), var(--km-tex-alpha)) 1px, transparent 1px);
    background-size: var(--km-tex-size) var(--km-tex-size);
}

/* Directional reveal variants. Base state is set here (overriding the
   translateY default in style.css); .is-visible resolves them. */
[data-animate="slide-left"],
[data-animate="slide-right"] {
    opacity: 0;
    transition: opacity 0.45s var(--ease), transform 0.45s var(--ease);
}

[data-animate="slide-left"] {
    transform: translateX(-24px);
}

[data-animate="slide-right"] {
    transform: translateX(24px);
}

[data-animate="slide-left"].is-visible,
[data-animate="slide-right"].is-visible {
    opacity: 1;
    transform: none;
}

/* ============================================================
   P2 HOMEPAGE RESTRUCTURE (2026-08-17)
   ------------------------------------------------------------
   Three things live here:
     1. .proof-strip  - the four ledger-verified tiles in the trust
        section (now homepage position 3). Mono labels, display-size
        numerals. Two-up at every width: it sits inside the narrow
        intro column on desktop and must stay legible there.
     2. .commercials  - the demoted engagement terms strip in
        section-process.php. One hairline-divided row on desktop,
        clean stack on mobile. Deliberately NOT card-shaped: it is
        not a process story any more.
     3. The mobile degrade for the P1 side-entrance utilities.

   COLOUR RULE: the tile figures use terracotta because they are
   display size (>= 1.9rem). The commercials numbers are small, so
   they use the derived accent ink #8B584D. Never the other way round.
   ============================================================ */

.proof-strip {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.75rem;
    margin-top: 1.75rem;
    list-style: none;
}

.proof-tile {
    display: grid;
    align-content: start;
    gap: 0.35rem;
    padding: 0.9rem 1rem;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
}

.proof-tile__figure {
    font-family: var(--font-mono);
    font-size: clamp(1.9rem, 3.4vw, 2.5rem);
    font-weight: 600;
    line-height: 1;
    letter-spacing: -0.02em;
    color: var(--color-accent); /* display size only: large-text AA */
}

.proof-tile__label {
    font-size: 0.625rem;
    line-height: 1.45;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--color-ink-soft);
}

.proof-strip__note {
    font-size: 0.75rem;
    line-height: 1.5;
}

/* Mono kicker for the recent-builds strip, the last sans-serif
   hold-out among the section kickers. Not uppercased: the industry
   strings are long and carry ampersands. */
.recent-builds__industry {
    font-size: 0.6875rem;
    line-height: 1.4;
    letter-spacing: 0.04em;
}

.commercials__title {
    margin-bottom: 1.25rem;
}

.commercials__strip {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 1px;
    overflow: hidden;
    list-style: none;
    background: var(--color-border);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
}

.commercials__item {
    display: grid;
    align-content: start;
    gap: 0.3rem;
    padding: 1rem 1.15rem;
    background: var(--color-surface);
}

.commercials__num {
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.1em;
    color: var(--color-accent-ink);
}

.commercials__label {
    font-size: 0.9375rem;
    font-weight: 600;
    line-height: 1.35;
    color: var(--color-ink);
}

.commercials__note {
    font-size: 0.8125rem;
    line-height: 1.5;
    color: var(--color-ink-soft);
}

@media (max-width: 991px) {
    .commercials__strip {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/* Side entrances are a DESKTOP effect. Below 760px they degrade to the
   plain fade-up used everywhere else: a horizontal translate on a narrow
   viewport is the fastest way to create an overflow scrollbar, and the
   directionality reads as noise once the cards are stacked. */
@media (max-width: 760px) {
    [data-animate="slide-left"],
    [data-animate="slide-right"] {
        transform: translateY(14px);
    }

    [data-animate="slide-left"].is-visible,
    [data-animate="slide-right"].is-visible {
        transform: none;
    }
}

@media (max-width: 560px) {
    .commercials__strip {
        grid-template-columns: 1fr;
    }
}

/* ============================================================
   P4: estimator lane switcher + Lane B (custom app or automation)
   ------------------------------------------------------------
   Step 0 sits above the goal picker and reuses .calc-goal so the two
   lanes read as the same control family. Lane B is a brief, not a
   basket: radios and checkboxes only, and NO totals anywhere.

   Deliberately motionless. PLAN section 2 budgets the estimator as a
   static section (header reveal only), so nothing here carries a
   [data-animate] hook or an entrance transition.
   ============================================================ */
.calc-lanes__options {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.75rem;
}

.calc-lane {
    padding: 1.15rem 1.25rem;
}

.calc-lane .calc-goal__label {
    font-size: 1rem;
}

/* The lane wrapper restores the 1.5rem the form grid used to put between
   .calc-goals and .calc-services before they were wrapped. Because it now
   sets a display, the [hidden] rule below is LOAD-BEARING: without it a
   hidden lane would still be painted. */
.calc-lane-panel {
    display: grid;
    gap: 1.5rem;
    min-width: 0;
}

.calc-lane-panel[hidden] {
    display: none;
}

.calc-custom {
    display: grid;
    gap: 1.5rem;
}

.calc-custom__intro {
    display: grid;
    justify-items: start;
    gap: 0.5rem;
}

.calc-custom__intro p {
    margin: 0;
    font-size: 0.9375rem;
    line-height: 1.55;
    color: var(--color-ink-soft);
    max-width: 62ch;
}

.calc-custom__step {
    border: 0;
    margin: 0;
    padding: 0;
    min-width: 0;
}

.calc-custom__legend {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    padding: 0;
    margin-bottom: 0.75rem;
    font-weight: 600;
}

.calc-custom__hint {
    margin: -0.35rem 0 0.75rem;
    font-size: 0.8125rem;
    color: var(--color-ink-soft);
}

.calc-custom__options {
    grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
}

/* 44px minimum tap target on every wizard control. */
.calc-custom__options .pricing-calc__radio-box {
    min-height: 2.75rem;
    justify-content: center;
}

/* The honest answer instead of a total. */
.calc-custom__panel {
    display: grid;
    gap: 1rem;
    padding: clamp(1rem, 2.5vw, 1.5rem);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-md);
    background: var(--color-surface-soft);
}

.calc-custom__panel-title {
    margin: 0;
    font-size: 1.0625rem;
}

.calc-custom__price-steps {
    display: grid;
    gap: 0.9rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.calc-custom__price-step {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-items: start;
    gap: 0.75rem;
}

.calc-custom__price-num {
    font-family: var(--font-mono);
    font-size: 0.75rem;
    letter-spacing: 0.08em;
    color: var(--color-accent-ink);
    padding-top: 0.15rem;
}

.calc-custom__price-body {
    display: grid;
    gap: 0.2rem;
    min-width: 0;
}

.calc-custom__price-body strong {
    font-size: 0.9375rem;
    color: var(--color-ink);
}

.calc-custom__price-amount {
    font-family: var(--font-mono);
    font-weight: 600;
    font-size: 0.9375rem;
    color: var(--color-ink);
}

.calc-custom__price-body p {
    margin: 0;
    font-size: 0.8125rem;
    line-height: 1.5;
    color: var(--color-ink-soft);
}

.calc-custom__readback {
    display: grid;
    gap: 0.5rem;
    padding-top: 0.9rem;
    border-top: 1px solid var(--color-border);
}

.calc-custom__readback-label {
    font-family: var(--font-mono);
    font-size: 0.6875rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--color-ink-soft);
}

.calc-custom__chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.calc-custom__chip {
    padding: 0.25rem 0.7rem;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-pill);
    background: var(--color-surface);
    font-size: 0.8125rem;
    color: var(--color-ink);
}

/* Lane B's sticky bar carries a sentence where Lane A carries numbers. */
.pricing-calc__lane-line {
    flex: 1 1 22rem;
    min-width: 0;
    margin: 0;
    font-size: 0.9375rem;
    font-weight: 600;
    line-height: 1.45;
    color: var(--color-ink);
}

@media (max-width: 560px) {
    .calc-lanes__options {
        grid-template-columns: 1fr;
    }

    /* The lane cards keep their sub-line where the goal tiles drop theirs:
       at one column there is room, and "which lane am I in" is the single
       most important thing to get right on a phone. */
    .calc-lane .calc-goal__sub {
        display: block;
    }

    .calc-custom__options {
        grid-template-columns: 1fr;
    }

    /* LOAD-BEARING. Below 560px .pricing-calc__total-inner flips to
       flex-direction: column, and in a column flex container flex-basis sizes
       the HEIGHT. The 22rem basis above is a WIDTH hint for the desktop row;
       left in place on mobile it stretched this one-line sentence into a
       352px-tall block and opened a dead gap in the bar. */
    .pricing-calc__lane-line {
        flex: 1 1 auto;
    }
}

/* ============================================================
   P5 PAGES AND DIAGRAMS (2026-08-17)
   ------------------------------------------------------------
   Five things live here:
     1. Anchor clearance for the in-page targets that style.css's
        `section[id], article[id]` rule cannot reach.
     2. .terminal-bar  - the three-dot chrome, generalised out of
        the hero blueprint so more than one card can wear it.
     3. .hub-diagram   - the /systems/ hub-and-spoke.
     4. .flow-diagram  - the custom-apps / ai-automation flow.
     5. Small support: the services bridge child links.

   THE DRAW CONTRACT (both diagrams, non-negotiable)
     The resting state is DRAWN: stroke-dashoffset 0 against a
     pathLength="1" / stroke-dasharray: 1 pair. The animation is
     the only thing that ever shows an UNdrawn line, and it lives
     inside @media (prefers-reduced-motion: no-preference). So:
       - no JS      -> .is-visible never lands -> drawn
       - no CSS anim support -> drawn
       - reduced motion      -> drawn
     That is the opposite polarity to the [data-animate] fade,
     which hides first and reveals second, and it is deliberate:
     a half-drawn diagram is misinformation, a hidden card is not.
     NEVER express this as a reduce-block override; an override
     cannot save a browser that never matched the enabling query.

   COLOUR RULE
     Strokes and node borders are granite-derived tokens. Terracotta
     appears only as GRAPHICS: the hub outline and the small node
     ticks. Every small text label uses --color-ink or the derived
     accent ink #8B584D, never display terracotta.

   NEVER add vector-effect: non-scaling-stroke to a .*__link rule.
   It makes Chromium stroke in screen space, which discards the
   pathLength normalisation and renders the line dashed (proved in
   P3 on the journey connector; same comment sits there).
   ============================================================ */

/* 1. ANCHOR CLEARANCE ---------------------------------------- */

/* js/navigation.js uses scrollIntoView since P5, so scroll-margin-top
   is now the SINGLE source of anchor clearance theme-wide. style.css
   covers section[id] and article[id]; these three in-page targets are
   none of those, so before P5 they landed under the sticky header:
     #main-content     the skip link target, a <main>
     #systems-process  the /systems/ planning-process button target, a
                       <div> wrapping the journey part (P3 note 3)
     #possibilities    a <div> on the homepage (it is a <section> on
                       /systems/, where the value is already identical)
   Same value as the global rule, on purpose: one clearance, one look. */
#main-content,
#systems-process,
#possibilities {
    scroll-margin-top: calc(var(--header-h) + 1rem);
}

/* 2. TERMINAL CHROME ----------------------------------------- */

/* The one terminal-chrome pattern, used by the hero blueprint card and the
   /systems/ brief card. Generalised in P5 from the hero's private copy;
   P6 deleted that copy and migrated the hero onto these classes, so this
   is now the single definition. Any new terminal card uses it too, and
   per-surface tweaks belong in a scoped override, never in a new copy. */
.terminal-bar {
    min-height: 3.15rem;
    display: grid;
    grid-template-columns: auto 1fr auto;
    align-items: center;
    gap: 0.8rem;
    padding-inline: 1rem;
    color: var(--brand-cream);
    background: var(--brand-granite);
    border-bottom: 1px solid var(--color-panel-raise);
}

.terminal-bar__dots {
    display: flex;
    gap: 0.3rem;
}

.terminal-bar__dots i {
    width: 0.48rem;
    height: 0.48rem;
    border-radius: 50%;
    background: var(--brand-cream);
    opacity: 0.42;
}

.terminal-bar__dots i:first-child {
    background: var(--brand-terracotta);
    opacity: 1;
}

.terminal-bar__title,
.terminal-bar__status {
    font-size: 0.6875rem;
    letter-spacing: 0.11em;
}

.terminal-bar__title {
    opacity: 0.78;
}

.terminal-bar__status {
    padding: 0.22rem 0.5rem;
    border: 1px solid rgba(242, 237, 225, 0.3);
    border-radius: var(--radius-pill);
    white-space: nowrap;
}

/* The /systems/ brief card. The card is already granite, so the bar has
   to be the RAISED granite or the chrome disappears into the body. */
.systems-page-hero__brief.brief-terminal {
    padding: 0;
    overflow: hidden; /* clips the bar into the card radius */
}

.brief-terminal .terminal-bar {
    background: var(--color-panel-raise);
    border-bottom-color: rgba(242, 237, 225, 0.16);
}

.brief-terminal__body {
    padding: clamp(1.5rem, 4vw, 2.25rem);
}

/* Re-declared: .systems-page-hero__brief > p stopped matching when the
   body wrapper went in, and the bar now supplies the top spacing the old
   margin created. */
.brief-terminal__body > p {
    margin-top: 0;
    font-size: clamp(1.25rem, 2.5vw, 1.7rem);
    line-height: 1.4;
}

/* 3. HUB AND SPOKE (/systems/) -------------------------------- */

/* The layout row is now copy | diagram, so centre them against each other
   instead of top-aligning the copy against a much taller column. */
.systems-page-connections__layout {
    align-items: center;
}

/* Full-width legend below the row. Three across on desktop; the earlier
   two-across rule and the <= 760px single-column rule both sit ABOVE this
   block in the file, so the breakpoints have to be restated here. */
.systems-page-connections__list {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    margin-top: clamp(2rem, 4.5vw, 3.25rem);
}

@media (max-width: 900px) {
    .systems-page-connections__list {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (max-width: 640px) {
    .systems-page-connections__list {
        grid-template-columns: 1fr;
    }

    .systems-page-connections__list li {
        min-height: 0;
    }
}

.hub-diagram {
    display: block;
    width: 100%;
    max-width: 34rem;
    height: auto;
    margin-inline: auto;
}

.hub-diagram__link {
    fill: none;
    stroke: var(--color-border-strong);
    stroke-width: 2;
    stroke-linecap: round;
    stroke-dasharray: 1;
    stroke-dashoffset: 0;
}

.hub-diagram__box {
    fill: var(--color-surface);
    stroke: var(--color-border);
    stroke-width: 1.5;
}

.hub-diagram__tick {
    fill: var(--brand-terracotta);
}

/* Lengths inside an SVG are USER UNITS, so 18px here is 18 viewBox
   units and scales with the diagram: about 12px on a 390px screen and
   about 19px at the 34rem cap. */
.hub-diagram__tag {
    font-family: var(--font-mono);
    font-size: 18px;
    font-weight: 500;
    letter-spacing: 0.04em;
    fill: var(--color-ink);
}

.hub-diagram__hub-box {
    fill: var(--brand-granite);
    stroke: var(--brand-terracotta);
    stroke-width: 2;
}

.hub-diagram__hub-tag {
    font-family: var(--font-mono);
    font-size: 20px;
    font-weight: 600;
    letter-spacing: 0.1em;
    fill: var(--brand-cream);
}

/* 4. FLOW DIAGRAM (custom-apps / ai-automation) ---------------- */

.service-flow {
    display: grid;
    grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
    gap: clamp(2rem, 6vw, 4.5rem);
    align-items: center;
}

.service-flow__copy h2 {
    max-width: 15em;
    margin-top: 0.85rem;
}

.service-flow__legend {
    display: grid;
    gap: 0.85rem;
    margin-top: 1.75rem;
    list-style: none;
}

.service-flow__legend li {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: 0.2rem 0.9rem;
    padding-top: 0.85rem;
    border-top: 1px solid var(--color-border);
}

.service-flow__num {
    grid-row: span 2;
    padding-top: 0.2rem;
    font-size: 0.75rem;
    letter-spacing: 0.12em;
    color: var(--color-accent-ink); /* small text: accent INK, never terracotta */
}

.service-flow__legend strong {
    font-size: 1.0625rem;
}

.service-flow__legend span.text-soft {
    font-size: 0.9375rem;
    line-height: 1.55;
}

.flow-diagram {
    display: block;
    width: 100%;
    max-width: 21rem;
    height: auto;
    margin-inline: auto;
}

.flow-diagram__link {
    fill: none;
    stroke: var(--color-border-strong);
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
    stroke-dasharray: 1;
    stroke-dashoffset: 0;
}

.flow-diagram__box {
    fill: var(--color-surface);
    stroke: var(--color-border);
    stroke-width: 1.5;
}

.flow-diagram__tick {
    fill: var(--brand-terracotta);
}

.flow-diagram__num {
    font-family: var(--font-mono);
    font-size: 13px;
    letter-spacing: 0.12em;
    fill: var(--color-accent-ink);
}

.flow-diagram__tag {
    font-family: var(--font-mono);
    font-size: 19px;
    font-weight: 500;
    letter-spacing: 0.04em;
    fill: var(--color-ink);
}

/* 5. SERVICES BRIDGE CHILD LINKS ------------------------------ */

/* Inside .section--panel. The panel sets colour by inheritance, but the
   global `a { color: var(--color-ink) }` beats inheritance, so cream has
   to be stated here or the links vanish into the granite. */
.services-systems-bridge__links {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem 1.5rem;
    margin-top: 1.1rem;
    list-style: none;
}

.services-systems-bridge__links a {
    font-size: 0.9375rem;
    color: var(--brand-cream);
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 0.25em;
}

/* THE DRAW ITSELF -------------------------------------------- */

@keyframes km-diagram-draw {
    from { stroke-dashoffset: 1; }
    to   { stroke-dashoffset: 0; }
}

/* Enabling query, not an overriding one: see the draw contract above.
   Budget: hub 275ms of stagger + 400ms = 675ms, flow 180 + 400 = 580ms,
   both inside PLAN.md section 5's 700ms ceiling, both once, both driven
   by the .is-visible class js/reveal.js already sets. */
@media (prefers-reduced-motion: no-preference) {
    [data-animate].is-visible .hub-diagram__link,
    [data-animate].is-visible .flow-diagram__link {
        animation: km-diagram-draw 400ms var(--ease) backwards;
    }

    [data-animate].is-visible .hub-diagram__link:nth-of-type(2) { animation-delay: 55ms; }
    [data-animate].is-visible .hub-diagram__link:nth-of-type(3) { animation-delay: 110ms; }
    [data-animate].is-visible .hub-diagram__link:nth-of-type(4) { animation-delay: 165ms; }
    [data-animate].is-visible .hub-diagram__link:nth-of-type(5) { animation-delay: 220ms; }
    [data-animate].is-visible .hub-diagram__link:nth-of-type(6) { animation-delay: 275ms; }

    [data-animate].is-visible .flow-diagram__link:nth-of-type(2) { animation-delay: 90ms; }
    [data-animate].is-visible .flow-diagram__link:nth-of-type(3) { animation-delay: 180ms; }
}

@media (max-width: 900px) {
    .service-flow {
        grid-template-columns: 1fr;
    }
}

/* ============================================================
   P7 SYSTEMS SECTION RESTRUCTURE (2026-08-18)
   ------------------------------------------------------------
   Milan asked for three things on the homepage Systems & Apps
   panel in the design review. What lives here:

     1. DECISION PAIR mobile behaviour. The pair is 2-up at EVERY
        width now, so the P2 mobile block's
        `.systems__decision-grid { grid-template-columns: 1fr }`
        is superseded from here by source order. The kicker
        abbreviates to "01 / IDEA" and "02 / BLUEPRINT" below
        760px by hiding .systems__decision-num-full; the full
        words stay in the DOM for desktop and for assistive tech.
        (Border and alignment changes are in place at the base
        rules, each marked "P7:".)

     2. APP-PATTERN CARD FACE: title, "View blueprint" affordance,
        hover and the granite focus ring. The face is a <button>
        inside .section--panel, and style.css turns every
        :focus-visible inside a panel CREAM, which is invisible on
        a cream card. The ring is restated here in granite.

     3. APP-PATTERN BLUEPRINT MODAL: singleton dialog rendered on
        wp_footer with all six patterns as hidden slides. Same
        geometry, z-index (200) and panel treatment as the review
        and estimator modals, so the three read as one system.

     4. BREAKPOINTS for 1 and 2, all inside this block and nowhere
        else in the file.

     5. MOTION, both polarities.

   CONTRACTS HONOURED HERE
     DRAW: .flow-diagram__link rests DRAWN (stroke-dashoffset 0,
     set once at the P5 base rule). The draw is an ENABLING
     (prefers-reduced-motion: no-preference) query keyed off
     .app-pattern-modal.is-open, reusing @keyframes
     km-diagram-draw. That keyframe is never redefined, and no
     __link rule ever gets vector-effect: non-scaling-stroke.
     MOTION BUDGET: panel rise 320ms; connector 1 draws at 120ms,
     connector 2 at 210ms, each over 400ms, so 610ms worst case,
     inside the 700ms ceiling, and each runs once per open.
     COLOUR: terracotta only as graphics (the card hover border,
     the diagram ticks). Every small accent label uses the derived
     ink var(--color-accent-ink) #8B584D, never display terracotta.
   ============================================================ */

/* 1. DECISION PAIR ------------------------------------------- */

/* Desktop keeps the full kicker; the 760px rule below hides it. */
.systems__decision-num-full {
    display: inline;
}

/* 2. APP-PATTERN CARD FACE ----------------------------------- */

/* No reserved second line here on purpose. Alignment is owned by two
   other things: the rail's `grid-auto-rows: 1fr` makes both rows the
   same height, and `margin-top: auto` on .app-pattern__view pins the
   affordance to the bottom of every card. A title that wraps therefore
   grows all six cards together and the six affordance rows stay level,
   without a permanently empty line on the five that do not wrap. */
.app-pattern__title {
    margin-top: 0.3rem;
    font-family: var(--font-sans);
    font-size: 1.0625rem;
    font-weight: 500;
    line-height: 1.25;
    color: var(--color-ink);
}

.app-pattern__view {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    margin-top: auto;
    padding-top: 1rem;
    font-size: 0.8125rem;
    font-weight: 500;
    color: var(--color-accent-ink);
}

.app-pattern {
    transition: transform 0.25s var(--ease), border-color 0.25s var(--ease), box-shadow 0.25s var(--ease);
}

.app-pattern__view svg {
    transition: transform 0.25s var(--ease);
}

.app-pattern:hover {
    transform: translateY(-2px);
    border-color: var(--brand-terracotta);
    box-shadow: var(--shadow-md);
}

.app-pattern:hover .app-pattern__view svg {
    transform: translateX(2px);
}

/* Granite ring, restated: see note 2 in the manifest above. */
.app-pattern:focus-visible {
    outline: 2px solid var(--color-focus);
    outline-offset: 2px;
}

/* 3. APP-PATTERN BLUEPRINT MODAL ----------------------------- */

/* display:flex on the class, never on an :not([hidden]) variant:
   the `[hidden] { display: none !important }` contract at the top
   of this file is what closes the dialog. */
.app-pattern-modal {
    position: fixed;
    inset: 0;
    z-index: 200;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
}

.app-pattern-modal__backdrop {
    position: absolute;
    inset: 0;
    background: rgba(47, 62, 81, 0.5);
}

.app-pattern-modal__panel {
    position: relative;
    width: min(34rem, 100%);
    max-height: calc(100dvh - 2rem);
    overflow-y: auto;
    padding: clamp(1.5rem, 4vw, 2rem);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
}

.app-pattern-modal__close {
    position: absolute;
    top: 0.9rem;
    right: 0.9rem;
    width: 2.5rem;
    height: 2.5rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    color: var(--color-ink);
    cursor: pointer;
}

/* The right padding on both keeps the copy clear of the close button. */
.app-pattern-modal__meta {
    display: block;
    padding-right: 3rem;
    font-size: 0.6875rem;
    letter-spacing: 0.11em;
    text-transform: uppercase;
    color: var(--color-accent-ink);
}

.app-pattern-modal__title {
    margin-top: 0.35rem;
    padding-right: 3rem;
    font-size: clamp(1.25rem, 3vw, 1.5rem);
    line-height: 1.2;
    color: var(--color-ink);
}

.app-pattern-modal__blurb {
    margin-top: 0.7rem;
    font-size: 0.9375rem;
    line-height: 1.6;
    color: var(--color-ink-soft);
}

.app-pattern-modal__diagram {
    margin-top: 1.35rem;
}

.app-pattern-modal__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin-top: 1.5rem;
}

/* 4. BREAKPOINTS --------------------------------------------- */

@media (max-width: 760px) {
    /* Supersedes the P2 mobile stack. Two half-width cards read as
       a pair; one full-width card above another reads as a list. */
    .systems__decision-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 0.6rem;
    }

    .systems__decision-card {
        min-height: 0;
        gap: 0.45rem;
        padding: 0.9rem;
    }

    .systems__decision-card h3 {
        font-size: 0.9375rem;
        line-height: 1.25;
    }

    .systems__decision-card p {
        font-size: 0.75rem;
        line-height: 1.5;
    }

    .systems__decision-num {
        font-size: 0.5625rem;
        letter-spacing: 0.06em;
    }

    /* "01 / IDEA", "02 / BLUEPRINT". The full kicker wraps to two
       lines in a half-width card at 390px. */
    .systems__decision-num-full {
        display: none;
    }

    .app-pattern {
        padding: 0.65rem;
    }

    /* padding-top resets the P2 mobile rule. The label stays nowrap at
       every width, which is what keeps the six titles on one baseline,
       so it has to fit a ~140px content box at 390px. The longest
       label ("Projects / people / approvals", 29 characters) is what
       sets this size: measured at 126px here, leaving ~14px of slack
       for a fallback mono face. Do not raise it without re-measuring
       that string at 390. */
    .app-pattern__meta {
        margin-top: 0.6rem;
        padding-top: 0;
        font-size: 0.4375rem;
        letter-spacing: 0.02em;
    }

    .app-pattern__title {
        font-size: 0.8125rem;
    }

    .app-pattern__view {
        padding-top: 0.7rem;
        font-size: 0.6875rem;
    }
}

/* 5. MOTION -------------------------------------------------- */

/* ENABLING query. Nothing in here is required for the dialog to be
   readable: with no CSS animation support, or under reduced motion,
   the panel is simply present and every connector is already drawn. */
@media (prefers-reduced-motion: no-preference) {
    .app-pattern-modal.is-open .app-pattern-modal__panel {
        animation: km-app-pattern-rise 320ms var(--ease) backwards;
    }

    .app-pattern-modal.is-open .flow-diagram__link {
        animation: km-diagram-draw 400ms var(--ease) 120ms backwards;
    }

    .app-pattern-modal.is-open .flow-diagram__link:nth-of-type(2) {
        animation-delay: 210ms;
    }
}

@keyframes km-app-pattern-rise {
    from { opacity: 0; transform: translateY(12px); }
    to   { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
    .app-pattern,
    .app-pattern__view svg {
        transition: none;
    }

    .app-pattern:hover {
        transform: none;
    }
}

/* ============================================================
   P8 MOBILE HORIZONTAL RAILS - .km-rail (2026-08-18)
   ------------------------------------------------------------
   DELIBERATE POLICY REVERSAL, ordered by Milan in the 2026-08-18
   design review. House rule 6 ("no horizontal mobile rails") is
   replaced: on phones, a group of many similar blocks now scrolls
   left to right instead of stacking into a long cluttered column.

   The pattern retired in P2/P3 failed because it HID content - no
   peek, a suppressed scrollbar, ~85% wide cards, and a "swipe to
   explore" label doing the job the layout should have done. This
   one carries two mandatory affordances and no instruction text:

     1. NEXT-CARD PEEK. Cards are min(78%, 300px) of the rail
        content box and the rail bleeds to the viewport edge, so
        the following card is always cut visibly. At a 390px
        device (375px layout viewport, 20px container pad) that
        is a 261.3px card and an 82.5px peek. Floor is 24px.
     2. A VISIBLE THIN SCROLLBAR. scrollbar-width + scrollbar-color
        with the legacy WebKit pseudo-elements behind them, themed
        per surface. Never suppress it.

   Scope: ONE class, five wrappers, CSS only, no JS. Everything is
   inside @media (max-width: 760px), so at 761px and above
   .km-rail is completely inert and every desktop and tablet
   layout is exactly the one that shipped in P7.

   Members (wrapper -> cards):
     .systems__rail                    -> .app-pattern           (6, granite panel)
     .services__rail                   -> .service-tile          (7, light)
     .grid-3.services-index__grid      -> .card.service-tile     (7, light)
     .process-steps                    -> .process-step          (4-5, light)
     .systems-page-possibilities__grid -> .systems-page-example   (6, granite panel)

   NOT railed, deliberately: the journey, case studies, trust
   tiles, testimonials, the systems decision pair, the proof band
   and the footer. Content-heavy cards still stack.

   CASCADE: this block is the last thing in the file bar the
   reduced-motion tail, so .km-rail (0,1,0) beats the earlier
   same-specificity display declarations on .grid-3 (style.css,
   which is always enqueued BEFORE components.css), .process-steps,
   .systems__rail, .services__rail and
   .systems-page-possibilities__grid. Do not move this block, and
   do not edit the protected .process-steps base rules to make it
   work - source order is doing that job on purpose.

   REDUCED MOTION: nothing here animates. Scrolling is entirely
   user-driven, scroll-behavior is left at its initial `auto`
   (the `smooth` on <html> does not inherit), and the reveal
   transition on the cards is the shared [data-animate-group]
   one, which the final block in this file already neutralises.
   A rail therefore needs no reduced-motion branch of its own.
   ============================================================ */

@media (max-width: 760px) {

    /* 1. THE SCROLL PORT ------------------------------------- */

    .km-rail {
        display: flex;
        flex-wrap: nowrap;
        gap: 0.7rem;

        /* Bleed to the viewport edge, then restore the gutter as
           padding. This is what turns the cut card into an obvious
           peek instead of a clipped mistake, while the first card
           still lines up with every other section on the page.
           The two values MUST stay equal or the rail leaks past
           its container and the page scrolls sideways. */
        margin-inline: calc(var(--container-pad) * -1);
        padding-inline: var(--container-pad);

        /* Top: clearance for a card's 2px granite focus ring at 2px
           offset. Bottom: clearance so the scrollbar never overlaps
           a card border. */
        padding-block: 0.55rem 0.95rem;

        overflow-x: auto;
        /* Explicit, not left to the shorthand's coercion. The shared
           reveal helper parks children at translateY(14px) until the
           group intersects, which would otherwise raise a vertical
           scrollbar inside the rail for the first ~550ms. */
        overflow-y: hidden;
        overscroll-behavior-inline: contain;
        -webkit-overflow-scrolling: touch;

        scroll-snap-type: x mandatory;
        /* Snap to the CONTENT edge, not the bled border edge, so a
           snapped card lines up with the heading above it. Must
           match padding-inline. */
        scroll-padding-inline-start: var(--container-pad);

        /* Affordance 2, light surfaces. NEVER remove: a rail with a
           hidden scrollbar is the pattern that got rails banned. */
        scrollbar-width: thin;
        scrollbar-color: rgba(47, 62, 81, 0.4) rgba(47, 62, 81, 0.12);
    }

    .km-rail::-webkit-scrollbar {
        height: 6px;
    }

    .km-rail::-webkit-scrollbar-track {
        background: rgba(47, 62, 81, 0.12);
        border-radius: 999px;
    }

    .km-rail::-webkit-scrollbar-thumb {
        background: rgba(47, 62, 81, 0.4);
        border-radius: 999px;
    }

    /* Affordance 2, granite panels: the homepage systems rail and the
       /systems/ possibilities rail. Cream alphas at the same weights. */
    .section--panel .km-rail {
        scrollbar-color: rgba(242, 237, 225, 0.45) rgba(242, 237, 225, 0.14);
    }

    .section--panel .km-rail::-webkit-scrollbar-track {
        background: rgba(242, 237, 225, 0.14);
    }

    .section--panel .km-rail::-webkit-scrollbar-thumb {
        background: rgba(242, 237, 225, 0.45);
    }

    /* 2. THE CARDS ------------------------------------------- */

    /* Affordance 1. The 300px cap keeps the peek honest on the widest
       phones in range; 78% sets it everywhere else. Note .app-pattern
       carries `width: 100%` in its base rule - this wins on source
       order, not on specificity. */
    .km-rail > * {
        flex: 0 0 auto;
        width: min(78%, 300px);
        scroll-snap-align: start;
    }

    /* 3. PER-RAIL REPAIRS ------------------------------------ */

    /* The 163px two-up app-pattern card is gone: a rail card is 261px
       at 390px, so the two values the P7 block squeezed for the old
       card come back up. The meta label stays `nowrap` (P7 trap 5);
       the longest one, "Projects / people / approvals", measured
       126px at 0.4375rem, so 0.5625rem lands near 162px inside a
       240px content box - re-measure that string if you change it. */
    .km-rail > .app-pattern {
        padding: 1rem;
    }

    .km-rail .app-pattern__meta {
        font-size: 0.5625rem;
    }

    /* The /systems/ possibilities grid draws its separators as 1px
       gaps over a tinted wrapper, clipped by overflow:hidden. That
       trick cannot survive a flex rail: the hairlines would become
       gaps and the wrapper border would box the scroll port. Below
       760px the wrapper goes transparent and each example carries
       its own border and radius instead. Desktop is untouched -
       all of this is inside the query. */
    .systems-page-possibilities__grid.km-rail {
        background: none;
        border: 0;
        border-radius: 0;
    }

    .systems-page-possibilities__grid.km-rail > .systems-page-example {
        background: var(--color-panel);
        border: 1px solid rgba(242, 237, 225, 0.18);
        border-radius: var(--radius-md);
    }
}

/* ============================================================
   P9 SERVICE-PAGE READABILITY (2026-08-18)
   ------------------------------------------------------------
   Milan's design review: the eight service pages are heavy
   reading. Four changes, all scoped to those pages:

     1. The flow diagram moved to section 2, on EVERY service,
        so a visual anchor lands before the reading starts. The
        section is otherwise unchanged - all of its styling is
        still the P5 ".flow-diagram" block above, including the
        draw contract. Only the hairline below is new: hero and
        flow are now two adjacent plain bands and needed a
        divider.
     2. The "Our approach" steps get a terracotta top border
        (echoing .service-tile--editorial) and a light-to-dark
        tint that steps left to right, so the row reads as a
        sequence instead of four identical boxes.
     3. .term-chip - a jargon explainer button with a pulsing
        terracotta dot, sitting under the hero meta list. Opens
        the plain-English dialog below.
     4. .service-design - the web-development depth block,
        rendered only when a service carries a design_approach
        array.

   SCOPE: everything approach-related is under .service-approach.
   The shared .process-steps / .process-step base rules in the
   "Process + FAQ" block are PROTECTED and untouched (STATE.md
   G7/G8 rulings) - specificity, not editing, does the work here.

   THE ≤760 RAIL still owns the approach steps on phones. This
   block's only breakpointed rule is the 5-up grid, which sits
   inside @media (min-width: 992px), well clear of the rail's
   @media (max-width: 760px). Everything else here is either
   unbreakpointed (paint, not layout) or a max-width: 900px
   stack for .service-design, which is not a rail member.

   TINTS AND AA CONTRAST. The tint is color-mix of granite over
   the surface, with a literal hex fallback declared FIRST on
   every one, matching the token convention in style.css :root.
   The progression stops at 12%: the step number chip is
   --color-accent-ink (#8B584D), which measures 4.75:1 on 12%
   granite-over-white but only 4.41:1 on 16%, i.e. below AA for
   normal text. 4-step services therefore run 0/4/8/12 and the
   one 5-step service (custom-apps) runs 0/3/6/9/12, so both end
   on the same darkest tint. Granite body text is 8.86:1 and
   --color-ink-soft is 5.13:1 at that tint.

   MOTION: the chip dot pulse - keyframes AND declaration - is
   inside a (prefers-reduced-motion: no-preference) query, so
   the dot is a plain static dot when motion is reduced. The
   dialog entrance reuses @keyframes km-app-pattern-rise from
   the P7 block rather than defining a second one.
   ============================================================ */

/* 1. FLOW SECTION AT POSITION 2 ------------------------------ */

/* Hero and flow are both plain bands now. Without this the two
   run together into one very tall block of cream. */
.service-flow-section {
    border-top: 1px solid var(--color-border);
}

/* 2. APPROACH BLOCK ------------------------------------------ */

.service-approach .process-step {
    padding: 1.15rem 1.1rem 1.25rem;
    border-top: 3px solid var(--brand-terracotta);
}

/* Sized for the narrowest case: five columns at 1440 leaves each
   card about 214px wide, and the base h3 clamp resolves to 22.4px
   there, which wraps a 19-character title. */
.service-approach .process-step h3 {
    font-size: 1.0625rem;
    line-height: 1.3;
}

.service-approach .process-step p {
    font-size: 0.875rem;
    line-height: 1.55;
}

/* Light to dark, left to right. Literal fallback first, then the
   color-mix, exactly as style.css declares its own tokens. */
.service-approach .process-steps[data-steps="4"] > .process-step:nth-child(2) {
    background: #F7F7F8;
    background: color-mix(in srgb, var(--brand-granite) 4%, var(--color-surface));
}

.service-approach .process-steps[data-steps="4"] > .process-step:nth-child(3) {
    background: #EEF0F1;
    background: color-mix(in srgb, var(--brand-granite) 8%, var(--color-surface));
}

.service-approach .process-steps[data-steps="4"] > .process-step:nth-child(4) {
    background: #E6E8EA;
    background: color-mix(in srgb, var(--brand-granite) 12%, var(--color-surface));
}

.service-approach .process-steps[data-steps="5"] > .process-step:nth-child(2) {
    background: #F9F9FA;
    background: color-mix(in srgb, var(--brand-granite) 3%, var(--color-surface));
}

.service-approach .process-steps[data-steps="5"] > .process-step:nth-child(3) {
    background: #F3F3F5;
    background: color-mix(in srgb, var(--brand-granite) 6%, var(--color-surface));
}

.service-approach .process-steps[data-steps="5"] > .process-step:nth-child(4) {
    background: #ECEEEF;
    background: color-mix(in srgb, var(--brand-granite) 9%, var(--color-surface));
}

.service-approach .process-steps[data-steps="5"] > .process-step:nth-child(5) {
    background: #E6E8EA;
    background: color-mix(in srgb, var(--brand-granite) 12%, var(--color-surface));
}

/* Five steps in one row rather than 4 + an orphan with three
   empty cells beside it. Deliberately min-width: 992px: below
   that the protected base rules keep their 2-up tablet layout,
   and below 760 the .km-rail block owns the row. */
@media (min-width: 992px) {
    .service-approach .process-steps[data-steps="5"] {
        grid-template-columns: repeat(5, minmax(0, 1fr));
        gap: 0.85rem;
    }
}

/* 3. JARGON TERM CHIPS --------------------------------------- */

.term-chips {
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-top: -0.15rem;
}

.term-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    min-height: 2.25rem;
    padding: 0.4rem 0.85rem;
    font-family: var(--font-mono);
    font-size: 0.75rem;
    letter-spacing: 0.04em;
    color: var(--color-ink-soft);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-pill);
    cursor: pointer;
    transition: border-color 0.2s var(--ease), color 0.2s var(--ease);
}

.term-chip:hover {
    color: var(--color-ink);
    border-color: var(--color-border-strong);
}

.term-chip:focus-visible {
    outline: 2px solid var(--color-focus);
    outline-offset: 2px;
}

/* A 6px graphic, so terracotta itself is correct here: the brand
   lock reserves #C86A4A for display-size text and graphics, and
   restricts SMALL TEXT to --color-accent-ink, which is what the
   label beside it inherits. */
.term-chip__dot {
    flex: 0 0 auto;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--brand-terracotta);
}

/* ENABLING query: with reduced motion, or no animation support,
   the dot is simply a dot. Small amplitude on purpose - this
   loops, and a loop that draws the eye is a loop that annoys. */
@media (prefers-reduced-motion: no-preference) {
    @keyframes km-term-pulse {
        0%, 100% { opacity: 1; transform: scale(1); }
        50%      { opacity: 0.45; transform: scale(0.7); }
    }

    .term-chip__dot {
        animation: km-term-pulse 2.4s var(--ease) infinite;
    }
}

@media (prefers-reduced-motion: reduce) {
    .term-chip {
        transition: none;
    }
}

/* 4. WEB-DEVELOPMENT DESIGN-APPROACH BLOCK ------------------- */

/* Compact band. Its bottom hairline is dropped because
   .service-scope directly below is also .section--soft and
   supplies the divider; two would render as one 2px rule. */
.service-design {
    padding-block: clamp(2.5rem, 5vw, 4rem);
    border-bottom: 0;
}

.service-design__inner {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: clamp(1.75rem, 5vw, 3.5rem);
    align-items: start;
}

.service-design__lede {
    max-width: 34em;
    margin-top: 0.85rem;
    font-size: 1.0625rem;
    line-height: 1.65;
    color: var(--color-ink-soft);
}

.service-design__points {
    display: grid;
    gap: 0.85rem;
    list-style: none;
}

.service-design__points li {
    display: grid;
    gap: 0.3rem;
    padding-top: 0.85rem;
    border-top: 1px solid var(--color-border);
}

.service-design__label {
    font-size: 0.6875rem;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--color-accent-ink);
}

.service-design__points span.text-soft {
    font-size: 0.9375rem;
    line-height: 1.55;
}

@media (max-width: 900px) {
    .service-design__inner {
        grid-template-columns: 1fr;
    }
}

/* 5. PLAIN-ENGLISH TERM MODAL -------------------------------- */

/* display:flex on the class, never on an :not([hidden]) variant:
   the `[hidden] { display: none !important }` contract at the top
   of this file is what closes the dialog. Same as P7. */
.term-modal {
    position: fixed;
    inset: 0;
    z-index: 200;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
}

.term-modal__backdrop {
    position: absolute;
    inset: 0;
    background: rgba(47, 62, 81, 0.5);
}

.term-modal__panel {
    position: relative;
    width: min(30rem, 100%);
    max-height: calc(100dvh - 2rem);
    overflow-y: auto;
    padding: clamp(1.5rem, 4vw, 2rem);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
}

.term-modal__close {
    position: absolute;
    top: 0.9rem;
    right: 0.9rem;
    width: 2.5rem;
    height: 2.5rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    color: var(--color-ink);
    cursor: pointer;
}

/* The right padding on both keeps the copy clear of the close button. */
.term-modal__meta {
    display: block;
    padding-right: 3rem;
    font-size: 0.6875rem;
    letter-spacing: 0.11em;
    text-transform: uppercase;
    color: var(--color-accent-ink);
}

.term-modal__title {
    margin-top: 0.35rem;
    padding-right: 3rem;
    font-size: clamp(1.25rem, 3vw, 1.5rem);
    line-height: 1.2;
    color: var(--color-ink);
}

.term-modal__definition {
    margin-top: 0.8rem;
    font-size: 0.9375rem;
    line-height: 1.65;
    color: var(--color-ink-soft);
}

.term-modal__why {
    margin-top: 1rem;
    padding: 0.85rem 1rem;
    font-size: 0.9375rem;
    line-height: 1.6;
    color: var(--color-ink);
    background: #F9F7F2;
    background: var(--color-surface-soft);
    border-left: 3px solid var(--brand-terracotta);
    border-radius: var(--radius-sm);
}

.term-modal__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin-top: 1.4rem;
}

/* ENABLING query, reusing the P7 keyframe. Nothing in here is
   required for the dialog to be readable. */
@media (prefers-reduced-motion: no-preference) {
    .term-modal.is-open .term-modal__panel {
        animation: km-app-pattern-rise 320ms var(--ease) backwards;
    }
}

/* ============================================================
   P10 - Straight answers (2026-08-18)
   ============================================================
   The .faq component itself is complete and untouched (46rem column,
   native details/summary, chevron rotation on [open]). All this block
   does is give the three NEW standalone FAQ sections a divider, because
   a plain .section carries no border of its own and the FAQ would
   otherwise merge into the band above it - the same problem P9 solved
   for .service-flow-section.

   The suppression rule matters: .section--soft already paints a
   border-block, and .section--panel is a dark band whose own edge is the
   divider. A hairline drawn 1px below either of those reads as a stray
   second rule, which is the doubled-border artefact P9 recorded on the
   web-development page. Order of surfaces:
     service pages      approach (plain) -> FAQ (soft) -> CTA (plain)
     custom-apps/AI     systems note (soft) -> FAQ (soft, top suppressed)
     /systems/          choice (plain) -> FAQ (hairline) -> CTA (soft)
     /services/         bridge (panel) -> FAQ (top suppressed) -> CTA (soft)
   The homepage work FAQ is INSIDE section-case-studies and needs nothing
   here; its spacing comes from the component's own margin-top. */
.km-faq-section {
    border-top: 1px solid var(--color-border);
}

.section--soft + .km-faq-section,
.section--panel + .km-faq-section {
    border-top: 0;
}

/* Keep this block LAST: it must override the mobile degrade above. */
@media (prefers-reduced-motion: reduce) {
    [data-animate="slide-left"],
    [data-animate="slide-right"] {
        opacity: 1;
        transform: none;
        transition: none;
    }
}

/* ============================================================
   P11 SEO + CONVERSION PASS (2026-08-18)
   1) .service-related - catalogue-driven cross-links on service pages
      (the eight pages previously had no links between each other).
   2) Blog index migrated to the brand-locked system: the pre-P11
      classes below had NO rules in either stylesheet (filter pills,
      empty state, placeholder grid, card meta, single-post pills).
   ============================================================ */
.service-related__links {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 1rem;
}

.service-related__link {
    display: grid;
    gap: 0.4rem;
    align-content: start;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    padding: 1.15rem 1.3rem;
    text-decoration: none;
    transition: border-color 200ms var(--ease), box-shadow 200ms var(--ease);
}

.service-related__link:hover {
    border-color: var(--color-border-strong);
    box-shadow: var(--shadow-sm);
}

.service-related__name {
    font-weight: 600;
    color: var(--color-ink);
}

.service-related__outcome {
    font-size: 0.875rem;
    line-height: 1.55;
    color: var(--color-ink-soft);
}

@media (max-width: 760px) {
    .service-related__links {
        grid-template-columns: 1fr;
    }
}

.blog-filter-bar {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-bottom: 1.75rem;
}

.blog-filter-pill {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    padding: 0.45rem 0.9rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-pill);
    background: var(--color-surface);
    color: var(--color-ink);
    font-family: var(--font-mono);
    font-size: 0.75rem;
    letter-spacing: 0.04em;
    cursor: pointer;
    transition: border-color 200ms var(--ease), background 200ms var(--ease);
}

.blog-filter-pill:hover {
    border-color: var(--color-border-strong);
}

.blog-filter-pill--active {
    background: var(--color-panel);
    border-color: var(--color-panel);
    color: var(--color-inverse);
}

.blog-filter-pill__count {
    font-size: 0.6875rem;
    opacity: 0.75;
}

.blog-card__meta {
    display: flex;
    gap: 0.4rem;
    font-family: var(--font-mono);
    font-size: 0.75rem;
    color: var(--color-ink-soft);
    margin-top: 0.35rem;
}

.blog-card__categories {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-bottom: 0.85rem;
}

.blog-empty-state {
    text-align: center;
    padding: 3rem 1rem;
    color: var(--color-ink-soft);
}

.blog-placeholder-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 1rem;
    margin-top: 2rem;
}

.blog-card--placeholder {
    pointer-events: none;
}

.blog-card__image--placeholder {
    aspect-ratio: 16 / 9;
    background: var(--color-surface-soft);
    border-bottom: 1px solid var(--color-border);
}

.blog-card__excerpt--placeholder {
    opacity: 0.7;
}

@media (max-width: 900px) {
    .blog-placeholder-grid {
        grid-template-columns: 1fr;
    }
}

/* P11: closing CTA rows for the two homepage sections that ended cold
   (commercials/FAQ and the case-study grid), plus the enquire page's
   talk-instead escape hatch. */
.process-cta,
.work-cta {
    margin-top: 2.5rem;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 1rem 1.5rem;
    border-top: 1px solid var(--color-border);
    padding-top: 1.75rem;
}

.process-cta p,
.work-cta p {
    margin: 0;
    font-weight: 500;
}

.work-cta__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
}

.enquire-page__alt {
    margin-top: 1.25rem;
    text-align: center;
}

.enquire-page__alt a {
    color: inherit;
    text-decoration: underline;
}

/* P11: landing-page template additions - top bar, offer body, trust strip,
   framed form. The template is a standalone document (no site chrome). */
.landing-topbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 1rem var(--container-pad);
    border-bottom: 1px solid var(--color-border);
}

/* .landing-topbar__brand was declared here in P11 for a text brand
   (font-weight/letter-spacing) and AGAIN in the P12 block below. Since P13 the
   brand is a single <img> of the full lockup, so the typographic properties are
   dead and the duplicate is gone - the one surviving rule is in the P13 block. */

.landing-topbar__phone {
    font-family: var(--font-mono);
    font-size: 0.875rem;
    color: var(--color-ink);
    text-decoration: none;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-pill);
    padding: 0.4rem 0.9rem;
}

.landing-topbar__phone:hover {
    border-color: var(--color-border-strong);
}

.landing-hero__cta {
    margin-top: 1.5rem;
}

.landing-body {
    max-width: 44rem;
    margin-inline: auto;
    padding: 0 var(--container-pad) 2rem;
}

.landing-content {
    margin-bottom: 2rem;
}

.landing-trust {
    list-style: none;
    display: grid;
    gap: 0.6rem;
    margin: 0 0 2rem;
    padding: 1.1rem 1.35rem;
    background: var(--color-surface-soft);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    font-size: 0.9375rem;
}

.landing-trust li {
    position: relative;
    padding-left: 1.4rem;
}

.landing-trust li::before {
    content: "";
    position: absolute;
    left: 0;
    top: 0.45em;
    width: 0.55rem;
    height: 0.55rem;
    border-radius: 50%;
    background: var(--color-accent);
}

.landing-form__title {
    font-size: 1.35rem;
    margin-bottom: 1.25rem;
}

.landing-footnote a {
    color: inherit;
}


/* ══════════════════════════════════════════════════════════════════════════
   P12  GOOGLE ADS LANDING PAGES  (2026-08-19)
   ══════════════════════════════════════════════════════════════════════════
   Both Ads landing pages rendered their offer copy inside
   .landing-content.post-content - the blog prose class - so they read as
   articles. The sections now come from inc/landing-data.php through
   template-parts/landing-sections.php and reuse the existing components
   (.card, .grid-3, .process-steps.km-rail, .flow-diagram,
   .systems__decision-card, .chip, .faq, .work-cta). Only the pieces below
   are genuinely new.

   RULES FOR THIS BLOCK
   1. Never declare `display` on an element that also carries .km-rail. The
      km-rail block sits earlier in this file; a later same-specificity
      display would silently undo the mobile rail.
   2. No texture classes on the hero, on forms, on FAQ or on legal copy.
   3. Terracotta on text ONLY at display size (>= 24px). Small accent text
      uses --color-accent-ink. Bars, ticks and rules are non-text graphics
      and may use --color-accent directly.
   4. Motion follows the km-diagram-draw polarity: the RESTING state is the
      finished state (bars at full height), and the animation is declared
      only inside `prefers-reduced-motion: no-preference`. A browser with no
      JS, no IntersectionObserver or reduced motion shows finished bars.
   ────────────────────────────────────────────────────────────────────── */

/* Tighter band for the mid-page CTAs, which sit between two full sections
   and would otherwise stack three lots of --section-pad in a row. */
.section--tight {
    padding-block: clamp(2rem, 4.5vw, 3.25rem);
}

/* ── Real logo in the landing topbar ─────────────────────────────────── */

/* The full km-logo.svg lockup (P13), same height as the site header's
   .site-logo__img so the two bars agree. Width comes from the img's own
   863.5:318.6 ratio - never set one here or the mark distorts. */
.landing-topbar__brand {
    display: inline-flex;
    align-items: center;
    color: var(--color-ink);
}

.landing-topbar__logo {
    height: 3rem;
    width: auto;
}

/* The topbar is one flex row: lockup left, phone pill right, nothing wraps.
   Before P13 no breakpoint touched this bar at all. */
@media (max-width: 430px) {
    .landing-topbar {
        gap: 0.6rem;
        padding-inline: 1rem;
    }

    .landing-topbar__phone {
        font-size: 0.8125rem;
        padding: 0.35rem 0.7rem;
    }
}

/* The mark shrinks ONLY on the smallest phones still in service, and this is a
   measured floor rather than a round number. At a 305px layout viewport the
   full 3rem lockup leaves 10px between itself and the phone pill and pushes the
   bar to 89px tall; 2.6rem restores 19px and a 75px bar. The cost is the small
   line dropping from a 7.05px cap to 6.11px, which is why the rule starts here
   and not at the 430px the rest of this bar uses - every phone from 361px up
   keeps the full-size mark. */
@media (max-width: 360px) {
    .landing-topbar__logo {
        height: 2.6rem;
    }
}

/* ── Hero additions ──────────────────────────────────────────────────── */

.lp-hero-chips {
    list-style: none;
    margin: 1.5rem 0 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.5rem;
}

.landing-hero__actions {
    margin-top: 1.75rem;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.75rem;
}

.landing-hero__actions .landing-hero__cta {
    margin-top: 0;
}

/* ── Benefit / pain cards ────────────────────────────────────────────── */

.lp-benefit__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.75rem;
    height: 2.75rem;
    margin-bottom: 1rem;
    border-radius: var(--radius-md);
    background: var(--color-accent-soft);
    color: var(--color-accent-ink);
}

.lp-benefit h3 {
    font-size: 1.0625rem;
    margin-bottom: 0.5rem;
}

.lp-chip-row {
    list-style: none;
    margin: 1.75rem 0 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.5rem;
}

/* ── Price cards (replaces the table whose price column fell off at 390px) */

.lp-price-card {
    display: flex;
    flex-direction: column;
}

.lp-price-card--highlight {
    border-color: var(--color-border-strong);
    box-shadow: var(--shadow-md);
}

.lp-price-card__name {
    font-size: 1rem;
    font-weight: 500;
    color: var(--color-ink-soft);
    margin-bottom: 0.5rem;
}

.lp-price-card__amount {
    /* Display size, so terracotta is legal here (rule 3 above). */
    font-size: clamp(1.9rem, 3.4vw, 2.5rem);
    line-height: 1.1;
    font-weight: 600;
    color: var(--color-accent);
    margin: 0 0 0.75rem;
}

.lp-price-card__amount--quote {
    color: var(--color-ink-soft);
}

.lp-price-card__unit {
    display: block;
    margin-top: 0.35rem;
    font-size: 0.75rem;
    font-weight: 500;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--color-ink-soft);
}

.lp-price-note {
    margin-top: 1.75rem;
    text-align: center;
    max-width: 46rem;
    margin-inline: auto;
}

/* ── Live-build proof grid ───────────────────────────────────────────── */

.lp-build {
    display: flex;
    flex-direction: column;
    overflow: hidden;
    text-decoration: none;
    color: inherit;
}

.lp-build__shot {
    display: block;
    aspect-ratio: 16 / 10;
    overflow: hidden;
    background: var(--color-surface-soft);
}

.lp-build__shot img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: top;
    display: block;
}

.lp-build__meta {
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    padding: 1rem 1.15rem 1.15rem;
}

.lp-build__client {
    font-weight: 500;
}

.lp-build__industry {
    font-size: 0.75rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

/* ── Search-impressions bar chart ────────────────────────────────────── */

.lp-graph-wrap {
    max-width: 46rem;
    margin-inline: auto;
    text-align: center;
}

.lp-graph {
    display: flex;
    align-items: flex-end;
    justify-content: center;
    gap: clamp(1.5rem, 6vw, 3.5rem);
    margin-bottom: 0.85rem;
}

.lp-graph__col {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.5rem;
    width: clamp(4.5rem, 18vw, 7rem);
}

.lp-graph__value {
    font-size: 0.9375rem;
    font-weight: 600;
    color: var(--color-ink);
}

.lp-graph__track {
    width: 100%;
    height: clamp(7rem, 22vw, 10rem);
    display: flex;
    align-items: flex-end;
}

.lp-graph__bar {
    width: 100%;
    /* Non-text graphic: terracotta is allowed at any size. */
    background: var(--color-accent);
    border-radius: var(--radius-sm) var(--radius-sm) 0 0;
    min-height: 4px;
}

.lp-graph__label {
    font-size: 0.75rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--color-ink-soft);
}

.lp-graph__caption {
    margin-bottom: 1.5rem;
}

.lp-graph__stats {
    justify-content: center;
    margin-bottom: 1rem;
    text-align: left;
}

/* Resting state is the FINISHED state; the growth is additive and only
   exists where motion is welcome (rule 4). */
@media (prefers-reduced-motion: no-preference) {
    @keyframes lp-bar-grow {
        from { transform: scaleY(0); }
        to   { transform: scaleY(1); }
    }

    [data-animate].is-visible .lp-graph__bar {
        transform-origin: bottom;
        animation: lp-bar-grow 0.7s var(--ease) backwards;
    }

    [data-animate].is-visible .lp-graph__col:nth-child(2) .lp-graph__bar {
        animation-delay: 0.14s;
    }
}

/* ── Inline testimonials ─────────────────────────────────────────────── */

.lp-quote {
    display: flex;
    flex-direction: column;
    gap: 0.9rem;
    margin: 0;
}

.lp-quote__stars {
    display: flex;
    gap: 0.15rem;
    color: var(--color-accent);
}

.lp-quote__text {
    margin: 0;
    font-size: 1.0625rem;
    line-height: 1.6;
}

.lp-quote__meta {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-top: auto;
    padding-top: 0.9rem;
    border-top: 1px solid var(--color-border);
}

.lp-quote__author {
    display: block;
    font-weight: 500;
    font-size: 0.9375rem;
}

.lp-quote__role {
    display: block;
    font-size: 0.8125rem;
}

.lp-quote__badge {
    flex: 0 0 auto;
    font-family: var(--font-mono);
    font-size: 0.6875rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--color-ink-soft);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-pill);
    padding: 0.25rem 0.6rem;
}

/* ── Granite decision band ───────────────────────────────────────────── */

.lp-decision__proof {
    margin-top: clamp(2rem, 5vw, 3rem);
}

/* ── Discovery fee card ──────────────────────────────────────────────── */

.lp-discovery {
    display: grid;
    grid-template-columns: 1.15fr 1fr;
    gap: clamp(1.5rem, 4vw, 3rem);
    align-items: start;
    max-width: 58rem;
    margin-inline: auto;
}

.lp-discovery h2 {
    font-size: clamp(1.5rem, 3vw, 2rem);
    margin-bottom: 0.75rem;
}

.lp-discovery__list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 0.85rem;
}

.lp-discovery__list li {
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    font-size: 0.9375rem;
    line-height: 1.55;
}

.lp-discovery__list svg {
    flex: 0 0 auto;
    margin-top: 0.15rem;
    color: var(--color-accent);
}

@media (max-width: 760px) {
    .lp-discovery {
        grid-template-columns: 1fr;
    }
}

/* ── Sticky mobile CTA bar ───────────────────────────────────────────── */

.lp-sticky-cta {
    position: fixed;
    inset-inline: 0;
    bottom: 0;
    /* Above page content, below the modals (which sit at 200). */
    z-index: 90;
    display: none;
    gap: 0.6rem;
    padding: 0.7rem var(--container-pad);
    padding-bottom: calc(0.7rem + env(safe-area-inset-bottom, 0px));
    background: var(--color-panel);
    border-top: 1px solid rgba(242, 237, 225, 0.18);
    opacity: 0;
    transform: translateY(100%);
    transition: opacity var(--speed) var(--ease), transform var(--speed) var(--ease);
}

.lp-sticky-cta .btn {
    flex: 1 1 0;
    justify-content: center;
    white-space: nowrap;
}

/* The bar is a granite surface, so the buttons take the same inversion the
   panel sections use (style.css). Cream fill on granite reads 9.3:1. */
.lp-sticky-cta .btn--primary {
    background: var(--color-inverse);
    color: var(--color-ink);
    border-color: var(--color-inverse);
}

.lp-sticky-cta .btn--primary:hover {
    background: #FFFFFF;
    border-color: #FFFFFF;
}

.lp-sticky-cta .btn--outline {
    color: var(--color-inverse);
    border-color: rgba(242, 237, 225, 0.45);
}

.lp-sticky-cta .btn--outline:hover {
    background: rgba(242, 237, 225, 0.12);
    border-color: var(--color-inverse);
}

@media (max-width: 760px) {
    .lp-sticky-cta {
        display: flex;
    }

    .lp-sticky-cta.is-shown {
        opacity: 1;
        transform: none;
    }

    /* Nothing may sit permanently behind the bar: the footnote reserves the
       space even in the moment before the observer hides it again. */
    body.landing-page .landing-footnote {
        padding-bottom: 5.5rem;
    }
}


/* ============================================================
   P13 - POP-UPS, PROOF CARDS AND THE MOBILE SHEET (2026-08-19)
   ------------------------------------------------------------
   Three things live here:

   1. .km-modal, the generic dialog driven by js/km-modal.js. Same geometry,
      backdrop and close button as the five hand-copied dialogs that came
      before it, so every dialog on the site still looks identical.

   2. The two dialogs built on it - .build-modal and .price-modal - and the
      cards that open them.

   3. THE MOBILE SHEET. Until P13 not one of the six dialogs had a single
      @media rule: a phone got a centred desktop panel with 1rem of margin.
      Below 760px every panel is now a bottom sheet.

   RULES THIS BLOCK KEEPS
   - display goes on the BARE class, never on :not([hidden]). The
     [hidden] { display: none !important } contract at the top of this file is
     what closes a dialog.
   - Nothing here declares display or grid-template-columns on an element that
     carries .km-rail. The rail block at ~4972 wins on source order alone and
     this block sits after it.
   - Entrance animation lives inside prefers-reduced-motion: no-preference.
   ============================================================ */

/* ---- Generic dialog ------------------------------------------------- */

.km-modal {
    position: fixed;
    inset: 0;
    z-index: 200;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
}

.km-modal__backdrop {
    position: absolute;
    inset: 0;
    background: rgba(47, 62, 81, 0.5);
}

.km-modal__panel {
    position: relative;
    width: min(38rem, 100%);
    max-height: calc(100dvh - 2rem);
    overflow-y: auto;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-md);
    padding: clamp(1.5rem, 4vw, 2rem);
}

.km-modal__close {
    position: absolute;
    top: 0.9rem;
    right: 0.9rem;
    z-index: 1;
    width: 2.5rem;
    height: 2.5rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    color: var(--color-ink);
    cursor: pointer;
}

.km-modal__close:hover {
    border-color: var(--color-border-strong);
}

.km-modal__slide {
    display: grid;
    gap: 0.9rem;
}

/* ---- Build dialog --------------------------------------------------- */

.build-modal__kicker,
.price-modal__kicker {
    font-size: 0.6875rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--color-ink-soft);
    padding-right: 3rem; /* clear the close button */
}

.build-modal__title,
.price-modal__title {
    font-size: clamp(1.35rem, 3vw, 1.7rem);
    line-height: 1.2;
    margin: 0;
}

.build-modal__shot {
    display: block;
    overflow: hidden;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
}

.build-modal__shot img {
    display: block;
    width: 100%;
    height: auto;
}

.build-modal__built {
    color: var(--color-ink-soft);
    line-height: 1.65;
    margin: 0;
}

.build-modal__features {
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin: 0;
    padding: 0;
}

.build-modal__stats {
    margin-top: 0.25rem;
}

.build-modal__source {
    margin: 0;
}

.build-modal__actions,
.price-modal__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem;
    margin-top: 0.35rem;
}

/* ---- Price dialog --------------------------------------------------- */

.price-modal__amount {
    font-size: clamp(1.75rem, 5vw, 2.25rem);
    font-weight: 600;
    color: var(--color-accent);
    line-height: 1;
    margin: 0;
}

.price-modal__unit {
    display: inline-block;
    margin-left: 0.5rem;
    font-size: 0.8125rem;
    font-weight: 400;
    color: var(--color-ink-soft);
}

.price-modal__detail {
    color: var(--color-ink-soft);
    line-height: 1.65;
    margin: 0;
}

.price-modal__sub {
    font-size: 0.6875rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--color-ink-soft);
    margin: 0.35rem 0 0;
}

.price-modal__includes {
    list-style: none;
    display: grid;
    gap: 0.5rem;
    margin: 0;
    padding: 0;
}

.price-modal__includes li {
    display: flex;
    align-items: flex-start;
    gap: 0.55rem;
    line-height: 1.55;
}

.price-modal__includes svg {
    flex: 0 0 auto;
    margin-top: 0.2rem;
    color: var(--color-accent);
}

.price-modal__fineprint {
    margin: 0;
    line-height: 1.6;
}

/* ---- Build card as a trigger ---------------------------------------- */

/* Was a whole-card outbound <a>; it is a <button> since P13, so it needs the
   same reset .app-pattern uses. */
.lp-build {
    width: 100%;
    font: inherit;
    text-align: left;
    cursor: pointer;
    padding: 0;
}

.lp-build__cue {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    margin-top: 0.5rem;
    font-size: 0.8125rem;
    font-weight: 500;
    color: var(--color-accent-ink);
}

.lp-build__cue svg {
    transition: transform 0.2s var(--ease);
}

.lp-build:hover .lp-build__cue svg,
.lp-build:focus-visible .lp-build__cue svg {
    transform: translateX(2px);
}

/* Five cards in a three-column grid leave a hole in the second row. Flex
   centres the remainder instead, so the block reads deliberate. */
.lp-builds-grid {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 1.25rem;
}

/* Exactly one third of the row minus the two gaps, and NOT allowed to grow.
   Letting the last row's two cards stretch made them 382px against the 363px
   of the three above - the hole was gone but the row still did not line up. */
.lp-builds-grid > * {
    flex: 0 1 calc((100% - 2.5rem) / 3);
    min-width: 15rem;
}

/* ---- Price card as a trigger ---------------------------------------- */

.lp-price-card {
    position: relative;
    display: flex;
    flex-direction: column;
}

/* Pins the cue to the bottom of a stretched card so all three line up
   regardless of how long the note above it runs. */
.lp-price-card__cue {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    margin-top: auto;
    padding: 0.75rem 0 0;
    background: none;
    border: 0;
    font: inherit;
    font-size: 0.8125rem;
    font-weight: 500;
    color: var(--color-accent-ink);
    text-align: left;
    cursor: pointer;
}

/* Stretched hit area: the whole card is clickable, the button stays the only
   focusable control and keeps its own accessible name. */
.lp-price-card__cue::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
}

.lp-price-card__cue svg {
    transition: transform 0.2s var(--ease);
}

.lp-price-card:hover .lp-price-card__cue svg,
.lp-price-card__cue:focus-visible svg {
    transform: translateX(2px);
}

/* ---- Case cards: pin the trailing link ------------------------------ */

/* The grid stretches every card in a row to the tallest, but the content did
   not stretch with it: the Celsa card ran 739px tall carrying 254px of body,
   leaving its "Visit the live site" link floating 167px above the bottom
   while its neighbour's sat at 29px. Pinning the tail fixes the row. */
/* stretch, not flex-start: .case-card__stats is a grid that must keep the
   full body width. flex: 1 is what makes the pin below work at all - the card
   is already a flex column, but without the body GROWING to fill it there is
   no free space for margin-top: auto to consume, and the trailing row just
   sits under the copy exactly where it did before. */
.case-card__body {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
}

/* The pin lives on the row, not on either control inside it, so both cards in
   a stretched grid row end on the same line however long the copy above runs. */
.case-card__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 1rem;
    margin-top: auto;
    padding-top: 0.9rem;
}

.case-card__cue {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0;
    background: none;
    border: 0;
    font: inherit;
    font-size: 0.875rem;
    font-weight: 500;
    color: var(--color-accent-ink);
    cursor: pointer;
}

.case-card__cue svg {
    transition: transform 0.2s var(--ease);
}

.case-card__cue:hover svg,
.case-card__cue:focus-visible svg {
    transform: translateX(2px);
}

/* ---- Recent-builds card as a trigger -------------------------------- */

.recent-builds__item {
    width: 100%;
    font: inherit;
    text-align: left;
    cursor: pointer;
    padding: 0;
}

.recent-builds__cue {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    margin-top: 0.35rem;
    font-size: 0.75rem;
    font-weight: 500;
    color: var(--color-accent-ink);
}

.recent-builds__cue svg {
    transition: transform 0.2s var(--ease);
}

.recent-builds__item:hover .recent-builds__cue svg,
.recent-builds__item:focus-visible .recent-builds__cue svg {
    transform: translateX(2px);
}

/* ---- The founder dialog's missing entrance -------------------------- */

/* js/founder-modal.js forces a reflow and adds .is-open for a "CSS-only
   entrance animation" whose rule was never written, so the dialog appeared
   instantly and the reflow was dead code. This is the missing half. */
@media (prefers-reduced-motion: no-preference) {
    .km-modal.is-open .km-modal__panel,
    .founder-modal.is-open .founder-modal__panel {
        animation: km-modal-rise 0.28s var(--ease) backwards;
    }

    @keyframes km-modal-rise {
        from { opacity: 0; transform: translateY(10px); }
        to   { opacity: 1; transform: translateY(0); }
    }
}

/* ---- Landing proof grid on phones ----------------------------------- */

@media (max-width: 760px) {
    .lp-builds-grid > * {
        flex: 1 1 100%;
        max-width: none;
    }
}

/* ---- THE MOBILE SHEET ----------------------------------------------- */

/* Every dialog in the theme, including the five that predate the engine.
   Until P13 not one of the six carried a single @media rule: a phone got a
   centred desktop panel with 1rem of margin, which on a 360px screen meant a
   313px box holding more than twice its own height with the close button
   scrolled out of reach.

   Below 560px each one is a bottom sheet: full width, pinned to the bottom,
   rounded on top only, clear of the home indicator, and capped at 88dvh so a
   tappable strip of backdrop always remains above it - that strip is the
   dismissal affordance a sheet is expected to have. 560px, not 760px: the
   panel is only 38rem wide, so a tablet is better served by the centred
   shape it already has. */
@media (max-width: 560px) {
    .km-modal,
    .review-modal,
    .calc-info-modal,
    .founder-modal,
    .app-pattern-modal,
    .term-modal {
        align-items: flex-end;
        padding: 0;
    }

    .km-modal__panel,
    .review-modal__panel,
    .calc-info-modal__panel,
    .founder-modal__panel,
    .app-pattern-modal__panel,
    .term-modal__panel {
        width: 100%;
        max-height: 88dvh;
        border-radius: var(--radius-lg) var(--radius-lg) 0 0;
        border-bottom: 0;
        padding-bottom: max(1.5rem, env(safe-area-inset-bottom));
    }

    /* The grab handle: what tells a thumb this thing scrolls and can be
       flicked away. Decorative, so it is drawn rather than marked up. */
    .km-modal__panel::before,
    .review-modal__panel::before,
    .calc-info-modal__panel::before,
    .founder-modal__panel::before,
    .app-pattern-modal__panel::before,
    .term-modal__panel::before {
        content: '';
        display: block;
        width: 2.5rem;
        height: 4px;
        margin: -0.4rem auto 0.9rem;
        border-radius: 999px;
        background: var(--color-border-strong);
    }

    /* A phone-sized target. */
    .km-modal__close,
    .review-modal__close,
    .calc-info-modal__close,
    .founder-modal__close,
    .app-pattern-modal__close,
    .term-modal__close {
        top: 0.7rem;
        right: 0.7rem;
        width: 2.75rem;
        height: 2.75rem;
    }

    .build-modal__actions .btn,
    .price-modal__actions .btn {
        flex: 1 1 100%;
        justify-content: center;
    }
}

@media (max-width: 560px) and (prefers-reduced-motion: no-preference) {
    .km-modal.is-open .km-modal__panel {
        animation: km-sheet-rise 0.3s var(--ease) backwards;
    }

    @keyframes km-sheet-rise {
        from { transform: translateY(12%); }
        to   { transform: translateY(0); }
    }
}


/* ============================================================
   P13 - NAVIGATION, BREADCRUMBS AND THE THIN ROUTES (2026-08-19)
   ------------------------------------------------------------
   Styles for the surfaces P13 added: the visible breadcrumb that finally
   matches the BreadcrumbList schema, the 404's new conversion block, the
   related-posts module under a post, and the search empty state.
   ============================================================ */

/* ---- Breadcrumbs ---------------------------------------------------- */

/* Sits above the page heading inside the hero container, so it needs to read
   as navigation furniture rather than content: mono, small, muted. */
.breadcrumbs {
    margin-bottom: 1.1rem;
}

.breadcrumbs__list {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.35rem;
    margin: 0;
    padding: 0;
    list-style: none;
    font-family: var(--font-mono);
    font-size: 0.75rem;
    letter-spacing: 0.02em;
    color: var(--color-ink-soft);
}

.breadcrumbs__item {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
}

.breadcrumbs__item a {
    color: var(--color-ink-soft);
    text-decoration: none;
    border-bottom: 1px solid transparent;
}

.breadcrumbs__item a:hover {
    color: var(--color-ink);
    border-bottom-color: var(--color-accent);
}

.breadcrumbs__item [aria-current="page"] {
    color: var(--color-ink);
}

.breadcrumbs__sep {
    flex: 0 0 auto;
    color: var(--color-border-strong);
}

/* The current page can be a long service name; let it wrap rather than
   pushing the row sideways on a phone. */
@media (max-width: 560px) {
    .breadcrumbs__list {
        font-size: 0.6875rem;
    }
}

/* ---- 404 ------------------------------------------------------------ */

/* This route had one button and no way to reach a human. */
.error-404__actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.75rem;
    margin-top: 1.5rem;
}

.error-404__wayfinding {
    margin-top: 1.5rem;
}

.error-404__wayfinding a {
    color: var(--color-accent-ink);
}

/* ---- Related posts -------------------------------------------------- */

.related-posts {
    margin-top: clamp(2.5rem, 6vw, 4rem);
    padding-top: clamp(2rem, 5vw, 3rem);
    border-top: 1px solid var(--color-border);
}

.related-posts .blog-grid {
    margin-top: 1.25rem;
}

.related-posts__all {
    margin-top: 1.25rem;
}

.related-posts__all a {
    font-weight: 500;
    color: var(--color-accent-ink);
    text-decoration: none;
}

.related-posts__all a:hover {
    text-decoration: underline;
    text-underline-offset: 0.25em;
}

/* ---- Search empty state --------------------------------------------- */

.search-suggestions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem 1.25rem;
    margin: 1.1rem 0 0;
    padding: 0;
    list-style: none;
}

.search-suggestions a {
    font-weight: 500;
    color: var(--color-accent-ink);
}


/* ============================================================
   P14 - REAL NAV ON THE LANDING PAGES (2026-08-19)
   ------------------------------------------------------------
   Milan reversed the "no nav on Ads pages" rule: the landing template now
   calls get_header() and carries the real sticky bar. Two consequences to
   clean up here.
   ============================================================ */

/* 1. ANCHOR CLEARANCE. style.css gives scroll-margin-top to `section[id],
      article[id]`. #enquire is a DIV (.landing-form.card), so it matched
      neither - which was harmless while these pages had no sticky header and
      is a real bug now: every "Get a quote" would scroll the form's heading
      up underneath the bar. scroll-margin-top is the single source of anchor
      clearance theme-wide (see the contract in js/navigation.js); never put
      header maths back into JS to solve this. */
#enquire {
    scroll-margin-top: calc(var(--header-h) + 1rem);
}

/* 2. TOMBSTONE. .landing-topbar, .landing-topbar__brand, .landing-topbar__logo
      and .landing-topbar__phone are no longer rendered by anything - the P11
      bar they styled was replaced by the real header. The rules are left in
      place, unused, because a one-off landing page written straight in wp-admin
      could still want a minimal bar, and deleting them costs more than the
      ~400 bytes they occupy. If that never happens, remove them post-launch. */

/* ============================================================
   P15 - ESTIMATE PANEL (2026-08-20)
   ============================================================
   The sticky total bar is gone from the markup. Its rules above
   (.pricing-calc__total-bar, __total-inner, __bar-actions and the
   max-width:560px `position: static` override) are DEAD but stay put:
   this file is append-only because its cascade is source-order
   dependent, and deleting mid-file risks more than the bytes save.

   Also inert now, for the same reason: .pricing-calc__lane-line's
   `flex: 1 1 22rem` and its 560px counter-rule. The lane line is a grid
   child in the panel, and flex-basis means nothing to a grid child - the
   old "352px-tall lane line" trap dissolves structurally rather than
   being patched.

   No motion is declared anywhere in this block. The estimator has been
   deliberately motionless since P4, rows that slide in would fight the
   reveal system, and shipping zero animation means there is no
   reduced-motion guard to get wrong.
   ============================================================ */

.pricing-calc__main {
    display: grid;
    gap: 1.5rem;
    /* A grid child's default min-width:auto lets wide content (the option
       rows) push the column past its track and squeeze the panel. */
    min-width: 0;
}

@media (min-width: 901px) {
    .pricing-calc__form {
        display: grid;
        grid-template-columns: minmax(0, 1fr) 20.5rem;
        gap: 2rem;
        /* LOAD-BEARING. Grid items stretch to the row height by default, and
           a stretched item has no room to travel - position:sticky on the
           panel silently does nothing without this. */
        align-items: start;
    }

    .pricing-calc__panel {
        position: sticky;
        /* Clears the sticky header, same arithmetic the anchor rules use. */
        top: calc(var(--header-h) + 1rem);
    }
}

/* The goal grid is 4-up at full width. Inside a column that now shares the
   row with a 20.5rem panel, 4-up shreds the labels; 2x2 holds at every
   width, and the existing max-width:900px rules already said 2-up. */
.pricing-calc__form .calc-goals__options {
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

/* ── Panel shell ── */
.pricing-calc__panel {
    display: grid;
    gap: 1rem;
    align-content: start;
    padding: 1.15rem;
    min-width: 0;
    background: var(--color-surface);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-md);
}

.pricing-calc__panel-head {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
}

.pricing-calc__panel-title {
    margin: 0;
    font-size: 1rem;
    font-weight: 600;
    color: var(--color-ink);
}

.pricing-calc__panel-count {
    font-family: var(--font-mono);
    font-size: 0.75rem;
    color: var(--color-ink-soft);
}

.pricing-calc__panel-count[hidden] {
    display: none;
}

/* ── Item rows ── */
.pricing-calc__items {
    display: grid;
    margin: 0;
    padding: 0;
    list-style: none;
}

/* LOAD-BEARING, exactly like .calc-lane-panel[hidden] above: the display
   declaration beats the UA's [hidden] rule, so without this the empty list
   still occupies the panel. */
.pricing-calc__items[hidden] {
    display: none;
}

.calc-item {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    align-items: start;
    gap: 0.6rem;
    padding: 0.7rem 0;
}

.calc-item + .calc-item {
    border-top: 1px solid var(--color-border);
}

.calc-item__check {
    display: inline-flex;
    /* Optical alignment with the name's cap height, not its line box. */
    margin-top: 0.1rem;
    color: var(--color-accent-ink);
}

.calc-item__body {
    display: grid;
    gap: 0.2rem;
    min-width: 0;
}

.calc-item__name {
    font-size: 0.875rem;
    font-weight: 500;
    line-height: 1.35;
    color: var(--color-ink);
}

.calc-item__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.5rem;
}

.calc-item__tier {
    font-family: var(--font-mono);
    font-size: 0.6875rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-ink-soft);
}

.calc-item__price {
    font-family: var(--font-mono);
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--color-ink);
}

.calc-item__price small {
    font-family: var(--font-sans);
    font-size: 0.75rem;
    font-weight: 400;
    color: var(--color-ink-soft);
}

.calc-item__price--free {
    font-size: 0.8125rem;
    font-weight: 500;
    color: var(--color-accent-ink);
}

/* ── Remove ──
   Deliberately not terracotta on hover: the accent marks a SELECTED state
   in this system, and an X is the opposite of one. */
.calc-item__remove {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
    padding: 0;
    background: none;
    border: 0;
    border-radius: var(--radius-sm);
    color: var(--color-ink-soft);
    cursor: pointer;
    transition: color 0.2s var(--ease), background-color 0.2s var(--ease);
}

.calc-item__remove:hover {
    background: var(--color-surface-soft);
    color: var(--color-ink);
}

.calc-item__remove:focus-visible {
    outline: 2px solid var(--color-focus);
    outline-offset: 2px;
}

/* ── Totals, below the rows ── */
.pricing-calc__panel .pricing-calc__total-nums {
    justify-content: space-between;
    gap: 1rem;
    padding-top: 0.9rem;
    border-top: 1px solid var(--color-border-strong);
}

.pricing-calc__panel .pricing-calc__zero-note,
.pricing-calc__panel .pricing-calc__lane-line {
    margin: 0;
}

/* ── Actions ──
   Stacked and full-width: right for a 20.5rem rail on desktop and right
   again for the single-column phone layout, so no media query is needed. */
.pricing-calc__panel-actions {
    display: grid;
    gap: 0.5rem;
}

.pricing-calc__panel-actions .btn {
    width: 100%;
    justify-content: center;
}

@media (max-width: 560px) {
    .pricing-calc__panel {
        padding: 0.95rem;
    }
}

/* ============================================================
   P16 - CURRENCY SWITCHER (2026-08-20)
   ============================================================
   js/currency-render.js has built this component since the P-series, and
   22 of its 23 class names had NO RULES AT ALL. It therefore shipped to
   production as a bare <ul>: visible list bullets, no panel, no radius,
   no positioning - so the open dropdown escaped the header and ran off
   the top of the viewport with the first option clipped, and the code
   and symbol collided ("CADCA$"). That is what Milan reported after
   launch, and it was a missing stylesheet rather than a layout bug.

   Two switchers share one visual language:
     .km-currency-switcher         - the pill in the header (.nav-inner)
     .km-inline-currency-switcher  - the "Showing prices in ..." control
                                     inside the estimator section

   The [hidden] rules are LOAD-BEARING. Both lists get `display: grid`
   here, which beats the UA's [hidden] rule, so without an explicit
   display:none the "closed" menu would sit open permanently - the same
   trap documented on .calc-lane-panel and .pricing-calc__items.
   ============================================================ */

/* ── Header pill ── */
.km-currency-switcher {
    position: relative;
    display: inline-flex;
    margin-left: 0.75rem;
}

.km-currency-switcher__btn,
.km-inline-currency-switcher__btn {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.35rem 0.7rem;
    font-family: var(--font-mono);
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    color: var(--color-ink);
    background: var(--color-surface);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-pill);
    cursor: pointer;
    transition: background-color 0.2s var(--ease), border-color 0.2s var(--ease), color 0.2s var(--ease);
}

.km-currency-switcher__btn:hover,
.km-inline-currency-switcher__btn:hover {
    background: var(--color-surface-soft);
    border-color: var(--color-ink-soft);
}

.km-currency-switcher__btn:focus-visible,
.km-inline-currency-switcher__btn:focus-visible {
    outline: 2px solid var(--color-focus);
    outline-offset: 2px;
}

.km-currency-switcher__chev,
.km-inline-currency-switcher__chev {
    /* Only the chevron moves on open - a transform, so it composites. */
    transition: transform 0.2s var(--ease);
}

.km-currency-switcher__btn[aria-expanded='true'] .km-currency-switcher__chev,
.km-inline-currency-switcher__btn[aria-expanded='true'] .km-inline-currency-switcher__chev {
    transform: rotate(180deg);
}

/* ── The dropdown panel ── */
.km-currency-switcher__list,
.km-inline-currency-switcher__list {
    position: absolute;
    z-index: 120;              /* above the sticky header (100) */
    top: calc(100% + 0.4rem);
    right: 0;
    display: grid;
    gap: 0.1rem;
    min-width: 11rem;
    margin: 0;
    padding: 0.35rem;
    list-style: none;          /* the bullets in the bug report */
    background: var(--color-surface);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-md);
}

/* LOAD-BEARING - see the block header. */
.km-currency-switcher__list[hidden],
.km-inline-currency-switcher__list[hidden] {
    display: none;
}

.km-currency-switcher__list li,
.km-inline-currency-switcher__list li {
    margin: 0;
    padding: 0;
    list-style: none;
}

/* ── Options ──
   Two columns with the symbol pushed right, so CAD / CA$ can never collide
   the way they did in the bug report. */
.km-currency-switcher__option,
.km-inline-currency-switcher__option {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1.25rem;
    width: 100%;
    padding: 0.5rem 0.65rem;
    font-family: var(--font-mono);
    font-size: 0.75rem;
    text-align: left;
    color: var(--color-ink);
    background: none;
    border: 0;
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: background-color 0.2s var(--ease), color 0.2s var(--ease);
}

.km-currency-switcher__option:hover,
.km-inline-currency-switcher__option:hover {
    background: var(--color-surface-soft);
}

.km-currency-switcher__option:focus-visible,
.km-inline-currency-switcher__option:focus-visible {
    outline: 2px solid var(--color-focus);
    outline-offset: -2px;
}

.km-currency-switcher__option.is-active,
.km-inline-currency-switcher__option.is-active {
    background: var(--brand-granite);
    color: var(--brand-cream);
}

.km-currency-switcher__opt-code,
.km-inline-currency-switcher__opt-code {
    font-weight: 600;
    letter-spacing: 0.04em;
}

.km-currency-switcher__opt-symbol,
.km-inline-currency-switcher__opt-symbol {
    color: var(--color-ink-soft);
}

.km-currency-switcher__option.is-active .km-currency-switcher__opt-symbol,
.km-inline-currency-switcher__option.is-active .km-inline-currency-switcher__opt-symbol {
    /* Ink-soft on granite fails contrast; the active row inverts. */
    color: var(--brand-cream);
}

/* ── Inline switcher (estimator section) ── */
.km-inline-currency-switcher {
    position: relative;
    flex-wrap: wrap;
}

.km-inline-currency-switcher__label {
    color: var(--color-ink-soft);
}

.km-inline-currency-switcher__change {
    /* "Change" was rendering flush against the code as "ZARChange". */
    margin-left: 0.4rem;
    font-family: var(--font-sans);
    font-size: 0.75rem;
    font-weight: 400;
    color: var(--color-ink-soft);
    text-decoration: underline;
    text-underline-offset: 2px;
}

.km-inline-currency-switcher__btn:hover .km-inline-currency-switcher__change {
    color: var(--color-ink);
}

/* The inline list opens LEFT-aligned: its trigger sits at the start of a
   line of prose, not at the right edge of a bar. */
.km-inline-currency-switcher__list {
    right: auto;
    left: 0;
}

/* ── Floating fallback ──
   currency-render.js appends the pill to <body> with this class when it
   finds no .nav-inner to mount into. Without positioning that lands at the
   very bottom of the document; pin it so the fallback is at least usable. */
.km-currency-switcher--floating {
    position: fixed;
    z-index: 120;
    top: auto;
    bottom: 1rem;
    left: 1rem;
}

.km-currency-switcher--floating .km-currency-switcher__list {
    top: auto;
    bottom: calc(100% + 0.4rem);
}

@media (max-width: 900px) {
    /* Keep the pill clear of the burger, and let the menu open leftwards so
       it cannot push the header wider than the viewport. */
    .km-currency-switcher {
        margin-left: auto;
        margin-right: 0.5rem;
    }
}

@media (max-width: 560px) {
    .km-currency-switcher__btn {
        padding: 0.3rem 0.55rem;
        font-size: 0.6875rem;
    }

    .km-currency-switcher__list,
    .km-inline-currency-switcher__list {
        min-width: 9.5rem;
    }
}
