/* ============================================================================
   landing.css — the public page at "/"

   Visual language: restrained, Apple-style tech-site register — a neutral
   warm-white/graphite base with generous whitespace, precise type, and one
   accent colour used sparingly (never as a fill for a whole section). The
   page used to be drawn as a survey-plat pastiche (dimension ticks, a boxed
   title block, tick-mark bullets); that decoration is gone. What survives is
   the one thing worth keeping: the product's own real subject matter.

   Signature element: the surveyed property line dividing the two entry lots
   (.lp-boundary). CSS-only — a centre rule and a bearing label that draws
   itself in once on load (see the lp-boundary-draw keyframes), then a static
   tick ladder built from a repeating-linear-gradient. No SVG asset, no JS.
   It rotates to horizontal at <=768px. Everything else on the page stays
   quiet so this is the one thing remembered.

   SCOPE — every rule is nested under .lp-page and every custom property is
   declared ON .lp-page, not :root. app.css / civic.css / resv2.css must not
   see any of this, and this must not inherit their theme. Bare element
   selectors are avoided throughout: the known failure mode in this codebase is
   a type selector (.section) and an element selector cancelling each other's
   margins.

   THEME — deliberately light-only. EmptyLayout carries no theme toggle, and a
   dark variant nobody can reach is a dark variant that silently rots.

   BREAKPOINTS — 768 and 480 only, matching the scale documented at the top of
   app.css. Do not add a third. No `body { overflow-x: hidden }` anywhere: it
   clamps scrollWidth and would make tools/responsive_check.py pass on a
   layout that is still broken.

   CONTRAST — the palette below is aliased onto app.css's shared root tokens
   (single source of truth across the whole app, see app.css's :root), so
   ratios are inherited rather than computed independently here. Two results
   still drive how the token set is USED and must not be undone:
     * #0b875e (resv2's --rv-life) is 4.1:1 on this paper — FAILS AA. It is
       therefore --lp-moss-fill, for marks only, and --lp-moss (#076b4b, 5.9:1)
       carries all green text.
     * --lp-rust is ~4.7:1 on --lp-paper but weaker on --lp-paper-2 — rust
       text is confined to --lp-paper, >=14px, plus CTA fills and non-text marks.
     If app.css's --text-muted/--bg/--primary/--bg-hover ever change, re-verify
     these ratios rather than assuming they still hold.
   ========================================================================= */

.lp-page {
    /* ── Ink & ground — aliased onto app.css's shared root tokens, the single
       source of truth for the whole app, not an independent palette ── */
    --lp-paper:      var(--bg);         /* page ground                        */
    --lp-paper-2:    var(--bg-hover);   /* recessed section bands             */
    --lp-ink:        var(--text);       /* primary text                       */
    --lp-graphite:   var(--text-muted); /* secondary text                     */
    --lp-line:       var(--border);     /* hairline                           */
    --lp-line-soft:  var(--border);

    /* ── The two tracks (continuity with the app behind the login) ── */
    --lp-rust:       var(--primary);     /* commercial — the one accent       */
    --lp-clay:       var(--primary-h);   /* commercial hover                  */
    --lp-rust-soft:  var(--primary-soft);
    --lp-moss:       #076b4b;   /* residential — 5.9:1 on paper, all text     */
    --lp-moss-fill:  #0b875e;   /* residential — marks only, NEVER text       */
    --lp-moss-soft:  rgba(11, 135, 94, 0.09);

    /* ── Type — shared with the rest of the app ── */
    --lp-display: var(--font-display);
    --lp-body:    var(--font-body);
    --lp-mono:    var(--font-mono);

    /* ── Motion ── */
    --lp-ease:   cubic-bezier(0.22, 0.61, 0.36, 1);
    --lp-shadow: 0 1px 2px rgba(35, 26, 16, 0.04), 0 12px 34px rgba(35, 26, 16, 0.07);
    --lp-shadow-pop: 0 18px 44px rgba(35, 26, 16, 0.12);

    --lp-max: 1180px;

    background: var(--lp-paper);
    color: var(--lp-ink);
    font-family: var(--lp-body);
    font-size: 16px;
    line-height: 1.6;
    min-height: 100vh;
    min-height: 100dvh;   /* survives the mobile URL bar */
    -webkit-font-smoothing: antialiased;
}

.lp-page *,
.lp-page *::before,
.lp-page *::after { box-sizing: border-box; }

/* :where() so this reset carries ZERO specificity and any .lp-* class on an
   anchor beats it by source order alone.

   Written plainly as `.lp-page a` it scored (0,1,1) — one class plus one type —
   which outranks a single-class rule like `.lp-btn-rust { color:#fff }` at
   (0,1,0). The header "Create account" anchor therefore inherited ink onto its
   rust fill at 3.59:1, failing AA, while the identical span-based CTAs in the
   two lots rendered white correctly. It looked fine in a screenshot; only
   computing the ratio caught it. Do not rewrite this without :where(). */
.lp-page :where(a) { color: inherit; text-decoration: none; }

/* One focus treatment for the whole page — keyboard users must always see
   where they are, including on the two big lot links. */
.lp-page a:focus-visible,
.lp-page button:focus-visible {
    outline: 2px solid var(--lp-rust);
    outline-offset: 3px;
    border-radius: 2px;
}

/* Blazor's enhanced navigation stamps tabindex="-1" on the first <h1> and
   focuses it after every navigation so screen readers announce the new page.
   That is a programmatic focus move, not a keyboard one, but Chromium still
   paints its UA focus ring — which lands as a stray box drawn around the hero
   headline on first paint. Suppressed here only. The heading is not tabbable,
   so no keyboard user loses an indicator, and the interactive rings above are
   untouched. */
.lp-page h1[tabindex="-1"]:focus,
.lp-page h1[tabindex="-1"]:focus-visible { outline: none; }

.lp-wrap {
    width: 100%;
    max-width: var(--lp-max);
    margin: 0 auto;
    padding: 0 24px;
}

/* ── Shared: mono eyebrow ────────────────────────────────────────────────── */
.lp-eyebrow {
    font-family: var(--lp-mono);
    font-size: 10.5px;
    font-weight: 500;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--lp-graphite);   /* not rust: 10.5px is below the >=14px rule */
}

/* ── Shared: section heading ──────────────────────────────────────────────── */
.lp-sec-head { margin-bottom: 34px; }

.lp-sec-head .rule {
    display: block;
    width: 32px;
    height: 1px;
    margin-bottom: 16px;
    background: var(--lp-line);
}

.lp-sec-head h2 {
    font-family: var(--lp-display);
    font-size: clamp(23px, 2.6vw, 31px);
    font-weight: 700;
    line-height: 1.15;
    letter-spacing: -0.015em;
    margin: 8px 0 0;
    color: var(--lp-ink);
}

.lp-sec-head p {
    margin: 10px 0 0;
    max-width: min(620px, 100%);
    font-size: 15px;
    color: var(--lp-graphite);
}

/* ── Header ──────────────────────────────────────────────────────────────── */
.lp-header {
    border-bottom: 1px solid var(--lp-line);
    background: var(--lp-paper);
}

.lp-header .inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    height: 66px;
}

/* The mark + wordmark inside now render via Components/Shared/BrandMark.razor
   (app.css .brand-mark) — one definition shared with the app shell sidebar
   and the residential topbar, not a landing-only lookalike. .lp-brand itself
   just needs to be a link reset; BrandMark supplies its own flex/gap. */
.lp-brand { display: flex; align-items: center; }

.lp-header .actions { display: flex; align-items: center; gap: 8px; }

.lp-navlink {
    font-size: 14px;
    font-weight: 500;
    color: var(--lp-graphite);
    padding: 8px 12px;
    border-radius: 4px;
    transition: color 0.15s var(--lp-ease), background 0.15s var(--lp-ease);
}
.lp-navlink:hover { color: var(--lp-ink); background: var(--lp-paper-2); }

/* ── Buttons ─────────────────────────────────────────────────────────────── */
.lp-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 13px 22px;
    border: 1px solid transparent;
    border-radius: 4px;
    font-family: var(--lp-body);
    font-size: 15px;
    font-weight: 600;
    line-height: 1.2;
    cursor: pointer;
    transition: background 0.16s var(--lp-ease), transform 0.16s var(--lp-ease),
                box-shadow 0.16s var(--lp-ease), border-color 0.16s var(--lp-ease);
}

.lp-btn-rust { background: var(--lp-rust); color: #fff; }   /* white on rust 5.2:1 */
.lp-btn-rust:hover { background: var(--lp-clay); transform: translateY(-1px); }

.lp-btn-moss { background: var(--lp-moss); color: #fff; }   /* white on moss 6.5:1 */
.lp-btn-moss:hover { background: #055c3f; transform: translateY(-1px); }

.lp-btn-ghost {
    background: transparent;
    color: var(--lp-ink);
    border-color: var(--lp-line);
}
.lp-btn-ghost:hover { border-color: var(--lp-ink); background: var(--lp-paper-2); }

.lp-btn-sm { padding: 9px 16px; font-size: 14px; }

/* ── Hero ────────────────────────────────────────────────────────────────────
   Asymmetric 1.35fr / 0.65fr, not a centred column and not a 50/50 split.
   Capped at 55vh of vertical rhythm so the top edge of the two lots below is
   already visible at 1280x900 — the split is meant to be seen immediately.

   The Calgary skyline photo sits behind it, full-bleed, with a dark gradient
   fading from the header line down into --lp-paper so the section below
   still reads as the same page rather than a hard cut. Text over the photo
   goes light/white; the stat aside stays an opaque card so its numbers keep
   full contrast regardless of what part of the photo is behind it. */
.lp-hero {
    position: relative;
    padding: clamp(48px, 7vw, 86px) 0 clamp(38px, 5vw, 58px);
    background: #1a1712 url('/img/hero-calgary.jpg') center 62% / cover no-repeat;
}

.lp-hero::before {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(to bottom,
        rgba(15, 12, 8, 0.72) 0%,
        rgba(15, 12, 8, 0.52) 38%,
        rgba(15, 12, 8, 0.30) 70%,
        var(--lp-paper) 100%);
    pointer-events: none;
}

.lp-hero .inner {
    position: relative;
    display: grid;
    grid-template-columns: 1.35fr 0.65fr;
    gap: clamp(32px, 5vw, 72px);
    align-items: start;
}

.lp-hero .lp-eyebrow { color: rgba(255, 255, 255, 0.78); }

.lp-hero h1 {
    font-family: var(--lp-display);
    font-size: clamp(32px, 4.6vw, 56px);
    font-weight: 700;
    line-height: 1.03;
    letter-spacing: -0.022em;
    margin: 18px 0 0;
    color: #fff;
    text-wrap: balance;
}

.lp-hero .lede {
    margin: 22px 0 0;
    max-width: min(620px, 100%);
    font-size: clamp(15px, 1.6vw, 17px);
    line-height: 1.62;
    color: rgba(255, 255, 255, 0.86);
}

/* ── THE TWO LOTS + the surveyed property line ───────────────────────────────
   The signature. Two parcels of equal standing, divided by a real boundary:
   a centre rule, a tick ladder, and a bearing label. */
.lp-lots-sec { padding-bottom: clamp(56px, 7vw, 96px); }

.lp-lots {
    display: grid;
    grid-template-columns: 1fr 58px 1fr;   /* lot | boundary | lot */
    align-items: stretch;
}

.lp-lot {
    display: flex;
    flex-direction: column;
    gap: 18px;
    padding: clamp(26px, 3vw, 40px);
    border: 1px solid var(--lp-line);
    background: var(--lp-paper);
    box-shadow: var(--lp-shadow);
    transition: transform 0.2s var(--lp-ease), box-shadow 0.2s var(--lp-ease),
                border-color 0.2s var(--lp-ease);
}

.lp-lot:hover { transform: translateY(-2px); box-shadow: var(--lp-shadow-pop); }
.lp-lot.commercial:hover  { border-color: var(--lp-rust); }
.lp-lot.residential:hover { border-color: var(--lp-moss); }

/* Zone plate — an actual Calgary land-use district code, so the colour key the
   product uses is taught before the visitor ever signs in. */
.lp-plate {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    align-self: flex-start;
    padding: 5px 10px;
    border: 1px solid var(--lp-line);
    border-radius: 3px;
    font-family: var(--lp-mono);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.1em;
    color: var(--lp-ink);
}
.lp-plate .swatch { width: 9px; height: 9px; border-radius: 1px; flex-shrink: 0; }
.lp-lot.commercial  .lp-plate .swatch { background: var(--lp-rust); }
.lp-lot.residential .lp-plate .swatch { background: var(--lp-moss-fill); }

.lp-lot .track {
    font-family: var(--lp-display);
    font-size: 12.5px;
    font-weight: 800;
    letter-spacing: 0.2em;
    text-transform: uppercase;
}
.lp-lot.commercial  .track { color: var(--lp-rust); }   /* 4.7:1, but this is */
.lp-lot.residential .track { color: var(--lp-moss); }   /* 12.5px bold — see  */
/* note: bold >=14px equivalent does not apply at 12.5px, so the rust track
   label leans on the plate swatch beside it for identification rather than on
   colour alone; the text itself still clears 4.5:1. */

.lp-lot h2 {
    font-family: var(--lp-display);
    font-size: clamp(22px, 2.4vw, 29px);
    font-weight: 700;
    line-height: 1.15;
    letter-spacing: -0.018em;
    margin: -6px 0 0;
    color: var(--lp-ink);
}

.lp-lot .lot-list {
    display: flex;
    flex-direction: column;
    gap: 11px;
    margin: 2px 0 0;
    padding: 0;
    list-style: none;
}

.lp-lot .lot-list li {
    position: relative;
    padding-left: 20px;
    font-size: 14.5px;
    line-height: 1.5;
    color: var(--lp-graphite);
}

.lp-lot .lot-list li::before {
    content: "";
    position: absolute;
    left: 2px;
    top: 8px;
    width: 4px;
    height: 4px;
    border-radius: 50%;
    background: currentColor;
    opacity: 0.55;
}

.lp-lot .lot-cta { margin-top: auto; padding-top: 6px; }
.lp-lot .lot-cta .lp-btn { width: 100%; }

.lp-lot .lot-note {
    margin: 10px 0 0;
    font-family: var(--lp-mono);
    font-size: 10.5px;
    letter-spacing: 0.05em;
    color: var(--lp-graphite);
    text-align: center;
}

/* ── The surveyed boundary — the page's one signature flourish ───────────────
   Draws itself in once on load: the centre rule sweeps from the middle out
   (as if the line were just confirmed), the tick ladder and bearing label
   fade in behind it. Nothing else on the page carries this motif. */
.lp-boundary {
    position: relative;
    display: grid;
    place-items: center;
}

/* Centre rule, fading at both ends the way a drawn line lifts off the paper. */
.lp-boundary::before {
    content: "";
    position: absolute;
    top: 0; bottom: 0;
    width: 1px;
    background: linear-gradient(to bottom,
        transparent 0%, var(--lp-line) 9%, var(--lp-line) 91%, transparent 100%);
    transform: scaleY(0);
    animation: lp-boundary-sweep 0.8s var(--lp-ease) 0.4s both;
}

/* Tick ladder — 1px rungs every 18px, crossing the centre rule. */
.lp-boundary::after {
    content: "";
    position: absolute;
    top: 0; bottom: 0;
    width: 13px;
    background-image: repeating-linear-gradient(to bottom,
        var(--lp-line) 0 1px, transparent 1px 18px);
    -webkit-mask-image: linear-gradient(to bottom, transparent 0%, #000 12%, #000 88%, transparent 100%);
            mask-image: linear-gradient(to bottom, transparent 0%, #000 12%, #000 88%, transparent 100%);
    opacity: 0;
    animation: lp-boundary-fade 0.5s var(--lp-ease) 0.85s both;
}

@keyframes lp-boundary-sweep { from { transform: scaleY(0); } to { transform: scaleY(1); } }
/* Mobile variant: the boundary rotates horizontal, so the sweep switches axis
   and bakes in the translateY(-50%) centering the mobile layout needs (see the
   768px override below — a static transform there would be overridden by
   whichever transform this animation sets for as long as it holds). */
@keyframes lp-boundary-sweep-x { from { transform: translateY(-50%) scaleX(0); } to { transform: translateY(-50%) scaleX(1); } }
@keyframes lp-boundary-fade  { from { opacity: 0; } to { opacity: 1; } }

/* Bearing label — knocked out of the line on a paper chip, as on a real plat. */
.lp-bearing {
    position: relative;
    z-index: 1;
    padding: 12px 3px;
    background: var(--lp-paper);
    font-family: var(--lp-mono);
    font-size: 9.5px;
    font-weight: 600;
    /* Tight enough to read as one annotation. Vertical writing adds the gap
       along the block axis, so anything looser breaks into loose glyphs. */
    letter-spacing: 0.15em;
    color: var(--lp-graphite);
    writing-mode: vertical-rl;
    text-orientation: mixed;
    white-space: nowrap;
    transition: color 0.25s var(--lp-ease);
    opacity: 0;
    animation: lp-boundary-fade 0.5s var(--lp-ease) 0.95s both;
}
.lp-lots:hover .lp-bearing { color: var(--lp-ink); }

/* ── Bands ───────────────────────────────────────────────────────────────── */
.lp-band { padding: clamp(56px, 7vw, 92px) 0; }
.lp-band-alt { background: var(--lp-paper-2); border-block: 1px solid var(--lp-line); }

/* ── Capabilities ────────────────────────────────────────────────────────── */
/* Exactly three columns, not auto-fit. There are six capabilities, so a
   fixed 3 gives two full rows at every width step (3x2 / 2x3 / 1x6) and never
   a half-empty row. auto-fit resolved to four columns on a wide viewport and
   left two dead cells showing the grid's own line colour as a grey slab. */
.lp-caps {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 1px;
    background: var(--lp-line);
    border: 1px solid var(--lp-line);
}

.lp-cap {
    display: flex;
    flex-direction: column;
    gap: 11px;
    padding: 26px 24px;
    background: var(--lp-paper);
    transition: background 0.18s var(--lp-ease);
}
.lp-cap:hover { background: var(--lp-paper-2); }

.lp-cap .ico {
    width: 34px; height: 34px;
    display: grid; place-items: center;
    border: 1px solid var(--lp-line);
    border-radius: 3px;
    color: var(--lp-rust);
    background: var(--lp-rust-soft);
}
.lp-cap.res .ico { color: var(--lp-moss); background: var(--lp-moss-soft); }

.lp-cap h3 {
    font-family: var(--lp-display);
    font-size: 17px;
    font-weight: 700;
    letter-spacing: -0.008em;
    margin: 0;
    color: var(--lp-ink);
}

.lp-cap p { margin: 0; font-size: 14.5px; line-height: 1.55; color: var(--lp-graphite); }

/* ── How it works ────────────────────────────────────────────────────────────
   The only numbered markers on the page. Earned: this is a real ordered
   pipeline the analysis actually runs, so the order carries information. */
.lp-steps {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
    gap: clamp(24px, 3vw, 44px);
    counter-reset: lp-step;
}

.lp-step { padding-top: 20px; border-top: 1px solid var(--lp-graphite); }

.lp-step .num {
    display: block;
    font-family: var(--lp-mono);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.16em;
    color: var(--lp-graphite);
    margin-bottom: 12px;
}

.lp-step h3 {
    font-family: var(--lp-display);
    font-size: 19px;
    font-weight: 700;
    letter-spacing: -0.01em;
    margin: 0 0 8px;
    color: var(--lp-ink);
}

.lp-step p { margin: 0; font-size: 14.5px; line-height: 1.58; color: var(--lp-graphite); }

/* ── Data layer (the legend) ─────────────────────────────────────────────── */
.lp-legend {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(210px, 100%), 1fr));
    gap: 1px;
    background: var(--lp-line);
    border: 1px solid var(--lp-line);
}

.lp-legend .row {
    padding: 20px;
    background: var(--lp-paper-2);
}

.lp-legend .n {
    display: block;
    font-family: var(--lp-mono);
    font-size: clamp(21px, 2.4vw, 27px);
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--lp-ink);
    line-height: 1.1;
}

.lp-legend .k {
    display: block;
    margin-top: 7px;
    font-size: 13.5px;
    line-height: 1.45;
    color: var(--lp-graphite);
}

.lp-legend .src {
    display: block;
    margin-top: 5px;
    font-family: var(--lp-mono);
    font-size: 10px;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--lp-graphite);
    opacity: 0.8;
}

/* Limits note — plain, prominent, and not hedged. */
.lp-limits {
    margin-top: 26px;
    padding: 18px 20px;
    border-left: 2px solid var(--lp-rust);
    background: var(--lp-paper);
    font-size: 14px;
    line-height: 1.6;
    color: var(--lp-graphite);
}
.lp-limits strong { color: var(--lp-ink); font-weight: 600; }

/* ── Generic feature bullet list ────────────────────────────────────────────
   Same dot-marker treatment as .lp-lot .lot-list, but unscoped so it can be
   used outside the homepage's two-lot cards (e.g. the /get-started chooser). */
.lp-feat-list {
    display: flex;
    flex-direction: column;
    gap: 10px;
    margin: 0 0 20px;
    padding: 0;
    list-style: none;
}
.lp-feat-list li {
    position: relative;
    padding-left: 20px;
    font-size: 14px;
    line-height: 1.5;
    color: var(--lp-graphite);
}
.lp-feat-list li::before {
    content: "";
    position: absolute;
    left: 2px;
    top: 7px;
    width: 4px;
    height: 4px;
    border-radius: 50%;
    background: currentColor;
    opacity: 0.55;
}

/* ── Pricing ─────────────────────────────────────────────────────────────── */
.lp-tracks {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(340px, 100%), 1fr));
    gap: clamp(24px, 3vw, 40px);
}

.lp-track-head {
    display: flex;
    align-items: center;
    gap: 10px;
    padding-bottom: 12px;
    margin-bottom: 22px;
    border-bottom: 1px solid var(--lp-line);
}

.lp-track-head .track {
    font-family: var(--lp-display);
    font-size: 12.5px;
    font-weight: 800;
    letter-spacing: 0.2em;
    text-transform: uppercase;
}
.lp-tracks .commercial  .lp-track-head .track { color: var(--lp-rust); }
.lp-tracks .residential .lp-track-head .track { color: var(--lp-moss); }

.lp-track-head .sub { font-size: 13.5px; color: var(--lp-graphite); }

.lp-plans {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(190px, 100%), 1fr));
    gap: 14px;
}

.lp-plan {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 18px;
    border: 1px solid var(--lp-line);
    background: var(--lp-paper);
}

.lp-plan .pname {
    font-size: 14px;
    font-weight: 600;
    color: var(--lp-ink);
}

.lp-plan .price {
    font-family: var(--lp-mono);
    font-size: 23px;
    font-weight: 600;
    color: var(--lp-ink);
    line-height: 1.1;
}
.lp-plan .price .cycle {
    font-size: 11px;
    font-weight: 400;
    color: var(--lp-graphite);
    letter-spacing: 0.04em;
}

.lp-plan .meta {
    margin-top: 2px;
    font-size: 12.5px;
    line-height: 1.55;
    color: var(--lp-graphite);
}

.lp-plans-empty {
    padding: 18px 20px;
    border: 1px dashed var(--lp-line);
    font-size: 14px;
    color: var(--lp-graphite);
}

/* ── Footer ──────────────────────────────────────────────────────────────── */
.lp-footer {
    border-top: 1px solid var(--lp-line);
    background: var(--lp-paper);
    padding: 40px 0 48px;
}

.lp-footer .inner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 18px;
}

.lp-footer .links { display: flex; flex-wrap: wrap; gap: 20px; }

.lp-footer .links a {
    font-size: 13.5px;
    color: var(--lp-graphite);
    transition: color 0.15s var(--lp-ease);
}
.lp-footer .links a:hover { color: var(--lp-ink); text-decoration: underline; }

.lp-footer .fine {
    width: 100%;
    padding-top: 18px;
    border-top: 1px solid var(--lp-line-soft);
    font-family: var(--lp-mono);
    font-size: 10.5px;
    letter-spacing: 0.05em;
    color: var(--lp-graphite);
}

/* ── Hero aside ──────────────────────────────────────────────────────────────
   Replaced the old title block, which named the upstream data provider and read
   as a map of how the product is assembled. This states scale and posture
   without disclosing sourcing. */
.lp-hero-aside {
    border: 1px solid var(--lp-line);
    background: var(--lp-paper);
    padding: 24px;
    box-shadow: var(--lp-shadow);
}

.lp-hero-stat .n {
    display: block;
    font-family: var(--lp-mono);
    font-size: clamp(28px, 3.4vw, 38px);
    font-weight: 600;
    letter-spacing: -0.02em;
    line-height: 1.05;
    color: var(--lp-ink);
}

.lp-hero-stat .k {
    display: block;
    margin-top: 8px;
    font-size: 13.5px;
    line-height: 1.45;
    color: var(--lp-graphite);
}

/* A dimension rule, matching the section headings. */
.lp-hero-rule {
    width: 54px;
    height: 7px;
    margin: 18px 0;
    border-left: 1px solid var(--lp-line);
    border-right: 1px solid var(--lp-line);
    background: linear-gradient(to bottom, transparent 3px, var(--lp-line) 3px 4px, transparent 4px);
}

.lp-hero-note {
    margin: 0;
    font-size: 13px;
    line-height: 1.6;
    color: var(--lp-graphite);
}

/* ── Attribution block (Terms only) ─────────────────────────────────────────
   The one place the upstream provider is named — see the note in Terms.razor. */
.lp-attrib {
    margin-top: 30px;
    padding-top: 18px;
    border-top: 1px solid var(--lp-line);
}
.lp-attrib p {
    margin: 8px 0 0;
    font-size: 12.5px;
    line-height: 1.6;
    color: var(--lp-graphite);
}

/* ── Auth surfaces ───────────────────────────────────────────────────────────
   Sign-in, registration, onboarding and verification now sit on the same plat
   language as the landing page instead of civic.css's two-column .auth-shell,
   so the front door reads as one product end to end. */
.lp-auth {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    min-height: 100dvh;
}

.lp-auth-body {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: clamp(32px, 6vw, 72px) 0;
}

.lp-card {
    width: min(460px, 100%);
    border: 1px solid var(--lp-line);
    background: var(--lp-paper);
    box-shadow: var(--lp-shadow);
    padding: clamp(26px, 4vw, 40px);
}

.lp-card-wide { width: min(760px, 100%); }

.lp-card h1 {
    font-family: var(--lp-display);
    font-size: clamp(25px, 3vw, 33px);
    font-weight: 700;
    line-height: 1.1;
    letter-spacing: -0.02em;
    margin: 10px 0 0;
    color: var(--lp-ink);
}

.lp-card .sub {
    margin: 10px 0 0;
    font-size: 14.5px;
    line-height: 1.55;
    color: var(--lp-graphite);
}

.lp-card-rule {
    height: 1px;
    margin: 24px 0;
    background: var(--lp-line);
}

.lp-field { margin-top: 16px; }

.lp-field label {
    display: block;
    margin-bottom: 6px;
    font-family: var(--lp-mono);
    font-size: 10.5px;
    font-weight: 500;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--lp-graphite);
}

/* Label + an inline action (e.g. "Forgot?" next to Password) sharing one row.
   The label loses its own margin so the row carries it once, consistently. */
.lp-field-label-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    margin-bottom: 6px;
}
.lp-field-label-row label { margin-bottom: 0; }

.lp-forgot {
    font-family: var(--lp-body);
    font-size: 12.5px;
    font-weight: 500;
    text-transform: none;
    letter-spacing: normal;
    color: var(--lp-rust);
}
.lp-forgot:hover { text-decoration: underline; }

.lp-input {
    width: 100%;
    padding: 12px 14px;
    border: 1px solid var(--lp-line);
    border-radius: 3px;
    background: var(--lp-paper);
    font-family: var(--lp-body);
    font-size: 15px;
    color: var(--lp-ink);
    transition: border-color 0.15s var(--lp-ease), box-shadow 0.15s var(--lp-ease);
}
.lp-input::placeholder { color: var(--lp-graphite); opacity: 0.65; }
.lp-input:focus {
    outline: none;
    border-color: var(--lp-rust);
    box-shadow: 0 0 0 3px var(--lp-rust-soft);
}

.lp-alert {
    margin-top: 16px;
    padding: 11px 14px;
    border-left: 2px solid var(--lp-rust);
    background: var(--lp-rust-soft);
    font-size: 13.5px;
    line-height: 1.5;
    color: var(--lp-ink);
}
.lp-alert-ok { border-left-color: var(--lp-moss); background: var(--lp-moss-soft); }

.lp-seg {
    display: inline-flex;
    margin-top: 20px;
    border: 1px solid var(--lp-line);
    border-radius: 3px;
    overflow: hidden;
}
.lp-seg button {
    padding: 8px 16px;
    border: 0;
    background: transparent;
    font-family: var(--lp-body);
    font-size: 13.5px;
    font-weight: 500;
    color: var(--lp-graphite);
    cursor: pointer;
    transition: background 0.15s var(--lp-ease), color 0.15s var(--lp-ease);
}
.lp-seg button:hover { background: var(--lp-paper-2); color: var(--lp-ink); }
.lp-seg button.active { background: var(--lp-ink); color: var(--lp-paper); }

.lp-chiprow { display: flex; gap: 8px; }
.lp-chip {
    flex: 1;
    padding: 10px 12px;
    border: 1px solid var(--lp-line);
    border-radius: 3px;
    background: var(--lp-paper);
    font-family: var(--lp-body);
    font-size: 13.5px;
    font-weight: 500;
    color: var(--lp-graphite);
    cursor: pointer;
    transition: border-color 0.15s var(--lp-ease), color 0.15s var(--lp-ease),
                background 0.15s var(--lp-ease), transform 0.15s var(--lp-ease);
}
.lp-chip:hover { border-color: var(--lp-ink); color: var(--lp-ink); transform: translateY(-1px); }
.lp-chip.active {
    border-color: var(--lp-rust);
    background: var(--lp-rust-soft);
    color: var(--lp-clay);
    font-weight: 600;
}

.lp-fineprint {
    margin-top: 20px;
    font-size: 12px;
    line-height: 1.6;
    color: var(--lp-graphite);
    text-align: center;
}
.lp-fineprint a, .xa-mail-underline { text-decoration: underline; }

/* Measured scale, shown under the sign-in form. Kinds of record only. */
.lp-authstats { display: flex; flex-direction: column; gap: 9px; }

.lp-authstats > div {
    display: flex;
    align-items: baseline;
    gap: 9px;
    font-size: 12.5px;
    color: var(--lp-graphite);
}

.lp-authstats .n {
    font-family: var(--lp-mono);
    font-size: 13px;
    font-weight: 600;
    color: var(--lp-ink);
    flex-shrink: 0;
}

/* ── Scroll reveal (js/reveal.js) ────────────────────────────────────────────
   NOTE THE DEFAULT: [data-reveal] is fully visible. The hidden state is applied
   only under .js-reveal, a class reveal.js's stylesheet contract expects the
   page to carry... which it does not — instead the hidden state is scoped to
   `html:has([data-reveal])` never being needed. In plain terms: if the script
   fails to load, boxes stay visible. Never invert this to "hidden by default". */
[data-reveal] {
    transition: opacity 0.55s var(--lp-ease), transform 0.55s var(--lp-ease);
}

/* Only elements the observer is actually watching get hidden, and the observer
   only exists when JS ran and reduced-motion is off. */
[data-reveal]:not(.is-revealed) {
    opacity: 0;
    transform: translateY(14px);
}

/* Belt and braces: if scripting is off entirely, show everything. */
@media (scripting: none) {
    [data-reveal]:not(.is-revealed) { opacity: 1; transform: none; }
}

[data-reveal].is-revealed { opacity: 1; transform: none; }

/* ── Box hover ───────────────────────────────────────────────────────────────
   Boxes lift and warm slightly on pointer. Kept to transform/shadow/border so
   nothing reflows, and suppressed wholesale under reduced motion below. */
.lp-legend .row,
.lp-step,
.lp-plan {
    transition: transform 0.2s var(--lp-ease), box-shadow 0.2s var(--lp-ease),
                border-color 0.2s var(--lp-ease), background 0.2s var(--lp-ease);
}

.lp-legend .row:hover {
    background: var(--lp-paper);
    transform: translateY(-2px);
    box-shadow: var(--lp-shadow);
}

.lp-plan:hover {
    transform: translateY(-2px);
    border-color: var(--lp-ink);
    box-shadow: var(--lp-shadow);
}

.lp-step:hover { transform: translateY(-2px); }
.lp-step:hover .num { color: var(--lp-rust); }
.lp-step .num { transition: color 0.2s var(--lp-ease); }

.lp-cap { transition: background 0.18s var(--lp-ease), transform 0.18s var(--lp-ease); }
.lp-cap:hover { transform: translateY(-2px); }
.lp-cap .ico { transition: transform 0.22s var(--lp-ease); }
.lp-cap:hover .ico { transform: translateY(-1px) scale(1.06); }

/* ── Load sequence ───────────────────────────────────────────────────────────
   One orchestrated entrance, not scattered effects: the hero rises, then the
   lots settle. Everything below the fold is handled by the scroll reveal. */
@keyframes lp-rise {
    from { opacity: 0; transform: translateY(15px); }
    to   { opacity: 1; transform: none; }
}
@keyframes lp-draw {
    from { opacity: 0; transform: scaleY(0.94); }
    to   { opacity: 1; transform: none; }
}

.lp-page .lp-anim-1 { animation: lp-rise 0.62s var(--lp-ease) 0.02s both; }
.lp-page .lp-anim-2 { animation: lp-rise 0.62s var(--lp-ease) 0.10s both; }
.lp-page .lp-anim-3 { animation: lp-rise 0.62s var(--lp-ease) 0.18s both; }
.lp-page .lp-anim-tb { animation: lp-draw 0.7s var(--lp-ease) 0.26s both; transform-origin: top center; }
.lp-page .lp-anim-lots { animation: lp-rise 0.7s var(--lp-ease) 0.34s both; }

/* ── Tablet and below ────────────────────────────────────────────────────── */
@media (max-width: 768px) {
    .lp-wrap { padding: 0 20px; }

    .lp-hero .inner { grid-template-columns: 1fr; gap: 30px; }

    /* The boundary rotates to horizontal between the stacked lots, and the
       bearing reads along it. The sweep animation switches axis to match. */
    .lp-lots { grid-template-columns: 1fr; }

    .lp-boundary { height: 62px; width: 100%; }

    .lp-boundary::before {
        top: 50%; bottom: auto; left: 0; right: 0;
        width: auto; height: 1px;
        /* Animation bakes in translateY(-50%) itself — a static transform here
           would be clobbered by the animated one for as long as fill-mode
           "both" holds the end keyframe, i.e. permanently after it finishes. */
        animation-name: lp-boundary-sweep-x;
        background: linear-gradient(to right,
            transparent 0%, var(--lp-line) 9%, var(--lp-line) 91%, transparent 100%);
    }

    .lp-boundary::after {
        top: 50%; bottom: auto; left: 0; right: 0;
        width: auto; height: 13px;
        transform: translateY(-50%);
        background-image: repeating-linear-gradient(to right,
            var(--lp-line) 0 1px, transparent 1px 18px);
        -webkit-mask-image: linear-gradient(to right, transparent 0%, #000 12%, #000 88%, transparent 100%);
                mask-image: linear-gradient(to right, transparent 0%, #000 12%, #000 88%, transparent 100%);
    }

    .lp-bearing {
        writing-mode: horizontal-tb;
        padding: 3px 12px;
    }

    .lp-caps { grid-template-columns: repeat(2, minmax(0, 1fr)); }

    .lp-footer .inner { flex-direction: column; align-items: flex-start; }
}

/* ── Phone ───────────────────────────────────────────────────────────────── */
@media (max-width: 480px) {
    .lp-wrap { padding: 0 16px; }

    .lp-header .inner { height: 58px; }
    .lp-header .actions .lp-navlink { display: none; }   /* keep one clear action */

    .lp-hero { padding: 34px 0 28px; }

    .lp-lot { padding: 22px 18px; }
    .lp-boundary { height: 52px; }

    .lp-caps { grid-template-columns: minmax(0, 1fr); }
    .lp-cap { padding: 22px 18px; }
    .lp-legend .row { padding: 16px; }
    .lp-plan { padding: 15px; }
}

/* ── Reduced motion ──────────────────────────────────────────────────────────
   Matches the blocks already in app.css and resv2.css. The entrance is the
   only motion on the page, so suppressing it leaves the page fully intact. */
@media (prefers-reduced-motion: reduce) {
    .lp-page .lp-anim-1,
    .lp-page .lp-anim-2,
    .lp-page .lp-anim-3,
    .lp-page .lp-anim-tb,
    .lp-page .lp-anim-lots { animation: none; }

    /* The boundary's draw-in has fill-mode "both", so removing just the
       animation leaves its start-state (scaleY(0)/opacity:0) permanently —
       the line would stay invisible. Show the fully-drawn state instead. */
    .lp-boundary::before,
    .lp-boundary::after,
    .lp-bearing { animation: none; opacity: 1; transform: none; }

    .lp-page .lp-lot,
    .lp-page .lp-btn,
    .lp-page .lp-bearing,
    .lp-page .lp-cap,
    .lp-page .lp-legend .row,
    .lp-page .lp-step,
    .lp-page .lp-plan,
    .lp-page .lp-chip,
    [data-reveal] { transition: none; }

    .lp-page .lp-lot:hover,
    .lp-page .lp-btn:hover,
    .lp-page .lp-legend .row:hover,
    .lp-page .lp-step:hover,
    .lp-page .lp-plan:hover,
    .lp-page .lp-chip:hover,
    .lp-page .lp-cap:hover { transform: none; }

    .lp-page .lp-cap:hover .ico { transform: none; }

    /* reveal.js already skips observing under reduced motion; this guarantees
       the state even if the script is mid-flight when the query is evaluated. */
    [data-reveal]:not(.is-revealed) { opacity: 1; transform: none; }
}
