/* ============================================================================
   components.css — reusable building blocks
   Header, wordmark, buttons, panels, cards, badges, gallery, tutorials, footer
   ========================================================================= */

/* ── Site header — the application bar, translated to the web ──────────── */
.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  height: var(--header-h);
  background: var(--g-header);
  border-bottom: 2px solid var(--c-accent);
  box-shadow: var(--shadow-2);
}
/* Brand and navigation sit together as ONE centred cluster, rather than being
   pushed to opposite edges. Mobile reverts to logo-left / toggle-right — see
   responsive.css. */
.site-header__inner {
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-12);
}

/* The wordmark — ROOF in silver, DATUM in RoofDatum blue, exactly as the app. */
.brand { display: inline-flex; align-items: center; gap: 11px; flex-shrink: 0; }
.brand__icon {
  width: 32px; height: 32px;
  border-radius: 8px;
  box-shadow: 0 1px 4px rgba(0,0,0,0.45);
}
.wordmark {
  font-size: 15px;
  font-weight: 900;
  letter-spacing: 1.5px;
  line-height: 1;
  white-space: nowrap;
}
.wordmark__roof  { color: var(--c-wordmark-roof); }
.wordmark__datum { color: var(--c-accent); }
.wordmark--lg { font-size: 19px; letter-spacing: 2px; }

/* ── Header branding ──────────────────────────────────────────────────────
   The header uses `roofdatum-mark.png` — the roof-and-ruler mark on its own,
   cropped from the official logo. The full square app icon is NOT used here:
   it has ROOFDATUM baked into it, and at header size that wording turns to
   mush sitting right next to the real wordmark. Two illegible wordmarks is
   worse than one legible one. The square badge is still correct everywhere it
   is shown large — the footer keeps using it.

   The mark is 1.535:1, not square, so it is sized by HEIGHT and the width
   follows. Never set both, and never set a width that fights the height:
   stretching a logo is the one thing you must not do to it.

   These rules are scoped to `.site-header` on purpose, so the footer brand is
   untouched.                                                                */
.site-header .brand { gap: 12px; }
.site-header .brand__icon {
  width: auto;
  height: 48px;                       /* mark renders ~74 x 48 */
  border-radius: 0;                   /* no tile behind it any more */
  box-shadow: none;
  filter: drop-shadow(0 1px 3px rgba(0,0,0,0.5));
}
.site-header .wordmark { font-size: 22px; letter-spacing: 2px; }

/* ── Primary navigation ───────────────────────────────────────────────── */
.nav { display: flex; align-items: center; gap: var(--sp-1); }
.nav__link {
  position: relative;                 /* anchors the current-page underline */
  display: inline-flex;
  align-items: center;
  height: 38px;
  padding: 0 12px;
  border-radius: var(--r-md);
  /* #dbe6f2 gives 14.3:1 against the header navy — the links were legible
     before at #c6d4e4, but at 13.5px they read as faint. Size and weight were
     doing more damage than colour; all three are lifted together. The nav must
     still sit BELOW the brand in the hierarchy, so weight stays at 500 while
     the wordmark is 900. */
  color: #dbe6f2;
  font-size: 15px;
  font-weight: 500;
  white-space: nowrap;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.nav__link:hover { background: rgba(255,255,255,0.08); color: #fff; }

/* Current page. A filled pill here read as a pressed-in button sitting next to
   the real button, so the marker is a 2px underline instead: brighter text plus
   a rule under the word. It says "you are here" without imitating a control.
   The underline is decorative — aria-current already conveys this to assistive
   technology — but the brighter text means it is never colour alone. */
.nav__link[aria-current="page"] {
  color: #fff;
  font-weight: 600;
  background: transparent;
}
.nav__link[aria-current="page"]:hover { background: rgba(255,255,255,0.08); }
.nav__link[aria-current="page"]::after {
  content: "";
  position: absolute;
  left: 12px;
  right: 12px;
  bottom: 2px;
  height: 2px;
  border-radius: 2px;
  background: var(--c-accent);
}

/* Mobile menu toggle — hidden on desktop (see responsive.css) */
.nav-toggle {
  display: none;
  width: 40px; height: 34px;
  align-items: center; justify-content: center;
  background: rgba(255,255,255,0.06);
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: var(--r-md);
  color: #c6d4e4;
  cursor: pointer;
}
.nav-toggle:hover { background: rgba(255,255,255,0.13); color: #fff; }
.nav-toggle__bars, .nav-toggle__bars::before, .nav-toggle__bars::after {
  display: block; width: 17px; height: 1.5px;
  background: currentColor; border-radius: 2px;
  transition: transform var(--t-med) var(--ease), opacity var(--t-fast) var(--ease);
}
.nav-toggle__bars::before, .nav-toggle__bars::after { content: ""; position: absolute; }
.nav-toggle__bars::before { transform: translateY(-5px); }
.nav-toggle__bars::after  { transform: translateY(5px); }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars { background: transparent; }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars::before { transform: rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars::after  { transform: rotate(-45deg); }

/* ── Header action button ─────────────────────────────────────────────────
   While downloads are "coming soon", site.js sets aria-disabled="true" on this
   button, and the global rule for that is `opacity: 0.5`. On a small outlined
   button against navy, half opacity was what made it look broken rather than
   pending — the border faded to a smudge and the label to a whisper.

   So inside the header the blanket opacity is dropped and replaced with an
   explicit palette: full-strength accent border, and #9ed0ff text, which is
   8.9:1 against the button's own background. Readable, unmistakably an
   outlined secondary control, and — because it stays small and 13px — still
   visually quieter than the large buttons in the hero.

   Note the hero's own "Coming soon" button is still on the global 0.5 rule.
   That is deliberate: the hero was out of scope for this change.             */
.site-header .btn[aria-disabled="true"] {
  opacity: 1;
  background: var(--c-accent-deep);
  border-color: var(--c-accent);
  color: #9ed0ff;
}
.site-header .btn--primary {
  font-weight: 650;
  letter-spacing: 0.2px;
}

/* ── Buttons ──────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  padding: 11px 22px;
  border: 1px solid transparent;
  border-radius: var(--r-md);
  font-family: inherit;
  font-size: 14.5px;
  font-weight: 600;
  line-height: 1.2;
  cursor: pointer;
  white-space: nowrap;
  text-decoration: none;
  transition: background var(--t-fast) var(--ease),
              border-color var(--t-fast) var(--ease),
              color var(--t-fast) var(--ease),
              transform var(--t-fast) var(--ease);
}
.btn:active { transform: translateY(1px); }
.btn[aria-disabled="true"], .btn:disabled { opacity: 0.5; cursor: not-allowed; }
.btn[aria-disabled="true"]:active { transform: none; }

.btn--primary {
  background: var(--c-accent-deep);
  border-color: var(--c-accent);
  color: var(--c-accent-hi);
}
.btn--primary:hover {
  background: var(--c-accent-deep-2);
  border-color: #3fa0ff;
  color: #fff;
}

.btn--solid { background: var(--c-accent); border-color: var(--c-accent); color: #fff; }
.btn--solid:hover { background: #006fe6; border-color: #006fe6; color: #fff; }

.btn--ghost {
  background: var(--c-surface-3);
  border-color: var(--c-border-2);
  color: var(--c-text-2);
}
.btn--ghost:hover { background: var(--c-surface-hover); border-color: var(--c-border-hover); color: #fff; }

.btn--quiet { background: transparent; border-color: var(--c-border-2); color: var(--c-text-2); }
.btn--quiet:hover { background: var(--c-surface-2); color: var(--c-text); }

.btn--lg { padding: 14px 28px; font-size: 15.5px; }
.btn--sm { padding: 7px 14px; font-size: 13px; }
.btn--block { width: 100%; }

.btn-row { display: flex; flex-wrap: wrap; gap: var(--sp-3); }

/* ── Eyebrow micro-label (uppercase, letter-spaced — app convention) ───── */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-2);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: 1.6px;
  text-transform: uppercase;
  color: var(--c-text-3);
  margin-bottom: var(--sp-4);
}
.eyebrow::before {
  content: "";
  width: 22px; height: 1px;
  background: var(--c-accent);
  opacity: 0.75;
}
.eyebrow--center { justify-content: center; }

/* ── Section heading block ────────────────────────────────────────────── */
.section-head { max-width: 720px; margin-bottom: var(--sp-12); }
.section-head--center { margin-inline: auto; text-align: center; }
.section-head p { margin-top: var(--sp-4); font-size: var(--fs-md); color: var(--c-text-2); }

/* ── Panels & cards ───────────────────────────────────────────────────── */
.panel {
  background: var(--c-surface);
  background-image: var(--g-panel);
  border: 1px solid var(--c-border);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-1), var(--ring);
}
.panel__body { padding: var(--sp-8); }

.card {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  padding: var(--sp-6);
  background: var(--c-surface);
  background-image: var(--g-panel);
  border: 1px solid var(--c-border);
  border-radius: var(--r-lg);
  box-shadow: var(--ring);
  transition: border-color var(--t-med) var(--ease),
              transform var(--t-med) var(--ease),
              box-shadow var(--t-med) var(--ease);
}
.card:hover { border-color: var(--c-border-2); transform: translateY(-2px); box-shadow: var(--shadow-2), var(--ring); }
.card h3 { color: var(--c-text); }
.card p  { font-size: var(--fs-sm); color: var(--c-text-2); margin: 0; }

/* A thin blue leading rule — the application's "status by left border" idea. */
.card--ruled { border-left: 2px solid var(--c-accent-line); }
.card--ruled:hover { border-left-color: var(--c-accent); }

.card__icon {
  width: 38px; height: 38px;
  display: grid; place-items: center;
  border-radius: var(--r-md);
  background: var(--c-accent-soft);
  border: 1px solid rgba(11,132,255,0.22);
  color: var(--c-accent-hi);
  flex-shrink: 0;
}
.card__icon svg { width: 19px; height: 19px; }

.grid { display: grid; gap: var(--sp-5); }
.grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }

/* ── Badges & pills ───────────────────────────────────────────────────── */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 11px;
  border-radius: 999px;
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: 0.9px;
  text-transform: uppercase;
  border: 1px solid var(--c-border-2);
  background: var(--c-surface-2);
  color: var(--c-text-3);
}
.badge--accent { border-color: rgba(11,132,255,0.35); background: rgba(11,132,255,0.10); color: var(--c-accent-hi); }
.badge--amber  { border-color: rgba(212,134,10,0.38); background: rgba(212,134,10,0.10); color: #e0a martin; }
.badge--amber  { color: #e6a740; }
.badge--green  { border-color: rgba(34,197,94,0.35); background: rgba(34,197,94,0.10); color: #58d489; }
.badge__dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }

/* ── Notice panel (professional-use / legal) ──────────────────────────── */
/* Padding matches .req-card__body (24px) so a notice sits at the same internal
   rhythm as the cards above it, rather than reading as a roomier block. */
.notice {
  border: 1px solid var(--c-border-2);
  border-left: 3px solid var(--c-accent);
  border-radius: var(--r-lg);
  background: linear-gradient(180deg, rgba(11,132,255,0.05), rgba(11,132,255,0));
  padding: var(--sp-6);
}
.notice h3 { margin-bottom: var(--sp-4); }
.notice p + p { margin-top: var(--sp-4); }
.notice__fine { font-size: var(--fs-sm); color: var(--c-text-3); }

.notice--warn { border-left-color: var(--c-amber); background: linear-gradient(180deg, rgba(212,134,10,0.06), transparent); }

/* ── The gallery's beta notice ────────────────────────────────────────────
   The house `.notice` treatment, dialled down: it has to be read, not
   noticed. 24px below the grid — the same gap the tiles use between
   themselves — so it belongs to the gallery instead of floating between two
   sections. Body text at --c-text-2 is 8.7:1 on the banded background;
   the label alone is lifted to --c-text (16.2:1) and 650 weight, which is
   enough emphasis to find without shouting. Deliberately one notice for the
   whole gallery, never one per tile.                                        */
.gallery-notice {
  margin-top: var(--sp-6);
  font-size: var(--fs-sm);
  line-height: var(--lh-body);
  color: var(--c-text-2);
}
.gallery-notice strong { color: var(--c-text); font-weight: 650; }

/* ── Screenshot frame ─────────────────────────────────────────────────── */
.shot {
  position: relative;
  border: 1px solid var(--c-border-2);
  border-radius: var(--r-xl);
  overflow: hidden;
  background: var(--c-surface);
  box-shadow: var(--shadow-3), var(--ring);
}
.shot::after {
  content: "";
  position: absolute; inset: 0;
  border-radius: inherit;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.06);
  pointer-events: none;
}
.shot__bar {
  display: flex; align-items: center; gap: var(--sp-3);
  height: 34px; padding-inline: var(--sp-4);
  background: var(--c-navy);
  border-bottom: 1px solid rgba(11,132,255,0.30);
}
.shot__dots { display: flex; gap: 6px; }
.shot__dots span { width: 8px; height: 8px; border-radius: 50%; background: #2b3a4e; }
.shot__title {
  font-size: var(--fs-micro);
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--c-text-4);
}
.shot img { width: 100%; display: block; }

/* ── Screenshot gallery ───────────────────────────────────────────────────
   Every tile is the same size, whatever shape the screenshot inside it is.
   That takes three separate rules, because three different things can pull a
   tile out of line:

     1. `grid-auto-rows: 1fr` — every ROW is as tall as the tallest tile in the
        gallery, not just the tallest in its own row.
     2. `height: 100%` down through the listitem wrapper to the button — a grid
        item stretches, but gallery.js wraps each button in a <div role=
        "listitem"> for accessibility, and without this the button would sit at
        its own content height inside a stretched wrapper.
     3. `aspect-ratio` + `object-fit: contain` on the image — the picture box is
        always 16:10 regardless of the file's own proportions, and the picture
        is fitted inside it rather than cropped to fill it. A very wide or very
        tall screenshot gets bars beside it instead of losing its edges.

   `contain` rather than `cover` is deliberate: cropping a screenshot to fit a
   tile is how you lose the toolbar, the page list, or the top-left of a plan —
   the parts that make it recognisable. Placeholder art is drawn at 16:10, so it
   still fills the box exactly and nothing about it changes.                  */
.gallery {
  display: grid;
  grid-template-columns: repeat(3, minmax(0,1fr));
  grid-auto-rows: 1fr;
  gap: var(--sp-5);
}
.gallery > [role="listitem"] { display: flex; height: 100%; }

.gallery__item {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  padding: 0;
  text-align: left;
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--r-lg);
  overflow: hidden;
  cursor: zoom-in;
  font-family: inherit;
  color: inherit;
  transition: border-color var(--t-med) var(--ease), transform var(--t-med) var(--ease);
}
.gallery__item:hover { border-color: var(--c-accent-line); transform: translateY(-2px); }
.gallery__thumb {
  width: 100%;
  aspect-ratio: 16 / 10;
  flex: 0 0 auto;
  object-fit: contain;
  background: var(--c-base-2);
}
.gallery__caption {
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
  flex: 1 1 auto;                 /* soaks up the leftover height, so the */
  padding: var(--sp-4) var(--sp-5); /* picture box stays 16:10 in every tile */
  border-top: 1px solid var(--c-border);
  font-size: var(--fs-sm);
  color: var(--c-text-2);
}
.gallery__caption strong { display: block; color: var(--c-text); font-weight: 600; }
.gallery__zoom { color: var(--c-text-4); flex-shrink: 0; }
.gallery__item:hover .gallery__zoom { color: var(--c-accent-hi); }

.gallery-lightbox {
  position: fixed; inset: 0; z-index: 300;
  display: none;
  align-items: center; justify-content: center;
  padding: var(--sp-6);
  background: rgba(4, 7, 12, 0.92);
  backdrop-filter: blur(4px);
}
.gallery-lightbox[data-open="true"] { display: flex; }
.gallery-lightbox__figure {
  max-width: min(1400px, 94vw);
  max-height: 92vh;
  display: flex; flex-direction: column; gap: var(--sp-4);
}
.gallery-lightbox__img {
  max-height: 78vh;
  width: auto; max-width: 100%;
  margin-inline: auto;
  border: 1px solid var(--c-border-2);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-3);
  background: var(--c-surface);
}
.gallery-lightbox__cap {
  text-align: center;
  font-size: var(--fs-sm);
  color: var(--c-text-2);
}
.gallery-lightbox__cap strong { color: var(--c-text); }
.lb-btn {
  position: absolute;
  display: grid; place-items: center;
  width: 44px; height: 44px;
  border-radius: 50%;
  background: rgba(21, 29, 42, 0.9);
  border: 1px solid var(--c-border-2);
  color: var(--c-text-2);
  cursor: pointer;
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.lb-btn:hover { background: var(--c-surface-hover); color: #fff; }
.lb-btn--close { top: var(--sp-5); right: var(--sp-5); }
.lb-btn--prev  { left: var(--sp-5);  top: 50%; transform: translateY(-50%); }
.lb-btn--next  { right: var(--sp-5); top: 50%; transform: translateY(-50%); }
.lb-count {
  position: absolute; bottom: var(--sp-5); left: 50%; transform: translateX(-50%);
  font-family: var(--f-mono); font-size: var(--fs-xs); color: var(--c-text-4);
}

/* ── Tutorial cards ───────────────────────────────────────────────────── */
.tutorials { display: grid; grid-template-columns: repeat(4, minmax(0,1fr)); gap: var(--sp-5); }

.tutorial {
  position: relative;                 /* anchors the "Coming soon" ribbon */
  display: flex; flex-direction: column;
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--r-lg);
  overflow: hidden;                   /* clips the ribbon to the corner */
  transition: border-color var(--t-med) var(--ease), transform var(--t-med) var(--ease);
}
.tutorial:hover { border-color: var(--c-border-2); transform: translateY(-2px); }

.tutorial__media {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  background: linear-gradient(160deg, #0d1524, #070b12);
  border-bottom: 1px solid var(--c-border);
  display: grid; place-items: center;
  padding: 0; margin: 0;
}
.tutorial__media iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

button.tutorial__media { cursor: pointer; font-family: inherit; border: 0; border-bottom: 1px solid var(--c-border); }
button.tutorial__media:hover .tutorial__play { background: var(--c-accent); border-color: var(--c-accent); color: #fff; }

.tutorial__thumb { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.tutorial__play {
  position: relative;
  width: 52px; height: 52px;
  display: grid; place-items: center;
  border-radius: 50%;
  background: rgba(10, 42, 74, 0.86);
  border: 1px solid var(--c-accent);
  color: var(--c-accent-hi);
  transition: background var(--t-fast) var(--ease), color var(--t-fast) var(--ease);
}
.tutorial__play svg { width: 18px; height: 18px; margin-left: 2px; }

/* ── "Coming soon" treatment for tutorials with no video yet ────────────
   A diagonal ribbon wraps the top-right corner of the card, and the media
   area shows a dimmed play mark instead of a dashed box. Both disappear on
   their own the moment a YouTube ID is added in site.js. */
.tutorial--soon { border-color: var(--c-border); }
.tutorial--soon:hover { border-color: var(--c-accent-line); }

/* Geometry note: the band is clipped by the card's corner, so only part of its
   width is ever visible. For a 45° band at perpendicular distance d from the
   corner, the visible chord is 2d — so d must exceed half the text width or the
   wording clips. These values give d ≈ 55px (chord ≈ 110px) against a rendered
   text width of ≈ 84px, leaving comfortable margin at every breakpoint. */
.tutorial__ribbon {
  position: absolute;
  top: 30px;
  right: -46px;
  z-index: 3;
  width: 172px;
  padding: 6px 0;
  transform: rotate(45deg);
  text-align: center;
  background: linear-gradient(135deg, #1f9bff 0%, var(--c-accent) 45%, #0a5fd0 100%);
  color: #fff;
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: 1.1px;
  text-transform: uppercase;
  line-height: 1.35;
  white-space: nowrap;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.45), inset 0 1px 0 rgba(255,255,255,0.25);
  pointer-events: none;
}

/* The media panel behind the ribbon: dimmed, with a soft blue wash so the
   corner reads as deliberate rather than as a broken thumbnail. */
.tutorial__media--soon {
  background:
    radial-gradient(140px 90px at 78% 12%, rgba(11,132,255,0.16), transparent 70%),
    linear-gradient(160deg, #0e1725, #070b12);
}
.tutorial__soon-play {
  display: grid; place-items: center;
  width: 46px; height: 46px;
  border-radius: 50%;
  border: 1px solid var(--c-border-2);
  background: rgba(255,255,255,0.03);
  color: var(--c-text-4);
}
.tutorial__soon-play svg { width: 16px; height: 16px; margin-left: 2px; }

/* Retained: used by any future placeholder that is not the ribbon state. */
.tutorial__placeholder {
  display: flex; flex-direction: column; align-items: center; gap: var(--sp-2);
  color: var(--c-text-4);
  font-size: var(--fs-micro);
  letter-spacing: 1.4px;
  text-transform: uppercase;
  border: 1px dashed var(--c-border-2);
  border-radius: var(--r-md);
  padding: var(--sp-4) var(--sp-5);
  margin: var(--sp-4);
}
.tutorial__body { padding: var(--sp-5); display: flex; flex-direction: column; gap: 6px; flex: 1; }
.tutorial__body h3 { font-size: var(--fs-sm); font-weight: 650; }
.tutorial__body p  { font-size: var(--fs-xs); color: var(--c-text-3); margin: 0; }

/* ── Steps (How it works) ─────────────────────────────────────────────── */
.steps { counter-reset: step; display: grid; gap: var(--sp-4); }
/* Content is centred on BOTH axes: the number badge sits above the text, the
   whole group is centred horizontally, and `align-content: center` centres it
   vertically inside the tile — which matters because every tile is stretched
   to a uniform height (see .workflow in pages.css). */
.step {
  counter-increment: step;
  position: relative;
  display: grid;
  grid-template-columns: 1fr;
  justify-items: center;
  align-content: center;
  text-align: center;
  gap: var(--sp-4);
  padding: var(--sp-6);
  background: var(--c-surface);
  border: 1px solid var(--c-border);
  border-radius: var(--r-lg);
  transition: border-color var(--t-med) var(--ease);
}
.step:hover { border-color: var(--c-border-2); }
.step::before {
  content: counter(step, decimal-leading-zero);
  display: grid; place-items: center;
  width: 46px; height: 46px;
  border-radius: var(--r-md);
  background: var(--c-accent-soft);
  border: 1px solid rgba(11,132,255,0.24);
  font-family: var(--f-mono);
  font-size: 15px;
  font-weight: 600;
  color: var(--c-accent-hi);
}
.step > div { max-width: 46ch; }
.step h3 { font-size: var(--fs-md); margin-bottom: 6px; }
.step p  { font-size: var(--fs-sm); color: var(--c-text-2); margin: 0; }

/* ── Spec / requirement rows ──────────────────────────────────────────── */
.spec { display: grid; gap: 0; }
.spec__row {
  display: grid;
  grid-template-columns: 168px 1fr;
  gap: var(--sp-4);
  padding: var(--sp-3) 0;
  border-bottom: 1px solid var(--c-border);
  font-size: var(--fs-sm);
}
.spec__row:last-child { border-bottom: 0; }
.spec__key {
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: 1.1px;
  text-transform: uppercase;
  color: var(--c-text-3);
  padding-top: 2px;
}
.spec__val { color: var(--c-text); }
.spec__val .num { color: var(--c-text); }

/* A value the site owner still has to supply. */
.placeholder-value {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 1px 8px;
  border: 1px dashed rgba(212,134,10,0.5);
  border-radius: var(--r-sm);
  background: rgba(212,134,10,0.07);
  color: #e6a740;
  font-family: var(--f-mono);
  font-size: 12px;
}

/* ── Footer ───────────────────────────────────────────────────────────────
   No margin-top on purpose. Every page's last section already carries
   --sp-16 of bottom padding, and the footer carries --sp-16 of its own top
   padding inside its border — so there is 64px above the rule and 64px below
   it without adding any more. The old --sp-24 margin stacked on top of that
   and left a 160px band of nothing between the final card and the footer,
   which read as the page having stopped early. Don't put it back; if a
   particular page needs more air, give that page's last section a modifier. */
.site-footer {
  border-top: 1px solid var(--c-border);
  background: linear-gradient(180deg, var(--c-base-2), var(--c-base));
  padding-block: var(--sp-16) var(--sp-8);
  font-size: var(--fs-sm);
}
.footer-grid {
  display: grid;
  grid-template-columns: 1.6fr repeat(3, 1fr);
  gap: var(--sp-10);
}
.footer-col h4 {
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: 1.4px;
  text-transform: uppercase;
  color: var(--c-text-3);
  margin-bottom: var(--sp-4);
}
.footer-col ul { list-style: none; padding: 0; }
.footer-col li { margin-bottom: var(--sp-2); }
.footer-col a { color: var(--c-text-2); }
.footer-col a:hover { color: var(--c-accent-hi); }

.footer-legal-entity { margin-top: var(--sp-5); color: var(--c-text-3); font-size: var(--fs-xs); line-height: 1.75; }
.footer-legal-entity strong { display: block; color: var(--c-text-2); letter-spacing: 0.6px; }

.footer-bottom {
  margin-top: var(--sp-12);
  padding-top: var(--sp-6);
  border-top: 1px solid var(--c-border);
  display: flex; flex-wrap: wrap; gap: var(--sp-4);
  align-items: center; justify-content: space-between;
  font-size: var(--fs-xs);
  color: var(--c-text-4);
}

/* ── Reveal-on-scroll (disabled under reduced motion, see base.css) ────── */
.reveal { opacity: 0; transform: translateY(14px); transition: opacity 520ms var(--ease), transform 520ms var(--ease); }
.reveal.is-visible { opacity: 1; transform: none; }


/* ── Forms (Beta Tester application) ──────────────────────────────────────
   Deliberately generous targets and always-visible labels. Errors are shown
   in text as well as colour, so they never depend on colour alone. */
.fieldset {
  border: 0;
  padding: 0;
  margin: 0 0 var(--sp-10);
}
.fieldset > legend {
  display: block;
  width: 100%;
  padding: 0 0 var(--sp-4);
  margin-bottom: var(--sp-6);
  border-bottom: 1px solid var(--c-border);
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: 1.5px;
  text-transform: uppercase;
  color: var(--c-text-3);
}
.fieldset:last-of-type { margin-bottom: var(--sp-6); }

.field { display: flex; flex-direction: column; gap: 6px; margin-bottom: var(--sp-6); }

.field-label {
  font-size: var(--fs-sm);
  font-weight: 600;
  color: var(--c-text);
  display: flex; align-items: baseline; flex-wrap: wrap; gap: var(--sp-2);
}

/* Required / optional stated in TEXT, not by an asterisk or colour alone. */
.req-mark, .opt-mark {
  font-size: var(--fs-micro);
  font-weight: 700;
  letter-spacing: 0.8px;
  text-transform: uppercase;
  padding: 1px 7px;
  border-radius: 999px;
}
.req-mark { color: var(--c-accent-hi); background: rgba(11,132,255,0.12); border: 1px solid rgba(11,132,255,0.30); }
.opt-mark { color: var(--c-text-3);    background: var(--c-surface-2);    border: 1px solid var(--c-border-2); }

.field-hint { font-size: var(--fs-xs); color: var(--c-text-3); margin: 0; }

.field-input {
  width: 100%;
  padding: 11px 13px;
  background: var(--c-base);
  border: 1px solid var(--c-border-2);
  border-radius: var(--r-md);
  color: var(--c-text);
  font-family: inherit;
  font-size: var(--fs-sm);
  line-height: 1.5;
  transition: border-color var(--t-fast) var(--ease), box-shadow var(--t-fast) var(--ease);
}
.field-input::placeholder { color: var(--c-text-4); }
.field-input:hover { border-color: var(--c-border-hover); }
.field-input:focus {
  outline: none;
  border-color: var(--c-accent);
  box-shadow: 0 0 0 3px rgba(11,132,255,0.18);
}
.field-textarea { resize: vertical; min-height: 96px; }

.field-input.is-invalid, .field-input[aria-invalid="true"] { border-color: var(--c-danger); }
.field-input.is-invalid:focus { box-shadow: 0 0 0 3px rgba(239,68,68,0.20); }

.field-error {
  display: flex; align-items: flex-start; gap: 6px;
  font-size: var(--fs-xs);
  color: #ff9a9a;
  margin: 0;
}
.field-error::before { content: "\26A0"; line-height: 1.35; }

/* ── Radio / checkbox choices ─────────────────────────────────────────── */
.choice {
  display: flex; align-items: flex-start; gap: var(--sp-3);
  padding: 11px 14px;
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
  background: var(--c-surface-2);
  font-size: var(--fs-sm);
  color: var(--c-text-2);
  cursor: pointer;
  transition: border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.choice:hover { border-color: var(--c-border-hover); background: var(--c-surface-3); }
.choice input { width: 17px; height: 17px; margin-top: 2px; flex-shrink: 0; accent-color: var(--c-accent); cursor: pointer; }
.choice:has(input:checked) { border-color: var(--c-accent); background: rgba(11,132,255,0.08); color: var(--c-text); }
.choice--block { align-items: flex-start; line-height: 1.55; }

.radio-group { border: 0; padding: 0; margin-bottom: var(--sp-6); }
.radio-group > legend { padding: 0; margin-bottom: var(--sp-3); border: 0; }
.radio-group .choice + .choice { margin-top: var(--sp-2); }

/* ── Honeypot — hidden from sight, from layout and from screen readers ─── */
.hp-field {
  position: absolute !important;
  left: -9999px;
  width: 1px; height: 1px;
  overflow: hidden;
}

/* ── Error summary / success panel ────────────────────────────────────── */
.form-summary {
  padding: var(--sp-6) var(--sp-8);
  border: 1px solid var(--c-border-2);
  border-left: 3px solid var(--c-border-hover);
  border-radius: var(--r-lg);
  margin-bottom: var(--sp-6);
  background: var(--c-surface);
}
.form-summary:focus-visible { outline: 2px solid var(--c-accent); outline-offset: 3px; }
.form-summary h2 { font-size: var(--fs-lg); margin-bottom: var(--sp-3); }
.form-summary p  { font-size: var(--fs-sm); }
.form-summary ul { margin-top: var(--sp-3); font-size: var(--fs-sm); }
.form-summary a  { text-decoration: underline; text-underline-offset: 3px; }

.form-summary--error { border-left-color: var(--c-danger); background: linear-gradient(180deg, rgba(239,68,68,0.06), transparent); }
.form-summary--error h2 { color: #ffb4b4; }
.form-summary--ok    { border-left-color: var(--c-green); background: linear-gradient(180deg, rgba(34,197,94,0.07), transparent); }
.form-summary--ok h2 { color: #7ee2a4; }

/* ── Beta application page layout ─────────────────────────────────────── */
.beta-layout { display: grid; grid-template-columns: minmax(0, 1.55fr) minmax(0, 1fr); gap: var(--sp-10); align-items: start; }
.beta-aside  { position: sticky; top: calc(var(--header-h) + var(--sp-6)); }
.beta-privacy-warning { margin-bottom: var(--sp-6); padding: var(--sp-4) var(--sp-5); font-size: var(--fs-sm); }
.beta-required-note { margin-bottom: var(--sp-8); }
.beta-actions { margin-top: var(--sp-8); }
.beta-steps { font-size: var(--fs-sm); padding-left: 1.15em; }
.beta-steps li { margin-bottom: var(--sp-3); }
.beta-steps li::marker { color: var(--c-accent-hi); font-weight: 700; }

.beta-collect { padding-left: 1.15em; margin: 0; }
.beta-collect li { margin-bottom: var(--sp-3); line-height: 1.6; }
.beta-collect li::marker { color: var(--c-accent-hi); }
.beta-collect strong { color: var(--c-text); }


/* ── Product-scope line in the hero ───────────────────────────────────── */
.hero__scope {
  margin-top: var(--sp-5);
  font-size: var(--fs-sm);
  font-weight: 600;
  letter-spacing: 0.2px;
  color: var(--c-accent-hi);
}
.hero__scope span { margin-inline: 8px; opacity: 0.55; }

/* ── Feature spotlight (copy beside a screenshot) ─────────────────────────
   Home page only, for the two points that need more room than a feature
   tile: the scale check and the production workflow.

   The markup is always COPY FIRST, then the figure. `--flip` moves the image
   to the left visually with `order`, which changes nothing for a screen
   reader or for keyboard order — so the heading still introduces its own
   picture either way. Do not reorder the markup to achieve the same effect. */
.spotlight {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
  gap: var(--sp-10);
  align-items: center;
}
.spotlight--flip .spotlight__copy  { order: 2; }
.spotlight--flip .spotlight__media { order: 1; }
.spotlight__copy h2 { margin-bottom: var(--sp-5); }
.spotlight__copy > p { font-size: var(--fs-md); color: var(--c-text-2); }
.spotlight__copy > p + p { margin-top: var(--sp-4); }
.spotlight__copy .req-list { margin-top: var(--sp-6); }
.spotlight__copy .fine { margin-top: var(--sp-5); }
.spotlight__media { margin: 0; }

/* ── Scope callout ("Built for metal roofing") ────────────────────────── */
.scope-callout {
  display: grid;
  grid-template-columns: minmax(0, 1.85fr) minmax(0, 1fr);
  gap: var(--sp-10);
  align-items: start;
  padding: var(--sp-10);
  border: 1px solid var(--c-border-2);
  border-left: 3px solid var(--c-accent);
  border-radius: var(--r-xl);
  background:
    radial-gradient(620px 260px at 12% 0%, rgba(11,132,255,0.10), transparent 70%),
    var(--c-surface);
  box-shadow: var(--shadow-1), var(--ring);
}
.scope-callout h2 { font-size: var(--fs-xl); margin-bottom: var(--sp-4); }
.scope-callout p  { font-size: var(--fs-sm); }
.scope-callout__main p { font-size: var(--fs-base); color: var(--c-text-2); }
.scope-callout__units {
  padding-left: var(--sp-10);
  border-left: 1px solid var(--c-border);
}
.scope-units__lead {
  font-size: var(--fs-lg);
  font-weight: 700;
  color: var(--c-text);
  margin-bottom: var(--sp-3);
}

/* ── Scope notice (downloads page, beta form) ─────────────────────────── */
.scope-notice {
  padding: var(--sp-5) var(--sp-6);
  font-size: var(--fs-sm);
  margin-bottom: var(--sp-6);
}
.scope-notice p { margin: 0; }
.beta-scope-notice { margin-bottom: var(--sp-5); }

/* A "not supported" line in a tick list — a cross, and never colour alone. */
.req-list__no svg { color: var(--c-text-3); }
.req-list__no span { color: var(--c-text-3); }
.req-card--wide { grid-column: 1 / -1; }
